2011-12-11 13 views
15

Sto provando a fare amici asio e SSL. Tutto sta andando bene, ma una cosa sta causando disagio: come rilevare se la connessione peer close e distinguerla dalla situazione quando peer basta fare una breve pausa nell'invio dei dati, con l'obiettivo di continuare pochi secondi dopo?boost :: flusso SSL asincrono e asincrono: come rilevare la fine della connessione dati/connessione?

  • spinta 1.48
  • OpenSSL 1.0.0e
  • compilato in codice a 32 bit utilizzando VS10
  • Lavorare su W7 x64.

La mia confusione deriva dal fatto che il comportamento di asio è diverso per il socket ordinario e il flusso SSL. Se uso tcp :: socket - ricevo l'errore EOF quando la connessione peer close. Ma per boost :: asio :: ssl :: stream - è non è il caso. Invece, async_read_some restituisce 0 come byte trasferito, e se provo a continuare a leggere da SSL stream - restituisce short_error (http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/streams.html).

Quindi, la domanda è: è il comportamento previsto o non si configura nulla?

codice

Cliente frammento di:.

class client 
{ 
public: 

    // bla-bla-bla-bla-bla .... 
    // 
    void handle_write(const boost::system::error_code& error) 
    { 
     if (!error) 
     { 
      socket_.async_read_some(boost::asio::buffer(reply_, max_length), 
       boost::bind(&client::handle_read, this, 
       boost::asio::placeholders::error, 
       boost::asio::placeholders::bytes_transferred)); 
     } 
     else 
     { 
      std::cout << "Write failed: " << error.message() << "\n"; 
     } 
    } 

    void handle_read(const boost::system::error_code& error, 
        size_t bytes_transferred) 
    { 

     std::cout << "Bytes transfered: " << bytes_transferred << "\n"; 
     if (!error) 
     { 
      std::cout << "Reply: "; 
      std::cout.write(reply_, bytes_transferred); 
      std::cout << "\n"; 

      std::cout << "Reading...\n"; 
      socket_.async_read_some(boost::asio::buffer(reply_, max_length), 
       boost::bind(&client::handle_read, this, 
       boost::asio::placeholders::error, 
       boost::asio::placeholders::bytes_transferred)); 
     } 
     else if (0 != bytes_transferred) 
     { 
      std::cout << "Read failed: " << error.message() << ":" 
        << error.value() << "\n"; 
     } 
    } 

private: 
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; 
    boost::asio::streambuf request_; 
    char reply_[max_length]; 
}; 

