STEPXX: TODO: oplock break tcp ack...
authorStefan Metzmacher <metze@samba.org>
Thu, 18 Sep 2014 19:24:13 +0000 (21:24 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 10 Feb 2020 13:43:11 +0000 (14:43 +0100)
source3/smbd/globals.h
source3/smbd/smb2_break.c
source3/smbd/smb2_server.c

index 7b26d04ed0f192d85e7c6112bec84a9b6741606f..45cfb5d607e81ffebd4400a882e8bde7cc41c723 100644 (file)
@@ -443,6 +443,7 @@ struct smbXsrv_connection {
                } request_read_state;
                struct smbd_smb2_send_queue *send_queue;
                size_t send_queue_len;
+               struct smbd_smb2_send_queue *ack_queue;
 
                struct {
                        /*
@@ -674,6 +675,12 @@ struct smbd_smb2_send_queue {
        struct iovec *vector;
        int count;
 
+       struct {
+               struct tevent_req *req;
+               bool started;
+               uint32_t seqnum;
+       } ack;
+
        TALLOC_CTX *mem_ctx;
 };
 
index ae6b9214b229c46e8091973a5c82ae5f071828f3..c9493d670be763a47a2c2353bc2f65fd31c464d4 100644 (file)
@@ -438,6 +438,12 @@ static NTSTATUS smbd_smb2_lease_break_recv(struct tevent_req *req,
  SMB2 OPLOCK_BREAK_NOTIFICATION.
 *********************************************************/
 
+struct send_break_message_smb2_state {
+       struct files_struct *fsp;
+       int level;
+       uint32_t tcp_seqnum;
+};
+
 void send_break_message_smb2(files_struct *fsp,
                             uint32_t break_from,
                             uint32_t break_to)
index 69a26acc07fd7faa4e2ff84e867c96fcbbd41b10..f94bd97dbf3b8774a6c49f20a2469489659c6358 100644 (file)
@@ -31,6 +31,7 @@
 #include "lib/util/iov_buf.h"
 #include "auth.h"
 #include "libcli/smb/smbXcli_base.h"
+#include "lib/tevent_wait.h"
 
 #include "lib/crypto/gnutls_helpers.h"
 #include <gnutls/gnutls.h>
@@ -3341,6 +3342,18 @@ struct smbd_smb2_send_break_state {
        uint8_t body[1];
 };
 
+static void smbd_smb2_send_break_done(struct tevent_req *ack_req)
+{
+       struct smbd_smb2_send_break_state *state =
+               tevent_req_callback_data(ack_req,
+               struct smbd_smb2_send_break_state);
+
+       tevent_wait_recv(ack_req);
+       TALLOC_FREE(ack_req);
+
+       TALLOC_FREE(state);
+}
+
 static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
                                     struct smbXsrv_session *session,
                                     struct smbXsrv_tcon *tcon,
@@ -3456,6 +3469,13 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
        state->queue_entry.mem_ctx = state;
        state->queue_entry.vector = state->vector;
        state->queue_entry.count = ARRAY_SIZE(state->vector);
+       state->queue_entry.ack.req = tevent_wait_send(state, xconn->ev_ctx);
+       if (state->queue_entry.ack.req == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       tevent_req_set_callback(state->queue_entry.ack.req,
+                               smbd_smb2_send_break_done,
+                               state);
        DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry);
        xconn->smb2.send_queue_len++;
 
@@ -3752,6 +3772,36 @@ static int socket_error_from_errno(int ret,
        return sys_errno;
 }
 
+static NTSTATUS smbd_smb2_check_ack_queue(struct smbXsrv_connection *xconn)
+{
+       while (xconn->smb2.ack_queue != NULL) {
+               struct smbd_smb2_send_queue *e = xconn->smb2.ack_queue;
+               struct tcp_info info;
+               socklen_t ilen = sizeof(info);
+               int ret;
+
+               ret = getsockopt(xconn->transport.sock, IPPROTO_TCP,
+                                TCP_INFO, (void *)&info, &ilen);
+               if (ret != 0) {
+                       DEBUG(0,("%s:%s: errno[%d/%s]\n",
+                             __location__, __func__,
+                             errno, strerror(errno)));
+                       ZERO_STRUCT(info);
+               } else {
+                       DEBUG(0,("%s:%s: unacked[%u] sacked[%u]\n",
+                             __location__, __func__,
+                             (unsigned)info.tcpi_unacked,
+                             (unsigned)info.tcpi_sacked));
+               }
+
+               DLIST_REMOVE(xconn->smb2.ack_queue, e);
+               //e->ack.seqnum >=info.tcpi_sacked + iov_buflen(e->vector, e->count);
+               tevent_wait_done(e->ack.req);
+       }
+
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
 {
        int ret;
@@ -3759,6 +3809,11 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
        bool retry;
        NTSTATUS status;
 
+       status = smbd_smb2_check_ack_queue(xconn);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        if (xconn->smb2.send_queue == NULL) {
                TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
                return NT_STATUS_OK;
@@ -3801,6 +3856,7 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
                        e->sendfile_header->length = size;
                        e->sendfile_status = &status;
                        e->count = 0;
+                       status = NT_STATUS_INTERNAL_ERROR;
 
                        xconn->smb2.send_queue_len--;
                        DLIST_REMOVE(xconn->smb2.send_queue, e);
@@ -3816,6 +3872,28 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
                        continue;
                }
 
+               if (e->ack.req != NULL && !e->ack.started) {
+                       struct tcp_info info;
+                       socklen_t ilen = sizeof(info);
+
+                       ret = getsockopt(xconn->transport.sock, IPPROTO_TCP,
+                                        TCP_INFO, (void *)&info, &ilen);
+                       if (ret != 0) {
+                               DEBUG(0,("%s:%s: errno[%d/%s]\n",
+                                     __location__, __func__,
+                                     errno, strerror(errno)));
+                               ZERO_STRUCT(info);
+                       } else {
+                               DEBUG(0,("%s:%s: unacked[%u] sacked[%u]\n",
+                                     __location__, __func__,
+                                     (unsigned)info.tcpi_unacked,
+                                     (unsigned)info.tcpi_sacked));
+                       }
+
+                       e->ack.started = true;
+                       e->ack.seqnum = info.tcpi_sacked + iov_buflen(e->vector, e->count);
+               }
+
                msg = (struct msghdr) {
                        .msg_iov = e->vector,
                        .msg_iovlen = e->count,
@@ -3847,11 +3925,25 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
                        return NT_STATUS_OK;
                }
 
+               if (e->ack.req != NULL && e->ack.started) {
+                       tevent_wait_done(e->ack.req);
+               }
+
                xconn->smb2.send_queue_len--;
                DLIST_REMOVE(xconn->smb2.send_queue, e);
+               if (e->ack.req != NULL && e->ack.started) {
+                       DLIST_ADD_END(xconn->smb2.ack_queue, e);
+                       continue;
+               }
                talloc_free(e->mem_ctx);
        }
 
+       /* not sure after rebase ... */
+       status = smbd_smb2_check_ack_queue(xconn);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        /*
         * Restart reads if we were blocked on
         * draining the send queue.