2009-02-13 17:43:04 +03:00
/*
Unix SMB / CIFS implementation .
Infrastructure for async requests
Copyright ( C ) Volker Lendecke 2008
2009-02-13 17:37:35 +03:00
Copyright ( C ) Stefan Metzmacher 2009
2009-02-13 17:43:04 +03:00
2009-02-16 10:52:06 +03:00
* * NOTE ! The following LGPL license applies to the tevent
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
2009-02-13 17:43:04 +03:00
2009-02-16 10:52:06 +03:00
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 3 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
2009-02-13 17:43:04 +03:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2009-02-16 10:52:06 +03:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
2009-02-13 17:43:04 +03:00
2009-02-16 10:52:06 +03:00
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2009-02-13 17:43:04 +03:00
*/
2009-02-13 17:37:35 +03:00
# include "replace.h"
# include "tevent.h"
# include "tevent_internal.h"
# include "tevent_util.h"
2009-02-13 17:43:04 +03:00
/**
2009-02-25 16:29:31 +03:00
* @ brief The default print function for creating debug messages
2009-02-13 17:43:04 +03:00
* @ param [ in ] req The request to be printed
2009-02-25 16:29:31 +03:00
* @ param [ in ] mem_ctx The memory context for the result
2009-02-13 17:43:04 +03:00
* @ retval Text representation of req
*
2009-02-25 16:29:31 +03:00
* The function should not be used by users of the asynx API ,
* but custom print function can use it and append custom text
* to the string .
2009-02-13 17:43:04 +03:00
*/
2009-02-25 16:29:31 +03:00
char * tevent_req_default_print ( struct tevent_req * req , TALLOC_CTX * mem_ctx )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
return talloc_asprintf ( mem_ctx ,
" tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
" state[%s (%p)] timer[%p] " ,
req , req - > internal . location ,
req - > internal . state ,
( unsigned long long ) req - > internal . error ,
( unsigned long long ) req - > internal . error ,
2009-02-28 23:44:30 +03:00
talloc_get_name ( req - > data ) ,
req - > data ,
2009-02-13 17:37:35 +03:00
req - > internal . timer
) ;
2009-02-13 17:43:04 +03:00
}
2009-02-25 16:29:31 +03:00
/**
* @ brief Print an tevent_req structure in debug messages
* @ param [ in ] mem_ctx The memory context for the result
* @ param [ in ] req The request to be printed
* @ retval Text representation of req
*
* This function should be used by callers of the async API
*/
char * tevent_req_print ( TALLOC_CTX * mem_ctx , struct tevent_req * req )
{
if ( ! req - > private_print ) {
return tevent_req_default_print ( req , mem_ctx ) ;
}
return req - > private_print ( req , mem_ctx ) ;
}
2009-02-13 17:43:04 +03:00
/**
* @ brief Create an async request
* @ param [ in ] mem_ctx The memory context for the result
* @ param [ in ] ev The event context this async request will be driven by
* @ retval A new async request
*
* The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
*/
2009-02-13 17:37:35 +03:00
struct tevent_req * _tevent_req_create ( TALLOC_CTX * mem_ctx ,
2009-02-28 23:44:30 +03:00
void * pdata ,
size_t data_size ,
2009-02-13 17:37:35 +03:00
const char * type ,
const char * location )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
struct tevent_req * req ;
2009-02-28 23:44:30 +03:00
void * * ppdata = ( void * * ) pdata ;
void * data ;
2009-02-13 17:37:35 +03:00
req = talloc_zero ( mem_ctx , struct tevent_req ) ;
if ( req = = NULL ) {
return NULL ;
}
req - > internal . private_type = type ;
req - > internal . location = location ;
req - > internal . state = TEVENT_REQ_IN_PROGRESS ;
2009-02-13 17:43:04 +03:00
2009-02-28 23:44:30 +03:00
data = talloc_size ( req , data_size ) ;
if ( data = = NULL ) {
2009-02-13 17:37:35 +03:00
talloc_free ( req ) ;
2009-02-13 17:43:04 +03:00
return NULL ;
}
2009-02-28 23:44:30 +03:00
talloc_set_name_const ( data , type ) ;
2009-02-13 17:37:35 +03:00
2009-02-28 23:44:30 +03:00
req - > data = data ;
2009-02-13 17:37:35 +03:00
2009-02-28 23:44:30 +03:00
* ppdata = data ;
2009-02-13 17:37:35 +03:00
return req ;
2009-02-13 17:43:04 +03:00
}
2009-02-13 17:37:35 +03:00
static void tevent_req_finish ( struct tevent_req * req , enum tevent_req_state state )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
req - > internal . state = state ;
2009-02-13 17:43:04 +03:00
if ( req - > async . fn ! = NULL ) {
req - > async . fn ( req ) ;
}
}
/**
* @ brief An async request has successfully finished
* @ param [ in ] req The finished request
*
* async_req_done is to be used by implementors of async requests . When a
* request is successfully finished , this function calls the user ' s completion
* function .
*/
2009-02-13 17:37:35 +03:00
void tevent_req_done ( struct tevent_req * req )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
tevent_req_finish ( req , TEVENT_REQ_DONE ) ;
2009-02-13 17:43:04 +03:00
}
/**
* @ brief An async request has seen an error
* @ param [ in ] req The request with an error
* @ param [ in ] error The error code
*
2009-02-13 17:37:35 +03:00
* tevent_req_done is to be used by implementors of async requests . When a
2009-02-13 17:43:04 +03:00
* request can not successfully completed , the implementation should call this
* function with the appropriate status code .
2009-02-13 17:37:35 +03:00
*
* If error is 0 the function returns false and does nothing more .
*
* Call pattern would be
* \ code
* int error = first_function ( ) ;
* if ( tevent_req_error ( req , error ) ) {
* return ;
* }
*
* error = second_function ( ) ;
* if ( tevent_req_error ( req , error ) ) {
* return ;
* }
*
* tevent_req_done ( req ) ;
* return ;
* \ endcode
2009-02-13 17:43:04 +03:00
*/
2009-02-13 17:37:35 +03:00
bool tevent_req_error ( struct tevent_req * req , uint64_t error )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
if ( error = = 0 ) {
return false ;
2009-02-13 17:43:04 +03:00
}
2009-02-13 17:37:35 +03:00
req - > internal . error = error ;
tevent_req_finish ( req , TEVENT_REQ_USER_ERROR ) ;
return true ;
2009-02-13 17:43:04 +03:00
}
/**
* @ brief Helper function for nomem check
* @ param [ in ] p The pointer to be checked
* @ param [ in ] req The request being processed
*
* Convenience helper to easily check alloc failure within a callback
* implementing the next step of an async request .
*
* Call pattern would be
* \ code
* p = talloc ( mem_ctx , bla ) ;
2009-02-13 17:37:35 +03:00
* if ( tevent_req_nomem ( p , req ) ) {
2009-02-13 17:43:04 +03:00
* return ;
* }
* \ endcode
*/
2009-02-13 17:37:35 +03:00
bool tevent_req_nomem ( const void * p , struct tevent_req * req )
2009-02-13 17:43:04 +03:00
{
if ( p ! = NULL ) {
return false ;
}
2009-02-13 17:37:35 +03:00
tevent_req_finish ( req , TEVENT_REQ_NO_MEMORY ) ;
2009-02-13 17:43:04 +03:00
return true ;
}
/**
2009-02-13 17:37:35 +03:00
* @ brief Timed event callback
* @ param [ in ] ev Event context
* @ param [ in ] te The timed event
* @ param [ in ] now zero time
* @ param [ in ] priv The async request to be finished
*/
static void tevent_req_trigger ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval zero ,
void * private_data )
{
struct tevent_req * req = talloc_get_type ( private_data ,
struct tevent_req ) ;
talloc_free ( req - > internal . trigger ) ;
req - > internal . trigger = NULL ;
tevent_req_finish ( req , req - > internal . state ) ;
}
/**
* @ brief Finish a request before the caller had the change to set the callback
2009-02-13 17:43:04 +03:00
* @ param [ in ] req The finished request
2009-02-13 17:37:35 +03:00
* @ param [ in ] ev The tevent_context for the timed event
* @ retval On success req will be returned ,
* on failure req will be destroyed
2009-02-13 17:43:04 +03:00
*
* An implementation of an async request might find that it can either finish
* the request without waiting for an external event , or it can ' t even start
* the engine . To present the illusion of a callback to the user of the API ,
* the implementation can call this helper function which triggers an
* immediate timed event . This way the caller can use the same calling
* conventions , independent of whether the request was actually deferred .
*/
2009-02-13 17:37:35 +03:00
struct tevent_req * tevent_req_post ( struct tevent_req * req ,
struct tevent_context * ev )
2009-02-13 17:43:04 +03:00
{
2009-02-17 01:34:15 +03:00
req - > internal . trigger = tevent_add_timer ( ev , req , tevent_timeval_zero ( ) ,
2009-02-13 17:37:35 +03:00
tevent_req_trigger , req ) ;
if ( ! req - > internal . trigger ) {
talloc_free ( req ) ;
return NULL ;
2009-02-13 17:43:04 +03:00
}
2009-02-13 17:37:35 +03:00
return req ;
2009-02-13 17:43:04 +03:00
}
2009-02-13 17:37:35 +03:00
bool tevent_req_is_in_progress ( struct tevent_req * req )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
if ( req - > internal . state = = TEVENT_REQ_IN_PROGRESS ) {
return true ;
}
2009-02-13 17:43:04 +03:00
2009-02-13 17:37:35 +03:00
return false ;
2009-02-13 17:43:04 +03:00
}
2009-03-10 15:54:57 +03:00
/**
* @ brief This function destroys the attached private data
* @ param [ in ] req The finished request
*
* This function can be called as last action of a _recv ( )
* function , it destroys the data attached to the tevent_req .
*/
void tevent_req_received ( struct tevent_req * req )
{
talloc_free ( req - > data ) ;
req - > data = NULL ;
req - > private_print = NULL ;
talloc_free ( req - > internal . trigger ) ;
req - > internal . trigger = NULL ;
talloc_free ( req - > internal . timer ) ;
req - > internal . timer = NULL ;
req - > internal . state = TEVENT_REQ_RECEIVED ;
}
2009-02-25 15:53:19 +03:00
bool tevent_req_poll ( struct tevent_req * req ,
struct tevent_context * ev )
{
while ( tevent_req_is_in_progress ( req ) ) {
int ret ;
ret = tevent_loop_once ( ev ) ;
if ( ret ! = 0 ) {
return false ;
}
}
return true ;
}
2009-02-13 17:37:35 +03:00
bool tevent_req_is_error ( struct tevent_req * req , enum tevent_req_state * state ,
uint64_t * error )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
if ( req - > internal . state = = TEVENT_REQ_DONE ) {
return false ;
2009-02-13 17:43:04 +03:00
}
2009-02-13 17:37:35 +03:00
if ( req - > internal . state = = TEVENT_REQ_USER_ERROR ) {
* error = req - > internal . error ;
2009-02-13 17:43:04 +03:00
}
2009-02-13 17:37:35 +03:00
* state = req - > internal . state ;
2009-02-13 17:43:04 +03:00
return true ;
}
2009-02-13 17:37:35 +03:00
static void tevent_req_timedout ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval now ,
void * private_data )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
struct tevent_req * req = talloc_get_type ( private_data ,
struct tevent_req ) ;
2009-02-13 17:43:04 +03:00
2009-02-13 17:37:35 +03:00
talloc_free ( req - > internal . timer ) ;
req - > internal . timer = NULL ;
2009-02-13 17:43:04 +03:00
2009-02-13 17:37:35 +03:00
tevent_req_finish ( req , TEVENT_REQ_TIMED_OUT ) ;
2009-02-13 17:43:04 +03:00
}
2009-02-17 12:15:18 +03:00
bool tevent_req_set_endtime ( struct tevent_req * req ,
2009-02-13 17:37:35 +03:00
struct tevent_context * ev ,
struct timeval endtime )
2009-02-13 17:43:04 +03:00
{
2009-02-13 17:37:35 +03:00
talloc_free ( req - > internal . timer ) ;
2009-02-13 17:43:04 +03:00
2009-02-13 17:37:35 +03:00
req - > internal . timer = tevent_add_timer ( ev , req , endtime ,
tevent_req_timedout ,
req ) ;
if ( tevent_req_nomem ( req - > internal . timer , req ) ) {
2009-02-13 17:43:04 +03:00
return false ;
}
return true ;
}
2009-02-28 23:44:30 +03:00
void tevent_req_set_callback ( struct tevent_req * req , tevent_req_fn fn , void * pvt )
{
req - > async . fn = fn ;
req - > async . private_data = pvt ;
}
void * _tevent_req_callback_data ( struct tevent_req * req )
{
return req - > async . private_data ;
}
void * _tevent_req_data ( struct tevent_req * req )
{
return req - > data ;
}
void tevent_req_set_print_fn ( struct tevent_req * req , tevent_req_print_fn fn )
{
req - > private_print = fn ;
}