metze dixit
authorGünther Deschner <gd@samba.org>
Tue, 6 Sep 2016 11:57:31 +0000 (13:57 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 10 Feb 2020 14:11:51 +0000 (15:11 +0100)
source3/smbd/globals.h
source3/smbd/smb2_break.c
source3/smbd/smb2_server.c

index 45cfb5d607e81ffebd4400a882e8bde7cc41c723..badc99d7065851d15a49f16b4b81c716d465404f 100644 (file)
@@ -443,6 +443,7 @@ struct smbXsrv_connection {
                } request_read_state;
                struct smbd_smb2_send_queue *send_queue;
                size_t send_queue_len;
+               uint64_t sent_bytes;
                struct smbd_smb2_send_queue *ack_queue;
 
                struct {
@@ -677,8 +678,7 @@ struct smbd_smb2_send_queue {
 
        struct {
                struct tevent_req *req;
-               bool started;
-               uint32_t seqnum;
+               uint64_t last_byte;
        } ack;
 
        TALLOC_CTX *mem_ctx;
index c9493d670be763a47a2c2353bc2f65fd31c464d4..ae6b9214b229c46e8091973a5c82ae5f071828f3 100644 (file)
@@ -438,12 +438,6 @@ 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 52e8336996d1736935bad3db477c3f9873f0e2ad..f9826c26a6a3d445cbe6f8b9e282b58a9870f1fb 100644 (file)
@@ -3348,24 +3348,15 @@ 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);
+static void smbd_smb2_send_break_done(struct tevent_req *ack_req);
 
-       TALLOC_FREE(state);
-}
-
-static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
+static NTSTATUS smbd_smb2_send_break(struct smbXsrv_client *client,
                                     struct smbXsrv_session *session,
                                     struct smbXsrv_tcon *tcon,
                                     const uint8_t *body,
                                     size_t body_len)
 {
+       struct smbXsrv_connection *xconn = NULL;
        struct smbd_smb2_send_break_state *state;
        bool do_encryption = false;
        uint64_t session_wire_id = 0;
@@ -3386,7 +3377,7 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
        statelen = offsetof(struct smbd_smb2_send_break_state, body) +
                body_len;
 
-       state = talloc_zero_size(xconn, statelen);
+       state = talloc_zero_size(client, statelen);
        if (state == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -3472,6 +3463,9 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
                }
        }
 
+       // TODO: which channel should be used???
+       xconn = client->connections;
+
        state->queue_entry.mem_ctx = state;
        state->queue_entry.vector = state->vector;
        state->queue_entry.count = ARRAY_SIZE(state->vector);
@@ -3482,6 +3476,9 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
        tevent_req_set_callback(state->queue_entry.ack.req,
                                smbd_smb2_send_break_done,
                                state);
+       tevent_req_set_endtime(state->queue_entry.ack.req,
+                              xconn->ev_ctx,
+                              timeval_zero() /* FIXME */);
        DLIST_ADD_END(xconn->smb2.send_queue, &state->queue_entry);
        xconn->smb2.send_queue_len++;
 
@@ -3493,6 +3490,23 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
        return NT_STATUS_OK;
 }
 
