jpe*_*pen 7 c openssl cross-compiling
libcurl有这样的超时选项:
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.
Run Code Online (Sandbox Code Playgroud)
我想在OpenSSL中实现类似的超时机制.
下面的代码需要进行哪些更改,以便将超时值应用于BIO_do_connect(),BIO_write()和BIO_read()?
我正在使用OpenSSL提供的BIO_write()/ BIO_read()连接到服务器并向/从服务器发送/接收数据.我的代码是基于可从下面的示例代码在这里.
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;
}
Run Code Online (Sandbox Code Playgroud)
我在Ubuntu上用ARM交叉编译(带有CodeSourcery Lite的Eclipse).
我最终做了类似下面的事情(伪代码):
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.
}
Run Code Online (Sandbox Code Playgroud)
您也可以对BIO_read()使用相同的方法.
您可能会发现此链接很有用.
对于连接,@jpen 在那里给出了最好的答案。您必须将 BIO 标记为非阻塞并select用于确定它是否已连接和/或超时。
读取有点不同。因为 OpenSSL 可能会缓冲解密的数据(取决于所使用的 TLS 密码套件),所以select在您尝试读取时可能会超时 - 即使数据实际上可用。处理读取超时的正确方法是首先检查SSL_pending或BIO_pending。如果挂起的函数返回零,则使用 select 设置超时。如果挂起函数返回大于零,则只需调用SSL_read或BIO_read或任何其他读取函数。