Skip to content

Commit

Permalink
[agroal#392] Add application name and version in management protocol
Browse files Browse the repository at this point in the history
In order to improve debugging, [agroal#392] suggested to write
the sender application name and its version in the
socket over which pgagroal-cli and pgagroal communicate.

Introduces the 'write_info' function in management.c.
  • Loading branch information
EuGig committed Apr 6, 2024
1 parent ce6be90 commit cc68a67
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 7 deletions.
19 changes: 19 additions & 0 deletions src/include/management.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,25 @@ extern "C" {
#define COMMAND_OUTPUT_FORMAT_TEXT 'T'
#define COMMAND_OUTPUT_FORMAT_JSON 'J'

/**
* Available applications
*/
#define PGAGROAL 1
#define PGAGROAL_CLI 2
#define PGAGROAL_VAULT 3

/*
* stores the application name and its version
* which are sent through the socket
*/
struct pgagroal_version_info
{
char* s;
int command;
char* v;
int version;
};

/**
* Get the frontend password of a user
* @param ssl The SSL connection
Expand Down
193 changes: 186 additions & 7 deletions src/libpgagroal/management.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,17 @@
#include <openssl/ssl.h>

#define MANAGEMENT_HEADER_SIZE 5
#define MANAGEMENT_INFO_SIZE sizeof(struct pgagroal_version_info)

#define S "S:"
#define V ",V:"

static int read_complete(SSL* ssl, int socket, void* buf, size_t size);
static int write_complete(SSL* ssl, int socket, void* buf, size_t size);
static int write_socket(int socket, void* buf, size_t size);
static int write_ssl(SSL* ssl, void* buf, size_t size);
static int write_header(SSL* ssl, int fd, signed char type, int slot);
static int write_info(char* buffer, int command, int offset);

static int pgagroal_management_write_conf_ls_detail(int socket, char* what);
static int pgagroal_management_read_conf_ls_detail(SSL* ssl, int socket, char* buffer);
Expand All @@ -71,10 +76,14 @@ static cJSON* pgagroal_managment_json_read_config_get(int socket, char* config_k
static cJSON* pgagroal_management_json_read_conf_ls(SSL* ssl, int socket);
static int pgagroal_management_json_print_conf_ls(cJSON* json);

static int pgagroal_get_executable_name(char* version);
static char* pgagroal_get_command_name(int command);

int
pgagroal_management_read_header(int socket, signed char* id, int32_t* slot)
{
char header[MANAGEMENT_HEADER_SIZE];
char buf_info[MANAGEMENT_INFO_SIZE];

if (read_complete(NULL, socket, &header[0], sizeof(header)))
{
Expand All @@ -86,6 +95,13 @@ pgagroal_management_read_header(int socket, signed char* id, int32_t* slot)
*id = pgagroal_read_byte(&(header));
*slot = pgagroal_read_int32(&(header[1]));

if (read_complete(NULL, socket, &buf_info[0], sizeof(buf_info)))
{
pgagroal_log_warn("pgagroal_management_read_header: %d %s", socket, strerror(errno));
errno = 0;
goto error;
}

return 0;

error:
Expand Down Expand Up @@ -188,7 +204,6 @@ pgagroal_management_read_payload(int socket, signed char id, int* payload_i, cha
case MANAGEMENT_CONFIG_GET:
case MANAGEMENT_GET_PASSWORD:
case MANAGEMENT_CONFIG_SET:

if (read_complete(NULL, socket, &buf4[0], sizeof(buf4)))
{
goto error;
Expand Down Expand Up @@ -685,11 +700,15 @@ pgagroal_management_json_read_status_details(SSL* ssl, int socket, bool include_
int limits = 0;
int servers = 0;
char header[12 + MAX_NUMBER_OF_CONNECTIONS];
char buf_info[MANAGEMENT_INFO_SIZE];

memset(&buf, 0, sizeof(buf));
memset(&disabled, 0, sizeof(disabled));
memset(&header, 0, sizeof(header));

// consumes info
read_complete(ssl, socket, &buf_info[0], sizeof(buf_info));

cJSON* json = pgagroal_json_create_new_command_object(include_details ? "status details" : "status", true, "pgagroal-cli");
cJSON* output = pgagroal_json_extract_command_output_object(json);

Expand Down Expand Up @@ -900,10 +919,21 @@ int
pgagroal_management_write_status(int socket, bool graceful)
{
char buf[16];
char buf_info[MANAGEMENT_INFO_SIZE];

int active;
int total;
struct main_configuration* config;

write_info(buf_info, PGAGROAL, 0);

if (write_complete(NULL, socket, &buf_info, sizeof(buf_info)))
{
pgagroal_log_warn("pgagroal_management_write_status: write: %d %s", socket, strerror(errno));
errno = 0;
goto error;
}

memset(&buf, 0, sizeof(buf));
active = 0;
total = 0;
Expand Down Expand Up @@ -1014,8 +1044,9 @@ pgagroal_management_read_details(SSL* ssl, int socket, char output_format)
int
pgagroal_management_write_details(int socket)
{
char header[12 + MAX_NUMBER_OF_CONNECTIONS];
struct main_configuration* config;
int offset = 12;
char header[offset + MAX_NUMBER_OF_CONNECTIONS];

config = (struct main_configuration*)shmem;

Expand All @@ -1028,7 +1059,7 @@ pgagroal_management_write_details(int socket)
for (int i = 0; i < config->max_connections; i++)
{
signed char state = atomic_load(&config->states[i]);
header[12 + i] = (char)state;
header[offset + i] = (char)state;
}

if (write_complete(NULL, socket, header, sizeof(header)))
Expand Down Expand Up @@ -1128,7 +1159,7 @@ pgagroal_management_isalive(SSL* ssl, int fd)
int
pgagroal_management_read_isalive(SSL* ssl, int socket, int* status, char output_format)
{
char buf[4];
char buf[MANAGEMENT_INFO_SIZE + 4];

memset(&buf, 0, sizeof(buf));

Expand All @@ -1139,7 +1170,7 @@ pgagroal_management_read_isalive(SSL* ssl, int socket, int* status, char output_
goto error;
}

*status = pgagroal_read_int32(&buf);
*status = pgagroal_read_int32(&buf[MANAGEMENT_INFO_SIZE]);

// do I need to provide JSON output?
if (output_format == COMMAND_OUTPUT_FORMAT_JSON)
Expand Down Expand Up @@ -1177,6 +1208,16 @@ int
pgagroal_management_write_isalive(int socket, bool gracefully)
{
char buf[4];
char buf_info[MANAGEMENT_INFO_SIZE];

write_info(buf_info, PGAGROAL, 0);

if (write_complete(NULL, socket, &buf_info, sizeof(buf_info)))
{
pgagroal_log_warn("pgagroal_management_write_isalive: write: %d %s", socket, strerror(errno));
errno = 0;
goto error;
}

memset(&buf, 0, sizeof(buf));

Expand Down Expand Up @@ -1696,15 +1737,128 @@ write_ssl(SSL* ssl, void* buf, size_t size)
return 1;
}

/**
* Function to write sender application name and its version
* into header socket.
*
* @param header: the header to write sender application name and its version into
* @param command: the server application name
* @param offset: the offset at which info has to be written
* @return 0 on success
*/
static int
write_info(char* buffer, int command, int offset)
{
struct pgagroal_version_info info;

info.command = command;

int version_name = pgagroal_get_executable_name(PGAGROAL_VERSION);
if (version_name == 1)
{
return 1;
}

info.version = version_name;
info.s = S;
info.v = V;

pgagroal_write_string(buffer + offset, info.s);
pgagroal_write_int32(buffer + offset + 2, info.command);
pgagroal_write_string(buffer + offset + 6, info.v);
pgagroal_write_int32(buffer + offset + 9, info.version);

char* command_name = pgagroal_get_command_name(command);
if (strcmp(command_name, "unxpected") == 0)
{
return 1;
}

pgagroal_log_debug("%s version %s", command_name, PGAGROAL_VERSION);

return 0;
}

/*
* Utility function to convert PGAGROAL_VERSION into a number.
*/
static int
pgagroal_get_executable_name(char* version)
{
int major;
int minor;
int patch;

long val;

char* del = ".";
char* endptr;
char buf[sizeof(version)];

if (version == NULL)
{
version = PGAGROAL_VERSION;
}

memcpy(buf, version, sizeof(buf));

char* token = strtok(buf, del);
val = strtol(token, &endptr, 10);
major = (int)val;

token = strtok(NULL, del);
val = strtol(token, &endptr, 10);
minor = (int)val;

token = strtok(NULL, del);
val = strtol(token, &endptr, 10);
patch = (int)val;

int version_name = major * 100000 + minor * 1000 + 10 * patch;

if (version_name < INT_MIN || version_name > INT_MAX)
{
pgagroal_log_debug("pgagroal_get_executable_name got overflowed value: %s\n", version);
return 1;
}

return version_name;
}

/*
* Utility function to convert command into a string.
*/
static char*
pgagroal_get_command_name(int command)
{
switch (command)
{
case PGAGROAL:
return "pgagroal";
case PGAGROAL_CLI:
return "pgagroal-cli";
case PGAGROAL_VAULT:
return "pgagroal-vault";
default:
pgagroal_log_debug("pgagroal_get_command_name got unexpected value: %d\n", command);
return "unexpected";
}
}

static int
write_header(SSL* ssl, int fd, signed char type, int slot)
{
char header[MANAGEMENT_HEADER_SIZE];
char header[MANAGEMENT_HEADER_SIZE + MANAGEMENT_INFO_SIZE];

pgagroal_write_byte(&(header), type);
pgagroal_write_int32(&(header[1]), slot);

return write_complete(ssl, fd, &(header), MANAGEMENT_HEADER_SIZE);
if (write_info(header, PGAGROAL_CLI, MANAGEMENT_HEADER_SIZE))
{
pgagroal_log_debug("write_info got either unexpected value for executable name or overflow version");
}

return write_complete(ssl, fd, &(header), sizeof(header));
}

int
Expand Down Expand Up @@ -1768,8 +1922,17 @@ pgagroal_management_write_config_get(int socket, char* config_key)
{
char data[MISC_LENGTH];
char buf[4];
char buf_info[MANAGEMENT_INFO_SIZE];

size_t size;

write_info(buf_info, PGAGROAL, 0);
if (write_complete(NULL, socket, buf_info, sizeof(buf_info)))
{
pgagroal_log_debug("pgagroal_management_config_get: write: %d %s", socket, strerror(errno));
goto error;
}

if (!config_key || !strlen(config_key))
{
pgagroal_log_debug("pgagroal_management_write_config_get: no key specified");
Expand Down Expand Up @@ -1884,6 +2047,8 @@ pgagroal_managment_json_read_config_get(int socket, char* config_key, char* expe
int
pgagroal_management_read_config_get(int socket, char* config_key, char* expected_value, bool verbose, char output_format)
{
char buf_info[MANAGEMENT_INFO_SIZE];
read_complete(NULL, socket, &buf_info[0], sizeof(buf_info));

cJSON* json = pgagroal_managment_json_read_config_get(socket, config_key, expected_value);
int status = EXIT_STATUS_OK;
Expand Down Expand Up @@ -2103,6 +2268,14 @@ pgagroal_management_write_conf_ls(int socket)

config = (struct main_configuration*)shmem;

char buf_info[MANAGEMENT_INFO_SIZE];
write_info(buf_info, PGAGROAL, 0);

if (write_complete(NULL, socket, &buf_info, sizeof(buf_info)))
{
goto error;
}

if (pgagroal_management_write_conf_ls_detail(socket, config->common.configuration_path))
{
goto error;
Expand Down Expand Up @@ -2429,6 +2602,7 @@ pgagroal_management_json_read_conf_ls(SSL* ssl, int socket)
{
char buf[4];
char* buffer;
char buf_info[MANAGEMENT_INFO_SIZE];

cJSON* json = pgagroal_json_create_new_command_object("conf ls", true, "pgagroal-cli");
cJSON* output = pgagroal_json_extract_command_output_object(json);
Expand All @@ -2442,6 +2616,11 @@ pgagroal_management_json_read_conf_ls(SSL* ssl, int socket)
memset(&buf, 0, sizeof(buf));
buffer = calloc(1, MAX_PATH);

if (read_complete(ssl, socket, &buf_info[0], sizeof(buf_info)))
{
goto error;
}

if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
{
goto error;
Expand Down

0 comments on commit cc68a67

Please sign in to comment.