VirtualBox

source: vbox/trunk/src/libs/libslirp-4.7.0/test/pingtest.c@ 105681

最後變更 在這個檔案從105681是 105101,由 vboxsync 提交於 8 月 前

libs/libslirp: fix OSE export

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 11.6 KB
 
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (c) 2021 Samuel Thibault
4 */
5
6/*
7 * This simple test configures slirp and tries to ping it
8 *
9 * Note: to make this example actually be able to use the outside world, you
10 * need to either
11 * - run as root
12 * - set /proc/sys/net/ipv4/ping_group_range to allow sending ICMP echo requests
13 * - run a UDP echo server on the target
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <time.h>
19#include <assert.h>
20
21#include "libslirp.h"
22
23//#define _WIN32
24#ifdef _WIN32
25//#include <sys/select.h>
26#include <winsock2.h>
27int slirp_inet_aton(const char *cp, struct in_addr *ia)
28{
29 uint32_t addr = inet_addr(cp);
30 if (addr == 0xffffffff) {
31 return 0;
32 }
33 ia->s_addr = addr;
34 return 1;
35}
36#define inet_aton slirp_inet_aton
37#else
38#include <poll.h>
39#endif
40
41/* Dumb simulation tick: 100ms */
42#define TICK 100
43
44static Slirp *slirp;
45static bool done;
46static int64_t mytime;
47
48/* Print a frame for debugging */
49static void print_frame(const uint8_t *data, size_t len) {
50 int i;
51
52 printf("\ngot packet size %zd:\n", len);
53 for (i = 0; i < len; i++) {
54 if (i && i % 16 == 0)
55 printf("\n");
56 printf("%s%02x", i % 16 ? " " : "", data[i]);
57 }
58 if (len % 16 != 0)
59 printf("\n");
60 printf("\n");
61}
62
63/* Classical 16bit checksum */
64static void checksum(uint8_t *data, size_t size, uint8_t *cksum) {
65 uint32_t sum = 0;
66 int i;
67
68 cksum[0] = 0;
69 cksum[1] = 0;
70
71 for (i = 0; i+1 < size; i += 2)
72 sum += (((uint16_t) data[i]) << 8) + data[i+1];
73 if (i < size) /* Odd number of bytes */
74 sum += ((uint16_t) data[i]) << 8;
75
76 sum = (sum & 0xffff) + (sum >> 16);
77 sum = (sum & 0xffff) + (sum >> 16);
78 sum = ~sum;
79
80 cksum[0] = sum >> 8;
81 cksum[1] = sum;
82}
83
84/* This is called when receiving a packet from the virtual network, for the
85 * guest */
86static ssize_t send_packet(const void *buf, size_t len, void *opaque) {
87 const uint8_t *data = buf;
88
89 assert(len >= 14);
90
91 if (data[12] == 0x86 &&
92 data[13] == 0xdd) {
93 /* Ignore IPv6 */
94 return len;
95 }
96
97 print_frame(data, len);
98
99 if (data[12] == 0x08 &&
100 data[13] == 0x06) {
101 /* ARP */
102 /* We expect receiving an ARP request for our address */
103
104 /* Ethernet address type */
105 assert(data[14] == 0x00);
106 assert(data[15] == 0x01);
107
108 /* IPv4 address type */
109 assert(data[16] == 0x08);
110 assert(data[17] == 0x00);
111
112 /* Ethernet addresses are 6 bytes long */
113 assert(data[18] == 0x06);
114
115 /* IPv4 addresses are 4 bytes long */
116 assert(data[19] == 0x04);
117
118 /* Opcode: ARP request */
119 assert(data[20] == 0x00);
120 assert(data[21] == 0x01);
121
122 /* Ok, reply! */
123 uint8_t myframe[] = {
124 /*** Ethernet ***/
125 /* dst */
126 0x52, 0x55, 0x0a, 0x00, 0x02, 0x02,
127 /* src */
128 0x52, 0x55, 0x0a, 0x00, 0x02, 0x0e,
129 /* Type: ARP */
130 0x08, 0x06,
131
132 /* ether, IPv4, */
133 0x00, 0x01, 0x08, 0x00,
134 /* elen, IPlen */
135 0x06, 0x04,
136 /* ARP reply */
137 0x00, 0x02,
138
139 /* Our ethernet address */
140 0x52, 0x55, 0x0a, 0x00, 0x02, 0x0e,
141 /* Our IP address */
142 0x0a, 0x00, 0x02, 0x0e,
143
144 /* Host ethernet address */
145 0x52, 0x55, 0x0a, 0x00, 0x02, 0x02,
146 /* Host IP address */
147 0x0a, 0x00, 0x02, 0x02,
148 };
149
150 slirp_input(slirp, myframe, sizeof(myframe));
151 }
152
153 if (data[12] == 0x08 &&
154 data[13] == 0x00) {
155 /* IPv4 */
156 assert(len >= 14 + 20);
157
158 /* We expect receiving the ICMP echo reply for our echo request */
159
160 /* IPv + hlen */
161 assert(data[14] == 0x45);
162
163 /* proto: ICMP */
164 assert(data[23] == 0x01);
165
166 /* ICMP */
167 assert(len >= 14 + 20 + 8 + 4);
168
169 /* ICMP type: reply */
170 assert(data[34] == 0x00);
171
172 /* Check the data */
173 assert(data[42] == 0xde);
174 assert(data[43] == 0xad);
175 assert(data[44] == 0xbe);
176 assert(data[45] == 0xef);
177
178 /* Got the answer! */
179 printf("got it!\n");
180 done = 1;
181 }
182
183 return len;
184}
185
186static void guest_error(const char *msg, void *opaque) {
187 printf("guest error %s\n", msg);
188}
189
190
191/*
192 * Dumb timer implementation
193 */
194static int64_t clock_get_ns(void *opaque) {
195 return mytime;
196}
197
198struct timer {
199 SlirpTimerId id;
200 void *cb_opaque;
201 int64_t expire;
202 struct timer *next;
203};
204
205static struct timer *timer_queue;
206
207static void *timer_new_opaque(SlirpTimerId id, void *cb_opaque, void *opaque) {
208 struct timer *new_timer = malloc(sizeof(*new_timer));
209 new_timer->id = id;
210 new_timer->cb_opaque = cb_opaque;
211 new_timer->next = NULL;
212 return new_timer;
213}
214
215static void timer_free(void *_timer, void *opaque) {
216 struct timer *timer = _timer;
217 struct timer **t;
218
219 for (t = &timer_queue; *t != NULL; *t = (*t)->next) {
220 if (*t == timer) {
221 /* Not expired yet, drop it */
222 *t = timer->next;
223 break;
224 }
225 }
226
227 free(timer);
228}
229
230static void timer_mod(void *_timer, int64_t expire_time, void *opaque) {
231 struct timer *timer = _timer;
232 struct timer **t;
233
234 timer->expire = expire_time * 1000 * 1000;
235
236 for (t = &timer_queue; *t != NULL; *t = (*t)->next) {
237 if (expire_time < (*t)->expire)
238 break;
239 }
240
241 timer->next = *t;
242 *t = timer;
243}
244
245static void timer_check(Slirp *slirp) {
246 while (timer_queue && timer_queue->expire <= mytime)
247 {
248 struct timer *t = timer_queue;
249 printf("handling %p at time %lu\n",
250 t, (unsigned long) timer_queue->expire);
251 timer_queue = t->next;
252 slirp_handle_timer(slirp, t->id, t->cb_opaque);
253 }
254}
255
256static uint32_t timer_timeout(void) {
257 if (timer_queue)
258 {
259 uint32_t timeout = (timer_queue->expire - mytime) / (1000 * 1000);
260 if (timeout < TICK)
261 return timeout;
262 }
263
264 return TICK;
265}
266
267
268/*
269 * Dumb polling implementation
270 */
271static int npoll;
272static void register_poll_fd(int fd, void *opaque) {
273 /* We might want to prepare for polling on fd */
274 npoll++;
275}
276
277static void unregister_poll_fd(int fd, void *opaque) {
278 /* We might want to clear polling on fd */
279 npoll--;
280}
281
282static void notify(void *opaque) {
283 /* No need for this in single-thread case */
284}
285
286#ifdef _WIN32
287/* select() variant */
288static fd_set readfds, writefds, exceptfds;
289static int maxfd;
290static int add_poll_cb(int fd, int events, void *opaque)
291{
292 if (events & SLIRP_POLL_IN)
293 FD_SET(fd, &readfds);
294 if (events & SLIRP_POLL_OUT)
295 FD_SET(fd, &writefds);
296 if (events & SLIRP_POLL_PRI)
297 FD_SET(fd, &exceptfds);
298 if (maxfd < fd)
299 maxfd = fd;
300 return fd;
301}
302
303static int get_revents_cb(int idx, void *opaque)
304{
305 int event = 0;
306 if (FD_ISSET(idx, &readfds))
307 event |= SLIRP_POLL_IN;
308 if (FD_ISSET(idx, &writefds))
309 event |= SLIRP_POLL_OUT;
310 if (FD_ISSET(idx, &exceptfds))
311 event |= SLIRP_POLL_PRI;
312 return event;
313}
314
315static void dopoll(uint32_t timeout) {
316 int err;
317 FD_ZERO(&readfds);
318 FD_ZERO(&writefds);
319 FD_ZERO(&exceptfds);
320 maxfd = 0;
321
322 slirp_pollfds_fill(slirp, &timeout, add_poll_cb, NULL);
323 printf("we will use timeout %u\n", (unsigned) timeout);
324
325 struct timeval tv = {
326 .tv_sec = timeout / 1000,
327 .tv_usec = (timeout % 1000) * 1000,
328 };
329 err = select(maxfd+1, &readfds, &writefds, &exceptfds, &tv);
330
331 slirp_pollfds_poll(slirp, err < 0, get_revents_cb, NULL);
332}
333#else
334/* poll() variant */
335static struct pollfd *fds;
336static int cur_poll;
337static int add_poll_cb(int fd, int events, void *opaque)
338{
339 short poll_events = 0;
340
341 assert(cur_poll < npoll);
342 fds[cur_poll].fd = fd;
343
344 if (events & SLIRP_POLL_IN)
345 poll_events |= POLLIN;
346 if (events & SLIRP_POLL_OUT)
347 poll_events |= POLLOUT;
348 if (events & SLIRP_POLL_PRI)
349 poll_events |= POLLPRI;
350 fds[cur_poll].events = poll_events;
351
352 return cur_poll++;
353}
354
355static int get_revents_cb(int idx, void *opaque)
356{
357 return fds[idx].revents;
358}
359
360static void dopoll(uint32_t timeout) {
361 int err;
362 fds = malloc(sizeof(*fds) * npoll);
363 cur_poll = 0;
364
365 slirp_pollfds_fill(slirp, &timeout, add_poll_cb, NULL);
366 printf("we will use timeout %u\n", (unsigned) timeout);
367
368 err = poll(fds, cur_poll, timeout);
369
370 slirp_pollfds_poll(slirp, err < 0, get_revents_cb, NULL);
371
372 free(fds);
373}
374#endif
375
376
377static struct SlirpCb callbacks = {
378 .send_packet = send_packet,
379 .guest_error = guest_error,
380 .clock_get_ns = clock_get_ns,
381 .timer_new_opaque = timer_new_opaque,
382 .timer_free = timer_free,
383 .timer_mod = timer_mod,
384 .register_poll_fd = register_poll_fd,
385 .unregister_poll_fd = unregister_poll_fd,
386 .notify = notify,
387};
388
389
390int main(int argc, char *argv[]) {
391 SlirpConfig config = {
392 .version = 4,
393 .restricted = false,
394 .in_enabled = true,
395 .vnetwork.s_addr = htonl(0x0a000200),
396 .vnetmask.s_addr = htonl(0xffffff00),
397 .vhost.s_addr = htonl(0x0a000202),
398 .vdhcp_start.s_addr = htonl(0x0a00020f),
399 .vnameserver.s_addr = htonl(0x0a000203),
400 .disable_host_loopback = false,
401 .enable_emu = false,
402 .disable_dns = false,
403 };
404 uint32_t timeout = 0;
405
406 printf("Slirp version %s\n", slirp_version_string());
407
408#if !defined(_WIN32)
409 inet_pton(AF_INET6, "fec0::", &config.vprefix_addr6);
410 config.vprefix_len = 64;
411 config.vhost6 = config.vprefix_addr6;
412 config.vhost6.s6_addr[15] = 2;
413 config.vnameserver6 = config.vprefix_addr6;
414 config.vnameserver6.s6_addr[15] = 2;
415 config.in6_enabled = true,
416#endif
417
418 slirp = slirp_new(&config, &callbacks, NULL);
419
420 /* Send echo request */
421 uint8_t myframe[] = {
422 /*** Ethernet ***/
423 /* dst */
424 0x52, 0x55, 0x0a, 0x00, 0x02, 0x02,
425 /* src */
426 0x52, 0x55, 0x0a, 0x00, 0x02, 0x0e,
427 /* Type: IPv4 */
428 0x08, 0x00,
429
430 /*** IPv4 ***/
431 /* vhl,tos, len */
432 0x45, 0x00, 0x00, 0x20,
433 /* id, off (DF) */
434 0x68, 0xd7, 0x40, 0x00,
435 /* ttl,pro, cksum */
436 0x40, 0x01, 0x00, 0x00,
437 /* src */
438 0x0a, 0x00, 0x02, 0x0e,
439 /* dst */
440 0x00, 0x00, 0x00, 0x00,
441
442 /*** ICMPv4 ***/
443 /* type, code, cksum */
444 0x08, 0x00, 0x00, 0x00,
445 /* id, seq */
446 0x01, 0xec, 0x00, 0x01,
447 /* data */
448 0xde, 0xad, 0xbe, 0xef,
449 };
450
451 struct in_addr in_addr = { .s_addr = htonl(0x0a000202) };
452 if (argc > 1) {
453 if (inet_aton(argv[1], &in_addr) == 0) {
454 printf("usage: %s [destination IPv4 address]\n", argv[0]);
455 exit(EXIT_FAILURE);
456 }
457 }
458 uint32_t addr = ntohl(in_addr.s_addr);
459 myframe[30] = addr >> 24;
460 myframe[31] = addr >> 16;
461 myframe[32] = addr >> 8;
462 myframe[33] = addr >> 0;
463
464 /* IPv4 header checksum */
465 checksum(&myframe[14], 20, &myframe[24]);
466 /* ICMP header checksum */
467 checksum(&myframe[34], 12, &myframe[36]);
468
469 slirp_input(slirp, myframe, sizeof(myframe));
470
471 /* Wait for echo reply */
472 while (!done) {
473 printf("time %lu\n", (unsigned long) mytime);
474
475 timer_check(slirp);
476 /* Here we make the virtual time wait like the real time, but we could
477 * make it wait differently */
478 timeout = timer_timeout();
479 printf("we wish timeout %u\n", (unsigned) timeout);
480
481 dopoll(timeout);
482
483 /* Fake that the tick elapsed */
484 mytime += TICK * 1000 * 1000;
485 }
486
487 slirp_cleanup(slirp);
488}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette