Modified send logic to allow large messages.
[vlendec/samba-autobuild/.git] / ctdb / tests / ibwrapper_test.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Test the infiniband wrapper.
4  *
5  * Copyright (C) Sven Oehme <oehmes@de.ibm.com> 2006
6  *
7  * Major code contributions by Peter Somogyi <psomogyi@gamax.hu>
8  *
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 2 of the License, or
12  * (at your option) any later version.
13  *
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.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <netinet/in.h>
30 #include <sys/socket.h>
31 #include <netdb.h>
32 #include <arpa/inet.h>
33 #include <malloc.h>
34 #include <assert.h>
35 #include <unistd.h>
36 #include <signal.h>
37
38 #include "includes.h"
39 #include "lib/events/events.h"
40 #include "ib/ibwrapper.h"
41
42 struct ibwtest_ctx {
43         int     is_server;
44         char    *id; /* my id */
45
46         struct ibw_initattr *attrs;
47         int     nattrs;
48         char    *opts; /* option string */
49
50         struct sockaddr_in *addrs; /* dynamic array of dest addrs */
51         int     naddrs;
52
53         unsigned int    nsec; /* nanosleep between messages */
54
55         int     cnt;
56
57         int     kill_me;
58         struct ibw_ctx  *ibwctx;
59 };
60
61 struct ibwtest_conn {
62         char    *id;
63 };
64
65 enum testopcode {
66         TESTOP_SEND_ID = 1,
67         TESTOP_SEND_DATA = 2
68 };
69
70 int ibwtest_connect_everybody(struct ibwtest_ctx *tcx)
71 {
72         struct ibwtest_conn     *pconn = talloc_zero(tcx, struct ibwtest_conn);
73         int     i;
74
75         for(i=0; i<tcx->naddrs; i++) {
76                 if (ibw_connect(tcx->ibwctx, &tcx->addrs[i], pconn)) {
77                         fprintf(stderr, "ibw_connect error at %d\n", i);
78                         return -1;
79                 }
80         }
81         DEBUG(10, ("sent %d connect request...\n", tcx->naddrs));
82
83         return 0;
84 }
85
86 int ibwtest_send_id(struct ibw_conn *conn)
87 {
88         char *buf;
89         void *key;
90         struct ibwtest_ctx *tcx = talloc_get_type(conn->ctx->ctx_userdata, struct ibwtest_ctx);
91
92         DEBUG(10, ("test IBWC_CONNECTED\n"));
93         if (ibw_alloc_send_buf(conn, (void **)&buf, &key, strlen(tcx->id)+2)) {
94                 DEBUG(0, ("send_id: ibw_alloc_send_buf failed\n"));
95                 return -1;
96         }
97
98         buf[0] = (char)TESTOP_SEND_ID;
99         strcpy(buf+1, tcx->id);
100
101         if (ibw_send(conn, buf, key, strlen(buf+1)+2)) {
102                 DEBUG(0, ("send_id: ibw_send error\n"));
103                 return -1;
104         }
105         return 0;
106 }
107
108 int ibwtest_send_test_msg(struct ibwtest_ctx *tcx, struct ibw_conn *conn, const char *msg)
109 {
110         char *buf;
111         void *key;
112
113         if (ibw_alloc_send_buf(conn, (void **)&buf, &key, strlen(msg)+2)) {
114                 fprintf(stderr, "send_test_msg: ibw_alloc_send_buf failed\n");
115                 return -1;
116         }
117
118         buf[0] = (char)TESTOP_SEND_DATA;
119         strcpy(buf+1, msg);
120         
121         if (ibw_send(conn, buf, key, strlen(buf+1)+2)) {
122                 DEBUG(0, ("send_test_msg: ibw_send error\n"));
123                 return -1;
124         }
125         return 0;
126 }
127
128 int ibwtest_connstate_handler(struct ibw_ctx *ctx, struct ibw_conn *conn)
129 {
130         struct ibwtest_ctx      *tcx = NULL; /* userdata */
131         struct ibwtest_conn     *pconn = NULL; /* userdata */
132
133         if (ctx) {
134                 tcx = talloc_get_type(ctx->ctx_userdata, struct ibwtest_ctx);
135
136                 switch(ctx->state) {
137                 case IBWS_INIT:
138                         DEBUG(10, ("test IBWS_INIT\n"));
139                         break;
140                 case IBWS_READY:
141                         DEBUG(10, ("test IBWS_READY\n"));
142                         break;
143                 case IBWS_CONNECT_REQUEST:
144                         DEBUG(10, ("test IBWS_CONNECT_REQUEST\n"));
145                         pconn = talloc_zero(conn, struct ibwtest_conn);
146                         if (ibw_accept(ctx, conn, pconn)) {
147                                 DEBUG(0, ("error accepting the connect request\n"));
148                         }
149                         break;
150                 case IBWS_STOPPED:
151                         DEBUG(10, ("test IBWS_STOPPED\n"));
152                         talloc_free(tcx->ibwctx);
153                         DEBUG(10, ("talloc_free(tcx->ibwctx) DONE\n"));
154                         tcx->kill_me = 1; /* main loop can exit */
155                         break;
156                 case IBWS_ERROR:
157                         DEBUG(10, ("test IBWS_ERROR\n"));
158                         ibw_stop(tcx->ibwctx);
159                         break;
160                 default:
161                         assert(0);
162                         break;
163                 }
164         }
165
166         if (conn) {
167                 pconn = talloc_get_type(conn->conn_userdata, struct ibwtest_conn);
168                 switch(conn->state) {
169                 case IBWC_INIT:
170                         DEBUG(10, ("test IBWC_INIT\n"));
171                         break;
172                 case IBWC_CONNECTED:
173                         ibwtest_send_id(conn);
174                         break;
175                 case IBWC_DISCONNECTED:
176                         DEBUG(10, ("test IBWC_DISCONNECTED\n"));
177                         break;
178                 case IBWC_ERROR:
179                         DEBUG(10, ("test IBWC_ERROR\n"));
180                         break;
181                 default:
182                         assert(0);
183                         break;
184                 }
185         }
186         return 0;
187 }
188
189 int ibwtest_receive_handler(struct ibw_conn *conn, void *buf, int n)
190 {
191         struct ibwtest_conn *pconn;
192         enum testopcode op;
193         struct ibwtest_ctx *tcx = talloc_get_type(conn->ctx->ctx_userdata, struct ibwtest_ctx);
194
195         assert(conn!=NULL);
196         pconn = talloc_get_type(conn->conn_userdata, struct ibwtest_conn);
197
198         op = (enum testopcode)((char *)buf)[0];
199         DEBUG(11, ("[%d]msg from %s: \"%s\"(%d)\n", op,
200                 pconn->id ? pconn->id : NULL, ((char *)buf)+1, n));
201
202         if (tcx->is_server) {
203                 char *buf2;
204                 void *key2;
205                 /* bounce message */
206                 if (ibw_alloc_send_buf(conn, (void **)&buf2, &key2, n)) {
207                         fprintf(stderr, "ibw_alloc_send_buf error #2\n");
208                         return -1;
209                 }
210                 memcpy(buf2, buf, n);
211                 if (ibw_send(conn, buf2, key2, n)) {
212                         fprintf(stderr, "ibw_send error #2\n");
213                         return -2;
214                 }
215         }
216
217         return 0;
218 }
219
220 void ibwtest_timeout_handler(struct event_context *ev, struct timed_event *te, 
221         struct timeval t, void *private)
222 {
223         struct ibwtest_ctx *tcx = talloc_get_type(private, struct ibwtest_ctx);
224
225         if (!tcx->is_server) {
226                 struct ibw_conn *p;
227                 char    msg[50];
228
229                 /* fill it with something variable... */
230                 sprintf(msg, "hello world %d", tcx->cnt++);
231
232                 /* send something to everybody... */
233                 for(p=tcx->ibwctx->conn_list; p!=NULL; p=p->next) {
234                         ibwtest_send_test_msg(tcx, p, msg);
235                 }
236         } /* else allow main loop run */
237 }
238
239 static struct ibwtest_ctx *testctx = NULL;
240
241 void ibwtest_sigquit_handler(int sig)
242 {
243         DEBUG(0, ("got SIGQUIT\n"));
244         if (testctx)
245                 ibw_stop(testctx->ibwctx);
246 }
247
248 int ibwtest_parse_attrs(struct ibwtest_ctx *tcx, char *optext,
249         struct ibw_initattr **pattrs, int *nattrs, char op)
250 {
251         int     i = 0, n = 1;
252         int     porcess_next = 1;
253         char    *p, *q;
254         struct ibw_initattr *attrs = NULL;
255
256         *pattrs = NULL;
257         for(p = optext; *p!='\0'; p++) {
258                 if (*p==',')
259                         n++;
260         }
261
262         attrs = (struct ibw_initattr *)talloc_size(tcx,
263                 n * sizeof(struct ibw_initattr));
264         for(p = optext; *p!='\0'; p++) {
265                 if (porcess_next) {
266                         attrs[i].name = p;
267                         q = strchr(p, ':');
268                         if (q==NULL) {
269                                 fprintf(stderr, "-%c format error\n", op);
270                                 return -1;
271                         }
272                         *q = '\0';
273                         attrs[i].value = q + 1;
274
275                         porcess_next = 0;
276                         i++;
277                 }
278                 if (*p==',') {
279                         *p = '\0';
280                         porcess_next = 1;
281                 }
282         }
283         *pattrs = attrs;
284         *nattrs = n;
285
286         return 0;
287 }
288
289 int ibwtest_getdests(struct ibwtest_ctx *tcx, char op)
290 {
291         int     i;
292         struct ibw_initattr     *attrs = NULL;
293         struct sockaddr_in      *p;
294         char    *tmp;
295
296         tmp = talloc_strdup(tcx, optarg);
297         /* hack to reuse the above ibw_initattr parser */
298         if (ibwtest_parse_attrs(tcx, tmp, &attrs, &tcx->naddrs, op))
299                 return -1;
300
301         tcx->addrs = talloc_size(tcx,
302                 tcx->naddrs * sizeof(struct sockaddr_in));
303         for(i=0; i<tcx->naddrs; i++) {
304                 p = tcx->addrs + i;
305                 p->sin_addr.s_addr = inet_addr(attrs[i].name);
306                 p->sin_port = atoi(attrs[i].value);
307                 p->sin_family = AF_INET;
308         }
309
310         return 0;
311 }
312
313 int ibwtest_init_server(struct ibwtest_ctx *tcx)
314 {
315         if (tcx->naddrs!=1) {
316                 fprintf(stderr, "incorrecr number of addrs(%d!=1)\n", tcx->naddrs);
317                 return -1;
318         }
319
320         if (ibw_bind(tcx->ibwctx, &tcx->addrs[0])) {
321                 DEBUG(0, ("ERROR: ibw_bind failed\n"));
322                 return -1;
323         }
324
325         /* continued at IBWS_READY */
326         return 0;
327 }
328
329 void ibwtest_usage(struct ibwtest_ctx *tcx, char *name)
330 {
331         printf("Usage:\n");
332         printf("\t%s -i <id> -o {name:value} -d {addr:port} -t nsec -s\n", name);
333         printf("\t-i <id> is a free text, acting as a server id, max 23 chars [mandatory]\n");
334         printf("\t-o name1:value1,name2:value2,... is a list of (name, value) pairs\n");
335         printf("\t-d addr1:port1,addr2:port2,... is a list of destination ip addresses\n");
336         printf("\t-t nsec delta time between sends in nanosec [default %d]\n", tcx->nsec);
337         printf("\t-s server mode (you have to give exactly one -d address:port in this case)\n");
338         printf("Press ctrl+C to stop the program.\n");
339 }
340
341 int main(int argc, char *argv[])
342 {
343         int     rc, op;
344         int     result = 1;
345         struct event_context *ev = NULL;
346         struct ibwtest_ctx *tcx = NULL;
347
348         tcx = talloc_zero(NULL, struct ibwtest_ctx);
349         memset(tcx, 0, sizeof(struct ibwtest_ctx));
350         tcx->nsec = 1000;
351
352         /* here is the only case we can't avoid using global... */
353         testctx = tcx;
354         signal(SIGQUIT, ibwtest_sigquit_handler);
355
356         while ((op=getopt(argc, argv, "i:o:d:m:s")) != -1) {
357                 switch (op) {
358                 case 'i':
359                         tcx->id = talloc_strdup(tcx, optarg);
360                         break;
361                 case 'o':
362                         tcx->opts = talloc_strdup(tcx, optarg);
363                         if (ibwtest_parse_attrs(tcx, tcx->opts, &tcx->attrs,
364                                 &tcx->nattrs, op))
365                                 goto cleanup;
366                         break;
367                 case 'd':
368                         if (ibwtest_getdests(tcx, op))
369                                 goto cleanup;
370                         break;
371                 case 's':
372                         tcx->is_server = 1;
373                         break;
374                 default:
375                         fprintf(stderr, "ERROR: unknown option -%c\n", (char)op);
376                         ibwtest_usage(tcx, argv[0]);
377                         goto cleanup;
378                 }
379         }
380         if (tcx->id==NULL) {
381                 ibwtest_usage(tcx, argv[0]);
382                 goto cleanup;
383         }
384
385         ev = event_context_init(NULL);
386         assert(ev);
387
388         tcx->ibwctx = ibw_init(tcx->attrs, tcx->nattrs,
389                 tcx,
390                 ibwtest_connstate_handler,
391                 ibwtest_receive_handler,
392                 ev
393         );
394         if (!tcx->ibwctx)
395                 goto cleanup;
396
397         if (tcx->is_server)
398                 rc = ibwtest_init_server(tcx);
399         else
400                 rc = ibwtest_connect_everybody(tcx);
401         if (rc)
402                 goto cleanup;
403
404         while(!tcx->kill_me) {
405                 event_add_timed(ev, tcx, timeval_current_ofs(0, tcx->nsec),
406                         ibwtest_timeout_handler, tcx);
407                 event_loop_once(ev);
408         }
409
410         result = 0; /* everything OK */
411
412 cleanup:
413         if (tcx)
414                 talloc_free(tcx);
415         if (ev)
416                 talloc_free(ev);
417         DEBUG(0, ("exited with code %d\n", result));
418         return result;
419 }