vnetd.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,201 行 · 第 1/3 页
C
1,201 行
}}static void vnet_handle(Vnetd *vnetd, SelectSet *set){ HashTable_for_decl(entry); HashTable_for_each(entry, vnetd->vnet_table){ Vnet *vnet = entry->value; struct net_device *dev = vnet->dev; if(!dev) continue; if(dev->tapfd < 0) continue; if(SelectSet_in_read(set, dev->tapfd)){ int n; for(n = 64; n > 0; --n){ if(vnet_read(vnet) < 0) break; } } }}static int vnetd_handle_udp(Vnetd *vnetd, struct sockaddr_in *addr, int sock){ int err = 0, n = 0; struct sockaddr_in peer, dest; socklen_t peer_n = sizeof(peer), dest_n = sizeof(dest); int flags = MSG_DONTWAIT; struct sk_buff *skb = NULL; dest = *addr; n = skb_recv_udp(sock, flags, &peer, &peer_n, &dest, &dest_n, &skb); if(n < 0){ err = n; goto exit; } dprintf("> Received %d bytes from=%s:%d dest=%s:%d\n", n, inet_ntoa(peer.sin_addr), htons(peer.sin_port), inet_ntoa(dest.sin_addr), htons(dest.sin_port)); if(peer.sin_addr.s_addr == vnetd_intf_addr(vnetd)){ dprintf("> Ignoring message from self.\n"); goto exit; } if(dest.sin_addr.s_addr == vnetd_mcast_addr(vnetd)){ vnet_forward_send(skb); } err = varp_handle_message(skb); exit: if(skb) kfree_skb(skb); return err;}static int vnetd_handle_etherip(Vnetd *vnetd, struct sockaddr_in *addr, int sock){ int err = 0, n = 0; struct sockaddr_in peer, dest; socklen_t peer_n = sizeof(peer), dest_n = sizeof(dest); int flags = 0; struct sk_buff *skb = NULL; dest = *addr; n = skb_recv_raw(sock, flags, &peer, &peer_n, &dest, &dest_n, &skb); if(n < 0){ err = n; goto exit; } dprintf("> Received %d bytes from=%s:%d dest=%s:%d\n", n, inet_ntoa(peer.sin_addr), htons(peer.sin_port), inet_ntoa(dest.sin_addr), htons(dest.sin_port)); if(peer.sin_addr.s_addr == vnetd_intf_addr(vnetd)){ dprintf("> Ignoring message from self.\n"); goto exit; } err = etherip_protocol_recv(skb); exit: if(skb) kfree_skb(skb); return err;}typedef struct ConnClient { Vnetd *vnetd; Parser *parser;} ConnClient;static int conn_handle_fn(Conn *conn, int mode){ int err; ConnClient *client = conn->data; char data[1024] = {}; int k; int done = false; k = IOStream_read(conn->in, data, sizeof(data)); if(k < 0){ err = k; goto exit; } if(!client->parser){ err = -ENOSYS; goto exit; } if((k == 0) && Parser_at_eof(client->parser)){ err = -EINVAL; goto exit; } err = Parser_input(client->parser, data, k); if(err < 0) goto exit; while(Parser_ready(client->parser)){ Sxpr sxpr = Parser_get_val(client->parser); err = vnet_eval(sxpr, conn->out, NULL); if(err) goto exit; done = true; } if(done || Parser_at_eof(client->parser)){ // Close at EOF. err = -EIO; } exit: if(err < 0){ Parser_free(client->parser); client->parser = NULL; } return (err < 0 ? err : 0);}static int vnetd_handle_unix(Vnetd *vnetd, int sock){ int err; ConnClient *client = NULL; Conn *conn = NULL; struct sockaddr_un peer = {}; socklen_t peer_n = sizeof(peer); int peersock; peersock = accept(sock, (struct sockaddr *)&peer, &peer_n); if(peersock < 0){ perror("accept"); err = -errno; goto exit; } // We want non-blocking i/o. fcntl(peersock, F_SETFL, O_NONBLOCK); client = ALLOCATE(ConnClient); client->vnetd = vnetd; client->parser = Parser_new(); conn = Conn_new(conn_handle_fn, client); err = Conn_init(conn, peersock, SOCK_STREAM, SELECT_READ, (struct sockaddr_in){}); if(err) goto exit; vnetd->conns = ConnList_add(vnetd->conns, conn); exit: if(err){ Conn_close(conn); close(peersock); } if(err < 0) wprintf("< err=%d\n", err); return err;}static void vnetd_select(Vnetd *vnetd, SelectSet *set){ SelectSet_add(set, vnetd->unix_sock, SELECT_READ); SelectSet_add(set, vnetd->udp_sock, SELECT_READ); SelectSet_add(set, vnetd->mcast_sock, SELECT_READ); if(vnetd->etherip_sock >= 0){ SelectSet_add(set, vnetd->etherip_sock, SELECT_READ); } vnet_select(vnetd, set); ConnList_select(vnetd->conns, set);}static void vnetd_handle(Vnetd *vnetd, SelectSet *set){ if(SelectSet_in_read(set, vnetd->unix_sock)){ vnetd_handle_unix(vnetd, vnetd->unix_sock); } if(SelectSet_in_read(set, vnetd->udp_sock)){ int n; for(n = 256; n > 0; --n){ if(vnetd_handle_udp(vnetd, &vnetd->udp_sock_addr, vnetd->udp_sock) < 0){ break; } } } if(SelectSet_in_read(set, vnetd->mcast_sock)){ vnetd_handle_udp(vnetd, &vnetd->mcast_sock_addr, vnetd->mcast_sock); } if((vnetd->etherip_sock >= 0) && SelectSet_in_read(set, vnetd->etherip_sock)){ vnetd_handle_etherip(vnetd, &vnetd->etherip_sock_addr, vnetd->etherip_sock); } vnet_handle(vnetd, set); vnetd->conns = ConnList_handle(vnetd->conns, set);}/** Counter for timer alarms. */static unsigned timer_alarms = 0;static int vnetd_main(Vnetd *vnetd){ int err = 0; SelectSet _set = {}, *set = &_set; struct timeval _timeout = {}, *timeout = &_timeout; vnetd->vnet_table = vnet_table; for( ; ; ){ timeout->tv_sec = 0; timeout->tv_usec = 500000; SelectSet_zero(set); vnetd_select(vnetd, set); err = SelectSet_select(set, timeout); if(err == 0) continue; if(err < 0){ switch(errno){ case EINTR: if(timer_alarms){ timer_alarms = 0; process_timers(); } continue; case EBADF: continue; default: perror("select"); goto exit; } } vnetd_handle(vnetd, set); } exit: return err;}static int getsockaddr(int sock, struct sockaddr_in *addr){ socklen_t addr_n = sizeof(struct sockaddr_in); return getsockname(sock, (struct sockaddr*)addr, &addr_n);}static int vnetd_etherip_sock(Vnetd *vnetd){ int err = 0; if(!vnetd->etherip) goto exit; err = vnetd_raw_socket(vnetd, IPPROTO_ETHERIP, (VSOCK_BROADCAST | VSOCK_MULTICAST), vnetd_mcast_addr(vnetd), &vnetd->etherip_sock); if(err < 0) goto exit; err = setsock_pktinfo(vnetd->etherip_sock, true); if(err < 0) goto exit; getsockaddr(vnetd->etherip_sock, &vnetd->etherip_sock_addr); exit: return err;}static int vnetd_udp_sock(Vnetd *vnetd){ int err; uint32_t mcaddr = vnetd_mcast_addr(vnetd); err = create_socket(SOCK_DGRAM, INADDR_ANY, vnetd->port, (VSOCK_BIND | VSOCK_REUSE), &vnetd->udp_sock); if(err < 0) goto exit; err = setsock_pktinfo(vnetd->udp_sock, true); if(err < 0) goto exit; getsockaddr(vnetd->udp_sock, &vnetd->udp_sock_addr); vnetd->mcast_sock_addr.sin_addr.s_addr = vnetd_intf_addr(vnetd); err = create_socket(SOCK_DGRAM, mcaddr, vnetd_mcast_port(vnetd), (VSOCK_REUSE | VSOCK_BROADCAST | VSOCK_MULTICAST), &vnetd->mcast_sock); if(err < 0) goto exit; err = setsock_pktinfo(vnetd->udp_sock, true); if(err < 0) goto exit; err = setsock_multicast(vnetd->mcast_sock, INADDR_ANY, mcaddr); if(err < 0) goto exit; err = setsock_multicast_ttl(vnetd->mcast_sock, vnetd->ttl); if(err < 0) goto exit; getsockaddr(vnetd->mcast_sock, &vnetd->mcast_sock_addr); vnetd->mcast_sock_addr.sin_addr.s_addr = mcaddr; exit: if(err < 0){ close(vnetd->udp_sock); close(vnetd->mcast_sock); vnetd->udp_sock = -1; vnetd->mcast_sock = -1; } return err;}static int vnetd_raw_sock(Vnetd *vnetd){ int err; err = vnetd_raw_socket(vnetd, IPPROTO_RAW, (VSOCK_BROADCAST), vnetd_mcast_addr(vnetd), &vnetd->raw_sock); if(err){ close(vnetd->raw_sock); vnetd->raw_sock = -1; } return err;}static int vnetd_unix_sock(Vnetd *vnetd){ int err = 0; struct sockaddr_un addr = { .sun_family = AF_UNIX }; socklen_t addr_n; vnetd->unix_sock = socket(addr.sun_family, SOCK_STREAM, 0); if(vnetd->unix_sock < 0){ err = -errno; perror("unix socket"); goto exit; } unlink(vnetd->unix_path); strcpy(addr.sun_path, vnetd->unix_path); addr_n = sizeof(addr) - sizeof(addr.sun_path) + strlen(vnetd->unix_path) + 1; err = bind(vnetd->unix_sock, (struct sockaddr *)&addr, addr_n); if(err < 0){ err = -errno; perror("unix bind"); goto exit; } err = listen(vnetd->unix_sock, 5); if(err < 0){ err = -errno; perror("unix listen"); } exit: return err;} /** Handle SIGPIPE. * * @param code signal code * @param info signal info * @param data */static void sigaction_SIGPIPE(int code, siginfo_t *info, void *data){ dprintf("> SIGPIPE\n");}/** Handle SIGALRM. * * @param code signal code * @param info signal info * @param data */static void sigaction_SIGALRM(int code, siginfo_t *info, void *data){ timer_alarms++;}/** Type for signal handling functions. */typedef void SignalAction(int code, siginfo_t *info, void *data);/** Install a handler for a signal. * * @param signum signal * @param action handler * @return 0 on success, error code otherwise */static int catch_signal(int signum, SignalAction *action){ int err = 0; struct sigaction sig = {}; dprintf(">\n"); sig.sa_sigaction = action; sig.sa_flags = SA_SIGINFO; err = sigaction(signum, &sig, NULL); if(err){ err = -errno; perror("sigaction"); } return err;} int main(int argc, char *argv[]){ int err = 0; err = tunnel_module_init(); if(err < 0) goto exit; err = vnet_init(); if(err < 0) goto exit; err = vnetd_init(vnetd, argc, argv); if(err < 0) goto exit; err = catch_signal(SIGPIPE, sigaction_SIGPIPE); if(err < 0) goto exit; err = catch_signal(SIGALRM, sigaction_SIGALRM); if(err < 0) goto exit; err = vnetd_etherip_sock(vnetd); if(err < 0) goto exit; err = vnetd_udp_sock(vnetd); if(err < 0) goto exit; err = vnetd_raw_sock(vnetd); if(err < 0) goto exit; err = vnetd_unix_sock(vnetd); if(err < 0) goto exit; err = vnetd_main(vnetd);exit: return (err ? 1 : 0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?