Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

SSL_connect on non blocking socket: Works but need better

1,691 views
Skip to first unread message

Rij

unread,
Jul 31, 2009, 1:04:16 PM7/31/09
to
Hello,

I am using a non-blocking socket to connect to a server. I have the
following code which works fine. The issue is that the while loop
executes almost 3000 times! Is this expected? When I am waiting for
select/epoll to return, I was expecting it to return only when the
connection completes, much like blocking connect(). Is there a better
way of writing the code?

Thanks, Rij

ssl = SSL_new(ctx);
sbio = BIO_new_socket(sock, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);
connected = 0;
while (1)
{
r_code = SSL_connect(ssl);
if (r_code == 1)
break;

switch(SSL_get_error(ssl, r_code))
{
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
/* Wait for epoll/select to return */
break;
}
}
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List openss...@openssl.org
Automated List Manager majo...@openssl.org

Rij

unread,
Aug 1, 2009, 12:28:27 AM8/1/09
to
> If you get SSL_ERROR_WANT_READ, you need to epoll/select for readability. If
> you get SSL_ERROR_WANT_WRITE, you need to epoll/select for readability.
>

I am assuming the above was a typo and you meant writeability for
SSL_ERROR_WRITE.
Ok. That's interesting. I actually followed the concept from non
blocking tcp connect where you monitor the socket for both readability
and writeability. So accordingly I had set epoll to: EPOLLIN |
EPOLLOUT.

Now making the above change definitely helped. So now, the while loop
is executing once most of the time. But every once in a while (I
connect to 100 servers every 1 second), the value goes up to close to
100. Any particular reason for that?

Rij

unread,
Aug 4, 2009, 1:57:05 PM8/4/09
to
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

0 new messages