diff options
author | Stefan Metzmacher <metze@samba.org> | 2015-05-02 09:57:03 +0200 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2015-05-06 22:33:19 +0200 |
commit | 4fceb4531ccd6bb1fd6ebd7b6eb5b894959bc010 (patch) | |
tree | c25398e5f3fa96993c28cd0ba820afedf427face /source3 | |
parent | b6c34a07760141bda3e78624d62eb556bb70da65 (diff) | |
download | samba-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.h | 5 | ||||
-rw-r--r-- | source3/smbd/smbXsrv_session.c | 121 |
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; |