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

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

Hostname resolution in ping command.

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