1/* 2 Unix SMB/CIFS implementation. 3 4 POSIX NTVFS backend - async request wait routines 5 6 Copyright (C) Andrew Tridgell 2004 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "lib/events/events.h" 24#include "../lib/util/dlinklist.h" 25#include "vfs_posix.h" 26#include "smbd/service_stream.h" 27#include "lib/messaging/irpc.h" 28 29/* the context for a single wait instance */ 30struct pvfs_wait { 31 struct pvfs_wait *next, *prev; 32 struct pvfs_state *pvfs; 33 void (*handler)(void *, enum pvfs_wait_notice); 34 void *private_data; 35 int msg_type; 36 struct messaging_context *msg_ctx; 37 struct tevent_context *ev; 38 struct ntvfs_request *req; 39 enum pvfs_wait_notice reason; 40}; 41 42/* 43 called from the ntvfs layer when we have requested setup of an async 44 call. this ensures that async calls runs with the right state of 45 previous ntvfs handlers in the chain (such as security context) 46*/ 47NTSTATUS pvfs_async_setup(struct ntvfs_module_context *ntvfs, 48 struct ntvfs_request *req, void *private_data) 49{ 50 struct pvfs_wait *pwait = talloc_get_type(private_data, 51 struct pvfs_wait); 52 pwait->handler(pwait->private_data, pwait->reason); 53 return NT_STATUS_OK; 54} 55 56/* 57 receive a completion message for a wait 58*/ 59static void pvfs_wait_dispatch(struct messaging_context *msg, 60 void *private_data, uint32_t msg_type, 61 struct server_id src, DATA_BLOB *data) 62{ 63 struct pvfs_wait *pwait = talloc_get_type(private_data, 64 struct pvfs_wait); 65 struct ntvfs_request *req; 66 void *p = NULL; 67 68 /* we need to check that this one is for us. See 69 messaging_send_ptr() for the other side of this. 70 */ 71 if (data->length == sizeof(void *)) { 72 void **pp; 73 pp = (void **)data->data; 74 p = *pp; 75 } 76 if (p == NULL || p != pwait->private_data) { 77 return; 78 } 79 80 pwait->reason = PVFS_WAIT_EVENT; 81 82 /* the extra reference here is to ensure that the req 83 structure is not destroyed when the async request reply is 84 sent, which would cause problems with the other ntvfs 85 modules above us */ 86 req = talloc_reference(msg, pwait->req); 87 ntvfs_async_setup(pwait->req, pwait); 88 talloc_unlink(msg, req); 89} 90 91 92/* 93 receive a timeout on a message wait 94*/ 95static void pvfs_wait_timeout(struct tevent_context *ev, 96 struct tevent_timer *te, struct timeval t, 97 void *private_data) 98{ 99 struct pvfs_wait *pwait = talloc_get_type(private_data, 100 struct pvfs_wait); 101 struct ntvfs_request *req = pwait->req; 102 103 pwait->reason = PVFS_WAIT_TIMEOUT; 104 105 talloc_increase_ref_count(req); 106 ntvfs_async_setup(pwait->req, pwait); 107 talloc_free(req); 108} 109 110 111/* 112 destroy a pending wait 113 */ 114static int pvfs_wait_destructor(struct pvfs_wait *pwait) 115{ 116 if (pwait->msg_type != -1) { 117 messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait); 118 } 119 DLIST_REMOVE(pwait->pvfs->wait_list, pwait); 120 return 0; 121} 122 123/* 124 setup a request to wait on a message of type msg_type, with a 125 timeout (given as an expiry time) 126 127 the return value is a handle. To stop waiting talloc_free this 128 handle. 129 130 if msg_type == -1 then no message is registered, and it is assumed 131 that the caller handles any messaging setup needed 132*/ 133struct pvfs_wait *pvfs_wait_message(struct pvfs_state *pvfs, 134 struct ntvfs_request *req, 135 int msg_type, 136 struct timeval end_time, 137 void (*fn)(void *, enum pvfs_wait_notice), 138 void *private_data) 139{ 140 struct pvfs_wait *pwait; 141 142 pwait = talloc(pvfs, struct pvfs_wait); 143 if (pwait == NULL) { 144 return NULL; 145 } 146 147 pwait->private_data = private_data; 148 pwait->handler = fn; 149 pwait->msg_ctx = pvfs->ntvfs->ctx->msg_ctx; 150 pwait->ev = pvfs->ntvfs->ctx->event_ctx; 151 pwait->msg_type = msg_type; 152 pwait->req = talloc_reference(pwait, req); 153 pwait->pvfs = pvfs; 154 155 if (!timeval_is_zero(&end_time)) { 156 /* setup a timer */ 157 event_add_timed(pwait->ev, pwait, end_time, pvfs_wait_timeout, pwait); 158 } 159 160 /* register with the messaging subsystem for this message 161 type */ 162 if (msg_type != -1) { 163 messaging_register(pwait->msg_ctx, 164 pwait, 165 msg_type, 166 pvfs_wait_dispatch); 167 } 168 169 /* tell the main smb server layer that we will be replying 170 asynchronously */ 171 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; 172 173 DLIST_ADD(pvfs->wait_list, pwait); 174 175 /* make sure we cleanup the timer and message handler */ 176 talloc_set_destructor(pwait, pvfs_wait_destructor); 177 178 return pwait; 179} 180 181 182/* 183 cancel an outstanding async request 184*/ 185NTSTATUS pvfs_cancel(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req) 186{ 187 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data, 188 struct pvfs_state); 189 struct pvfs_wait *pwait; 190 191 for (pwait=pvfs->wait_list;pwait;pwait=pwait->next) { 192 if (pwait->req == req) { 193 /* trigger a cancel on the request */ 194 pwait->reason = PVFS_WAIT_CANCEL; 195 ntvfs_async_setup(pwait->req, pwait); 196 return NT_STATUS_OK; 197 } 198 } 199 200 return NT_STATUS_DOS(ERRDOS, ERRcancelviolation); 201} 202