00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00145 if (argv[i][0] != '-')
00146 break;
00147
00148
00149 if (str_cmp(argv[i], "--") == 0) {
00150 i++;
00151 break;
00152 }
00153
00154 int off;
00155
00156
00157 if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1)
00158 return CL_USAGE;
00159
00160
00161 if ((off = arg_parse_short_long(argv[i], "-v", "--verbose")) != -1) {
00162 config->verbose = true;
00163 continue;
00164 }
00165
00166
00167 if (str_cmp(argv[i], "--dont_fragment") == 0) {
00168 config->fragments = false;
00169 continue;
00170 }
00171
00172
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
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
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
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
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
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
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
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
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
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