【问题标题】:Does libevent support netlink socketlibevent 是否支持 netlink 套接字
【发布时间】:2017-07-04 23:35:23
【问题描述】:

我使用 netlink 从内核接收中断号。用户空间中的应用程序使用 libevent 来处理 TCP/IP 请求和 netlink 消息。 libevent 是否支持 Linux netlink 套接字?我会很感激一个简单的例子。

【问题讨论】:

    标签: linux libevent netlink


    【解决方案1】:

    是的,libevent 支持 netlink 套接字。

    https://github.com/libevent/libevent/blob/master/sample/hello-world.c,下面修改为监听netlink socket。

    基本示例监听 Linux 网络接口的创建/删除,可以使用 sudo 执行以获得所需的权限。它侦听与ip monitor link 相同的事件。

    另一个使用 libevent 监听 RAW 套接字的例子是这里https://github.com/bodgit/libevent-natpmp/blob/master/natpmp.c

    static void link_recvmsg(int fd, short event, void *arg)
    {
        char          buf[NLMSG_SPACE(BUF_SIZE)] = {0};
        socklen_t     socklen;
        struct iovec  iov = {.iov_base = buf, .iov_len = sizeof(buf)};
        struct sockaddr addr;
        memset(&addr, 0, sizeof(struct sockaddr));
    
        if (!fd || -1 == fd)
            return;
    
        int status = getsockname(fd, &addr, &socklen);
        if(-1 == status)
            return;
    
        struct msghdr mh = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1,
            .msg_flags = 0, .msg_name = &addr, .msg_namelen = sizeof(struct sockaddr)};
    
        status = recvmsg(fd, &mh, 0);
        if ((-1 == status) && ((EINTR == errno) || (EAGAIN == errno)))
            return;
        if(-1 == status)
            return;
        if ((mh.msg_flags & MSG_TRUNC) == MSG_TRUNC)
            return;
        if ((mh.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
            return;
    
        for (const struct nlmsghdr *h = (struct nlmsghdr *)buf; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) {
            switch (h->nlmsg_type) {
                case RTM_NEWLINK:
                    fprintf(stderr, "got RTM_NEWLINK\n");
                    break;
                case RTM_DELLINK:
                    fprintf(stderr, "got RTM_DELLINK\n");
                    break;
                default:
                    fprintf(stderr, "unexpected case in swtch statement\n");
                    break;
            }
        }
    }
    int main(int argc, char **argv)
    {
        /* some init code here */
        /* NETLINK socket */
        int status;
        int buf_size = BUF_SIZE; 
        struct sockaddr_nl src_addr;
    
        int socket_nl = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
        if(-1 == socket_nl) return -1;
    
        memset(&src_addr, 0, sizeof(struct sockaddr_nl));
        src_addr.nl_family = AF_NETLINK;
        src_addr.nl_pid = getpid();
        src_addr.nl_groups |= RTNLGRP_LINK;
    
        status = setsockopt(socket_nl, SOL_SOCKET, SO_RCVBUF,
                &buf_size, sizeof(buf_size));
        if(-1 == status) return -1; 
    
        status = bind(socket_nl, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_nl));
        if(status < 0) return -1;
    
        static struct event nl_ev;
        event_set(&nl_ev, socket_nl, EV_READ|EV_PERSIST, link_recvmsg,
                NULL);
        if (base) {
            event_base_set(base, &nl_ev);
        }
        event_add(&nl_ev, NULL);
        /* some other code, dispatch event and deinit */
    }
    

    【讨论】: