source: mainline/uspace/app/ping/ping.c@ 78d50bd

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

ping6 - resistance is futile.

  • Property mode set to 100644
File size: 7.8 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>
[3495654]40#include <inet/addr.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 dnsr_hostinfo_t *hinfo = NULL;
217 char *asrc = NULL;
218 char *adest = NULL;
219 char *sdest = NULL;
[9749e47]220 ip_ver_t ip_ver = ip_any;
[ccdc63e]221
222 int rc = inetping_init(&ev_ops);
[6428115]223 if (rc != EOK) {
[ccdc63e]224 printf("Failed connecting to internet ping service: "
225 "%s (%d).\n", str_error(rc), rc);
[c55cbbf]226 goto error;
[6428115]227 }
[ccdc63e]228
229 int c;
230 while ((c = getopt(argc, argv, short_options)) != -1) {
231 switch (c) {
232 case 'r':
233 repeat_forever = true;
234 break;
235 case 'n':
236 rc = str_size_t(optarg, NULL, 10, true, &repeat_count);
237 if (rc != EOK) {
238 printf("Invalid repeat count.\n");
239 print_syntax();
240 goto error;
241 }
242 break;
[9749e47]243 case '4':
244 ip_ver = ip_v4;
245 break;
246 case '6':
247 ip_ver = ip_v6;
248 break;
[ccdc63e]249 default:
250 printf("Unknown option passed.\n");
251 print_syntax();
252 goto error;
253 }
[3b3c689]254 }
[ccdc63e]255
256 if (optind >= argc) {
257 printf("IP address or host name not supplied.\n");
[6428115]258 print_syntax();
[c55cbbf]259 goto error;
[6428115]260 }
[ccdc63e]261
[6428115]262 /* Parse destination address */
[ccdc63e]263 rc = inet_addr_parse(argv[optind], &dest_addr);
[6428115]264 if (rc != EOK) {
[c55cbbf]265 /* Try interpreting as a host name */
[9749e47]266 rc = dnsr_name2host(argv[optind], &hinfo, ip_ver);
[c55cbbf]267 if (rc != EOK) {
[ccdc63e]268 printf("Error resolving host '%s'.\n", argv[optind]);
[c55cbbf]269 goto error;
270 }
[3e66428]271
[c55cbbf]272 dest_addr = hinfo->addr;
[6428115]273 }
[3e66428]274
[6428115]275 /* Determine source address */
[9749e47]276 rc = inetping_get_srcaddr(&dest_addr, &src_addr);
[6428115]277 if (rc != EOK) {
[ccdc63e]278 printf("Failed determining source address.\n");
[c55cbbf]279 goto error;
280 }
[3e66428]281
[a2e3ee6]282 rc = inet_addr_format(&src_addr, &asrc);
[c55cbbf]283 if (rc != EOK) {
[ccdc63e]284 printf("Out of memory.\n");
[c55cbbf]285 goto error;
286 }
[3e66428]287
[a2e3ee6]288 rc = inet_addr_format(&dest_addr, &adest);
[c55cbbf]289 if (rc != EOK) {
[ccdc63e]290 printf("Out of memory.\n");
[c55cbbf]291 goto error;
292 }
[3e66428]293
[c55cbbf]294 if (hinfo != NULL) {
[959d2ec]295 rc = asprintf(&sdest, "%s (%s)", hinfo->cname, adest);
[c55cbbf]296 if (rc < 0) {
[ccdc63e]297 printf("Out of memory.\n");
[c55cbbf]298 goto error;
299 }
300 } else {
301 sdest = adest;
302 adest = NULL;
[6428115]303 }
[ccdc63e]304
305 printf("Sending ICMP echo request from %s to %s (Ctrl+Q to quit)\n",
[c55cbbf]306 asrc, sdest);
[ccdc63e]307
308 fid_t fid = fibril_create(transmit_fibril, NULL);
309 if (fid == 0) {
310 printf("Failed creating transmit fibril.\n");
311 goto error;
[3b3c689]312 }
[ccdc63e]313
314 fibril_add_ready(fid);
315
316 fid = fibril_create(input_fibril, NULL);
317 if (fid == 0) {
318 printf("Failed creating input fibril.\n");
[c55cbbf]319 goto error;
[6428115]320 }
[ccdc63e]321
322 fibril_add_ready(fid);
323
324 fibril_mutex_lock(&quit_lock);
325 while (!quit)
326 fibril_condvar_wait(&quit_cv, &quit_lock);
327 fibril_mutex_unlock(&quit_lock);
328
[c55cbbf]329 free(asrc);
330 free(adest);
331 free(sdest);
332 dnsr_hostinfo_destroy(hinfo);
[6428115]333 return 0;
[3e66428]334
[c55cbbf]335error:
336 free(asrc);
337 free(adest);
338 free(sdest);
339 dnsr_hostinfo_destroy(hinfo);
340 return 1;
[6428115]341}
342
343/** @}
344 */
Note: See TracBrowser for help on using the repository browser.