/*
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 .
*/
#include "replace.h"
#include
#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; inum_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; inum_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; iscript[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;
}