Imported Upstream version 1.0.10
[platform/upstream/lksctp-tools.git] / src / apps / sctp_xconnect.c
1 /* SCTP kernel Implementation
2  * (C) Copyright IBM Corp. 2003
3  *
4  * The SCTP implementation is free software;
5  * you can redistribute it and/or modify it under the terms of
6  * the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * The SCTP implementation is distributed in the hope that it
11  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12  *                 ************************
13  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GNU CC; see the file COPYING.  If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Please send any bug reports or fixes you make to the
22  * email address(es):
23  *    lksctp developers <lksctp-developers@lists.sourceforge.net>
24  *
25  * Or submit a bug report through the following website:
26  *    http://www.sf.net/projects/lksctp
27  *
28  * Any bugs reported given to us we will try to fix... any fixes shared will
29  * be incorporated into the next SCTP release.
30  *
31  * Written or modified by:
32  *    Ryan Layer                <rmlayer@us.ibm.com>
33  */
34
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <fcntl.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/uio.h>
43 #include <netinet/in.h>
44 #include <errno.h>
45 #include <netinet/sctp.h>
46 #include <sctputil.h>
47 #include <netdb.h>
48 #include <getopt.h>
49
50 char *TCID = __FILE__;
51 int TST_TOTAL = 1;
52 int TST_CNT = 0;
53
54 #define MAXHOSTNAME 64
55
56 #define MAXCLIENTNUM 10000
57
58 #define TRUE 1
59
60 #define SERVER 1
61 #define CLIENT 0
62 #define NOT_DEFINED -1
63
64 int mode = NOT_DEFINED;
65
66 int     assoc_num,
67         remote_port,
68         local_port;
69 int active = 0;
70
71 char *local_host = NULL;
72 char *remote_host = NULL;
73 sockaddr_storage_t client_loop,
74                 server_loop;
75 struct hostent *hst;
76
77 void usage(char *argv0);
78 void parse_arguments(int argc, char*argv[]);
79 void data_received(struct msghdr *inmessage, int len, int stream,
80                         int server_socket);
81 int event_received(struct msghdr *inmessage, int assoc_num);
82 void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds);
83 void server_mode(void);
84 void client_mode(void);
85
86 /* Print the syntax/usage */
87 void usage(char *argv0)
88 {
89         printf("usage: %s -H localhost -P localport -l|c [-h remotehost]\n"
90                "\t\t[-p remoteport] [-a] [-n <cnt>]\n" 
91                " -H\t\tspecify a local address.\n"
92                " -P\t\tspecify the local port number to be used\n"
93                " -l\t\trun in server mode.\n"
94                " -c\t\trun in client mode.\n"
95                " -h\t\tspecify the peer address.\n"
96                " -p\t\tspecify the port number for the peer address.\n"
97                " -a\t\tactively generate traffic with the server.\n"
98                " -n\t\tspecify the number of associations to create.\n",
99                argv0);
100 }
101
102 /* Parse command line options */
103 void parse_arguments(int argc, char*argv[]) {
104         int c;
105
106         while ((c = getopt(argc, argv, ":H:P:ach:ln:p:")) >= 0) {
107                 switch (c) {
108                         case 'H':
109                                 local_host = optarg;
110                                 break;
111                         case 'P':
112                                 local_port = atoi(optarg);
113                                 break;
114                         case 'c':
115                             if (mode == NOT_DEFINED)
116                                         mode = CLIENT;
117                                 else {
118                                         usage(argv[0]);
119                                         exit(0);
120                                 }
121                                 break;
122                         case 'a':
123                                 active = 1;
124                                 break;
125                         case 'h':
126                                 remote_host = optarg;
127                                 break;
128                         case 'l':
129                             if (mode == NOT_DEFINED)
130                                         mode = SERVER;
131                                 else {
132                                         usage(argv[0]);
133                                         exit(0);
134                                 }
135                                 break;
136                         case 'n':
137                                 assoc_num = atoi(optarg);
138                                 break;
139                         case 'p':
140                                 remote_port = atoi(optarg);
141                                 break;
142                         default:
143                                 usage(argv[0]);
144                                 exit(0);
145                 }
146         } /* while() */
147
148         if (mode == CLIENT) {
149                 if (assoc_num) {
150                         if (assoc_num > MAXCLIENTNUM) {
151                                 printf("The number of associations indicated "
152                                         "is greater than the");
153                                 printf("max number of associations "
154                                         "allowed(%d).", MAXCLIENTNUM);
155                                 usage(argv[0]);
156                                 exit(0);
157                         }
158                 } else
159                         assoc_num = 1;
160
161                 if (remote_host && remote_port) {
162                         hst = gethostbyname(remote_host);
163
164                         memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0],
165                                    sizeof(server_loop.v4.sin_addr));
166
167                         server_loop.v4.sin_family = AF_INET;
168 server_loop.v4.sin_port = htons(remote_port);
169                 } else {
170                         printf("Remote host and remote port must be defined "
171                                 "in client mode\n");
172                         usage(argv[0]);
173                         exit(0);
174                 }
175
176                 if (local_host) {
177                         hst = gethostbyname(local_host);
178
179                         memcpy(&client_loop.v4.sin_addr, hst->h_addr_list[0],
180                                    sizeof(client_loop.v4.sin_addr));
181                 } else
182                         client_loop.v4.sin_addr.s_addr = INADDR_ANY;
183
184                 if (local_port)
185                         client_loop.v4.sin_port = htons(local_port);
186                 else
187                         client_loop.v4.sin_port = 0;
188
189                 client_loop.v4.sin_family = AF_INET;
190         } else if (mode == SERVER) {
191                 if (active) {
192                         printf("This option if for client use only");
193                         usage(argv[0]);
194                         exit(0);
195                 }
196
197                 if (remote_host || remote_port) {
198                         printf("Remote values not needed in server mode.\n");
199                         usage(argv[0]);
200                         exit(0);
201                 }
202
203                 if (local_host) {
204                         hst = gethostbyname(local_host);
205
206                         memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0],
207                                    sizeof(server_loop.v4.sin_addr));
208                 } else
209                         server_loop.v4.sin_addr.s_addr = INADDR_ANY;
210
211                 if (local_port)
212                         server_loop.v4.sin_port = htons(local_port);
213                 else {
214                         printf("Specify a local port in server mode.\n");
215                         usage(argv[0]);
216                         exit(0);
217                 }
218
219                 server_loop.v4.sin_family = AF_INET;
220         } else {
221                 printf("Must assisgn a client or server mode.\n");
222                 usage(argv[0]);
223                 exit(0);
224         }
225 } /* parse_arguments() */
226
227 /* Handle data recieved */
228 void data_received(struct msghdr *inmessage, int len, int stream, int socket) {
229
230         int ppid, error;
231         char *ping = "PING";
232
233         if (mode == SERVER) {
234                 ppid = rand();
235
236                 error = sctp_sendmsg(socket,
237                                 inmessage->msg_iov->iov_base,
238                                 len,
239                                 (struct sockaddr *)inmessage->msg_name,
240                                 inmessage->msg_namelen,
241                                 ppid,
242                                 0,
243                                 stream,
244                                 0, 0);
245
246                 if (error < 0) {
247                         printf("Send Failure: %s.\n", strerror(errno));
248                         DUMP_CORE;
249                 }
250         } else {
251                 ppid = rand();
252
253                 printf("Data Received by socket #: %d.\n", socket);
254                 printf("\tMessage = %s\n",
255                         (char *)inmessage->msg_iov->iov_base);
256
257                 if (active) {
258                         sctp_sendmsg(socket,
259                                 ping,
260                                 strlen(ping) + 1,
261                                 (struct sockaddr *)&server_loop,
262                                 sizeof (server_loop),
263                                 ppid,
264                                 0,
265                                 stream,
266                                 0, 0);
267                 }
268         }
269 }
270
271 /* This will print what type of SCTP_ASSOC_CHANGE state that was recieved */
272 void print_sctp_sac_state(struct msghdr *msg) {
273
274         char *data;
275         union sctp_notification *sn;
276
277         if (msg->msg_flags & MSG_NOTIFICATION) {
278                 data = (char *)msg->msg_iov[0].iov_base;
279
280                 sn = (union sctp_notification *)data;
281
282                 switch (sn->sn_assoc_change.sac_state) {
283                                 case SCTP_COMM_UP:
284                                                 printf("SCTP_COMM_UP\n");
285                                                 break;
286                                 case SCTP_COMM_LOST:
287                                                 printf("SCTP_COMM_LOST\n");
288                                                 break;
289                                 case SCTP_RESTART:
290                                                 printf("SCTP_RESTART");
291                                                 break;
292                                 case SCTP_SHUTDOWN_COMP:
293                                                 printf("SCTP_SHUTDOWN_COMP\n");
294                                                 break;
295                                 case SCTP_CANT_STR_ASSOC:
296                                                 printf("SCTP_CANT_STR_ASSOC\n");
297                                                 break;
298                                 default:
299                                                 break;
300                 }
301         }
302 } /* void print_sctp_sac_state() */
303
304 /* Tests what type of MSG_NOTIFICATION has been received.
305 * For now this fucntion only works with SCTP_ASSOC_CHANGE 
306 * types, but can be easily expanded.
307 *
308 * Will return...
309 * -1 if the msg_flags is not MSG_NOTIFICATION
310 *  0 if the MSG_NOTIFICATION type differs from the type
311 *       passed into the additional variable
312 *  1 if the MSG_NOTIFICATION type matches the type
313 *       passed into the additional variable
314 */
315 int test_check_notification_type(struct msghdr *msg,
316         uint16_t sn_type,
317         uint32_t additional) {
318
319         char *data;
320         union sctp_notification *sn;
321
322         if (!(msg->msg_flags & MSG_NOTIFICATION)) {
323                 return -1;
324         } else {
325
326                 /* Fixup for testframe. */
327                 data = (char *)msg->msg_iov[0].iov_base;
328
329                 sn = (union sctp_notification *)data;
330
331                 if (sn->sn_header.sn_type != sn_type)
332                         return 0;
333                 else if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE)
334                         if (sn->sn_assoc_change.sac_state == additional)
335                                 return 1;
336                 return 0;
337         }
338 }
339
340 /* Determine the type of event and make correct adjustments to the
341 * association count
342 */
343 int event_received(struct msghdr *inmessage, int assoc_num) {
344
345         int error;
346
347         printf("Event Received\n");
348
349         print_sctp_sac_state(inmessage);
350
351         if (mode == SERVER) {
352                 /* Test type of Event */
353                 error = test_check_notification_type(inmessage,
354                                                 SCTP_ASSOC_CHANGE,
355                                                 SCTP_COMM_UP);
356                 if (error > 0) {
357                         assoc_num++;
358                         printf("Assosiation Established: count = %d.\n",
359                                 assoc_num);
360                 } else {
361                         error = test_check_notification_type(inmessage,
362                                                         SCTP_ASSOC_CHANGE,
363                                                         SCTP_SHUTDOWN_COMP);
364
365                         if (error > 0) {
366                                 assoc_num--;
367                                 printf("Assosiation Shutdown: count = %d.\n",
368                                         assoc_num);
369                         }
370                 }
371         }
372         return assoc_num;
373 }
374
375 void server_mode() {
376         sockaddr_storage_t msgname;
377         int server_socket,
378                 error,
379                 stream;
380         int assoc_num =0;
381         struct msghdr inmessage;
382         struct iovec iov;
383         char *big_buffer;
384         char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
385
386         if ((big_buffer = malloc(REALLY_BIG)) == NULL) {
387                 printf("malloc failure: %s\n", strerror(errno));
388                 DUMP_CORE;
389         }
390
391         printf("Running in Server Mode...\n");
392
393         memset(&inmessage, 0, sizeof(inmessage));
394         iov.iov_base = big_buffer;
395         iov.iov_len = REALLY_BIG;
396         inmessage.msg_iov = &iov;
397         inmessage.msg_iovlen =1;
398         inmessage.msg_control = incmsg;
399         inmessage.msg_controllen = sizeof(incmsg);
400         inmessage.msg_name = &msgname;
401         inmessage.msg_namelen = sizeof (msgname);
402
403         stream = 1;
404
405         server_socket = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
406         if (server_socket < 0) {
407                 printf("Socket Failure:  %s.\n", strerror(errno));
408                 DUMP_CORE;
409         }
410
411         error = bind(server_socket, &server_loop.sa, sizeof(server_loop));
412         if (error != 0 ) {
413                 printf("Bind Failure: %s.\n", strerror(errno));
414                 DUMP_CORE;
415         }
416
417         error = listen(server_socket, 1);
418         if (error != 0) {
419                 printf("Listen Failure: %s.\n", strerror(errno));
420                 DUMP_CORE;
421         }
422         while (TRUE) {
423                 error = recvmsg(server_socket, &inmessage, MSG_WAITALL);
424                 if (error < 0) {
425                         printf("Receive Failure: %s\n",
426                         strerror(errno));
427                 } else {
428                 if (inmessage.msg_flags & MSG_NOTIFICATION)
429                         assoc_num = event_received(&inmessage, assoc_num);
430                 else
431                         data_received(&inmessage, error, stream, server_socket);
432                 }
433         }
434 }
435
436 void client_mode() {
437
438         int i, error, stream, max_socket = 0;
439         uint32_t ppid = 0;
440         int client_socket[assoc_num];
441         char *message = "Awake";
442         fd_set rfds;
443         struct timeval tv;
444
445         stream = 1;
446
447         printf("Running in Client Mode...\n");
448
449         /* Create the sockets */
450         for (i = 0; i < assoc_num; i++) {
451                 client_socket[i] = socket(PF_INET, SOCK_SEQPACKET,
452                                         IPPROTO_SCTP);
453                 if (client_socket[i] < 0 ){
454                         printf("Socket Failure: %s.\n", strerror(errno));
455                         DUMP_CORE;
456                 }
457
458                 if (local_port) {
459                         error = bind(client_socket[i], &client_loop.sa,
460                                 sizeof(client_loop));
461                         if (error < 0) {
462                                 printf("Bind Failure: %s\n", strerror(errno));
463                                 DUMP_CORE;
464                         }
465                 }
466
467                 printf("Create Socket #: %d\n", client_socket[i]);
468
469                 /* Connect to server and send initial message */
470                 error = connect(client_socket[i], &server_loop.sa,
471                                                     sizeof(server_loop));
472                 if (error < 0){
473                         printf("Connect Failure: %s.\n", strerror(errno));
474                         DUMP_CORE;
475                 }
476
477                 max_socket = client_socket[i];
478
479                 ppid++;
480
481                 /* Send initial message */
482                 error = sctp_sendmsg(client_socket[i],
483                                 message,
484                                 strlen(message) + 1,
485                                 (struct sockaddr *)&server_loop,
486                                 sizeof(server_loop),
487                                 ppid,
488                                 0,
489                                 stream,
490                                 0, 0);
491                 if (error < 0 ) {
492                         printf("Send Failure: %s.\n", strerror(errno));
493                         DUMP_CORE;
494                 }
495         }
496
497         while (TRUE){
498
499                 /* Clear the set for select() */
500                 FD_ZERO(&rfds);
501
502                 /* Set time out values for select() */
503                 tv.tv_sec = 5;
504                 tv.tv_usec = 0;
505
506                 /* Add the sockets select() will examine */
507                 for (i = 0; i < assoc_num; i++) {
508                         FD_SET(client_socket[i], &rfds);
509                 }
510
511                 /* Wait until there is data to be read from one of the
512                  * sockets, or until the timer expires
513                  */
514                 error = select(max_socket + 1, &rfds, NULL, NULL, &tv);
515
516                 if (error < 0) {
517                         printf("Select Failure: %s.\n", strerror(errno));
518                         DUMP_CORE;
519                 } else if (error) {
520                         /* Loop through the array of sockets to find the ones
521                          *that have information to be read
522                          */
523                         process_ready_sockets(client_socket, assoc_num, &rfds);
524                 }
525         }
526 }
527
528 void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds) {
529
530         int i, stream, error;
531         struct msghdr inmessage;
532         struct iovec iov;
533         char *big_buffer;
534         char incmsg[CMSG_SPACE(sizeof (sctp_cmsg_data_t))];
535         sockaddr_storage_t msgname;
536
537         if ((big_buffer = malloc(REALLY_BIG)) == NULL) {
538                 printf("malloc failure: %s\n", strerror(errno));
539                 DUMP_CORE;
540         }
541
542         /* Setup inmessage to be able to receive in incomming message */
543         memset(&inmessage, 0, sizeof (inmessage));
544         iov.iov_base = big_buffer;
545         iov.iov_len = REALLY_BIG;
546         inmessage.msg_iov = &iov;
547         inmessage.msg_iovlen =1;
548         inmessage.msg_control = incmsg;
549         inmessage.msg_controllen = sizeof (incmsg);
550         inmessage.msg_name = &msgname;
551         inmessage.msg_namelen = sizeof (msgname);
552
553         stream = 1;
554
555         for( i = 0; i < assoc_num; i++) {
556                 if (FD_ISSET(client_socket[i], rfds)) {
557                                 error = recvmsg(client_socket[i], &inmessage,
558                                                 MSG_WAITALL);
559                                 if (error < 0)
560                                                 printf("Receive Failure: %s\n",
561                                                         strerror(errno));
562                                 else {
563                 /* Test to find the type of message that was read(event/data) */
564                                         if (inmessage.msg_flags &
565                                                 MSG_NOTIFICATION)
566                                                  event_received(&inmessage,
567                                                                 0);
568
569                                         else
570                                                 data_received(&inmessage, error,
571                                                         stream,
572                                                         client_socket[i]);
573                         }
574                 }
575         }
576 }
577
578 int main(int argc, char *argv[]) {
579
580         parse_arguments(argc, argv);
581
582         if (mode == SERVER) {
583                 server_mode();
584         } else if (mode == CLIENT){
585                 client_mode();
586         }
587         exit(1);
588 }
589