Changes in uspace/app/ping/ping.c [d8e3467:849ed54] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/ping/ping.c

    rd8e3467 r849ed54  
    2828
    2929/** @addtogroup ping
    30  * @{
     30 *  @{
    3131 */
    3232
    3333/** @file
    34  * Packet Internet Network Grouper.
     34 *  Ping application.
    3535 */
    3636
     
    4141#include <ipc/ipc.h>
    4242#include <ipc/services.h>
    43 #include <str_error.h>
    44 #include <arg_parse.h>
    4543
    4644#include <icmp_api.h>
     
    5048#include <ip_codes.h>
    5149#include <socket_errno.h>
    52 #include <socket_parse.h>
    53 
     50#include <net_err.h>
     51
     52#include "parse.h"
    5453#include "print_error.h"
    5554
    56 #define NAME  "ping"
    57 
    58 #define CL_OK           0
    59 #define CL_USAGE        -1
    60 #define CL_MISSING      -2
    61 #define CL_INVALID      -3
    62 #define CL_UNSUPPORTED  -4
    63 #define CL_ERROR        -5
    64 
    65 /** Ping configuration
    66  *
    67  */
    68 typedef struct {
    69         bool verbose;               /**< Verbose printouts. */
    70         size_t size;                /**< Outgoing packet size. */
    71         unsigned int count;         /**< Number of packets to send. */
    72         suseconds_t timeout;        /**< Reply wait timeout. */
    73         int af;                     /**< Address family. */
    74         ip_tos_t tos;               /**< Type of service. */
    75         ip_ttl_t ttl;               /**< Time-to-live. */
    76         bool fragments;             /**< Fragmentation. */
    77        
    78         char *dest_addr;            /**< Destination address. */
    79         struct sockaddr_in dest;    /**< IPv4 destionation. */
    80         struct sockaddr_in6 dest6;  /**< IPv6 destionation. */
    81        
    82         struct sockaddr *dest_raw;  /**< Raw destination address. */
    83         socklen_t dest_len;         /**< Raw destination address length. */
    84        
    85         /** Converted address string. */
    86         char dest_str[INET6_ADDRSTRLEN];
    87 } ping_config_t;
    88 
    89 
    90 static void usage(void)
    91 {
     55/** Echo module name.
     56 */
     57#define NAME    "Ping"
     58
     59/** Module entry point.
     60 *  Reads command line parameters and pings.
     61 *  @param[in] argc The number of command line parameters.
     62 *  @param[in] argv The command line parameters.
     63 *  @returns EOK on success.
     64 */
     65int main(int argc, char * argv[]);
     66
     67/** Prints the application help.
     68 */
     69void ping_print_help(void);
     70
     71int main(int argc, char * argv[]){
     72        ERROR_DECLARE;
     73
     74        size_t size                     = 38;
     75        int verbose                     = 0;
     76        int dont_fragment       = 0;
     77        ip_ttl_t ttl            = 0;
     78        ip_tos_t tos            = 0;
     79        int count                       = 3;
     80        suseconds_t timeout     = 3000;
     81        int family                      = AF_INET;
     82
     83        socklen_t max_length                            = sizeof(struct sockaddr_in6);
     84        uint8_t address_data[max_length];
     85        struct sockaddr * address                       = (struct sockaddr *) address_data;
     86        struct sockaddr_in * address_in         = (struct sockaddr_in *) address;
     87        struct sockaddr_in6 * address_in6       = (struct sockaddr_in6 *) address;
     88        socklen_t addrlen;
     89        char address_string[INET6_ADDRSTRLEN];
     90        uint8_t * address_start;
     91        int icmp_phone;
     92        struct timeval time_before;
     93        struct timeval time_after;
     94        int result;
     95        int value;
     96        int index;
     97
     98        // print the program label
     99        printf("Task %d - ", task_get_id());
     100        printf("%s\n", NAME);
     101
     102        // parse the command line arguments
     103        // stop before the last argument if it does not start with the minus sign ('-')
     104        for(index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); ++ index){
     105                // options should start with the minus sign ('-')
     106                if(argv[index][0] == '-'){
     107                        switch(argv[index][1]){
     108                                // short options with only one letter
     109                                case 'c':
     110                                        ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "count", 0));
     111                                        break;
     112                                case 'f':
     113                                        ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "address family", 0, parse_address_family));
     114                                        break;
     115                                case 'h':
     116                                        ping_print_help();
     117                                        return EOK;
     118                                        break;
     119                                case 's':
     120                                        ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
     121                                        size = (value >= 0) ? (size_t) value : 0;
     122                                        break;
     123                                case 't':
     124                                        ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "timeout", 0));
     125                                        timeout = (value >= 0) ? (suseconds_t) value : 0;
     126                                        break;
     127                                case 'v':
     128                                        verbose = 1;
     129                                        break;
     130                                // long options with the double minus sign ('-')
     131                                case '-':
     132                                        if(str_lcmp(argv[index] + 2, "count=", 6) == 0){
     133                                                ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "received count", 8));
     134                                        }else if(str_lcmp(argv[index] + 2, "dont_fragment", 13) == 0){
     135                                                dont_fragment = 1;
     136                                        }else if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
     137                                                ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "address family", 9, parse_address_family));
     138                                        }else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
     139                                                ping_print_help();
     140                                                return EOK;
     141                                        }else if(str_lcmp(argv[index] + 2, "size=", 5) == 0){
     142                                                ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 7));
     143                                                size = (value >= 0) ? (size_t) value : 0;
     144                                        }else if(str_lcmp(argv[index] + 2, "timeout=", 8) == 0){
     145                                                ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "timeout", 7));
     146                                                timeout = (value >= 0) ? (suseconds_t) value : 0;
     147                                        }else if(str_lcmp(argv[index] + 2, "tos=", 4) == 0){
     148                                                ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "type of service", 7));
     149                                                tos = (value >= 0) ? (ip_tos_t) value : 0;
     150                                        }else if(str_lcmp(argv[index] + 2, "ttl=", 4) == 0){
     151                                                ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "time to live", 7));
     152                                                ttl = (value >= 0) ? (ip_ttl_t) value : 0;
     153                                        }else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
     154                                                verbose = 1;
     155                                        }else{
     156                                                print_unrecognized(index, argv[index] + 2);
     157                                                ping_print_help();
     158                                                return EINVAL;
     159                                        }
     160                                        break;
     161                                default:
     162                                        print_unrecognized(index, argv[index] + 1);
     163                                        ping_print_help();
     164                                        return EINVAL;
     165                        }
     166                }else{
     167                        print_unrecognized(index, argv[index]);
     168                        ping_print_help();
     169                        return EINVAL;
     170                }
     171        }
     172
     173        // if not before the last argument containing the address
     174        if(index >= argc){
     175                printf("Command line error: missing address\n");
     176                ping_print_help();
     177                return EINVAL;
     178        }
     179
     180        // prepare the address buffer
     181        bzero(address_data, max_length);
     182        switch(family){
     183                case AF_INET:
     184                        address_in->sin_family = AF_INET;
     185                        address_start = (uint8_t *) &address_in->sin_addr.s_addr;
     186                        addrlen = sizeof(struct sockaddr_in);
     187                        break;
     188                case AF_INET6:
     189                        address_in6->sin6_family = AF_INET6;
     190                        address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
     191                        addrlen = sizeof(struct sockaddr_in6);
     192                        break;
     193                default:
     194                        fprintf(stderr, "Address family is not supported\n");
     195                        return EAFNOSUPPORT;
     196        }
     197
     198        // parse the last argument which should contain the address
     199        if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
     200                fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
     201                return ERROR_CODE;
     202        }
     203
     204        // connect to the ICMP module
     205        icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
     206        if(icmp_phone < 0){
     207                fprintf(stderr, "ICMP connect error %d\n", icmp_phone);
     208                return icmp_phone;
     209        }
     210
     211        // print the ping header
     212        printf("PING %d bytes of data\n", size);
     213        if(ERROR_OCCURRED(inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)))){
     214                fprintf(stderr, "Address error %d\n", ERROR_CODE);
     215        }else{
     216                printf("Address %s:\n", address_string);
     217        }
     218
     219        // do count times
     220        while(count > 0){
     221
     222                // get the starting time
     223                if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
     224                        fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
     225                        // release the ICMP phone
     226                        ipc_hangup(icmp_phone);
     227                        return ERROR_CODE;
     228                }
     229
     230                // request the ping
     231                result = icmp_echo_msg(icmp_phone, size, timeout, ttl, tos, dont_fragment, address, addrlen);
     232
     233                // get the ending time
     234                if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
     235                        fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
     236                        // release the ICMP phone
     237                        ipc_hangup(icmp_phone);
     238                        return ERROR_CODE;
     239                }
     240
     241                // print the result
     242                switch(result){
     243                        case ICMP_ECHO:
     244                                printf("Ping round trip time %d miliseconds\n", tv_sub(&time_after, &time_before) / 1000);
     245                                break;
     246                        case ETIMEOUT:
     247                                printf("Timed out.\n");
     248                                break;
     249                        default:
     250                                print_error(stdout, result, NULL, "\n");
     251                }
     252                -- count;
     253        }
     254
     255        if(verbose){
     256                printf("Exiting\n");
     257        }
     258
     259        // release the ICMP phone
     260        ipc_hangup(icmp_phone);
     261
     262        return EOK;
     263}
     264
     265void ping_print_help(void){
    92266        printf(
    93             "Usage: ping [-c count] [-s size] [-W timeout] [-f family] [-t ttl]\n" \
    94             "            [-Q tos] [--dont_fragment] destination\n" \
    95             "\n" \
    96             "Options:\n" \
    97             "\t-c count\n" \
    98             "\t--count=count\n" \
    99             "\t\tNumber of outgoing packets (default: 4)\n" \
    100             "\n" \
    101             "\t-s size\n" \
    102             "\t--size=bytes\n" \
    103             "\t\tOutgoing packet size (default: 56 bytes)\n" \
    104             "\n" \
    105             "\t-W timeout\n" \
    106             "\t--timeout=ms\n" \
    107             "\t\tReply wait timeout (default: 3000 ms)\n" \
    108             "\n" \
    109             "\t-f family\n" \
    110             "\t--family=family\n" \
    111             "\t\tDestination address family, AF_INET or AF_INET6 (default: AF_INET)\n" \
    112             "\n" \
    113             "\t-t ttl\n" \
    114             "\t--ttl=ttl\n" \
    115             "\t\tOutgoing packet time-to-live (default: 0)\n" \
    116             "\n" \
    117             "\t-Q tos\n" \
    118             "\t--tos=tos\n" \
    119             "\t\tOutgoing packet type of service (default: 0)\n" \
    120             "\n" \
    121             "\t--dont_fragment\n" \
    122             "\t\tDisable packet fragmentation (default: enabled)\n" \
    123             "\n" \
    124             "\t-v\n" \
    125             "\t--verbose\n" \
    126             "\t\tVerbose operation\n" \
    127             "\n" \
    128             "\t-h\n" \
    129             "\t--help\n" \
    130             "\t\tPrint this usage information\n"
     267                "Network Ping aplication\n" \
     268                "Usage: ping [options] numeric_address\n" \
     269                "Where options are:\n" \
     270                "\n" \
     271                "-c request_count | --count=request_count\n" \
     272                "\tThe number of packets the application sends. The default is three (3).\n" \
     273                "\n" \
     274                "--dont_fragment\n" \
     275                "\tDisable packet fragmentation.\n"
     276                "\n" \
     277                "-f address_family | --family=address_family\n" \
     278                "\tThe given address family. Only the AF_INET and AF_INET6 are supported.\n"
     279                "\n" \
     280                "-h | --help\n" \
     281                "\tShow this application help.\n"
     282                "\n" \
     283                "-s packet_size | --size=packet_size\n" \
     284                "\tThe packet data size the application sends. The default is 38 bytes.\n" \
     285                "\n" \
     286                "-t timeout | --timeout=timeout\n" \
     287                "\tThe number of miliseconds the application waits for a reply. The default is three thousands (3 000).\n" \
     288                "\n" \
     289                "--tos=tos\n" \
     290                "\tThe type of service to be used.\n" \
     291                "\n" \
     292                "--ttl=ttl\n" \
     293                "\tThe time to live to be used.\n" \
     294                "\n" \
     295                "-v | --verbose\n" \
     296                "\tShow all output messages.\n"
    131297        );
    132298}
    133299
    134 static int args_parse(int argc, char *argv[], ping_config_t *config)
    135 {
    136         if (argc < 2)
    137                 return CL_USAGE;
    138        
    139         int i;
    140         int ret;
    141        
    142         for (i = 1; i < argc; i++) {
    143                
    144                 /* Not an option */
    145                 if (argv[i][0] != '-')
    146                         break;
    147                
    148                 /* Options terminator */
    149                 if (str_cmp(argv[i], "--") == 0) {
    150                         i++;
    151                         break;
    152                 }
    153                
    154                 int off;
    155                
    156                 /* Usage */
    157                 if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1)
    158                         return CL_USAGE;
    159                
    160                 /* Verbose */
    161                 if ((off = arg_parse_short_long(argv[i], "-v", "--verbose")) != -1) {
    162                         config->verbose = true;
    163                         continue;
    164                 }
    165                
    166                 /* Don't fragment */
    167                 if (str_cmp(argv[i], "--dont_fragment") == 0) {
    168                         config->fragments = false;
    169                         continue;
    170                 }
    171                
    172                 /* Count */
    173                 if ((off = arg_parse_short_long(argv[i], "-c", "--count=")) != -1) {
    174                         int tmp;
    175                         ret = arg_parse_int(argc, argv, &i, &tmp, off);
    176                        
    177                         if ((ret != EOK) || (tmp < 0))
    178                                 return i;
    179                        
    180                         config->count = (unsigned int) tmp;
    181                         continue;
    182                 }
    183                
    184                 /* Outgoing packet size */
    185                 if ((off = arg_parse_short_long(argv[i], "-s", "--size=")) != -1) {
    186                         int tmp;
    187                         ret = arg_parse_int(argc, argv, &i, &tmp, off);
    188                        
    189                         if ((ret != EOK) || (tmp < 0))
    190                                 return i;
    191                        
    192                         config->size = (size_t) tmp;
    193                         continue;
    194                 }
    195                
    196                 /* Reply wait timeout */
    197                 if ((off = arg_parse_short_long(argv[i], "-W", "--timeout=")) != -1) {
    198                         int tmp;
    199                         ret = arg_parse_int(argc, argv, &i, &tmp, off);
    200                        
    201                         if ((ret != EOK) || (tmp < 0))
    202                                 return i;
    203                        
    204                         config->timeout = (suseconds_t) tmp;
    205                         continue;
    206                 }
    207                
    208                 /* Address family */
    209                 if ((off = arg_parse_short_long(argv[i], "-f", "--family=")) != -1) {
    210                         ret = arg_parse_name_int(argc, argv, &i, &config->af, off,
    211                             socket_parse_address_family);
    212                        
    213                         if (ret != EOK)
    214                                 return i;
    215                        
    216                         continue;
    217                 }
    218                
    219                 /* Type of service */
    220                 if ((off = arg_parse_short_long(argv[i], "-Q", "--tos=")) != -1) {
    221                         int tmp;
    222                         ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
    223                             socket_parse_address_family);
    224                        
    225                         if ((ret != EOK) || (tmp < 0))
    226                                 return i;
    227                        
    228                         config->tos = (ip_tos_t) tmp;
    229                         continue;
    230                 }
    231                
    232                 /* Time to live */
    233                 if ((off = arg_parse_short_long(argv[i], "-t", "--ttl=")) != -1) {
    234                         int tmp;
    235                         ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
    236                             socket_parse_address_family);
    237                        
    238                         if ((ret != EOK) || (tmp < 0))
    239                                 return i;
    240                        
    241                         config->ttl = (ip_ttl_t) tmp;
    242                         continue;
    243                 }
    244         }
    245        
    246         if (i >= argc)
    247                 return CL_MISSING;
    248        
    249         config->dest_addr = argv[i];
    250        
    251         /* Resolve destionation address */
    252         switch (config->af) {
    253         case AF_INET:
    254                 config->dest_raw = (struct sockaddr *) &config->dest;
    255                 config->dest_len = sizeof(config->dest);
    256                 config->dest.sin_family = config->af;
    257                 ret = inet_pton(config->af, config->dest_addr,
    258                     (uint8_t *) &config->dest.sin_addr.s_addr);
    259                 break;
    260         case AF_INET6:
    261                 config->dest_raw = (struct sockaddr *) &config->dest6;
    262                 config->dest_len = sizeof(config->dest6);
    263                 config->dest6.sin6_family = config->af;
    264                 ret = inet_pton(config->af, config->dest_addr,
    265                     (uint8_t *) &config->dest6.sin6_addr.s6_addr);
    266                 break;
    267         default:
    268                 return CL_UNSUPPORTED;
    269         }
    270        
    271         if (ret != EOK)
    272                 return CL_INVALID;
    273        
    274         /* Convert destination address back to string */
    275         switch (config->af) {
    276         case AF_INET:
    277                 ret = inet_ntop(config->af,
    278                     (uint8_t *) &config->dest.sin_addr.s_addr,
    279                     config->dest_str, sizeof(config->dest_str));
    280                 break;
    281         case AF_INET6:
    282                 ret = inet_ntop(config->af,
    283                     (uint8_t *) &config->dest6.sin6_addr.s6_addr,
    284                     config->dest_str, sizeof(config->dest_str));
    285                 break;
    286         default:
    287                 return CL_UNSUPPORTED;
    288         }
    289        
    290         if (ret != EOK)
    291                 return CL_ERROR;
    292        
    293         return CL_OK;
    294 }
    295 
    296 int main(int argc, char *argv[])
    297 {
    298         ping_config_t config;
    299        
    300         /* Default configuration */
    301         config.verbose = false;
    302         config.size = 56;
    303         config.count = 4;
    304         config.timeout = 3000;
    305         config.af = AF_INET;
    306         config.tos = 0;
    307         config.ttl = 0;
    308         config.fragments = true;
    309        
    310         int ret = args_parse(argc, argv, &config);
    311        
    312         switch (ret) {
    313         case CL_OK:
    314                 break;
    315         case CL_USAGE:
    316                 usage();
    317                 return 0;
    318         case CL_MISSING:
    319                 fprintf(stderr, "%s: Destination address missing\n", NAME);
    320                 return 1;
    321         case CL_INVALID:
    322                 fprintf(stderr, "%s: Destination address '%s' invalid or malformed\n",
    323                     NAME, config.dest_addr);
    324                 return 2;
    325         case CL_UNSUPPORTED:
    326                 fprintf(stderr, "%s: Destination address '%s' unsupported\n",
    327                     NAME, config.dest_addr);
    328                 return 3;
    329         case CL_ERROR:
    330                 fprintf(stderr, "%s: Destination address '%s' error\n",
    331                     NAME, config.dest_addr);
    332                 return 4;
    333         default:
    334                 fprintf(stderr, "%s: Unknown or invalid option '%s'\n", NAME,
    335                     argv[ret]);
    336                 return 5;
    337         }
    338        
    339         printf("PING %s (%s) %u(%u) bytes of data\n", config.dest_addr,
    340             config.dest_str, config.size, config.size);
    341        
    342         int icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
    343         if (icmp_phone < 0) {
    344                 fprintf(stderr, "%s: Unable to connect to ICMP service (%s)\n", NAME,
    345                     str_error(icmp_phone));
    346                 return icmp_phone;
    347         }
    348        
    349         unsigned int seq;
    350         for (seq = 0; seq < config.count; seq++) {
    351                 struct timeval t0;
    352                 ret = gettimeofday(&t0, NULL);
    353                 if (ret != EOK) {
    354                         fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
    355                             str_error(ret));
    356                        
    357                         ipc_hangup(icmp_phone);
    358                         return ret;
    359                 }
    360                
    361                 /* Ping! */
    362                 int result = icmp_echo_msg(icmp_phone, config.size, config.timeout,
    363                     config.ttl, config.tos, !config.fragments, config.dest_raw,
    364                     config.dest_len);
    365                
    366                 struct timeval t1;
    367                 ret = gettimeofday(&t1, NULL);
    368                 if (ret != EOK) {
    369                         fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
    370                             str_error(ret));
    371                        
    372                         ipc_hangup(icmp_phone);
    373                         return ret;
    374                 }
    375                
    376                 suseconds_t elapsed = tv_sub(&t1, &t0);
    377                
    378                 switch (result) {
    379                 case ICMP_ECHO:
    380                         printf("%u bytes from ? (?): icmp_seq=%u ttl=? time=%u.%04u\n",
    381                                 config.size, seq, elapsed / 1000, elapsed % 1000);
    382                         break;
    383                 case ETIMEOUT:
    384                         printf("%u bytes from ? (?): icmp_seq=%u Timed out\n",
    385                                 config.size, seq);
    386                         break;
    387                 default:
    388                         print_error(stdout, result, NULL, "\n");
    389                 }
    390         }
    391        
    392         ipc_hangup(icmp_phone);
    393        
    394         return 0;
    395 }
    396 
    397300/** @}
    398301 */
Note: See TracChangeset for help on using the changeset viewer.