/[dynamips]/trunk/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

Annotation of /trunk/net_io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (hide annotations)
Sat Oct 6 16:09:07 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC5/net_io.c
File MIME type: text/plain
File size: 39508 byte(s)
dynamips-0.2.6-RC5

1 dpavlin 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 dpavlin 3 tv.tv_usec = 20 * 1000; /* 200 ms */
1507 dpavlin 1 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