source: mainline/uspace/app/ping/ping.c@ 5a324d99

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

Remove include where not needed anymore.

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