Se togliamo if (! = 0 bytes_transferred), ci arriveremo "breve lettura" :(

Se useremo codice come-ai , output sarà simile a questo:

richiesta è:

GET/HTTP/1.0

Cookie: Nama-nama = Vala-Vala

Bytes trasferito: 1024

Rispondi: HTTP/1.0 200 OK Content-Type: text/html

..... bla -BLA-bla ....

Reading ... Byte trasferiti: 1024

..... bla-bla-bla .... ..... bla-bla-bla ....

Reading ... Byte trasferiti: 482

..... bla-bla-bla ....

Reading ...

byte trasferiti: 0

Allo stesso tempo, se invece async_read_some scriviamo codice, quello che per presa ordinaria restituirà EOF:

boost::asio::async_read(socket_, response_, 
    boost::asio::transfer_at_least(1), 
    boost::bind(&client::handle_read_content, this, 
    boost::asio::placeholders::error)); 

poi per SSL-socket faremo ottieni 0 come byte trasferiti, quindi short_read.

So che non c'è modo di rilevare la disconnessione nel caso in cui peer, per esempio , fosse appena scollegato dalla rete. Ma come rilevare la disconnessione peer clean esplicita dalla situazione quando il peer non invia dati per un po 'di tempo, ma potrebbe farlo lo un po' più tardi?

Oppure, può essere che non capisco qualcosa?

WBR, Andrey

Alcuni clausola aggiuntiva: SSL/TLS ha la notazione per informare altre parti di chiudere il collegamento. It close_notify alert. Anche il socket TCP sottostante può essere chiuso.

Quindi, fondamentalmente, la mia domanda è: perché, nelle stesse condizioni (il socket TCP è stato chiuso in modo chiaro) ricevo EOF in caso di tcp :: socket, e non ricevo nulla per boost :: asio :: ssl: : flusso.

È una funzionalità di bug o asio?

Ancora un addentum: Per alcuni motivi, asio non mi ha fornito un EOF né se SSL ha ricevuto close_notify né il socket TCP sottostante è stato chiuso.

Sì, sono in grado di rilevare le connessioni morte per timeout. Ma come posso rilevare connessioni SSL correttamente chiuse? Ricevendo short_read?

risposta

5

Potreste essere interessati a queste discussioni:

In sostanza, il fatto che si ottiene un EOF a volte (anche la maggior parte del tempo), quando la parte remota disconnette un semplice socket TCP è solo fortuna. Non si può fare affidamento su di esso nel caso generale, dal momento che non è in alcun modo possibile distinguere tra una presa inattiva e una presa chiusa bruscamente senza scriverle.

È necessario definire alcuni delimitatori, a livello di protocollo dell'applicazione, per sapere quando interrompere la lettura. In HTTP, ciò avviene tramite la riga vuota che termina l'intestazione (per l'intestazione), l'intestazione Content-Length che definisce la lunghezza del corpo oi delimitatori chunked transfer encoding quando la lunghezza del corpo non è nota in anticipo.

+1

SSL/TLS ha notazione per informare l'altra parte sulla chiusura della connessione. It close_notify alert. Anche il socket TCP sottostante viene chiuso. Quindi, sostanzialmente, la mia domanda era: perché, nelle stesse condizioni (il socket TCP era chiuso in modo chiaro) ricevo EOF in caso di tcp :: socket, e non ricevo nulla per boost :: asio :: ssl :: stream . È un bug o una funzionalità? – Amdei

+0

Certo, 'close_notify' è per chiusure pulite, che non ti aiuteranno a rilevare quelle cattive. Non so molto su 'boost :: asio :: ssl :: stream', ma suppongo che tu stia facendo operazioni asincrone e la chiusura SSL/TLS causerà problemi con operazioni asincrone (vedi link" Chiusura corretta SSLSocket ") sopra). Potrebbe spiegare un comportamento leggermente diverso. In ogni caso, non importa. Non sarebbe un bug che deve essere corretto, dal momento che non è il modo corretto di scoprire quando interrompere la lettura da uno stream/socket. – Bruno

+0

A proposito, non sono sicuro di cosa intendessi per "* Chiudi alert_notify, anche se il socket TCP sottostante è chiuso. *", Ma un avviso di chiusura TLS non implica che il socket TCP sottostante debba essere chiuso. – Bruno

14

L'errore SSL_R_SHORT_READ è previsto qui. Quando il server avvia un arresto pulito con SSL_Shutdown, invia l'avviso di chiusura notifica di chiusura al client. L'implementazione di Asio mappa questo in un errore SSL_R_SHORT_READ con la categoria di error::get_ssl_category().Lo fa rilevando se il peer ha avviato l'arresto tramite SSL_get_shutdown.

Questo può essere visto ispezionando l'intestazione asio/ssl/detail/impl/engine.ipp e in particolare la funzione engine::map_error_code(boost::system::error_code&).

Credo che l'implementazione di ssl sia stata riscritta in boost 1.47, quindi le versioni precedenti hanno un comportamento potenzialmente diverso.

+0

Non vedo una lettura breve. l'host remoto chiama shutdown, quindi la lettura dell'host locale verrà completata con eof Se entrambi gli host chiamano shutdown, le chiamate allo shutdown verranno completate con eof Questi sono ssl :: stream shutdowns, non TCP/IP shutdown. lo conferma. –