nettest1.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 
00047 #include <net/in.h>
00048 #include <net/in6.h>
00049 #include <net/inet.h>
00050 #include <net/socket.h>
00051 #include <net/socket_parse.h>
00052 
00054 #define NAME    "Nettest1"
00055 
00057 #define NETTEST1_TEXT   "Networking test 1 - sockets"
00058 
00059 static int family = PF_INET;
00060 static sock_type_t type = SOCK_DGRAM;
00061 static char *data;
00062 static size_t size = 27;
00063 static int verbose = 0;
00064 
00065 static struct sockaddr *address;
00066 static socklen_t addrlen;
00067 
00068 static int sockets;
00069 static int messages;
00070 static uint16_t port;
00071 
00072 static void nettest1_print_help(void)
00073 {
00074         printf(
00075             "Network Networking test 1 aplication - sockets\n"
00076             "Usage: echo [options] numeric_address\n"
00077             "Where options are:\n"
00078             "-f protocol_family | --family=protocol_family\n"
00079             "\tThe listenning socket protocol family. Only the PF_INET and "
00080             "PF_INET6 are supported.\n"
00081             "\n"
00082             "-h | --help\n"
00083             "\tShow this application help.\n"
00084             "\n"
00085             "-m count | --messages=count\n"
00086             "\tThe number of messages to send and receive per socket. The "
00087             "default is 10.\n"
00088             "\n"
00089             "-n sockets | --sockets=count\n"
00090             "\tThe number of sockets to use. The default is 10.\n"
00091             "\n"
00092             "-p port_number | --port=port_number\n"
00093             "\tThe port number the application should send messages to. The "
00094             "default is 7.\n"
00095             "\n"
00096             "-s packet_size | --size=packet_size\n"
00097             "\tThe packet data size the application sends. The default is "
00098             "28 bytes.\n"
00099             "\n"
00100             "-v | --verbose\n"
00101             "\tShow all output messages.\n");
00102 }
00103 
00110 static int nettest1_parse_opt(int argc, char *argv[], int *index)
00111 {
00112         int value;
00113         int rc;
00114 
00115         switch (argv[*index][1]) {
00116         /*
00117          * Short options with only one letter
00118          */
00119         case 'f':
00120                 rc = arg_parse_name_int(argc, argv, index, &family, 0, socket_parse_protocol_family);
00121                 if (rc != EOK)
00122                         return rc;
00123                 break;
00124         case 'h':
00125                 nettest1_print_help();
00126                 return EOK;
00127         case 'm':
00128                 rc = arg_parse_int(argc, argv, index, &messages, 0);
00129                 if (rc != EOK)
00130                         return rc;
00131                 break;
00132         case 'n':
00133                 rc = arg_parse_int(argc, argv, index, &sockets, 0);
00134                 if (rc != EOK)
00135                         return rc;
00136                 break;
00137         case 'p':
00138                 rc = arg_parse_int(argc, argv, index, &value, 0);
00139                 if (rc != EOK)
00140                         return rc;
00141                 port = (uint16_t) value;
00142                 break;
00143         case 's':
00144                 rc = arg_parse_int(argc, argv, index, &value, 0);
00145                 if (rc != EOK)
00146                         return rc;
00147                 size = (value >= 0) ? (size_t) value : 0;
00148                 break;
00149         case 't':
00150                 rc = arg_parse_name_int(argc, argv, index, &value, 0, socket_parse_socket_type);
00151                 if (rc != EOK)
00152                         return rc;
00153                 type = (sock_type_t) value;
00154                 break;
00155         case 'v':
00156                 verbose = 1;
00157                 break;
00158         /*
00159          * Long options with double dash ('-')
00160          */
00161         case '-':
00162                 if (str_lcmp(argv[*index] + 2, "family=", 7) == 0) {
00163                         rc = arg_parse_name_int(argc, argv, index, &family, 9,
00164                             socket_parse_protocol_family);
00165                         if (rc != EOK)
00166                                 return rc;
00167                 } else if (str_lcmp(argv[*index] + 2, "help", 5) == 0) {
00168                         nettest1_print_help();
00169                         return EOK;
00170                 } else if (str_lcmp(argv[*index] + 2, "messages=", 6) == 0) {
00171                         rc = arg_parse_int(argc, argv, index, &messages, 8);
00172                         if (rc != EOK)
00173                                 return rc;
00174                 } else if (str_lcmp(argv[*index] + 2, "sockets=", 6) == 0) {
00175                         rc = arg_parse_int(argc, argv, index, &sockets, 8);
00176                         if (rc != EOK)
00177                                 return rc;
00178                 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) {
00179                         rc = arg_parse_int(argc, argv, index, &value, 7);
00180                         if (rc != EOK)
00181                                 return rc;
00182                         port = (uint16_t) value;
00183                 } else if (str_lcmp(argv[*index] + 2, "type=", 5) == 0) {
00184                         rc = arg_parse_name_int(argc, argv, index, &value, 7,
00185                             socket_parse_socket_type);
00186                         if (rc != EOK)
00187                                 return rc;
00188                         type = (sock_type_t) value;
00189                 } else if (str_lcmp(argv[*index] + 2, "verbose", 8) == 0) {
00190                         verbose = 1;
00191                 } else {
00192                         nettest1_print_help();
00193                         return EINVAL;
00194                 }
00195                 break;
00196         default:
00197                 nettest1_print_help();
00198                 return EINVAL;
00199         }
00200 
00201         return EOK;
00202 }
00203 
00209 static void nettest1_fill_buffer(char *buffer, size_t size)
00210 {
00211         size_t length;
00212 
00213         length = 0;
00214         while (size > length + sizeof(NETTEST1_TEXT) - 1) {
00215                 memcpy(buffer + length, NETTEST1_TEXT,
00216                     sizeof(NETTEST1_TEXT) - 1);
00217                 length += sizeof(NETTEST1_TEXT) - 1;
00218         }
00219 
00220         memcpy(buffer + length, NETTEST1_TEXT, size - length);
00221         buffer[size] = '\0';
00222 }
00223 
00224 static int nettest1_test(int *socket_ids, int nsockets, int nmessages)
00225 {
00226         int rc;
00227 
00228         if (verbose)
00229                 printf("%d sockets, %d messages\n", nsockets, nmessages);
00230 
00231         rc = sockets_create(verbose, socket_ids, nsockets, family, type);
00232         if (rc != EOK)
00233                 return rc;
00234 
00235         if (type == SOCK_STREAM) {
00236                 rc = sockets_connect(verbose, socket_ids, nsockets, address,
00237                     addrlen);
00238                 if (rc != EOK)
00239                         return rc;
00240         }
00241 
00242         rc = sockets_sendto_recvfrom(verbose, socket_ids, nsockets, address,
00243             &addrlen, data, size, nmessages);
00244         if (rc != EOK)
00245                 return rc;
00246 
00247         rc = sockets_close(verbose, socket_ids, nsockets);
00248         if (rc != EOK)
00249                 return rc;
00250 
00251         if (verbose)
00252                 printf("\tOK\n");
00253 
00254         /****/
00255 
00256         rc = sockets_create(verbose, socket_ids, nsockets, family, type);
00257         if (rc != EOK)
00258                 return rc;
00259 
00260         if (type == SOCK_STREAM) {
00261                 rc = sockets_connect(verbose, socket_ids, nsockets, address,
00262                     addrlen);
00263                 if (rc != EOK)
00264                         return rc;
00265         }
00266 
00267         rc = sockets_sendto(verbose, socket_ids, nsockets, address, addrlen,
00268             data, size, nmessages);
00269         if (rc != EOK)
00270                 return rc;
00271 
00272         rc = sockets_recvfrom(verbose, socket_ids, nsockets, address, &addrlen,
00273             data, size, nmessages);
00274         if (rc != EOK)
00275                 return rc;
00276 
00277         rc = sockets_close(verbose, socket_ids, nsockets);
00278         if (rc != EOK)
00279                 return rc;
00280 
00281         if (verbose)
00282                 printf("\tOK\n");
00283 
00284         return EOK;
00285 }
00286 
00287 int main(int argc, char *argv[])
00288 {
00289         struct sockaddr_in address_in;
00290         struct sockaddr_in6 address_in6;
00291         uint8_t *address_start;
00292 
00293         int *socket_ids;
00294         int index;
00295         struct timeval time_before;
00296         struct timeval time_after;
00297 
00298         int rc;
00299 
00300         sockets = 10;
00301         messages = 10;
00302         port = 7;
00303 
00304         /*
00305          * Parse the command line arguments. Stop before the last argument
00306          * if it does not start with dash ('-')
00307          */
00308         for (index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); index++) {
00309                 /* Options should start with dash ('-') */
00310                 if (argv[index][0] == '-') {
00311                         rc = nettest1_parse_opt(argc, argv, &index);
00312                         if (rc != EOK)
00313                                 return rc;
00314                 } else {
00315                         nettest1_print_help();
00316                         return EINVAL;
00317                 }
00318         }
00319 
00320         /* If not before the last argument containing the address */
00321         if (index >= argc) {
00322                 printf("Command line error: missing address\n");
00323                 nettest1_print_help();
00324                 return EINVAL;
00325         }
00326 
00327         /* Prepare the address buffer */
00328 
00329         switch (family) {
00330         case PF_INET:
00331                 address_in.sin_family = AF_INET;
00332                 address_in.sin_port = htons(port);
00333                 address = (struct sockaddr *) &address_in;
00334                 addrlen = sizeof(address_in);
00335                 address_start = (uint8_t *) &address_in.sin_addr.s_addr;
00336                 break;
00337         case PF_INET6:
00338                 address_in6.sin6_family = AF_INET6;
00339                 address_in6.sin6_port = htons(port);
00340                 address = (struct sockaddr *) &address_in6;
00341                 addrlen = sizeof(address_in6);
00342                 address_start = (uint8_t *) &address_in6.sin6_addr.s6_addr;
00343                 break;
00344         default:
00345                 fprintf(stderr, "Address family is not supported\n");
00346                 return EAFNOSUPPORT;
00347         }
00348 
00349         /* Parse the last argument which should contain the address */
00350         rc = inet_pton(family, argv[argc - 1], address_start);
00351         if (rc != EOK) {
00352                 fprintf(stderr, "Address parse error %d\n", rc);
00353                 return rc;
00354         }
00355 
00356         /* Check data buffer size */
00357         if (size <= 0) {
00358                 fprintf(stderr, "Data buffer size too small (%zu). Using 1024 "
00359                     "bytes instead.\n", size);
00360                 size = 1024;
00361         }
00362 
00363         /*
00364          * Prepare data buffer. Allocate size bytes plus one for the
00365          * trailing null character.
00366          */
00367         data = (char *) malloc(size + 1);
00368         if (!data) {
00369                 fprintf(stderr, "Failed to allocate data buffer.\n");
00370                 return ENOMEM;
00371         }
00372         nettest1_fill_buffer(data, size);
00373 
00374         /* Check socket count */
00375         if (sockets <= 0) {
00376                 fprintf(stderr, "Socket count too small (%d). Using "
00377                     "2 instead.\n", sockets);
00378                 sockets = 2;
00379         }
00380 
00381         /*
00382          * Prepare socket buffer. Allocate count fields plus the terminating
00383          * null (\0).
00384          */
00385         socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
00386         if (!socket_ids) {
00387                 fprintf(stderr, "Failed to allocate receive buffer.\n");
00388                 return ENOMEM;
00389         }
00390         socket_ids[sockets] = 0;
00391 
00392         if (verbose)
00393                 printf("Starting tests\n");
00394 
00395         rc = gettimeofday(&time_before, NULL);
00396         if (rc != EOK) {
00397                 fprintf(stderr, "Get time of day error %d\n", rc);
00398                 return rc;
00399         }
00400 
00401         nettest1_test(socket_ids,       1,        1);
00402         nettest1_test(socket_ids,       1, messages);
00403         nettest1_test(socket_ids, sockets,        1);
00404         nettest1_test(socket_ids, sockets, messages);
00405 
00406         rc = gettimeofday(&time_after, NULL);
00407         if (rc != EOK) {
00408                 fprintf(stderr, "Get time of day error %d\n", rc);
00409                 return rc;
00410         }
00411 
00412         printf("Tested in %ld microseconds\n", tv_sub(&time_after,
00413             &time_before));
00414 
00415         if (verbose)
00416                 printf("Exiting\n");
00417 
00418         return EOK;
00419 }
00420 
00421 

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