Subversion Repositories HelenOS

Rev

Rev 4720 | Rev 4734 | Go to most recent revision | 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 echo
  30.  *  @{
  31.  */
  32.  
  33. /** @file
  34.  *  Echo application.
  35.  *  Answers received packets.
  36.  */
  37.  
  38. #include <malloc.h>
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include <task.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    "Echo"
  56.  
  57. /** Module entry point.
  58.  *  Reads command line parameters and starts listenning.
  59.  *  @param argc The number of command line parameters. Input parameter.
  60.  *  @param argv The command line parameters. Input parameter.
  61.  *  @returns EOK on success.
  62.  */
  63. int     main( int argc, char * argv[] );
  64.  
  65. /** Prints the application help.
  66.  */
  67. void    print_help( void );
  68.  
  69. /** Translates the character string to the protocol family number.
  70.  *  @param name The protocol family name. Input parameter.
  71.  *  @returns The corresponding protocol family number.
  72.  *  @returns EPFNOSUPPORTED if the protocol family is not supported.
  73.  */
  74. int     parse_protocol_family( const char * name );
  75.  
  76. /** Translates the character string to the socket type number.
  77.  *  @param name The socket type name. Input parameter.
  78.  *  @returns The corresponding socket type number.
  79.  *  @returns ESOCKNOSUPPORTED if the socket type is not supported.
  80.  */
  81. int     parse_socket_type( const char * name );
  82.  
  83. void print_help( void ){
  84.     printf(
  85.         "Network Echo aplication\n" \
  86.         "Usage: echo [options]\n" \
  87.         "Where options are:\n" \
  88.         "-c count | --count=count\n" \
  89.         "\tThe number of received messages to handle. A negative number means infinity. The default is infinity.\n" \
  90.         "\n" \
  91.         "-f protocol_family | --family=protocol_family\n" \
  92.         "\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
  93.         "\n" \
  94.         "-h | --help\n" \
  95.         "\tShow this application help.\n"
  96.         "\n" \
  97.         "-p port_number | --port=port_number\n" \
  98.         "\tThe port number the application should listen at. The default is 7.\n" \
  99.         "\n" \
  100.         "-r reply_string | --reply=reply_string\n" \
  101.         "\tThe constant reply string. The default is the original data received.\n" \
  102.         "\n" \
  103.         "-s receive_size | --size=receive_size\n" \
  104.         "\tThe maximum receive data size the application should accept. The default is 1024 bytes.\n" \
  105.         "\n" \
  106.         "-t socket_type | --type=socket_type\n" \
  107.         "\tThe listenning socket type. Only the SOCK_DGRAM is supported.\n" \
  108.         "\n" \
  109.         "-v | --verbose\n" \
  110.         "\tShow all output messages.\n"
  111.     );
  112. }
  113.  
  114. int parse_protocol_family( const char * name ){
  115.     if( str_lcmp( name, "PF_INET", 7 ) == 0 ){
  116.         return PF_INET;
  117.     }else if( str_lcmp( name, "PF_INET6", 8 ) == 0 ){
  118.         return PF_INET6;
  119.     }
  120.     return EPFNOSUPPORT;
  121. }
  122.  
  123. int parse_socket_type( const char * name ){
  124.     if( str_lcmp( name, "SOCK_DGRAM", 11 ) == 0 ){
  125.         return SOCK_DGRAM;
  126.     }
  127.     return ESOCKTNOSUPPORT;
  128. }
  129.  
  130. int main( int argc, char * argv[] ){
  131.     ERROR_DECLARE;
  132.  
  133.     size_t              size            = 1024;
  134.     int                 verbose         = 0;
  135.     char *              reply           = NULL;
  136.     sock_type_t         type            = SOCK_DGRAM;
  137.     int                 count           = -1;
  138.     int                 family          = PF_INET;
  139.     uint16_t            port            = 7;
  140.  
  141.     socklen_t           max_length      = sizeof( struct sockaddr_in6 );
  142.     uint8_t             address_data[ max_length ];
  143.     struct sockaddr *       address     = ( struct sockaddr * ) address_data;
  144.     struct sockaddr_in *    address_in      = ( struct sockaddr_in * ) address;
  145.     struct sockaddr_in6 *   address_in6 = ( struct sockaddr_in6 * ) address;
  146.     socklen_t           addrlen;
  147.     char                address_string[ INET6_ADDRSTRLEN ];
  148.     uint8_t *           address_start;
  149.     int                 socket_id;
  150.     char *              data;
  151.     size_t              length;
  152.     int                 index;
  153.     size_t              reply_length;
  154.     int                 value;
  155.  
  156.     printf( "Task %d - ", task_get_id());
  157.     printf( "%s\n", NAME );
  158.  
  159.     for( index = 1; index < argc; ++ index ){
  160.         if( argv[ index ][ 0 ] == '-' ){
  161.             switch( argv[ index ][ 1 ] ){
  162.                 case 'c':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & count, "count", 0 ));
  163.                             break;
  164.                 case 'f':   ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & family, "protocol family", 0, parse_protocol_family ));
  165.                             break;
  166.                 case 'h':   print_help();
  167.                             return EOK;
  168.                             break;
  169.                 case 'p':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "port number", 0 ));
  170.                             port = ( uint16_t ) value;
  171.                             break;
  172.                 case 'r':   ERROR_PROPAGATE( parse_parameter_string( argc, argv, & index, & reply, "reply string", 0 ));
  173.                             break;
  174.                 case 's':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "receive size", 0 ));
  175.                             size = (value >= 0 ) ? ( size_t ) value : 0;
  176.                             break;
  177.                 case 't':   ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & value, "socket_type", 0, parse_socket_type ));
  178.                             type = ( sock_type_t ) value;
  179.                             break;
  180.                 case 'v':   verbose = 1;
  181.                             break;
  182.                 case '-':   if( str_lcmp( argv[ index ] + 2, "count=", 6 ) == 0 ){
  183.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & count, "received count", 8 ))
  184.                             }else if( str_lcmp( argv[ index ] + 2, "family=", 7 ) == 0 ){
  185.                                 ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & family, "protocol family", 9, parse_protocol_family ));
  186.                             }else if( str_lcmp( argv[ index ] + 2, "help", 5 ) == 0 ){
  187.                                 print_help();
  188.                                 return EOK;
  189.                             }else if( str_lcmp( argv[ index ] + 2, "port=", 5 ) == 0 ){
  190.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "port number", 7 ));
  191.                                 port = ( uint16_t ) value;
  192.                             }else if( str_lcmp( argv[ index ] + 2, "reply=", 6 ) == 0 ){
  193.                                 ERROR_PROPAGATE( parse_parameter_string( argc, argv, & index, & reply, "reply string", 8 ));
  194.                             }else if( str_lcmp( argv[ index ] + 2, "size=", 5 ) == 0 ){
  195.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "receive size", 7 ));
  196.                                 size = (value >= 0 ) ? ( size_t ) value : 0;
  197.                             }else if( str_lcmp( argv[ index ] + 2, "type=", 5 ) == 0 ){
  198.                                 ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & value, "socket_type", 7, parse_socket_type ));
  199.                                 type = ( sock_type_t ) value;
  200.                             }else if( str_lcmp( argv[ index ] + 2, "verbose", 8 ) == 0 ){
  201.                                 verbose = 1;
  202.                             }else{
  203.                                 print_unrecognized( index, argv[ index ] + 2 );
  204.                                 print_help();
  205.                                 return EINVAL;
  206.                             }
  207.                             break;
  208.                 default:
  209.                     print_unrecognized( index, argv[ index ] + 1 );
  210.                     print_help();
  211.                     return EINVAL;
  212.             }
  213.         }else{
  214.             print_unrecognized( index, argv[ index ] );
  215.             print_help();
  216.             return EINVAL;
  217.         }
  218.     }
  219.  
  220.     if( size <= 0 ){
  221.         fprintf( stderr, "Receive size too small (%d). Using 1024 bytes instead.\n", size );
  222.         size = 1024;
  223.     }
  224.     // size plus terminating null (\0)
  225.     data = ( char * ) malloc( size + 1 );
  226.     if( ! data ){
  227.         fprintf( stderr, "Failed to allocate receive buffer.\n" );
  228.         return ENOMEM;
  229.     }
  230.  
  231.     reply_length = reply ? str_length( reply ) : 0;
  232.  
  233.     socket_id = socket( family, type, 0 );
  234.     if( socket_id < 0 ){
  235.         fprintf( stderr, "Socket create error %d\n", socket_id );
  236.         return socket_id;
  237.     }
  238.  
  239.     bzero( address_data, max_length );
  240.     switch( family ){
  241.         case PF_INET:
  242.             address_in->sin_family = AF_INET;
  243.             address_in->sin_port = port;
  244.             addrlen = sizeof( struct sockaddr_in );
  245.             break;
  246.         case PF_INET6:
  247.             address_in6->sin6_family = AF_INET6;
  248.             address_in6->sin6_port = port;
  249.             addrlen = sizeof( struct sockaddr_in6 );
  250.             break;
  251.         default:
  252.             fprintf( stderr, "Protocol family is not supported\n" );
  253.             return EAFNOSUPPORT;
  254.     }
  255.     if( ERROR_OCCURRED( bind( socket_id, address, addrlen ))){
  256.         socket_print_error( stderr, ERROR_CODE, "Socket bind: ", "\n" );
  257.         return ERROR_CODE;
  258.     }
  259.  
  260.     if( verbose ) printf( "Listenning at %d\n", port );
  261.  
  262.     while( count ){
  263.         addrlen = max_length;
  264.         value = recvfrom( socket_id, data, size, 0, address, & addrlen );
  265.         if( value < 0 ){
  266.             socket_print_error( stderr, value, "Socket receive: ", "\n" );
  267.         }else{
  268.             length = ( size_t ) value;
  269.             if( verbose ){
  270.                 address_start = NULL;
  271.                 switch( address->sa_family ){
  272.                     case AF_INET:
  273.                         port = address_in->sin_port;
  274.                         address_start = ( uint8_t * ) & address_in->sin_addr.s_addr;
  275.                         break;
  276.                     case AF_INET6:
  277.                         port = address_in6->sin6_port;
  278.                         address_start = ( uint8_t * ) & address_in6->sin6_addr.s6_addr;
  279.                         break;
  280.                     default:
  281.                         fprintf( stderr, "Address family %d (0x%X) is not supported.\n", address->sa_family );
  282.                 }
  283.                 if( address_start ){
  284.                     if( ERROR_OCCURRED( inet_ntop( address->sa_family, address_start, address_string, sizeof( address_string )))){
  285.                         fprintf( stderr, "Received address error %d\n", ERROR_CODE );
  286.                     }else{
  287.                         data[ length ] = '\0';
  288.                         printf( "Received %d bytes from %s:%d\n%s\n", length, address_string, port, data );
  289.                     }
  290.                 }
  291.             }
  292.             if( ERROR_OCCURRED( sendto( socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen ))){
  293.                 socket_print_error( stderr, ERROR_CODE, "Socket send: ", "\n" );
  294.             }
  295.         }
  296.         if( count > 0 ){
  297.             -- count;
  298.             if( verbose ) printf( "Waiting for next %d packet(s)\n", count );
  299.         }
  300.     }
  301.  
  302.     if( verbose ) printf( "Closing the socket\n" );
  303.  
  304.     if( ERROR_OCCURRED( closesocket( socket_id ))){
  305.         socket_print_error( stderr, ERROR_CODE, "Close socket: ", "\n" );
  306.         return ERROR_CODE;
  307.     }
  308.  
  309.     if( verbose ) printf( "Exiting\n" );
  310.  
  311.     return EOK;
  312. }
  313.  
  314. /** @}
  315.  */
  316.