cosinus0
cosinus0

Reputation: 613

recvmsg returned EDEADLK?

I have socket family PF_PACKET type SOCK_RAW. Messages read via recvmsg and with poll(). Rendomly and periodicly I got recvmsg return EDEADLK. I try debug this problem with next code. I try investigate who and how blocked my socket descriptor. May be some one know other method how debug such case? As I right understand

EDEADLK resource deadlock avoided. An attempt was made to lock a system resource that would have resulted in a deadlock situation. In my case it is socket file descriptor locking problem. Allocating a system resource socket file descriptor would have resulted in a deadlock situation. The system does not guarantee that it will notice all such situations. This error means you got lucky and the system noticed.

error = recvmsg(fd, &msghdr, flags);
msghdr_flags = msg_hdr.msg_flags;

void recvmsg_errno(int fd, unsigned int msghdr_flags, int flags, int error)
{
    struct flock fl;
    memset(&fl, 0x0, sizeof(fl));

    printf("recvmsg return: %d errno: %d description: %s\n", error, errno,
                    strerror(errno));

    printf("recvmsg flags: %x %d\n", flags, flags);
    if (flags & MSG_ERRQUEUE) printf("MSG_ERRQUEUE\n");
    if (flags & MSG_OOB) printf("MSG_OOB\n");
    if (flags & MSG_PEEK) printf("MSG_PEEK\n");
    if (flags & MSG_TRUNC) printf("MSG_TRUNC\n");
    if (flags & MSG_WAITALL) printf("MSG_WAITALL\n");

    printf("msghdr flags: %x %d\n", msghdr_flags, msghdr_flags);
    if (msghdr_flags & MSG_EOR) printf("MSG_EOR\n");           //indicates end-of-record; SOCK_SEQPACKET
    if (msghdr_flags & MSG_TRUNC) printf("MSG_TRUNC\n");       //discarded datagram was larger than the buffer supplied
    if (msghdr_flags & MSG_CTRUNC) printf("MSG_CTRUNC\n");     //control data were discarded due to lack of space in the buffer
    if (msghdr_flags & MSG_OOB) printf("MSG_OOB\n");           //out-of-band data were received
    if (msghdr_flags & MSG_ERRQUEUE) printf("MSG_ERRQUEUE\n"); //no data received; extended error from the socket error queue

    flags = 0;
    flags = fcntl(fd, F_GETLK, &fl); {
            printf("F_GETLK: 0x%x\n", flags);
            printf("l_start: %x l_len: %x l_pid: %d l_type: %x l_whence: %x\n",
                            fl.l_start,   //Starting offset for lock
                            fl.l_len,     //Number of bytes to lock
                            fl.l_pid,     //PID of process blocking our lock (F_GETLK only)
                            fl.l_type,    //Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
                            fl.l_whence); // How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END
    }//Get the first lock which blocks the lock description

    flags = 0;
    flags = fcntl(fd, F_GETFD); {
            printf("F_GETFD: 0x%x\n", flags);
    }//Get the file descriptor flags

    flags = 0;
    flags = fcntl(fd, F_GETFL); {
            printf("F_GETFL: 0x%x\n", flags);
            if (flags & O_NONBLOCK) printf("O_NONBLOCK\n");
            if (!(flags & O_NONBLOCK)) printf("BLOCK\n");
            if (flags & O_APPEND) printf("O_APPEND\n");
    }//Get the file status flags and file access modes

    flags = 0;
    flags = fcntl(fd, F_GETOWN); {
            printf("F_GETOWN: %d\n", flags);
    }//Socket, set the process or process group ID specified to receive SIGURG signals when out-of-band data is available.
}

Upvotes: 3

Views: 1867

Answers (1)

Nominal Animal
Nominal Animal

Reputation: 39406

If recvmsg() returns 0, it does not mean an error occurred. It means that the other end closed the connection.

In a followup comment to the question, the OP mentioned that they used if ((error = recvmsg()) <= 0) {return -errno;}. This is wrong. When the other end closes the connection, recvmsg() returns zero, without setting errno. Even the use of variable named error is wrong, as the function returns the number of bytes received.

In other words, the OP is seeing an old, stale errno == EDEADLK from some other earlier failed locking function, and handling the case where the other end closes the connection incorrectly as an error.

(errno is only set when an error occurs; no library function clears it to zero, ever, because that could cause errors to be hidden in certain cases.)

Upvotes: 8

Related Questions