source: mainline/uspace/app/ping/ping.c@ 1d1bb0f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1d1bb0f was 79ae36dd, checked in by Martin Decky <martin@…>, 14 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 10.0 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 * Packet Internet Network Grouper.
35 */
36
37#include <async.h>
38#include <async_obsolete.h>
39#include <stdio.h>
40#include <str.h>
41#include <task.h>
42#include <time.h>
43#include <ipc/services.h>
44#include <str_error.h>
45#include <errno.h>
46#include <arg_parse.h>
47
48#include <net/icmp_api.h>
49#include <net/in.h>
50#include <net/in6.h>
51#include <net/inet.h>
52#include <net/socket_parse.h>
53#include <net/ip_codes.h>
54
55#include "print_error.h"
56
57#define NAME "ping"
58
59#define CL_OK 0
60#define CL_USAGE -1
61#define CL_MISSING -2
62#define CL_INVALID -3
63#define CL_UNSUPPORTED -4
64#define CL_ERROR -5
65
66/** Ping configuration
67 *
68 */
69typedef struct {
70 bool verbose; /**< Verbose printouts. */
71 size_t size; /**< Outgoing packet size. */
72 unsigned int count; /**< Number of packets to send. */
73 suseconds_t timeout; /**< Reply wait timeout. */
74 int af; /**< Address family. */
75 ip_tos_t tos; /**< Type of service. */
76 ip_ttl_t ttl; /**< Time-to-live. */
77 bool fragments; /**< Fragmentation. */
78
79 char *dest_addr; /**< Destination address. */
80 struct sockaddr_in dest; /**< IPv4 destionation. */
81 struct sockaddr_in6 dest6; /**< IPv6 destionation. */
82
83 struct sockaddr *dest_raw; /**< Raw destination address. */
84 socklen_t dest_len; /**< Raw destination address length. */
85
86 /** Converted address string. */
87 char dest_str[INET6_ADDRSTRLEN];
88} ping_config_t;
89
90
91static void usage(void)
92{
93 printf(
94 "Usage: ping [-c count] [-s size] [-W timeout] [-f family] [-t ttl]\n" \
95 " [-Q tos] [--dont_fragment] destination\n" \
96 "\n" \
97 "Options:\n" \
98 "\t-c count\n" \
99 "\t--count=count\n" \
100 "\t\tNumber of outgoing packets (default: 4)\n" \
101 "\n" \
102 "\t-s size\n" \
103 "\t--size=bytes\n" \
104 "\t\tOutgoing packet size (default: 56 bytes)\n" \
105 "\n" \
106 "\t-W timeout\n" \
107 "\t--timeout=ms\n" \
108 "\t\tReply wait timeout (default: 3000 ms)\n" \
109 "\n" \
110 "\t-f family\n" \
111 "\t--family=family\n" \
112 "\t\tDestination address family, AF_INET or AF_INET6 (default: AF_INET)\n" \
113 "\n" \
114 "\t-t ttl\n" \
115 "\t--ttl=ttl\n" \
116 "\t\tOutgoing packet time-to-live (default: 0)\n" \
117 "\n" \
118 "\t-Q tos\n" \
119 "\t--tos=tos\n" \
120 "\t\tOutgoing packet type of service (default: 0)\n" \
121 "\n" \
122 "\t--dont_fragment\n" \
123 "\t\tDisable packet fragmentation (default: enabled)\n" \
124 "\n" \
125 "\t-v\n" \
126 "\t--verbose\n" \
127 "\t\tVerbose operation\n" \
128 "\n" \
129 "\t-h\n" \
130 "\t--help\n" \
131 "\t\tPrint this usage information\n"
132 );
133}
134
135static int args_parse(int argc, char *argv[], ping_config_t *config)
136{
137 if (argc < 2)
138 return CL_USAGE;
139
140 int i;
141 int ret;
142
143 for (i = 1; i < argc; i++) {
144
145 /* Not an option */
146 if (argv[i][0] != '-')
147 break;
148
149 /* Options terminator */
150 if (str_cmp(argv[i], "--") == 0) {
151 i++;
152 break;
153 }
154
155 int off;
156
157 /* Usage */
158 if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1)
159 return CL_USAGE;
160
161 /* Verbose */
162 if ((off = arg_parse_short_long(argv[i], "-v", "--verbose")) != -1) {
163 config->verbose = true;
164 continue;
165 }
166
167 /* Don't fragment */
168 if (str_cmp(argv[i], "--dont_fragment") == 0) {
169 config->fragments = false;
170 continue;
171 }
172
173 /* Count */
174 if ((off = arg_parse_short_long(argv[i], "-c", "--count=")) != -1) {
175 int tmp;
176 ret = arg_parse_int(argc, argv, &i, &tmp, off);
177
178 if ((ret != EOK) || (tmp < 0))
179 return i;
180
181 config->count = (unsigned int) tmp;
182 continue;
183 }
184
185 /* Outgoing packet size */
186 if ((off = arg_parse_short_long(argv[i], "-s", "--size=")) != -1) {
187 int tmp;
188 ret = arg_parse_int(argc, argv, &i, &tmp, off);
189
190 if ((ret != EOK) || (tmp < 0))
191 return i;
192
193 config->size = (size_t) tmp;
194 continue;
195 }
196
197 /* Reply wait timeout */
198 if ((off = arg_parse_short_long(argv[i], "-W", "--timeout=")) != -1) {
199 int tmp;
200 ret = arg_parse_int(argc, argv, &i, &tmp, off);
201
202 if ((ret != EOK) || (tmp < 0))
203 return i;
204
205 config->timeout = (suseconds_t) tmp;
206 continue;
207 }
208
209 /* Address family */
210 if ((off = arg_parse_short_long(argv[i], "-f", "--family=")) != -1) {
211 ret = arg_parse_name_int(argc, argv, &i, &config->af, off,
212 socket_parse_address_family);
213
214 if (ret != EOK)
215 return i;
216
217 continue;
218 }
219
220 /* Type of service */
221 if ((off = arg_parse_short_long(argv[i], "-Q", "--tos=")) != -1) {
222 int tmp;
223 ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
224 socket_parse_address_family);
225
226 if ((ret != EOK) || (tmp < 0))
227 return i;
228
229 config->tos = (ip_tos_t) tmp;
230 continue;
231 }
232
233 /* Time to live */
234 if ((off = arg_parse_short_long(argv[i], "-t", "--ttl=")) != -1) {
235 int tmp;
236 ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
237 socket_parse_address_family);
238
239 if ((ret != EOK) || (tmp < 0))
240 return i;
241
242 config->ttl = (ip_ttl_t) tmp;
243 continue;
244 }
245 }
246
247 if (i >= argc)
248 return CL_MISSING;
249
250 config->dest_addr = argv[i];
251
252 /* Resolve destionation address */
253 switch (config->af) {
254 case AF_INET:
255 config->dest_raw = (struct sockaddr *) &config->dest;
256 config->dest_len = sizeof(config->dest);
257 config->dest.sin_family = config->af;
258 ret = inet_pton(config->af, config->dest_addr,
259 (uint8_t *) &config->dest.sin_addr.s_addr);
260 break;
261 case AF_INET6:
262 config->dest_raw = (struct sockaddr *) &config->dest6;
263 config->dest_len = sizeof(config->dest6);
264 config->dest6.sin6_family = config->af;
265 ret = inet_pton(config->af, config->dest_addr,
266 (uint8_t *) &config->dest6.sin6_addr.s6_addr);
267 break;
268 default:
269 return CL_UNSUPPORTED;
270 }
271
272 if (ret != EOK)
273 return CL_INVALID;
274
275 /* Convert destination address back to string */
276 switch (config->af) {
277 case AF_INET:
278 ret = inet_ntop(config->af,
279 (uint8_t *) &config->dest.sin_addr.s_addr,
280 config->dest_str, sizeof(config->dest_str));
281 break;
282 case AF_INET6:
283 ret = inet_ntop(config->af,
284 (uint8_t *) &config->dest6.sin6_addr.s6_addr,
285 config->dest_str, sizeof(config->dest_str));
286 break;
287 default:
288 return CL_UNSUPPORTED;
289 }
290
291 if (ret != EOK)
292 return CL_ERROR;
293
294 return CL_OK;
295}
296
297int main(int argc, char *argv[])
298{
299 ping_config_t config;
300
301 /* Default configuration */
302 config.verbose = false;
303 config.size = 56;
304 config.count = 4;
305 config.timeout = 3000;
306 config.af = AF_INET;
307 config.tos = 0;
308 config.ttl = 0;
309 config.fragments = true;
310
311 int ret = args_parse(argc, argv, &config);
312
313 switch (ret) {
314 case CL_OK:
315 break;
316 case CL_USAGE:
317 usage();
318 return 0;
319 case CL_MISSING:
320 fprintf(stderr, "%s: Destination address missing\n", NAME);
321 return 1;
322 case CL_INVALID:
323 fprintf(stderr, "%s: Destination address '%s' invalid or malformed\n",
324 NAME, config.dest_addr);
325 return 2;
326 case CL_UNSUPPORTED:
327 fprintf(stderr, "%s: Destination address '%s' unsupported\n",
328 NAME, config.dest_addr);
329 return 3;
330 case CL_ERROR:
331 fprintf(stderr, "%s: Destination address '%s' error\n",
332 NAME, config.dest_addr);
333 return 4;
334 default:
335 fprintf(stderr, "%s: Unknown or invalid option '%s'\n", NAME,
336 argv[ret]);
337 return 5;
338 }
339
340 printf("PING %s (%s) %zu(%zu) bytes of data\n", config.dest_addr,
341 config.dest_str, config.size, config.size);
342
343 int icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT);
344 if (icmp_phone < 0) {
345 fprintf(stderr, "%s: Unable to connect to ICMP service (%s)\n", NAME,
346 str_error(icmp_phone));
347 return icmp_phone;
348 }
349
350 unsigned int seq;
351 for (seq = 0; seq < config.count; seq++) {
352 struct timeval t0;
353 ret = gettimeofday(&t0, NULL);
354 if (ret != EOK) {
355 fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
356 str_error(ret));
357
358 async_obsolete_hangup(icmp_phone);
359 return ret;
360 }
361
362 /* Ping! */
363 int result = icmp_echo_msg(icmp_phone, config.size, config.timeout,
364 config.ttl, config.tos, !config.fragments, config.dest_raw,
365 config.dest_len);
366
367 struct timeval t1;
368 ret = gettimeofday(&t1, NULL);
369 if (ret != EOK) {
370 fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
371 str_error(ret));
372
373 async_obsolete_hangup(icmp_phone);
374 return ret;
375 }
376
377 suseconds_t elapsed = tv_sub(&t1, &t0);
378
379 switch (result) {
380 case ICMP_ECHO:
381 printf("%zu bytes from ? (?): icmp_seq=%u ttl=? time=%ld.%04ld\n",
382 config.size, seq, elapsed / 1000, elapsed % 1000);
383 break;
384 case ETIMEOUT:
385 printf("%zu bytes from ? (?): icmp_seq=%u Timed out\n",
386 config.size, seq);
387 break;
388 default:
389 print_error(stdout, result, NULL, "\n");
390 }
391 }
392
393 async_obsolete_hangup(icmp_phone);
394
395 return 0;
396}
397
398/** @}
399 */
Note: See TracBrowser for help on using the repository browser.