1 /*
2    protocol tests
3 
4    Copyright (C) Amitay Isaacs  2015
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 <assert.h>
21 
22 #include "protocol/protocol_basic.c"
23 #include "protocol/protocol_types.c"
24 #include "protocol/protocol_header.c"
25 #include "protocol/protocol_call.c"
26 #include "protocol/protocol_control.c"
27 #include "protocol/protocol_message.c"
28 #include "protocol/protocol_keepalive.c"
29 #include "protocol/protocol_tunnel.c"
30 #include "protocol/protocol_packet.c"
31 
32 #include "tests/src/protocol_common.h"
33 #include "tests/src/protocol_common_ctdb.h"
34 
35 /*
36  * Functions to test marshalling
37  */
38 
39 /* for ctdb_req_header */
40 #define PROTOCOL_CTDB1_TEST(TYPE, NAME) \
41 static void TEST_FUNC(NAME)(void) \
42 { \
43 	TALLOC_CTX *mem_ctx; \
44 	TYPE c1, c2; \
45 	uint8_t *pkt; \
46 	size_t pkt_len, buflen, np; \
47 	int ret; \
48 \
49 	printf("%s\n", #NAME); \
50 	fflush(stdout); \
51 	mem_ctx = talloc_new(NULL); \
52 	assert(mem_ctx != NULL); \
53 	FILL_FUNC(NAME)(&c1); \
54 	buflen = LEN_FUNC(NAME)(&c1); \
55 	ret = ctdb_allocate_pkt(mem_ctx, buflen, &pkt, &pkt_len); \
56 	assert(ret == 0); \
57 	assert(pkt != NULL); \
58 	assert(pkt_len >= buflen); \
59 	np = 0; \
60 	PUSH_FUNC(NAME)(&c1, pkt, &np); \
61 	assert(np == buflen); \
62 	np = 0; \
63 	ret = PULL_FUNC(NAME)(pkt, pkt_len, &c2, &np); \
64 	assert(ret == 0); \
65 	assert(np == buflen); \
66 	VERIFY_FUNC(NAME)(&c1, &c2); \
67 	talloc_free(mem_ctx); \
68 }
69 
70 /* for ctdb_req_control_data, ctdb_reply_control_data */
71 #define PROTOCOL_CTDB2_TEST(TYPE, NAME) \
72 static void TEST_FUNC(NAME)(uint32_t opcode) \
73 { \
74 	TALLOC_CTX *mem_ctx; \
75 	TYPE c1, c2; \
76 	uint8_t *pkt; \
77 	size_t pkt_len, buflen, np; \
78 	int ret; \
79 \
80 	printf("%s %u\n", #NAME, opcode); \
81 	fflush(stdout); \
82 	mem_ctx = talloc_new(NULL); \
83 	assert(mem_ctx != NULL); \
84 	FILL_FUNC(NAME)(mem_ctx, &c1, opcode); \
85 	buflen = LEN_FUNC(NAME)(&c1); \
86 	ret = ctdb_allocate_pkt(mem_ctx, buflen, &pkt, &pkt_len); \
87 	assert(ret == 0); \
88 	assert(pkt != NULL); \
89 	assert(pkt_len >= buflen); \
90 	np = 0; \
91 	PUSH_FUNC(NAME)(&c1, pkt, &np); \
92 	assert(np == buflen); \
93 	np = 0; \
94 	ret = PULL_FUNC(NAME)(pkt, pkt_len, opcode, mem_ctx, &c2, &np); \
95 	assert(ret == 0); \
96 	assert(np == buflen); \
97 	VERIFY_FUNC(NAME)(&c1, &c2); \
98 	talloc_free(mem_ctx); \
99 }
100 
101 /* for ctdb_message_data */
102 #define PROTOCOL_CTDB3_TEST(TYPE, NAME) \
103 static void TEST_FUNC(NAME)(uint64_t srvid) \
104 { \
105 	TALLOC_CTX *mem_ctx; \
106 	TYPE c1, c2; \
107 	uint8_t *pkt; \
108 	size_t pkt_len, buflen, np; \
109 	int ret; \
110 \
111 	printf("%s %"PRIx64"\n", #NAME, srvid); \
112 	fflush(stdout); \
113 	mem_ctx = talloc_new(NULL); \
114 	assert(mem_ctx != NULL); \
115 	FILL_FUNC(NAME)(mem_ctx, &c1, srvid); \
116 	buflen = LEN_FUNC(NAME)(&c1, srvid); \
117 	ret = ctdb_allocate_pkt(mem_ctx, buflen, &pkt, &pkt_len); \
118 	assert(ret == 0); \
119 	assert(pkt != NULL); \
120 	assert(pkt_len >= buflen); \
121 	np = 0; \
122 	PUSH_FUNC(NAME)(&c1, srvid, pkt, &np); \
123 	assert(np == buflen); \
124 	np = 0; \
125 	ret = PULL_FUNC(NAME)(pkt, pkt_len, srvid, mem_ctx, &c2, &np); \
126 	assert(ret == 0); \
127 	assert(np == buflen); \
128 	VERIFY_FUNC(NAME)(&c1, &c2, srvid); \
129 	talloc_free(mem_ctx); \
130 }
131 
132 /* for ctdb_req_call, ctdb_reply_call, etc. */
133 #define PROTOCOL_CTDB4_TEST(TYPE, NAME, OPER) \
134 static void TEST_FUNC(NAME)(void) \
135 { \
136 	TALLOC_CTX *mem_ctx; \
137 	struct ctdb_req_header h1, h2; \
138 	TYPE c1, c2; \
139 	uint8_t *pkt; \
140 	size_t pkt_len, buflen, len; \
141 	int ret; \
142 \
143 	printf("%s\n", #NAME); \
144 	fflush(stdout); \
145 	mem_ctx = talloc_new(NULL); \
146 	assert(mem_ctx != NULL); \
147 	fill_ctdb_req_header(&h1); \
148 	FILL_FUNC(NAME)(mem_ctx, &c1); \
149 	buflen = LEN_FUNC(NAME)(&h1, &c1); \
150 	ret = ctdb_allocate_pkt(mem_ctx, buflen, &pkt, &pkt_len); \
151 	assert(ret == 0); \
152 	assert(pkt != NULL); \
153 	assert(pkt_len >= buflen); \
154 	len = 0; \
155 	ret = PUSH_FUNC(NAME)(&h1, &c1, pkt, &len); \
156 	assert(ret == EMSGSIZE); \
157 	assert(len == buflen); \
158 	ret = PUSH_FUNC(NAME)(&h1, &c1, pkt, &pkt_len); \
159 	assert(ret == 0); \
160 	ret = PULL_FUNC(NAME)(pkt, pkt_len, &h2, mem_ctx, &c2); \
161 	assert(ret == 0); \
162 	verify_ctdb_req_header(&h1, &h2); \
163 	assert(h2.length == pkt_len); \
164 	VERIFY_FUNC(NAME)(&c1, &c2); \
165 	talloc_free(mem_ctx); \
166 }
167 
168 /* for ctdb_req_control */
169 #define PROTOCOL_CTDB5_TEST(TYPE, NAME, OPER) \
170 static void TEST_FUNC(NAME)(uint32_t opcode) \
171 { \
172 	TALLOC_CTX *mem_ctx; \
173 	struct ctdb_req_header h1, h2; \
174 	TYPE c1, c2; \
175 	uint8_t *pkt; \
176 	size_t pkt_len, buflen, len; \
177 	int ret; \
178 \
179 	printf("%s %u\n", #NAME, opcode); \
180 	fflush(stdout); \
181 	mem_ctx = talloc_new(NULL); \
182 	assert(mem_ctx != NULL); \
183 	fill_ctdb_req_header(&h1); \
184 	FILL_FUNC(NAME)(mem_ctx, &c1, opcode); \
185 	buflen = LEN_FUNC(NAME)(&h1, &c1); \
186 	ret = ctdb_allocate_pkt(mem_ctx, buflen, &pkt, &pkt_len); \
187 	assert(ret == 0); \
188 	assert(pkt != NULL); \
189 	assert(pkt_len >= buflen); \
190 	len = 0; \
191 	ret = PUSH_FUNC(NAME)(&h1, &c1, pkt, &len); \
192 	assert(ret == EMSGSIZE); \
193 	assert(len == buflen); \
194 	ret = PUSH_FUNC(NAME)(&h1, &c1, pkt, &pkt_len); \
195 	assert(ret == 0); \
196 	ret = PULL_FUNC(NAME)(pkt, pkt_len, &h2, mem_ctx, &c2); \
197 	assert(ret == 0); \
198 	verify_ctdb_req_header(&h1, &h2); \
199 	assert(h2.length == pkt_len); \
200 	VERIFY_FUNC(NAME)(&c1, &c2); \
201 	talloc_free(mem_ctx); \
202 }
203 
204 /* for ctdb_reply_control */
205 #define PROTOCOL_CTDB6_TEST(TYPE, NAME, OPER) \
206 static void TEST_FUNC(NAME)(uint32_t opcode) \
207 { \
208 	TALLOC_CTX *mem_ctx; \
209 	struct ctdb_req_header h1, h2; \
210 	TYPE c1, c2; \
211 	uint8_t *pkt; \
212 	size_t pkt_len, buflen, len; \
ctdb_req_header_len_old(struct ctdb_req_header * in)213 	int ret; \
214 \
215 	printf("%s %u\n", #NAME, opcode); \
216 	fflush(stdout); \
217 	mem_ctx = talloc_new(NULL); \
ctdb_req_header_push_old(struct ctdb_req_header * in,uint8_t * buf)218 	assert(mem_ctx != NULL); \
219 	fill_ctdb_req_header(&h1); \
220 	FILL_FUNC(NAME)(mem_ctx, &c1, opcode); \
221 	buflen = LEN_FUNC(NAME)(&h1, &c1); \
222 	ret = ctdb_allocate_pkt(mem_ctx, buflen, &pkt, &pkt_len); \
ctdb_req_header_pull_old(uint8_t * buf,size_t buflen,struct ctdb_req_header * out)223 	assert(ret == 0); \
224 	assert(pkt != NULL); \
225 	assert(pkt_len >= buflen); \
226 	len = 0; \
227 	ret = PUSH_FUNC(NAME)(&h1, &c1, pkt, &len); \
228 	assert(ret == EMSGSIZE); \
229 	assert(len == buflen); \
230 	ret = PUSH_FUNC(NAME)(&h1, &c1, pkt, &pkt_len); \
231 	assert(ret == 0); \
232 	ret = PULL_FUNC(NAME)(pkt, pkt_len, opcode, &h2, mem_ctx, &c2); \
233 	assert(ret == 0); \
234 	verify_ctdb_req_header(&h1, &h2); \
235 	assert(h2.length == pkt_len); \
236 	VERIFY_FUNC(NAME)(&c1, &c2); \
237 	talloc_free(mem_ctx); \
238 }
239 
240 /* for ctdb_req_message */
241 #define PROTOCOL_CTDB7_TEST(TYPE, NAME, OPER) \
242 static void TEST_FUNC(NAME)(uint64_t srvid) \
243 { \
244 	TALLOC_CTX *mem_ctx; \
ctdb_req_call_len_old(struct ctdb_req_header * h,struct ctdb_req_call * c)245 	struct ctdb_req_header h1, h2; \
246 	TYPE c1, c2; \
247 	uint8_t *pkt; \
248 	size_t pkt_len, buflen, len; \
249 	int ret; \
250 \
251 	printf("%s %"PRIx64"\n", #NAME, srvid); \
252 	fflush(stdout); \
ctdb_req_call_push_old(struct ctdb_req_header * h,struct ctdb_req_call * c,uint8_t * buf,size_t * buflen)253 	mem_ctx = talloc_new(NULL); \
254 	assert(mem_ctx != NULL); \
255 	fill_ctdb_req_header(&h1); \
256 	FILL_FUNC(NAME)(mem_ctx, &c1, srvid); \
257 	buflen = LEN_FUNC(NAME)(&h1, &c1); \
258 	ret = ctdb_allocate_pkt(mem_ctx, buflen, &pkt, &pkt_len); \
259 	assert(ret == 0); \
260 	assert(pkt != NULL); \
261 	assert(pkt_len >= buflen); \
262 	len = 0; \
263 	ret = PUSH_FUNC(NAME)(&h1, &c1, pkt, &len); \
264 	assert(ret == EMSGSIZE); \
265 	assert(len == buflen); \
266 	ret = PUSH_FUNC(NAME)(&h1, &c1, pkt, &pkt_len); \
267 	assert(ret == 0); \
268 	ret = PULL_FUNC(NAME)(pkt, pkt_len, &h2, mem_ctx, &c2); \
269 	assert(ret == 0); \
270 	verify_ctdb_req_header(&h1, &h2); \
271 	assert(h2.length == pkt_len); \
272 	VERIFY_FUNC(NAME)(&c1, &c2); \
273 	talloc_free(mem_ctx); \
274 }
275 
276 PROTOCOL_CTDB1_TEST(struct ctdb_req_header, ctdb_req_header);
277 
278 PROTOCOL_CTDB4_TEST(struct ctdb_req_call, ctdb_req_call, CTDB_REQ_CALL);
279 PROTOCOL_CTDB4_TEST(struct ctdb_reply_call, ctdb_reply_call, CTDB_REPLY_CALL);
280 PROTOCOL_CTDB4_TEST(struct ctdb_reply_error, ctdb_reply_error,
281 			CTDB_REPLY_ERROR);
282 PROTOCOL_CTDB4_TEST(struct ctdb_req_dmaster, ctdb_req_dmaster,
283 			CTDB_REQ_DMASTER);
284 PROTOCOL_CTDB4_TEST(struct ctdb_reply_dmaster, ctdb_reply_dmaster,
285 			CTDB_REPLY_DMASTER);
ctdb_req_call_pull_old(uint8_t * buf,size_t buflen,struct ctdb_req_header * h,TALLOC_CTX * mem_ctx,struct ctdb_req_call * c)286 
287 #define NUM_CONTROLS	156
288 
289 PROTOCOL_CTDB2_TEST(struct ctdb_req_control_data, ctdb_req_control_data);
290 PROTOCOL_CTDB2_TEST(struct ctdb_reply_control_data, ctdb_reply_control_data);
291 
292 PROTOCOL_CTDB5_TEST(struct ctdb_req_control, ctdb_req_control,
293 			CTDB_REQ_CONTROL);
294 PROTOCOL_CTDB6_TEST(struct ctdb_reply_control, ctdb_reply_control,
295 			CTDB_REPLY_CONTROL);
296 
297 PROTOCOL_CTDB3_TEST(union ctdb_message_data, ctdb_message_data);
298 PROTOCOL_CTDB7_TEST(struct ctdb_req_message, ctdb_req_message,
299 			CTDB_REQ_MESSAGE);
300 PROTOCOL_CTDB4_TEST(struct ctdb_req_message_data, ctdb_req_message_data,
301 			CTDB_REQ_MESSAGE);
302 
303 PROTOCOL_CTDB4_TEST(struct ctdb_req_keepalive, ctdb_req_keepalive,
304 			CTDB_REQ_KEEPALIVE);
305 PROTOCOL_CTDB4_TEST(struct ctdb_req_tunnel, ctdb_req_tunnel, CTDB_REQ_TUNNEL);
306 
307 int main(int argc, char *argv[])
308 {
309 	uint32_t opcode;
310 	uint64_t test_srvid[] = {
311 		CTDB_SRVID_BANNING,
312 		CTDB_SRVID_ELECTION,
313 		CTDB_SRVID_RECONFIGURE,
314 		CTDB_SRVID_RELEASE_IP,
315 		CTDB_SRVID_TAKE_IP,
316 		CTDB_SRVID_SET_NODE_FLAGS,
317 		CTDB_SRVID_RECD_UPDATE_IP,
318 		CTDB_SRVID_VACUUM_FETCH,
319 		CTDB_SRVID_DETACH_DATABASE,
320 		CTDB_SRVID_MEM_DUMP,
321 		CTDB_SRVID_GETLOG,
322 		CTDB_SRVID_CLEARLOG,
323 		CTDB_SRVID_PUSH_NODE_FLAGS,
324 		CTDB_SRVID_RELOAD_NODES,
325 		CTDB_SRVID_TAKEOVER_RUN,
326 		CTDB_SRVID_REBALANCE_NODE,
327 		CTDB_SRVID_DISABLE_TAKEOVER_RUNS,
328 		CTDB_SRVID_DISABLE_RECOVERIES,
329 		CTDB_SRVID_DISABLE_IP_CHECK,
330 	};
331 	size_t i;
332 
333 	if (argc == 2) {
334 		int seed = atoi(argv[1]);
335 		srandom(seed);
336 	}
337 
338 	TEST_FUNC(ctdb_req_header)();
339 
340 	TEST_FUNC(ctdb_req_call)();
341 	TEST_FUNC(ctdb_reply_call)();
342 	TEST_FUNC(ctdb_reply_error)();
343 	TEST_FUNC(ctdb_req_dmaster)();
344 	TEST_FUNC(ctdb_reply_dmaster)();
345 
346 	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
347 		TEST_FUNC(ctdb_req_control_data)(opcode);
ctdb_reply_call_len_old(struct ctdb_req_header * h,struct ctdb_reply_call * c)348 	}
349 	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
350 		TEST_FUNC(ctdb_reply_control_data)(opcode);
351 	}
352 
353 	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
354 		TEST_FUNC(ctdb_req_control)(opcode);
ctdb_reply_call_push_old(struct ctdb_req_header * h,struct ctdb_reply_call * c,uint8_t * buf,size_t * buflen)355 	}
356 	for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
357 		TEST_FUNC(ctdb_reply_control)(opcode);
358 	}
359 
360 	for (i=0; i<ARRAY_SIZE(test_srvid); i++) {
361 		TEST_FUNC(ctdb_message_data)(test_srvid[i]);
362 	}
363 	for (i=0; i<ARRAY_SIZE(test_srvid); i++) {
364 		TEST_FUNC(ctdb_req_message)(test_srvid[i]);
365 	}
366 	TEST_FUNC(ctdb_req_message_data)();
367 
368 	TEST_FUNC(ctdb_req_keepalive)();
369 	TEST_FUNC(ctdb_req_tunnel)();
370 
371 	return 0;
372 }
373