2013-04-06 7 views
6

Libcurl hat timeout options wie diese:Wie in OpenSSL Verbindungszeit und Betrieb Timeout einstellen

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. 

Ich mag einen ähnlichen Timeout-Mechanismus in OpenSSL implementieren.

Welche Änderungen wären im folgenden Code erforderlich, damit ein Timeout-Wert auf BIO_do_connect(), BIO_write() und BIO_read() angewendet wird?

Ich verbinde mich mit einem Server und senden/empfangen Daten zu/von dem Server mit BIO_write()/BIO_read(), die OpenSSL bietet. Mein Code basiert auf dem folgenden Beispielcode, der von here verfügbar ist.

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; 
} 

Ich bin Cross-Kompilierung für ARM auf Ubuntu (Eclipse CodeSourcery Lite).

+0

verwandt: [openssl ssl_connect Blöcke für immer - wie Timeout festlegen?] (Http://stackoverflow.com/questions/11835203/openssl-ssl-connect-blocks-forever-how-to-set-timeout) – jfs

Antwort

5

ich am Ende etwas zu tun, wie folgt aus (Pseudo-Code) auf:

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. 
} 

Sie den gleichen Ansatz für BIO_read verwenden können (auch).

Sie könnten this link nützlich finden.

+0

Seien Sie vorsichtig, wenn Sie dies mit 'BIO_read' verwenden. Die [Dokumentation] (https://www.openssl.org/docs/manmaster/crypto/BIO_read.html) besagt, dass 'BIO_read' mehrere Aufrufe von' read' zur Folge haben kann, die möglicherweise über das angegebene Zeitlimit hinaus blockiert werden. –

+0

Kannst du deinen tatsächlichen Code oder einen Link dazu posten? – am3

-1

Werfen Sie einen Blick auf SSL_CTX_set_timeout() Funktion, die CURLOPT_TIMEOUT Variable Libcurl die ähnlich funktioniert:

Von http://www.openssl.org/docs/ssl/SSL_CTX_set_timeout.html:

SSL_CTX_set_timeout() setzt das Timeout für neu erstellte Sitzungen für ctx bis t. Der Timeout-Wert t muss in Sekunden angegeben werden.

In Ihrem Fall könnten Sie die folgende Zeile hinzufügen, nachdem Sie CTX-Objekt erstellen:

SSL_CTX_set_timeout (ctx, 60); 

Hoffe, es hilft!

+0

@ Wizzard: Ich bin mir nicht sicher, ob ich danach gesucht habe. Vielen Dank für Ihre Antwort. – jpen

+1

Ich glaube, 'SSL_CTX_set_timeout' und' SSL_SESSION_set_timeout' sind die Zeitüberschreitung für Session Caching und Wiederaufnahme; und kein Timeout für 'select'. – jww

2

Zum Verbinden gab @jpen dort die beste Antwort. Sie müssen das BIO als nicht blockierend markieren und select verwenden, um festzustellen, ob es verbunden und/oder abgelaufen ist.

Liest sind ein wenig anders. Da OpenSSL entschlüsselte Daten puffern kann (abhängig von der verwendeten TLS-Verschlüsselungssuite), select kann Timeout, wenn Sie versuchen zu lesen - auch wenn Daten tatsächlich verfügbar sind. Die richtige Art, Lese-Timeouts zu verarbeiten, besteht darin, zuerst SSL_pending oder BIO_pending zu überprüfen. Wenn die ausstehende Funktion null zurückgibt, verwenden Sie die Option zum Festlegen eines Zeitlimits. Wenn die ausstehende Funktion größer als Null ist, rufen Sie einfach SSL_read oder BIO_read oder eine andere Lesefunktion an.