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

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

Extend console library API to support different event types.

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