2016-07-05 16 views
2

Ich habe einen Netzwerkserver geschrieben, der OpenSSL für SSL/TLS verwendet. Der Server sendet und empfängt große Datenblöcke und führt dazwischen verschiedene Transformationen durch. Aus Performancegründen werden Transformationen hauptsächlich mit Vektorinformationen ausgeführt (siehe iovec von POSIX), die teure Speicherverschiebungen vermeiden (memcpy() usw.). Wenn Daten zum Senden bereit sind, verwende ich die writev() POSIX-Funktion, die Daten aus dem Speicher unter Verwendung dieser Vektoren sammelt und sie normalerweise als ein Netzwerkpaket sendet.OpenSSL SSL_write von mehreren Puffern/SSL_writev

Jetzt mit OpenSSL, ist es nicht vollständig möglich, weil OpenSSL nur die Funktion SSL_write() bietet, soweit ich weiß. Das heißt, ich muss diese Funktion für jeden Vektoreintrag aufrufen, den ich senden möchte. Dies führt leider dazu, dass jedes Vektor-Datenpaket in seinem eigenen SSL-Frame übertragen wird, was unerwünschten und unnötigen Netzwerk-Overhead mit sich bringt.

Meine Frage ist: Gibt es SSL_writev() entspricht writev()? Oder gibt es generell eine Technik, wie ich OpenSSL mitteilen kann, SSL_write() Daten in einen einzigen SSL-Anwendungsdatensatz (Typ 22) zu speichern, ohne es zu senden (und dann natürlich eine Art von flush() -Funktion)?

Bearbeiten: Wie unten diskutiert, ist ein praktikabler Ansatz, vectored Daten in einem großen Chunk vor einem abschließenden einzelnen Aufruf SSL_write() zu konsolidieren. Es gibt jedoch einen Overhead mit 2 Kopien (1. während der Konsolidierung, 2. wenn SSL_write() die AES-Verschlüsselung durchführt). Theoretischer Aufruf von SSL_writev() führt diesen Overhead nicht ein.

+0

Ich denke, dass Sie eine "Pull-up" -Funktion benötigen. Das heißt, eines, das mehrere Puffer zu einem kombiniert. – jww

+0

Genau das mache ich heute. Aber es ist ziemlich teuer b/c es bewegt sich ein großer Teil der Daten im Speicher. –

+0

Es scheint, als ob die großen Brocken die Kosten von TCP-Overhead amortisieren. Vielleicht sollten Sie die separaten Schreibvorgänge für große Daten zulassen und nur kleinere aufziehen. Wenn Sie mit '-march = native' und' -O3' kompilieren, sollten Sie die SSE4- und AVX-Versionen von 'memcpy' und' memmove' auf moderner Hardware bekommen. Sie sind blitzschnell, weil sie sich 16, 32 und 64 Bytes gleichzeitig bewegen. – jww

Antwort

0

Sie können eine BIO_f_buffer() verwenden, um dies zu erreichen. Wickeln Sie Ihre BIO-Netzwerkschicht in eine BIO_f_buffer()-Filter-BIO ein und legen Sie diese als BIO-Schreibzugriff für Ihr SSL-Objekt fest. Dies führt dazu, dass alle ausgeschriebenen Daten im Puffer bleiben, bis Sie eine Flush-Operation ausführen.

+0

Übrigens sollten Sie warten, bis der Handshake abgeschlossen ist. Andernfalls müssen Sie für jeden Flug von Handshake-Nachrichten, die ausgetauscht werden, manuell "Flush" -Befehle eingeben. –

+0

Zustimmen, aber es wird immer noch ein SSL-Anwendungsdatensatz (Typ 23) für jeden Aufruf von SSL_write erstellt. Das bedeutet einen unerwünschten Netzwerk-Overhead, den ich vermeiden möchte. –

+0

Ja, es wird - obwohl es aus Ihrer Beschreibung klang, als ob Ihr Hauptanliegen war, mehrere Netzwerkpakete * zu vermeiden. Das ist anders als bei einem TLS-Datensatz. Mehrere Datensätze können in einem einzelnen TCP-Paket enthalten sein oder über mehrere verteilt sein. Durch Pufferung und Spülung in der Art, wie ich vorschlage, bietet die Netzwerkschicht die beste Möglichkeit, die Daten möglichst effizient über das Netzwerk zu übertragen. Der Overhead ist dann auf die zusätzlichen Datensatz-Header-Bytes (5 Bytes) plus die MAC-Größe (abhängig von der Cipher-Suite) beschränkt. Wenn Ihr Ziel ist, die Anzahl der Datensätze zu reduzieren, dann ... –