/[dynamips]/upstream/dynamips-0.2.5/net_io.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.5/net_io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Sat Oct 6 16:01:44 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 39509 byte(s)
import 0.2.5 from upstream

1 /*
2 * Cisco 7200 (Predator) simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Network Input/Output Abstraction Layer.
6 */
7
8 /* By default, Cygwin supports only 64 FDs with select()! */
9 #ifdef __CYGWIN__
10 #define FD_SETSIZE 1024
11 #endif
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdarg.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <signal.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22 #include <time.h>
23 #include <sys/time.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <sys/wait.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <netdb.h>
33 #include <pthread.h>
34
35 #ifdef __linux__
36 #include <net/if.h>
37 #include <linux/if_tun.h>
38 #endif
39
40 #include "registry.h"
41 #include "net.h"
42 #include "net_io.h"
43 #include "net_io_filter.h"
44
45 /* Free a NetIO descriptor */
46 static int netio_free(void *data,void *arg);
47
48 /* NIO RX listener */
49 static pthread_mutex_t netio_rxl_mutex = PTHREAD_MUTEX_INITIALIZER;
50 static pthread_mutex_t netio_rxq_mutex = PTHREAD_MUTEX_INITIALIZER;
51 static struct netio_rx_listener *netio_rxl_list = NULL;
52 static struct netio_rx_listener *netio_rxl_add_list = NULL;
53 static netio_desc_t *netio_rxl_remove_list = NULL;
54 static pthread_t netio_rxl_thread;
55 static pthread_cond_t netio_rxl_cond;
56
57 #define NETIO_RXL_LOCK() pthread_mutex_lock(&netio_rxl_mutex);
58 #define NETIO_RXL_UNLOCK() pthread_mutex_unlock(&netio_rxl_mutex);
59
60 #define NETIO_RXQ_LOCK() pthread_mutex_lock(&netio_rxq_mutex);
61 #define NETIO_RXQ_UNLOCK() pthread_mutex_unlock(&netio_rxq_mutex);
62
63 /* NetIO type */
64 typedef struct {
65 char *name;
66 char *desc;
67 }netio_type_t;
68
69 /* NETIO types (must follow the enum definition) */
70 static netio_type_t netio_types[NETIO_TYPE_MAX] = {
71 { "unix" , "UNIX local sockets" },
72 { "vde" , "Virtual Distributed Ethernet / UML switch" },
73 { "tap" , "Linux/FreeBSD TAP device" },
74 { "udp" , "UDP sockets" },
75 { "tcp_cli" , "TCP client" },
76 { "tcp_ser" , "TCP server" },
77 #ifdef LINUX_ETH
78 { "linux_eth" , "Linux Ethernet device" },
79 #endif
80 #ifdef GEN_ETH
81 { "gen_eth" , "Generic Ethernet device (PCAP)" },
82 #endif
83 { "fifo" , "FIFO (intra-hypervisor)" },
84 { "null" , "Null device" },
85 };
86
87 /* Get NETIO type given a description */
88 int netio_get_type(char *type)
89 {
90 int i;
91
92 for(i=0;i<NETIO_TYPE_MAX;i++)
93 if (!strcmp(type,netio_types[i].name))
94 return(i);
95
96 return(-1);
97 }
98
99 /* Show the NETIO types */
100 void netio_show_types(void)
101 {
102 int i;
103
104 printf("Available NETIO types:\n");
105
106 for(i=0;i<NETIO_TYPE_MAX;i++)
107 printf(" * %-10s : %s\n",netio_types[i].name,netio_types[i].desc);
108
109 printf("\n");
110 }
111
112 /*
113 * =========================================================================
114 * Generic functions (abstraction layer)
115 * =========================================================================
116 */
117
118 /* Acquire a reference to NIO from registry (increment reference count) */
119 netio_desc_t *netio_acquire(char *name)
120 {
121 return(registry_find(name,OBJ_TYPE_NIO));
122 }
123
124 /* Release an NIO (decrement reference count) */
125 int netio_release(char *name)
126 {
127 return(registry_unref(name,OBJ_TYPE_NIO));
128 }
129
130 /* Record an NIO in registry */
131 static int netio_record(netio_desc_t *nio)
132 {
133 return(registry_add(nio->name,OBJ_TYPE_NIO,nio));
134 }
135
136 /* Create a new NetIO descriptor */
137 static netio_desc_t *netio_create(char *name)
138 {
139 netio_desc_t *nio;
140
141 if (!(nio = malloc(sizeof(*nio))))
142 return NULL;
143
144 /* setup as a NULL descriptor */
145 memset(nio,0,sizeof(*nio));
146 nio->type = NETIO_TYPE_NULL;
147
148 /* save name for registry */
149 if (!(nio->name = strdup(name))) {
150 free(nio);
151 return NULL;
152 }
153
154 return nio;
155 }
156
157 /* Delete a NetIO descriptor */
158 int netio_delete(char *name)
159 {
160 return(registry_delete_if_unused(name,OBJ_TYPE_NIO,netio_free,NULL));
161 }
162
163 /* Delete all NetIO descriptors */
164 int netio_delete_all(void)
165 {
166 return(registry_delete_type(OBJ_TYPE_NIO,netio_free,NULL));
167 }
168
169 /* Save the configuration of a NetIO descriptor */
170 void netio_save_config(netio_desc_t *nio,FILE *fd)
171 {
172 if (nio->save_cfg)
173 nio->save_cfg(nio,fd);
174 }
175
176 /* Save configurations of all NetIO descriptors */
177 static void netio_reg_save_config(registry_entry_t *entry,void *opt,int *err)
178 {
179 netio_save_config((netio_desc_t *)entry->data,(FILE *)opt);
180 }
181
182 void netio_save_config_all(FILE *fd)
183 {
184 registry_foreach_type(OBJ_TYPE_NIO,netio_reg_save_config,fd,NULL);
185 fprintf(fd,"\n");
186 }
187
188 /* Send a packet through a NetIO descriptor */
189 ssize_t netio_send(netio_desc_t *nio,void *pkt,size_t len)
190 {
191 int res;
192
193 if (!nio)
194 return(-1);
195
196 if (nio->debug) {
197 printf("NIO %s: sending a packet of %lu bytes:\n",nio->name,(u_long)len);
198 mem_dump(stdout,pkt,len);
199 }
200
201 /* Apply the TX filter */
202 if (nio->tx_filter != NULL) {
203 res = nio->tx_filter->pkt_handler(nio,pkt,len,nio->tx_filter_data);
204
205 if (res <= 0)
206 return(-1);
207 }
208
209 return(nio->send(nio->dptr,pkt,len));
210 }
211
212 /* Receive a packet through a NetIO descriptor */
213 ssize_t netio_recv(netio_desc_t *nio,void *pkt,size_t max_len)
214 {
215 ssize_t len;
216 int res;
217
218 if (!nio)
219 return(-1);
220
221 /* Receive the packet */
222 if ((len = nio->recv(nio->dptr,pkt,max_len)) <= 0)
223 return(-1);
224
225 if (nio->debug) {
226 printf("NIO %s: receiving a packet of %ld bytes:\n",nio->name,(long)len);
227 mem_dump(stdout,pkt,len);
228 }
229
230 /* Apply the RX filter */
231 if (nio->rx_filter != NULL) {
232 res = nio->rx_filter->pkt_handler(nio,pkt,len,nio->rx_filter_data);
233
234 if (res == NETIO_FILTER_ACTION_DROP)
235 return(-1);
236 }
237
238 return(len);
239 }
240
241 /* Get a NetIO FD */
242 int netio_get_fd(netio_desc_t *nio)
243 {
244 int fd = -1;
245
246 switch(nio->type) {
247 case NETIO_TYPE_UNIX:
248 fd = nio->u.nud.fd;
249 break;
250 case NETIO_TYPE_VDE:
251 fd = nio->u.nvd.data_fd;
252 break;
253 case NETIO_TYPE_TAP:
254 fd = nio->u.ntd.fd;
255 break;
256 case NETIO_TYPE_TCP_CLI:
257 case NETIO_TYPE_TCP_SER:
258 case NETIO_TYPE_UDP:
259 fd = nio->u.nid.fd;
260 break;
261 #ifdef LINUX_ETH
262 case NETIO_TYPE_LINUX_ETH:
263 fd = nio->u.nled.fd;
264 break;
265 #endif
266 }
267
268 return(fd);
269 }
270
271 /*
272 * =========================================================================
273 * UNIX sockets
274 * =========================================================================
275 */
276
277 /* Create an UNIX socket */
278 static int netio_unix_create_socket(netio_unix_desc_t *nud)
279 {
280 struct sockaddr_un local_sock;
281
282 if ((nud->fd = socket(AF_UNIX,SOCK_DGRAM,0)) == -1) {
283 perror("netio_unix: socket");
284 return(-1);
285 }
286
287 memset(&local_sock,0,sizeof(local_sock));
288 local_sock.sun_family = AF_UNIX;
289 strcpy(local_sock.sun_path,nud->local_filename);
290
291 if (bind(nud->fd,(struct sockaddr *)&local_sock,sizeof(local_sock)) == -1) {
292 perror("netio_unix: bind");
293 return(-1);
294 }
295
296 return(nud->fd);
297 }
298
299 /* Free a NetIO unix descriptor */
300 static void netio_unix_free(netio_unix_desc_t *nud)
301 {
302 if (nud->fd != -1)
303 close(nud->fd);
304
305 if (nud->local_filename) {
306 unlink(nud->local_filename);
307 free(nud->local_filename);
308 }
309 }
310
311 /* Allocate a new NetIO UNIX descriptor */
312 static int netio_unix_create(netio_unix_desc_t *nud,char *local,char *remote)
313 {
314 memset(nud,0,sizeof(*nud));
315 nud->fd = -1;
316
317 /* check lengths */
318 if ((strlen(local) >= sizeof(nud->remote_sock.sun_path)) ||
319 (strlen(remote) >= sizeof(nud->remote_sock.sun_path)))
320 goto nomem_error;
321
322 if (!(nud->local_filename = strdup(local)))
323 goto nomem_error;
324
325 if (netio_unix_create_socket(nud) == -1)
326 return(-1);
327
328 /* prepare the remote info */
329 nud->remote_sock.sun_family = AF_UNIX;
330 strcpy(nud->remote_sock.sun_path,remote);
331 return(0);
332
333 nomem_error:
334 fprintf(stderr,"netio_unix_create: "
335 "invalid file size or insufficient memory\n");
336 return(-1);
337 }
338
339 /* Write a packet to an UNIX socket */
340 static ssize_t netio_unix_send(netio_unix_desc_t *nud,void *pkt,size_t pkt_len)
341 {
342 return(sendto(nud->fd,pkt,pkt_len,0,
343 (struct sockaddr *)&nud->remote_sock,
344 sizeof(&nud->remote_sock)));
345 }
346
347 /* Receive a packet from an UNIX socket */
348 static ssize_t netio_unix_recv(netio_unix_desc_t *nud,void *pkt,size_t max_len)
349 {
350 return(recvfrom(nud->fd,pkt,max_len,0,NULL,NULL));
351 }
352
353 /* Save the NIO configuration */
354 static void netio_unix_save_cfg(netio_desc_t *nio,FILE *fd)
355 {
356 netio_unix_desc_t *nud = nio->dptr;
357 fprintf(fd,"nio create_unix %s %s %s\n",
358 nio->name,nud->local_filename,nud->remote_sock.sun_path);
359 }
360
361 /* Create a new NetIO descriptor with UNIX method */
362 netio_desc_t *netio_desc_create_unix(char *nio_name,char *local,char *remote)
363 {
364 netio_desc_t *nio;
365
366 if (!(nio = netio_create(nio_name)))
367 return NULL;
368
369 if (netio_unix_create(&nio->u.nud,local,remote) == -1) {
370 netio_free(nio,NULL);
371 return NULL;
372 }
373
374 nio->type = NETIO_TYPE_UNIX;
375 nio->send = (void *)netio_unix_send;
376 nio->recv = (void *)netio_unix_recv;
377 nio->save_cfg = netio_unix_save_cfg;
378 nio->dptr = &nio->u.nud;
379
380 if (netio_record(nio) == -1) {
381 netio_free(nio,NULL);
382 return NULL;
383 }
384
385 return nio;
386 }
387
388 /*
389 * =========================================================================
390 * VDE (Virtual Distributed Ethernet) interface
391 * =========================================================================
392 */
393
394 /* Free a NetIO VDE descriptor */
395 static void netio_vde_free(netio_vde_desc_t *nvd)
396 {
397 if (nvd->data_fd != -1)
398 close(nvd->data_fd);
399
400 if (nvd->ctrl_fd != -1)
401 close(nvd->ctrl_fd);
402
403 if (nvd->local_filename) {
404 unlink(nvd->local_filename);
405 free(nvd->local_filename);
406 }
407 }
408
409 /* Create a new NetIO VDE descriptor */
410 static int netio_vde_create(netio_vde_desc_t *nvd,char *control,char *local)
411 {
412 struct sockaddr_un ctrl_sock,tst;
413 struct vde_request_v3 req;
414 ssize_t len;
415 int res;
416
417 memset(nvd,0,sizeof(*nvd));
418 nvd->ctrl_fd = nvd->data_fd = -1;
419
420 if ((strlen(control) >= sizeof(ctrl_sock.sun_path)) ||
421 (strlen(local) >= sizeof(nvd->remote_sock.sun_path))) {
422 fprintf(stderr,"netio_vde_create: bad filenames specified\n");
423 return(-1);
424 }
425
426 /* Copy the local filename */
427 if (!(nvd->local_filename = strdup(local))) {
428 fprintf(stderr,"netio_vde_create: insufficient memory\n");
429 return(-1);
430 }
431
432 /* Connect to the VDE switch controller */
433 nvd->ctrl_fd = socket(AF_UNIX,SOCK_STREAM,0);
434 if (nvd->ctrl_fd < 0) {
435 perror("netio_vde_create: socket(control)");
436 return(-1);
437 }
438
439 memset(&ctrl_sock,0,sizeof(ctrl_sock));
440 ctrl_sock.sun_family = AF_UNIX;
441 strcpy(ctrl_sock.sun_path,control);
442
443 res = connect(nvd->ctrl_fd,(struct sockaddr *)&ctrl_sock,
444 sizeof(ctrl_sock));
445
446 if (res < 0) {
447 perror("netio_vde_create: connect(control)");
448 return(-1);
449 }
450
451 tst.sun_family = AF_UNIX;
452 strcpy(tst.sun_path,local);
453
454 /* Create the data connection */
455 nvd->data_fd = socket(AF_UNIX,SOCK_DGRAM,0);
456 if (nvd->data_fd < 0) {
457 perror("netio_vde_create: socket(data)");
458 return(-1);
459 }
460
461 if (bind(nvd->data_fd,(struct sockaddr *)&tst,sizeof(tst))<0) {
462 perror("netio_vde_create: bind(data)");
463 return(-1);
464 }
465
466 /* Now, process to registration */
467 memset(&req,0,sizeof(req));
468 req.sock.sun_family = AF_UNIX;
469 strcpy(req.sock.sun_path,local);
470 req.magic = VDE_SWITCH_MAGIC;
471 req.version = VDE_SWITCH_VERSION;
472 req.type = VDE_REQ_NEW_CONTROL;
473
474 len = write(nvd->ctrl_fd,&req,sizeof(req));
475 if (len != sizeof(req)) {
476 perror("netio_vde_create: write(req)");
477 return(-1);
478 }
479
480 /* Read the remote socket descriptor */
481 len = read(nvd->ctrl_fd,&nvd->remote_sock,sizeof(nvd->remote_sock));
482 if (len != sizeof(nvd->remote_sock)) {
483 perror("netio_vde_create: read(req)");
484 return(-1);
485 }
486
487 return(0);
488 }
489
490 /* Write a packet to a VDE data socket */
491 static ssize_t netio_vde_send(netio_vde_desc_t *nvd,void *pkt,size_t pkt_len)
492 {
493 return(sendto(nvd->data_fd,pkt,pkt_len,0,
494 (struct sockaddr *)&nvd->remote_sock,
495 sizeof(nvd->remote_sock)));
496 }
497
498 /* Receive a packet from a VDE socket */
499 static ssize_t netio_vde_recv(netio_vde_desc_t *nvd,void *pkt,size_t max_len)
500 {
501 return(recvfrom(nvd->data_fd,pkt,max_len,0,NULL,NULL));
502 }
503
504 /* Save the NIO configuration */
505 static void netio_vde_save_cfg(netio_desc_t *nio,FILE *fd)
506 {
507 netio_vde_desc_t *nvd = nio->dptr;
508 fprintf(fd,"nio create_vde %s %s %s\n",
509 nio->name,nvd->remote_sock.sun_path,nvd->local_filename);
510 }
511
512 /* Create a new NetIO descriptor with VDE method */
513 netio_desc_t *netio_desc_create_vde(char *nio_name,char *control,char *local)
514 {
515 netio_vde_desc_t *nvd;
516 netio_desc_t *nio;
517
518 if (!(nio = netio_create(nio_name)))
519 return NULL;
520
521 nvd = &nio->u.nvd;
522
523 if (netio_vde_create(nvd,control,local) == -1) {
524 netio_free(nio,NULL);
525 return NULL;
526 }
527
528 nio->type = NETIO_TYPE_VDE;
529 nio->send = (void *)netio_vde_send;
530 nio->recv = (void *)netio_vde_recv;
531 nio->save_cfg = netio_vde_save_cfg;
532 nio->dptr = &nio->u.nvd;
533
534 if (netio_record(nio) == -1) {
535 netio_free(nio,NULL);
536 return NULL;
537 }
538
539 return nio;
540 }
541
542 /*
543 * =========================================================================
544 * TAP devices
545 * =========================================================================
546 */
547
548 /* Free a NetIO TAP descriptor */
549 static void netio_tap_free(netio_tap_desc_t *ntd)
550 {
551 if (ntd->fd != -1)
552 close(ntd->fd);
553 }
554
555 /* Open a TAP device */
556 static int netio_tap_open(char *tap_devname)
557 {
558 #ifdef __linux__
559 struct ifreq ifr;
560 int fd,err;
561
562 if ((fd = open("/dev/net/tun",O_RDWR)) < 0)
563 return(-1);
564
565 memset(&ifr,0,sizeof(ifr));
566
567 /* Flags: IFF_TUN - TUN device (no Ethernet headers)
568 * IFF_TAP - TAP device
569 *
570 * IFF_NO_PI - Do not provide packet information
571 */
572 ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
573 if (*tap_devname)
574 strncpy(ifr.ifr_name,tap_devname,IFNAMSIZ);
575
576 if ((err = ioctl(fd,TUNSETIFF,(void *)&ifr)) < 0) {
577 close(fd);
578 return err;
579 }
580
581 strcpy(tap_devname,ifr.ifr_name);
582 return(fd);
583 #else
584 int i,fd = -1;
585
586 if (*tap_devname) {
587 fd = open(tap_devname,O_RDWR);
588 } else {
589 for(i=0;i<16;i++) {
590 snprintf(tap_devname,NETIO_DEV_MAXLEN,"/dev/tap%d",i);
591
592 if ((fd = open(tap_devname,O_RDWR)) >= 0)
593 break;
594 }
595 }
596
597 return(fd);
598 #endif
599 }
600
601 /* Allocate a new NetIO TAP descriptor */
602 static int netio_tap_create(netio_tap_desc_t *ntd,char *tap_name)
603 {
604 if (strlen(tap_name) >= NETIO_DEV_MAXLEN) {
605 fprintf(stderr,"netio_tap_create: bad TAP device string specified.\n");
606 return(-1);
607 }
608
609 memset(ntd,0,sizeof(*ntd));
610 strcpy(ntd->filename,tap_name);
611 ntd->fd = netio_tap_open(ntd->filename);
612
613 if (ntd->fd == -1) {
614 fprintf(stderr,"netio_tap_create: unable to open TAP device %s (%s)\n",
615 tap_name,strerror(errno));
616 return(-1);
617 }
618
619 return(0);
620 }
621
622 /* Write a packet to a TAP device */
623 static ssize_t netio_tap_send(netio_tap_desc_t *ntd,void *pkt,size_t pkt_len)
624 {
625 return(write(ntd->fd,pkt,pkt_len));
626 }
627
628 /* Receive a packet through a TAP device */
629 static ssize_t netio_tap_recv(netio_tap_desc_t *ntd,void *pkt,size_t max_len)
630 {
631 return(read(ntd->fd,pkt,max_len));
632 }
633
634 /* Save the NIO configuration */
635 static void netio_tap_save_cfg(netio_desc_t *nio,FILE *fd)
636 {
637 netio_tap_desc_t *ntd = nio->dptr;
638 fprintf(fd,"nio create_tap %s %s\n",nio->name,ntd->filename);
639 }
640
641 /* Create a new NetIO descriptor with TAP method */
642 netio_desc_t *netio_desc_create_tap(char *nio_name,char *tap_name)
643 {
644 netio_tap_desc_t *ntd;
645 netio_desc_t *nio;
646
647 if (!(nio = netio_create(nio_name)))
648 return NULL;
649
650 ntd = &nio->u.ntd;
651
652 if (netio_tap_create(ntd,tap_name) == -1) {
653 netio_free(nio,NULL);
654 return NULL;
655 }
656
657 nio->type = NETIO_TYPE_TAP;
658 nio->send = (void *)netio_tap_send;
659 nio->recv = (void *)netio_tap_recv;
660 nio->save_cfg = netio_tap_save_cfg;
661 nio->dptr = &nio->u.ntd;
662
663 if (netio_record(nio) == -1) {
664 netio_free(nio,NULL);
665 return NULL;
666 }
667
668 return nio;
669 }
670
671 /*
672 * =========================================================================
673 * TCP sockets
674 * =========================================================================
675 */
676
677 /* Free a NetIO TCP descriptor */
678 static void netio_tcp_free(netio_inet_desc_t *nid)
679 {
680 if (nid->fd != -1)
681 close(nid->fd);
682 }
683
684 /*
685 * very simple protocol to send packets over tcp
686 * 32 bits in network format - size of packet, then packet itself and so on.
687 */
688 static ssize_t netio_tcp_send(netio_inet_desc_t *nid,void *pkt,size_t pkt_len)
689 {
690 u_long l = htonl(pkt_len);
691
692 if (write(nid->fd,&l,sizeof(l)) == -1)
693 return(-1);
694
695 return(write(nid->fd,pkt,pkt_len));
696 }
697
698 static ssize_t netio_tcp_recv(netio_inet_desc_t *nid,void *pkt,size_t max_len)
699 {
700 u_long l;
701
702 if (read(nid->fd,&l,sizeof(l)) != sizeof(l))
703 return(-1);
704
705 if (ntohl(l) > max_len)
706 return(-1);
707
708 return(read(nid->fd,pkt,ntohl(l)));
709 }
710
711 static int netio_tcp_cli_create(netio_inet_desc_t *nid,char *host,char *port)
712 {
713 struct sockaddr_in serv;
714 struct servent *sp;
715 struct hostent *hp;
716
717 if ((nid->fd = socket(PF_INET,SOCK_STREAM,0)) < 0) {
718 perror("netio_tcp_cli_create: socket");
719 return(-1);
720 }
721
722 memset(&serv,0,sizeof(serv));
723 serv.sin_family = AF_INET;
724
725 if (atoi(port) == 0) {
726 if (!(sp = getservbyname(port,"tcp"))) {
727 fprintf(stderr,"netio_tcp_cli_create: port %s is neither "
728 "number not service %s\n",port,strerror(errno));
729 close(nid->fd);
730 return(-1);
731 }
732 serv.sin_port = sp->s_port;
733 } else
734 serv.sin_port = htons(atoi(port));
735
736 if (inet_addr(host) == INADDR_NONE) {
737 if (!(hp = gethostbyname(host))) {
738 fprintf(stderr,"netio_tcp_cli_create: no host %s\n",host);
739 close(nid->fd);
740 return(-1);
741 }
742 serv.sin_addr.s_addr = *hp->h_addr;
743 } else
744 serv.sin_addr.s_addr = inet_addr(host);
745
746 if (connect(nid->fd,(struct sockaddr *)&serv,sizeof(serv)) < 0) {
747 fprintf(stderr,"netio_tcp_cli_create: connect to %s:%s failed %s\n",
748 host,port,strerror(errno));
749 close(nid->fd);
750 return(-1);
751 }
752 return(0);
753 }
754
755 /* Create a new NetIO descriptor with TCP_CLI method */
756 netio_desc_t *netio_desc_create_tcp_cli(char *nio_name,char *host,char *port)
757 {
758 netio_desc_t *nio;
759
760 if (!(nio = netio_create(nio_name)))
761 return NULL;
762
763 if (netio_tcp_cli_create(&nio->u.nid,host,port) < 0) {
764 netio_free(nio,NULL);
765 return NULL;
766 }
767
768 nio->type = NETIO_TYPE_TCP_CLI;
769 nio->send = (void *)netio_tcp_send;
770 nio->recv = (void *)netio_tcp_recv;
771 nio->dptr = &nio->u.nid;
772
773 if (netio_record(nio) == -1) {
774 netio_free(nio,NULL);
775 return NULL;
776 }
777
778 return nio;
779 }
780
781 static int netio_tcp_ser_create(netio_inet_desc_t *nid,char *port)
782 {
783 struct sockaddr_in serv;
784 struct servent *sp;
785 int sock_fd;
786
787 if ((sock_fd = socket(PF_INET,SOCK_STREAM,0)) < 0) {
788 perror("netio_tcp_cli_create: socket\n");
789 return(-1);
790 }
791
792 memset(&serv,0,sizeof(serv));
793 serv.sin_family = AF_INET;
794 serv.sin_addr.s_addr = htonl(INADDR_ANY);
795
796 if (atoi(port) == 0) {
797 if (!(sp = getservbyname(port,"tcp"))) {
798 fprintf(stderr,"netio_tcp_ser_create: port %s is neither "
799 "number not service %s\n",port,strerror(errno));
800 close(sock_fd);
801 return(-1);
802 }
803 serv.sin_port = sp->s_port;
804 } else
805 serv.sin_port = htons(atoi(port));
806
807 if (bind(sock_fd,(struct sockaddr *)&serv,sizeof(serv)) < 0) {
808 fprintf(stderr,"netio_tcp_ser_create: bind %s failed %s\n",
809 port,strerror(errno));
810 close(sock_fd);
811 return(-1);
812 }
813
814 if (listen(sock_fd,1) < 0) {
815 fprintf(stderr,"netio_tcp_ser_create: listen %s failed %s\n",
816 port,strerror(errno));
817 close(sock_fd);
818 return(-1);
819 }
820
821 fprintf(stderr,"Waiting connection on port %s...\n",port);
822
823 if ((nid->fd = accept(sock_fd,NULL,NULL)) < 0) {
824 fprintf(stderr,"netio_tcp_ser_create: accept %s failed %s\n",
825 port,strerror(errno));
826 close(sock_fd);
827 return(-1);
828 }
829
830 fprintf(stderr,"Connected\n");
831
832 close(sock_fd);
833 return(0);
834 }
835
836 /* Create a new NetIO descriptor with TCP_SER method */
837 netio_desc_t *netio_desc_create_tcp_ser(char *nio_name,char *port)
838 {
839 netio_desc_t *nio;
840
841 if (!(nio = netio_create(nio_name)))
842 return NULL;
843
844 if (netio_tcp_ser_create(&nio->u.nid,port) == -1) {
845 netio_free(nio,NULL);
846 return NULL;
847 }
848
849 nio->type = NETIO_TYPE_TCP_SER;
850 nio->send = (void *)netio_tcp_send;
851 nio->recv = (void *)netio_tcp_recv;
852 nio->dptr = &nio->u.nid;
853
854 if (netio_record(nio) == -1) {
855 netio_free(nio,NULL);
856 return NULL;
857 }
858
859 return nio;
860 }
861
862 /*
863 * =========================================================================
864 * UDP sockets
865 * =========================================================================
866 */
867
868 /* Free a NetIO UDP descriptor */
869 static void netio_udp_free(netio_inet_desc_t *nid)
870 {
871 if (nid->remote_host) {
872 free(nid->remote_host);
873 nid->remote_host = NULL;
874 }
875
876 if (nid->fd != -1)
877 close(nid->fd);
878 }
879
880 /* Write a packet to an UDP socket */
881 static ssize_t netio_udp_send(netio_inet_desc_t *nid,void *pkt,size_t pkt_len)
882 {
883 return(send(nid->fd,pkt,pkt_len,0));
884 }
885
886 /* Receive a packet from an UDP socket */
887 static ssize_t netio_udp_recv(netio_inet_desc_t *nid,void *pkt,size_t max_len)
888 {
889 return(recvfrom(nid->fd,pkt,max_len,0,NULL,NULL));
890 }
891
892 /* Save the NIO configuration */
893 static void netio_udp_save_cfg(netio_desc_t *nio,FILE *fd)
894 {
895 netio_inet_desc_t *nid = nio->dptr;
896 fprintf(fd,"nio create_udp %s %d %s %d\n",
897 nio->name,nid->local_port,nid->remote_host,nid->remote_port);
898 }
899
900 /* Create a new NetIO descriptor with UDP method */
901 netio_desc_t *netio_desc_create_udp(char *nio_name,int local_port,
902 char *remote_host,int remote_port)
903 {
904 netio_inet_desc_t *nid;
905 netio_desc_t *nio;
906
907 if (!(nio = netio_create(nio_name)))
908 return NULL;
909
910 nid = &nio->u.nid;
911 nid->local_port = local_port;
912 nid->remote_port = remote_port;
913
914 if (!(nid->remote_host = strdup(remote_host))) {
915 fprintf(stderr,"netio_desc_create_udp: insufficient memory\n");
916 goto error;
917 }
918
919 if ((nid->fd = udp_connect(local_port,remote_host,remote_port)) < 0) {
920 fprintf(stderr,"netio_desc_create_udp: unable to connect to %s:%d\n",
921 remote_host,remote_port);
922 goto error;
923 }
924
925 nio->type = NETIO_TYPE_UDP;
926 nio->send = (void *)netio_udp_send;
927 nio->recv = (void *)netio_udp_recv;
928 nio->save_cfg = netio_udp_save_cfg;
929 nio->dptr = &nio->u.nid;
930
931 if (netio_record(nio) == -1)
932 goto error;
933
934 return nio;
935
936 error:
937 netio_free(nio,NULL);
938 return NULL;
939 }
940
941 /*
942 * =========================================================================
943 * Linux RAW Ethernet driver
944 * =========================================================================
945 */
946 #ifdef LINUX_ETH
947 /* Free a NetIO raw ethernet descriptor */
948 static void netio_lnxeth_free(netio_lnxeth_desc_t *nled)
949 {
950 if (nled->fd != -1)
951 close(nled->fd);
952 }
953
954 /* Write a packet to a raw Ethernet socket */
955 static ssize_t netio_lnxeth_send(netio_lnxeth_desc_t *nled,
956 void *pkt,size_t pkt_len)
957 {
958 return(lnx_eth_send(nled->fd,nled->dev_id,pkt,pkt_len));
959 }
960
961 /* Receive a packet from an raw Ethernet socket */
962 static ssize_t netio_lnxeth_recv(netio_lnxeth_desc_t *nled,
963 void *pkt,size_t max_len)
964 {
965 return(lnx_eth_recv(nled->fd,pkt,max_len));
966 }
967
968 /* Save the NIO configuration */
969 static void netio_lnxeth_save_cfg(netio_desc_t *nio,FILE *fd)
970 {
971 netio_lnxeth_desc_t *nled = nio->dptr;
972 fprintf(fd,"nio create_linux_eth %s %s\n",nio->name,nled->dev_name);
973 }
974
975 /* Create a new NetIO descriptor with raw Ethernet method */
976 netio_desc_t *netio_desc_create_lnxeth(char *nio_name,char *dev_name)
977 {
978 netio_lnxeth_desc_t *nled;
979 netio_desc_t *nio;
980
981 if (!(nio = netio_create(nio_name)))
982 return NULL;
983
984 nled = &nio->u.nled;
985
986 if (strlen(dev_name) >= NETIO_DEV_MAXLEN) {
987 fprintf(stderr,"netio_desc_create_lnxeth: bad Ethernet device string "
988 "specified.\n");
989 netio_free(nio,NULL);
990 return NULL;
991 }
992
993 strcpy(nled->dev_name,dev_name);
994
995 nled->fd = lnx_eth_init_socket(dev_name);
996 nled->dev_id = lnx_eth_get_dev_index(dev_name);
997
998 if (nled->fd < 0) {
999 netio_free(nio,NULL);
1000 return NULL;
1001 }
1002
1003 nio->type = NETIO_TYPE_LINUX_ETH;
1004 nio->send = (void *)netio_lnxeth_send;
1005 nio->recv = (void *)netio_lnxeth_recv;
1006 nio->save_cfg = netio_lnxeth_save_cfg;
1007 nio->dptr = &nio->u.nled;
1008
1009 if (netio_record(nio) == -1) {
1010 netio_free(nio,NULL);
1011 return NULL;
1012 }
1013
1014 return nio;
1015 }
1016 #endif /* LINUX_ETH */
1017
1018 /*
1019 * =========================================================================
1020 * Generic RAW Ethernet driver
1021 * =========================================================================
1022 */
1023 #ifdef GEN_ETH
1024 /* Free a NetIO raw ethernet descriptor */
1025 static void netio_geneth_free(netio_geneth_desc_t *nged)
1026 {
1027 gen_eth_close(nged->pcap_dev);
1028 }
1029
1030 /* Write a packet to an Ethernet device */
1031 static ssize_t netio_geneth_send(netio_geneth_desc_t *nged,
1032 void *pkt,size_t pkt_len)
1033 {
1034 return(gen_eth_send(nged->pcap_dev,pkt,pkt_len));
1035 }
1036
1037 /* Receive a packet from an Ethernet device */
1038 static ssize_t netio_geneth_recv(netio_geneth_desc_t *nged,
1039 void *pkt,size_t max_len)
1040 {
1041 return(gen_eth_recv(nged->pcap_dev,pkt,max_len));
1042 }
1043
1044 /* Save the NIO configuration */
1045 static void netio_geneth_save_cfg(netio_desc_t *nio,FILE *fd)
1046 {
1047 netio_geneth_desc_t *nged = nio->dptr;
1048 fprintf(fd,"nio create_gen_eth %s %s\n",nio->name,nged->dev_name);
1049 }
1050
1051 /* Create a new NetIO descriptor with generic raw Ethernet method */
1052 netio_desc_t *netio_desc_create_geneth(char *nio_name,char *dev_name)
1053 {
1054 netio_geneth_desc_t *nged;
1055 netio_desc_t *nio;
1056
1057 if (!(nio = netio_create(nio_name)))
1058 return NULL;
1059
1060 nged = &nio->u.nged;
1061
1062 if (strlen(dev_name) >= NETIO_DEV_MAXLEN) {
1063 fprintf(stderr,"netio_desc_create_geneth: bad Ethernet device string "
1064 "specified.\n");
1065 netio_free(nio,NULL);
1066 return NULL;
1067 }
1068
1069 strcpy(nged->dev_name,dev_name);
1070
1071 if (!(nged->pcap_dev = gen_eth_init(dev_name))) {
1072 netio_free(nio,NULL);
1073 return NULL;
1074 }
1075
1076 nio->type = NETIO_TYPE_GEN_ETH;
1077 nio->send = (void *)netio_geneth_send;
1078 nio->recv = (void *)netio_geneth_recv;
1079 nio->save_cfg = netio_geneth_save_cfg;
1080 nio->dptr = &nio->u.nged;
1081
1082 if (netio_record(nio) == -1) {
1083 netio_free(nio,NULL);
1084 return NULL;
1085 }
1086
1087 return nio;
1088 }
1089 #endif /* GEN_ETH */
1090
1091 /*
1092 * =========================================================================
1093 * FIFO Driver (intra-hypervisor communications)
1094 * =========================================================================
1095 */
1096
1097 /* Extract the first packet of the FIFO */
1098 static netio_fifo_pkt_t *netio_fifo_extract_pkt(netio_fifo_desc_t *nfd)
1099 {
1100 netio_fifo_pkt_t *p;
1101
1102 if (!(p = nfd->head))
1103 return NULL;
1104
1105 nfd->pkt_count--;
1106 nfd->head = p->next;
1107
1108 if (!nfd->head)
1109 nfd->last = NULL;
1110
1111 return p;
1112 }
1113
1114 /* Insert a packet into the FIFO (in tail) */
1115 static void netio_fifo_insert_pkt(netio_fifo_desc_t *nfd,netio_fifo_pkt_t *p)
1116 {
1117 pthread_mutex_lock(&nfd->lock);
1118
1119 nfd->pkt_count++;
1120 p->next = NULL;
1121
1122 if (nfd->last) {
1123 nfd->last->next = p;
1124 } else {
1125 nfd->head = p;
1126 }
1127
1128 nfd->last = p;
1129 pthread_mutex_unlock(&nfd->lock);
1130 }
1131
1132 /* Free the packet list */
1133 static void netio_fifo_free_pkt_list(netio_fifo_desc_t *nfd)
1134 {
1135 netio_fifo_pkt_t *p,*next;
1136
1137 for(p=nfd->head;p;p=next) {
1138 next = p->next;
1139 free(p);
1140 }
1141
1142 nfd->head = nfd->last = NULL;
1143 nfd->pkt_count = 0;
1144 }
1145
1146 /* Establish a cross-connect between two FIFO NetIO */
1147 int netio_fifo_crossconnect(netio_desc_t *a,netio_desc_t *b)
1148 {
1149 netio_fifo_desc_t *pa,*pb;
1150
1151 if ((a->type != NETIO_TYPE_FIFO) || (b->type != NETIO_TYPE_FIFO))
1152 return(-1);
1153
1154 pa = &a->u.nfd;
1155 pb = &b->u.nfd;
1156
1157 /* A => B */
1158 pthread_mutex_lock(&pa->endpoint_lock);
1159 pthread_mutex_lock(&pa->lock);
1160 pa->endpoint = pb;
1161 netio_fifo_free_pkt_list(pa);
1162 pthread_mutex_unlock(&pa->lock);
1163 pthread_mutex_unlock(&pa->endpoint_lock);
1164
1165 /* B => A */
1166 pthread_mutex_lock(&pb->endpoint_lock);
1167 pthread_mutex_lock(&pb->lock);
1168 pb->endpoint = pa;
1169 netio_fifo_free_pkt_list(pb);
1170 pthread_mutex_unlock(&pb->lock);
1171 pthread_mutex_unlock(&pb->endpoint_lock);
1172 return(0);
1173 }
1174
1175 /* Unbind an endpoint */
1176 static void netio_fifo_unbind_endpoint(netio_fifo_desc_t *nfd)
1177 {
1178 pthread_mutex_lock(&nfd->endpoint_lock);
1179 nfd->endpoint = NULL;
1180 pthread_mutex_unlock(&nfd->endpoint_lock);
1181 }
1182
1183 /* Free a NetIO FIFO descriptor */
1184 static void netio_fifo_free(netio_fifo_desc_t *nfd)
1185 {
1186 if (nfd->endpoint)
1187 netio_fifo_unbind_endpoint(nfd->endpoint);
1188
1189 netio_fifo_free_pkt_list(nfd);
1190 pthread_mutex_destroy(&nfd->lock);
1191 pthread_cond_destroy(&nfd->cond);
1192 }
1193
1194 /* Send a packet (to the endpoint FIFO) */
1195 static ssize_t netio_fifo_send(netio_fifo_desc_t *nfd,void *pkt,size_t pkt_len)
1196 {
1197 netio_fifo_pkt_t *p;
1198 size_t len;
1199
1200 pthread_mutex_lock(&nfd->endpoint_lock);
1201
1202 /* The cross-connect must have been established before */
1203 if (!nfd->endpoint)
1204 goto error;
1205
1206 /* Allocate a a new packet and insert it into the endpoint FIFO */
1207 len = sizeof(netio_fifo_pkt_t) + pkt_len;
1208 if (!(p = malloc(len)))
1209 goto error;
1210
1211 memcpy(p->pkt,pkt,pkt_len);
1212 p->pkt_len = pkt_len;
1213 netio_fifo_insert_pkt(nfd->endpoint,p);
1214 pthread_cond_signal(&nfd->endpoint->cond);
1215 pthread_mutex_unlock(&nfd->endpoint_lock);
1216 return(pkt_len);
1217
1218 error:
1219 pthread_mutex_unlock(&nfd->endpoint_lock);
1220 return(-1);
1221 }
1222
1223 /* Read a packet from the local FIFO queue */
1224 static ssize_t netio_fifo_recv(netio_fifo_desc_t *nfd,void *pkt,size_t max_len)
1225 {
1226 struct timespec ts;
1227 m_tmcnt_t expire;
1228 netio_fifo_pkt_t *p;
1229 size_t len = -1;
1230
1231 /* Wait for the endpoint to signal a new arriving packet */
1232 expire = m_gettime_usec() + 50000;
1233 ts.tv_sec = expire / 1000000;
1234 ts.tv_nsec = (expire % 1000000) * 1000;
1235
1236 pthread_mutex_lock(&nfd->lock);
1237 pthread_cond_timedwait(&nfd->cond,&nfd->lock,&ts);
1238
1239 /* Extract a packet from the list */
1240 p = netio_fifo_extract_pkt(nfd);
1241 pthread_mutex_unlock(&nfd->lock);
1242
1243 if (p) {
1244 len = m_min(p->pkt_len,max_len);
1245 memcpy(pkt,p->pkt,len);
1246 free(p);
1247 }
1248
1249 return(len);
1250 }
1251
1252 /* Create a new NetIO descriptor with FIFO method */
1253 netio_desc_t *netio_desc_create_fifo(char *nio_name)
1254 {
1255 netio_fifo_desc_t *nfd;
1256 netio_desc_t *nio;
1257
1258 if (!(nio = netio_create(nio_name)))
1259 return NULL;
1260
1261 nfd = &nio->u.nfd;
1262 pthread_mutex_init(&nfd->lock,NULL);
1263 pthread_mutex_init(&nfd->endpoint_lock,NULL);
1264 pthread_cond_init(&nfd->cond,NULL);
1265
1266 nio->type = NETIO_TYPE_FIFO;
1267 nio->send = (void *)netio_fifo_send;
1268 nio->recv = (void *)netio_fifo_recv;
1269 nio->dptr = nfd;
1270
1271 if (netio_record(nio) == -1) {
1272 netio_free(nio,NULL);
1273 return NULL;
1274 }
1275
1276 return nio;
1277 }
1278
1279 /*
1280 * =========================================================================
1281 * NULL Driver (does nothing, used for debugging)
1282 * =========================================================================
1283 */
1284 static ssize_t netio_null_send(void *null_ptr,void *pkt,size_t pkt_len)
1285 {
1286 return(pkt_len);
1287 }
1288
1289 static ssize_t netio_null_recv(void *null_ptr,void *pkt,size_t max_len)
1290 {
1291 usleep(200000);
1292 return(-1);
1293 }
1294
1295 static void netio_null_save_cfg(netio_desc_t *nio,FILE *fd)
1296 {
1297 fprintf(fd,"nio create_null %s\n",nio->name);
1298 }
1299
1300 /* Create a new NetIO descriptor with NULL method */
1301 netio_desc_t *netio_desc_create_null(char *nio_name)
1302 {
1303 netio_desc_t *nio;
1304
1305 if (!(nio = netio_create(nio_name)))
1306 return NULL;
1307
1308 nio->type = NETIO_TYPE_NULL;
1309 nio->send = (void *)netio_null_send;
1310 nio->recv = (void *)netio_null_recv;
1311 nio->save_cfg = netio_null_save_cfg;
1312 nio->dptr = NULL;
1313
1314 if (netio_record(nio) == -1) {
1315 netio_free(nio,NULL);
1316 return NULL;
1317 }
1318
1319 return nio;
1320 }
1321
1322 /* Free a NetIO descriptor */
1323 static int netio_free(void *data,void *arg)
1324 {
1325 netio_desc_t *nio = data;
1326
1327 if (nio) {
1328 netio_filter_unbind(nio,NETIO_FILTER_DIR_RX);
1329 netio_filter_unbind(nio,NETIO_FILTER_DIR_TX);
1330
1331 switch(nio->type) {
1332 case NETIO_TYPE_UNIX:
1333 netio_unix_free(&nio->u.nud);
1334 break;
1335 case NETIO_TYPE_VDE:
1336 netio_vde_free(&nio->u.nvd);
1337 break;
1338 case NETIO_TYPE_TAP:
1339 netio_tap_free(&nio->u.ntd);
1340 break;
1341 case NETIO_TYPE_TCP_CLI:
1342 case NETIO_TYPE_TCP_SER:
1343 netio_tcp_free(&nio->u.nid);
1344 break;
1345 case NETIO_TYPE_UDP:
1346 netio_udp_free(&nio->u.nid);
1347 break;
1348 #ifdef LINUX_ETH
1349 case NETIO_TYPE_LINUX_ETH:
1350 netio_lnxeth_free(&nio->u.nled);
1351 break;
1352 #endif
1353 #ifdef GEN_ETH
1354 case NETIO_TYPE_GEN_ETH:
1355 netio_geneth_free(&nio->u.nged);
1356 break;
1357 #endif
1358 case NETIO_TYPE_FIFO:
1359 netio_fifo_free(&nio->u.nfd);
1360 break;
1361 case NETIO_TYPE_NULL:
1362 break;
1363 default:
1364 fprintf(stderr,"NETIO: unknown descriptor type %u\n",nio->type);
1365 }
1366
1367 free(nio->name);
1368 free(nio);
1369 }
1370
1371 return(TRUE);
1372 }
1373
1374 /*
1375 * =========================================================================
1376 * RX Listeners
1377 * =========================================================================
1378 */
1379
1380 /* Find a RX listener */
1381 static inline struct netio_rx_listener *netio_rxl_find(netio_desc_t *nio)
1382 {
1383 struct netio_rx_listener *rxl;
1384
1385 for(rxl=netio_rxl_list;rxl;rxl=rxl->next)
1386 if (rxl->nio == nio)
1387 return rxl;
1388
1389 return NULL;
1390 }
1391
1392 /* Remove a NIO from the listener list */
1393 static int netio_rxl_remove_internal(netio_desc_t *nio)
1394 {
1395 struct netio_rx_listener *rxl;
1396 int res = -1;
1397
1398 if ((rxl = netio_rxl_find(nio))) {
1399 /* we suppress this NIO only when the ref count hits 0 */
1400 rxl->ref_count--;
1401
1402 if (!rxl->ref_count) {
1403 /* remove this listener from the double linked list */
1404 if (rxl->next)
1405 rxl->next->prev = rxl->prev;
1406
1407 if (rxl->prev)
1408 rxl->prev->next = rxl->next;
1409 else
1410 netio_rxl_list = rxl->next;
1411
1412 /* if this is non-FD NIO, wait for thread to terminate */
1413 if (netio_get_fd(rxl->nio) == -1) {
1414 rxl->running = FALSE;
1415 pthread_join(rxl->spec_thread,NULL);
1416 }
1417
1418 free(rxl);
1419 }
1420
1421 res = 0;
1422 }
1423
1424 return(res);
1425 }
1426
1427 /* Add a RXL listener to the listener list */
1428 static void netio_rxl_add_internal(struct netio_rx_listener *rxl)
1429 {
1430 struct netio_rx_listener *tmp;
1431
1432 if ((tmp = netio_rxl_find(rxl->nio))) {
1433 tmp->ref_count++;
1434 free(rxl);
1435 } else {
1436 rxl->prev = NULL;
1437 rxl->next = netio_rxl_list;
1438 if (rxl->next) rxl->next->prev = rxl;
1439 netio_rxl_list = rxl;
1440 }
1441 }
1442
1443 /* RX Listener dedicated thread (for non-FD NIO) */
1444 static void *netio_rxl_spec_thread(void *arg)
1445 {
1446 struct netio_rx_listener *rxl = arg;
1447 u_char pkt[NETIO_MAX_PKT_SIZE];
1448 ssize_t pkt_len;
1449
1450 while(rxl->running) {
1451 pkt_len = netio_recv(rxl->nio,pkt,sizeof(pkt));
1452
1453 if (pkt_len > 0)
1454 rxl->rx_handler(rxl->nio,pkt,pkt_len,rxl->arg1,rxl->arg2);
1455 }
1456
1457 return NULL;
1458 }
1459
1460 /* RX Listener General Thread */
1461 void *netio_rxl_gen_thread(void *arg)
1462 {
1463 struct netio_rx_listener *rxl;
1464 u_char pkt[NETIO_MAX_PKT_SIZE];
1465 ssize_t pkt_len;
1466 netio_desc_t *nio;
1467 struct timeval tv;
1468 int fd,fd_max,res;
1469 fd_set rfds;
1470
1471 for(;;) {
1472 NETIO_RXL_LOCK();
1473
1474 NETIO_RXQ_LOCK();
1475 /* Add the new waiting NIO to the active list */
1476 while(netio_rxl_add_list != NULL) {
1477 rxl = netio_rxl_add_list;
1478 netio_rxl_add_list = netio_rxl_add_list->next;
1479 netio_rxl_add_internal(rxl);
1480 }
1481
1482 /* Delete the NIO present in the remove list */
1483 while(netio_rxl_remove_list != NULL) {
1484 nio = netio_rxl_remove_list;
1485 netio_rxl_remove_list = netio_rxl_remove_list->rxl_next;
1486 netio_rxl_remove_internal(nio);
1487 }
1488
1489 pthread_cond_broadcast(&netio_rxl_cond);
1490 NETIO_RXQ_UNLOCK();
1491
1492 /* Build the FD set */
1493 FD_ZERO(&rfds);
1494 fd_max = -1;
1495 for(rxl=netio_rxl_list;rxl;rxl=rxl->next) {
1496 if ((fd = netio_get_fd(rxl->nio)) == -1)
1497 continue;
1498
1499 if (fd > fd_max) fd_max = fd;
1500 FD_SET(fd,&rfds);
1501 }
1502 NETIO_RXL_UNLOCK();
1503
1504 /* Wait for incoming packets */
1505 tv.tv_sec = 0;
1506 tv.tv_usec = 200 * 1000; /* 200 ms */
1507 res = select(fd_max+1,&rfds,NULL,NULL,&tv);
1508
1509 if (res == -1) {
1510 if (errno != EINTR)
1511 perror("netio_rxl_thread: select");
1512 continue;
1513 }
1514
1515 /* Examine active FDs and call user handlers */
1516 NETIO_RXL_LOCK();
1517
1518 for(rxl=netio_rxl_list;rxl;rxl=rxl->next) {
1519 if ((fd = netio_get_fd(rxl->nio)) == -1)
1520 continue;
1521
1522 if (FD_ISSET(fd,&rfds)) {
1523 pkt_len = netio_recv(rxl->nio,pkt,sizeof(pkt));
1524
1525 if (pkt_len > 0)
1526 rxl->rx_handler(rxl->nio,pkt,pkt_len,rxl->arg1,rxl->arg2);
1527 }
1528 }
1529
1530 NETIO_RXL_UNLOCK();
1531 }
1532
1533 return NULL;
1534 }
1535
1536 /* Add a RX listener in the listener list */
1537 int netio_rxl_add(netio_desc_t *nio,netio_rx_handler_t rx_handler,
1538 void *arg1,void *arg2)
1539 {
1540 struct netio_rx_listener *rxl;
1541
1542 NETIO_RXQ_LOCK();
1543
1544 if (!(rxl = malloc(sizeof(*rxl)))) {
1545 NETIO_RXQ_UNLOCK();
1546 fprintf(stderr,"netio_rxl_add: unable to create structure.\n");
1547 return(-1);
1548 }
1549
1550 memset(rxl,0,sizeof(*rxl));
1551 rxl->nio = nio;
1552 rxl->ref_count = 1;
1553 rxl->rx_handler = rx_handler;
1554 rxl->arg1 = arg1;
1555 rxl->arg2 = arg2;
1556 rxl->running = TRUE;
1557
1558 if ((netio_get_fd(rxl->nio) == -1) &&
1559 pthread_create(&rxl->spec_thread,NULL,netio_rxl_spec_thread,rxl))
1560 {
1561 NETIO_RXQ_UNLOCK();
1562 fprintf(stderr,"netio_rxl_add: unable to create specific thread.\n");
1563 free(rxl);
1564 return(-1);
1565 }
1566
1567 rxl->next = netio_rxl_add_list;
1568 netio_rxl_add_list = rxl;
1569
1570 pthread_cond_wait(&netio_rxl_cond,&netio_rxq_mutex);
1571 NETIO_RXQ_UNLOCK();
1572 return(0);
1573 }
1574
1575 /* Remove a NIO from the listener list */
1576 int netio_rxl_remove(netio_desc_t *nio)
1577 {
1578 NETIO_RXQ_LOCK();
1579 nio->rxl_next = netio_rxl_remove_list;
1580 netio_rxl_remove_list = nio;
1581 pthread_cond_wait(&netio_rxl_cond,&netio_rxq_mutex);
1582 NETIO_RXQ_UNLOCK();
1583 return(0);
1584 }
1585
1586 /* Initialize the RXL thread */
1587 int netio_rxl_init(void)
1588 {
1589 pthread_cond_init(&netio_rxl_cond,NULL);
1590
1591 if (pthread_create(&netio_rxl_thread,NULL,netio_rxl_gen_thread,NULL)) {
1592 perror("netio_rxl_init: pthread_create");
1593 return(-1);
1594 }
1595
1596 return(0);
1597 }

  ViewVC Help
Powered by ViewVC 1.1.26