ctdb-protocol: Fix marshalling for ctdb_req_call
[vlendec/samba-autobuild/.git] / ctdb / protocol / protocol_message.c
1 /*
2    CTDB protocol marshalling
3
4    Copyright (C) Amitay Isaacs  2015
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/network.h"
22
23 #include <talloc.h>
24 #include <tdb.h>
25
26 #include "protocol.h"
27 #include "protocol_api.h"
28 #include "protocol_private.h"
29
30 struct ctdb_req_message_wire {
31         struct ctdb_req_header hdr;
32         uint64_t srvid;
33         uint32_t datalen;
34         uint8_t data[1];
35 };
36
37 static size_t ctdb_message_data_len(union ctdb_message_data *mdata,
38                                     uint64_t srvid)
39 {
40         size_t len = 0;
41
42         switch (srvid) {
43         case CTDB_SRVID_BANNING:
44                 len = ctdb_uint32_len(&mdata->pnn);
45                 break;
46
47         case CTDB_SRVID_ELECTION:
48                 len = ctdb_election_message_len(mdata->election);
49                 break;
50
51         case CTDB_SRVID_RECONFIGURE:
52                 break;
53
54         case CTDB_SRVID_RELEASE_IP:
55                 len = ctdb_string_len(&mdata->ipaddr);
56                 break;
57
58         case CTDB_SRVID_TAKE_IP:
59                 len = ctdb_string_len(&mdata->ipaddr);
60                 break;
61
62         case CTDB_SRVID_SET_NODE_FLAGS:
63                 len = ctdb_node_flag_change_len(mdata->flag_change);
64                 break;
65
66         case CTDB_SRVID_RECD_UPDATE_IP:
67                 len = ctdb_public_ip_len(mdata->pubip);
68                 break;
69
70         case CTDB_SRVID_VACUUM_FETCH:
71                 len = ctdb_rec_buffer_len(mdata->recbuf);
72                 break;
73
74         case CTDB_SRVID_DETACH_DATABASE:
75                 len = ctdb_uint32_len(&mdata->db_id);
76                 break;
77
78         case CTDB_SRVID_MEM_DUMP:
79                 len = ctdb_srvid_message_len(mdata->msg);
80                 break;
81
82         case CTDB_SRVID_PUSH_NODE_FLAGS:
83                 len = ctdb_node_flag_change_len(mdata->flag_change);
84                 break;
85
86         case CTDB_SRVID_RELOAD_NODES:
87                 break;
88
89         case CTDB_SRVID_TAKEOVER_RUN:
90                 len = ctdb_srvid_message_len(mdata->msg);
91                 break;
92
93         case CTDB_SRVID_REBALANCE_NODE:
94                 len = ctdb_uint32_len(&mdata->pnn);
95                 break;
96
97         case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
98                 len = ctdb_disable_message_len(mdata->disable);
99                 break;
100
101         case CTDB_SRVID_DISABLE_RECOVERIES:
102                 len = ctdb_disable_message_len(mdata->disable);
103                 break;
104
105         case CTDB_SRVID_DISABLE_IP_CHECK:
106                 len = ctdb_uint32_len(&mdata->timeout);
107                 break;
108
109         default:
110                 len = ctdb_tdb_data_len(&mdata->data);
111                 break;
112         }
113
114         return len;
115 }
116
117 static void ctdb_message_data_push(union ctdb_message_data *mdata,
118                                    uint64_t srvid, uint8_t *buf)
119 {
120         size_t np;
121
122         switch (srvid) {
123         case CTDB_SRVID_BANNING:
124                 ctdb_uint32_push(&mdata->pnn, buf, &np);
125                 break;
126
127         case CTDB_SRVID_ELECTION:
128                 ctdb_election_message_push(mdata->election, buf, &np);
129                 break;
130
131         case CTDB_SRVID_RECONFIGURE:
132                 break;
133
134         case CTDB_SRVID_RELEASE_IP:
135                 ctdb_string_push(&mdata->ipaddr, buf, &np);
136                 break;
137
138         case CTDB_SRVID_TAKE_IP:
139                 ctdb_string_push(&mdata->ipaddr, buf, &np);
140                 break;
141
142         case CTDB_SRVID_SET_NODE_FLAGS:
143                 ctdb_node_flag_change_push(mdata->flag_change, buf, &np);
144                 break;
145
146         case CTDB_SRVID_RECD_UPDATE_IP:
147                 ctdb_public_ip_push(mdata->pubip, buf, &np);
148                 break;
149
150         case CTDB_SRVID_VACUUM_FETCH:
151                 ctdb_rec_buffer_push(mdata->recbuf, buf, &np);
152                 break;
153
154         case CTDB_SRVID_DETACH_DATABASE:
155                 ctdb_uint32_push(&mdata->db_id, buf, &np);
156                 break;
157
158         case CTDB_SRVID_MEM_DUMP:
159                 ctdb_srvid_message_push(mdata->msg, buf, &np);
160                 break;
161
162         case CTDB_SRVID_PUSH_NODE_FLAGS:
163                 ctdb_node_flag_change_push(mdata->flag_change, buf, &np);
164                 break;
165
166         case CTDB_SRVID_RELOAD_NODES:
167                 break;
168
169         case CTDB_SRVID_TAKEOVER_RUN:
170                 ctdb_srvid_message_push(mdata->msg, buf, &np);
171                 break;
172
173         case CTDB_SRVID_REBALANCE_NODE:
174                 ctdb_uint32_push(&mdata->pnn, buf, &np);
175                 break;
176
177         case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
178                 ctdb_disable_message_push(mdata->disable, buf, &np);
179                 break;
180
181         case CTDB_SRVID_DISABLE_RECOVERIES:
182                 ctdb_disable_message_push(mdata->disable, buf, &np);
183                 break;
184
185         case CTDB_SRVID_DISABLE_IP_CHECK:
186                 ctdb_uint32_push(&mdata->timeout, buf, &np);
187                 break;
188
189         default:
190                 ctdb_tdb_data_push(&mdata->data, buf, &np);
191                 break;
192         }
193 }
194
195 static int ctdb_message_data_pull(uint8_t *buf, size_t buflen,
196                                   uint64_t srvid, TALLOC_CTX *mem_ctx,
197                                   union ctdb_message_data *mdata)
198 {
199         int ret = 0;
200         size_t np;
201
202         switch (srvid) {
203         case CTDB_SRVID_BANNING:
204                 ret = ctdb_uint32_pull(buf, buflen, &mdata->pnn, &np);
205                 break;
206
207         case CTDB_SRVID_ELECTION:
208                 ret = ctdb_election_message_pull(buf, buflen, mem_ctx,
209                                                  &mdata->election, &np);
210                 break;
211
212         case CTDB_SRVID_RECONFIGURE:
213                 break;
214
215         case CTDB_SRVID_RELEASE_IP:
216                 ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr,
217                                        &np);
218                 break;
219
220         case CTDB_SRVID_TAKE_IP:
221                 ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr,
222                                        &np);
223                 break;
224
225         case CTDB_SRVID_SET_NODE_FLAGS:
226                 ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
227                                                  &mdata->flag_change, &np);
228                 break;
229
230         case CTDB_SRVID_RECD_UPDATE_IP:
231                 ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
232                                           &mdata->pubip, &np);
233                 break;
234
235         case CTDB_SRVID_VACUUM_FETCH:
236                 ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
237                                            &mdata->recbuf, &np);
238                 break;
239
240         case CTDB_SRVID_DETACH_DATABASE:
241                 ret = ctdb_uint32_pull(buf, buflen, &mdata->db_id, &np);
242                 break;
243
244         case CTDB_SRVID_MEM_DUMP:
245                 ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx,
246                                               &mdata->msg, &np);
247                 break;
248
249         case CTDB_SRVID_PUSH_NODE_FLAGS:
250                 ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
251                                                  &mdata->flag_change, &np);
252                 break;
253
254         case CTDB_SRVID_RELOAD_NODES:
255                 break;
256
257         case CTDB_SRVID_TAKEOVER_RUN:
258                 ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx,
259                                               &mdata->msg, &np);
260                 break;
261
262         case CTDB_SRVID_REBALANCE_NODE:
263                 ret = ctdb_uint32_pull(buf, buflen, &mdata->pnn, &np);
264                 break;
265
266         case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
267                 ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
268                                                 &mdata->disable, &np);
269                 break;
270
271         case CTDB_SRVID_DISABLE_RECOVERIES:
272                 ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
273                                                 &mdata->disable, &np);
274                 break;
275
276         case CTDB_SRVID_DISABLE_IP_CHECK:
277                 ret = ctdb_uint32_pull(buf, buflen, &mdata->timeout, &np);
278                 break;
279
280         default:
281                 ret = ctdb_tdb_data_pull(buf, buflen, mem_ctx, &mdata->data,
282                                          &np);
283                 break;
284         }
285
286         return ret;
287 }
288
289 size_t ctdb_req_message_len(struct ctdb_req_header *h,
290                             struct ctdb_req_message *c)
291 {
292         return offsetof(struct ctdb_req_message_wire, data) +
293                 ctdb_message_data_len(&c->data, c->srvid);
294 }
295
296 int ctdb_req_message_push(struct ctdb_req_header *h,
297                           struct ctdb_req_message *message,
298                           uint8_t *buf, size_t *buflen)
299 {
300         struct ctdb_req_message_wire *wire =
301                 (struct ctdb_req_message_wire *)buf;
302         size_t length, np;
303
304         length = ctdb_req_message_len(h, message);
305         if (*buflen < length) {
306                 *buflen = length;
307                 return EMSGSIZE;
308         }
309
310         h->length = *buflen;
311         ctdb_req_header_push(h, (uint8_t *)&wire->hdr, &np);
312
313         wire->srvid = message->srvid;
314         wire->datalen = ctdb_message_data_len(&message->data, message->srvid);
315         ctdb_message_data_push(&message->data, message->srvid, wire->data);
316
317         return 0;
318 }
319
320 int ctdb_req_message_pull(uint8_t *buf, size_t buflen,
321                           struct ctdb_req_header *h,
322                           TALLOC_CTX *mem_ctx,
323                           struct ctdb_req_message *c)
324 {
325         struct ctdb_req_message_wire *wire =
326                 (struct ctdb_req_message_wire *)buf;
327         size_t length, np;
328         int ret;
329
330         length = offsetof(struct ctdb_req_message_wire, data);
331         if (buflen < length) {
332                 return EMSGSIZE;
333         }
334         if (wire->datalen > buflen) {
335                 return EMSGSIZE;
336         }
337         if (length + wire->datalen < length) {
338                 return EMSGSIZE;
339         }
340         if (buflen < length + wire->datalen) {
341                 return EMSGSIZE;
342         }
343
344         if (h != NULL) {
345                 ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, buflen, h,
346                                            &np);
347                 if (ret != 0) {
348                         return ret;
349                 }
350         }
351
352         c->srvid = wire->srvid;
353         ret = ctdb_message_data_pull(wire->data, wire->datalen, wire->srvid,
354                                      mem_ctx, &c->data);
355         return ret;
356 }
357
358 size_t ctdb_req_message_data_len(struct ctdb_req_header *h,
359                                  struct ctdb_req_message_data *c)
360 {
361         return offsetof(struct ctdb_req_message_wire, data) +
362                 ctdb_tdb_data_len(&c->data);
363 }
364
365 int ctdb_req_message_data_push(struct ctdb_req_header *h,
366                                struct ctdb_req_message_data *message,
367                                uint8_t *buf, size_t *buflen)
368 {
369         struct ctdb_req_message_wire *wire =
370                 (struct ctdb_req_message_wire *)buf;
371         size_t length, np;
372
373         length = ctdb_req_message_data_len(h, message);
374         if (*buflen < length) {
375                 *buflen = length;
376                 return EMSGSIZE;
377         }
378
379         h->length = *buflen;
380         ctdb_req_header_push(h, (uint8_t *)&wire->hdr, &np);
381
382         wire->srvid = message->srvid;
383         wire->datalen = ctdb_tdb_data_len(&message->data);
384         ctdb_tdb_data_push(&message->data, wire->data, &np);
385
386         return 0;
387 }
388
389 int ctdb_req_message_data_pull(uint8_t *buf, size_t buflen,
390                                struct ctdb_req_header *h,
391                                TALLOC_CTX *mem_ctx,
392                                struct ctdb_req_message_data *c)
393 {
394         struct ctdb_req_message_wire *wire =
395                 (struct ctdb_req_message_wire *)buf;
396         size_t length, np;
397         int ret;
398
399         length = offsetof(struct ctdb_req_message_wire, data);
400         if (buflen < length) {
401                 return EMSGSIZE;
402         }
403         if (wire->datalen > buflen) {
404                 return EMSGSIZE;
405         }
406         if (length + wire->datalen < length) {
407                 return EMSGSIZE;
408         }
409         if (buflen < length + wire->datalen) {
410                 return EMSGSIZE;
411         }
412
413         if (h != NULL) {
414                 ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, buflen, h,
415                                            &np);
416                 if (ret != 0) {
417                         return ret;
418                 }
419         }
420
421         c->srvid = wire->srvid;
422
423         ret = ctdb_tdb_data_pull(wire->data, wire->datalen,
424                                  mem_ctx, &c->data, &np);
425         if (ret != 0) {
426                 return ret;
427         }
428
429         return 0;
430 }