1 /*
2    Dummy CTDB client for testing
3 
4    Copyright (C) Amitay Isaacs  2017
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "replace.h"
21 #include "system/network.h"
22 
23 #include <popt.h>
24 #include <talloc.h>
25 #include <tevent.h>
26 
27 #include "common/logging.h"
28 #include "common/path.h"
29 
30 #include "client/client.h"
31 
32 static struct {
33 	const char *sockpath;
34 	const char *debuglevel;
35 	int num_connections;
36 	int timelimit;
37 	const char *srvidstr;
38 } options;
39 
40 static struct poptOption cmdline_options[] = {
41 	POPT_AUTOHELP
42 	{ "socket", 's', POPT_ARG_STRING, &options.sockpath, 0,
43 		"Unix domain socket path", "filename" },
44 	{ "debug", 'd', POPT_ARG_STRING, &options.debuglevel, 0,
45 		"debug level", "ERR|WARNING|NOTICE|INFO|DEBUG" } ,
46 	{ "nconn", 'n', POPT_ARG_INT, &options.num_connections, 0,
47 		"number of connections", "" },
48 	{ "timelimit", 't', POPT_ARG_INT, &options.timelimit, 0,
49 		"time limit", "seconds" },
50 	{ "srvid", 'S', POPT_ARG_STRING, &options.srvidstr, 0,
51 		"srvid to register", "srvid" },
52 	POPT_TABLEEND
53 };
54 
55 static void dummy_handler(uint64_t srvid, TDB_DATA data, void *private_data)
56 {
57 	bool *done = (bool *)private_data;
58 
59 	*done = true;
60 }
61 
62 int main(int argc, const char *argv[])
63 {
64 	TALLOC_CTX *mem_ctx;
65 	struct tevent_context *ev;
66 	struct ctdb_client_context **client;
67 	struct ctdb_client_context *last_client;
68 	poptContext pc;
69 	int opt, ret, i;
70 	int log_level;
71 	bool status, done;
72 
73 	/* Set default options */
74 	options.sockpath = NULL;
75 	options.debuglevel = "ERR";
76 	options.num_connections = 1;
db_test_get_lmaster(TALLOC_CTX * mem_ctx,int argc,const char ** argv,void * private_data)77 	options.timelimit = 60;
78 	options.srvidstr = NULL;
79 
80 	pc = poptGetContext(argv[0], argc, argv, cmdline_options,
81 			    POPT_CONTEXT_KEEP_FIRST);
82 	while ((opt = poptGetNextOpt(pc)) != -1) {
83 		fprintf(stderr, "Invalid option %s\n", poptBadOption(pc, 0));
84 		exit(1);
85 	}
86 
87 	mem_ctx = talloc_new(NULL);
88 	if (mem_ctx == NULL) {
89 		fprintf(stderr, "Memory allocation error\n");
90 		exit(1);
91 	}
92 
93 	ev = tevent_context_init(mem_ctx);
94 	if (ev == NULL) {
95 		fprintf(stderr, "Memory allocation error\n");
96 		exit(1);
97 	}
98 
99 	status = debug_level_parse(options.debuglevel, &log_level);
100 	if (! status) {
101 		fprintf(stderr, "Invalid debug level\n");
102 		poptPrintHelp(pc, stdout, 0);
103 		exit(1);
104 	}
105 
106 	setup_logging("dummy_client", DEBUG_STDERR);
107 	debuglevel_set(log_level);
108 
109 	if (options.sockpath == NULL) {
110 		options.sockpath = path_socket(mem_ctx, "ctdbd");
111 		if (options.sockpath == NULL) {
112 			D_ERR("Memory allocation error\n");
113 			exit(1);
114 		}
115 	}
116 
117 	client = talloc_array(mem_ctx, struct ctdb_client_context *,
db_find(TALLOC_CTX * mem_ctx,struct db_test_tool_context * ctx,struct ctdb_dbid_map * dbmap,const char * db_name)118 			      options.num_connections);
119 	if (client == NULL) {
120 		fprintf(stderr, "Memory allocation error\n");
121 		exit(1);
122 	}
123 
124 	for (i=0; i<options.num_connections; i++) {
125 		ret = ctdb_client_init(client, ev, options.sockpath,
126 				       &client[i]);
127 		if (ret != 0) {
128 			D_ERR("Failed to initialize client %d, ret=%d\n",
129 			      i, ret);
130 			exit(1);
131 		}
132 	}
133 
134 	last_client = client[options.num_connections-1];
135 
136 	done = false;
137 	if (options.srvidstr != NULL) {
138 		uint64_t srvid;
139 
140 		srvid = strtoull(options.srvidstr, NULL, 0);
141 
142 		ret = ctdb_client_set_message_handler(ev, last_client, srvid,
143 						      dummy_handler, &done);
144 		if (ret != 0) {
145 			D_ERR("Failed to register srvid, ret=%d\n", ret);
146 			talloc_free(client);
147 			exit(1);
148 		}
149 
db_exists(TALLOC_CTX * mem_ctx,struct db_test_tool_context * ctx,const char * db_arg,uint32_t * db_id,const char ** db_name,uint8_t * db_flags)150 		D_INFO("Registered SRVID 0x%"PRIx64"\n", srvid);
151 	}
152 
153 	ret = ctdb_client_wait_timeout(ev, &done,
154 			tevent_timeval_current_ofs(options.timelimit, 0));
155 	if (ret != 0 && ret == ETIMEDOUT) {
156 		D_ERR("client_wait_timeout() failed, ret=%d\n", ret);
157 		talloc_free(client);
158 		exit(1);
159 	}
160 
161 	talloc_free(mem_ctx);
162 	exit(0);
163 }
164