2016-11-24 4 views
2

USB 장치가 (dis) 연결될 때 netlink 소켓을 통해 커널에서 uevent를 수신하려고합니다. 나는 같은 일을하는 파이썬 스크립트를 가지고 있고 그것은 작동하지만, 나는 지금까지 내가이있는 C.에서 같은 기능이 필요합니다Netlink 소켓으로 커널 uevents를받는 방법?

#include <sys/types.h> 
#include <sys/socket.h> 
#include <linux/netlink.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

#define NL_MAX_PAYLOAD 8192 

int main() { 
    int nl_socket; 
    struct sockaddr_nl src_addr, dest_addr; 
    struct nlmsghdr* nlh; 
    struct msghdr msg; 
    struct iovec iov; 

    // Prepare source address 
    memset(&src_addr, 0, sizeof(src_addr)); 
    src_addr.nl_family = AF_NETLINK; 
    src_addr.nl_pid = getpid(); 

    // Prepare destination address 
    memset(&dest_addr, 0, sizeof(dest_addr)); 
    dest_addr.nl_family = AF_NETLINK; 
    dest_addr.nl_pid = 0; 
    dest_addr.nl_groups = 0; 

    // Prepare netlink message 
    nlh = (struct nlmsghdr*) malloc(NLMSG_SPACE(NL_MAX_PAYLOAD)); 
    memset(nlh, 0, NLMSG_SPACE(NL_MAX_PAYLOAD)); 
    nlh->nlmsg_len = NLMSG_SPACE(NL_MAX_PAYLOAD); 
    nlh->nlmsg_pid = getpid(); 
    nlh->nlmsg_flags = 0; 
    iov.iov_base = (void *) nlh; 
    iov.iov_len = nlh->nlmsg_len; 
    msg.msg_iov = &iov; 
    msg.msg_iovlen = 1; 

    nl_socket = socket(AF_NETLINK, SOCK_DGRAM,  NETLINK_KOBJECT_UEVENT); 
    if (nl_socket < 0) { 
     printf("Failed to create socket for DeviceFinder"); 
     exit(1); 
    } 

    bind(nl_socket, (struct sockaddr*) &src_addr, sizeof(src_addr)); 

    while (1) { 
     int r = recvmsg(nl_socket, &msg, 0); 
     printf("%i\n", r); 
     if (r < 0) { 
      perror(""); 
     } 
    } 
} 

이 작은, 작업 예제를 만들 맥락에서 촬영된다.

문제는 단지 아무 것도받지 못한다는 것입니다. 어떤 오류도 발생하지 않습니다. recvmsg의 호출은 장치를 연결할 때 결코 반환되지 않습니다. 왜?

답변

1

수신 부분 대신 내가 RECV을 사용하고 recvmmsg를 사용하여 정확, 나는 다음과 같은 프로그램을 약간 수정 한은 uevents 출력 코드입니다 : RECV보다

#include <sys/types.h> 
#include <sys/socket.h> 
#include <linux/netlink.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

#define NL_MAX_PAYLOAD 8192 

int main() { 
    int nl_socket; 
    struct sockaddr_nl src_addr; 
    char msg[NL_MAX_PAYLOAD]; 
    int ret; 

    // Prepare source address 
    memset(&src_addr, 0, sizeof(src_addr)); 
    src_addr.nl_family = AF_NETLINK; 
    src_addr.nl_pid = getpid(); 
    src_addr.nl_groups = -1; 

    nl_socket = socket(AF_NETLINK, (SOCK_DGRAM | SOCK_CLOEXEC),  NETLINK_KOBJECT_UEVENT); 
    if (nl_socket < 0) { 
     printf("Failed to create socket for DeviceFinder"); 
     exit(1); 
    } 

    ret = bind(nl_socket, (struct sockaddr*) &src_addr, sizeof(src_addr)); 
    if (ret) { 
     printf("Failed to bind netlink socket.."); 
     close(nl_socket); 
     return 1; 
    } 

    printf("Waiting for events now...\n"); 
    while (1) { 
     int r = recv(nl_socket, msg, sizeof(msg), MSG_DONTWAIT); 
     if (r == -1) 
      continue; 
     if (r < 0) { 
      perror(""); 
      continue; 
     } 
     printf("length:%i\n msg:%s", r, msg); 

    } 
} 
+0

감사합니다. 어떤 이유로 많은 메시지가 비어 있어도 완벽하게 작동합니다. 내가 필요한 것들은 괜찮아. –

0

이 좋은 사용 recvmsg을 (단지 연결된 링크 용) .ref man recvmsg. 그리고 프로그램은 성공에 가깝습니다.

src_addr.nl_family = AF_NETLINK; 
src_addr.nl_pid = getpid(); 
src_addr.nl_groups = -1; <--add this so can receive from kernel broadcast