s4-lib/tls: Try socket_send() multiple times to send partial packets
authorAndrew Bartlett <abartlet@samba.org>
Wed, 18 Jul 2012 05:28:50 +0000 (15:28 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 18 Jul 2012 09:23:55 +0000 (11:23 +0200)
This works around an artificial limitation in socket_wrapper that breaks
some versions of GnuTLS when we return a short write.

Instead, keep pushing until the OS will not take it.

The correct solution will be to use tls_tstream, but the client code
for this is not yet tested and needs the ldap client layer changed
to use it.

Andrew Bartlett

Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Wed Jul 18 11:23:55 CEST 2012 on sn-devel-104

source4/lib/tls/tls.c

index 7bf2ff8e432a3d7db24f29d08f9c7a714caf2af7..db6d1eb5def7eda011f3d1a220e0a63ecb380eb7 100644 (file)
@@ -152,7 +152,7 @@ static ssize_t tls_push(gnutls_transport_ptr ptr, const void *buf, size_t size)
 {
        struct tls_context *tls = talloc_get_type(ptr, struct tls_context);
        NTSTATUS status;
-       size_t nwritten;
+       size_t nwritten, total_nwritten = 0;
        DATA_BLOB b;
 
        if (!tls->tls_enabled) {
@@ -162,19 +162,32 @@ static ssize_t tls_push(gnutls_transport_ptr ptr, const void *buf, size_t size)
        b.data = discard_const(buf);
        b.length = size;
 
-       status = socket_send(tls->socket, &b, &nwritten);
-       if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
-               errno = EAGAIN;
-               return -1;
-       }
-       if (!NT_STATUS_IS_OK(status)) {
-               TEVENT_FD_WRITEABLE(tls->fde);
-               return -1;
-       }
-       if (size != nwritten) {
+       /* Cope with socket_wrapper 1500 byte chunking for PCAP */
+       do {
+               status = socket_send(tls->socket, &b, &nwritten);
+               
+               if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+                       errno = EAGAIN;
+                       return -1;
+               }
+               if (!NT_STATUS_IS_OK(status)) {
+                       TEVENT_FD_WRITEABLE(tls->fde);
+                       return -1;
+               }
+
+               total_nwritten += nwritten;
+
+               if (size == nwritten) {
+                       break;
+               }
+
+               b.data += nwritten;
+               b.length -= nwritten;
+
                TEVENT_FD_WRITEABLE(tls->fde);
-       }
-       return nwritten;
+       } while (b.length);
+
+       return total_nwritten;
 }
 
 /*