diff --git a/ctdb/protocol/protocol_call.c b/ctdb/protocol/protocol_call.c index b1805155f63..393b1181bd2 100644 --- a/ctdb/protocol/protocol_call.c +++ b/ctdb/protocol/protocol_call.c @@ -27,15 +27,6 @@ #include "protocol_api.h" #include "protocol_private.h" -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]; -}; - size_t ctdb_req_call_len(struct ctdb_req_header *h, struct ctdb_req_call *c) { return ctdb_req_header_len(h) + @@ -460,18 +451,21 @@ int ctdb_req_dmaster_pull(uint8_t *buf, size_t buflen, size_t ctdb_reply_dmaster_len(struct ctdb_req_header *h, struct ctdb_reply_dmaster *c) { - return offsetof(struct ctdb_reply_dmaster_wire, data) + - ctdb_tdb_data_len(&c->key) + - ctdb_tdb_data_len(&c->data); + return ctdb_req_header_len(h) + + ctdb_uint32_len(&c->db_id) + + ctdb_padding_len(4) + + ctdb_uint64_len(&c->rsn) + + ctdb_tdb_datan_len(&c->key) + + ctdb_tdb_datan_len(&c->data); } int ctdb_reply_dmaster_push(struct ctdb_req_header *h, struct ctdb_reply_dmaster *c, uint8_t *buf, size_t *buflen) { - struct ctdb_reply_dmaster_wire *wire = - (struct ctdb_reply_dmaster_wire *)buf; - size_t length, np; + size_t offset = 0, np; + size_t length; + uint32_t u32; length = ctdb_reply_dmaster_len(h, c); if (*buflen < length) { @@ -480,14 +474,31 @@ int ctdb_reply_dmaster_push(struct ctdb_req_header *h, } h->length = *buflen; - ctdb_req_header_push(h, (uint8_t *)&wire->hdr, &np); + ctdb_req_header_push(h, buf+offset, &np); + offset += np; - wire->db_id = c->db_id; - wire->rsn = c->rsn; - wire->keylen = ctdb_tdb_data_len(&c->key); - wire->datalen = ctdb_tdb_data_len(&c->data); - ctdb_tdb_data_push(&c->key, wire->data, &np); - ctdb_tdb_data_push(&c->data, wire->data + wire->keylen, &np); + ctdb_uint32_push(&c->db_id, buf+offset, &np); + offset += np; + + ctdb_padding_push(4, buf+offset, &np); + offset += np; + + ctdb_uint64_push(&c->rsn, buf+offset, &np); + offset += np; + + u32 = ctdb_tdb_data_len(&c->key); + ctdb_uint32_push(&u32, buf+offset, &np); + offset += np; + + u32 = ctdb_tdb_data_len(&c->data); + ctdb_uint32_push(&u32, buf+offset, &np); + offset += np; + + ctdb_tdb_data_push(&c->key, buf+offset, &np); + offset += np; + + ctdb_tdb_data_push(&c->data, buf+offset, &np); + offset += np; return 0; } @@ -497,50 +508,74 @@ int ctdb_reply_dmaster_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx, struct ctdb_reply_dmaster *c) { - struct ctdb_reply_dmaster_wire *wire = - (struct ctdb_reply_dmaster_wire *)buf; - size_t length, np; + struct ctdb_req_header header; + size_t offset = 0, np; + uint32_t u32; int ret; - length = offsetof(struct ctdb_reply_dmaster_wire, data); - if (buflen < length) { - return EMSGSIZE; - } - if (wire->keylen > buflen || wire->datalen > buflen) { - return EMSGSIZE; - } - if (length + wire->keylen < length) { - return EMSGSIZE; - } - if (length + wire->keylen + wire->datalen < length) { - return EMSGSIZE; - } - if (buflen < length + wire->keylen + wire->datalen) { - return EMSGSIZE; + ret = ctdb_req_header_pull(buf+offset, buflen-offset, &header, &np); + if (ret != 0) { + return ret; } + offset += np; if (h != NULL) { - ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, buflen, h, - &np); - if (ret != 0) { - return ret; - } + *h = header; } - c->db_id = wire->db_id; - c->rsn = wire->rsn; + ret = ctdb_uint32_pull(buf+offset, buflen-offset, &c->db_id, &np); + if (ret != 0) { + return ret; + } + offset += np; - ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key, + ret = ctdb_padding_pull(buf+offset, buflen-offset, 4, &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_uint64_pull(buf+offset, buflen-offset, &c->rsn, &np); + if (ret != 0) { + return ret; + } + offset += np; + + ret = ctdb_uint32_pull(buf+offset, buflen-offset, &u32, &np); + if (ret != 0) { + return ret; + } + offset += np; + c->key.dsize = u32; + + ret = ctdb_uint32_pull(buf+offset, buflen-offset, &u32, &np); + if (ret != 0) { + return ret; + } + offset += np; + c->data.dsize = u32; + + if (buflen-offset < c->key.dsize) { + return EMSGSIZE; + } + + ret = ctdb_tdb_data_pull(buf+offset, c->key.dsize, mem_ctx, &c->key, &np); if (ret != 0) { return ret; } + offset += np; - ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->datalen, - mem_ctx, &c->data, &np); + if (buflen-offset < c->data.dsize) { + return EMSGSIZE; + } + + ret = ctdb_tdb_data_pull(buf+offset, c->data.dsize, mem_ctx, &c->data, + &np); if (ret != 0) { return ret; } + offset += np; return 0; } diff --git a/ctdb/tests/src/protocol_ctdb_compat_test.c b/ctdb/tests/src/protocol_ctdb_compat_test.c index 5a751d47626..60a3d94621a 100644 --- a/ctdb/tests/src/protocol_ctdb_compat_test.c +++ b/ctdb/tests/src/protocol_ctdb_compat_test.c @@ -595,6 +595,102 @@ static int ctdb_req_dmaster_pull_old(uint8_t *buf, size_t buflen, return 0; } +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]; +}; + +static size_t ctdb_reply_dmaster_len_old(struct ctdb_req_header *h, + struct ctdb_reply_dmaster *c) +{ + return offsetof(struct ctdb_reply_dmaster_wire, data) + + ctdb_tdb_data_len(&c->key) + ctdb_tdb_data_len(&c->data); +} + +static int ctdb_reply_dmaster_push_old(struct ctdb_req_header *h, + struct ctdb_reply_dmaster *c, + uint8_t *buf, size_t *buflen) +{ + struct ctdb_reply_dmaster_wire *wire = + (struct ctdb_reply_dmaster_wire *)buf; + size_t length, np; + + length = ctdb_reply_dmaster_len_old(h, c); + if (*buflen < length) { + *buflen = length; + return EMSGSIZE; + } + + h->length = *buflen; + ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); + + wire->db_id = c->db_id; + wire->rsn = c->rsn; + wire->keylen = ctdb_tdb_data_len(&c->key); + wire->datalen = ctdb_tdb_data_len(&c->data); + ctdb_tdb_data_push(&c->key, wire->data, &np); + ctdb_tdb_data_push(&c->data, wire->data + wire->keylen, &np); + + return 0; +} + +static int ctdb_reply_dmaster_pull_old(uint8_t *buf, size_t buflen, + struct ctdb_req_header *h, + TALLOC_CTX *mem_ctx, + struct ctdb_reply_dmaster *c) +{ + struct ctdb_reply_dmaster_wire *wire = + (struct ctdb_reply_dmaster_wire *)buf; + size_t length, np; + int ret; + + length = offsetof(struct ctdb_reply_dmaster_wire, data); + if (buflen < length) { + return EMSGSIZE; + } + if (wire->keylen > buflen || wire->datalen > buflen) { + return EMSGSIZE; + } + if (length + wire->keylen < length) { + return EMSGSIZE; + } + if (length + wire->keylen + wire->datalen < length) { + return EMSGSIZE; + } + if (buflen < length + wire->keylen + wire->datalen) { + return EMSGSIZE; + } + + if (h != NULL) { + ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, + h); + if (ret != 0) { + return ret; + } + } + + c->db_id = wire->db_id; + c->rsn = wire->rsn; + + ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key, + &np); + if (ret != 0) { + return ret; + } + + ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->datalen, + mem_ctx, &c->data, &np); + if (ret != 0) { + return ret; + } + + return 0; +} + COMPAT_CTDB1_TEST(struct ctdb_req_header, ctdb_req_header); @@ -602,6 +698,7 @@ COMPAT_CTDB4_TEST(struct ctdb_req_call, ctdb_req_call, CTDB_REQ_CALL); COMPAT_CTDB4_TEST(struct ctdb_reply_call, ctdb_reply_call, CTDB_REPLY_CALL); COMPAT_CTDB4_TEST(struct ctdb_reply_error, ctdb_reply_error, CTDB_REPLY_ERROR); COMPAT_CTDB4_TEST(struct ctdb_req_dmaster, ctdb_req_dmaster, CTDB_REQ_DMASTER); +COMPAT_CTDB4_TEST(struct ctdb_reply_dmaster, ctdb_reply_dmaster, CTDB_REPLY_DMASTER); int main(int argc, char *argv[]) { @@ -616,6 +713,7 @@ int main(int argc, char *argv[]) COMPAT_TEST_FUNC(ctdb_reply_call)(); COMPAT_TEST_FUNC(ctdb_reply_error)(); COMPAT_TEST_FUNC(ctdb_req_dmaster)(); + COMPAT_TEST_FUNC(ctdb_reply_dmaster)(); return 0; } diff --git a/ctdb/tests/src/protocol_ctdb_test.c b/ctdb/tests/src/protocol_ctdb_test.c index 539d3dd5777..b2918a8fbc5 100644 --- a/ctdb/tests/src/protocol_ctdb_test.c +++ b/ctdb/tests/src/protocol_ctdb_test.c @@ -286,45 +286,8 @@ PROTOCOL_CTDB4_TEST(struct ctdb_reply_error, ctdb_reply_error, CTDB_REPLY_ERROR); PROTOCOL_CTDB4_TEST(struct ctdb_req_dmaster, ctdb_req_dmaster, CTDB_REQ_DMASTER); - -static void test_ctdb_reply_dmaster(void) -{ - TALLOC_CTX *mem_ctx; - uint8_t *pkt; - size_t datalen, pkt_len, 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); - datalen = ctdb_reply_dmaster_len(&h, &c); - ret = ctdb_allocate_pkt(mem_ctx, datalen, &pkt, &pkt_len); - assert(ret == 0); - assert(pkt != NULL); - assert(pkt_len >= datalen); - len = 0; - ret = ctdb_reply_dmaster_push(&h, &c, pkt, &len); - assert(ret == EMSGSIZE); - assert(len == datalen); - ret = ctdb_reply_dmaster_push(&h, &c, 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); - assert(h2.length == pkt_len); - verify_ctdb_reply_dmaster(&c, &c2); - - talloc_free(mem_ctx); -} +PROTOCOL_CTDB4_TEST(struct ctdb_reply_dmaster, ctdb_reply_dmaster, + CTDB_REPLY_DMASTER); #define NUM_CONTROLS 151 @@ -534,7 +497,7 @@ int main(int argc, char *argv[]) TEST_FUNC(ctdb_reply_call)(); TEST_FUNC(ctdb_reply_error)(); TEST_FUNC(ctdb_req_dmaster)(); - test_ctdb_reply_dmaster(); + TEST_FUNC(ctdb_reply_dmaster)(); test_ctdb_req_control_data(); test_ctdb_reply_control_data();