Subversion Repositories HelenOS

Rev

Rev 4731 | Rev 4743 | 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 ping
  30.  *  @{
  31.  */
  32.  
  33. /** @file
  34.  *  Ping application.
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <string.h>
  39. #include <task.h>
  40. #include <time.h>
  41. #include <ipc/services.h>
  42.  
  43. #include "../../include/icmp_api.h"
  44. #include "../../include/in.h"
  45. #include "../../include/in6.h"
  46. #include "../../include/inet.h"
  47. #include "../../include/ip_codes.h"
  48. #include "../../include/socket_errno.h"
  49.  
  50. #include "../../err.h"
  51.  
  52. #include "../parse.h"
  53. #include "../print_error.h"
  54.  
  55. /** Echo module name.
  56.  */
  57. #define NAME    "Ping"
  58.  
  59. /** Module entry point.
  60.  *  Reads command line parameters and pings.
  61.  *  @param argc The number of command line parameters. Input parameter.
  62.  *  @param argv The command line parameters. Input parameter.
  63.  *  @returns EOK on success.
  64.  */
  65. int     main( int argc, char * argv[] );
  66.  
  67. /** Prints the application help.
  68.  */
  69. void    print_help( void );
  70.  
  71. /** Translates the character string to the address family number.
  72.  *  @param name The address family name. Input parameter.
  73.  *  @returns The corresponding address family number.
  74.  *  @returns EAFNOSUPPORTED if the address family is not supported.
  75.  */
  76. int     parse_address_family( const char * name );
  77.  
  78. void print_help( void ){
  79.     printf(
  80.         "Network Ping aplication\n" \
  81.         "Usage: ping [options] numeric_address\n" \
  82.         "Where options are:\n" \
  83.         "\n" \
  84.         "-c request_count | --count=request_count\n" \
  85.         "\tThe number of packets the application sends. The default is three (3).\n" \
  86.         "\n" \
  87.         "--dont_fragment\n" \
  88.         "\tDisable packet fragmentation.\n"
  89.         "\n" \
  90.         "-f address_family | --family=address_family\n" \
  91.         "\tThe given address family. Only the AF_INET and AF_INET6 are supported.\n"
  92.         "\n" \
  93.         "-h | --help\n" \
  94.         "\tShow this application help.\n"
  95.         "\n" \
  96.         "-s packet_size | --size=packet_size\n" \
  97.         "\tThe packet data size the application sends. The default is 38 bytes.\n" \
  98.         "\n" \
  99.         "-t timeout | --timeout=timeout\n" \
  100.         "\tThe number of miliseconds the application waits for a reply. The default is three thousands (3 000).\n" \
  101.         "\n" \
  102.         "--tos=tos\n" \
  103.         "\tThe type of service to be used.\n" \
  104.         "\n" \
  105.         "--ttl=ttl\n" \
  106.         "\tThe time to live to be used.\n" \
  107.         "\n" \
  108.         "-v | --verbose\n" \
  109.         "\tShow all output messages.\n"
  110.     );
  111. }
  112.  
  113. int parse_address_family( const char * name ){
  114.     if( str_lcmp( name, "AF_INET", 7 ) == 0 ){
  115.         return AF_INET;
  116.     }else if( str_lcmp( name, "AF_INET6", 8 ) == 0 ){
  117.         return AF_INET6;
  118.     }
  119.     return EAFNOSUPPORT;
  120. }
  121.  
  122. int main( int argc, char * argv[] ){
  123.     ERROR_DECLARE;
  124.  
  125.     size_t              size            = 38;
  126.     int                 verbose         = 0;
  127.     int                 dont_fragment   = 0;
  128.     ip_ttl_t            ttl             = 0;
  129.     ip_tos_t            tos             = 0;
  130.     int                 count           = 3;
  131.     suseconds_t         timeout         = 3000;
  132.     int                 family          = AF_INET;
  133.  
  134.     socklen_t           max_length      = sizeof( struct sockaddr_in6 );
  135.     uint8_t             address_data[ max_length ];
  136.     struct sockaddr *       address     = ( struct sockaddr * ) address_data;
  137.     struct sockaddr_in *    address_in      = ( struct sockaddr_in * ) address;
  138.     struct sockaddr_in6 *   address_in6 = ( struct sockaddr_in6 * ) address;
  139.     socklen_t           addrlen;
  140.     char                address_string[ INET6_ADDRSTRLEN ];
  141.     uint8_t *           address_start;
  142.     int                 icmp_phone;
  143.     struct timeval      time_before;
  144.     struct timeval      time_after;
  145.     int                 result;
  146.     int                 value;
  147.     int                 index;
  148.  
  149.     printf( "Task %d - ", task_get_id());
  150.     printf( "%s\n", NAME );
  151.  
  152.     if( argc <= 1 ){
  153.         print_help();
  154.         return EINVAL;
  155.     }
  156.  
  157.     for( index = 1; ( index < argc - 1 ) || (( index == argc ) && ( argv[ index ][ 0 ] == '-' )); ++ index ){
  158.         if( argv[ index ][ 0 ] == '-' ){
  159.             switch( argv[ index ][ 1 ] ){
  160.                 case 'c':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & count, "count", 0 ));
  161.                             break;
  162.                 case 'f':   ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & family, "address family", 0, parse_address_family ));
  163.                             break;
  164.                 case 'h':   print_help();
  165.                             return EOK;
  166.                             break;
  167.                 case 's':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "packet size", 0 ));
  168.                             size = (value >= 0 ) ? ( size_t ) value : 0;
  169.                             break;
  170.                 case 't':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "timeout", 0 ));
  171.                             timeout = (value >= 0 ) ? ( suseconds_t ) value : 0;
  172.                             break;
  173.                 case 'v':   verbose = 1;
  174.                             break;
  175.                 case '-':   if( str_lcmp( argv[ index ] + 2, "count=", 6 ) == 0 ){
  176.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & count, "received count", 8 ));
  177.                             }else if( str_lcmp( argv[ index ] + 2, "dont_fragment", 13 ) == 0 ){
  178.                                 dont_fragment = 1;
  179.                             }else if( str_lcmp( argv[ index ] + 2, "family=", 7 ) == 0 ){
  180.                                 ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & family, "address family", 9, parse_address_family ));
  181.                             }else if( str_lcmp( argv[ index ] + 2, "help", 5 ) == 0 ){
  182.                                 print_help();
  183.                                 return EOK;
  184.                             }else if( str_lcmp( argv[ index ] + 2, "size=", 5 ) == 0 ){
  185.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "packet size", 7 ));
  186.                                 size = (value >= 0 ) ? ( size_t ) value : 0;
  187.                             }else if( str_lcmp( argv[ index ] + 2, "timeout=", 8 ) == 0 ){
  188.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "timeout", 7 ));
  189.                                 timeout = (value >= 0 ) ? ( suseconds_t ) value : 0;
  190.                             }else if( str_lcmp( argv[ index ] + 2, "tos=", 4 ) == 0 ){
  191.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "type of service", 7 ));
  192.                                 tos = (value >= 0 ) ? ( ip_tos_t ) value : 0;
  193.                             }else if( str_lcmp( argv[ index ] + 2, "ttl=", 4 ) == 0 ){
  194.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "time to live", 7 ));
  195.                                 ttl = (value >= 0 ) ? ( ip_ttl_t ) value : 0;
  196.                             }else if( str_lcmp( argv[ index ] + 2, "verbose", 8 ) == 0 ){
  197.                                 verbose = 1;
  198.                             }else{
  199.                                 print_unrecognized( index, argv[ index ] + 2 );
  200.                                 print_help();
  201.                                 return EINVAL;
  202.                             }
  203.                             break;
  204.                 default:
  205.                     print_unrecognized( index, argv[ index ] + 1 );
  206.                     print_help();
  207.                     return EINVAL;
  208.             }
  209.         }else{
  210.             print_unrecognized( index, argv[ index ] );
  211.             print_help();
  212.             return EINVAL;
  213.         }
  214.     }
  215.  
  216.     bzero( address_data, max_length );
  217.     switch( family ){
  218.         case AF_INET:
  219.             address_in->sin_family = AF_INET;
  220.             address_start = ( uint8_t * ) & address_in->sin_addr.s_addr;
  221.             addrlen = sizeof( struct sockaddr_in );
  222.             break;
  223.         case AF_INET6:
  224.             address_in6->sin6_family = AF_INET6;
  225.             address_start = ( uint8_t * ) & address_in6->sin6_addr.s6_addr;
  226.             addrlen = sizeof( struct sockaddr_in6 );
  227.             break;
  228.         default:
  229.             fprintf( stderr, "Address family is not supported\n" );
  230.             return EAFNOSUPPORT;
  231.     }
  232.  
  233.     if( ERROR_OCCURRED( inet_pton( family, argv[ argc - 1 ], address_start ))){
  234.         fprintf( stderr, "Address parse error %d\n", ERROR_CODE );
  235.         return ERROR_CODE;
  236.     }
  237.  
  238.     // TODO timeout?
  239.     icmp_phone = icmp_connect_module( SERVICE_ICMP );
  240.     if( icmp_phone < 0 ){
  241.         fprintf( stderr, "ICMP connect error %d\n", icmp_phone );
  242.     }
  243.  
  244.     printf( "PING %d bytes of data\n", size );
  245.     if( ERROR_OCCURRED( inet_ntop( address->sa_family, address_start, address_string, sizeof( address_string )))){
  246.         fprintf( stderr, "Address error %d\n", ERROR_CODE );
  247.     }else{
  248.         printf( "Address %s:\n", address_string );
  249.     }
  250.  
  251.     while( count > 0 ){
  252.         if( ERROR_OCCURRED( gettimeofday( & time_before, NULL ))){
  253.             fprintf( stderr, "Get time of day error %d\n", ERROR_CODE );
  254.             return ERROR_CODE;
  255.         }
  256.         result = icmp_echo_msg( icmp_phone, size, timeout, ttl, tos, dont_fragment, address, addrlen );
  257.         if( ERROR_OCCURRED( gettimeofday( & time_after, NULL ))){
  258.             fprintf( stderr, "Get time of day error %d\n", ERROR_CODE );
  259.             return ERROR_CODE;
  260.         }
  261.         switch( result ){
  262.             case ICMP_ECHO:
  263.                 printf( "Ping round trip time %d microseconds\n", tv_sub( & time_after, & time_before ));
  264.                 break;
  265.             case ETIMEOUT:
  266.                 printf( "Timeouted.\n" );
  267.                 break;
  268.             default:
  269.                 print_error( stdout, result, NULL, "\n" );
  270.         }
  271.         -- count;
  272.     }
  273.  
  274.     if( verbose ) printf( "Exiting\n" );
  275.  
  276.     return EOK;
  277. }
  278.  
  279. /** @}
  280.  */
  281.