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 
ctdb_message_data_len(union ctdb_message_data * mdata,uint64_t srvid)31 static size_t ctdb_message_data_len(union ctdb_message_data *mdata,
32 				    uint64_t srvid)
33 {
34 	size_t len = 0;
35 
36 	switch (srvid) {
37 	case CTDB_SRVID_BANNING:
38 		len = ctdb_uint32_len(&mdata->pnn);
39 		break;
40 
41 	case CTDB_SRVID_ELECTION:
42 		len = ctdb_election_message_len(mdata->election);
43 		break;
44 
45 	case CTDB_SRVID_RECONFIGURE:
46 		break;
47 
48 	case CTDB_SRVID_RELEASE_IP:
49 		len = ctdb_string_len(&mdata->ipaddr);
50 		break;
51 
52 	case CTDB_SRVID_TAKE_IP:
53 		len = ctdb_string_len(&mdata->ipaddr);
54 		break;
55 
56 	case CTDB_SRVID_SET_NODE_FLAGS:
57 		len = ctdb_node_flag_change_len(mdata->flag_change);
58 		break;
59 
60 	case CTDB_SRVID_RECD_UPDATE_IP:
61 		len = ctdb_public_ip_len(mdata->pubip);
62 		break;
63 
64 	case CTDB_SRVID_VACUUM_FETCH:
65 		len = ctdb_rec_buffer_len(mdata->recbuf);
66 		break;
67 
68 	case CTDB_SRVID_DETACH_DATABASE:
69 		len = ctdb_uint32_len(&mdata->db_id);
70 		break;
71 
72 	case CTDB_SRVID_MEM_DUMP:
73 		len = ctdb_srvid_message_len(mdata->msg);
74 		break;
75 
76 	case CTDB_SRVID_GETLOG:
77 		break;
78 
79 	case CTDB_SRVID_CLEARLOG:
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 
ctdb_message_data_push(union ctdb_message_data * mdata,uint64_t srvid,uint8_t * buf,size_t * npush)117 static void ctdb_message_data_push(union ctdb_message_data *mdata,
118 				   uint64_t srvid, uint8_t *buf,
119 				   size_t *npush)
120 {
121 	size_t np = 0;
122 
123 	switch (srvid) {
124 	case CTDB_SRVID_BANNING:
125 		ctdb_uint32_push(&mdata->pnn, buf, &np);
126 		break;
127 
128 	case CTDB_SRVID_ELECTION:
129 		ctdb_election_message_push(mdata->election, buf, &np);
130 		break;
131 
132 	case CTDB_SRVID_RECONFIGURE:
133 		break;
134 
135 	case CTDB_SRVID_RELEASE_IP:
136 		ctdb_string_push(&mdata->ipaddr, buf, &np);
137 		break;
138 
139 	case CTDB_SRVID_TAKE_IP:
140 		ctdb_string_push(&mdata->ipaddr, buf, &np);
141 		break;
142 
143 	case CTDB_SRVID_SET_NODE_FLAGS:
144 		ctdb_node_flag_change_push(mdata->flag_change, buf, &np);
145 		break;
146 
147 	case CTDB_SRVID_RECD_UPDATE_IP:
148 		ctdb_public_ip_push(mdata->pubip, buf, &np);
149 		break;
150 
151 	case CTDB_SRVID_VACUUM_FETCH:
152 		ctdb_rec_buffer_push(mdata->recbuf, buf, &np);
153 		break;
154 
155 	case CTDB_SRVID_DETACH_DATABASE:
156 		ctdb_uint32_push(&mdata->db_id, buf, &np);
157 		break;
158 
159 	case CTDB_SRVID_MEM_DUMP:
160 		ctdb_srvid_message_push(mdata->msg, buf, &np);
161 		break;
162 
163 	case CTDB_SRVID_GETLOG:
164 		break;
165 
166 	case CTDB_SRVID_CLEARLOG:
167 		break;
168 
169 	case CTDB_SRVID_PUSH_NODE_FLAGS:
170 		ctdb_node_flag_change_push(mdata->flag_change, buf, &np);
171 		break;
172 
173 	case CTDB_SRVID_RELOAD_NODES:
174 		break;
175 
176 	case CTDB_SRVID_TAKEOVER_RUN:
177 		ctdb_srvid_message_push(mdata->msg, buf, &np);
178 		break;
179 
180 	case CTDB_SRVID_REBALANCE_NODE:
181 		ctdb_uint32_push(&mdata->pnn, buf, &np);
182 		break;
183 
184 	case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
185 		ctdb_disable_message_push(mdata->disable, buf, &np);
186 		break;
187 
188 	case CTDB_SRVID_DISABLE_RECOVERIES:
189 		ctdb_disable_message_push(mdata->disable, buf, &np);
190 		break;
191 
192 	case CTDB_SRVID_DISABLE_IP_CHECK:
193 		ctdb_uint32_push(&mdata->timeout, buf, &np);
194 		break;
195 
196 	default:
197 		ctdb_tdb_data_push(&mdata->data, buf, &np);
198 		break;
199 	}
200 
201 	*npush = np;
202 }
203 
ctdb_message_data_pull(uint8_t * buf,size_t buflen,uint64_t srvid,TALLOC_CTX * mem_ctx,union ctdb_message_data * mdata,size_t * npull)204 static int ctdb_message_data_pull(uint8_t *buf, size_t buflen,
205 				  uint64_t srvid, TALLOC_CTX *mem_ctx,
206 				  union ctdb_message_data *mdata,
207 				  size_t *npull)
208 {
209 	int ret = 0;
210 	size_t np = 0;
211 
212 	switch (srvid) {
213 	case CTDB_SRVID_BANNING:
214 		ret = ctdb_uint32_pull(buf, buflen, &mdata->pnn, &np);
215 		break;
216 
217 	case CTDB_SRVID_ELECTION:
218 		ret = ctdb_election_message_pull(buf, buflen, mem_ctx,
219 						 &mdata->election, &np);
220 		break;
221 
222 	case CTDB_SRVID_RECONFIGURE:
223 		break;
224 
225 	case CTDB_SRVID_RELEASE_IP:
226 		ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr,
227 				       &np);
228 		break;
229 
230 	case CTDB_SRVID_TAKE_IP:
231 		ret = ctdb_string_pull(buf, buflen, mem_ctx, &mdata->ipaddr,
232 				       &np);
233 		break;
234 
235 	case CTDB_SRVID_SET_NODE_FLAGS:
236 		ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
237 						 &mdata->flag_change, &np);
238 		break;
239 
240 	case CTDB_SRVID_RECD_UPDATE_IP:
241 		ret = ctdb_public_ip_pull(buf, buflen, mem_ctx,
242 					  &mdata->pubip, &np);
243 		break;
244 
245 	case CTDB_SRVID_VACUUM_FETCH:
246 		ret = ctdb_rec_buffer_pull(buf, buflen, mem_ctx,
247 					   &mdata->recbuf, &np);
248 		break;
249 
250 	case CTDB_SRVID_DETACH_DATABASE:
251 		ret = ctdb_uint32_pull(buf, buflen, &mdata->db_id, &np);
252 		break;
253 
254 	case CTDB_SRVID_MEM_DUMP:
255 		ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx,
256 					      &mdata->msg, &np);
257 		break;
258 
259 	case CTDB_SRVID_GETLOG:
260 		break;
261 
262 	case CTDB_SRVID_CLEARLOG:
263 		break;
264 
265 	case CTDB_SRVID_PUSH_NODE_FLAGS:
266 		ret = ctdb_node_flag_change_pull(buf, buflen, mem_ctx,
267 						 &mdata->flag_change, &np);
268 		break;
269 
270 	case CTDB_SRVID_RELOAD_NODES:
271 		break;
272 
273 	case CTDB_SRVID_TAKEOVER_RUN:
274 		ret = ctdb_srvid_message_pull(buf, buflen, mem_ctx,
275 					      &mdata->msg, &np);
276 		break;
277 
278 	case CTDB_SRVID_REBALANCE_NODE:
279 		ret = ctdb_uint32_pull(buf, buflen, &mdata->pnn, &np);
280 		break;
281 
282 	case CTDB_SRVID_DISABLE_TAKEOVER_RUNS:
283 		ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
284 						&mdata->disable, &np);
285 		break;
286 
287 	case CTDB_SRVID_DISABLE_RECOVERIES:
288 		ret = ctdb_disable_message_pull(buf, buflen, mem_ctx,
289 						&mdata->disable, &np);
290 		break;
291 
292 	case CTDB_SRVID_DISABLE_IP_CHECK:
293 		ret = ctdb_uint32_pull(buf, buflen, &mdata->timeout, &np);
294 		break;
295 
296 	default:
297 		ret = ctdb_tdb_data_pull(buf, buflen, mem_ctx, &mdata->data,
298 					 &np);
299 		break;
300 	}
301 
302 	if (ret != 0) {
303 		return ret;
304 	}
305 
306 	*npull = np;
307 	return 0;
308 }
309 
ctdb_req_message_len(struct ctdb_req_header * h,struct ctdb_req_message * c)310 size_t ctdb_req_message_len(struct ctdb_req_header *h,
311 			    struct ctdb_req_message *c)
312 {
313 	uint32_t u32 = ctdb_message_data_len(&c->data, c->srvid);
314 
315 	return ctdb_req_header_len(h) +
316 		ctdb_uint64_len(&c->srvid) +
317 		ctdb_uint32_len(&u32) + u32;
318 }
319 
ctdb_req_message_push(struct ctdb_req_header * h,struct ctdb_req_message * c,uint8_t * buf,size_t * buflen)320 int ctdb_req_message_push(struct ctdb_req_header *h,
321 			  struct ctdb_req_message *c,
322 			  uint8_t *buf, size_t *buflen)
323 {
324 	size_t offset = 0, np;
325 	size_t length;
326 	uint32_t u32;
327 
328 	length = ctdb_req_message_len(h, c);
329 	if (*buflen < length) {
330 		*buflen = length;
331 		return EMSGSIZE;
332 	}
333 
334 	h->length = *buflen;
335 	ctdb_req_header_push(h, buf+offset, &np);
336 	offset += np;
337 
338 	ctdb_uint64_push(&c->srvid, buf+offset, &np);
339 	offset += np;
340 
341 	u32 = ctdb_message_data_len(&c->data, c->srvid);
342 	ctdb_uint32_push(&u32, buf+offset, &np);
343 	offset += np;
344 
345 	ctdb_message_data_push(&c->data, c->srvid, buf+offset, &np);
346 	offset += np;
347 
348 	return 0;
349 }
350 
ctdb_req_message_pull(uint8_t * buf,size_t buflen,struct ctdb_req_header * h,TALLOC_CTX * mem_ctx,struct ctdb_req_message * c)351 int ctdb_req_message_pull(uint8_t *buf, size_t buflen,
352 			  struct ctdb_req_header *h,
353 			  TALLOC_CTX *mem_ctx,
354 			  struct ctdb_req_message *c)
355 {
356 	struct ctdb_req_header header;
357 	size_t offset = 0, np;
358 	uint32_t u32;
359 	int ret;
360 
361 	ret = ctdb_req_header_pull(buf+offset, buflen-offset, &header, &np);
362 	if (ret != 0) {
363 		return ret;
364 	}
365 	offset += np;
366 
367 	if (h != NULL) {
368 		*h = header;
369 	}
370 
371 	ret = ctdb_uint64_pull(buf+offset, buflen-offset, &c->srvid, &np);
372 	if (ret != 0) {
373 		return ret;
374 	}
375 	offset += np;
376 
377 	ret = ctdb_uint32_pull(buf+offset, buflen-offset, &u32, &np);
378 	if (ret != 0) {
379 		return ret;
380 	}
381 	offset += np;
382 
383 	if (buflen-offset < u32) {
384 		return EMSGSIZE;
385 	}
386 
387 	ret = ctdb_message_data_pull(buf+offset, u32, c->srvid,
388 				     mem_ctx, &c->data, &np);
389 	if (ret != 0) {
390 		return ret;
391 	}
392 	offset += np;
393 
394 	return ret;
395 }
396 
ctdb_req_message_data_len(struct ctdb_req_header * h,struct ctdb_req_message_data * c)397 size_t ctdb_req_message_data_len(struct ctdb_req_header *h,
398 				 struct ctdb_req_message_data *c)
399 {
400 	return ctdb_req_header_len(h) +
401 		ctdb_uint64_len(&c->srvid) +
402 		ctdb_tdb_datan_len(&c->data);
403 }
404 
ctdb_req_message_data_push(struct ctdb_req_header * h,struct ctdb_req_message_data * c,uint8_t * buf,size_t * buflen)405 int ctdb_req_message_data_push(struct ctdb_req_header *h,
406 			       struct ctdb_req_message_data *c,
407 			       uint8_t *buf, size_t *buflen)
408 {
409 	size_t offset = 0, np;
410 	size_t length;
411 
412 	length = ctdb_req_message_data_len(h, c);
413 	if (*buflen < length) {
414 		*buflen = length;
415 		return EMSGSIZE;
416 	}
417 
418 	h->length = *buflen;
419 	ctdb_req_header_push(h, buf+offset, &np);
420 	offset += np;
421 
422 	ctdb_uint64_push(&c->srvid, buf+offset, &np);
423 	offset += np;
424 
425 	ctdb_tdb_datan_push(&c->data, buf+offset, &np);
426 	offset += np;
427 
428 	return 0;
429 }
430 
ctdb_req_message_data_pull(uint8_t * buf,size_t buflen,struct ctdb_req_header * h,TALLOC_CTX * mem_ctx,struct ctdb_req_message_data * c)431 int ctdb_req_message_data_pull(uint8_t *buf, size_t buflen,
432 			       struct ctdb_req_header *h,
433 			       TALLOC_CTX *mem_ctx,
434 			       struct ctdb_req_message_data *c)
435 {
436 	struct ctdb_req_header header;
437 	size_t offset = 0, np;
438 	int ret;
439 
440 	ret = ctdb_req_header_pull(buf+offset, buflen-offset, &header, &np);
441 	if (ret != 0) {
442 		return ret;
443 	}
444 	offset += np;
445 
446 	if (h != NULL) {
447 		*h = header;
448 	}
449 
450 	ret = ctdb_uint64_pull(buf+offset, buflen-offset, &c->srvid, &np);
451 	if (ret != 0) {
452 		return ret;
453 	}
454 	offset += np;
455 
456 	ret = ctdb_tdb_datan_pull(buf+offset, buflen-offset,
457 				  mem_ctx, &c->data, &np);
458 	if (ret != 0) {
459 		return ret;
460 	}
461 	offset += np;
462 
463 	return 0;
464 }
465