Merge remote branch 'martins/master'
[ctdb.git] / libctdb / control.c
1 /*
2    Misc control routines of libctdb
3
4    Copyright (C) Rusty Russell 2010
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 #include <sys/socket.h>
20 #include <string.h>
21 #include <ctdb.h>
22 #include <ctdb_protocol.h>
23 #include "libctdb_private.h"
24
25 /* Remove type-safety macros. */
26 #undef ctdb_getrecmaster_send
27 #undef ctdb_getrecmode_send
28 #undef ctdb_getpnn_send
29 #undef ctdb_getdbstat_send
30 #undef ctdb_check_message_handlers_send
31 #undef ctdb_getnodemap_send
32 #undef ctdb_getpublicips_send
33 #undef ctdb_getdbseqnum_send
34 #undef ctdb_getifaces_send
35 #undef ctdb_getvnnmap_send
36
37 bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb,
38                            struct ctdb_request *req, uint32_t *recmaster)
39 {
40         struct ctdb_reply_control *reply;
41
42         reply = unpack_reply_control(req, CTDB_CONTROL_GET_RECMASTER);
43         if (!reply) {
44                 return false;
45         }
46         if (reply->status == -1) {
47                 DEBUG(ctdb, LOG_ERR, "ctdb_getrecmaster_recv: status -1");
48                 return false;
49         }
50         *recmaster = reply->status;
51         return true;
52 }
53
54 struct ctdb_request *ctdb_getrecmaster_send(struct ctdb_connection *ctdb,
55                                             uint32_t destnode,
56                                             ctdb_callback_t callback,
57                                             void *private_data)
58 {
59         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_RECMASTER,
60                                         destnode, NULL, 0,
61                                         callback, private_data);
62 }
63
64 bool ctdb_getrecmode_recv(struct ctdb_connection *ctdb,
65                           struct ctdb_request *req, uint32_t *recmode)
66 {
67         struct ctdb_reply_control *reply;
68
69         reply = unpack_reply_control(req, CTDB_CONTROL_GET_RECMODE);
70         if (!reply) {
71                 return false;
72         }
73         if (reply->status == -1) {
74                 DEBUG(ctdb, LOG_ERR, "ctdb_getrecmode_recv: status -1");
75                 return false;
76         }
77         *recmode = reply->status;
78         return true;
79 }
80
81 struct ctdb_request *ctdb_getrecmode_send(struct ctdb_connection *ctdb,
82                                             uint32_t destnode,
83                                             ctdb_callback_t callback,
84                                             void *private_data)
85 {
86         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_RECMODE,
87                                         destnode, NULL, 0,
88                                         callback, private_data);
89 }
90
91 bool ctdb_getpnn_recv(struct ctdb_connection *ctdb,
92                      struct ctdb_request *req, uint32_t *pnn)
93 {
94         struct ctdb_reply_control *reply;
95
96         reply = unpack_reply_control(req, CTDB_CONTROL_GET_PNN);
97         if (!reply) {
98                 return false;
99         }
100         if (reply->status == -1) {
101                 DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
102                 return false;
103         }
104         *pnn = reply->status;
105         return true;
106 }
107
108 struct ctdb_request *ctdb_getpnn_send(struct ctdb_connection *ctdb,
109                                       uint32_t destnode,
110                                       ctdb_callback_t callback,
111                                       void *private_data)
112 {
113         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_PNN, destnode,
114                                         NULL, 0, callback, private_data);
115 }
116
117 bool ctdb_getdbstat_recv(struct ctdb_connection *ctdb,
118                          struct ctdb_request *req,
119                          struct ctdb_db_statistics **stat)
120 {
121         struct ctdb_reply_control *reply;
122         struct ctdb_db_statistics *s;
123
124         reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_STATISTICS);
125         if (!reply) {
126                 return false;
127         }
128         if (reply->status == -1) {
129                 DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
130                 return false;
131         }
132         if (reply->datalen != sizeof(struct ctdb_db_statistics)) {
133                 DEBUG(ctdb, LOG_ERR, "ctdb_getdbstat_recv: returned data is %d bytes but should be %d", reply->datalen, (int)sizeof(struct ctdb_db_statistics));
134                 return false;
135         }
136
137         s = malloc(sizeof(struct ctdb_db_statistics));
138         if (!s) {
139                 return false;
140         }
141         memcpy(s, reply->data, sizeof(struct ctdb_db_statistics));
142         *stat = s;
143
144         return true;
145 }
146
147 struct ctdb_request *ctdb_getdbstat_send(struct ctdb_connection *ctdb,
148                                       uint32_t destnode,
149                                       uint32_t db_id,
150                                       ctdb_callback_t callback,
151                                       void *private_data)
152 {
153         uint32_t indata = db_id;
154
155         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_STATISTICS, destnode,
156                                         &indata, sizeof(indata), callback, private_data);
157 }
158
159 void ctdb_free_dbstat(struct ctdb_db_statistics *stat)
160 {
161         if (stat == NULL) {
162                 return;
163         }
164         free(stat);
165 }
166
167 bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb,
168                       struct ctdb_request *req, struct ctdb_node_map **nodemap)
169 {
170         struct ctdb_reply_control *reply;
171
172         *nodemap = NULL;
173         reply = unpack_reply_control(req, CTDB_CONTROL_GET_NODEMAP);
174         if (!reply) {
175                 return false;
176         }
177         if (reply->status == -1) {
178                 DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: status -1");
179                 return false;
180         }
181         if (reply->datalen == 0) {
182                 DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: returned data is 0 bytes");
183                 return false;
184         }
185
186         *nodemap = malloc(reply->datalen);
187         if (*nodemap == NULL) {
188                 DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: failed to malloc buffer");
189                 return false;
190         }
191         memcpy(*nodemap, reply->data, reply->datalen);
192
193         return true;
194 }
195 struct ctdb_request *ctdb_getnodemap_send(struct ctdb_connection *ctdb,
196                                           uint32_t destnode,
197                                           ctdb_callback_t callback,
198                                           void *private_data)
199 {
200         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_NODEMAP,
201                                         destnode,
202                                         NULL, 0, callback, private_data);
203 }
204
205 void ctdb_free_nodemap(struct ctdb_node_map *nodemap)
206 {
207         if (nodemap == NULL) {
208                 return;
209         }
210         free(nodemap);
211 }
212
213 bool ctdb_getpublicips_recv(struct ctdb_connection *ctdb,
214                             struct ctdb_request *req,
215                             struct ctdb_all_public_ips **ips)
216 {
217         struct ctdb_reply_control *reply;
218
219         *ips = NULL;
220         reply = unpack_reply_control(req, CTDB_CONTROL_GET_PUBLIC_IPS);
221         if (!reply) {
222                 return false;
223         }
224         if (reply->status == -1) {
225                 DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: status -1");
226                 return false;
227         }
228         if (reply->datalen == 0) {
229                 DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: returned data is 0 bytes");
230                 return false;
231         }
232
233         *ips = malloc(reply->datalen);
234         if (*ips == NULL) {
235                 DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: failed to malloc buffer");
236                 return false;
237         }
238         memcpy(*ips, reply->data, reply->datalen);
239
240         return true;
241 }
242 struct ctdb_request *ctdb_getpublicips_send(struct ctdb_connection *ctdb,
243                                             uint32_t destnode,
244                                             ctdb_callback_t callback,
245                                             void *private_data)
246 {
247         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_PUBLIC_IPS,
248                                         destnode,
249                                         NULL, 0, callback, private_data);
250 }
251
252 void ctdb_free_publicips(struct ctdb_all_public_ips *ips)
253 {
254         if (ips == NULL) {
255                 return;
256         }
257         free(ips);
258 }
259
260 bool ctdb_getdbseqnum_recv(struct ctdb_connection *ctdb,
261                            struct ctdb_request *req, uint64_t *seqnum)
262 {
263         struct ctdb_reply_control *reply;
264
265         reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_SEQNUM);
266         if (!reply) {
267                 return false;
268         }
269         if (reply->status == -1) {
270                 DEBUG(ctdb, LOG_ERR, "ctdb_getdbseqnum_recv: status -1");
271                 return false;
272         }
273
274         if (reply->datalen != sizeof(uint64_t)) {
275                 DEBUG(ctdb, LOG_ERR, "ctdb_getdbseqnum wrong size of data was %d but expected %d bytes", reply->datalen, (int)sizeof(uint64_t));
276                 return false;
277         }
278
279         *seqnum = *((uint64_t *)reply->data);
280
281         return true;
282 }
283
284 struct ctdb_request *ctdb_getdbseqnum_send(struct ctdb_connection *ctdb,
285                                             uint32_t destnode,
286                                             uint32_t dbid,
287                                             ctdb_callback_t callback,
288                                             void *private_data)
289 {
290         uint64_t indata;
291
292         *((uint32_t *)&indata) = dbid;
293
294         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_SEQNUM,
295                                         destnode, &indata, sizeof(uint64_t),
296                                         callback, private_data);
297 }
298
299 bool ctdb_check_message_handlers_recv(struct ctdb_connection *ctdb,
300                                       struct ctdb_request *req,
301                                       uint32_t num, uint8_t *result)
302 {
303         struct ctdb_reply_control *reply;
304         int i, count;
305
306         reply = unpack_reply_control(req, CTDB_CONTROL_CHECK_SRVIDS);
307         if (!reply) {
308                 return false;
309         }
310         if (reply->status == -1) {
311                 DEBUG(ctdb, LOG_ERR, "ctdb_check_message_handlers_recv: status -1");
312                 return false;
313         }
314         
315         count = (num + 7) / 8;
316         if (count != reply->datalen) {
317                 DEBUG(ctdb, LOG_ERR, "ctdb_check_message_handlers_recv: wrong amount of data returned, expected %d bytes for %d srvids but received %d bytes", count, num, reply->datalen);
318                 return false;
319         }
320
321         for (i = 0; i < num; i++) {
322                 result[i] = !!(reply->data[i / 8] & (1 << (i % 8)));
323         }
324
325         return true;
326 }
327
328 struct ctdb_request *
329 ctdb_check_message_handlers_send(struct ctdb_connection *ctdb,
330                                 uint32_t destnode,
331                                 uint32_t num,
332                                 uint64_t *mhs,
333                                 ctdb_callback_t callback,
334                                 void *private_data)
335 {
336         return new_ctdb_control_request(ctdb, CTDB_CONTROL_CHECK_SRVIDS,
337                                         destnode,
338                                         mhs, num * sizeof(uint64_t) ,
339                                         callback, private_data);
340 }
341
342
343 bool ctdb_getifaces_recv(struct ctdb_connection *ctdb,
344                          struct ctdb_request *req,
345                          struct ctdb_ifaces_list **ifaces)
346 {
347         struct ctdb_reply_control *reply;
348         struct ctdb_ifaces_list *ifc;
349         int i, len;
350
351         *ifaces = NULL;
352         reply = unpack_reply_control(req, CTDB_CONTROL_GET_IFACES);
353         if (!reply) {
354                 return false;
355         }
356         if (reply->status == -1) {
357                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: status -1");
358                 return false;
359         }
360         if (reply->datalen == 0) {
361                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is 0 bytes");
362                 return false;
363         }
364
365         len = offsetof(struct ctdb_ifaces_list, ifaces);
366         if (len > reply->datalen) {
367                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is %d bytes but %d is minimum", reply->datalen,  (int)offsetof(struct ctdb_ifaces_list, ifaces));
368                 return false;
369         }
370
371         ifc = (struct ctdb_ifaces_list *)(reply->data);
372         len += ifc->num * sizeof(struct ctdb_iface_info);
373
374         if (len != reply->datalen) {
375                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is %d bytes but should be %d", reply->datalen,  len);
376                 return false;
377         }
378
379         ifc = malloc(reply->datalen);
380         if (ifc == NULL) {
381                 DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: failed to malloc buffer");
382                 return false;
383         }
384         memcpy(ifc, reply->data, reply->datalen);
385
386         /* make sure we null terminate the returned strings */
387         for (i = 0; i < ifc->num; i++) {
388                 ifc->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
389         }
390
391         *ifaces = ifc;
392
393         return true;
394 }
395
396 void ctdb_free_ifaces(struct ctdb_ifaces_list *ifaces)
397 {
398         free(ifaces);
399 }
400
401 struct ctdb_request *ctdb_getifaces_send(struct ctdb_connection *ctdb,
402                                           uint32_t destnode,
403                                           ctdb_callback_t callback,
404                                           void *private_data)
405 {
406         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_IFACES,
407                                         destnode,
408                                         NULL, 0, callback, private_data);
409 }
410
411 bool ctdb_getvnnmap_recv(struct ctdb_connection *ctdb,
412                          struct ctdb_request *req,
413                          struct ctdb_vnn_map **vnnmap)
414 {
415         struct ctdb_reply_control *reply;
416         struct ctdb_vnn_map_wire *map;
417         struct ctdb_vnn_map *tmap;
418         int len;
419
420         *vnnmap = NULL;
421         reply = unpack_reply_control(req, CTDB_CONTROL_GETVNNMAP);
422         if (!reply) {
423                 return false;
424         }
425         if (reply->status == -1) {
426                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: status -1");
427                 return false;
428         }
429         if (reply->datalen == 0) {
430                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is 0 bytes");
431                 return false;
432         }
433
434         len = offsetof(struct ctdb_vnn_map_wire, map);
435         if (len > reply->datalen) {
436                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is %d bytes but %d is minimum", reply->datalen,  (int)offsetof(struct ctdb_vnn_map_wire, map));
437                 return false;
438         }
439
440         map = (struct ctdb_vnn_map_wire *)(reply->data);
441         len += map->size * sizeof(uint32_t);
442
443         if (len != reply->datalen) {
444                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is %d bytes but should be %d", reply->datalen,  len);
445                 return false;
446         }
447
448         tmap = malloc(sizeof(struct ctdb_vnn_map));
449         if (tmap == NULL) {
450                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: failed to malloc buffer");
451                 return false;
452         }
453
454         tmap->generation = map->generation;
455         tmap->size       = map->size;
456         tmap->map        = malloc(sizeof(uint32_t) * map->size);
457         if (tmap->map == NULL) {
458                 DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: failed to malloc buffer");
459                 free(tmap);
460                 return false;
461         }
462
463         memcpy(tmap->map, map->map, sizeof(uint32_t)*map->size);
464
465         *vnnmap = tmap;
466
467         return true;
468 }
469
470 void ctdb_free_vnnmap(struct ctdb_vnn_map *vnnmap)
471 {
472         free(vnnmap->map);
473         free(vnnmap);
474 }
475
476 struct ctdb_request *ctdb_getvnnmap_send(struct ctdb_connection *ctdb,
477                                          uint32_t destnode,
478                                          ctdb_callback_t callback,
479                                          void *private_data)
480 {
481         return new_ctdb_control_request(ctdb, CTDB_CONTROL_GETVNNMAP,
482                                         destnode,
483                                         NULL, 0, callback, private_data);
484 }
485