1 /* SCTP kernel Implementation
2 * (C) Copyright IBM Corp. 2003
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)
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.
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.
21 * Please send any bug reports or fixes you make to the
23 * lksctp developers <lksctp-developers@lists.sourceforge.net>
25 * Or submit a bug report through the following website:
26 * http://www.sf.net/projects/lksctp
28 * Any bugs reported given to us we will try to fix... any fixes shared will
29 * be incorporated into the next SCTP release.
31 * Written or modified by:
32 * Ryan Layer <rmlayer@us.ibm.com>
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #include <netinet/in.h>
45 #include <netinet/sctp.h>
50 char *TCID = __FILE__;
54 #define MAXHOSTNAME 64
56 #define MAXCLIENTNUM 10000
62 #define NOT_DEFINED -1
64 int mode = NOT_DEFINED;
71 char *local_host = NULL;
72 char *remote_host = NULL;
73 sockaddr_storage_t client_loop,
77 void usage(char *argv0);
78 void parse_arguments(int argc, char*argv[]);
79 void data_received(struct msghdr *inmessage, int len, int stream,
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);
86 /* Print the syntax/usage */
87 void usage(char *argv0)
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",
102 /* Parse command line options */
103 void parse_arguments(int argc, char*argv[]) {
106 while ((c = getopt(argc, argv, ":H:P:ach:ln:p:")) >= 0) {
112 local_port = atoi(optarg);
115 if (mode == NOT_DEFINED)
126 remote_host = optarg;
129 if (mode == NOT_DEFINED)
137 assoc_num = atoi(optarg);
140 remote_port = atoi(optarg);
148 if (mode == CLIENT) {
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);
161 if (remote_host && remote_port) {
162 hst = gethostbyname(remote_host);
164 memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0],
165 sizeof(server_loop.v4.sin_addr));
167 server_loop.v4.sin_family = AF_INET;
168 server_loop.v4.sin_port = htons(remote_port);
170 printf("Remote host and remote port must be defined "
177 hst = gethostbyname(local_host);
179 memcpy(&client_loop.v4.sin_addr, hst->h_addr_list[0],
180 sizeof(client_loop.v4.sin_addr));
182 client_loop.v4.sin_addr.s_addr = INADDR_ANY;
185 client_loop.v4.sin_port = htons(local_port);
187 client_loop.v4.sin_port = 0;
189 client_loop.v4.sin_family = AF_INET;
190 } else if (mode == SERVER) {
192 printf("This option if for client use only");
197 if (remote_host || remote_port) {
198 printf("Remote values not needed in server mode.\n");
204 hst = gethostbyname(local_host);
206 memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0],
207 sizeof(server_loop.v4.sin_addr));
209 server_loop.v4.sin_addr.s_addr = INADDR_ANY;
212 server_loop.v4.sin_port = htons(local_port);
214 printf("Specify a local port in server mode.\n");
219 server_loop.v4.sin_family = AF_INET;
221 printf("Must assisgn a client or server mode.\n");
225 } /* parse_arguments() */
227 /* Handle data recieved */
228 void data_received(struct msghdr *inmessage, int len, int stream, int socket) {
233 if (mode == SERVER) {
236 error = sctp_sendmsg(socket,
237 inmessage->msg_iov->iov_base,
239 (struct sockaddr *)inmessage->msg_name,
240 inmessage->msg_namelen,
247 printf("Send Failure: %s.\n", strerror(errno));
253 printf("Data Received by socket #: %d.\n", socket);
254 printf("\tMessage = %s\n",
255 (char *)inmessage->msg_iov->iov_base);
261 (struct sockaddr *)&server_loop,
262 sizeof (server_loop),
271 /* This will print what type of SCTP_ASSOC_CHANGE state that was recieved */
272 void print_sctp_sac_state(struct msghdr *msg) {
275 union sctp_notification *sn;
277 if (msg->msg_flags & MSG_NOTIFICATION) {
278 data = (char *)msg->msg_iov[0].iov_base;
280 sn = (union sctp_notification *)data;
282 switch (sn->sn_assoc_change.sac_state) {
284 printf("SCTP_COMM_UP\n");
287 printf("SCTP_COMM_LOST\n");
290 printf("SCTP_RESTART");
292 case SCTP_SHUTDOWN_COMP:
293 printf("SCTP_SHUTDOWN_COMP\n");
295 case SCTP_CANT_STR_ASSOC:
296 printf("SCTP_CANT_STR_ASSOC\n");
302 } /* void print_sctp_sac_state() */
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.
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
315 int test_check_notification_type(struct msghdr *msg,
317 uint32_t additional) {
320 union sctp_notification *sn;
322 if (!(msg->msg_flags & MSG_NOTIFICATION)) {
326 /* Fixup for testframe. */
327 data = (char *)msg->msg_iov[0].iov_base;
329 sn = (union sctp_notification *)data;
331 if (sn->sn_header.sn_type != sn_type)
333 else if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE)
334 if (sn->sn_assoc_change.sac_state == additional)
340 /* Determine the type of event and make correct adjustments to the
343 int event_received(struct msghdr *inmessage, int assoc_num) {
347 printf("Event Received\n");
349 print_sctp_sac_state(inmessage);
351 if (mode == SERVER) {
352 /* Test type of Event */
353 error = test_check_notification_type(inmessage,
358 printf("Assosiation Established: count = %d.\n",
361 error = test_check_notification_type(inmessage,
367 printf("Assosiation Shutdown: count = %d.\n",
376 sockaddr_storage_t msgname;
381 struct msghdr inmessage;
384 char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
386 if ((big_buffer = malloc(REALLY_BIG)) == NULL) {
387 printf("malloc failure: %s\n", strerror(errno));
391 printf("Running in Server Mode...\n");
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);
405 server_socket = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
406 if (server_socket < 0) {
407 printf("Socket Failure: %s.\n", strerror(errno));
411 error = bind(server_socket, &server_loop.sa, sizeof(server_loop));
413 printf("Bind Failure: %s.\n", strerror(errno));
417 error = listen(server_socket, 1);
419 printf("Listen Failure: %s.\n", strerror(errno));
423 error = recvmsg(server_socket, &inmessage, MSG_WAITALL);
425 printf("Receive Failure: %s\n",
428 if (inmessage.msg_flags & MSG_NOTIFICATION)
429 assoc_num = event_received(&inmessage, assoc_num);
431 data_received(&inmessage, error, stream, server_socket);
438 int i, error, stream, max_socket = 0;
440 int client_socket[assoc_num];
441 char *message = "Awake";
447 printf("Running in Client Mode...\n");
449 /* Create the sockets */
450 for (i = 0; i < assoc_num; i++) {
451 client_socket[i] = socket(PF_INET, SOCK_SEQPACKET,
453 if (client_socket[i] < 0 ){
454 printf("Socket Failure: %s.\n", strerror(errno));
459 error = bind(client_socket[i], &client_loop.sa,
460 sizeof(client_loop));
462 printf("Bind Failure: %s\n", strerror(errno));
467 printf("Create Socket #: %d\n", client_socket[i]);
469 /* Connect to server and send initial message */
470 error = connect(client_socket[i], &server_loop.sa,
471 sizeof(server_loop));
473 printf("Connect Failure: %s.\n", strerror(errno));
477 max_socket = client_socket[i];
481 /* Send initial message */
482 error = sctp_sendmsg(client_socket[i],
485 (struct sockaddr *)&server_loop,
492 printf("Send Failure: %s.\n", strerror(errno));
499 /* Clear the set for select() */
502 /* Set time out values for select() */
506 /* Add the sockets select() will examine */
507 for (i = 0; i < assoc_num; i++) {
508 FD_SET(client_socket[i], &rfds);
511 /* Wait until there is data to be read from one of the
512 * sockets, or until the timer expires
514 error = select(max_socket + 1, &rfds, NULL, NULL, &tv);
517 printf("Select Failure: %s.\n", strerror(errno));
520 /* Loop through the array of sockets to find the ones
521 *that have information to be read
523 process_ready_sockets(client_socket, assoc_num, &rfds);
528 void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds) {
530 int i, stream, error;
531 struct msghdr inmessage;
534 char incmsg[CMSG_SPACE(sizeof (sctp_cmsg_data_t))];
535 sockaddr_storage_t msgname;
537 if ((big_buffer = malloc(REALLY_BIG)) == NULL) {
538 printf("malloc failure: %s\n", strerror(errno));
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);
555 for( i = 0; i < assoc_num; i++) {
556 if (FD_ISSET(client_socket[i], rfds)) {
557 error = recvmsg(client_socket[i], &inmessage,
560 printf("Receive Failure: %s\n",
563 /* Test to find the type of message that was read(event/data) */
564 if (inmessage.msg_flags &
566 event_received(&inmessage,
570 data_received(&inmessage, error,
578 int main(int argc, char *argv[]) {
580 parse_arguments(argc, argv);
582 if (mode == SERVER) {
584 } else if (mode == CLIENT){