Dr. Stephen Henson wrote:
On Wed, Sep 12, 2007, Jim Marshall wrote:

I have setup my BIO to be non-blocking in my server. In my server I want to use 'select' to detect when there is a connection available, but for some reason it is not working. either select returns '-1' with errno set to EINTR or select returns 0, but it has not waited for 2 seconds for a connection. Maybe someone can give me an idea what I am doing wrong?

here is the code I am using:

void startListening(BIO* sock) {
        int acceptSock = BIO_get_fd(sock, NULL);
        int waitVal = 0;
        fd_set rfds, wfds, efds;
        struct timeval tv;
        /* Wait up to two seconds. */
        tv.tv_sec = 2;
        tv.tv_usec = 0;
        /* This is just one of the tests I have tried */
        FD_ZERO(&rfds);
        FD_SET(acceptSock, &rfds);
        FD_ZERO(&wfds);
        FD_SET(acceptSock, &wfds);
        FD_ZERO(&rfds);
        FD_SET(acceptSock, &efds);
        do {
                /* see if we have any activity on the socket */
                waitVal = select(acceptSock, &rfds, &wfds, &efds, &tv);
                if (waitVal < 0)
                {
                    char* err = strerror(errno);
                    printf("select error: %s\n", err);
                    fflush(stdout);
                    return;
                } if (waitVal > 0) {
                        BIO_do_accept(sock)
                        handleAccept(sock);
                }
            } while (waitVal == 0);
...
}

If I change this code to do a 'BIO_do_accept' and the call 'sleep(1)' when 'BIO_do_accept' returns -1 and errno is EAGAIN it seems to work fine. But that means my server could be sleeping when a request come in.

Any thoughts?

Thanks
Jim

p.s.
 The BIO passed into the function above is created like this:

        ret = BIO_new_accept(hostString);
        if (ret != NULL)
        {
            /* set the accept socket to non-blocking */
            BIO_set_nbio_accept(ret, 1);
/* set sockets created from this accept socket to non-blocking */
            BIO_set_nbio(ret, 1);
            BIO_set_bind_mode(ret, BIO_BIND_REUSEADDR);
            /* bind & listen */
            val = BIO_do_accept(ret)
...

it is returned to a calling function which in turn calls startListening.


Well you should loop round calling BIO_do_accept() in the startListening()
function and not call it outside. Check the return value and if >0 a
connection has occurred and you can process it.

If <=0 check the status with BIO_should_retry() if that returns 0 some error
has occurred.

If BIO_should_retry() is true get the fd from the BIO and wait for a
connection condition: what you wait for depends on the OS but select (or
similar) for a read condition is typical.

Steve.
--
Dr Stephen N. Henson. Email, S/MIME and PGP keys: see homepage
OpenSSL project core developer and freelance consultant.
Funding needed! Details on homepage.
Homepage: http://www.drh-consultancy.demon.co.uk
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Hi Steve,
Thanks again for your help. What you suggested is very similar to what I was doing orginally (although I was using errno and not BIO_should_retry). When the code is setup as you describe (see code below) what happens is that the first couple of times the 'select' call is made it returns with a -1 with errno set to EINTR. If I let it continue it does this like 4 times and then select 'seems' to start working, in that it will actually timeout (wait 2 seconds before returning). However client connections are never detected. For example if I connect with the openssl command line tool, the tool says

"CONNECTED(00000003)"

But select just continues to return 0 (and the app pauses for 2 seconds at a time).

void startListening(BIO* sock)
{
    int acceptRet = -1;
    acceptRet = BIO_do_accept(sock);
    if (acceptRet > 0)
    {
        BIO* client = NULL;
        SSL* ssl = NULL;
        client = BIO_pop(sock);
        BIO_set_nbio_accept(client, 1);
        ssl = SSL_new(gCtx);
        if (ssl != NULL)
        {
            SSL_set_bio(ssl, client, client);
            SSL_set_accept_state(ssl);
            starthandler(ssl))
        } else {
            handleSSLError("SSL_startListening");
        }
    } else {
        if (BIO_should_retry(sock) == 0)
        {
            int reason = 0;
            (void) BIO_get_retry_BIO(sock, &reason);
printf("SSL_startListening: BIO_do_accept returned %d, error: %s",
            reason, strerror(reason));
        } else {
            int waitVal = 0;
            acceptRet = BIO_get_fd(sock, NULL);
            do {
                fd_set fds;
                struct timeval tv;
                /* Wait up to two seconds. */
                tv.tv_sec = 2;
                tv.tv_usec = 0;
                /* Watch the socket to see when it has input. */
                FD_ZERO(&fds);
                FD_SET(acceptRet, &fds);
                /* see if we have any activity on the socket */
                waitVal = select(acceptRet, &fds, NULL, NULL, &tv);
                if (waitVal < 0)
                {
                    char* err = strerror(errno);
                    printf("select error: %s\n", err);
                    fflush(stdout);
                    if (errno != EINTR) return;
                }
            } while (waitVal == 0);
        }
    }
}

Note if I change the final else clause to just do a "Sleep(1)" I can accept connections no problem.

I appreciate any feedback. I'm sure I'm doing something wrong...

Thanks
Jim

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to