tap.cc (291:ba3bdac49128) tap.cc (1762:6bf5cf6d9903)
1/*
1/*
2 * Copyright (c) 2003 The Regents of The University of Michigan
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
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 are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * 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
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29extern "C" {
30#include <pcap.h>
31}
32
33#include <dnet.h>
34
35#include <arpa/inet.h>
36
37#include <sys/ioctl.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40
41#include <netinet/in.h>
42#include <netinet/tcp.h>
43
44#include <errno.h>
45#include <fcntl.h>
46#include <libgen.h>
47#include <netdb.h>
48#include <poll.h>
49#include <signal.h>
50#include <unistd.h>
51
52#include <list>
53#include <string>
54
55#include "base/cprintf.hh"
56
57#define panic(arg...) \
58 do { cprintf("Panic: " arg); exit(1); } while (0)
59
60char *program = "ethertap";
61void
62usage()
63{
64 cprintf(
65 "usage: \n"
66 "\t%s [-b bufsize] [-d] [-f filter] [-p port] [-v] <device> <host>\n"
67 "\t%s [-b bufsize] [-d] [-f filter] [-l] [-p port] [-v] <device>\n",
68 program, program);
69 exit(2);
70}
71
72int verbose = 0;
73#define DPRINTF(args...) do { \
74 if (verbose >= 1) \
75 cprintf(args); \
76} while (0)
77
78#define DDUMP(args...) do { \
79 if (verbose >= 2) \
80 dump((const u_char *)args); \
81} while (0)
82
83void
84dump(const u_char *data, int len)
85{
86 int c, i, j;
87
88 for (i = 0; i < len; i += 16) {
89 cprintf("%08x ", i);
90 c = len - i;
91 if (c > 16) c = 16;
92
93 for (j = 0; j < c; j++) {
94 cprintf("%02x ", data[i + j] & 0xff);
95 if ((j & 0xf) == 7 && j > 0)
96 cprintf(" ");
97 }
98
99 for (; j < 16; j++)
100 cprintf(" ");
101 cprintf(" ");
102
103 for (j = 0; j < c; j++) {
104 int ch = data[i + j] & 0x7f;
105 cprintf("%c", (char)(isprint(ch) ? ch : ' '));
106 }
107
108 cprintf("\n");
109
110 if (c < 16)
111 break;
112 }
113}
114
115bool quit = false;
116void
117quit_now(int sigtype)
118{
119 DPRINTF("User requested exit\n");
120 quit = true;
121}
122
123
124int
125Socket(int reuse)
126{
127 int fd = ::socket(PF_INET, SOCK_STREAM, 0);
128 if (fd < 0)
129 panic("Can't create socket!\n");
130
131 if (reuse) {
132 int i = 1;
133 if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i,
134 sizeof(i)) < 0)
135 panic("setsockopt() SO_REUSEADDR failed!\n");
136 }
137
138 return fd;
139}
140
141void
142Listen(int fd, int port)
143{
144 struct sockaddr_in sockaddr;
145 sockaddr.sin_family = PF_INET;
146 sockaddr.sin_addr.s_addr = INADDR_ANY;
147
148 sockaddr.sin_port = htons(port);
149 int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr));
150 if (ret == -1)
151 panic("bind() failed!\n");
152
153 if (::listen(fd, 1) == -1)
154 panic("listen() failed!\n");
155}
156
157// Open a connection. Accept will block, so if you don't want it to,
158// make sure a connection is ready before you call accept.
159int
160Accept(int fd, bool nodelay)
161{
162 struct sockaddr_in sockaddr;
163 socklen_t slen = sizeof (sockaddr);
164 int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
165 if (sfd == -1)
166 panic("accept() failed!\n");
167
168 if (nodelay) {
169 int i = 1;
170 ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
171 }
172 return sfd;
173}
174
175void
176Connect(int fd, const string &host, int port)
177{
178 struct sockaddr_in sockaddr;
179 if (::inet_aton(host.c_str(), &sockaddr.sin_addr) == 0) {
180 struct hostent *hp;
181 hp = ::gethostbyname(host.c_str());
182 if (!hp)
183 panic("Host %s not found\n", host);
184
185 sockaddr.sin_family = hp->h_addrtype;
186 memcpy(&sockaddr.sin_addr, hp->h_addr, hp->h_length);
187 }
188
189 sockaddr.sin_port = htons(port);
190 if (::connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0)
191 panic("could not connect to %s on port %d\n", host, port);
192
193 DPRINTF("connected to %s on port %d\n", host, port);
194}
195
196int
197main(int argc, char *argv[])
198{
199 int port = 3500;
200 int bufsize = 2000;
201 bool listening = false;
202 char *device = NULL;
203 char *filter = NULL;
204 char c;
205 int daemon = false;
206 string host;
207
208 program = basename(argv[0]);
209
210 while ((c = getopt(argc, argv, "b:df:lp:v")) != -1) {
211 switch (c) {
212 case 'b':
213 bufsize = atoi(optarg);
214 break;
215 case 'd':
216 daemon = true;
217 break;
218 case 'f':
219 filter = optarg;
220 break;
221 case 'l':
222 listening = true;
223 break;
224 case 'p':
225 port = atoi(optarg);
226 break;
227 case 'v':
228 verbose++;
229 break;
230 default:
231 usage();
232 break;
233 }
234 }
235
236 signal(SIGINT, quit_now);
237 signal(SIGTERM, quit_now);
238 signal(SIGHUP, quit_now);
239
240 if (daemon) {
241 verbose = 0;
242 switch(fork()) {
243 case -1:
244 panic("Fork failed\n");
245 case 0:
246 break;
247 default:
248 exit(0);
249 }
250 }
251
252 char *buffer = new char[bufsize];
253 argc -= optind;
254 argv += optind;
255
256 if (argc-- == 0)
257 usage();
258
259 device = *argv++;
260
261 if (listening) {
262 if (argc)
263 usage();
264 } else {
265 if (argc != 1)
266 usage();
267
268 host = *argv;
269 }
270
271 char errbuf[PCAP_ERRBUF_SIZE];
272 memset(errbuf, 0, sizeof errbuf);
273 pcap_t *pcap = pcap_open_live(device, 1500, 1, -1, errbuf);
274 if (pcap == NULL)
275 panic("pcap_open_live failed: %s\n", errbuf);
276
277 if (filter) {
278 bpf_program program;
279 bpf_u_int32 localnet, netmask;
280 if (pcap_lookupnet(device, &localnet, &netmask, errbuf) == -1) {
281 DPRINTF("pcap_lookupnet failed: %s\n", errbuf);
282 netmask = 0xffffff00;
283 }
284
285 if (pcap_compile(pcap, &program, filter, 1, netmask) == -1)
286 panic("pcap_compile failed, invalid filter:\n%s\n", filter);
287
288 if (pcap_setfilter(pcap, &program) == -1)
289 panic("pcap_setfilter failed\n");
290 }
291
292 eth_t *ethernet = eth_open(device);
293 if (!ethernet)
294 panic("cannot open the ethernet device for writing\n");
295
296 pollfd pfds[3];
297 pfds[0].fd = Socket(true);
298 pfds[0].events = POLLIN;
299 pfds[0].revents = 0;
300
301 if (listening)
302 Listen(pfds[0].fd, port);
303 else
304 Connect(pfds[0].fd, host, port);
305
306 pfds[1].fd = pcap_fileno(pcap);
307 pfds[1].events = POLLIN;
308 pfds[1].revents = 0;
309
310 pfds[2].fd = 0;
311 pfds[2].events = POLLIN|POLLERR;
312 pfds[2].revents = 0;
313
314 pollfd *listen_pfd = listening ? &pfds[0] : NULL;
315 pollfd *tap_pfd = &pfds[1];
316 pollfd *client_pfd = listening ? NULL : &pfds[0];
317 int npfds = 2;
318
319 int32_t buffer_offset = 0;
320 int32_t data_len = 0;
321
322 DPRINTF("Begin poll loop\n");
323 while (!quit) {
324 int ret = ::poll(pfds, npfds, INFTIM);
325 if (ret < 0)
326 continue;
327
328 if (listen_pfd && listen_pfd->revents) {
329 if (listen_pfd->revents & POLLIN) {
330 int fd = Accept(listen_pfd->fd, false);
331 if (client_pfd) {
332 DPRINTF("Connection rejected\n");
333 close(fd);
334 } else {
335 DPRINTF("Connection accepted\n");
336 client_pfd = &pfds[2];
337 client_pfd->fd = fd;
338 npfds++;
339 }
340 }
341 listen_pfd->revents = 0;
342 }
343
344 if (tap_pfd && tap_pfd->revents) {
345 if (tap_pfd->revents & POLLIN) {
346 pcap_pkthdr hdr;
347 const u_char *data = pcap_next(pcap, &hdr);
348 if (data && client_pfd) {
349 DPRINTF("Received packet from ethernet len=%d\n", hdr.len);
350 DDUMP(data, hdr.len);
351 u_int32_t len = htonl(hdr.len);
352 write(client_pfd->fd, &len, sizeof(len));
353 write(client_pfd->fd, data, hdr.len);
354 }
355 }
356
357 tap_pfd->revents = 0;
358 }
359
360 if (client_pfd && client_pfd->revents) {
361 if (client_pfd->revents & POLLIN) {
362 if (buffer_offset < data_len + sizeof(u_int32_t)) {
363 int len = read(client_pfd->fd, buffer + buffer_offset,
364 bufsize - buffer_offset);
365
366 if (len <= 0) {
367 perror("read");
368 goto error;
369 }
370
371 buffer_offset += len;
372 if (data_len == 0)
373 data_len = ntohl(*(u_int32_t *)buffer);
374
375 DPRINTF("Received data from peer: len=%d buffer_offset=%d "
376 "data_len=%d\n", len, buffer_offset, data_len);
377 }
378
379 while (data_len != 0 &&
380 buffer_offset >= data_len + sizeof(u_int32_t)) {
381 char *data = buffer + sizeof(u_int32_t);
382 eth_send(ethernet, data, data_len);
383 DPRINTF("Sent packet to ethernet len = %d\n", data_len);
384 DDUMP(data, data_len);
385
386 buffer_offset -= data_len + sizeof(u_int32_t);
387 if (buffer_offset > 0 && data_len > 0) {
388 memmove(buffer, data + data_len, buffer_offset);
389 data_len = ntohl(*(u_int32_t *)buffer);
390 } else
391 data_len = 0;
392 }
393 }
394
395 if (client_pfd->revents & POLLERR) {
396 error:
397 DPRINTF("Error on client socket\n");
398 close(client_pfd->fd);
399 client_pfd = NULL;
400
401 if (listening)
402 npfds--;
403 else {
404 DPRINTF("Calling it quits because of poll error\n");
405 quit = true;
406 }
407 }
408
409 if (client_pfd)
410 client_pfd->revents = 0;
411 }
412 }
413
414 delete [] buffer;
415 pcap_close(pcap);
416 eth_close(ethernet);
417 if (listen_pfd)
418 close(listen_pfd->fd);
419
420 if (client_pfd)
421 close(client_pfd->fd);
422
423 return 0;
424}
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 are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * 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
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29extern "C" {
30#include <pcap.h>
31}
32
33#include <dnet.h>
34
35#include <arpa/inet.h>
36
37#include <sys/ioctl.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40
41#include <netinet/in.h>
42#include <netinet/tcp.h>
43
44#include <errno.h>
45#include <fcntl.h>
46#include <libgen.h>
47#include <netdb.h>
48#include <poll.h>
49#include <signal.h>
50#include <unistd.h>
51
52#include <list>
53#include <string>
54
55#include "base/cprintf.hh"
56
57#define panic(arg...) \
58 do { cprintf("Panic: " arg); exit(1); } while (0)
59
60char *program = "ethertap";
61void
62usage()
63{
64 cprintf(
65 "usage: \n"
66 "\t%s [-b bufsize] [-d] [-f filter] [-p port] [-v] <device> <host>\n"
67 "\t%s [-b bufsize] [-d] [-f filter] [-l] [-p port] [-v] <device>\n",
68 program, program);
69 exit(2);
70}
71
72int verbose = 0;
73#define DPRINTF(args...) do { \
74 if (verbose >= 1) \
75 cprintf(args); \
76} while (0)
77
78#define DDUMP(args...) do { \
79 if (verbose >= 2) \
80 dump((const u_char *)args); \
81} while (0)
82
83void
84dump(const u_char *data, int len)
85{
86 int c, i, j;
87
88 for (i = 0; i < len; i += 16) {
89 cprintf("%08x ", i);
90 c = len - i;
91 if (c > 16) c = 16;
92
93 for (j = 0; j < c; j++) {
94 cprintf("%02x ", data[i + j] & 0xff);
95 if ((j & 0xf) == 7 && j > 0)
96 cprintf(" ");
97 }
98
99 for (; j < 16; j++)
100 cprintf(" ");
101 cprintf(" ");
102
103 for (j = 0; j < c; j++) {
104 int ch = data[i + j] & 0x7f;
105 cprintf("%c", (char)(isprint(ch) ? ch : ' '));
106 }
107
108 cprintf("\n");
109
110 if (c < 16)
111 break;
112 }
113}
114
115bool quit = false;
116void
117quit_now(int sigtype)
118{
119 DPRINTF("User requested exit\n");
120 quit = true;
121}
122
123
124int
125Socket(int reuse)
126{
127 int fd = ::socket(PF_INET, SOCK_STREAM, 0);
128 if (fd < 0)
129 panic("Can't create socket!\n");
130
131 if (reuse) {
132 int i = 1;
133 if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i,
134 sizeof(i)) < 0)
135 panic("setsockopt() SO_REUSEADDR failed!\n");
136 }
137
138 return fd;
139}
140
141void
142Listen(int fd, int port)
143{
144 struct sockaddr_in sockaddr;
145 sockaddr.sin_family = PF_INET;
146 sockaddr.sin_addr.s_addr = INADDR_ANY;
147
148 sockaddr.sin_port = htons(port);
149 int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr));
150 if (ret == -1)
151 panic("bind() failed!\n");
152
153 if (::listen(fd, 1) == -1)
154 panic("listen() failed!\n");
155}
156
157// Open a connection. Accept will block, so if you don't want it to,
158// make sure a connection is ready before you call accept.
159int
160Accept(int fd, bool nodelay)
161{
162 struct sockaddr_in sockaddr;
163 socklen_t slen = sizeof (sockaddr);
164 int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
165 if (sfd == -1)
166 panic("accept() failed!\n");
167
168 if (nodelay) {
169 int i = 1;
170 ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
171 }
172 return sfd;
173}
174
175void
176Connect(int fd, const string &host, int port)
177{
178 struct sockaddr_in sockaddr;
179 if (::inet_aton(host.c_str(), &sockaddr.sin_addr) == 0) {
180 struct hostent *hp;
181 hp = ::gethostbyname(host.c_str());
182 if (!hp)
183 panic("Host %s not found\n", host);
184
185 sockaddr.sin_family = hp->h_addrtype;
186 memcpy(&sockaddr.sin_addr, hp->h_addr, hp->h_length);
187 }
188
189 sockaddr.sin_port = htons(port);
190 if (::connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0)
191 panic("could not connect to %s on port %d\n", host, port);
192
193 DPRINTF("connected to %s on port %d\n", host, port);
194}
195
196int
197main(int argc, char *argv[])
198{
199 int port = 3500;
200 int bufsize = 2000;
201 bool listening = false;
202 char *device = NULL;
203 char *filter = NULL;
204 char c;
205 int daemon = false;
206 string host;
207
208 program = basename(argv[0]);
209
210 while ((c = getopt(argc, argv, "b:df:lp:v")) != -1) {
211 switch (c) {
212 case 'b':
213 bufsize = atoi(optarg);
214 break;
215 case 'd':
216 daemon = true;
217 break;
218 case 'f':
219 filter = optarg;
220 break;
221 case 'l':
222 listening = true;
223 break;
224 case 'p':
225 port = atoi(optarg);
226 break;
227 case 'v':
228 verbose++;
229 break;
230 default:
231 usage();
232 break;
233 }
234 }
235
236 signal(SIGINT, quit_now);
237 signal(SIGTERM, quit_now);
238 signal(SIGHUP, quit_now);
239
240 if (daemon) {
241 verbose = 0;
242 switch(fork()) {
243 case -1:
244 panic("Fork failed\n");
245 case 0:
246 break;
247 default:
248 exit(0);
249 }
250 }
251
252 char *buffer = new char[bufsize];
253 argc -= optind;
254 argv += optind;
255
256 if (argc-- == 0)
257 usage();
258
259 device = *argv++;
260
261 if (listening) {
262 if (argc)
263 usage();
264 } else {
265 if (argc != 1)
266 usage();
267
268 host = *argv;
269 }
270
271 char errbuf[PCAP_ERRBUF_SIZE];
272 memset(errbuf, 0, sizeof errbuf);
273 pcap_t *pcap = pcap_open_live(device, 1500, 1, -1, errbuf);
274 if (pcap == NULL)
275 panic("pcap_open_live failed: %s\n", errbuf);
276
277 if (filter) {
278 bpf_program program;
279 bpf_u_int32 localnet, netmask;
280 if (pcap_lookupnet(device, &localnet, &netmask, errbuf) == -1) {
281 DPRINTF("pcap_lookupnet failed: %s\n", errbuf);
282 netmask = 0xffffff00;
283 }
284
285 if (pcap_compile(pcap, &program, filter, 1, netmask) == -1)
286 panic("pcap_compile failed, invalid filter:\n%s\n", filter);
287
288 if (pcap_setfilter(pcap, &program) == -1)
289 panic("pcap_setfilter failed\n");
290 }
291
292 eth_t *ethernet = eth_open(device);
293 if (!ethernet)
294 panic("cannot open the ethernet device for writing\n");
295
296 pollfd pfds[3];
297 pfds[0].fd = Socket(true);
298 pfds[0].events = POLLIN;
299 pfds[0].revents = 0;
300
301 if (listening)
302 Listen(pfds[0].fd, port);
303 else
304 Connect(pfds[0].fd, host, port);
305
306 pfds[1].fd = pcap_fileno(pcap);
307 pfds[1].events = POLLIN;
308 pfds[1].revents = 0;
309
310 pfds[2].fd = 0;
311 pfds[2].events = POLLIN|POLLERR;
312 pfds[2].revents = 0;
313
314 pollfd *listen_pfd = listening ? &pfds[0] : NULL;
315 pollfd *tap_pfd = &pfds[1];
316 pollfd *client_pfd = listening ? NULL : &pfds[0];
317 int npfds = 2;
318
319 int32_t buffer_offset = 0;
320 int32_t data_len = 0;
321
322 DPRINTF("Begin poll loop\n");
323 while (!quit) {
324 int ret = ::poll(pfds, npfds, INFTIM);
325 if (ret < 0)
326 continue;
327
328 if (listen_pfd && listen_pfd->revents) {
329 if (listen_pfd->revents & POLLIN) {
330 int fd = Accept(listen_pfd->fd, false);
331 if (client_pfd) {
332 DPRINTF("Connection rejected\n");
333 close(fd);
334 } else {
335 DPRINTF("Connection accepted\n");
336 client_pfd = &pfds[2];
337 client_pfd->fd = fd;
338 npfds++;
339 }
340 }
341 listen_pfd->revents = 0;
342 }
343
344 if (tap_pfd && tap_pfd->revents) {
345 if (tap_pfd->revents & POLLIN) {
346 pcap_pkthdr hdr;
347 const u_char *data = pcap_next(pcap, &hdr);
348 if (data && client_pfd) {
349 DPRINTF("Received packet from ethernet len=%d\n", hdr.len);
350 DDUMP(data, hdr.len);
351 u_int32_t len = htonl(hdr.len);
352 write(client_pfd->fd, &len, sizeof(len));
353 write(client_pfd->fd, data, hdr.len);
354 }
355 }
356
357 tap_pfd->revents = 0;
358 }
359
360 if (client_pfd && client_pfd->revents) {
361 if (client_pfd->revents & POLLIN) {
362 if (buffer_offset < data_len + sizeof(u_int32_t)) {
363 int len = read(client_pfd->fd, buffer + buffer_offset,
364 bufsize - buffer_offset);
365
366 if (len <= 0) {
367 perror("read");
368 goto error;
369 }
370
371 buffer_offset += len;
372 if (data_len == 0)
373 data_len = ntohl(*(u_int32_t *)buffer);
374
375 DPRINTF("Received data from peer: len=%d buffer_offset=%d "
376 "data_len=%d\n", len, buffer_offset, data_len);
377 }
378
379 while (data_len != 0 &&
380 buffer_offset >= data_len + sizeof(u_int32_t)) {
381 char *data = buffer + sizeof(u_int32_t);
382 eth_send(ethernet, data, data_len);
383 DPRINTF("Sent packet to ethernet len = %d\n", data_len);
384 DDUMP(data, data_len);
385
386 buffer_offset -= data_len + sizeof(u_int32_t);
387 if (buffer_offset > 0 && data_len > 0) {
388 memmove(buffer, data + data_len, buffer_offset);
389 data_len = ntohl(*(u_int32_t *)buffer);
390 } else
391 data_len = 0;
392 }
393 }
394
395 if (client_pfd->revents & POLLERR) {
396 error:
397 DPRINTF("Error on client socket\n");
398 close(client_pfd->fd);
399 client_pfd = NULL;
400
401 if (listening)
402 npfds--;
403 else {
404 DPRINTF("Calling it quits because of poll error\n");
405 quit = true;
406 }
407 }
408
409 if (client_pfd)
410 client_pfd->revents = 0;
411 }
412 }
413
414 delete [] buffer;
415 pcap_close(pcap);
416 eth_close(ethernet);
417 if (listen_pfd)
418 close(listen_pfd->fd);
419
420 if (client_pfd)
421 close(client_pfd->fd);
422
423 return 0;
424}