Debugging Linux socket programming?

I have a function like this:

static int
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr,
     socklen_t *addrlen)
{
    struct timeval timeout = {1, 0};
    fd_set set;
    int status;

    FD_SET(sock, &set);
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) {
        FD_ZERO(&set);
        fprintf(stderr, 
            "timeout while receiving answer from kernel\n");
        exit(1);
    } else if (status == -1) {
        FD_ZERO(&set);
        perror("recvfrom failed");
        exit(1);
    }
    FD_ZERO(&set);
    return recvfrom(sock, buf, len, 0, addr, addrlen);
}

      

which is used to receive a message from kernel space using netlink. But when I run it, the result always says a message that "timeout while returning a response from the kernel", from the source code, this is called for the reason that the "select" method always returns "0". I don't know the reason, who can give me some suggestions, thanks.

+1


source to share


5 answers


Charlie,
A few things:

1) You should probably wrap your select () call and ONLY call recvfrom if FD_ISSET () returns true on the file descriptor.
2) Make sure your actual driver or kernel code that is sent to the netlink socket is actually writing / sending data to it. If not, then your function will be disabled if it does not receive data in 1 second. (this is what you set the timeout for).

A few general notes ... On Linux when using the select () system call. the timeout data structure gets reset after every call, so if you change your code to a loop, pick which you probably should ... you will have to reset your timeout value for each iteration in the loop.



Also, choosing a time-out doesn't necessarily mean an error. Remember to choose a non-blocking call. It will just wait for the socket for the given timeout and return. If you want to read from a file descriptor, no matter what ... which means you want your recv_kern () function to block until data is returned, don't bother using select (). Just call recvfrom () directly on the file descriptor. This way, your recv_kernel () function will block and only return after reading the data sent by the kernel.


It's hard to give more specific help here without knowing more about the context of how this code is used. I'm guessing this is a special kernel module that you wrote that sends data to user space, right?
Try changing the recv_kern () function to block (select the highlighted code and just call recvfrom ()). This method should be able to determine if your kernel driver is actually sending data to user space. If you block recvfrom () and nothing is returned, then you may also have a kernel driver problem.

Hope it helps.

+4


source


You should rewrite this function as follows:

static int
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr,
     socklen_t *addrlen)
{
    struct timeval timeout = {1, 0};
    fd_set set;
    int status;

    FD_ZERO(&set);
    FD_SET(sock, &set);
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) {
        fprintf(stderr, 
                "timeout while receiving answer from kernel\n");
        exit(1);
    } else if (status < 0) {
        perror("recvfrom failed");
        exit(1);
    }
    if ((status = recvfrom(sock, buf, len, 0, addr, addrlen)) < 0) {
        perror("recvfrom error");
        exit(1);
    }
    if (status == 0) {
        fprintf(stderr, "kernel closed socket\n");
        exit(1);
    }
    return status;
}

      



Like anyone else, you need to call FD_ZERO before calling select. Other calls to FD_ZERO are redundant. Also, you need to do full error checking.

+2


source


Not related to timeout, but you need FD_ZERO (& set) before FD_SET (sock, & set), otherwise fd_set will be uninitialized and will probably contain many set bits. Also, FD_ZERO () before exiting is pretty pointless.

+1


source


I am studying my code in kernel space, I know that the kernel cannot receive a message from the client using the "skb_dequeue (& sk-> sk_receive_queue)" method. I don't know how it goes.

0


source


For starters, you can find out what the actual error is by printing strerror(errno)

(printing errno is also reasonable) when the timeout occurs.

As for guessing the problem that might arise if errno is missing, note that there is no guarantee that you will read anything; even if you received a socket via accept (2), it might just be a connection that was configured but that the client didn't write. Usually you don't make only one choice (2); you want to have a single main loop that keeps calling select (2) until the program wants to exit, as timeouts can happen for almost any reason at about any time.

Other possible problems:

  • The client cannot connect.
  • You cannot bind the socket correctly.
  • You forget to call listen (2) on the server socket after calling bind (2).

If you are using IP sockets, you can watch your network traffic with Wireshark to see if the client is doing what you expect.

0


source







All Articles