/[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

Contents of /trunk/net_io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 40014 byte(s)
make working copy

1 /*
2 * Cisco router) 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 /* 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 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 /* 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 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 netio_filter_unbind(nio,NETIO_FILTER_DIR_BOTH);
1347
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 netio_desc_t *nio = rxl->nio;
1465 ssize_t pkt_len;
1466
1467 while(rxl->running) {
1468 pkt_len = netio_recv(nio,nio->rx_pkt,sizeof(nio->rx_pkt));
1469
1470 if (pkt_len > 0)
1471 rxl->rx_handler(nio,nio->rx_pkt,pkt_len,rxl->arg1,rxl->arg2);
1472 }
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 tv.tv_usec = 20 * 1000; /* 200 ms */
1523 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 nio = rxl->nio;
1536
1537 if ((fd = netio_get_fd(nio)) == -1)
1538 continue;
1539
1540 if (FD_ISSET(fd,&rfds)) {
1541 pkt_len = netio_recv(nio,nio->rx_pkt,sizeof(nio->rx_pkt));
1542
1543 if (pkt_len > 0)
1544 rxl->rx_handler(nio,nio->rx_pkt,pkt_len,rxl->arg1,rxl->arg2);
1545 }
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