summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2015-05-02 09:57:03 +0200
committerJeremy Allison <jra@samba.org>2015-05-06 22:33:19 +0200
commit4fceb4531ccd6bb1fd6ebd7b6eb5b894959bc010 (patch)
treec25398e5f3fa96993c28cd0ba820afedf427face /source3
parentb6c34a07760141bda3e78624d62eb556bb70da65 (diff)
downloadsamba-4fceb4531ccd6bb1fd6ebd7b6eb5b894959bc010.tar.gz
s3:smbXsrv_session: add smb2srv_session_shutdown_send/recv helper functions
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>
Diffstat (limited to 'source3')
-rw-r--r--source3/smbd/globals.h5
-rw-r--r--source3/smbd/smbXsrv_session.c121
2 files changed, 126 insertions, 0 deletions
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index c7e260830ef..22cf5d60890 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -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);
diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index 5ee4bbe3f82..f4617f794a6 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -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;