非阻塞连接OpenSSL

时间:2014-04-23 00:36:54

标签: c++ c sockets openssl

我创建了一个普通的C套接字。连接后,它会按预期返回EWOULDBLOCK/WSAEWOULDBLOCK,因为我做了:

unsigned long int mode = 0;
ioctlsocket(ssl_info->sock, FIONBIO, &mode);
setsockopt(ssl_info->sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
setsockopt(ssl_info->sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));

将套接字置于非阻塞模式。之后我做了:

ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
return SSL_connect(ssl);

然而,它返回-1。

我在线阅读这意味着我需要处理SSL_ERROR_WANT_READSSL_ERROR_WANT_WRITE

所以我做了:

int res = -1;
while(res == -1)
{
    res = SSL_connect(ssl);
    switch (SSL_get_error(ssl, res))
    {
        case SSL_ERROR_WANT_CONNECT:
        MessageBox(NULL, "Connect Error", "", 0);
        break;

        case SSL_ERROR_WANT_READ:   //prints this every time..
        MessageBox(NULL, "Read Error", "", 0);
        break;

        case SSL_ERROR_WANT_WRITE:
        MessageBox(NULL, "Write Error", "", 0);
        break;
    }

    SelectSocket(ssl);
}

std::cout<<"Connected!\n";

SelectSocket定义为:

bool SelectSocket(SSL* ssl)
{
    if (blockmode)
    {
        fd_set readfds;
        fd_set writefds;
        FD_ZERO(&readfds);
        FD_ZERO (&writefds);
        FD_SET(ssl_info->sock, &readfds);
        FD_SET(ssl_info->sock, &writefds);

        struct timeval tv = {0};
        tv.tv_sec = timeout / 1000;
        tv.tv_usec = timeout % 1000;
        return select(sock + 1, &readfds, &writefds, NULL, &tv) >= 0;
    }

    return select(sock + 1, NULL, NULL, NULL, NULL) != SOCKET_ERROR;
}

那么我怎么能连接它呢?当套接字无阻塞时,我似乎无法读取或写入任何内容:S。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您的代码实际上禁用非阻塞I / O.当您将0作为FIONBIO的参数值传递给ioctlsocket时,记录为:

  

FIONBIO

     
    

* argp参数是指向unsigned long值的指针。如果非阻止模式启用,则将* argp设置为非零值;如果非阻止模式应为,则将* argp设置为非零值 禁用。 [..]

  

https://msdn.microsoft.com/en-us/library/windows/desktop/ms738573%28v=vs.85%29.aspx

答案 1 :(得分:1)

SSL_connect()返回的(-1)表示底层BIO无法满足SSL_connect()的需要以继续握手。

通常,调用进程必须在采取适当的操作以满足SSL_connect()的需要后重复调用。

然而,当使用非阻塞套接字时,不需要做任何事情;但是select()可以用来检查所需的条件。

(当使用缓冲BIO时,如BIO对,必须先将数据写入BIO或从BIO中检索,然后才能继续。)