@@ -346,6 +346,41 @@ int pb_protocol_url_len(const char *url)
return 4 + optional_strlen(url);
}
+int pb_protocol_command_len(const struct command *cmd)
+{
+ unsigned int i, len = 0;
+
+ len += 4 + optional_strlen(cmd->platform);
+ len += 4 + optional_strlen(cmd->name);
+ len += 4 + optional_strlen(cmd->cmd);
+ len += 4 + optional_strlen(cmd->args_fmt);
+ len += 4; /* n_args */
+
+ for (i = 0; i < cmd->n_args; i++) {
+ len += 4 + optional_strlen(cmd->args[i].name);
+ len += 4; /* type */
+ switch(cmd->args[i].type) {
+ case ARG_STR:
+ len += 4 + optional_strlen(cmd->args[i].arg_str);
+ break;
+ case ARG_I64:
+ len += sizeof(cmd->args[i].arg_i64);
+ break;
+ case ARG_F64:
+ len += sizeof(cmd->args[i].arg_f64);
+ break;
+ default:
+ pb_log("Argument %s has unknown field type %d\n",
+ cmd->args[i].name,
+ cmd->args[i].type);
+ break;
+ }
+ }
+
+ len += 4 + optional_strlen(cmd->help);
+
+ return len;
+}
int pb_protocol_plugin_option_len(const struct plugin_option *opt)
{
@@ -363,6 +398,10 @@ int pb_protocol_plugin_option_len(const struct plugin_option *opt)
for (i = 0; i < opt->n_executables; i++)
len += 4 + optional_strlen(opt->executables[i]);
+ len += 4; /* command options */
+ for (i = 0; i < opt->n_commands; i++)
+ len += pb_protocol_command_len(&opt->commands[i]);
+
return len;
}
@@ -682,6 +721,51 @@ int pb_protocol_serialise_url(const char *url, char *buf, int buf_len)
return 0;
}
+int pb_protocol_serialise_command(char *buf,
+ const struct command *config)
+{
+ char *pos = buf;
+ unsigned int i;
+
+ pos += pb_protocol_serialise_string(pos, config->platform);
+ pos += pb_protocol_serialise_string(pos, config->name);
+ pos += pb_protocol_serialise_string(pos, config->cmd);
+ pos += pb_protocol_serialise_string(pos, config->args_fmt);
+
+ *(uint32_t *)pos = __cpu_to_be32(config->n_args);
+ pos += 4;
+
+ for (i = 0; i < config->n_args; i++) {
+ pos += pb_protocol_serialise_string(pos, config->args[i].name);
+ *(enum cmd_arg_type *)pos = config->args[i].type;
+ pos += sizeof(enum cmd_arg_type);
+
+ switch(config->args[i].type) {
+ case ARG_STR:
+ pos += pb_protocol_serialise_string(pos,
+ config->args[i].arg_str);
+ break;
+ case ARG_I64:
+ *(int64_t *)pos = __cpu_to_be64(config->args[i].arg_i64);
+ pos += sizeof(int64_t);
+ break;
+ case ARG_F64:
+ memcpy(pos, &config->args[i].arg_f64, sizeof(double));
+ pos += sizeof(double);
+ break;
+ default:
+ pb_log("Argument %s with unknown field type %d skipped\n",
+ config->args[i].name,
+ config->args[i].type);
+ break;
+ }
+ }
+
+ pos += pb_protocol_serialise_string(pos, config->help);
+
+ return pos - buf;
+}
+
int pb_protocol_serialise_plugin_option(const struct plugin_option *opt,
char *buf, int buf_len)
{
@@ -702,6 +786,13 @@ int pb_protocol_serialise_plugin_option(const struct plugin_option *opt,
for (i = 0; i < opt->n_executables; i++)
pos += pb_protocol_serialise_string(pos, opt->executables[i]);
+ *(uint32_t *)pos = __cpu_to_be32(opt->n_commands);
+ pos += 4;
+
+ for (i = 0; i < opt->n_commands; i++)
+ pos += pb_protocol_serialise_command(pos,
+ &opt->commands[i]);
+
assert(pos <= buf + buf_len);
(void)buf_len;
@@ -1318,6 +1409,71 @@ out:
return rc;
}
+int pb_protocol_deserialise_command(void *ctx, const char **pos,
+ unsigned int *len, struct command *cmd)
+{
+ unsigned int i;
+ char *str;
+ int rc = -1;
+
+ if (read_string(ctx, pos, len, &str))
+ goto out;
+ cmd->platform = str;
+
+ if (read_string(ctx, pos, len, &str))
+ goto out;
+ cmd->name = str;
+
+ if (read_string(ctx, pos, len, &str))
+ goto out;
+ cmd->cmd = str;
+
+ if (read_string(ctx, pos, len, &str))
+ goto out;
+ cmd->args_fmt = str;
+
+ if (read_u32(pos, len, &cmd->n_args))
+ goto out;
+
+ cmd->args = talloc_zero_array(ctx, struct argument, cmd->n_args);
+ for (i = 0; i < cmd->n_args; i++) {
+ if (read_string(ctx, pos, len, &str))
+ goto out;
+ cmd->args[i].name = str;
+
+ cmd->args[i].type = *(enum cmd_arg_type *)*pos;
+ *pos += sizeof(enum cmd_arg_type);
+
+ switch (cmd->args[i].type) {
+ case ARG_STR:
+ if (read_string(ctx, pos, len, &str))
+ goto out;
+ cmd->args[i].arg_str = str;
+ break;
+ case ARG_I64:
+ cmd->args[i].arg_i64 = __be64_to_cpu(*(int64_t *)(*pos));
+ *pos += sizeof(int64_t);
+ break;
+ case ARG_F64:
+ memcpy(&cmd->args[i].arg_f64, *pos, sizeof(double));
+ *pos += sizeof(double);
+ break;
+ default:
+ pb_log("Unknown field type %d for argument %s\n",
+ cmd->args[i].type,
+ cmd->args[i].name);
+ }
+ }
+
+ if (read_string(ctx, pos, len, &str))
+ goto out;
+ cmd->help = str;
+
+ rc = 0;
+out:
+ return rc;
+}
+
int pb_protocol_deserialise_plugin_option(struct plugin_option *opt,
const struct pb_protocol_message *message)
{
@@ -1371,6 +1527,18 @@ int pb_protocol_deserialise_plugin_option(struct plugin_option *opt,
opt->executables[i] = talloc_strdup(opt, str);
}
+ if (read_u32(&pos, &len, &tmp))
+ goto out;
+ opt->n_commands = tmp;
+
+ opt->commands = talloc_zero_array(opt, struct command, opt->n_commands);
+ if (!opt->commands)
+ goto out;
+
+ for (i = 0; i < opt->n_commands; i++)
+ pb_protocol_deserialise_command(opt, &pos, &len,
+ &opt->commands[i]);
+
rc = 0;
out:
return rc;
@@ -63,6 +63,7 @@ int pb_protocol_boot_status_len(const struct status *status);
int pb_protocol_system_info_len(const struct system_info *sysinfo);
int pb_protocol_config_len(const struct config *config);
int pb_protocol_url_len(const char *url);
+int pb_protocol_command_len(const struct command *command);
int pb_protocol_plugin_option_len(const struct plugin_option *opt);
int pb_protocol_temp_autoboot_len(const struct autoboot_option *opt);
int pb_protocol_authenticate_len(struct auth_message *msg);
@@ -88,6 +89,8 @@ int pb_protocol_serialise_system_info(const struct system_info *sysinfo,
int pb_protocol_serialise_config(const struct config *config,
char *buf, int buf_len);
int pb_protocol_serialise_url(const char *url, char *buf, int buf_len);
+int pb_protocol_serialise_command(char *buf,
+ const struct command *command);
int pb_protocol_serialise_plugin_option(const struct plugin_option *opt,
char *buf, int buf_len);
int pb_protocol_serialise_temp_autoboot(const struct autoboot_option *opt,
@@ -120,6 +123,9 @@ int pb_protocol_deserialise_system_info(struct system_info *sysinfo,
int pb_protocol_deserialise_config(struct config *config,
const struct pb_protocol_message *message);
+int pb_protocol_deserialise_command(void *ctx, const char **pos,
+ unsigned int *len, struct command *command);
+
int pb_protocol_deserialise_plugin_option(struct plugin_option *opt,
const struct pb_protocol_message *message);
@@ -24,7 +24,8 @@ lib_TESTS = \
test/lib/test-process-both \
test/lib/test-process-stdout-eintr \
test/lib/test-fold \
- test/lib/test-efivar
+ test/lib/test-efivar \
+ test/lib/test-protocol
if WITH_OPENSSL
lib_TESTS += \
new file mode 100644
@@ -0,0 +1,158 @@
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <types/types.h>
+#include <talloc/talloc.h>
+#include <pb-protocol/pb-protocol.h>
+
+static int test_command_protocol(void *ctx)
+{
+ unsigned int len, write_len, read_len;
+ struct command *write, *read;
+ const char *read_buf;
+ char *buf, *pos;
+
+ write = talloc_zero(ctx, struct command);
+ if (!write)
+ return -1;
+
+ write->platform = talloc_asprintf(ctx, "platform");
+ write->name = talloc_asprintf(ctx, "test config");
+ write->cmd = talloc_asprintf(ctx, "command");
+ write->args_fmt = talloc_asprintf(ctx, "{} {} {}");
+ write->n_args = 3;
+ write->args = talloc_zero_array(write, struct argument, write->n_args);
+
+ write->args[0].name = talloc_asprintf(write, "arg 0");
+ write->args[0].type = ARG_STR;
+ write->args[0].arg_str = talloc_asprintf(write, "string arg");
+
+ write->args[1].name = talloc_asprintf(write, "arg 1");
+ write->args[1].type = ARG_I64;
+ write->args[1].arg_i64 = 5;
+
+ write->args[2].name = talloc_asprintf(write, "arg 2");
+ write->args[2].type = ARG_F64;
+ write->args[2].arg_f64 = 4.4;
+
+ write->help = talloc_asprintf(write, "good luck");
+
+ len = pb_protocol_command_len(write);
+ fprintf(stderr, "write config is %d bytes\n", len);
+
+ buf = talloc_array(ctx, char, len);
+ pos = buf;
+
+ write_len = pb_protocol_serialise_command(pos, write);
+ if (write_len != len) {
+ fprintf(stderr, "Failed to serialise machine config\n");
+ fprintf(stderr, "Serialised length does not match expected (%lu vs %d)\n",
+ pos - buf, write_len);
+ return -1;
+ }
+
+ read_buf = talloc_memdup(ctx, buf, write_len);
+ read_len = write_len;
+ read = talloc_zero(ctx, struct command);
+ if (pb_protocol_deserialise_command(ctx, &read_buf, &read_len, read)) {
+ fprintf(stderr, "Failed to deserialise machine config\n");
+ return -1;
+ }
+
+ if (strcmp(write->platform, read->platform)) {
+ fprintf(stderr, "platform field does not match: %s vs %s\n",
+ write->platform, read->platform);
+ return -1;
+ }
+ if (strcmp(write->name, read->name)) {
+ fprintf(stderr, "name field does not match: %s vs %s\n",
+ write->name, read->name);
+ return -1;
+ }
+ if (strcmp(write->cmd, read->cmd)) {
+ fprintf(stderr, "cmd field does not match: %s vs %s\n",
+ write->cmd, read->cmd);
+ return -1;
+ }
+ if (strcmp(write->args_fmt, read->args_fmt)) {
+ fprintf(stderr, "args_fmt field does not match: %s vs %s\n",
+ write->args_fmt, read->args_fmt);
+ return -1;
+ }
+
+ if (write->n_args != read->n_args) {
+ fprintf(stderr, "n_args mismatch: %u vs %u\n", write->n_args,
+ read->n_args);
+ return -1;
+ }
+
+ if (strcmp(write->args[0].name, read->args[0].name)) {
+ fprintf(stderr, "arg 0 name does not match: %s vs %s\n",
+ write->args[0].name, read->args[0].name);
+ return -1;
+ }
+ if (write->args[0].type != read->args[0].type) {
+ fprintf(stderr, "arg 0 field type does not match: %d vs %d\n",
+ write->args[0].type, read->args[0].type);
+ return -1;
+ }
+ if (strcmp(write->args[0].arg_str, read->args[0].arg_str)) {
+ fprintf(stderr, "arg 0 arg does not match: %s vs %s\n",
+ write->args[0].arg_str, read->args[0].arg_str);
+ return -1;
+ }
+
+ if (strcmp(write->args[1].name, read->args[1].name)) {
+ fprintf(stderr, "arg 1 name does not match: %s vs %s\n",
+ write->args[1].name, read->args[1].name);
+ return -1;
+ }
+ if (write->args[1].type != read->args[1].type) {
+ fprintf(stderr, "arg 1 field type does not match: %d vs %d\n",
+ write->args[1].type, read->args[1].type);
+ return -1;
+ }
+ if (write->args[1].arg_i64 != read->args[1].arg_i64) {
+ fprintf(stderr, "arg 1 field arg does not match: %ld vs %ld\n",
+ write->args[1].arg_i64, read->args[1].arg_i64);
+ return -1;
+ }
+
+ if (strcmp(write->args[2].name, read->args[2].name)) {
+ fprintf(stderr, "arg 2 name does not match: %s vs %s\n",
+ write->args[2].name, read->args[2].name);
+ return -1;
+ }
+ if (write->args[2].type != read->args[2].type) {
+ fprintf(stderr, "arg 2 field type does not match: %d vs %d\n",
+ write->args[2].type, read->args[2].type);
+ return -1;
+ }
+ if (write->args[2].arg_f64 != read->args[2].arg_f64) {
+ fprintf(stderr, "arg 2 field arg does not match: %f vs %f\n",
+ write->args[2].arg_f64, read->args[2].arg_f64);
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ void *ctx;
+ int rc = 0;
+
+ ctx = talloc_new(NULL);
+
+ rc = test_command_protocol(ctx);
+ if (rc)
+ printf("FAIL: test_command\n");
+
+ talloc_free(ctx);
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
Plus add test-protocol which validates the serialisation and de-serialisation of the command structs. Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com> --- lib/pb-protocol/pb-protocol.c | 168 ++++++++++++++++++++++++++++++++++ lib/pb-protocol/pb-protocol.h | 6 ++ test/lib/Makefile.am | 3 +- test/lib/test-protocol.c | 158 ++++++++++++++++++++++++++++++++ 4 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 test/lib/test-protocol.c