ctdb-protocol: Fix marshalling for a string
[bbaumbach/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);
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);
144                 break;
145
146         case CTDB_SRVID_RECD_UPDATE_IP:
147                 ctdb_public_ip_push(mdata->pubip, buf);
148                 break;
149
150         case CTDB_SRVID_VACUUM_FETCH:
151                 ctdb_rec_buffer_push(mdata->recbuf, buf);
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);
160                 break;
161
162         case CTDB_SRVID_PUSH_NODE_FLAGS:
163                 ctdb_node_flag_change_push(mdata->flag_change, buf);
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);
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);
179                 break;
180
181         case CTDB_SRVID_DISABLE_RECOVERIES:
182                 ctdb_disable_message_push(mdata->disable, buf);
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);
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);
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);
228                 break;
229
230         case CTDB_SRVID_RECD_UPDATE_IP:
231                 ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
232                                           &mdata->pubip);
233                 break;
234
235         case CTDB_SRVID_VACUUM_FETCH:
236                 ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
237                                            &mdata->recbuf);
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);
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);
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);
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);
269                 break;
270
271         case CTDB_SRVID_DISABLE_RECOVERIES:
272                 ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
273                                                 &mdata->disable);
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                 break;
283         }
284
285         return ret;
286 }
287
288 size_t ctdb_req_message_len(struct ctdb_req_header *h,
289                             struct ctdb_req_message *c)
290 {
291         return offsetof(struct ctdb_req_message_wire, data) +
292                 ctdb_message_data_len(&c->data, c->srvid);
293 }
294
295 int ctdb_req_message_push(struct ctdb_req_header *h,
296                           struct ctdb_req_message *message,
297                           uint8_t *buf, size_t *buflen)
298 {
299         struct ctdb_req_message_wire *wire =
300                 (struct ctdb_req_message_wire *)buf;
301         size_t length;
302
303         length = ctdb_req_message_len(h, message);
304         if (*buflen < length) {
305                 *buflen = length;
306                 return EMSGSIZE;
307         }
308
309         h->length = *buflen;
310         ctdb_req_header_push(h, (uint8_t *)&wire->hdr);
311
312         wire->srvid = message->srvid;
313         wire->datalen = ctdb_message_data_len(&message->data, message->srvid);
314         ctdb_message_data_push(&message->data, message->srvid, wire->data);
315
316         return 0;
317 }
318
319 int ctdb_req_message_pull(uint8_t *buf, size_t buflen,
320                           struct ctdb_req_header *h,
321                           TALLOC_CTX *mem_ctx,
322                           struct ctdb_req_message *c)
323 {
324         struct ctdb_req_message_wire *wire =
325                 (struct ctdb_req_message_wire *)buf;
326         size_t length;
327         int ret;
328
329         length = offsetof(struct ctdb_req_message_wire, data);
330         if (buflen < length) {
331                 return EMSGSIZE;
332         }
333         if (wire->datalen > buflen) {
334                 return EMSGSIZE;
335         }
336         if (length + wire->datalen < length) {
337                 return EMSGSIZE;
338         }
339         if (buflen < length + wire->datalen) {
340                 return EMSGSIZE;
341         }
342
343         if (h != NULL) {
344                 ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, buflen, h);
345                 if (ret != 0) {
346                         return ret;
347                 }
348         }
349
350         c->srvid = wire->srvid;
351         ret = ctdb_message_data_pull(wire->data, wire->datalen, wire->srvid,
352                                      mem_ctx, &c->data);
353         return ret;
354 }
355
356 size_t ctdb_req_message_data_len(struct ctdb_req_header *h,
357                                  struct ctdb_req_message_data *c)
358 {
359         return offsetof(struct ctdb_req_message_wire, data) +
360                 ctdb_tdb_data_len(c->data);
361 }
362
363 int ctdb_req_message_data_push(struct ctdb_req_header *h,
364                                struct ctdb_req_message_data *message,
365                                uint8_t *buf, size_t *buflen)
366 {
367         struct ctdb_req_message_wire *wire =
368                 (struct ctdb_req_message_wire *)buf;
369         size_t length;
370
371         length = ctdb_req_message_data_len(h, message);
372         if (*buflen < length) {
373                 *buflen = length;
374                 return EMSGSIZE;
375         }
376
377         h->length = *buflen;
378         ctdb_req_header_push(h, (uint8_t *)&wire->hdr);
379
380         wire->srvid = message->srvid;
381         wire->datalen = ctdb_tdb_data_len(message->data);
382         ctdb_tdb_data_push(message->data, wire->data);
383
384         return 0;
385 }
386
387 int ctdb_req_message_data_pull(uint8_t *buf, size_t buflen,
388                                struct ctdb_req_header *h,
389                                TALLOC_CTX *mem_ctx,
390                                struct ctdb_req_message_data *c)
391 {
392         struct ctdb_req_message_wire *wire =
393                 (struct ctdb_req_message_wire *)buf;
394         size_t length;
395         int ret;
396
397         length = offsetof(struct ctdb_req_message_wire, data);
398         if (buflen < length) {
399                 return EMSGSIZE;
400         }
401         if (wire->datalen > buflen) {
402                 return EMSGSIZE;
403         }
404         if (length + wire->datalen < length) {
405                 return EMSGSIZE;
406         }
407         if (buflen < length + wire->datalen) {
408                 return EMSGSIZE;
409         }
410
411         if (h != NULL) {
412                 ret = ctdb_req_header_pull((uint8_t *)&wire->hdr, buflen, h);
413                 if (ret != 0) {
414                         return ret;
415                 }
416         }
417
418         c->srvid = wire->srvid;
419
420         ret = ctdb_tdb_data_pull(wire->data, wire->datalen,
421                                  mem_ctx, &c->data);
422         if (ret != 0) {
423                 return ret;
424         }
425
426         return 0;
427 }