ctdb-protocol: Add ctdb protocol serialization routines
authorAmitay Isaacs <amitay@gmail.com>
Tue, 14 Apr 2015 07:20:05 +0000 (17:20 +1000)
committerAmitay Isaacs <amitay@samba.org>
Wed, 7 Oct 2015 12:53:29 +0000 (14:53 +0200)
Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
16 files changed:
ctdb/protocol/protocol.h [new file with mode: 0644]
ctdb/protocol/protocol_api.h [new file with mode: 0644]
ctdb/protocol/protocol_call.c [new file with mode: 0644]
ctdb/protocol/protocol_client.c [new file with mode: 0644]
ctdb/protocol/protocol_control.c [new file with mode: 0644]
ctdb/protocol/protocol_header.c [new file with mode: 0644]
ctdb/protocol/protocol_message.c [new file with mode: 0644]
ctdb/protocol/protocol_packet.c [new file with mode: 0644]
ctdb/protocol/protocol_private.h [new file with mode: 0644]
ctdb/protocol/protocol_types.c [new file with mode: 0644]
ctdb/protocol/protocol_util.c [new file with mode: 0644]
ctdb/tests/cunit/protocol_test_001.sh [new file with mode: 0755]
ctdb/tests/cunit/protocol_test_002.sh [new file with mode: 0755]
ctdb/tests/src/protocol_client_test.c [new file with mode: 0644]
ctdb/tests/src/protocol_types_test.c [new file with mode: 0644]
ctdb/wscript

diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h
new file mode 100644 (file)
index 0000000..805fdd1
--- /dev/null
@@ -0,0 +1,1002 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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_PROTOCOL_H__
+#define __CTDB_PROTOCOL_H__
+
+#define CTDB_MAGIC     0x43544442 /* CTDB */
+#define CTDB_PROTOCOL  1
+
+enum ctdb_operation {
+       CTDB_REQ_CALL           = 0,
+       CTDB_REPLY_CALL         = 1,
+       CTDB_REQ_DMASTER        = 2,
+       CTDB_REPLY_DMASTER      = 3,
+       CTDB_REPLY_ERROR        = 4,
+       CTDB_REQ_MESSAGE        = 5,
+       /* #6 removed */
+       CTDB_REQ_CONTROL        = 7,
+       CTDB_REPLY_CONTROL      = 8,
+       CTDB_REQ_KEEPALIVE      = 9,
+};
+
+/* used on the domain socket, send a pdu to the local daemon */
+#define CTDB_CURRENT_NODE     0xF0000001
+/* send a broadcast to all nodes in the cluster, active or not */
+#define CTDB_BROADCAST_ALL    0xF0000002
+/* send a broadcast to all nodes in the current vnn map */
+#define CTDB_BROADCAST_VNNMAP 0xF0000003
+/* send a broadcast to all connected nodes */
+#define CTDB_BROADCAST_CONNECTED 0xF0000004
+/* send a broadcast to selected connected nodes */
+#define CTDB_MULTICAST 0xF0000005
+
+#define CTDB_UNKNOWN_PNN       0xFFFFFFFF
+
+/* the key used to store persistent db sequence number */
+#define CTDB_DB_SEQNUM_KEY "__db_sequence_number__"
+
+struct ctdb_req_header {
+       uint32_t length;
+       uint32_t ctdb_magic;
+       uint32_t ctdb_version;
+       uint32_t generation;
+       uint32_t operation;
+       uint32_t destnode;
+       uint32_t srcnode;
+       uint32_t reqid;
+};
+
+struct ctdb_req_call {
+       uint32_t flags;
+       uint32_t db_id;
+       uint32_t callid;
+       uint32_t hopcount;
+       TDB_DATA key;
+       TDB_DATA calldata;
+};
+
+struct ctdb_reply_call {
+       int32_t status;
+       TDB_DATA data;
+};
+
+struct ctdb_reply_error {
+       int32_t status;
+       TDB_DATA msg;
+};
+
+struct ctdb_req_dmaster {
+       uint32_t db_id;
+       uint64_t rsn;
+       uint32_t dmaster;
+       TDB_DATA key;
+       TDB_DATA data;
+};
+
+struct ctdb_reply_dmaster {
+       uint32_t db_id;
+       uint64_t rsn;
+       TDB_DATA key;
+       TDB_DATA data;
+};
+
+#define CTDB_NULL_FUNC                  0xFF000001
+#define CTDB_FETCH_FUNC                 0xFF000002
+#define CTDB_FETCH_WITH_HEADER_FUNC     0xFF000003
+
+struct ctdb_call {
+       int call_id;
+       TDB_DATA key;
+       TDB_DATA call_data;
+       TDB_DATA reply_data;
+       uint32_t status;
+#define CTDB_IMMEDIATE_MIGRATION               0x00000001
+#define CTDB_CALL_FLAG_VACUUM_MIGRATION                0x00000002
+#define CTDB_WANT_READONLY                     0x00000004
+       uint32_t flags;
+};
+
+/* SRVID to catch all messages */
+#define CTDB_SRVID_ALL (~(uint64_t)0)
+
+/* SRVID prefix used by CTDB */
+#define CTDB_SRVID_PREFIX      0xF000000000000000LL
+
+/* SRVID to inform of election data */
+#define CTDB_SRVID_ELECTION    0xF100000000000000LL
+
+/* SRVID to inform clients that the cluster has been reconfigured */
+#define CTDB_SRVID_RECONFIGURE 0xF200000000000000LL
+
+/* SRVID to inform clients an IP address has been released */
+#define CTDB_SRVID_RELEASE_IP 0xF300000000000000LL
+
+/* SRVID to inform clients that an IP address has been taken over */
+#define CTDB_SRVID_TAKE_IP 0xF301000000000000LL
+
+/* SRVID to inform recovery daemon of the node flags */
+#define CTDB_SRVID_SET_NODE_FLAGS 0xF400000000000000LL
+
+/* SRVID to inform recovery daemon to update public ip assignment */
+#define CTDB_SRVID_RECD_UPDATE_IP 0xF500000000000000LL
+
+/* SRVID to inform recovery daemon to migrate a set of records */
+#define CTDB_SRVID_VACUUM_FETCH 0xF700000000000000LL
+
+/* SRVID to inform recovery daemon to detach a database */
+#define CTDB_SRVID_DETACH_DATABASE 0xF701000000000000LL
+
+/* SRVID to inform recovery daemon to dump talloc memdump to the log */
+#define CTDB_SRVID_MEM_DUMP 0xF800000000000000LL
+
+/* SRVID to inform recovery daemon to send logs */
+#define CTDB_SRVID_GETLOG  0xF801000000000000LL
+
+/* SRVID to inform recovery daemon to clear logs */
+#define CTDB_SRVID_CLEARLOG  0xF802000000000000LL
+
+/* SRVID to inform recovery daemon to push the node flags to other nodes */
+#define CTDB_SRVID_PUSH_NODE_FLAGS 0xF900000000000000LL
+
+/* SRVID to inform recovery daemon to reload the nodes file */
+#define CTDB_SRVID_RELOAD_NODES 0xFA00000000000000LL
+
+/* SRVID to inform recovery daemon to perform a takeover run */
+#define CTDB_SRVID_TAKEOVER_RUN 0xFB00000000000000LL
+
+/* SRVID to inform recovery daemon to rebalance ips for a node.  */
+#define CTDB_SRVID_REBALANCE_NODE 0xFB01000000000000LL
+
+/* SRVID to inform recovery daemon to stop takeover runs from occurring */
+#define CTDB_SRVID_DISABLE_TAKEOVER_RUNS 0xFB03000000000000LL
+
+/* SRVID to inform recovery daemon to stop recoveries from occurring */
+#define CTDB_SRVID_DISABLE_RECOVERIES 0xFB04000000000000LL
+
+/* SRVID to inform recovery daemon to disable the public ip checks */
+#define CTDB_SRVID_DISABLE_IP_CHECK  0xFC00000000000000LL
+
+/* SRVID to inform recovery daemon of ipreallocate resposnes from ctdbd */
+#define CTDB_SRVID_TAKEOVER_RUN_RESPONSE  0xFD00000000000000LL
+
+/* A range of ports reserved for registering a PID (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * registering a SRVID that matches the process-id of the requesting process
+ */
+#define CTDB_SRVID_PID_RANGE   0x0000000000000000LL
+
+/* A range of ports reserved for samba (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * CIFS server
+ */
+#define CTDB_SRVID_SAMBA_NOTIFY  0xFE00000000000000LL
+#define CTDB_SRVID_SAMBA_RANGE   0xFE00000000000000LL
+
+/* A range of ports reserved for a CTDB NFS server (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * NFS server
+ */
+#define CTDB_SRVID_NFSD_RANGE  0xEE00000000000000LL
+
+/* A range of ports reserved for a CTDB ISCSI server (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * ISCSI server
+ */
+#define CTDB_SRVID_ISCSID_RANGE  0xDE00000000000000LL
+
+/* A range of ports reserved for testing (top 8 bits)
+ * All ports matching the 8 top bits are reserved for exclusive use by
+ * test applications
+ */
+#define CTDB_SRVID_TEST_RANGE  0xCE00000000000000LL
+
+/* Range of ports reserved for traversals */
+#define CTDB_SRVID_TRAVERSE_RANGE  0xBE00000000000000LL
+
+
+enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS          = 0,
+                   CTDB_CONTROL_STATISTICS              = 1,
+                   /* #2 removed */
+                   CTDB_CONTROL_PING                    = 3,
+                   CTDB_CONTROL_GETDBPATH               = 4,
+                   CTDB_CONTROL_GETVNNMAP               = 5,
+                   CTDB_CONTROL_SETVNNMAP               = 6,
+                   CTDB_CONTROL_GET_DEBUG               = 7,
+                   CTDB_CONTROL_SET_DEBUG               = 8,
+                   CTDB_CONTROL_GET_DBMAP               = 9,
+                   CTDB_CONTROL_GET_NODEMAPv4           = 10, /* obsolete */
+                   CTDB_CONTROL_SET_DMASTER             = 11, /* obsolete */
+                   /* #12 removed */
+                   CTDB_CONTROL_PULL_DB                 = 13,
+                   CTDB_CONTROL_PUSH_DB                 = 14,
+                   CTDB_CONTROL_GET_RECMODE             = 15,
+                   CTDB_CONTROL_SET_RECMODE             = 16,
+                   CTDB_CONTROL_STATISTICS_RESET        = 17,
+                   CTDB_CONTROL_DB_ATTACH               = 18,
+                   CTDB_CONTROL_SET_CALL                = 19, /* obsolete */
+                   CTDB_CONTROL_TRAVERSE_START          = 20,
+                   CTDB_CONTROL_TRAVERSE_ALL            = 21,
+                   CTDB_CONTROL_TRAVERSE_DATA           = 22,
+                   CTDB_CONTROL_REGISTER_SRVID          = 23,
+                   CTDB_CONTROL_DEREGISTER_SRVID        = 24,
+                   CTDB_CONTROL_GET_DBNAME              = 25,
+                   CTDB_CONTROL_ENABLE_SEQNUM           = 26,
+                   CTDB_CONTROL_UPDATE_SEQNUM           = 27,
+                   /* #28 removed */
+                   CTDB_CONTROL_DUMP_MEMORY             = 29,
+                   CTDB_CONTROL_GET_PID                 = 30,
+                   CTDB_CONTROL_GET_RECMASTER           = 31,
+                   CTDB_CONTROL_SET_RECMASTER           = 32,
+                   CTDB_CONTROL_FREEZE                  = 33,
+                   CTDB_CONTROL_THAW                    = 34,
+                   CTDB_CONTROL_GET_PNN                 = 35,
+                   CTDB_CONTROL_SHUTDOWN                = 36,
+                   CTDB_CONTROL_GET_MONMODE             = 37,
+                   /* #38 removed */
+                   /* #39 removed */
+                   /* #40 removed */
+                   /* #41 removed */
+                   CTDB_CONTROL_TAKEOVER_IPv4           = 42, /* obsolete */
+                   CTDB_CONTROL_RELEASE_IPv4            = 43, /* obsolete */
+                   CTDB_CONTROL_TCP_CLIENT              = 44,
+                   CTDB_CONTROL_TCP_ADD                 = 45,
+                   CTDB_CONTROL_TCP_REMOVE              = 46,
+                   CTDB_CONTROL_STARTUP                 = 47,
+                   CTDB_CONTROL_SET_TUNABLE             = 48,
+                   CTDB_CONTROL_GET_TUNABLE             = 49,
+                   CTDB_CONTROL_LIST_TUNABLES           = 50,
+                   CTDB_CONTROL_GET_PUBLIC_IPSv4        = 51, /* obsolete */
+                   CTDB_CONTROL_MODIFY_FLAGS            = 52,
+                   CTDB_CONTROL_GET_ALL_TUNABLES        = 53,
+                   CTDB_CONTROL_KILL_TCP                = 54,
+                   CTDB_CONTROL_GET_TCP_TICKLE_LIST     = 55,
+                   CTDB_CONTROL_SET_TCP_TICKLE_LIST     = 56,
+                   CTDB_CONTROL_REGISTER_SERVER_ID      = 57,
+                   CTDB_CONTROL_UNREGISTER_SERVER_ID    = 58,
+                   CTDB_CONTROL_CHECK_SERVER_ID         = 59,
+                   CTDB_CONTROL_GET_SERVER_ID_LIST      = 60,
+                   CTDB_CONTROL_DB_ATTACH_PERSISTENT    = 61,
+                   CTDB_CONTROL_PERSISTENT_STORE        = 62, /* obsolete */
+                   CTDB_CONTROL_UPDATE_RECORD           = 63,
+                   CTDB_CONTROL_SEND_GRATUITOUS_ARP     = 64,
+                   CTDB_CONTROL_TRANSACTION_START       = 65,
+                   CTDB_CONTROL_TRANSACTION_COMMIT      = 66,
+                   CTDB_CONTROL_WIPE_DATABASE           = 67,
+                   /* #68 removed */
+                   CTDB_CONTROL_UPTIME                  = 69,
+                   CTDB_CONTROL_START_RECOVERY          = 70,
+                   CTDB_CONTROL_END_RECOVERY            = 71,
+                   CTDB_CONTROL_RELOAD_NODES_FILE       = 72,
+                   /* #73 removed */
+                   CTDB_CONTROL_TRY_DELETE_RECORDS      = 74,
+                   CTDB_CONTROL_ENABLE_MONITOR          = 75,
+                   CTDB_CONTROL_DISABLE_MONITOR         = 76,
+                   CTDB_CONTROL_ADD_PUBLIC_IP           = 77,
+                   CTDB_CONTROL_DEL_PUBLIC_IP           = 78,
+                   CTDB_CONTROL_RUN_EVENTSCRIPTS        = 79,
+                   CTDB_CONTROL_GET_CAPABILITIES        = 80,
+                   CTDB_CONTROL_START_PERSISTENT_UPDATE = 81, /* obsolete */
+                   CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE= 82, /* obsolete */
+                   CTDB_CONTROL_TRANS2_COMMIT           = 83, /* obsolete */
+                   CTDB_CONTROL_TRANS2_FINISHED         = 84, /* obsolete */
+                   CTDB_CONTROL_TRANS2_ERROR            = 85, /* obsolete */
+                   CTDB_CONTROL_TRANS2_COMMIT_RETRY     = 86, /* obsolete */
+                   CTDB_CONTROL_RECD_PING               = 87,
+                   CTDB_CONTROL_RELEASE_IP              = 88,
+                   CTDB_CONTROL_TAKEOVER_IP             = 89,
+                   CTDB_CONTROL_GET_PUBLIC_IPS          = 90,
+                   CTDB_CONTROL_GET_NODEMAP             = 91,
+                   /* missing */
+                   CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS = 96,
+                   CTDB_CONTROL_TRAVERSE_KILL           = 97,
+                   CTDB_CONTROL_RECD_RECLOCK_LATENCY    = 98,
+                   CTDB_CONTROL_GET_RECLOCK_FILE        = 99,
+                   CTDB_CONTROL_SET_RECLOCK_FILE        = 100,
+                   CTDB_CONTROL_STOP_NODE               = 101,
+                   CTDB_CONTROL_CONTINUE_NODE           = 102,
+                   CTDB_CONTROL_SET_NATGWSTATE          = 103,
+                   CTDB_CONTROL_SET_LMASTERROLE         = 104,
+                   CTDB_CONTROL_SET_RECMASTERROLE       = 105,
+                   CTDB_CONTROL_ENABLE_SCRIPT           = 107,
+                   CTDB_CONTROL_DISABLE_SCRIPT          = 108,
+                   CTDB_CONTROL_SET_BAN_STATE           = 109,
+                   CTDB_CONTROL_GET_BAN_STATE           = 110,
+                   CTDB_CONTROL_SET_DB_PRIORITY         = 111,
+                   CTDB_CONTROL_GET_DB_PRIORITY         = 112,
+                   CTDB_CONTROL_TRANSACTION_CANCEL      = 113,
+                   CTDB_CONTROL_REGISTER_NOTIFY         = 114,
+                   CTDB_CONTROL_DEREGISTER_NOTIFY       = 115,
+                   CTDB_CONTROL_TRANS2_ACTIVE           = 116, /* obsolete */
+                   CTDB_CONTROL_GET_LOG                 = 117, /* obsolete */
+                   CTDB_CONTROL_CLEAR_LOG               = 118, /* obsolete */
+                   CTDB_CONTROL_TRANS3_COMMIT           = 119,
+                   CTDB_CONTROL_GET_DB_SEQNUM           = 120,
+                   CTDB_CONTROL_DB_SET_HEALTHY          = 121,
+                   CTDB_CONTROL_DB_GET_HEALTH           = 122,
+                   CTDB_CONTROL_GET_PUBLIC_IP_INFO      = 123,
+                   CTDB_CONTROL_GET_IFACES              = 124,
+                   CTDB_CONTROL_SET_IFACE_LINK_STATE    = 125,
+                   CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE  = 126,
+                   CTDB_CONTROL_GET_STAT_HISTORY        = 127,
+                   CTDB_CONTROL_SCHEDULE_FOR_DELETION   = 128,
+                   CTDB_CONTROL_SET_DB_READONLY         = 129,
+                   CTDB_CONTROL_CHECK_SRVIDS            = 130,
+                   CTDB_CONTROL_TRAVERSE_START_EXT      = 131,
+                   CTDB_CONTROL_GET_DB_STATISTICS       = 132,
+                   CTDB_CONTROL_SET_DB_STICKY           = 133,
+                   CTDB_CONTROL_RELOAD_PUBLIC_IPS       = 134,
+                   CTDB_CONTROL_TRAVERSE_ALL_EXT        = 135,
+                   CTDB_CONTROL_RECEIVE_RECORDS         = 136,
+                   CTDB_CONTROL_IPREALLOCATED           = 137,
+                   CTDB_CONTROL_GET_RUNSTATE            = 138,
+                   CTDB_CONTROL_DB_DETACH               = 139,
+                   CTDB_CONTROL_GET_NODES_FILE          = 140,
+};
+
+#define CTDB_MONITORING_ACTIVE         0
+#define CTDB_MONITORING_DISABLED       1
+
+#define MAX_COUNT_BUCKETS 16
+#define MAX_HOT_KEYS      10
+
+struct ctdb_latency_counter {
+       int num;
+       double min;
+       double max;
+       double total;
+};
+
+struct ctdb_statistics {
+       uint32_t num_clients;
+       uint32_t frozen;
+       uint32_t recovering;
+       uint32_t client_packets_sent;
+       uint32_t client_packets_recv;
+       uint32_t node_packets_sent;
+       uint32_t node_packets_recv;
+       uint32_t keepalive_packets_sent;
+       uint32_t keepalive_packets_recv;
+       struct {
+               uint32_t req_call;
+               uint32_t reply_call;
+               uint32_t req_dmaster;
+               uint32_t reply_dmaster;
+               uint32_t reply_error;
+               uint32_t req_message;
+               uint32_t req_control;
+               uint32_t reply_control;
+       } node;
+       struct {
+               uint32_t req_call;
+               uint32_t req_message;
+               uint32_t req_control;
+       } client;
+       struct {
+               uint32_t call;
+               uint32_t control;
+               uint32_t traverse;
+       } timeouts;
+       struct {
+               struct ctdb_latency_counter ctdbd;
+               struct ctdb_latency_counter recd;
+       } reclock;
+       struct {
+               uint32_t num_calls;
+               uint32_t num_current;
+               uint32_t num_pending;
+               uint32_t num_failed;
+               struct ctdb_latency_counter latency;
+               uint32_t buckets[MAX_COUNT_BUCKETS];
+       } locks;
+       uint32_t total_calls;
+       uint32_t pending_calls;
+       uint32_t childwrite_calls;
+       uint32_t pending_childwrite_calls;
+       uint32_t memory_used;
+       uint32_t __last_counter; /* hack */
+       uint32_t max_hop_count;
+       uint32_t hop_count_bucket[MAX_COUNT_BUCKETS];
+       struct ctdb_latency_counter call_latency;
+       struct ctdb_latency_counter childwrite_latency;
+       uint32_t num_recoveries;
+       struct timeval statistics_start_time;
+       struct timeval statistics_current_time;
+       uint32_t total_ro_delegations;
+       uint32_t total_ro_revokes;
+};
+
+#define INVALID_GENERATION 1
+/* table that contains the mapping between a hash value and lmaster
+ */
+struct ctdb_vnn_map {
+       uint32_t generation;
+       uint32_t size;
+       uint32_t *map;
+};
+
+struct ctdb_dbid {
+       uint32_t db_id;
+#define CTDB_DB_FLAGS_PERSISTENT       0x01
+#define CTDB_DB_FLAGS_READONLY         0x02
+#define CTDB_DB_FLAGS_STICKY           0x04
+       uint8_t flags;
+};
+
+struct ctdb_dbid_map {
+       uint32_t num;
+       struct ctdb_dbid *dbs;
+};
+
+struct ctdb_pulldb {
+       uint32_t db_id;
+#define CTDB_LMASTER_ANY       0xffffffff
+       uint32_t lmaster;
+};
+
+#define CTDB_RECOVERY_NORMAL           0
+#define CTDB_RECOVERY_ACTIVE           1
+
+#define CTDB_NUM_DB_PRIORITIES         3
+
+/*
+  the extended header for records in the ltdb
+*/
+struct ctdb_ltdb_header {
+       uint64_t rsn;
+       uint32_t dmaster;
+       uint32_t reserved1;
+#define CTDB_REC_FLAG_DEFAULT                  0x00000000
+#define CTDB_REC_FLAG_MIGRATED_WITH_DATA       0x00010000
+#define CTDB_REC_FLAG_VACUUM_MIGRATED          0x00020000
+#define CTDB_REC_FLAG_AUTOMATIC                        0x00040000
+#define CTDB_REC_RO_HAVE_DELEGATIONS           0x01000000
+#define CTDB_REC_RO_HAVE_READONLY              0x02000000
+#define CTDB_REC_RO_REVOKING_READONLY          0x04000000
+#define CTDB_REC_RO_REVOKE_COMPLETE            0x08000000
+#define CTDB_REC_RO_FLAGS                      (CTDB_REC_RO_HAVE_DELEGATIONS|\
+                                                CTDB_REC_RO_HAVE_READONLY|\
+                                                CTDB_REC_RO_REVOKING_READONLY|\
+                                                CTDB_REC_RO_REVOKE_COMPLETE)
+       uint32_t flags;
+};
+
+struct ctdb_rec_data {
+       uint32_t reqid;
+       struct ctdb_ltdb_header *header;
+       TDB_DATA key, data;
+};
+
+struct ctdb_rec_buffer {
+       uint32_t db_id;
+       uint32_t count;
+       uint8_t *buf;
+       size_t buflen;
+};
+
+typedef int (*ctdb_rec_parser_func_t)(uint32_t reqid,
+                                     struct ctdb_ltdb_header *header,
+                                     TDB_DATA key, TDB_DATA data,
+                                     void *private_data);
+
+struct ctdb_traverse_start {
+       uint32_t db_id;
+       uint32_t reqid;
+       uint64_t srvid;
+};
+
+struct ctdb_traverse_all {
+       uint32_t db_id;
+       uint32_t reqid;
+       uint32_t pnn;
+       uint32_t client_reqid;
+       uint64_t srvid;
+};
+
+struct ctdb_traverse_start_ext {
+       uint32_t db_id;
+       uint32_t reqid;
+       uint64_t srvid;
+       bool withemptyrecords;
+};
+
+struct ctdb_traverse_all_ext {
+       uint32_t db_id;
+       uint32_t reqid;
+       uint32_t pnn;
+       uint32_t client_reqid;
+       uint64_t srvid;
+       bool withemptyrecords;
+};
+
+typedef union {
+       struct sockaddr sa;
+       struct sockaddr_in ip;
+       struct sockaddr_in6 ip6;
+} ctdb_sock_addr;
+
+struct ctdb_connection {
+       ctdb_sock_addr src;
+       ctdb_sock_addr dst;
+};
+
+struct ctdb_tunable {
+       const char *name;
+       uint32_t value;
+};
+
+struct ctdb_var_list {
+       int count;
+       const char **var;
+};
+
+struct ctdb_node_flag_change {
+       uint32_t pnn;
+       uint32_t new_flags;
+       uint32_t old_flags;
+};
+
+/* all tunable variables go in here */
+struct ctdb_tunable_list {
+       uint32_t max_redirect_count;
+       uint32_t seqnum_interval; /* unit is ms */
+       uint32_t control_timeout;
+       uint32_t traverse_timeout;
+       uint32_t keepalive_interval;
+       uint32_t keepalive_limit;
+       uint32_t recover_timeout;
+       uint32_t recover_interval;
+       uint32_t election_timeout;
+       uint32_t takeover_timeout;
+       uint32_t monitor_interval;
+       uint32_t tickle_update_interval;
+       uint32_t script_timeout;
+       uint32_t script_timeout_count; /* allow dodgy scripts to hang this many times in a row before we mark the node unhealthy */
+       uint32_t script_unhealthy_on_timeout; /* obsolete */
+       uint32_t recovery_grace_period;
+       uint32_t recovery_ban_period;
+       uint32_t database_hash_size;
+       uint32_t database_max_dead;
+       uint32_t rerecovery_timeout;
+       uint32_t enable_bans;
+       uint32_t deterministic_public_ips;
+       uint32_t reclock_ping_period;
+       uint32_t no_ip_failback;
+       uint32_t disable_ip_failover;
+       uint32_t verbose_memory_names;
+       uint32_t recd_ping_timeout;
+       uint32_t recd_ping_failcount;
+       uint32_t log_latency_ms;
+       uint32_t reclock_latency_ms;
+       uint32_t recovery_drop_all_ips;
+       uint32_t verify_recovery_lock;
+       uint32_t vacuum_interval;
+       uint32_t vacuum_max_run_time;
+       uint32_t repack_limit;
+       uint32_t vacuum_limit;
+       uint32_t max_queue_depth_drop_msg;
+       uint32_t allow_unhealthy_db_read;
+       uint32_t stat_history_interval;
+       uint32_t deferred_attach_timeout;
+       uint32_t vacuum_fast_path_count;
+       uint32_t lcp2_public_ip_assignment;
+       uint32_t allow_client_db_attach;
+       uint32_t recover_pdb_by_seqnum;
+       uint32_t deferred_rebalance_on_node_add;
+       uint32_t fetch_collapse;
+       uint32_t hopcount_make_sticky;
+       uint32_t sticky_duration;
+       uint32_t sticky_pindown;
+       uint32_t no_ip_takeover;
+       uint32_t db_record_count_warn;
+       uint32_t db_record_size_warn;
+       uint32_t db_size_warn;
+       uint32_t pulldb_preallocation_size;
+       uint32_t no_ip_host_on_all_disabled;
+       uint32_t samba3_hack;
+       uint32_t mutex_enabled;
+       uint32_t lock_processes_per_db;
+};
+
+struct ctdb_tickle_list {
+       ctdb_sock_addr addr;
+       uint32_t num;
+       struct ctdb_connection *conn;
+};
+
+enum ctdb_client_type {
+       SERVER_TYPE_CTDB = 0,
+       SERVER_TYPE_SAMBA = 1,
+       SERVER_TYPE_NFSD = 2,
+       SERVER_TYPE_ISCSID = 3
+};
+
+struct ctdb_client_id {
+       enum ctdb_client_type type;
+       uint32_t pnn;
+       uint32_t server_id;
+};
+
+struct ctdb_client_id_list {
+       uint32_t num;
+       struct ctdb_client_id *cid;
+};
+
+struct ctdb_client_id_map {
+       int count;
+       struct ctdb_client_id_list *list;
+};
+
+struct ctdb_addr_info {
+       ctdb_sock_addr addr;
+       uint32_t mask;
+       const char *iface;
+};
+
+struct ctdb_transdb {
+       uint32_t db_id;
+       uint32_t tid;
+};
+
+struct ctdb_uptime {
+       struct timeval current_time;
+       struct timeval ctdbd_start_time;
+       struct timeval last_recovery_started;
+       struct timeval last_recovery_finished;
+};
+
+struct ctdb_public_ip {
+       uint32_t pnn;
+       ctdb_sock_addr addr;
+};
+
+struct ctdb_public_ip_list {
+       uint32_t num;
+       struct ctdb_public_ip *ip;
+};
+
+/*
+ * Node flags
+ */
+#define NODE_FLAGS_DISCONNECTED                0x00000001 /* node isn't connected */
+#define NODE_FLAGS_UNHEALTHY           0x00000002 /* monitoring says node is unhealthy */
+#define NODE_FLAGS_PERMANENTLY_DISABLED        0x00000004 /* administrator has disabled node */
+#define NODE_FLAGS_BANNED              0x00000008 /* recovery daemon has banned the node */
+#define NODE_FLAGS_DELETED             0x00000010 /* this node has been deleted */
+#define NODE_FLAGS_STOPPED             0x00000020 /* this node has been stopped */
+#define NODE_FLAGS_DISABLED            (NODE_FLAGS_UNHEALTHY|NODE_FLAGS_PERMANENTLY_DISABLED)
+#define NODE_FLAGS_INACTIVE            (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED)
+
+/*
+ * Node capabilities
+ */
+#define CTDB_CAP_RECMASTER             0x00000001
+#define CTDB_CAP_LMASTER               0x00000002
+/* This capability is set if CTDB_LVS_PUBLIC_IP is set */
+#define CTDB_CAP_LVS                   0x00000004
+/* This capability is set if NATGW is enabled */
+#define CTDB_CAP_NATGW                 0x00000008
+
+struct ctdb_node_and_flags {
+       uint32_t pnn;
+       uint32_t flags;
+       ctdb_sock_addr addr;
+};
+
+struct ctdb_node_map {
+       uint32_t num;
+       struct ctdb_node_and_flags *node;
+};
+
+enum ctdb_event {
+       CTDB_EVENT_INIT,                /* CTDB starting up: no args */
+       CTDB_EVENT_SETUP,               /* CTDB starting up after transport is readdy: no args. */
+       CTDB_EVENT_STARTUP,             /* CTDB starting up after initial recovery: no args. */
+       CTDB_EVENT_START_RECOVERY,      /* CTDB recovery starting: no args. */
+       CTDB_EVENT_RECOVERED,           /* CTDB recovery finished: no args. */
+       CTDB_EVENT_TAKE_IP,             /* IP taken: interface, IP address, netmask bits. */
+       CTDB_EVENT_RELEASE_IP,          /* IP released: interface, IP address, netmask bits. */
+       CTDB_EVENT_STOPPED,             /* Deprecated, do not use. */
+       CTDB_EVENT_MONITOR,             /* Please check if service is healthy: no args. */
+       CTDB_EVENT_STATUS,              /* Deprecated, do not use. */
+       CTDB_EVENT_SHUTDOWN,            /* CTDB shutting down: no args. */
+       CTDB_EVENT_RELOAD,              /* Deprecated, do not use */
+       CTDB_EVENT_UPDATE_IP,           /* IP updating: old interface, new interface, IP address, netmask bits. */
+       CTDB_EVENT_IPREALLOCATED,       /* when a takeover_run() completes */
+       CTDB_EVENT_MAX
+};
+
+#define MAX_SCRIPT_NAME 31
+#define MAX_SCRIPT_OUTPUT 511
+
+struct ctdb_script {
+       char name[MAX_SCRIPT_NAME+1];
+       struct timeval start;
+       struct timeval finished;
+       int32_t status;
+       char output[MAX_SCRIPT_OUTPUT+1];
+};
+
+struct ctdb_script_list {
+       uint32_t num_scripts;
+       struct ctdb_script *script;
+};
+
+struct ctdb_ban_state {
+       uint32_t pnn;
+       uint32_t time;
+};
+
+struct ctdb_db_priority {
+       uint32_t db_id;
+       uint32_t priority;
+};
+
+struct ctdb_notify_data {
+       uint64_t srvid;
+       TDB_DATA data;
+};
+
+#ifdef IFNAMSIZ
+#define CTDB_IFACE_SIZE IFNAMSIZ
+#else
+#define CTDB_IFACE_SIZE 16
+#endif
+
+struct ctdb_iface {
+       char name[CTDB_IFACE_SIZE+2];
+       uint16_t link_state;
+       uint32_t references;
+};
+
+struct ctdb_iface_list {
+       uint32_t num;
+       struct ctdb_iface *iface;
+};
+
+struct ctdb_public_ip_info {
+       struct ctdb_public_ip ip;
+       uint32_t active_idx;
+       struct ctdb_iface_list *ifaces;
+};
+
+struct ctdb_statistics_list {
+       int num;
+       struct ctdb_statistics *stats;
+};
+
+struct ctdb_key_data {
+       uint32_t db_id;
+       struct ctdb_ltdb_header header;
+       TDB_DATA key;
+};
+
+struct ctdb_uint8_array {
+       int num;
+       uint8_t *val;
+};
+
+struct ctdb_uint64_array {
+       int num;
+       uint64_t *val;
+};
+
+struct ctdb_db_statistics {
+       struct {
+               uint32_t num_calls;
+               uint32_t num_current;
+               uint32_t num_pending;
+               uint32_t num_failed;
+               struct ctdb_latency_counter latency;
+               uint32_t buckets[MAX_COUNT_BUCKETS];
+       } locks;
+       struct {
+               struct ctdb_latency_counter latency;
+       } vacuum;
+       uint32_t db_ro_delegations;
+       uint32_t db_ro_revokes;
+       uint32_t hop_count_bucket[MAX_COUNT_BUCKETS];
+       uint32_t num_hot_keys;
+       struct {
+               uint32_t count;
+               TDB_DATA key;
+       } hot_keys[MAX_HOT_KEYS];
+};
+
+enum ctdb_runstate {
+       CTDB_RUNSTATE_UNKNOWN,
+       CTDB_RUNSTATE_INIT,
+       CTDB_RUNSTATE_SETUP,
+       CTDB_RUNSTATE_FIRST_RECOVERY,
+       CTDB_RUNSTATE_STARTUP,
+       CTDB_RUNSTATE_RUNNING,
+       CTDB_RUNSTATE_SHUTDOWN,
+};
+
+struct ctdb_req_control_data {
+       uint32_t opcode;
+       union {
+               pid_t pid;
+               uint32_t db_id;
+               struct ctdb_vnn_map *vnnmap;
+               uint32_t loglevel;
+               struct ctdb_pulldb *pulldb;
+               struct ctdb_rec_buffer *recbuf;
+               uint32_t recmode;
+               const char *db_name;
+               struct ctdb_traverse_start *traverse_start;
+               struct ctdb_traverse_all *traverse_all;
+               struct ctdb_rec_data *rec_data;
+               uint32_t recmaster;
+               struct ctdb_connection *conn;
+               struct ctdb_tunable *tunable;
+               const char *tun_var;
+               struct ctdb_node_flag_change *flag_change;
+               ctdb_sock_addr *addr;
+               struct ctdb_tickle_list *tickles;
+               struct ctdb_client_id *cid;
+               struct ctdb_addr_info *addr_info;
+               uint32_t tid;
+               struct ctdb_transdb *transdb;
+               const char *event_str;
+               struct ctdb_public_ip *pubip;
+               enum ctdb_event event;
+               double reclock_latency;
+               const char *reclock_file;
+               uint32_t role;
+               const char *script;
+               struct ctdb_ban_state *ban_state;
+               struct ctdb_db_priority *db_prio;
+               struct ctdb_notify_data *notify;
+               uint64_t srvid;
+               struct ctdb_iface *iface;
+               struct ctdb_key_data *key;
+               struct ctdb_uint64_array *u64_array;
+               struct ctdb_traverse_start_ext *traverse_start_ext;
+               struct ctdb_traverse_all_ext *traverse_all_ext;
+       } data;
+};
+
+struct ctdb_reply_control_data {
+       uint32_t opcode;
+       union {
+               struct ctdb_statistics *stats;
+               const char *db_path;
+               struct ctdb_vnn_map *vnnmap;
+               uint32_t loglevel;
+               struct ctdb_dbid_map *dbmap;
+               struct ctdb_rec_buffer *recbuf;
+               uint32_t db_id;
+               const char *db_name;
+               const char *mem_str;
+               uint32_t tun_value;
+               struct ctdb_var_list *tun_var_list;
+               struct ctdb_tunable_list *tun_list;
+               struct ctdb_tickle_list *tickles;
+               struct ctdb_client_id_map *cid_map;
+               struct ctdb_uptime *uptime;
+               uint32_t caps;
+               struct ctdb_public_ip_list *pubip_list;
+               struct ctdb_node_map *nodemap;
+               struct ctdb_script_list *script_list;
+               const char *reclock_file;
+               struct ctdb_ban_state *ban_state;
+               uint64_t seqnum;
+               const char *reason;
+               struct ctdb_public_ip_info *ipinfo;
+               struct ctdb_iface_list *iface_list;
+               struct ctdb_statistics_list *stats_list;
+               struct ctdb_uint8_array *u8_array;
+               struct ctdb_db_statistics *dbstats;
+               enum ctdb_runstate runstate;
+       } data;
+};
+
+struct ctdb_req_control {
+       uint32_t opcode;
+       uint32_t pad;
+       uint64_t srvid;
+       uint32_t client_id;
+#define CTDB_CTRL_FLAG_NOREPLY   1
+#define CTDB_CTRL_FLAG_OPCODE_SPECIFIC   0xFFFF0000
+       uint32_t flags;
+       struct ctdb_req_control_data rdata;
+};
+
+struct ctdb_reply_control {
+       int32_t status;
+       const char *errmsg;
+       struct ctdb_reply_control_data rdata;
+};
+
+struct ctdb_election_message {
+       uint32_t num_connected;
+       struct timeval priority_time;
+       uint32_t pnn;
+       uint32_t node_flags;
+};
+
+struct ctdb_srvid_message {
+       uint32_t pnn;
+       uint64_t srvid;
+};
+
+struct ctdb_disable_message {
+       uint32_t pnn;
+       uint64_t srvid;
+       uint32_t timeout;
+};
+
+union ctdb_message_data {
+       /* SRVID_ELECTION */
+       struct ctdb_election_message *election;
+       /* SRVID_RELEASE_IP, SRVID_TAKE_IP */
+       const char *ipaddr;
+       /* SRVID_SET_NODE_FLAGS, SERVID_PUSH_NODE_FLAGS */
+       struct ctdb_node_flag_change *flag_change;
+       /* SRVID_RECD_UPDATE_IP */
+       struct ctdb_public_ip *pubip;
+       /* SRVID_VACUUM_FETCH */
+       struct ctdb_rec_buffer *recbuf;
+       /* SRVID_DETACH_DATABASE */
+       uint32_t db_id;
+       /* SRVID_MEM_DUMP, SRVID_TAKEOVER_RUN */
+       struct ctdb_srvid_message *msg;
+       /* SRVID_REBALANCE_NODE */
+       uint32_t pnn;
+       /* SRVID_DISABLE_TAKEOVER_RUNS, SRVID_DISABLE_RECOVERIES */
+       struct ctdb_disable_message *disable;
+       /* SRVID_DISABLE_IP_CHECK */
+       uint32_t timeout;
+};
+
+struct ctdb_req_message {
+       uint64_t srvid;
+       union ctdb_message_data data;
+};
+
+struct ctdb_req_message_data {
+       uint64_t srvid;
+       TDB_DATA data;
+};
+
+/* This is equivalent to server_id */
+struct ctdb_server_id {
+       uint64_t pid;
+       uint32_t task_id;
+       uint32_t vnn;
+       uint64_t unique_id;
+};
+
+enum ctdb_g_lock_type {
+       G_LOCK_READ = 0,
+       G_LOCK_WRITE = 1,
+};
+
+struct ctdb_g_lock {
+       enum ctdb_g_lock_type type;
+       struct ctdb_server_id sid;
+};
+
+struct ctdb_g_lock_list {
+       unsigned int num;
+       struct ctdb_g_lock *lock;
+};
+
+#endif /* __CTDB_PROTOCOL_H__ */
diff --git a/ctdb/protocol/protocol_api.h b/ctdb/protocol/protocol_api.h
new file mode 100644 (file)
index 0000000..3628c3e
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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_PROTOCOL_API_H__
+#define __CTDB_PROTOCOL_API_H__
+
+#include "protocol/protocol.h"
+
+/* From protocol/protocol_types.c */
+
+size_t ctdb_ltdb_header_len(struct ctdb_ltdb_header *header);
+void ctdb_ltdb_header_push(struct ctdb_ltdb_header *header, uint8_t *buf);
+int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen,
+                         struct ctdb_ltdb_header *header);
+
+size_t ctdb_rec_data_len(struct ctdb_rec_data *rec);
+void ctdb_rec_data_push(struct ctdb_rec_data *rec, uint8_t *buf);
+int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_rec_data **out);
+
+size_t ctdb_rec_buffer_len(struct ctdb_rec_buffer *recbuf);
+void ctdb_rec_buffer_push(struct ctdb_rec_buffer *recbuf, uint8_t *buf);
+int ctdb_rec_buffer_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                     struct ctdb_rec_buffer **out);
+
+struct ctdb_rec_buffer *ctdb_rec_buffer_init(TALLOC_CTX *mem_ctx,
+                                            uint32_t db_id);
+int ctdb_rec_buffer_add(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *recbuf,
+                       uint32_t reqid, struct ctdb_ltdb_header *header,
+                       TDB_DATA key, TDB_DATA data);
+int ctdb_rec_buffer_traverse(struct ctdb_rec_buffer *recbuf,
+                            ctdb_rec_parser_func_t func,
+                            void *private_data);
+
+size_t ctdb_server_id_len(struct ctdb_server_id *sid);
+void ctdb_server_id_push(struct ctdb_server_id *sid, uint8_t *buf);
+int ctdb_server_id_pull(uint8_t *buf, size_t buflen,
+                        struct ctdb_server_id *sid);
+
+size_t ctdb_g_lock_len(struct ctdb_g_lock *lock);
+void ctdb_g_lock_push(struct ctdb_g_lock *lock, uint8_t *buf);
+int ctdb_g_lock_pull(uint8_t *buf, size_t buflen, struct ctdb_g_lock *lock);
+
+size_t ctdb_g_lock_list_len(struct ctdb_g_lock_list *lock_list);
+void ctdb_g_lock_list_push(struct ctdb_g_lock_list *lock_list, uint8_t *buf);
+int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_g_lock_list **out);
+
+/* From protocol/protocol_header.c */
+
+void ctdb_req_header_fill(struct ctdb_req_header *h, uint32_t generation,
+                         uint32_t operation, uint32_t destnode,
+                         uint32_t srcnode, uint32_t reqid);
+
+int ctdb_req_header_pull(uint8_t *pkt, size_t pkt_len,
+                        struct ctdb_req_header *h);
+
+int ctdb_req_header_verify(struct ctdb_req_header *h, uint32_t operation);
+
+/* From protocol/protocol_call.c */
+
+int ctdb_req_call_push(struct ctdb_req_header *h,
+                      struct ctdb_req_call *c,
+                      TALLOC_CTX *mem_ctx,
+                      uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_call_pull(uint8_t *pkt, size_t pkt_len,
+                      struct ctdb_req_header *h,
+                      TALLOC_CTX *mem_ctx,
+                      struct ctdb_req_call *c);
+
+int ctdb_reply_call_push(struct ctdb_req_header *h,
+                        struct ctdb_reply_call *c,
+                        TALLOC_CTX *mem_ctx,
+                        uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_reply_call_pull(uint8_t *pkt, size_t pkt_len,
+                        struct ctdb_req_header *h,
+                        TALLOC_CTX *mem_ctx,
+                        struct ctdb_reply_call *c);
+
+int ctdb_reply_error_push(struct ctdb_req_header *h,
+                         struct ctdb_reply_error *c,
+                         TALLOC_CTX *mem_ctx,
+                         uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_reply_error_pull(uint8_t *pkt, size_t pkt_len,
+                         struct ctdb_req_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_reply_error *c);
+
+int ctdb_req_dmaster_push(struct ctdb_req_header *h,
+                         struct ctdb_req_dmaster *c,
+                         TALLOC_CTX *mem_ctx,
+                         uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_dmaster_pull(uint8_t *pkt, size_t pkt_len,
+                         struct ctdb_req_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_req_dmaster *c);
+
+int ctdb_reply_dmaster_push(struct ctdb_req_header *h,
+                           struct ctdb_reply_dmaster *c,
+                           TALLOC_CTX *mem_ctx,
+                           uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_reply_dmaster_pull(uint8_t *pkt, size_t pkt_len,
+                           struct ctdb_req_header *h,
+                           TALLOC_CTX *mem_ctx,
+                           struct ctdb_reply_dmaster *c);
+
+/* From protocol/protocol_control.c */
+
+int ctdb_req_control_push(struct ctdb_req_header *h,
+                         struct ctdb_req_control *c,
+                         TALLOC_CTX *mem_ctx,
+                         uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_control_pull(uint8_t *pkt, size_t pkt_len,
+                         struct ctdb_req_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_req_control *c);
+
+int ctdb_reply_control_push(struct ctdb_req_header *h,
+                           struct ctdb_reply_control *c,
+                           TALLOC_CTX *mem_ctx,
+                           uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_reply_control_pull(uint8_t *pkt, size_t pkt_len, uint32_t opcode,
+                           struct ctdb_req_header *h,
+                           TALLOC_CTX *mem_ctx,
+                           struct ctdb_reply_control *c);
+
+/* From protocol/protocol_client.c */
+
+void ctdb_req_control_process_exists(struct ctdb_req_control *request,
+                                    pid_t pid);
+int ctdb_reply_control_process_exists(struct ctdb_reply_control *reply,
+                                     int *status);
+
+void ctdb_req_control_statistics(struct ctdb_req_control *request);
+
+int ctdb_reply_control_statistics(struct ctdb_reply_control *reply,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct ctdb_statistics **stats);
+
+void ctdb_req_control_ping(struct ctdb_req_control *request);
+int ctdb_reply_control_ping(struct ctdb_reply_control *reply,
+                           int *num_clients);
+
+void ctdb_req_control_getdbpath(struct ctdb_req_control *request,
+                               uint32_t db_id);
+int ctdb_reply_control_getdbpath(struct ctdb_reply_control *reply,
+                                TALLOC_CTX *mem_ctx, const char **db_path);
+
+void ctdb_req_control_getvnnmap(struct ctdb_req_control *request);
+int ctdb_reply_control_getvnnmap(struct ctdb_reply_control *reply,
+                                TALLOC_CTX *mem_ctx,
+                                struct ctdb_vnn_map **vnnmap);
+
+void ctdb_req_control_setvnnmap(struct ctdb_req_control *request,
+                               struct ctdb_vnn_map *vnnmap);
+int ctdb_reply_control_setvnnmap(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_debug(struct ctdb_req_control *request);
+int ctdb_reply_control_get_debug(struct ctdb_reply_control *reply,
+                                uint32_t *debug_level);
+
+void ctdb_req_control_set_debug(struct ctdb_req_control *request,
+                               uint32_t debug_level);
+int ctdb_reply_control_set_debug(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_dbmap(struct ctdb_req_control *request);
+int ctdb_reply_control_get_dbmap(struct ctdb_reply_control *reply,
+                                TALLOC_CTX *mem_ctx,
+                                struct ctdb_dbid_map **dbmap);
+
+void ctdb_req_control_pull_db(struct ctdb_req_control *request,
+                             struct ctdb_pulldb *pulldb);
+int ctdb_reply_control_pull_db(struct ctdb_reply_control *reply,
+                              TALLOC_CTX *mem_ctx,
+                              struct ctdb_rec_buffer **recbuf);
+
+void ctdb_req_control_push_db(struct ctdb_req_control *request,
+                             struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_push_db(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_recmode(struct ctdb_req_control *request);
+int ctdb_reply_control_get_recmode(struct ctdb_reply_control *reply,
+                                  int *recmode);
+
+void ctdb_req_control_set_recmode(struct ctdb_req_control *request,
+                                 int recmode);
+int ctdb_reply_control_set_recmode(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_statistics_reset(struct ctdb_req_control *request);
+int ctdb_reply_control_statistics_reset(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_db_attach(struct ctdb_req_control *request,
+                               const char *db_name, uint32_t tdb_flags);
+int ctdb_reply_control_db_attach(struct ctdb_reply_control *reply,
+                                uint32_t *db_id);
+
+void ctdb_req_control_traverse_start(struct ctdb_req_control *request,
+                                    struct ctdb_traverse_start *traverse);
+int ctdb_reply_control_traverse_start(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_register_srvid(struct ctdb_req_control *request,
+                                    uint64_t srvid);
+int ctdb_reply_control_register_srvid(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_deregister_srvid(struct ctdb_req_control *request,
+                                      uint64_t srvid);
+int ctdb_reply_control_deregister_srvid(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_dbname(struct ctdb_req_control *request,
+                                uint32_t db_id);
+int ctdb_reply_control_get_dbname(struct ctdb_reply_control *reply,
+                                 TALLOC_CTX *mem_ctx, const char **db_name);
+
+void ctdb_req_control_enable_seqnum(struct ctdb_req_control *request,
+                                   uint32_t db_id);
+int ctdb_reply_control_enable_seqnum(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_update_seqnum(struct ctdb_req_control *request,
+                                   uint32_t db_id);
+int ctdb_reply_control_update_seqnum(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_dump_memory(struct ctdb_req_control *request);
+int ctdb_reply_control_dump_memory(struct ctdb_reply_control *reply,
+                                  TALLOC_CTX *mem_ctx, const char **mem_str);
+
+void ctdb_req_control_get_pid(struct ctdb_req_control *request);
+int ctdb_reply_control_get_pid(struct ctdb_reply_control *reply,
+                              pid_t *pid);
+
+void ctdb_req_control_get_recmaster(struct ctdb_req_control *request);
+int ctdb_reply_control_get_recmaster(struct ctdb_reply_control *reply,
+                                    uint32_t *recmaster);
+
+void ctdb_req_control_set_recmaster(struct ctdb_req_control *request,
+                                   int recmaster);
+int ctdb_reply_control_set_recmaster(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_freeze(struct ctdb_req_control *request,
+                            uint32_t priority);
+int ctdb_reply_control_freeze(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_thaw(struct ctdb_req_control *request,
+                          uint32_t priority);
+int ctdb_reply_control_thaw(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_pnn(struct ctdb_req_control *request);
+int ctdb_reply_control_get_pnn(struct ctdb_reply_control *reply,
+                              uint32_t *pnn);
+
+void ctdb_req_control_shutdown(struct ctdb_req_control *request);
+int ctdb_reply_control_shutdown(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_monmode(struct ctdb_req_control *request);
+int ctdb_reply_control_get_monmode(struct ctdb_reply_control *reply,
+                                  int *mon_mode);
+
+void ctdb_req_control_tcp_client(struct ctdb_req_control *request,
+                                struct ctdb_connection *conn);
+int ctdb_reply_control_tcp_client(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_tcp_add(struct ctdb_req_control *request,
+                             struct ctdb_connection *conn);
+int ctdb_reply_control_tcp_add(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_tcp_remove(struct ctdb_req_control *request,
+                                struct ctdb_connection *conn);
+int ctdb_reply_control_tcp_remove(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_startup(struct ctdb_req_control *request);
+int ctdb_reply_control_startup(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_tunable(struct ctdb_req_control *request,
+                                 struct ctdb_tunable *tunable);
+int ctdb_reply_control_set_tunable(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_tunable(struct ctdb_req_control *request,
+                                 const char *name);
+int ctdb_reply_control_get_tunable(struct ctdb_reply_control *reply,
+                                  uint32_t *value);
+
+void ctdb_req_control_list_tunables(struct ctdb_req_control *request);
+int ctdb_reply_control_list_tunables(struct ctdb_reply_control *reply,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct ctdb_var_list **tun_var_list);
+
+void ctdb_req_control_modify_flags(struct ctdb_req_control *request,
+                                  struct ctdb_node_flag_change *flag_change);
+int ctdb_reply_control_modify_flags(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_all_tunables(struct ctdb_req_control *request);
+int ctdb_reply_control_get_all_tunables(struct ctdb_reply_control *reply,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct ctdb_tunable_list **tun_list);
+
+void ctdb_req_control_kill_tcp(struct ctdb_req_control *request,
+                              struct ctdb_connection *conn);
+int ctdb_reply_control_kill_tcp(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_tcp_tickle_list(struct ctdb_req_control *request,
+                                         ctdb_sock_addr *addr);
+int ctdb_reply_control_get_tcp_tickle_list(struct ctdb_reply_control *reply,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct ctdb_tickle_list **tickles);
+
+void ctdb_req_control_set_tcp_tickle_list(struct ctdb_req_control *request,
+                                         struct ctdb_tickle_list *tickles);
+int ctdb_reply_control_set_tcp_tickle_list(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_register_server_id(struct ctdb_req_control *request,
+                                        struct ctdb_client_id *sid);
+int ctdb_reply_control_register_server_id(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_unregister_server_id(struct ctdb_req_control *request,
+                                          struct ctdb_client_id *sid);
+int ctdb_reply_control_unregister_server_id(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_check_server_id(struct ctdb_req_control *request,
+                                     struct ctdb_client_id *sid);
+int ctdb_reply_control_check_server_id(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_server_id_list(struct ctdb_req_control *request);
+int ctdb_reply_control_get_server_id_list(struct ctdb_reply_control *reply,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct ctdb_client_id_map **cid_map);
+
+void ctdb_req_control_db_attach_persistent(struct ctdb_req_control *request,
+                                          const char *name,
+                                          uint32_t tdb_flags);
+int ctdb_reply_control_db_attach_persistent(struct ctdb_reply_control *reply,
+                                           uint32_t *db_id);
+
+void ctdb_req_control_update_record(struct ctdb_req_control *request,
+                                   struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_update_record(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_send_gratuitous_arp(struct ctdb_req_control *request,
+                                         struct ctdb_addr_info *addr_info);
+int ctdb_reply_control_send_gratuitous_arp(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_transaction_start(struct ctdb_req_control *request,
+                                       uint32_t tid);
+int ctdb_reply_control_transaction_start(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_transaction_commit(struct ctdb_req_control *request,
+                                        uint32_t tid);
+int ctdb_reply_control_transaction_commit(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_wipe_database(struct ctdb_req_control *request,
+                                   struct ctdb_transdb *transdb);
+int ctdb_reply_control_wipe_database(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_uptime(struct ctdb_req_control *request);
+int ctdb_reply_control_uptime(struct ctdb_reply_control *reply,
+                             TALLOC_CTX *mem_ctx,
+                             struct ctdb_uptime **uptime);
+
+void ctdb_req_control_start_recovery(struct ctdb_req_control *request);
+int ctdb_reply_control_start_recovery(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_end_recovery(struct ctdb_req_control *request);
+int ctdb_reply_control_end_recovery(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_reload_nodes_file(struct ctdb_req_control *request);
+int ctdb_reply_control_reload_nodes_file(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_try_delete_records(struct ctdb_req_control *request,
+                                        struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_try_delete_records(struct ctdb_reply_control *reply,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct ctdb_rec_buffer **recbuf);
+
+void ctdb_req_control_enable_monitor(struct ctdb_req_control *request);
+int ctdb_reply_control_enable_monitor(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_disable_monitor(struct ctdb_req_control *request);
+int ctdb_reply_control_disable_monitor(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_add_public_ip(struct ctdb_req_control *request,
+                                   struct ctdb_addr_info *addr_info);
+int ctdb_reply_control_add_public_ip(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_del_public_ip(struct ctdb_req_control *request,
+                                   struct ctdb_addr_info *addr_info);
+int ctdb_reply_control_del_public_ip(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_run_eventscripts(struct ctdb_req_control *request,
+                                      const char *event_str);
+int ctdb_reply_control_run_eventscripts(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_capabilities(struct ctdb_req_control *request);
+int ctdb_reply_control_get_capabilities(struct ctdb_reply_control *reply,
+                                       uint32_t *caps);
+
+void ctdb_req_control_recd_ping(struct ctdb_req_control *request);
+int ctdb_reply_control_recd_ping(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_release_ip(struct ctdb_req_control *request,
+                                struct ctdb_public_ip *pubip);
+int ctdb_reply_control_release_ip(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_takeover_ip(struct ctdb_req_control *request,
+                                 struct ctdb_public_ip *pubip);
+int ctdb_reply_control_takeover_ip(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_public_ips(struct ctdb_req_control *request);
+int ctdb_reply_control_get_public_ips(struct ctdb_reply_control *reply,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct ctdb_public_ip_list **pubip_list);
+
+void ctdb_req_control_get_nodemap(struct ctdb_req_control *request);
+int ctdb_reply_control_get_nodemap(struct ctdb_reply_control *reply,
+                                  TALLOC_CTX *mem_ctx,
+                                  struct ctdb_node_map **nodemap);
+
+void ctdb_req_control_get_event_script_status(struct ctdb_req_control *request,
+                                             uint32_t event);
+int ctdb_reply_control_get_event_script_status(struct ctdb_reply_control *reply,
+                                              TALLOC_CTX *mem_ctx,
+                                              struct ctdb_script_list **script_list);
+
+void ctdb_req_control_traverse_kill(struct ctdb_req_control *request,
+                                   struct ctdb_traverse_start *traverse);
+int ctdb_reply_control_traverse_kill(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_recd_reclock_latency(struct ctdb_req_control *request,
+                                          double reclock_latency);
+int ctdb_reply_control_recd_reclock_latency(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_reclock_file(struct ctdb_req_control *request);
+int ctdb_reply_control_get_reclock_file(struct ctdb_reply_control *reply,
+                                       TALLOC_CTX *mem_ctx,
+                                       const char **reclock_file);
+
+void ctdb_req_control_set_reclock_file(struct ctdb_req_control *request,
+                                      const char *reclock_file);
+int ctdb_reply_control_set_reclock_file(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_stop_node(struct ctdb_req_control *request);
+int ctdb_reply_control_stop_node(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_continue_node(struct ctdb_req_control *request);
+int ctdb_reply_control_continue_node(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_natgwstate(struct ctdb_req_control *request,
+                                    uint32_t natgw_role);
+int ctdb_reply_control_set_natgwstate(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_lmasterrole(struct ctdb_req_control *request,
+                                     uint32_t lmaster_role);
+int ctdb_reply_control_set_lmasterrole(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_recmasterrole(struct ctdb_req_control *request,
+                                       uint32_t recmaster_role);
+int ctdb_reply_control_set_recmasterrole(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_enable_script(struct ctdb_req_control *request,
+                                   const char *script);
+int ctdb_reply_control_enable_script(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_disable_script(struct ctdb_req_control *request,
+                                    const char *script);
+int ctdb_reply_control_disable_script(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_ban_state(struct ctdb_req_control *request,
+                                   struct ctdb_ban_state *ban_state);
+int ctdb_reply_control_set_ban_state(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_ban_state(struct ctdb_req_control *request);
+int ctdb_reply_control_get_ban_state(struct ctdb_reply_control *reply,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct ctdb_ban_state **ban_state);
+
+void ctdb_req_control_set_db_priority(struct ctdb_req_control *request,
+                                     struct ctdb_db_priority *db_prio);
+int ctdb_reply_control_set_db_priority(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_db_priority(struct ctdb_req_control *request,
+                                     uint32_t db_id);
+int ctdb_reply_control_get_db_priority(struct ctdb_reply_control *reply,
+                                      uint32_t *priority);
+
+void ctdb_req_control_transaction_cancel(struct ctdb_req_control *request,
+                                        uint32_t tid);
+int ctdb_reply_control_transaction_cancel(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_register_notify(struct ctdb_req_control *request,
+                                     struct ctdb_notify_data *notify);
+int ctdb_reply_control_register_notify(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_deregister_notify(struct ctdb_req_control *request,
+                                       uint64_t srvid);
+int ctdb_reply_control_deregister_notify(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_trans3_commit(struct ctdb_req_control *request,
+                                   struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_trans3_commit(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_db_seqnum(struct ctdb_req_control *request,
+                                   uint32_t db_id);
+int ctdb_reply_control_get_db_seqnum(struct ctdb_reply_control *reply,
+                                    uint64_t *seqnum);
+
+void ctdb_req_control_db_set_healthy(struct ctdb_req_control *request,
+                                    uint32_t db_id);
+int ctdb_reply_control_db_set_healthy(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_db_get_health(struct ctdb_req_control *request,
+                                   uint32_t db_id);
+int ctdb_reply_control_db_get_health(struct ctdb_reply_control *reply,
+                                    TALLOC_CTX *mem_ctx,
+                                    const char **reason);
+
+void ctdb_req_control_get_public_ip_info(struct ctdb_req_control *request,
+                                        ctdb_sock_addr *addr);
+int ctdb_reply_control_get_public_ip_info(struct ctdb_reply_control *reply,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct ctdb_public_ip_info **ipinfo);
+
+void ctdb_req_control_get_ifaces(struct ctdb_req_control *request);
+int ctdb_reply_control_get_ifaces(struct ctdb_reply_control *reply,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct ctdb_iface_list **iface_list);
+
+void ctdb_req_control_set_iface_link_state(struct ctdb_req_control *request,
+                                          struct ctdb_iface *iface);
+int ctdb_reply_control_set_iface_link_state(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_tcp_add_delayed_update(struct ctdb_req_control *request,
+                                            struct ctdb_connection *conn);
+int ctdb_reply_control_tcp_add_delayed_update(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_stat_history(struct ctdb_req_control *request);
+int ctdb_reply_control_get_stat_history(struct ctdb_reply_control *reply,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct ctdb_statistics_list **stats_list);
+
+void ctdb_req_control_schedule_for_deletion(struct ctdb_req_control *request,
+                                           struct ctdb_key_data *key);
+int ctdb_reply_control_schedule_for_deletion(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_set_db_readonly(struct ctdb_req_control *request,
+                                     uint32_t db_id);
+int ctdb_reply_control_set_db_readonly(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_check_srvids(struct ctdb_req_control *request,
+                                  struct ctdb_uint64_array *u64_array);
+int ctdb_reply_control_check_srvids(struct ctdb_reply_control *reply,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct ctdb_uint8_array **u8_array);
+
+void ctdb_req_control_traverse_start_ext(struct ctdb_req_control *request,
+                                        struct ctdb_traverse_start_ext *traverse);
+int ctdb_reply_control_traverse_start_ext(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_db_statistics(struct ctdb_req_control *request,
+                                       uint32_t db_id);
+int ctdb_reply_control_get_db_statistics(struct ctdb_reply_control *reply,
+                                        TALLOC_CTX *mem_ctx,
+                                        struct ctdb_db_statistics **dbstats);
+
+void ctdb_req_control_set_db_sticky(struct ctdb_req_control *request,
+                                   uint32_t db_id);
+int ctdb_reply_control_set_db_sticky(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_reload_public_ips(struct ctdb_req_control *request);
+int ctdb_reply_control_reload_public_ips(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_receive_records(struct ctdb_req_control *request,
+                                     struct ctdb_rec_buffer *recbuf);
+int ctdb_reply_control_receive_records(struct ctdb_reply_control *reply,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct ctdb_rec_buffer **recbuf);
+
+void ctdb_req_control_ipreallocated(struct ctdb_req_control *request);
+int ctdb_reply_control_ipreallocated(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_runstate(struct ctdb_req_control *request);
+int ctdb_reply_control_get_runstate(struct ctdb_reply_control *reply,
+                                   enum ctdb_runstate *runstate);
+
+void ctdb_req_control_db_detach(struct ctdb_req_control *request,
+                               uint32_t db_id);
+int ctdb_reply_control_db_detach(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_get_nodes_file(struct ctdb_req_control *request);
+int ctdb_reply_control_get_nodes_file(struct ctdb_reply_control *reply,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct ctdb_node_map **nodemap);
+
+/* From protocol/protocol_message.c */
+
+int ctdb_req_message_push(struct ctdb_req_header *h,
+                         struct ctdb_req_message *c,
+                         TALLOC_CTX *mem_ctx,
+                         uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_message_pull(uint8_t *pkt, size_t pkt_len,
+                         struct ctdb_req_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_req_message *c);
+
+int ctdb_req_message_data_push(struct ctdb_req_header *h,
+                              struct ctdb_req_message_data *message,
+                              TALLOC_CTX *mem_ctx,
+                              uint8_t **pkt, size_t *pkt_len);
+
+int ctdb_req_message_data_pull(uint8_t *pkt, size_t pkt_len,
+                              struct ctdb_req_header *h,
+                              TALLOC_CTX *mem_ctx,
+                              struct ctdb_req_message_data *message);
+
+/* From protocol/protocol_util.c */
+
+const char *ctdb_runstate_to_string(enum ctdb_runstate runstate);
+enum ctdb_runstate ctdb_runstate_from_string(const char *runstate_str);
+
+const char *ctdb_event_to_string(enum ctdb_event event);
+enum ctdb_event ctdb_event_from_string(const char *event_str);
+
+#endif /* __CTDB_PROTOCOL_API_H__ */
diff --git a/ctdb/protocol/protocol_call.c b/ctdb/protocol/protocol_call.c
new file mode 100644 (file)
index 0000000..e0f38d9
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+#include "protocol_private.h"
+
+struct ctdb_req_call_wire {
+       struct ctdb_req_header hdr;
+       uint32_t flags;
+       uint32_t db_id;
+       uint32_t callid;
+       uint32_t hopcount;
+       uint32_t keylen;
+       uint32_t calldatalen;
+       uint8_t data[1]; /* key[] followed by calldata[] */
+};
+
+struct ctdb_reply_call_wire {
+       struct ctdb_req_header hdr;
+       uint32_t status;
+       uint32_t datalen;
+       uint8_t  data[1];
+};
+
+struct ctdb_reply_error_wire {
+       struct ctdb_req_header hdr;
+       uint32_t status;
+       uint32_t msglen;
+       uint8_t  msg[1];
+};
+
+struct ctdb_req_dmaster_wire {
+       struct ctdb_req_header hdr;
+       uint32_t db_id;
+       uint64_t rsn;
+       uint32_t dmaster;
+       uint32_t keylen;
+       uint32_t datalen;
+       uint8_t  data[1];
+};
+
+struct ctdb_reply_dmaster_wire {
+       struct ctdb_req_header hdr;
+       uint32_t db_id;
+       uint64_t rsn;
+       uint32_t keylen;
+       uint32_t datalen;
+       uint8_t  data[1];
+};
+
+int ctdb_req_call_push(struct ctdb_req_header *h, struct ctdb_req_call *c,
+                      TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_req_call_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen;
+       int ret;
+
+       if (c->key.dsize == 0) {
+               return EINVAL;
+       }
+
+       length = offsetof(struct ctdb_req_call_wire, data) +
+                c->key.dsize + c->calldata.dsize;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_req_call_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->flags = c->flags;
+       wire->db_id = c->db_id;
+       wire->callid = c->callid;
+       wire->hopcount = c->hopcount;
+       wire->keylen = c->key.dsize;
+       wire->calldatalen = c->calldata.dsize;
+       memcpy(wire->data, c->key.dptr, c->key.dsize);
+       if (c->calldata.dsize > 0) {
+               memcpy(wire->data + c->key.dsize, c->calldata.dptr,
+                      c->calldata.dsize);
+       }
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_req_call_pull(uint8_t *pkt, size_t pkt_len,
+                      struct ctdb_req_header *h,
+                      TALLOC_CTX *mem_ctx,
+                      struct ctdb_req_call *c)
+{
+       struct ctdb_req_call_wire *wire;
+       size_t length;
+
+       length = offsetof(struct ctdb_req_call_wire, data);
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+
+       wire = (struct ctdb_req_call_wire *)pkt;
+
+       if (pkt_len < length + wire->keylen + wire->calldatalen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       c->flags = wire->flags;
+       c->db_id = wire->db_id;
+       c->callid = wire->callid;
+       c->hopcount = wire->hopcount;
+       c->key.dsize = wire->keylen;
+       c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen);
+       if (c->key.dptr == NULL) {
+               return ENOMEM;
+       }
+       c->calldata.dsize = wire->calldatalen;
+       if (wire->calldatalen > 0) {
+               c->calldata.dptr = talloc_memdup(mem_ctx,
+                                                wire->data + wire->keylen,
+                                                wire->calldatalen);
+               if (c->calldata.dptr == NULL) {
+                       talloc_free(c->key.dptr);
+                       return ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+int ctdb_reply_call_push(struct ctdb_req_header *h, struct ctdb_reply_call *c,
+                        TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_reply_call_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen;
+       int ret;
+
+       length = offsetof(struct ctdb_reply_call_wire, data) + c->data.dsize;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_reply_call_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->status = c->status;
+       wire->datalen = c->data.dsize;
+       if (c->data.dsize > 0) {
+               memcpy(wire->data, c->data.dptr, c->data.dsize);
+       }
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_reply_call_pull(uint8_t *pkt, size_t pkt_len,
+                        struct ctdb_req_header *h,
+                        TALLOC_CTX *mem_ctx,
+                        struct ctdb_reply_call *c)
+{
+       struct ctdb_reply_call_wire *wire;
+       size_t length;
+
+       length = offsetof(struct ctdb_reply_call_wire, data);
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+
+       wire = (struct ctdb_reply_call_wire *)pkt;
+
+       if (pkt_len < length + wire->datalen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       c->status = wire->status;
+       c->data.dsize = wire->datalen;
+       if (wire->datalen > 0) {
+               c->data.dptr = talloc_memdup(mem_ctx, wire->data,
+                                            wire->datalen);
+               if (c->data.dptr == NULL) {
+                       return ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+int ctdb_reply_error_push(struct ctdb_req_header *h, struct ctdb_reply_error *c,
+                         TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_reply_error_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen;
+       int ret;
+
+       length = offsetof(struct ctdb_reply_error_wire, msg) + c->msg.dsize;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_reply_error_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->status = c->status;
+       wire->msglen = c->msg.dsize;
+       if (c->msg.dsize > 0) {
+               memcpy(wire->msg, c->msg.dptr, c->msg.dsize);
+       }
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_reply_error_pull(uint8_t *pkt, size_t pkt_len,
+                         struct ctdb_req_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_reply_error *c)
+{
+       struct ctdb_reply_error_wire *wire;
+       size_t length;
+
+       length = offsetof(struct ctdb_reply_error_wire, msg);
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+
+       wire = (struct ctdb_reply_error_wire *)pkt;
+
+       if (pkt_len < length + wire->msglen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       c->status = wire->status;
+       c->msg.dsize = wire->msglen;
+       if (wire->msglen > 0) {
+               c->msg.dptr = talloc_memdup(mem_ctx, wire->msg, wire->msglen);
+               if (c->msg.dptr == NULL) {
+                       return ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+int ctdb_req_dmaster_push(struct ctdb_req_header *h, struct ctdb_req_dmaster *c,
+                         TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_req_dmaster_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen;
+       int ret;
+
+       length = offsetof(struct ctdb_req_dmaster_wire, data) +
+                c->key.dsize + c->data.dsize;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_req_dmaster_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->db_id = c->db_id;
+       wire->rsn = c->rsn;
+       wire->dmaster = c->dmaster;
+       wire->keylen = c->key.dsize;
+       if (c->key.dsize > 0) {
+               memcpy(wire->data, c->key.dptr, c->key.dsize);
+       }
+       wire->datalen = c->data.dsize;
+       if (c->data.dsize > 0) {
+               memcpy(wire->data + c->key.dsize, c->data.dptr, c->data.dsize);
+       }
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_req_dmaster_pull(uint8_t *pkt, size_t pkt_len,
+                         struct ctdb_req_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_req_dmaster *c)
+{
+       struct ctdb_req_dmaster_wire *wire;
+       size_t length;
+
+       length = offsetof(struct ctdb_req_dmaster_wire, data);
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+
+       wire = (struct ctdb_req_dmaster_wire *)pkt;
+
+       if (pkt_len < length + wire->keylen + wire->datalen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       c->db_id = wire->db_id;
+       c->rsn = wire->rsn;
+       c->dmaster = wire->dmaster;
+       c->key.dsize = wire->keylen;
+       c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen);
+       if (c->key.dptr == NULL) {
+               return ENOMEM;
+       }
+       c->data.dsize = wire->datalen;
+       if (wire->datalen > 0) {
+               c->data.dptr = talloc_memdup(mem_ctx, wire->data + wire->keylen,
+                                            wire->datalen);
+               if (c->data.dptr == NULL) {
+                       talloc_free(c->key.dptr);
+                       return ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+int ctdb_reply_dmaster_push(struct ctdb_req_header *h,
+                           struct ctdb_reply_dmaster *c,
+                           TALLOC_CTX *mem_ctx, uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_reply_dmaster_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen;
+       int ret;
+
+       length = offsetof(struct ctdb_reply_dmaster_wire, data) +
+                c->key.dsize + c->data.dsize;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_reply_dmaster_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->db_id = c->db_id;
+       wire->rsn = c->rsn;
+       wire->keylen = c->key.dsize;
+       if (c->key.dsize > 0) {
+               memcpy(wire->data, c->key.dptr, c->key.dsize);
+       }
+       wire->datalen = c->data.dsize;
+       if (c->data.dsize > 0) {
+               memcpy(wire->data + c->key.dsize, c->data.dptr, c->data.dsize);
+       }
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_reply_dmaster_pull(uint8_t *pkt, size_t pkt_len,
+                           struct ctdb_req_header *h,
+                           TALLOC_CTX *mem_ctx,
+                           struct ctdb_reply_dmaster *c)
+{
+       struct ctdb_reply_dmaster_wire *wire;
+       size_t length;
+
+       length = offsetof(struct ctdb_reply_dmaster_wire, data);
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+
+       wire = (struct ctdb_reply_dmaster_wire *)pkt;
+
+       if (pkt_len < length + wire->keylen + wire->datalen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       c->db_id = wire->db_id;
+       c->rsn = wire->rsn;
+       c->key.dsize = wire->keylen;
+       c->key.dptr = talloc_memdup(mem_ctx, wire->data, wire->keylen);
+       if (c->key.dptr == NULL) {
+               return ENOMEM;
+       }
+       c->data.dsize = wire->datalen;
+       if (wire->datalen > 0) {
+               c->data.dptr = talloc_memdup(mem_ctx, wire->data + wire->keylen,
+                                            wire->datalen);
+               if (c->data.dptr == NULL) {
+                       talloc_free(c->key.dptr);
+                       return ENOMEM;
+               }
+       }
+
+       return 0;
+}
diff --git a/ctdb/protocol/protocol_client.c b/ctdb/protocol/protocol_client.c
new file mode 100644 (file)
index 0000000..f4bfe19
--- /dev/null
@@ -0,0 +1,2370 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+#include "protocol_private.h"
+
+/*
+void ctdb_req_call_fill(struct ctdb_req_call *c,
+                       uint32_t db_id, uint32_t flags,
+                       uint32_t call_id, TDB_DATA key)
+{
+       request->flags = flags;
+       c->db_id = db_id;
+       c->call_id = call_id;
+       c->key = key;
+       c->calldata = tdb_null;
+}
+*/
+
+static int ctdb_reply_control_generic(struct ctdb_reply_control *reply)
+{
+       return reply->status;
+}
+
+/* CTDB_CONTROL_PROCESS_EXISTS */
+
+void ctdb_req_control_process_exists(struct ctdb_req_control *request,
+                                    pid_t pid)
+{
+       request->opcode = CTDB_CONTROL_PROCESS_EXISTS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_PROCESS_EXISTS;
+       request->rdata.data.pid = pid;
+
+}
+
+int ctdb_reply_control_process_exists(struct ctdb_reply_control *reply,
+                                     int *status)
+{
+       if (reply->rdata.opcode == CTDB_CONTROL_PROCESS_EXISTS) {
+               *status = reply->status;
+               reply->status = 0;
+
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_STATISTICS */
+
+void ctdb_req_control_statistics(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_STATISTICS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_STATISTICS;
+}
+
+int ctdb_reply_control_statistics(struct ctdb_reply_control *reply,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct ctdb_statistics **stats)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_STATISTICS) {
+               *stats = talloc_steal(mem_ctx, reply->rdata.data.stats);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_PING */
+
+void ctdb_req_control_ping(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_PING;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_PING;
+}
+
+int ctdb_reply_control_ping(struct ctdb_reply_control *reply,
+                           int *num_clients)
+{
+       if (reply->status >= 0) {
+               *num_clients = reply->status;
+               reply->status = 0;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GETDBPATH */
+
+void ctdb_req_control_getdbpath(struct ctdb_req_control *request,
+                               uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_GETDBPATH;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GETDBPATH;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_getdbpath(struct ctdb_reply_control *reply,
+                                TALLOC_CTX *mem_ctx, const char **db_path)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GETDBPATH) {
+               *db_path = talloc_steal(mem_ctx, reply->rdata.data.db_path);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GETVNNMAP */
+
+void ctdb_req_control_getvnnmap(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GETVNNMAP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GETVNNMAP;
+}
+
+int ctdb_reply_control_getvnnmap(struct ctdb_reply_control *reply,
+                                TALLOC_CTX *mem_ctx,
+                                struct ctdb_vnn_map **vnnmap)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GETVNNMAP) {
+               *vnnmap = talloc_steal(mem_ctx, reply->rdata.data.vnnmap);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SETVNNMAP */
+
+void ctdb_req_control_setvnnmap(struct ctdb_req_control *request,
+                               struct ctdb_vnn_map *vnnmap)
+{
+       request->opcode = CTDB_CONTROL_SETVNNMAP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SETVNNMAP;
+       request->rdata.data.vnnmap = vnnmap;
+}
+
+int ctdb_reply_control_setvnnmap(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DEBUG */
+
+void ctdb_req_control_get_debug(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_DEBUG;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_DEBUG;
+}
+
+int ctdb_reply_control_get_debug(struct ctdb_reply_control *reply,
+                                uint32_t *loglevel)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_DEBUG) {
+               *loglevel = reply->rdata.data.loglevel;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_DEBUG */
+
+void ctdb_req_control_set_debug(struct ctdb_req_control *request,
+                               uint32_t loglevel)
+{
+       request->opcode = CTDB_CONTROL_SET_DEBUG;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_DEBUG;
+       request->rdata.data.loglevel = loglevel;
+}
+
+int ctdb_reply_control_set_debug(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DBMAP */
+
+void ctdb_req_control_get_dbmap(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_DBMAP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_DBMAP;
+}
+
+int ctdb_reply_control_get_dbmap(struct ctdb_reply_control *reply,
+                                TALLOC_CTX *mem_ctx,
+                                struct ctdb_dbid_map **dbmap)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_DBMAP) {
+               *dbmap = talloc_steal(mem_ctx, reply->rdata.data.dbmap);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_PULL_DB */
+
+void ctdb_req_control_pull_db(struct ctdb_req_control *request,
+                             struct ctdb_pulldb *pulldb)
+{
+       request->opcode = CTDB_CONTROL_PULL_DB;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_PULL_DB;
+       request->rdata.data.pulldb = pulldb;
+}
+
+int ctdb_reply_control_pull_db(struct ctdb_reply_control *reply,
+                              TALLOC_CTX *mem_ctx,
+                              struct ctdb_rec_buffer **recbuf)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_PULL_DB) {
+               *recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_PUSH_DB */
+
+void ctdb_req_control_push_db(struct ctdb_req_control *request,
+                             struct ctdb_rec_buffer *recbuf)
+{
+       request->opcode = CTDB_CONTROL_PUSH_DB;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_PUSH_DB;
+       request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_push_db(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_RECMODE */
+
+void ctdb_req_control_get_recmode(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_RECMODE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_RECMODE;
+}
+
+int ctdb_reply_control_get_recmode(struct ctdb_reply_control *reply,
+                                  int *recmode)
+{
+       if (reply->status >= 0) {
+               *recmode = reply->status;
+               reply->status = 0;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_RECMODE */
+
+void ctdb_req_control_set_recmode(struct ctdb_req_control *request,
+                                 int recmode)
+{
+       request->opcode = CTDB_CONTROL_SET_RECMODE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_RECMODE;
+       request->rdata.data.recmode = recmode;
+}
+
+int ctdb_reply_control_set_recmode(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_STATISTICS_RESET */
+
+void ctdb_req_control_statistics_reset(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_STATISTICS_RESET;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_STATISTICS_RESET;
+}
+
+int ctdb_reply_control_statistics_reset(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DB_ATTACH */
+
+void ctdb_req_control_db_attach(struct ctdb_req_control *request,
+                               const char *db_name, uint32_t tdb_flags)
+{
+       request->opcode = CTDB_CONTROL_DB_ATTACH;
+       request->pad = 0;
+       request->srvid = tdb_flags;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DB_ATTACH;
+       request->rdata.data.db_name = db_name;
+}
+
+int ctdb_reply_control_db_attach(struct ctdb_reply_control *reply,
+                                uint32_t *db_id)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_DB_ATTACH) {
+               *db_id = reply->rdata.data.db_id;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_CALL */
+
+/* CTDB_CONTROL_TRAVERSE_START */
+
+void ctdb_req_control_traverse_start(struct ctdb_req_control *request,
+                                    struct ctdb_traverse_start *traverse)
+{
+       request->opcode = CTDB_CONTROL_TRAVERSE_START;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TRAVERSE_START;
+       request->rdata.data.traverse_start = traverse;
+}
+
+int ctdb_reply_control_traverse_start(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRAVERSE_ALL */
+/* CTDB_CONTROL_TRAVERSE_DATA */
+
+/* CTDB_CONTROL_REGISTER_SRVID */
+
+void ctdb_req_control_register_srvid(struct ctdb_req_control *request,
+                                    uint64_t srvid)
+{
+       request->opcode = CTDB_CONTROL_REGISTER_SRVID;
+       request->pad = 0;
+       request->srvid = srvid;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_REGISTER_SRVID;
+}
+
+int ctdb_reply_control_register_srvid(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DEREGISTER_SRVID */
+
+void ctdb_req_control_deregister_srvid(struct ctdb_req_control *request,
+                                      uint64_t srvid)
+{
+       request->opcode = CTDB_CONTROL_DEREGISTER_SRVID;
+       request->pad = 0;
+       request->srvid = srvid;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DEREGISTER_SRVID;
+}
+
+int ctdb_reply_control_deregister_srvid(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DBNAME */
+
+void ctdb_req_control_get_dbname(struct ctdb_req_control *request,
+                                uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_GET_DBNAME;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_DBNAME;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_get_dbname(struct ctdb_reply_control *reply,
+                                 TALLOC_CTX *mem_ctx, const char **db_name)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_DBNAME) {
+               *db_name = talloc_steal(mem_ctx, reply->rdata.data.db_name);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_ENABLE_SEQNUM */
+
+void ctdb_req_control_enable_seqnum(struct ctdb_req_control *request,
+                                   uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_ENABLE_SEQNUM;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_ENABLE_SEQNUM;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_enable_seqnum(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_UPDATE_SEQNUM */
+
+void ctdb_req_control_update_seqnum(struct ctdb_req_control *request,
+                                   uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_UPDATE_SEQNUM;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_UPDATE_SEQNUM;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_update_seqnum(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DUMP_MEMORY */
+
+void ctdb_req_control_dump_memory(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_DUMP_MEMORY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DUMP_MEMORY;
+}
+
+int ctdb_reply_control_dump_memory(struct ctdb_reply_control *reply,
+                                  TALLOC_CTX *mem_ctx, const char **mem_str)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_DUMP_MEMORY) {
+               *mem_str = talloc_steal(mem_ctx, reply->rdata.data.mem_str);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GET_PID */
+
+void ctdb_req_control_get_pid(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_PID;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_PID;
+}
+
+int ctdb_reply_control_get_pid(struct ctdb_reply_control *reply,
+                              pid_t *pid)
+{
+       if (reply->rdata.opcode == CTDB_CONTROL_GET_PID) {
+               *pid = reply->status;
+               reply->status = 0;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GET_RECMASTER */
+
+void ctdb_req_control_get_recmaster(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_RECMASTER;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_RECMASTER;
+}
+
+int ctdb_reply_control_get_recmaster(struct ctdb_reply_control *reply,
+                                    uint32_t *recmaster)
+{
+       if (reply->rdata.opcode == CTDB_CONTROL_GET_RECMASTER) {
+               *recmaster = reply->status;
+               reply->status = 0;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_RECMASTER */
+
+void ctdb_req_control_set_recmaster(struct ctdb_req_control *request,
+                                   int recmaster)
+{
+       request->opcode = CTDB_CONTROL_SET_RECMASTER;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_RECMASTER;
+       request->rdata.data.recmaster = recmaster;
+}
+
+int ctdb_reply_control_set_recmaster(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_FREEZE */
+
+void ctdb_req_control_freeze(struct ctdb_req_control *request,
+                            uint32_t priority)
+{
+       request->opcode = CTDB_CONTROL_FREEZE;
+       request->pad = 0;
+       request->srvid = priority;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_FREEZE;
+}
+
+int ctdb_reply_control_freeze(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_THAW */
+
+void ctdb_req_control_thaw(struct ctdb_req_control *request,
+                          uint32_t priority)
+{
+       request->opcode = CTDB_CONTROL_THAW;
+       request->pad = 0;
+       request->srvid = priority;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_THAW;
+}
+
+int ctdb_reply_control_thaw(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_PNN */
+
+void ctdb_req_control_get_pnn(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_PNN;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_PNN;
+}
+
+int ctdb_reply_control_get_pnn(struct ctdb_reply_control *reply,
+                              uint32_t *pnn)
+{
+       if (reply->status >= 0) {
+               *pnn = reply->status;
+               reply->status = 0;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SHUTDOWN */
+
+void ctdb_req_control_shutdown(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_SHUTDOWN;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SHUTDOWN;
+}
+
+int ctdb_reply_control_shutdown(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_MONMODE */
+
+void ctdb_req_control_get_monmode(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_MONMODE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_MONMODE;
+}
+
+int ctdb_reply_control_get_monmode(struct ctdb_reply_control *reply,
+                                  int *mon_mode)
+{
+       if (reply->status >= 0) {
+               *mon_mode = reply->status;
+               reply->status = 0;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_TCP_CLIENT */
+
+void ctdb_req_control_tcp_client(struct ctdb_req_control *request,
+                                struct ctdb_connection *conn)
+{
+       request->opcode = CTDB_CONTROL_TCP_CLIENT;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TCP_CLIENT;
+       request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_tcp_client(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TCP_ADD */
+
+void ctdb_req_control_tcp_add(struct ctdb_req_control *request,
+                             struct ctdb_connection *conn)
+{
+       request->opcode = CTDB_CONTROL_TCP_ADD;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TCP_ADD;
+       request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_tcp_add(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TCP_REMOVE */
+
+void ctdb_req_control_tcp_remove(struct ctdb_req_control *request,
+                                struct ctdb_connection *conn)
+{
+       request->opcode = CTDB_CONTROL_TCP_REMOVE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TCP_REMOVE;
+       request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_tcp_remove(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_STARTUP */
+
+void ctdb_req_control_startup(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_STARTUP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_STARTUP;
+}
+
+int ctdb_reply_control_startup(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_TUNABLE */
+
+void ctdb_req_control_set_tunable(struct ctdb_req_control *request,
+                                 struct ctdb_tunable *tunable)
+{
+       request->opcode = CTDB_CONTROL_SET_TUNABLE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_TUNABLE;
+       request->rdata.data.tunable = tunable;
+}
+
+int ctdb_reply_control_set_tunable(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_TUNABLE */
+
+void ctdb_req_control_get_tunable(struct ctdb_req_control *request,
+                                 const char *name)
+{
+       request->opcode = CTDB_CONTROL_GET_TUNABLE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_TUNABLE;
+       request->rdata.data.tun_var = discard_const(name);
+}
+
+int ctdb_reply_control_get_tunable(struct ctdb_reply_control *reply,
+                                  uint32_t *value)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_TUNABLE) {
+               *value = reply->rdata.data.tun_value;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_LIST_TUNABLES */
+
+void ctdb_req_control_list_tunables(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_LIST_TUNABLES;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_LIST_TUNABLES;
+}
+
+int ctdb_reply_control_list_tunables(struct ctdb_reply_control *reply,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct ctdb_var_list **tun_var_list)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_LIST_TUNABLES) {
+               *tun_var_list = talloc_steal(mem_ctx,
+                                            reply->rdata.data.tun_var_list);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_MODIFY_FLAGS */
+
+void ctdb_req_control_modify_flags(struct ctdb_req_control *request,
+                                  struct ctdb_node_flag_change *flag_change)
+{
+       request->opcode = CTDB_CONTROL_MODIFY_FLAGS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_MODIFY_FLAGS;
+       request->rdata.data.flag_change = flag_change;
+}
+
+int ctdb_reply_control_modify_flags(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_ALL_TUNABLES */
+
+void ctdb_req_control_get_all_tunables(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_ALL_TUNABLES;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_ALL_TUNABLES;
+}
+
+int ctdb_reply_control_get_all_tunables(struct ctdb_reply_control *reply,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct ctdb_tunable_list **tun_list)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_ALL_TUNABLES) {
+               *tun_list = talloc_steal(mem_ctx, reply->rdata.data.tun_list);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_KILL_TCP */
+
+void ctdb_req_control_kill_tcp(struct ctdb_req_control *request,
+                              struct ctdb_connection *conn)
+{
+       request->opcode = CTDB_CONTROL_KILL_TCP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_KILL_TCP;
+       request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_kill_tcp(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_TCP_TICKLE_LIST */
+
+void ctdb_req_control_get_tcp_tickle_list(struct ctdb_req_control *request,
+                                         ctdb_sock_addr *addr)
+{
+       request->opcode = CTDB_CONTROL_GET_TCP_TICKLE_LIST;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_TCP_TICKLE_LIST;
+       request->rdata.data.addr = addr;
+}
+
+int ctdb_reply_control_get_tcp_tickle_list(struct ctdb_reply_control *reply,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct ctdb_tickle_list **tickles)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_TCP_TICKLE_LIST) {
+               *tickles = talloc_steal(mem_ctx, reply->rdata.data.tickles);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_TCP_TICKLE_LIST */
+
+void ctdb_req_control_set_tcp_tickle_list(struct ctdb_req_control *request,
+                                         struct ctdb_tickle_list *tickles)
+{
+       request->opcode = CTDB_CONTROL_SET_TCP_TICKLE_LIST;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_TCP_TICKLE_LIST;
+       request->rdata.data.tickles = tickles;
+}
+
+int ctdb_reply_control_set_tcp_tickle_list(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_REGISTER_SERVER_ID */
+
+void ctdb_req_control_register_server_id(struct ctdb_req_control *request,
+                                        struct ctdb_client_id *cid)
+{
+       request->opcode = CTDB_CONTROL_REGISTER_SERVER_ID;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_REGISTER_SERVER_ID;
+       request->rdata.data.cid = cid;
+}
+
+int ctdb_reply_control_register_server_id(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_UNREGISTER_SERVER_ID */
+
+void ctdb_req_control_unregister_server_id(struct ctdb_req_control *request,
+                                          struct ctdb_client_id *cid)
+{
+       request->opcode = CTDB_CONTROL_UNREGISTER_SERVER_ID;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_UNREGISTER_SERVER_ID;
+       request->rdata.data.cid = cid;
+}
+
+int ctdb_reply_control_unregister_server_id(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_CHECK_SERVER_ID */
+
+void ctdb_req_control_check_server_id(struct ctdb_req_control *request,
+                                     struct ctdb_client_id *cid)
+{
+       request->opcode = CTDB_CONTROL_CHECK_SERVER_ID;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_CHECK_SERVER_ID;
+       request->rdata.data.cid = cid;
+}
+
+int ctdb_reply_control_check_server_id(struct ctdb_reply_control *reply)
+{
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GET_SERVER_ID_LIST */
+
+void ctdb_req_control_get_server_id_list(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_SERVER_ID_LIST;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_SERVER_ID_LIST;
+}
+
+int ctdb_reply_control_get_server_id_list(struct ctdb_reply_control *reply,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct ctdb_client_id_map **cid_map)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_SERVER_ID_LIST) {
+               *cid_map = talloc_steal(mem_ctx, reply->rdata.data.cid_map);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_DB_ATTACH_PERSISTENT */
+
+void ctdb_req_control_db_attach_persistent(struct ctdb_req_control *request,
+                                          const char *db_name,
+                                          uint32_t tdb_flags)
+{
+       request->opcode = CTDB_CONTROL_DB_ATTACH_PERSISTENT;
+       request->pad = 0;
+       request->srvid = tdb_flags;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DB_ATTACH_PERSISTENT;
+       request->rdata.data.db_name = db_name;
+}
+
+int ctdb_reply_control_db_attach_persistent(struct ctdb_reply_control *reply,
+                                           uint32_t *db_id)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_DB_ATTACH_PERSISTENT) {
+               *db_id = reply->rdata.data.db_id;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_UPDATE_RECORD */
+
+void ctdb_req_control_update_record(struct ctdb_req_control *request,
+                                   struct ctdb_rec_buffer *recbuf)
+{
+       request->opcode = CTDB_CONTROL_UPDATE_RECORD;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_UPDATE_RECORD;
+       request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_update_record(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SEND_GRATUITOUS_ARP */
+
+void ctdb_req_control_send_gratuitous_arp(struct ctdb_req_control *request,
+                                         struct ctdb_addr_info *addr_info)
+{
+       request->opcode = CTDB_CONTROL_SEND_GRATUITOUS_ARP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SEND_GRATUITOUS_ARP;
+       request->rdata.data.addr_info = addr_info;
+}
+
+int ctdb_reply_control_send_gratuitous_arp(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRANSACTION_START */
+
+void ctdb_req_control_transaction_start(struct ctdb_req_control *request,
+                                       uint32_t tid)
+{
+       request->opcode = CTDB_CONTROL_TRANSACTION_START;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TRANSACTION_START;
+       request->rdata.data.tid = tid;
+}
+
+int ctdb_reply_control_transaction_start(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRANSACTION_COMMIT */
+
+void ctdb_req_control_transaction_commit(struct ctdb_req_control *request,
+                                        uint32_t tid)
+{
+       request->opcode = CTDB_CONTROL_TRANSACTION_COMMIT;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TRANSACTION_COMMIT;
+       request->rdata.data.tid = tid;
+}
+
+int ctdb_reply_control_transaction_commit(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_WIPE_DATABASE */
+
+void ctdb_req_control_wipe_database(struct ctdb_req_control *request,
+                                   struct ctdb_transdb *transdb)
+{
+       request->opcode = CTDB_CONTROL_WIPE_DATABASE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_WIPE_DATABASE;
+       request->rdata.data.transdb = transdb;
+}
+
+int ctdb_reply_control_wipe_database(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_UPTIME */
+
+void ctdb_req_control_uptime(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_UPTIME;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_UPTIME;
+}
+
+int ctdb_reply_control_uptime(struct ctdb_reply_control *reply,
+                             TALLOC_CTX *mem_ctx, struct ctdb_uptime **uptime)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_UPTIME) {
+               *uptime = talloc_steal(mem_ctx, reply->rdata.data.uptime);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_START_RECOVERY */
+
+void ctdb_req_control_start_recovery(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_START_RECOVERY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_START_RECOVERY;
+}
+
+int ctdb_reply_control_start_recovery(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_END_RECOVERY */
+
+void ctdb_req_control_end_recovery(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_END_RECOVERY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_END_RECOVERY;
+}
+
+int ctdb_reply_control_end_recovery(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RELOAD_NODES_FILE */
+
+void ctdb_req_control_reload_nodes_file(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_RELOAD_NODES_FILE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_RELOAD_NODES_FILE;
+}
+
+int ctdb_reply_control_reload_nodes_file(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRY_DELETE_RECORDS */
+
+void ctdb_req_control_try_delete_records(struct ctdb_req_control *request,
+                                        struct ctdb_rec_buffer *recbuf)
+{
+       request->opcode = CTDB_CONTROL_TRY_DELETE_RECORDS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TRY_DELETE_RECORDS;
+       request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_try_delete_records(struct ctdb_reply_control *reply,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct ctdb_rec_buffer **recbuf)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_TRY_DELETE_RECORDS) {
+               *recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_ENABLE_MONITOR */
+
+void ctdb_req_control_enable_monitor(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_ENABLE_MONITOR;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_ENABLE_MONITOR;
+}
+
+int ctdb_reply_control_enable_monitor(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DISABLE_MONITOR */
+
+void ctdb_req_control_disable_monitor(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_DISABLE_MONITOR;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DISABLE_MONITOR;
+}
+
+int ctdb_reply_control_disable_monitor(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_ADD_PUBLIC_IP */
+
+void ctdb_req_control_add_public_ip(struct ctdb_req_control *request,
+                                   struct ctdb_addr_info *addr_info)
+{
+       request->opcode = CTDB_CONTROL_ADD_PUBLIC_IP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_ADD_PUBLIC_IP;
+       request->rdata.data.addr_info = addr_info;
+}
+
+int ctdb_reply_control_add_public_ip(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DEL_PUBLIC_IP */
+
+void ctdb_req_control_del_public_ip(struct ctdb_req_control *request,
+                                   struct ctdb_addr_info *addr_info)
+{
+       request->opcode = CTDB_CONTROL_DEL_PUBLIC_IP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DEL_PUBLIC_IP;
+       request->rdata.data.addr_info = addr_info;
+}
+
+int ctdb_reply_control_del_public_ip(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RUN_EVENTSCRIPTS */
+
+void ctdb_req_control_run_eventscripts(struct ctdb_req_control *request,
+                                      const char *event_str)
+{
+       request->opcode = CTDB_CONTROL_RUN_EVENTSCRIPTS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_RUN_EVENTSCRIPTS;
+       request->rdata.data.event_str = event_str;
+}
+
+int ctdb_reply_control_run_eventscripts(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_CAPABILITIES */
+
+void ctdb_req_control_get_capabilities(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_CAPABILITIES;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_CAPABILITIES;
+}
+
+int ctdb_reply_control_get_capabilities(struct ctdb_reply_control *reply,
+                                       uint32_t *caps)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_CAPABILITIES) {
+               *caps = reply->rdata.data.caps;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_RECD_PING */
+
+void ctdb_req_control_recd_ping(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_RECD_PING;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_RECD_PING;
+}
+
+int ctdb_reply_control_recd_ping(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RELEASE_IP */
+
+void ctdb_req_control_release_ip(struct ctdb_req_control *request,
+                                struct ctdb_public_ip *pubip)
+{
+       request->opcode = CTDB_CONTROL_RELEASE_IP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_RELEASE_IP;
+       request->rdata.data.pubip = pubip;
+}
+
+int ctdb_reply_control_release_ip(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TAKEOVER_IP */
+
+void ctdb_req_control_takeover_ip(struct ctdb_req_control *request,
+                                 struct ctdb_public_ip *pubip)
+{
+       request->opcode = CTDB_CONTROL_TAKEOVER_IP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TAKEOVER_IP;
+       request->rdata.data.pubip = pubip;
+}
+
+int ctdb_reply_control_takeover_ip(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_PUBLIC_IPS */
+
+void ctdb_req_control_get_public_ips(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_PUBLIC_IPS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_PUBLIC_IPS;
+}
+
+int ctdb_reply_control_get_public_ips(struct ctdb_reply_control *reply,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct ctdb_public_ip_list **pubip_list)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_PUBLIC_IPS) {
+               *pubip_list = talloc_steal(mem_ctx, reply->rdata.data.pubip_list);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GET_NODEMAP */
+
+void ctdb_req_control_get_nodemap(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_NODEMAP;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_NODEMAP;
+}
+
+int ctdb_reply_control_get_nodemap(struct ctdb_reply_control *reply,
+                                  TALLOC_CTX *mem_ctx,
+                                  struct ctdb_node_map **nodemap)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_NODEMAP) {
+               *nodemap = talloc_steal(mem_ctx, reply->rdata.data.nodemap);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS */
+
+void ctdb_req_control_get_event_script_status(struct ctdb_req_control *request,
+                                             uint32_t event)
+{
+       request->opcode = CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS;
+       request->rdata.data.event = event;
+}
+
+int ctdb_reply_control_get_event_script_status(struct ctdb_reply_control *reply,
+                                              TALLOC_CTX *mem_ctx,
+                                              struct ctdb_script_list **slist)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS) {
+               *slist = talloc_steal(mem_ctx, reply->rdata.data.script_list);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_TRAVERSE_KILL */
+
+void ctdb_req_control_traverse_kill(struct ctdb_req_control *request,
+                                   struct ctdb_traverse_start *traverse)
+{
+       request->opcode = CTDB_CONTROL_TRAVERSE_KILL;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TRAVERSE_KILL;
+       request->rdata.data.traverse_start = traverse;
+}
+
+int ctdb_reply_control_traverse_kill(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RECD_RECLOCK_LATENCY */
+
+void ctdb_req_control_recd_reclock_latency(struct ctdb_req_control *request,
+                                          double reclock_latency)
+{
+       request->opcode = CTDB_CONTROL_RECD_RECLOCK_LATENCY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_RECD_RECLOCK_LATENCY;
+       request->rdata.data.reclock_latency = reclock_latency;
+}
+
+int ctdb_reply_control_recd_reclock_latency(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_RECLOCK_FILE */
+
+void ctdb_req_control_get_reclock_file(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_RECLOCK_FILE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_RECLOCK_FILE;
+}
+
+int ctdb_reply_control_get_reclock_file(struct ctdb_reply_control *reply,
+                                       TALLOC_CTX *mem_ctx,
+                                       const char **reclock_file)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_RECLOCK_FILE) {
+               *reclock_file = talloc_steal(mem_ctx,
+                                            reply->rdata.data.reclock_file);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_RECLOCK_FILE */
+
+void ctdb_req_control_set_reclock_file(struct ctdb_req_control *request,
+                                      const char *reclock_file)
+{
+       request->opcode = CTDB_CONTROL_SET_RECLOCK_FILE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_RECLOCK_FILE;
+       request->rdata.data.reclock_file = reclock_file;
+}
+
+int ctdb_reply_control_set_reclock_file(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+
+/* CTDB_CONTROL_STOP_NODE */
+
+void ctdb_req_control_stop_node(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_STOP_NODE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_STOP_NODE;
+}
+
+int ctdb_reply_control_stop_node(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_CONTINUE_NODE */
+
+void ctdb_req_control_continue_node(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_CONTINUE_NODE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_CONTINUE_NODE;
+}
+
+int ctdb_reply_control_continue_node(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_NATGWSTATE */
+
+void ctdb_req_control_set_natgwstate(struct ctdb_req_control *request,
+                                    uint32_t natgw_role)
+{
+       request->opcode = CTDB_CONTROL_SET_NATGWSTATE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_NATGWSTATE;
+       request->rdata.data.role = natgw_role;
+}
+
+int ctdb_reply_control_set_natgwstate(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_LMASTERROLE */
+
+void ctdb_req_control_set_lmasterrole(struct ctdb_req_control *request,
+                                     uint32_t lmaster_role)
+{
+       request->opcode = CTDB_CONTROL_SET_LMASTERROLE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_LMASTERROLE;
+       request->rdata.data.role = lmaster_role;
+}
+
+int ctdb_reply_control_set_lmasterrole(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_RECMASTERROLE */
+
+void ctdb_req_control_set_recmasterrole(struct ctdb_req_control *request,
+                                       uint32_t recmaster_role)
+{
+       request->opcode = CTDB_CONTROL_SET_RECMASTERROLE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_RECMASTERROLE;
+       request->rdata.data.role = recmaster_role;
+}
+
+int ctdb_reply_control_set_recmasterrole(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_ENABLE_SCRIPT */
+
+void ctdb_req_control_enable_script(struct ctdb_req_control *request,
+                                   const char *script)
+{
+       request->opcode = CTDB_CONTROL_ENABLE_SCRIPT;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_ENABLE_SCRIPT;
+       request->rdata.data.script = script;
+}
+
+int ctdb_reply_control_enable_script(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DISABLE_SCRIPT */
+
+void ctdb_req_control_disable_script(struct ctdb_req_control *request,
+                                    const char *script)
+{
+       request->opcode = CTDB_CONTROL_DISABLE_SCRIPT;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DISABLE_SCRIPT;
+       request->rdata.data.script = script;
+}
+
+int ctdb_reply_control_disable_script(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_BAN_STATE */
+
+void ctdb_req_control_set_ban_state(struct ctdb_req_control *request,
+                                   struct ctdb_ban_state *ban_state)
+{
+       request->opcode = CTDB_CONTROL_SET_BAN_STATE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_BAN_STATE;
+       request->rdata.data.ban_state = ban_state;
+}
+
+int ctdb_reply_control_set_ban_state(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_BAN_STATE */
+
+void ctdb_req_control_get_ban_state(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_BAN_STATE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_BAN_STATE;
+}
+
+int ctdb_reply_control_get_ban_state(struct ctdb_reply_control *reply,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct ctdb_ban_state **ban_state)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_BAN_STATE) {
+               *ban_state = talloc_steal(mem_ctx,
+                                         reply->rdata.data.ban_state);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_DB_PRIORITY */
+
+void ctdb_req_control_set_db_priority(struct ctdb_req_control *request,
+                                     struct ctdb_db_priority *db_prio)
+{
+       request->opcode = CTDB_CONTROL_SET_DB_PRIORITY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_DB_PRIORITY;
+       request->rdata.data.db_prio = db_prio;
+}
+
+int ctdb_reply_control_set_db_priority(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DB_PRIORITY */
+
+void ctdb_req_control_get_db_priority(struct ctdb_req_control *request,
+                                     uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_GET_DB_PRIORITY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_DB_PRIORITY;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_get_db_priority(struct ctdb_reply_control *reply,
+                                      uint32_t *priority)
+{
+       if (reply->rdata.opcode == CTDB_CONTROL_GET_DB_PRIORITY) {
+               *priority = reply->status;
+               reply->status = 0;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_TRANSACTION_CANCEL */
+
+void ctdb_req_control_transaction_cancel(struct ctdb_req_control *request,
+                                        uint32_t tid)
+{
+       request->opcode = CTDB_CONTROL_TRANSACTION_CANCEL;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TRANSACTION_CANCEL;
+       request->rdata.data.tid = tid;
+}
+
+int ctdb_reply_control_transaction_cancel(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_REGISTER_NOTIFY */
+
+void ctdb_req_control_register_notify(struct ctdb_req_control *request,
+                                     struct ctdb_notify_data *notify)
+{
+       request->opcode = CTDB_CONTROL_REGISTER_NOTIFY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_REGISTER_NOTIFY;
+       request->rdata.data.notify = notify;
+}
+
+int ctdb_reply_control_register_notify(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DEREGISTER_NOTIFY */
+
+void ctdb_req_control_deregister_notify(struct ctdb_req_control *request,
+                                       uint64_t srvid)
+{
+       request->opcode = CTDB_CONTROL_DEREGISTER_NOTIFY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DEREGISTER_NOTIFY;
+       request->rdata.data.srvid = srvid;
+}
+
+int ctdb_reply_control_deregister_notify(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRANS3_COMMIT */
+
+void ctdb_req_control_trans3_commit(struct ctdb_req_control *request,
+                                   struct ctdb_rec_buffer *recbuf)
+{
+       request->opcode = CTDB_CONTROL_TRANS3_COMMIT;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TRANS3_COMMIT;
+       request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_trans3_commit(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DB_SEQNUM */
+
+void ctdb_req_control_get_db_seqnum(struct ctdb_req_control *request,
+                                   uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_GET_DB_SEQNUM;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_DB_SEQNUM;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_get_db_seqnum(struct ctdb_reply_control *reply,
+                                    uint64_t *seqnum)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_DB_SEQNUM) {
+               *seqnum = reply->rdata.data.seqnum;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_DB_SET_HEALTHY */
+
+void ctdb_req_control_db_set_healthy(struct ctdb_req_control *request,
+                                    uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_DB_SET_HEALTHY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DB_SET_HEALTHY;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_set_healthy(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_DB_GET_HEALTH */
+
+void ctdb_req_control_db_get_health(struct ctdb_req_control *request,
+                                   uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_DB_GET_HEALTH;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DB_GET_HEALTH;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_get_health(struct ctdb_reply_control *reply,
+                                    TALLOC_CTX *mem_ctx, const char **reason)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_DB_GET_HEALTH) {
+               *reason = talloc_steal(mem_ctx, reply->rdata.data.reason);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GET_PUBLIC_IP_INFO */
+
+void ctdb_req_control_get_public_ip_info(struct ctdb_req_control *request,
+                                        ctdb_sock_addr *addr)
+{
+       request->opcode = CTDB_CONTROL_GET_PUBLIC_IP_INFO;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_PUBLIC_IP_INFO;
+       request->rdata.data.addr = addr;
+}
+
+int ctdb_reply_control_get_public_ip_info(struct ctdb_reply_control *reply,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct ctdb_public_ip_info **ipinfo)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_PUBLIC_IP_INFO) {
+               *ipinfo = talloc_steal(mem_ctx, reply->rdata.data.ipinfo);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_GET_IFACES */
+
+void ctdb_req_control_get_ifaces(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_IFACES;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_IFACES;
+}
+
+int ctdb_reply_control_get_ifaces(struct ctdb_reply_control *reply,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct ctdb_iface_list **iface_list)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_IFACES) {
+               *iface_list = talloc_steal(mem_ctx,
+                                          reply->rdata.data.iface_list);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_IFACE_LINK_STATE */
+
+void ctdb_req_control_set_iface_link_state(struct ctdb_req_control *request,
+                                          struct ctdb_iface *iface)
+{
+       request->opcode = CTDB_CONTROL_SET_IFACE_LINK_STATE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_IFACE_LINK_STATE;
+       request->rdata.data.iface = iface;
+}
+
+int ctdb_reply_control_set_iface_link_state(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE */
+
+void ctdb_req_control_tcp_add_delayed_update(struct ctdb_req_control *request,
+                                            struct ctdb_connection *conn)
+{
+       request->opcode = CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE;
+       request->rdata.data.conn = conn;
+}
+
+int ctdb_reply_control_tcp_add_delayed_update(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_STAT_HISTORY */
+
+void ctdb_req_control_get_stat_history(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_STAT_HISTORY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_STAT_HISTORY;
+}
+
+int ctdb_reply_control_get_stat_history(struct ctdb_reply_control *reply,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct ctdb_statistics_list **stats_list)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_STAT_HISTORY) {
+               *stats_list = talloc_steal(mem_ctx,
+                                          reply->rdata.data.stats_list);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SCHEDULE_FOR_DELETION */
+
+void ctdb_req_control_schedule_for_deletion(struct ctdb_req_control *request,
+                                           struct ctdb_key_data *key)
+{
+       request->opcode = CTDB_CONTROL_SCHEDULE_FOR_DELETION;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SCHEDULE_FOR_DELETION;
+       request->rdata.data.key = key;
+}
+
+int ctdb_reply_control_schedule_for_deletion(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_SET_DB_READONLY */
+
+void ctdb_req_control_set_db_readonly(struct ctdb_req_control *request,
+                                     uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_SET_DB_READONLY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_DB_READONLY;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_set_db_readonly(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_CHECK_SRVIDS */
+
+void ctdb_req_control_check_srvids(struct ctdb_req_control *request,
+                                  struct ctdb_uint64_array *u64_array)
+{
+       request->opcode = CTDB_CONTROL_CHECK_SRVIDS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_CHECK_SRVIDS;
+       request->rdata.data.u64_array = u64_array;
+}
+
+int ctdb_reply_control_check_srvids(struct ctdb_reply_control *reply,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct ctdb_uint8_array **u8_array)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_CHECK_SRVIDS) {
+               *u8_array = talloc_steal(mem_ctx, reply->rdata.data.u8_array);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_TRAVERSE_START_EXT */
+
+void ctdb_req_control_traverse_start_ext(struct ctdb_req_control *request,
+                                        struct ctdb_traverse_start_ext *traverse)
+{
+       request->opcode = CTDB_CONTROL_TRAVERSE_START_EXT;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_TRAVERSE_START_EXT;
+       request->rdata.data.traverse_start_ext = traverse;
+}
+
+int ctdb_reply_control_traverse_start_ext(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_DB_STATISTICS */
+
+void ctdb_req_control_get_db_statistics(struct ctdb_req_control *request,
+                                       uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_GET_DB_STATISTICS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_DB_STATISTICS;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_get_db_statistics(struct ctdb_reply_control *reply,
+                                        TALLOC_CTX *mem_ctx,
+                                        struct ctdb_db_statistics **dbstats)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_DB_STATISTICS) {
+               *dbstats = talloc_steal(mem_ctx, reply->rdata.data.dbstats);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_SET_DB_STICKY */
+
+void ctdb_req_control_set_db_sticky(struct ctdb_req_control *request,
+                                   uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_SET_DB_STICKY;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_SET_DB_STICKY;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_set_db_sticky(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_RELOAD_PUBLIC_IPS */
+
+void ctdb_req_control_reload_public_ips(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_RELOAD_PUBLIC_IPS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_RELOAD_PUBLIC_IPS;
+}
+
+int ctdb_reply_control_reload_public_ips(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_TRAVERSE_ALL_EXT */
+
+/* CTDB_CONTROL_RECEIVE_RECORDS */
+
+void ctdb_req_control_receive_records(struct ctdb_req_control *request,
+                                     struct ctdb_rec_buffer *recbuf)
+{
+       request->opcode = CTDB_CONTROL_RECEIVE_RECORDS;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_RECEIVE_RECORDS;
+       request->rdata.data.recbuf = recbuf;
+}
+
+int ctdb_reply_control_receive_records(struct ctdb_reply_control *reply,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct ctdb_rec_buffer **recbuf)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_RECEIVE_RECORDS) {
+               *recbuf = talloc_steal(mem_ctx, reply->rdata.data.recbuf);
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_IPREALLOCATED */
+
+void ctdb_req_control_ipreallocated(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_IPREALLOCATED;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_IPREALLOCATED;
+}
+
+int ctdb_reply_control_ipreallocated(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_RUNSTATE */
+
+void ctdb_req_control_get_runstate(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_RUNSTATE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_RUNSTATE;
+}
+
+int ctdb_reply_control_get_runstate(struct ctdb_reply_control *reply,
+                                   enum ctdb_runstate *runstate)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_RUNSTATE) {
+               *runstate = reply->rdata.data.runstate;
+       }
+       return reply->status;
+}
+
+/* CTDB_CONTROL_DB_DETACH */
+
+void ctdb_req_control_db_detach(struct ctdb_req_control *request,
+                               uint32_t db_id)
+{
+       request->opcode = CTDB_CONTROL_DB_DETACH;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_DB_DETACH;
+       request->rdata.data.db_id = db_id;
+}
+
+int ctdb_reply_control_db_detach(struct ctdb_reply_control *reply)
+{
+       return ctdb_reply_control_generic(reply);
+}
+
+/* CTDB_CONTROL_GET_NODES_FILE */
+
+void ctdb_req_control_get_nodes_file(struct ctdb_req_control *request)
+{
+       request->opcode = CTDB_CONTROL_GET_NODES_FILE;
+       request->pad = 0;
+       request->srvid = 0;
+       request->client_id = 0;
+       request->flags = 0;
+
+       request->rdata.opcode = CTDB_CONTROL_GET_NODES_FILE;
+}
+
+int ctdb_reply_control_get_nodes_file(struct ctdb_reply_control *reply,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct ctdb_node_map **nodemap)
+{
+       if (reply->status == 0 &&
+           reply->rdata.opcode == CTDB_CONTROL_GET_NODES_FILE) {
+               *nodemap = talloc_steal(mem_ctx, reply->rdata.data.nodemap);
+       }
+       return reply->status;
+}
diff --git a/ctdb/protocol/protocol_control.c b/ctdb/protocol/protocol_control.c
new file mode 100644 (file)
index 0000000..da87351
--- /dev/null
@@ -0,0 +1,2007 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+#include "protocol_private.h"
+
+struct ctdb_req_control_wire {
+       struct ctdb_req_header hdr;
+       uint32_t opcode;
+       uint32_t pad;
+       uint64_t srvid;
+       uint32_t client_id;
+       uint32_t flags;
+       uint32_t datalen;
+       uint8_t data[1];
+};
+
+struct ctdb_reply_control_wire {
+       struct ctdb_req_header hdr;
+       int32_t status;
+       uint32_t datalen;
+       uint32_t errorlen;
+       uint8_t data[1];
+};
+
+static size_t ctdb_req_control_data_len(struct ctdb_req_control_data *cd)
+{
+       size_t len = 0;
+       uint64_t u64;
+
+       if (cd == NULL) {
+               return 0;
+       }
+
+       switch (cd->opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS:
+               len = ctdb_pid_len(cd->data.pid);
+               break;
+
+       case CTDB_CONTROL_STATISTICS:
+               break;
+
+       case CTDB_CONTROL_PING:
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_GETVNNMAP:
+               break;
+
+       case CTDB_CONTROL_SETVNNMAP:
+               len = ctdb_vnn_map_len(cd->data.vnnmap);
+               break;
+
+       case CTDB_CONTROL_GET_DEBUG:
+               break;
+
+       case CTDB_CONTROL_SET_DEBUG:
+               len = ctdb_uint32_len(cd->data.loglevel);
+               break;
+
+       case CTDB_CONTROL_GET_DBMAP:
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               len = ctdb_pulldb_len(cd->data.pulldb);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               len = ctdb_rec_buffer_len(cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMODE:
+               len = ctdb_uint32_len(cd->data.recmode);
+               break;
+
+       case CTDB_CONTROL_STATISTICS_RESET:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               len = ctdb_string_len(cd->data.db_name);
+               break;
+
+       case CTDB_CONTROL_SET_CALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START:
+               len = ctdb_traverse_start_len(cd->data.traverse_start);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL:
+               len = ctdb_traverse_all_len(cd->data.traverse_all);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_DATA:
+               len = ctdb_rec_data_len(cd->data.rec_data);
+               break;
+
+       case CTDB_CONTROL_REGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SEQNUM:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_UPDATE_SEQNUM:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_DUMP_MEMORY:
+               break;
+
+       case CTDB_CONTROL_GET_PID:
+               break;
+
+       case CTDB_CONTROL_GET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTER:
+               len = ctdb_uint32_len(cd->data.recmaster);
+               break;
+
+       case CTDB_CONTROL_FREEZE:
+               break;
+
+       case CTDB_CONTROL_THAW:
+               break;
+
+       case CTDB_CONTROL_GET_PNN:
+               break;
+
+       case CTDB_CONTROL_SHUTDOWN:
+               break;
+
+       case CTDB_CONTROL_GET_MONMODE:
+               break;
+
+       case CTDB_CONTROL_TCP_CLIENT:
+               len = ctdb_connection_len(cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD:
+               len = ctdb_connection_len(cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_TCP_REMOVE:
+               len = ctdb_connection_len(cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_STARTUP:
+               break;
+
+       case CTDB_CONTROL_SET_TUNABLE:
+               len = ctdb_tunable_len(cd->data.tunable);
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               len = ctdb_stringn_len(cd->data.tun_var);
+               break;
+
+       case CTDB_CONTROL_LIST_TUNABLES:
+               break;
+
+       case CTDB_CONTROL_MODIFY_FLAGS:
+               len = ctdb_node_flag_change_len(cd->data.flag_change);
+               break;
+
+       case CTDB_CONTROL_GET_ALL_TUNABLES:
+               break;
+
+       case CTDB_CONTROL_KILL_TCP:
+               len = ctdb_connection_len(cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               len = ctdb_sock_addr_len(cd->data.addr);
+               break;
+
+       case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+               len = ctdb_tickle_list_len(cd->data.tickles);
+               break;
+
+       case CTDB_CONTROL_REGISTER_SERVER_ID:
+               len = ctdb_client_id_len(cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+               len = ctdb_client_id_len(cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_CHECK_SERVER_ID:
+               len = ctdb_client_id_len(cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_GET_SERVER_ID_LIST:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               len = ctdb_string_len(cd->data.db_name);
+               break;
+
+       case CTDB_CONTROL_UPDATE_RECORD:
+               len = ctdb_rec_buffer_len(cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+               len = ctdb_addr_info_len(cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_START:
+               len = ctdb_uint32_len(cd->data.tid);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_COMMIT:
+               len = ctdb_uint32_len(cd->data.tid);
+               break;
+
+       case CTDB_CONTROL_WIPE_DATABASE:
+               len = ctdb_transdb_len(cd->data.transdb);
+               break;
+
+       case CTDB_CONTROL_UPTIME:
+               break;
+
+       case CTDB_CONTROL_START_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_END_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_NODES_FILE:
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               len = ctdb_rec_buffer_len(cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_ENABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_DISABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               len = ctdb_addr_info_len(cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               len = ctdb_addr_info_len(cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+               len = ctdb_string_len(cd->data.event_str);
+               break;
+
+       case CTDB_CONTROL_GET_CAPABILITIES:
+               break;
+
+       case CTDB_CONTROL_RECD_PING:
+               break;
+
+       case CTDB_CONTROL_RELEASE_IP:
+               len = ctdb_public_ip_len(cd->data.pubip);
+               break;
+
+       case CTDB_CONTROL_TAKEOVER_IP:
+               len = ctdb_public_ip_len(cd->data.pubip);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_GET_NODEMAP:
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               len = ctdb_uint32_len(cd->data.event);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_KILL:
+               len = ctdb_traverse_start_len(cd->data.traverse_start);
+               break;
+
+       case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+               len = ctdb_double_len(cd->data.reclock_latency);
+               break;
+
+       case CTDB_CONTROL_GET_RECLOCK_FILE:
+               break;
+
+       case CTDB_CONTROL_SET_RECLOCK_FILE:
+               len = ctdb_string_len(cd->data.reclock_file);
+               break;
+
+       case CTDB_CONTROL_STOP_NODE:
+               break;
+
+       case CTDB_CONTROL_CONTINUE_NODE:
+               break;
+
+       case CTDB_CONTROL_SET_NATGWSTATE:
+               len = ctdb_uint32_len(cd->data.role);
+               break;
+
+       case CTDB_CONTROL_SET_LMASTERROLE:
+               len = ctdb_uint32_len(cd->data.role);
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTERROLE:
+               len = ctdb_uint32_len(cd->data.role);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SCRIPT:
+               len = ctdb_string_len(cd->data.script);
+               break;
+
+       case CTDB_CONTROL_DISABLE_SCRIPT:
+               len = ctdb_string_len(cd->data.script);
+               break;
+
+       case CTDB_CONTROL_SET_BAN_STATE:
+               len = ctdb_ban_state_len(cd->data.ban_state);
+               break;
+
+       case CTDB_CONTROL_GET_BAN_STATE:
+               break;
+
+       case CTDB_CONTROL_SET_DB_PRIORITY:
+               len = ctdb_db_priority_len(cd->data.db_prio);
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_CANCEL:
+               break;
+
+       case CTDB_CONTROL_REGISTER_NOTIFY:
+               len = ctdb_notify_data_len(cd->data.notify);
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_NOTIFY:
+               len = ctdb_uint64_len(cd->data.srvid);
+               break;
+
+       case CTDB_CONTROL_TRANS3_COMMIT:
+               len = ctdb_rec_buffer_len(cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               u64 = cd->data.db_id;
+               len = ctdb_uint64_len(u64);
+               break;
+
+       case CTDB_CONTROL_DB_SET_HEALTHY:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               len = ctdb_sock_addr_len(cd->data.addr);
+               break;
+
+       case CTDB_CONTROL_GET_IFACES:
+               break;
+
+       case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+               len = ctdb_iface_len(cd->data.iface);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+               len = ctdb_connection_len(cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_GET_STAT_HISTORY:
+               break;
+
+       case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+               len = ctdb_key_data_len(cd->data.key);
+               break;
+
+       case CTDB_CONTROL_SET_DB_READONLY:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               len = ctdb_uint64_array_len(cd->data.u64_array);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START_EXT:
+               len = ctdb_traverse_start_ext_len(cd->data.traverse_start_ext);
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_SET_DB_STICKY:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+               len = ctdb_traverse_all_ext_len(cd->data.traverse_all_ext);
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               len = ctdb_rec_buffer_len(cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_IPREALLOCATED:
+               break;
+
+       case CTDB_CONTROL_GET_RUNSTATE:
+               break;
+
+       case CTDB_CONTROL_DB_DETACH:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_GET_NODES_FILE:
+               break;
+       }
+
+       return len;
+}
+
+static void ctdb_req_control_data_push(struct ctdb_req_control_data *cd,
+                                      uint8_t *buf)
+{
+       uint64_t u64;
+
+       switch (cd->opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS:
+               ctdb_pid_push(cd->data.pid, buf);
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_SETVNNMAP:
+               ctdb_vnn_map_push(cd->data.vnnmap, buf);
+               break;
+
+       case CTDB_CONTROL_SET_DEBUG:
+               ctdb_uint32_push(cd->data.loglevel, buf);
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               ctdb_pulldb_push(cd->data.pulldb, buf);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               ctdb_rec_buffer_push(cd->data.recbuf, buf);
+               break;
+
+       case CTDB_CONTROL_SET_RECMODE:
+               ctdb_uint32_push(cd->data.recmode, buf);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               ctdb_string_push(cd->data.db_name, buf);
+               break;
+
+       case CTDB_CONTROL_SET_CALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START:
+               ctdb_traverse_start_push(cd->data.traverse_start, buf);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL:
+               ctdb_traverse_all_push(cd->data.traverse_all, buf);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_DATA:
+               ctdb_rec_data_push(cd->data.rec_data, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SEQNUM:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_UPDATE_SEQNUM:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTER:
+               ctdb_uint32_push(cd->data.recmaster, buf);
+               break;
+
+       case CTDB_CONTROL_TCP_CLIENT:
+               ctdb_connection_push(cd->data.conn, buf);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD:
+               ctdb_connection_push(cd->data.conn, buf);
+               break;
+
+       case CTDB_CONTROL_TCP_REMOVE:
+               ctdb_connection_push(cd->data.conn, buf);
+               break;
+
+       case CTDB_CONTROL_SET_TUNABLE:
+               ctdb_tunable_push(cd->data.tunable, buf);
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               ctdb_stringn_push(cd->data.tun_var, buf);
+               break;
+
+       case CTDB_CONTROL_MODIFY_FLAGS:
+               ctdb_node_flag_change_push(cd->data.flag_change, buf);
+               break;
+
+       case CTDB_CONTROL_KILL_TCP:
+               ctdb_connection_push(cd->data.conn, buf);
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               ctdb_sock_addr_push(cd->data.addr, buf);
+               break;
+
+       case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+               ctdb_tickle_list_push(cd->data.tickles, buf);
+               break;
+
+       case CTDB_CONTROL_REGISTER_SERVER_ID:
+               ctdb_client_id_push(cd->data.cid, buf);
+               break;
+
+       case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+               ctdb_client_id_push(cd->data.cid, buf);
+               break;
+
+       case CTDB_CONTROL_CHECK_SERVER_ID:
+               ctdb_client_id_push(cd->data.cid, buf);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               ctdb_string_push(cd->data.db_name, buf);
+               break;
+
+       case CTDB_CONTROL_UPDATE_RECORD:
+               ctdb_rec_buffer_push(cd->data.recbuf, buf);
+               break;
+
+       case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+               ctdb_addr_info_push(cd->data.addr_info, buf);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_START:
+               ctdb_uint32_push(cd->data.tid, buf);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_COMMIT:
+               ctdb_uint32_push(cd->data.tid, buf);
+               break;
+
+       case CTDB_CONTROL_WIPE_DATABASE:
+               ctdb_transdb_push(cd->data.transdb, buf);
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               ctdb_rec_buffer_push(cd->data.recbuf, buf);
+               break;
+
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               ctdb_addr_info_push(cd->data.addr_info, buf);
+               break;
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               ctdb_addr_info_push(cd->data.addr_info, buf);
+               break;
+
+       case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+               ctdb_string_push(cd->data.event_str, buf);
+               break;
+
+       case CTDB_CONTROL_RELEASE_IP:
+               ctdb_public_ip_push(cd->data.pubip, buf);
+               break;
+
+       case CTDB_CONTROL_TAKEOVER_IP:
+               ctdb_public_ip_push(cd->data.pubip, buf);
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               ctdb_uint32_push(cd->data.event, buf);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_KILL:
+               ctdb_traverse_start_push(cd->data.traverse_start, buf);
+               break;
+
+       case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+               ctdb_double_push(cd->data.reclock_latency, buf);
+               break;
+
+       case CTDB_CONTROL_SET_RECLOCK_FILE:
+               ctdb_string_push(cd->data.reclock_file, buf);
+               break;
+
+       case CTDB_CONTROL_SET_NATGWSTATE:
+               ctdb_uint32_push(cd->data.role, buf);
+               break;
+
+       case CTDB_CONTROL_SET_LMASTERROLE:
+               ctdb_uint32_push(cd->data.role, buf);
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTERROLE:
+               ctdb_uint32_push(cd->data.role, buf);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SCRIPT:
+               ctdb_string_push(cd->data.script, buf);
+               break;
+
+       case CTDB_CONTROL_DISABLE_SCRIPT:
+               ctdb_string_push(cd->data.script, buf);
+               break;
+
+       case CTDB_CONTROL_SET_BAN_STATE:
+               ctdb_ban_state_push(cd->data.ban_state, buf);
+               break;
+
+       case CTDB_CONTROL_SET_DB_PRIORITY:
+               ctdb_db_priority_push(cd->data.db_prio, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_REGISTER_NOTIFY:
+               ctdb_notify_data_push(cd->data.notify, buf);
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_NOTIFY:
+               ctdb_uint64_push(cd->data.srvid, buf);
+               break;
+
+       case CTDB_CONTROL_TRANS3_COMMIT:
+               ctdb_rec_buffer_push(cd->data.recbuf, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               u64 = cd->data.db_id;
+               ctdb_uint32_push(u64, buf);
+               break;
+
+       case CTDB_CONTROL_DB_SET_HEALTHY:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               ctdb_sock_addr_push(cd->data.addr, buf);
+               break;
+
+       case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+               ctdb_iface_push(cd->data.iface, buf);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+               ctdb_connection_push(cd->data.conn, buf);
+               break;
+
+       case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+               ctdb_key_data_push(cd->data.key, buf);
+               break;
+
+       case CTDB_CONTROL_SET_DB_READONLY:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               ctdb_uint64_array_push(cd->data.u64_array, buf);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START_EXT:
+               ctdb_traverse_start_ext_push(cd->data.traverse_start_ext, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_SET_DB_STICKY:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+               ctdb_traverse_all_ext_push(cd->data.traverse_all_ext, buf);
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               ctdb_rec_buffer_push(cd->data.recbuf, buf);
+               break;
+
+       case CTDB_CONTROL_DB_DETACH:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+       }
+}
+
+static int ctdb_req_control_data_pull(uint8_t *buf, size_t buflen,
+                                     uint32_t opcode,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct ctdb_req_control_data *cd)
+{
+       int ret = 0;
+       uint64_t u64;
+
+       cd->opcode = opcode;
+
+       switch (opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS:
+               ret = ctdb_pid_pull(buf, buflen, mem_ctx,
+                                   &cd->data.pid);
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_SETVNNMAP:
+               ret = ctdb_vnn_map_pull(buf, buflen, mem_ctx,
+                                       &cd->data.vnnmap);
+               break;
+
+       case CTDB_CONTROL_SET_DEBUG:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.loglevel);
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               ret = ctdb_pulldb_pull(buf, buflen, mem_ctx,
+                                      &cd->data.pulldb);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                          &cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_SET_RECMODE:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.recmode);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_name);
+               break;
+
+       case CTDB_CONTROL_SET_CALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START:
+               ret = ctdb_traverse_start_pull(buf, buflen, mem_ctx,
+                                              &cd->data.traverse_start);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL:
+               ret = ctdb_traverse_all_pull(buf, buflen, mem_ctx,
+                                            &cd->data.traverse_all);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_DATA:
+               ret = ctdb_rec_data_pull(buf, buflen, mem_ctx,
+                                        &cd->data.rec_data);
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SEQNUM:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_UPDATE_SEQNUM:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTER:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.recmaster);
+               break;
+
+       case CTDB_CONTROL_TCP_CLIENT:
+               ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+                                          &cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD:
+               ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+                                          &cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_TCP_REMOVE:
+               ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+                                          &cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_SET_TUNABLE:
+               ret = ctdb_tunable_pull(buf, buflen, mem_ctx,
+                                       &cd->data.tunable);
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               ret = ctdb_stringn_pull(buf, buflen, mem_ctx,
+                                       &cd->data.tun_var);
+               break;
+
+       case CTDB_CONTROL_MODIFY_FLAGS:
+               ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
+                                                &cd->data.flag_change);
+               break;
+
+       case CTDB_CONTROL_KILL_TCP:
+               ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+                                          &cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               ret = ctdb_sock_addr_pull(buf, buflen, mem_ctx,
+                                         &cd->data.addr);
+               break;
+
+       case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+               ret = ctdb_tickle_list_pull(buf, buflen, mem_ctx,
+                                           &cd->data.tickles);
+               break;
+
+       case CTDB_CONTROL_REGISTER_SERVER_ID:
+               ret = ctdb_client_id_pull(buf, buflen, mem_ctx,
+                                         &cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+               ret = ctdb_client_id_pull(buf, buflen, mem_ctx,
+                                         &cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_CHECK_SERVER_ID:
+               ret = ctdb_client_id_pull(buf, buflen, mem_ctx,
+                                         &cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_name);
+               break;
+
+       case CTDB_CONTROL_UPDATE_RECORD:
+               ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                          &cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+               ret = ctdb_addr_info_pull(buf, buflen, mem_ctx,
+                                         &cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_START:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.tid);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_COMMIT:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.tid);
+               break;
+
+       case CTDB_CONTROL_WIPE_DATABASE:
+               ret = ctdb_transdb_pull(buf, buflen, mem_ctx,
+                                      &cd->data.transdb);
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                          &cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               ret = ctdb_addr_info_pull(buf, buflen, mem_ctx,
+                                         &cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               ret = ctdb_addr_info_pull(buf, buflen, mem_ctx,
+                                         &cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.event_str);
+               break;
+
+       case CTDB_CONTROL_RELEASE_IP:
+               ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
+                                         &cd->data.pubip);
+               break;
+
+       case CTDB_CONTROL_TAKEOVER_IP:
+               ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
+                                         &cd->data.pubip);
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                      &cd->data.event);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_KILL:
+               ret = ctdb_traverse_start_pull(buf, buflen, mem_ctx,
+                                              &cd->data.traverse_start);
+               break;
+
+       case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+               ret = ctdb_double_pull(buf, buflen, mem_ctx,
+                                      &cd->data.reclock_latency);
+               break;
+
+       case CTDB_CONTROL_SET_RECLOCK_FILE:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.reclock_file);
+               break;
+
+       case CTDB_CONTROL_SET_NATGWSTATE:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.role);
+               break;
+
+       case CTDB_CONTROL_SET_LMASTERROLE:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.role);
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTERROLE:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.role);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SCRIPT:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.script);
+               break;
+
+       case CTDB_CONTROL_DISABLE_SCRIPT:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.script);
+               break;
+
+       case CTDB_CONTROL_SET_BAN_STATE:
+               ret = ctdb_ban_state_pull(buf, buflen, mem_ctx,
+                                         &cd->data.ban_state);
+               break;
+
+       case CTDB_CONTROL_SET_DB_PRIORITY:
+               ret = ctdb_db_priority_pull(buf, buflen, mem_ctx,
+                                           &cd->data.db_prio);
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_REGISTER_NOTIFY:
+               ret = ctdb_notify_data_pull(buf, buflen, mem_ctx,
+                                           &cd->data.notify);
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_NOTIFY:
+               ctdb_uint64_pull(buf, buflen, mem_ctx,
+                                &cd->data.srvid);
+               break;
+
+       case CTDB_CONTROL_TRANS3_COMMIT:
+               ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                          &cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               ret = ctdb_uint64_pull(buf, buflen, mem_ctx, &u64);
+               cd->data.db_id = (uint32_t)u64;
+               break;
+
+       case CTDB_CONTROL_DB_SET_HEALTHY:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               ret = ctdb_sock_addr_pull(buf, buflen, mem_ctx,
+                                         &cd->data.addr);
+               break;
+
+       case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+               ret = ctdb_iface_pull(buf, buflen, mem_ctx,
+                                     &cd->data.iface);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+               ret = ctdb_connection_pull(buf, buflen, mem_ctx,
+                                          &cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+               ret = ctdb_key_data_pull(buf, buflen, mem_ctx,
+                                        &cd->data.key);
+               break;
+
+       case CTDB_CONTROL_SET_DB_READONLY:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               ret = ctdb_uint64_array_pull(buf, buflen, mem_ctx,
+                                            &cd->data.u64_array);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START_EXT:
+               ret = ctdb_traverse_start_ext_pull(buf, buflen, mem_ctx,
+                                                  &cd->data.traverse_start_ext);
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_SET_DB_STICKY:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+               ret = ctdb_traverse_all_ext_pull(buf, buflen, mem_ctx,
+                                                &cd->data.traverse_all_ext);
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                          &cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_DB_DETACH:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_id);
+               break;
+       }
+
+       return ret;
+}
+
+static size_t ctdb_reply_control_data_len(struct ctdb_reply_control_data *cd)
+{
+       size_t len = 0;
+
+       if (cd == NULL) {
+               return 0;
+       }
+
+       switch (cd->opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS:
+               break;
+
+       case CTDB_CONTROL_STATISTICS:
+               len = ctdb_statistics_len(cd->data.stats);
+               break;
+
+       case CTDB_CONTROL_PING:
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               len = ctdb_string_len(cd->data.db_path);
+               break;
+
+       case CTDB_CONTROL_GETVNNMAP:
+               len = ctdb_vnn_map_len(cd->data.vnnmap);
+               break;
+
+       case CTDB_CONTROL_SETVNNMAP:
+               break;
+
+       case CTDB_CONTROL_GET_DEBUG:
+               len = ctdb_uint32_len(cd->data.loglevel);
+               break;
+
+       case CTDB_CONTROL_SET_DEBUG:
+               break;
+
+       case CTDB_CONTROL_GET_DBMAP:
+               len = ctdb_dbid_map_len(cd->data.dbmap);
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               len = ctdb_rec_buffer_len(cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               break;
+
+       case CTDB_CONTROL_GET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_STATISTICS_RESET:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_SET_CALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_DATA:
+               break;
+
+       case CTDB_CONTROL_REGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               len = ctdb_string_len(cd->data.db_name);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SEQNUM:
+               break;
+
+       case CTDB_CONTROL_UPDATE_SEQNUM:
+               break;
+
+       case CTDB_CONTROL_DUMP_MEMORY:
+               len = ctdb_string_len(cd->data.mem_str);
+               break;
+
+       case CTDB_CONTROL_GET_PID:
+               break;
+
+       case CTDB_CONTROL_GET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_FREEZE:
+               break;
+
+       case CTDB_CONTROL_THAW:
+               break;
+
+       case CTDB_CONTROL_GET_PNN:
+               break;
+
+       case CTDB_CONTROL_SHUTDOWN:
+               break;
+
+       case CTDB_CONTROL_GET_MONMODE:
+               break;
+
+       case CTDB_CONTROL_TCP_CLIENT:
+               break;
+
+       case CTDB_CONTROL_TCP_ADD:
+               break;
+
+       case CTDB_CONTROL_TCP_REMOVE:
+               break;
+
+       case CTDB_CONTROL_STARTUP:
+               break;
+
+       case CTDB_CONTROL_SET_TUNABLE:
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               len = ctdb_uint32_len(cd->data.tun_value);
+               break;
+
+       case CTDB_CONTROL_LIST_TUNABLES:
+               len = ctdb_var_list_len(cd->data.tun_var_list);
+               break;
+
+       case CTDB_CONTROL_MODIFY_FLAGS:
+               break;
+
+       case CTDB_CONTROL_GET_ALL_TUNABLES:
+               len = ctdb_tunable_list_len(cd->data.tun_list);
+               break;
+
+       case CTDB_CONTROL_KILL_TCP:
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               len = ctdb_tickle_list_len(cd->data.tickles);
+               break;
+
+       case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+               break;
+
+       case CTDB_CONTROL_REGISTER_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_CHECK_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_GET_SERVER_ID_LIST:
+               len = ctdb_client_id_map_len(cd->data.cid_map);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               len = ctdb_uint32_len(cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_UPDATE_RECORD:
+               break;
+
+       case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_START:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_COMMIT:
+               break;
+
+       case CTDB_CONTROL_WIPE_DATABASE:
+               break;
+
+       case CTDB_CONTROL_UPTIME:
+               len = ctdb_uptime_len(cd->data.uptime);
+               break;
+
+       case CTDB_CONTROL_START_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_END_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_NODES_FILE:
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               len = ctdb_rec_buffer_len(cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_ENABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_DISABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               break;
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               break;
+
+       case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+               break;
+
+       case CTDB_CONTROL_GET_CAPABILITIES:
+               len = ctdb_uint32_len(cd->data.caps);
+               break;
+
+       case CTDB_CONTROL_RECD_PING:
+               break;
+
+       case CTDB_CONTROL_RELEASE_IP:
+               break;
+
+       case CTDB_CONTROL_TAKEOVER_IP:
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IPS:
+               len = ctdb_public_ip_list_len(cd->data.pubip_list);
+               break;
+
+       case CTDB_CONTROL_GET_NODEMAP:
+               len = ctdb_node_map_len(cd->data.nodemap);
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               len = ctdb_script_list_len(cd->data.script_list);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_KILL:
+               break;
+
+       case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+               break;
+
+       case CTDB_CONTROL_GET_RECLOCK_FILE:
+               len = ctdb_string_len(cd->data.reclock_file);
+               break;
+
+       case CTDB_CONTROL_SET_RECLOCK_FILE:
+               break;
+
+       case CTDB_CONTROL_STOP_NODE:
+               break;
+
+       case CTDB_CONTROL_CONTINUE_NODE:
+               break;
+
+       case CTDB_CONTROL_SET_NATGWSTATE:
+               break;
+
+       case CTDB_CONTROL_SET_LMASTERROLE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTERROLE:
+               break;
+
+       case CTDB_CONTROL_ENABLE_SCRIPT:
+               break;
+
+       case CTDB_CONTROL_DISABLE_SCRIPT:
+               break;
+
+       case CTDB_CONTROL_SET_BAN_STATE:
+               break;
+
+       case CTDB_CONTROL_GET_BAN_STATE:
+               len = ctdb_ban_state_len(cd->data.ban_state);
+               break;
+
+       case CTDB_CONTROL_SET_DB_PRIORITY:
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_CANCEL:
+               break;
+
+       case CTDB_CONTROL_REGISTER_NOTIFY:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_NOTIFY:
+               break;
+
+       case CTDB_CONTROL_TRANS3_COMMIT:
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               len = ctdb_uint64_len(cd->data.seqnum);
+               break;
+
+       case CTDB_CONTROL_DB_SET_HEALTHY:
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               len = ctdb_string_len(cd->data.reason);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               len = ctdb_public_ip_info_len(cd->data.ipinfo);
+               break;
+
+       case CTDB_CONTROL_GET_IFACES:
+               len = ctdb_iface_list_len(cd->data.iface_list);
+               break;
+
+       case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+               break;
+
+       case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+               break;
+
+       case CTDB_CONTROL_GET_STAT_HISTORY:
+               len = ctdb_statistics_list_len(cd->data.stats_list);
+               break;
+
+       case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+               break;
+
+       case CTDB_CONTROL_SET_DB_READONLY:
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               len = ctdb_uint8_array_len(cd->data.u8_array);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START_EXT:
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               len = ctdb_db_statistics_len(cd->data.dbstats);
+               break;
+
+       case CTDB_CONTROL_SET_DB_STICKY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               len = ctdb_rec_buffer_len(cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_IPREALLOCATED:
+               break;
+
+       case CTDB_CONTROL_GET_RUNSTATE:
+               len = ctdb_uint32_len(cd->data.runstate);
+               break;
+
+       case CTDB_CONTROL_DB_DETACH:
+               break;
+
+       case CTDB_CONTROL_GET_NODES_FILE:
+               len = ctdb_node_map_len(cd->data.nodemap);
+               break;
+       }
+
+       return len;
+}
+
+static void ctdb_reply_control_data_push(struct ctdb_reply_control_data *cd,
+                                        uint8_t *buf)
+{
+       switch (cd->opcode) {
+       case CTDB_CONTROL_STATISTICS:
+               ctdb_statistics_push(cd->data.stats, buf);
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               ctdb_string_push(cd->data.db_path, buf);
+               break;
+
+       case CTDB_CONTROL_GETVNNMAP:
+               ctdb_vnn_map_push(cd->data.vnnmap, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DEBUG:
+               ctdb_uint32_push(cd->data.loglevel, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DBMAP:
+               ctdb_dbid_map_push(cd->data.dbmap, buf);
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               ctdb_rec_buffer_push(cd->data.recbuf, buf);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               ctdb_string_push(cd->data.db_name, buf);
+               break;
+
+       case CTDB_CONTROL_DUMP_MEMORY:
+               ctdb_string_push(cd->data.mem_str, buf);
+               break;
+
+       case CTDB_CONTROL_GET_PID:
+               break;
+
+       case CTDB_CONTROL_GET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               ctdb_uint32_push(cd->data.tun_value, buf);
+               break;
+
+       case CTDB_CONTROL_LIST_TUNABLES:
+               ctdb_var_list_push(cd->data.tun_var_list, buf);
+               break;
+
+       case CTDB_CONTROL_GET_ALL_TUNABLES:
+               ctdb_tunable_list_push(cd->data.tun_list, buf);
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               ctdb_tickle_list_push(cd->data.tickles, buf);
+               break;
+
+       case CTDB_CONTROL_GET_SERVER_ID_LIST:
+               ctdb_client_id_map_push(cd->data.cid_map, buf);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               ctdb_uint32_push(cd->data.db_id, buf);
+               break;
+
+       case CTDB_CONTROL_UPTIME:
+               ctdb_uptime_push(cd->data.uptime, buf);
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               ctdb_rec_buffer_push(cd->data.recbuf, buf);
+               break;
+
+       case CTDB_CONTROL_GET_CAPABILITIES:
+               ctdb_uint32_push(cd->data.caps, buf);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IPS:
+               ctdb_public_ip_list_push(cd->data.pubip_list, buf);
+               break;
+
+       case CTDB_CONTROL_GET_NODEMAP:
+               ctdb_node_map_push(cd->data.nodemap, buf);
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               ctdb_script_list_push(cd->data.script_list, buf);
+               break;
+
+       case CTDB_CONTROL_GET_RECLOCK_FILE:
+               ctdb_string_push(cd->data.reclock_file, buf);
+               break;
+
+       case CTDB_CONTROL_GET_BAN_STATE:
+               ctdb_ban_state_push(cd->data.ban_state, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               ctdb_uint64_push(cd->data.seqnum, buf);
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               ctdb_string_push(cd->data.reason, buf);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               ctdb_public_ip_info_push(cd->data.ipinfo, buf);
+               break;
+
+       case CTDB_CONTROL_GET_IFACES:
+               ctdb_iface_list_push(cd->data.iface_list, buf);
+               break;
+
+       case CTDB_CONTROL_GET_STAT_HISTORY:
+               ctdb_statistics_list_push(cd->data.stats_list, buf);
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               ctdb_uint8_array_push(cd->data.u8_array, buf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               ctdb_db_statistics_push(cd->data.dbstats, buf);
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               ctdb_rec_buffer_push(cd->data.recbuf, buf);
+               break;
+
+       case CTDB_CONTROL_GET_RUNSTATE:
+               ctdb_uint32_push(cd->data.runstate, buf);
+               break;
+
+       case CTDB_CONTROL_GET_NODES_FILE:
+               ctdb_node_map_push(cd->data.nodemap, buf);
+               break;
+       }
+}
+
+static int ctdb_reply_control_data_pull(uint8_t *buf, size_t buflen,
+                                       uint32_t opcode, TALLOC_CTX *mem_ctx,
+                                       struct ctdb_reply_control_data *cd)
+{
+       int ret = 0;
+       cd->opcode = opcode;
+
+       switch (opcode) {
+       case CTDB_CONTROL_STATISTICS:
+               ret = ctdb_statistics_pull(buf, buflen, mem_ctx,
+                                          &cd->data.stats);
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_path);
+               break;
+
+       case CTDB_CONTROL_GETVNNMAP:
+               ret = ctdb_vnn_map_pull(buf, buflen, mem_ctx,
+                                       &cd->data.vnnmap);
+               break;
+
+       case CTDB_CONTROL_GET_DEBUG:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.loglevel);
+               break;
+
+       case CTDB_CONTROL_GET_DBMAP:
+               ret = ctdb_dbid_map_pull(buf, buflen, mem_ctx,
+                                        &cd->data.dbmap);
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                          &cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_name);
+               break;
+
+       case CTDB_CONTROL_DUMP_MEMORY:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.mem_str);
+               break;
+
+       case CTDB_CONTROL_GET_PID:
+               break;
+
+       case CTDB_CONTROL_GET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.tun_value);
+               break;
+
+       case CTDB_CONTROL_LIST_TUNABLES:
+               ret = ctdb_var_list_pull(buf, buflen, mem_ctx,
+                                        &cd->data.tun_var_list);
+               break;
+
+       case CTDB_CONTROL_GET_ALL_TUNABLES:
+               ret = ctdb_tunable_list_pull(buf, buflen, mem_ctx,
+                                            &cd->data.tun_list);
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               ret = ctdb_tickle_list_pull(buf, buflen, mem_ctx,
+                                           &cd->data.tickles);
+               break;
+
+       case CTDB_CONTROL_GET_SERVER_ID_LIST:
+               ret = ctdb_client_id_map_pull(buf, buflen, mem_ctx,
+                                             &cd->data.cid_map);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                      &cd->data.db_id);
+               break;
+
+       case CTDB_CONTROL_UPTIME:
+               ret = ctdb_uptime_pull(buf, buflen, mem_ctx,
+                                      &cd->data.uptime);
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                    &cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_CAPABILITIES:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                    &cd->data.caps);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IPS:
+               ret = ctdb_public_ip_list_pull(buf, buflen, mem_ctx,
+                                              &cd->data.pubip_list);
+               break;
+
+       case CTDB_CONTROL_GET_NODEMAP:
+               ret = ctdb_node_map_pull(buf, buflen, mem_ctx,
+                                        &cd->data.nodemap);
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               ret = ctdb_script_list_pull(buf, buflen, mem_ctx,
+                                           &cd->data.script_list);
+               break;
+
+       case CTDB_CONTROL_GET_RECLOCK_FILE:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.reclock_file);
+               break;
+
+       case CTDB_CONTROL_GET_BAN_STATE:
+               ret = ctdb_ban_state_pull(buf, buflen, mem_ctx,
+                                         &cd->data.ban_state);
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               ret = ctdb_uint64_pull(buf, buflen, mem_ctx,
+                                      &cd->data.seqnum);
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx,
+                                      &cd->data.reason);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               ret = ctdb_public_ip_info_pull(buf, buflen, mem_ctx,
+                                              &cd->data.ipinfo);
+               break;
+
+       case CTDB_CONTROL_GET_IFACES:
+               ret = ctdb_iface_list_pull(buf, buflen, mem_ctx,
+                                          &cd->data.iface_list);
+               break;
+
+       case CTDB_CONTROL_GET_STAT_HISTORY:
+               ret = ctdb_statistics_list_pull(buf, buflen, mem_ctx,
+                                               &cd->data.stats_list);
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               ret = ctdb_uint8_array_pull(buf, buflen, mem_ctx,
+                                           &cd->data.u8_array);
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               ret = ctdb_db_statistics_pull(buf, buflen, mem_ctx,
+                                             &cd->data.dbstats);
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                          &cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_RUNSTATE:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx,
+                                      &cd->data.runstate);
+               break;
+
+       case CTDB_CONTROL_GET_NODES_FILE:
+               ret = ctdb_node_map_pull(buf, buflen, mem_ctx,
+                                        &cd->data.nodemap);
+               break;
+       }
+
+       return ret;
+}
+
+int ctdb_req_control_push(struct ctdb_req_header *h,
+                         struct ctdb_req_control *request,
+                         TALLOC_CTX *mem_ctx,
+                         uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_req_control_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen, datalen;
+       int ret;
+
+       datalen = ctdb_req_control_data_len(&request->rdata);
+       length = offsetof(struct ctdb_req_control_wire, data) + datalen;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_req_control_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->opcode = request->opcode;
+       wire->pad = request->pad;
+       wire->srvid = request->srvid;
+       wire->client_id = request->client_id;
+       wire->flags = request->flags;
+
+       wire->datalen = datalen;
+       ctdb_req_control_data_push(&request->rdata, wire->data);
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_req_control_pull(uint8_t *pkt, size_t pkt_len,
+                         struct ctdb_req_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_req_control *request)
+{
+       struct ctdb_req_control_wire *wire =
+               (struct ctdb_req_control_wire *)pkt;
+       size_t length;
+       int ret;
+
+       length = offsetof(struct ctdb_req_control_wire, data);
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+       if (pkt_len < length + wire->datalen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       request->opcode = wire->opcode;
+       request->pad = wire->pad;
+       request->srvid = wire->srvid;
+       request->client_id = wire->client_id;
+       request->flags = wire->flags;
+
+       ret = ctdb_req_control_data_pull(wire->data, wire->datalen,
+                                        request->opcode, mem_ctx,
+                                        &request->rdata);
+       if (ret != 0) {
+               return ret;
+       }
+
+       return 0;
+}
+
+int ctdb_reply_control_push(struct ctdb_req_header *h,
+                           struct ctdb_reply_control *reply,
+                           TALLOC_CTX *mem_ctx,
+                           uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_reply_control_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen, datalen, errlen;
+       int ret;
+
+       if (reply->status == 0) {
+               datalen = ctdb_reply_control_data_len(&reply->rdata);
+       } else {
+               datalen = 0;
+       }
+
+       if (reply->errmsg == NULL) {
+               errlen = 0;
+       } else {
+               errlen = strlen(reply->errmsg) + 1;
+       }
+
+       length = offsetof(struct ctdb_reply_control_wire, data) +
+                datalen + errlen;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_reply_control_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->status = reply->status;
+
+       wire->datalen = datalen;
+       if (reply->status == 0) {
+               ctdb_reply_control_data_push(&reply->rdata, wire->data);
+       }
+
+       wire->errorlen = errlen;
+       if (errlen > 0) {
+               memcpy(wire->data + datalen, reply->errmsg, wire->errorlen);
+       }
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_reply_control_pull(uint8_t *pkt, size_t pkt_len, uint32_t opcode,
+                           struct ctdb_req_header *h,
+                           TALLOC_CTX *mem_ctx,
+                           struct ctdb_reply_control *reply)
+{
+       struct ctdb_reply_control_wire *wire =
+               (struct ctdb_reply_control_wire *)pkt;
+       size_t length;
+       int ret;
+
+       length = offsetof(struct ctdb_reply_control_wire, data);
+
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+       if (pkt_len < length + wire->datalen + wire->errorlen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       reply->status = wire->status;
+
+       if (reply->status != -1) {
+               ret = ctdb_reply_control_data_pull(wire->data, wire->datalen,
+                                                  opcode, mem_ctx,
+                                                  &reply->rdata);
+               if (ret != 0) {
+                       return ret;
+               }
+       }
+
+       if (wire->errorlen > 0) {
+               reply->errmsg = talloc_memdup(mem_ctx,
+                                             wire->data + wire->datalen,
+                                             wire->errorlen);
+       } else {
+               reply->errmsg = NULL;
+       }
+
+       return 0;
+}
diff --git a/ctdb/protocol/protocol_header.c b/ctdb/protocol/protocol_header.c
new file mode 100644 (file)
index 0000000..b802d08
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+
+int ctdb_req_header_verify(struct ctdb_req_header *h, uint32_t operation)
+{
+       if (h->length < sizeof(struct ctdb_req_header)) {
+               return EMSGSIZE;
+       }
+
+       if (h->ctdb_magic != CTDB_MAGIC) {
+               return EPROTO;
+       }
+
+       if (h->ctdb_version != CTDB_PROTOCOL) {
+               return EPROTO;
+       }
+
+       if (operation != 0 && h->operation != operation) {
+               return EPROTO;
+       }
+
+       return 0;
+}
+
+void ctdb_req_header_fill(struct ctdb_req_header *h, uint32_t generation,
+                         uint32_t operation, uint32_t destnode,
+                         uint32_t srcnode, uint32_t reqid)
+{
+       h->length = sizeof(struct ctdb_req_header);
+       h->ctdb_magic = CTDB_MAGIC;
+       h->ctdb_version = CTDB_PROTOCOL;
+       h->generation = generation;
+       h->operation = operation;
+       h->destnode = destnode;
+       h->srcnode = srcnode;
+       h->reqid = reqid;
+}
+
+int ctdb_req_header_pull(uint8_t *pkt, size_t pkt_len,
+                        struct ctdb_req_header *h)
+{
+       if (pkt_len < sizeof(struct ctdb_req_header)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, pkt, sizeof(struct ctdb_req_header));
+       return 0;
+}
diff --git a/ctdb/protocol/protocol_message.c b/ctdb/protocol/protocol_message.c
new file mode 100644 (file)
index 0000000..07d2dbb
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_api.h"
+#include "protocol_private.h"
+
+struct ctdb_req_message_wire {
+       struct ctdb_req_header hdr;
+       uint64_t srvid;
+       uint32_t datalen;
+       uint8_t data[1];
+};
+
+static size_t ctdb_message_data_len(union ctdb_message_data *mdata,
+                                   uint64_t srvid)
+{
+       size_t len = 0;
+
+       switch (srvid) {
+       case CTDB_SRVID_ELECTION:
+               len = ctdb_election_message_len(mdata->election);
+               break;
+
+       case CTDB_SRVID_RECONFIGURE:
+               break;
+
+       case CTDB_SRVID_RELEASE_IP:
+               len = ctdb_string_len(mdata->ipaddr);
+               break;
+
+       case CTDB_SRVID_TAKE_IP:
+               len = ctdb_string_len(mdata->ipaddr);
+               break;
+
+       case CTDB_SRVID_SET_NODE_FLAGS:
+               len = ctdb_node_flag_change_len(mdata->flag_change);
+               break;
+
+       case CTDB_SRVID_RECD_UPDATE_IP:
+               len = ctdb_public_ip_len(mdata->pubip);
+               break;
+
+       case CTDB_SRVID_VACUUM_FETCH:
+               len = ctdb_rec_buffer_len(mdata->recbuf);
+               break;
+
+       case CTDB_SRVID_DETACH_DATABASE:
+               len = ctdb_uint32_len(mdata->db_id);
+               break;
+
+       case CTDB_SRVID_MEM_DUMP:
+               len = ctdb_srvid_message_len(mdata->msg);
+               break;
+
+       case CTDB_SRVID_PUSH_NODE_FLAGS:
+               len = ctdb_node_flag_change_len(mdata->flag_change);
+               break;
+
+       case CTDB_SRVID_RELOAD_NODES:
+               break;
+
+       case CTDB_SRVID_TAKEOVER_RUN:
+               len = ctdb_srvid_message_len(mdata->msg);
+               break;
+
+       case CTDB_SRVID_REBALANCE_NODE:
+               len = ctdb_uint32_len(mdata->pnn);
+               break;
+
+       case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
+               len = ctdb_disable_message_len(mdata->disable);
+               break;
+
+       case CTDB_SRVID_DISABLE_RECOVERIES:
+               len = ctdb_disable_message_len(mdata->disable);
+               break;
+
+       case CTDB_SRVID_DISABLE_IP_CHECK:
+               len = ctdb_uint32_len(mdata->timeout);
+               break;
+       }
+
+       return len;
+}
+
+static void ctdb_message_data_push(union ctdb_message_data *mdata,
+                                  uint64_t srvid, uint8_t *buf)
+{
+       switch (srvid) {
+       case CTDB_SRVID_ELECTION:
+               ctdb_election_message_push(mdata->election, buf);
+               break;
+
+       case CTDB_SRVID_RECONFIGURE:
+               break;
+
+       case CTDB_SRVID_RELEASE_IP:
+               ctdb_string_push(mdata->ipaddr, buf);
+               break;
+
+       case CTDB_SRVID_TAKE_IP:
+               ctdb_string_push(mdata->ipaddr, buf);
+               break;
+
+       case CTDB_SRVID_SET_NODE_FLAGS:
+               ctdb_node_flag_change_push(mdata->flag_change, buf);
+               break;
+
+       case CTDB_SRVID_RECD_UPDATE_IP:
+               ctdb_public_ip_push(mdata->pubip, buf);
+               break;
+
+       case CTDB_SRVID_VACUUM_FETCH:
+               ctdb_rec_buffer_push(mdata->recbuf, buf);
+               break;
+
+       case CTDB_SRVID_DETACH_DATABASE:
+               ctdb_uint32_push(mdata->db_id, buf);
+               break;
+
+       case CTDB_SRVID_MEM_DUMP:
+               ctdb_srvid_message_push(mdata->msg, buf);
+               break;
+
+       case CTDB_SRVID_PUSH_NODE_FLAGS:
+               ctdb_node_flag_change_push(mdata->flag_change, buf);
+               break;
+
+       case CTDB_SRVID_RELOAD_NODES:
+               break;
+
+       case CTDB_SRVID_TAKEOVER_RUN:
+               ctdb_srvid_message_push(mdata->msg, buf);
+               break;
+
+       case CTDB_SRVID_REBALANCE_NODE:
+               ctdb_uint32_push(mdata->pnn, buf);
+               break;
+
+       case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
+               ctdb_disable_message_push(mdata->disable, buf);
+               break;
+
+       case CTDB_SRVID_DISABLE_RECOVERIES:
+               ctdb_disable_message_push(mdata->disable, buf);
+               break;
+
+       case CTDB_SRVID_DISABLE_IP_CHECK:
+               ctdb_uint32_push(mdata->timeout, buf);
+               break;
+       }
+}
+
+static int ctdb_message_data_pull(uint8_t *buf, size_t buflen,
+                                 uint64_t srvid, TALLOC_CTX *mem_ctx,
+                                 union ctdb_message_data *mdata)
+{
+       int ret = 0;
+
+       switch (srvid) {
+       case CTDB_SRVID_ELECTION:
+               ret = ctdb_election_message_pull(buf, buflen, mem_ctx,
+                                                &mdata->election);
+               break;
+
+       case CTDB_SRVID_RECONFIGURE:
+               break;
+
+       case CTDB_SRVID_RELEASE_IP:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr);
+               break;
+
+       case CTDB_SRVID_TAKE_IP:
+               ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr);
+               break;
+
+       case CTDB_SRVID_SET_NODE_FLAGS:
+               ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
+                                                &mdata->flag_change);
+               break;
+
+       case CTDB_SRVID_RECD_UPDATE_IP:
+               ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
+                                         &mdata->pubip);
+               break;
+
+       case CTDB_SRVID_VACUUM_FETCH:
+               ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
+                                          &mdata->recbuf);
+               break;
+
+       case CTDB_SRVID_DETACH_DATABASE:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->db_id);
+               break;
+
+       case CTDB_SRVID_MEM_DUMP:
+               ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx,
+                                             &mdata->msg);
+               break;
+
+       case CTDB_SRVID_PUSH_NODE_FLAGS:
+               ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
+                                                &mdata->flag_change);
+               break;
+
+       case CTDB_SRVID_RELOAD_NODES:
+               break;
+
+       case CTDB_SRVID_TAKEOVER_RUN:
+               ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx,
+                                             &mdata->msg);
+               break;
+
+       case CTDB_SRVID_REBALANCE_NODE:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->pnn);
+               break;
+
+       case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
+               ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
+                                               &mdata->disable);
+               break;
+
+       case CTDB_SRVID_DISABLE_RECOVERIES:
+               ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
+                                               &mdata->disable);
+               break;
+
+       case CTDB_SRVID_DISABLE_IP_CHECK:
+               ret = ctdb_uint32_pull(buf, buflen, mem_ctx, &mdata->timeout);
+               break;
+       }
+
+       return ret;
+}
+
+int ctdb_req_message_push(struct ctdb_req_header *h,
+                         struct ctdb_req_message *message,
+                         TALLOC_CTX *mem_ctx,
+                         uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_req_message_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen, datalen;
+       int ret;
+
+       datalen = ctdb_message_data_len(&message->data, message->srvid);
+       length = offsetof(struct ctdb_req_message_wire, data) + datalen;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_req_message_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->srvid = message->srvid;
+       wire->datalen = datalen;
+       ctdb_message_data_push(&message->data, message->srvid, wire->data);
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_req_message_pull(uint8_t *pkt, size_t pkt_len,
+                         struct ctdb_req_header *h,
+                         TALLOC_CTX *mem_ctx,
+                         struct ctdb_req_message *message)
+{
+       struct ctdb_req_message_wire *wire =
+               (struct ctdb_req_message_wire *)pkt;
+       size_t length;
+       int ret;
+
+       length = offsetof(struct ctdb_req_message_wire, data);
+
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+       if (pkt_len < length + wire->datalen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       message->srvid = wire->srvid;
+       ret = ctdb_message_data_pull(wire->data, wire->datalen, wire->srvid,
+                                    mem_ctx, &message->data);
+       return ret;
+}
+
+int ctdb_req_message_data_push(struct ctdb_req_header *h,
+                              struct ctdb_req_message_data *message,
+                              TALLOC_CTX *mem_ctx,
+                              uint8_t **pkt, size_t *pkt_len)
+{
+       struct ctdb_req_message_wire *wire;
+       uint8_t *buf;
+       size_t length, buflen;
+       int ret;
+
+       length = offsetof(struct ctdb_req_message_wire, data) +
+                message->data.dsize;
+
+       ret = allocate_pkt(mem_ctx, length, &buf, &buflen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       wire = (struct ctdb_req_message_wire *)buf;
+
+       h->length = buflen;
+       memcpy(&wire->hdr, h, sizeof(struct ctdb_req_header));
+
+       wire->srvid = message->srvid;
+       wire->datalen = message->data.dsize;
+       if (message->data.dsize > 0) {
+               memcpy(wire->data, message->data.dptr, message->data.dsize);
+       }
+
+       *pkt = buf;
+       *pkt_len = buflen;
+       return 0;
+}
+
+int ctdb_req_message_data_pull(uint8_t *pkt, size_t pkt_len,
+                              struct ctdb_req_header *h,
+                              TALLOC_CTX *mem_ctx,
+                              struct ctdb_req_message_data *message)
+{
+       struct ctdb_req_message_wire *wire =
+               (struct ctdb_req_message_wire *)pkt;
+       size_t length;
+
+       length = offsetof(struct ctdb_req_message_wire, data);
+
+       if (pkt_len < length) {
+               return EMSGSIZE;
+       }
+       if (pkt_len < length + wire->datalen) {
+               return EMSGSIZE;
+       }
+
+       memcpy(h, &wire->hdr, sizeof(struct ctdb_req_header));
+
+       message->srvid = wire->srvid;
+       message->data.dsize = wire->datalen;
+       if (wire->datalen > 0) {
+               message->data.dptr = talloc_memdup(mem_ctx, wire->data,
+                                                  wire->datalen);
+               if (message->data.dptr == NULL) {
+                       return ENOMEM;
+               }
+       }
+
+       return 0;
+}
diff --git a/ctdb/protocol/protocol_packet.c b/ctdb/protocol/protocol_packet.c
new file mode 100644 (file)
index 0000000..0e1a61c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol_private.h"
+
+#define CTDB_DS_ALIGNMENT 8
+
+int allocate_pkt(TALLOC_CTX *mem_ctx, size_t length,
+                uint8_t **buf, size_t *buflen)
+{
+       size_t new_length;
+
+       new_length = (length + CTDB_DS_ALIGNMENT-1) & ~(CTDB_DS_ALIGNMENT-1);
+
+       *buflen = new_length;
+       *buf = talloc_zero_size(mem_ctx, new_length);
+       if (*buf == NULL) {
+               return ENOMEM;
+       }
+
+       return 0;
+}
diff --git a/ctdb/protocol/protocol_private.h b/ctdb/protocol/protocol_private.h
new file mode 100644 (file)
index 0000000..ffe3fb2
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 __PROTOCOL_PRIVATE_H__
+#define __PROTOCOL_PRIVATE_H__
+
+#include "protocol.h"
+
+int allocate_pkt(TALLOC_CTX *mem_ctx, size_t length,
+                uint8_t **buf, size_t *buflen);
+
+size_t ctdb_uint32_len(uint32_t val);
+void ctdb_uint32_push(uint32_t val, uint8_t *buf);
+int ctdb_uint32_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    uint32_t *out);
+
+size_t ctdb_uint64_len(uint64_t val);
+void ctdb_uint64_push(uint64_t val, uint8_t *buf);
+int ctdb_uint64_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    uint64_t *out);
+
+size_t ctdb_double_len(double val);
+void ctdb_double_push(double val, uint8_t *buf);
+int ctdb_double_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    double *out);
+
+size_t ctdb_uint8_array_len(struct ctdb_uint8_array *array);
+void ctdb_uint8_array_push(struct ctdb_uint8_array *array, uint8_t *buf);
+int ctdb_uint8_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_uint8_array **out);
+
+size_t ctdb_uint64_array_len(struct ctdb_uint64_array *array);
+void ctdb_uint64_array_push(struct ctdb_uint64_array *array, uint8_t *buf);
+int ctdb_uint64_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                          struct ctdb_uint64_array **out);
+
+size_t ctdb_pid_len(pid_t pid);
+void ctdb_pid_push(pid_t pid, uint8_t *buf);
+int ctdb_pid_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                 pid_t *out);
+
+size_t ctdb_string_len(const char *str);
+void ctdb_string_push(const char *str, uint8_t *buf);
+int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    const char **out);
+
+size_t ctdb_stringn_len(const char *str);
+void ctdb_stringn_push(const char *str, uint8_t *buf);
+int ctdb_stringn_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                     const char **out);
+
+size_t ctdb_statistics_len(struct ctdb_statistics *stats);
+void ctdb_statistics_push(struct ctdb_statistics *stats, uint8_t *buf);
+int ctdb_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                        struct ctdb_statistics **out);
+
+size_t ctdb_statistics_list_len(struct ctdb_statistics_list *stats_list);
+void ctdb_statistics_list_push(struct ctdb_statistics_list *stats_list,
+                              uint8_t *buf);
+int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                             struct ctdb_statistics_list **out);
+
+size_t ctdb_vnn_map_len(struct ctdb_vnn_map *vnnmap);
+void ctdb_vnn_map_push(struct ctdb_vnn_map *vnnmap, uint8_t *buf);
+int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                     struct ctdb_vnn_map **out);
+
+size_t ctdb_dbid_map_len(struct ctdb_dbid_map *dbmap);
+void ctdb_dbid_map_push(struct ctdb_dbid_map *dbmap, uint8_t *buf);
+int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_dbid_map **out);
+
+size_t ctdb_pulldb_len(struct ctdb_pulldb *pulldb);
+void ctdb_pulldb_push(struct ctdb_pulldb *pulldb, uint8_t *buf);
+int ctdb_pulldb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    struct ctdb_pulldb **out);
+
+size_t ctdb_traverse_start_len(struct ctdb_traverse_start *traverse);
+void ctdb_traverse_start_push(struct ctdb_traverse_start *traverse,
+                             uint8_t *buf);
+int ctdb_traverse_start_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_traverse_start **out);
+
+size_t ctdb_traverse_all_len(struct ctdb_traverse_all *traverse);
+void ctdb_traverse_all_push(struct ctdb_traverse_all *traverse, uint8_t *buf);
+int ctdb_traverse_all_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                          struct ctdb_traverse_all **out);
+
+size_t ctdb_traverse_start_ext_len(struct ctdb_traverse_start_ext *traverse);
+void ctdb_traverse_start_ext_push(struct ctdb_traverse_start_ext *traverse,
+                                 uint8_t *buf);
+int ctdb_traverse_start_ext_pull(uint8_t *buf, size_t buflen,
+                                TALLOC_CTX *mem_ctx,
+                                struct ctdb_traverse_start_ext **out);
+
+size_t ctdb_traverse_all_ext_len(struct ctdb_traverse_all_ext *traverse);
+void ctdb_traverse_all_ext_push(struct ctdb_traverse_all_ext *traverse,
+                               uint8_t *buf);
+int ctdb_traverse_all_ext_pull(uint8_t *buf, size_t buflen,
+                              TALLOC_CTX *mem_ctx,
+                              struct ctdb_traverse_all_ext **out);
+
+size_t ctdb_sock_addr_len(ctdb_sock_addr *addr);
+void ctdb_sock_addr_push(ctdb_sock_addr *addr, uint8_t *buf);
+int ctdb_sock_addr_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       ctdb_sock_addr **out);
+
+size_t ctdb_connection_len(struct ctdb_connection *conn);
+void ctdb_connection_push(struct ctdb_connection *conn, uint8_t *buf);
+int ctdb_connection_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                        struct ctdb_connection **out);
+
+size_t ctdb_tunable_len(struct ctdb_tunable *tunable);
+void ctdb_tunable_push(struct ctdb_tunable *tunable, uint8_t *buf);
+int ctdb_tunable_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                     struct ctdb_tunable **out);
+
+size_t ctdb_node_flag_change_len(struct ctdb_node_flag_change *flag_change);
+void ctdb_node_flag_change_push(struct ctdb_node_flag_change *flag_change,
+                               uint8_t *buf);
+int ctdb_node_flag_change_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                              struct ctdb_node_flag_change **out);
+
+size_t ctdb_var_list_len(struct ctdb_var_list *var_list);
+void ctdb_var_list_push(struct ctdb_var_list *var_list, uint8_t *buf);
+int ctdb_var_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_var_list **out);
+
+size_t ctdb_tunable_list_len(struct ctdb_tunable_list *tun_list);
+void ctdb_tunable_list_push(struct ctdb_tunable_list *tun_list, uint8_t *buf);
+int ctdb_tunable_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                          struct ctdb_tunable_list **out);
+
+size_t ctdb_tickle_list_len(struct ctdb_tickle_list *tickles);
+void ctdb_tickle_list_push(struct ctdb_tickle_list *tickles, uint8_t *buf);
+int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_tickle_list **out);
+
+size_t ctdb_client_id_len(struct ctdb_client_id *cid);
+void ctdb_client_id_push(struct ctdb_client_id *cid, uint8_t *buf);
+int ctdb_client_id_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       struct ctdb_client_id **out);
+
+size_t ctdb_client_id_list_len(struct ctdb_client_id_list *cid_list);
+void ctdb_client_id_list_push(struct ctdb_client_id_list *cid_list,
+                             uint8_t *buf);
+int ctdb_client_id_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_client_id_list **out);
+
+size_t ctdb_client_id_map_len(struct ctdb_client_id_map *cid_map);
+void ctdb_client_id_map_push(struct ctdb_client_id_map *cid_map, uint8_t *buf);
+int ctdb_client_id_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                           struct ctdb_client_id_map **out);
+
+size_t ctdb_addr_info_len(struct ctdb_addr_info *addr_info);
+void ctdb_addr_info_push(struct ctdb_addr_info *addr_info, uint8_t *buf);
+int ctdb_addr_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       struct ctdb_addr_info **out);
+
+size_t ctdb_transdb_len(struct ctdb_transdb *transdb);
+void ctdb_transdb_push(struct ctdb_transdb *transdb, uint8_t *buf);
+int ctdb_transdb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    struct ctdb_transdb **out);
+
+size_t ctdb_uptime_len(struct ctdb_uptime *uptime);
+void ctdb_uptime_push(struct ctdb_uptime *uptime, uint8_t *buf);
+int ctdb_uptime_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    struct ctdb_uptime **out);
+
+size_t ctdb_public_ip_len(struct ctdb_public_ip *public_ip);
+void ctdb_public_ip_push(struct ctdb_public_ip *public_ip, uint8_t *buf);
+int ctdb_public_ip_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       struct ctdb_public_ip **out);
+
+size_t ctdb_public_ip_list_len(struct ctdb_public_ip_list *pubip_list);
+void ctdb_public_ip_list_push(struct ctdb_public_ip_list *pubip_list,
+                             uint8_t *buf);
+int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_public_ip_list **out);
+
+size_t ctdb_node_and_flags_len(struct ctdb_node_and_flags *node);
+void ctdb_node_and_flags_push(struct ctdb_node_and_flags *node, uint8_t *buf);
+int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_node_and_flags **out);
+
+size_t ctdb_node_map_len(struct ctdb_node_map *nodemap);
+void ctdb_node_map_push(struct ctdb_node_map *nodemap, uint8_t *buf);
+int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_node_map **out);
+
+size_t ctdb_script_len(struct ctdb_script *script);
+void ctdb_script_push(struct ctdb_script *script, uint8_t *buf);
+int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    struct ctdb_script **out);
+
+size_t ctdb_script_list_len(struct ctdb_script_list *script_list);
+void ctdb_script_list_push(struct ctdb_script_list *script_list, uint8_t *buf);
+int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_script_list **out);
+
+size_t ctdb_ban_state_len(struct ctdb_ban_state *ban_state);
+void ctdb_ban_state_push(struct ctdb_ban_state *ban_state, uint8_t *buf);
+int ctdb_ban_state_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       struct ctdb_ban_state **out);
+
+size_t ctdb_db_priority_len(struct ctdb_db_priority *db_prio);
+void ctdb_db_priority_push(struct ctdb_db_priority *db_prio, uint8_t *buf);
+int ctdb_db_priority_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_db_priority **out);
+
+size_t ctdb_notify_data_len(struct ctdb_notify_data *notify);
+void ctdb_notify_data_push(struct ctdb_notify_data *notify, uint8_t *buf);
+int ctdb_notify_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_notify_data **out);
+
+size_t ctdb_iface_len(struct ctdb_iface *iface);
+void ctdb_iface_push(struct ctdb_iface *iface, uint8_t *buf);
+int ctdb_iface_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                   struct ctdb_iface **out);
+
+size_t ctdb_iface_list_len(struct ctdb_iface_list *iface_list);
+void ctdb_iface_list_push(struct ctdb_iface_list *iface_list, uint8_t *buf);
+int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                        struct ctdb_iface_list **out);
+
+size_t ctdb_public_ip_info_len(struct ctdb_public_ip_info *ipinfo);
+void ctdb_public_ip_info_push(struct ctdb_public_ip_info *ipinfo, uint8_t *buf);
+int ctdb_public_ip_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_public_ip_info **out);
+
+size_t ctdb_key_data_len(struct ctdb_key_data *key);
+void ctdb_key_data_push(struct ctdb_key_data *key, uint8_t *buf);
+int ctdb_key_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_key_data **out);
+
+size_t ctdb_db_statistics_len(struct ctdb_db_statistics *dbstats);
+void ctdb_db_statistics_push(struct ctdb_db_statistics *dbstats, void *buf);
+int ctdb_db_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                           struct ctdb_db_statistics **out);
+
+size_t ctdb_election_message_len(struct ctdb_election_message *election);
+void ctdb_election_message_push(struct ctdb_election_message *election,
+                               uint8_t *buf);
+int ctdb_election_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                              struct ctdb_election_message **out);
+
+size_t ctdb_srvid_message_len(struct ctdb_srvid_message *msg);
+void ctdb_srvid_message_push(struct ctdb_srvid_message *msg, uint8_t *buf);
+int ctdb_srvid_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                           struct ctdb_srvid_message **out);
+
+size_t ctdb_disable_message_len(struct ctdb_disable_message *disable);
+void ctdb_disable_message_push(struct ctdb_disable_message *disable,
+                              uint8_t *buf);
+int ctdb_disable_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                             struct ctdb_disable_message **out);
+
+#endif /* __PROTOCOL_PRIVATE_H__ */
diff --git a/ctdb/protocol/protocol_types.c b/ctdb/protocol/protocol_types.c
new file mode 100644 (file)
index 0000000..f868d76
--- /dev/null
@@ -0,0 +1,2519 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_private.h"
+#include "protocol_api.h"
+
+size_t ctdb_uint32_len(uint32_t val)
+{
+       return sizeof(uint32_t);
+}
+
+void ctdb_uint32_push(uint32_t val, uint8_t *buf)
+{
+       memcpy(buf, &val, sizeof(uint32_t));
+}
+
+int ctdb_uint32_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    uint32_t *out)
+{
+       if (buflen < sizeof(uint32_t)) {
+               return EMSGSIZE;
+       }
+
+       *out = *(uint32_t *)buf;
+       return 0;
+}
+
+size_t ctdb_uint64_len(uint64_t val)
+{
+       return sizeof(uint64_t);
+}
+
+void ctdb_uint64_push(uint64_t val, uint8_t *buf)
+{
+       memcpy(buf, &val, sizeof(uint64_t));
+}
+
+int ctdb_uint64_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    uint64_t *out)
+{
+       if (buflen < sizeof(uint64_t)) {
+               return EMSGSIZE;
+       }
+
+       *out = *(uint64_t *)buf;
+       return 0;
+}
+
+size_t ctdb_double_len(double val)
+{
+       return sizeof(double);
+}
+
+void ctdb_double_push(double val, uint8_t *buf)
+{
+       memcpy(buf, &val, sizeof(double));
+}
+
+int ctdb_double_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    double *out)
+{
+       if (buflen < sizeof(double)) {
+               return EMSGSIZE;
+       }
+
+       *out = *(double *)buf;
+       return 0;
+}
+
+size_t ctdb_uint8_array_len(struct ctdb_uint8_array *array)
+{
+       return array->num * sizeof(uint8_t);
+}
+
+void ctdb_uint8_array_push(struct ctdb_uint8_array *array, uint8_t *buf)
+{
+       memcpy(buf, array->val, array->num * sizeof(uint8_t));
+}
+
+int ctdb_uint8_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_uint8_array **out)
+{
+       struct ctdb_uint8_array *array;
+
+       array = talloc(mem_ctx, struct ctdb_uint8_array);
+       if (array == NULL) {
+               return ENOMEM;
+       }
+
+       array->num = buflen / sizeof(uint8_t);
+
+       array->val = talloc_array(array, uint8_t, array->num);
+       if (array->val == NULL) {
+               talloc_free(array);
+               return ENOMEM;
+       }
+       memcpy(array->val, buf, buflen);
+
+       *out = array;
+       return 0;
+}
+
+size_t ctdb_uint64_array_len(struct ctdb_uint64_array *array)
+{
+       return array->num * sizeof(uint64_t);
+}
+
+void ctdb_uint64_array_push(struct ctdb_uint64_array *array, uint8_t *buf)
+{
+       memcpy(buf, array->val, array->num * sizeof(uint64_t));
+}
+
+int ctdb_uint64_array_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                          struct ctdb_uint64_array **out)
+{
+       struct ctdb_uint64_array *array;
+
+       array = talloc(mem_ctx, struct ctdb_uint64_array);
+       if (array == NULL) {
+               return ENOMEM;
+       }
+
+       array->num = buflen / sizeof(uint64_t);
+
+       array->val = talloc_array(array, uint64_t, array->num);
+       if (array->val == NULL) {
+               talloc_free(array);
+               return ENOMEM;
+       }
+       memcpy(array->val, buf, buflen);
+
+       *out = array;
+       return 0;
+}
+
+size_t ctdb_pid_len(pid_t pid)
+{
+       return sizeof(pid_t);
+}
+
+void ctdb_pid_push(pid_t pid, uint8_t *buf)
+{
+       memcpy(buf, &pid, sizeof(pid_t));
+}
+
+int ctdb_pid_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                 pid_t *out)
+{
+       if (buflen < sizeof(pid_t)) {
+               return EMSGSIZE;
+       }
+
+       *out = *(pid_t *)buf;
+       return 0;
+}
+
+size_t ctdb_string_len(const char *str)
+{
+       if (str == NULL) {
+               return 0;
+       }
+       return strlen(str) + 1;
+}
+
+void ctdb_string_push(const char *str, uint8_t *buf)
+{
+       if (str == NULL) {
+               return;
+       }
+       memcpy(buf, str, strlen(str)+1);
+}
+
+int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    const char **out)
+{
+       char *str;
+
+       if (buflen == 0) {
+               return 0;
+       }
+
+       str = talloc_strndup(mem_ctx, (char *)buf, buflen);
+       if (str == NULL) {
+               return ENOMEM;
+       }
+
+       *out = str;
+       return 0;
+}
+
+struct stringn_wire {
+       uint32_t length;
+       uint8_t str[1];
+};
+
+size_t ctdb_stringn_len(const char *str)
+{
+       return sizeof(uint32_t) + strlen(str) + 1;
+}
+
+void ctdb_stringn_push(const char *str, uint8_t *buf)
+{
+       struct stringn_wire *wire = (struct stringn_wire *)buf;
+
+       if (str == NULL) {
+               wire->length = 0;
+       } else {
+               wire->length = strlen(str) + 1;
+               memcpy(wire->str, str, wire->length);
+       }
+}
+
+int ctdb_stringn_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                     const char **out)
+{
+       char *str;
+       struct stringn_wire *wire = (struct stringn_wire *)buf;
+
+       if (buflen < sizeof(uint32_t)) {
+               return EMSGSIZE;
+       }
+
+       if (buflen < sizeof(uint32_t) + wire->length) {
+               return EMSGSIZE;
+       }
+
+       str = talloc_strndup(mem_ctx, (char *)wire->str, wire->length);
+       if (str == NULL) {
+               return ENOMEM;
+       }
+
+       *out = str;
+       return 0;
+}
+
+size_t ctdb_statistics_len(struct ctdb_statistics *stats)
+{
+       return sizeof(struct ctdb_statistics);
+}
+
+void ctdb_statistics_push(struct ctdb_statistics *stats, uint8_t *buf)
+{
+       memcpy(buf, stats, sizeof(struct ctdb_statistics));
+}
+
+int ctdb_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                        struct ctdb_statistics **out)
+{
+       struct ctdb_statistics *stats;
+       struct ctdb_statistics *wire = (struct ctdb_statistics *)buf;
+
+       if (buflen < sizeof(struct ctdb_statistics)) {
+               return EMSGSIZE;
+       }
+
+       stats = talloc(mem_ctx, struct ctdb_statistics);
+       if (stats == NULL) {
+               return ENOMEM;
+       }
+       memcpy(stats, wire, sizeof(struct ctdb_statistics));
+
+       *out = stats;
+       return 0;
+}
+
+struct ctdb_statistics_list_wire {
+       uint32_t num;
+       struct ctdb_statistics stats[1];
+};
+
+size_t ctdb_statistics_list_len(struct ctdb_statistics_list *stats_list)
+{
+       return offsetof(struct ctdb_statistics_list_wire, stats) +
+              stats_list->num * sizeof(struct ctdb_statistics);
+}
+
+void ctdb_statistics_list_push(struct ctdb_statistics_list *stats_list,
+                              uint8_t *buf)
+{
+       struct ctdb_statistics_list_wire *wire =
+               (struct ctdb_statistics_list_wire *)buf;
+
+       wire->num = stats_list->num;
+       memcpy(wire->stats, stats_list->stats,
+              stats_list->num * sizeof(struct ctdb_statistics));
+}
+
+int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                             struct ctdb_statistics_list **out)
+{
+       struct ctdb_statistics_list *stats_list;
+       struct ctdb_statistics_list_wire *wire =
+               (struct ctdb_statistics_list_wire *)buf;
+
+       if (buflen < offsetof(struct ctdb_statistics_list_wire, stats)) {
+               return EMSGSIZE;
+       }
+       if (buflen < offsetof(struct ctdb_statistics_list_wire, stats) +
+                    wire->num * sizeof(struct ctdb_statistics)) {
+               return EMSGSIZE;
+       }
+
+       stats_list = talloc(mem_ctx, struct ctdb_statistics_list);
+       if (stats_list == NULL) {
+               return ENOMEM;
+       }
+
+       stats_list->num = wire->num;
+
+       stats_list->stats = talloc_array(stats_list, struct ctdb_statistics,
+                                        wire->num);
+       if (stats_list->stats == NULL) {
+               talloc_free(stats_list);
+               return ENOMEM;
+       }
+
+       memcpy(stats_list->stats, wire->stats,
+              wire->num * sizeof(struct ctdb_statistics));
+
+       *out = stats_list;
+       return 0;
+}
+
+struct ctdb_vnn_map_wire {
+       uint32_t generation;
+       uint32_t size;
+       uint32_t map[1];
+};
+
+size_t ctdb_vnn_map_len(struct ctdb_vnn_map *vnnmap)
+{
+       return offsetof(struct ctdb_vnn_map, map) +
+              vnnmap->size * sizeof(uint32_t);
+}
+
+void ctdb_vnn_map_push(struct ctdb_vnn_map *vnnmap, uint8_t *buf)
+{
+       struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf;
+
+       memcpy(wire, vnnmap, offsetof(struct ctdb_vnn_map, map));
+       memcpy(wire->map, vnnmap->map, vnnmap->size * sizeof(uint32_t));
+}
+
+int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                     struct ctdb_vnn_map **out)
+{
+       struct ctdb_vnn_map *vnnmap;
+       struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf;
+
+       if (buflen < offsetof(struct ctdb_vnn_map_wire, map)) {
+               return EMSGSIZE;
+       }
+       if (buflen < offsetof(struct ctdb_vnn_map_wire, map) +
+                    wire->size * sizeof(uint32_t)) {
+               return EMSGSIZE;
+       }
+
+       vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
+       if (vnnmap == NULL) {
+               return ENOMEM;
+       }
+
+       memcpy(vnnmap, wire, offsetof(struct ctdb_vnn_map, map));
+
+       vnnmap->map = talloc_memdup(vnnmap, wire->map,
+                                   wire->size * sizeof(uint32_t));
+       if (vnnmap->map == NULL) {
+               talloc_free(vnnmap);
+               return ENOMEM;
+       }
+
+       *out = vnnmap;
+       return 0;
+}
+
+struct ctdb_dbid_map_wire {
+       uint32_t num;
+       struct ctdb_dbid dbs[1];
+};
+
+size_t ctdb_dbid_map_len(struct ctdb_dbid_map *dbmap)
+{
+       return sizeof(uint32_t) + dbmap->num * sizeof(struct ctdb_dbid);
+}
+
+void ctdb_dbid_map_push(struct ctdb_dbid_map *dbmap, uint8_t *buf)
+{
+       struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf;
+
+       wire->num = dbmap->num;
+       memcpy(wire->dbs, dbmap->dbs, dbmap->num * sizeof(struct ctdb_dbid));
+}
+
+int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_dbid_map **out)
+{
+       struct ctdb_dbid_map *dbmap;
+       struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf;
+
+       if (buflen < sizeof(uint32_t)) {
+               return EMSGSIZE;
+       }
+       if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_dbid)) {
+               return EMSGSIZE;
+       }
+
+       dbmap = talloc(mem_ctx, struct ctdb_dbid_map);
+       if (dbmap == NULL) {
+               return ENOMEM;
+       }
+
+       dbmap->num = wire->num;
+
+       dbmap->dbs = talloc_memdup(dbmap, wire->dbs,
+                                  wire->num * sizeof(struct ctdb_dbid));
+       if (dbmap->dbs == NULL) {
+               talloc_free(dbmap);
+               return ENOMEM;
+       }
+
+       *out = dbmap;
+       return 0;
+}
+
+size_t ctdb_pulldb_len(struct ctdb_pulldb *pulldb)
+{
+       return sizeof(struct ctdb_pulldb);
+}
+
+void ctdb_pulldb_push(struct ctdb_pulldb *pulldb, uint8_t *buf)
+{
+       memcpy(buf, pulldb, sizeof(struct ctdb_pulldb));
+}
+
+int ctdb_pulldb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    struct ctdb_pulldb **out)
+{
+       struct ctdb_pulldb *pulldb;
+
+       if (buflen < sizeof(struct ctdb_pulldb)) {
+               return EMSGSIZE;
+       }
+
+       pulldb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_pulldb));
+       if (pulldb == NULL) {
+               return ENOMEM;
+       }
+
+       *out = pulldb;
+       return 0;
+}
+
+size_t ctdb_ltdb_header_len(struct ctdb_ltdb_header *header)
+{
+       return sizeof(struct ctdb_ltdb_header);
+}
+
+void ctdb_ltdb_header_push(struct ctdb_ltdb_header *header, uint8_t *buf)
+{
+       memcpy(buf, header, sizeof(struct ctdb_ltdb_header));
+}
+
+int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen,
+                         struct ctdb_ltdb_header *header)
+{
+       if (buflen < sizeof(struct ctdb_ltdb_header)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(header, buf, sizeof(struct ctdb_ltdb_header));
+       return 0;
+}
+
+struct ctdb_rec_data_wire {
+       uint32_t length;
+       uint32_t reqid;
+       uint32_t keylen;
+       uint32_t datalen;
+       uint8_t data[1];
+};
+
+size_t ctdb_rec_data_len(struct ctdb_rec_data *rec)
+{
+       return offsetof(struct ctdb_rec_data_wire, data) +
+              rec->key.dsize + rec->data.dsize +
+              (rec->header == NULL ? 0 : sizeof(struct ctdb_ltdb_header));
+}
+
+void ctdb_rec_data_push(struct ctdb_rec_data *rec, uint8_t *buf)
+{
+       struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf;
+       size_t offset;
+
+       wire->length = ctdb_rec_data_len(rec);
+       wire->reqid = rec->reqid;
+       wire->keylen = rec->key.dsize;
+       wire->datalen = rec->data.dsize;
+
+       memcpy(wire->data, rec->key.dptr, rec->key.dsize);
+       offset = rec->key.dsize;
+       if (rec->header != NULL) {
+               memcpy(&wire->data[offset], rec->header,
+                      sizeof(struct ctdb_ltdb_header));
+               offset += sizeof(struct ctdb_ltdb_header);
+       }
+       if (rec->data.dsize > 0) {
+               memcpy(&wire->data[offset], rec->data.dptr, rec->data.dsize);
+       }
+}
+
+static int ctdb_rec_data_pull_data(uint8_t *buf, size_t buflen,
+                                  uint32_t *reqid,
+                                  struct ctdb_ltdb_header **header,
+                                  TDB_DATA *key, TDB_DATA *data,
+                                  size_t *reclen)
+{
+       struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf;
+       size_t offset, n;
+
+       if (buflen < offsetof(struct ctdb_rec_data_wire, data)) {
+               return EMSGSIZE;
+       }
+       n = offsetof(struct ctdb_rec_data_wire, data) +
+               wire->keylen + wire->datalen;
+       if (buflen < n) {
+               return EMSGSIZE;
+       }
+
+       *reqid = wire->reqid;
+
+       key->dsize = wire->keylen;
+       key->dptr = wire->data;
+       offset = wire->keylen;
+
+       if (wire->length - n == sizeof(struct ctdb_ltdb_header)) {
+               *header = (struct ctdb_ltdb_header *)&wire->data[offset];
+               offset += sizeof(struct ctdb_ltdb_header);
+       } else {
+               *header = NULL;
+       }
+
+       data->dsize = wire->datalen;
+       data->dptr = &wire->data[offset];
+
+       *reclen = n;
+
+       return 0;
+}
+
+static int ctdb_rec_data_pull_elems(uint8_t *buf, size_t buflen,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct ctdb_rec_data *out)
+{
+       uint32_t reqid;
+       struct ctdb_ltdb_header *header;
+       TDB_DATA key, data;
+       size_t reclen;
+       int ret;
+
+       ret = ctdb_rec_data_pull_data(buf, buflen, &reqid, &header,
+                                     &key, &data, &reclen);
+       if (ret != 0) {
+               return ret;
+       }
+
+       out->reqid = reqid;
+
+       if (header != NULL) {
+               out->header = talloc_memdup(mem_ctx, header,
+                                           sizeof(struct ctdb_ltdb_header));
+               if (out->header == NULL) {
+                       return ENOMEM;
+               }
+       } else {
+               out->header = NULL;
+       }
+
+       out->key.dsize = key.dsize;
+       if (key.dsize > 0) {
+               out->key.dptr = talloc_memdup(mem_ctx, key.dptr, key.dsize);
+               if (out->key.dptr == NULL) {
+                       return ENOMEM;
+               }
+       }
+
+       out->data.dsize = data.dsize;
+       if (data.dsize > 0) {
+               out->data.dptr = talloc_memdup(mem_ctx, data.dptr, data.dsize);
+               if (out->data.dptr == NULL) {
+                       return ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_rec_data **out)
+{
+       struct ctdb_rec_data *rec;
+       int ret;
+
+       rec = talloc(mem_ctx, struct ctdb_rec_data);
+       if (rec == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_rec_data_pull_elems(buf, buflen, rec, rec);
+       if (ret != 0) {
+               TALLOC_FREE(rec);
+       }
+
+       *out = rec;
+       return ret;
+}
+
+struct ctdb_rec_buffer_wire {
+       uint32_t db_id;
+       uint32_t count;
+       uint8_t data[1];
+};
+
+size_t ctdb_rec_buffer_len(struct ctdb_rec_buffer *recbuf)
+{
+       return offsetof(struct ctdb_rec_buffer_wire, data) + recbuf->buflen;
+}
+
+void ctdb_rec_buffer_push(struct ctdb_rec_buffer *recbuf, uint8_t *buf)
+{
+       struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf;
+
+       wire->db_id = recbuf->db_id;
+       wire->count = recbuf->count;
+       if (recbuf->buflen > 0) {
+               memcpy(wire->data, recbuf->buf, recbuf->buflen);
+       }
+}
+
+int ctdb_rec_buffer_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                        struct ctdb_rec_buffer **out)
+{
+       struct ctdb_rec_buffer *recbuf;
+       struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf;
+       size_t offset;
+
+       if (buflen < offsetof(struct ctdb_rec_buffer_wire, data)) {
+               return EMSGSIZE;
+       }
+
+       recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+       if (recbuf == NULL) {
+               return ENOMEM;
+       }
+
+       recbuf->db_id = wire->db_id;
+       recbuf->count = wire->count;
+
+       offset = offsetof(struct ctdb_rec_buffer_wire, data);
+       recbuf->buflen = buflen - offset;
+       recbuf->buf = talloc_memdup(recbuf, wire->data, recbuf->buflen);
+       if (recbuf->buf == NULL) {
+               talloc_free(recbuf);
+               return ENOMEM;
+       }
+
+       *out = recbuf;
+       return 0;
+}
+
+struct ctdb_rec_buffer *ctdb_rec_buffer_init(TALLOC_CTX *mem_ctx,
+                                            uint32_t db_id)
+{
+       struct ctdb_rec_buffer *recbuf;
+
+       recbuf = talloc_zero(mem_ctx, struct ctdb_rec_buffer);
+       if (recbuf == NULL) {
+               return recbuf;
+       }
+
+       recbuf->db_id = db_id;
+
+       return recbuf;
+}
+
+int ctdb_rec_buffer_add(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *recbuf,
+                       uint32_t reqid, struct ctdb_ltdb_header *header,
+                       TDB_DATA key, TDB_DATA data)
+{
+       struct ctdb_rec_data recdata;
+       size_t len;
+       uint8_t *ptr;
+
+       recdata.reqid = reqid;
+       recdata.header = header;
+       recdata.key = key;
+       recdata.data = data;
+
+       len = ctdb_rec_data_len(&recdata);
+
+       ptr = talloc_realloc(mem_ctx, recbuf->buf, uint8_t,
+                            recbuf->buflen + len);
+       if (ptr == NULL) {
+               return ENOMEM;
+       }
+
+       ctdb_rec_data_push(&recdata, &ptr[recbuf->buflen]);
+
+       recbuf->count++;
+       recbuf->buf = ptr;
+       recbuf->buflen += len;
+       return 0;
+}
+
+int ctdb_rec_buffer_traverse(struct ctdb_rec_buffer *recbuf,
+                            ctdb_rec_parser_func_t func,
+                            void *private_data)
+{
+       struct ctdb_ltdb_header *header;
+       TDB_DATA key, data;
+       uint32_t reqid;
+       size_t offset, reclen;
+       int ret = 0, i;
+
+       offset = 0;
+       for (i=0; i<recbuf->count; i++) {
+               ret = ctdb_rec_data_pull_data(&recbuf->buf[offset],
+                                             recbuf->buflen - offset,
+                                             &reqid, &header,
+                                             &key, &data, &reclen);
+               if (ret != 0) {
+                       return ret;
+               }
+
+               ret = func(reqid, header, key, data, private_data);
+               if (ret != 0) {
+                       break;
+               }
+
+               offset += reclen;
+       }
+
+       return ret;
+}
+
+size_t ctdb_traverse_start_len(struct ctdb_traverse_start *traverse)
+{
+       return sizeof(struct ctdb_traverse_start);
+}
+
+void ctdb_traverse_start_push(struct ctdb_traverse_start *traverse,
+                             uint8_t *buf)
+{
+       memcpy(buf, traverse, sizeof(struct ctdb_traverse_start));
+}
+
+int ctdb_traverse_start_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_traverse_start **out)
+{
+       struct ctdb_traverse_start *traverse;
+
+       if (buflen < sizeof(struct ctdb_traverse_start)) {
+               return EMSGSIZE;
+       }
+
+       traverse = talloc_memdup(mem_ctx, buf,
+                                sizeof(struct ctdb_traverse_start));
+       if (traverse == NULL) {
+               return ENOMEM;
+       }
+
+       *out = traverse;
+       return 0;
+}
+
+size_t ctdb_traverse_all_len(struct ctdb_traverse_all *traverse)
+{
+       return sizeof(struct ctdb_traverse_all);
+}
+
+void ctdb_traverse_all_push(struct ctdb_traverse_all *traverse, uint8_t *buf)
+{
+       memcpy(buf, traverse, sizeof(struct ctdb_traverse_all));
+}
+
+int ctdb_traverse_all_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                          struct ctdb_traverse_all **out)
+{
+       struct ctdb_traverse_all *traverse;
+
+       if (buflen < sizeof(struct ctdb_traverse_all)) {
+               return EMSGSIZE;
+       }
+
+       traverse = talloc_memdup(mem_ctx, buf,
+                                sizeof(struct ctdb_traverse_all));
+       if (traverse == NULL) {
+               return ENOMEM;
+       }
+
+       *out = traverse;
+       return 0;
+}
+
+size_t ctdb_traverse_start_ext_len(struct ctdb_traverse_start_ext *traverse)
+{
+       return sizeof(struct ctdb_traverse_start_ext);
+}
+
+void ctdb_traverse_start_ext_push(struct ctdb_traverse_start_ext *traverse,
+                                 uint8_t *buf)
+{
+       memcpy(buf, traverse, sizeof(struct ctdb_traverse_start_ext));
+}
+
+int ctdb_traverse_start_ext_pull(uint8_t *buf, size_t buflen,
+                                TALLOC_CTX *mem_ctx,
+                                struct ctdb_traverse_start_ext **out)
+{
+       struct ctdb_traverse_start_ext *traverse;
+
+       if (buflen < sizeof(struct ctdb_traverse_start_ext)) {
+               return EMSGSIZE;
+       }
+
+       traverse = talloc_memdup(mem_ctx, buf,
+                                sizeof(struct ctdb_traverse_start_ext));
+       if (traverse == NULL) {
+               return ENOMEM;
+       }
+
+       *out = traverse;
+       return 0;
+}
+
+size_t ctdb_traverse_all_ext_len(struct ctdb_traverse_all_ext *traverse)
+{
+       return sizeof(struct ctdb_traverse_all_ext);
+}
+
+void ctdb_traverse_all_ext_push(struct ctdb_traverse_all_ext *traverse,
+                               uint8_t *buf)
+{
+       memcpy(buf, traverse, sizeof(struct ctdb_traverse_all_ext));
+}
+
+int ctdb_traverse_all_ext_pull(uint8_t *buf, size_t buflen,
+                              TALLOC_CTX *mem_ctx,
+                              struct ctdb_traverse_all_ext **out)
+{
+       struct ctdb_traverse_all_ext *traverse;
+
+       if (buflen < sizeof(struct ctdb_traverse_all_ext)) {
+               return EMSGSIZE;
+       }
+
+       traverse = talloc_memdup(mem_ctx, buf,
+                                sizeof(struct ctdb_traverse_all_ext));
+       if (traverse == NULL) {
+               return ENOMEM;
+       }
+
+       *out = traverse;
+       return 0;
+}
+
+size_t ctdb_sock_addr_len(ctdb_sock_addr *addr)
+{
+       return sizeof(ctdb_sock_addr);
+}
+
+void ctdb_sock_addr_push(ctdb_sock_addr *addr, uint8_t *buf)
+{
+       memcpy(buf, addr, sizeof(ctdb_sock_addr));
+}
+
+static int ctdb_sock_addr_pull_elems(uint8_t *buf, size_t buflen,
+                                    TALLOC_CTX *mem_ctx, ctdb_sock_addr *out)
+{
+       if (buflen < sizeof(ctdb_sock_addr)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(out, buf, sizeof(ctdb_sock_addr));
+
+       return 0;
+}
+
+int ctdb_sock_addr_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       ctdb_sock_addr **out)
+{
+       ctdb_sock_addr *addr;
+       int ret;
+
+       addr = talloc(mem_ctx, ctdb_sock_addr);
+       if (addr == NULL) {
+               return false;
+       }
+
+       ret = ctdb_sock_addr_pull_elems(buf, buflen, addr, addr);
+       if (ret != 0) {
+               TALLOC_FREE(addr);
+       }
+
+       *out = addr;
+       return ret;
+}
+
+size_t ctdb_connection_len(struct ctdb_connection *conn)
+{
+       return sizeof(struct ctdb_connection);
+}
+
+void ctdb_connection_push(struct ctdb_connection *conn, uint8_t *buf)
+{
+       memcpy(buf, conn, sizeof(struct ctdb_connection));
+}
+
+static int ctdb_connection_pull_elems(uint8_t *buf, size_t buflen,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct ctdb_connection *out)
+{
+       if (buflen < sizeof(struct ctdb_connection)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(out, buf, sizeof(struct ctdb_connection));
+
+       return 0;
+}
+
+int ctdb_connection_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                        struct ctdb_connection **out)
+{
+       struct ctdb_connection *conn;
+       int ret;
+
+       conn = talloc(mem_ctx, struct ctdb_connection);
+       if (conn == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_connection_pull_elems(buf, buflen, conn, conn);
+       if (ret != 0) {
+               TALLOC_FREE(conn);
+       }
+
+       *out = conn;
+       return ret;
+}
+
+struct ctdb_tunable_wire {
+       uint32_t value;
+       uint32_t length;
+       uint8_t name[1];
+};
+
+size_t ctdb_tunable_len(struct ctdb_tunable *tunable)
+{
+       return offsetof(struct ctdb_tunable_wire, name) +
+              strlen(tunable->name) + 1;
+}
+
+void ctdb_tunable_push(struct ctdb_tunable *tunable, uint8_t *buf)
+{
+       struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf;
+
+       wire->value = tunable->value;
+       wire->length = strlen(tunable->name) + 1;
+       memcpy(wire->name, tunable->name, wire->length);
+}
+
+int ctdb_tunable_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                     struct ctdb_tunable **out)
+{
+       struct ctdb_tunable *tunable;
+       struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf;
+
+       if (buflen < offsetof(struct ctdb_tunable_wire, name)) {
+               return EMSGSIZE;
+       }
+       if (buflen < offsetof(struct ctdb_tunable_wire, name) + wire->length) {
+               return EMSGSIZE;
+       }
+
+       tunable = talloc(mem_ctx, struct ctdb_tunable);
+       if (tunable == NULL) {
+               return ENOMEM;
+       }
+
+       tunable->value = wire->value;
+       tunable->name = talloc_memdup(tunable, wire->name, wire->length);
+       if (tunable->name == NULL) {
+               talloc_free(tunable);
+               return ENOMEM;
+       }
+
+       *out = tunable;
+       return 0;
+}
+
+size_t ctdb_node_flag_change_len(struct ctdb_node_flag_change *flag_change)
+{
+       return sizeof(struct ctdb_node_flag_change);
+}
+
+void ctdb_node_flag_change_push(struct ctdb_node_flag_change *flag_change,
+                               uint8_t *buf)
+{
+       memcpy(buf, flag_change, sizeof(struct ctdb_node_flag_change));
+}
+
+int ctdb_node_flag_change_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                              struct ctdb_node_flag_change **out)
+{
+       struct ctdb_node_flag_change *flag_change;
+
+       if (buflen < sizeof(struct ctdb_node_flag_change)) {
+               return EMSGSIZE;
+       }
+
+       flag_change = talloc_memdup(mem_ctx, buf,
+                                   sizeof(struct ctdb_node_flag_change));
+       if (flag_change == NULL) {
+               return ENOMEM;
+       }
+
+       *out = flag_change;
+       return 0;
+}
+
+struct ctdb_var_list_wire {
+       uint32_t length;
+       char list_str[1];
+};
+
+size_t ctdb_var_list_len(struct ctdb_var_list *var_list)
+{
+       int i;
+       size_t len = sizeof(uint32_t);
+
+       for (i=0; i<var_list->count; i++) {
+               len += strlen(var_list->var[i]) + 1;
+       }
+       return len;
+}
+
+void ctdb_var_list_push(struct ctdb_var_list *var_list, uint8_t *buf)
+{
+       struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf;
+       int i, n;
+       size_t offset = 0;
+
+       if (var_list->count > 0) {
+               n = sprintf(wire->list_str, "%s", var_list->var[0]);
+               offset += n;
+       }
+       for (i=1; i<var_list->count; i++) {
+               n = sprintf(&wire->list_str[offset], ":%s", var_list->var[i]);
+               offset += n;
+       }
+       wire->length = offset + 1;
+}
+
+int ctdb_var_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_var_list **out)
+{
+       struct ctdb_var_list *var_list = NULL;
+       struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf;
+       char *str, *s, *tok, *ptr;
+       const char **list;
+
+       if (buflen < sizeof(uint32_t)) {
+               return EMSGSIZE;
+       }
+       if (buflen < sizeof(uint32_t) + wire->length) {
+               return EMSGSIZE;
+       }
+
+       str = talloc_strndup(mem_ctx, (char *)wire->list_str, wire->length);
+       if (str == NULL) {
+               return ENOMEM;
+       }
+
+       var_list = talloc_zero(mem_ctx, struct ctdb_var_list);
+       if (var_list == NULL) {
+               goto fail;
+       }
+
+       s = str;
+       while ((tok = strtok_r(s, ":", &ptr)) != NULL) {
+               s = NULL;
+               list = talloc_realloc(var_list, var_list->var, const char *,
+                                     var_list->count+1);
+               if (list == NULL) {
+                       goto fail;
+               }
+
+               var_list->var = list;
+               var_list->var[var_list->count] = talloc_strdup(var_list, tok);
+               if (var_list->var[var_list->count] == NULL) {
+                       goto fail;
+               }
+               var_list->count++;
+       }
+
+       talloc_free(str);
+       *out = var_list;
+       return 0;
+
+fail:
+       talloc_free(str);
+       talloc_free(var_list);
+       return ENOMEM;
+}
+
+size_t ctdb_tunable_list_len(struct ctdb_tunable_list *tun_list)
+{
+       return sizeof(struct ctdb_tunable_list);
+}
+
+void ctdb_tunable_list_push(struct ctdb_tunable_list *tun_list, uint8_t *buf)
+{
+       memcpy(buf, tun_list, sizeof(struct ctdb_tunable_list));
+}
+
+int ctdb_tunable_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                          struct ctdb_tunable_list **out)
+{
+       struct ctdb_tunable_list *tun_list;
+
+       if (buflen < sizeof(struct ctdb_tunable_list)) {
+               return EMSGSIZE;
+       }
+
+       tun_list = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_tunable_list));
+       if (tun_list == NULL) {
+               return ENOMEM;
+       }
+
+       *out = tun_list;
+       return 0;
+}
+
+struct ctdb_tickle_list_wire {
+       ctdb_sock_addr addr;
+       uint32_t num;
+       struct ctdb_connection conn[1];
+};
+
+size_t ctdb_tickle_list_len(struct ctdb_tickle_list *tickles)
+{
+       return offsetof(struct ctdb_tickle_list, conn) +
+              tickles->num * sizeof(struct ctdb_connection);
+}
+
+void ctdb_tickle_list_push(struct ctdb_tickle_list *tickles, uint8_t *buf)
+{
+       struct ctdb_tickle_list_wire *wire =
+               (struct ctdb_tickle_list_wire *)buf;
+       size_t offset;
+       int i;
+
+       memcpy(&wire->addr, &tickles->addr, sizeof(ctdb_sock_addr));
+       wire->num = tickles->num;
+
+       offset = offsetof(struct ctdb_tickle_list_wire, conn);
+       for (i=0; i<tickles->num; i++) {
+               ctdb_connection_push(&tickles->conn[i], &buf[offset]);
+               offset += ctdb_connection_len(&tickles->conn[i]);
+       }
+}
+
+int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                          struct ctdb_tickle_list **out)
+{
+       struct ctdb_tickle_list *tickles;
+       struct ctdb_tickle_list_wire *wire =
+               (struct ctdb_tickle_list_wire *)buf;
+       size_t offset;
+       int i, ret;
+
+       if (buflen < offsetof(struct ctdb_tickle_list_wire, conn)) {
+               return EMSGSIZE;
+       }
+       if (buflen < offsetof(struct ctdb_tickle_list_wire, conn) +
+                    wire->num * sizeof(struct ctdb_connection)) {
+               return EMSGSIZE;
+       }
+
+       tickles = talloc(mem_ctx, struct ctdb_tickle_list);
+       if (tickles == NULL) {
+               return ENOMEM;
+       }
+
+       offset = offsetof(struct ctdb_tickle_list, conn);
+       memcpy(tickles, wire, offset);
+
+       tickles->conn = talloc_array(tickles, struct ctdb_connection,
+                                    wire->num);
+       if (tickles->conn == NULL) {
+               talloc_free(tickles);
+               return ENOMEM;
+       }
+
+       for (i=0; i<wire->num; i++) {
+               ret = ctdb_connection_pull_elems(&buf[offset], buflen-offset,
+                                                tickles->conn,
+                                                &tickles->conn[i]);
+               if (ret != 0) {
+                       talloc_free(tickles);
+                       return ret;
+               }
+               offset += ctdb_connection_len(&tickles->conn[i]);
+       }
+
+       *out = tickles;
+       return 0;
+}
+
+size_t ctdb_client_id_len(struct ctdb_client_id *cid)
+{
+       return sizeof(struct ctdb_client_id);
+}
+
+void ctdb_client_id_push(struct ctdb_client_id *cid, uint8_t *buf)
+{
+       memcpy(buf, cid, sizeof(struct ctdb_client_id));
+}
+
+static int ctdb_client_id_pull_elems(uint8_t *buf, size_t buflen,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct ctdb_client_id *out)
+{
+       if (buflen < sizeof(struct ctdb_client_id)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(out, buf, sizeof(struct ctdb_client_id));
+
+       return 0;
+}
+
+int ctdb_client_id_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       struct ctdb_client_id **out)
+{
+       struct ctdb_client_id *cid;
+       int ret;
+
+       cid = talloc(mem_ctx, struct ctdb_client_id);
+       if (cid == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_client_id_pull_elems(buf, buflen, cid, cid);
+       if (ret != 0) {
+               TALLOC_FREE(cid);
+       }
+
+       *out = cid;
+       return ret;
+}
+
+struct ctdb_client_id_list_wire {
+       uint32_t num;
+       struct ctdb_client_id cid[1];
+};
+
+size_t ctdb_client_id_list_len(struct ctdb_client_id_list *cid_list)
+{
+       return sizeof(uint32_t) +
+              cid_list->num * sizeof(struct ctdb_client_id);
+}
+
+void ctdb_client_id_list_push(struct ctdb_client_id_list *cid_list,
+                             uint8_t *buf)
+{
+       struct ctdb_client_id_list_wire *wire =
+               (struct ctdb_client_id_list_wire *)buf;
+       size_t offset;
+       int i;
+
+       wire->num = cid_list->num;
+
+       offset = offsetof(struct ctdb_client_id_list_wire, cid);
+       for (i=0; i<cid_list->num; i++) {
+               ctdb_client_id_push(&cid_list->cid[i], &buf[offset]);
+               offset += ctdb_client_id_len(&cid_list->cid[i]);
+       }
+}
+
+static int ctdb_client_id_list_pull_elems(uint8_t *buf, size_t buflen,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct ctdb_client_id_list *out)
+{
+       struct ctdb_client_id_list_wire *wire =
+               (struct ctdb_client_id_list_wire *)buf;
+       size_t offset;
+       int i;
+
+       if (buflen < sizeof(uint32_t)) {
+               return EMSGSIZE;
+       }
+       if (buflen < sizeof(uint32_t) +
+                    wire->num * sizeof(struct ctdb_client_id)) {
+               return EMSGSIZE;
+       }
+
+       out->num = wire->num;
+       out->cid = talloc_array(mem_ctx, struct ctdb_client_id,
+                               wire->num);
+       if (out->cid == NULL) {
+               return ENOMEM;
+       }
+
+       offset = offsetof(struct ctdb_client_id_list_wire, cid);
+       for (i=0; i<wire->num; i++) {
+               bool ret;
+               ret = ctdb_client_id_pull_elems(&buf[offset], buflen-offset,
+                                               out->cid, &out->cid[i]);
+               if (ret != 0) {
+                       return ret;
+               }
+               offset += ctdb_client_id_len(&out->cid[i]);
+       }
+
+       return 0;
+}
+
+int ctdb_client_id_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_client_id_list **out)
+{
+       struct ctdb_client_id_list *cid_list;
+       int ret;
+
+       cid_list = talloc(mem_ctx, struct ctdb_client_id_list);
+       if (cid_list == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_client_id_list_pull_elems(buf, buflen, cid_list, cid_list);
+       if (ret != 0) {
+               TALLOC_FREE(cid_list);
+       }
+
+       *out = cid_list;
+       return ret;
+}
+
+struct ctdb_client_id_map_wire {
+       int count;
+       struct ctdb_client_id_list list[1];
+};
+
+size_t ctdb_client_id_map_len(struct ctdb_client_id_map *cid_map)
+{
+       int i;
+       size_t len;
+
+       len = sizeof(int);
+       for (i=0; i<cid_map->count; i++) {
+               len += ctdb_client_id_list_len(&cid_map->list[i]);
+       }
+       return len;
+}
+
+void ctdb_client_id_map_push(struct ctdb_client_id_map *cid_map, uint8_t *buf)
+{
+       struct ctdb_client_id_map_wire *wire =
+               (struct ctdb_client_id_map_wire *)buf;
+       size_t offset;
+       int i;
+
+       wire->count = cid_map->count;
+
+       offset = sizeof(int);
+       for (i=0; i<cid_map->count; i++) {
+               ctdb_client_id_list_push(&cid_map->list[i], &buf[offset]);
+               offset += ctdb_client_id_list_len(&cid_map->list[i]);
+       }
+}
+
+int ctdb_client_id_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                           struct ctdb_client_id_map **out)
+{
+       struct ctdb_client_id_map *cid_map;
+       struct ctdb_client_id_map_wire *wire =
+               (struct ctdb_client_id_map_wire *)buf;
+       size_t offset;
+       int i;
+       bool ret;
+
+       if (buflen < sizeof(int)) {
+               return EMSGSIZE;
+       }
+       if (buflen < sizeof(int) +
+                    wire->count * sizeof(struct ctdb_client_id_list)) {
+               return EMSGSIZE;
+       }
+
+       cid_map = talloc(mem_ctx, struct ctdb_client_id_map);
+       if (cid_map == NULL) {
+               return ENOMEM;
+       }
+
+       cid_map->count = wire->count;
+       cid_map->list = talloc_array(cid_map, struct ctdb_client_id_list,
+                                    wire->count);
+       if (cid_map->list == NULL) {
+               return ENOMEM;
+       }
+
+       offset = sizeof(int);
+       for (i=0; i<wire->count; i++) {
+               ret = ctdb_client_id_list_pull_elems(&buf[offset],
+                                                    buflen-offset,
+                                                    cid_map->list,
+                                                    &cid_map->list[i]);
+               if (ret != 0) {
+                       talloc_free(cid_map);
+                       return ret;
+               }
+               offset += ctdb_client_id_list_len(&cid_map->list[i]);
+       }
+
+       *out = cid_map;
+       return 0;
+}
+
+struct ctdb_addr_info_wire {
+       ctdb_sock_addr addr;
+       uint32_t mask;
+       uint32_t len;
+       char iface[1];
+};
+
+size_t ctdb_addr_info_len(struct ctdb_addr_info *arp)
+{
+       return offsetof(struct ctdb_addr_info_wire, iface) +
+              strlen(arp->iface)+1;
+}
+
+void ctdb_addr_info_push(struct ctdb_addr_info *addr_info, uint8_t *buf)
+{
+       struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf;
+
+       wire->addr = addr_info->addr;
+       wire->mask = addr_info->mask;
+       wire->len = strlen(addr_info->iface)+1;
+       memcpy(wire->iface, addr_info->iface, wire->len);
+}
+
+int ctdb_addr_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       struct ctdb_addr_info **out)
+{
+       struct ctdb_addr_info *addr_info;
+       struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf;
+
+       if (buflen < offsetof(struct ctdb_addr_info_wire, iface)) {
+               return EMSGSIZE;
+       }
+       if (buflen < offsetof(struct ctdb_addr_info_wire, iface) + wire->len) {
+               return EMSGSIZE;
+       }
+
+       addr_info = talloc(mem_ctx, struct ctdb_addr_info);
+       if (addr_info == NULL) {
+               return ENOMEM;
+       }
+
+       addr_info->addr = wire->addr;
+       addr_info->mask = wire->mask;
+
+       addr_info->iface = talloc_strndup(addr_info, wire->iface, wire->len);
+       if (addr_info->iface == NULL) {
+               talloc_free(addr_info);
+               return ENOMEM;
+       }
+
+       *out = addr_info;
+       return 0;
+}
+
+size_t ctdb_transdb_len(struct ctdb_transdb *transdb)
+{
+       return sizeof(struct ctdb_transdb);
+}
+
+void ctdb_transdb_push(struct ctdb_transdb *transdb, uint8_t *buf)
+{
+       memcpy(buf, transdb, sizeof(struct ctdb_transdb));
+}
+
+int ctdb_transdb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    struct ctdb_transdb **out)
+{
+       struct ctdb_transdb *transdb;
+
+       if (buflen < sizeof(struct ctdb_transdb)) {
+               return EMSGSIZE;
+       }
+
+       transdb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_transdb));
+       if (transdb == NULL) {
+               return ENOMEM;
+       }
+
+       *out = transdb;
+       return 0;
+}
+
+size_t ctdb_uptime_len(struct ctdb_uptime *uptime)
+{
+       return sizeof(struct ctdb_uptime);
+}
+
+void ctdb_uptime_push(struct ctdb_uptime *uptime, uint8_t *buf)
+{
+       memcpy(buf, uptime, sizeof(struct ctdb_uptime));
+}
+
+int ctdb_uptime_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    struct ctdb_uptime **out)
+{
+       struct ctdb_uptime *uptime;
+
+       if (buflen < sizeof(struct ctdb_uptime)) {
+               return EMSGSIZE;
+       }
+
+       uptime = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_uptime));
+       if (uptime == NULL) {
+               return ENOMEM;
+       }
+
+       *out = uptime;
+       return 0;
+}
+
+size_t ctdb_public_ip_len(struct ctdb_public_ip *pubip)
+{
+       return sizeof(struct ctdb_public_ip);
+}
+
+void ctdb_public_ip_push(struct ctdb_public_ip *pubip, uint8_t *buf)
+{
+       memcpy(buf, pubip, sizeof(struct ctdb_public_ip));
+}
+
+static int ctdb_public_ip_pull_elems(uint8_t *buf, size_t buflen,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct ctdb_public_ip *out)
+{
+       if (buflen < sizeof(struct ctdb_public_ip)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(out, buf, sizeof(struct ctdb_public_ip));
+
+       return 0;
+}
+
+int ctdb_public_ip_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       struct ctdb_public_ip **out)
+{
+       struct ctdb_public_ip *pubip;
+       int ret;
+
+       pubip = talloc(mem_ctx, struct ctdb_public_ip);
+       if (pubip == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_public_ip_pull_elems(buf, buflen, pubip, pubip);
+       if (ret != 0) {
+               TALLOC_FREE(pubip);
+       }
+
+       *out = pubip;
+       return ret;
+}
+
+struct ctdb_public_ip_list_wire {
+       uint32_t num;
+       struct ctdb_public_ip ip[1];
+};
+
+size_t ctdb_public_ip_list_len(struct ctdb_public_ip_list *pubip_list)
+{
+       int i;
+       size_t len;
+
+       len = sizeof(uint32_t);
+       for (i=0; i<pubip_list->num; i++) {
+               len += ctdb_public_ip_len(&pubip_list->ip[i]);
+       }
+       return len;
+}
+
+void ctdb_public_ip_list_push(struct ctdb_public_ip_list *pubip_list,
+                             uint8_t *buf)
+{
+       struct ctdb_public_ip_list_wire *wire =
+               (struct ctdb_public_ip_list_wire *)buf;
+       size_t offset;
+       int i;
+
+       wire->num = pubip_list->num;
+
+       offset = offsetof(struct ctdb_public_ip_list_wire, ip);
+       for (i=0; i<pubip_list->num; i++) {
+               ctdb_public_ip_push(&pubip_list->ip[i], &buf[offset]);
+               offset += ctdb_public_ip_len(&pubip_list->ip[i]);
+       }
+}
+
+int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_public_ip_list **out)
+{
+       struct ctdb_public_ip_list *pubip_list;
+       struct ctdb_public_ip_list_wire *wire =
+               (struct ctdb_public_ip_list_wire *)buf;
+       size_t offset;
+       int i;
+       bool ret;
+
+       if (buflen < sizeof(uint32_t)) {
+               return EMSGSIZE;
+       }
+       if (buflen < sizeof(uint32_t) +
+                    wire->num * sizeof(struct ctdb_public_ip)) {
+               return EMSGSIZE;
+       }
+
+       pubip_list = talloc(mem_ctx, struct ctdb_public_ip_list);
+       if (pubip_list == NULL) {
+               return ENOMEM;
+       }
+
+       pubip_list->num = wire->num;
+       pubip_list->ip = talloc_array(pubip_list, struct ctdb_public_ip,
+                                     wire->num);
+       if (pubip_list->ip == NULL) {
+               talloc_free(pubip_list);
+               return ENOMEM;
+       }
+
+       offset = offsetof(struct ctdb_public_ip_list_wire, ip);
+       for (i=0; i<wire->num; i++) {
+               ret = ctdb_public_ip_pull_elems(&buf[offset], buflen-offset,
+                                               pubip_list->ip,
+                                               &pubip_list->ip[i]);
+               if (ret != 0) {
+                       talloc_free(pubip_list);
+                       return ret;
+               }
+               offset += ctdb_public_ip_len(&pubip_list->ip[i]);
+       }
+
+       *out = pubip_list;
+       return 0;
+}
+
+size_t ctdb_node_and_flags_len(struct ctdb_node_and_flags *node)
+{
+       return sizeof(struct ctdb_node_and_flags);
+}
+
+void ctdb_node_and_flags_push(struct ctdb_node_and_flags *node, uint8_t *buf)
+{
+       memcpy(buf, node, sizeof(struct ctdb_node_and_flags));
+}
+
+static int ctdb_node_and_flags_pull_elems(TALLOC_CTX *mem_ctx,
+                                         uint8_t *buf, size_t buflen,
+                                         struct ctdb_node_and_flags *out)
+{
+       if (buflen < sizeof(struct ctdb_node_and_flags)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(out, buf, sizeof(struct ctdb_node_and_flags));
+
+       return 0;
+}
+
+int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                             struct ctdb_node_and_flags **out)
+{
+       struct ctdb_node_and_flags *node;
+       int ret;
+
+       node = talloc(mem_ctx, struct ctdb_node_and_flags);
+       if (node == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_node_and_flags_pull_elems(node, buf, buflen, node);
+       if (ret != 0) {
+               TALLOC_FREE(node);
+       }
+
+       *out = node;
+       return ret;
+}
+
+struct ctdb_node_map_wire {
+       uint32_t num;
+       struct ctdb_node_and_flags node[1];
+};
+
+size_t ctdb_node_map_len(struct ctdb_node_map *nodemap)
+{
+       return sizeof(uint32_t) +
+              nodemap->num * sizeof(struct ctdb_node_and_flags);
+}
+
+void ctdb_node_map_push(struct ctdb_node_map *nodemap, uint8_t *buf)
+{
+       struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf;
+       size_t offset;
+       int i;
+
+       wire->num = nodemap->num;
+
+       offset = offsetof(struct ctdb_node_map_wire, node);
+       for (i=0; i<nodemap->num; i++) {
+               ctdb_node_and_flags_push(&nodemap->node[i], &buf[offset]);
+               offset += ctdb_node_and_flags_len(&nodemap->node[i]);
+       }
+}
+
+int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_node_map **out)
+{
+       struct ctdb_node_map *nodemap;
+       struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf;
+       size_t offset;
+       int i;
+       bool ret;
+
+       nodemap = talloc(mem_ctx, struct ctdb_node_map);
+       if (nodemap == NULL) {
+               return ENOMEM;
+       }
+
+       nodemap->num = wire->num;
+       nodemap->node = talloc_array(nodemap, struct ctdb_node_and_flags,
+                                    wire->num);
+       if (nodemap->node == NULL) {
+               talloc_free(nodemap);
+               return ENOMEM;
+       }
+
+       offset = offsetof(struct ctdb_node_map_wire, node);
+       for (i=0; i<wire->num; i++) {
+               ret = ctdb_node_and_flags_pull_elems(nodemap->node,
+                                                    &buf[offset],
+                                                    buflen-offset,
+                                                    &nodemap->node[i]);
+               if (ret != 0) {
+                       talloc_free(nodemap);
+                       return ret;
+               }
+               offset += ctdb_node_and_flags_len(&nodemap->node[i]);
+       }
+
+       *out = nodemap;
+       return 0;
+}
+
+size_t ctdb_script_len(struct ctdb_script *script)
+{
+       return sizeof(struct ctdb_script);
+}
+
+void ctdb_script_push(struct ctdb_script *script, uint8_t *buf)
+{
+       memcpy(buf, script, sizeof(struct ctdb_script));
+}
+
+static int ctdb_script_pull_elems(uint8_t *buf, size_t buflen,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct ctdb_script *out)
+{
+       if (buflen < sizeof(struct ctdb_script)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(out, buf, sizeof(struct ctdb_script));
+
+       return 0;
+}
+
+int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                    struct ctdb_script **out)
+{
+       struct ctdb_script *script;
+       int ret;
+
+       script = talloc(mem_ctx, struct ctdb_script);
+       if (script == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_script_pull_elems(buf, buflen, script, script);
+       if (ret != 0) {
+               TALLOC_FREE(script);
+       }
+
+       *out = script;
+       return ret;
+}
+
+struct ctdb_script_list_wire {
+       uint32_t num_scripts;
+       struct ctdb_script script[1];
+};
+
+size_t ctdb_script_list_len(struct ctdb_script_list *script_list)
+{
+       int i;
+       size_t len;
+
+       if (script_list == NULL) {
+               return 0;
+       }
+
+       len = offsetof(struct ctdb_script_list_wire, script);
+       for (i=0; i<script_list->num_scripts; i++) {
+               len += ctdb_script_len(&script_list->script[i]);
+       }
+       return len;
+}
+
+void ctdb_script_list_push(struct ctdb_script_list *script_list, uint8_t *buf)
+{
+       struct ctdb_script_list_wire *wire =
+               (struct ctdb_script_list_wire *)buf;
+       size_t offset;
+       int i;
+
+       if (script_list == NULL) {
+               return;
+       }
+
+       wire->num_scripts = script_list->num_scripts;
+
+       offset = offsetof(struct ctdb_script_list_wire, script);
+       for (i=0; i<script_list->num_scripts; i++) {
+               ctdb_script_push(&script_list->script[i], &buf[offset]);
+               offset += ctdb_script_len(&script_list->script[i]);
+       }
+}
+
+int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_script_list **out)
+{
+       struct ctdb_script_list *script_list;
+       struct ctdb_script_list_wire *wire =
+               (struct ctdb_script_list_wire *)buf;
+       size_t offset;
+       int i;
+       bool ret;
+
+       /* If event scripts have never been run, the result will be NULL */
+       if (buflen == 0) {
+               *out = NULL;
+               return 0;
+       }
+
+       offset = offsetof(struct ctdb_script_list_wire, script);
+
+       if (buflen < offset) {
+               return EMSGSIZE;
+       }
+       if (buflen < offset + wire->num_scripts * sizeof(struct ctdb_script)) {
+               return EMSGSIZE;
+       }
+
+       script_list = talloc(mem_ctx, struct ctdb_script_list);
+       if (script_list == NULL) {
+               return ENOMEM;
+
+       }
+
+       script_list->num_scripts = wire->num_scripts;
+       script_list->script = talloc_array(script_list, struct ctdb_script,
+                                          wire->num_scripts);
+       if (script_list->script == NULL) {
+               talloc_free(script_list);
+               return ENOMEM;
+       }
+
+       for (i=0; i<wire->num_scripts; i++) {
+               ret = ctdb_script_pull_elems(&buf[offset], buflen-offset,
+                                            script_list->script,
+                                            &script_list->script[i]);
+               if (ret != 0) {
+                       talloc_free(script_list);
+                       return ret;
+               }
+               offset += ctdb_script_len(&script_list->script[i]);
+       }
+
+       *out = script_list;
+       return 0;
+}
+
+size_t ctdb_ban_state_len(struct ctdb_ban_state *ban_state)
+{
+       return sizeof(struct ctdb_ban_state);
+}
+
+void ctdb_ban_state_push(struct ctdb_ban_state *ban_state, uint8_t *buf)
+{
+       memcpy(buf, ban_state, sizeof(struct ctdb_ban_state));
+}
+
+int ctdb_ban_state_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                       struct ctdb_ban_state **out)
+{
+       struct ctdb_ban_state *ban_state;
+
+       if (buflen < sizeof(struct ctdb_ban_state)) {
+               return EMSGSIZE;
+       }
+
+       ban_state = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_ban_state));
+       if (ban_state == NULL) {
+               return ENOMEM;
+       }
+
+       *out = ban_state;
+       return 0;
+}
+
+size_t ctdb_db_priority_len(struct ctdb_db_priority *db_prio)
+{
+       return sizeof(struct ctdb_db_priority);
+}
+
+void ctdb_db_priority_push(struct ctdb_db_priority *db_prio, uint8_t *buf)
+{
+       memcpy(buf, db_prio, sizeof(struct ctdb_db_priority));
+}
+
+int ctdb_db_priority_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_db_priority **out)
+{
+       struct ctdb_db_priority *db_prio;
+
+       if (buflen < sizeof(struct ctdb_db_priority)) {
+               return EMSGSIZE;
+       }
+
+       db_prio = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_db_priority));
+       if (db_prio == NULL) {
+               return ENOMEM;
+       }
+
+       *out = db_prio;
+       return 0;
+}
+
+struct ctdb_notify_data_wire {
+       uint64_t srvid;
+       uint32_t len;
+       uint8_t data[1];
+};
+
+size_t ctdb_notify_data_len(struct ctdb_notify_data *notify)
+{
+       return offsetof(struct ctdb_notify_data_wire, data) +
+              notify->data.dsize;
+}
+
+void ctdb_notify_data_push(struct ctdb_notify_data *notify, uint8_t *buf)
+{
+       struct ctdb_notify_data_wire *wire =
+               (struct ctdb_notify_data_wire *)buf;
+
+       wire->srvid = notify->srvid;
+       wire->len = notify->data.dsize;
+       memcpy(wire->data, notify->data.dptr, notify->data.dsize);
+}
+
+int ctdb_notify_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_notify_data **out)
+{
+       struct ctdb_notify_data *notify;
+       struct ctdb_notify_data_wire *wire =
+               (struct ctdb_notify_data_wire *)buf;
+
+       if (buflen < offsetof(struct ctdb_notify_data_wire, data)) {
+               return EMSGSIZE;
+       }
+       if (buflen < offsetof(struct ctdb_notify_data_wire, data) + wire->len) {
+               return EMSGSIZE;
+       }
+
+       notify = talloc(mem_ctx, struct ctdb_notify_data);
+       if (notify == NULL) {
+               return ENOMEM;
+       }
+
+       notify->srvid = wire->srvid;
+       notify->data.dsize = wire->len;
+       notify->data.dptr = talloc_memdup(notify, wire->data, wire->len);
+       if (notify->data.dptr == NULL) {
+               talloc_free(notify);
+               return ENOMEM;
+       }
+
+       *out = notify;
+       return 0;
+}
+
+size_t ctdb_iface_len(struct ctdb_iface *iface)
+{
+       return sizeof(struct ctdb_iface);
+}
+
+void ctdb_iface_push(struct ctdb_iface *iface, uint8_t *buf)
+{
+       memcpy(buf, iface, sizeof(struct ctdb_iface));
+}
+
+static int ctdb_iface_pull_elems(uint8_t *buf, size_t buflen,
+                                TALLOC_CTX *mem_ctx,
+                                struct ctdb_iface *out)
+{
+       if (buflen < sizeof(struct ctdb_iface)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(out, buf, sizeof(struct ctdb_iface));
+
+       return 0;
+}
+
+int ctdb_iface_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                   struct ctdb_iface **out)
+{
+       struct ctdb_iface *iface;
+       int ret;
+
+       iface = talloc(mem_ctx, struct ctdb_iface);
+       if (iface == NULL) {
+               return ENOMEM;
+       }
+
+       ret = ctdb_iface_pull_elems(buf, buflen, iface, iface);
+       if (ret != 0) {
+               TALLOC_FREE(iface);
+       }
+
+       *out = iface;
+       return ret;
+}
+
+struct ctdb_iface_list_wire {
+       uint32_t num;
+       struct ctdb_iface iface[1];
+};
+
+size_t ctdb_iface_list_len(struct ctdb_iface_list *iface_list)
+{
+       return sizeof(uint32_t) +
+              iface_list->num * sizeof(struct ctdb_iface);
+}
+
+void ctdb_iface_list_push(struct ctdb_iface_list *iface_list, uint8_t *buf)
+{
+       struct ctdb_iface_list_wire *wire =
+               (struct ctdb_iface_list_wire *)buf;
+
+       wire->num = iface_list->num;
+       memcpy(wire->iface, iface_list->iface,
+              iface_list->num * sizeof(struct ctdb_iface));
+}
+
+int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                        struct ctdb_iface_list **out)
+{
+       struct ctdb_iface_list *iface_list;
+       struct ctdb_iface_list_wire *wire =
+               (struct ctdb_iface_list_wire *)buf;
+
+       if (buflen < sizeof(uint32_t)) {
+               return EMSGSIZE;
+       }
+       if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_iface)) {
+               return EMSGSIZE;
+       }
+
+       iface_list = talloc(mem_ctx, struct ctdb_iface_list);
+       if (iface_list == NULL) {
+               return ENOMEM;
+       }
+
+       iface_list->num = wire->num;
+       iface_list->iface = talloc_array(iface_list, struct ctdb_iface,
+                                        wire->num);
+       if (iface_list->iface == NULL) {
+               talloc_free(iface_list);
+               return ENOMEM;
+       }
+
+       memcpy(iface_list->iface, wire->iface,
+              wire->num * sizeof(struct ctdb_iface));
+
+       *out = iface_list;
+       return 0;
+}
+
+struct ctdb_public_ip_info_wire {
+       struct ctdb_public_ip ip;
+       uint32_t active_idx;
+       uint32_t num;
+       struct ctdb_iface ifaces[1];
+};
+
+size_t ctdb_public_ip_info_len(struct ctdb_public_ip_info *ipinfo)
+{
+       return offsetof(struct ctdb_public_ip_info_wire, num) +
+              ctdb_iface_list_len(ipinfo->ifaces);
+}
+
+void ctdb_public_ip_info_push(struct ctdb_public_ip_info *ipinfo, uint8_t *buf)
+{
+       struct ctdb_public_ip_info_wire *wire =
+               (struct ctdb_public_ip_info_wire *)buf;
+       size_t offset;
+
+       offset = offsetof(struct ctdb_public_ip_info_wire, num);
+       memcpy(wire, ipinfo, offset);
+       wire->num = ipinfo->ifaces->num;
+       memcpy(wire->ifaces, ipinfo->ifaces->iface,
+              ipinfo->ifaces->num * sizeof(struct ctdb_iface));
+}
+
+int ctdb_public_ip_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                            struct ctdb_public_ip_info **out)
+{
+       struct ctdb_public_ip_info *ipinfo;
+       struct ctdb_public_ip_info_wire *wire =
+               (struct ctdb_public_ip_info_wire *)buf;
+
+       if (buflen < offsetof(struct ctdb_public_ip_info_wire, ifaces)) {
+               return EMSGSIZE;
+       }
+
+       ipinfo = talloc(mem_ctx, struct ctdb_public_ip_info);
+       if (ipinfo == NULL) {
+               return ENOMEM;
+       }
+
+       memcpy(ipinfo, wire, offsetof(struct ctdb_public_ip_info_wire, num));
+
+       ipinfo->ifaces = talloc(ipinfo, struct ctdb_iface_list);
+       if (ipinfo->ifaces == NULL) {
+               talloc_free(ipinfo);
+               return ENOMEM;
+       }
+
+       ipinfo->ifaces->num = wire->num;
+       ipinfo->ifaces->iface = talloc_array(ipinfo->ifaces, struct ctdb_iface,
+                                            wire->num);
+       if (ipinfo->ifaces->iface == NULL) {
+               talloc_free(ipinfo);
+               return ENOMEM;
+       }
+
+       memcpy(ipinfo->ifaces->iface, wire->ifaces,
+              wire->num * sizeof(struct ctdb_iface));
+
+       *out = ipinfo;
+       return 0;
+}
+
+struct ctdb_key_data_wire {
+       uint32_t db_id;
+       struct ctdb_ltdb_header header;
+       uint32_t keylen;
+       uint8_t key[1];
+};
+
+size_t ctdb_key_data_len(struct ctdb_key_data *key)
+{
+       return offsetof(struct ctdb_key_data_wire, key) + key->key.dsize;
+}
+
+void ctdb_key_data_push(struct ctdb_key_data *key, uint8_t *buf)
+{
+       struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf;
+
+       memcpy(wire, key, offsetof(struct ctdb_key_data, key));
+       wire->keylen = key->key.dsize;
+       memcpy(wire->key, key->key.dptr, key->key.dsize);
+}
+
+int ctdb_key_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                      struct ctdb_key_data **out)
+{
+       struct ctdb_key_data *key_data;
+       struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf;
+
+       if (buflen < offsetof(struct ctdb_key_data_wire, key)) {
+               return EMSGSIZE;
+       }
+       if (buflen < offsetof(struct ctdb_key_data_wire, key) + wire->keylen) {
+               return EMSGSIZE;
+       }
+
+       key_data = talloc(mem_ctx, struct ctdb_key_data);
+       if (key_data == NULL) {
+               return ENOMEM;
+       }
+
+       memcpy(key_data, wire, offsetof(struct ctdb_key_data, key));
+
+       key_data->key.dsize = wire->keylen;
+       key_data->key.dptr = talloc_memdup(key_data, wire->key, wire->keylen);
+       if (key_data->key.dptr == NULL) {
+               talloc_free(key_data);
+               return ENOMEM;
+       }
+
+       *out = key_data;
+       return 0;
+}
+
+struct ctdb_db_statistics_wire {
+       struct ctdb_db_statistics dbstats;
+       char hot_keys_wire[1];
+};
+
+size_t ctdb_db_statistics_len(struct ctdb_db_statistics *dbstats)
+{
+       size_t len;
+       int i;
+
+       len = sizeof(struct ctdb_db_statistics);
+       for (i=0; i<MAX_HOT_KEYS; i++) {
+               len += dbstats->hot_keys[i].key.dsize;
+       }
+       return len;
+}
+
+void ctdb_db_statistics_push(struct ctdb_db_statistics *dbstats, void *buf)
+{
+       struct ctdb_db_statistics_wire *wire =
+               (struct ctdb_db_statistics_wire *)buf;
+       size_t offset;
+       int i;
+
+       dbstats->num_hot_keys = MAX_HOT_KEYS;
+       memcpy(wire, dbstats, sizeof(struct ctdb_db_statistics));
+
+       offset = 0;
+       for (i=0; i<MAX_HOT_KEYS; i++) {
+               memcpy(&wire->hot_keys_wire[offset],
+                      dbstats->hot_keys[i].key.dptr,
+                      dbstats->hot_keys[i].key.dsize);
+               offset += dbstats->hot_keys[i].key.dsize;
+       }
+}
+
+int ctdb_db_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                           struct ctdb_db_statistics **out)
+{
+       struct ctdb_db_statistics *dbstats;
+       struct ctdb_db_statistics_wire *wire =
+               (struct ctdb_db_statistics_wire *)buf;
+       size_t offset;
+       int i;
+
+       if (buflen < sizeof(struct ctdb_db_statistics)) {
+               return EMSGSIZE;
+       }
+       offset = 0;
+       for (i=0; i<wire->dbstats.num_hot_keys; i++) {
+               offset += wire->dbstats.hot_keys[i].key.dsize;
+       }
+       if (buflen < sizeof(struct ctdb_db_statistics) + offset) {
+               return EMSGSIZE;
+       }
+
+       dbstats = talloc(mem_ctx, struct ctdb_db_statistics);
+       if (dbstats == NULL) {
+               return ENOMEM;
+       }
+
+       memcpy(dbstats, wire, sizeof(struct ctdb_db_statistics));
+
+       offset = 0;
+       for (i=0; i<wire->dbstats.num_hot_keys; i++) {
+               uint8_t *ptr;
+               size_t key_size;
+
+               key_size = dbstats->hot_keys[i].key.dsize;
+               ptr = talloc_memdup(mem_ctx, &wire->hot_keys_wire[offset],
+                                   key_size);
+               if (ptr == NULL) {
+                       talloc_free(dbstats);
+                       return ENOMEM;
+               }
+               dbstats->hot_keys[i].key.dptr = ptr;
+               offset += key_size;
+       }
+
+       *out = dbstats;
+       return 0;
+}
+
+size_t ctdb_election_message_len(struct ctdb_election_message *election)
+{
+       return sizeof(struct ctdb_election_message);
+}
+
+void ctdb_election_message_push(struct ctdb_election_message *election,
+                               uint8_t *buf)
+{
+       memcpy(buf, election, sizeof(struct ctdb_election_message));
+}
+
+int ctdb_election_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                              struct ctdb_election_message **out)
+{
+       struct ctdb_election_message *election;
+
+       if (buflen < sizeof(struct ctdb_election_message)) {
+               return EMSGSIZE;
+       }
+
+       election = talloc_memdup(mem_ctx, buf,
+                                sizeof(struct ctdb_election_message));
+       if (election == NULL) {
+               return ENOMEM;
+       }
+
+       *out = election;
+       return 0;
+}
+
+size_t ctdb_srvid_message_len(struct ctdb_srvid_message *msg)
+{
+       return sizeof(struct ctdb_srvid_message);
+}
+
+void ctdb_srvid_message_push(struct ctdb_srvid_message *msg, uint8_t *buf)
+{
+       memcpy(buf, msg, sizeof(struct ctdb_srvid_message));
+}
+
+int ctdb_srvid_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                           struct ctdb_srvid_message **out)
+{
+       struct ctdb_srvid_message *msg;
+
+       if (buflen < sizeof(struct ctdb_srvid_message)) {
+               return EMSGSIZE;
+       }
+
+       msg = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_srvid_message));
+       if (msg == NULL) {
+               return ENOMEM;
+       }
+
+       *out = msg;
+       return 0;
+}
+
+size_t ctdb_disable_message_len(struct ctdb_disable_message *disable)
+{
+       return sizeof(struct ctdb_disable_message);
+}
+
+void ctdb_disable_message_push(struct ctdb_disable_message *disable,
+                              uint8_t *buf)
+{
+       memcpy(buf, disable, sizeof(struct ctdb_disable_message));
+}
+
+int ctdb_disable_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                             struct ctdb_disable_message **out)
+{
+       struct ctdb_disable_message *disable;
+
+       if (buflen < sizeof(struct ctdb_disable_message)) {
+               return EMSGSIZE;
+       }
+
+       disable = talloc_memdup(mem_ctx, buf,
+                               sizeof(struct ctdb_disable_message));
+       if (disable == NULL) {
+               return ENOMEM;
+       }
+
+       *out = disable;
+       return 0;
+}
+
+size_t ctdb_server_id_len(struct ctdb_server_id *sid)
+{
+       return sizeof(struct ctdb_server_id);
+}
+
+void ctdb_server_id_push(struct ctdb_server_id *sid, uint8_t *buf)
+{
+       memcpy(buf, sid, sizeof(struct ctdb_server_id));
+}
+
+int ctdb_server_id_pull(uint8_t *buf, size_t buflen,
+                       struct ctdb_server_id *sid)
+{
+       if (buflen < sizeof(struct ctdb_server_id)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(sid, buf, sizeof(struct ctdb_server_id));
+       return 0;
+}
+
+size_t ctdb_g_lock_len(struct ctdb_g_lock *lock)
+{
+       return sizeof(struct ctdb_g_lock);
+}
+
+void ctdb_g_lock_push(struct ctdb_g_lock *lock, uint8_t *buf)
+{
+       memcpy(buf, lock, sizeof(struct ctdb_g_lock));
+}
+
+int ctdb_g_lock_pull(uint8_t *buf, size_t buflen, struct ctdb_g_lock *lock)
+{
+       if (buflen < sizeof(struct ctdb_g_lock)) {
+               return EMSGSIZE;
+       }
+
+       memcpy(lock, buf, sizeof(struct ctdb_g_lock));
+       return 0;
+}
+
+size_t ctdb_g_lock_list_len(struct ctdb_g_lock_list *lock_list)
+{
+       return lock_list->num * sizeof(struct ctdb_g_lock);
+}
+
+void ctdb_g_lock_list_push(struct ctdb_g_lock_list *lock_list, uint8_t *buf)
+{
+       size_t offset = 0;
+       int i;
+
+       for (i=0; i<lock_list->num; i++) {
+               ctdb_g_lock_push(&lock_list->lock[i], &buf[offset]);
+               offset += sizeof(struct ctdb_g_lock);
+       }
+}
+
+int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+                         struct ctdb_g_lock_list **out)
+{
+       struct ctdb_g_lock_list *lock_list;
+       unsigned count;
+       size_t offset;
+       int ret, i;
+
+       lock_list = talloc_zero(mem_ctx, struct ctdb_g_lock_list);
+       if (lock_list == NULL) {
+               return ENOMEM;
+       }
+
+       count = buflen / sizeof(struct ctdb_g_lock);
+       lock_list->lock = talloc_array(lock_list, struct ctdb_g_lock, count);
+       if (lock_list->lock == NULL) {
+               talloc_free(lock_list);
+               return ENOMEM;
+       }
+
+       offset = 0;
+       for (i=0; i<count; i++) {
+               ret = ctdb_g_lock_pull(&buf[offset], buflen-offset,
+                                      &lock_list->lock[i]);
+               if (ret != 0) {
+                       talloc_free(lock_list);
+                       return ret;
+               }
+               offset += sizeof(struct ctdb_g_lock);
+       }
+
+       lock_list->num = count;
+
+       *out = lock_list;
+       return 0;
+}
diff --git a/ctdb/protocol/protocol_util.c b/ctdb/protocol/protocol_util.c
new file mode 100644 (file)
index 0000000..1082b0b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+   CTDB protocol marshalling
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <talloc.h>
+#include <tdb.h>
+
+#include "protocol.h"
+#include "protocol_private.h"
+#include "protocol_api.h"
+
+static struct {
+       enum ctdb_runstate runstate;
+       const char * label;
+} runstate_map[] = {
+       { CTDB_RUNSTATE_UNKNOWN, "UNKNOWN" },
+       { CTDB_RUNSTATE_INIT, "INIT" },
+       { CTDB_RUNSTATE_SETUP, "SETUP" },
+       { CTDB_RUNSTATE_FIRST_RECOVERY, "FIRST_RECOVERY" },
+       { CTDB_RUNSTATE_STARTUP, "STARTUP" },
+       { CTDB_RUNSTATE_RUNNING, "RUNNING" },
+       { CTDB_RUNSTATE_SHUTDOWN, "SHUTDOWN" },
+       { -1, NULL },
+};
+
+const char *ctdb_runstate_to_string(enum ctdb_runstate runstate)
+{
+       int i;
+
+       for (i=0; runstate_map[i].label != NULL; i++) {
+               if (runstate_map[i].runstate == runstate) {
+                       return runstate_map[i].label;
+               }
+       }
+
+       return runstate_map[0].label;
+}
+
+enum ctdb_runstate ctdb_runstate_from_string(const char *runstate_str)
+{
+       int i;
+
+       for (i=0; runstate_map[i].label != NULL; i++) {
+               if (strcasecmp(runstate_map[i].label,
+                              runstate_str) == 0) {
+                       return runstate_map[i].runstate;
+               }
+       }
+
+       return CTDB_RUNSTATE_UNKNOWN;
+}
+
+static struct {
+       enum ctdb_event event;
+       const char *label;
+} event_map[] = {
+       { CTDB_EVENT_INIT, "init" },
+       { CTDB_EVENT_SETUP, "setup" },
+       { CTDB_EVENT_STARTUP, "startup" },
+       { CTDB_EVENT_START_RECOVERY, "startrecovery" },
+       { CTDB_EVENT_RECOVERED, "recovered" },
+       { CTDB_EVENT_TAKE_IP, "takeip" },
+       { CTDB_EVENT_RELEASE_IP, "releaseip" },
+       { CTDB_EVENT_MONITOR, "monitor" },
+       { CTDB_EVENT_SHUTDOWN, "shutdown" },
+       { CTDB_EVENT_UPDATE_IP, "updateip" },
+       { CTDB_EVENT_IPREALLOCATED, "ipreallocated" },
+       { CTDB_EVENT_MAX, "all" },
+       { -1, NULL },
+};
+
+const char *ctdb_event_to_string(enum ctdb_event event)
+{
+       int i;
+
+       for (i=0; event_map[i].label != NULL; i++) {
+               if (event_map[i].event == event) {
+                       return event_map[i].label;
+               }
+       }
+
+       return "unknown";
+}
+
+enum ctdb_event ctdb_event_from_string(const char *event_str)
+{
+       int i;
+
+       for (i=0; event_map[i].label != NULL; i++) {
+               if (strcmp(event_map[i].label, event_str) == 0) {
+                       return event_map[i].event;
+               }
+       }
+
+       return CTDB_EVENT_MAX;
+}
diff --git a/ctdb/tests/cunit/protocol_test_001.sh b/ctdb/tests/cunit/protocol_test_001.sh
new file mode 100755 (executable)
index 0000000..41afda5
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+ok_null
+
+for i in $(seq 1 1000) ; do
+    unit_test protocol_types_test $i
+done
diff --git a/ctdb/tests/cunit/protocol_test_002.sh b/ctdb/tests/cunit/protocol_test_002.sh
new file mode 100755 (executable)
index 0000000..47410be
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+. "${TEST_SCRIPTS_DIR}/unit.sh"
+
+last_control=140
+
+control_output=$(
+    for i in $(seq 0 $last_control) ; do
+       echo -n "$i.. "
+    done
+    echo
+)
+
+output=$(
+    echo "ctdb_req_header"
+    echo "ctdb_req_call"
+    echo "ctdb_reply_call"
+    echo "ctdb_reply_error"
+    echo "ctdb_req_dmaster"
+    echo "ctdb_reply_dmaster"
+    echo "ctdb_req_control_data"
+    echo "$control_output"
+    echo "ctdb_reply_control_data"
+    echo "$control_output"
+    echo "ctdb_req_control"
+    echo "$control_output"
+    echo "ctdb_reply_control"
+    echo "$control_output"
+    echo "ctdb_req_message"
+)
+
+ok "$output"
+
+for i in $(seq 1 100) ; do
+    unit_test protocol_client_test $i
+done
diff --git a/ctdb/tests/src/protocol_client_test.c b/ctdb/tests/src/protocol_client_test.c
new file mode 100644 (file)
index 0000000..a17fac0
--- /dev/null
@@ -0,0 +1,2311 @@
+/*
+   protocol tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <assert.h>
+
+#define PROTOCOL_TEST
+
+#include "protocol_types_test.c"
+
+
+#define GENERATION     0xabcdef12
+#define OPERATION      CTDB_REQ_KEEPALIVE
+#define REQID          0x34567890
+#define SRCNODE                7
+#define DESTNODE       13
+
+/*
+ * Functions to fill and verify protocol structures
+ */
+
+static void verify_ctdb_req_header(struct ctdb_req_header *h,
+                                  struct ctdb_req_header *h2)
+{
+       verify_buffer(h, h2, sizeof(struct ctdb_req_header));
+}
+
+static void fill_ctdb_req_call(TALLOC_CTX *mem_ctx,
+                              struct ctdb_req_call *c)
+{
+       c->flags = rand32();
+       c->db_id = rand32();
+       c->callid = rand32();
+       c->hopcount = rand32();
+       fill_tdb_data(mem_ctx, &c->key);
+       fill_tdb_data(mem_ctx, &c->calldata);
+}
+
+static void verify_ctdb_req_call(struct ctdb_req_call *c,
+                                struct ctdb_req_call *c2)
+{
+       assert(c->flags == c2->flags);
+       assert(c->db_id == c2->db_id);
+       assert(c->callid == c2->callid);
+       assert(c->hopcount == c2->hopcount);
+       verify_tdb_data(&c->key, &c2->key);
+       verify_tdb_data(&c->calldata, &c2->calldata);
+}
+
+static void fill_ctdb_reply_call(TALLOC_CTX *mem_ctx,
+                                struct ctdb_reply_call *c)
+{
+       c->status = rand32();
+       fill_tdb_data(mem_ctx, &c->data);
+}
+
+static void verify_ctdb_reply_call(struct ctdb_reply_call *c,
+                                  struct ctdb_reply_call *c2)
+{
+       assert(c->status == c2->status);
+       verify_tdb_data(&c->data, &c2->data);
+}
+
+static void fill_ctdb_reply_error(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_reply_error *c)
+{
+       c->status = rand32();
+       fill_tdb_data(mem_ctx, &c->msg);
+}
+
+static void verify_ctdb_reply_error(struct ctdb_reply_error *c,
+                                   struct ctdb_reply_error *c2)
+{
+       assert(c->status == c2->status);
+       verify_tdb_data(&c->msg, &c2->msg);
+}
+
+static void fill_ctdb_req_dmaster(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_req_dmaster *c)
+{
+       c->db_id = rand32();
+       c->rsn = rand64();
+       c->dmaster = rand32();
+       fill_tdb_data(mem_ctx, &c->key);
+       fill_tdb_data(mem_ctx, &c->data);
+}
+
+static void verify_ctdb_req_dmaster(struct ctdb_req_dmaster *c,
+                                   struct ctdb_req_dmaster *c2)
+{
+       assert(c->db_id == c2->db_id);
+       assert(c->rsn == c2->rsn);
+       assert(c->dmaster == c2->dmaster);
+       verify_tdb_data(&c->key, &c2->key);
+       verify_tdb_data(&c->data, &c2->data);
+}
+
+static void fill_ctdb_reply_dmaster(TALLOC_CTX *mem_ctx,
+                                   struct ctdb_reply_dmaster *c)
+{
+       c->db_id = rand32();
+       c->rsn = rand64();
+       fill_tdb_data(mem_ctx, &c->key);
+       fill_tdb_data(mem_ctx, &c->data);
+}
+
+static void verify_ctdb_reply_dmaster(struct ctdb_reply_dmaster *c,
+                                     struct ctdb_reply_dmaster *c2)
+{
+       assert(c->db_id == c2->db_id);
+       assert(c->rsn == c2->rsn);
+       verify_tdb_data(&c->key, &c2->key);
+       verify_tdb_data(&c->data, &c2->data);
+}
+
+static void fill_ctdb_req_control_data(TALLOC_CTX *mem_ctx,
+                                      struct ctdb_req_control_data *cd,
+                                      uint32_t opcode)
+{
+       cd->opcode = opcode;
+       switch (opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS:
+               cd->data.pid = rand32();
+               break;
+
+       case CTDB_CONTROL_STATISTICS:
+               break;
+
+       case CTDB_CONTROL_PING:
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_GETVNNMAP:
+               break;
+
+       case CTDB_CONTROL_SETVNNMAP:
+               cd->data.vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
+               assert(cd->data.vnnmap != NULL);
+               fill_ctdb_vnn_map(mem_ctx, cd->data.vnnmap);
+               break;
+
+       case CTDB_CONTROL_GET_DEBUG:
+               break;
+
+       case CTDB_CONTROL_SET_DEBUG:
+               cd->data.loglevel = rand_int(5);
+               break;
+
+       case CTDB_CONTROL_GET_DBMAP:
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               cd->data.pulldb = talloc(mem_ctx, struct ctdb_pulldb);
+               assert(cd->data.pulldb != NULL);
+               fill_ctdb_pulldb(mem_ctx, cd->data.pulldb);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+               assert(cd->data.recbuf != NULL);
+               fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMODE:
+               cd->data.recmode = rand_int(2);
+               break;
+
+       case CTDB_CONTROL_STATISTICS_RESET:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               fill_ctdb_string(mem_ctx, &cd->data.db_name);
+               assert(cd->data.db_name != NULL);
+               break;
+
+       case CTDB_CONTROL_SET_CALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START:
+               cd->data.traverse_start = talloc(mem_ctx, struct ctdb_traverse_start);
+               assert(cd->data.traverse_start != NULL);
+               fill_ctdb_traverse_start(mem_ctx, cd->data.traverse_start);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL:
+               cd->data.traverse_all = talloc(mem_ctx, struct ctdb_traverse_all);
+               assert(cd->data.traverse_all != NULL);
+               fill_ctdb_traverse_all(mem_ctx, cd->data.traverse_all);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_DATA:
+               cd->data.rec_data = talloc(mem_ctx, struct ctdb_rec_data);
+               assert(cd->data.rec_data != NULL);
+               fill_ctdb_rec_data(mem_ctx, cd->data.rec_data);
+               break;
+
+       case CTDB_CONTROL_REGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_ENABLE_SEQNUM:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_UPDATE_SEQNUM:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_DUMP_MEMORY:
+               break;
+
+       case CTDB_CONTROL_GET_PID:
+               break;
+
+       case CTDB_CONTROL_GET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTER:
+               cd->data.recmaster = rand_int(32);
+               break;
+
+       case CTDB_CONTROL_FREEZE:
+               break;
+
+       case CTDB_CONTROL_THAW:
+               break;
+
+       case CTDB_CONTROL_GET_PNN:
+               break;
+
+       case CTDB_CONTROL_SHUTDOWN:
+               break;
+
+       case CTDB_CONTROL_GET_MONMODE:
+               break;
+
+       case CTDB_CONTROL_TCP_CLIENT:
+               cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+               assert(cd->data.conn != NULL);
+               fill_ctdb_connection(mem_ctx, cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD:
+               cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+               assert(cd->data.conn != NULL);
+               fill_ctdb_connection(mem_ctx, cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_TCP_REMOVE:
+               cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+               assert(cd->data.conn != NULL);
+               fill_ctdb_connection(mem_ctx, cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_STARTUP:
+               break;
+
+       case CTDB_CONTROL_SET_TUNABLE:
+               cd->data.tunable = talloc(mem_ctx, struct ctdb_tunable);
+               assert(cd->data.tunable != NULL);
+               fill_ctdb_tunable(mem_ctx, cd->data.tunable);
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               fill_ctdb_string(mem_ctx, &cd->data.tun_var);
+               assert(cd->data.tun_var != NULL);
+               break;
+
+       case CTDB_CONTROL_LIST_TUNABLES:
+               break;
+
+       case CTDB_CONTROL_MODIFY_FLAGS:
+               cd->data.flag_change = talloc(mem_ctx, struct ctdb_node_flag_change);
+               assert(cd->data.flag_change != NULL);
+               fill_ctdb_node_flag_change(mem_ctx, cd->data.flag_change);
+               break;
+
+       case CTDB_CONTROL_GET_ALL_TUNABLES:
+               break;
+
+       case CTDB_CONTROL_KILL_TCP:
+               cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+               assert(cd->data.conn != NULL);
+               fill_ctdb_connection(mem_ctx, cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               cd->data.addr = talloc(mem_ctx, ctdb_sock_addr);
+               assert(cd->data.addr != NULL);
+               fill_ctdb_sock_addr(mem_ctx, cd->data.addr);
+               break;
+
+       case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+               cd->data.tickles = talloc(mem_ctx, struct ctdb_tickle_list);
+               assert(cd->data.tickles != NULL);
+               fill_ctdb_tickle_list(mem_ctx, cd->data.tickles);
+               break;
+
+       case CTDB_CONTROL_REGISTER_SERVER_ID:
+               cd->data.cid = talloc(mem_ctx, struct ctdb_client_id);
+               assert(cd->data.cid != NULL);
+               fill_ctdb_client_id(mem_ctx, cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+               cd->data.cid = talloc(mem_ctx, struct ctdb_client_id);
+               assert(cd->data.cid != NULL);
+               fill_ctdb_client_id(mem_ctx, cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_CHECK_SERVER_ID:
+               cd->data.cid = talloc(mem_ctx, struct ctdb_client_id);
+               assert(cd->data.cid != NULL);
+               fill_ctdb_client_id(mem_ctx, cd->data.cid);
+               break;
+
+       case CTDB_CONTROL_GET_SERVER_ID_LIST:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               fill_ctdb_string(mem_ctx, &cd->data.db_name);
+               assert(cd->data.db_name != NULL);
+               break;
+
+       case CTDB_CONTROL_UPDATE_RECORD:
+               cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+               assert(cd->data.recbuf != NULL);
+               fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+               cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info);
+               assert(cd->data.addr_info != NULL);
+               fill_ctdb_addr_info(mem_ctx, cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_START:
+               cd->data.tid = rand32();
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_COMMIT:
+               cd->data.tid = rand32();
+               break;
+
+       case CTDB_CONTROL_WIPE_DATABASE:
+               cd->data.transdb = talloc(mem_ctx, struct ctdb_transdb);
+               assert(cd->data.transdb != NULL);
+               fill_ctdb_transdb(mem_ctx, cd->data.transdb);
+               break;
+
+       case CTDB_CONTROL_UPTIME:
+               break;
+
+       case CTDB_CONTROL_START_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_END_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_NODES_FILE:
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+               assert(cd->data.recbuf != NULL);
+               fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_ENABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_DISABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info);
+               assert(cd->data.addr_info != NULL);
+               fill_ctdb_addr_info(mem_ctx, cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               cd->data.addr_info = talloc(mem_ctx, struct ctdb_addr_info);
+               assert(cd->data.addr_info != NULL);
+               fill_ctdb_addr_info(mem_ctx, cd->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+               fill_ctdb_string(mem_ctx, &cd->data.event_str);
+               assert(cd->data.event_str != NULL);
+               break;
+
+       case CTDB_CONTROL_GET_CAPABILITIES:
+               break;
+
+       case CTDB_CONTROL_START_PERSISTENT_UPDATE:
+               break;
+
+       case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
+               break;
+
+       case CTDB_CONTROL_RECD_PING:
+               break;
+
+       case CTDB_CONTROL_RELEASE_IP:
+               cd->data.pubip = talloc(mem_ctx, struct ctdb_public_ip);
+               assert(cd->data.pubip != NULL);
+               fill_ctdb_public_ip(mem_ctx, cd->data.pubip);
+               break;
+
+       case CTDB_CONTROL_TAKEOVER_IP:
+               cd->data.pubip = talloc(mem_ctx, struct ctdb_public_ip);
+               assert(cd->data.pubip != NULL);
+               fill_ctdb_public_ip(mem_ctx, cd->data.pubip);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_GET_NODEMAP:
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               cd->data.event = rand_int(CTDB_EVENT_MAX);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_KILL:
+               cd->data.traverse_start = talloc(mem_ctx, struct ctdb_traverse_start);
+               assert(cd->data.traverse_start != NULL);
+               fill_ctdb_traverse_start(mem_ctx, cd->data.traverse_start);
+               break;
+
+       case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+               cd->data.reclock_latency = rand_double();
+               break;
+
+       case CTDB_CONTROL_GET_RECLOCK_FILE:
+               break;
+
+       case CTDB_CONTROL_SET_RECLOCK_FILE:
+               fill_ctdb_string(mem_ctx, &cd->data.reclock_file);
+               assert(cd->data.reclock_file != NULL);
+               break;
+
+       case CTDB_CONTROL_STOP_NODE:
+               break;
+
+       case CTDB_CONTROL_CONTINUE_NODE:
+               break;
+
+       case CTDB_CONTROL_SET_NATGWSTATE:
+               cd->data.role = rand_int(2);
+               break;
+
+       case CTDB_CONTROL_SET_LMASTERROLE:
+               cd->data.role = rand_int(2);
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTERROLE:
+               cd->data.role = rand_int(2);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SCRIPT:
+               fill_ctdb_string(mem_ctx, &cd->data.script);
+               assert(cd->data.script != NULL);
+               break;
+
+       case CTDB_CONTROL_DISABLE_SCRIPT:
+               fill_ctdb_string(mem_ctx, &cd->data.script);
+               assert(cd->data.script != NULL);
+               break;
+
+       case CTDB_CONTROL_SET_BAN_STATE:
+               cd->data.ban_state = talloc(mem_ctx, struct ctdb_ban_state);
+               assert(cd->data.ban_state != NULL);
+               fill_ctdb_ban_state(mem_ctx, cd->data.ban_state);
+               break;
+
+       case CTDB_CONTROL_GET_BAN_STATE:
+               break;
+
+       case CTDB_CONTROL_SET_DB_PRIORITY:
+               cd->data.db_prio = talloc(mem_ctx, struct ctdb_db_priority);
+               assert(cd->data.db_prio != NULL);
+               fill_ctdb_db_priority(mem_ctx, cd->data.db_prio);
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               cd->data.db_prio = talloc(mem_ctx, struct ctdb_db_priority);
+               assert(cd->data.db_prio != NULL);
+               fill_ctdb_db_priority(mem_ctx, cd->data.db_prio);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_CANCEL:
+               break;
+
+       case CTDB_CONTROL_REGISTER_NOTIFY:
+               cd->data.notify = talloc(mem_ctx, struct ctdb_notify_data);
+               assert(cd->data.notify != NULL);
+               fill_ctdb_notify_data(mem_ctx, cd->data.notify);
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_NOTIFY:
+               cd->data.srvid = rand64();
+               break;
+
+       case CTDB_CONTROL_TRANS3_COMMIT:
+               cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+               assert(cd->data.recbuf != NULL);
+               fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_DB_SET_HEALTHY:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               cd->data.addr = talloc(mem_ctx, ctdb_sock_addr);
+               assert(cd->data.addr != NULL);
+               fill_ctdb_sock_addr(mem_ctx, cd->data.addr);
+               break;
+
+       case CTDB_CONTROL_GET_IFACES:
+               break;
+
+       case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+               cd->data.iface = talloc(mem_ctx, struct ctdb_iface);
+               assert(cd->data.iface != NULL);
+               fill_ctdb_iface(mem_ctx, cd->data.iface);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+               cd->data.conn = talloc(mem_ctx, struct ctdb_connection);
+               assert(cd->data.conn != NULL);
+               fill_ctdb_connection(mem_ctx, cd->data.conn);
+               break;
+
+       case CTDB_CONTROL_GET_STAT_HISTORY:
+               break;
+
+       case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+               cd->data.key = talloc(mem_ctx, struct ctdb_key_data);
+               assert(cd->data.key != NULL);
+               fill_ctdb_key_data(mem_ctx, cd->data.key);
+               break;
+
+       case CTDB_CONTROL_SET_DB_READONLY:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               cd->data.u64_array = talloc(mem_ctx, struct ctdb_uint64_array);
+               assert(cd->data.u64_array != NULL);
+               fill_ctdb_uint64_array(mem_ctx, cd->data.u64_array);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START_EXT:
+               cd->data.traverse_start_ext = talloc(mem_ctx, struct ctdb_traverse_start_ext);
+               assert(cd->data.traverse_start_ext != NULL);
+               fill_ctdb_traverse_start_ext(mem_ctx, cd->data.traverse_start_ext);
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_SET_DB_STICKY:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+               cd->data.traverse_all_ext = talloc(mem_ctx, struct ctdb_traverse_all_ext);
+               assert(cd->data.traverse_all_ext != NULL);
+               fill_ctdb_traverse_all_ext(mem_ctx, cd->data.traverse_all_ext);
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+               assert(cd->data.recbuf != NULL);
+               fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_IPREALLOCATED:
+               break;
+
+       case CTDB_CONTROL_GET_RUNSTATE:
+               break;
+
+       case CTDB_CONTROL_DB_DETACH:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_GET_NODES_FILE:
+               break;
+
+       }
+}
+
+static void verify_ctdb_req_control_data(struct ctdb_req_control_data *cd,
+                                        struct ctdb_req_control_data *cd2)
+{
+       assert(cd->opcode == cd2->opcode);
+
+       switch (cd->opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS:
+               assert(cd->data.pid == cd2->data.pid);
+               break;
+
+       case CTDB_CONTROL_STATISTICS:
+               break;
+
+       case CTDB_CONTROL_PING:
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_GETVNNMAP:
+               break;
+
+       case CTDB_CONTROL_SETVNNMAP:
+               verify_ctdb_vnn_map(cd->data.vnnmap, cd2->data.vnnmap);
+               break;
+
+       case CTDB_CONTROL_GET_DEBUG:
+               break;
+
+       case CTDB_CONTROL_SET_DEBUG:
+               assert(cd->data.loglevel == cd2->data.loglevel);
+               break;
+
+       case CTDB_CONTROL_GET_DBMAP:
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               verify_ctdb_pulldb(cd->data.pulldb, cd2->data.pulldb);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMODE:
+               assert(cd->data.recmode == cd2->data.recmode);
+               break;
+
+       case CTDB_CONTROL_STATISTICS_RESET:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               verify_ctdb_string(cd->data.db_name, cd2->data.db_name);
+               break;
+
+       case CTDB_CONTROL_SET_CALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START:
+               verify_ctdb_traverse_start(cd->data.traverse_start,
+                                          cd2->data.traverse_start);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL:
+               verify_ctdb_traverse_all(cd->data.traverse_all,
+                                        cd2->data.traverse_all);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_DATA:
+               verify_ctdb_rec_data(cd->data.rec_data, cd2->data.rec_data);
+               break;
+
+       case CTDB_CONTROL_REGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SEQNUM:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_UPDATE_SEQNUM:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_DUMP_MEMORY:
+               break;
+
+       case CTDB_CONTROL_GET_PID:
+               break;
+
+       case CTDB_CONTROL_GET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTER:
+               assert(cd->data.recmaster == cd2->data.recmaster);
+               break;
+
+       case CTDB_CONTROL_FREEZE:
+               break;
+
+       case CTDB_CONTROL_THAW:
+               break;
+
+       case CTDB_CONTROL_GET_PNN:
+               break;
+
+       case CTDB_CONTROL_SHUTDOWN:
+               break;
+
+       case CTDB_CONTROL_GET_MONMODE:
+               break;
+
+       case CTDB_CONTROL_TCP_CLIENT:
+               verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD:
+               verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+               break;
+
+       case CTDB_CONTROL_TCP_REMOVE:
+               verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+               break;
+
+       case CTDB_CONTROL_STARTUP:
+               break;
+
+       case CTDB_CONTROL_SET_TUNABLE:
+               verify_ctdb_tunable(cd->data.tunable, cd2->data.tunable);
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               verify_ctdb_string(cd->data.tun_var, cd2->data.tun_var);
+               break;
+
+       case CTDB_CONTROL_LIST_TUNABLES:
+               break;
+
+       case CTDB_CONTROL_MODIFY_FLAGS:
+               verify_ctdb_node_flag_change(cd->data.flag_change,
+                                            cd2->data.flag_change);
+               break;
+
+       case CTDB_CONTROL_GET_ALL_TUNABLES:
+               break;
+
+       case CTDB_CONTROL_KILL_TCP:
+               verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               verify_ctdb_sock_addr(cd->data.addr, cd2->data.addr);
+               break;
+
+       case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+               verify_ctdb_tickle_list(cd->data.tickles, cd2->data.tickles);
+               break;
+
+       case CTDB_CONTROL_REGISTER_SERVER_ID:
+               verify_ctdb_client_id(cd->data.cid, cd2->data.cid);
+               break;
+
+       case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+               verify_ctdb_client_id(cd->data.cid, cd2->data.cid);
+               break;
+
+       case CTDB_CONTROL_CHECK_SERVER_ID:
+               verify_ctdb_client_id(cd->data.cid, cd2->data.cid);
+               break;
+
+       case CTDB_CONTROL_GET_SERVER_ID_LIST:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               verify_ctdb_string(cd->data.db_name, cd2->data.db_name);
+               break;
+
+       case CTDB_CONTROL_UPDATE_RECORD:
+               verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+               verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_START:
+               assert(cd->data.tid == cd2->data.tid);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_COMMIT:
+               assert(cd->data.tid == cd2->data.tid);
+               break;
+
+       case CTDB_CONTROL_WIPE_DATABASE:
+               verify_ctdb_transdb(cd->data.transdb, cd2->data.transdb);
+               break;
+
+       case CTDB_CONTROL_UPTIME:
+               break;
+
+       case CTDB_CONTROL_START_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_END_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_NODES_FILE:
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_ENABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_DISABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               verify_ctdb_addr_info(cd->data.addr_info, cd2->data.addr_info);
+               break;
+
+       case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+               verify_ctdb_string(cd->data.event_str, cd2->data.event_str);
+               break;
+
+       case CTDB_CONTROL_GET_CAPABILITIES:
+               break;
+
+       case CTDB_CONTROL_START_PERSISTENT_UPDATE:
+               break;
+
+       case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
+               break;
+
+       case CTDB_CONTROL_RECD_PING:
+               break;
+
+       case CTDB_CONTROL_RELEASE_IP:
+               verify_ctdb_public_ip(cd->data.pubip, cd2->data.pubip);
+               break;
+
+       case CTDB_CONTROL_TAKEOVER_IP:
+               verify_ctdb_public_ip(cd->data.pubip, cd2->data.pubip);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_GET_NODEMAP:
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               assert(cd->data.event == cd2->data.event);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_KILL:
+               verify_ctdb_traverse_start(cd->data.traverse_start,
+                                          cd2->data.traverse_start);
+               break;
+
+       case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+               assert(cd->data.reclock_latency == cd2->data.reclock_latency);
+               break;
+
+       case CTDB_CONTROL_GET_RECLOCK_FILE:
+               break;
+
+       case CTDB_CONTROL_SET_RECLOCK_FILE:
+               verify_ctdb_string(cd->data.reclock_file,
+                                  cd2->data.reclock_file);
+               break;
+
+       case CTDB_CONTROL_STOP_NODE:
+               break;
+
+       case CTDB_CONTROL_CONTINUE_NODE:
+               break;
+
+       case CTDB_CONTROL_SET_NATGWSTATE:
+               assert(cd->data.role == cd2->data.role);
+               break;
+
+       case CTDB_CONTROL_SET_LMASTERROLE:
+               assert(cd->data.role == cd2->data.role);
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTERROLE:
+               assert(cd->data.role == cd2->data.role);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SCRIPT:
+               verify_ctdb_string(cd->data.script, cd2->data.script);
+               break;
+
+       case CTDB_CONTROL_DISABLE_SCRIPT:
+               verify_ctdb_string(cd->data.script, cd2->data.script);
+               break;
+
+       case CTDB_CONTROL_SET_BAN_STATE:
+               verify_ctdb_ban_state(cd->data.ban_state, cd2->data.ban_state);
+               break;
+
+       case CTDB_CONTROL_GET_BAN_STATE:
+               break;
+
+       case CTDB_CONTROL_SET_DB_PRIORITY:
+               verify_ctdb_db_priority(cd->data.db_prio, cd2->data.db_prio);
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_CANCEL:
+               break;
+
+       case CTDB_CONTROL_REGISTER_NOTIFY:
+               verify_ctdb_notify_data(cd->data.notify, cd2->data.notify);
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_NOTIFY:
+               assert(cd->data.srvid == cd2->data.srvid);
+               break;
+
+       case CTDB_CONTROL_TRANS3_COMMIT:
+               verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_DB_SET_HEALTHY:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               verify_ctdb_sock_addr(cd->data.addr, cd2->data.addr);
+               break;
+
+       case CTDB_CONTROL_GET_IFACES:
+               break;
+
+       case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+               verify_ctdb_iface(cd->data.iface, cd2->data.iface);
+               break;
+
+       case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+               verify_ctdb_connection(cd->data.conn, cd2->data.conn);
+               break;
+
+       case CTDB_CONTROL_GET_STAT_HISTORY:
+               break;
+
+       case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+               verify_ctdb_key_data(cd->data.key, cd2->data.key);
+               break;
+
+       case CTDB_CONTROL_SET_DB_READONLY:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               verify_ctdb_uint64_array(cd->data.u64_array,
+                                        cd2->data.u64_array);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START_EXT:
+               verify_ctdb_traverse_start_ext(cd->data.traverse_start_ext,
+                                              cd2->data.traverse_start_ext);
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_SET_DB_STICKY:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+               verify_ctdb_traverse_all_ext(cd->data.traverse_all_ext,
+                                            cd2->data.traverse_all_ext);
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_IPREALLOCATED:
+               break;
+
+       case CTDB_CONTROL_GET_RUNSTATE:
+               break;
+
+       case CTDB_CONTROL_DB_DETACH:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_GET_NODES_FILE:
+               break;
+
+       }
+}
+
+static void fill_ctdb_req_control(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_req_control *c,
+                                 uint32_t opcode)
+{
+       c->opcode = opcode;
+       c->pad = rand32();
+       c->srvid = rand64();
+       c->client_id = rand32();
+       c->flags = rand32();
+
+       fill_ctdb_req_control_data(mem_ctx, &c->rdata, opcode);
+}
+
+static void verify_ctdb_req_control(struct ctdb_req_control *c,
+                                   struct ctdb_req_control *c2)
+{
+       assert(c->opcode == c2->opcode);
+       assert(c->pad == c2->pad);
+       assert(c->srvid == c2->srvid);
+       assert(c->client_id == c2->client_id);
+       assert(c->flags == c2->flags);
+
+       verify_ctdb_req_control_data(&c->rdata, &c2->rdata);
+}
+
+static void fill_ctdb_reply_control_data(TALLOC_CTX *mem_ctx,
+                                        struct ctdb_reply_control_data *cd,
+                                        uint32_t opcode)
+{
+       cd->opcode = opcode;
+
+       switch (opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS:
+               break;
+
+       case CTDB_CONTROL_STATISTICS:
+               cd->data.stats = talloc(mem_ctx, struct ctdb_statistics);
+               assert(cd->data.stats != NULL);
+               fill_ctdb_statistics(mem_ctx, cd->data.stats);
+               break;
+
+       case CTDB_CONTROL_PING:
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               fill_ctdb_string(mem_ctx, &cd->data.db_path);
+               assert(cd->data.db_path != NULL);
+               break;
+
+       case CTDB_CONTROL_GETVNNMAP:
+               cd->data.vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
+               assert(cd->data.vnnmap != NULL);
+               fill_ctdb_vnn_map(mem_ctx, cd->data.vnnmap);
+               break;
+
+       case CTDB_CONTROL_SETVNNMAP:
+               break;
+
+       case CTDB_CONTROL_GET_DEBUG:
+               cd->data.loglevel = rand_int(5);
+               break;
+
+       case CTDB_CONTROL_SET_DEBUG:
+               break;
+
+       case CTDB_CONTROL_GET_DBMAP:
+               cd->data.dbmap = talloc(mem_ctx, struct ctdb_dbid_map);
+               assert(cd->data.dbmap != NULL);
+               fill_ctdb_dbid_map(mem_ctx, cd->data.dbmap);
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+               assert(cd->data.recbuf != NULL);
+               fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               break;
+
+       case CTDB_CONTROL_GET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_STATISTICS_RESET:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               cd->data.db_id = rand32();
+               break;
+
+       case CTDB_CONTROL_SET_CALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_DATA:
+               break;
+
+       case CTDB_CONTROL_REGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               fill_ctdb_string(mem_ctx, &cd->data.db_name);
+               assert(cd->data.db_name);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SEQNUM:
+               break;
+
+       case CTDB_CONTROL_UPDATE_SEQNUM:
+               break;
+
+       case CTDB_CONTROL_DUMP_MEMORY:
+               fill_ctdb_string(mem_ctx, &cd->data.mem_str);
+               assert(cd->data.mem_str);
+               break;
+
+       case CTDB_CONTROL_GET_PID:
+               break;
+
+       case CTDB_CONTROL_GET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_FREEZE:
+               break;
+
+       case CTDB_CONTROL_THAW:
+               break;
+
+       case CTDB_CONTROL_GET_PNN:
+               break;
+
+       case CTDB_CONTROL_SHUTDOWN:
+               break;
+
+       case CTDB_CONTROL_GET_MONMODE:
+               break;
+
+       case CTDB_CONTROL_TCP_CLIENT:
+               break;
+
+       case CTDB_CONTROL_TCP_ADD:
+               break;
+
+       case CTDB_CONTROL_TCP_REMOVE:
+               break;
+
+       case CTDB_CONTROL_STARTUP:
+               break;
+
+       case CTDB_CONTROL_SET_TUNABLE:
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               cd->data.tun_value = rand32();
+               break;
+
+       case CTDB_CONTROL_LIST_TUNABLES:
+               cd->data.tun_var_list = talloc(mem_ctx, struct ctdb_var_list);
+               assert(cd->data.tun_var_list != NULL);
+               fill_ctdb_var_list(mem_ctx, cd->data.tun_var_list);
+               break;
+
+       case CTDB_CONTROL_MODIFY_FLAGS:
+               break;
+
+       case CTDB_CONTROL_GET_ALL_TUNABLES:
+               cd->data.tun_list = talloc(mem_ctx, struct ctdb_tunable_list);
+               assert(cd->data.tun_list != NULL);
+               fill_ctdb_tunable_list(mem_ctx, cd->data.tun_list);
+               break;
+
+       case CTDB_CONTROL_KILL_TCP:
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               cd->data.tickles = talloc(mem_ctx, struct ctdb_tickle_list);
+               assert(cd->data.tickles != NULL);
+               fill_ctdb_tickle_list(mem_ctx, cd->data.tickles);
+               break;
+
+       case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+               break;
+
+       case CTDB_CONTROL_REGISTER_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_CHECK_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_GET_SERVER_ID_LIST:
+               cd->data.cid_map = talloc(mem_ctx, struct ctdb_client_id_map);
+               assert(cd->data.cid_map != NULL);
+               fill_ctdb_client_id_map(mem_ctx, cd->data.cid_map);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               break;
+
+       case CTDB_CONTROL_UPDATE_RECORD:
+               break;
+
+       case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_START:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_COMMIT:
+               break;
+
+       case CTDB_CONTROL_WIPE_DATABASE:
+               break;
+
+       case CTDB_CONTROL_UPTIME:
+               cd->data.uptime = talloc(mem_ctx, struct ctdb_uptime);
+               assert(cd->data.uptime != NULL);
+               fill_ctdb_uptime(mem_ctx, cd->data.uptime);
+               break;
+
+       case CTDB_CONTROL_START_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_END_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_NODES_FILE:
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+               assert(cd->data.recbuf != NULL);
+               fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_ENABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_DISABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               break;
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               break;
+
+       case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+               break;
+
+       case CTDB_CONTROL_GET_CAPABILITIES:
+               cd->data.caps = rand32();
+               break;
+
+       case CTDB_CONTROL_START_PERSISTENT_UPDATE:
+               break;
+
+       case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
+               break;
+
+       case CTDB_CONTROL_RECD_PING:
+               break;
+
+       case CTDB_CONTROL_RELEASE_IP:
+               break;
+
+       case CTDB_CONTROL_TAKEOVER_IP:
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IPS:
+               cd->data.pubip_list = talloc(mem_ctx, struct ctdb_public_ip_list);
+               assert(cd->data.pubip_list != NULL);
+               fill_ctdb_public_ip_list(mem_ctx, cd->data.pubip_list);
+               break;
+
+       case CTDB_CONTROL_GET_NODEMAP:
+               cd->data.nodemap = talloc(mem_ctx, struct ctdb_node_map);
+               assert(cd->data.nodemap != NULL);
+               fill_ctdb_node_map(mem_ctx, cd->data.nodemap);
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               cd->data.script_list = talloc(mem_ctx, struct ctdb_script_list);
+               assert(cd->data.script_list != NULL);
+               fill_ctdb_script_list(mem_ctx, cd->data.script_list);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_KILL:
+               break;
+
+       case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+               break;
+
+       case CTDB_CONTROL_GET_RECLOCK_FILE:
+               fill_ctdb_string(mem_ctx, &cd->data.reclock_file);
+               assert(cd->data.reclock_file != NULL);
+               break;
+
+       case CTDB_CONTROL_SET_RECLOCK_FILE:
+               break;
+
+       case CTDB_CONTROL_STOP_NODE:
+               break;
+
+       case CTDB_CONTROL_CONTINUE_NODE:
+               break;
+
+       case CTDB_CONTROL_SET_NATGWSTATE:
+               break;
+
+       case CTDB_CONTROL_SET_LMASTERROLE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTERROLE:
+               break;
+
+       case CTDB_CONTROL_ENABLE_SCRIPT:
+               break;
+
+       case CTDB_CONTROL_DISABLE_SCRIPT:
+               break;
+
+       case CTDB_CONTROL_SET_BAN_STATE:
+               break;
+
+       case CTDB_CONTROL_GET_BAN_STATE:
+               cd->data.ban_state = talloc(mem_ctx, struct ctdb_ban_state);
+               assert(cd->data.ban_state != NULL);
+               fill_ctdb_ban_state(mem_ctx, cd->data.ban_state);
+               break;
+
+       case CTDB_CONTROL_SET_DB_PRIORITY:
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_CANCEL:
+               break;
+
+       case CTDB_CONTROL_REGISTER_NOTIFY:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_NOTIFY:
+               break;
+
+       case CTDB_CONTROL_TRANS3_COMMIT:
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               cd->data.seqnum = rand64();
+               break;
+
+       case CTDB_CONTROL_DB_SET_HEALTHY:
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               fill_ctdb_string(mem_ctx, &cd->data.reason);
+               assert(cd->data.reason != NULL);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               cd->data.ipinfo = talloc(mem_ctx, struct ctdb_public_ip_info);
+               assert(cd->data.ipinfo != NULL);
+               fill_ctdb_public_ip_info(mem_ctx, cd->data.ipinfo);
+               break;
+
+       case CTDB_CONTROL_GET_IFACES:
+               cd->data.iface_list = talloc(mem_ctx, struct ctdb_iface_list);
+               assert(cd->data.iface_list != NULL);
+               fill_ctdb_iface_list(mem_ctx, cd->data.iface_list);
+               break;
+
+       case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+               break;
+
+       case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+               break;
+
+       case CTDB_CONTROL_GET_STAT_HISTORY:
+               cd->data.stats_list = talloc(mem_ctx, struct ctdb_statistics_list);
+               assert(cd->data.stats_list != NULL);
+               fill_ctdb_statistics_list(mem_ctx, cd->data.stats_list);
+               break;
+
+       case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+               break;
+
+       case CTDB_CONTROL_SET_DB_READONLY:
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               cd->data.u8_array = talloc(mem_ctx, struct ctdb_uint8_array);
+               assert(cd->data.u8_array != NULL);
+               fill_ctdb_uint8_array(mem_ctx, cd->data.u8_array);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START_EXT:
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               cd->data.dbstats = talloc(mem_ctx, struct ctdb_db_statistics);
+               assert(cd->data.dbstats != NULL);
+               fill_ctdb_db_statistics(mem_ctx, cd->data.dbstats);
+               break;
+
+       case CTDB_CONTROL_SET_DB_STICKY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               cd->data.recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
+               assert(cd->data.recbuf != NULL);
+               fill_ctdb_rec_buffer(mem_ctx, cd->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_IPREALLOCATED:
+               break;
+
+       case CTDB_CONTROL_GET_RUNSTATE:
+               cd->data.runstate = rand32();
+               break;
+
+       case CTDB_CONTROL_DB_DETACH:
+               break;
+
+       case CTDB_CONTROL_GET_NODES_FILE:
+               cd->data.nodemap = talloc(mem_ctx, struct ctdb_node_map);
+               assert(cd->data.nodemap != NULL);
+               fill_ctdb_node_map(mem_ctx, cd->data.nodemap);
+               break;
+
+       }
+}
+
+static void verify_ctdb_reply_control_data(struct ctdb_reply_control_data *cd,
+                                          struct ctdb_reply_control_data *cd2)
+{
+       assert(cd->opcode == cd2->opcode);
+
+       switch (cd->opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS:
+               break;
+
+       case CTDB_CONTROL_STATISTICS:
+               verify_ctdb_statistics(cd->data.stats, cd2->data.stats);
+               break;
+
+       case CTDB_CONTROL_PING:
+               break;
+
+       case CTDB_CONTROL_GETDBPATH:
+               verify_ctdb_string(cd->data.db_path, cd2->data.db_path);
+               break;
+
+       case CTDB_CONTROL_GETVNNMAP:
+               verify_ctdb_vnn_map(cd->data.vnnmap, cd2->data.vnnmap);
+               break;
+
+       case CTDB_CONTROL_SETVNNMAP:
+               break;
+
+       case CTDB_CONTROL_GET_DEBUG:
+               assert(cd->data.loglevel == cd2->data.loglevel);
+               break;
+
+       case CTDB_CONTROL_SET_DEBUG:
+               break;
+
+       case CTDB_CONTROL_GET_DBMAP:
+               verify_ctdb_dbid_map(cd->data.dbmap, cd2->data.dbmap);
+               break;
+
+       case CTDB_CONTROL_PULL_DB:
+               verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_PUSH_DB:
+               break;
+
+       case CTDB_CONTROL_GET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMODE:
+               break;
+
+       case CTDB_CONTROL_STATISTICS_RESET:
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH:
+               assert(cd->data.db_id == cd2->data.db_id);
+               break;
+
+       case CTDB_CONTROL_SET_CALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_DATA:
+               break;
+
+       case CTDB_CONTROL_REGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_SRVID:
+               break;
+
+       case CTDB_CONTROL_GET_DBNAME:
+               verify_ctdb_string(cd->data.db_name, cd2->data.db_name);
+               break;
+
+       case CTDB_CONTROL_ENABLE_SEQNUM:
+               break;
+
+       case CTDB_CONTROL_UPDATE_SEQNUM:
+               break;
+
+       case CTDB_CONTROL_DUMP_MEMORY:
+               verify_ctdb_string(cd->data.mem_str, cd2->data.mem_str);
+               break;
+
+       case CTDB_CONTROL_GET_PID:
+               break;
+
+       case CTDB_CONTROL_GET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTER:
+               break;
+
+       case CTDB_CONTROL_FREEZE:
+               break;
+
+       case CTDB_CONTROL_THAW:
+               break;
+
+       case CTDB_CONTROL_GET_PNN:
+               break;
+
+       case CTDB_CONTROL_SHUTDOWN:
+               break;
+
+       case CTDB_CONTROL_GET_MONMODE:
+               break;
+
+       case CTDB_CONTROL_TCP_CLIENT:
+               break;
+
+       case CTDB_CONTROL_TCP_ADD:
+               break;
+
+       case CTDB_CONTROL_TCP_REMOVE:
+               break;
+
+       case CTDB_CONTROL_STARTUP:
+               break;
+
+       case CTDB_CONTROL_SET_TUNABLE:
+               break;
+
+       case CTDB_CONTROL_GET_TUNABLE:
+               assert(cd->data.tun_value == cd2->data.tun_value);
+               break;
+
+       case CTDB_CONTROL_LIST_TUNABLES:
+               verify_ctdb_var_list(cd->data.tun_var_list,
+                                    cd2->data.tun_var_list);
+               break;
+
+       case CTDB_CONTROL_MODIFY_FLAGS:
+               break;
+
+       case CTDB_CONTROL_GET_ALL_TUNABLES:
+               verify_ctdb_tunable_list(cd->data.tun_list, cd2->data.tun_list);
+               break;
+
+       case CTDB_CONTROL_KILL_TCP:
+               break;
+
+       case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
+               verify_ctdb_tickle_list(cd->data.tickles, cd2->data.tickles);
+               break;
+
+       case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
+               break;
+
+       case CTDB_CONTROL_REGISTER_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_UNREGISTER_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_CHECK_SERVER_ID:
+               break;
+
+       case CTDB_CONTROL_GET_SERVER_ID_LIST:
+               verify_ctdb_client_id_map(cd->data.cid_map, cd2->data.cid_map);
+               break;
+
+       case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
+               break;
+
+       case CTDB_CONTROL_UPDATE_RECORD:
+               break;
+
+       case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_START:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_COMMIT:
+               break;
+
+       case CTDB_CONTROL_WIPE_DATABASE:
+               break;
+
+       case CTDB_CONTROL_UPTIME:
+               verify_ctdb_uptime(cd->data.uptime, cd2->data.uptime);
+               break;
+
+       case CTDB_CONTROL_START_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_END_RECOVERY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_NODES_FILE:
+               break;
+
+       case CTDB_CONTROL_TRY_DELETE_RECORDS:
+               verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_ENABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_DISABLE_MONITOR:
+               break;
+
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               break;
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               break;
+
+       case CTDB_CONTROL_RUN_EVENTSCRIPTS:
+               break;
+
+       case CTDB_CONTROL_GET_CAPABILITIES:
+               assert(cd->data.caps == cd2->data.caps);
+               break;
+
+       case CTDB_CONTROL_RECD_PING:
+               break;
+
+       case CTDB_CONTROL_RELEASE_IP:
+               break;
+
+       case CTDB_CONTROL_TAKEOVER_IP:
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IPS:
+               verify_ctdb_public_ip_list(cd->data.pubip_list,
+                                          cd2->data.pubip_list);
+               break;
+
+       case CTDB_CONTROL_GET_NODEMAP:
+               verify_ctdb_node_map(cd->data.nodemap, cd2->data.nodemap);
+               break;
+
+       case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
+               verify_ctdb_script_list(cd->data.script_list,
+                                       cd2->data.script_list);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_KILL:
+               break;
+
+       case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
+               break;
+
+       case CTDB_CONTROL_GET_RECLOCK_FILE:
+               verify_ctdb_string(cd->data.reclock_file,
+                                  cd2->data.reclock_file);
+               break;
+
+       case CTDB_CONTROL_SET_RECLOCK_FILE:
+               break;
+
+       case CTDB_CONTROL_STOP_NODE:
+               break;
+
+       case CTDB_CONTROL_CONTINUE_NODE:
+               break;
+
+       case CTDB_CONTROL_SET_NATGWSTATE:
+               break;
+
+       case CTDB_CONTROL_SET_LMASTERROLE:
+               break;
+
+       case CTDB_CONTROL_SET_RECMASTERROLE:
+               break;
+
+       case CTDB_CONTROL_ENABLE_SCRIPT:
+               break;
+
+       case CTDB_CONTROL_DISABLE_SCRIPT:
+               break;
+
+       case CTDB_CONTROL_SET_BAN_STATE:
+               break;
+
+       case CTDB_CONTROL_GET_BAN_STATE:
+               verify_ctdb_ban_state(cd->data.ban_state, cd2->data.ban_state);
+               break;
+
+       case CTDB_CONTROL_SET_DB_PRIORITY:
+               break;
+
+       case CTDB_CONTROL_GET_DB_PRIORITY:
+               break;
+
+       case CTDB_CONTROL_TRANSACTION_CANCEL:
+               break;
+
+       case CTDB_CONTROL_REGISTER_NOTIFY:
+               break;
+
+       case CTDB_CONTROL_DEREGISTER_NOTIFY:
+               break;
+
+       case CTDB_CONTROL_TRANS3_COMMIT:
+               break;
+
+       case CTDB_CONTROL_GET_DB_SEQNUM:
+               assert(cd->data.seqnum == cd2->data.seqnum);
+               break;
+
+       case CTDB_CONTROL_DB_SET_HEALTHY:
+               break;
+
+       case CTDB_CONTROL_DB_GET_HEALTH:
+               verify_ctdb_string(cd->data.reason, cd2->data.reason);
+               break;
+
+       case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
+               verify_ctdb_public_ip_info(cd->data.ipinfo, cd2->data.ipinfo);
+               break;
+
+       case CTDB_CONTROL_GET_IFACES:
+               verify_ctdb_iface_list(cd->data.iface_list,
+                                      cd2->data.iface_list);
+               break;
+
+       case CTDB_CONTROL_SET_IFACE_LINK_STATE:
+               break;
+
+       case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE:
+               break;
+
+       case CTDB_CONTROL_GET_STAT_HISTORY:
+               verify_ctdb_statistics_list(cd->data.stats_list,
+                                           cd2->data.stats_list);
+               break;
+
+       case CTDB_CONTROL_SCHEDULE_FOR_DELETION:
+               break;
+
+       case CTDB_CONTROL_SET_DB_READONLY:
+               break;
+
+       case CTDB_CONTROL_CHECK_SRVIDS:
+               verify_ctdb_uint8_array(cd->data.u8_array, cd2->data.u8_array);
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_START_EXT:
+               break;
+
+       case CTDB_CONTROL_GET_DB_STATISTICS:
+               verify_ctdb_db_statistics(cd->data.dbstats, cd2->data.dbstats);
+               break;
+
+       case CTDB_CONTROL_SET_DB_STICKY:
+               break;
+
+       case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
+               break;
+
+       case CTDB_CONTROL_TRAVERSE_ALL_EXT:
+               break;
+
+       case CTDB_CONTROL_RECEIVE_RECORDS:
+               verify_ctdb_rec_buffer(cd->data.recbuf, cd2->data.recbuf);
+               break;
+
+       case CTDB_CONTROL_IPREALLOCATED:
+               break;
+
+       case CTDB_CONTROL_GET_RUNSTATE:
+               assert(cd->data.runstate == cd2->data.runstate);
+               break;
+
+       case CTDB_CONTROL_DB_DETACH:
+               break;
+
+       case CTDB_CONTROL_GET_NODES_FILE:
+               verify_ctdb_node_map(cd->data.nodemap, cd2->data.nodemap);
+               break;
+
+       }
+}
+
+static void fill_ctdb_reply_control(TALLOC_CTX *mem_ctx,
+                                   struct ctdb_reply_control *c,
+                                   uint32_t opcode)
+{
+       c->status = -rand_int(2);
+       if (c->status == 0) {
+               c->errmsg = NULL;
+               fill_ctdb_reply_control_data(mem_ctx, &c->rdata, opcode);
+       } else {
+               fill_ctdb_string(mem_ctx, &c->errmsg);
+       }
+}
+
+static void verify_ctdb_reply_control(struct ctdb_reply_control *c,
+                                     struct ctdb_reply_control *c2)
+{
+       assert(c->status == c2->status);
+       verify_ctdb_string(c->errmsg, c2->errmsg);
+       if (c->status == 0) {
+               verify_ctdb_reply_control_data(&c->rdata, &c2->rdata);
+       }
+}
+
+static void fill_ctdb_req_message_data(TALLOC_CTX *mem_ctx,
+                                      struct ctdb_req_message_data *c)
+{
+       c->srvid = rand64();
+       fill_tdb_data(mem_ctx, &c->data);
+}
+
+static void verify_ctdb_req_message_data(struct ctdb_req_message_data *c,
+                                        struct ctdb_req_message_data *c2)
+{
+       assert(c->srvid == c2->srvid);
+       verify_tdb_data(&c->data, &c2->data);
+}
+
+/*
+ * Functions to test marshalling
+ */
+
+static void test_ctdb_req_header(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       struct ctdb_req_header *h, h2;
+       int ret;
+
+       printf("ctdb_req_header\n");
+       fflush(stdout);
+
+       mem_ctx = talloc_new(NULL);
+       assert(mem_ctx != NULL);
+
+       ret = allocate_pkt(mem_ctx, sizeof(struct ctdb_req_header),
+                          &pkt, &pkt_len);
+       assert(ret == 0);
+
+       h = (struct ctdb_req_header *)pkt;
+       ctdb_req_header_fill(h, GENERATION, OPERATION, DESTNODE, SRCNODE,
+                            REQID);
+
+       ret = ctdb_req_header_pull(pkt, pkt_len, &h2);
+       assert(ret == 0);
+
+       verify_ctdb_req_header(h, &h2);
+
+       talloc_free(mem_ctx);
+}
+
+static void test_req_call_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       int ret;
+       struct ctdb_req_header h, h2;
+       struct ctdb_req_call c, c2;
+
+       printf("ctdb_req_call\n");
+       fflush(stdout);
+
+       mem_ctx = talloc_new(NULL);
+       assert(mem_ctx != NULL);
+
+       ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_CALL,
+                            DESTNODE, SRCNODE, REQID);
+
+       fill_ctdb_req_call(mem_ctx, &c);
+       ret = ctdb_req_call_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+       assert(ret == 0);
+       ret = ctdb_req_call_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+       assert(ret == 0);
+       verify_ctdb_req_header(&h, &h2);
+       verify_ctdb_req_call(&c, &c2);
+
+       talloc_free(mem_ctx);
+}
+
+static void test_reply_call_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       int ret;
+       struct ctdb_req_header h, h2;
+       struct ctdb_reply_call c, c2;
+
+       printf("ctdb_reply_call\n");
+       fflush(stdout);
+
+       mem_ctx = talloc_new(NULL);
+       assert(mem_ctx != NULL);
+
+       ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_CALL,
+                            DESTNODE, SRCNODE, REQID);
+
+       fill_ctdb_reply_call(mem_ctx, &c);
+       ret = ctdb_reply_call_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+       assert(ret == 0);
+       ret = ctdb_reply_call_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+       assert(ret == 0);
+       verify_ctdb_req_header(&h, &h2);
+       verify_ctdb_reply_call(&c, &c2);
+
+       talloc_free(mem_ctx);
+}
+
+static void test_reply_error_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       int ret;
+       struct ctdb_req_header h, h2;
+       struct ctdb_reply_error c, c2;
+
+       printf("ctdb_reply_error\n");
+       fflush(stdout);
+
+       mem_ctx = talloc_new(NULL);
+       assert(mem_ctx != NULL);
+
+       ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_ERROR,
+                            DESTNODE, SRCNODE, REQID);
+
+       fill_ctdb_reply_error(mem_ctx, &c);
+       ret = ctdb_reply_error_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+       assert(ret == 0);
+       ret = ctdb_reply_error_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+       assert(ret == 0);
+       verify_ctdb_req_header(&h, &h2);
+       verify_ctdb_reply_error(&c, &c2);
+
+       talloc_free(mem_ctx);
+}
+
+static void test_req_dmaster_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       int ret;
+       struct ctdb_req_header h, h2;
+       struct ctdb_req_dmaster c, c2;
+
+       printf("ctdb_req_dmaster\n");
+       fflush(stdout);
+
+       mem_ctx = talloc_new(NULL);
+       assert(mem_ctx != NULL);
+
+       ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_DMASTER,
+                            DESTNODE, SRCNODE, REQID);
+
+       fill_ctdb_req_dmaster(mem_ctx, &c);
+       ret = ctdb_req_dmaster_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+       assert(ret == 0);
+       ret = ctdb_req_dmaster_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+       assert(ret == 0);
+       verify_ctdb_req_header(&h, &h2);
+       verify_ctdb_req_dmaster(&c, &c2);
+
+       talloc_free(mem_ctx);
+}
+
+static void test_reply_dmaster_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       int ret;
+       struct ctdb_req_header h, h2;
+       struct ctdb_reply_dmaster c, c2;
+
+       printf("ctdb_reply_dmaster\n");
+       fflush(stdout);
+
+       mem_ctx = talloc_new(NULL);
+       assert(mem_ctx != NULL);
+
+       ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_DMASTER,
+                            DESTNODE, SRCNODE, REQID);
+
+       fill_ctdb_reply_dmaster(mem_ctx, &c);
+       ret = ctdb_reply_dmaster_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+       assert(ret == 0);
+       ret = ctdb_reply_dmaster_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+       assert(ret == 0);
+       verify_ctdb_req_header(&h, &h2);
+       verify_ctdb_reply_dmaster(&c, &c2);
+
+       talloc_free(mem_ctx);
+}
+
+#define NUM_CONTROLS   141
+
+static void test_req_control_data_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       size_t buflen;
+       int ret;
+       struct ctdb_req_control_data cd, cd2;
+       uint32_t opcode;
+
+       printf("ctdb_req_control_data\n");
+       fflush(stdout);
+
+       for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
+               mem_ctx = talloc_new(NULL);
+               assert(mem_ctx != NULL);
+
+               printf("%u.. ", opcode);
+               fflush(stdout);
+               fill_ctdb_req_control_data(mem_ctx, &cd, opcode);
+               buflen = ctdb_req_control_data_len(&cd);
+               ctdb_req_control_data_push(&cd, BUFFER);
+               ret = ctdb_req_control_data_pull(BUFFER, buflen, opcode, mem_ctx, &cd2);
+               assert(ret == 0);
+               verify_ctdb_req_control_data(&cd, &cd2);
+               talloc_free(mem_ctx);
+       }
+
+       printf("\n");
+       fflush(stdout);
+}
+
+static void test_reply_control_data_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       size_t buflen;
+       int ret;
+       struct ctdb_reply_control_data cd, cd2;
+       uint32_t opcode;
+
+       printf("ctdb_reply_control_data\n");
+       fflush(stdout);
+
+       for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
+               mem_ctx = talloc_new(NULL);
+               assert(mem_ctx != NULL);
+
+               printf("%u.. ", opcode);
+               fflush(stdout);
+               fill_ctdb_reply_control_data(mem_ctx, &cd, opcode);
+               buflen = ctdb_reply_control_data_len(&cd);
+               ctdb_reply_control_data_push(&cd, BUFFER);
+               ret = ctdb_reply_control_data_pull(BUFFER, buflen, opcode, mem_ctx, &cd2);
+               assert(ret == 0);
+               verify_ctdb_reply_control_data(&cd, &cd2);
+               talloc_free(mem_ctx);
+       }
+
+       printf("\n");
+       fflush(stdout);
+}
+
+static void test_req_control_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       int ret;
+       struct ctdb_req_header h, h2;
+       struct ctdb_req_control c, c2;
+       uint32_t opcode;
+
+       printf("ctdb_req_control\n");
+       fflush(stdout);
+
+       ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_CONTROL,
+                            DESTNODE, SRCNODE, REQID);
+
+       for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
+               mem_ctx = talloc_new(NULL);
+               assert(mem_ctx != NULL);
+
+               printf("%u.. ", opcode);
+               fflush(stdout);
+               fill_ctdb_req_control(mem_ctx, &c, opcode);
+               ret = ctdb_req_control_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+               assert(ret == 0);
+               ret = ctdb_req_control_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+               assert(ret == 0);
+               verify_ctdb_req_header(&h, &h2);
+               verify_ctdb_req_control(&c, &c2);
+
+               talloc_free(mem_ctx);
+       }
+
+       printf("\n");
+       fflush(stdout);
+}
+
+static void test_reply_control_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       int ret;
+       struct ctdb_req_header h, h2;
+       struct ctdb_reply_control c, c2;
+       uint32_t opcode;
+
+       printf("ctdb_reply_control\n");
+       fflush(stdout);
+
+       ctdb_req_header_fill(&h, GENERATION, CTDB_REPLY_CONTROL,
+                            DESTNODE, SRCNODE, REQID);
+
+       for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
+               mem_ctx = talloc_new(NULL);
+               assert(mem_ctx != NULL);
+
+               printf("%u.. ", opcode);
+               fflush(stdout);
+               fill_ctdb_reply_control(mem_ctx, &c, opcode);
+               ret = ctdb_reply_control_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+               assert(ret == 0);
+               ret = ctdb_reply_control_pull(pkt, pkt_len, opcode, &h2, mem_ctx, &c2);
+               assert(ret == 0);
+               verify_ctdb_req_header(&h, &h2);
+               verify_ctdb_reply_control(&c, &c2);
+
+               talloc_free(mem_ctx);
+       }
+
+       printf("\n");
+       fflush(stdout);
+}
+
+static void test_req_message_test(void)
+{
+       TALLOC_CTX *mem_ctx;
+       uint8_t *pkt;
+       size_t pkt_len;
+       int ret;
+       struct ctdb_req_header h, h2;
+       struct ctdb_req_message_data c, c2;
+
+       printf("ctdb_req_message\n");
+       fflush(stdout);
+
+       mem_ctx = talloc_new(NULL);
+       assert(mem_ctx != NULL);
+
+       ctdb_req_header_fill(&h, GENERATION, CTDB_REQ_MESSAGE,
+                            DESTNODE, SRCNODE, REQID);
+
+       fill_ctdb_req_message_data(mem_ctx, &c);
+       ret = ctdb_req_message_data_push(&h, &c, mem_ctx, &pkt, &pkt_len);
+       assert(ret == 0);
+       ret = ctdb_req_message_data_pull(pkt, pkt_len, &h2, mem_ctx, &c2);
+       assert(ret == 0);
+       verify_ctdb_req_header(&h, &h2);
+       verify_ctdb_req_message_data(&c, &c2);
+
+       talloc_free(mem_ctx);
+}
+
+int main(int argc, char *argv[])
+{
+       if (argc == 2) {
+               int seed = atoi(argv[1]);
+               srandom(seed);
+       }
+
+       test_ctdb_req_header();
+
+       test_req_call_test();
+       test_reply_call_test();
+       test_reply_error_test();
+       test_req_dmaster_test();
+       test_reply_dmaster_test();
+
+       test_req_control_data_test();
+       test_reply_control_data_test();
+
+       test_req_control_test();
+       test_reply_control_test();
+
+       test_req_message_test();
+
+       return 0;
+}
diff --git a/ctdb/tests/src/protocol_types_test.c b/ctdb/tests/src/protocol_types_test.c
new file mode 100644 (file)
index 0000000..4e85315
--- /dev/null
@@ -0,0 +1,1278 @@
+/*
+   protocol types tests
+
+   Copyright (C) Amitay Isaacs  2015
+
+   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 "system/network.h"
+
+#include <assert.h>
+
+#include "protocol/protocol_types.c"
+#include "protocol/protocol_header.c"
+#include "protocol/protocol_call.c"
+#include "protocol/protocol_control.c"
+#include "protocol/protocol_message.c"
+#include "protocol/protocol_packet.c"
+
+uint8_t BUFFER[1024*1024];
+
+/*
+ * Functions to generation random data
+ */
+
+static int rand_int(int max)
+{
+       return random() % max;
+}
+
+static uint8_t rand8(void)
+{
+       uint8_t val = rand_int(256) & 0xff;
+       return val;
+}
+
+static uint32_t rand32(void)
+{
+       return random();
+}
+
+static uint64_t rand64(void)
+{
+       uint64_t t = random();
+       t = (t << 32) | random();
+       return t;
+}
+
+static double rand_double(void)
+{
+       return 1.0 / rand64();
+}
+
+static void fill_buffer(void *p, size_t len)
+{
+       int i;
+       uint8_t *ptr = p;
+
+       for (i=0; i<len; i++) {
+               ptr[i] = rand8();
+       }
+}
+
+static void verify_buffer(void *p1, void *p2, size_t len)
+{
+       if (len > 0) {
+               assert(memcmp(p1, p2, len) == 0);
+       }
+}
+
+/*
+ * Functions to fill and verify data types
+ */
+
+static void fill_tdb_data(TALLOC_CTX *mem_ctx, TDB_DATA *p)
+{
+       p->dsize = rand_int(1024) + 1;
+       p->dptr = talloc_array(mem_ctx, uint8_t, p->dsize);
+       assert(p->dptr != NULL);
+       fill_buffer(p->dptr, p->dsize);
+}
+
+static void verify_tdb_data(TDB_DATA *p1, TDB_DATA *p2)
+{
+       assert(p1->dsize == p2->dsize);
+       verify_buffer(p1->dptr, p2->dptr, p1->dsize);
+}
+
+static void fill_ctdb_statistics(TALLOC_CTX *mem_ctx, struct ctdb_statistics *p)
+{
+       fill_buffer((uint8_t *)p, sizeof(struct ctdb_statistics));
+}
+
+static void verify_ctdb_statistics(struct ctdb_statistics *p1,
+                                  struct ctdb_statistics *p2)
+{
+       verify_buffer(p1, p2, sizeof(struct ctdb_statistics));
+}
+
+static void fill_ctdb_vnn_map(TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *p)
+{
+       int i;
+
+       p->generation = rand32();
+       p->size = rand_int(20) + 1;
+       p->map = talloc_array(mem_ctx, uint32_t, p->size);
+       assert(p->map != NULL);
+
+       for (i=0; i<p->size; i++) {
+               p->map[i] = rand32();
+       }
+}
+
+static void verify_ctdb_vnn_map(struct ctdb_vnn_map *p1,
+                               struct ctdb_vnn_map *p2)
+{
+       int i;
+
+       assert(p1->generation == p2->generation);
+       assert(p1->size == p2->size);
+       for (i=0; i<p1->size; i++) {
+               assert(p1->map[i] == p2->map[i]);
+       }
+}
+
+static void fill_ctdb_dbid(TALLOC_CTX *mem_ctx, struct ctdb_dbid *p)
+{
+       p->db_id = rand32();
+       p->flags = rand8();
+}
+
+static void verify_ctdb_dbid(struct ctdb_dbid *p1, struct ctdb_dbid *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->flags == p2->flags);
+}
+
+static void fill_ctdb_dbid_map(TALLOC_CTX *mem_ctx, struct ctdb_dbid_map *p)
+{
+       int i;
+
+       p->num = rand_int(40) + 1;
+       p->dbs = talloc_array(mem_ctx, struct ctdb_dbid, p->num);
+       assert(p->dbs != NULL);
+       for (i=0; i<p->num; i++) {
+               fill_ctdb_dbid(mem_ctx, &p->dbs[i]);
+       }
+}
+
+static void verify_ctdb_dbid_map(struct ctdb_dbid_map *p1,
+                                struct ctdb_dbid_map *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               verify_ctdb_dbid(&p1->dbs[i], &p2->dbs[i]);
+       }
+}
+
+static void fill_ctdb_pulldb(TALLOC_CTX *mem_ctx, struct ctdb_pulldb *p)
+{
+       p->db_id = rand32();
+       p->lmaster = rand32();
+}
+
+static void verify_ctdb_pulldb(struct ctdb_pulldb *p1, struct ctdb_pulldb *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->lmaster == p2->lmaster);
+}
+
+static void fill_ctdb_ltdb_header(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_ltdb_header *p)
+{
+       p->rsn = rand64();
+       p->dmaster = rand32();
+       p->flags = rand32();
+}
+
+static void verify_ctdb_ltdb_header(struct ctdb_ltdb_header *p1,
+                                   struct ctdb_ltdb_header *p2)
+{
+       assert(p1->rsn == p2->rsn);
+       assert(p1->dmaster == p2->dmaster);
+       assert(p1->flags == p2->flags);
+}
+
+static void fill_ctdb_rec_data(TALLOC_CTX *mem_ctx, struct ctdb_rec_data *p)
+{
+       p->reqid = rand32();
+       if (p->reqid % 5 == 0) {
+               p->header = talloc(mem_ctx, struct ctdb_ltdb_header);
+               assert(p->header != NULL);
+               fill_ctdb_ltdb_header(mem_ctx, p->header);
+       } else {
+               p->header = NULL;
+       }
+       fill_tdb_data(mem_ctx, &p->key);
+       fill_tdb_data(mem_ctx, &p->data);
+}
+
+static void verify_ctdb_rec_data(struct ctdb_rec_data *p1,
+                                struct ctdb_rec_data *p2)
+{
+       assert(p1->reqid == p2->reqid);
+       if (p1->header == NULL || p2->header == NULL) {
+               assert(p1->header == p2->header);
+       } else {
+               verify_ctdb_ltdb_header(p1->header, p2->header);
+       }
+       verify_tdb_data(&p1->key, &p2->key);
+       verify_tdb_data(&p1->data, &p2->data);
+}
+
+static void fill_ctdb_rec_buffer(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *p)
+{
+       struct ctdb_rec_data rec;
+       int ret, i;
+       int count;
+
+       p->db_id = rand32();
+       p->count = 0;
+       p->buf = NULL;
+       p->buflen = 0;
+
+       count = rand_int(100) + 1;
+       for (i=0; i<count; i++) {
+               fill_ctdb_rec_data(mem_ctx, &rec);
+               ret = ctdb_rec_buffer_add(mem_ctx, p, rec.reqid, rec.header,
+                                         rec.key, rec.data);
+               assert(ret == 0);
+       }
+}
+
+static void verify_ctdb_rec_buffer(struct ctdb_rec_buffer *p1,
+                                  struct ctdb_rec_buffer *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->count == p2->count);
+       assert(p1->buflen == p2->buflen);
+       verify_buffer(p1->buf, p2->buf, p1->buflen);
+}
+
+static void fill_ctdb_traverse_start(TALLOC_CTX *mem_ctx,
+                                    struct ctdb_traverse_start *p)
+{
+       p->db_id = rand32();
+       p->reqid = rand32();
+       p->srvid = rand64();
+}
+
+static void verify_ctdb_traverse_start(struct ctdb_traverse_start *p1,
+                                      struct ctdb_traverse_start *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->reqid == p2->reqid);
+       assert(p1->srvid == p2->srvid);
+}
+
+static void fill_ctdb_traverse_all(TALLOC_CTX *mem_ctx,
+                                  struct ctdb_traverse_all *p)
+{
+       p->db_id = rand32();
+       p->reqid = rand32();
+       p->pnn = rand32();
+       p->client_reqid = rand32();
+       p->srvid = rand64();
+}
+
+static void verify_ctdb_traverse_all(struct ctdb_traverse_all *p1,
+                                    struct ctdb_traverse_all *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->reqid == p2->reqid);
+       assert(p1->pnn == p2->pnn);
+       assert(p1->client_reqid == p2->client_reqid);
+       assert(p1->srvid == p2->srvid);
+}
+
+static void fill_ctdb_traverse_start_ext(TALLOC_CTX *mem_ctx,
+                                        struct ctdb_traverse_start_ext *p)
+{
+       p->db_id = rand32();
+       p->reqid = rand32();
+       p->srvid = rand64();
+       p->withemptyrecords = rand_int(2);
+}
+
+static void verify_ctdb_traverse_start_ext(struct ctdb_traverse_start_ext *p1,
+                                          struct ctdb_traverse_start_ext *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->reqid == p2->reqid);
+       assert(p1->srvid == p2->srvid);
+       assert(p1->withemptyrecords == p2->withemptyrecords);
+}
+
+static void fill_ctdb_traverse_all_ext(TALLOC_CTX *mem_ctx,
+                                      struct ctdb_traverse_all_ext *p)
+{
+       p->db_id = rand32();
+       p->reqid = rand32();
+       p->pnn = rand32();
+       p->client_reqid = rand32();
+       p->srvid = rand64();
+       p->withemptyrecords = rand_int(2);
+}
+
+static void verify_ctdb_traverse_all_ext(struct ctdb_traverse_all_ext *p1,
+                                        struct ctdb_traverse_all_ext *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->reqid == p2->reqid);
+       assert(p1->pnn == p2->pnn);
+       assert(p1->client_reqid == p2->client_reqid);
+       assert(p1->srvid == p2->srvid);
+       assert(p1->withemptyrecords == p2->withemptyrecords);
+}
+
+static void fill_ctdb_sock_addr(TALLOC_CTX *mem_ctx, ctdb_sock_addr *p)
+{
+       if (rand_int(2) == 0) {
+               p->ip.sin_family = AF_INET;
+               p->ip.sin_port = rand_int(65535);
+               fill_buffer(&p->ip.sin_addr, sizeof(struct in_addr));
+       } else {
+               p->ip6.sin6_family = AF_INET6;
+               p->ip6.sin6_port = rand_int(65535);
+               fill_buffer(&p->ip6.sin6_addr, sizeof(struct in6_addr));
+       }
+}
+
+static void verify_ctdb_sock_addr(ctdb_sock_addr *p1, ctdb_sock_addr *p2)
+{
+       assert(p1->sa.sa_family == p2->sa.sa_family);
+       if (p1->sa.sa_family == AF_INET) {
+               assert(p1->ip.sin_port == p2->ip.sin_port);
+               verify_buffer(&p1->ip.sin_addr, &p2->ip.sin_addr,
+                                  sizeof(struct in_addr));
+       } else {
+               assert(p1->ip6.sin6_port == p2->ip6.sin6_port);
+               verify_buffer(&p1->ip6.sin6_addr, &p2->ip6.sin6_addr,
+                                  sizeof(struct in6_addr));
+       }
+}
+
+static void fill_ctdb_connection(TALLOC_CTX *mem_ctx,
+                                struct ctdb_connection *p)
+{
+       fill_ctdb_sock_addr(mem_ctx, &p->src);
+       fill_ctdb_sock_addr(mem_ctx, &p->dst);
+}
+
+static void verify_ctdb_connection(struct ctdb_connection *p1,
+                                  struct ctdb_connection *p2)
+{
+       verify_ctdb_sock_addr(&p1->src, &p2->src);
+       verify_ctdb_sock_addr(&p1->dst, &p2->dst);
+}
+
+static void fill_ctdb_string(TALLOC_CTX *mem_ctx, const char **out)
+{
+       char *p;
+       int len, i;
+
+       len = rand_int(1024) + 1;
+       p = talloc_size(mem_ctx, len+1);
+       assert(p != NULL);
+
+       for (i=0; i<len; i++) {
+               p[i] = 'A' + rand_int(26);
+       }
+       p[len] = '\0';
+       *out = p;
+}
+
+static void verify_ctdb_string(const char *p1, const char *p2)
+{
+       if (p1 == NULL || p2 == NULL) {
+               assert(p1 == p2);
+       } else {
+               assert(strlen(p1) == strlen(p2));
+               assert(strcmp(p1, p2) == 0);
+       }
+}
+
+static void fill_ctdb_tunable(TALLOC_CTX *mem_ctx, struct ctdb_tunable *p)
+{
+       fill_ctdb_string(mem_ctx, discard_const(&p->name));
+       p->value = rand32();
+}
+
+static void verify_ctdb_tunable(struct ctdb_tunable *p1,
+                               struct ctdb_tunable *p2)
+{
+       verify_ctdb_string(discard_const(p1->name), discard_const(p2->name));
+       assert(p1->value == p2->value);
+}
+
+static void fill_ctdb_node_flag_change(TALLOC_CTX *mem_ctx,
+                                      struct ctdb_node_flag_change *p)
+{
+       p->pnn = rand32();
+       p->new_flags = rand32();
+       p->old_flags = rand32();
+}
+
+static void verify_ctdb_node_flag_change(struct ctdb_node_flag_change *p1,
+                                        struct ctdb_node_flag_change *p2)
+{
+       assert(p1->pnn == p2->pnn);
+       assert(p1->new_flags == p2->new_flags);
+       assert(p1->old_flags == p2->old_flags);
+}
+
+static void fill_ctdb_var_list(TALLOC_CTX *mem_ctx,
+                              struct ctdb_var_list *p)
+{
+       int i;
+
+       p->count = rand_int(100) + 1;
+       p->var = talloc_array(mem_ctx, const char *, p->count);
+       for (i=0; i<p->count; i++) {
+               fill_ctdb_string(p->var, discard_const(&p->var[i]));
+       }
+}
+
+static void verify_ctdb_var_list(struct ctdb_var_list *p1,
+                                struct ctdb_var_list *p2)
+{
+       int i;
+
+       assert(p1->count == p2->count);
+       for (i=0; i<p1->count; i++) {
+               verify_ctdb_string(discard_const(p1->var[i]),
+                                  discard_const(p2->var[i]));
+       }
+}
+
+static void fill_ctdb_tunable_list(TALLOC_CTX *mem_ctx,
+                                  struct ctdb_tunable_list *p)
+{
+       fill_buffer(p, sizeof(struct ctdb_tunable_list));
+}
+
+static void verify_ctdb_tunable_list(struct ctdb_tunable_list *p1,
+                                    struct ctdb_tunable_list *p2)
+{
+       verify_buffer(p1, p2, sizeof(struct ctdb_tunable_list));
+}
+
+static void fill_ctdb_tickle_list(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_tickle_list *p)
+{
+       int i;
+
+       fill_ctdb_sock_addr(mem_ctx, &p->addr);
+       p->num = rand_int(1000) + 1;
+       p->conn = talloc_array(mem_ctx, struct ctdb_connection, p->num);
+       assert(p->conn != NULL);
+       for (i=0; i<p->num; i++) {
+               fill_ctdb_connection(mem_ctx, &p->conn[i]);
+       }
+}
+
+static void verify_ctdb_tickle_list(struct ctdb_tickle_list *p1,
+                                   struct ctdb_tickle_list *p2)
+{
+       int i;
+
+       verify_ctdb_sock_addr(&p1->addr, &p2->addr);
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               verify_ctdb_connection(&p1->conn[i], &p2->conn[i]);
+       }
+}
+
+static void fill_ctdb_client_id(TALLOC_CTX *mem_ctx,
+                               struct ctdb_client_id *p)
+{
+       p->type = rand8();
+       p->pnn = rand32();
+       p->server_id = rand32();
+}
+
+static void verify_ctdb_client_id(struct ctdb_client_id *p1,
+                                 struct ctdb_client_id *p2)
+{
+       assert(p1->type == p2->type);
+       assert(p1->pnn == p2->pnn);
+       assert(p1->server_id == p2->server_id);
+}
+
+static void fill_ctdb_client_id_list(TALLOC_CTX *mem_ctx,
+                                    struct ctdb_client_id_list *p)
+{
+       int i;
+
+       p->num = rand_int(1000) + 1;
+       p->cid = talloc_array(mem_ctx, struct ctdb_client_id, p->num);
+       assert(p->cid != NULL);
+       for (i=0; i<p->num; i++) {
+               fill_ctdb_client_id(mem_ctx, &p->cid[i]);
+       }
+}
+
+static void verify_ctdb_client_id_list(struct ctdb_client_id_list *p1,
+                                      struct ctdb_client_id_list *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               verify_ctdb_client_id(&p1->cid[i], &p2->cid[i]);
+       }
+}
+
+static void fill_ctdb_client_id_map(TALLOC_CTX *mem_ctx,
+                                   struct ctdb_client_id_map *p)
+{
+       int i;
+
+       p->count = rand_int(10) + 1;
+       p->list = talloc_array(mem_ctx, struct ctdb_client_id_list, p->count);
+       assert(p->list != NULL);
+       for (i=0; i<p->count; i++) {
+               fill_ctdb_client_id_list(mem_ctx, &p->list[i]);
+       }
+}
+
+static void verify_ctdb_client_id_map(struct ctdb_client_id_map *p1,
+                                     struct ctdb_client_id_map *p2)
+{
+       int i;
+
+       assert(p1->count == p2->count);
+       for (i=0; i<p1->count; i++) {
+               verify_ctdb_client_id_list(&p1->list[i], &p2->list[i]);
+       }
+}
+
+static void fill_ctdb_addr_info(TALLOC_CTX *mem_ctx, struct ctdb_addr_info *p)
+{
+       fill_ctdb_sock_addr(mem_ctx, &p->addr);
+       p->mask = rand_int(33);
+       fill_ctdb_string(mem_ctx, &p->iface);
+}
+
+static void verify_ctdb_addr_info(struct ctdb_addr_info *p1,
+                                 struct ctdb_addr_info *p2)
+{
+       verify_ctdb_sock_addr(&p1->addr, &p2->addr);
+       assert(p1->mask == p2->mask);
+       verify_ctdb_string(p1->iface, p2->iface);
+}
+
+static void fill_ctdb_transdb(TALLOC_CTX *mem_ctx, struct ctdb_transdb *p)
+{
+       p->db_id = rand32();
+       p->tid = rand32();
+}
+
+static void verify_ctdb_transdb(struct ctdb_transdb *p1, struct ctdb_transdb *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->tid == p2->tid);
+}
+
+static void fill_ctdb_uptime(TALLOC_CTX *mem_ctx, struct ctdb_uptime *p)
+{
+       fill_buffer(p, sizeof(struct ctdb_uptime));
+}
+
+static void verify_ctdb_uptime(struct ctdb_uptime *p1, struct ctdb_uptime *p2)
+{
+       verify_buffer(p1, p2, sizeof(struct ctdb_uptime));
+}
+
+static void fill_ctdb_public_ip(TALLOC_CTX *mem_ctx, struct ctdb_public_ip *p)
+{
+       p->pnn = rand32();
+       fill_ctdb_sock_addr(mem_ctx, &p->addr);
+}
+
+static void verify_ctdb_public_ip(struct ctdb_public_ip *p1,
+                                 struct ctdb_public_ip *p2)
+{
+       assert(p1->pnn == p2->pnn);
+       verify_ctdb_sock_addr(&p1->addr, &p2->addr);
+}
+
+static void fill_ctdb_public_ip_list(TALLOC_CTX *mem_ctx,
+                                    struct ctdb_public_ip_list *p)
+{
+       int i;
+
+       p->num = rand_int(32) + 1;
+       p->ip = talloc_array(mem_ctx, struct ctdb_public_ip, p->num);
+       assert(p->ip != NULL);
+       for (i=0; i<p->num; i++) {
+               fill_ctdb_public_ip(mem_ctx, &p->ip[i]);
+       }
+}
+
+static void verify_ctdb_public_ip_list(struct ctdb_public_ip_list *p1,
+                                      struct ctdb_public_ip_list *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               verify_ctdb_public_ip(&p1->ip[i], &p2->ip[i]);
+       }
+}
+
+static void fill_ctdb_node_and_flags(TALLOC_CTX *mem_ctx,
+                                    struct ctdb_node_and_flags *p)
+{
+       p->pnn = rand32();
+       p->flags = rand32();
+       fill_ctdb_sock_addr(mem_ctx, &p->addr);
+}
+
+static void verify_ctdb_node_and_flags(struct ctdb_node_and_flags *p1,
+                                      struct ctdb_node_and_flags *p2)
+{
+       assert(p1->pnn == p2->pnn);
+       assert(p1->flags == p2->flags);
+       verify_ctdb_sock_addr(&p1->addr, &p2->addr);
+}
+
+static void fill_ctdb_node_map(TALLOC_CTX *mem_ctx, struct ctdb_node_map *p)
+{
+       int i;
+
+       p->num = rand_int(32) + 1;
+       p->node = talloc_array(mem_ctx, struct ctdb_node_and_flags, p->num);
+       assert(p->node != NULL);
+       for (i=0; i<p->num; i++) {
+               fill_ctdb_node_and_flags(mem_ctx, &p->node[i]);
+       }
+}
+
+static void verify_ctdb_node_map(struct ctdb_node_map *p1,
+                                struct ctdb_node_map *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               verify_ctdb_node_and_flags(&p1->node[i], &p2->node[i]);
+       }
+}
+
+static void fill_ctdb_script(TALLOC_CTX *mem_ctx, struct ctdb_script *p)
+{
+       fill_buffer(p, sizeof(struct ctdb_script));
+}
+
+static void verify_ctdb_script(struct ctdb_script *p1, struct ctdb_script *p2)
+{
+       verify_buffer(p1, p2, sizeof(struct ctdb_script));
+}
+
+static void fill_ctdb_script_list(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_script_list *p)
+{
+       int i;
+
+       p->num_scripts = rand_int(32) + 1;
+       p->script = talloc_array(mem_ctx, struct ctdb_script, p->num_scripts);
+       assert(p->script != NULL);
+       for (i=0; i<p->num_scripts; i++) {
+               fill_ctdb_script(mem_ctx, &p->script[i]);
+       }
+}
+
+static void verify_ctdb_script_list(struct ctdb_script_list *p1,
+                                   struct ctdb_script_list *p2)
+{
+       int i;
+
+       assert(p1->num_scripts == p2->num_scripts);
+       for (i=0; i<p1->num_scripts; i++) {
+               verify_ctdb_script(&p1->script[i], &p2->script[i]);
+       }
+}
+
+static void fill_ctdb_ban_state(TALLOC_CTX *mem_ctx, struct ctdb_ban_state *p)
+{
+       p->pnn = rand32();
+       p->time = rand32();
+}
+
+static void verify_ctdb_ban_state(struct ctdb_ban_state *p1,
+                                 struct ctdb_ban_state *p2)
+{
+       assert(p1->pnn == p2->pnn);
+       assert(p1->time == p2->time);
+}
+
+static void fill_ctdb_db_priority(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_db_priority *p)
+{
+       p->db_id = rand32();
+       p->priority = rand32();
+}
+
+static void verify_ctdb_db_priority(struct ctdb_db_priority *p1,
+                                   struct ctdb_db_priority *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       assert(p1->priority == p2->priority);
+}
+
+static void fill_ctdb_notify_data(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_notify_data *p)
+{
+       p->srvid = rand64();
+       fill_tdb_data(mem_ctx, &p->data);
+}
+
+static void verify_ctdb_notify_data(struct ctdb_notify_data *p1,
+                                   struct ctdb_notify_data *p2)
+{
+       assert(p1->srvid == p2->srvid);
+       verify_tdb_data(&p1->data, &p2->data);
+}
+
+static void fill_ctdb_iface(TALLOC_CTX *mem_ctx, struct ctdb_iface *p)
+{
+       fill_buffer(p, sizeof(struct ctdb_iface));
+}
+
+static void verify_ctdb_iface(struct ctdb_iface *p1, struct ctdb_iface *p2)
+{
+       verify_buffer(p1, p2, sizeof(struct ctdb_iface));
+}
+
+static void fill_ctdb_iface_list(TALLOC_CTX *mem_ctx,
+                                struct ctdb_iface_list *p)
+{
+       int i;
+
+       p->num = rand_int(32) + 1;
+       p->iface = talloc_array(mem_ctx, struct ctdb_iface, p->num);
+       assert(p->iface != NULL);
+       for (i=0; i<p->num; i++) {
+               fill_ctdb_iface(mem_ctx, &p->iface[i]);
+       }
+}
+
+static void verify_ctdb_iface_list(struct ctdb_iface_list *p1,
+                                  struct ctdb_iface_list *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               verify_ctdb_iface(&p1->iface[i], &p2->iface[i]);
+       }
+}
+
+static void fill_ctdb_public_ip_info(TALLOC_CTX *mem_ctx,
+                                    struct ctdb_public_ip_info *p)
+{
+       fill_ctdb_public_ip(mem_ctx, &p->ip);
+       p->active_idx = rand_int(32) + 1;
+       p->ifaces = talloc(mem_ctx, struct ctdb_iface_list);
+       assert(p->ifaces != NULL);
+       fill_ctdb_iface_list(mem_ctx, p->ifaces);
+}
+
+static void verify_ctdb_public_ip_info(struct ctdb_public_ip_info *p1,
+                                      struct ctdb_public_ip_info *p2)
+{
+       verify_ctdb_public_ip(&p1->ip, &p2->ip);
+       assert(p1->active_idx == p2->active_idx);
+       verify_ctdb_iface_list(p1->ifaces, p2->ifaces);
+}
+
+static void fill_ctdb_statistics_list(TALLOC_CTX *mem_ctx,
+                                     struct ctdb_statistics_list *p)
+{
+       int i;
+
+       p->num = rand_int(10) + 1;
+       p->stats = talloc_array(mem_ctx, struct ctdb_statistics, p->num);
+       assert(p->stats != NULL);
+
+       for (i=0; i<p->num; i++) {
+               fill_ctdb_statistics(mem_ctx, &p->stats[i]);
+       }
+}
+
+static void verify_ctdb_statistics_list(struct ctdb_statistics_list *p1,
+                                       struct ctdb_statistics_list *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               verify_ctdb_statistics(&p1->stats[i], &p2->stats[i]);
+       }
+}
+
+static void fill_ctdb_key_data(TALLOC_CTX *mem_ctx, struct ctdb_key_data *p)
+{
+       p->db_id = rand32();
+       fill_ctdb_ltdb_header(mem_ctx, &p->header);
+       fill_tdb_data(mem_ctx, &p->key);
+}
+
+static void verify_ctdb_key_data(struct ctdb_key_data *p1,
+                                struct ctdb_key_data *p2)
+{
+       assert(p1->db_id == p2->db_id);
+       verify_ctdb_ltdb_header(&p1->header, &p2->header);
+       verify_tdb_data(&p1->key, &p2->key);
+}
+
+static void fill_ctdb_uint8_array(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_uint8_array *p)
+{
+       int i;
+
+       p->num = rand_int(1024) + 1;
+       p->val = talloc_array(mem_ctx, uint8_t, p->num);
+       assert(p->val != NULL);
+
+       for (i=0; i<p->num; i++) {
+               p->val[i] = rand8();
+       }
+}
+
+static void verify_ctdb_uint8_array(struct ctdb_uint8_array *p1,
+                                   struct ctdb_uint8_array *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               assert(p1->val[i] == p2->val[i]);
+       }
+}
+
+static void fill_ctdb_uint64_array(TALLOC_CTX *mem_ctx,
+                                  struct ctdb_uint64_array *p)
+{
+       int i;
+
+       p->num = rand_int(1024) + 1;
+       p->val = talloc_array(mem_ctx, uint64_t, p->num);
+       assert(p->val != NULL);
+
+       for (i=0; i<p->num; i++) {
+               p->val[i] = rand64();
+       }
+}
+
+static void verify_ctdb_uint64_array(struct ctdb_uint64_array *p1,
+                                    struct ctdb_uint64_array *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               assert(p1->val[i] == p2->val[i]);
+       }
+}
+
+static void fill_ctdb_db_statistics(TALLOC_CTX *mem_ctx,
+                                  struct ctdb_db_statistics *p)
+{
+       int i;
+
+       fill_buffer(p, offsetof(struct ctdb_db_statistics, num_hot_keys));
+       p->num_hot_keys = 10;
+       for (i=0; i<p->num_hot_keys; i++) {
+               p->hot_keys[i].count = rand32();
+               fill_tdb_data(mem_ctx, &p->hot_keys[i].key);
+       }
+}
+
+static void verify_ctdb_db_statistics(struct ctdb_db_statistics *p1,
+                                     struct ctdb_db_statistics *p2)
+{
+       int i;
+
+       verify_buffer(p1, p2, offsetof(struct ctdb_db_statistics,
+                                           num_hot_keys));
+       assert(p1->num_hot_keys == p2->num_hot_keys);
+       for (i=0; i<p1->num_hot_keys; i++) {
+               assert(p1->hot_keys[i].count == p2->hot_keys[i].count);
+               verify_tdb_data(&p1->hot_keys[i].key, &p2->hot_keys[i].key);
+       }
+}
+
+#ifndef PROTOCOL_TEST
+
+static void fill_ctdb_election_message(TALLOC_CTX *mem_ctx,
+                                      struct ctdb_election_message *p)
+{
+       p->num_connected = rand_int(32);
+       fill_buffer(&p->priority_time, sizeof(struct timeval));
+       p->pnn = rand_int(32);
+       p->node_flags = rand32();
+}
+
+static void verify_ctdb_election_message(struct ctdb_election_message *p1,
+                                        struct ctdb_election_message *p2)
+{
+       assert(p1->num_connected == p2->num_connected);
+       verify_buffer(p1, p2, sizeof(struct timeval));
+       assert(p1->pnn == p2->pnn);
+       assert(p1->node_flags == p2->node_flags);
+}
+
+static void fill_ctdb_srvid_message(TALLOC_CTX *mem_ctx,
+                                   struct ctdb_srvid_message *p)
+{
+       p->pnn = rand_int(32);
+       p->srvid = rand64();
+}
+
+static void verify_ctdb_srvid_message(struct ctdb_srvid_message *p1,
+                                     struct ctdb_srvid_message *p2)
+{
+       assert(p1->pnn == p2->pnn);
+       assert(p1->srvid == p2->srvid);
+}
+
+static void fill_ctdb_disable_message(TALLOC_CTX *mem_ctx,
+                                     struct ctdb_disable_message *p)
+{
+       p->pnn = rand_int(32);
+       p->srvid = rand64();
+       p->timeout = rand32();
+}
+
+static void verify_ctdb_disable_message(struct ctdb_disable_message *p1,
+                                       struct ctdb_disable_message *p2)
+{
+       assert(p1->pnn == p2->pnn);
+       assert(p1->srvid == p2->srvid);
+       assert(p1->timeout == p2->timeout);
+}
+
+static void fill_ctdb_server_id(TALLOC_CTX *mem_ctx,
+                               struct ctdb_server_id *p)
+{
+       p->pid = rand64();
+       p->task_id = rand32();
+       p->vnn = rand_int(32);
+       p->unique_id = rand64();
+}
+
+static void verify_ctdb_server_id(struct ctdb_server_id *p1,
+                                 struct ctdb_server_id *p2)
+{
+       assert(p1->pid == p2->pid);
+       assert(p1->task_id == p2->task_id);
+       assert(p1->vnn == p2->vnn);
+       assert(p1->unique_id == p2->unique_id);
+}
+
+static void fill_ctdb_g_lock(TALLOC_CTX *mem_ctx, struct ctdb_g_lock *p)
+{
+       p->type = rand_int(2);
+       fill_ctdb_server_id(mem_ctx, &p->sid);
+}
+
+static void verify_ctdb_g_lock(struct ctdb_g_lock *p1, struct ctdb_g_lock *p2)
+{
+       assert(p1->type == p2->type);
+       verify_ctdb_server_id(&p1->sid, &p2->sid);
+}
+
+static void fill_ctdb_g_lock_list(TALLOC_CTX *mem_ctx,
+                                 struct ctdb_g_lock_list *p)
+{
+       int i;
+
+       p->num = rand_int(20) + 1;
+       p->lock = talloc_array(mem_ctx, struct ctdb_g_lock, p->num);
+       assert(p->lock != NULL);
+       for (i=0; i<p->num; i++) {
+               fill_ctdb_g_lock(mem_ctx, &p->lock[i]);
+       }
+}
+
+static void verify_ctdb_g_lock_list(struct ctdb_g_lock_list *p1,
+                                   struct ctdb_g_lock_list *p2)
+{
+       int i;
+
+       assert(p1->num == p2->num);
+       for (i=0; i<p1->num; i++) {
+               verify_ctdb_g_lock(&p1->lock[i], &p2->lock[i]);
+       }
+}
+
+/*
+ * Functions to test marshalling routines
+ */
+
+static void test_ctdb_uint32(void)
+{
+       uint32_t p1, p2;
+       size_t buflen;
+       int ret;
+
+       p1 = rand32();
+       buflen = ctdb_uint32_len(p1);
+       ctdb_uint32_push(p1, BUFFER);
+       ret = ctdb_uint32_pull(BUFFER, buflen, NULL, &p2);
+       assert(ret == 0);
+       assert(p1 == p2);
+}
+
+static void test_ctdb_uint64(void)
+{
+       uint64_t p1, p2;
+       size_t buflen;
+       int ret;
+
+       p1 = rand64();
+       buflen = ctdb_uint64_len(p1);
+       ctdb_uint64_push(p1, BUFFER);
+       ret = ctdb_uint64_pull(BUFFER, buflen, NULL, &p2);
+       assert(ret == 0);
+       assert(p1 == p2);
+}
+
+static void test_ctdb_double(void)
+{
+       double p1, p2;
+       size_t buflen;
+       int ret;
+
+       p1 = rand_double();
+       buflen = ctdb_double_len(p1);
+       ctdb_double_push(p1, BUFFER);
+       ret = ctdb_double_pull(BUFFER, buflen, NULL, &p2);
+       assert(ret == 0);
+       assert(p1 == p2);
+}
+
+static void test_ctdb_pid(void)
+{
+       pid_t p1, p2;
+       size_t buflen;
+       int ret;
+
+       p1 = rand32();
+       buflen = ctdb_pid_len(p1);
+       ctdb_pid_push(p1, BUFFER);
+       ret = ctdb_pid_pull(BUFFER, buflen, NULL, &p2);
+       assert(ret == 0);
+       assert(p1 == p2);
+}
+
+#define TEST_FUNC(NAME)                test_ ##NAME
+#define FILL_FUNC(NAME)                fill_ ##NAME
+#define VERIFY_FUNC(NAME)      verify_ ##NAME
+#define LEN_FUNC(NAME)         NAME## _len
+#define PUSH_FUNC(NAME)                NAME## _push
+#define PULL_FUNC(NAME)                NAME## _pull
+
+#define DEFINE_TEST(TYPE, NAME)        \
+static void TEST_FUNC(NAME)(void) \
+{ \
+       TALLOC_CTX *mem_ctx = talloc_new(NULL); \
+       TYPE *p1, *p2; \
+       size_t buflen; \
+       int ret; \
+\
+       p1 = talloc_zero(mem_ctx, TYPE); \
+       assert(p1 != NULL); \
+       FILL_FUNC(NAME)(p1, p1); \
+       buflen = LEN_FUNC(NAME)(p1); \
+       PUSH_FUNC(NAME)(p1, BUFFER); \
+       ret = PULL_FUNC(NAME)(BUFFER, buflen, mem_ctx, &p2); \
+       assert(ret == 0); \
+       VERIFY_FUNC(NAME)(p1, p2); \
+       talloc_free(mem_ctx); \
+}
+
+
+static void test_ctdb_string(void)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(NULL);
+       const char *p1, *p2;
+       size_t buflen;
+       int ret;
+
+       fill_ctdb_string(mem_ctx, &p1);
+       buflen = ctdb_string_len(p1);
+       ctdb_string_push(p1, BUFFER);
+       ret = ctdb_string_pull(BUFFER, buflen, mem_ctx, &p2);
+       assert(ret == 0);
+       verify_ctdb_string(p1, p2);
+       talloc_free(mem_ctx);
+}
+
+static void test_ctdb_stringn(void)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(NULL);
+       const char *p1, *p2;
+       size_t buflen;
+       int ret;
+
+       fill_ctdb_string(mem_ctx, &p1);
+       buflen = ctdb_stringn_len(p1);
+       ctdb_stringn_push(p1, BUFFER);
+       ret = ctdb_stringn_pull(BUFFER, buflen, mem_ctx, &p2);
+       assert(ret == 0);
+       verify_ctdb_string(p1, p2);
+       talloc_free(mem_ctx);
+}
+
+static void test_ctdb_ltdb_header(void)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(NULL);
+       struct ctdb_ltdb_header p1, p2;
+       size_t buflen;
+       int ret;
+
+       fill_ctdb_ltdb_header(mem_ctx, &p1);
+       buflen = ctdb_ltdb_header_len(&p1);
+       ctdb_ltdb_header_push(&p1, BUFFER);
+       ret = ctdb_ltdb_header_pull(BUFFER, buflen, &p2);
+       assert(ret == 0);
+       verify_ctdb_ltdb_header(&p1, &p2);
+       talloc_free(mem_ctx);
+}
+
+static void test_ctdb_g_lock(void)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(NULL);
+       struct ctdb_g_lock p1, p2;
+       size_t buflen;
+       int ret;
+
+       fill_ctdb_g_lock(mem_ctx, &p1);
+       buflen = ctdb_g_lock_len(&p1);
+       ctdb_g_lock_push(&p1, BUFFER);
+       ret = ctdb_g_lock_pull(BUFFER, buflen, &p2);
+       assert(ret == 0);
+       verify_ctdb_g_lock(&p1, &p2);
+       talloc_free(mem_ctx);
+}
+
+DEFINE_TEST(struct ctdb_statistics, ctdb_statistics);
+DEFINE_TEST(struct ctdb_vnn_map, ctdb_vnn_map);
+DEFINE_TEST(struct ctdb_dbid_map, ctdb_dbid_map);
+DEFINE_TEST(struct ctdb_pulldb, ctdb_pulldb);
+DEFINE_TEST(struct ctdb_rec_data, ctdb_rec_data);
+DEFINE_TEST(struct ctdb_rec_buffer, ctdb_rec_buffer);
+DEFINE_TEST(struct ctdb_traverse_start, ctdb_traverse_start);
+DEFINE_TEST(struct ctdb_traverse_all, ctdb_traverse_all);
+DEFINE_TEST(struct ctdb_traverse_start_ext, ctdb_traverse_start_ext);
+DEFINE_TEST(struct ctdb_traverse_all_ext, ctdb_traverse_all_ext);
+DEFINE_TEST(ctdb_sock_addr, ctdb_sock_addr);
+DEFINE_TEST(struct ctdb_connection, ctdb_connection);
+DEFINE_TEST(struct ctdb_tunable, ctdb_tunable);
+DEFINE_TEST(struct ctdb_node_flag_change, ctdb_node_flag_change);
+DEFINE_TEST(struct ctdb_var_list, ctdb_var_list);
+DEFINE_TEST(struct ctdb_tunable_list, ctdb_tunable_list);
+DEFINE_TEST(struct ctdb_tickle_list, ctdb_tickle_list);
+DEFINE_TEST(struct ctdb_client_id, ctdb_client_id);
+DEFINE_TEST(struct ctdb_client_id_list, ctdb_client_id_list);
+DEFINE_TEST(struct ctdb_client_id_map, ctdb_client_id_map);
+DEFINE_TEST(struct ctdb_addr_info, ctdb_addr_info);
+DEFINE_TEST(struct ctdb_transdb, ctdb_transdb);
+DEFINE_TEST(struct ctdb_uptime, ctdb_uptime);
+DEFINE_TEST(struct ctdb_public_ip, ctdb_public_ip);
+DEFINE_TEST(struct ctdb_public_ip_list, ctdb_public_ip_list);
+DEFINE_TEST(struct ctdb_node_and_flags, ctdb_node_and_flags);
+DEFINE_TEST(struct ctdb_node_map, ctdb_node_map);
+DEFINE_TEST(struct ctdb_script, ctdb_script);
+DEFINE_TEST(struct ctdb_script_list, ctdb_script_list);
+DEFINE_TEST(struct ctdb_ban_state, ctdb_ban_state);
+DEFINE_TEST(struct ctdb_db_priority, ctdb_db_priority);
+DEFINE_TEST(struct ctdb_notify_data, ctdb_notify_data);
+DEFINE_TEST(struct ctdb_iface, ctdb_iface);
+DEFINE_TEST(struct ctdb_iface_list, ctdb_iface_list);
+DEFINE_TEST(struct ctdb_public_ip_info, ctdb_public_ip_info);
+DEFINE_TEST(struct ctdb_statistics_list, ctdb_statistics_list);
+DEFINE_TEST(struct ctdb_key_data, ctdb_key_data);
+DEFINE_TEST(struct ctdb_uint8_array, ctdb_uint8_array);
+DEFINE_TEST(struct ctdb_uint64_array, ctdb_uint64_array);
+DEFINE_TEST(struct ctdb_db_statistics, ctdb_db_statistics);
+DEFINE_TEST(struct ctdb_election_message, ctdb_election_message);
+DEFINE_TEST(struct ctdb_srvid_message, ctdb_srvid_message);
+DEFINE_TEST(struct ctdb_disable_message, ctdb_disable_message);
+DEFINE_TEST(struct ctdb_g_lock_list, ctdb_g_lock_list);
+
+int main(int argc, char *argv[])
+{
+       if (argc == 2) {
+               int seed = atoi(argv[1]);
+               srandom(seed);
+       }
+
+       test_ctdb_uint32();
+       test_ctdb_uint64();
+       test_ctdb_double();
+       test_ctdb_pid();
+
+       test_ctdb_string();
+       test_ctdb_stringn();
+
+       test_ctdb_ltdb_header();
+       test_ctdb_g_lock();
+
+       TEST_FUNC(ctdb_statistics)();
+       TEST_FUNC(ctdb_vnn_map)();
+       TEST_FUNC(ctdb_dbid_map)();
+       TEST_FUNC(ctdb_pulldb)();
+       TEST_FUNC(ctdb_rec_data)();
+       TEST_FUNC(ctdb_rec_buffer)();
+       TEST_FUNC(ctdb_traverse_start)();
+       TEST_FUNC(ctdb_traverse_all)();
+       TEST_FUNC(ctdb_traverse_start_ext)();
+       TEST_FUNC(ctdb_traverse_all_ext)();
+       TEST_FUNC(ctdb_sock_addr)();
+       TEST_FUNC(ctdb_connection)();
+       TEST_FUNC(ctdb_tunable)();
+       TEST_FUNC(ctdb_node_flag_change)();
+       TEST_FUNC(ctdb_var_list)();
+       TEST_FUNC(ctdb_tunable_list)();
+       TEST_FUNC(ctdb_tickle_list)();
+       TEST_FUNC(ctdb_client_id)();
+       TEST_FUNC(ctdb_client_id_list)();
+       TEST_FUNC(ctdb_client_id_map)();
+       TEST_FUNC(ctdb_addr_info)();
+       TEST_FUNC(ctdb_transdb)();
+       TEST_FUNC(ctdb_uptime)();
+       TEST_FUNC(ctdb_public_ip)();
+       TEST_FUNC(ctdb_public_ip_list)();
+       TEST_FUNC(ctdb_node_and_flags)();
+       TEST_FUNC(ctdb_node_map)();
+       TEST_FUNC(ctdb_script)();
+       TEST_FUNC(ctdb_script_list)();
+       TEST_FUNC(ctdb_ban_state)();
+       TEST_FUNC(ctdb_db_priority)();
+       TEST_FUNC(ctdb_notify_data)();
+       TEST_FUNC(ctdb_iface)();
+       TEST_FUNC(ctdb_iface_list)();
+       TEST_FUNC(ctdb_public_ip_info)();
+       TEST_FUNC(ctdb_statistics_list)();
+       TEST_FUNC(ctdb_key_data)();
+       TEST_FUNC(ctdb_uint8_array)();
+       TEST_FUNC(ctdb_uint64_array)();
+       TEST_FUNC(ctdb_db_statistics)();
+       TEST_FUNC(ctdb_election_message)();
+       TEST_FUNC(ctdb_srvid_message)();
+       TEST_FUNC(ctdb_disable_message)();
+       TEST_FUNC(ctdb_g_lock_list)();
+
+       return 0;
+}
+
+#endif
index 243ac9b0b784825ce7be63adad5d4061db0daa23..3d8664279ada85ed49f2f5d773531089f5346fba 100755 (executable)
@@ -340,6 +340,17 @@ def build(bld):
                                              logging.c'''),
                         deps='replace talloc tevent tdb tevent-unix-util')
 
+    bld.SAMBA_SUBSYSTEM('ctdb-protocol',
+                        source=bld.SUBDIR('protocol',
+                                          '''protocol_header.c protocol_packet.c
+                                             protocol_types.c protocol_call.c
+                                             protocol_message.c
+                                             protocol_control.c
+                                             protocol_client.c
+                                             protocol_util.c'''),
+                        includes='include',
+                        deps='replace talloc tdb')
+
     bld.SAMBA_SUBSYSTEM('ctdb-client',
                         source=bld.SUBDIR('client', 'ctdb_client.c'),
                         includes='include include/internal',
@@ -584,6 +595,8 @@ def build(bld):
         'comm_test',
         'comm_server_test',
         'comm_client_test',
+        'protocol_types_test',
+        'protocol_client_test',
     ]
 
     for target in ctdb_unit_tests: