Search code examples
cwinsock

Why when I add POLLHUP as event, WSAPoll returns error (invalid arguments)?


I'm using WSAPoll for my project. I used tracking POLLIN and POLLOUT events. Everything worked nice. When I add POLLHUP as event, WSAPoll returns error 10022 (Invalid argument).

I've no idea what's wrong, please guide me how to fix it:(

cc_qnt - quantity of connected clients

        int ev_cnt = WSAPoll(pfd, cc_qnt + 1, 100);
        if (ev_cnt > 0) { 

            for (i = 0; i < cc_qnt; i++)  {   

                if (pfd[i].revents & POLLHUP) {      

                    // some code
                } 

                if (pfd[i].revents & POLLIN) {

                    // some code
                }
            } 

            if (pfd[cc_qnt].revents & POLLIN) { 

In this part we have new connection ready for accepting. We edit pfd[cc_qnt] adding new socket (returned by accept) instead of listening socket. Then we reallocate pfd with size + 1, copying previous data and adding listening socket at the end of cc array.

                int addrlen = sizeof(addr);
                cc[cc_qnt].s = accept(ls, (struct sockaddr*) &addr, &addrlen);
                cc[cc_qnt].ip = ntohl(addr.sin_addr.s_addr);
                cc[cc_qnt].sent_put = 0;
                cc[cc_qnt].c_cl_cn = 0;

                pfd[cc_qnt].fd = cc[i].s;
                pfd[cc_qnt].events = POLLIN | POLLOUT | POLLHUP;

                cc_qnt++;
                pfd = init_pfd(pfd, ls, cc_qnt);
            }   
        }   
        else if (ev_cnt < 0) {    

            exit(printf("\nprocess_events: WSAPoll, ev_cnt = %d, WSAGetLastError: %d \n", ev_cnt, WSAGetLastError()));
        }  

Everything I changed for tracking POLLHUP - adding it's bit to pfd[cc_qnt].events and WSAPoll started returning error. I expect tracking POLLHUP event.


Solution

  • Per the WSAPoll() documentation:

    WSAEINVAL

    An invalid parameter was passed. This error is returned if the fdarray parameter contains a NULL pointer. This error is also returned if invalid flags were specified in the events member of any of the WSAPOLLFD structures pointed to by the fdarray parameter when requesting socket status. This error is also returned if none of the sockets specified in the fd member of any of the WSAPOLLFD structures pointed to by the fdarray parameter were valid.

    And per the WSAPOLLFD documentation:

    events

    Type: short

    A set of flags indicating the type of status being requested. This must be one or more of the following.

    POLLPRI
    Priority data may be read without blocking. This flag is not supported by the Microsoft Winsock provider.

    POLLRDBAND
    Priority band (out-of-band) data can be read without blocking.

    POLLRDNORM
    Normal data can be read without blocking.

    POLLWRNORM
    Normal data can be written without blocking.

    The POLLIN flag is defined as the combination of the POLLRDNORM and POLLRDBAND flag values. The POLLOUT flag is defined as the same as the POLLWRNORM flag value.

    So, as you can see, POLLHUP is not documented as being a valid flag for input to WSAPoll(). Indeed, it does not match any of the above flags defined in winsock2.h:

    /* Event flag definitions for WSAPoll(). */
    
    #define POLLRDNORM  0x0100
    #define POLLRDBAND  0x0200
    #define POLLIN      (POLLRDNORM | POLLRDBAND)
    #define POLLPRI     0x0400
    
    #define POLLWRNORM  0x0010
    #define POLLOUT     (POLLWRNORM)
    #define POLLWRBAND  0x0020
    
    #define POLLERR     0x0001
    #define POLLHUP     0x0002
    #define POLLNVAL    0x0004
    

    POLLHUP is, however, documented as an output flag in the revents member of WSAPOLLFD:

    revents

    Type: short

    A set of flags that indicate, upon return from the WSAPoll function call, the results of the status query. This can a combination of the following flags.

    ...

    POLLHUP
    A stream-oriented connection was either disconnected or aborted.

    ...

    This matches the use of POLLHUP in poll() on *nix platforms:

    POLLHUP
    Hang up (only returned in revents; ignored in events). Note that when reading from a channel such as a pipe or a stream socket, this event merely indicates that the peer closed its end of the channel. Subsequent reads from the channel will return 0 (end of file) only after all outstanding data in the channel has been consumed.

    So, you don't need to (and on Windows, you cannot) explicitly request POLLHUP, you just get it for free.