s3:smb2_server: generate a header blob for the sendfile path
authorStefan Metzmacher <metze@samba.org>
Mon, 14 Oct 2013 12:18:26 +0000 (14:18 +0200)
committerStefan Metzmacher <metze@samba.org>
Wed, 27 Nov 2013 13:39:11 +0000 (14:39 +0100)
We need to pass the NBT header, SMB2 header and SMB2 Read header
as header blob to SMB_VFS_SENDFILE(). This allows the usage
of MSG_SEND or other tricks to avoid multiple TCP packets
on the wire.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: David Disseldorp <ddiss@samba.org>
source3/smbd/globals.h
source3/smbd/smb2_read.c
source3/smbd/smb2_server.c

index 5809ad76f1e42f5aa107800c00c0bc48b1f7bee5..e2c763bafd3641adf02dc99bd2da5d85454b69e1 100644 (file)
@@ -470,6 +470,7 @@ NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id);
 struct smbd_smb2_send_queue {
        struct smbd_smb2_send_queue *prev, *next;
 
+       DATA_BLOB *sendfile_header;
        struct iovec *vector;
        int count;
 
index 41adb03408393ececb6680e1a833734b94c57c5e..d6d3d908787e248ebaa40600c0902defec51c3b4 100644 (file)
@@ -166,6 +166,7 @@ struct smbd_smb2_read_state {
        uint32_t in_length;
        uint64_t in_offset;
        uint32_t in_minimum;
+       DATA_BLOB out_headers;
        DATA_BLOB out_data;
        uint32_t out_remaining;
 };
@@ -180,10 +181,10 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
        ssize_t nread;
 
        nread = SMB_VFS_SENDFILE(fsp->conn->sconn->sock,
-                                       fsp,
-                                       NULL,
-                                       in_offset,
-                                       in_length);
+                                fsp,
+                                state->smb2req->queue_entry.sendfile_header,
+                                in_offset,
+                                in_length);
        DEBUG(10,("smb2_sendfile_send_data: SMB_VFS_SENDFILE returned %d on file %s\n",
                (int)nread,
                fsp_str_dbg(fsp) ));
@@ -301,6 +302,7 @@ static NTSTATUS schedule_smb2_sendfile_read(struct smbd_smb2_request *smb2req,
        }
        *state_copy = *state;
        talloc_set_destructor(state_copy, smb2_sendfile_send_data);
+       state->smb2req->queue_entry.sendfile_header = &state_copy->out_headers;
        return NT_STATUS_OK;
 }
 
index ee5747d227e217444fdc07c2fe241c1b3cf8800f..a3ed09bbb21ea33a275e2dece1d805abbb7b1357 100644 (file)
@@ -2680,7 +2680,7 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
                do_encryption = true;
        }
 
-       state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
+       state = talloc_zero(sconn, struct smbd_smb2_send_oplock_break_state);
        if (state == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -2983,6 +2983,38 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn)
        while (sconn->smb2.send_queue != NULL) {
                struct smbd_smb2_send_queue *e = sconn->smb2.send_queue;
 
+               if (e->sendfile_header != NULL) {
+                       size_t size = 0;
+                       size_t i = 0;
+                       uint8_t *buf;
+
+                       for (i=0; i < e->count; i++) {
+                               size += e->vector[i].iov_len;
+                       }
+
+                       buf = talloc_array(e->mem_ctx, uint8_t, size);
+                       if (buf == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+
+                       size = 0;
+                       for (i=0; i < e->count; i++) {
+                               memcpy(buf+size,
+                                      e->vector[i].iov_base,
+                                      e->vector[i].iov_len);
+                               size += e->vector[i].iov_len;
+                       }
+
+                       e->sendfile_header->data = buf;
+                       e->sendfile_header->length = size;
+                       e->count = 0;
+
+                       sconn->smb2.send_queue_len--;
+                       DLIST_REMOVE(sconn->smb2.send_queue, e);
+                       talloc_free(e->mem_ctx);
+                       continue;
+               }
+
                ret = writev(sconn->sock, e->vector, e->count);
                if (ret == 0) {
                        /* propagate end of file */