Search code examples
csocketspolling

Unexpected revents value in poll for non blocking socket connect


I am trying to create a non-blocking socket connect. Below is the code for the same

#include<fcntl.h>
#include<errno.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<strings.h>
#include<string.h>
#include <sys/poll.h>
#define MAX_EPOLL_EVENTS 64

void perror(char const * s);

int main()
{
    int result, n, rc;
    socklen_t result_len = sizeof(result);
    struct pollfd fds[1];
    int sockfd, flags;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    int len = sizeof(int);
    flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(20000);
    server_addr.sin_addr.s_addr = inet_addr("10.0.1.17");
    n = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (n != 0)
        //if (errno != EINPROGRESS) {
        perror("Connection gone wrong");

    fds[0].fd = sockfd;
    fds[0].events  = POLLOUT;
    fds[0].revents = 0;
    while(1){
         rc = poll(fds, (nfds_t)1, 10*1000);
         printf("value of poll result is - %d- %d\n", rc, errno);
         if (rc == 1){
             getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &result, &result_len);
             printf("%d\n", result);
         }
         printf("code for POLLOUT - %d\n", POLLOUT);
         printf("revents - %d\n", fds[0].revents);
         if(result == 0){
              break;
         }
    }
}

Output:

Connection gone wrong: Operation now in progress
value of poll result is - 1- 115
111
code for POLLOUT - 4
revents - 28
value of poll result is - 1- 115
0
code for POLLOUT - 4
revents - 20

As per the poll documentation

The field revents is an output parameter, filled by the kernel with the events that actually occurred. The bits returned in revents can include any of those specified in events, or one of the values POLLERR, POLLHUP, or POLLNVAL. (These three bits are meaningless in the events field, and will be set in the revents field whenever the corresponding condition is true.)

When I print the value of revents, that is set to a different value to POLLOUT. Is this the exact behaviour of poll()?


Solution

  • The value of poll.revents is a bitfield.

    From the header file poll.h

    #define POLLIN          0x0001
    #define POLLPRI         0x0002
    #define POLLOUT         0x0004
    #define POLLERR         0x0008
    #define POLLHUP         0x0010
    #define POLLNVAL        0x0020
    

    So your value 0x28 is comprised of POLLERR|POLLNVAL, which can occur, when the filedescriptor polled for is not open:

      POLLNVAL
             Invalid request: fd not open (only returned in revents; ignored in events).
    

    These values can always occur, even when not asked for in poll.events.

    As you can see, the socket error is 111 (first call to getsockopt()), which means Connection refused. After this, the filedescriptor is invalid to poll for, because it is no longer connected.