nettest2.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00037 #include "nettest.h"
00038 #include "print_error.h"
00039 
00040 #include <malloc.h>
00041 #include <stdio.h>
00042 #include <str.h>
00043 #include <task.h>
00044 #include <time.h>
00045 #include <arg_parse.h>
00046 #include <bool.h>
00047 
00048 #include <net/in.h>
00049 #include <net/in6.h>
00050 #include <net/inet.h>
00051 #include <net/socket.h>
00052 #include <net/socket_parse.h>
00053 
00055 #define NAME    "Nettest2"
00056 
00058 #define NETTEST2_TEXT   "Networking test 2 - transfer"
00059 
00060 static size_t size;
00061 static bool verbose;
00062 static sock_type_t type;
00063 static int sockets;
00064 static int messages;
00065 static int family;
00066 static uint16_t port;
00067 
00068 static void nettest2_print_help(void)
00069 {
00070         printf(
00071             "Network Networking test 2 aplication - UDP transfer\n"
00072             "Usage: echo [options] address\n"
00073             "Where options are:\n"
00074             "-f protocol_family | --family=protocol_family\n"
00075             "\tThe listenning socket protocol family. Only the PF_INET and "
00076             "PF_INET6 are supported.\n"
00077             "\n"
00078             "-h | --help\n"
00079             "\tShow this application help.\n"
00080             "\n"
00081             "-m count | --messages=count\n"
00082             "\tThe number of messages to send and receive per socket. The "
00083             "default is 10.\n"
00084             "\n"
00085             "-n sockets | --sockets=count\n"
00086             "\tThe number of sockets to use. The default is 10.\n"
00087             "\n"
00088             "-p port_number | --port=port_number\n"
00089             "\tThe port number the application should send messages to. The "
00090             "default is 7.\n"
00091             "\n"
00092             "-s packet_size | --size=packet_size\n"
00093             "\tThe packet data size the application sends. The default is 29 "
00094             "bytes.\n"
00095             "\n"
00096             "-v | --verbose\n"
00097             "\tShow all output messages.\n");
00098 }
00099 
00105 static void nettest2_fill_buffer(char *buffer, size_t size)
00106 {
00107         size_t length;
00108 
00109         length = 0;
00110         while (size > length + sizeof(NETTEST2_TEXT) - 1) {
00111                 memcpy(buffer + length, NETTEST2_TEXT,
00112                     sizeof(NETTEST2_TEXT) - 1);
00113                 length += sizeof(NETTEST2_TEXT) - 1;
00114         }
00115 
00116         memcpy(buffer + length, NETTEST2_TEXT, size - length);
00117         buffer[size] = '\0';
00118 }
00119 
00126 static int nettest2_parse_opt(int argc, char *argv[], int *index)
00127 {
00128         int value;
00129         int rc;
00130 
00131         switch (argv[*index][1]) {
00132         /*
00133          * Short options with only one letter
00134          */
00135         case 'f':
00136                 rc = arg_parse_name_int(argc, argv, index, &family, 0,
00137                     socket_parse_protocol_family);
00138                 if (rc != EOK)
00139                         return rc;
00140                 break;
00141         case 'h':
00142                 nettest2_print_help();
00143                 return EOK;
00144                 break;
00145         case 'm':
00146                 rc = arg_parse_int(argc, argv, index, &messages, 0);
00147                 if (rc != EOK)
00148                         return rc;
00149                 break;
00150         case 'n':
00151                 rc = arg_parse_int(argc, argv, index, &sockets, 0);
00152                 if (rc != EOK)
00153                         return rc;
00154                 break;
00155         case 'p':
00156                 rc = arg_parse_int(argc, argv, index, &value, 0);
00157                 if (rc != EOK)
00158                         return rc;
00159                 port = (uint16_t) value;
00160                 break;
00161         case 's':
00162                 rc = arg_parse_int(argc, argv, index, &value, 0);
00163                 if (rc != EOK)
00164                         return rc;
00165                 size = (value >= 0) ? (size_t) value : 0;
00166                 break;
00167         case 't':
00168                 rc = arg_parse_name_int(argc, argv, index, &value, 0,
00169                     socket_parse_socket_type);
00170                 if (rc != EOK)
00171                         return rc;
00172                 type = (sock_type_t) value;
00173                 break;
00174         case 'v':
00175                 verbose = true;
00176                 break;
00177         /*
00178          * Long options with double dash ('-')
00179          */
00180         case '-':
00181                 if (str_lcmp(argv[*index] + 2, "family=", 7) == 0) {
00182                         rc = arg_parse_name_int(argc, argv, index, &family, 9,
00183                             socket_parse_protocol_family);
00184                         if (rc != EOK)
00185                                 return rc;
00186                 } else if (str_lcmp(argv[*index] + 2, "help", 5) == 0) {
00187                         nettest2_print_help();
00188                         return EOK;
00189                 } else if (str_lcmp(argv[*index] + 2, "messages=", 6) == 0) {
00190                         rc = arg_parse_int(argc, argv, index, &messages, 8);
00191                         if (rc != EOK)
00192                                 return rc;
00193                 } else if (str_lcmp(argv[*index] + 2, "sockets=", 6) == 0) {
00194                         rc = arg_parse_int(argc, argv, index, &sockets, 8);
00195                         if (rc != EOK)
00196                                 return rc;
00197                 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) {
00198                         rc = arg_parse_int(argc, argv, index, &value, 7);
00199                         if (rc != EOK)
00200                                 return rc;
00201                         port = (uint16_t) value;
00202                 } else if (str_lcmp(argv[*index] + 2, "type=", 5) == 0) {
00203                         rc = arg_parse_name_int(argc, argv, index, &value, 7,
00204                             socket_parse_socket_type);
00205                         if (rc != EOK)
00206                                 return rc;
00207                         type = (sock_type_t) value;
00208                 } else if (str_lcmp(argv[*index] + 2, "verbose", 8) == 0) {
00209                         verbose = 1;
00210                 } else {
00211                         nettest2_print_help();
00212                         return EINVAL;
00213                 }
00214                 break;
00215         default:
00216                 nettest2_print_help();
00217                 return EINVAL;
00218         }
00219 
00220         return EOK;
00221 }
00222 
00223 int main(int argc, char *argv[])
00224 {
00225         struct sockaddr *address;
00226         struct sockaddr_in address_in;
00227         struct sockaddr_in6 address_in6;
00228         socklen_t addrlen;
00229         uint8_t *address_start;
00230 
00231         int *socket_ids;
00232         char *data;
00233         int index;
00234         struct timeval time_before;
00235         struct timeval time_after;
00236 
00237         int rc;
00238 
00239         size = 28;
00240         verbose = false;
00241         type = SOCK_DGRAM;
00242         sockets = 10;
00243         messages = 10;
00244         family = PF_INET;
00245         port = 7;
00246 
00247         /*
00248          * Parse the command line arguments.
00249          *
00250          * Stop before the last argument if it does not start with dash ('-')
00251          */
00252         for (index = 1; (index < argc - 1) || ((index == argc - 1) &&
00253             (argv[index][0] == '-')); ++index) {
00254 
00255                 /* Options should start with dash ('-') */
00256                 if (argv[index][0] == '-') {
00257                         rc = nettest2_parse_opt(argc, argv, &index);
00258                         if (rc != EOK)
00259                                 return rc;
00260                 } else {
00261                         nettest2_print_help();
00262                         return EINVAL;
00263                 }
00264         }
00265 
00266         /* If not before the last argument containing the address */
00267         if (index >= argc) {
00268                 printf("Command line error: missing address\n");
00269                 nettest2_print_help();
00270                 return EINVAL;
00271         }
00272 
00273         /* Prepare the address buffer */
00274 
00275         switch (family) {
00276         case PF_INET:
00277                 address_in.sin_family = AF_INET;
00278                 address_in.sin_port = htons(port);
00279                 address = (struct sockaddr *) &address_in;
00280                 addrlen = sizeof(address_in);
00281                 address_start = (uint8_t *) &address_in.sin_addr.s_addr;
00282                 break;
00283         case PF_INET6:
00284                 address_in6.sin6_family = AF_INET6;
00285                 address_in6.sin6_port = htons(port);
00286                 address = (struct sockaddr *) &address_in6;
00287                 addrlen = sizeof(address_in6);
00288                 address_start = (uint8_t *) &address_in6.sin6_addr.s6_addr;
00289                 break;
00290         default:
00291                 fprintf(stderr, "Address family is not supported\n");
00292                 return EAFNOSUPPORT;
00293         }
00294 
00295         /* Parse the last argument which should contain the address. */
00296         rc = inet_pton(family, argv[argc - 1], address_start);
00297         if (rc != EOK) {
00298                 fprintf(stderr, "Address parse error %d\n", rc);
00299                 return rc;
00300         }
00301 
00302         /* Check data buffer size. */
00303         if (size <= 0) {
00304                 fprintf(stderr, "Data buffer size too small (%zu). Using 1024 "
00305                     "bytes instead.\n", size);
00306                 size = 1024;
00307         }
00308 
00309         /*
00310          * Prepare the buffer. Allocate size bytes plus one for terminating
00311          * null character.
00312          */
00313         data = (char *) malloc(size + 1);
00314         if (!data) {
00315                 fprintf(stderr, "Failed to allocate data buffer.\n");
00316                 return ENOMEM;
00317         }
00318 
00319         /* Fill buffer with a pattern. */
00320         nettest2_fill_buffer(data, size);
00321 
00322         /* Check socket count. */
00323         if (sockets <= 0) {
00324                 fprintf(stderr, "Socket count too small (%d). Using "
00325                     "2 instead.\n", sockets);
00326                 sockets = 2;
00327         }
00328 
00329         /*
00330          * Prepare the socket buffer.
00331          * Allocate count entries plus the terminating null (\0)
00332          */
00333         socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
00334         if (!socket_ids) {
00335                 fprintf(stderr, "Failed to allocate receive buffer.\n");
00336                 return ENOMEM;
00337         }
00338         socket_ids[sockets] = 0;
00339 
00340         if (verbose)
00341                 printf("Starting tests\n");
00342 
00343         rc = sockets_create(verbose, socket_ids, sockets, family, type);
00344         if (rc != EOK)
00345                 return rc;
00346 
00347         if (type == SOCK_STREAM) {
00348                 rc = sockets_connect(verbose, socket_ids, sockets,
00349                     address, addrlen);
00350                 if (rc != EOK)
00351                         return rc;
00352         }
00353 
00354         if (verbose)
00355                 printf("\n");
00356 
00357         rc = gettimeofday(&time_before, NULL);
00358         if (rc != EOK) {
00359                 fprintf(stderr, "Get time of day error %d\n", rc);
00360                 return rc;
00361         }
00362 
00363         rc = sockets_sendto_recvfrom(verbose, socket_ids, sockets, address,
00364             &addrlen, data, size, messages);
00365         if (rc != EOK)
00366                 return rc;
00367 
00368         rc = gettimeofday(&time_after, NULL);
00369         if (rc != EOK) {
00370                 fprintf(stderr, "Get time of day error %d\n", rc);
00371                 return rc;
00372         }
00373 
00374         if (verbose)
00375                 printf("\tOK\n");
00376 
00377         printf("sendto + recvfrom tested in %ld microseconds\n",
00378             tv_sub(&time_after, &time_before));
00379 
00380         rc = gettimeofday(&time_before, NULL);
00381         if (rc != EOK) {
00382                 fprintf(stderr, "Get time of day error %d\n", rc);
00383                 return rc;
00384         }
00385 
00386         rc = sockets_sendto(verbose, socket_ids, sockets, address, addrlen,
00387             data, size, messages);
00388         if (rc != EOK)
00389                 return rc;
00390 
00391         rc = sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen,
00392             data, size, messages);
00393         if (rc != EOK)
00394                 return rc;
00395 
00396         rc = gettimeofday(&time_after, NULL);
00397         if (rc != EOK) {
00398                 fprintf(stderr, "Get time of day error %d\n", rc);
00399                 return rc;
00400         }
00401 
00402         if (verbose)
00403                 printf("\tOK\n");
00404 
00405         printf("sendto, recvfrom tested in %ld microseconds\n",
00406             tv_sub(&time_after, &time_before));
00407 
00408         rc = sockets_close(verbose, socket_ids, sockets);
00409         if (rc != EOK)
00410                 return rc;
00411 
00412         if (verbose)
00413                 printf("\nExiting\n");
00414 
00415         return EOK;
00416 }
00417 

Generated on Thu Jun 2 07:45:42 2011 for HelenOS/USB by  doxygen 1.4.7