Subversion Repositories HelenOS

Rev

Rev 4700 | Rev 4708 | 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/inet.h"
  45. #include "../../include/socket.h"
  46.  
  47. #include "../../err.h"
  48.  
  49. /** Echo module name.
  50.  */
  51. #define NAME    "Echo"
  52.  
  53. /** Module entry point.
  54.  *  Reads command line parameters and starts listenning.
  55.  *  @param argc The number of command line parameters. Input parameter.
  56.  *  @param argv The command line parameters. Input parameter.
  57.  *  @returns EOK on success.
  58.  */
  59. int     main( int argc, char * argv[] );
  60.  
  61. /** @name Output printing functions
  62.  */
  63. /*@{*/
  64.  
  65. /** Prints the application help.
  66.  */
  67. void    print_help( void );
  68.  
  69. /** Prints the parameter unrecognized message and the application help.
  70.  *  @param index The index of the parameter. Input parameter.
  71.  *  @param parameter The parameter name. Input parameter.
  72.  */
  73. void    print_unrecognized( int index, const char * parameter );
  74.  
  75. /*@}*/
  76.  
  77. /** @name Command line argumets parsing functions
  78.  */
  79. /*@{*/
  80.  
  81. /** Parses the next parameter as an integral number.
  82.  *  Uses the offseted actual parameter if the offset is set or the next one if not.
  83.  *  @param argc The total number of the parameters. Input parameter.
  84.  *  @param argv The parameters. Input parameter.
  85.  *  @param index The actual parameter index. Input/output parameter.
  86.  *  @param value The parsed parameter value. Output parameter.
  87.  *  @param name The parameter name to be printed on errors. Input parameter.
  88.  *  @param offset The value offset in the actual parameter. If not set, the next parameter is parsed instead. Input parameter.
  89.  *  @returns EOK on success.
  90.  *  @returns EINVAL if the parameter is missing.
  91.  *  @returns EINVAL if the parameter is in wrong format.
  92.  */
  93. int parse_parameter_int( int argc, char ** argv, int * index, int * value, const char * name, int offset );
  94.  
  95. /** Parses the next parameter as a character string.
  96.  *  Uses the offseted actual parameter if the offset is set or the next one if not.
  97.  *  @param argc The total number of the parameters. Input parameter.
  98.  *  @param argv The parameters. Input parameter.
  99.  *  @param index The actual parameter index. Input/output parameter.
  100.  *  @param value The parsed parameter value. Output parameter.
  101.  *  @param name The parameter name to be printed on errors. Input parameter.
  102.  *  @param offset The value offset in the actual parameter. If not set, the next parameter is parsed instead. Input parameter.
  103.  *  @returns EOK on success.
  104.  *  @returns EINVAL if the parameter is missing.
  105.  */
  106. int parse_parameter_string( int argc, char ** argv, int * index, char ** value, const char * name, int offset );
  107.  
  108. /** Parses the next named parameter as an integral number.
  109.  *  Uses the offseted actual parameter if the offset is set or the next one if not.
  110.  *  Translates the parameter using the parse_value function.
  111.  *  @param argc The total number of the parameters. Input parameter.
  112.  *  @param argv The parameters. Input parameter.
  113.  *  @param index The actual parameter index. Input/output parameter.
  114.  *  @param value The parsed parameter value. Output parameter.
  115.  *  @param name The parameter name to be printed on errors. Input parameter.
  116.  *  @param offset The value offset in the actual parameter. If not set, the next parameter is parsed instead. Input parameter.
  117.  *  @param parse_value The translation function to parse the named value.
  118.  *  @returns EOK on success.
  119.  *  @returns EINVAL if the parameter is missing.
  120.  *  @returns ENOENT if the parameter name has not been found.
  121.  */
  122. int parse_parameter_name_int( int argc, char ** argv, int * index, int * value, const char * name, int offset, int ( * parse_value )( const char * value ));
  123.  
  124. /** Translates the character string to the protocol family number.
  125.  *  @param name The protocol family name. Input parameter.
  126.  *  @returns The corresponding protocol family number.
  127.  */
  128. int parse_protocol_family( const char * name );
  129.  
  130. /** Translates the character string to the socket type number.
  131.  *  @param name The socket type name. Input parameter.
  132.  *  @returns The corresponding socket type number.
  133.  */
  134. int parse_socket_type( const char * name );
  135.  
  136. /*@}*/
  137.  
  138. void print_help( void ){
  139.     printf(
  140.         "Network Echo aplication\n" \
  141.         "Usage: echo [options]\n" \
  142.         "Where options are:\n" \
  143.         "-p port_number | --port=port_number\n" \
  144.         "\tThe port number the application should listen at. The default is 7.\n" \
  145.         "\n" \
  146.         "-s receive_size | --size=receive_size\n" \
  147.         "\tThe maximum receive data size the application should accept. The default is 1024 bytes.\n" \
  148.         "\n" \
  149.         "-c count | --count\n" \
  150.         "\tThe number of received messages to handle. A negative number means infinity. The default is infinity.\n" \
  151.         "\n" \
  152.         "-r reply_string | --reply=reply_string\n" \
  153.         "\tThe constant reply string. The default is the original data received.\n" \
  154.         "\n" \
  155.         "-f protocol_family | --family=protocol_family\n" \
  156.         "\tThe listenning socket protocol family. Only the PF_INET is supported.\n"
  157.         "\n" \
  158.         "-h | --help\n" \
  159.         "\tShow this application help.\n"
  160.         "\n" \
  161.         "-t socket_type | --type=socket_type\n" \
  162.         "\tThe listenning socket type. Only the SOCK_DGRAM is supported.\n" \
  163.         "\n" \
  164.         "-v | --verbose\n" \
  165.         "\tShow all output messages.\n"
  166.     );
  167. }
  168.  
  169. int parse_parameter_int( int argc, char ** argv, int * index, int * value, const char * name, int offset ){
  170.     char *  rest;
  171.  
  172.     if( offset ){
  173.         * value = strtol( argv[ * index ] + offset, & rest, 10 );
  174.     }else if(( * index ) + 1 < argc ){
  175.         ++ ( * index );
  176.         * value = strtol( argv[ * index ], & rest, 10 );
  177.     }else{
  178.         fprintf( stderr, "Command line error: missing %s\n", name );
  179.         return EINVAL;
  180.     }
  181.     if( rest && ( * rest )){
  182.         fprintf( stderr, "Command line error: %s unrecognized (%d: %s)\n", name, * index, argv[ * index ] );
  183.         return EINVAL;
  184.     }
  185.     return EOK;
  186. }
  187.  
  188. int parse_parameter_string( int argc, char ** argv, int * index, char ** value, const char * name, int offset ){
  189.     if( offset ){
  190.         * value = argv[ * index ] + offset;
  191.     }else if(( * index ) + 1 < argc ){
  192.         ++ ( * index );
  193.         * value = argv[ * index ];
  194.     }else{
  195.         fprintf( stderr, "Command line error: missing %s\n", name );
  196.         return EINVAL;
  197.     }
  198.     return EOK;
  199. }
  200.  
  201. int parse_parameter_name_int( int argc, char ** argv, int * index, int * value, const char * name, int offset, int ( * parse_value )( const char * value )){
  202.     ERROR_DECLARE;
  203.  
  204.     char *  parameter;
  205.  
  206.     ERROR_PROPAGATE( parse_parameter_string( argc, argv, index, & parameter, name, offset ));
  207.     * value = ( * parse_value )( parameter );
  208.     if(( * value ) == ENOENT ){
  209.         fprintf( stderr, "Command line error: unrecognized %s value (%d: %s)\n", name, * index, parameter );
  210.         return ENOENT;
  211.     }
  212.     return EOK;
  213. }
  214.  
  215. int parse_protocol_family( const char * name ){
  216.     if( str_lcmp( name, "PF_INET", 7 ) == 0 ){
  217.         return PF_INET;
  218.     }
  219.     return ENOENT;
  220. }
  221.  
  222. int parse_socket_type( const char * name ){
  223.     if( str_lcmp( name, "SOCK_DGRAM", 11 ) == 0 ){
  224.         return SOCK_DGRAM;
  225.     }
  226.     return ENOENT;
  227. }
  228.  
  229. void print_unrecognized( int index, const char * parameter ){
  230.     fprintf( stderr, "Command line error - unrecognized parameter (%d: %s)\n", index, parameter );
  231.     print_help();
  232. }
  233.  
  234. int main( int argc, char * argv[] ){
  235.     ERROR_DECLARE;
  236.  
  237.     int                 size            = 1024;
  238.     int                 verbose         = 0;
  239.     char *              reply           = NULL;
  240.     sock_type_t         type            = SOCK_DGRAM;
  241.     int                 count           = -1;
  242.     struct sockaddr_in  address         = { .sin_family = PF_INET, .sin_port = 7 };
  243.  
  244.     int                 socket_id;
  245.     int                 address_length;
  246.     char                address_string[ INET_ADDRSTRLEN ];
  247.     char *              data;
  248.     int                 length;
  249.     int                 index;
  250.     size_t              reply_length;
  251.     int                 value;
  252.  
  253.     printf( "Task %d - ", task_get_id());
  254.     printf( "%s\n", NAME );
  255.  
  256.     for( index = 1; index < argc; ++ index ){
  257.         if( argv[ index ][ 0 ] == '-' ){
  258.             switch( argv[ index ][ 1 ] ){
  259.                 case 'c':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & count, "count", 0 ));
  260.                             break;
  261.                 case 'f':   ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & value, "protocol family", 0, parse_protocol_family ));
  262.                             address.sin_family = ( uint16_t ) value;
  263.                             break;
  264.                 case 'h':   print_help();
  265.                             return EOK;
  266.                             break;
  267.                 case 'p':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "port number", 0 ));
  268.                             address.sin_port = value;
  269.                             break;
  270.                 case 'r':   ERROR_PROPAGATE( parse_parameter_string( argc, argv, & index, & reply, "reply string", 0 ));
  271.                             break;
  272.                 case 's':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & size, "receive size", 0 ));
  273.                             break;
  274.                 case 't':   ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, ( int * ) & type, "socket_type", 0, parse_socket_type ));
  275.                             break;
  276.                 case 'v':   verbose = 1;
  277.                             break;
  278.                 case '-':   if( str_lcmp( argv[ index ] + 2, "count=", 6 ) == 0 ){
  279.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & count, "received count", 8 ))
  280.                             }else if( str_lcmp( argv[ index ] + 2, "family=", 7 ) == 0 ){
  281.                                 ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & value, "protocol family", 9, parse_protocol_family ));
  282.                                 address.sin_family = value;
  283.                             }else if( str_lcmp( argv[ index ] + 2, "help", 5 ) == 0 ){
  284.                                 print_help();
  285.                                 return EOK;
  286.                             }else if( str_lcmp( argv[ index ] + 2, "port=", 5 ) == 0 ){
  287.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "port number", 7 ));
  288.                                 address.sin_port = value;
  289.                             }else if( str_lcmp( argv[ index ] + 2, "reply=", 6 ) == 0 ){
  290.                                 ERROR_PROPAGATE( parse_parameter_string( argc, argv, & index, & reply, "reply string", 8 ));
  291.                             }else if( str_lcmp( argv[ index ] + 2, "size=", 5 ) == 0 ){
  292.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & size, "receive size", 7 ));
  293.                             }else if( str_lcmp( argv[ index ] + 2, "type=", 5 ) == 0 ){
  294.                                 ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, ( int * ) & type, "socket_type", 7, parse_socket_type ));
  295.                             }else if( str_lcmp( argv[ index ] + 2, "verbose", 8 ) == 0 ){
  296.                                 verbose = 1;
  297.                             }else{
  298.                                 print_unrecognized( index, argv[ index ] + 2 );
  299.                                 return EINVAL;
  300.                             }
  301.                             break;
  302.                 default:
  303.                     print_unrecognized( index, argv[ index ] + 1 );
  304.                     return EINVAL;
  305.             }
  306.         }else{
  307.             print_unrecognized( index, argv[ index ] );
  308.             return EINVAL;
  309.         }
  310.     }
  311.  
  312.     if( size <= 0 ){
  313.         fprintf( stderr, "Receive size too small (%d). Using 1024 bytes instead.\n", size );
  314.         size = 1024;
  315.     }
  316.     data = ( char * ) malloc( size + 1 );
  317.     if( ! data ){
  318.         fprintf( stderr, "Failed to allocate receive buffer.\n" );
  319.         return ENOMEM;
  320.     }
  321.  
  322.     reply_length = reply ? str_length( reply ) : 0;
  323.  
  324.     socket_id = socket( address.sin_family, type, 0 );
  325.     if( socket_id < 0 ){
  326.         fprintf( stderr, "Socket create error %d\n", socket_id );
  327.         return socket_id;
  328.     }
  329.     if( ERROR_OCCURRED( bind( socket_id, ( struct sockaddr * ) & address, sizeof( address )))){
  330.         fprintf( stderr, "Socket bind error %d\n", ERROR_CODE );
  331.         return ERROR_CODE;
  332.     }
  333.  
  334.     if( verbose ) printf( "Listenning at %d\n", address.sin_port );
  335.  
  336.     while( count ){
  337.         address_length = sizeof( address );
  338.         length = recvfrom( socket_id, data, size, 0, ( struct sockaddr * ) & address, & address_length );
  339.         if( length < 0 ){
  340.             fprintf( stderr, "Socket receive error %d\n", length );
  341.         }else{
  342.             if( verbose ){
  343.                 if( ERROR_OCCURRED( inet_ntop( address.sin_family, ( uint8_t * ) & address.sin_addr.s_addr, address_string, sizeof( address_string )))){
  344.                     fprintf( stderr, "Received address error %d\n", ERROR_CODE );
  345.                     continue;
  346.                 }else{
  347.                     data[ length ] = '\0';
  348.                     printf( "Received from %s:%d\n%s\n", address_string, address.sin_port, data );
  349.                 }
  350.             }
  351.             if( ERROR_OCCURRED( sendto( socket_id, reply ? reply : data, reply ? reply_length : ( size_t ) length, 0, ( struct sockaddr * ) & address, sizeof( address )))){
  352.                 fprintf( stderr, "Socket send error %d\n", ERROR_CODE );
  353.             }
  354.         }
  355.         if( count > 0 ){
  356.             -- count;
  357.             if( verbose ) printf( "Waiting for next %d packet(s)\n", count );
  358.         }
  359.     }
  360.  
  361.     if( verbose ) printf( "Closing the socket\n" );
  362.  
  363.     if( ERROR_OCCURRED( closesocket( socket_id ))){
  364.         fprintf( stderr, "Close socket error %d\n", ERROR_CODE );
  365.         return ERROR_CODE;
  366.     }
  367.  
  368.     if( verbose ) printf( "Exiting\n" );
  369.  
  370.     return EOK;
  371. }
  372.  
  373. /** @}
  374.  */
  375.