/* 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 . */ #include "replace.h" #include "system/network.h" #include #include #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) + ctdb_tdb_data_len(c->key) + ctdb_tdb_data_len(c->calldata); ret = allocate_pkt(mem_ctx, length, &buf, &buflen); if (ret != 0) { return ret; } wire = (struct ctdb_req_call_wire *)buf; h->length = buflen; ctdb_req_header_push(h, (uint8_t *)&wire->hdr); wire->flags = c->flags; wire->db_id = c->db_id; wire->callid = c->callid; wire->hopcount = c->hopcount; wire->keylen = ctdb_tdb_data_len(c->key); wire->calldatalen = ctdb_tdb_data_len(c->calldata); ctdb_tdb_data_push(c->key, wire->data); ctdb_tdb_data_push(c->calldata, wire->data + wire->keylen); *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; int ret; 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; } if (h != NULL) { ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, pkt_len, h); if (ret != 0) { return ret; } } c->flags = wire->flags; c->db_id = wire->db_id; c->callid = wire->callid; c->hopcount = wire->hopcount; ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key); if (ret != 0) { return ret; } ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->calldatalen, mem_ctx, &c->calldata); if (ret != 0) { return ret; } 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) + ctdb_tdb_data_len(c->data); ret = allocate_pkt(mem_ctx, length, &buf, &buflen); if (ret != 0) { return ret; } wire = (struct ctdb_reply_call_wire *)buf; h->length = buflen; ctdb_req_header_push(h, (uint8_t *)&wire->hdr); wire->status = c->status; wire->datalen = ctdb_tdb_data_len(c->data); ctdb_tdb_data_push(c->data, wire->data); *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; int ret; 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; } if (h != NULL) { ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, pkt_len, h); if (ret != 0) { return ret; } } c->status = wire->status; ret = ctdb_tdb_data_pull(wire->data, wire->datalen, mem_ctx, &c->data); if (ret != 0) { return ret; } 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) + ctdb_tdb_data_len(c->msg); ret = allocate_pkt(mem_ctx, length, &buf, &buflen); if (ret != 0) { return ret; } wire = (struct ctdb_reply_error_wire *)buf; h->length = buflen; ctdb_req_header_push(h, (uint8_t *)&wire->hdr); wire->status = c->status; wire->msglen = ctdb_tdb_data_len(c->msg); ctdb_tdb_data_push(c->msg, wire->msg); *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; int ret; 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; } if (h != NULL) { ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, pkt_len, h); if (ret != 0) { return ret; } } c->status = wire->status; ret = ctdb_tdb_data_pull(wire->msg, wire->msglen, mem_ctx, &c->msg); if (ret != 0) { return ret; } 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) + ctdb_tdb_data_len(c->key) + ctdb_tdb_data_len(c->data); ret = allocate_pkt(mem_ctx, length, &buf, &buflen); if (ret != 0) { return ret; } wire = (struct ctdb_req_dmaster_wire *)buf; h->length = buflen; ctdb_req_header_push(h, (uint8_t *)&wire->hdr); wire->db_id = c->db_id; wire->rsn = c->rsn; wire->dmaster = c->dmaster; wire->keylen = ctdb_tdb_data_len(c->key); wire->datalen = ctdb_tdb_data_len(c->data); ctdb_tdb_data_push(c->key, wire->data); ctdb_tdb_data_push(c->data, wire->data + wire->keylen); *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; int ret; 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; } if (h != NULL) { ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, pkt_len, h); if (ret != 0) { return ret; } } c->db_id = wire->db_id; c->rsn = wire->rsn; c->dmaster = wire->dmaster; ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key); if (ret != 0) { return ret; } ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->datalen, mem_ctx, &c->data); if (ret != 0) { return ret; } 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) + ctdb_tdb_data_len(c->key) + ctdb_tdb_data_len(c->data); ret = allocate_pkt(mem_ctx, length, &buf, &buflen); if (ret != 0) { return ret; } wire = (struct ctdb_reply_dmaster_wire *)buf; h->length = buflen; ctdb_req_header_push(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); ctdb_tdb_data_push(c->data, wire->data + wire->keylen); *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; int ret; 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; } if (h != NULL) { ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, pkt_len, 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); if (ret != 0) { return ret; } ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->datalen, mem_ctx, &c->data); if (ret != 0) { return ret; } return 0; }