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 |
|
|
} |