2017-10-01 5 views
1

Ich versuche, Daten von einem OpenSSL verknüpften Socket mit SSL_read zu lesen. Ich führe Openssl-Operationen im Client-Modus durch, der Befehle sendet und Daten von einem realen Server empfängt. Ich habe zwei Threads verwendet, wobei ein Thread alle OpenSSL-Operationen wie Verbinden, Schreiben und Schließen behandelt. Ich führe SSL_read in einem separaten Thread durch. Ich kann Daten richtig lesen, wenn ich SSL_read einmal ausstelle.SSL_read blockiert unbegrenzt

Aber ich stieß auf Probleme, wenn ich versuchte, mehrere verbinden, schreiben, schließen Sequenzen. Idealerweise sollte ich den Thread beenden, der SSL_read als Antwort auf Schließen ausführt. Das liegt daran, dass wir für die nächste Verbindung einen neuen ssl-Zeiger erhalten würden, und deshalb wollen wir keinen alten ssl-Zeiger lesen. Aber wenn ich SSL_read mache, stehe ich fest, bis Daten im SSL Puffer verfügbar sind. Es wird auf dem SSL-Zeiger blockiert, auch wenn ich die SSL-Verbindung in dem anderen Thread geschlossen habe.

while(1) { 
    memset(sbuf, 0, sizeof(uint8_t) * TLS_READ_RCVBUF_MAX_LEN); 

    read_data_len = SSL_read(con, sbuf, TLS_READ_RCVBUF_MAX_LEN); 
    switch (SSL_get_error(con, read)) { 
     case SSL_ERROR_NONE: 
. 
. 
. 
} 

Ich versuchte alle möglichen Lösungen für das Problem, aber funktioniert nicht. Meistens probierte ich Indikationen aus, um mich wissen zu lassen, dass es Daten im SSL-Puffer geben könnte, aber keine davon liefert eine korrekte Anzeige.

Ich habe versucht:

- Doing SSL_pending zuerst zu wissen, ob es Daten in SSL-Puffer ist. Aber das liefert immer Null

- Wählen Sie auf dem OpenSSL-Socket, um zu sehen, ob es Wert größer als Null zurückgibt. Aber es gibt immer Null zurück.

- Machen Sie den Sockel als nicht blockierend und versuchen Sie die Auswahl, aber es scheint nicht zu funktionieren. Ich bin mir nicht sicher, ob ich den Code richtig verstanden habe.

Ein Beispiel, wo ich ausgewählt habe, um Sockel zu blockieren, ist wie folgt. Aber Auswahl gibt immer Null zurück.

while(1) { 
    // The use of Select here is to timeout 
    // while waiting for data to read on SSL. 
    // The timeout is set to 1 second 
    i = select(width, &readfds, NULL, 
      NULL, &tv); 
    if (i < 0) { 
     // Select Error. Take appropriate action for this error 
    } 

    // Check if there is data to be read 
    if (i > 0) { 
     if (FD_ISSET(SSL_get_fd(con), &readfds)) { 
      // TODO: We have data in the SSL buffer. But are we 
      //  sure that the data is from read buffer? If not, 
      //  SSL_read can be stuck indefinitely. 
      //  Maybe we can do SSL_read(con, sbuf, 0) followed 
      //  by SSL_pending to find out? 
      memset(sbuf, 0, sizeof(uint8_t) * TLS_READ_RCVBUF_MAX_LEN); 

      read_data_len = SSL_read(con, sbuf, TLS_READ_RCVBUF_MAX_LEN); 
      error = SSL_get_error(con, read_data_len); 
      switch (error) { 
. 
. 
} 

So wie Sie sehen können wir verschiedene Weise versucht haben, den Faden der Durchführung SSL_read zu bekommen als Reaktion zu beenden, zu schließen, aber ich nicht, wie ich an der Arbeit zu erwarten. Hat jemand SSL_read richtig arbeiten lassen? Ist nicht blockierende Socket-Lösung nur mein Problem? Zum Blockieren von Sockets, wie lösen Sie das Problem des Beendens von SSL_read, wenn Sie nie eine Antwort für den Befehl erhalten? Können Sie ein Beispiel für eine funktionierende Lösung für nicht blockierende Sockets mit lesen geben?

Antwort

0

Ich kann Ihnen zu einem Arbeitsbeispiel der nicht-blockierenden Client-Socket mit SSL Punkt ... https://github.com/darrenjs/openssl_examples

Es nicht-blockierende Sockets mit Standard-Linux-IO (basierend auf Umfrage Ereignisschleife) verwendet. Rohdaten werden aus dem Socket gelesen und dann in SSL-Speicher-BIOs eingegeben, die dann die Entschlüsselung durchführen.

Der Ansatz, den ich verwendete, war single-threaded. Ein einzelner Thread führt das Verbinden, Schreiben und Lesen aus. Dies bedeutet, dass es keine Probleme geben kann, wenn ein Thread einen Socket schließt, während ein anderer Thread versucht, diesen Socket zu verwenden. Wie in der SSL-FAQ angegeben, kann "eine SSL-Verbindung nicht gleichzeitig von mehreren Threads verwendet werden" (https://www.openssl.org/docs/faq.html#PROG1), so dass ein Single-Thread-Ansatz Probleme mit gleichzeitigem SSL-Schreiben & lesen vermeidet.

Die Herausforderung bei Single-Threaded-Ansatz ist, dass Sie dann für die Einreichung und Halt von Daten anhängig für ausgehende (zB die Befehle, die Sie vom Client zum Server gesendet werden sollen) eine Art von synchronisierten Warteschlange & Signalmechanismus erstellen müssen, und Holen Sie sich die Socket-Event-Schleife, um zu erkennen, wann Daten zum Schreiben anstehen und ziehen Sie sie aus der Warteschlange usw. Dafür würde ich Standard std :: list, std :: mutex usw. und pipe2 oder eventfd für die Signalisierung des Ereignisses betrachten Schleife.