Subversion Repositories HelenOS

Rev

Rev 4717 | 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/inet.h"
  46. #include "../../include/ip_codes.h"
  47. #include "../../include/socket_codes.h"
  48.  
  49. #include "../../err.h"
  50.  
  51. #include "../parse.h"
  52.  
  53. /** Echo module name.
  54.  */
  55. #define NAME    "Ping"
  56.  
  57. /** Module entry point.
  58.  *  Reads command line parameters and pings.
  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 address family number.
  70.  *  @param name The address family name. Input parameter.
  71.  *  @returns The corresponding address family number.
  72.  */
  73. int parse_address_family( const char * name );
  74.  
  75. void print_help( void ){
  76.     printf(
  77.         "Network Ping aplication\n" \
  78.         "Usage: ping [options] numeric_address\n" \
  79.         "Where options are:\n" \
  80.         "\n" \
  81.         "-c request_count | --count=request_count\n" \
  82.         "\tThe number of packets the application sends. The default is three (3).\n" \
  83.         "\n" \
  84.         "--dont_fragment\n" \
  85.         "\tDisable packet fragmentation.\n"
  86.         "\n" \
  87.         "-f address_family | --family=address_family\n" \
  88.         "\tThe given address family. Only the AF_INET is supported.\n"
  89.         "\n" \
  90.         "-h | --help\n" \
  91.         "\tShow this application help.\n"
  92.         "\n" \
  93.         "-s packet_size | --size=packet_size\n" \
  94.         "\tThe packet data size the application sends. The default is 38 bytes.\n" \
  95.         "\n" \
  96.         "-t timeout | --timeout=timeout\n" \
  97.         "\tThe number of miliseconds the application waits for a reply. The default is three thousands (3 000).\n" \
  98.         "\n" \
  99.         "--tos=tos\n" \
  100.         "\tThe type of service to be used.\n" \
  101.         "\n" \
  102.         "--ttl=ttl\n" \
  103.         "\tThe time to live to be used.\n" \
  104.         "\n" \
  105.         "-v | --verbose\n" \
  106.         "\tShow all output messages.\n"
  107.     );
  108. }
  109.  
  110. int parse_address_family( const char * name ){
  111.     if( str_lcmp( name, "AF_INET", 7 ) == 0 ){
  112.         return AF_INET;
  113.     }
  114.     return ENOENT;
  115. }
  116.  
  117. int main( int argc, char * argv[] ){
  118.     ERROR_DECLARE;
  119.  
  120.     size_t              size            = 38;
  121.     int                 verbose         = 0;
  122.     int                 dont_fragment   = 0;
  123.     ip_ttl_t            ttl             = 0;
  124.     ip_tos_t            tos             = 0;
  125.     int                 count           = 3;
  126.     suseconds_t         timeout         = 3000;
  127.     struct sockaddr_in  address         = { .sin_family = AF_INET, .sin_port = 7 };
  128.  
  129.     int                 icmp_phone;
  130.     struct timeval      time_before;
  131.     struct timeval      time_after;
  132.     int                 result;
  133.     int                 value;
  134.     int                 index;
  135.  
  136.     printf( "Task %d - ", task_get_id());
  137.     printf( "%s\n", NAME );
  138.  
  139.     for( index = 1; index < argc - 1; ++ index ){
  140.         if( argv[ index ][ 0 ] == '-' ){
  141.             switch( argv[ index ][ 1 ] ){
  142.                 case 'c':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & count, "count", 0 ));
  143.                             break;
  144.                 case 'f':   ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & value, "address family", 0, parse_address_family ));
  145.                             address.sin_family = ( uint16_t ) value;
  146.                             break;
  147.                 case 'h':   print_help();
  148.                             return EOK;
  149.                             break;
  150.                 case 's':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "packet size", 0 ));
  151.                             size = (value >= 0 ) ? ( size_t ) value : 0;
  152.                             break;
  153.                 case 't':   ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "timeout", 0 ));
  154.                             timeout = (value >= 0 ) ? ( suseconds_t ) value : 0;
  155.                             break;
  156.                 case 'v':   verbose = 1;
  157.                             break;
  158.                 case '-':   if( str_lcmp( argv[ index ] + 2, "count=", 6 ) == 0 ){
  159.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & count, "received count", 8 ))
  160.                             }else if( str_lcmp( argv[ index ] + 2, "dont_fragment", 13 ) == 0 ){
  161.                                 dont_fragment = 1;
  162.                             }else if( str_lcmp( argv[ index ] + 2, "family=", 7 ) == 0 ){
  163.                                 ERROR_PROPAGATE( parse_parameter_name_int( argc, argv, & index, & value, "address family", 9, parse_address_family ));
  164.                                 address.sin_family = ( uint16_t ) value;
  165.                             }else if( str_lcmp( argv[ index ] + 2, "help", 5 ) == 0 ){
  166.                                 print_help();
  167.                                 return EOK;
  168.                             }else if( str_lcmp( argv[ index ] + 2, "size=", 5 ) == 0 ){
  169.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "packet size", 7 ));
  170.                                 size = (value >= 0 ) ? ( size_t ) value : 0;
  171.                             }else if( str_lcmp( argv[ index ] + 2, "timeout=", 8 ) == 0 ){
  172.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "timeout", 7 ));
  173.                                 timeout = (value >= 0 ) ? ( suseconds_t ) value : 0;
  174.                             }else if( str_lcmp( argv[ index ] + 2, "tos=", 4 ) == 0 ){
  175.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "type of service", 7 ));
  176.                                 tos = (value >= 0 ) ? ( ip_tos_t ) value : 0;
  177.                             }else if( str_lcmp( argv[ index ] + 2, "ttl=", 4 ) == 0 ){
  178.                                 ERROR_PROPAGATE( parse_parameter_int( argc, argv, & index, & value, "time to live", 7 ));
  179.                                 ttl = (value >= 0 ) ? ( ip_ttl_t ) value : 0;
  180.                             }else if( str_lcmp( argv[ index ] + 2, "verbose", 8 ) == 0 ){
  181.                                 verbose = 1;
  182.                             }else{
  183.                                 print_unrecognized( index, argv[ index ] + 2 );
  184.                                 print_help();
  185.                                 return EINVAL;
  186.                             }
  187.                             break;
  188.                 default:
  189.                     print_unrecognized( index, argv[ index ] + 1 );
  190.                     print_help();
  191.                     return EINVAL;
  192.             }
  193.         }else{
  194.             print_unrecognized( index, argv[ index ] );
  195.             print_help();
  196.             return EINVAL;
  197.         }
  198.     }
  199.  
  200.     if( ERROR_OCCURRED( inet_pton( address.sin_family, argv[ argc - 1 ], ( uint8_t * ) & address.sin_addr ))){
  201.         fprintf( stderr, "Address parse error %d\n", ERROR_CODE );
  202.         return ERROR_CODE;
  203.     }
  204.  
  205.     icmp_phone = icmp_connect_module( SERVICE_ICMP );
  206.     if( icmp_phone < 0 ){
  207.         fprintf( stderr, "ICMP connect error %d\n", icmp_phone );
  208.     }
  209.  
  210.     printf( "PING %d bytes of data\n", size );
  211.  
  212.     while( count > 0 ){
  213.         if( ERROR_OCCURRED( gettimeofday( & time_before, NULL ))){
  214.             fprintf( stderr, "Get time of day error %d\n", ERROR_CODE );
  215.             return ERROR_CODE;
  216.         }
  217.         result = icmp_echo_msg( icmp_phone, size, timeout, ttl, tos, dont_fragment, ( struct sockaddr * ) & address, sizeof( address ));
  218.         if( ERROR_OCCURRED( gettimeofday( & time_after, NULL ))){
  219.             fprintf( stderr, "Get time of day error %d\n", ERROR_CODE );
  220.             return ERROR_CODE;
  221.         }
  222.         switch( result ){
  223.             case ICMP_ECHO:
  224.                 printf( "Ping round trip time %d microseconds\n", tv_sub( & time_after, & time_before ));
  225.                 break;
  226.             case ELIMIT:
  227.                 printf( "Timeouted.\n" );
  228.                 break;
  229.             default:
  230.                 printf( "Error %d.\n", result );
  231.         }
  232.         -- count;
  233.     }
  234.  
  235.     if( verbose ) fprintf( "Exiting\n" );
  236.  
  237.     return EOK;
  238. }
  239.  
  240. /** @}
  241.  */
  242.