Imported Upstream version 1.0.10
[platform/upstream/lksctp-tools.git] / src / apps / nagle_rcv.c
1 /* SCTP kernel Implementation
2  * (C) Copyright IBM Corp. 2002, 2003
3  * Copyright (c) 1999-2000 Cisco, Inc.
4  * Copyright (c) 1999-2001 Motorola, Inc.
5  * Copyright (c) 2001 Intel Corp.
6  * Copyright (c) 2001 Nokia, Inc.
7  *
8  * The SCTP implementation is free software;
9  * you can redistribute it and/or modify it under the terms of
10  * the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * The SCTP implementation is distributed in the hope that it
15  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16  *                 ************************
17  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18  * See the GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with GNU CC; see the file COPYING.  If not, write to
22  * the Free Software Foundation, 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  * Please send any bug reports or fixes you make to the
26  * email address(es):
27  *    lksctp developers <lksctp-developers@lists.sourceforge.net>
28  *
29  * Or submit a bug report through the following website:
30  *    http://www.sf.net/projects/lksctp
31  *
32  * Any bugs reported to us we will try to fix... any fixes shared will
33  * be incorporated into the next SCTP release.
34  *
35  * Written or modified by:
36  *    Ardelle Fan <ardelle.fan@intel.com>
37  *    Sridhar Samudrala <sri@us.ibm.com>
38  */
39
40 /* This is a receiver for the performance test to verify Nagle's algorithm. 
41  * It creates a socket, binds to a address specified as a parameter and
42  * goes into a receive loop waiting for 1,000,000 packets. Then it calculates
43  * the packet receive rate, i.e. packets/second.
44  */
45
46 #include <stdio.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <sys/uio.h>
53 #include <netinet/in.h>
54 #include <sys/errno.h>
55 #include <errno.h>
56 #include <netinet/sctp.h>
57 #include <sctputil.h>
58 #include <getopt.h>
59 #include <netdb.h>
60 #include <time.h>
61
62 char *TCID = __FILE__;
63 int TST_TOTAL = 1;
64 int TST_CNT = 0;
65
66 void
67 usage(char *progname)
68 {
69         fprintf(stderr, "Usage: %s -H hostname [-P port]\n", progname);
70         fprintf(stderr, " -H, --local\t\t local hostname,\n");
71         fprintf(stderr, " -P, --local-port\t local port,\n");
72 }
73
74 int
75 main(int argc, char *argv[])
76 {
77         int sk, i;
78         struct hostent *hst;
79         sockaddr_storage_t host;
80         sockaddr_storage_t msgname;
81         struct iovec iov;
82         struct msghdr inmessage;
83         char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
84         int error;
85         int pf_class, af_family;
86         char *big_buffer;
87         char *local_host = NULL;
88         int local_port = SCTP_TESTPORT_1; 
89         int option_index = 0;
90         time_t from, to;
91         int bytes_received = 0; 
92         int c;
93         static struct option long_options[] = {
94                 {"local",       1, 0, 1},
95                 {"local-port",  1, 0, 2},
96                 {0,             0, 0, 0}
97         };
98
99         /* Rather than fflush() throughout the code, set stdout to 
100          * be unbuffered. 
101          */
102         setvbuf(stdout, NULL, _IONBF, 0); 
103
104         /* Parse the arguments.  */
105         while (1) {
106                 c = getopt_long (argc, argv, "H:P:",
107                                  long_options, &option_index);
108                 if (c == -1)
109                         break;
110
111                 switch (c) {
112                 case 0:
113                         printf("option %s", long_options[option_index].name);
114                         if (optarg) {
115                                 printf(" with arg %s", optarg);
116                         }
117                         printf("\n");
118                         break;
119                 case 1:         /* local host */
120                 case 'H':
121                         local_host = optarg;
122                         break;
123                 case 2:         /* local port */
124                 case 'P':
125                         local_port = atoi(optarg);
126                         break;
127                 case '?':
128                         usage(argv[0]);
129                         exit(0);
130
131                 default:
132                         printf ("%s: unrecognized option 0%c\n", argv[0], c);
133                         usage(argv[0]);
134                         exit(1);
135                 }
136         }
137
138         if (optind < argc)
139         {
140                 fprintf(stderr, "%s: non-option arguments are illegal: ",
141                         argv[0]);
142                 while (optind < argc)
143                         fprintf(stderr, "%s ", argv[optind++]);
144                 fprintf (stderr, "\n");
145                 usage(argv[0]);
146                 exit(1);
147         }
148
149         if (!local_host) {
150                 fprintf(stderr, "%s: : option -H, --local is required\n",
151                         argv[0]);
152                 usage(argv[0]);
153                 exit(1);
154         }
155         
156         /* Set some basic values which depend on the address family. */
157 #if TEST_V6
158         hst = gethostbyname2(local_host, AF_INET6);
159         if (hst == NULL || hst->h_length < 1) {
160                 fprintf(stderr, "%s: bad hostname: %s\n", argv[0], local_host);
161                 exit(1);
162         }
163         pf_class = PF_INET6;
164         af_family = AF_INET6;
165
166         host.v6.sin6_family = AF_INET6;
167         memcpy(&host.v6.sin_addr, hst->h_addr_list[0], hst->h_length);
168         host.v6.sin6_port = htons(local_port);
169
170 #else
171         hst = gethostbyname(local_host);
172         if (hst == NULL || hst->h_length < 1) {
173                 fprintf(stderr, "%s: bad hostname: %s\n", argv[0], local_host);
174                 exit(1);
175         }
176         pf_class = PF_INET;
177         af_family = AF_INET;
178
179         host.v4.sin_family = AF_INET;
180         memcpy(&host.v4.sin_addr, hst->h_addr_list[0], hst->h_length);
181         host.v4.sin_port = htons(local_port);
182
183 #endif /* TEST_V6 */
184
185         /* Create the endpoint which will talk to nagle_snd.  */
186         sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
187
188         /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */
189         test_enable_assoc_change(sk);
190
191         /* Bind the sockets to the test port.  */
192         test_bind(sk, &host.sa, sizeof(host));
193         
194        /* Mark sk as being able to accept new associations.  */
195         test_listen(sk, 1);
196        
197         printf("Listening on port:%d\n", local_port);
198  
199         /* Initialize inmessage for receives. */
200         memset(&inmessage, 0, sizeof(inmessage));       
201         big_buffer = test_malloc(REALLY_BIG);
202         iov.iov_base = big_buffer;
203         iov.iov_len = REALLY_BIG;
204         inmessage.msg_iov = &iov;
205         inmessage.msg_iovlen = 1;
206         inmessage.msg_control = incmsg;
207         inmessage.msg_controllen = sizeof(incmsg);
208         inmessage.msg_name = &msgname;
209         inmessage.msg_namelen = sizeof(msgname);
210         memset(&msgname, 0, sizeof(msgname));
211
212         /* Get the communication up message on sk.  */
213         error = test_recvmsg(sk, &inmessage, MSG_WAITALL);
214         test_check_msg_notification(&inmessage, error,
215                                     sizeof(struct sctp_assoc_change),
216                                     SCTP_ASSOC_CHANGE, SCTP_COMM_UP);   
217
218         printf("Established connection with "); 
219         if (AF_INET == msgname.sa.sa_family)
220                 printf("%d.%d.%d.%d(%d)\n", NIPQUAD(msgname.v4.sin_addr),
221                        ntohs(msgname.v4.sin_port));
222         if (AF_INET6 == msgname.sa.sa_family)
223                 printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x(%d)\n",
224                        NIP6(msgname.v6.sin6_addr), ntohs(msgname.v6.sin6_port));
225
226         time(&from);
227         for (i=0; i<1000000; i++) {
228                 inmessage.msg_controllen = sizeof(incmsg);
229                 inmessage.msg_namelen = sizeof(msgname);
230                 error = test_recvmsg(sk, &inmessage, MSG_WAITALL);
231                 if (inmessage.msg_flags & MSG_NOTIFICATION)
232                         break;
233                 printf("Received %d bytes of data\n", error);
234                 bytes_received += error;
235         }
236         time(&to);
237
238         printf("\t%d messages(%d bytes) successfully received in %ld "
239                "seconds.\n", i, bytes_received, to - from);
240         printf("The receive rate is %ld bytes/second\n",
241                bytes_received/(to - from));
242
243         /* Shut down the link.  */
244         error = 0;
245         close(sk);
246
247         return 0;
248 }