s4:rpc_server: parse auth data only for BIND,ALTER_REQ,AUTH3
[Samba.git] / ctdb / ib / ibwrapper_test.c
blobeaa14fb4e43a4e24465af9199771de89442aa742
1 /*
2 * Unix SMB/CIFS implementation.
3 * Test the infiniband wrapper.
5 * Copyright (C) Sven Oehme <oehmes@de.ibm.com> 2006
7 * Major code contributions by Peter Somogyi <psomogyi@gamax.hu>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "replace.h"
24 #include "system/network.h"
25 #include "system/time.h"
27 #include <assert.h>
28 #include <talloc.h>
29 #include <tevent.h>
31 #include "lib/util/time.h"
32 #include "lib/util/debug.h"
34 #include "common/logging.h"
36 #include "ib/ibwrapper.h"
38 struct ibwtest_ctx {
39 int is_server;
40 char *id; /* my id */
42 struct ibw_initattr *attrs;
43 int nattrs;
44 char *opts; /* option string */
46 struct sockaddr_in *addrs; /* dynamic array of dest addrs */
47 int naddrs;
49 unsigned int nsec; /* delta times between messages in nanosec */
50 unsigned int sleep_usec; /* microsecs to sleep in the main loop to emulate overloading */
51 uint32_t maxsize; /* maximum variable message size */
53 int cnt;
54 int nsent;
56 int nmsg; /* number of messages to send (client) */
58 int kill_me;
59 int stopping;
60 int error;
61 struct ibw_ctx *ibwctx;
63 struct timeval start_time, end_time;
66 struct ibwtest_conn {
67 char *id;
70 enum testopcode {
71 TESTOP_SEND_ID = 1,
72 TESTOP_SEND_TEXT = 2,
73 TESTOP_SEND_RND = 3
76 static int ibwtest_connect_everybody(struct ibwtest_ctx *tcx)
78 struct ibw_conn *conn;
79 struct ibwtest_conn *tconn = talloc_zero(tcx, struct ibwtest_conn);
80 int i;
82 for(i=0; i<tcx->naddrs; i++) {
83 conn = ibw_conn_new(tcx->ibwctx, tconn);
84 if (ibw_connect(conn, &tcx->addrs[i], tconn)) {
85 fprintf(stderr, "ibw_connect error at %d\n", i);
86 return -1;
89 DEBUG(DEBUG_DEBUG, ("sent %d connect request...\n", tcx->naddrs));
91 return 0;
94 static int ibwtest_send_id(struct ibw_conn *conn)
96 struct ibwtest_ctx *tcx = talloc_get_type(conn->ctx->ctx_userdata, struct ibwtest_ctx);
97 char *buf;
98 void *key;
99 uint32_t len;
101 DEBUG(DEBUG_DEBUG, ("ibwtest_send_id\n"));
102 len = sizeof(uint32_t)+strlen(tcx->id)+2;
103 if (ibw_alloc_send_buf(conn, (void **)&buf, &key, len)) {
104 DEBUG(DEBUG_ERR, ("send_id: ibw_alloc_send_buf failed\n"));
105 return -1;
108 /* first sizeof(uint32_t) size bytes are for length */
109 *((uint32_t *)buf) = len;
110 buf[sizeof(uint32_t)] = (char)TESTOP_SEND_ID;
111 strcpy(buf+sizeof(uint32_t)+1, tcx->id);
113 if (ibw_send(conn, buf, key, len)) {
114 DEBUG(DEBUG_ERR, ("send_id: ibw_send error\n"));
115 return -1;
117 tcx->nsent++;
119 return 0;
122 static int ibwtest_send_test_msg(struct ibwtest_ctx *tcx, struct ibw_conn *conn, const char *msg)
124 char *buf, *p;
125 void *key;
126 uint32_t len;
128 if (conn->state!=IBWC_CONNECTED)
129 return 0; /* not yet up */
131 len = strlen(msg) + 2 + sizeof(uint32_t);
132 if (ibw_alloc_send_buf(conn, (void **)&buf, &key, len)) {
133 fprintf(stderr, "send_test_msg: ibw_alloc_send_buf failed\n");
134 return -1;
137 *((uint32_t *)buf) = len;
138 p = buf;
139 p += sizeof(uint32_t);
140 p[0] = (char)TESTOP_SEND_TEXT;
141 p++;
142 strcpy(p, msg);
144 if (ibw_send(conn, buf, key, len)) {
145 DEBUG(DEBUG_ERR, ("send_test_msg: ibw_send error\n"));
146 return -1;
148 tcx->nsent++;
150 return 0;
153 static unsigned char ibwtest_fill_random(unsigned char *buf, uint32_t size)
155 uint32_t i = size;
156 unsigned char sum = 0;
157 unsigned char value;
158 while(i) {
159 i--;
160 value = (unsigned char)(256.0 * (rand() / (RAND_MAX + 1.0)));
161 buf[i] = value;
162 sum += value;
164 return sum;
167 static unsigned char ibwtest_get_sum(unsigned char *buf, uint32_t size)
169 uint32_t i = size;
170 unsigned char sum = 0;
172 while(i) {
173 i--;
174 sum += buf[i];
176 return sum;
179 static int ibwtest_do_varsize_scenario_conn_size(struct ibwtest_ctx *tcx, struct ibw_conn *conn, uint32_t size)
181 unsigned char *buf;
182 void *key;
183 uint32_t len;
184 unsigned char sum;
186 len = sizeof(uint32_t) + 1 + size + 1;
187 if (ibw_alloc_send_buf(conn, (void **)&buf, &key, len)) {
188 DEBUG(DEBUG_ERR, ("varsize/ibw_alloc_send_buf failed\n"));
189 return -1;
191 *((uint32_t *)buf) = len;
192 buf[sizeof(uint32_t)] = TESTOP_SEND_RND;
193 sum = ibwtest_fill_random(buf + sizeof(uint32_t) + 1, size);
194 buf[sizeof(uint32_t) + 1 + size] = sum;
195 if (ibw_send(conn, buf, key, len)) {
196 DEBUG(DEBUG_ERR, ("varsize/ibw_send failed\n"));
197 return -1;
199 tcx->nsent++;
201 return 0;
204 static int ibwtest_do_varsize_scenario_conn(struct ibwtest_ctx *tcx, struct ibw_conn *conn)
206 uint32_t size;
207 int i;
209 for(i=0; i<tcx->nmsg; i++)
211 //size = (uint32_t)((float)(tcx->maxsize) * (rand() / (RAND_MAX + 1.0)));
212 size = (uint32_t)((float)(tcx->maxsize) * ((float)(i+1)/(float)tcx->nmsg));
213 if (ibwtest_do_varsize_scenario_conn_size(tcx, conn, size))
214 return -1;
216 return 0;
219 /*int ibwtest_do_varsize_scenario(ibwtest_ctx *tcx)
221 int rc;
222 struct ibw_conn *conn;
224 for(conn=tcx->ibwctx->conn_list; conn!=NULL; conn=conn->next) {
225 if (conn->state==IBWC_CONNECTED) {
226 rc = ibwtest_do_varsize_scenario_conn(tcx, conn);
227 if (rc)
228 tcx->error = rc;
233 static int ibwtest_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn)
235 struct ibwtest_ctx *tcx = NULL; /* userdata */
236 struct ibwtest_conn *tconn = NULL; /* userdata */
238 if (ctx) {
239 tcx = talloc_get_type(ctx->ctx_userdata, struct ibwtest_ctx);
241 switch(ctx->state) {
242 case IBWS_INIT:
243 DEBUG(DEBUG_DEBUG, ("test IBWS_INIT\n"));
244 break;
245 case IBWS_READY:
246 DEBUG(DEBUG_DEBUG, ("test IBWS_READY\n"));
247 break;
248 case IBWS_CONNECT_REQUEST:
249 DEBUG(DEBUG_DEBUG, ("test IBWS_CONNECT_REQUEST\n"));
250 tconn = talloc_zero(conn, struct ibwtest_conn);
251 if (ibw_accept(ctx, conn, tconn)) {
252 DEBUG(DEBUG_ERR, ("error accepting the connect request\n"));
254 break;
255 case IBWS_STOPPED:
256 DEBUG(DEBUG_DEBUG, ("test IBWS_STOPPED\n"));
257 tcx->kill_me = 1; /* main loop can exit */
258 break;
259 case IBWS_ERROR:
260 DEBUG(DEBUG_DEBUG, ("test IBWS_ERROR\n"));
261 ibw_stop(tcx->ibwctx);
262 break;
263 default:
264 assert(0);
265 break;
269 if (conn) {
270 tconn = talloc_get_type(conn->conn_userdata, struct ibwtest_conn);
271 switch(conn->state) {
272 case IBWC_INIT:
273 DEBUG(DEBUG_DEBUG, ("test IBWC_INIT\n"));
274 break;
275 case IBWC_CONNECTED:
276 if (gettimeofday(&tcx->start_time, NULL)) {
277 DEBUG(DEBUG_ERR, ("gettimeofday error %d", errno));
278 return -1;
280 ibwtest_send_id(conn);
281 break;
282 case IBWC_DISCONNECTED:
283 DEBUG(DEBUG_DEBUG, ("test IBWC_DISCONNECTED\n"));
284 talloc_free(conn);
285 break;
286 case IBWC_ERROR:
287 DEBUG(DEBUG_DEBUG, ("test IBWC_ERROR %s\n", ibw_getLastError()));
288 break;
289 default:
290 assert(0);
291 break;
294 return 0;
297 static int ibwtest_receive_handler(struct ibw_conn *conn, void *buf, int n)
299 struct ibwtest_conn *tconn;
300 enum testopcode op;
301 struct ibwtest_ctx *tcx = talloc_get_type(conn->ctx->ctx_userdata, struct ibwtest_ctx);
302 int rc = 0;
304 assert(conn!=NULL);
305 assert(n>=sizeof(uint32_t)+1);
306 tconn = talloc_get_type(conn->conn_userdata, struct ibwtest_conn);
308 op = (enum testopcode)((char *)buf)[sizeof(uint32_t)];
309 if (op==TESTOP_SEND_ID) {
310 tconn->id = talloc_strdup(tconn, ((char *)buf)+sizeof(uint32_t)+1);
312 if (op==TESTOP_SEND_ID || op==TESTOP_SEND_TEXT) {
313 DEBUG(DEBUG_DEBUG, ("[%d]msg from %s: \"%s\"(%d)\n", op,
314 tconn->id ? tconn->id : "NULL", ((char *)buf)+sizeof(uint32_t)+1, n));
317 if (tcx->is_server) {
318 if (op==TESTOP_SEND_RND) {
319 unsigned char sum;
320 sum = ibwtest_get_sum((unsigned char *)buf + sizeof(uint32_t) + 1,
321 n - sizeof(uint32_t) - 2);
322 DEBUG(DEBUG_DEBUG, ("[%d]msg varsize %u/sum %u from %s\n",
324 (uint32_t)(n - sizeof(uint32_t) - 2),
325 (uint32_t)sum,
326 tconn->id ? tconn->id : "NULL"));
327 if (sum!=((unsigned char *)buf)[n-1]) {
328 DEBUG(DEBUG_ERR, ("ERROR: checksum mismatch %u!=%u\n",
329 (uint32_t)sum, (uint32_t)((unsigned char *)buf)[n-1]));
330 ibw_stop(tcx->ibwctx);
331 goto error;
333 } else if (op!=TESTOP_SEND_ID) {
334 char *buf2;
335 void *key2;
337 /* bounce message regardless what it is */
338 if (ibw_alloc_send_buf(conn, (void **)&buf2, &key2, n)) {
339 fprintf(stderr, "ibw_alloc_send_buf error #2\n");
340 goto error;
342 memcpy(buf2, buf, n);
343 if (ibw_send(conn, buf2, key2, n)) {
344 fprintf(stderr, "ibw_send error #2\n");
345 goto error;
347 tcx->nsent++;
349 } else { /* client: */
350 if (op==TESTOP_SEND_ID && tcx->maxsize) {
351 /* send them in one blow */
352 rc = ibwtest_do_varsize_scenario_conn(tcx, conn);
355 if (tcx->nmsg) {
356 char msg[26];
357 sprintf(msg, "hello world %d", tcx->nmsg--);
358 rc = ibwtest_send_test_msg(tcx, conn, msg);
359 if (tcx->nmsg==0) {
360 ibw_stop(tcx->ibwctx);
361 tcx->stopping = 1;
366 if (rc)
367 tcx->error = rc;
369 return rc;
370 error:
371 return -1;
374 static void ibwtest_timeout_handler(struct tevent_context *ev,
375 struct tevent_timer *te,
376 struct timeval t, void *private_data)
378 struct ibwtest_ctx *tcx = talloc_get_type(private_data, struct ibwtest_ctx);
379 int rc;
381 if (!tcx->is_server) {
382 struct ibw_conn *conn;
383 char msg[50];
385 /* fill it with something variable... */
386 sprintf(msg, "hello world %d", tcx->cnt++);
388 /* send something to everybody... */
389 for(conn=tcx->ibwctx->conn_list; conn!=NULL; conn=conn->next) {
390 if (conn->state==IBWC_CONNECTED) {
391 rc = ibwtest_send_test_msg(tcx, conn, msg);
392 if (rc)
393 tcx->error = rc;
396 } /* else allow main loop run */
399 static struct ibwtest_ctx *testctx = NULL;
401 static void ibwtest_sigint_handler(int sig)
403 DEBUG(DEBUG_ERR, ("got SIGINT\n"));
404 if (testctx) {
405 if (testctx->ibwctx->state==IBWS_READY ||
406 testctx->ibwctx->state==IBWS_CONNECT_REQUEST ||
407 testctx->ibwctx->state==IBWS_ERROR)
409 if (testctx->stopping) {
410 DEBUG(DEBUG_DEBUG, ("forcing exit...\n"));
411 testctx->kill_me = 1;
412 } else {
413 /* mostly expected case */
414 ibw_stop(testctx->ibwctx);
415 testctx->stopping = 1;
417 } else
418 testctx->kill_me = 1;
422 static int ibwtest_parse_attrs(struct ibwtest_ctx *tcx, char *optext,
423 struct ibw_initattr **pattrs, int *nattrs, char op)
425 int i = 0, n = 1;
426 int porcess_next = 1;
427 char *p, *q;
428 struct ibw_initattr *attrs = NULL;
430 *pattrs = NULL;
431 for(p = optext; *p!='\0'; p++) {
432 if (*p==',')
433 n++;
436 attrs = (struct ibw_initattr *)talloc_size(tcx,
437 n * sizeof(struct ibw_initattr));
438 for(p = optext; *p!='\0'; p++) {
439 if (porcess_next) {
440 attrs[i].name = p;
441 q = strchr(p, ':');
442 if (q==NULL) {
443 fprintf(stderr, "-%c format error\n", op);
444 return -1;
446 *q = '\0';
447 attrs[i].value = q + 1;
449 porcess_next = 0;
450 i++;
451 p = q; /* ++ at end */
453 if (*p==',') {
454 *p = '\0'; /* ++ at end */
455 porcess_next = 1;
458 *pattrs = attrs;
459 *nattrs = n;
461 return 0;
464 static int ibwtest_get_address(const char *address, struct in_addr *addr)
466 if (inet_pton(AF_INET, address, addr) <= 0) {
467 struct hostent *he = gethostbyname(address);
468 if (he == NULL || he->h_length > sizeof(*addr)) {
469 DEBUG(DEBUG_ERR, ("invalid nework address '%s'\n", address));
470 return -1;
472 memcpy(addr, he->h_addr, he->h_length);
474 return 0;
477 static int ibwtest_getdests(struct ibwtest_ctx *tcx, char op)
479 int i;
480 struct ibw_initattr *attrs = NULL;
481 struct sockaddr_in *p;
482 char *tmp;
484 tmp = talloc_strdup(tcx, optarg);
485 if (tmp == NULL) return -1;
486 /* hack to reuse the above ibw_initattr parser */
487 if (ibwtest_parse_attrs(tcx, tmp, &attrs, &tcx->naddrs, op))
488 return -1;
490 tcx->addrs = talloc_size(tcx,
491 tcx->naddrs * sizeof(struct sockaddr_in));
492 for(i=0; i<tcx->naddrs; i++) {
493 p = tcx->addrs + i;
494 p->sin_family = AF_INET;
495 if (ibwtest_get_address(attrs[i].name, &p->sin_addr))
496 return -1;
497 p->sin_port = htons(atoi(attrs[i].value));
500 return 0;
503 static int ibwtest_init_server(struct ibwtest_ctx *tcx)
505 if (tcx->naddrs!=1) {
506 fprintf(stderr, "incorrect number of addrs(%d!=1)\n", tcx->naddrs);
507 return -1;
510 if (ibw_bind(tcx->ibwctx, &tcx->addrs[0])) {
511 DEBUG(DEBUG_ERR, ("ERROR: ibw_bind failed\n"));
512 return -1;
515 if (ibw_listen(tcx->ibwctx, 1)) {
516 DEBUG(DEBUG_ERR, ("ERROR: ibw_listen failed\n"));
517 return -1;
520 /* continued at IBWS_READY */
521 return 0;
524 static void ibwtest_usage(struct ibwtest_ctx *tcx, char *name)
526 printf("Usage:\n");
527 printf("\t%s -i <id> -o {name:value} -d {addr:port} -t nsec -s\n", name);
528 printf("\t-i <id> is a free text, acting as a server id, max 23 chars [mandatory]\n");
529 printf("\t-o name1:value1,name2:value2,... is a list of (name, value) pairs\n");
530 printf("\t-a addr1:port1,addr2:port2,... is a list of destination ip addresses\n");
531 printf("\t-t nsec delta time between sends in nanosec [default %d]\n", tcx->nsec);
532 printf("\t\t send message periodically and endless when nsec is non-zero\n");
533 printf("\t-s server mode (you have to give exactly one -d address:port in this case)\n");
534 printf("\t-n number of messages to send [default %d]\n", tcx->nmsg);
535 printf("\t-l usec time to sleep in the main loop [default %d]\n", tcx->sleep_usec);
536 printf("\t-v max variable msg size in bytes [default %d], 0=don't send var. size\n", tcx->maxsize);
537 printf("\t-d LogLevel [default %d]\n", DEBUGLEVEL);
538 printf("Press ctrl+C to stop the program.\n");
541 int main(int argc, char *argv[])
543 int rc, op;
544 int result = 1;
545 struct tevent_context *ev = NULL;
546 struct ibwtest_ctx *tcx = NULL;
547 float usec;
549 tcx = talloc_zero(NULL, struct ibwtest_ctx);
550 memset(tcx, 0, sizeof(struct ibwtest_ctx));
551 tcx->nsec = 0;
552 tcx->nmsg = 1000;
553 DEBUGLEVEL = 0;
555 /* here is the only case we can't avoid using global... */
556 testctx = tcx;
557 signal(SIGINT, ibwtest_sigint_handler);
558 srand((unsigned)time(NULL));
560 while ((op=getopt(argc, argv, "i:o:d:m:st:n:l:v:a:")) != -1) {
561 switch (op) {
562 case 'i':
563 tcx->id = talloc_strdup(tcx, optarg);
564 break;
565 case 'o':
566 tcx->opts = talloc_strdup(tcx, optarg);
567 if (tcx->opts) goto cleanup;
568 if (ibwtest_parse_attrs(tcx, tcx->opts, &tcx->attrs,
569 &tcx->nattrs, op))
570 goto cleanup;
571 break;
572 case 'a':
573 if (ibwtest_getdests(tcx, op))
574 goto cleanup;
575 break;
576 case 's':
577 tcx->is_server = 1;
578 break;
579 case 't':
580 tcx->nsec = (unsigned int)atoi(optarg);
581 break;
582 case 'n':
583 tcx->nmsg = atoi(optarg);
584 break;
585 case 'l':
586 tcx->sleep_usec = (unsigned int)atoi(optarg);
587 break;
588 case 'v':
589 tcx->maxsize = (unsigned int)atoi(optarg);
590 break;
591 case 'd':
592 DEBUGLEVEL = atoi(optarg);
593 break;
594 default:
595 fprintf(stderr, "ERROR: unknown option -%c\n", (char)op);
596 ibwtest_usage(tcx, argv[0]);
597 goto cleanup;
600 if (tcx->id==NULL) {
601 ibwtest_usage(tcx, argv[0]);
602 goto cleanup;
605 ev = tevent_context_init(NULL);
606 assert(ev);
608 tcx->ibwctx = ibw_init(tcx->attrs, tcx->nattrs,
609 tcx,
610 ibwtest_connstate_handler,
611 ibwtest_receive_handler,
614 if (!tcx->ibwctx)
615 goto cleanup;
617 if (tcx->is_server)
618 rc = ibwtest_init_server(tcx);
619 else
620 rc = ibwtest_connect_everybody(tcx);
621 if (rc)
622 goto cleanup;
624 while(!tcx->kill_me && !tcx->error) {
625 if (tcx->nsec) {
626 tevent_add_timer(ev, tcx,
627 timeval_current_ofs(0, tcx->nsec),
628 ibwtest_timeout_handler, tcx);
631 tevent_loop_once(ev);
633 if (tcx->sleep_usec)
634 usleep(tcx->sleep_usec);
637 if (!tcx->is_server && tcx->nsent!=0 && !tcx->error) {
638 if (gettimeofday(&tcx->end_time, NULL)) {
639 DEBUG(DEBUG_ERR, ("gettimeofday error %d\n", errno));
640 goto cleanup;
642 usec = (tcx->end_time.tv_sec - tcx->start_time.tv_sec) * 1000000 +
643 (tcx->end_time.tv_usec - tcx->start_time.tv_usec);
644 printf("usec: %f, nmsg: %d, usec/nmsg: %f\n",
645 usec, tcx->nsent, usec/(float)tcx->nsent);
648 if (!tcx->error)
649 result = 0; /* everything OK */
651 cleanup:
652 if (tcx)
653 talloc_free(tcx);
654 if (ev)
655 talloc_free(ev);
656 DEBUG(DEBUG_ERR, ("exited with code %d\n", result));
657 return result;