Subversion Repositories HelenOS

Rev

Rev 4749 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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.  */
  67. int     main( int argc, char * argv[] );
  68.  
  69. /** Prints the application help.
  70.  */
  71. void    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.  */
  78. int     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.  */
  85. int     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.  */
  92. void    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.  */
  103. int 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.  */
  112. int 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.  */
  123. int 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.  */
  137. int 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.  */
  151. int 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.  */
  167. int 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.  */
  173. void    print_mark( int index );
  174.  
  175. void 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.  
  203. int 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.  
  212. int 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.  
  221. void 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.  
  234. int sockets_create( int verbose, int * socket_ids, int sockets, int family, sock_type_t type ){
  235.     int index;
  236.  
  237.     if( verbose ) printf( "Create\t" );
  238.     fflush( stdout );
  239.     for( index = 0; index < sockets; ++ index ){
  240.         socket_ids[ index ] = socket( family, type, 0 );
  241.         if( socket_ids[ index ] < 0 ){
  242.             printf( "Socket %d (%d) error:\n", index, socket_ids[ index ] );
  243.             socket_print_error( stderr, socket_ids[ index ], "Socket create: ", "\n" );
  244.             return socket_ids[ index ];
  245.         }
  246.         if( verbose ) print_mark( index );
  247.     }
  248.     return EOK;
  249. }
  250.  
  251. int sockets_close( int verbose, int * socket_ids, int sockets ){
  252.     ERROR_DECLARE;
  253.  
  254.     int index;
  255.  
  256.     if( verbose ) printf( "\tClose\t" );
  257.     fflush( stdout );
  258.     for( index = 0; index < sockets; ++ index ){
  259.         if( ERROR_OCCURRED( closesocket( socket_ids[ index ] ))){
  260.             printf( "Socket %d (%d) error:\n", index, socket_ids[ index ] );
  261.             socket_print_error( stderr, ERROR_CODE, "Socket close: ", "\n" );
  262.             return ERROR_CODE;
  263.         }
  264.         if( verbose ) print_mark( index );
  265.     }
  266.     return EOK;
  267. }
  268.  
  269. int sockets_connect( int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen ){
  270.     ERROR_DECLARE;
  271.  
  272.     int index;
  273.  
  274.     if( verbose ) printf( "\tConnect\t" );
  275.     fflush( stdout );
  276.     for( index = 0; index < sockets; ++ index ){
  277.         if( ERROR_OCCURRED( connect( socket_ids[ index ], address, addrlen ))){
  278.             socket_print_error( stderr, ERROR_CODE, "Socket connect: ", "\n" );
  279.             return ERROR_CODE;
  280.         }
  281.         if( verbose ) print_mark( index );
  282.     }
  283.     return EOK;
  284. }
  285.  
  286. int sockets_sendto( int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen, char * data, int size, int messages ){
  287.     ERROR_DECLARE;
  288.  
  289.     int index;
  290.     int message;
  291.  
  292.     if( verbose ) printf( "\tSendto\t" );
  293.     fflush( stdout );
  294.     for( index = 0; index < sockets; ++ index ){
  295.         for( message = 0; message < messages; ++ message ){
  296.             if( ERROR_OCCURRED( sendto( socket_ids[ index ], data, size, 0, address, addrlen ))){
  297.                 printf( "Socket %d (%d), message %d error:\n", index, socket_ids[ index ], message );
  298.                 socket_print_error( stderr, ERROR_CODE, "Socket send: ", "\n" );
  299.                 return ERROR_CODE;
  300.             }
  301.         }
  302.         if( verbose ) print_mark( index );
  303.     }
  304.     return EOK;
  305. }
  306.  
  307. int sockets_recvfrom( int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages ){
  308.     int value;
  309.     int index;
  310.     int message;
  311.  
  312.     if( verbose ) printf( "\tRecvfrom\t" );
  313.     fflush( stdout );
  314.     for( index = 0; index < sockets; ++ index ){
  315.         for( message = 0; message < messages; ++ message ){
  316.             value = recvfrom( socket_ids[ index ], data, size, 0, address, addrlen );
  317.             if( value < 0 ){
  318.                 printf( "Socket %d (%d), message %d error:\n", index, socket_ids[ index ], message );
  319.                 socket_print_error( stderr, value, "Socket receive: ", "\n" );
  320.                 return value;
  321.             }
  322.         }
  323.         if( verbose ) print_mark( index );
  324.     }
  325.     return EOK;
  326. }
  327.  
  328. int sockets_sendto_recvfrom( int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages ){
  329.     ERROR_DECLARE;
  330.  
  331.     int value;
  332.     int index;
  333.     int message;
  334.  
  335.     if( verbose ) printf( "\tSendto and recvfrom\t" );
  336.     fflush( stdout );
  337.     for( index = 0; index < sockets; ++ index ){
  338.         for( message = 0; message < messages; ++ message ){
  339.             if( ERROR_OCCURRED( sendto( socket_ids[ index ], data, size, 0, address, * addrlen ))){
  340.                 printf( "Socket %d (%d), message %d error:\n", index, socket_ids[ index ], message );
  341.                 socket_print_error( stderr, ERROR_CODE, "Socket send: ", "\n" );
  342.                 return ERROR_CODE;
  343.             }
  344.             value = recvfrom( socket_ids[ index ], data, size, 0, address, addrlen );
  345.             if( value < 0 ){
  346.                 printf( "Socket %d (%d), message %d error:\n", index, socket_ids[ index ], message );
  347.                 socket_print_error( stderr, value, "Socket receive: ", "\n" );
  348.                 return value;
  349.             }
  350.         }
  351.         if( verbose ) print_mark( index );
  352.     }
  353.     return EOK;
  354. }
  355.  
  356. void print_mark( int index ){
  357.     if(( index + 1 ) % 10 ){
  358.         printf( "*" );
  359.     }else{
  360.         printf( "|" );
  361.     }
  362.     fflush( stdout );
  363. }
  364.  
  365. int main( int argc, char * argv[] ){
  366.     ERROR_DECLARE;
  367.  
  368.     size_t              size            = 29;
  369.     int                 verbose         = 0;
  370.     sock_type_t         type            = SOCK_DGRAM;
  371.     int                 sockets         = 10;
  372.     int                 messages        = 10;
  373.     int                 family          = PF_INET;
  374.     uint16_t            port            = 7;
  375.  
  376.     socklen_t           max_length      = sizeof( struct sockaddr_in6 );
  377.     uint8_t             address_data[ max_length ];
  378.     struct sockaddr *       address     = ( struct sockaddr * ) address_data;
  379.     struct sockaddr_in *    address_in      = ( struct sockaddr_in * ) address;
  380.     struct sockaddr_in6 *   address_in6 = ( struct sockaddr_in6 * ) address;
  381.     socklen_t           addrlen;
  382. //  char                address_string[ INET6_ADDRSTRLEN ];
  383.     uint8_t *           address_start;
  384.  
  385.     int *               socket_ids;
  386.     char *              data;
  387.     int                 value;
  388.     int                 index;
  389.     struct timeval      time_before;
  390.     struct timeval      time_after;
  391.  
  392.     printf( "Task %d - ", task_get_id());
  393.     printf( "%s\n", NAME );
  394.  
  395.     if( argc <= 1 ){
  396.         print_help();
  397.         return EINVAL;
  398.     }
  399.  
  400.     for( index = 1; ( index < argc - 1 ) || (( index == argc ) && ( argv[ index ][ 0 ] == '-' )); ++ index ){
  401.         if( argv[ index ][ 0 ] == '-' ){
  402.             switch( argv[ index ][ 1 ] ){
  403.                 case 'f':   ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & family, "protocol family", 0, parse_protocol_family ));
  404.                             break;
  405.                 case 'h':   print_help();
  406.                             return EOK;
  407.                             break;
  408.                 case 'm':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & messages, "message count", 0 ));
  409.                             break;
  410.                 case 'n':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & sockets, "socket count", 0 ));
  411.                             break;
  412.                 case 'p':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "port number", 0 ));
  413.                             port = ( uint16_t ) value;
  414.                             break;
  415.                 case 's':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "packet size", 0 ));
  416.                             size = (value >= 0 ) ? ( size_t ) value : 0;
  417.                             break;
  418.                 case 't':   ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & value, "socket type", 0, parse_socket_type ));
  419.                             type = ( sock_type_t ) value;
  420.                             break;
  421.                 case 'v':   verbose = 1;
  422.                             break;
  423.                 case '-':   if( str_lcmp( argv[ index ] + 2, "family=", 7 ) == 0 ){
  424.                                 ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & family, "protocol family", 9, parse_protocol_family ));
  425.                             }else if( str_lcmp( argv[ index ] + 2, "help", 5 ) == 0 ){
  426.                                 print_help();
  427.                                 return EOK;
  428.                             }else if( str_lcmp( argv[ index ] + 2, "messages=", 6 ) == 0 ){
  429.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & messages, "message count", 8 ));
  430.                             }else if( str_lcmp( argv[ index ] + 2, "sockets=", 6 ) == 0 ){
  431.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & sockets, "socket count", 8 ));
  432.                             }else if( str_lcmp( argv[ index ] + 2, "port=", 5 ) == 0 ){
  433.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "port number", 7 ));
  434.                                 port = ( uint16_t ) value;
  435.                             }else if( str_lcmp( argv[ index ] + 2, "type=", 5 ) == 0 ){
  436.                                 ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & value, "socket type", 7, parse_socket_type ));
  437.                                 type = ( sock_type_t ) value;
  438.                             }else if( str_lcmp( argv[ index ] + 2, "verbose", 8 ) == 0 ){
  439.                                 verbose = 1;
  440.                             }else{
  441.                                 print_unrecognized( index, argv[ index ] + 2 );
  442.                                 print_help();
  443.                                 return EINVAL;
  444.                             }
  445.                             break;
  446.                 default:
  447.                     print_unrecognized( index, argv[ index ] + 1 );
  448.                     print_help();
  449.                     return EINVAL;
  450.             }
  451.         }else{
  452.             print_unrecognized( index, argv[ index ] );
  453.             print_help();
  454.             return EINVAL;
  455.         }
  456.     }
  457.  
  458.     bzero( address_data, max_length );
  459.     switch( family ){
  460.         case PF_INET:
  461.             address_in->sin_family = AF_INET;
  462.             address_in->sin_port = htons( port );
  463.             address_start = ( uint8_t * ) & address_in->sin_addr.s_addr;
  464.             addrlen = sizeof( struct sockaddr_in );
  465.             break;
  466.         case PF_INET6:
  467.             address_in6->sin6_family = AF_INET6;
  468.             address_in6->sin6_port = htons( port );
  469.             address_start = ( uint8_t * ) & address_in6->sin6_addr.s6_addr;
  470.             addrlen = sizeof( struct sockaddr_in6 );
  471.             break;
  472.         default:
  473.             fprintf( stderr, "Address family is not supported\n" );
  474.             return EAFNOSUPPORT;
  475.     }
  476.  
  477.     if( ERROR_OCCURRED( inet_pton( family, argv[ argc - 1 ], address_start ))){
  478.         fprintf( stderr, "Address parse error %d\n", ERROR_CODE );
  479.         return ERROR_CODE;
  480.     }
  481.  
  482.     if( size <= 0 ){
  483.         fprintf( stderr, "Data buffer size too small (%d). Using 1024 bytes instead.\n", size );
  484.         size = 1024;
  485.     }
  486.     // size plus terminating null (\0)
  487.     data = ( char * ) malloc( size + 1 );
  488.     if( ! data ){
  489.         fprintf( stderr, "Failed to allocate data buffer.\n" );
  490.         return ENOMEM;
  491.     }
  492.     refresh_data( data, size );
  493.  
  494.     if( sockets <= 0 ){
  495.         fprintf( stderr, "Socket count too small (%d). Using 2 instead.\n", sockets );
  496.         sockets = 2;
  497.     }
  498.     // count plus terminating null (\0)
  499.     socket_ids = ( int * ) malloc( sizeof( int ) * ( sockets + 1 ));
  500.     if( ! socket_ids ){
  501.         fprintf( stderr, "Failed to allocate receive buffer.\n" );
  502.         return ENOMEM;
  503.     }
  504.     socket_ids[ sockets ] = NULL;
  505.  
  506.     if( verbose ) printf( "Starting tests\n" );
  507.  
  508.     ERROR_PROPAGATE( sockets_create( verbose, socket_ids, sockets, family, type ));
  509.     if( type == SOCK_STREAM ){
  510.         ERROR_PROPAGATE( sockets_connect( verbose, socket_ids, sockets, address, addrlen ));
  511.     }
  512.  
  513.     if( ERROR_OCCURRED( gettimeofday( & time_before, NULL ))){
  514.         fprintf( stderr, "Get time of day error %d\n", ERROR_CODE );
  515.         return ERROR_CODE;
  516.     }
  517.  
  518.     ERROR_PROPAGATE( sockets_sendto_recvfrom( verbose, socket_ids, sockets, address, & addrlen, data, size, messages ));
  519.  
  520.     if( ERROR_OCCURRED( gettimeofday( & time_after, NULL ))){
  521.         fprintf( stderr, "Get time of day error %d\n", ERROR_CODE );
  522.         return ERROR_CODE;
  523.     }
  524.  
  525.     if( verbose ) printf( "\tOK\n" );
  526.  
  527.     printf( "sendto + recvfrom tested in %d microseconds\n", tv_sub( & time_after, & time_before ));
  528.  
  529.     if( ERROR_OCCURRED( gettimeofday( & time_before, NULL ))){
  530.         fprintf( stderr, "Get time of day error %d\n", ERROR_CODE );
  531.         return ERROR_CODE;
  532.     }
  533.  
  534.     ERROR_PROPAGATE( sockets_sendto( verbose, socket_ids, sockets, address, addrlen, data, size, messages ));
  535.     ERROR_PROPAGATE( sockets_recvfrom( verbose, socket_ids, sockets, address, & addrlen, data, size, messages ));
  536.  
  537.     if( ERROR_OCCURRED( gettimeofday( & time_after, NULL ))){
  538.         fprintf( stderr, "Get time of day error %d\n", ERROR_CODE );
  539.         return ERROR_CODE;
  540.     }
  541.  
  542.     if( verbose ) printf( "\tOK\n" );
  543.  
  544.     printf( "sendto, recvfrom tested in %d microseconds\n", tv_sub( & time_after, & time_before ));
  545.  
  546.     ERROR_PROPAGATE( sockets_close( verbose, socket_ids, sockets ));
  547.  
  548.     if( verbose ) printf( "Exiting\n" );
  549.  
  550.     return EOK;
  551. }
  552.  
  553. /** @}
  554.  */
  555.