source: mainline/uspace/app/ping/ping.c@ a397f1d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a397f1d was 849ed54, checked in by Martin Decky <martin@…>, 15 years ago

Networking work:
Split the networking stack into end-user library (libsocket) and two helper libraries (libnet and libnetif).
Don't use over-the-hand compiling and linking, but rather separation of conserns.
There might be still some issues and the non-modular networking architecture is currently broken, but this will be fixed soon.

  • Property mode set to 100644
File size: 9.1 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 <str.h>
39#include <task.h>
40#include <time.h>
41#include <ipc/ipc.h>
42#include <ipc/services.h>
43
44#include <icmp_api.h>
45#include <in.h>
46#include <in6.h>
47#include <inet.h>
48#include <ip_codes.h>
49#include <socket_errno.h>
50#include <net_err.h>
51
52#include "parse.h"
53#include "print_error.h"
54
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 */
65int main(int argc, char * argv[]);
66
67/** Prints the application help.
68 */
69void ping_print_help(void);
70
71int 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
265void 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/** @}
301 */
Note: See TracBrowser for help on using the repository browser.