s3:smbXsrv_session: add smb2srv_session_shutdown_send/recv helper functions
authorStefan Metzmacher <metze@samba.org>
Sat, 2 May 2015 07:57:03 +0000 (09:57 +0200)
committerKarolin Seeger <kseeger@samba.org>
Wed, 20 May 2015 14:34:29 +0000 (16:34 +0200)
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11182

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
(similar to commit 4fceb4531ccd6bb1fd6ebd7b6eb5b894959bc010)

source3/smbd/globals.h
source3/smbd/smbXsrv_session.c

index 0942e46744dcf69c41397ed599bac2a8205b7d06..66358fb41fee7ce55647bce8d283333c566451ef 100644 (file)
@@ -394,6 +394,11 @@ NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
                                NTTIME now,
                                struct smbXsrv_session **_session);
 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session);
+struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct smbXsrv_session *session,
+                                       struct smbd_smb2_request *current_req);
+NTSTATUS smb2srv_session_shutdown_recv(struct tevent_req *req);
 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session);
 NTSTATUS smbXsrv_session_logoff_all(struct smbXsrv_connection *conn);
 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn);
index 362cff8c989c94de09e61a53f1b5ecaec68a9b7e..a2ebfb192017bb5aa28be8b22db1aa02446644de 100644 (file)
@@ -38,6 +38,7 @@
 #include "serverid.h"
 #include "lib/util/tevent_ntstatus.h"
 #include "msg_channel.h"
+#include "lib/smbd_tevent_queue.h"
 
 struct smbXsrv_session_table {
        struct {
@@ -1300,6 +1301,112 @@ NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
        return NT_STATUS_OK;
 }
 
+struct smb2srv_session_shutdown_state {
+       struct tevent_queue *wait_queue;
+};
+
+static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct smbXsrv_session *session,
+                                       struct smbd_smb2_request *current_req)
+{
+       struct tevent_req *req;
+       struct smb2srv_session_shutdown_state *state;
+       struct tevent_req *subreq;
+       struct smbd_smb2_request *preq = NULL;
+       size_t len = 0;
+
+       /*
+        * Make sure that no new request will be able to use this session.
+        */
+       session->status = NT_STATUS_USER_SESSION_DELETED;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct smb2srv_session_shutdown_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->wait_queue = tevent_queue_create(state, "smb2srv_session_shutdown_queue");
+       if (tevent_req_nomem(state->wait_queue, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       if (session->connection != NULL) {
+               preq = session->connection->sconn->smb2.requests;
+       }
+
+       for (; preq != NULL; preq = preq->next) {
+               if (preq == current_req) {
+                       /* Can't cancel current request. */
+                       continue;
+               }
+               if (preq->session != session) {
+                       /* Request on different session. */
+                       continue;
+               }
+
+               /*
+                * Never cancel anything in a compound
+                * request. Way too hard to deal with
+                * the result.
+                */
+               if (!preq->compound_related && preq->subreq != NULL) {
+                       tevent_req_cancel(preq->subreq);
+               }
+
+               /*
+                * Now wait until the request is finished.
+                *
+                * We don't set a callback, as we just want to block the
+                * wait queue and the talloc_free() of the request will
+                * remove the item from the wait queue.
+                */
+               subreq = smbd_tevent_queue_wait_send(preq, ev, state->wait_queue);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+       }
+
+       len = tevent_queue_length(state->wait_queue);
+       if (len == 0) {
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
+       }
+
+       /*
+        * Now we add our own waiter to the end of the queue,
+        * this way we get notified when all pending requests are finished
+        * and send to the socket.
+        */
+       subreq = smbd_tevent_queue_wait_send(state, ev, state->wait_queue);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smb2srv_session_shutdown_wait_done, req);
+
+       return req;
+}
+
+static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+
+       smbd_tevent_queue_wait_recv(subreq);
+       TALLOC_FREE(subreq);
+
+       tevent_req_done(req);
+}
+
+NTSTATUS smb2srv_session_shutdown_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
 {
        struct smbXsrv_session_table *table;