summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2013-04-01 13:24:07 -0700
committerJeremy Allison <jra@samba.org>2013-04-19 14:11:15 -0700
commit53b87f2fbabe3a2dcb5df6f6c494ef332bea81e7 (patch)
treea8302e62a554d6ea833a99ed47636a440875c54e
parentfdcaf0fa360b9590114605d24af545b1d42b9fd5 (diff)
downloadsamba-53b87f2fbabe3a2dcb5df6f6c494ef332bea81e7.tar.gz
samba-53b87f2fbabe3a2dcb5df6f6c494ef332bea81e7.tar.bz2
samba-53b87f2fbabe3a2dcb5df6f6c494ef332bea81e7.zip
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@samba.org> Reviewed-by: Stefan (metze) Metzmacher <metze@samba.org>
-rw-r--r--source3/smbd/smb2_server.c65
1 files changed, 60 insertions, 5 deletions
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index a983dcdfa5..226db15d73 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);