Changes in uspace/app/ping/ping.c [849ed54:d8e3467] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/ping/ping.c
r849ed54 rd8e3467 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 */ 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 */ 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 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] != '-') 187 146 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 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); 192 386 break; 193 387 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 260 392 ipc_hangup(icmp_phone); 261 262 return EOK;393 394 return 0; 263 395 } 264 396 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 300 397 /** @} 301 398 */
Note:
See TracChangeset
for help on using the changeset viewer.