libcurl有这样的timeout options:
CURLOPT_CONNECTTIMEOUT - maximum time in seconds that you allow the connection to the server to take.
CURLOPT_TIMEOUT - maximum time in seconds that you allow the libcurl transfer operation to take.
我想在OpenSSL中实现类似的超时机制。
下面的代码需要进行哪些更改,以便将超时值应用于BIO_do_connect(),BIO_write()和BIO_read()?
我正在使用OpenSSL提供的BIO_write()/ BIO_read()连接到服务器并向/从服务器发送/接收数据。我的代码基于here提供的以下示例代码。
int main()
{
BIO * bio;
SSL * ssl;
SSL_CTX * ctx;
int p;
char * request = "GET / HTTP/1.1\x0D\x0AHost: www.verisign.com\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A";
char r[1024];
/* Set up the library */
ERR_load_BIO_strings();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
/* Set up the SSL context */
ctx = SSL_CTX_new(SSLv23_client_method());
/* Load the trust store */
if(! SSL_CTX_load_verify_locations(ctx, "TrustStore.pem", NULL))
{
fprintf(stderr, "Error loading trust store\n");
ERR_print_errors_fp(stderr);
SSL_CTX_free(ctx);
return 0;
}
/* Setup the connection */
bio = BIO_new_ssl_connect(ctx);
/* Set the SSL_MODE_AUTO_RETRY flag */
BIO_get_ssl(bio, & ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
/* Create and setup the connection */
BIO_set_conn_hostname(bio, "www.verisign.com:https");
if(BIO_do_connect(bio) <= 0)
{
fprintf(stderr, "Error attempting to connect\n");
ERR_print_errors_fp(stderr);
BIO_free_all(bio);
SSL_CTX_free(ctx);
return 0;
}
/* Check the certificate */
if(SSL_get_verify_result(ssl) != X509_V_OK)
{
fprintf(stderr, "Certificate verification error: %i\n", SSL_get_verify_result(ssl));
BIO_free_all(bio);
SSL_CTX_free(ctx);
return 0;
}
/* Send the request */
BIO_write(bio, request, strlen(request));
/* Read in the response */
for(;;)
{
p = BIO_read(bio, r, 1023);
if(p <= 0) break;
r[p] = 0;
printf("%s", r);
}
/* Close the connection and free the context */
BIO_free_all(bio);
SSL_CTX_free(ctx);
return 0;
}
我在Ubuntu上用ARM交叉编译(带有CodeSourcery Lite的Eclipse)。
答案 0 :(得分:6)
我最终做了类似下面的事情(伪代码):
int nRet;
int fdSocket;
fd_set connectionfds;
struct timeval timeout;
BIO_set_nbio(pBio, 1);
nRet = BIO_do_connect(pBio);
if ((nRet <= 0) && !BIO_should_retry(pBio))
// failed to establish connection.
if (BIO_get_fd(pBio, &fdSocket) < 0)
// failed to get fd.
if (nRet <= 0)
{
FD_ZERO(&connectionfds);
FD_SET(fdSocket, &connectionfds);
timeout.tv_usec = 0;
timeout.tv_sec = 10;
nRet = select(fdSocket + 1, NULL, &connectionfds, NULL, &timeout);
if (nRet == 0)
// timeout has occurred.
}
您也可以对BIO_read()使用相同的方法。
您可能会发现this link有用。
答案 1 :(得分:2)
为了连接,@ jpen在那里给出了最好的答案。您必须将BIO标记为非阻止,并使用select
来确定它是否已连接和/或超时。
阅读有点不同。由于OpenSSL可能会缓冲解密数据(取决于所使用的TLS密码套件),因此当您尝试读取时,select
可能会超时 - 即使数据实际可用。处理读取超时的正确方法是首先检查SSL_pending
或BIO_pending
。如果pending函数返回零,则使用select设置超时。如果pending函数返回大于零,则只需调用SSL_read
或BIO_read
或任何其他读取函数。
答案 2 :(得分:-1)
查看SSL_CTX_set_timeout ()
函数,它与libcurl的CURLOPT_TIMEOUT
变量类似:
来自http://www.openssl.org/docs/ssl/SSL_CTX_set_timeout.html:
SSL_CTX_set_timeout()将新创建的ctx会话的超时设置为t。超时值t必须以秒为单位。
在您的情况下,您可以在创建ctx对象后添加以下行:
SSL_CTX_set_timeout (ctx, 60);
希望它有所帮助!