source: mainline/uspace/srv/net/app/ping/ping.c@ 3be62bc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3be62bc was 3be62bc, checked in by Lukas Mejdrech <lukasmejdrech@…>, 16 years ago
  • net app command line argument checks, * code reorganization
  • Property mode set to 100644
File size: 9.2 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ping
30 * @{
31 */
32
33/** @file
34 * Ping application.
35 */
36
37#include <stdio.h>
38#include <string.h>
39#include <task.h>
40#include <time.h>
41#include <ipc/ipc.h>
42#include <ipc/services.h>
43
44#include "../../include/icmp_api.h"
45#include "../../include/in.h"
46#include "../../include/in6.h"
47#include "../../include/inet.h"
48#include "../../include/ip_codes.h"
49#include "../../include/socket_errno.h"
50
51#include "../../err.h"
52
53#include "../parse.h"
54#include "../print_error.h"
55
56/** Echo module name.
57 */
58#define NAME "Ping"
59
60/** Module entry point.
61 * Reads command line parameters and pings.
62 * @param[in] argc The number of command line parameters.
63 * @param[in] argv The command line parameters.
64 * @returns EOK on success.
65 */
66int main(int argc, char * argv[]);
67
68/** Prints the application help.
69 */
70void ping_print_help(void);
71
72int main(int argc, char * argv[]){
73 ERROR_DECLARE;
74
75 size_t size = 38;
76 int verbose = 0;
77 int dont_fragment = 0;
78 ip_ttl_t ttl = 0;
79 ip_tos_t tos = 0;
80 int count = 3;
81 suseconds_t timeout = 3000;
82 int family = AF_INET;
83
84 socklen_t max_length = sizeof(struct sockaddr_in6);
85 uint8_t address_data[max_length];
86 struct sockaddr * address = (struct sockaddr *) address_data;
87 struct sockaddr_in * address_in = (struct sockaddr_in *) address;
88 struct sockaddr_in6 * address_in6 = (struct sockaddr_in6 *) address;
89 socklen_t addrlen;
90 char address_string[INET6_ADDRSTRLEN];
91 uint8_t * address_start;
92 int icmp_phone;
93 struct timeval time_before;
94 struct timeval time_after;
95 int result;
96 int value;
97 int index;
98
99 // print the program label
100 printf("Task %d - ", task_get_id());
101 printf("%s\n", NAME);
102
103 // parse the command line arguments
104 // stop before the last argument if it does not start with the minus sign ('-')
105 for(index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); ++ index){
106 // options should start with the minus sign ('-')
107 if(argv[index][0] == '-'){
108 switch(argv[index][1]){
109 // short options with only one letter
110 case 'c':
111 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "count", 0));
112 break;
113 case 'f':
114 ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "address family", 0, parse_address_family));
115 break;
116 case 'h':
117 ping_print_help();
118 return EOK;
119 break;
120 case 's':
121 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
122 size = (value >= 0) ? (size_t) value : 0;
123 break;
124 case 't':
125 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "timeout", 0));
126 timeout = (value >= 0) ? (suseconds_t) value : 0;
127 break;
128 case 'v':
129 verbose = 1;
130 break;
131 // long options with the double minus sign ('-')
132 case '-':
133 if(str_lcmp(argv[index] + 2, "count=", 6) == 0){
134 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "received count", 8));
135 }else if(str_lcmp(argv[index] + 2, "dont_fragment", 13) == 0){
136 dont_fragment = 1;
137 }else if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
138 ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "address family", 9, parse_address_family));
139 }else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
140 ping_print_help();
141 return EOK;
142 }else if(str_lcmp(argv[index] + 2, "size=", 5) == 0){
143 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 7));
144 size = (value >= 0) ? (size_t) value : 0;
145 }else if(str_lcmp(argv[index] + 2, "timeout=", 8) == 0){
146 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "timeout", 7));
147 timeout = (value >= 0) ? (suseconds_t) value : 0;
148 }else if(str_lcmp(argv[index] + 2, "tos=", 4) == 0){
149 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "type of service", 7));
150 tos = (value >= 0) ? (ip_tos_t) value : 0;
151 }else if(str_lcmp(argv[index] + 2, "ttl=", 4) == 0){
152 ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "time to live", 7));
153 ttl = (value >= 0) ? (ip_ttl_t) value : 0;
154 }else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
155 verbose = 1;
156 }else{
157 print_unrecognized(index, argv[index] + 2);
158 ping_print_help();
159 return EINVAL;
160 }
161 break;
162 default:
163 print_unrecognized(index, argv[index] + 1);
164 ping_print_help();
165 return EINVAL;
166 }
167 }else{
168 print_unrecognized(index, argv[index]);
169 ping_print_help();
170 return EINVAL;
171 }
172 }
173
174 // if not before the last argument containing the address
175 if(index >= argc){
176 printf("Command line error: missing address\n");
177 ping_print_help();
178 return EINVAL;
179 }
180
181 // prepare the address buffer
182 bzero(address_data, max_length);
183 switch(family){
184 case AF_INET:
185 address_in->sin_family = AF_INET;
186 address_start = (uint8_t *) &address_in->sin_addr.s_addr;
187 addrlen = sizeof(struct sockaddr_in);
188 break;
189 case AF_INET6:
190 address_in6->sin6_family = AF_INET6;
191 address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
192 addrlen = sizeof(struct sockaddr_in6);
193 break;
194 default:
195 fprintf(stderr, "Address family is not supported\n");
196 return EAFNOSUPPORT;
197 }
198
199 // parse the last argument which should contain the address
200 if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
201 fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
202 return ERROR_CODE;
203 }
204
205 // connect to the ICMP module
206 icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
207 if(icmp_phone < 0){
208 fprintf(stderr, "ICMP connect error %d\n", icmp_phone);
209 return icmp_phone;
210 }
211
212 // print the ping header
213 printf("PING %d bytes of data\n", size);
214 if(ERROR_OCCURRED(inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)))){
215 fprintf(stderr, "Address error %d\n", ERROR_CODE);
216 }else{
217 printf("Address %s:\n", address_string);
218 }
219
220 // do count times
221 while(count > 0){
222
223 // get the starting time
224 if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
225 fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
226 // release the ICMP phone
227 ipc_hangup(icmp_phone);
228 return ERROR_CODE;
229 }
230
231 // request the ping
232 result = icmp_echo_msg(icmp_phone, size, timeout, ttl, tos, dont_fragment, address, addrlen);
233
234 // get the ending time
235 if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
236 fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
237 // release the ICMP phone
238 ipc_hangup(icmp_phone);
239 return ERROR_CODE;
240 }
241
242 // print the result
243 switch(result){
244 case ICMP_ECHO:
245 printf("Ping round trip time %d miliseconds\n", tv_sub(&time_after, &time_before) / 1000);
246 break;
247 case ETIMEOUT:
248 printf("Timed out.\n");
249 break;
250 default:
251 print_error(stdout, result, NULL, "\n");
252 }
253 -- count;
254 }
255
256 if(verbose){
257 printf("Exiting\n");
258 }
259
260 // release the ICMP phone
261 ipc_hangup(icmp_phone);
262
263 return EOK;
264}
265
266void ping_print_help(void){
267 printf(
268 "Network Ping aplication\n" \
269 "Usage: ping [options] numeric_address\n" \
270 "Where options are:\n" \
271 "\n" \
272 "-c request_count | --count=request_count\n" \
273 "\tThe number of packets the application sends. The default is three (3).\n" \
274 "\n" \
275 "--dont_fragment\n" \
276 "\tDisable packet fragmentation.\n"
277 "\n" \
278 "-f address_family | --family=address_family\n" \
279 "\tThe given address family. Only the AF_INET and AF_INET6 are supported.\n"
280 "\n" \
281 "-h | --help\n" \
282 "\tShow this application help.\n"
283 "\n" \
284 "-s packet_size | --size=packet_size\n" \
285 "\tThe packet data size the application sends. The default is 38 bytes.\n" \
286 "\n" \
287 "-t timeout | --timeout=timeout\n" \
288 "\tThe number of miliseconds the application waits for a reply. The default is three thousands (3 000).\n" \
289 "\n" \
290 "--tos=tos\n" \
291 "\tThe type of service to be used.\n" \
292 "\n" \
293 "--ttl=ttl\n" \
294 "\tThe time to live to be used.\n" \
295 "\n" \
296 "-v | --verbose\n" \
297 "\tShow all output messages.\n"
298 );
299}
300
301/** @}
302 */
Note: See TracBrowser for help on using the repository browser.