Changes in uspace/app/ping/ping.c [2721a75:849ed54] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/ping/ping.c
r2721a75 r849ed54 28 28 29 29 /** @addtogroup ping 30 * @{30 * @{ 31 31 */ 32 32 33 33 /** @file 34 * Packet Internet Network Grouper.34 * Ping application. 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>45 43 46 44 #include <icmp_api.h> … … 50 48 #include <ip_codes.h> 51 49 #include <socket_errno.h> 52 #include <socket_parse.h> 53 50 #include <net_err.h> 51 52 #include "parse.h" 54 53 #include "print_error.h" 55 54 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 { 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); 187 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); 192 break; 193 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 260 ipc_hangup(icmp_phone); 261 262 return EOK; 263 } 264 265 void ping_print_help(void){ 92 266 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" 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" 131 297 ); 132 298 } 133 299 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] != '-')158 break;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);394 break;395 default:396 print_error(stdout, result, NULL, "\n");397 }398 }399 400 ipc_hangup(icmp_phone);401 402 return 0;403 }404 405 300 /** @} 406 301 */
Note:
See TracChangeset
for help on using the changeset viewer.