s3:idmap_ad: add support for ADS_AUTH_SASL_{STARTTLS,LDAPS}
[Samba.git] / ctdb / server / ctdb_client.c
blobc9edb1d554cc04ec442038d76ba584f0d8c627c2
1 /*
2 ctdb daemon code
4 Copyright (C) Andrew Tridgell 2007
5 Copyright (C) Ronnie Sahlberg 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "replace.h"
22 #include "system/network.h"
23 #include "system/filesys.h"
24 #include "system/locale.h"
26 #include <talloc.h>
27 #include <tevent.h>
28 #include <tdb.h>
30 #include "lib/tdb_wrap/tdb_wrap.h"
31 #include "lib/util/dlinklist.h"
32 #include "lib/util/time.h"
33 #include "lib/util/debug.h"
34 #include "lib/util/samba_util.h"
36 #include "ctdb_private.h"
37 #include "ctdb_client.h"
39 #include "common/reqid.h"
40 #include "common/system.h"
41 #include "common/common.h"
42 #include "common/logging.h"
45 allocate a packet for use in client<->daemon communication
47 struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb,
48 TALLOC_CTX *mem_ctx,
49 enum ctdb_operation operation,
50 size_t length, size_t slength,
51 const char *type)
53 int size;
54 struct ctdb_req_header *hdr;
56 length = MAX(length, slength);
57 size = (length+(CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1);
59 hdr = (struct ctdb_req_header *)talloc_zero_size(mem_ctx, size);
60 if (hdr == NULL) {
61 DEBUG(DEBUG_ERR,("Unable to allocate packet for operation %u of length %u\n",
62 operation, (unsigned)length));
63 return NULL;
65 talloc_set_name_const(hdr, type);
66 hdr->length = length;
67 hdr->operation = operation;
68 hdr->ctdb_magic = CTDB_MAGIC;
69 hdr->ctdb_version = CTDB_PROTOCOL;
70 hdr->srcnode = ctdb->pnn;
71 if (ctdb->vnn_map) {
72 hdr->generation = ctdb->vnn_map->generation;
75 return hdr;
79 local version of ctdb_call
81 int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call,
82 struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx,
83 TDB_DATA *data, bool updatetdb)
85 struct ctdb_call_info *c;
86 struct ctdb_registered_call *fn;
87 struct ctdb_context *ctdb = ctdb_db->ctdb;
89 c = talloc_zero(mem_ctx, struct ctdb_call_info);
90 CTDB_NO_MEMORY(ctdb, c);
92 c->key = call->key;
93 c->call_data = &call->call_data;
94 c->record_data.dptr = talloc_memdup(c, data->dptr, data->dsize);
95 c->record_data.dsize = data->dsize;
96 CTDB_NO_MEMORY(ctdb, c->record_data.dptr);
97 c->header = header;
99 for (fn=ctdb_db->calls;fn;fn=fn->next) {
100 if (fn->id == (uint32_t)call->call_id) {
101 break;
104 if (fn == NULL) {
105 ctdb_set_error(ctdb, "Unknown call id %u\n", call->call_id);
106 talloc_free(c);
107 return -1;
110 if (fn->fn(c) != 0) {
111 ctdb_set_error(ctdb, "ctdb_call %u failed\n", call->call_id);
112 talloc_free(c);
113 return -1;
116 /* we need to force the record to be written out if this was a remote access */
117 if (c->new_data == NULL) {
118 c->new_data = &c->record_data;
121 if (c->new_data && updatetdb) {
122 /* XXX check that we always have the lock here? */
123 if (ctdb_ltdb_store(ctdb_db, call->key, header, *c->new_data) != 0) {
124 ctdb_set_error(ctdb, "ctdb_call tdb_store failed\n");
125 talloc_free(c);
126 return -1;
130 if (c->reply_data) {
131 call->reply_data = *c->reply_data;
133 talloc_steal(call, call->reply_data.dptr);
134 talloc_set_name_const(call->reply_data.dptr, __location__);
135 } else {
136 call->reply_data.dptr = NULL;
137 call->reply_data.dsize = 0;
139 call->status = c->status;
141 talloc_free(c);
143 return 0;
148 queue a packet for sending from client to daemon
150 static int ctdb_client_queue_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
152 return ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)hdr, hdr->length);
157 called when a CTDB_REPLY_CALL packet comes in in the client
159 This packet comes in response to a CTDB_REQ_CALL request packet. It
160 contains any reply data from the call
162 static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
164 struct ctdb_reply_call_old *c = (struct ctdb_reply_call_old *)hdr;
165 struct ctdb_client_call_state *state;
167 state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_client_call_state);
168 if (state == NULL) {
169 DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
170 return;
173 if (hdr->reqid != state->reqid) {
174 /* we found a record but it was the wrong one */
175 DEBUG(DEBUG_ERR, ("Dropped client call reply with reqid:%u\n",hdr->reqid));
176 return;
179 state->call->reply_data.dptr = c->data;
180 state->call->reply_data.dsize = c->datalen;
181 state->call->status = c->status;
183 talloc_steal(state, c);
185 state->state = CTDB_CALL_DONE;
187 if (state->async.fn) {
188 state->async.fn(state);
192 void ctdb_request_message(struct ctdb_context *ctdb,
193 struct ctdb_req_header *hdr)
195 struct ctdb_req_message_old *c = (struct ctdb_req_message_old *)hdr;
196 TDB_DATA data;
198 data.dsize = c->datalen;
199 data.dptr = talloc_memdup(c, &c->data[0], c->datalen);
200 if (data.dptr == NULL) {
201 DEBUG(DEBUG_ERR, (__location__ " Memory allocation failure\n"));
202 return;
205 srvid_dispatch(ctdb->srv, c->srvid, CTDB_SRVID_ALL, data);
208 static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
211 this is called in the client, when data comes in from the daemon
213 void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args)
215 struct ctdb_context *ctdb = talloc_get_type(args, struct ctdb_context);
216 struct ctdb_req_header *hdr = (struct ctdb_req_header *)data;
217 TALLOC_CTX *tmp_ctx;
219 /* place the packet as a child of a tmp_ctx. We then use
220 talloc_free() below to free it. If any of the calls want
221 to keep it, then they will steal it somewhere else, and the
222 talloc_free() will be a no-op */
223 tmp_ctx = talloc_new(ctdb);
224 talloc_steal(tmp_ctx, hdr);
226 if (cnt == 0) {
227 DEBUG(DEBUG_CRIT,("Daemon has exited - shutting down client\n"));
228 exit(1);
231 if (cnt < sizeof(*hdr)) {
232 DEBUG(DEBUG_CRIT,("Bad packet length %u in client\n", (unsigned)cnt));
233 goto done;
235 if (cnt != hdr->length) {
236 ctdb_set_error(ctdb, "Bad header length %u expected %u in client\n",
237 (unsigned)hdr->length, (unsigned)cnt);
238 goto done;
241 if (hdr->ctdb_magic != CTDB_MAGIC) {
242 ctdb_set_error(ctdb, "Non CTDB packet rejected in client\n");
243 goto done;
246 if (hdr->ctdb_version != CTDB_PROTOCOL) {
247 ctdb_set_error(ctdb, "Bad CTDB version 0x%x rejected in client\n", hdr->ctdb_version);
248 goto done;
251 switch (hdr->operation) {
252 case CTDB_REPLY_CALL:
253 ctdb_client_reply_call(ctdb, hdr);
254 break;
256 case CTDB_REQ_MESSAGE:
257 ctdb_request_message(ctdb, hdr);
258 break;
260 case CTDB_REPLY_CONTROL:
261 ctdb_client_reply_control(ctdb, hdr);
262 break;
264 default:
265 DEBUG(DEBUG_CRIT,("bogus operation code:%u\n",hdr->operation));
268 done:
269 talloc_free(tmp_ctx);
273 connect to a unix domain socket
275 int ctdb_socket_connect(struct ctdb_context *ctdb)
277 struct sockaddr_un addr;
278 int ret;
280 memset(&addr, 0, sizeof(addr));
281 addr.sun_family = AF_UNIX;
282 strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path)-1);
284 ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0);
285 if (ctdb->daemon.sd == -1) {
286 DEBUG(DEBUG_ERR,(__location__ " Failed to open client socket. Errno:%s(%d)\n", strerror(errno), errno));
287 return -1;
290 if (connect(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
291 DEBUG(DEBUG_ERR,
292 (__location__
293 "Failed to connect client socket to daemon (%s)\n",
294 strerror(errno)));
295 close(ctdb->daemon.sd);
296 ctdb->daemon.sd = -1;
297 return -1;
300 ret = set_blocking(ctdb->daemon.sd, false);
301 if (ret != 0) {
302 DEBUG(DEBUG_ERR,
303 (__location__
304 " failed to set socket non-blocking (%s)\n",
305 strerror(errno)));
306 close(ctdb->daemon.sd);
307 ctdb->daemon.sd = -1;
308 return -1;
311 set_close_on_exec(ctdb->daemon.sd);
313 ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd,
314 CTDB_DS_ALIGNMENT,
315 ctdb_client_read_cb, ctdb, "to-ctdbd");
316 return 0;
320 struct ctdb_record_handle {
321 struct ctdb_db_context *ctdb_db;
322 TDB_DATA key;
323 TDB_DATA *data;
324 struct ctdb_ltdb_header header;
329 make a recv call to the local ctdb daemon - called from client context
331 This is called when the program wants to wait for a ctdb_call to complete and get the
332 results. This call will block unless the call has already completed.
334 int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call)
336 if (state == NULL) {
337 return -1;
340 while (state->state < CTDB_CALL_DONE) {
341 tevent_loop_once(state->ctdb_db->ctdb->ev);
343 if (state->state != CTDB_CALL_DONE) {
344 DEBUG(DEBUG_ERR,(__location__ " ctdb_call_recv failed\n"));
345 talloc_free(state);
346 return -1;
349 if (state->call->reply_data.dsize) {
350 call->reply_data.dptr = talloc_memdup(state->ctdb_db,
351 state->call->reply_data.dptr,
352 state->call->reply_data.dsize);
353 call->reply_data.dsize = state->call->reply_data.dsize;
354 } else {
355 call->reply_data.dptr = NULL;
356 call->reply_data.dsize = 0;
358 call->status = state->call->status;
359 talloc_free(state);
361 return call->status;
368 destroy a ctdb_call in client
370 static int ctdb_client_call_destructor(struct ctdb_client_call_state *state)
372 reqid_remove(state->ctdb_db->ctdb->idr, state->reqid);
373 return 0;
377 construct an event driven local ctdb_call
379 this is used so that locally processed ctdb_call requests are processed
380 in an event driven manner
382 static struct ctdb_client_call_state *ctdb_client_call_local_send(struct ctdb_db_context *ctdb_db,
383 struct ctdb_call *call,
384 struct ctdb_ltdb_header *header,
385 TDB_DATA *data)
387 struct ctdb_client_call_state *state;
388 struct ctdb_context *ctdb = ctdb_db->ctdb;
389 int ret;
391 state = talloc_zero(ctdb_db, struct ctdb_client_call_state);
392 CTDB_NO_MEMORY_NULL(ctdb, state);
393 state->call = talloc_zero(state, struct ctdb_call);
394 CTDB_NO_MEMORY_NULL(ctdb, state->call);
396 talloc_steal(state, data->dptr);
398 state->state = CTDB_CALL_DONE;
399 *(state->call) = *call;
400 state->ctdb_db = ctdb_db;
402 ret = ctdb_call_local(ctdb_db, state->call, header, state, data, true);
403 if (ret != 0) {
404 DEBUG(DEBUG_DEBUG,("ctdb_call_local() failed, ignoring return code %d\n", ret));
407 return state;
411 make a ctdb call to the local daemon - async send. Called from client context.
413 This constructs a ctdb_call request and queues it for processing.
414 This call never blocks.
416 struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db,
417 struct ctdb_call *call)
419 struct ctdb_client_call_state *state;
420 struct ctdb_context *ctdb = ctdb_db->ctdb;
421 struct ctdb_ltdb_header header;
422 TDB_DATA data;
423 int ret;
424 size_t len;
425 struct ctdb_req_call_old *c;
427 /* if the domain socket is not yet open, open it */
428 if (ctdb->daemon.sd==-1) {
429 ctdb_socket_connect(ctdb);
432 ret = ctdb_ltdb_lock(ctdb_db, call->key);
433 if (ret != 0) {
434 DEBUG(DEBUG_ERR,(__location__ " Failed to get chainlock\n"));
435 return NULL;
438 ret = ctdb_ltdb_fetch(ctdb_db, call->key, &header, ctdb_db, &data);
440 if ((call->flags & CTDB_IMMEDIATE_MIGRATION) && (header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) {
441 ret = -1;
444 if (ret == 0 && header.dmaster == ctdb->pnn) {
445 state = ctdb_client_call_local_send(ctdb_db, call, &header, &data);
446 talloc_free(data.dptr);
447 ctdb_ltdb_unlock(ctdb_db, call->key);
448 return state;
451 ctdb_ltdb_unlock(ctdb_db, call->key);
452 talloc_free(data.dptr);
454 state = talloc_zero(ctdb_db, struct ctdb_client_call_state);
455 if (state == NULL) {
456 DEBUG(DEBUG_ERR, (__location__ " failed to allocate state\n"));
457 return NULL;
459 state->call = talloc_zero(state, struct ctdb_call);
460 if (state->call == NULL) {
461 DEBUG(DEBUG_ERR, (__location__ " failed to allocate state->call\n"));
462 return NULL;
465 len = offsetof(struct ctdb_req_call_old, data) + call->key.dsize + call->call_data.dsize;
466 c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call_old);
467 if (c == NULL) {
468 DEBUG(DEBUG_ERR, (__location__ " failed to allocate packet\n"));
469 return NULL;
472 state->reqid = reqid_new(ctdb->idr, state);
473 state->ctdb_db = ctdb_db;
474 talloc_set_destructor(state, ctdb_client_call_destructor);
476 c->hdr.reqid = state->reqid;
477 c->flags = call->flags;
478 c->db_id = ctdb_db->db_id;
479 c->callid = call->call_id;
480 c->hopcount = 0;
481 c->keylen = call->key.dsize;
482 c->calldatalen = call->call_data.dsize;
483 memcpy(&c->data[0], call->key.dptr, call->key.dsize);
484 memcpy(&c->data[call->key.dsize],
485 call->call_data.dptr, call->call_data.dsize);
486 *(state->call) = *call;
487 state->call->call_data.dptr = &c->data[call->key.dsize];
488 state->call->key.dptr = &c->data[0];
490 state->state = CTDB_CALL_WAIT;
493 ctdb_client_queue_pkt(ctdb, &c->hdr);
495 return state;
500 full ctdb_call. Equivalent to a ctdb_call_send() followed by a ctdb_call_recv()
502 int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call)
504 struct ctdb_client_call_state *state;
506 state = ctdb_call_send(ctdb_db, call);
507 return ctdb_call_recv(state, call);
512 tell the daemon what messaging srvid we will use, and register the message
513 handler function in the client
515 int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid,
516 srvid_handler_fn handler,
517 void *private_data)
519 int res;
520 int32_t status;
522 res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid,
523 CTDB_CONTROL_REGISTER_SRVID, 0,
524 tdb_null, NULL, NULL, &status, NULL, NULL);
525 if (res != 0 || status != 0) {
526 DEBUG(DEBUG_ERR,
527 ("Failed to register srvid %llu\n",
528 (unsigned long long)srvid));
529 return -1;
532 /* also need to register the handler with our own ctdb structure */
533 return srvid_register(ctdb->srv, ctdb, srvid, handler, private_data);
537 tell the daemon we no longer want a srvid
539 int ctdb_client_remove_message_handler(struct ctdb_context *ctdb,
540 uint64_t srvid, void *private_data)
542 int res;
543 int32_t status;
545 res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid,
546 CTDB_CONTROL_DEREGISTER_SRVID, 0,
547 tdb_null, NULL, NULL, &status, NULL, NULL);
548 if (res != 0 || status != 0) {
549 DEBUG(DEBUG_ERR,
550 ("Failed to deregister srvid %llu\n",
551 (unsigned long long)srvid));
552 return -1;
555 /* also need to register the handler with our own ctdb structure */
556 srvid_deregister(ctdb->srv, srvid, private_data);
557 return 0;
561 send a message - from client context
563 int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t pnn,
564 uint64_t srvid, TDB_DATA data)
566 struct ctdb_req_message_old *r;
567 int len, res;
569 len = offsetof(struct ctdb_req_message_old, data) + data.dsize;
570 r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE,
571 len, struct ctdb_req_message_old);
572 CTDB_NO_MEMORY(ctdb, r);
574 r->hdr.destnode = pnn;
575 r->srvid = srvid;
576 r->datalen = data.dsize;
577 memcpy(&r->data[0], data.dptr, data.dsize);
579 res = ctdb_client_queue_pkt(ctdb, &r->hdr);
580 talloc_free(r);
581 return res;
586 called when a control completes or timesout to invoke the callback
587 function the user provided
589 static void invoke_control_callback(struct tevent_context *ev,
590 struct tevent_timer *te,
591 struct timeval t, void *private_data)
593 struct ctdb_client_control_state *state;
594 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
595 int ret;
597 state = talloc_get_type(private_data, struct ctdb_client_control_state);
598 talloc_steal(tmp_ctx, state);
600 ret = ctdb_control_recv(state->ctdb, state, state,
601 NULL,
602 NULL,
603 NULL);
604 if (ret != 0) {
605 DEBUG(DEBUG_DEBUG,("ctdb_control_recv() failed, ignoring return code %d\n", ret));
608 talloc_free(tmp_ctx);
612 called when a CTDB_REPLY_CONTROL packet comes in in the client
614 This packet comes in response to a CTDB_REQ_CONTROL request packet. It
615 contains any reply data from the control
617 static void ctdb_client_reply_control(struct ctdb_context *ctdb,
618 struct ctdb_req_header *hdr)
620 struct ctdb_reply_control_old *c = (struct ctdb_reply_control_old *)hdr;
621 struct ctdb_client_control_state *state;
623 state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_client_control_state);
624 if (state == NULL) {
625 DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
626 return;
629 if (hdr->reqid != state->reqid) {
630 /* we found a record but it was the wrong one */
631 DEBUG(DEBUG_ERR, ("Dropped orphaned reply control with reqid:%u\n",hdr->reqid));
632 return;
635 state->outdata.dptr = c->data;
636 state->outdata.dsize = c->datalen;
637 state->status = c->status;
638 if (c->errorlen) {
639 state->errormsg = talloc_strndup(state,
640 (char *)&c->data[c->datalen],
641 c->errorlen);
644 /* state->outdata now uses resources from c so we don't want c
645 to just disappear from under us while state is still alive
647 talloc_steal(state, c);
649 state->state = CTDB_CONTROL_DONE;
651 /* if we had a callback registered for this control, pull the response
652 and call the callback.
654 if (state->async.fn) {
655 tevent_add_timer(ctdb->ev, state, timeval_zero(),
656 invoke_control_callback, state);
662 destroy a ctdb_control in client
664 static int ctdb_client_control_destructor(struct ctdb_client_control_state *state)
666 reqid_remove(state->ctdb->idr, state->reqid);
667 return 0;
671 /* time out handler for ctdb_control */
672 static void control_timeout_func(struct tevent_context *ev,
673 struct tevent_timer *te,
674 struct timeval t, void *private_data)
676 struct ctdb_client_control_state *state = talloc_get_type(private_data, struct ctdb_client_control_state);
678 DEBUG(DEBUG_ERR,(__location__ " control timed out. reqid:%u opcode:%u "
679 "dstnode:%u\n", state->reqid, state->c->opcode,
680 state->c->hdr.destnode));
682 state->state = CTDB_CONTROL_TIMEOUT;
684 /* if we had a callback registered for this control, pull the response
685 and call the callback.
687 if (state->async.fn) {
688 tevent_add_timer(state->ctdb->ev, state, timeval_zero(),
689 invoke_control_callback, state);
693 /* async version of send control request */
694 struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb,
695 uint32_t destnode, uint64_t srvid,
696 uint32_t opcode, uint32_t flags, TDB_DATA data,
697 TALLOC_CTX *mem_ctx,
698 struct timeval *timeout,
699 char **errormsg)
701 struct ctdb_client_control_state *state;
702 size_t len;
703 struct ctdb_req_control_old *c;
704 int ret;
706 if (errormsg) {
707 *errormsg = NULL;
710 /* if the domain socket is not yet open, open it */
711 if (ctdb->daemon.sd==-1) {
712 ctdb_socket_connect(ctdb);
715 state = talloc_zero(mem_ctx, struct ctdb_client_control_state);
716 CTDB_NO_MEMORY_NULL(ctdb, state);
718 state->ctdb = ctdb;
719 state->reqid = reqid_new(ctdb->idr, state);
720 state->state = CTDB_CONTROL_WAIT;
721 state->errormsg = NULL;
723 talloc_set_destructor(state, ctdb_client_control_destructor);
725 len = offsetof(struct ctdb_req_control_old, data) + data.dsize;
726 c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CONTROL,
727 len, struct ctdb_req_control_old);
728 state->c = c;
729 CTDB_NO_MEMORY_NULL(ctdb, c);
730 c->hdr.reqid = state->reqid;
731 c->hdr.destnode = destnode;
732 c->opcode = opcode;
733 c->client_id = 0;
734 c->flags = flags;
735 c->srvid = srvid;
736 c->datalen = data.dsize;
737 if (data.dsize) {
738 memcpy(&c->data[0], data.dptr, data.dsize);
741 /* timeout */
742 if (timeout && !timeval_is_zero(timeout)) {
743 tevent_add_timer(ctdb->ev, state, *timeout,
744 control_timeout_func, state);
747 ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
748 if (ret != 0) {
749 talloc_free(state);
750 return NULL;
753 if (flags & CTDB_CTRL_FLAG_NOREPLY) {
754 talloc_free(state);
755 return NULL;
758 return state;
762 /* async version of receive control reply */
763 int ctdb_control_recv(struct ctdb_context *ctdb,
764 struct ctdb_client_control_state *state,
765 TALLOC_CTX *mem_ctx,
766 TDB_DATA *outdata, int32_t *status, char **errormsg)
768 TALLOC_CTX *tmp_ctx;
770 if (status != NULL) {
771 *status = -1;
773 if (errormsg != NULL) {
774 *errormsg = NULL;
777 if (state == NULL) {
778 return -1;
781 /* prevent double free of state */
782 tmp_ctx = talloc_new(ctdb);
783 talloc_steal(tmp_ctx, state);
785 /* loop one event at a time until we either timeout or the control
786 completes.
788 while (state->state == CTDB_CONTROL_WAIT) {
789 tevent_loop_once(ctdb->ev);
792 if (state->state != CTDB_CONTROL_DONE) {
793 DEBUG(DEBUG_ERR,(__location__ " ctdb_control_recv failed\n"));
794 if (state->async.fn) {
795 state->async.fn(state);
797 talloc_free(tmp_ctx);
798 return -1;
801 if (state->errormsg) {
802 int s = (state->status == 0 ? -1 : state->status);
803 DEBUG(DEBUG_ERR,("ctdb_control error: '%s'\n", state->errormsg));
804 if (errormsg) {
805 (*errormsg) = talloc_move(mem_ctx, &state->errormsg);
807 if (state->async.fn) {
808 state->async.fn(state);
810 talloc_free(tmp_ctx);
811 return s;
814 if (outdata) {
815 *outdata = state->outdata;
816 outdata->dptr = talloc_memdup(mem_ctx, outdata->dptr, outdata->dsize);
819 if (status) {
820 *status = state->status;
823 if (state->async.fn) {
824 state->async.fn(state);
827 talloc_free(tmp_ctx);
828 return 0;
834 send a ctdb control message
835 timeout specifies how long we should wait for a reply.
836 if timeout is NULL we wait indefinitely
838 int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid,
839 uint32_t opcode, uint32_t flags, TDB_DATA data,
840 TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status,
841 struct timeval *timeout,
842 char **errormsg)
844 struct ctdb_client_control_state *state;
846 state = ctdb_control_send(ctdb, destnode, srvid, opcode,
847 flags, data, mem_ctx,
848 timeout, errormsg);
850 /* FIXME: Error conditions in ctdb_control_send return NULL without
851 * setting errormsg. So, there is no way to distinguish between success
852 * and failure when CTDB_CTRL_FLAG_NOREPLY is set */
853 if (flags & CTDB_CTRL_FLAG_NOREPLY) {
854 if (status != NULL) {
855 *status = 0;
857 return 0;
860 return ctdb_control_recv(ctdb, state, mem_ctx, outdata, status,
861 errormsg);
865 get vnn map from a remote node
867 int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_vnn_map **vnnmap)
869 int ret;
870 TDB_DATA outdata;
871 int32_t res;
872 struct ctdb_vnn_map_wire *map;
874 ret = ctdb_control(ctdb, destnode, 0,
875 CTDB_CONTROL_GETVNNMAP, 0, tdb_null,
876 mem_ctx, &outdata, &res, &timeout, NULL);
877 if (ret != 0 || res != 0) {
878 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getvnnmap failed\n"));
879 return -1;
882 map = (struct ctdb_vnn_map_wire *)outdata.dptr;
883 if (outdata.dsize < offsetof(struct ctdb_vnn_map_wire, map) ||
884 outdata.dsize != map->size*sizeof(uint32_t) + offsetof(struct ctdb_vnn_map_wire, map)) {
885 DEBUG(DEBUG_ERR,("Bad vnn map size received in ctdb_ctrl_getvnnmap\n"));
886 return -1;
889 (*vnnmap) = talloc(mem_ctx, struct ctdb_vnn_map);
890 CTDB_NO_MEMORY(ctdb, *vnnmap);
891 (*vnnmap)->generation = map->generation;
892 (*vnnmap)->size = map->size;
893 (*vnnmap)->map = talloc_array(*vnnmap, uint32_t, map->size);
895 CTDB_NO_MEMORY(ctdb, (*vnnmap)->map);
896 memcpy((*vnnmap)->map, map->map, sizeof(uint32_t)*map->size);
897 talloc_free(outdata.dptr);
899 return 0;
904 get the recovery mode of a remote node
906 struct ctdb_client_control_state *
907 ctdb_ctrl_getrecmode_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode)
909 return ctdb_control_send(ctdb, destnode, 0,
910 CTDB_CONTROL_GET_RECMODE, 0, tdb_null,
911 mem_ctx, &timeout, NULL);
914 int ctdb_ctrl_getrecmode_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmode)
916 int ret;
917 int32_t res;
919 ret = ctdb_control_recv(ctdb, state, mem_ctx, NULL, &res, NULL);
920 if (ret != 0) {
921 DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_getrecmode_recv failed\n"));
922 return -1;
925 if (recmode) {
926 *recmode = (uint32_t)res;
929 return 0;
932 int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmode)
934 struct ctdb_client_control_state *state;
936 state = ctdb_ctrl_getrecmode_send(ctdb, mem_ctx, timeout, destnode);
937 return ctdb_ctrl_getrecmode_recv(ctdb, mem_ctx, state, recmode);
944 set the recovery mode of a remote node
946 int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmode)
948 int ret;
949 TDB_DATA data;
950 int32_t res;
952 data.dsize = sizeof(uint32_t);
953 data.dptr = (unsigned char *)&recmode;
955 ret = ctdb_control(ctdb, destnode, 0,
956 CTDB_CONTROL_SET_RECMODE, 0, data,
957 NULL, NULL, &res, &timeout, NULL);
958 if (ret != 0 || res != 0) {
959 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setrecmode failed\n"));
960 return -1;
963 return 0;
969 get a list of nodes (vnn and flags ) from a remote node
971 int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb,
972 struct timeval timeout, uint32_t destnode,
973 TALLOC_CTX *mem_ctx, struct ctdb_node_map_old **nodemap)
975 int ret;
976 TDB_DATA outdata;
977 int32_t res;
979 ret = ctdb_control(ctdb, destnode, 0,
980 CTDB_CONTROL_GET_NODEMAP, 0, tdb_null,
981 mem_ctx, &outdata, &res, &timeout, NULL);
982 if (ret != 0 || res != 0 || outdata.dsize == 0) {
983 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodes failed ret:%d res:%d\n", ret, res));
984 return -1;
987 *nodemap = (struct ctdb_node_map_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
988 talloc_free(outdata.dptr);
989 return 0;
992 int ctdb_ctrl_get_runstate(struct ctdb_context *ctdb,
993 struct timeval timeout,
994 uint32_t destnode,
995 uint32_t *runstate)
997 TDB_DATA outdata;
998 int32_t res;
999 int ret;
1001 ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_RUNSTATE, 0,
1002 tdb_null, ctdb, &outdata, &res, &timeout, NULL);
1003 if (ret != 0 || res != 0) {
1004 DEBUG(DEBUG_ERR,("ctdb_control for get_runstate failed\n"));
1005 return ret != 0 ? ret : res;
1008 if (outdata.dsize != sizeof(uint32_t)) {
1009 DEBUG(DEBUG_ERR,("Invalid return data in get_runstate\n"));
1010 talloc_free(outdata.dptr);
1011 return -1;
1014 if (runstate != NULL) {
1015 *runstate = *(uint32_t *)outdata.dptr;
1017 talloc_free(outdata.dptr);
1019 return 0;
1023 get debug level on a node
1025 int ctdb_ctrl_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t *level)
1027 int ret;
1028 int32_t res;
1029 TDB_DATA data;
1031 ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DEBUG, 0, tdb_null,
1032 ctdb, &data, &res, NULL, NULL);
1033 if (ret != 0 || res != 0) {
1034 return -1;
1036 if (data.dsize != sizeof(int32_t)) {
1037 DEBUG(DEBUG_ERR,("Bad control reply size in ctdb_get_debuglevel (got %u)\n",
1038 (unsigned)data.dsize));
1039 return -1;
1041 *level = *(int32_t *)data.dptr;
1042 talloc_free(data.dptr);
1043 return 0;
1046 /* Freeze all databases */
1047 int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout,
1048 uint32_t destnode)
1050 int ret;
1051 int32_t res;
1053 ret = ctdb_control(ctdb, destnode, 0,
1054 CTDB_CONTROL_FREEZE, 0, tdb_null,
1055 NULL, NULL, &res, &timeout, NULL);
1056 if (ret != 0 || res != 0) {
1057 DEBUG(DEBUG_ERR, ("ctdb_ctrl_freeze_priority failed\n"));
1058 return -1;
1061 return 0;
1065 get pnn of a node, or -1
1067 int ctdb_ctrl_getpnn(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode)
1069 int ret;
1070 int32_t res;
1072 ret = ctdb_control(ctdb, destnode, 0,
1073 CTDB_CONTROL_GET_PNN, 0, tdb_null,
1074 NULL, NULL, &res, &timeout, NULL);
1075 if (ret != 0) {
1076 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpnn failed\n"));
1077 return -1;
1080 return res;
1083 int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
1084 struct timeval timeout, uint32_t destnode,
1085 TALLOC_CTX *mem_ctx,
1086 uint32_t flags,
1087 struct ctdb_public_ip_list_old **ips)
1089 int ret;
1090 TDB_DATA outdata;
1091 int32_t res;
1093 ret = ctdb_control(ctdb, destnode, 0,
1094 CTDB_CONTROL_GET_PUBLIC_IPS, flags, tdb_null,
1095 mem_ctx, &outdata, &res, &timeout, NULL);
1096 if (ret != 0 || res != 0) {
1097 DEBUG(DEBUG_ERR,(__location__
1098 " ctdb_control for getpublicips failed ret:%d res:%d\n",
1099 ret, res));
1100 return -1;
1103 *ips = (struct ctdb_public_ip_list_old *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize);
1104 talloc_free(outdata.dptr);
1106 return 0;
1109 int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
1110 struct timeval timeout, uint32_t destnode,
1111 TALLOC_CTX *mem_ctx,
1112 struct ctdb_public_ip_list_old **ips)
1114 return ctdb_ctrl_get_public_ips_flags(ctdb, timeout,
1115 destnode, mem_ctx,
1116 0, ips);
1119 int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
1120 struct timeval timeout, uint32_t destnode,
1121 TALLOC_CTX *mem_ctx,
1122 struct ctdb_iface_list_old **_ifaces)
1124 int ret;
1125 TDB_DATA outdata;
1126 int32_t res;
1127 struct ctdb_iface_list_old *ifaces;
1128 uint32_t len;
1129 uint32_t i;
1131 ret = ctdb_control(ctdb, destnode, 0,
1132 CTDB_CONTROL_GET_IFACES, 0, tdb_null,
1133 mem_ctx, &outdata, &res, &timeout, NULL);
1134 if (ret != 0 || res != 0) {
1135 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
1136 "failed ret:%d res:%d\n",
1137 ret, res));
1138 return -1;
1141 len = offsetof(struct ctdb_iface_list_old, ifaces);
1142 if (len > outdata.dsize) {
1143 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
1144 "returned invalid data with size %u > %u\n",
1145 (unsigned int)outdata.dsize,
1146 (unsigned int)len));
1147 dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
1148 return -1;
1151 ifaces = (struct ctdb_iface_list_old *)outdata.dptr;
1152 len += ifaces->num*sizeof(struct ctdb_iface);
1154 if (len > outdata.dsize) {
1155 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
1156 "returned invalid data with size %u > %u\n",
1157 (unsigned int)outdata.dsize,
1158 (unsigned int)len));
1159 dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
1160 return -1;
1163 /* make sure we null terminate the returned strings */
1164 for (i=0; i < ifaces->num; i++) {
1165 ifaces->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
1168 *_ifaces = (struct ctdb_iface_list_old *)talloc_memdup(mem_ctx,
1169 outdata.dptr,
1170 outdata.dsize);
1171 talloc_free(outdata.dptr);
1172 if (*_ifaces == NULL) {
1173 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
1174 "talloc_memdup size %u failed\n",
1175 (unsigned int)outdata.dsize));
1176 return -1;
1179 return 0;
1183 get all tunables
1185 int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
1186 struct timeval timeout,
1187 uint32_t destnode,
1188 struct ctdb_tunable_list *tunables)
1190 TDB_DATA outdata;
1191 int ret;
1192 int32_t res;
1194 ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_ALL_TUNABLES, 0, tdb_null, ctdb,
1195 &outdata, &res, &timeout, NULL);
1196 if (ret != 0 || res != 0) {
1197 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get all tunables failed\n"));
1198 return -1;
1201 if (outdata.dsize != sizeof(*tunables)) {
1202 DEBUG(DEBUG_ERR,(__location__ " bad data size %u in ctdb_ctrl_get_all_tunables should be %u\n",
1203 (unsigned)outdata.dsize, (unsigned)sizeof(*tunables)));
1204 return -1;
1207 *tunables = *(struct ctdb_tunable_list *)outdata.dptr;
1208 talloc_free(outdata.dptr);
1209 return 0;
1213 set some ctdb flags
1215 void ctdb_set_flags(struct ctdb_context *ctdb, unsigned flags)
1217 ctdb->flags |= flags;
1220 const char *ctdb_get_socketname(struct ctdb_context *ctdb)
1222 return ctdb->daemon.name;
1226 return the pnn of this node
1228 uint32_t ctdb_get_pnn(struct ctdb_context *ctdb)
1230 return ctdb->pnn;
1234 callback for the async helpers used when sending the same control
1235 to multiple nodes in parallel.
1237 static void async_callback(struct ctdb_client_control_state *state)
1239 struct client_async_data *data = talloc_get_type(state->async.private_data, struct client_async_data);
1240 struct ctdb_context *ctdb = talloc_get_type(state->ctdb, struct ctdb_context);
1241 int ret;
1242 TDB_DATA outdata;
1243 int32_t res = -1;
1244 uint32_t destnode = state->c->hdr.destnode;
1246 outdata.dsize = 0;
1247 outdata.dptr = NULL;
1249 /* one more node has responded with recmode data */
1250 data->count--;
1252 /* if we failed to push the db, then return an error and let
1253 the main loop try again.
1255 if (state->state != CTDB_CONTROL_DONE) {
1256 if ( !data->dont_log_errors) {
1257 DEBUG(DEBUG_ERR,("Async operation failed with state %d, opcode:%u\n", state->state, data->opcode));
1259 data->fail_count++;
1260 if (state->state == CTDB_CONTROL_TIMEOUT) {
1261 res = -ETIMEDOUT;
1262 } else {
1263 res = -1;
1265 if (data->fail_callback) {
1266 data->fail_callback(ctdb, destnode, res, outdata,
1267 data->callback_data);
1269 return;
1272 state->async.fn = NULL;
1274 ret = ctdb_control_recv(ctdb, state, data, &outdata, &res, NULL);
1275 if ((ret != 0) || (res != 0)) {
1276 if ( !data->dont_log_errors) {
1277 DEBUG(DEBUG_ERR,("Async operation failed with ret=%d res=%d opcode=%u\n", ret, (int)res, data->opcode));
1279 data->fail_count++;
1280 if (data->fail_callback) {
1281 data->fail_callback(ctdb, destnode, res, outdata,
1282 data->callback_data);
1285 if ((ret == 0) && (data->callback != NULL)) {
1286 data->callback(ctdb, destnode, res, outdata,
1287 data->callback_data);
1292 void ctdb_client_async_add(struct client_async_data *data, struct ctdb_client_control_state *state)
1294 /* set up the callback functions */
1295 state->async.fn = async_callback;
1296 state->async.private_data = data;
1298 /* one more control to wait for to complete */
1299 data->count++;
1303 /* wait for up to the maximum number of seconds allowed
1304 or until all nodes we expect a response from has replied
1306 int ctdb_client_async_wait(struct ctdb_context *ctdb, struct client_async_data *data)
1308 while (data->count > 0) {
1309 tevent_loop_once(ctdb->ev);
1311 if (data->fail_count != 0) {
1312 if (!data->dont_log_errors) {
1313 DEBUG(DEBUG_ERR,("Async wait failed - fail_count=%u\n",
1314 data->fail_count));
1316 return -1;
1318 return 0;
1323 perform a simple control on the listed nodes
1324 The control cannot return data
1326 int ctdb_client_async_control(struct ctdb_context *ctdb,
1327 enum ctdb_controls opcode,
1328 uint32_t *nodes,
1329 uint64_t srvid,
1330 struct timeval timeout,
1331 bool dont_log_errors,
1332 TDB_DATA data,
1333 client_async_callback client_callback,
1334 client_async_callback fail_callback,
1335 void *callback_data)
1337 struct client_async_data *async_data;
1338 struct ctdb_client_control_state *state;
1339 int j, num_nodes;
1341 async_data = talloc_zero(ctdb, struct client_async_data);
1342 CTDB_NO_MEMORY_FATAL(ctdb, async_data);
1343 async_data->dont_log_errors = dont_log_errors;
1344 async_data->callback = client_callback;
1345 async_data->fail_callback = fail_callback;
1346 async_data->callback_data = callback_data;
1347 async_data->opcode = opcode;
1349 num_nodes = talloc_get_size(nodes) / sizeof(uint32_t);
1351 /* loop over all nodes and send an async control to each of them */
1352 for (j=0; j<num_nodes; j++) {
1353 uint32_t pnn = nodes[j];
1355 state = ctdb_control_send(ctdb, pnn, srvid, opcode,
1356 0, data, async_data, &timeout, NULL);
1357 if (state == NULL) {
1358 DEBUG(DEBUG_ERR,(__location__ " Failed to call async control %u\n", (unsigned)opcode));
1359 talloc_free(async_data);
1360 return -1;
1363 ctdb_client_async_add(async_data, state);
1366 if (ctdb_client_async_wait(ctdb, async_data) != 0) {
1367 talloc_free(async_data);
1368 return -1;
1371 talloc_free(async_data);
1372 return 0;
1375 uint32_t *list_of_vnnmap_nodes(struct ctdb_context *ctdb,
1376 struct ctdb_vnn_map *vnn_map,
1377 TALLOC_CTX *mem_ctx,
1378 bool include_self)
1380 unsigned int i, j, num_nodes;
1381 uint32_t *nodes;
1383 for (i=num_nodes=0;i<vnn_map->size;i++) {
1384 if (vnn_map->map[i] == ctdb->pnn && !include_self) {
1385 continue;
1387 num_nodes++;
1390 nodes = talloc_array(mem_ctx, uint32_t, num_nodes);
1391 CTDB_NO_MEMORY_FATAL(ctdb, nodes);
1393 for (i=j=0;i<vnn_map->size;i++) {
1394 if (vnn_map->map[i] == ctdb->pnn && !include_self) {
1395 continue;
1397 nodes[j++] = vnn_map->map[i];
1400 return nodes;
1403 /* Get list of nodes not including those with flags specified by mask */
1404 static uint32_t *list_of_nodes(struct ctdb_context *ctdb,
1405 struct ctdb_node_map_old *node_map,
1406 TALLOC_CTX *mem_ctx,
1407 uint32_t mask,
1408 bool include_self)
1410 unsigned int i, j, num_nodes;
1411 uint32_t exclude_pnn;
1412 uint32_t *nodes;
1414 exclude_pnn = include_self ? CTDB_UNKNOWN_PNN : ctdb->pnn;
1416 for (i=num_nodes=0;i<node_map->num;i++) {
1417 if (node_map->nodes[i].flags & mask) {
1418 continue;
1420 if (node_map->nodes[i].pnn == exclude_pnn) {
1421 continue;
1423 num_nodes++;
1426 nodes = talloc_array(mem_ctx, uint32_t, num_nodes);
1427 CTDB_NO_MEMORY_FATAL(ctdb, nodes);
1429 for (i=j=0;i<node_map->num;i++) {
1430 if (node_map->nodes[i].flags & mask) {
1431 continue;
1433 if (node_map->nodes[i].pnn == exclude_pnn) {
1434 continue;
1436 nodes[j++] = node_map->nodes[i].pnn;
1439 return nodes;
1442 uint32_t *list_of_active_nodes(struct ctdb_context *ctdb,
1443 struct ctdb_node_map_old *node_map,
1444 TALLOC_CTX *mem_ctx,
1445 bool include_self)
1447 return list_of_nodes(ctdb,
1448 node_map,
1449 mem_ctx,
1450 NODE_FLAGS_INACTIVE,
1451 include_self);
1454 uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb,
1455 struct ctdb_node_map_old *node_map,
1456 TALLOC_CTX *mem_ctx,
1457 bool include_self)
1459 return list_of_nodes(ctdb,
1460 node_map,
1461 mem_ctx,
1462 NODE_FLAGS_DISCONNECTED,
1463 include_self);
1467 get capabilities of a remote node
1469 struct ctdb_client_control_state *
1470 ctdb_ctrl_getcapabilities_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode)
1472 return ctdb_control_send(ctdb, destnode, 0,
1473 CTDB_CONTROL_GET_CAPABILITIES, 0, tdb_null,
1474 mem_ctx, &timeout, NULL);
1477 int ctdb_ctrl_getcapabilities_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *capabilities)
1479 int ret;
1480 int32_t res;
1481 TDB_DATA outdata;
1483 ret = ctdb_control_recv(ctdb, state, mem_ctx, &outdata, &res, NULL);
1484 if ( (ret != 0) || (res != 0) ) {
1485 DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_getcapabilities_recv failed\n"));
1486 return -1;
1489 if (capabilities) {
1490 *capabilities = *((uint32_t *)outdata.dptr);
1493 return 0;
1496 int ctdb_ctrl_getcapabilities(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *capabilities)
1498 struct ctdb_client_control_state *state;
1499 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
1500 int ret;
1502 state = ctdb_ctrl_getcapabilities_send(ctdb, tmp_ctx, timeout, destnode);
1503 ret = ctdb_ctrl_getcapabilities_recv(ctdb, tmp_ctx, state, capabilities);
1504 talloc_free(tmp_ctx);
1505 return ret;
1508 static void get_capabilities_callback(struct ctdb_context *ctdb,
1509 uint32_t node_pnn, int32_t res,
1510 TDB_DATA outdata, void *callback_data)
1512 struct ctdb_node_capabilities *caps =
1513 talloc_get_type(callback_data,
1514 struct ctdb_node_capabilities);
1516 if ( (outdata.dsize != sizeof(uint32_t)) || (outdata.dptr == NULL) ) {
1517 DEBUG(DEBUG_ERR, (__location__ " Invalid length/pointer for getcap callback : %u %p\n", (unsigned)outdata.dsize, outdata.dptr));
1518 return;
1521 if (node_pnn >= talloc_array_length(caps)) {
1522 DEBUG(DEBUG_ERR,
1523 (__location__ " unexpected PNN %u\n", node_pnn));
1524 return;
1527 caps[node_pnn].retrieved = true;
1528 caps[node_pnn].capabilities = *((uint32_t *)outdata.dptr);
1531 struct ctdb_node_capabilities *
1532 ctdb_get_capabilities(struct ctdb_context *ctdb,
1533 TALLOC_CTX *mem_ctx,
1534 struct timeval timeout,
1535 struct ctdb_node_map_old *nodemap)
1537 uint32_t *nodes;
1538 uint32_t i, res;
1539 struct ctdb_node_capabilities *ret;
1541 nodes = list_of_active_nodes(ctdb, nodemap, mem_ctx, true);
1543 ret = talloc_array(mem_ctx, struct ctdb_node_capabilities,
1544 nodemap->num);
1545 CTDB_NO_MEMORY_NULL(ctdb, ret);
1546 /* Prepopulate the expected PNNs */
1547 for (i = 0; i < talloc_array_length(ret); i++) {
1548 ret[i].retrieved = false;
1551 res = ctdb_client_async_control(ctdb, CTDB_CONTROL_GET_CAPABILITIES,
1552 nodes, 0, timeout,
1553 false, tdb_null,
1554 get_capabilities_callback, NULL,
1555 ret);
1556 if (res != 0) {
1557 DEBUG(DEBUG_ERR,
1558 (__location__ " Failed to read node capabilities.\n"));
1559 TALLOC_FREE(ret);
1562 return ret;
1565 uint32_t *
1566 ctdb_get_node_capabilities(struct ctdb_node_capabilities *caps,
1567 uint32_t pnn)
1569 if (pnn < talloc_array_length(caps) && caps[pnn].retrieved) {
1570 return &caps[pnn].capabilities;
1573 return NULL;
1576 bool ctdb_node_has_capabilities(struct ctdb_node_capabilities *caps,
1577 uint32_t pnn,
1578 uint32_t capabilities_required)
1580 uint32_t *capp = ctdb_get_node_capabilities(caps, pnn);
1581 return (capp != NULL) &&
1582 ((*capp & capabilities_required) == capabilities_required);
1586 recovery daemon ping to main daemon
1588 int ctdb_ctrl_recd_ping(struct ctdb_context *ctdb)
1590 int ret;
1591 int32_t res;
1593 ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_RECD_PING, 0, tdb_null,
1594 ctdb, NULL, &res, NULL, NULL);
1595 if (ret != 0 || res != 0) {
1596 DEBUG(DEBUG_ERR,("Failed to send recd ping\n"));
1597 return -1;
1600 return 0;
1604 tell the main daemon how long it took to lock the reclock file
1606 int ctdb_ctrl_report_recd_lock_latency(struct ctdb_context *ctdb, struct timeval timeout, double latency)
1608 int ret;
1609 int32_t res;
1610 TDB_DATA data;
1612 data.dptr = (uint8_t *)&latency;
1613 data.dsize = sizeof(latency);
1615 ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_RECD_RECLOCK_LATENCY, 0, data,
1616 ctdb, NULL, &res, NULL, NULL);
1617 if (ret != 0 || res != 0) {
1618 DEBUG(DEBUG_ERR,("Failed to send recd reclock latency\n"));
1619 return -1;
1622 return 0;
1625 int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout,
1626 uint32_t destnode, struct ctdb_ban_state *bantime)
1628 int ret;
1629 TDB_DATA data;
1630 int32_t res;
1632 data.dsize = sizeof(*bantime);
1633 data.dptr = (uint8_t *)bantime;
1635 ret = ctdb_control(ctdb, destnode, 0,
1636 CTDB_CONTROL_SET_BAN_STATE, 0, data,
1637 NULL, NULL, &res, &timeout, NULL);
1638 if (ret != 0 || res != 0) {
1639 DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set ban state failed\n"));
1640 return -1;
1643 return 0;
1646 struct ctdb_client_control_state *
1647 ctdb_ctrl_updaterecord_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data)
1649 struct ctdb_client_control_state *handle;
1650 struct ctdb_marshall_buffer *m;
1651 struct ctdb_rec_data_old *rec;
1652 TDB_DATA outdata;
1654 m = talloc_zero(mem_ctx, struct ctdb_marshall_buffer);
1655 if (m == NULL) {
1656 DEBUG(DEBUG_ERR, ("Failed to allocate marshall buffer for update record\n"));
1657 return NULL;
1660 m->db_id = ctdb_db->db_id;
1662 rec = ctdb_marshall_record(m, 0, key, header, data);
1663 if (rec == NULL) {
1664 DEBUG(DEBUG_ERR,("Failed to marshall record for update record\n"));
1665 talloc_free(m);
1666 return NULL;
1668 m = talloc_realloc_size(mem_ctx, m, rec->length + offsetof(struct ctdb_marshall_buffer, data));
1669 if (m == NULL) {
1670 DEBUG(DEBUG_CRIT,(__location__ " Failed to expand recdata\n"));
1671 talloc_free(m);
1672 return NULL;
1674 m->count++;
1675 memcpy((uint8_t *)m + offsetof(struct ctdb_marshall_buffer, data), rec, rec->length);
1678 outdata.dptr = (uint8_t *)m;
1679 outdata.dsize = talloc_get_size(m);
1681 handle = ctdb_control_send(ctdb, destnode, 0,
1682 CTDB_CONTROL_UPDATE_RECORD, 0, outdata,
1683 mem_ctx, &timeout, NULL);
1684 talloc_free(m);
1685 return handle;
1688 int ctdb_ctrl_updaterecord_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state)
1690 int ret;
1691 int32_t res;
1693 ret = ctdb_control_recv(ctdb, state, state, NULL, &res, NULL);
1694 if ( (ret != 0) || (res != 0) ){
1695 DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_update_record_recv failed\n"));
1696 return -1;
1699 return 0;
1703 ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data)
1705 struct ctdb_client_control_state *state;
1707 state = ctdb_ctrl_updaterecord_send(ctdb, mem_ctx, timeout, destnode, ctdb_db, key, header, data);
1708 return ctdb_ctrl_updaterecord_recv(ctdb, state);