source: mainline/uspace/app/ping/ping.c@ 9c4cf0d

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

Need better interfaces for handling internet host and host:port specifications.

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