[PATCH] Fix bug 9412 - SMB2 server doesn't support recvfile.
Jeremy Allison
jra at samba.org
Mon Apr 8 17:28:21 MDT 2013
On Fri, Apr 05, 2013 at 09:20:08AM +0200, Stefan (metze) Metzmacher wrote:
>
> As the socket is non-blocking, we need to make sure recvfile()
> doesn't get EAGAIN. We could extent the tstream_readv_pdu code
> to handle an iovec with iov_len != 0 and iov_base == NULL.
> This could be used to wait until the whole request arrived
> in the kernel, by checking tstream_pending_bytes().
> Or we have to mark the socket blocking during for recvfile() and
>
> ....
> Maybe you can change "caller" into "caller (smbd_smb2_request_read_done)".
> From just reading the comment it was not clear to me what 'caller' was
> referring to.
Ok, here is the updated patchset for master which fixes the
issue you had with the comment and also ensures the socket
is in blocking mode for drain_socket and recvfile calls.
Vendor has confirmed this works and still provides the
needed performance.
Please review and push if you're ok with it.
Cheers,
Jeremy.
-------------- next part --------------
From bfd489407abf5083cd58605038e529bf6023e7f6 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 18 Mar 2013 12:00:25 -0700
Subject: [PATCH 01/13] Ensure we don't do an SMB2 aio write if RECVFILE is
active.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/aio.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index 3f553eb..e8be408 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -861,6 +861,11 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
return NT_STATUS_RETRY;
}
+ if (smbreq->unread_bytes) {
+ /* Can't do async with recvfile. */
+ return NT_STATUS_RETRY;
+ }
+
if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
return NT_STATUS_NO_MEMORY;
}
--
1.8.1.3
From 35b384c0c4d6c60a3c5bea386296570e78a83d1a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 19 Mar 2013 12:16:32 -0700
Subject: [PATCH 02/13] If we already have an smb1req attached to the struct
smbd_smb2_request, don't recreate it.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/smb2_glue.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/source3/smbd/smb2_glue.c b/source3/smbd/smb2_glue.c
index 1b2b4dd..9fc1e49 100644
--- a/source3/smbd/smb2_glue.c
+++ b/source3/smbd/smb2_glue.c
@@ -28,9 +28,13 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req)
struct smb_request *smbreq;
const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
- smbreq = talloc_zero(req, struct smb_request);
- if (smbreq == NULL) {
- return NULL;
+ if (req->smb1req) {
+ smbreq = req->smb1req;
+ } else {
+ smbreq = talloc_zero(req, struct smb_request);
+ if (smbreq == NULL) {
+ return NULL;
+ }
}
smbreq->request_time = req->request_time;
--
1.8.1.3
From ba4ec4874d3aa6fa483f7962fb39d926b4a7a950 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 19 Mar 2013 12:24:17 -0700
Subject: [PATCH 03/13] Add function smbd_smb2_unread_bytes().
Returns number of bytes left to read for recvfile. Will be
used in SMB_2_WRITE_FILE code path.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/globals.h | 1 +
source3/smbd/smb2_glue.c | 12 ++++++++++++
2 files changed, 13 insertions(+)
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 3461bc5..a0a04bb 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -247,6 +247,7 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
uint32_t defer_time);
struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req);
+size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req);
void remove_smb2_chained_fsp(files_struct *fsp);
NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
diff --git a/source3/smbd/smb2_glue.c b/source3/smbd/smb2_glue.c
index 9fc1e49..54135b5 100644
--- a/source3/smbd/smb2_glue.c
+++ b/source3/smbd/smb2_glue.c
@@ -59,6 +59,18 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req)
}
/*********************************************************
+ Are there unread bytes for recvfile ?
+*********************************************************/
+
+size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req)
+{
+ if (req->smb1req) {
+ return req->smb1req->unread_bytes;
+ }
+ return 0;
+}
+
+/*********************************************************
Called from file_free() to remove any chained fsp pointers.
*********************************************************/
--
1.8.1.3
From 53e52c2e5c32d51fd3d71ce69fdf447ba1c50bdd Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 19 Mar 2013 12:36:52 -0700
Subject: [PATCH 04/13] Allow smbd_smb2_request_error_ex() to cope with unread
bytes on error.
Drain the socket if a RECVFILE write failed.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/smb2_server.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index eb7059e..7eb62fc 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2621,11 +2621,21 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
{
DATA_BLOB body;
uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
+ size_t unread_bytes = smbd_smb2_unread_bytes(req);
DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
req->current_idx, nt_errstr(status), info ? " +info" : "",
location));
+ if (unread_bytes) {
+ /* Recvfile error. Drain incoming socket. */
+ size_t ret = drain_socket(req->sconn->sock, unread_bytes);
+ if (ret != unread_bytes) {
+ smbd_server_connection_terminate(req->sconn,
+ "Failed to drain SMB2 socket\n");
+ }
+ }
+
body.data = outhdr + SMB2_HDR_BODY;
body.length = 8;
SSVAL(body.data, 0, 9);
--
1.8.1.3
From b3073bcba6638456556694b311fe874bb8ff4c8a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 1 Apr 2013 13:12:55 -0700
Subject: [PATCH 05/13] Add utility function get_min_receive_file_size().
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/smb2_server.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 7eb62fc..1c622a8 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2842,6 +2842,17 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
size_t *_count);
static void smbd_smb2_request_read_done(struct tevent_req *subreq);
+static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
+{
+ if (smb2_req->do_signing) {
+ return 0;
+ }
+ if (smb2_req->do_encryption) {
+ return 0;
+ }
+ return (size_t)lp_min_receive_file_size();
+}
+
static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbd_server_connection *sconn)
--
1.8.1.3
From fd95f9c131dd3926d6dc38b67713d3c3068dc64d Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 1 Apr 2013 13:14:13 -0700
Subject: [PATCH 06/13] Add macro SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN.
This is the 'short' length we'll read in the SMB2_WRITE receivefile
code path.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/globals.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index a0a04bb..f075a6d 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -546,6 +546,8 @@ struct smbd_smb2_request {
#define SMBD_SMB2_OUT_DYN_PTR(req) (uint8_t *)(SMBD_SMB2_OUT_DYN_IOV(req)->iov_base)
#define SMBD_SMB2_OUT_DYN_LEN(req) (SMBD_SMB2_OUT_DYN_IOV(req)->iov_len)
+#define SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN (SMB2_HDR_BODY + 0x30)
+
struct {
/*
* vector[0] TRANSPORT HEADER (empty)
--
1.8.1.3
From b84a813f4b757dfa8f9b77aaedd321d5410cf4e4 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 1 Apr 2013 13:17:09 -0700
Subject: [PATCH 07/13] Add extra fields into struct
smbd_smb2_request_read_state to support receivefile.
Initialize min_recv_size with the size that will trigger the
receivefile write path.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/smb2_server.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 1c622a8..e1671a7 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2831,6 +2831,8 @@ struct smbd_smb2_request_read_state {
uint8_t nbt[NBT_HDR_SIZE];
bool done;
} hdr;
+ bool doing_receivefile;
+ size_t min_recv_size;
size_t pktlen;
uint8_t *pktbuf;
};
@@ -2874,6 +2876,7 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
state->smb2_req->sconn = sconn;
+ state->min_recv_size = get_min_receive_file_size(state->smb2_req);
subreq = tstream_readv_pdu_queue_send(state->smb2_req,
state->ev,
--
1.8.1.3
From fe8205f24291936d2385f55296c53fcca68d02bb Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 1 Apr 2013 13:19:01 -0700
Subject: [PATCH 08/13] Add stub static function that will turn on/off
receivefile code path.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/smb2_server.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index e1671a7..a983dcd 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2892,6 +2892,11 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
return req;
}
+static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
+{
+ return false;
+}
+
static int smbd_smb2_request_next_vector(struct tstream_context *stream,
void *private_data,
TALLOC_CTX *mem_ctx,
--
1.8.1.3
From 48383d003e6dd3efd411b67fbdbed8054b5608a7 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 1 Apr 2013 13:24:07 -0700
Subject: [PATCH 09/13] The guts of the receivefile code changes.
If an incoming PDU might qualify, only read
SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN = (SMB2_HEADER + SMB2_WRITE_BODY_LEN)
bytes rather than the whole PDU.
Next time we're called, use is_smb2_recvfile_write() to decide if
this is an SMB2_WRITE that fit the receivefile criteria, otherwise
just read the rest of the PDU.
If we did do a short receivefile read, set up the smb2_req->smb1req->unread_bytes
value to show what bytes remain in the TCP buffers.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/smb2_server.c | 65 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 60 insertions(+), 5 deletions(-)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index a983dcd..226db15 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2906,12 +2906,38 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
struct smbd_smb2_request_read_state *state =
talloc_get_type_abort(private_data,
struct smbd_smb2_request_read_state);
- struct iovec *vector;
+ struct iovec *vector = NULL;
+ size_t min_recvfile_size = UINT32_MAX;
if (state->pktlen > 0) {
- /* if there're no remaining bytes, we're done */
- *_vector = NULL;
- *_count = 0;
+ if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
+ /*
+ * Not a possible receivefile write.
+ * Read the rest of the data.
+ */
+ state->doing_receivefile = false;
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (vector == NULL) {
+ return -1;
+ }
+ vector[0].iov_base = (void *)(state->pktbuf +
+ SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+ vector[0].iov_len = (state->pktlen -
+ SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+ *_vector = vector;
+ *_count = 1;
+ } else {
+ /*
+ * Either this is a receivefile write so we've
+ * done a short read, or if not we have all the data.
+ * Either way, we're done and
+ * smbd_smb2_request_read_done() will handle
+ * and short read case by looking at the
+ * state->doing_receivefile value.
+ */
+ *_vector = NULL;
+ *_count = 0;
+ }
return 0;
}
@@ -2957,7 +2983,26 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
}
vector[0].iov_base = (void *)state->pktbuf;
- vector[0].iov_len = state->pktlen;
+
+ if (state->min_recv_size != 0) {
+ min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+ min_recvfile_size += state->min_recv_size;
+ }
+
+ if (state->pktlen > min_recvfile_size) {
+ /*
+ * Might be a receivefile write. Read the SMB2 HEADER +
+ * SMB2_WRITE header first. Set 'doing_receivefile'
+ * as we're *attempting* receivefile write. If this
+ * turns out not to be a SMB2_WRITE request or otherwise
+ * not suitable then we'll just read the rest of the data
+ * the next time this function is called.
+ */
+ vector[0].iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+ state->doing_receivefile = true;
+ } else {
+ vector[0].iov_len = state->pktlen;
+ }
*_vector = vector;
*_count = 1;
@@ -3020,6 +3065,16 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq)
return;
}
+ if (state->doing_receivefile) {
+ state->smb2_req->smb1req = talloc_zero(state->smb2_req,
+ struct smb_request);
+ if (tevent_req_nomem(state->smb2_req->smb1req, req)) {
+ return;
+ }
+ state->smb2_req->smb1req->unread_bytes =
+ state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+ }
+
state->smb2_req->current_idx = 1;
tevent_req_done(req);
--
1.8.1.3
From 9ce62cc107fb46b17d05c2f841ac97c2f5e455dc Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 1 Apr 2013 11:16:01 -0700
Subject: [PATCH 10/13] Add the internals of is_smb2_recvfile_write.
This turns on the real receivefile detection, and completes
the receivefile code path changes.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/smb2_server.c | 38 +++++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 226db15..57e9c7b 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2894,7 +2894,43 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
{
- return false;
+ uint32_t flags;
+
+ if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
+ /* Transform header. Cannot recvfile. */
+ return false;
+ }
+ if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
+ /* Not SMB2. Normal error path will cope. */
+ return false;
+ }
+ if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
+ /* Not SMB2. Normal error path will cope. */
+ return false;
+ }
+ if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
+ /* Needs to be a WRITE. */
+ return false;
+ }
+ if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
+ /* Chained. Cannot recvfile. */
+ return false;
+ }
+ flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
+ if (flags & SMB2_HDR_FLAG_CHAINED) {
+ /* Chained. Cannot recvfile. */
+ return false;
+ }
+ if (flags & SMB2_HDR_FLAG_SIGNED) {
+ /* Signed. Cannot recvfile. */
+ return false;
+ }
+
+ DEBUG(10,("Doing recvfile write len = %u\n",
+ (unsigned int)(state->pktlen -
+ SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
+
+ return true;
}
static int smbd_smb2_request_next_vector(struct tstream_context *stream,
--
1.8.1.3
From 04aeb6d8a75e48a5db818940e668d6442c440913 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 8 Apr 2013 10:16:48 -0700
Subject: [PATCH 11/13] Ensure drain_socket() operates on a blocking socket.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/lib/recvfile.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c
index c53ba77..72f4257 100644
--- a/source3/lib/recvfile.c
+++ b/source3/lib/recvfile.c
@@ -240,6 +240,7 @@ ssize_t sys_recvfile(int fromfd,
/*****************************************************************
Throw away "count" bytes from the client socket.
Returns count or -1 on error.
+ Must only operate on a blocking socket.
*****************************************************************/
ssize_t drain_socket(int sockfd, size_t count)
@@ -247,6 +248,7 @@ ssize_t drain_socket(int sockfd, size_t count)
size_t total = 0;
size_t bufsize = MIN(TRANSFER_BUF_SIZE,count);
char *buffer = NULL;
+ int old_flags = 0;
if (count == 0) {
return 0;
@@ -257,6 +259,12 @@ ssize_t drain_socket(int sockfd, size_t count)
return -1;
}
+ old_flags = fcntl(sockfd, F_GETFL, 0);
+ if (set_blocking(sockfd, true) == -1) {
+ free(buffer);
+ return -1;
+ }
+
while (total < count) {
ssize_t read_ret;
size_t toread = MIN(bufsize,count - total);
@@ -265,12 +273,17 @@ ssize_t drain_socket(int sockfd, size_t count)
read_ret = sys_read(sockfd, buffer, toread);
if (read_ret <= 0) {
/* EOF or socket error. */
- free(buffer);
- return -1;
+ count = (size_t)-1;
+ goto out;
}
total += read_ret;
}
+ out:
+
free(buffer);
+ if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+ return -1;
+ }
return count;
}
--
1.8.1.3
From d7a185d9cc5d2e7d08b27c3b622cacf38d140983 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 8 Apr 2013 10:32:10 -0700
Subject: [PATCH 12/13] Ensure the RECVFILE path in vfs_write_data() operates
on a blocking socket.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/vfs.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index b81e8de..ddac7d9 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -428,14 +428,25 @@ ssize_t vfs_write_data(struct smb_request *req,
ssize_t ret;
if (req && req->unread_bytes) {
+ int sockfd = req->sconn->sock;
+ int old_flags;
SMB_ASSERT(req->unread_bytes == N);
/* VFS_RECVFILE must drain the socket
* before returning. */
req->unread_bytes = 0;
- return SMB_VFS_RECVFILE(req->sconn->sock,
+ /* Ensure the socket is blocking. */
+ old_flags = fcntl(sockfd, F_GETFL, 0);
+ if (set_blocking(sockfd, true) == -1) {
+ return (ssize_t)-1;
+ }
+ ret = SMB_VFS_RECVFILE(sockfd,
fsp,
(off_t)-1,
N);
+ if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+ return (ssize_t)-1;
+ }
+ return ret;
}
while (total < N) {
--
1.8.1.3
From 3062bc0dc530612258b0625b96b07117082e4227 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 8 Apr 2013 10:49:03 -0700
Subject: [PATCH 13/13] Ensure the RECVFILE path in vfs_pwrite_data() operates
on a blocking socket.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/smbd/vfs.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index ddac7d9..7f67af7 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -472,14 +472,25 @@ ssize_t vfs_pwrite_data(struct smb_request *req,
ssize_t ret;
if (req && req->unread_bytes) {
+ int sockfd = req->sconn->sock;
+ int old_flags;
SMB_ASSERT(req->unread_bytes == N);
/* VFS_RECVFILE must drain the socket
* before returning. */
req->unread_bytes = 0;
- return SMB_VFS_RECVFILE(req->sconn->sock,
+ /* Ensure the socket is blocking. */
+ old_flags = fcntl(sockfd, F_GETFL, 0);
+ if (set_blocking(sockfd, true) == -1) {
+ return (ssize_t)-1;
+ }
+ ret = SMB_VFS_RECVFILE(sockfd,
fsp,
offset,
N);
+ if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+ return (ssize_t)-1;
+ }
+ return ret;
}
while (total < N) {
--
1.8.1.3
More information about the samba-technical
mailing list