Changes in uspace/app/ping/ping.c [849ed54:2721a75] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/ping/ping.c
r849ed54 r2721a75 28 28 29 29 /** @addtogroup ping 30 * 30 * @{ 31 31 */ 32 32 33 33 /** @file 34 * Ping application.34 * Packet Internet Network Grouper. 35 35 */ 36 36 … … 41 41 #include <ipc/ipc.h> 42 42 #include <ipc/services.h> 43 #include <str_error.h> 44 #include <arg_parse.h> 43 45 44 46 #include <icmp_api.h> … … 48 50 #include <ip_codes.h> 49 51 #include <socket_errno.h> 50 #include <net_err.h> 51 52 #include "parse.h" 52 #include <socket_parse.h> 53 53 54 #include "print_error.h" 54 55 55 /** Echo module name. 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 * 56 67 */ 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); 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 { 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 134 static int arg_short_long(const char *arg, const char *ashort, 135 const char *along) 136 { 137 if (str_cmp(arg, ashort) == 0) 138 return 0; 139 140 if (str_lcmp(arg, along, str_length(along)) == 0) 141 return str_length(along); 142 143 return -1; 144 } 145 146 static int args_parse(int argc, char *argv[], ping_config_t *config) 147 { 148 if (argc < 2) 149 return CL_USAGE; 150 151 int i; 152 int ret; 153 154 for (i = 1; i < argc; i++) { 155 156 /* Not an option */ 157 if (argv[i][0] != '-') 187 158 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); 159 160 /* Options terminator */ 161 if (str_cmp(argv[i], "--") == 0) { 162 i++; 163 break; 164 } 165 166 int off; 167 int tmp; 168 169 /* Usage */ 170 if ((off = arg_short_long(argv[i], "-h", "--help")) != -1) 171 return CL_USAGE; 172 173 /* Verbose */ 174 if ((off = arg_short_long(argv[i], "-v", "--verbose")) != -1) { 175 config->verbose = true; 176 continue; 177 } 178 179 /* Don't fragment */ 180 if (str_cmp(argv[i], "--dont_fragment") == 0) { 181 config->fragments = false; 182 continue; 183 } 184 185 /* Count */ 186 if ((off = arg_short_long(argv[i], "-c", "--count=")) != -1) { 187 ret = arg_parse_int(argc, argv, &i, &tmp, off); 188 189 if ((ret != EOK) || (tmp < 0)) 190 return i; 191 192 config->count = (unsigned int) tmp; 193 continue; 194 } 195 196 /* Outgoing packet size */ 197 if ((off = arg_short_long(argv[i], "-s", "--size=")) != -1) { 198 ret = arg_parse_int(argc, argv, &i, &tmp, off); 199 200 if ((ret != EOK) || (tmp < 0)) 201 return i; 202 203 config->size = (size_t) tmp; 204 continue; 205 } 206 207 /* Reply wait timeout */ 208 if ((off = arg_short_long(argv[i], "-W", "--timeout=")) != -1) { 209 ret = arg_parse_int(argc, argv, &i, &tmp, off); 210 211 if ((ret != EOK) || (tmp < 0)) 212 return i; 213 214 config->timeout = (suseconds_t) tmp; 215 continue; 216 } 217 218 /* Address family */ 219 if ((off = arg_short_long(argv[i], "-f", "--family=")) != -1) { 220 ret = arg_parse_name_int(argc, argv, &i, &config->af, off, 221 socket_parse_address_family); 222 223 if (ret != EOK) 224 return i; 225 226 continue; 227 } 228 229 /* Type of service */ 230 if ((off = arg_short_long(argv[i], "-Q", "--tos=")) != -1) { 231 ret = arg_parse_name_int(argc, argv, &i, &tmp, off, 232 socket_parse_address_family); 233 234 if ((ret != EOK) || (tmp < 0)) 235 return i; 236 237 config->tos = (ip_tos_t) tmp; 238 continue; 239 } 240 241 /* Time to live */ 242 if ((off = arg_short_long(argv[i], "-t", "--ttl=")) != -1) { 243 ret = arg_parse_name_int(argc, argv, &i, &tmp, off, 244 socket_parse_address_family); 245 246 if ((ret != EOK) || (tmp < 0)) 247 return i; 248 249 config->ttl = (ip_ttl_t) tmp; 250 continue; 251 } 252 } 253 254 if (i >= argc) 255 return CL_MISSING; 256 257 config->dest_addr = argv[i]; 258 259 /* Resolve destionation address */ 260 switch (config->af) { 261 case AF_INET: 262 config->dest_raw = (struct sockaddr *) &config->dest; 263 config->dest_len = sizeof(config->dest); 264 config->dest.sin_family = config->af; 265 ret = inet_pton(config->af, config->dest_addr, 266 (uint8_t *) &config->dest.sin_addr.s_addr); 267 break; 268 case AF_INET6: 269 config->dest_raw = (struct sockaddr *) &config->dest6; 270 config->dest_len = sizeof(config->dest6); 271 config->dest6.sin6_family = config->af; 272 ret = inet_pton(config->af, config->dest_addr, 273 (uint8_t *) &config->dest6.sin6_addr.s6_addr); 274 break; 275 default: 276 return CL_UNSUPPORTED; 277 } 278 279 if (ret != EOK) 280 return CL_INVALID; 281 282 /* Convert destination address back to string */ 283 switch (config->af) { 284 case AF_INET: 285 ret = inet_ntop(config->af, 286 (uint8_t *) &config->dest.sin_addr.s_addr, 287 config->dest_str, sizeof(config->dest_str)); 288 break; 289 case AF_INET6: 290 ret = inet_ntop(config->af, 291 (uint8_t *) &config->dest6.sin6_addr.s6_addr, 292 config->dest_str, sizeof(config->dest_str)); 293 break; 294 default: 295 return CL_UNSUPPORTED; 296 } 297 298 if (ret != EOK) 299 return CL_ERROR; 300 301 return CL_OK; 302 } 303 304 int main(int argc, char *argv[]) 305 { 306 ping_config_t config; 307 308 /* Default configuration */ 309 config.verbose = false; 310 config.size = 56; 311 config.count = 4; 312 config.timeout = 3000; 313 config.af = AF_INET; 314 config.tos = 0; 315 config.ttl = 0; 316 config.fragments = true; 317 318 int ret = args_parse(argc, argv, &config); 319 320 switch (ret) { 321 case CL_OK: 322 break; 323 case CL_USAGE: 324 usage(); 325 return 0; 326 case CL_MISSING: 327 fprintf(stderr, "%s: Destination address missing\n", NAME); 328 return 1; 329 case CL_INVALID: 330 fprintf(stderr, "%s: Destination address '%s' invalid or malformed\n", 331 NAME, config.dest_addr); 332 return 2; 333 case CL_UNSUPPORTED: 334 fprintf(stderr, "%s: Destination address '%s' unsupported\n", 335 NAME, config.dest_addr); 336 return 3; 337 case CL_ERROR: 338 fprintf(stderr, "%s: Destination address '%s' error\n", 339 NAME, config.dest_addr); 340 return 4; 341 default: 342 fprintf(stderr, "%s: Unknown or invalid option '%s'\n", NAME, 343 argv[ret]); 344 return 5; 345 } 346 347 printf("PING %s (%s) %u(%u) bytes of data\n", config.dest_addr, 348 config.dest_str, config.size, config.size); 349 350 int icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT); 351 if (icmp_phone < 0) { 352 fprintf(stderr, "%s: Unable to connect to ICMP service (%s)\n", NAME, 353 str_error(icmp_phone)); 354 return icmp_phone; 355 } 356 357 unsigned int seq; 358 for (seq = 0; seq < config.count; seq++) { 359 struct timeval t0; 360 ret = gettimeofday(&t0, NULL); 361 if (ret != EOK) { 362 fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME, 363 str_error(ret)); 364 365 ipc_hangup(icmp_phone); 366 return ret; 367 } 368 369 /* Ping! */ 370 int result = icmp_echo_msg(icmp_phone, config.size, config.timeout, 371 config.ttl, config.tos, !config.fragments, config.dest_raw, 372 config.dest_len); 373 374 struct timeval t1; 375 ret = gettimeofday(&t1, NULL); 376 if (ret != EOK) { 377 fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME, 378 str_error(ret)); 379 380 ipc_hangup(icmp_phone); 381 return ret; 382 } 383 384 suseconds_t elapsed = tv_sub(&t1, &t0); 385 386 switch (result) { 387 case ICMP_ECHO: 388 printf("%u bytes from ? (?): icmp_seq=%u ttl=? time=%u.%04u\n", 389 config.size, seq, elapsed / 1000, elapsed % 1000); 390 break; 391 case ETIMEOUT: 392 printf("%u bytes from ? (?): icmp_seq=%u Timed out\n", 393 config.size, seq); 192 394 break; 193 395 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 396 print_error(stdout, result, NULL, "\n"); 397 } 398 } 399 260 400 ipc_hangup(icmp_phone); 261 262 return EOK; 263 } 264 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 ); 401 402 return 0; 298 403 } 299 404
Note:
See TracChangeset
for help on using the changeset viewer.