2 * Copyright (c) 2013 Jiri Svoboda
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
32 /** @file ICMP echo utility.
38 #include <fibril_synch.h>
39 #include <net/socket_codes.h>
40 #include <inet/dnsr.h>
41 #include <inet/addr.h>
42 #include <inet/inetping.h>
43 #include <io/console.h>
48 #include <str_error.h>
49 #include <sys/types.h>
53 /** Delay between subsequent ping requests in microseconds */
54 #define PING_DELAY (1000 * 1000)
56 /** Ping request timeout in microseconds */
57 #define PING_TIMEOUT (1000 * 1000)
65 static received_t received
;
66 static FIBRIL_CONDVAR_INITIALIZE(received_cv
);
67 static FIBRIL_MUTEX_INITIALIZE(received_lock
);
69 static bool quit
= false;
70 static FIBRIL_CONDVAR_INITIALIZE(quit_cv
);
71 static FIBRIL_MUTEX_INITIALIZE(quit_lock
);
73 static int ping_ev_recv(inetping_sdu_t
*);
75 static inetping_ev_ops_t ev_ops
= {
82 static bool repeat_forever
= false;
83 static size_t repeat_count
= 1;
85 static const char *short_options
= "rn:";
87 static void print_syntax(void)
89 printf("Syntax: %s [-n <count>|-r] <host>\n", NAME
);
92 static void ping_signal_received(received_t value
)
94 fibril_mutex_lock(&received_lock
);
96 fibril_mutex_unlock(&received_lock
);
97 fibril_condvar_broadcast(&received_cv
);
100 static void ping_signal_quit(void)
102 fibril_mutex_lock(&quit_lock
);
104 fibril_mutex_unlock(&quit_lock
);
105 fibril_condvar_broadcast(&quit_cv
);
108 static int ping_ev_recv(inetping_sdu_t
*sdu
)
110 inet_addr_t src_addr
;
111 inet_addr_set(sdu
->src
, &src_addr
);
113 inet_addr_t dest_addr
;
114 inet_addr_set(sdu
->dest
, &dest_addr
);
117 int rc
= inet_addr_format(&src_addr
, &asrc
);
122 rc
= inet_addr_format(&dest_addr
, &adest
);
128 printf("Received ICMP echo reply: from %s to %s, seq. no %u, "
129 "payload size %zu\n", asrc
, adest
, sdu
->seq_no
, sdu
->size
);
131 ping_signal_received(RECEIVED_SUCCESS
);
138 static int ping_send(uint16_t seq_no
)
145 sdu
.data
= (void *) "foo";
148 int rc
= inetping_send(&sdu
);
150 printf("Failed sending echo request: %s (%d).\n",
156 static int transmit_fibril(void *arg
)
160 while ((repeat_count
--) || (repeat_forever
)) {
161 fibril_mutex_lock(&received_lock
);
162 received
= RECEIVED_NONE
;
163 fibril_mutex_unlock(&received_lock
);
165 (void) ping_send(++seq_no
);
167 fibril_mutex_lock(&received_lock
);
168 int rc
= fibril_condvar_wait_timeout(&received_cv
, &received_lock
,
170 received_t recv
= received
;
171 fibril_mutex_unlock(&received_lock
);
173 if ((rc
== ETIMEOUT
) || (recv
== RECEIVED_NONE
))
174 printf("Echo request timed out (seq. no %u)\n", seq_no
);
176 if (recv
== RECEIVED_INTERRUPT
)
179 if ((repeat_count
> 0) || (repeat_forever
)) {
180 fibril_mutex_lock(&received_lock
);
181 rc
= fibril_condvar_wait_timeout(&received_cv
, &received_lock
,
184 fibril_mutex_unlock(&received_lock
);
186 if (recv
== RECEIVED_INTERRUPT
)
195 static int input_fibril(void *arg
)
197 console_ctrl_t
*con
= console_init(stdin
, stdout
);
201 if (!console_get_event(con
, &ev
))
204 if ((ev
.type
== CEV_KEY
) && (ev
.ev
.key
.type
== KEY_PRESS
) &&
205 ((ev
.ev
.key
.mods
& (KM_ALT
| KM_SHIFT
)) == 0) &&
206 ((ev
.ev
.key
.mods
& KM_CTRL
) != 0)) {
208 if (ev
.ev
.key
.key
== KC_Q
) {
209 ping_signal_received(RECEIVED_INTERRUPT
);
218 int main(int argc
, char *argv
[])
220 dnsr_hostinfo_t
*hinfo
= NULL
;
225 int rc
= inetping_init(&ev_ops
);
227 printf("Failed connecting to internet ping service: "
228 "%s (%d).\n", str_error(rc
), rc
);
233 while ((c
= getopt(argc
, argv
, short_options
)) != -1) {
236 repeat_forever
= true;
239 rc
= str_size_t(optarg
, NULL
, 10, true, &repeat_count
);
241 printf("Invalid repeat count.\n");
247 printf("Unknown option passed.\n");
253 if (optind
>= argc
) {
254 printf("IP address or host name not supplied.\n");
259 /* Parse destination address */
260 inet_addr_t dest_addr
;
261 rc
= inet_addr_parse(argv
[optind
], &dest_addr
);
263 /* Try interpreting as a host name */
264 rc
= dnsr_name2host(argv
[optind
], &hinfo
, AF_INET
);
266 printf("Error resolving host '%s'.\n", argv
[optind
]);
270 dest_addr
= hinfo
->addr
;
273 uint16_t af
= inet_addr_get(&dest_addr
, &dest
, NULL
);
275 printf("Destination '%s' is not an IPv4 address.\n",
280 /* Determine source address */
281 rc
= inetping_get_srcaddr(dest
, &src
);
283 printf("Failed determining source address.\n");
287 inet_addr_t src_addr
;
288 inet_addr_set(src
, &src_addr
);
290 rc
= inet_addr_format(&src_addr
, &asrc
);
292 printf("Out of memory.\n");
296 rc
= inet_addr_format(&dest_addr
, &adest
);
298 printf("Out of memory.\n");
303 rc
= asprintf(&sdest
, "%s (%s)", hinfo
->cname
, adest
);
305 printf("Out of memory.\n");
313 printf("Sending ICMP echo request from %s to %s (Ctrl+Q to quit)\n",
316 fid_t fid
= fibril_create(transmit_fibril
, NULL
);
318 printf("Failed creating transmit fibril.\n");
322 fibril_add_ready(fid
);
324 fid
= fibril_create(input_fibril
, NULL
);
326 printf("Failed creating input fibril.\n");
330 fibril_add_ready(fid
);
332 fibril_mutex_lock(&quit_lock
);
334 fibril_condvar_wait(&quit_cv
, &quit_lock
);
335 fibril_mutex_unlock(&quit_lock
);
340 dnsr_hostinfo_destroy(hinfo
);
347 dnsr_hostinfo_destroy(hinfo
);