/[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 12 - (hide annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 40014 byte(s)
make working copy

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

  ViewVC Help
Powered by ViewVC 1.1.26