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"
43 #define CTDB_PORT 4379
45 /* A fake flag that is only supported by some functions */
46 #define NODE_FLAGS_FAKE_TIMEOUT 0x80000000
52 uint32_t capabilities;
53 bool recovery_disabled;
54 void *recovery_substate;
70 struct interface_map {
72 struct interface *iface;
82 struct srvid_register_state {
83 struct srvid_register_state *prev, *next;
84 struct ctdbd_context *ctdb;
88 struct ctdbd_context {
89 struct node_map *node_map;
90 struct interface_map *iface_map;
91 struct vnn_map *vnn_map;
92 struct srvid_register_state *rstate;
94 struct timeval start_time;
95 struct timeval recovery_start_time;
96 struct timeval recovery_end_time;
97 bool takeover_disabled;
98 enum debug_level log_level;
105 static struct node_map *nodemap_init(TALLOC_CTX *mem_ctx)
107 struct node_map *node_map;
109 node_map = talloc_zero(mem_ctx, struct node_map);
110 if (node_map == NULL) {
114 node_map->pnn = CTDB_UNKNOWN_PNN;
115 node_map->recmaster = CTDB_UNKNOWN_PNN;
120 /* Read a nodemap from stdin. Each line looks like:
121 * <PNN> <FLAGS> [RECMASTER] [CURRENT] [CAPABILITIES]
122 * EOF or a blank line terminates input.
124 * By default, capablities for each node are
125 * CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER. These 2
126 * capabilities can be faked off by adding, for example,
127 * -CTDB_CAP_RECMASTER.
130 static bool nodemap_parse(struct node_map *node_map)
134 while ((fgets(line, sizeof(line), stdin) != NULL)) {
135 uint32_t pnn, flags, capabilities;
138 ctdb_sock_addr saddr;
141 if (line[0] == '\n') {
145 /* Get rid of pesky newline */
146 if ((t = strchr(line, '\n')) != NULL) {
151 tok = strtok(line, " \t");
153 fprintf(stderr, "bad line (%s) - missing PNN\n", line);
156 pnn = (uint32_t)strtoul(tok, NULL, 0);
159 tok = strtok(NULL, " \t");
161 fprintf(stderr, "bad line (%s) - missing IP\n", line);
164 if (!parse_ip(tok, NULL, CTDB_PORT, &saddr)) {
165 fprintf(stderr, "bad line (%s) - invalid IP\n", line);
168 ip = talloc_strdup(node_map, tok);
174 tok = strtok(NULL, " \t");
176 fprintf(stderr, "bad line (%s) - missing flags\n",
180 flags = (uint32_t)strtoul(tok, NULL, 0);
181 /* Handle deleted nodes */
182 if (flags & NODE_FLAGS_DELETED) {
184 ip = talloc_strdup(node_map, "0.0.0.0");
189 capabilities = CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER;
191 tok = strtok(NULL, " \t");
192 while (tok != NULL) {
193 if (strcmp(tok, "CURRENT") == 0) {
195 } else if (strcmp(tok, "RECMASTER") == 0) {
196 node_map->recmaster = pnn;
197 } else if (strcmp(tok, "-CTDB_CAP_RECMASTER") == 0) {
198 capabilities &= ~CTDB_CAP_RECMASTER;
199 } else if (strcmp(tok, "-CTDB_CAP_LMASTER") == 0) {
200 capabilities &= ~CTDB_CAP_LMASTER;
201 } else if (strcmp(tok, "TIMEOUT") == 0) {
202 /* This can be done with just a flag
203 * value but it is probably clearer
204 * and less error-prone to fake this
205 * with an explicit token */
206 flags |= NODE_FLAGS_FAKE_TIMEOUT;
208 tok = strtok(NULL, " \t");
211 node_map->node = talloc_realloc(node_map, node_map->node,
213 node_map->num_nodes + 1);
214 if (node_map->node == NULL) {
217 node = &node_map->node[node_map->num_nodes];
219 parse_ip(ip, NULL, CTDB_PORT, &node->addr);
222 node->capabilities = capabilities;
223 node->recovery_disabled = false;
224 node->recovery_substate = NULL;
226 node_map->num_nodes += 1;
229 DEBUG(DEBUG_INFO, ("Parsing nodemap done\n"));
233 DEBUG(DEBUG_INFO, ("Parsing nodemap failed\n"));
238 /* Append a node to a node map with given address and flags */
239 static bool node_map_add(struct ctdb_node_map *nodemap,
240 const char *nstr, uint32_t flags)
244 struct ctdb_node_and_flags *n;
246 if (! parse_ip(nstr, NULL, CTDB_PORT, &addr)) {
247 fprintf(stderr, "Invalid IP address %s\n", nstr);
252 nodemap->node = talloc_realloc(nodemap, nodemap->node,
253 struct ctdb_node_and_flags, num+1);
254 if (nodemap->node == NULL) {
258 n = &nodemap->node[num];
263 nodemap->num = num+1;
267 /* Read a nodes file into a node map */
268 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
274 struct ctdb_node_map *nodemap;
276 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
277 if (nodemap == NULL) {
281 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
286 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
290 for (i=0; i<nlines; i++) {
296 /* strip leading spaces */
297 while((*node == ' ') || (*node == '\t')) {
303 /* strip trailing spaces */
305 ((node[len-1] == ' ') || (node[len-1] == '\t')))
315 /* A "deleted" node is a node that is
316 commented out in the nodes file. This is
317 used instead of removing a line, which
318 would cause subsequent nodes to change
320 flags = NODE_FLAGS_DELETED;
321 node = discard_const("0.0.0.0");
325 if (! node_map_add(nodemap, node, flags)) {
327 TALLOC_FREE(nodemap);
336 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx,
339 struct ctdb_node_map *nodemap;
340 char nodepath[PATH_MAX];
341 const char *nodes_list;
343 /* read the nodes file */
344 sprintf(nodepath, "CTDB_NODES_%u", pnn);
345 nodes_list = getenv(nodepath);
346 if (nodes_list == NULL) {
347 nodes_list = getenv("CTDB_NODES");
348 if (nodes_list == NULL) {
349 DEBUG(DEBUG_INFO, ("Nodes file not defined\n"));
354 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
355 if (nodemap == NULL) {
356 DEBUG(DEBUG_INFO, ("Failed to read nodes file \"%s\"\n",
364 static struct interface_map *interfaces_init(TALLOC_CTX *mem_ctx)
366 struct interface_map *iface_map;
368 iface_map = talloc_zero(mem_ctx, struct interface_map);
369 if (iface_map == NULL) {
376 /* Read interfaces information. Same format as "ctdb ifaces -Y"
378 * :Name:LinkStatus:References:
383 static bool interfaces_parse(struct interface_map *iface_map)
387 while ((fgets(line, sizeof(line), stdin) != NULL)) {
390 char *tok, *t, *name;
391 struct interface *iface;
393 if (line[0] == '\n') {
397 /* Get rid of pesky newline */
398 if ((t = strchr(line, '\n')) != NULL) {
402 if (strcmp(line, ":Name:LinkStatus:References:") == 0) {
406 /* Leading colon... */
407 // tok = strtok(line, ":");
410 tok = strtok(line, ":");
412 fprintf(stderr, "bad line (%s) - missing name\n", line);
418 tok = strtok(NULL, ":");
420 fprintf(stderr, "bad line (%s) - missing link state\n",
424 link_state = (uint16_t)strtoul(tok, NULL, 0);
427 tok = strtok(NULL, ":");
429 fprintf(stderr, "bad line (%s) - missing references\n",
433 references = (uint32_t)strtoul(tok, NULL, 0);
435 iface_map->iface = talloc_realloc(iface_map, iface_map->iface,
438 if (iface_map->iface == NULL) {
442 iface = &iface_map->iface[iface_map->num];
444 iface->name = talloc_strdup(iface_map, name);
445 if (iface->name == NULL) {
448 iface->link_up = link_state;
449 iface->references = references;
454 DEBUG(DEBUG_INFO, ("Parsing interfaces done\n"));
458 fprintf(stderr, "Parsing interfaces failed\n");
462 static struct vnn_map *vnnmap_init(TALLOC_CTX *mem_ctx)
464 struct vnn_map *vnn_map;
466 vnn_map = talloc_zero(mem_ctx, struct vnn_map);
467 if (vnn_map == NULL) {
468 fprintf(stderr, "Memory error\n");
471 vnn_map->recmode = CTDB_RECOVERY_ACTIVE;
472 vnn_map->generation = INVALID_GENERATION;
485 static bool vnnmap_parse(struct vnn_map *vnn_map)
489 while (fgets(line, sizeof(line), stdin) != NULL) {
493 if (line[0] == '\n') {
497 /* Get rid of pesky newline */
498 if ((t = strchr(line, '\n')) != NULL) {
502 n = (uint32_t) strtol(line, NULL, 0);
505 if (vnn_map->generation == INVALID_GENERATION) {
506 vnn_map->generation = n;
510 vnn_map->map = talloc_realloc(vnn_map, vnn_map->map, uint32_t,
512 if (vnn_map->map == NULL) {
513 fprintf(stderr, "Memory error\n");
517 vnn_map->map[vnn_map->size] = n;
521 DEBUG(DEBUG_INFO, ("Parsing vnnmap done\n"));
525 fprintf(stderr, "Parsing vnnmap failed\n");
533 static uint32_t new_generation(uint32_t old_generation)
538 generation = random();
539 if (generation != INVALID_GENERATION &&
540 generation != old_generation) {
548 static struct ctdbd_context *ctdbd_setup(TALLOC_CTX *mem_ctx)
550 struct ctdbd_context *ctdb;
554 ctdb = talloc_zero(mem_ctx, struct ctdbd_context);
559 ctdb->node_map = nodemap_init(ctdb);
560 if (ctdb->node_map == NULL) {
564 ctdb->iface_map = interfaces_init(ctdb);
565 if (ctdb->iface_map == NULL) {
569 ctdb->vnn_map = vnnmap_init(ctdb);
570 if (ctdb->vnn_map == NULL) {
574 while (fgets(line, sizeof(line), stdin) != NULL) {
577 if ((t = strchr(line, '\n')) != NULL) {
581 if (strcmp(line, "NODEMAP") == 0) {
582 status = nodemap_parse(ctdb->node_map);
583 } else if (strcmp(line, "IFACES") == 0) {
584 status = interfaces_parse(ctdb->iface_map);
585 } else if (strcmp(line, "VNNMAP") == 0) {
586 status = vnnmap_parse(ctdb->vnn_map);
588 fprintf(stderr, "Unknown line %s\n", line);
597 ctdb->start_time = tevent_timeval_current();
598 ctdb->recovery_start_time = tevent_timeval_current();
599 ctdb->vnn_map->recmode = CTDB_RECOVERY_NORMAL;
600 if (ctdb->vnn_map->generation == INVALID_GENERATION) {
601 ctdb->vnn_map->generation =
602 new_generation(ctdb->vnn_map->generation);
604 ctdb->recovery_end_time = tevent_timeval_current();
606 ctdb->log_level = DEBUG_ERR;
615 static bool ctdbd_verify(struct ctdbd_context *ctdb)
620 if (ctdb->node_map->num_nodes == 0) {
624 /* Make sure all the nodes are in order */
625 for (i=0; i<ctdb->node_map->num_nodes; i++) {
626 node = &ctdb->node_map->node[i];
627 if (node->pnn != i) {
628 fprintf(stderr, "Expected node %u, found %u\n",
634 node = &ctdb->node_map->node[ctdb->node_map->pnn];
635 if (node->flags & NODE_FLAGS_DISCONNECTED) {
636 DEBUG(DEBUG_INFO, ("Node disconnected, exiting\n"));
647 struct recover_state {
648 struct tevent_context *ev;
649 struct ctdbd_context *ctdb;
652 static int recover_check(struct tevent_req *req);
653 static void recover_wait_done(struct tevent_req *subreq);
654 static void recover_done(struct tevent_req *subreq);
656 static struct tevent_req *recover_send(TALLOC_CTX *mem_ctx,
657 struct tevent_context *ev,
658 struct ctdbd_context *ctdb)
660 struct tevent_req *req;
661 struct recover_state *state;
664 req = tevent_req_create(mem_ctx, &state, struct recover_state);
672 ret = recover_check(req);
674 tevent_req_error(req, ret);
675 return tevent_req_post(req, ev);
681 static int recover_check(struct tevent_req *req)
683 struct recover_state *state = tevent_req_data(
684 req, struct recover_state);
685 struct ctdbd_context *ctdb = state->ctdb;
686 struct tevent_req *subreq;
687 bool recovery_disabled;
690 recovery_disabled = false;
691 for (i=0; i<ctdb->node_map->num_nodes; i++) {
692 if (ctdb->node_map->node[i].recovery_disabled) {
693 recovery_disabled = true;
698 subreq = tevent_wakeup_send(state, state->ev,
699 tevent_timeval_current_ofs(1, 0));
700 if (subreq == NULL) {
704 if (recovery_disabled) {
705 tevent_req_set_callback(subreq, recover_wait_done, req);
707 ctdb->recovery_start_time = tevent_timeval_current();
708 tevent_req_set_callback(subreq, recover_done, req);
714 static void recover_wait_done(struct tevent_req *subreq)
716 struct tevent_req *req = tevent_req_callback_data(
717 subreq, struct tevent_req);
721 status = tevent_wakeup_recv(subreq);
724 tevent_req_error(req, EIO);
728 ret = recover_check(req);
730 tevent_req_error(req, ret);
734 static void recover_done(struct tevent_req *subreq)
736 struct tevent_req *req = tevent_req_callback_data(
737 subreq, struct tevent_req);
738 struct recover_state *state = tevent_req_data(
739 req, struct recover_state);
740 struct ctdbd_context *ctdb = state->ctdb;
743 status = tevent_wakeup_recv(subreq);
746 tevent_req_error(req, EIO);
750 ctdb->vnn_map->recmode = CTDB_RECOVERY_NORMAL;
751 ctdb->recovery_end_time = tevent_timeval_current();
752 ctdb->vnn_map->generation = new_generation(ctdb->vnn_map->generation);
754 tevent_req_done(req);
757 static bool recover_recv(struct tevent_req *req, int *perr)
761 if (tevent_req_is_unix_error(req, &err)) {
772 * Routines for ctdb_req_header
775 static void header_fix_pnn(struct ctdb_req_header *header,
776 struct ctdbd_context *ctdb)
778 if (header->srcnode == CTDB_CURRENT_NODE) {
779 header->srcnode = ctdb->node_map->pnn;
782 if (header->destnode == CTDB_CURRENT_NODE) {
783 header->destnode = ctdb->node_map->pnn;
787 static struct ctdb_req_header header_reply_control(
788 struct ctdb_req_header *header,
789 struct ctdbd_context *ctdb)
791 struct ctdb_req_header reply_header;
793 reply_header = (struct ctdb_req_header) {
794 .ctdb_magic = CTDB_MAGIC,
795 .ctdb_version = CTDB_PROTOCOL,
796 .generation = ctdb->vnn_map->generation,
797 .operation = CTDB_REPLY_CONTROL,
798 .destnode = header->srcnode,
799 .srcnode = header->destnode,
800 .reqid = header->reqid,
806 static struct ctdb_req_header header_reply_message(
807 struct ctdb_req_header *header,
808 struct ctdbd_context *ctdb)
810 struct ctdb_req_header reply_header;
812 reply_header = (struct ctdb_req_header) {
813 .ctdb_magic = CTDB_MAGIC,
814 .ctdb_version = CTDB_PROTOCOL,
815 .generation = ctdb->vnn_map->generation,
816 .operation = CTDB_REQ_MESSAGE,
817 .destnode = header->srcnode,
818 .srcnode = header->destnode,
829 struct client_state {
830 struct tevent_context *ev;
832 struct ctdbd_context *ctdb;
834 struct comm_context *comm;
835 struct srvid_register_state *rstate;
840 * Send replies to controls and messages
843 static void client_reply_done(struct tevent_req *subreq);
845 static void client_send_message(struct tevent_req *req,
846 struct ctdb_req_header *header,
847 struct ctdb_req_message_data *message)
849 struct client_state *state = tevent_req_data(
850 req, struct client_state);
851 struct ctdbd_context *ctdb = state->ctdb;
852 struct tevent_req *subreq;
853 struct ctdb_req_header reply_header;
855 size_t datalen, buflen;
858 reply_header = header_reply_message(header, ctdb);
860 datalen = ctdb_req_message_data_len(&reply_header, message);
861 ret = ctdb_allocate_pkt(state, datalen, &buf, &buflen);
863 tevent_req_error(req, ret);
867 ret = ctdb_req_message_data_push(&reply_header, message,
870 tevent_req_error(req, ret);
874 DEBUG(DEBUG_INFO, ("message srvid = 0x%"PRIx64"\n", message->srvid));
876 subreq = comm_write_send(state, state->ev, state->comm, buf, buflen);
877 if (tevent_req_nomem(subreq, req)) {
880 tevent_req_set_callback(subreq, client_reply_done, req);
882 talloc_steal(subreq, buf);
885 static void client_send_control(struct tevent_req *req,
886 struct ctdb_req_header *header,
887 struct ctdb_reply_control *reply)
889 struct client_state *state = tevent_req_data(
890 req, struct client_state);
891 struct ctdbd_context *ctdb = state->ctdb;
892 struct tevent_req *subreq;
893 struct ctdb_req_header reply_header;
895 size_t datalen, buflen;
898 reply_header = header_reply_control(header, ctdb);
900 datalen = ctdb_reply_control_len(&reply_header, reply);
901 ret = ctdb_allocate_pkt(state, datalen, &buf, &buflen);
903 tevent_req_error(req, ret);
907 ret = ctdb_reply_control_push(&reply_header, reply, buf, &buflen);
909 tevent_req_error(req, ret);
913 DEBUG(DEBUG_INFO, ("reply opcode = %u\n", reply->rdata.opcode));
915 subreq = comm_write_send(state, state->ev, state->comm, buf, buflen);
916 if (tevent_req_nomem(subreq, req)) {
919 tevent_req_set_callback(subreq, client_reply_done, req);
921 talloc_steal(subreq, buf);
924 static void client_reply_done(struct tevent_req *subreq)
926 struct tevent_req *req = tevent_req_callback_data(
927 subreq, struct tevent_req);
931 status = comm_write_recv(subreq, &ret);
934 tevent_req_error(req, ret);
939 * Handling protocol - controls
942 static void control_process_exists(TALLOC_CTX *mem_ctx,
943 struct tevent_req *req,
944 struct ctdb_req_header *header,
945 struct ctdb_req_control *request)
947 struct ctdb_reply_control reply;
949 reply.rdata.opcode = request->opcode;
950 reply.status = kill(request->rdata.data.pid, 0);
953 client_send_control(req, header, &reply);
956 static void control_ping(TALLOC_CTX *mem_ctx,
957 struct tevent_req *req,
958 struct ctdb_req_header *header,
959 struct ctdb_req_control *request)
961 struct client_state *state = tevent_req_data(
962 req, struct client_state);
963 struct ctdbd_context *ctdb = state->ctdb;
964 struct ctdb_reply_control reply;
966 reply.rdata.opcode = request->opcode;
967 reply.status = ctdb->num_clients;
970 client_send_control(req, header, &reply);
973 static void control_getvnnmap(TALLOC_CTX *mem_ctx,
974 struct tevent_req *req,
975 struct ctdb_req_header *header,
976 struct ctdb_req_control *request)
978 struct client_state *state = tevent_req_data(
979 req, struct client_state);
980 struct ctdbd_context *ctdb = state->ctdb;
981 struct ctdb_reply_control reply;
982 struct ctdb_vnn_map *vnnmap;
984 reply.rdata.opcode = request->opcode;
986 vnnmap = talloc_zero(mem_ctx, struct ctdb_vnn_map);
987 if (vnnmap == NULL) {
988 reply.status = ENOMEM;
989 reply.errmsg = "Memory error";
991 vnnmap->generation = ctdb->vnn_map->generation;
992 vnnmap->size = ctdb->vnn_map->size;
993 vnnmap->map = ctdb->vnn_map->map;
995 reply.rdata.data.vnnmap = vnnmap;
1000 client_send_control(req, header, &reply);
1003 static void control_get_debug(TALLOC_CTX *mem_ctx,
1004 struct tevent_req *req,
1005 struct ctdb_req_header *header,
1006 struct ctdb_req_control *request)
1008 struct client_state *state = tevent_req_data(
1009 req, struct client_state);
1010 struct ctdbd_context *ctdb = state->ctdb;
1011 struct ctdb_reply_control reply;
1013 reply.rdata.opcode = request->opcode;
1014 reply.rdata.data.loglevel = debug_level_to_int(ctdb->log_level);
1016 reply.errmsg = NULL;
1018 client_send_control(req, header, &reply);
1021 static void control_set_debug(TALLOC_CTX *mem_ctx,
1022 struct tevent_req *req,
1023 struct ctdb_req_header *header,
1024 struct ctdb_req_control *request)
1026 struct client_state *state = tevent_req_data(
1027 req, struct client_state);
1028 struct ctdbd_context *ctdb = state->ctdb;
1029 struct ctdb_reply_control reply;
1031 ctdb->log_level = debug_level_from_int(request->rdata.data.loglevel);
1033 reply.rdata.opcode = request->opcode;
1035 reply.errmsg = NULL;
1037 client_send_control(req, header, &reply);
1040 static void control_get_recmode(TALLOC_CTX *mem_ctx,
1041 struct tevent_req *req,
1042 struct ctdb_req_header *header,
1043 struct ctdb_req_control *request)
1045 struct client_state *state = tevent_req_data(
1046 req, struct client_state);
1047 struct ctdbd_context *ctdb = state->ctdb;
1048 struct ctdb_reply_control reply;
1050 reply.rdata.opcode = request->opcode;
1051 reply.status = ctdb->vnn_map->recmode;
1052 reply.errmsg = NULL;
1054 client_send_control(req, header, &reply);
1057 struct set_recmode_state {
1058 struct tevent_req *req;
1059 struct ctdbd_context *ctdb;
1060 struct ctdb_req_header header;
1061 struct ctdb_reply_control reply;
1064 static void set_recmode_callback(struct tevent_req *subreq)
1066 struct set_recmode_state *substate = tevent_req_callback_data(
1067 subreq, struct set_recmode_state);
1071 status = recover_recv(subreq, &ret);
1072 TALLOC_FREE(subreq);
1074 substate->reply.status = ret;
1075 substate->reply.errmsg = "recovery failed";
1077 substate->reply.status = 0;
1078 substate->reply.errmsg = NULL;
1081 client_send_control(substate->req, &substate->header, &substate->reply);
1082 talloc_free(substate);
1085 static void control_set_recmode(TALLOC_CTX *mem_ctx,
1086 struct tevent_req *req,
1087 struct ctdb_req_header *header,
1088 struct ctdb_req_control *request)
1090 struct client_state *state = tevent_req_data(
1091 req, struct client_state);
1092 struct tevent_req *subreq;
1093 struct ctdbd_context *ctdb = state->ctdb;
1094 struct set_recmode_state *substate;
1095 struct ctdb_reply_control reply;
1097 reply.rdata.opcode = request->opcode;
1099 if (request->rdata.data.recmode == CTDB_RECOVERY_NORMAL) {
1101 reply.errmsg = "Client cannot set recmode to NORMAL";
1105 substate = talloc_zero(ctdb, struct set_recmode_state);
1106 if (substate == NULL) {
1108 reply.errmsg = "Memory error";
1112 substate->req = req;
1113 substate->ctdb = ctdb;
1114 substate->header = *header;
1115 substate->reply.rdata.opcode = request->opcode;
1117 subreq = recover_send(substate, state->ev, state->ctdb);
1118 if (subreq == NULL) {
1119 talloc_free(substate);
1122 tevent_req_set_callback(subreq, set_recmode_callback, substate);
1124 ctdb->vnn_map->recmode = CTDB_RECOVERY_ACTIVE;
1128 client_send_control(req, header, &reply);
1132 static int srvid_register_state_destructor(struct srvid_register_state *rstate)
1134 DLIST_REMOVE(rstate->ctdb->rstate, rstate);
1138 static void control_register_srvid(TALLOC_CTX *mem_ctx,
1139 struct tevent_req *req,
1140 struct ctdb_req_header *header,
1141 struct ctdb_req_control *request)
1143 struct client_state *state = tevent_req_data(
1144 req, struct client_state);
1145 struct ctdbd_context *ctdb = state->ctdb;
1146 struct ctdb_reply_control reply;
1147 struct srvid_register_state *rstate;
1149 reply.rdata.opcode = request->opcode;
1151 rstate = talloc_zero(ctdb, struct srvid_register_state);
1152 if (rstate == NULL) {
1154 reply.errmsg = "Memory error";
1157 rstate->ctdb = ctdb;
1158 rstate->srvid = request->srvid;
1160 talloc_set_destructor(rstate, srvid_register_state_destructor);
1162 DLIST_ADD_END(ctdb->rstate, rstate);
1164 DEBUG(DEBUG_INFO, ("Register srvid 0x%"PRIx64"\n", rstate->srvid));
1167 reply.errmsg = NULL;
1170 client_send_control(req, header, &reply);
1173 static void control_deregister_srvid(TALLOC_CTX *mem_ctx,
1174 struct tevent_req *req,
1175 struct ctdb_req_header *header,
1176 struct ctdb_req_control *request)
1178 struct client_state *state = tevent_req_data(
1179 req, struct client_state);
1180 struct ctdbd_context *ctdb = state->ctdb;
1181 struct ctdb_reply_control reply;
1182 struct srvid_register_state *rstate = NULL;
1184 reply.rdata.opcode = request->opcode;
1186 for (rstate = ctdb->rstate; rstate != NULL; rstate = rstate->next) {
1187 if (rstate->srvid == request->srvid) {
1192 if (rstate == NULL) {
1194 reply.errmsg = "srvid not registered";
1198 DEBUG(DEBUG_INFO, ("Deregister srvid 0x%"PRIx64"\n", rstate->srvid));
1199 talloc_free(rstate);
1202 reply.errmsg = NULL;
1204 client_send_control(req, header, &reply);
1208 TALLOC_FREE(rstate);
1209 client_send_control(req, header, &reply);
1212 static void control_get_pid(TALLOC_CTX *mem_ctx,
1213 struct tevent_req *req,
1214 struct ctdb_req_header *header,
1215 struct ctdb_req_control *request)
1217 struct ctdb_reply_control reply;
1219 reply.rdata.opcode = request->opcode;
1220 reply.status = getpid();
1221 reply.errmsg = NULL;
1223 client_send_control(req, header, &reply);
1226 static void control_get_recmaster(TALLOC_CTX *mem_ctx,
1227 struct tevent_req *req,
1228 struct ctdb_req_header *header,
1229 struct ctdb_req_control *request)
1231 struct client_state *state = tevent_req_data(
1232 req, struct client_state);
1233 struct ctdbd_context *ctdb = state->ctdb;
1234 struct ctdb_reply_control reply;
1236 reply.rdata.opcode = request->opcode;
1237 reply.status = ctdb->node_map->recmaster;
1238 reply.errmsg = NULL;
1240 client_send_control(req, header, &reply);
1243 static void control_get_pnn(TALLOC_CTX *mem_ctx,
1244 struct tevent_req *req,
1245 struct ctdb_req_header *header,
1246 struct ctdb_req_control *request)
1248 struct ctdb_reply_control reply;
1250 reply.rdata.opcode = request->opcode;
1251 reply.status = header->destnode;
1252 reply.errmsg = NULL;
1254 client_send_control(req, header, &reply);
1257 static void control_shutdown(TALLOC_CTX *mem_ctx,
1258 struct tevent_req *req,
1259 struct ctdb_req_header *hdr,
1260 struct ctdb_req_control *request)
1262 struct client_state *state = tevent_req_data(
1263 req, struct client_state);
1268 static void control_uptime(TALLOC_CTX *mem_ctx,
1269 struct tevent_req *req,
1270 struct ctdb_req_header *header,
1271 struct ctdb_req_control *request)
1273 struct client_state *state = tevent_req_data(
1274 req, struct client_state);
1275 struct ctdbd_context *ctdb = state->ctdb;
1276 struct ctdb_reply_control reply;
1277 struct ctdb_uptime *uptime;;
1279 reply.rdata.opcode = request->opcode;
1281 uptime = talloc_zero(mem_ctx, struct ctdb_uptime);
1282 if (uptime == NULL) {
1286 uptime->current_time = tevent_timeval_current();
1287 uptime->ctdbd_start_time = ctdb->start_time;
1288 uptime->last_recovery_started = ctdb->recovery_start_time;
1289 uptime->last_recovery_finished = ctdb->recovery_end_time;
1291 reply.rdata.data.uptime = uptime;
1293 reply.errmsg = NULL;
1294 client_send_control(req, header, &reply);
1299 reply.errmsg = "Memory error";
1300 client_send_control(req, header, &reply);
1303 static void control_reload_nodes_file(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;
1312 struct ctdb_node_map *nodemap;
1313 struct node_map *node_map = ctdb->node_map;
1316 reply.rdata.opcode = request->opcode;
1318 nodemap = read_nodes_file(mem_ctx, header->destnode);
1319 if (nodemap == NULL) {
1323 for (i=0; i<nodemap->num; i++) {
1326 if (i < node_map->num_nodes &&
1327 ctdb_sock_addr_same(&nodemap->node[i].addr,
1328 &node_map->node[i].addr)) {
1332 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
1333 node = &node_map->node[i];
1335 node->flags |= NODE_FLAGS_DELETED;
1336 parse_ip("0.0.0.0", NULL, 0, &node->addr);
1341 if (i < node_map->num_nodes &&
1342 node_map->node[i].flags & NODE_FLAGS_DELETED) {
1343 node = &node_map->node[i];
1345 node->flags &= ~NODE_FLAGS_DELETED;
1346 node->addr = nodemap->node[i].addr;
1351 node_map->node = talloc_realloc(node_map, node_map->node,
1353 node_map->num_nodes+1);
1354 if (node_map->node == NULL) {
1357 node = &node_map->node[node_map->num_nodes];
1359 node->addr = nodemap->node[i].addr;
1360 node->pnn = nodemap->node[i].pnn;
1362 node->capabilities = CTDB_CAP_DEFAULT;
1363 node->recovery_disabled = false;
1364 node->recovery_substate = NULL;
1366 node_map->num_nodes += 1;
1369 talloc_free(nodemap);
1372 reply.errmsg = NULL;
1373 client_send_control(req, header, &reply);
1378 reply.errmsg = "Memory error";
1379 client_send_control(req, header, &reply);
1382 static void control_get_capabilities(TALLOC_CTX *mem_ctx,
1383 struct tevent_req *req,
1384 struct ctdb_req_header *header,
1385 struct ctdb_req_control *request)
1387 struct client_state *state = tevent_req_data(
1388 req, struct client_state);
1389 struct ctdbd_context *ctdb = state->ctdb;
1390 struct ctdb_reply_control reply;
1394 reply.rdata.opcode = request->opcode;
1396 node = &ctdb->node_map->node[header->destnode];
1397 caps = node->capabilities;
1399 if (node->flags & NODE_FLAGS_FAKE_TIMEOUT) {
1400 /* Don't send reply */
1404 reply.rdata.data.caps = caps;
1406 reply.errmsg = NULL;
1408 client_send_control(req, header, &reply);
1411 static void control_get_nodemap(TALLOC_CTX *mem_ctx,
1412 struct tevent_req *req,
1413 struct ctdb_req_header *header,
1414 struct ctdb_req_control *request)
1416 struct client_state *state = tevent_req_data(
1417 req, struct client_state);
1418 struct ctdbd_context *ctdb = state->ctdb;
1419 struct ctdb_reply_control reply;
1420 struct ctdb_node_map *nodemap;
1424 reply.rdata.opcode = request->opcode;
1426 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
1427 if (nodemap == NULL) {
1431 nodemap->num = ctdb->node_map->num_nodes;
1432 nodemap->node = talloc_array(nodemap, struct ctdb_node_and_flags,
1434 if (nodemap->node == NULL) {
1438 for (i=0; i<nodemap->num; i++) {
1439 node = &ctdb->node_map->node[i];
1440 nodemap->node[i] = (struct ctdb_node_and_flags) {
1442 .flags = node->flags,
1447 reply.rdata.data.nodemap = nodemap;
1449 reply.errmsg = NULL;
1450 client_send_control(req, header, &reply);
1455 reply.errmsg = "Memory error";
1456 client_send_control(req, header, &reply);
1459 static void control_get_ifaces(TALLOC_CTX *mem_ctx,
1460 struct tevent_req *req,
1461 struct ctdb_req_header *header,
1462 struct ctdb_req_control *request)
1464 struct client_state *state = tevent_req_data(
1465 req, struct client_state);
1466 struct ctdbd_context *ctdb = state->ctdb;
1467 struct ctdb_reply_control reply;
1468 struct ctdb_iface_list *iface_list;
1469 struct interface *iface;
1472 reply.rdata.opcode = request->opcode;
1474 iface_list = talloc_zero(mem_ctx, struct ctdb_iface_list);
1475 if (iface_list == NULL) {
1479 iface_list->num = ctdb->iface_map->num;
1480 iface_list->iface = talloc_array(iface_list, struct ctdb_iface,
1482 if (iface_list->iface == NULL) {
1486 for (i=0; i<iface_list->num; i++) {
1487 iface = &ctdb->iface_map->iface[i];
1488 iface_list->iface[i] = (struct ctdb_iface) {
1489 .link_state = iface->link_up,
1490 .references = iface->references,
1492 strncpy(iface_list->iface[i].name, iface->name,
1496 reply.rdata.data.iface_list = iface_list;
1498 reply.errmsg = NULL;
1499 client_send_control(req, header, &reply);
1504 reply.errmsg = "Memory error";
1505 client_send_control(req, header, &reply);
1508 static void control_get_nodes_file(TALLOC_CTX *mem_ctx,
1509 struct tevent_req *req,
1510 struct ctdb_req_header *header,
1511 struct ctdb_req_control *request)
1513 struct ctdb_reply_control reply;
1514 struct ctdb_node_map *nodemap;
1516 reply.rdata.opcode = request->opcode;
1518 nodemap = read_nodes_file(mem_ctx, header->destnode);
1519 if (nodemap == NULL) {
1523 reply.rdata.data.nodemap = nodemap;
1525 reply.errmsg = NULL;
1526 client_send_control(req, header, &reply);
1531 reply.errmsg = "Failed to read nodes file";
1532 client_send_control(req, header, &reply);
1535 static void control_error(TALLOC_CTX *mem_ctx,
1536 struct tevent_req *req,
1537 struct ctdb_req_header *header,
1538 struct ctdb_req_control *request)
1540 struct ctdb_reply_control reply;
1542 reply.rdata.opcode = request->opcode;
1544 reply.errmsg = "Not implemented";
1546 client_send_control(req, header, &reply);
1550 * Handling protocol - messages
1553 struct disable_recoveries_state {
1557 static void disable_recoveries_callback(struct tevent_req *subreq)
1559 struct disable_recoveries_state *substate = tevent_req_callback_data(
1560 subreq, struct disable_recoveries_state);
1563 status = tevent_wakeup_recv(subreq);
1564 TALLOC_FREE(subreq);
1566 DEBUG(DEBUG_INFO, ("tevent_wakeup_recv failed\n"));
1569 substate->node->recovery_disabled = false;
1570 TALLOC_FREE(substate->node->recovery_substate);
1573 static void message_disable_recoveries(TALLOC_CTX *mem_ctx,
1574 struct tevent_req *req,
1575 struct ctdb_req_header *header,
1576 struct ctdb_req_message *request)
1578 struct client_state *state = tevent_req_data(
1579 req, struct client_state);
1580 struct tevent_req *subreq;
1581 struct ctdbd_context *ctdb = state->ctdb;
1582 struct disable_recoveries_state *substate;
1583 struct ctdb_disable_message *disable = request->data.disable;
1584 struct ctdb_req_message_data reply;
1589 node = &ctdb->node_map->node[header->destnode];
1591 if (disable->timeout == 0) {
1592 TALLOC_FREE(node->recovery_substate);
1593 node->recovery_disabled = false;
1594 DEBUG(DEBUG_INFO, ("Enabled recoveries on node %u\n",
1599 substate = talloc_zero(ctdb->node_map,
1600 struct disable_recoveries_state);
1601 if (substate == NULL) {
1605 substate->node = node;
1607 subreq = tevent_wakeup_send(substate, state->ev,
1608 tevent_timeval_current_ofs(
1609 disable->timeout, 0));
1610 if (subreq == NULL) {
1611 talloc_free(substate);
1614 tevent_req_set_callback(subreq, disable_recoveries_callback, substate);
1616 DEBUG(DEBUG_INFO, ("Disabled recoveries for %d seconds on node %u\n",
1617 disable->timeout, header->destnode));
1618 node->recovery_substate = substate;
1619 node->recovery_disabled = true;
1622 ret = header->destnode;
1625 reply.srvid = disable->srvid;
1626 data.dptr = (uint8_t *)&ret;
1627 data.dsize = sizeof(int);
1630 client_send_message(req, header, &reply);
1634 * Handle a single client
1637 static void client_read_handler(uint8_t *buf, size_t buflen,
1638 void *private_data);
1639 static void client_dead_handler(void *private_data);
1640 static void client_process_packet(struct tevent_req *req,
1641 uint8_t *buf, size_t buflen);
1642 static void client_process_message(struct tevent_req *req,
1643 uint8_t *buf, size_t buflen);
1644 static void client_process_control(struct tevent_req *req,
1645 uint8_t *buf, size_t buflen);
1646 static void client_reply_done(struct tevent_req *subreq);
1648 static struct tevent_req *client_send(TALLOC_CTX *mem_ctx,
1649 struct tevent_context *ev,
1650 int fd, struct ctdbd_context *ctdb,
1653 struct tevent_req *req;
1654 struct client_state *state;
1657 req = tevent_req_create(mem_ctx, &state, struct client_state);
1667 ret = comm_setup(state, ev, fd, client_read_handler, req,
1668 client_dead_handler, req, &state->comm);
1670 tevent_req_error(req, ret);
1671 return tevent_req_post(req, ev);
1674 DEBUG(DEBUG_INFO, ("New client fd=%d\n", fd));
1679 static void client_read_handler(uint8_t *buf, size_t buflen,
1682 struct tevent_req *req = talloc_get_type_abort(
1683 private_data, struct tevent_req);
1684 struct client_state *state = tevent_req_data(
1685 req, struct client_state);
1686 struct ctdbd_context *ctdb = state->ctdb;
1687 struct ctdb_req_header header;
1690 ret = ctdb_req_header_pull(buf, buflen, &header);
1695 if (buflen != header.length) {
1699 ret = ctdb_req_header_verify(&header, 0);
1704 header_fix_pnn(&header, ctdb);
1706 if (header.destnode == CTDB_BROADCAST_ALL) {
1707 for (i=0; i<ctdb->node_map->num_nodes; i++) {
1708 header.destnode = i;
1710 ctdb_req_header_push(&header, buf);
1711 client_process_packet(req, buf, buflen);
1716 if (header.destnode == CTDB_BROADCAST_CONNECTED) {
1717 for (i=0; i<ctdb->node_map->num_nodes; i++) {
1718 if (ctdb->node_map->node[i].flags &
1719 NODE_FLAGS_DISCONNECTED) {
1723 header.destnode = i;
1725 ctdb_req_header_push(&header, buf);
1726 client_process_packet(req, buf, buflen);
1731 if (header.destnode > ctdb->node_map->num_nodes) {
1732 fprintf(stderr, "Invalid destination pnn 0x%x\n",
1738 if (ctdb->node_map->node[header.destnode].flags & NODE_FLAGS_DISCONNECTED) {
1739 fprintf(stderr, "Packet for disconnected node pnn %u\n",
1744 ctdb_req_header_push(&header, buf);
1745 client_process_packet(req, buf, buflen);
1748 static void client_dead_handler(void *private_data)
1750 struct tevent_req *req = talloc_get_type_abort(
1751 private_data, struct tevent_req);
1753 tevent_req_done(req);
1756 static void client_process_packet(struct tevent_req *req,
1757 uint8_t *buf, size_t buflen)
1759 struct ctdb_req_header header;
1762 ret = ctdb_req_header_pull(buf, buflen, &header);
1767 switch (header.operation) {
1768 case CTDB_REQ_MESSAGE:
1769 client_process_message(req, buf, buflen);
1772 case CTDB_REQ_CONTROL:
1773 client_process_control(req, buf, buflen);
1781 static void client_process_message(struct tevent_req *req,
1782 uint8_t *buf, size_t buflen)
1784 struct client_state *state = tevent_req_data(
1785 req, struct client_state);
1786 struct ctdbd_context *ctdb = state->ctdb;
1787 TALLOC_CTX *mem_ctx;
1788 struct ctdb_req_header header;
1789 struct ctdb_req_message request;
1793 mem_ctx = talloc_new(state);
1794 if (tevent_req_nomem(mem_ctx, req)) {
1798 ret = ctdb_req_message_pull(buf, buflen, &header, mem_ctx, &request);
1800 talloc_free(mem_ctx);
1801 tevent_req_error(req, ret);
1805 header_fix_pnn(&header, ctdb);
1807 if (header.destnode >= ctdb->node_map->num_nodes) {
1808 /* Many messages are not replied to, so just behave as
1809 * though this message was not received */
1810 fprintf(stderr, "Invalid node %d\n", header.destnode);
1811 talloc_free(mem_ctx);
1815 srvid = request.srvid;
1816 DEBUG(DEBUG_INFO, ("request srvid = 0x%"PRIx64"\n", srvid));
1818 if (srvid == CTDB_SRVID_DISABLE_RECOVERIES) {
1819 message_disable_recoveries(mem_ctx, req, &header, &request);
1823 talloc_free(mem_ctx);
1826 static void client_process_control(struct tevent_req *req,
1827 uint8_t *buf, size_t buflen)
1829 struct client_state *state = tevent_req_data(
1830 req, struct client_state);
1831 struct ctdbd_context *ctdb = state->ctdb;
1832 TALLOC_CTX *mem_ctx;
1833 struct ctdb_req_header header;
1834 struct ctdb_req_control request;
1837 mem_ctx = talloc_new(state);
1838 if (tevent_req_nomem(mem_ctx, req)) {
1842 ret = ctdb_req_control_pull(buf, buflen, &header, mem_ctx, &request);
1844 talloc_free(mem_ctx);
1845 tevent_req_error(req, ret);
1849 header_fix_pnn(&header, ctdb);
1851 if (header.destnode >= ctdb->node_map->num_nodes) {
1852 struct ctdb_reply_control reply;
1854 reply.rdata.opcode = request.opcode;
1855 reply.errmsg = "Invalid node";
1857 client_send_control(req, &header, &reply);
1861 DEBUG(DEBUG_INFO, ("request opcode = %u, reqid = %u\n",
1862 request.opcode, header.reqid));
1864 switch (request.opcode) {
1865 case CTDB_CONTROL_PROCESS_EXISTS:
1866 control_process_exists(mem_ctx, req, &header, &request);
1869 case CTDB_CONTROL_PING:
1870 control_ping(mem_ctx, req, &header, &request);
1873 case CTDB_CONTROL_GETVNNMAP:
1874 control_getvnnmap(mem_ctx, req, &header, &request);
1877 case CTDB_CONTROL_GET_DEBUG:
1878 control_get_debug(mem_ctx, req, &header, &request);
1881 case CTDB_CONTROL_SET_DEBUG:
1882 control_set_debug(mem_ctx, req, &header, &request);
1885 case CTDB_CONTROL_GET_RECMODE:
1886 control_get_recmode(mem_ctx, req, &header, &request);
1889 case CTDB_CONTROL_SET_RECMODE:
1890 control_set_recmode(mem_ctx, req, &header, &request);
1893 case CTDB_CONTROL_REGISTER_SRVID:
1894 control_register_srvid(mem_ctx, req, &header, &request);
1897 case CTDB_CONTROL_DEREGISTER_SRVID:
1898 control_deregister_srvid(mem_ctx, req, &header, &request);
1901 case CTDB_CONTROL_GET_PID:
1902 control_get_pid(mem_ctx, req, &header, &request);
1905 case CTDB_CONTROL_GET_RECMASTER:
1906 control_get_recmaster(mem_ctx, req, &header, &request);
1909 case CTDB_CONTROL_GET_PNN:
1910 control_get_pnn(mem_ctx, req, &header, &request);
1913 case CTDB_CONTROL_SHUTDOWN:
1914 control_shutdown(mem_ctx, req, &header, &request);
1917 case CTDB_CONTROL_UPTIME:
1918 control_uptime(mem_ctx, req, &header, &request);
1921 case CTDB_CONTROL_RELOAD_NODES_FILE:
1922 control_reload_nodes_file(mem_ctx, req, &header, &request);
1925 case CTDB_CONTROL_GET_CAPABILITIES:
1926 control_get_capabilities(mem_ctx, req, &header, &request);
1929 case CTDB_CONTROL_GET_NODEMAP:
1930 control_get_nodemap(mem_ctx, req, &header, &request);
1933 case CTDB_CONTROL_GET_IFACES:
1934 control_get_ifaces(mem_ctx, req, &header, &request);
1937 case CTDB_CONTROL_GET_NODES_FILE:
1938 control_get_nodes_file(mem_ctx, req, &header, &request);
1942 if (! (request.flags & CTDB_CTRL_FLAG_NOREPLY)) {
1943 control_error(mem_ctx, req, &header, &request);
1948 talloc_free(mem_ctx);
1951 static int client_recv(struct tevent_req *req, int *perr)
1953 struct client_state *state = tevent_req_data(
1954 req, struct client_state);
1957 DEBUG(DEBUG_INFO, ("Client done fd=%d\n", state->fd));
1960 if (tevent_req_is_unix_error(req, &err)) {
1967 return state->status;
1974 struct server_state {
1975 struct tevent_context *ev;
1976 struct ctdbd_context *ctdb;
1980 static void server_new_client(struct tevent_req *subreq);
1981 static void server_client_done(struct tevent_req *subreq);
1983 static struct tevent_req *server_send(TALLOC_CTX *mem_ctx,
1984 struct tevent_context *ev,
1985 struct ctdbd_context *ctdb,
1988 struct tevent_req *req, *subreq;
1989 struct server_state *state;
1991 req = tevent_req_create(mem_ctx, &state, struct server_state);
2000 subreq = accept_send(state, ev, fd);
2001 if (tevent_req_nomem(subreq, req)) {
2002 return tevent_req_post(req, ev);
2004 tevent_req_set_callback(subreq, server_new_client, req);
2009 static void server_new_client(struct tevent_req *subreq)
2011 struct tevent_req *req = tevent_req_callback_data(
2012 subreq, struct tevent_req);
2013 struct server_state *state = tevent_req_data(
2014 req, struct server_state);
2015 struct ctdbd_context *ctdb = state->ctdb;
2019 client_fd = accept_recv(subreq, NULL, NULL, &ret);
2020 TALLOC_FREE(subreq);
2021 if (client_fd == -1) {
2022 tevent_req_error(req, ret);
2026 subreq = client_send(state, state->ev, client_fd,
2027 ctdb, ctdb->node_map->pnn);
2028 if (tevent_req_nomem(subreq, req)) {
2031 tevent_req_set_callback(subreq, server_client_done, req);
2033 ctdb->num_clients += 1;
2035 subreq = accept_send(state, state->ev, state->fd);
2036 if (tevent_req_nomem(subreq, req)) {
2039 tevent_req_set_callback(subreq, server_new_client, req);
2042 static void server_client_done(struct tevent_req *subreq)
2044 struct tevent_req *req = tevent_req_callback_data(
2045 subreq, struct tevent_req);
2046 struct server_state *state = tevent_req_data(
2047 req, struct server_state);
2048 struct ctdbd_context *ctdb = state->ctdb;
2052 status = client_recv(subreq, &ret);
2053 TALLOC_FREE(subreq);
2055 tevent_req_error(req, ret);
2059 ctdb->num_clients -= 1;
2062 /* Special status, to shutdown server */
2063 DEBUG(DEBUG_INFO, ("Shutting down server\n"));
2064 tevent_req_done(req);
2068 static bool server_recv(struct tevent_req *req, int *perr)
2072 if (tevent_req_is_unix_error(req, &err)) {
2085 static int socket_init(const char *sockpath)
2087 struct sockaddr_un addr;
2091 memset(&addr, 0, sizeof(addr));
2092 addr.sun_family = AF_UNIX;
2094 len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
2095 if (len >= sizeof(addr.sun_path)) {
2096 fprintf(stderr, "path too long: %s\n", sockpath);
2100 fd = socket(AF_UNIX, SOCK_STREAM, 0);
2102 fprintf(stderr, "socket failed - %s\n", sockpath);
2106 ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
2108 fprintf(stderr, "bind failed - %s\n", sockpath);
2112 ret = listen(fd, 10);
2114 fprintf(stderr, "listen failed\n");
2118 DEBUG(DEBUG_INFO, ("Socket init done\n"));
2129 static struct options {
2130 const char *sockpath;
2131 const char *pidfile;
2132 const char *debuglevel;
2135 static struct poptOption cmdline_options[] = {
2136 { "socket", 's', POPT_ARG_STRING, &options.sockpath, 0,
2137 "Unix domain socket path", "filename" },
2138 { "pidfile", 'p', POPT_ARG_STRING, &options.pidfile, 0,
2139 "pid file", "filename" } ,
2140 { "debug", 'd', POPT_ARG_STRING, &options.debuglevel, 0,
2141 "debug level", "ERR|WARNING|NOTICE|INFO|DEBUG" } ,
2144 static void cleanup(void)
2146 unlink(options.sockpath);
2147 unlink(options.pidfile);
2150 static void signal_handler(int sig)
2156 static void start_server(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2157 struct ctdbd_context *ctdb, int fd, int pfd)
2159 struct tevent_req *req;
2164 signal(SIGTERM, signal_handler);
2166 req = server_send(mem_ctx, ev, ctdb, fd);
2168 fprintf(stderr, "Memory error\n");
2172 len = write(pfd, &ret, sizeof(ret));
2173 if (len != sizeof(ret)) {
2174 fprintf(stderr, "Failed to send message to parent\n");
2179 tevent_req_poll(req, ev);
2181 server_recv(req, &ret);
2187 int main(int argc, const char *argv[])
2189 TALLOC_CTX *mem_ctx;
2190 struct ctdbd_context *ctdb;
2191 struct tevent_context *ev;
2192 enum debug_level debug_level;
2194 int opt, fd, ret, pfd[2];
2199 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
2200 POPT_CONTEXT_KEEP_FIRST);
2201 while ((opt = poptGetNextOpt(pc)) != -1) {
2202 fprintf(stderr, "Invalid option %s\n", poptBadOption(pc, 0));
2206 if (options.sockpath == NULL) {
2207 fprintf(stderr, "Please specify socket path\n");
2208 poptPrintHelp(pc, stdout, 0);
2212 if (options.pidfile == NULL) {
2213 fprintf(stderr, "Please specify pid file\n");
2214 poptPrintHelp(pc, stdout, 0);
2218 if (options.debuglevel == NULL) {
2219 DEBUGLEVEL = debug_level_to_int(DEBUG_ERR);
2221 if (debug_level_parse(options.debuglevel, &debug_level)) {
2222 DEBUGLEVEL = debug_level_to_int(debug_level);
2224 fprintf(stderr, "Invalid debug level\n");
2225 poptPrintHelp(pc, stdout, 0);
2230 mem_ctx = talloc_new(NULL);
2231 if (mem_ctx == NULL) {
2232 fprintf(stderr, "Memory error\n");
2236 ctdb = ctdbd_setup(mem_ctx);
2241 if (! ctdbd_verify(ctdb)) {
2245 ev = tevent_context_init(mem_ctx);
2247 fprintf(stderr, "Memory error\n");
2251 fd = socket_init(options.sockpath);
2258 fprintf(stderr, "Failed to create pipe\n");
2265 fprintf(stderr, "Failed to fork\n");
2273 start_server(mem_ctx, ev, ctdb, fd, pfd[1]);
2280 len = read(pfd[0], &ret, sizeof(ret));
2282 if (len != sizeof(ret)) {
2283 fprintf(stderr, "len = %zi\n", len);
2284 fprintf(stderr, "Failed to get message from child\n");
2289 fp = fopen(options.pidfile, "w");
2291 fprintf(stderr, "Failed to open pid file %s\n",
2296 fprintf(fp, "%d\n", pid);