source: mainline/uspace/srv/net/app/nettest2/nettest2.c@ aadf01e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since aadf01e was aadf01e, checked in by Lukas Mejdrech <lukasmejdrech@…>, 15 years ago

Coding style (no functional change)

  • Property mode set to 100644
File size: 19.0 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 <malloc.h>
38#include <stdio.h>
39#include <string.h>
40#include <task.h>
41#include <time.h>
42
43#include "../../include/in.h"
44#include "../../include/in6.h"
45#include "../../include/inet.h"
46#include "../../include/socket.h"
47
48#include "../../err.h"
49
50#include "../parse.h"
51#include "../print_error.h"
52
53/** Echo module name.
54 */
55#define NAME "Nettest2"
56
57/** Packet data pattern.
58 */
59#define NETTEST2_TEXT "Networking test 2 - transfer"
60
61/** Module entry point.
62 * Starts testing.
63 * @param[in] argc The number of command line parameters.
64 * @param[in] argv The command line parameters.
65 * @returns EOK on success.
66 */
67int main(int argc, char * argv[]);
68
69/** Prints the application help.
70 */
71void print_help(void);
72
73/** Translates the character string to the protocol family number.
74 * @param[in] name The protocol family name.
75 * @returns The corresponding protocol family number.
76 * @returns EPFNOSUPPORTED if the protocol family is not supported.
77 */
78int parse_protocol_family(const char * name);
79
80/** Translates the character string to the socket type number.
81 * @param[in] name The socket type name.
82 * @returns The corresponding socket type number.
83 * @returns ESOCKNOSUPPORTED if the socket type is not supported.
84 */
85int parse_socket_type(const char * name);
86
87/** Refreshes the data.
88 * Fills the data block with the NETTEST1_TEXT pattern.
89 * @param[out] data The data block.
90 * @param[in] size The data block size in bytes.
91 */
92void refresh_data(char * data, size_t size);
93
94/** Creates new sockets.
95 * @param[in] verbose A value indicating whether to print out verbose information.
96 * @param[out] socket_ids A field to store the socket identifiers.
97 * @param[in] sockets The number of sockets to create. Should be at most the size of the field.
98 * @param[in] family The socket address family.
99 * @param[in] type The socket type.
100 * @returns EOK on success.
101 * @returns Other error codes as defined for the socket() function.
102 */
103int sockets_create(int verbose, int * socket_ids, int sockets, int family, sock_type_t type);
104
105/** Closes sockets.
106 * @param[in] verbose A value indicating whether to print out verbose information.
107 * @param[in] socket_ids A field of stored socket identifiers.
108 * @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
109 * @returns EOK on success.
110 * @returns Other error codes as defined for the closesocket() function.
111 */
112int sockets_close(int verbose, int * socket_ids, int sockets);
113
114/** Connects sockets.
115 * @param[in] verbose A value indicating whether to print out verbose information.
116 * @param[in] socket_ids A field of stored socket identifiers.
117 * @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
118 * @param[in] address The destination host address to connect to.
119 * @param[in] addrlen The length of the destination address in bytes.
120 * @returns EOK on success.
121 * @returns Other error codes as defined for the connect() function.
122 */
123int sockets_connect(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen);
124
125/** Sends data via sockets.
126 * @param[in] verbose A value indicating whether to print out verbose information.
127 * @param[in] socket_ids A field of stored socket identifiers.
128 * @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
129 * @param[in] address The destination host address to send data to.
130 * @param[in] addrlen The length of the destination address in bytes.
131 * @param[in] data The data to be sent.
132 * @param[in] size The data size in bytes.
133 * @param[in] messages The number of datagrams per socket to be sent.
134 * @returns EOK on success.
135 * @returns Other error codes as defined for the sendto() function.
136 */
137int sockets_sendto(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen, char * data, int size, int messages);
138
139/** Receives data via sockets.
140 * @param[in] verbose A value indicating whether to print out verbose information.
141 * @param[in] socket_ids A field of stored socket identifiers.
142 * @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
143 * @param[in] address The source host address of received datagrams.
144 * @param[in,out] addrlen The maximum length of the source address in bytes. The actual size of the source address is set instead.
145 * @param[out] data The received data.
146 * @param[in] size The maximum data size in bytes.
147 * @param[in] messages The number of datagrams per socket to be received.
148 * @returns EOK on success.
149 * @returns Other error codes as defined for the recvfrom() function.
150 */
151int sockets_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages);
152
153/** Sends and receives data via sockets.
154 * Each datagram is sent and a reply read consequently.
155 * The next datagram is sent after the reply is received.
156 * @param[in] verbose A value indicating whether to print out verbose information.
157 * @param[in] socket_ids A field of stored socket identifiers.
158 * @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
159 * @param[in,out] address The destination host address to send data to. The source host address of received datagrams is set instead.
160 * @param[in] addrlen The length of the destination address in bytes.
161 * @param[in,out] data The data to be sent. The received data are set instead.
162 * @param[in] size The data size in bytes.
163 * @param[in] messages The number of datagrams per socket to be received.
164 * @returns EOK on success.
165 * @returns Other error codes as defined for the recvfrom() function.
166 */
167int sockets_sendto_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages);
168
169/** Prints a mark.
170 * If the index is a multiple of ten, a different mark is printed.
171 * @param[in] index The index of the mark to be printed.
172 */
173void print_mark(int index);
174
175void print_help(void){
176 printf(
177 "Network Networking test 2 aplication - UDP transfer\n" \
178 "Usage: echo [options] numeric_address\n" \
179 "Where options are:\n" \
180 "-f protocol_family | --family=protocol_family\n" \
181 "\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
182 "\n" \
183 "-h | --help\n" \
184 "\tShow this application help.\n"
185 "\n" \
186 "-m count | --messages=count\n" \
187 "\tThe number of messages to send and receive per socket. The default is 10.\n" \
188 "\n" \
189 "-n sockets | --sockets=count\n" \
190 "\tThe number of sockets to use. The default is 10.\n" \
191 "\n" \
192 "-p port_number | --port=port_number\n" \
193 "\tThe port number the application should send messages to. The default is 7.\n" \
194 "\n" \
195 "-s packet_size | --size=packet_size\n" \
196 "\tThe packet data size the application sends. The default is 29 bytes.\n" \
197 "\n" \
198 "-v | --verbose\n" \
199 "\tShow all output messages.\n"
200 );
201}
202
203int parse_protocol_family(const char * name){
204 if(str_lcmp(name, "PF_INET", 7) == 0){
205 return PF_INET;
206 }else if(str_lcmp(name, "PF_INET6", 8) == 0){
207 return PF_INET6;
208 }
209 return EPFNOSUPPORT;
210}
211
212int parse_socket_type(const char * name){
213 if(str_lcmp(name, "SOCK_DGRAM", 11) == 0){
214 return SOCK_DGRAM;
215 }else if(str_lcmp(name, "SOCK_STREAM", 12) == 0){
216 return SOCK_STREAM;
217 }
218 return ESOCKTNOSUPPORT;
219}
220
221void refresh_data(char * data, size_t size){
222 size_t length;
223
224 // fill the data
225 length = 0;
226 while(size > length + sizeof(NETTEST2_TEXT) - 1){
227 memcpy(data + length, NETTEST2_TEXT, sizeof(NETTEST2_TEXT) - 1);
228 length += sizeof(NETTEST2_TEXT) - 1;
229 }
230 memcpy(data + length, NETTEST2_TEXT, size - length);
231 data[size] = '\0';
232}
233
234int sockets_create(int verbose, int * socket_ids, int sockets, int family, sock_type_t type){
235 int index;
236
237 if(verbose){
238 printf("Create\t");
239 }
240 fflush(stdout);
241 for(index = 0; index < sockets; ++ index){
242 socket_ids[index] = socket(family, type, 0);
243 if(socket_ids[index] < 0){
244 printf("Socket %d (%d) error:\n", index, socket_ids[index]);
245 socket_print_error(stderr, socket_ids[index], "Socket create: ", "\n");
246 return socket_ids[index];
247 }
248 if(verbose){
249 print_mark(index);
250 }
251 }
252 return EOK;
253}
254
255int sockets_close(int verbose, int * socket_ids, int sockets){
256 ERROR_DECLARE;
257
258 int index;
259
260 if(verbose){
261 printf("\tClose\t");
262 }
263 fflush(stdout);
264 for(index = 0; index < sockets; ++ index){
265 if(ERROR_OCCURRED(closesocket(socket_ids[index]))){
266 printf("Socket %d (%d) error:\n", index, socket_ids[index]);
267 socket_print_error(stderr, ERROR_CODE, "Socket close: ", "\n");
268 return ERROR_CODE;
269 }
270 if(verbose){
271 print_mark(index);
272 }
273 }
274 return EOK;
275}
276
277int sockets_connect(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen){
278 ERROR_DECLARE;
279
280 int index;
281
282 if(verbose){
283 printf("\tConnect\t");
284 }
285 fflush(stdout);
286 for(index = 0; index < sockets; ++ index){
287 if(ERROR_OCCURRED(connect(socket_ids[index], address, addrlen))){
288 socket_print_error(stderr, ERROR_CODE, "Socket connect: ", "\n");
289 return ERROR_CODE;
290 }
291 if(verbose){
292 print_mark(index);
293 }
294 }
295 return EOK;
296}
297
298int sockets_sendto(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen, char * data, int size, int messages){
299 ERROR_DECLARE;
300
301 int index;
302 int message;
303
304 if(verbose){
305 printf("\tSendto\t");
306 }
307 fflush(stdout);
308 for(index = 0; index < sockets; ++ index){
309 for(message = 0; message < messages; ++ message){
310 if(ERROR_OCCURRED(sendto(socket_ids[index], data, size, 0, address, addrlen))){
311 printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
312 socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n");
313 return ERROR_CODE;
314 }
315 }
316 if(verbose){
317 print_mark(index);
318 }
319 }
320 return EOK;
321}
322
323int sockets_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages){
324 int value;
325 int index;
326 int message;
327
328 if(verbose){
329 printf("\tRecvfrom\t");
330 }
331 fflush(stdout);
332 for(index = 0; index < sockets; ++ index){
333 for(message = 0; message < messages; ++ message){
334 value = recvfrom(socket_ids[index], data, size, 0, address, addrlen);
335 if(value < 0){
336 printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
337 socket_print_error(stderr, value, "Socket receive: ", "\n");
338 return value;
339 }
340 }
341 if(verbose){
342 print_mark(index);
343 }
344 }
345 return EOK;
346}
347
348int sockets_sendto_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages){
349 ERROR_DECLARE;
350
351 int value;
352 int index;
353 int message;
354
355 if(verbose){
356 printf("\tSendto and recvfrom\t");
357 }
358 fflush(stdout);
359 for(index = 0; index < sockets; ++ index){
360 for(message = 0; message < messages; ++ message){
361 if(ERROR_OCCURRED(sendto(socket_ids[index], data, size, 0, address, * addrlen))){
362 printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
363 socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n");
364 return ERROR_CODE;
365 }
366 value = recvfrom(socket_ids[index], data, size, 0, address, addrlen);
367 if(value < 0){
368 printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
369 socket_print_error(stderr, value, "Socket receive: ", "\n");
370 return value;
371 }
372 }
373 if(verbose){
374 print_mark(index);
375 }
376 }
377 return EOK;
378}
379
380void print_mark(int index){
381 if((index + 1) % 10){
382 printf("*");
383 }else{
384 printf("|");
385 }
386 fflush(stdout);
387}
388
389int main(int argc, char * argv[]){
390 ERROR_DECLARE;
391
392 size_t size = 28;
393 int verbose = 0;
394 sock_type_t type = SOCK_DGRAM;
395 int sockets = 10;
396 int messages = 10;
397 int family = PF_INET;
398 uint16_t port = 7;
399
400 socklen_t max_length = sizeof(struct sockaddr_in6);
401 uint8_t address_data[max_length];
402 struct sockaddr * address = (struct sockaddr *) address_data;
403 struct sockaddr_in * address_in = (struct sockaddr_in *) address;
404 struct sockaddr_in6 * address_in6 = (struct sockaddr_in6 *) address;
405 socklen_t addrlen;
406// char address_string[INET6_ADDRSTRLEN];
407 uint8_t * address_start;
408
409 int * socket_ids;
410 char * data;
411 int value;
412 int index;
413 struct timeval time_before;
414 struct timeval time_after;
415
416 printf("Task %d - ", task_get_id());
417 printf("%s\n", NAME);
418
419 if(argc <= 1){
420 print_help();
421 return EINVAL;
422 }
423
424 for(index = 1; (index < argc - 1) || ((index == argc) && (argv[index][0] == '-')); ++ index){
425 if(argv[index][0] == '-'){
426 switch(argv[index][1]){
427 case 'f':
428 ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 0, parse_protocol_family));
429 break;
430 case 'h':
431 print_help();
432 return EOK;
433 break;
434 case 'm':
435 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 0));
436 break;
437 case 'n':
438 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 0));
439 break;
440 case 'p':
441 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 0));
442 port = (uint16_t) value;
443 break;
444 case 's':
445 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
446 size = (value >= 0) ? (size_t) value : 0;
447 break;
448 case 't':
449 ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 0, parse_socket_type));
450 type = (sock_type_t) value;
451 break;
452 case 'v':
453 verbose = 1;
454 break;
455 case '-':
456 if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
457 ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 9, parse_protocol_family));
458 }else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
459 print_help();
460 return EOK;
461 }else if(str_lcmp(argv[index] + 2, "messages=", 6) == 0){
462 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 8));
463 }else if(str_lcmp(argv[index] + 2, "sockets=", 6) == 0){
464 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 8));
465 }else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
466 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 7));
467 port = (uint16_t) value;
468 }else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
469 ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 7, parse_socket_type));
470 type = (sock_type_t) value;
471 }else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
472 verbose = 1;
473 }else{
474 print_unrecognized(index, argv[index] + 2);
475 print_help();
476 return EINVAL;
477 }
478 break;
479 default:
480 print_unrecognized(index, argv[index] + 1);
481 print_help();
482 return EINVAL;
483 }
484 }else{
485 print_unrecognized(index, argv[index]);
486 print_help();
487 return EINVAL;
488 }
489 }
490
491 bzero(address_data, max_length);
492 switch(family){
493 case PF_INET:
494 address_in->sin_family = AF_INET;
495 address_in->sin_port = htons(port);
496 address_start = (uint8_t *) &address_in->sin_addr.s_addr;
497 addrlen = sizeof(struct sockaddr_in);
498 break;
499 case PF_INET6:
500 address_in6->sin6_family = AF_INET6;
501 address_in6->sin6_port = htons(port);
502 address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
503 addrlen = sizeof(struct sockaddr_in6);
504 break;
505 default:
506 fprintf(stderr, "Address family is not supported\n");
507 return EAFNOSUPPORT;
508 }
509
510 if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
511 fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
512 return ERROR_CODE;
513 }
514
515 if(size <= 0){
516 fprintf(stderr, "Data buffer size too small (%d). Using 1024 bytes instead.\n", size);
517 size = 1024;
518 }
519 // size plus terminating null (\0)
520 data = (char *) malloc(size + 1);
521 if(! data){
522 fprintf(stderr, "Failed to allocate data buffer.\n");
523 return ENOMEM;
524 }
525 refresh_data(data, size);
526
527 if(sockets <= 0){
528 fprintf(stderr, "Socket count too small (%d). Using 2 instead.\n", sockets);
529 sockets = 2;
530 }
531 // count plus terminating null (\0)
532 socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
533 if(! socket_ids){
534 fprintf(stderr, "Failed to allocate receive buffer.\n");
535 return ENOMEM;
536 }
537 socket_ids[sockets] = NULL;
538
539 if(verbose){
540 printf("Starting tests\n");
541 }
542
543 ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
544
545 if(type == SOCK_STREAM){
546 ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
547 }
548
549 if(verbose){
550 printf("\n");
551 }
552
553 if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
554 fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
555 return ERROR_CODE;
556 }
557
558 ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
559
560 if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
561 fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
562 return ERROR_CODE;
563 }
564
565 if(verbose){
566 printf("\tOK\n");
567 }
568
569 printf("sendto + recvfrom tested in %d microseconds\n", tv_sub(&time_after, &time_before));
570
571 if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
572 fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
573 return ERROR_CODE;
574 }
575
576 ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, sockets, address, addrlen, data, size, messages));
577 ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
578
579 if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
580 fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
581 return ERROR_CODE;
582 }
583
584 if(verbose){
585 printf("\tOK\n");
586 }
587
588 printf("sendto, recvfrom tested in %d microseconds\n", tv_sub(&time_after, &time_before));
589
590 ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
591
592 if(verbose){
593 printf("\nExiting\n");
594 }
595
596 return EOK;
597}
598
599/** @}
600 */
Note: See TracBrowser for help on using the repository browser.