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

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

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

  • Property mode set to 100644
File size: 7.6 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 <errno.h>
37#include <fibril_synch.h>
38#include <inet/addr.h>
39#include <inet/host.h>
40#include <inet/inetping.h>
41#include <io/console.h>
42#include <getopt.h>
43#include <stdbool.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <stddef.h>
47#include <stdint.h>
48#include <str.h>
49#include <str_error.h>
50
51#define NAME "ping"
52
53/** Delay between subsequent ping requests in microseconds */
54#define PING_DELAY (1000 * 1000)
55
56/** Ping request timeout in microseconds */
57#define PING_TIMEOUT (1000 * 1000)
58
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);
68
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 *);
74
75static inetping_ev_ops_t ev_ops = {
76 .recv = ping_ev_recv
77};
78
79static inet_addr_t src_addr;
80static inet_addr_t dest_addr;
81
82static bool repeat_forever = false;
83static size_t repeat_count = 1;
84
85static const char *short_options = "46rn:";
86
87static void print_syntax(void)
88{
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");
93}
94
95static void ping_signal_received(received_t value)
96{
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);
109}
110
111static int ping_ev_recv(inetping_sdu_t *sdu)
112{
113 char *asrc;
114 int rc = inet_addr_format(&src_addr, &asrc);
115 if (rc != EOK)
116 return ENOMEM;
117
118 char *adest;
119 rc = inet_addr_format(&dest_addr, &adest);
120 if (rc != EOK) {
121 free(asrc);
122 return ENOMEM;
123 }
124
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);
127
128 ping_signal_received(RECEIVED_SUCCESS);
129
130 free(asrc);
131 free(adest);
132 return EOK;
133}
134
135static int ping_send(uint16_t seq_no)
136{
137 inetping_sdu_t sdu;
138
139 sdu.src = src_addr;
140 sdu.dest = dest_addr;
141 sdu.seq_no = seq_no;
142 sdu.data = (void *) "foo";
143 sdu.size = 3;
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;
151}
152
153static int transmit_fibril(void *arg)
154{
155 uint16_t seq_no = 0;
156
157 while ((repeat_count--) || (repeat_forever)) {
158 fibril_mutex_lock(&received_lock);
159 received = RECEIVED_NONE;
160 fibril_mutex_unlock(&received_lock);
161
162 (void) ping_send(++seq_no);
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 }
186 }
187
188 ping_signal_quit();
189 return 0;
190}
191
192static int input_fibril(void *arg)
193{
194 console_ctrl_t *con = console_init(stdin, stdout);
195
196 while (true) {
197 cons_event_t ev;
198 if (!console_get_event(con, &ev))
199 break;
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)) {
204 /* Ctrl+key */
205 if (ev.ev.key.key == KC_Q) {
206 ping_signal_received(RECEIVED_INTERRUPT);
207 break;
208 }
209 }
210 }
211
212 return 0;
213}
214
215int main(int argc, char *argv[])
216{
217 char *asrc = NULL;
218 char *adest = NULL;
219 char *sdest = NULL;
220 char *host;
221 const char *errmsg;
222 ip_ver_t ip_ver = ip_any;
223
224 int rc = inetping_init(&ev_ops);
225 if (rc != EOK) {
226 printf("Failed connecting to internet ping service: "
227 "%s (%d).\n", str_error(rc), rc);
228 goto error;
229 }
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;
245 case '4':
246 ip_ver = ip_v4;
247 break;
248 case '6':
249 ip_ver = ip_v6;
250 break;
251 default:
252 printf("Unknown option passed.\n");
253 print_syntax();
254 goto error;
255 }
256 }
257
258 if (optind >= argc) {
259 printf("IP address or host name not supplied.\n");
260 print_syntax();
261 goto error;
262 }
263
264 host = argv[optind];
265
266 /* Look up host */
267 rc = inet_host_plookup_one(host, ip_ver, &dest_addr, NULL, &errmsg);
268 if (rc != EOK) {
269 printf("Error resolving host '%s' (%s).\n", host, errmsg);
270 goto error;
271 }
272
273 /* Determine source address */
274 rc = inetping_get_srcaddr(&dest_addr, &src_addr);
275 if (rc != EOK) {
276 printf("Failed determining source address.\n");
277 goto error;
278 }
279
280 rc = inet_addr_format(&src_addr, &asrc);
281 if (rc != EOK) {
282 printf("Out of memory.\n");
283 goto error;
284 }
285
286 rc = inet_addr_format(&dest_addr, &adest);
287 if (rc != EOK) {
288 printf("Out of memory.\n");
289 goto error;
290 }
291
292 rc = asprintf(&sdest, "%s (%s)", host, adest);
293 if (rc < 0) {
294 printf("Out of memory.\n");
295 goto error;
296 }
297
298 printf("Sending ICMP echo request from %s to %s (Ctrl+Q to quit)\n",
299 asrc, sdest);
300
301 fid_t fid = fibril_create(transmit_fibril, NULL);
302 if (fid == 0) {
303 printf("Failed creating transmit fibril.\n");
304 goto error;
305 }
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");
312 goto error;
313 }
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
322 free(asrc);
323 free(adest);
324 free(sdest);
325 return 0;
326
327error:
328 free(asrc);
329 free(adest);
330 free(sdest);
331 return 1;
332}
333
334/** @}
335 */
Note: See TracBrowser for help on using the repository browser.