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

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

Return canonical name to caller.

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