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 + -
显示快捷键?