Hi David and others,

I was gone attending a conference and could not reply earlier.

David, I believe I am following your advise. Trying to connect and
wait only when SSL tells me to do so.

So here is what I have been doing, followed by the code.
1) Open a socket and make it non-blocking.
2) Add socket to epoll testing for writability.
3) When epoll returns, first do a TCP connect. If TCP connect
completes, move on to the next stage. Otherwise, monitor socket for
both readability and writeability and wait on epoll. When epoll
returns, tcp connect better be finished.
4) When TCP connect finishes, monitor the socket for writeability and
wait for epoll to return before I *start* the SSL connect. I am
dealing with many sockets so before I start SSL connect on the current
socket, I want to see if there is anything to do with some of the
other sockets (like reading/processing data).
5) Now, when epoll returns, I set up SSL specific parameters. Call
SSL_connect. If there is an error, call SSL_get_error. If it returns
*_WRITE/*_READ, I monitor the socket for EPOLLOUT/EPOLLIN and go back
and wait.
6) When epoll returns, I go back and try SSL_connect again.

Here is the code:

int main(int argc, char **argv)
{
        sock = socket(AF_INET, SOCK_STREAM, 0);

        // Set the socket as non-blocking
        mode = fcntl(sock, F_GETFL, 0);
        mode |= O_NONBLOCK;
        mode = fcntl(sock, F_SETFL, mode);

        // Set up epoll to be writeable
        ev.events = EPOLLOUT;
        ev.data.fd = sock;

        res = epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);

        state = TCP_CONNECT;
        while (!done)
        {
                num_fd = epoll_wait(epfd, events, MAXEVENTS, timeout_msec);
                action();
        }
}

//------------------------------------------------------------------------------

void action()
{
        switch (state)
        {
                case TCP_CONNECT:
                        if (tcp_connect())
                                state = SSL_CONNECT;
                        break;
                case SSL_CONNECT:
                        if (ssl_connect())
                                done = TRUE;
                        break;
        }       
}

//------------------------------------------------------------------------------

BOOL tcp_connect()
{
        struct sockaddr_in server_addr;
        int r_code, addrlen;

        if (first_time)
        {
                server_addr.sin_family = AF_INET;
                server_addr.sin_port = htons(443);
                server_addr.sin_addr.s_addr = some_addr;
                bzero(&(server_addr.sin_zero), 8);
                addrlen = sizeof(struct sockaddr);
                r_code = connect(sock, (struct sockaddr *)&server_addr, 
addrlen);

                if (r_code == 0)
                        return TRUE;

                if (errno == EINPROGRESS)
                {
                        ev.events = EPOLLIN | EPOLLOUT;
                        ev.data.fd = sock;
                        epoll_ctl(epfd, EPOLL_CTL_MOD, sock, &ev);
                }       
                else
                        exit(0);
                return FALSE;
        }

        r_code = getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen);
        if (r_code < 0 || optval != 0)
                return FALSE;
        
        /* Get ready for SSL connect */         
        ev.events = EPOLLOUT;
        ev.data.fd = sock;
        epoll_ctl(epfd, EPOLL_CTL_MOD, sock, &ev);
        return TRUE;
}

//------------------------------------------------------------------------------

BOOL ssl_connect()
{
        BIO *sbio;
        int r_code;

        if (first_time) // First time coming here
        {
                ssl = SSL_new(ctx);
                sbio = BIO_new_socket(sock, BIO_NOCLOSE);
                SSL_set_bio(ssl, sbio, sbio);
        }
        r_code = SSL_connect(ssl);
        if (r_code == 1)
                return TRUE;

        switch(SSL_get_error(ssl, r_code))
        {
                case SSL_ERROR_WANT_WRITE:
                        epoll_control(s_epfd, EPOLL_CTL_MOD, handle->sock, 
EPOLLOUT);
                        break;
                case SSL_ERROR_WANT_READ:       
                        epoll_control(s_epfd, EPOLL_CTL_MOD, handle->sock, 
EPOLLIN);
                        break;
        }
        return FALSE;
}



Any thoughts?

-Rij
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to