Changes in uspace/app/ping/ping.c [d8e3467:849ed54] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/ping/ping.c
rd8e3467 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 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] != '-')146 break;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);386 break;387 default:388 print_error(stdout, result, NULL, "\n");389 }390 }391 392 ipc_hangup(icmp_phone);393 394 return 0;395 }396 397 300 /** @} 398 301 */
Note:
See TracChangeset
for help on using the changeset viewer.