+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);
+
+       //TODO: check for errors on the used channel
+       // On timeout we need to recheck the queue
+       // => should we disconnect the channel if the ack is
+       // not completed in time
+       // TODO: retry on a remaining channel
+       TALLOC_FREE(state);
+}
+
 NTSTATUS smbd_smb2_send_oplock_break(struct smbXsrv_connection *xconn,
                                     struct smbXsrv_session *session,
                                     struct smbXsrv_tcon *tcon,
@@ -3780,66 +3794,42 @@ static int socket_error_from_errno(int ret,
 
 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;
-               uint32_t value;
-               socklen_t ilen = sizeof(info);
-               int ret;
-
-               ret = ioctl(xconn->transport.sock, SIOCOUTQ, &value);
-               if (ret == 0) {
-                       DEBUG(10, ("%s:%s: SIOCOUTQ value is: %d\n",
-                               __location__, __func__,
-                               value));
-               }
+       struct smbd_smb2_send_queue *cur = NULL;
+       struct smbd_smb2_send_queue *next = NULL;
+       int value;
+       int ret;
+       uint64_t acked_byte;
 
-               ret = getsockopt(xconn->transport.sock, IPPROTO_TCP,
-                                TCP_INFO, (void *)&info, &ilen);
-               if (ret != 0) {
-                       DEBUG(10,("%s:%s: errno[%d/%s]\n",
-                             __location__, __func__,
-                             errno, strerror(errno)));
-                       ZERO_STRUCT(info);
-               } else {
-                       DEBUG(10,("%s:%s: unacked[%u] sacked[%u]\n",
-                             __location__, __func__,
-                             (unsigned)info.tcpi_unacked,
-                             (unsigned)info.tcpi_sacked));
-               }
+       ret = ioctl(xconn->transport.sock, SIOCOUTQ, &value);
+       if (ret != 0) {
+               return NT_STATUS_FOOBAR;
+       }
 
-               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);
-
-               //
-               // gd / obnox --- oplock break : try resending if no ack...
-               //
-               // somewhere here -- or elsewhere ...
-               //
-               // - if timed out
-               // - smbd_smb2_send_queue-element e:
-               //   --> contains (raw) packet.
-               //   --> extract session_id ?!
-               //       - look for session in xconn
-               //         smb2srv_session_lookup_conn(xconn, session_id, now, &session);
-               //    -  session->channels = list of channels
-               //    -  mark this xconn transport 'bad'
-               //       (receiving data on bad conn resets bad flag to false)
-               //    -  resend packet on remaining channel if any:
-               //        put e into send_queue other xconn from channel list
-               //        (DLIST_ADD_END(other-xconn->send_queue, e))
-               //        Q: need to modify any flags in the smb2 header?
-               //
-               //  Q/TODO:
-               //   - todo: implement timer
-               //   - Q:    how to really detect bad channel
-               //           (arithmetic with written data and SIOCOUTQ counter)
-               //   - Q: what the heck does tevent_wait_done() etc do?
-               //
+       // check for underflow?
+       acked_byte = xconn->smb2.sent_bytes - value;
 
+       DEBUG(10, ("%s:%s: SIOCOUTQ value is: %d\n",
+               __location__, __func__,
+               value));
+
+       for (cur = xconn->smb2.ack_queue; cur != NULL; cur = next) {
+               next = cur->next;
+
+               if (cur->ack.last_byte > acked_byte) {
+                       /*
+                        * The ack_queue is ordered, if the first
+                        * one isn't acked none is acked.
+                        */
+                       break;
+               }
+
+               DLIST_REMOVE(xconn->smb2.ack_queue, cur);       
+               tevent_wait_done(cur->ack.req);
        }
 
+       //TODO: reset xconn->smb2.sent_bytes if queue is empty
+       // and > INT64_MAX?
+       // or always adjust when we acked anything...
        return NT_STATUS_OK;
 }
 
@@ -3850,12 +3840,12 @@ 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) {
+               status = smbd_smb2_check_ack_queue(xconn);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+
                TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
                return NT_STATUS_OK;
        }
@@ -3864,7 +3854,7 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
                struct smbd_smb2_send_queue *e = xconn->smb2.send_queue;
                bool ok;
                struct msghdr msg;
-               uint32_t value1, value2;
+               //uint32_t value1, value2;
 
                if (e->sendfile_header != NULL) {
                        size_t size = 0;
@@ -3914,6 +3904,7 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
                        continue;
                }
 
+#if 0
                if (e->ack.req != NULL && !e->ack.started) {
                        struct tcp_info info;
                        socklen_t ilen = sizeof(info);
@@ -3942,6 +3933,7 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
                                        value1));
                        }
                }
+#endif
 
                msg = (struct msghdr) {
                        .msg_iov = e->vector,
@@ -3965,35 +3957,24 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbXsrv_connection *xconn)
                        return map_nt_error_from_unix_common(err);
                }
 
+               xconn->smb2.sent_bytes += ret;
+
                ok = iov_advance(&e->vector, &e->count, ret);
                if (!ok) {
                        return NT_STATUS_INTERNAL_ERROR;
                }
 
-               if (e->ack.req != NULL && e->ack.started) {
-                       int _ret;
-                       _ret = ioctl(xconn->transport.sock, SIOCOUTQ, &value2);
-                       if (_ret == 0) {
-                               DEBUG(0, ("%s:%s:  after write SIOCOUTQ value is: %d\n",
-                                       __location__, __func__,
-                                       value2));
-                       }
-               }
-
                if (e->count > 0) {
                        /* we have more to write */
                        TEVENT_FD_WRITEABLE(xconn->transport.fde);
                        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) {
+               if (e->ack.req != NULL) {
+                       e->ack.last_byte = xconn->smb2.sent_bytes;
                        DLIST_ADD_END(xconn->smb2.ack_queue, e);
                        continue;
                }
@@ -4087,6 +4068,11 @@ again:
                return map_nt_error_from_unix_common(err);
        }
 
+       status = smbd_smb2_check_ack_queue(xconn);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        if (ret < state->vector.iov_len) {
                uint8_t *base;
                base = (uint8_t *)state->vector.iov_base;