Changeset f4f866c in mainline for uspace/app/ping/ping.c


Ignore:
Timestamp:
2010-04-23T21:42:26Z (14 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
6c39a907
Parents:
38aaacc2 (diff), 80badbe (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

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

    r38aaacc2 rf4f866c  
    2828
    2929/** @addtogroup ping
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  Ping application.
     34 * Packet Internet Network Grouper.
    3535 */
    3636
     
    4141#include <ipc/ipc.h>
    4242#include <ipc/services.h>
     43#include <str_error.h>
     44#include <arg_parse.h>
    4345
    4446#include <icmp_api.h>
     
    4850#include <ip_codes.h>
    4951#include <socket_errno.h>
    50 #include <net_err.h>
    51 
    52 #include "parse.h"
     52#include <socket_parse.h>
     53
    5354#include "print_error.h"
    5455
    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  */
    65 int main(int argc, char * argv[]);
    66 
    67 /** Prints the application help.
    68  */
    69 void ping_print_help(void);
    70 
    71 int 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);
     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 */
     68typedef 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
     90static void usage(void)
     91{
     92        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"
     131        );
     132}
     133
     134static 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] != '-')
    187146                        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);
     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
     296int 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);
    192386                        break;
    193387                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
     388                        print_error(stdout, result, NULL, "\n");
     389                }
     390        }
     391       
    260392        ipc_hangup(icmp_phone);
    261 
    262         return EOK;
     393       
     394        return 0;
    263395}
    264396
    265 void ping_print_help(void){
    266         printf(
    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"
    297         );
    298 }
    299 
    300397/** @}
    301398 */
Note: See TracChangeset for help on using the changeset viewer.