ctdb-event: Add event daemon protocol
authorAmitay Isaacs <amitay@gmail.com>
Thu, 15 Feb 2018 06:33:12 +0000 (17:33 +1100)
committerMartin Schwenke <martins@samba.org>
Thu, 5 Jul 2018 04:52:43 +0000 (06:52 +0200)
Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
ctdb/event/event_protocol.c [new file with mode: 0644]
ctdb/event/event_protocol.h [new file with mode: 0644]
ctdb/event/event_protocol_api.h [new file with mode: 0644]
ctdb/event/event_protocol_test.c [new file with mode: 0644]
ctdb/event/event_protocol_util.c [new file with mode: 0644]
ctdb/tests/cunit/event_protocol_test_001.sh [new file with mode: 0755]
ctdb/wscript

diff --git a/ctdb/event/event_protocol.c b/ctdb/event/event_protocol.c
new file mode 100644 (file)
index 0000000..21adb43
--- /dev/null
@@ -0,0 +1,1122 @@
+/*
+   CTDB event daemon protocol
+
+   Copyright (C) Amitay Isaacs  2018
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include <talloc.h>
+
+#include "protocol/protocol_basic.h"
+
+#include "event_protocol.h"
+#include "event_protocol_api.h"
+
+static size_t ctdb_event_script_action_len(enum ctdb_event_script_action in)
+{
+       uint32_t u32 = in;
+
+       return ctdb_uint32_len(&u32);
+}
+
+static void ctdb_event_script_action_push(enum ctdb_event_script_action in,
+                                         uint8_t *buf,
+                                         size_t *npush)
+{
+       uint32_t u32 = in;
+
+       ctdb_uint32_push(&u32, buf, npush);
+}
+
+static int ctdb_event_script_action_pull(uint8_t *buf,
+                                        size_t buflen,
+                                        enum ctdb_event_script_action *out,
+                                        size_t *npull)
+{
+       enum ctdb_event_script_action value;
+       uint32_t u32;
+       size_t np;
+       int ret;
+
+       ret = ctdb_uint32_pull(buf, buflen, &u32, &np);
+       if (ret != 0) {
+               return ret;
+       }
+
+       switch (u32) {
+       case 0:
+               value = CTDB_EVENT_SCRIPT_DISABLE;
+               break;
+
+       case 1:
+               value = CTDB_EVENT_SCRIPT_ENABLE;
+               break;
+
+       default:
+               return EINVAL;
+       }
+
+       *out = value;
+       *npull = np;
+
+       return 0;
+}
+
+static size_t ctdb_event_command_len(enum ctdb_event_command in)
+{
+       uint32_t u32 = in;
+
+       return ctdb_uint32_len(&u32);
+}
+
+static void ctdb_event_command_push(enum ctdb_event_command in,
+                                   uint8_t *buf,
+                                   size_t *npush)
+{
+       uint32_t u32 = in;
+
+       ctdb_uint32_push(&u32, buf, npush);
+}
+
+static int ctdb_event_command_pull(uint8_t *buf,
+                                  size_t buflen,
+                                  enum ctdb_event_command *out,
+                                  size_t *npull)
+{
+       enum ctdb_event_command value;
+       uint32_t u32;
+       size_t np;
+       int ret;
+
+       ret = ctdb_uint32_pull(buf, buflen, &u32, &np);
+       if (ret != 0) {
+               return ret;
+       }
+
+       switch (u32) {
+       case 1:
+               value = CTDB_EVENT_CMD_RUN;
+               break;
+
+       case 2:
+               value = CTDB_EVENT_CMD_STATUS;
+               break;
+
+       case 3:
+               value = CTDB_EVENT_CMD_SCRIPT;
+               break;
+
+       default:
+               return EINVAL;
+       }
+
+       *out = value;
+       *npull = np;
+
+       return 0;
+}
+
+static size_t ctdb_event_script_len(struct ctdb_event_script *in)
+{
+       return ctdb_stringn_len(&in->name) +
+               ctdb_timeval_len(&in->begin) +
+               ctdb_timeval_len(&in->end) +
+               ctdb_int32_len(&in->result) +
+               ctdb_stringn_len(&in->output);
+}
+
+static void ctdb_event_script_push(struct ctdb_event_script *in,
+                                  uint8_t *buf,
+                                  size_t *npush)
+{
+       size_t offset = 0, np;
+
+       ctdb_stringn_push(&in->name, buf+offset, &np);
+       offset += np;
+
+       ctdb_timeval_push(&in->begin, buf+offset, &np);
+       offset += np;
+
+       ctdb_timeval_push(&in->end, buf+offset, &np);
+       offset += np;
+
+       ctdb_int32_push(&in->result, buf+offset, &np);
+       offset += np;
+
+       ctdb_stringn_push(&in->output, buf+offset, &np);
+       offset += np;
+
+       *npush = offset;
+}
+
+static int ctdb_event_script_pull_elems(uint8_t *buf,
+                                       size_t buflen,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct ctdb_event_script *value,
+                                       size_t *npull)
+{
+       size_t offset = 0, np;
+       int ret;
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               mem_ctx,
+                               &value->name,
+                               &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       ret = ctdb_timeval_pull(buf+offset,
+                               buflen-offset,
+                               &value->begin,
+                               &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       ret = ctdb_timeval_pull(buf+offset,
+                               buflen-offset,
+                               &value->end,
+                               &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       ret = ctdb_int32_pull(buf+offset,
+                             buflen-offset,
+                             &value->result,
+                             &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               mem_ctx,
+                               &value->output,
+                               &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       *npull = offset;
+
+       return 0;
+}
+
+#ifdef EVENT_PROTOCOL_TEST
+static int ctdb_event_script_pull(uint8_t *buf,
+                                 size_t buflen,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct ctdb_event_script **out,
+                                 size_t *npull)
+{
+       struct ctdb_event_script *value;
+       int ret;
+
+       value = talloc(mem_ctx, struct ctdb_event_script);
+       if (value == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_event_script_pull_elems(buf, buflen, value, value, npull);
+       if (ret != 0) {
+               talloc_free(value);
+               return ret;
+       }
+
+       *out = value;
+
+       return 0;
+}
+#endif
+
+static size_t ctdb_event_script_list_len(struct ctdb_event_script_list *in)
+{
+       size_t len;
+       int i;
+
+       len = ctdb_int32_len(&in->num_scripts);
+
+       for (i=0; i<in->num_scripts; i++) {
+               len += ctdb_event_script_len(&in->script[i]);
+       }
+
+       return len;
+}
+
+static void ctdb_event_script_list_push(struct ctdb_event_script_list *in,
+                                       uint8_t *buf,
+                                       size_t *npush)
+{
+       size_t offset = 0, np;
+       int i;
+
+       ctdb_int32_push(&in->num_scripts, buf+offset, &np);
+       offset += np;
+
+       for (i=0; i<in->num_scripts; i++) {
+               ctdb_event_script_push(&in->script[i], buf+offset, &np);
+               offset += np;
+       }
+
+       *npush = offset;
+}
+
+static int ctdb_event_script_list_pull(uint8_t *buf,
+                                      size_t buflen,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct ctdb_event_script_list **out,
+                                      size_t *npull)
+{
+       struct ctdb_event_script_list *value = NULL;
+       size_t offset = 0, np;
+       int num_scripts;
+       int ret, i;
+
+       ret = ctdb_int32_pull(buf+offset, buflen-offset, &num_scripts, &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       if (num_scripts < 0) {
+               return EINVAL;
+       }
+
+       value = talloc_zero(mem_ctx, struct ctdb_event_script_list);
+       if (value == NULL) {
+               return ENOMEM;
+       }
+
+       value->num_scripts = num_scripts;
+       if (num_scripts == 0) {
+               goto done;
+       }
+
+       value->script = talloc_array(value, struct ctdb_event_script,
+                                    num_scripts);
+       if (value->script == NULL) {
+               goto fail;
+       }
+
+       for (i=0; i<num_scripts; i++) {
+               ret = ctdb_event_script_pull_elems(buf+offset,
+                                                  buflen-offset,
+                                                  value,
+                                                  &value->script[i],
+                                                  &np);
+               if (ret != 0) {
+                       goto fail;
+               }
+               offset += np;
+       }
+
+done:
+       *out = value;
+       *npull = offset;
+
+       return 0;
+
+fail:
+       talloc_free(value);
+       return ret;
+}
+
+static size_t ctdb_event_request_run_len(struct ctdb_event_request_run *in)
+{
+       return ctdb_stringn_len(&in->component) +
+               ctdb_stringn_len(&in->event) +
+               ctdb_stringn_len(&in->args) +
+               ctdb_uint32_len(&in->timeout) +
+               ctdb_uint32_len(&in->flags);
+}
+
+static void ctdb_event_request_run_push(struct ctdb_event_request_run *in,
+                                       uint8_t *buf,
+                                       size_t *npush)
+{
+       size_t offset = 0, np;
+
+       ctdb_stringn_push(&in->component, buf+offset, &np);
+       offset += np;
+
+       ctdb_stringn_push(&in->event, buf+offset, &np);
+       offset += np;
+
+       ctdb_stringn_push(&in->args, buf+offset, &np);
+       offset += np;
+
+       ctdb_uint32_push(&in->timeout, buf+offset, &np);
+       offset += np;
+
+       ctdb_uint32_push(&in->flags, buf+offset, &np);
+       offset += np;
+
+       *npush = offset;
+}
+
+static int ctdb_event_request_run_pull(uint8_t *buf,
+                                      size_t buflen,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct ctdb_event_request_run **out,
+                                      size_t *npull)
+{
+       struct ctdb_event_request_run *value;
+       size_t offset = 0, np;
+       int ret;
+
+       value = talloc(mem_ctx, struct ctdb_event_request_run);
+       if (value == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               value,
+                               &value->component,
+                               &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               value,
+                               &value->event,
+                               &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               value,
+                               &value->args,
+                               &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_uint32_pull(buf+offset,
+                              buflen-offset,
+                              &value->timeout,
+                              &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_uint32_pull(buf+offset,
+                              buflen-offset,
+                              &value->flags,
+                              &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       *out = value;
+       *npull = offset;
+
+       return 0;
+
+fail:
+       talloc_free(value);
+       return ret;
+}
+
+static size_t ctdb_event_request_status_len(
+                               struct ctdb_event_request_status *in)
+{
+       return ctdb_stringn_len(&in->component) +
+               ctdb_stringn_len(&in->event);
+}
+
+static void ctdb_event_request_status_push(
+                               struct ctdb_event_request_status *in,
+                               uint8_t *buf,
+                               size_t *npush)
+{
+       size_t offset = 0, np;
+
+       ctdb_stringn_push(&in->component, buf+offset, &np);
+       offset += np;
+
+       ctdb_stringn_push(&in->event, buf+offset, &np);
+       offset += np;
+
+       *npush = offset;
+}
+
+static int ctdb_event_request_status_pull(
+                               uint8_t *buf,
+                               size_t buflen,
+                               TALLOC_CTX *mem_ctx,
+                               struct ctdb_event_request_status **out,
+                               size_t *npull)
+{
+       struct ctdb_event_request_status *value;
+       size_t offset = 0, np;
+       int ret;
+
+       value = talloc(mem_ctx, struct ctdb_event_request_status);
+       if (value == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               value,
+                               &value->component,
+                               &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               value,
+                               &value->event,
+                               &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       *out = value;
+       *npull = offset;
+
+       return 0;
+
+fail:
+       talloc_free(value);
+       return ret;
+}
+
+static size_t ctdb_event_request_script_len(
+                               struct ctdb_event_request_script *in)
+{
+       return ctdb_stringn_len(&in->component) +
+               ctdb_stringn_len(&in->script) +
+               ctdb_event_script_action_len(in->action);
+}
+
+static void ctdb_event_request_script_push(
+                               struct ctdb_event_request_script *in,
+                               uint8_t *buf,
+                               size_t *npush)
+{
+       size_t offset = 0, np;
+
+       ctdb_stringn_push(&in->component, buf+offset, &np);
+       offset += np;
+
+       ctdb_stringn_push(&in->script, buf+offset, &np);
+       offset += np;
+
+       ctdb_event_script_action_push(in->action, buf+offset, &np);
+       offset += np;
+
+       *npush = offset;
+}
+
+static int ctdb_event_request_script_pull(
+                               uint8_t *buf,
+                               size_t buflen,
+                               TALLOC_CTX *mem_ctx,
+                               struct ctdb_event_request_script **out,
+                               size_t *npull)
+{
+       struct ctdb_event_request_script *value;
+       size_t offset = 0, np;
+       int ret;
+
+       value = talloc(mem_ctx, struct ctdb_event_request_script);
+       if (value == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               value,
+                               &value->component,
+                               &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_stringn_pull(buf+offset,
+                               buflen-offset,
+                               value,
+                               &value->script,
+                               &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_event_script_action_pull(buf+offset,
+                                           buflen-offset,
+                                           &value->action,
+                                           &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       *out = value;
+       *npull = offset;
+
+       return 0;
+
+fail:
+       talloc_free(value);
+       return ret;
+}
+
+static size_t ctdb_event_reply_status_len(
+                               struct ctdb_event_reply_status *in)
+{
+       return ctdb_int32_len(&in->summary) +
+               ctdb_event_script_list_len(in->script_list);
+}
+
+static void ctdb_event_reply_status_push(
+                               struct ctdb_event_reply_status *in,
+                               uint8_t *buf,
+                               size_t *npush)
+{
+       size_t offset = 0, np;
+
+       ctdb_int32_push(&in->summary, buf+offset, &np);
+       offset += np;
+
+       ctdb_event_script_list_push(in->script_list, buf+offset, &np);
+       offset += np;
+
+       *npush = offset;
+}
+
+static int ctdb_event_reply_status_pull(
+                               uint8_t *buf,
+                               size_t buflen,
+                               TALLOC_CTX *mem_ctx,
+                               struct ctdb_event_reply_status **out,
+                               size_t *npull)
+{
+       struct ctdb_event_reply_status *value;
+       size_t offset = 0, np;
+       int ret;
+
+       value = talloc(mem_ctx, struct ctdb_event_reply_status);
+       if (value == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_int32_pull(buf+offset, buflen-offset, &value->summary, &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_event_script_list_pull(buf+offset,
+                                         buflen-offset,
+                                         value,
+                                         &value->script_list,
+                                         &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       *out = value;
+       *npull = offset;
+
+       return 0;
+
+fail:
+       talloc_free(value);
+       return ret;
+}
+
+static size_t ctdb_event_header_len(struct ctdb_event_header *in)
+{
+       return ctdb_uint32_len(&in->length) +
+               ctdb_uint32_len(&in->version) +
+               ctdb_uint32_len(&in->reqid);
+}
+
+static void ctdb_event_header_push(struct ctdb_event_header *in,
+                                  uint8_t *buf,
+                                  size_t *npush)
+{
+       size_t offset = 0, np;
+
+       ctdb_uint32_push(&in->length, buf+offset, &np);
+       offset += np;
+
+       ctdb_uint32_push(&in->version, buf+offset, &np);
+       offset += np;
+
+       ctdb_uint32_push(&in->reqid, buf+offset, &np);
+       offset += np;
+
+       *npush = offset;
+}
+
+static int ctdb_event_header_pull(uint8_t *buf,
+                                 size_t buflen,
+                                 struct ctdb_event_header *value,
+                                 size_t *npull)
+{
+       size_t offset = 0, np;
+       int ret;
+
+       ret = ctdb_uint32_pull(buf+offset,
+                              buflen-offset,
+                              &value->length,
+                              &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       ret = ctdb_uint32_pull(buf+offset,
+                              buflen-offset,
+                              &value->version,
+                              &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       ret = ctdb_uint32_pull(buf+offset,
+                              buflen-offset,
+                              &value->reqid,
+                              &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       *npull = offset;
+
+       return 0;
+}
+
+int ctdb_event_header_extract(uint8_t *buf,
+                             size_t buflen,
+                             struct ctdb_event_header *value)
+{
+       size_t np;
+
+       return ctdb_event_header_pull(buf, buflen, value, &np);
+}
+
+static size_t ctdb_event_request_data_len(struct ctdb_event_request *in)
+{
+       size_t len;
+
+       len = ctdb_event_command_len(in->cmd);
+
+       switch (in->cmd) {
+       case CTDB_EVENT_CMD_RUN:
+               len += ctdb_event_request_run_len(in->data.run);
+               break;
+
+       case CTDB_EVENT_CMD_STATUS:
+               len += ctdb_event_request_status_len(in->data.status);
+               break;
+
+       case CTDB_EVENT_CMD_SCRIPT:
+               len += ctdb_event_request_script_len(in->data.script);
+               break;
+
+       default:
+               break;
+       }
+
+       return len;
+}
+
+static void ctdb_event_request_data_push(struct ctdb_event_request *in,
+                                        uint8_t *buf,
+                                        size_t *npush)
+{
+       size_t offset = 0, np;
+
+       ctdb_event_command_push(in->cmd, buf+offset, &np);
+       offset += np;
+
+       switch (in->cmd) {
+       case CTDB_EVENT_CMD_RUN:
+               ctdb_event_request_run_push(in->data.run, buf+offset, &np);
+               break;
+
+       case CTDB_EVENT_CMD_STATUS:
+               ctdb_event_request_status_push(in->data.status,
+                                              buf+offset,
+                                              &np);
+               break;
+
+       case CTDB_EVENT_CMD_SCRIPT:
+               ctdb_event_request_script_push(in->data.script,
+                                              buf+offset,
+                                              &np);
+               break;
+       default:
+               np = 0;
+               break;
+       }
+       offset += np;
+
+       *npush = offset;
+}
+
+static int ctdb_event_request_data_pull(uint8_t *buf,
+                                       size_t buflen,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct ctdb_event_request **out,
+                                       size_t *npull)
+{
+       struct ctdb_event_request *value;
+       size_t offset = 0, np;
+       int ret;
+
+       value = talloc(mem_ctx, struct ctdb_event_request);
+       if (value == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_event_command_pull(buf+offset,
+                                     buflen-offset,
+                                     &value->cmd,
+                                     &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       switch (value->cmd) {
+       case CTDB_EVENT_CMD_RUN:
+               ret = ctdb_event_request_run_pull(buf+offset,
+                                                 buflen-offset,
+                                                 value,
+                                                 &value->data.run,
+                                                 &np);
+               break;
+
+       case CTDB_EVENT_CMD_STATUS:
+               ret = ctdb_event_request_status_pull(buf+offset,
+                                                    buflen-offset,
+                                                    value,
+                                                    &value->data.status,
+                                                    &np);
+               break;
+
+       case CTDB_EVENT_CMD_SCRIPT:
+               ret = ctdb_event_request_script_pull(buf+offset,
+                                                    buflen-offset,
+                                                    value,
+                                                    &value->data.script,
+                                                    &np);
+               break;
+
+       default:
+               np = 0;
+               break;
+       }
+
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       *out = value;
+       *npull = offset;
+
+       return 0;
+
+fail:
+       talloc_free(value);
+       return ret;
+}
+
+static size_t ctdb_event_reply_data_len(struct ctdb_event_reply *in)
+{
+       size_t len;
+
+       len = ctdb_event_command_len(in->cmd) +
+               ctdb_int32_len(&in->result);
+
+       if (in->result != 0) {
+               goto done;
+       }
+
+       switch (in->cmd) {
+       case CTDB_EVENT_CMD_STATUS:
+               len += ctdb_event_reply_status_len(in->data.status);
+               break;
+
+       default:
+               break;
+       }
+
+done:
+       return len;
+}
+
+static void ctdb_event_reply_data_push(struct ctdb_event_reply *in,
+                                      uint8_t *buf,
+                                      size_t *npush)
+{
+       size_t offset = 0, np;
+
+       ctdb_event_command_push(in->cmd, buf+offset, &np);
+       offset += np;
+
+       ctdb_int32_push(&in->result, buf+offset, &np);
+       offset += np;
+
+       if (in->result != 0) {
+               goto done;
+       }
+
+       switch (in->cmd) {
+       case CTDB_EVENT_CMD_STATUS:
+               ctdb_event_reply_status_push(in->data.status, buf+offset, &np);
+               break;
+
+       default:
+               np = 0;
+               break;
+       }
+       offset += np;
+
+done:
+       *npush = offset;
+}
+
+static int ctdb_event_reply_data_pull(uint8_t *buf,
+                                     size_t buflen,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct ctdb_event_reply **out,
+                                     size_t *npull)
+{
+       struct ctdb_event_reply *value;
+       size_t offset = 0, np;
+       int ret;
+
+       value = talloc(mem_ctx, struct ctdb_event_reply);
+       if (value == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_event_command_pull(buf+offset,
+                                     buflen-offset,
+                                     &value->cmd,
+                                     &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       ret = ctdb_int32_pull(buf+offset, buflen-offset, &value->result, &np);
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+       if (value->result != 0) {
+               goto done;
+       }
+
+       switch (value->cmd) {
+       case CTDB_EVENT_CMD_STATUS:
+               ret = ctdb_event_reply_status_pull(buf+offset,
+                                                  buflen-offset,
+                                                  value,
+                                                  &value->data.status,
+                                                  &np);
+               break;
+
+       default:
+               np = 0;
+               break;
+       }
+
+       if (ret != 0) {
+               goto fail;
+       }
+       offset += np;
+
+done:
+       *out = value;
+       *npull = offset;
+
+       return 0;
+
+fail:
+       talloc_free(value);
+       return ret;
+}
+
+size_t ctdb_event_request_len(struct ctdb_event_header *h,
+                             struct ctdb_event_request *in)
+{
+       return ctdb_event_header_len(h) +
+               ctdb_event_request_data_len(in);
+}
+
+int ctdb_event_request_push(struct ctdb_event_header *h,
+                           struct ctdb_event_request *in,
+                           uint8_t *buf,
+                           size_t *buflen)
+{
+       size_t len, offset = 0, np;
+
+       len = ctdb_event_request_len(h, in);
+       if (*buflen < len) {
+               *buflen = len;
+               return EMSGSIZE;
+       }
+
+       h->length = *buflen;
+
+       ctdb_event_header_push(h, buf+offset, &np);
+       offset += np;
+
+       ctdb_event_request_data_push(in, buf+offset, &np);
+       offset += np;
+
+       if (offset > *buflen) {
+               return EMSGSIZE;
+       }
+
+       return 0;
+}
+
+int ctdb_event_request_pull(uint8_t *buf,
+                           size_t buflen,
+                           struct ctdb_event_header *h,
+                           TALLOC_CTX *mem_ctx,
+                           struct ctdb_event_request **out)
+{
+       size_t offset = 0, np;
+       int ret;
+
+       ret = ctdb_event_header_pull(buf+offset, buflen-offset, h, &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       ret = ctdb_event_request_data_pull(buf+offset,
+                                          buflen-offset,
+                                          mem_ctx,
+                                          out,
+                                          &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       if (offset > buflen) {
+               return EMSGSIZE;
+       }
+
+       return 0;
+}
+
+size_t ctdb_event_reply_len(struct ctdb_event_header *h,
+                           struct ctdb_event_reply *in)
+{
+       return ctdb_event_header_len(h) +
+               ctdb_event_reply_data_len(in);
+}
+
+int ctdb_event_reply_push(struct ctdb_event_header *h,
+                         struct ctdb_event_reply *in,
+                         uint8_t *buf,
+                         size_t *buflen)
+{
+       size_t len, offset = 0, np;
+
+       len = ctdb_event_reply_len(h, in);
+       if (*buflen < len) {
+               *buflen = len;
+               return EMSGSIZE;
+       }
+
+       h->length = *buflen;
+
+       ctdb_event_header_push(h, buf+offset, &np);
+       offset += np;
+
+       ctdb_event_reply_data_push(in, buf+offset, &np);
+       offset += np;
+
+       if (offset > *buflen) {
+               return EMSGSIZE;
+       }
+
+       return 0;
+}
+
+int ctdb_event_reply_pull(uint8_t *buf,
+                         size_t buflen,
+                         struct ctdb_event_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_event_reply **out)
+{
+       size_t offset = 0, np;
+       int ret;
+
+       ret = ctdb_event_header_pull(buf+offset, buflen-offset, h, &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       ret = ctdb_event_reply_data_pull(buf+offset,
+                                        buflen-offset,
+                                        mem_ctx,
+                                        out,
+                                        &np);
+       if (ret != 0) {
+               return ret;
+       }
+       offset += np;
+
+       if (offset > buflen) {
+               return EMSGSIZE;
+       }
+
+       return 0;
+}
diff --git a/ctdb/event/event_protocol.h b/ctdb/event/event_protocol.h
new file mode 100644 (file)
index 0000000..e7680fc
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+   CTDB event daemon protocol
+   Based on eventd code
+
+   Copyright (C) Amitay Isaacs  2018
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_EVENT_PROTOCOL_H__
+#define __CTDB_EVENT_PROTOCOL_H__
+
+#define CTDB_EVENT_PROTOCOL_VERSION    1
+
+enum ctdb_event_script_action {
+       CTDB_EVENT_SCRIPT_DISABLE = 0,
+       CTDB_EVENT_SCRIPT_ENABLE  = 1,
+};
+
+enum ctdb_event_command {
+       CTDB_EVENT_CMD_RUN     = 1,
+       CTDB_EVENT_CMD_STATUS  = 2,
+       CTDB_EVENT_CMD_SCRIPT  = 3,
+       CTDB_EVENT_CMD_MAX     = 4,
+};
+
+struct ctdb_event_script {
+       const char *name;
+       struct timeval begin;
+       struct timeval end;
+       int result;
+       const char *output;
+};
+
+struct ctdb_event_script_list {
+       int num_scripts;
+       struct ctdb_event_script *script;
+};
+
+#define CTDB_EVENT_RUN_ALL     1
+
+struct ctdb_event_request_run {
+       const char *component;
+       const char *event;
+       const char *args;
+       uint32_t timeout;
+       uint32_t flags;
+};
+
+struct ctdb_event_request_status {
+       const char *component;
+       const char *event;
+};
+
+struct ctdb_event_request_script {
+       const char *component;
+       const char *script;
+       enum ctdb_event_script_action action;
+};
+
+struct ctdb_event_reply_status {
+       int32_t summary;
+       struct ctdb_event_script_list *script_list;
+};
+
+struct ctdb_event_header {
+       uint32_t length;
+       uint32_t version;
+       uint32_t reqid;
+};
+
+struct ctdb_event_request {
+       enum ctdb_event_command cmd;
+       union {
+               struct ctdb_event_request_run *run;
+               struct ctdb_event_request_status *status;
+               struct ctdb_event_request_script *script;
+       } data;
+};
+
+struct ctdb_event_reply {
+       enum ctdb_event_command cmd;
+       int32_t result;
+       union {
+               struct ctdb_event_reply_status *status;
+       } data;
+};
+
+#endif /* __CTDB_EVENT_PROTOCOL_H__ */
diff --git a/ctdb/event/event_protocol_api.h b/ctdb/event/event_protocol_api.h
new file mode 100644 (file)
index 0000000..e2ab439
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+   CTDB event daemon protocol
+
+   Copyright (C) Amitay Isaacs  2018
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_EVENT_PROTOCOL_API_H__
+#define __CTDB_EVENT_PROTOCOL_API_H__
+
+#include <talloc.h>
+
+#include "event/event_protocol.h"
+
+/* From event/event_protocol.c */
+
+int ctdb_event_header_extract(uint8_t *buf,
+                             size_t buflen,
+                             struct ctdb_event_header *h);
+
+size_t ctdb_event_request_len(struct ctdb_event_header *h,
+                             struct ctdb_event_request *in);
+int ctdb_event_request_push(struct ctdb_event_header *h,
+                           struct ctdb_event_request *in,
+                           uint8_t *buf,
+                           size_t *buflen);
+int ctdb_event_request_pull(uint8_t *buf,
+                           size_t buflen,
+                           struct ctdb_event_header *h,
+                           TALLOC_CTX *mem_ctx,
+                           struct ctdb_event_request **out);
+
+size_t ctdb_event_reply_len(struct ctdb_event_header *h,
+                           struct ctdb_event_reply *in);
+int ctdb_event_reply_push(struct ctdb_event_header *h,
+                         struct ctdb_event_reply *in,
+                         uint8_t *buf,
+                         size_t *buflen);
+int ctdb_event_reply_pull(uint8_t *buf,
+                         size_t buflen,
+                         struct ctdb_event_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_event_reply **out);
+
+/* From event/event_protocol_util.c */
+
+const char *ctdb_event_command_to_string(enum ctdb_event_command cmd);
+
+#endif /* __CTDB_EVENT_PROTOCOL_API_H__ */
diff --git a/ctdb/event/event_protocol_test.c b/ctdb/event/event_protocol_test.c
new file mode 100644 (file)
index 0000000..7f939f8
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+   CTDB event daemon - protocol test
+
+   Copyright (C) Amitay Isaacs  2018
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include <talloc.h>
+#include <assert.h>
+
+#define EVENT_PROTOCOL_TEST
+#include "event/event_protocol.c"
+
+#include "tests/src/protocol_common_basic.h"
+
+/*
+ * Functions to fill and verify event protocol structures
+ */
+
+static void fill_ctdb_event_script(TALLOC_CTX *mem_ctx,
+                                  struct ctdb_event_script *p)
+{
+       fill_ctdb_stringn(mem_ctx, &p->name);
+       fill_ctdb_timeval(&p->begin);
+       fill_ctdb_timeval(&p->end);
+       p->result = rand32i();
+       fill_ctdb_stringn(mem_ctx, &p->output);
+}
+
+static void verify_ctdb_event_script(struct ctdb_event_script *p1,
+                                    struct ctdb_event_script *p2)
+{
+       verify_ctdb_stringn(&p1->name, &p2->name);
+       verify_ctdb_timeval(&p1->begin, &p2->begin);
+       verify_ctdb_timeval(&p1->end, &p2->end);
+       assert(p1->result == p2->result);
+       verify_ctdb_stringn(&p1->output, &p2->output);
+}
+
+static void fill_ctdb_event_script_list(TALLOC_CTX *mem_ctx,
+                                       struct ctdb_event_script_list *p)
+{
+       int i;
+
+       p->num_scripts = rand_int(32);
+       if (p->num_scripts > 0) {
+               p->script = talloc_array(mem_ctx,
+                                        struct ctdb_event_script,
+                                        p->num_scripts);
+               assert(p->script != NULL);
+
+               for (i=0; i<p->num_scripts; i++) {
+                       fill_ctdb_event_script(mem_ctx, &p->script[i]);
+               }
+       } else {
+               p->script = NULL;
+       }
+}
+
+static void verify_ctdb_event_script_list(struct ctdb_event_script_list *p1,
+                                         struct ctdb_event_script_list *p2)
+{
+       int i;
+
+       assert(p1->num_scripts == p2->num_scripts);
+       for (i=0; i<p1->num_scripts; i++) {
+               verify_ctdb_event_script(&p1->script[i], &p2->script[i]);
+       }
+}
+
+static void fill_ctdb_event_request_run(TALLOC_CTX *mem_ctx,
+                                       struct ctdb_event_request_run *p)
+{
+       fill_ctdb_stringn(mem_ctx, &p->component);
+       fill_ctdb_stringn(mem_ctx, &p->event);
+       fill_ctdb_stringn(mem_ctx, &p->args);
+       p->timeout = rand32();
+       p->flags = rand32();
+}
+
+static void verify_ctdb_event_request_run(struct ctdb_event_request_run *p1,
+                                         struct ctdb_event_request_run *p2)
+{
+       verify_ctdb_stringn(&p1->component, &p2->component);
+       verify_ctdb_stringn(&p1->event, &p2->event);
+       verify_ctdb_stringn(&p1->args, &p2->args);
+       assert(p1->timeout == p2->timeout);
+       assert(p1->flags == p2->flags);
+}
+
+static void fill_ctdb_event_request_status(TALLOC_CTX *mem_ctx,
+                                          struct ctdb_event_request_status *p)
+{
+       fill_ctdb_stringn(mem_ctx, &p->component);
+       fill_ctdb_stringn(mem_ctx, &p->event);
+}
+
+static void verify_ctdb_event_request_status(
+                                       struct ctdb_event_request_status *p1,
+                                       struct ctdb_event_request_status *p2)
+{
+       verify_ctdb_stringn(&p1->component, &p2->component);
+       verify_ctdb_stringn(&p1->event, &p2->event);
+}
+
+static void fill_ctdb_event_request_script(TALLOC_CTX *mem_ctx,
+                                          struct ctdb_event_request_script *p)
+{
+       fill_ctdb_stringn(mem_ctx, &p->component);
+       fill_ctdb_stringn(mem_ctx, &p->script);
+       if (rand_int(1) == 0) {
+               p->action = CTDB_EVENT_SCRIPT_DISABLE;
+       } else {
+               p->action = CTDB_EVENT_SCRIPT_ENABLE;
+       }
+}
+
+static void fill_ctdb_event_reply_status(TALLOC_CTX *mem_ctx,
+                                        struct ctdb_event_reply_status *p)
+{
+       p->summary = rand32i();
+       p->script_list = talloc(mem_ctx, struct ctdb_event_script_list);
+       assert(p->script_list != NULL);
+
+       fill_ctdb_event_script_list(mem_ctx, p->script_list);
+}
+
+static void verify_ctdb_event_reply_status(struct ctdb_event_reply_status *p1,
+                                          struct ctdb_event_reply_status *p2)
+{
+       assert(p1->summary == p2->summary);
+       verify_ctdb_event_script_list(p1->script_list, p2->script_list);
+}
+
+static void verify_ctdb_event_request_script(
+                                       struct ctdb_event_request_script *p1,
+                                       struct ctdb_event_request_script *p2)
+{
+       verify_ctdb_stringn(&p1->component, &p2->component);
+       verify_ctdb_stringn(&p1->script, &p2->script);
+       assert(p1->action == p2->action);
+}
+
+static void fill_ctdb_event_request_data(TALLOC_CTX *mem_ctx,
+                                        struct ctdb_event_request *p,
+                                        uint32_t cmd)
+{
+       p->cmd = cmd;
+
+       switch (cmd) {
+       case CTDB_EVENT_CMD_RUN:
+               p->data.run = talloc(mem_ctx, struct ctdb_event_request_run);
+               assert(p->data.run != NULL);
+
+               fill_ctdb_event_request_run(mem_ctx, p->data.run);
+               break;
+
+       case CTDB_EVENT_CMD_STATUS:
+               p->data.status = talloc(mem_ctx,
+                                       struct ctdb_event_request_status);
+               assert(p->data.status != NULL);
+
+               fill_ctdb_event_request_status(mem_ctx, p->data.status);
+               break;
+
+       case CTDB_EVENT_CMD_SCRIPT:
+               p->data.script = talloc(mem_ctx,
+                                       struct ctdb_event_request_script);
+               assert(p->data.script != NULL);
+
+               fill_ctdb_event_request_script(mem_ctx, p->data.script);
+               break;
+
+       default:
+               assert(cmd > 0 && cmd < CTDB_EVENT_CMD_MAX);
+       }
+}
+
+static void verify_ctdb_event_request_data(struct ctdb_event_request *p1,
+                                          struct ctdb_event_request *p2)
+{
+       assert(p1->cmd == p2->cmd);
+
+       switch (p1->cmd) {
+       case CTDB_EVENT_CMD_RUN:
+               verify_ctdb_event_request_run(p1->data.run, p2->data.run);
+               break;
+
+       case CTDB_EVENT_CMD_STATUS:
+               verify_ctdb_event_request_status(p1->data.status,
+                                                p2->data.status);
+               break;
+
+       case CTDB_EVENT_CMD_SCRIPT:
+               verify_ctdb_event_request_script(p1->data.script,
+                                                p2->data.script);
+               break;
+
+       default:
+               assert(p1->cmd > 0 && p1->cmd < CTDB_EVENT_CMD_MAX);
+       }
+}
+
+static void fill_ctdb_event_reply_data(TALLOC_CTX *mem_ctx,
+                                      struct ctdb_event_reply *p,
+                                      uint32_t cmd)
+{
+       p->cmd = cmd;
+       p->result = rand32i();
+
+       if (p->result != 0) {
+               return;
+       }
+
+       switch (cmd) {
+       case CTDB_EVENT_CMD_STATUS:
+               p->data.status = talloc(mem_ctx,
+                                       struct ctdb_event_reply_status);
+               assert(p->data.status != NULL);
+
+               fill_ctdb_event_reply_status(mem_ctx, p->data.status);
+               break;
+
+       default:
+               assert(cmd > 0 && cmd < CTDB_EVENT_CMD_MAX);
+       }
+}
+
+static void verify_ctdb_event_reply_data(struct ctdb_event_reply *p1,
+                                        struct ctdb_event_reply *p2)
+{
+       assert(p1->cmd == p2->cmd);
+       assert(p1->result == p2->result);
+
+       if (p1->result != 0) {
+               return;
+       }
+
+       switch (p1->cmd) {
+       case CTDB_EVENT_CMD_STATUS:
+               verify_ctdb_event_reply_status(p1->data.status,
+                                              p2->data.status);
+               break;
+
+       default:
+               assert(p1->cmd > 0 && p1->cmd < CTDB_EVENT_CMD_MAX);
+       }
+}
+
+static void fill_ctdb_event_header(struct ctdb_event_header *p)
+{
+       p->length = 0; /* updated by push functions */
+       p->version = 0; /* updated by push functions */
+       p->reqid = rand32();
+}
+
+static void verify_ctdb_event_header(struct ctdb_event_header *p1,
+                                    struct ctdb_event_header *p2)
+{
+       assert(p1->length == p2->length);
+       assert(p1->version == p2->version);
+       assert(p1->reqid == p2->reqid);
+}
+
+static void fill_ctdb_event_request(TALLOC_CTX *mem_ctx,
+                                   struct ctdb_event_request *p,
+                                   uint32_t cmd)
+{
+       fill_ctdb_event_request_data(mem_ctx, p, cmd);
+}
+
+static void verify_ctdb_event_request(struct ctdb_event_request *p1,
+                                     struct ctdb_event_request *p2)
+{
+       verify_ctdb_event_request_data(p1, p2);
+}
+
+static void fill_ctdb_event_reply(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_event_reply *p,
+                                 uint32_t cmd)
+{
+       fill_ctdb_event_reply_data(mem_ctx, p, cmd);
+}
+
+static void verify_ctdb_event_reply(struct ctdb_event_reply *p1,
+                                   struct ctdb_event_reply *p2)
+{
+       verify_ctdb_event_reply_data(p1, p2);
+}
+
+#define EVENT_PROTOCOL1_TEST(TYPE, NAME) \
+static void TEST_FUNC(NAME)(uint32_t cmd) \
+{ \
+       TALLOC_CTX *mem_ctx; \
+       TYPE c1, *c2; \
+       uint8_t *buf; \
+       size_t buflen, np; \
+       int ret; \
+\
+       printf("%s %u\n", #NAME, cmd); \
+       fflush(stdout); \
+       mem_ctx = talloc_new(NULL); \
+       assert(mem_ctx != NULL); \
+       FILL_FUNC(NAME)(mem_ctx, &c1, cmd); \
+       buflen = LEN_FUNC(NAME)(&c1); \
+       buf = talloc_size(mem_ctx, buflen); \
+       assert(buf != NULL); \
+       np = 0; \
+       PUSH_FUNC(NAME)(&c1, buf, &np); \
+       assert(np == buflen); \
+       np = 0; \
+       ret = PULL_FUNC(NAME)(buf, buflen, mem_ctx, &c2, &np); \
+       assert(ret == 0); \
+       assert(np == buflen); \
+       VERIFY_FUNC(NAME)(&c1, c2); \
+       talloc_free(mem_ctx); \
+}
+
+#define EVENT_PROTOCOL2_TEST(TYPE, NAME) \
+static void TEST_FUNC(NAME)(uint32_t cmd) \
+{ \
+       TALLOC_CTX *mem_ctx; \
+       struct ctdb_event_header h1, h2; \
+       TYPE c1, *c2; \
+       uint8_t *buf; \
+       size_t buflen, len; \
+       int ret; \
+\
+       printf("%s %u\n", #NAME, cmd); \
+       fflush(stdout); \
+       mem_ctx = talloc_new(NULL); \
+       assert(mem_ctx != NULL); \
+       fill_ctdb_event_header(&h1); \
+       FILL_FUNC(NAME)(mem_ctx, &c1, cmd); \
+       buflen = LEN_FUNC(NAME)(&h1, &c1); \
+       buf = talloc_size(mem_ctx, buflen); \
+       assert(buf != NULL); \
+       len = 0; \
+       ret = PUSH_FUNC(NAME)(&h1, &c1, buf, &len); \
+       assert(ret == EMSGSIZE); \
+       assert(len == buflen); \
+       ret = PUSH_FUNC(NAME)(&h1, &c1, buf, &buflen); \
+       assert(ret == 0); \
+       ret = PULL_FUNC(NAME)(buf, buflen, &h2, mem_ctx, &c2); \
+       assert(ret == 0); \
+       verify_ctdb_event_header(&h1, &h2); \
+       VERIFY_FUNC(NAME)(&c1, c2); \
+       talloc_free(mem_ctx); \
+}
+
+PROTOCOL_TYPE3_TEST(struct ctdb_event_script, ctdb_event_script);
+PROTOCOL_TYPE3_TEST(struct ctdb_event_script_list, ctdb_event_script_list);
+
+PROTOCOL_TYPE3_TEST(struct ctdb_event_request_run, ctdb_event_request_run);
+PROTOCOL_TYPE3_TEST(struct ctdb_event_request_status,
+                   ctdb_event_request_status);
+PROTOCOL_TYPE3_TEST(struct ctdb_event_request_script,
+                   ctdb_event_request_script);
+
+PROTOCOL_TYPE3_TEST(struct ctdb_event_reply_status, ctdb_event_reply_status);
+
+EVENT_PROTOCOL1_TEST(struct ctdb_event_request, ctdb_event_request_data);
+EVENT_PROTOCOL1_TEST(struct ctdb_event_reply, ctdb_event_reply_data);
+
+EVENT_PROTOCOL2_TEST(struct ctdb_event_request, ctdb_event_request);
+EVENT_PROTOCOL2_TEST(struct ctdb_event_reply, ctdb_event_reply);
+
+int main(int argc, const char **argv)
+{
+       uint32_t cmd;
+
+       if (argc == 2) {
+               int seed = atoi(argv[1]);
+               srandom(seed);
+       }
+
+       TEST_FUNC(ctdb_event_script)();
+       TEST_FUNC(ctdb_event_script_list)();
+
+       TEST_FUNC(ctdb_event_request_run)();
+       TEST_FUNC(ctdb_event_request_status)();
+       TEST_FUNC(ctdb_event_request_script)();
+
+       TEST_FUNC(ctdb_event_reply_status)();
+
+       for (cmd=1; cmd<CTDB_EVENT_CMD_MAX; cmd++) {
+               TEST_FUNC(ctdb_event_request_data)(cmd);
+       }
+       for (cmd=1; cmd<CTDB_EVENT_CMD_MAX; cmd++) {
+               TEST_FUNC(ctdb_event_reply_data)(cmd);
+       }
+
+       for (cmd=1; cmd<CTDB_EVENT_CMD_MAX; cmd++) {
+               TEST_FUNC(ctdb_event_request)(cmd);
+       }
+       for (cmd=1; cmd<CTDB_EVENT_CMD_MAX; cmd++) {
+               TEST_FUNC(ctdb_event_reply)(cmd);
+       }
+
+       return 0;
+}
diff --git a/ctdb/event/event_protocol_util.c b/ctdb/event/event_protocol_util.c
new file mode 100644 (file)
index 0000000..cc59615
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+   CTDB event daemon - protocol utilities
+
+   Copyright (C) Amitay Isaacs  2018
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include "event/event_protocol.h"
+#include "event/event_protocol_api.h"
+
+static struct {
+       enum ctdb_event_command command;
+       const char *label;
+} event_command_map[] = {
+       { CTDB_EVENT_CMD_RUN, "RUN" },
+       { CTDB_EVENT_CMD_STATUS, "STATUS" },
+       { CTDB_EVENT_CMD_SCRIPT, "SCRIPT" },
+       { CTDB_EVENT_CMD_MAX, NULL },
+};
+
+const char *ctdb_event_command_to_string(enum ctdb_event_command command)
+{
+       int i;
+
+       for (i=0; event_command_map[i].label != NULL; i++) {
+               if (event_command_map[i].command == command) {
+                       return event_command_map[i].label;
+               }
+       }
+
+       return "UNKNOWN";
+}
diff --git a/ctdb/tests/cunit/event_protocol_test_001.sh b/ctdb/tests/cunit/event_protocol_test_001.sh
new file mode 100755 (executable)
index 0000000..d1a7778
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+last_command=3
+
+generate_output ()
+{
+    for i in $(seq 1 $last_command) ; do
+       echo "$1 $i"
+    done
+}
+
+output=$(
+    generate_output "ctdb_event_request_data"
+    generate_output "ctdb_event_reply_data"
+    generate_output "ctdb_event_request"
+    generate_output "ctdb_event_reply"
+)
+
+ok "$output"
+
+for i in $(seq 1 100) ; do
+    unit_test event_protocol_test $i
+done
index c762106ccc055a0f3aa94b28dd0f74b84680af02..90cb0a6b2b31e8d5d31c04adc1046951da2c8c4e 100644 (file)
@@ -497,6 +497,13 @@ def build(bld):
                              ctdb-util samba-util talloc replace popt''',
                      install_path='${CTDB_HELPER_BINDIR}')
 
+    bld.SAMBA_SUBSYSTEM('ctdb-event-protocol',
+                        source=bld.SUBDIR('event',
+                                          '''event_protocol.c
+                                             event_protocol_util.c
+                                          '''),
+                        deps='ctdb-protocol-basic')
+
     bld.SAMBA_BINARY('ctdbd',
                      source='server/ctdbd.c ' +
                                bld.SUBDIR('server',
@@ -879,6 +886,12 @@ def build(bld):
                                  samba-util talloc tdb''',
                          install_path='${CTDB_TEST_LIBEXECDIR}')
 
+    bld.SAMBA_BINARY('event_protocol_test',
+                     source='event/event_protocol_test.c',
+                     deps='''ctdb-protocol-tests-basic
+                             ctdb-protocol-basic talloc''',
+                     install_path='${CTDB_TEST_LIBEXECDIR}')
+
     bld.SAMBA_SUBSYSTEM('ctdb-tests-common',
                         source=bld.SUBDIR('tests/src',
                                           'cluster_wait.c test_options.c'),