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)
committerJeremy Allison <jra@samba.org>
Wed, 6 May 2015 20:33:19 +0000 (22:33 +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>
source3/smbd/globals.h
source3/smbd/smbXsrv_session.c

index c7e260830efd7454c3b7a0d63f9a44bbb816717e..22cf5d608904b4e3258dbc607b2cf60eadbe7b61 100644 (file)
@@ -537,6 +537,11 @@ struct smbXsrv_channel_global0;
 NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
                                      const struct smbXsrv_connection *conn,
                                      struct smbXsrv_channel_global0 **_c);
+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 5ee4bbe3f8203e3a8709d86d458bc536b2b3d85d..f4617f794a6e96e4ae759d4e449611b5659f5a3a 100644 (file)
@@ -1327,6 +1327,127 @@ NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
        return NT_STATUS_USER_SESSION_DELETED;
 }
 
+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 smbXsrv_connection *xconn = 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);
+       }
+
+       for (xconn = session->client->connections; xconn != NULL; xconn = xconn->next) {
+               struct smbd_smb2_request *preq;
+
+               for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
+                       if (preq == current_req) {
+                               /* Can't cancel current request. */
+                               continue;
+                       }
+                       if (preq->session != session) {
+                               /* Request on different session. */
+                               continue;
+                       }
+
+                       if (!NT_STATUS_IS_OK(xconn->transport.status)) {
+                               preq->session = NULL;
+                               /*
+                                * If we no longer have a session we can't
+                                * sign or encrypt replies.
+                                */
+                               preq->do_signing = false;
+                               preq->do_encryption = false;
+
+                               if (preq->subreq != NULL) {
+                                       tevent_req_cancel(preq->subreq);
+                               }
+                               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 = 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 = 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);
+
+       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;