1/* 2 Unix SMB/CIFS implementation. 3 Infrastructure for async requests 4 Copyright (C) Volker Lendecke 2008 5 Copyright (C) Stefan Metzmacher 2009 6 7 ** NOTE! The following LGPL license applies to the tevent 8 ** library. This does NOT imply that all of Samba is released 9 ** under the LGPL 10 11 This library is free software; you can redistribute it and/or 12 modify it under the terms of the GNU Lesser General Public 13 License as published by the Free Software Foundation; either 14 version 3 of the License, or (at your option) any later version. 15 16 This library is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 Lesser General Public License for more details. 20 21 You should have received a copy of the GNU Lesser General Public 22 License along with this library; if not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#include "replace.h" 26#include "tevent.h" 27#include "tevent_internal.h" 28#include "tevent_util.h" 29 30/** 31 * @brief The default print function for creating debug messages 32 * @param[in] req The request to be printed 33 * @param[in] mem_ctx The memory context for the result 34 * @retval Text representation of req 35 * 36 * The function should not be used by users of the asynx API, 37 * but custom print function can use it and append custom text 38 * to the string. 39 */ 40 41char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx) 42{ 43 return talloc_asprintf(mem_ctx, 44 "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] " 45 " state[%s (%p)] timer[%p]", 46 req, req->internal.create_location, 47 req->internal.state, 48 (unsigned long long)req->internal.error, 49 (unsigned long long)req->internal.error, 50 talloc_get_name(req->data), 51 req->data, 52 req->internal.timer 53 ); 54} 55 56/** 57 * @brief Print an tevent_req structure in debug messages 58 * @param[in] mem_ctx The memory context for the result 59 * @param[in] req The request to be printed 60 * @retval Text representation of req 61 * 62 * This function should be used by callers of the async API 63 */ 64 65char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req) 66{ 67 if (!req->private_print) { 68 return tevent_req_default_print(req, mem_ctx); 69 } 70 71 return req->private_print(req, mem_ctx); 72} 73 74/** 75 * @brief Create an async request 76 * @param[in] mem_ctx The memory context for the result 77 * @param[in] ev The event context this async request will be driven by 78 * @retval A new async request 79 * 80 * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS 81 */ 82 83struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx, 84 void *pdata, 85 size_t data_size, 86 const char *type, 87 const char *location) 88{ 89 struct tevent_req *req; 90 void **ppdata = (void **)pdata; 91 void *data; 92 93 req = talloc_zero(mem_ctx, struct tevent_req); 94 if (req == NULL) { 95 return NULL; 96 } 97 req->internal.private_type = type; 98 req->internal.create_location = location; 99 req->internal.finish_location = NULL; 100 req->internal.state = TEVENT_REQ_IN_PROGRESS; 101 req->internal.trigger = tevent_create_immediate(req); 102 if (!req->internal.trigger) { 103 talloc_free(req); 104 return NULL; 105 } 106 107 data = talloc_zero_size(req, data_size); 108 if (data == NULL) { 109 talloc_free(req); 110 return NULL; 111 } 112 talloc_set_name_const(data, type); 113 114 req->data = data; 115 116 *ppdata = data; 117 return req; 118} 119 120void _tevent_req_notify_callback(struct tevent_req *req, const char *location) 121{ 122 req->internal.finish_location = location; 123 if (req->async.fn != NULL) { 124 req->async.fn(req); 125 } 126} 127 128static void tevent_req_finish(struct tevent_req *req, 129 enum tevent_req_state state, 130 const char *location) 131{ 132 req->internal.state = state; 133 _tevent_req_notify_callback(req, location); 134} 135 136/** 137 * @brief An async request has successfully finished 138 * @param[in] req The finished request 139 * 140 * tevent_req_done is to be used by implementors of async requests. When a 141 * request is successfully finished, this function calls the user's completion 142 * function. 143 */ 144 145void _tevent_req_done(struct tevent_req *req, 146 const char *location) 147{ 148 tevent_req_finish(req, TEVENT_REQ_DONE, location); 149} 150 151/** 152 * @brief An async request has seen an error 153 * @param[in] req The request with an error 154 * @param[in] error The error code 155 * 156 * tevent_req_done is to be used by implementors of async requests. When a 157 * request can not successfully completed, the implementation should call this 158 * function with the appropriate status code. 159 * 160 * If error is 0 the function returns false and does nothing more. 161 * 162 * Call pattern would be 163 * \code 164 * int error = first_function(); 165 * if (tevent_req_error(req, error)) { 166 * return; 167 * } 168 * 169 * error = second_function(); 170 * if (tevent_req_error(req, error)) { 171 * return; 172 * } 173 * 174 * tevent_req_done(req); 175 * return; 176 * \endcode 177 */ 178 179bool _tevent_req_error(struct tevent_req *req, 180 uint64_t error, 181 const char *location) 182{ 183 if (error == 0) { 184 return false; 185 } 186 187 req->internal.error = error; 188 tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location); 189 return true; 190} 191 192/** 193 * @brief Helper function for nomem check 194 * @param[in] p The pointer to be checked 195 * @param[in] req The request being processed 196 * 197 * Convenience helper to easily check alloc failure within a callback 198 * implementing the next step of an async request. 199 * 200 * Call pattern would be 201 * \code 202 * p = talloc(mem_ctx, bla); 203 * if (tevent_req_nomem(p, req)) { 204 * return; 205 * } 206 * \endcode 207 */ 208 209bool _tevent_req_nomem(const void *p, 210 struct tevent_req *req, 211 const char *location) 212{ 213 if (p != NULL) { 214 return false; 215 } 216 tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location); 217 return true; 218} 219 220/** 221 * @brief Immediate event callback 222 * @param[in] ev Event context 223 * @param[in] im The immediate event 224 * @param[in] priv The async request to be finished 225 */ 226static void tevent_req_trigger(struct tevent_context *ev, 227 struct tevent_immediate *im, 228 void *private_data) 229{ 230 struct tevent_req *req = talloc_get_type(private_data, 231 struct tevent_req); 232 233 tevent_req_finish(req, req->internal.state, 234 req->internal.finish_location); 235} 236 237/** 238 * @brief Finish a request before the caller had the change to set the callback 239 * @param[in] req The finished request 240 * @param[in] ev The tevent_context for the timed event 241 * @retval req will be returned 242 * 243 * An implementation of an async request might find that it can either finish 244 * the request without waiting for an external event, or it can't even start 245 * the engine. To present the illusion of a callback to the user of the API, 246 * the implementation can call this helper function which triggers an 247 * immediate timed event. This way the caller can use the same calling 248 * conventions, independent of whether the request was actually deferred. 249 */ 250 251struct tevent_req *tevent_req_post(struct tevent_req *req, 252 struct tevent_context *ev) 253{ 254 tevent_schedule_immediate(req->internal.trigger, 255 ev, tevent_req_trigger, req); 256 return req; 257} 258 259/** 260 * @brief This function destroys the attached private data 261 * @param[in] req The request to poll 262 * @retval The boolean form of "is in progress". 263 * 264 * This function can be used to ask if the given request 265 * is still in progress. 266 * 267 * This function is typically used by sync wrapper functions. 268 */ 269bool tevent_req_is_in_progress(struct tevent_req *req) 270{ 271 if (req->internal.state == TEVENT_REQ_IN_PROGRESS) { 272 return true; 273 } 274 275 return false; 276} 277 278/** 279 * @brief This function destroys the attached private data 280 * @param[in] req The finished request 281 * 282 * This function can be called as last action of a _recv() 283 * function, it destroys the data attached to the tevent_req. 284 */ 285void tevent_req_received(struct tevent_req *req) 286{ 287 TALLOC_FREE(req->data); 288 req->private_print = NULL; 289 290 TALLOC_FREE(req->internal.trigger); 291 TALLOC_FREE(req->internal.timer); 292 293 req->internal.state = TEVENT_REQ_RECEIVED; 294} 295 296/** 297 * @brief This function destroys the attached private data 298 * @param[in] req The request to poll 299 * @param[in] ev The tevent_context to be used 300 * @retval If a critical error has happened in the 301 * tevent loop layer false is returned. 302 * Otherwise true is returned. 303 * This is not the return value of the given request! 304 * 305 * This function can be used to actively poll for the 306 * given request to finish. 307 * 308 * Note: this should only be used if the given tevent context 309 * was created by the caller, to avoid event loop nesting. 310 * 311 * This function is typically used by sync wrapper functions. 312 */ 313bool tevent_req_poll(struct tevent_req *req, 314 struct tevent_context *ev) 315{ 316 while (tevent_req_is_in_progress(req)) { 317 int ret; 318 319 ret = tevent_loop_once(ev); 320 if (ret != 0) { 321 return false; 322 } 323 } 324 325 return true; 326} 327 328bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state, 329 uint64_t *error) 330{ 331 if (req->internal.state == TEVENT_REQ_DONE) { 332 return false; 333 } 334 if (req->internal.state == TEVENT_REQ_USER_ERROR) { 335 *error = req->internal.error; 336 } 337 *state = req->internal.state; 338 return true; 339} 340 341static void tevent_req_timedout(struct tevent_context *ev, 342 struct tevent_timer *te, 343 struct timeval now, 344 void *private_data) 345{ 346 struct tevent_req *req = talloc_get_type(private_data, 347 struct tevent_req); 348 349 TALLOC_FREE(req->internal.timer); 350 351 tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__); 352} 353 354bool tevent_req_set_endtime(struct tevent_req *req, 355 struct tevent_context *ev, 356 struct timeval endtime) 357{ 358 TALLOC_FREE(req->internal.timer); 359 360 req->internal.timer = tevent_add_timer(ev, req, endtime, 361 tevent_req_timedout, 362 req); 363 if (tevent_req_nomem(req->internal.timer, req)) { 364 return false; 365 } 366 367 return true; 368} 369 370void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt) 371{ 372 req->async.fn = fn; 373 req->async.private_data = pvt; 374} 375 376void *_tevent_req_callback_data(struct tevent_req *req) 377{ 378 return req->async.private_data; 379} 380 381void *_tevent_req_data(struct tevent_req *req) 382{ 383 return req->data; 384} 385 386/** 387 * @brief This function sets a print function for the given request 388 * @param[in] req The given request 389 * @param[in] fn A pointer to the print function 390 * 391 * This function can be used to setup a print function for the given request. 392 * This will be triggered if the tevent_req_print() function was 393 * called on the given request. 394 * 395 * Note: this function should only be used for debugging. 396 */ 397void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn) 398{ 399 req->private_print = fn; 400} 401 402/** 403 * @brief This function sets a cancel function for the given request 404 * @param[in] req The given request 405 * @param[in] fn A pointer to the cancel function 406 * 407 * This function can be used to setup a cancel function for the given request. 408 * This will be triggered if the tevent_req_cancel() function was 409 * called on the given request. 410 * 411 */ 412void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn) 413{ 414 req->private_cancel = fn; 415} 416 417/** 418 * @brief This function tries to cancel the given request 419 * @param[in] req The given request 420 * @param[in] location Automaticly filled with the __location__ macro 421 * via the tevent_req_cancel() macro. This is for debugging 422 * only! 423 * @retval This function returns true is the request is cancelable. 424 * Otherwise false is returned. 425 * 426 * This function can be used to cancel the given request. 427 * 428 * It is only possible to cancel a request when the implementation 429 * has registered a cancel function via the tevent_req_set_cancel_fn(). 430 * 431 * Note: Even if the function returns true, the caller need to wait 432 * for the function to complete normally. 433 * Only the _recv() function of the given request indicates 434 * if the request was really canceled. 435 */ 436bool _tevent_req_cancel(struct tevent_req *req, const char *location) 437{ 438 if (req->private_cancel == NULL) { 439 return false; 440 } 441 442 return req->private_cancel(req); 443} 444