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