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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a44424f was 9749e47, checked in by Jiri Svoboda <jiri@…>, 12 years ago

ping6 - resistance is futile.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * Copyright (c) 2013 Jiri Svoboda
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/** @file ICMP echo utility.
33 */
34
35#include <async.h>
36#include <stdbool.h>
37#include <errno.h>
38#include <fibril_synch.h>
39#include <inet/dnsr.h>
40#include <inet/addr.h>
41#include <inet/inetping.h>
42#include <io/console.h>
43#include <getopt.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <str.h>
47#include <str_error.h>
48#include <sys/types.h>
49
50#define NAME "ping"
51
52/** Delay between subsequent ping requests in microseconds */
53#define PING_DELAY (1000 * 1000)
54
55/** Ping request timeout in microseconds */
56#define PING_TIMEOUT (1000 * 1000)
57
58typedef enum {
59 RECEIVED_NONE,
60 RECEIVED_SUCCESS,
61 RECEIVED_INTERRUPT
62} received_t;
63
64static received_t received;
65static FIBRIL_CONDVAR_INITIALIZE(received_cv);
66static FIBRIL_MUTEX_INITIALIZE(received_lock);
67
68static bool quit = false;
69static FIBRIL_CONDVAR_INITIALIZE(quit_cv);
70static FIBRIL_MUTEX_INITIALIZE(quit_lock);
71
72static int ping_ev_recv(inetping_sdu_t *);
73
74static inetping_ev_ops_t ev_ops = {
75 .recv = ping_ev_recv
76};
77
78static inet_addr_t src_addr;
79static inet_addr_t dest_addr;
80
81static bool repeat_forever = false;
82static size_t repeat_count = 1;
83
84static const char *short_options = "46rn:";
85
86static void print_syntax(void)
87{
88 printf("Syntax: %s [<options>] <host>\n", NAME);
89 printf("\t-n <count> Repeat the specified number of times\n");
90 printf("\t-r Repeat forever\n");
91 printf("\t-4|-6 Use IPv4 or IPv6 destination host address\n");
92}
93
94static void ping_signal_received(received_t value)
95{
96 fibril_mutex_lock(&received_lock);
97 received = value;
98 fibril_mutex_unlock(&received_lock);
99 fibril_condvar_broadcast(&received_cv);
100}
101
102static void ping_signal_quit(void)
103{
104 fibril_mutex_lock(&quit_lock);
105 quit = true;
106 fibril_mutex_unlock(&quit_lock);
107 fibril_condvar_broadcast(&quit_cv);
108}
109
110static int ping_ev_recv(inetping_sdu_t *sdu)
111{
112 char *asrc;
113 int rc = inet_addr_format(&src_addr, &asrc);
114 if (rc != EOK)
115 return ENOMEM;
116
117 char *adest;
118 rc = inet_addr_format(&dest_addr, &adest);
119 if (rc != EOK) {
120 free(asrc);
121 return ENOMEM;
122 }
123
124 printf("Received ICMP echo reply: from %s to %s, seq. no %u, "
125 "payload size %zu\n", asrc, adest, sdu->seq_no, sdu->size);
126
127 ping_signal_received(RECEIVED_SUCCESS);
128
129 free(asrc);
130 free(adest);
131 return EOK;
132}
133
134static int ping_send(uint16_t seq_no)
135{
136 inetping_sdu_t sdu;
137
138 sdu.src = src_addr;
139 sdu.dest = dest_addr;
140 sdu.seq_no = seq_no;
141 sdu.data = (void *) "foo";
142 sdu.size = 3;
143
144 int rc = inetping_send(&sdu);
145 if (rc != EOK)
146 printf("Failed sending echo request: %s (%d).\n",
147 str_error(rc), rc);
148
149 return rc;
150}
151
152static int transmit_fibril(void *arg)
153{
154 uint16_t seq_no = 0;
155
156 while ((repeat_count--) || (repeat_forever)) {
157 fibril_mutex_lock(&received_lock);
158 received = RECEIVED_NONE;
159 fibril_mutex_unlock(&received_lock);
160
161 (void) ping_send(++seq_no);
162
163 fibril_mutex_lock(&received_lock);
164 int rc = fibril_condvar_wait_timeout(&received_cv, &received_lock,
165 PING_TIMEOUT);
166 received_t recv = received;
167 fibril_mutex_unlock(&received_lock);
168
169 if ((rc == ETIMEOUT) || (recv == RECEIVED_NONE))
170 printf("Echo request timed out (seq. no %u)\n", seq_no);
171
172 if (recv == RECEIVED_INTERRUPT)
173 break;
174
175 if ((repeat_count > 0) || (repeat_forever)) {
176 fibril_mutex_lock(&received_lock);
177 rc = fibril_condvar_wait_timeout(&received_cv, &received_lock,
178 PING_DELAY);
179 recv = received;
180 fibril_mutex_unlock(&received_lock);
181
182 if (recv == RECEIVED_INTERRUPT)
183 break;
184 }
185 }
186
187 ping_signal_quit();
188 return 0;
189}
190
191static int input_fibril(void *arg)
192{
193 console_ctrl_t *con = console_init(stdin, stdout);
194
195 while (true) {
196 cons_event_t ev;
197 if (!console_get_event(con, &ev))
198 break;
199
200 if ((ev.type == CEV_KEY) && (ev.ev.key.type == KEY_PRESS) &&
201 ((ev.ev.key.mods & (KM_ALT | KM_SHIFT)) == 0) &&
202 ((ev.ev.key.mods & KM_CTRL) != 0)) {
203 /* Ctrl+key */
204 if (ev.ev.key.key == KC_Q) {
205 ping_signal_received(RECEIVED_INTERRUPT);
206 break;
207 }
208 }
209 }
210
211 return 0;
212}
213
214int main(int argc, char *argv[])
215{
216 dnsr_hostinfo_t *hinfo = NULL;
217 char *asrc = NULL;
218 char *adest = NULL;
219 char *sdest = NULL;
220 ip_ver_t ip_ver = ip_any;
221
222 int rc = inetping_init(&ev_ops);
223 if (rc != EOK) {
224 printf("Failed connecting to internet ping service: "
225 "%s (%d).\n", str_error(rc), rc);
226 goto error;
227 }
228
229 int c;
230 while ((c = getopt(argc, argv, short_options)) != -1) {
231 switch (c) {
232 case 'r':
233 repeat_forever = true;
234 break;
235 case 'n':
236 rc = str_size_t(optarg, NULL, 10, true, &repeat_count);
237 if (rc != EOK) {
238 printf("Invalid repeat count.\n");
239 print_syntax();
240 goto error;
241 }
242 break;
243 case '4':
244 ip_ver = ip_v4;
245 break;
246 case '6':
247 ip_ver = ip_v6;
248 break;
249 default:
250 printf("Unknown option passed.\n");
251 print_syntax();
252 goto error;
253 }
254 }
255
256 if (optind >= argc) {
257 printf("IP address or host name not supplied.\n");
258 print_syntax();
259 goto error;
260 }
261
262 /* Parse destination address */
263 rc = inet_addr_parse(argv[optind], &dest_addr);
264 if (rc != EOK) {
265 /* Try interpreting as a host name */
266 rc = dnsr_name2host(argv[optind], &hinfo, ip_ver);
267 if (rc != EOK) {
268 printf("Error resolving host '%s'.\n", argv[optind]);
269 goto error;
270 }
271
272 dest_addr = hinfo->addr;
273 }
274
275 /* Determine source address */
276 rc = inetping_get_srcaddr(&dest_addr, &src_addr);
277 if (rc != EOK) {
278 printf("Failed determining source address.\n");
279 goto error;
280 }
281
282 rc = inet_addr_format(&src_addr, &asrc);
283 if (rc != EOK) {
284 printf("Out of memory.\n");
285 goto error;
286 }
287
288 rc = inet_addr_format(&dest_addr, &adest);
289 if (rc != EOK) {
290 printf("Out of memory.\n");
291 goto error;
292 }
293
294 if (hinfo != NULL) {
295 rc = asprintf(&sdest, "%s (%s)", hinfo->cname, adest);
296 if (rc < 0) {
297 printf("Out of memory.\n");
298 goto error;
299 }
300 } else {
301 sdest = adest;
302 adest = NULL;
303 }
304
305 printf("Sending ICMP echo request from %s to %s (Ctrl+Q to quit)\n",
306 asrc, sdest);
307
308 fid_t fid = fibril_create(transmit_fibril, NULL);
309 if (fid == 0) {
310 printf("Failed creating transmit fibril.\n");
311 goto error;
312 }
313
314 fibril_add_ready(fid);
315
316 fid = fibril_create(input_fibril, NULL);
317 if (fid == 0) {
318 printf("Failed creating input fibril.\n");
319 goto error;
320 }
321
322 fibril_add_ready(fid);
323
324 fibril_mutex_lock(&quit_lock);
325 while (!quit)
326 fibril_condvar_wait(&quit_cv, &quit_lock);
327 fibril_mutex_unlock(&quit_lock);
328
329 free(asrc);
330 free(adest);
331 free(sdest);
332 dnsr_hostinfo_destroy(hinfo);
333 return 0;
334
335error:
336 free(asrc);
337 free(adest);
338 free(sdest);
339 dnsr_hostinfo_destroy(hinfo);
340 return 1;
341}
342
343/** @}
344 */
Note: See TracBrowser for help on using the repository browser.