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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since db71e2a was 0aa70f4, checked in by Martin Decky <martin@…>, 12 years ago

support for IPv6 DNS name resolution (AAAA)
if the desired address family of the DNS query is not explicitly specified, then IPv6 addresses take precendece over IPv4 addresses

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