2 Fake CTDB server for testing
4 Copyright (C) Amitay Isaacs 2016
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.
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.
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/>.
21 #include "system/network.h"
22 #include "system/time.h"
29 #include "lib/util/dlinklist.h"
30 #include "lib/util/tevent_unix.h"
31 #include "lib/util/debug.h"
32 #include "lib/util/samba_util.h"
33 #include "lib/async_req/async_sock.h"
35 #include "protocol/protocol.h"
36 #include "protocol/protocol_api.h"
38 #include "common/comm.h"
39 #include "common/system.h"
40 #include "common/logging.h"
41 #include "common/tunable.h"
44 #define CTDB_PORT 4379
46 /* A fake flag that is only supported by some functions */
47 #define NODE_FLAGS_FAKE_TIMEOUT 0x80000000
53 uint32_t capabilities;
54 bool recovery_disabled;
55 void *recovery_substate;
71 struct interface_map {
73 struct interface *iface;
83 struct srvid_register_state {
84 struct srvid_register_state *prev, *next;
85 struct ctdbd_context *ctdb;
89 struct ctdbd_context {
90 struct node_map *node_map;
91 struct interface_map *iface_map;
92 struct vnn_map *vnn_map;
93 struct srvid_register_state *rstate;
95 struct timeval start_time;
96 struct timeval recovery_start_time;
97 struct timeval recovery_end_time;
98 bool takeover_disabled;
99 enum debug_level log_level;
100 enum ctdb_runstate runstate;
101 struct ctdb_tunable_list tun_list;
108 static struct node_map *nodemap_init(TALLOC_CTX *mem_ctx)
110 struct node_map *node_map;
112 node_map = talloc_zero(mem_ctx, struct node_map);
113 if (node_map == NULL) {
117 node_map->pnn = CTDB_UNKNOWN_PNN;
118 node_map->recmaster = CTDB_UNKNOWN_PNN;
123 /* Read a nodemap from stdin. Each line looks like:
124 * <PNN> <FLAGS> [RECMASTER] [CURRENT] [CAPABILITIES]
125 * EOF or a blank line terminates input.
127 * By default, capablities for each node are
128 * CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER. These 2
129 * capabilities can be faked off by adding, for example,
130 * -CTDB_CAP_RECMASTER.
133 static bool nodemap_parse(struct node_map *node_map)
137 while ((fgets(line, sizeof(line), stdin) != NULL)) {
138 uint32_t pnn, flags, capabilities;
141 ctdb_sock_addr saddr;
144 if (line[0] == '\n') {
148 /* Get rid of pesky newline */
149 if ((t = strchr(line, '\n')) != NULL) {
154 tok = strtok(line, " \t");
156 fprintf(stderr, "bad line (%s) - missing PNN\n", line);
159 pnn = (uint32_t)strtoul(tok, NULL, 0);
162 tok = strtok(NULL, " \t");
164 fprintf(stderr, "bad line (%s) - missing IP\n", line);
167 if (!parse_ip(tok, NULL, CTDB_PORT, &saddr)) {
168 fprintf(stderr, "bad line (%s) - invalid IP\n", line);
171 ip = talloc_strdup(node_map, tok);
177 tok = strtok(NULL, " \t");
179 fprintf(stderr, "bad line (%s) - missing flags\n",
183 flags = (uint32_t)strtoul(tok, NULL, 0);
184 /* Handle deleted nodes */
185 if (flags & NODE_FLAGS_DELETED) {
187 ip = talloc_strdup(node_map, "0.0.0.0");
192 capabilities = CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER;
194 tok = strtok(NULL, " \t");
195 while (tok != NULL) {
196 if (strcmp(tok, "CURRENT") == 0) {
198 } else if (strcmp(tok, "RECMASTER") == 0) {
199 node_map->recmaster = pnn;
200 } else if (strcmp(tok, "-CTDB_CAP_RECMASTER") == 0) {
201 capabilities &= ~CTDB_CAP_RECMASTER;
202 } else if (strcmp(tok, "-CTDB_CAP_LMASTER") == 0) {
203 capabilities &= ~CTDB_CAP_LMASTER;
204 } else if (strcmp(tok, "TIMEOUT") == 0) {
205 /* This can be done with just a flag
206 * value but it is probably clearer
207 * and less error-prone to fake this
208 * with an explicit token */
209 flags |= NODE_FLAGS_FAKE_TIMEOUT;
211 tok = strtok(NULL, " \t");
214 node_map->node = talloc_realloc(node_map, node_map->node,
216 node_map->num_nodes + 1);
217 if (node_map->node == NULL) {
220 node = &node_map->node[node_map->num_nodes];
222 parse_ip(ip, NULL, CTDB_PORT, &node->addr);
225 node->capabilities = capabilities;
226 node->recovery_disabled = false;
227 node->recovery_substate = NULL;
229 node_map->num_nodes += 1;
232 DEBUG(DEBUG_INFO, ("Parsing nodemap done\n"));
236 DEBUG(DEBUG_INFO, ("Parsing nodemap failed\n"));
241 /* Append a node to a node map with given address and flags */
242 static bool node_map_add(struct ctdb_node_map *nodemap,
243 const char *nstr, uint32_t flags)
247 struct ctdb_node_and_flags *n;
249 if (! parse_ip(nstr, NULL, CTDB_PORT, &addr)) {
250 fprintf(stderr, "Invalid IP address %s\n", nstr);
255 nodemap->node = talloc_realloc(nodemap, nodemap->node,
256 struct ctdb_node_and_flags, num+1);
257 if (nodemap->node == NULL) {
261 n = &nodemap->node[num];
266 nodemap->num = num+1;
270 /* Read a nodes file into a node map */
271 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
277 struct ctdb_node_map *nodemap;
279 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
280 if (nodemap == NULL) {
284 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
289 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
293 for (i=0; i<nlines; i++) {
299 /* strip leading spaces */
300 while((*node == ' ') || (*node == '\t')) {
306 /* strip trailing spaces */
308 ((node[len-1] == ' ') || (node[len-1] == '\t')))
318 /* A "deleted" node is a node that is
319 commented out in the nodes file. This is
320 used instead of removing a line, which
321 would cause subsequent nodes to change
323 flags = NODE_FLAGS_DELETED;
324 node = discard_const("0.0.0.0");
328 if (! node_map_add(nodemap, node, flags)) {
330 TALLOC_FREE(nodemap);
339 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx,
342 struct ctdb_node_map *nodemap;
343 char nodepath[PATH_MAX];
344 const char *nodes_list;
346 /* read the nodes file */
347 sprintf(nodepath, "CTDB_NODES_%u", pnn);
348 nodes_list = getenv(nodepath);
349 if (nodes_list == NULL) {
350 nodes_list = getenv("CTDB_NODES");
351 if (nodes_list == NULL) {
352 DEBUG(DEBUG_INFO, ("Nodes file not defined\n"));
357 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
358 if (nodemap == NULL) {
359 DEBUG(DEBUG_INFO, ("Failed to read nodes file \"%s\"\n",
367 static struct interface_map *interfaces_init(TALLOC_CTX *mem_ctx)
369 struct interface_map *iface_map;
371 iface_map = talloc_zero(mem_ctx, struct interface_map);
372 if (iface_map == NULL) {
379 /* Read interfaces information. Same format as "ctdb ifaces -Y"
381 * :Name:LinkStatus:References:
386 static bool interfaces_parse(struct interface_map *iface_map)
390 while ((fgets(line, sizeof(line), stdin) != NULL)) {
393 char *tok, *t, *name;
394 struct interface *iface;
396 if (line[0] == '\n') {
400 /* Get rid of pesky newline */
401 if ((t = strchr(line, '\n')) != NULL) {
405 if (strcmp(line, ":Name:LinkStatus:References:") == 0) {
409 /* Leading colon... */
410 // tok = strtok(line, ":");
413 tok = strtok(line, ":");
415 fprintf(stderr, "bad line (%s) - missing name\n", line);
421 tok = strtok(NULL, ":");
423 fprintf(stderr, "bad line (%s) - missing link state\n",
427 link_state = (uint16_t)strtoul(tok, NULL, 0);
430 tok = strtok(NULL, ":");
432 fprintf(stderr, "bad line (%s) - missing references\n",
436 references = (uint32_t)strtoul(tok, NULL, 0);
438 iface_map->iface = talloc_realloc(iface_map, iface_map->iface,
441 if (iface_map->iface == NULL) {
445 iface = &iface_map->iface[iface_map->num];
447 iface->name = talloc_strdup(iface_map, name);
448 if (iface->name == NULL) {
451 iface->link_up = link_state;
452 iface->references = references;
457 DEBUG(DEBUG_INFO, ("Parsing interfaces done\n"));
461 fprintf(stderr, "Parsing interfaces failed\n");
465 static struct vnn_map *vnnmap_init(TALLOC_CTX *mem_ctx)
467 struct vnn_map *vnn_map;
469 vnn_map = talloc_zero(mem_ctx, struct vnn_map);
470 if (vnn_map == NULL) {
471 fprintf(stderr, "Memory error\n");
474 vnn_map->recmode = CTDB_RECOVERY_ACTIVE;
475 vnn_map->generation = INVALID_GENERATION;
488 static bool vnnmap_parse(struct vnn_map *vnn_map)
492 while (fgets(line, sizeof(line), stdin) != NULL) {
496 if (line[0] == '\n') {
500 /* Get rid of pesky newline */
501 if ((t = strchr(line, '\n')) != NULL) {
505 n = (uint32_t) strtol(line, NULL, 0);
508 if (vnn_map->generation == INVALID_GENERATION) {
509 vnn_map->generation = n;
513 vnn_map->map = talloc_realloc(vnn_map, vnn_map->map, uint32_t,
515 if (vnn_map->map == NULL) {
516 fprintf(stderr, "Memory error\n");
520 vnn_map->map[vnn_map->size] = n;
524 DEBUG(DEBUG_INFO, ("Parsing vnnmap done\n"));
528 fprintf(stderr, "Parsing vnnmap failed\n");
536 static uint32_t new_generation(uint32_t old_generation)
541 generation = random();
542 if (generation != INVALID_GENERATION &&
543 generation != old_generation) {
551 static struct ctdbd_context *ctdbd_setup(TALLOC_CTX *mem_ctx)
553 struct ctdbd_context *ctdb;
557 ctdb = talloc_zero(mem_ctx, struct ctdbd_context);
562 ctdb->node_map = nodemap_init(ctdb);
563 if (ctdb->node_map == NULL) {
567 ctdb->iface_map = interfaces_init(ctdb);
568 if (ctdb->iface_map == NULL) {
572 ctdb->vnn_map = vnnmap_init(ctdb);
573 if (ctdb->vnn_map == NULL) {
577 while (fgets(line, sizeof(line), stdin) != NULL) {
580 if ((t = strchr(line, '\n')) != NULL) {
584 if (strcmp(line, "NODEMAP") == 0) {
585 status = nodemap_parse(ctdb->node_map);
586 } else if (strcmp(line, "IFACES") == 0) {
587 status = interfaces_parse(ctdb->iface_map);
588 } else if (strcmp(line, "VNNMAP") == 0) {
589 status = vnnmap_parse(ctdb->vnn_map);
591 fprintf(stderr, "Unknown line %s\n", line);
600 ctdb->start_time = tevent_timeval_current();
601 ctdb->recovery_start_time = tevent_timeval_current();
602 ctdb->vnn_map->recmode = CTDB_RECOVERY_NORMAL;
603 if (ctdb->vnn_map->generation == INVALID_GENERATION) {
604 ctdb->vnn_map->generation =
605 new_generation(ctdb->vnn_map->generation);
607 ctdb->recovery_end_time = tevent_timeval_current();
609 ctdb->log_level = DEBUG_ERR;
610 ctdb->runstate = CTDB_RUNSTATE_RUNNING;
612 ctdb_tunable_set_defaults(&ctdb->tun_list);
621 static bool ctdbd_verify(struct ctdbd_context *ctdb)
626 if (ctdb->node_map->num_nodes == 0) {
630 /* Make sure all the nodes are in order */
631 for (i=0; i<ctdb->node_map->num_nodes; i++) {
632 node = &ctdb->node_map->node[i];
633 if (node->pnn != i) {
634 fprintf(stderr, "Expected node %u, found %u\n",
640 node = &ctdb->node_map->node[ctdb->node_map->pnn];
641 if (node->flags & NODE_FLAGS_DISCONNECTED) {
642 DEBUG(DEBUG_INFO, ("Node disconnected, exiting\n"));
653 struct recover_state {
654 struct tevent_context *ev;
655 struct ctdbd_context *ctdb;
658 static int recover_check(struct tevent_req *req);
659 static void recover_wait_done(struct tevent_req *subreq);
660 static void recover_done(struct tevent_req *subreq);
662 static struct tevent_req *recover_send(TALLOC_CTX *mem_ctx,
663 struct tevent_context *ev,
664 struct ctdbd_context *ctdb)
666 struct tevent_req *req;
667 struct recover_state *state;
670 req = tevent_req_create(mem_ctx, &state, struct recover_state);
678 ret = recover_check(req);
680 tevent_req_error(req, ret);
681 return tevent_req_post(req, ev);
687 static int recover_check(struct tevent_req *req)
689 struct recover_state *state = tevent_req_data(
690 req, struct recover_state);
691 struct ctdbd_context *ctdb = state->ctdb;
692 struct tevent_req *subreq;
693 bool recovery_disabled;
696 recovery_disabled = false;
697 for (i=0; i<ctdb->node_map->num_nodes; i++) {
698 if (ctdb->node_map->node[i].recovery_disabled) {
699 recovery_disabled = true;
704 subreq = tevent_wakeup_send(state, state->ev,
705 tevent_timeval_current_ofs(1, 0));
706 if (subreq == NULL) {
710 if (recovery_disabled) {
711 tevent_req_set_callback(subreq, recover_wait_done, req);
713 ctdb->recovery_start_time = tevent_timeval_current();
714 tevent_req_set_callback(subreq, recover_done, req);
720 static void recover_wait_done(struct tevent_req *subreq)
722 struct tevent_req *req = tevent_req_callback_data(
723 subreq, struct tevent_req);
727 status = tevent_wakeup_recv(subreq);
730 tevent_req_error(req, EIO);
734 ret = recover_check(req);
736 tevent_req_error(req, ret);
740 static void recover_done(struct tevent_req *subreq)
742 struct tevent_req *req = tevent_req_callback_data(
743 subreq, struct tevent_req);
744 struct recover_state *state = tevent_req_data(
745 req, struct recover_state);
746 struct ctdbd_context *ctdb = state->ctdb;
749 status = tevent_wakeup_recv(subreq);
752 tevent_req_error(req, EIO);
756 ctdb->vnn_map->recmode = CTDB_RECOVERY_NORMAL;
757 ctdb->recovery_end_time = tevent_timeval_current();
758 ctdb->vnn_map->generation = new_generation(ctdb->vnn_map->generation);
760 tevent_req_done(req);
763 static bool recover_recv(struct tevent_req *req, int *perr)
767 if (tevent_req_is_unix_error(req, &err)) {
778 * Routines for ctdb_req_header
781 static void header_fix_pnn(struct ctdb_req_header *header,
782 struct ctdbd_context *ctdb)
784 if (header->srcnode == CTDB_CURRENT_NODE) {
785 header->srcnode = ctdb->node_map->pnn;
788 if (header->destnode == CTDB_CURRENT_NODE) {
789 header->destnode = ctdb->node_map->pnn;
793 static struct ctdb_req_header header_reply_control(
794 struct ctdb_req_header *header,
795 struct ctdbd_context *ctdb)
797 struct ctdb_req_header reply_header;
799 reply_header = (struct ctdb_req_header) {
800 .ctdb_magic = CTDB_MAGIC,
801 .ctdb_version = CTDB_PROTOCOL,
802 .generation = ctdb->vnn_map->generation,
803 .operation = CTDB_REPLY_CONTROL,
804 .destnode = header->srcnode,
805 .srcnode = header->destnode,
806 .reqid = header->reqid,
812 static struct ctdb_req_header header_reply_message(
813 struct ctdb_req_header *header,
814 struct ctdbd_context *ctdb)
816 struct ctdb_req_header reply_header;
818 reply_header = (struct ctdb_req_header) {
819 .ctdb_magic = CTDB_MAGIC,
820 .ctdb_version = CTDB_PROTOCOL,
821 .generation = ctdb->vnn_map->generation,
822 .operation = CTDB_REQ_MESSAGE,
823 .destnode = header->srcnode,
824 .srcnode = header->destnode,
835 struct client_state {
836 struct tevent_context *ev;
838 struct ctdbd_context *ctdb;
840 struct comm_context *comm;
841 struct srvid_register_state *rstate;
846 * Send replies to controls and messages
849 static void client_reply_done(struct tevent_req *subreq);
851 static void client_send_message(struct tevent_req *req,
852 struct ctdb_req_header *header,
853 struct ctdb_req_message_data *message)
855 struct client_state *state = tevent_req_data(
856 req, struct client_state);
857 struct ctdbd_context *ctdb = state->ctdb;
858 struct tevent_req *subreq;
859 struct ctdb_req_header reply_header;
861 size_t datalen, buflen;
864 reply_header = header_reply_message(header, ctdb);
866 datalen = ctdb_req_message_data_len(&reply_header, message);
867 ret = ctdb_allocate_pkt(state, datalen, &buf, &buflen);
869 tevent_req_error(req, ret);
873 ret = ctdb_req_message_data_push(&reply_header, message,
876 tevent_req_error(req, ret);
880 DEBUG(DEBUG_INFO, ("message srvid = 0x%"PRIx64"\n", message->srvid));
882 subreq = comm_write_send(state, state->ev, state->comm, buf, buflen);
883 if (tevent_req_nomem(subreq, req)) {
886 tevent_req_set_callback(subreq, client_reply_done, req);
888 talloc_steal(subreq, buf);
891 static void client_send_control(struct tevent_req *req,
892 struct ctdb_req_header *header,
893 struct ctdb_reply_control *reply)
895 struct client_state *state = tevent_req_data(
896 req, struct client_state);
897 struct ctdbd_context *ctdb = state->ctdb;
898 struct tevent_req *subreq;
899 struct ctdb_req_header reply_header;
901 size_t datalen, buflen;
904 reply_header = header_reply_control(header, ctdb);
906 datalen = ctdb_reply_control_len(&reply_header, reply);
907 ret = ctdb_allocate_pkt(state, datalen, &buf, &buflen);
909 tevent_req_error(req, ret);
913 ret = ctdb_reply_control_push(&reply_header, reply, buf, &buflen);
915 tevent_req_error(req, ret);
919 DEBUG(DEBUG_INFO, ("reply opcode = %u\n", reply->rdata.opcode));
921 subreq = comm_write_send(state, state->ev, state->comm, buf, buflen);
922 if (tevent_req_nomem(subreq, req)) {
925 tevent_req_set_callback(subreq, client_reply_done, req);
927 talloc_steal(subreq, buf);
930 static void client_reply_done(struct tevent_req *subreq)
932 struct tevent_req *req = tevent_req_callback_data(
933 subreq, struct tevent_req);
937 status = comm_write_recv(subreq, &ret);
940 tevent_req_error(req, ret);
945 * Handling protocol - controls
948 static void control_process_exists(TALLOC_CTX *mem_ctx,
949 struct tevent_req *req,
950 struct ctdb_req_header *header,
951 struct ctdb_req_control *request)
953 struct ctdb_reply_control reply;
955 reply.rdata.opcode = request->opcode;
956 reply.status = kill(request->rdata.data.pid, 0);
959 client_send_control(req, header, &reply);
962 static void control_ping(TALLOC_CTX *mem_ctx,
963 struct tevent_req *req,
964 struct ctdb_req_header *header,
965 struct ctdb_req_control *request)
967 struct client_state *state = tevent_req_data(
968 req, struct client_state);
969 struct ctdbd_context *ctdb = state->ctdb;
970 struct ctdb_reply_control reply;
972 reply.rdata.opcode = request->opcode;
973 reply.status = ctdb->num_clients;
976 client_send_control(req, header, &reply);
979 static void control_getvnnmap(TALLOC_CTX *mem_ctx,
980 struct tevent_req *req,
981 struct ctdb_req_header *header,
982 struct ctdb_req_control *request)
984 struct client_state *state = tevent_req_data(
985 req, struct client_state);
986 struct ctdbd_context *ctdb = state->ctdb;
987 struct ctdb_reply_control reply;
988 struct ctdb_vnn_map *vnnmap;
990 reply.rdata.opcode = request->opcode;
992 vnnmap = talloc_zero(mem_ctx, struct ctdb_vnn_map);
993 if (vnnmap == NULL) {
994 reply.status = ENOMEM;
995 reply.errmsg = "Memory error";
997 vnnmap->generation = ctdb->vnn_map->generation;
998 vnnmap->size = ctdb->vnn_map->size;
999 vnnmap->map = ctdb->vnn_map->map;
1001 reply.rdata.data.vnnmap = vnnmap;
1003 reply.errmsg = NULL;
1006 client_send_control(req, header, &reply);
1009 static void control_get_debug(TALLOC_CTX *mem_ctx,
1010 struct tevent_req *req,
1011 struct ctdb_req_header *header,
1012 struct ctdb_req_control *request)
1014 struct client_state *state = tevent_req_data(
1015 req, struct client_state);
1016 struct ctdbd_context *ctdb = state->ctdb;
1017 struct ctdb_reply_control reply;
1019 reply.rdata.opcode = request->opcode;
1020 reply.rdata.data.loglevel = debug_level_to_int(ctdb->log_level);
1022 reply.errmsg = NULL;
1024 client_send_control(req, header, &reply);
1027 static void control_set_debug(TALLOC_CTX *mem_ctx,
1028 struct tevent_req *req,
1029 struct ctdb_req_header *header,
1030 struct ctdb_req_control *request)
1032 struct client_state *state = tevent_req_data(
1033 req, struct client_state);
1034 struct ctdbd_context *ctdb = state->ctdb;
1035 struct ctdb_reply_control reply;
1037 ctdb->log_level = debug_level_from_int(request->rdata.data.loglevel);
1039 reply.rdata.opcode = request->opcode;
1041 reply.errmsg = NULL;
1043 client_send_control(req, header, &reply);
1046 static void control_get_recmode(TALLOC_CTX *mem_ctx,
1047 struct tevent_req *req,
1048 struct ctdb_req_header *header,
1049 struct ctdb_req_control *request)
1051 struct client_state *state = tevent_req_data(
1052 req, struct client_state);
1053 struct ctdbd_context *ctdb = state->ctdb;
1054 struct ctdb_reply_control reply;
1056 reply.rdata.opcode = request->opcode;
1057 reply.status = ctdb->vnn_map->recmode;
1058 reply.errmsg = NULL;
1060 client_send_control(req, header, &reply);
1063 struct set_recmode_state {
1064 struct tevent_req *req;
1065 struct ctdbd_context *ctdb;
1066 struct ctdb_req_header header;
1067 struct ctdb_reply_control reply;
1070 static void set_recmode_callback(struct tevent_req *subreq)
1072 struct set_recmode_state *substate = tevent_req_callback_data(
1073 subreq, struct set_recmode_state);
1077 status = recover_recv(subreq, &ret);
1078 TALLOC_FREE(subreq);
1080 substate->reply.status = ret;
1081 substate->reply.errmsg = "recovery failed";
1083 substate->reply.status = 0;
1084 substate->reply.errmsg = NULL;
1087 client_send_control(substate->req, &substate->header, &substate->reply);
1088 talloc_free(substate);
1091 static void control_set_recmode(TALLOC_CTX *mem_ctx,
1092 struct tevent_req *req,
1093 struct ctdb_req_header *header,
1094 struct ctdb_req_control *request)
1096 struct client_state *state = tevent_req_data(
1097 req, struct client_state);
1098 struct tevent_req *subreq;
1099 struct ctdbd_context *ctdb = state->ctdb;
1100 struct set_recmode_state *substate;
1101 struct ctdb_reply_control reply;
1103 reply.rdata.opcode = request->opcode;
1105 if (request->rdata.data.recmode == CTDB_RECOVERY_NORMAL) {
1107 reply.errmsg = "Client cannot set recmode to NORMAL";
1111 substate = talloc_zero(ctdb, struct set_recmode_state);
1112 if (substate == NULL) {
1114 reply.errmsg = "Memory error";
1118 substate->req = req;
1119 substate->ctdb = ctdb;
1120 substate->header = *header;
1121 substate->reply.rdata.opcode = request->opcode;
1123 subreq = recover_send(substate, state->ev, state->ctdb);
1124 if (subreq == NULL) {
1125 talloc_free(substate);
1128 tevent_req_set_callback(subreq, set_recmode_callback, substate);
1130 ctdb->vnn_map->recmode = CTDB_RECOVERY_ACTIVE;
1134 client_send_control(req, header, &reply);
1138 static int srvid_register_state_destructor(struct srvid_register_state *rstate)
1140 DLIST_REMOVE(rstate->ctdb->rstate, rstate);
1144 static void control_register_srvid(TALLOC_CTX *mem_ctx,
1145 struct tevent_req *req,
1146 struct ctdb_req_header *header,
1147 struct ctdb_req_control *request)
1149 struct client_state *state = tevent_req_data(
1150 req, struct client_state);
1151 struct ctdbd_context *ctdb = state->ctdb;
1152 struct ctdb_reply_control reply;
1153 struct srvid_register_state *rstate;
1155 reply.rdata.opcode = request->opcode;
1157 rstate = talloc_zero(ctdb, struct srvid_register_state);
1158 if (rstate == NULL) {
1160 reply.errmsg = "Memory error";
1163 rstate->ctdb = ctdb;
1164 rstate->srvid = request->srvid;
1166 talloc_set_destructor(rstate, srvid_register_state_destructor);
1168 DLIST_ADD_END(ctdb->rstate, rstate);
1170 DEBUG(DEBUG_INFO, ("Register srvid 0x%"PRIx64"\n", rstate->srvid));
1173 reply.errmsg = NULL;
1176 client_send_control(req, header, &reply);
1179 static void control_deregister_srvid(TALLOC_CTX *mem_ctx,
1180 struct tevent_req *req,
1181 struct ctdb_req_header *header,
1182 struct ctdb_req_control *request)
1184 struct client_state *state = tevent_req_data(
1185 req, struct client_state);
1186 struct ctdbd_context *ctdb = state->ctdb;
1187 struct ctdb_reply_control reply;
1188 struct srvid_register_state *rstate = NULL;
1190 reply.rdata.opcode = request->opcode;
1192 for (rstate = ctdb->rstate; rstate != NULL; rstate = rstate->next) {
1193 if (rstate->srvid == request->srvid) {
1198 if (rstate == NULL) {
1200 reply.errmsg = "srvid not registered";
1204 DEBUG(DEBUG_INFO, ("Deregister srvid 0x%"PRIx64"\n", rstate->srvid));
1205 talloc_free(rstate);
1208 reply.errmsg = NULL;
1210 client_send_control(req, header, &reply);
1214 TALLOC_FREE(rstate);
1215 client_send_control(req, header, &reply);
1218 static void control_get_pid(TALLOC_CTX *mem_ctx,
1219 struct tevent_req *req,
1220 struct ctdb_req_header *header,
1221 struct ctdb_req_control *request)
1223 struct ctdb_reply_control reply;
1225 reply.rdata.opcode = request->opcode;
1226 reply.status = getpid();
1227 reply.errmsg = NULL;
1229 client_send_control(req, header, &reply);
1232 static void control_get_recmaster(TALLOC_CTX *mem_ctx,
1233 struct tevent_req *req,
1234 struct ctdb_req_header *header,
1235 struct ctdb_req_control *request)
1237 struct client_state *state = tevent_req_data(
1238 req, struct client_state);
1239 struct ctdbd_context *ctdb = state->ctdb;
1240 struct ctdb_reply_control reply;
1242 reply.rdata.opcode = request->opcode;
1243 reply.status = ctdb->node_map->recmaster;
1244 reply.errmsg = NULL;
1246 client_send_control(req, header, &reply);
1249 static void control_get_pnn(TALLOC_CTX *mem_ctx,
1250 struct tevent_req *req,
1251 struct ctdb_req_header *header,
1252 struct ctdb_req_control *request)
1254 struct ctdb_reply_control reply;
1256 reply.rdata.opcode = request->opcode;
1257 reply.status = header->destnode;
1258 reply.errmsg = NULL;
1260 client_send_control(req, header, &reply);
1263 static void control_shutdown(TALLOC_CTX *mem_ctx,
1264 struct tevent_req *req,
1265 struct ctdb_req_header *hdr,
1266 struct ctdb_req_control *request)
1268 struct client_state *state = tevent_req_data(
1269 req, struct client_state);
1274 static void control_set_tunable(TALLOC_CTX *mem_ctx,
1275 struct tevent_req *req,
1276 struct ctdb_req_header *header,
1277 struct ctdb_req_control *request)
1279 struct client_state *state = tevent_req_data(
1280 req, struct client_state);
1281 struct ctdbd_context *ctdb = state->ctdb;
1282 struct ctdb_reply_control reply;
1285 reply.rdata.opcode = request->opcode;
1286 reply.errmsg = NULL;
1288 ret = ctdb_tunable_set_value(&ctdb->tun_list,
1289 request->rdata.data.tunable->name,
1290 request->rdata.data.tunable->value,
1294 } else if (obsolete) {
1300 client_send_control(req, header, &reply);
1303 static void control_get_tunable(TALLOC_CTX *mem_ctx,
1304 struct tevent_req *req,
1305 struct ctdb_req_header *header,
1306 struct ctdb_req_control *request)
1308 struct client_state *state = tevent_req_data(
1309 req, struct client_state);
1310 struct ctdbd_context *ctdb = state->ctdb;
1311 struct ctdb_reply_control reply;
1315 reply.rdata.opcode = request->opcode;
1316 reply.errmsg = NULL;
1318 ret = ctdb_tunable_get_value(&ctdb->tun_list,
1319 request->rdata.data.tun_var, &value);
1323 reply.rdata.data.tun_value = value;
1327 client_send_control(req, header, &reply);
1330 static void control_list_tunables(TALLOC_CTX *mem_ctx,
1331 struct tevent_req *req,
1332 struct ctdb_req_header *header,
1333 struct ctdb_req_control *request)
1335 struct ctdb_reply_control reply;
1336 struct ctdb_var_list *var_list;
1338 reply.rdata.opcode = request->opcode;
1339 reply.errmsg = NULL;
1341 var_list = ctdb_tunable_names(mem_ctx);
1342 if (var_list == NULL) {
1345 reply.rdata.data.tun_var_list = var_list;
1349 client_send_control(req, header, &reply);
1352 static void control_get_all_tunables(TALLOC_CTX *mem_ctx,
1353 struct tevent_req *req,
1354 struct ctdb_req_header *header,
1355 struct ctdb_req_control *request)
1357 struct client_state *state = tevent_req_data(
1358 req, struct client_state);
1359 struct ctdbd_context *ctdb = state->ctdb;
1360 struct ctdb_reply_control reply;
1362 reply.rdata.opcode = request->opcode;
1363 reply.rdata.data.tun_list = &ctdb->tun_list;
1365 reply.errmsg = NULL;
1367 client_send_control(req, header, &reply);
1370 static void control_uptime(TALLOC_CTX *mem_ctx,
1371 struct tevent_req *req,
1372 struct ctdb_req_header *header,
1373 struct ctdb_req_control *request)
1375 struct client_state *state = tevent_req_data(
1376 req, struct client_state);
1377 struct ctdbd_context *ctdb = state->ctdb;
1378 struct ctdb_reply_control reply;
1379 struct ctdb_uptime *uptime;;
1381 reply.rdata.opcode = request->opcode;
1383 uptime = talloc_zero(mem_ctx, struct ctdb_uptime);
1384 if (uptime == NULL) {
1388 uptime->current_time = tevent_timeval_current();
1389 uptime->ctdbd_start_time = ctdb->start_time;
1390 uptime->last_recovery_started = ctdb->recovery_start_time;
1391 uptime->last_recovery_finished = ctdb->recovery_end_time;
1393 reply.rdata.data.uptime = uptime;
1395 reply.errmsg = NULL;
1396 client_send_control(req, header, &reply);
1401 reply.errmsg = "Memory error";
1402 client_send_control(req, header, &reply);
1405 static void control_reload_nodes_file(TALLOC_CTX *mem_ctx,
1406 struct tevent_req *req,
1407 struct ctdb_req_header *header,
1408 struct ctdb_req_control *request)
1410 struct client_state *state = tevent_req_data(
1411 req, struct client_state);
1412 struct ctdbd_context *ctdb = state->ctdb;
1413 struct ctdb_reply_control reply;
1414 struct ctdb_node_map *nodemap;
1415 struct node_map *node_map = ctdb->node_map;
1418 reply.rdata.opcode = request->opcode;
1420 nodemap = read_nodes_file(mem_ctx, header->destnode);
1421 if (nodemap == NULL) {
1425 for (i=0; i<nodemap->num; i++) {
1428 if (i < node_map->num_nodes &&
1429 ctdb_sock_addr_same(&nodemap->node[i].addr,
1430 &node_map->node[i].addr)) {
1434 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
1435 node = &node_map->node[i];
1437 node->flags |= NODE_FLAGS_DELETED;
1438 parse_ip("0.0.0.0", NULL, 0, &node->addr);
1443 if (i < node_map->num_nodes &&
1444 node_map->node[i].flags & NODE_FLAGS_DELETED) {
1445 node = &node_map->node[i];
1447 node->flags &= ~NODE_FLAGS_DELETED;
1448 node->addr = nodemap->node[i].addr;
1453 node_map->node = talloc_realloc(node_map, node_map->node,
1455 node_map->num_nodes+1);
1456 if (node_map->node == NULL) {
1459 node = &node_map->node[node_map->num_nodes];
1461 node->addr = nodemap->node[i].addr;
1462 node->pnn = nodemap->node[i].pnn;
1464 node->capabilities = CTDB_CAP_DEFAULT;
1465 node->recovery_disabled = false;
1466 node->recovery_substate = NULL;
1468 node_map->num_nodes += 1;
1471 talloc_free(nodemap);
1474 reply.errmsg = NULL;
1475 client_send_control(req, header, &reply);
1480 reply.errmsg = "Memory error";
1481 client_send_control(req, header, &reply);
1484 static void control_get_capabilities(TALLOC_CTX *mem_ctx,
1485 struct tevent_req *req,
1486 struct ctdb_req_header *header,
1487 struct ctdb_req_control *request)
1489 struct client_state *state = tevent_req_data(
1490 req, struct client_state);
1491 struct ctdbd_context *ctdb = state->ctdb;
1492 struct ctdb_reply_control reply;
1496 reply.rdata.opcode = request->opcode;
1498 node = &ctdb->node_map->node[header->destnode];
1499 caps = node->capabilities;
1501 if (node->flags & NODE_FLAGS_FAKE_TIMEOUT) {
1502 /* Don't send reply */
1506 reply.rdata.data.caps = caps;
1508 reply.errmsg = NULL;
1510 client_send_control(req, header, &reply);
1513 static void control_get_nodemap(TALLOC_CTX *mem_ctx,
1514 struct tevent_req *req,
1515 struct ctdb_req_header *header,
1516 struct ctdb_req_control *request)
1518 struct client_state *state = tevent_req_data(
1519 req, struct client_state);
1520 struct ctdbd_context *ctdb = state->ctdb;
1521 struct ctdb_reply_control reply;
1522 struct ctdb_node_map *nodemap;
1526 reply.rdata.opcode = request->opcode;
1528 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
1529 if (nodemap == NULL) {
1533 nodemap->num = ctdb->node_map->num_nodes;
1534 nodemap->node = talloc_array(nodemap, struct ctdb_node_and_flags,
1536 if (nodemap->node == NULL) {
1540 for (i=0; i<nodemap->num; i++) {
1541 node = &ctdb->node_map->node[i];
1542 nodemap->node[i] = (struct ctdb_node_and_flags) {
1544 .flags = node->flags,
1549 reply.rdata.data.nodemap = nodemap;
1551 reply.errmsg = NULL;
1552 client_send_control(req, header, &reply);
1557 reply.errmsg = "Memory error";
1558 client_send_control(req, header, &reply);
1561 static void control_get_ifaces(TALLOC_CTX *mem_ctx,
1562 struct tevent_req *req,
1563 struct ctdb_req_header *header,
1564 struct ctdb_req_control *request)
1566 struct client_state *state = tevent_req_data(
1567 req, struct client_state);
1568 struct ctdbd_context *ctdb = state->ctdb;
1569 struct ctdb_reply_control reply;
1570 struct ctdb_iface_list *iface_list;
1571 struct interface *iface;
1574 reply.rdata.opcode = request->opcode;
1576 iface_list = talloc_zero(mem_ctx, struct ctdb_iface_list);
1577 if (iface_list == NULL) {
1581 iface_list->num = ctdb->iface_map->num;
1582 iface_list->iface = talloc_array(iface_list, struct ctdb_iface,
1584 if (iface_list->iface == NULL) {
1588 for (i=0; i<iface_list->num; i++) {
1589 iface = &ctdb->iface_map->iface[i];
1590 iface_list->iface[i] = (struct ctdb_iface) {
1591 .link_state = iface->link_up,
1592 .references = iface->references,
1594 strncpy(iface_list->iface[i].name, iface->name,
1598 reply.rdata.data.iface_list = iface_list;
1600 reply.errmsg = NULL;
1601 client_send_control(req, header, &reply);
1606 reply.errmsg = "Memory error";
1607 client_send_control(req, header, &reply);
1610 static void control_get_runstate(TALLOC_CTX *mem_ctx,
1611 struct tevent_req *req,
1612 struct ctdb_req_header *header,
1613 struct ctdb_req_control *request)
1615 struct client_state *state = tevent_req_data(
1616 req, struct client_state);
1617 struct ctdbd_context *ctdb = state->ctdb;
1618 struct ctdb_reply_control reply;
1620 reply.rdata.opcode = request->opcode;
1621 reply.rdata.data.runstate = ctdb->runstate;
1623 reply.errmsg = NULL;
1625 client_send_control(req, header, &reply);
1628 static void control_get_nodes_file(TALLOC_CTX *mem_ctx,
1629 struct tevent_req *req,
1630 struct ctdb_req_header *header,
1631 struct ctdb_req_control *request)
1633 struct ctdb_reply_control reply;
1634 struct ctdb_node_map *nodemap;
1636 reply.rdata.opcode = request->opcode;
1638 nodemap = read_nodes_file(mem_ctx, header->destnode);
1639 if (nodemap == NULL) {
1643 reply.rdata.data.nodemap = nodemap;
1645 reply.errmsg = NULL;
1646 client_send_control(req, header, &reply);
1651 reply.errmsg = "Failed to read nodes file";
1652 client_send_control(req, header, &reply);
1655 static void control_error(TALLOC_CTX *mem_ctx,
1656 struct tevent_req *req,
1657 struct ctdb_req_header *header,
1658 struct ctdb_req_control *request)
1660 struct ctdb_reply_control reply;
1662 reply.rdata.opcode = request->opcode;
1664 reply.errmsg = "Not implemented";
1666 client_send_control(req, header, &reply);
1670 * Handling protocol - messages
1673 struct disable_recoveries_state {
1677 static void disable_recoveries_callback(struct tevent_req *subreq)
1679 struct disable_recoveries_state *substate = tevent_req_callback_data(
1680 subreq, struct disable_recoveries_state);
1683 status = tevent_wakeup_recv(subreq);
1684 TALLOC_FREE(subreq);
1686 DEBUG(DEBUG_INFO, ("tevent_wakeup_recv failed\n"));
1689 substate->node->recovery_disabled = false;
1690 TALLOC_FREE(substate->node->recovery_substate);
1693 static void message_disable_recoveries(TALLOC_CTX *mem_ctx,
1694 struct tevent_req *req,
1695 struct ctdb_req_header *header,
1696 struct ctdb_req_message *request)
1698 struct client_state *state = tevent_req_data(
1699 req, struct client_state);
1700 struct tevent_req *subreq;
1701 struct ctdbd_context *ctdb = state->ctdb;
1702 struct disable_recoveries_state *substate;
1703 struct ctdb_disable_message *disable = request->data.disable;
1704 struct ctdb_req_message_data reply;
1709 node = &ctdb->node_map->node[header->destnode];
1711 if (disable->timeout == 0) {
1712 TALLOC_FREE(node->recovery_substate);
1713 node->recovery_disabled = false;
1714 DEBUG(DEBUG_INFO, ("Enabled recoveries on node %u\n",
1719 substate = talloc_zero(ctdb->node_map,
1720 struct disable_recoveries_state);
1721 if (substate == NULL) {
1725 substate->node = node;
1727 subreq = tevent_wakeup_send(substate, state->ev,
1728 tevent_timeval_current_ofs(
1729 disable->timeout, 0));
1730 if (subreq == NULL) {
1731 talloc_free(substate);
1734 tevent_req_set_callback(subreq, disable_recoveries_callback, substate);
1736 DEBUG(DEBUG_INFO, ("Disabled recoveries for %d seconds on node %u\n",
1737 disable->timeout, header->destnode));
1738 node->recovery_substate = substate;
1739 node->recovery_disabled = true;
1742 ret = header->destnode;
1745 reply.srvid = disable->srvid;
1746 data.dptr = (uint8_t *)&ret;
1747 data.dsize = sizeof(int);
1750 client_send_message(req, header, &reply);
1754 * Handle a single client
1757 static void client_read_handler(uint8_t *buf, size_t buflen,
1758 void *private_data);
1759 static void client_dead_handler(void *private_data);
1760 static void client_process_packet(struct tevent_req *req,
1761 uint8_t *buf, size_t buflen);
1762 static void client_process_message(struct tevent_req *req,
1763 uint8_t *buf, size_t buflen);
1764 static void client_process_control(struct tevent_req *req,
1765 uint8_t *buf, size_t buflen);
1766 static void client_reply_done(struct tevent_req *subreq);
1768 static struct tevent_req *client_send(TALLOC_CTX *mem_ctx,
1769 struct tevent_context *ev,
1770 int fd, struct ctdbd_context *ctdb,
1773 struct tevent_req *req;
1774 struct client_state *state;
1777 req = tevent_req_create(mem_ctx, &state, struct client_state);
1787 ret = comm_setup(state, ev, fd, client_read_handler, req,
1788 client_dead_handler, req, &state->comm);
1790 tevent_req_error(req, ret);
1791 return tevent_req_post(req, ev);
1794 DEBUG(DEBUG_INFO, ("New client fd=%d\n", fd));
1799 static void client_read_handler(uint8_t *buf, size_t buflen,
1802 struct tevent_req *req = talloc_get_type_abort(
1803 private_data, struct tevent_req);
1804 struct client_state *state = tevent_req_data(
1805 req, struct client_state);
1806 struct ctdbd_context *ctdb = state->ctdb;
1807 struct ctdb_req_header header;
1810 ret = ctdb_req_header_pull(buf, buflen, &header);
1815 if (buflen != header.length) {
1819 ret = ctdb_req_header_verify(&header, 0);
1824 header_fix_pnn(&header, ctdb);
1826 if (header.destnode == CTDB_BROADCAST_ALL) {
1827 for (i=0; i<ctdb->node_map->num_nodes; i++) {
1828 header.destnode = i;
1830 ctdb_req_header_push(&header, buf);
1831 client_process_packet(req, buf, buflen);
1836 if (header.destnode == CTDB_BROADCAST_CONNECTED) {
1837 for (i=0; i<ctdb->node_map->num_nodes; i++) {
1838 if (ctdb->node_map->node[i].flags &
1839 NODE_FLAGS_DISCONNECTED) {
1843 header.destnode = i;
1845 ctdb_req_header_push(&header, buf);
1846 client_process_packet(req, buf, buflen);
1851 if (header.destnode > ctdb->node_map->num_nodes) {
1852 fprintf(stderr, "Invalid destination pnn 0x%x\n",
1858 if (ctdb->node_map->node[header.destnode].flags & NODE_FLAGS_DISCONNECTED) {
1859 fprintf(stderr, "Packet for disconnected node pnn %u\n",
1864 ctdb_req_header_push(&header, buf);
1865 client_process_packet(req, buf, buflen);
1868 static void client_dead_handler(void *private_data)
1870 struct tevent_req *req = talloc_get_type_abort(
1871 private_data, struct tevent_req);
1873 tevent_req_done(req);
1876 static void client_process_packet(struct tevent_req *req,
1877 uint8_t *buf, size_t buflen)
1879 struct ctdb_req_header header;
1882 ret = ctdb_req_header_pull(buf, buflen, &header);
1887 switch (header.operation) {
1888 case CTDB_REQ_MESSAGE:
1889 client_process_message(req, buf, buflen);
1892 case CTDB_REQ_CONTROL:
1893 client_process_control(req, buf, buflen);
1901 static void client_process_message(struct tevent_req *req,
1902 uint8_t *buf, size_t buflen)
1904 struct client_state *state = tevent_req_data(
1905 req, struct client_state);
1906 struct ctdbd_context *ctdb = state->ctdb;
1907 TALLOC_CTX *mem_ctx;
1908 struct ctdb_req_header header;
1909 struct ctdb_req_message request;
1913 mem_ctx = talloc_new(state);
1914 if (tevent_req_nomem(mem_ctx, req)) {
1918 ret = ctdb_req_message_pull(buf, buflen, &header, mem_ctx, &request);
1920 talloc_free(mem_ctx);
1921 tevent_req_error(req, ret);
1925 header_fix_pnn(&header, ctdb);
1927 if (header.destnode >= ctdb->node_map->num_nodes) {
1928 /* Many messages are not replied to, so just behave as
1929 * though this message was not received */
1930 fprintf(stderr, "Invalid node %d\n", header.destnode);
1931 talloc_free(mem_ctx);
1935 srvid = request.srvid;
1936 DEBUG(DEBUG_INFO, ("request srvid = 0x%"PRIx64"\n", srvid));
1938 if (srvid == CTDB_SRVID_DISABLE_RECOVERIES) {
1939 message_disable_recoveries(mem_ctx, req, &header, &request);
1943 talloc_free(mem_ctx);
1946 static void client_process_control(struct tevent_req *req,
1947 uint8_t *buf, size_t buflen)
1949 struct client_state *state = tevent_req_data(
1950 req, struct client_state);
1951 struct ctdbd_context *ctdb = state->ctdb;
1952 TALLOC_CTX *mem_ctx;
1953 struct ctdb_req_header header;
1954 struct ctdb_req_control request;
1957 mem_ctx = talloc_new(state);
1958 if (tevent_req_nomem(mem_ctx, req)) {
1962 ret = ctdb_req_control_pull(buf, buflen, &header, mem_ctx, &request);
1964 talloc_free(mem_ctx);
1965 tevent_req_error(req, ret);
1969 header_fix_pnn(&header, ctdb);
1971 if (header.destnode >= ctdb->node_map->num_nodes) {
1972 struct ctdb_reply_control reply;
1974 reply.rdata.opcode = request.opcode;
1975 reply.errmsg = "Invalid node";
1977 client_send_control(req, &header, &reply);
1981 DEBUG(DEBUG_INFO, ("request opcode = %u, reqid = %u\n",
1982 request.opcode, header.reqid));
1984 switch (request.opcode) {
1985 case CTDB_CONTROL_PROCESS_EXISTS:
1986 control_process_exists(mem_ctx, req, &header, &request);
1989 case CTDB_CONTROL_PING:
1990 control_ping(mem_ctx, req, &header, &request);
1993 case CTDB_CONTROL_GETVNNMAP:
1994 control_getvnnmap(mem_ctx, req, &header, &request);
1997 case CTDB_CONTROL_GET_DEBUG:
1998 control_get_debug(mem_ctx, req, &header, &request);
2001 case CTDB_CONTROL_SET_DEBUG:
2002 control_set_debug(mem_ctx, req, &header, &request);
2005 case CTDB_CONTROL_GET_RECMODE:
2006 control_get_recmode(mem_ctx, req, &header, &request);
2009 case CTDB_CONTROL_SET_RECMODE:
2010 control_set_recmode(mem_ctx, req, &header, &request);
2013 case CTDB_CONTROL_REGISTER_SRVID:
2014 control_register_srvid(mem_ctx, req, &header, &request);
2017 case CTDB_CONTROL_DEREGISTER_SRVID:
2018 control_deregister_srvid(mem_ctx, req, &header, &request);
2021 case CTDB_CONTROL_GET_PID:
2022 control_get_pid(mem_ctx, req, &header, &request);
2025 case CTDB_CONTROL_GET_RECMASTER:
2026 control_get_recmaster(mem_ctx, req, &header, &request);
2029 case CTDB_CONTROL_GET_PNN:
2030 control_get_pnn(mem_ctx, req, &header, &request);
2033 case CTDB_CONTROL_SHUTDOWN:
2034 control_shutdown(mem_ctx, req, &header, &request);
2037 case CTDB_CONTROL_SET_TUNABLE:
2038 control_set_tunable(mem_ctx, req, &header, &request);
2041 case CTDB_CONTROL_GET_TUNABLE:
2042 control_get_tunable(mem_ctx, req, &header, &request);
2045 case CTDB_CONTROL_LIST_TUNABLES:
2046 control_list_tunables(mem_ctx, req, &header, &request);
2049 case CTDB_CONTROL_GET_ALL_TUNABLES:
2050 control_get_all_tunables(mem_ctx, req, &header, &request);
2053 case CTDB_CONTROL_UPTIME:
2054 control_uptime(mem_ctx, req, &header, &request);
2057 case CTDB_CONTROL_RELOAD_NODES_FILE:
2058 control_reload_nodes_file(mem_ctx, req, &header, &request);
2061 case CTDB_CONTROL_GET_CAPABILITIES:
2062 control_get_capabilities(mem_ctx, req, &header, &request);
2065 case CTDB_CONTROL_GET_NODEMAP:
2066 control_get_nodemap(mem_ctx, req, &header, &request);
2069 case CTDB_CONTROL_GET_IFACES:
2070 control_get_ifaces(mem_ctx, req, &header, &request);
2073 case CTDB_CONTROL_GET_RUNSTATE:
2074 control_get_runstate(mem_ctx, req, &header, &request);
2077 case CTDB_CONTROL_GET_NODES_FILE:
2078 control_get_nodes_file(mem_ctx, req, &header, &request);
2082 if (! (request.flags & CTDB_CTRL_FLAG_NOREPLY)) {
2083 control_error(mem_ctx, req, &header, &request);
2088 talloc_free(mem_ctx);
2091 static int client_recv(struct tevent_req *req, int *perr)
2093 struct client_state *state = tevent_req_data(
2094 req, struct client_state);
2097 DEBUG(DEBUG_INFO, ("Client done fd=%d\n", state->fd));
2100 if (tevent_req_is_unix_error(req, &err)) {
2107 return state->status;
2114 struct server_state {
2115 struct tevent_context *ev;
2116 struct ctdbd_context *ctdb;
2120 static void server_new_client(struct tevent_req *subreq);
2121 static void server_client_done(struct tevent_req *subreq);
2123 static struct tevent_req *server_send(TALLOC_CTX *mem_ctx,
2124 struct tevent_context *ev,
2125 struct ctdbd_context *ctdb,
2128 struct tevent_req *req, *subreq;
2129 struct server_state *state;
2131 req = tevent_req_create(mem_ctx, &state, struct server_state);
2140 subreq = accept_send(state, ev, fd);
2141 if (tevent_req_nomem(subreq, req)) {
2142 return tevent_req_post(req, ev);
2144 tevent_req_set_callback(subreq, server_new_client, req);
2149 static void server_new_client(struct tevent_req *subreq)
2151 struct tevent_req *req = tevent_req_callback_data(
2152 subreq, struct tevent_req);
2153 struct server_state *state = tevent_req_data(
2154 req, struct server_state);
2155 struct ctdbd_context *ctdb = state->ctdb;
2159 client_fd = accept_recv(subreq, NULL, NULL, &ret);
2160 TALLOC_FREE(subreq);
2161 if (client_fd == -1) {
2162 tevent_req_error(req, ret);
2166 subreq = client_send(state, state->ev, client_fd,
2167 ctdb, ctdb->node_map->pnn);
2168 if (tevent_req_nomem(subreq, req)) {
2171 tevent_req_set_callback(subreq, server_client_done, req);
2173 ctdb->num_clients += 1;
2175 subreq = accept_send(state, state->ev, state->fd);
2176 if (tevent_req_nomem(subreq, req)) {
2179 tevent_req_set_callback(subreq, server_new_client, req);
2182 static void server_client_done(struct tevent_req *subreq)
2184 struct tevent_req *req = tevent_req_callback_data(
2185 subreq, struct tevent_req);
2186 struct server_state *state = tevent_req_data(
2187 req, struct server_state);
2188 struct ctdbd_context *ctdb = state->ctdb;
2192 status = client_recv(subreq, &ret);
2193 TALLOC_FREE(subreq);
2195 tevent_req_error(req, ret);
2199 ctdb->num_clients -= 1;
2202 /* Special status, to shutdown server */
2203 DEBUG(DEBUG_INFO, ("Shutting down server\n"));
2204 tevent_req_done(req);
2208 static bool server_recv(struct tevent_req *req, int *perr)
2212 if (tevent_req_is_unix_error(req, &err)) {
2225 static int socket_init(const char *sockpath)
2227 struct sockaddr_un addr;
2231 memset(&addr, 0, sizeof(addr));
2232 addr.sun_family = AF_UNIX;
2234 len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
2235 if (len >= sizeof(addr.sun_path)) {
2236 fprintf(stderr, "path too long: %s\n", sockpath);
2240 fd = socket(AF_UNIX, SOCK_STREAM, 0);
2242 fprintf(stderr, "socket failed - %s\n", sockpath);
2246 ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
2248 fprintf(stderr, "bind failed - %s\n", sockpath);
2252 ret = listen(fd, 10);
2254 fprintf(stderr, "listen failed\n");
2258 DEBUG(DEBUG_INFO, ("Socket init done\n"));
2269 static struct options {
2270 const char *sockpath;
2271 const char *pidfile;
2272 const char *debuglevel;
2275 static struct poptOption cmdline_options[] = {
2276 { "socket", 's', POPT_ARG_STRING, &options.sockpath, 0,
2277 "Unix domain socket path", "filename" },
2278 { "pidfile", 'p', POPT_ARG_STRING, &options.pidfile, 0,
2279 "pid file", "filename" } ,
2280 { "debug", 'd', POPT_ARG_STRING, &options.debuglevel, 0,
2281 "debug level", "ERR|WARNING|NOTICE|INFO|DEBUG" } ,
2284 static void cleanup(void)
2286 unlink(options.sockpath);
2287 unlink(options.pidfile);
2290 static void signal_handler(int sig)
2296 static void start_server(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2297 struct ctdbd_context *ctdb, int fd, int pfd)
2299 struct tevent_req *req;
2304 signal(SIGTERM, signal_handler);
2306 req = server_send(mem_ctx, ev, ctdb, fd);
2308 fprintf(stderr, "Memory error\n");
2312 len = write(pfd, &ret, sizeof(ret));
2313 if (len != sizeof(ret)) {
2314 fprintf(stderr, "Failed to send message to parent\n");
2319 tevent_req_poll(req, ev);
2321 server_recv(req, &ret);
2327 int main(int argc, const char *argv[])
2329 TALLOC_CTX *mem_ctx;
2330 struct ctdbd_context *ctdb;
2331 struct tevent_context *ev;
2332 enum debug_level debug_level;
2334 int opt, fd, ret, pfd[2];
2339 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
2340 POPT_CONTEXT_KEEP_FIRST);
2341 while ((opt = poptGetNextOpt(pc)) != -1) {
2342 fprintf(stderr, "Invalid option %s\n", poptBadOption(pc, 0));
2346 if (options.sockpath == NULL) {
2347 fprintf(stderr, "Please specify socket path\n");
2348 poptPrintHelp(pc, stdout, 0);
2352 if (options.pidfile == NULL) {
2353 fprintf(stderr, "Please specify pid file\n");
2354 poptPrintHelp(pc, stdout, 0);
2358 if (options.debuglevel == NULL) {
2359 DEBUGLEVEL = debug_level_to_int(DEBUG_ERR);
2361 if (debug_level_parse(options.debuglevel, &debug_level)) {
2362 DEBUGLEVEL = debug_level_to_int(debug_level);
2364 fprintf(stderr, "Invalid debug level\n");
2365 poptPrintHelp(pc, stdout, 0);
2370 mem_ctx = talloc_new(NULL);
2371 if (mem_ctx == NULL) {
2372 fprintf(stderr, "Memory error\n");
2376 ctdb = ctdbd_setup(mem_ctx);
2381 if (! ctdbd_verify(ctdb)) {
2385 ev = tevent_context_init(mem_ctx);
2387 fprintf(stderr, "Memory error\n");
2391 fd = socket_init(options.sockpath);
2398 fprintf(stderr, "Failed to create pipe\n");
2405 fprintf(stderr, "Failed to fork\n");
2413 start_server(mem_ctx, ev, ctdb, fd, pfd[1]);
2420 len = read(pfd[0], &ret, sizeof(ret));
2422 if (len != sizeof(ret)) {
2423 fprintf(stderr, "len = %zi\n", len);
2424 fprintf(stderr, "Failed to get message from child\n");
2429 fp = fopen(options.pidfile, "w");
2431 fprintf(stderr, "Failed to open pid file %s\n",
2436 fprintf(fp, "%d\n", pid);