📄 net_io.c
字号:
/* * Cisco 7200 (Predator) simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * Network Input/Output Abstraction Layer. *//* By default, Cygwin supports only 64 FDs with select()! */#ifdef __CYGWIN__#define FD_SETSIZE 1024#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <unistd.h>#include <errno.h>#include <signal.h>#include <fcntl.h>#include <ctype.h>#include <time.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <pthread.h>#ifdef __linux__#include <net/if.h>#include <linux/if_tun.h>#endif#include "registry.h"#include "net.h"#include "net_io.h"#include "net_io_filter.h"/* Free a NetIO descriptor */static int netio_free(void *data,void *arg);/* NIO RX listener */static pthread_mutex_t netio_rxl_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_mutex_t netio_rxq_mutex = PTHREAD_MUTEX_INITIALIZER;static struct netio_rx_listener *netio_rxl_list = NULL;static struct netio_rx_listener *netio_rxl_add_list = NULL;static netio_desc_t *netio_rxl_remove_list = NULL;static pthread_t netio_rxl_thread;static pthread_cond_t netio_rxl_cond;#define NETIO_RXL_LOCK() pthread_mutex_lock(&netio_rxl_mutex);#define NETIO_RXL_UNLOCK() pthread_mutex_unlock(&netio_rxl_mutex);#define NETIO_RXQ_LOCK() pthread_mutex_lock(&netio_rxq_mutex);#define NETIO_RXQ_UNLOCK() pthread_mutex_unlock(&netio_rxq_mutex);/* NetIO type */typedef struct { char *name; char *desc;}netio_type_t;/* NETIO types (must follow the enum definition) */static netio_type_t netio_types[NETIO_TYPE_MAX] = { { "unix" , "UNIX local sockets" }, { "vde" , "Virtual Distributed Ethernet / UML switch" }, { "tap" , "Linux/FreeBSD TAP device" }, { "udp" , "UDP sockets" }, { "tcp_cli" , "TCP client" }, { "tcp_ser" , "TCP server" },#ifdef LINUX_ETH { "linux_eth" , "Linux Ethernet device" },#endif#ifdef GEN_ETH { "gen_eth" , "Generic Ethernet device (PCAP)" },#endif { "fifo" , "FIFO (intra-hypervisor)" }, { "null" , "Null device" },};/* Get NETIO type given a description */int netio_get_type(char *type){ int i; for(i=0;i<NETIO_TYPE_MAX;i++) if (!strcmp(type,netio_types[i].name)) return(i); return(-1);}/* Show the NETIO types */void netio_show_types(void){ int i; printf("Available NETIO types:\n"); for(i=0;i<NETIO_TYPE_MAX;i++) printf(" * %-10s : %s\n",netio_types[i].name,netio_types[i].desc); printf("\n");}/* * ========================================================================= * Generic functions (abstraction layer) * ========================================================================= *//* Acquire a reference to NIO from registry (increment reference count) */netio_desc_t *netio_acquire(char *name){ return(registry_find(name,OBJ_TYPE_NIO));}/* Release an NIO (decrement reference count) */int netio_release(char *name){ return(registry_unref(name,OBJ_TYPE_NIO));}/* Record an NIO in registry */static int netio_record(netio_desc_t *nio){ return(registry_add(nio->name,OBJ_TYPE_NIO,nio));}/* Create a new NetIO descriptor */static netio_desc_t *netio_create(char *name){ netio_desc_t *nio; if (!(nio = malloc(sizeof(*nio)))) return NULL; /* setup as a NULL descriptor */ memset(nio,0,sizeof(*nio)); nio->type = NETIO_TYPE_NULL; /* save name for registry */ if (!(nio->name = strdup(name))) { free(nio); return NULL; } return nio;}/* Delete a NetIO descriptor */int netio_delete(char *name){ return(registry_delete_if_unused(name,OBJ_TYPE_NIO,netio_free,NULL));}/* Delete all NetIO descriptors */int netio_delete_all(void){ return(registry_delete_type(OBJ_TYPE_NIO,netio_free,NULL));}/* Save the configuration of a NetIO descriptor */void netio_save_config(netio_desc_t *nio,FILE *fd){ if (nio->save_cfg) nio->save_cfg(nio,fd);}/* Save configurations of all NetIO descriptors */static void netio_reg_save_config(registry_entry_t *entry,void *opt,int *err){ netio_save_config((netio_desc_t *)entry->data,(FILE *)opt);}void netio_save_config_all(FILE *fd){ registry_foreach_type(OBJ_TYPE_NIO,netio_reg_save_config,fd,NULL); fprintf(fd,"\n");}/* Send a packet through a NetIO descriptor */ssize_t netio_send(netio_desc_t *nio,void *pkt,size_t len){ int res; if (!nio) return(-1); if (nio->debug) { printf("NIO %s: sending a packet of %lu bytes:\n",nio->name,(u_long)len); mem_dump(stdout,pkt,len); } /* Apply the TX filter */ if (nio->tx_filter != NULL) { res = nio->tx_filter->pkt_handler(nio,pkt,len,nio->tx_filter_data); if (res <= 0) return(-1); } return(nio->send(nio->dptr,pkt,len));}/* Receive a packet through a NetIO descriptor */ssize_t netio_recv(netio_desc_t *nio,void *pkt,size_t max_len){ ssize_t len; int res; if (!nio) return(-1); /* Receive the packet */ if ((len = nio->recv(nio->dptr,pkt,max_len)) <= 0) return(-1); if (nio->debug) { printf("NIO %s: receiving a packet of %ld bytes:\n",nio->name,(long)len); mem_dump(stdout,pkt,len); } /* Apply the RX filter */ if (nio->rx_filter != NULL) { res = nio->rx_filter->pkt_handler(nio,pkt,len,nio->rx_filter_data); if (res == NETIO_FILTER_ACTION_DROP) return(-1); } return(len);}/* Get a NetIO FD */int netio_get_fd(netio_desc_t *nio){ int fd = -1; switch(nio->type) { case NETIO_TYPE_UNIX: fd = nio->u.nud.fd; break; case NETIO_TYPE_VDE: fd = nio->u.nvd.data_fd; break; case NETIO_TYPE_TAP: fd = nio->u.ntd.fd; break; case NETIO_TYPE_TCP_CLI: case NETIO_TYPE_TCP_SER: case NETIO_TYPE_UDP: fd = nio->u.nid.fd; break;#ifdef LINUX_ETH case NETIO_TYPE_LINUX_ETH: fd = nio->u.nled.fd; break;#endif } return(fd);}/* * ========================================================================= * UNIX sockets * ========================================================================= *//* Create an UNIX socket */static int netio_unix_create_socket(netio_unix_desc_t *nud){ struct sockaddr_un local_sock; if ((nud->fd = socket(AF_UNIX,SOCK_DGRAM,0)) == -1) { perror("netio_unix: socket"); return(-1); } memset(&local_sock,0,sizeof(local_sock)); local_sock.sun_family = AF_UNIX; strcpy(local_sock.sun_path,nud->local_filename); if (bind(nud->fd,(struct sockaddr *)&local_sock,sizeof(local_sock)) == -1) { perror("netio_unix: bind"); return(-1); } return(nud->fd);}/* Free a NetIO unix descriptor */static void netio_unix_free(netio_unix_desc_t *nud){ if (nud->fd != -1) close(nud->fd); if (nud->local_filename) { unlink(nud->local_filename); free(nud->local_filename); }}/* Allocate a new NetIO UNIX descriptor */static int netio_unix_create(netio_unix_desc_t *nud,char *local,char *remote){ memset(nud,0,sizeof(*nud)); nud->fd = -1; /* check lengths */ if ((strlen(local) >= sizeof(nud->remote_sock.sun_path)) || (strlen(remote) >= sizeof(nud->remote_sock.sun_path))) goto nomem_error; if (!(nud->local_filename = strdup(local))) goto nomem_error; if (netio_unix_create_socket(nud) == -1) return(-1); /* prepare the remote info */ nud->remote_sock.sun_family = AF_UNIX; strcpy(nud->remote_sock.sun_path,remote); return(0); nomem_error: fprintf(stderr,"netio_unix_create: " "invalid file size or insufficient memory\n"); return(-1);}/* Write a packet to an UNIX socket */static ssize_t netio_unix_send(netio_unix_desc_t *nud,void *pkt,size_t pkt_len){ return(sendto(nud->fd,pkt,pkt_len,0, (struct sockaddr *)&nud->remote_sock, sizeof(&nud->remote_sock)));}/* Receive a packet from an UNIX socket */static ssize_t netio_unix_recv(netio_unix_desc_t *nud,void *pkt,size_t max_len){ return(recvfrom(nud->fd,pkt,max_len,0,NULL,NULL));}/* Save the NIO configuration */static void netio_unix_save_cfg(netio_desc_t *nio,FILE *fd){ netio_unix_desc_t *nud = nio->dptr; fprintf(fd,"nio create_unix %s %s %s\n", nio->name,nud->local_filename,nud->remote_sock.sun_path);}/* Create a new NetIO descriptor with UNIX method */netio_desc_t *netio_desc_create_unix(char *nio_name,char *local,char *remote){ netio_desc_t *nio; if (!(nio = netio_create(nio_name))) return NULL; if (netio_unix_create(&nio->u.nud,local,remote) == -1) { netio_free(nio,NULL); return NULL; } nio->type = NETIO_TYPE_UNIX; nio->send = (void *)netio_unix_send; nio->recv = (void *)netio_unix_recv; nio->save_cfg = netio_unix_save_cfg; nio->dptr = &nio->u.nud; if (netio_record(nio) == -1) { netio_free(nio,NULL); return NULL; } return nio;}/* * ========================================================================= * VDE (Virtual Distributed Ethernet) interface * ========================================================================= *//* Free a NetIO VDE descriptor */static void netio_vde_free(netio_vde_desc_t *nvd){ if (nvd->data_fd != -1) close(nvd->data_fd); if (nvd->ctrl_fd != -1) close(nvd->ctrl_fd); if (nvd->local_filename) { unlink(nvd->local_filename); free(nvd->local_filename); }}/* Create a new NetIO VDE descriptor */static int netio_vde_create(netio_vde_desc_t *nvd,char *control,char *local){ struct sockaddr_un ctrl_sock,tst; struct vde_request_v3 req; ssize_t len; int res; memset(nvd,0,sizeof(*nvd)); nvd->ctrl_fd = nvd->data_fd = -1; if ((strlen(control) >= sizeof(ctrl_sock.sun_path)) || (strlen(local) >= sizeof(nvd->remote_sock.sun_path))) { fprintf(stderr,"netio_vde_create: bad filenames specified\n"); return(-1); } /* Copy the local filename */ if (!(nvd->local_filename = strdup(local))) { fprintf(stderr,"netio_vde_create: insufficient memory\n"); return(-1); } /* Connect to the VDE switch controller */ nvd->ctrl_fd = socket(AF_UNIX,SOCK_STREAM,0); if (nvd->ctrl_fd < 0) { perror("netio_vde_create: socket(control)"); return(-1); } memset(&ctrl_sock,0,sizeof(ctrl_sock)); ctrl_sock.sun_family = AF_UNIX; strcpy(ctrl_sock.sun_path,control); res = connect(nvd->ctrl_fd,(struct sockaddr *)&ctrl_sock, sizeof(ctrl_sock)); if (res < 0) { perror("netio_vde_create: connect(control)"); return(-1); } tst.sun_family = AF_UNIX; strcpy(tst.sun_path,local); /* Create the data connection */ nvd->data_fd = socket(AF_UNIX,SOCK_DGRAM,0); if (nvd->data_fd < 0) { perror("netio_vde_create: socket(data)"); return(-1); } if (bind(nvd->data_fd,(struct sockaddr *)&tst,sizeof(tst))<0) { perror("netio_vde_create: bind(data)"); return(-1); } /* Now, process to registration */ memset(&req,0,sizeof(req)); req.sock.sun_family = AF_UNIX; strcpy(req.sock.sun_path,local); req.magic = VDE_SWITCH_MAGIC; req.version = VDE_SWITCH_VERSION; req.type = VDE_REQ_NEW_CONTROL; len = write(nvd->ctrl_fd,&req,sizeof(req)); if (len != sizeof(req)) { perror("netio_vde_create: write(req)"); return(-1); } /* Read the remote socket descriptor */ len = read(nvd->ctrl_fd,&nvd->remote_sock,sizeof(nvd->remote_sock)); if (len != sizeof(nvd->remote_sock)) { perror("netio_vde_create: read(req)"); return(-1); } return(0);}/* Write a packet to a VDE data socket */static ssize_t netio_vde_send(netio_vde_desc_t *nvd,void *pkt,size_t pkt_len){ return(sendto(nvd->data_fd,pkt,pkt_len,0, (struct sockaddr *)&nvd->remote_sock, sizeof(nvd->remote_sock)));}/* Receive a packet from a VDE socket */static ssize_t netio_vde_recv(netio_vde_desc_t *nvd,void *pkt,size_t max_len){ return(recvfrom(nvd->data_fd,pkt,max_len,0,NULL,NULL));}/* Save the NIO configuration */static void netio_vde_save_cfg(netio_desc_t *nio,FILE *fd){ netio_vde_desc_t *nvd = nio->dptr; fprintf(fd,"nio create_vde %s %s %s\n", nio->name,nvd->remote_sock.sun_path,nvd->local_filename);}/* Create a new NetIO descriptor with VDE method */netio_desc_t *netio_desc_create_vde(char *nio_name,char *control,char *local){ netio_vde_desc_t *nvd; netio_desc_t *nio; if (!(nio = netio_create(nio_name))) return NULL; nvd = &nio->u.nvd; if (netio_vde_create(nvd,control,local) == -1) { netio_free(nio,NULL); return NULL; } nio->type = NETIO_TYPE_VDE; nio->send = (void *)netio_vde_send; nio->recv = (void *)netio_vde_recv; nio->save_cfg = netio_vde_save_cfg; nio->dptr = &nio->u.nvd;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -