ping.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00037 #include <async.h>
00038 #include <stdio.h>
00039 #include <str.h>
00040 #include <task.h>
00041 #include <time.h>
00042 #include <ipc/services.h>
00043 #include <str_error.h>
00044 #include <errno.h>
00045 #include <arg_parse.h>
00046 
00047 #include <net/icmp_api.h>
00048 #include <net/in.h>
00049 #include <net/in6.h>
00050 #include <net/inet.h>
00051 #include <net/socket_parse.h>
00052 #include <net/ip_codes.h>
00053 
00054 #include "print_error.h"
00055 
00056 #define NAME  "ping"
00057 
00058 #define CL_OK           0
00059 #define CL_USAGE        -1
00060 #define CL_MISSING      -2
00061 #define CL_INVALID      -3
00062 #define CL_UNSUPPORTED  -4
00063 #define CL_ERROR        -5
00064 
00068 typedef struct {
00069         bool verbose;               
00070         size_t size;                
00071         unsigned int count;         
00072         suseconds_t timeout;        
00073         int af;                     
00074         ip_tos_t tos;               
00075         ip_ttl_t ttl;               
00076         bool fragments;             
00078         char *dest_addr;            
00079         struct sockaddr_in dest;    
00080         struct sockaddr_in6 dest6;  
00082         struct sockaddr *dest_raw;  
00083         socklen_t dest_len;         
00086         char dest_str[INET6_ADDRSTRLEN];
00087 } ping_config_t;
00088 
00089 
00090 static void usage(void)
00091 {
00092         printf(
00093             "Usage: ping [-c count] [-s size] [-W timeout] [-f family] [-t ttl]\n" \
00094             "            [-Q tos] [--dont_fragment] destination\n" \
00095             "\n" \
00096             "Options:\n" \
00097             "\t-c count\n" \
00098             "\t--count=count\n" \
00099             "\t\tNumber of outgoing packets (default: 4)\n" \
00100             "\n" \
00101             "\t-s size\n" \
00102             "\t--size=bytes\n" \
00103             "\t\tOutgoing packet size (default: 56 bytes)\n" \
00104             "\n" \
00105             "\t-W timeout\n" \
00106             "\t--timeout=ms\n" \
00107             "\t\tReply wait timeout (default: 3000 ms)\n" \
00108             "\n" \
00109             "\t-f family\n" \
00110             "\t--family=family\n" \
00111             "\t\tDestination address family, AF_INET or AF_INET6 (default: AF_INET)\n" \
00112             "\n" \
00113             "\t-t ttl\n" \
00114             "\t--ttl=ttl\n" \
00115             "\t\tOutgoing packet time-to-live (default: 0)\n" \
00116             "\n" \
00117             "\t-Q tos\n" \
00118             "\t--tos=tos\n" \
00119             "\t\tOutgoing packet type of service (default: 0)\n" \
00120             "\n" \
00121             "\t--dont_fragment\n" \
00122             "\t\tDisable packet fragmentation (default: enabled)\n" \
00123             "\n" \
00124             "\t-v\n" \
00125             "\t--verbose\n" \
00126             "\t\tVerbose operation\n" \
00127             "\n" \
00128             "\t-h\n" \
00129             "\t--help\n" \
00130             "\t\tPrint this usage information\n"
00131         );
00132 }
00133 
00134 static int args_parse(int argc, char *argv[], ping_config_t *config)
00135 {
00136         if (argc < 2)
00137                 return CL_USAGE;
00138         
00139         int i;
00140         int ret;
00141         
00142         for (i = 1; i < argc; i++) {
00143                 
00144                 /* Not an option */
00145                 if (argv[i][0] != '-')
00146                         break;
00147                 
00148                 /* Options terminator */
00149                 if (str_cmp(argv[i], "--") == 0) {
00150                         i++;
00151                         break;
00152                 }
00153                 
00154                 int off;
00155                 
00156                 /* Usage */
00157                 if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1)
00158                         return CL_USAGE;
00159                 
00160                 /* Verbose */
00161                 if ((off = arg_parse_short_long(argv[i], "-v", "--verbose")) != -1) {
00162                         config->verbose = true;
00163                         continue;
00164                 }
00165                 
00166                 /* Don't fragment */
00167                 if (str_cmp(argv[i], "--dont_fragment") == 0) {
00168                         config->fragments = false;
00169                         continue;
00170                 }
00171                 
00172                 /* Count */
00173                 if ((off = arg_parse_short_long(argv[i], "-c", "--count=")) != -1) {
00174                         int tmp;
00175                         ret = arg_parse_int(argc, argv, &i, &tmp, off);
00176                         
00177                         if ((ret != EOK) || (tmp < 0))
00178                                 return i;
00179                         
00180                         config->count = (unsigned int) tmp;
00181                         continue;
00182                 }
00183                 
00184                 /* Outgoing packet size */
00185                 if ((off = arg_parse_short_long(argv[i], "-s", "--size=")) != -1) {
00186                         int tmp;
00187                         ret = arg_parse_int(argc, argv, &i, &tmp, off);
00188                         
00189                         if ((ret != EOK) || (tmp < 0))
00190                                 return i;
00191                         
00192                         config->size = (size_t) tmp;
00193                         continue;
00194                 }
00195                 
00196                 /* Reply wait timeout */
00197                 if ((off = arg_parse_short_long(argv[i], "-W", "--timeout=")) != -1) {
00198                         int tmp;
00199                         ret = arg_parse_int(argc, argv, &i, &tmp, off);
00200                         
00201                         if ((ret != EOK) || (tmp < 0))
00202                                 return i;
00203                         
00204                         config->timeout = (suseconds_t) tmp;
00205                         continue;
00206                 }
00207                 
00208                 /* Address family */
00209                 if ((off = arg_parse_short_long(argv[i], "-f", "--family=")) != -1) {
00210                         ret = arg_parse_name_int(argc, argv, &i, &config->af, off,
00211                             socket_parse_address_family);
00212                         
00213                         if (ret != EOK)
00214                                 return i;
00215                         
00216                         continue;
00217                 }
00218                 
00219                 /* Type of service */
00220                 if ((off = arg_parse_short_long(argv[i], "-Q", "--tos=")) != -1) {
00221                         int tmp;
00222                         ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
00223                             socket_parse_address_family);
00224                         
00225                         if ((ret != EOK) || (tmp < 0))
00226                                 return i;
00227                         
00228                         config->tos = (ip_tos_t) tmp;
00229                         continue;
00230                 }
00231                 
00232                 /* Time to live */
00233                 if ((off = arg_parse_short_long(argv[i], "-t", "--ttl=")) != -1) {
00234                         int tmp;
00235                         ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
00236                             socket_parse_address_family);
00237                         
00238                         if ((ret != EOK) || (tmp < 0))
00239                                 return i;
00240                         
00241                         config->ttl = (ip_ttl_t) tmp;
00242                         continue;
00243                 }
00244         }
00245         
00246         if (i >= argc)
00247                 return CL_MISSING;
00248         
00249         config->dest_addr = argv[i];
00250         
00251         /* Resolve destionation address */
00252         switch (config->af) {
00253         case AF_INET:
00254                 config->dest_raw = (struct sockaddr *) &config->dest;
00255                 config->dest_len = sizeof(config->dest);
00256                 config->dest.sin_family = config->af;
00257                 ret = inet_pton(config->af, config->dest_addr,
00258                     (uint8_t *) &config->dest.sin_addr.s_addr);
00259                 break;
00260         case AF_INET6:
00261                 config->dest_raw = (struct sockaddr *) &config->dest6;
00262                 config->dest_len = sizeof(config->dest6);
00263                 config->dest6.sin6_family = config->af;
00264                 ret = inet_pton(config->af, config->dest_addr,
00265                     (uint8_t *) &config->dest6.sin6_addr.s6_addr);
00266                 break;
00267         default:
00268                 return CL_UNSUPPORTED;
00269         }
00270         
00271         if (ret != EOK)
00272                 return CL_INVALID;
00273         
00274         /* Convert destination address back to string */
00275         switch (config->af) {
00276         case AF_INET:
00277                 ret = inet_ntop(config->af,
00278                     (uint8_t *) &config->dest.sin_addr.s_addr,
00279                     config->dest_str, sizeof(config->dest_str));
00280                 break;
00281         case AF_INET6:
00282                 ret = inet_ntop(config->af,
00283                     (uint8_t *) &config->dest6.sin6_addr.s6_addr,
00284                     config->dest_str, sizeof(config->dest_str));
00285                 break;
00286         default:
00287                 return CL_UNSUPPORTED;
00288         }
00289         
00290         if (ret != EOK)
00291                 return CL_ERROR;
00292         
00293         return CL_OK;
00294 }
00295 
00296 int main(int argc, char *argv[])
00297 {
00298         ping_config_t config;
00299         
00300         /* Default configuration */
00301         config.verbose = false;
00302         config.size = 56;
00303         config.count = 4;
00304         config.timeout = 3000;
00305         config.af = AF_INET;
00306         config.tos = 0;
00307         config.ttl = 0;
00308         config.fragments = true;
00309         
00310         int ret = args_parse(argc, argv, &config);
00311         
00312         switch (ret) {
00313         case CL_OK:
00314                 break;
00315         case CL_USAGE:
00316                 usage();
00317                 return 0;
00318         case CL_MISSING:
00319                 fprintf(stderr, "%s: Destination address missing\n", NAME);
00320                 return 1;
00321         case CL_INVALID:
00322                 fprintf(stderr, "%s: Destination address '%s' invalid or malformed\n",
00323                     NAME, config.dest_addr);
00324                 return 2;
00325         case CL_UNSUPPORTED:
00326                 fprintf(stderr, "%s: Destination address '%s' unsupported\n",
00327                     NAME, config.dest_addr);
00328                 return 3;
00329         case CL_ERROR:
00330                 fprintf(stderr, "%s: Destination address '%s' error\n",
00331                     NAME, config.dest_addr);
00332                 return 4;
00333         default:
00334                 fprintf(stderr, "%s: Unknown or invalid option '%s'\n", NAME,
00335                     argv[ret]);
00336                 return 5;
00337         }
00338         
00339         printf("PING %s (%s) %zu(%zu) bytes of data\n", config.dest_addr,
00340             config.dest_str, config.size, config.size);
00341         
00342         int icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT);
00343         if (icmp_phone < 0) {
00344                 fprintf(stderr, "%s: Unable to connect to ICMP service (%s)\n", NAME,
00345                     str_error(icmp_phone));
00346                 return icmp_phone;
00347         }
00348         
00349         unsigned int seq;
00350         for (seq = 0; seq < config.count; seq++) {
00351                 struct timeval t0;
00352                 ret = gettimeofday(&t0, NULL);
00353                 if (ret != EOK) {
00354                         fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
00355                             str_error(ret));
00356                         
00357                         async_hangup(icmp_phone);
00358                         return ret;
00359                 }
00360                 
00361                 /* Ping! */
00362                 int result = icmp_echo_msg(icmp_phone, config.size, config.timeout,
00363                     config.ttl, config.tos, !config.fragments, config.dest_raw,
00364                     config.dest_len);
00365                 
00366                 struct timeval t1;
00367                 ret = gettimeofday(&t1, NULL);
00368                 if (ret != EOK) {
00369                         fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
00370                             str_error(ret));
00371                         
00372                         async_hangup(icmp_phone);
00373                         return ret;
00374                 }
00375                 
00376                 suseconds_t elapsed = tv_sub(&t1, &t0);
00377                 
00378                 switch (result) {
00379                 case ICMP_ECHO:
00380                         printf("%zu bytes from ? (?): icmp_seq=%u ttl=? time=%ld.%04ld\n",
00381                                 config.size, seq, elapsed / 1000, elapsed % 1000);
00382                         break;
00383                 case ETIMEOUT:
00384                         printf("%zu bytes from ? (?): icmp_seq=%u Timed out\n",
00385                                 config.size, seq);
00386                         break;
00387                 default:
00388                         print_error(stdout, result, NULL, "\n");
00389                 }
00390         }
00391         
00392         async_hangup(icmp_phone);
00393         
00394         return 0;
00395 }
00396 

Generated on Thu Jun 2 07:45:42 2011 for HelenOS/USB by  doxygen 1.4.7