Hi,

I ran into the same problem a couple of days ago. I modified the
implementation of apr_poll_revents_get() to the attached file, to fix the
problem. Basically, if the socket is listening, then the WSARecv isn't done.
Also I added another fix where if the WSARecv returns zero bytes on a
stream-type socket, that indicates a graceful shutdown (APR_POLLHUP instead
of APR_POLLIN).

I can create a proper diff-style patch for this if people agree it's
sensible?

cya,
Saxon

----- Original Message -----
From: "INOUE Seiichiro" <[EMAIL PROTECTED]>
To: <[email protected]>
Sent: Monday, March 25, 2002 12:32 AM
Subject: [Q] apr_poll_revents_get() before apr_accept() on Windows


> Hi,
>
> I have a question about apr_poll_revents_get() behavior on Windows.
> I want to check whether the socket is apr_accept()'able.
> On Unix, I can check the socket becomes readable by apr_poll().
> On Windows, when I do the same thing, apr_poll_revents_get() returns
APR_POLLERR.
>
> In apr_poll_revents_get(), WSARecv() causes WSAENOTCONN,
> if the socket hasn't been apr_accept()'ed yet.
> (Windows2000 case. I don't know other Windows.)
>
> I attach a sample program for an easy reproduction.
>
> My question is,
> What is a proper solution?
> libapr should take care of it, or applications should?
>
> Thanks in advance.
>
> - INOUE Seiichiro <[EMAIL PROTECTED]>
>   http://www.ariel-networks.com
APR_DECLARE(apr_status_t) apr_poll_revents_get(apr_int16_t *event,
                                          apr_socket_t *sock,
                                          apr_pollfd_t *aprset)
{
    apr_int16_t revents = 0;
    WSABUF data;
    char buf[256];
    DWORD dummy;
    DWORD flags = MSG_PEEK;

    BOOL optval;
    int optlen;

    /* We just want to PEEK at the data, so I am setting up a dummy WSABUF
     * variable here.
     */
    data.len = sizeof(buf);
    data.buf = buf;

    if (FD_ISSET(sock->sock, aprset->read)) {
        revents |= APR_POLLIN;

        /* Check if the socket is listening for a connection (SO_ACCEPTCONN
         * is true) - if it is we just leave APR_POLLIN in revents and
         * don't attempt the WSARecv, since it would return WSAENOTCONN.
         */
        optlen = sizeof(optval);
        getsockopt(sock->sock, SOL_SOCKET, SO_ACCEPTCONN, (char *)&optval, 
            &optlen);
        if (!optval) {
            /* The socket is not listening */
            if (WSARecv(sock->sock, &data, 1, &dummy, &flags, NULL, 
                        NULL) == SOCKET_ERROR) {
                /* This is only legit since we don't return the error */
                dummy = WSAGetLastError();
                switch (dummy) {
                    case WSAECONNRESET:
                    case WSAECONNABORTED:
                    case WSAESHUTDOWN:
                    case WSAENETRESET: {
                        revents ^= APR_POLLIN;
                        revents |= APR_POLLHUP;
                        break;
                    }
                    case WSAENOTSOCK: {
                        revents ^= APR_POLLIN;
                        revents |= APR_POLLNVAL;
                    }
                    default: {
                        revents ^= APR_POLLIN;
                        revents |= APR_POLLERR;
                    }
                }
            }
            else if ((dummy == 0) && (sock->type == SOCK_STREAM)) {
                /* Zero bytes received (dummy is the number of bytes) 
                 * from a stream socket indicates graceful shutdown.
                 */
                revents ^= APR_POLLIN;
                revents |= APR_POLLHUP;
            }
        }
    }
    if (FD_ISSET(sock->sock, aprset->write)) {
        revents |= APR_POLLOUT;
    }
    /* I am assuming that the except is for out of band data, not a failed
     * connection on a non-blocking socket.  Might be a bad assumption, but
     * it works for now. rbb.
     */
    if (FD_ISSET(sock->sock, aprset->except)) {
        revents |= APR_POLLPRI;
    }

    (*event) = revents;
    return APR_SUCCESS;
}

Reply via email to