source: mainline/uspace/app/nettest2/nettest2.c@ 192565b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 192565b was fff7ef4, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Make dnsr client initialization implicit (to allow for multiple consumers in the same program).

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup nettest
30 * @{
31 */
32
33/** @file
34 * Networking test 2 application - transfer.
35 */
36
37#include "nettest.h"
38#include "print_error.h"
39
40#include <malloc.h>
41#include <stdio.h>
42#include <unistd.h>
43#include <str.h>
44#include <task.h>
45#include <time.h>
46#include <arg_parse.h>
47#include <stdbool.h>
48
49#include <inet/dnsr.h>
50#include <net/in.h>
51#include <net/in6.h>
52#include <net/inet.h>
53#include <net/socket.h>
54#include <net/socket_parse.h>
55
56/** Echo module name. */
57#define NAME "Nettest2"
58
59/** Packet data pattern. */
60#define NETTEST2_TEXT "Networking test 2 - transfer"
61
62static size_t size;
63static bool verbose;
64static sock_type_t type;
65static int sockets;
66static int messages;
67static int family;
68static uint16_t port;
69
70static void nettest2_print_help(void)
71{
72 printf(
73 "Network Networking test 2 aplication - UDP transfer\n"
74 "Usage: nettest2 [options] host\n"
75 "Where options are:\n"
76 "-f protocol_family | --family=protocol_family\n"
77 "\tThe listenning socket protocol family. Only the PF_INET and "
78 "PF_INET6 are supported.\n"
79 "\n"
80 "-h | --help\n"
81 "\tShow this application help.\n"
82 "\n"
83 "-m count | --messages=count\n"
84 "\tThe number of messages to send and receive per socket. The "
85 "default is 10.\n"
86 "\n"
87 "-n sockets | --sockets=count\n"
88 "\tThe number of sockets to use. The default is 10.\n"
89 "\n"
90 "-p port_number | --port=port_number\n"
91 "\tThe port number the application should send messages to. The "
92 "default is 7.\n"
93 "\n"
94 "-s packet_size | --size=packet_size\n"
95 "\tThe packet data size the application sends. The default is 29 "
96 "bytes.\n"
97 "\n"
98 "-v | --verbose\n"
99 "\tShow all output messages.\n");
100}
101
102/** Fill buffer with the NETTEST2_TEXT pattern.
103 *
104 * @param buffer Data buffer.
105 * @param size Buffer size in bytes.
106 */
107static void nettest2_fill_buffer(char *buffer, size_t size)
108{
109 size_t length;
110
111 length = 0;
112 while (size > length + sizeof(NETTEST2_TEXT) - 1) {
113 memcpy(buffer + length, NETTEST2_TEXT,
114 sizeof(NETTEST2_TEXT) - 1);
115 length += sizeof(NETTEST2_TEXT) - 1;
116 }
117
118 memcpy(buffer + length, NETTEST2_TEXT, size - length);
119 buffer[size] = '\0';
120}
121
122/** Parse one command-line option.
123 *
124 * @param argc Number of all command-line arguments.
125 * @param argv All command-line arguments.
126 * @param index Current argument index (in, out).
127 */
128static int nettest2_parse_opt(int argc, char *argv[], int *index)
129{
130 int value;
131 int rc;
132
133 switch (argv[*index][1]) {
134 /*
135 * Short options with only one letter
136 */
137 case 'f':
138 rc = arg_parse_name_int(argc, argv, index, &family, 0,
139 socket_parse_protocol_family);
140 if (rc != EOK)
141 return rc;
142 break;
143 case 'h':
144 nettest2_print_help();
145 return EOK;
146 break;
147 case 'm':
148 rc = arg_parse_int(argc, argv, index, &messages, 0);
149 if (rc != EOK)
150 return rc;
151 break;
152 case 'n':
153 rc = arg_parse_int(argc, argv, index, &sockets, 0);
154 if (rc != EOK)
155 return rc;
156 break;
157 case 'p':
158 rc = arg_parse_int(argc, argv, index, &value, 0);
159 if (rc != EOK)
160 return rc;
161 port = (uint16_t) value;
162 break;
163 case 's':
164 rc = arg_parse_int(argc, argv, index, &value, 0);
165 if (rc != EOK)
166 return rc;
167 size = (value >= 0) ? (size_t) value : 0;
168 break;
169 case 't':
170 rc = arg_parse_name_int(argc, argv, index, &value, 0,
171 socket_parse_socket_type);
172 if (rc != EOK)
173 return rc;
174 type = (sock_type_t) value;
175 break;
176 case 'v':
177 verbose = true;
178 break;
179 /*
180 * Long options with double dash ('-')
181 */
182 case '-':
183 if (str_lcmp(argv[*index] + 2, "family=", 7) == 0) {
184 rc = arg_parse_name_int(argc, argv, index, &family, 9,
185 socket_parse_protocol_family);
186 if (rc != EOK)
187 return rc;
188 } else if (str_lcmp(argv[*index] + 2, "help", 5) == 0) {
189 nettest2_print_help();
190 return EOK;
191 } else if (str_lcmp(argv[*index] + 2, "messages=", 6) == 0) {
192 rc = arg_parse_int(argc, argv, index, &messages, 8);
193 if (rc != EOK)
194 return rc;
195 } else if (str_lcmp(argv[*index] + 2, "sockets=", 6) == 0) {
196 rc = arg_parse_int(argc, argv, index, &sockets, 8);
197 if (rc != EOK)
198 return rc;
199 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) {
200 rc = arg_parse_int(argc, argv, index, &value, 7);
201 if (rc != EOK)
202 return rc;
203 port = (uint16_t) value;
204 } else if (str_lcmp(argv[*index] + 2, "type=", 5) == 0) {
205 rc = arg_parse_name_int(argc, argv, index, &value, 7,
206 socket_parse_socket_type);
207 if (rc != EOK)
208 return rc;
209 type = (sock_type_t) value;
210 } else if (str_lcmp(argv[*index] + 2, "verbose", 8) == 0) {
211 verbose = 1;
212 } else {
213 nettest2_print_help();
214 return EINVAL;
215 }
216 break;
217 default:
218 nettest2_print_help();
219 return EINVAL;
220 }
221
222 return EOK;
223}
224
225int main(int argc, char *argv[])
226{
227 struct sockaddr *address;
228 struct sockaddr_in address_in;
229 struct sockaddr_in6 address_in6;
230 dnsr_hostinfo_t *hinfo;
231 socklen_t addrlen;
232 uint8_t *address_start;
233
234 int *socket_ids;
235 char *data;
236 int index;
237 struct timeval time_before;
238 struct timeval time_after;
239
240 int rc;
241
242 size = 28;
243 verbose = false;
244 type = SOCK_DGRAM;
245 sockets = 10;
246 messages = 10;
247 family = PF_INET;
248 port = 7;
249
250 /*
251 * Parse the command line arguments.
252 *
253 * Stop before the last argument if it does not start with dash ('-')
254 */
255 for (index = 1; (index < argc - 1) || ((index == argc - 1) &&
256 (argv[index][0] == '-')); ++index) {
257
258 /* Options should start with dash ('-') */
259 if (argv[index][0] == '-') {
260 rc = nettest2_parse_opt(argc, argv, &index);
261 if (rc != EOK)
262 return rc;
263 } else {
264 nettest2_print_help();
265 return EINVAL;
266 }
267 }
268
269 /* If not before the last argument containing the host */
270 if (index >= argc) {
271 printf("Command line error: missing host name\n");
272 nettest2_print_help();
273 return EINVAL;
274 }
275
276 /* Prepare the address buffer */
277
278 switch (family) {
279 case PF_INET:
280 address_in.sin_family = AF_INET;
281 address_in.sin_port = htons(port);
282 address = (struct sockaddr *) &address_in;
283 addrlen = sizeof(address_in);
284 address_start = (uint8_t *) &address_in.sin_addr.s_addr;
285 break;
286 case PF_INET6:
287 address_in6.sin6_family = AF_INET6;
288 address_in6.sin6_port = htons(port);
289 address = (struct sockaddr *) &address_in6;
290 addrlen = sizeof(address_in6);
291 address_start = (uint8_t *) &address_in6.sin6_addr.s6_addr;
292 break;
293 default:
294 fprintf(stderr, "Address family is not supported\n");
295 return EAFNOSUPPORT;
296 }
297
298 /* Parse the last argument which should contain the host/address */
299 rc = inet_pton(family, argv[argc - 1], address_start);
300 if (rc != EOK) {
301 /* Try interpreting as a host name */
302 rc = dnsr_name2host(argv[argc - 1], &hinfo);
303 if (rc != EOK) {
304 printf("Error resolving host '%s'.\n", argv[argc - 1]);
305 return rc;
306 }
307
308 address_in.sin_addr.s_addr = host2uint32_t_be(hinfo->addr.ipv4);
309 }
310
311 /* Check data buffer size. */
312 if (size <= 0) {
313 fprintf(stderr, "Data buffer size too small (%zu). Using 1024 "
314 "bytes instead.\n", size);
315 size = 1024;
316 }
317
318 /*
319 * Prepare the buffer. Allocate size bytes plus one for terminating
320 * null character.
321 */
322 data = (char *) malloc(size + 1);
323 if (!data) {
324 fprintf(stderr, "Failed to allocate data buffer.\n");
325 return ENOMEM;
326 }
327
328 /* Fill buffer with a pattern. */
329 nettest2_fill_buffer(data, size);
330
331 /* Check socket count. */
332 if (sockets <= 0) {
333 fprintf(stderr, "Socket count too small (%d). Using "
334 "2 instead.\n", sockets);
335 sockets = 2;
336 }
337
338 /*
339 * Prepare the socket buffer.
340 * Allocate count entries plus the terminating null (\0)
341 */
342 socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
343 if (!socket_ids) {
344 fprintf(stderr, "Failed to allocate receive buffer.\n");
345 return ENOMEM;
346 }
347 socket_ids[sockets] = 0;
348
349 if (verbose)
350 printf("Starting tests\n");
351
352 rc = sockets_create(verbose, socket_ids, sockets, family, type);
353 if (rc != EOK)
354 return rc;
355
356 if (type == SOCK_STREAM) {
357 rc = sockets_connect(verbose, socket_ids, sockets,
358 address, addrlen);
359 if (rc != EOK)
360 return rc;
361 }
362
363 if (verbose)
364 printf("\n");
365
366 rc = gettimeofday(&time_before, NULL);
367 if (rc != EOK) {
368 fprintf(stderr, "Get time of day error %d\n", rc);
369 return rc;
370 }
371
372 rc = sockets_sendto_recvfrom(verbose, socket_ids, sockets, address,
373 &addrlen, data, size, messages);
374 if (rc != EOK)
375 return rc;
376
377 rc = gettimeofday(&time_after, NULL);
378 if (rc != EOK) {
379 fprintf(stderr, "Get time of day error %d\n", rc);
380 return rc;
381 }
382
383 if (verbose)
384 printf("\tOK\n");
385
386 printf("sendto + recvfrom tested in %ld microseconds\n",
387 tv_sub(&time_after, &time_before));
388
389 rc = gettimeofday(&time_before, NULL);
390 if (rc != EOK) {
391 fprintf(stderr, "Get time of day error %d\n", rc);
392 return rc;
393 }
394
395 rc = sockets_sendto(verbose, socket_ids, sockets, address, addrlen,
396 data, size, messages);
397 if (rc != EOK)
398 return rc;
399
400 rc = sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen,
401 data, size, messages);
402 if (rc != EOK)
403 return rc;
404
405 rc = gettimeofday(&time_after, NULL);
406 if (rc != EOK) {
407 fprintf(stderr, "Get time of day error %d\n", rc);
408 return rc;
409 }
410
411 if (verbose)
412 printf("\tOK\n");
413
414 printf("sendto, recvfrom tested in %ld microseconds\n",
415 tv_sub(&time_after, &time_before));
416
417 rc = sockets_close(verbose, socket_ids, sockets);
418 if (rc != EOK)
419 return rc;
420
421 if (verbose)
422 printf("\nExiting\n");
423
424 return EOK;
425}
426
427/** @}
428 */
Note: See TracBrowser for help on using the repository browser.