source: mainline/uspace/app/ping/ping.c@ 93757c5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 93757c5 was 8d2dd7f2, checked in by Jakub Jermar <jakub@…>, 9 years ago

Reduce the number of files that include <sys/types.h>

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