2012-04-24 36 views
6

Mam bibliotekę sieciową TCP, która implementuje pakiet protokołów (redis, http itp.) I są one implementowane za pomocą gniazd BSD.Integracja SSL z programem korzystającym z gniazd BSD

Dużo kodu używa select() i innych funkcji, które są przeznaczone dla gniazd BSD. Czy mam rację, zakładając, że to nie zadziała na gniazdach SSL? Czy będą działać tak, jak jest?

Zastanawiam się, czy gniazda SSL i BSD są tak różne, że wymagają zupełnie innego podejścia do implementacji.

+1

Komunikacja SSL wykorzystuje normalne gniazda "BSD", to tylko kolejny poziom protokołu, na przykład TCP. –

Odpowiedz

6

Zakładając, że odwołujesz się do OpenSSL, znajduje się on na górze gniazda, ale go nie zastępuje. Tak więc wszystkie operacje z użyciem gniazda bezpośredniego, takie jak select(), nadal działają. Różnica polega jednak na tym, że OpenSSL radzi sobie z czytaniem i pisaniem, więc możesz zastąpić recv() z ssl_read() i send() z ssl_write(), ale możesz (i w niektórych przypadkach trzeba) nadal korzystać bezpośrednio z select(). Jednak nie możesz po prostu wywoływać go w dowolnym momencie, musisz poczekać, aż OpenSSL każe Ci go wywołać. Na przykład jeśli masz pętlę odczytu, która najpierw wywołuje select(), a następnie wywołuje recv() tylko wtedy, gdy select() raportuje czytelność, musisz zamienić tę logikę. Zadzwoń ssl_read() pierwszy, a następnie zadzwonić select() tylko jeśli ssl_read() powraca albo SSL_ERROR_WANT_READ lub SSL_ERROR_WANT_WRITE (zauważ, że ssl_read() może wykonywać operacje wewnętrznie pisania i czytania ssl_write() może wykonywać operacje wewnętrznie).

2

Jedną z rzeczy, która przychodzi do głowy, jest to, że nie powinieneś robić wyboru na fd, przez który działa połączenie ssl. Dzieje się tak dlatego, że może na przykład powiedzieć, że możesz odczytać z niego, gdy blok ssl_read zostanie zablokowany. Dzieje się tak, na przykład, przez SSL, wykonując kluczową renegocjację, a nie dane aplikacji, aby stały się dostępne. To jedna z pułapek.

+1

właściwie, select() jest nadal używany, ale logika protokołu powinna sprawdzać, czy nie wybrać(), ale dostępność zdekodowanych danych w buforze. –

0

Może to się spóźnić, ale może służyć dobrym referencjom dla przyszłych użytkowników. Istnieje dobry wątek przy użyciu funkcji select() na url http://developerweb.net/viewtopic.php?id=6824. Jednym z przykładów, na które powołano się następująco

int sslsock_handle_nbio (ssl, ret, totv) 
    void   *ssl;   /* -> the SSL info      */ 
    int    ret;   /* the SSL I/O function return value */ 
    struct timeval *totv;   /* -> timeout info, or NULL    */ 
{ 
    int  sfd, i; 
    fd_set rset, wset; 

    sfd = SSL_get_fd (ssl); 
    i = SSL_get_error (ssl, ret); 

    if (i == SSL_ERROR_WANT_READ) { 
    do { 
     FD_ZERO (&rset); 
     FD_SET (sfd, &rset); 
     i = select (sfd + 1, &rset, NULL, NULL, totv); 
    } while ((i < 0) && (errno == EINTR)); 
    if (i == 0) { 
     /* the select() timed out */ 
     ret = -2; 
     errno = ETIMEDOUT; 
    } else { 
     /* either an error, or it's readable */ 
     ret = i; 
    } 
    } else if (i == SSL_ERROR_WANT_WRITE) { 
    do { 
     FD_ZERO (&wset); 
     FD_SET (sfd, &wset); 
     i = select (sfd + 1, NULL, &wset, NULL, totv); 
    } while ((i < 0) && (errno == EINTR)); 
    if (i == 0) { 
     /* the select() timed out */ 
     ret = -2; 
     errno = ETIMEDOUT; 
    } else { 
     /* either an error, or it's writable */ 
     ret = i; 
    } 
    } 
    /* else, leave "ret" alone, and return it as-is */ 

    return (ret); 
} 

to dopiero po wykonaniu SSL_read() lub SSL_write().