From 4330bed1fc49328de3b1226313af3f25dccbfbc9 Mon Sep 17 00:00:00 2001 From: scottmk Date: Tue, 8 Dec 2009 03:40:00 +0000 Subject: [PATCH] Eliminated the function pointer osrf_stack_entry_point so that osrf_app_session_queue_wait() can call osrf_stack_process() directly. This change entails some juggling of declarations, headers, and the like, but does not substantively affect the processing. Also: made a number of other minor changes, mostly to comments and white space. M include/opensrf/osrf_stack.h M include/opensrf/osrf_app_session.h M src/libopensrf/osrf_app_session.c M src/libopensrf/osrf_stack.c git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@1868 9efc2488-bf62-4759-914b-345cdb29e865 --- include/opensrf/osrf_app_session.h | 22 ++- include/opensrf/osrf_stack.h | 6 +- src/libopensrf/osrf_app_session.c | 230 ++++++++++++++++++++++------- src/libopensrf/osrf_stack.c | 8 +- 4 files changed, 194 insertions(+), 72 deletions(-) diff --git a/include/opensrf/osrf_app_session.h b/include/opensrf/osrf_app_session.h index c626040..79de92f 100644 --- a/include/opensrf/osrf_app_session.h +++ b/include/opensrf/osrf_app_session.h @@ -33,9 +33,13 @@ enum OSRF_SESSION_TYPE { OSRF_SESSION_CLIENT }; -/* entry point for data into the stack. Gets set in osrf_stack.c */ -int (*osrf_stack_entry_point) (transport_client* client, int timeout, int* recvd ); +/** + @brief Representation of a session with another application. + An osrfAppSession is a list of lists. It includes a list of osrfAppRequests + representing outstanding requests. Each osrfAppRequest includes a list of + responses. +*/ struct osrf_app_session_struct { /** Our messag passing object */ @@ -48,7 +52,8 @@ struct osrf_app_session_struct { /** The current remote id of the remote service we're talking to */ char* remote_id; - /** Whom we're talking to if we're a client; what app we're serving if we're a server */ + /** Whom we're talking to if we're a client; + what app we're serving if we're a server */ char* remote_service; /** The current request thread_trace */ @@ -56,7 +61,7 @@ struct osrf_app_session_struct { /** Our ID */ char* session_id; - /** Boolean; true if this session does not require connect messages */ + /* true if this session does not require connect messages */ int stateless; /** The connect state */ @@ -73,7 +78,7 @@ struct osrf_app_session_struct { void (*userDataFree) (void*); - int transport_error; + int transport_error; }; typedef struct osrf_app_session_struct osrfAppSession; @@ -99,7 +104,8 @@ char* osrf_app_session_set_locale( osrfAppSession*, const char* ); osrfAppSession* osrf_app_session_find_session( const char* session_id ); /** Builds a new app_request object with the given payload andn returns - the id of the request. This id is then used to perform work on the requeset. + the id of the request. This id is then used to perform work on the + requeset. */ int osrfAppSessionMakeRequest( osrfAppSession* session, const jsonObject* params, @@ -140,7 +146,7 @@ int osrfAppSessionConnect( osrfAppSession* ); /** Sends a disconnect message to the remote service. No response is expected */ int osrf_app_session_disconnect( osrfAppSession* ); -/** Waits up to 'timeout' seconds for some data to arrive. +/** Waits up to 'timeout' seconds for some data to arrive. Any data that arrives will be processed according to its payload and message type. This method will return after any data has arrived. @@ -163,7 +169,7 @@ int osrfAppRequestRespondComplete( int osrfAppSessionStatus( osrfAppSession* ses, int type, const char* name, int reqId, const char* message ); -void osrfAppSessionCleanup(); +void osrfAppSessionCleanup( void ); #ifdef __cplusplus } diff --git a/include/opensrf/osrf_stack.h b/include/opensrf/osrf_stack.h index c3a14d6..029c374 100644 --- a/include/opensrf/osrf_stack.h +++ b/include/opensrf/osrf_stack.h @@ -9,9 +9,13 @@ extern "C" { #endif -osrfAppSession* osrf_stack_transport_handler( transport_message* msg, +struct osrf_app_session_struct; + +struct osrf_app_session_struct* osrf_stack_transport_handler( transport_message* msg, const char* my_service ); +int osrf_stack_process( transport_client* client, int timeout, int* msg_received ); + #ifdef __cplusplus } #endif diff --git a/src/libopensrf/osrf_app_session.c b/src/libopensrf/osrf_app_session.c index 5427e56..2709d69 100644 --- a/src/libopensrf/osrf_app_session.c +++ b/src/libopensrf/osrf_app_session.c @@ -5,42 +5,56 @@ #include #include "opensrf/osrf_app_session.h" +#include "opensrf/osrf_stack.h" struct osrf_app_request_struct { - /** Our controlling session. */ + /** The controlling session. */ struct osrf_app_session_struct* session; - /** Our "id". */ + /** Request id. It is the same as the thread_trace of the REQUEST message + for which it was created. + */ int request_id; /** True if we have received a 'request complete' message from our request. */ int complete; - /** Our original request payload. */ + /** The original REQUEST message payload. */ osrfMessage* payload; - /** List of responses to our request. */ + /** Linked list of responses to the request. */ osrfMessage* result; - /** Boolean; if true, then a call that is waiting on a response, will reset the + /** Boolean; if true, then a call that is waiting on a response will reset the timeout and set this variable back to false. */ int reset_timeout; }; typedef struct osrf_app_request_struct osrfAppRequest; -/** Send the given message */ +/* Send the given message */ static int _osrf_app_session_send( osrfAppSession*, osrfMessage* msg ); static int osrfAppSessionMakeLocaleRequest( osrfAppSession* session, const jsonObject* params, const char* method_name, int protocol, osrfStringArray* param_strings, char* locale ); -/* the global app_session cache */ +/** @brief The global session cache. + + Key: session_id. Data: osrfAppSession. +*/ static osrfHash* osrfAppSessionCache = NULL; -// -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // Request API // -------------------------------------------------------------------------- -/** Allocates and initializes a new app_request object */ +/** + @brief Create a new osrfAppRequest. + @param session Pointer to the osrfAppSession that will own the new osrfAppRequest. + @param msg Pointer to the osrfMessage representing the request. + @return Pointer to the new osrfAppRequest. + + The calling code is responsible for freeing the osrfAppRequest by calling + _osrf_app_request_free(). In practice this normally happens via a callback installed + in an osrfList. +*/ static osrfAppRequest* _osrf_app_request_init( osrfAppSession* session, osrfMessage* msg ) { @@ -55,42 +69,53 @@ static osrfAppRequest* _osrf_app_request_init( req->reset_timeout = 0; return req; - } -void osrfAppSessionCleanup() { - osrfHashFree(osrfAppSessionCache); - osrfAppSessionCache = NULL; -} +/** + @brief Free an osrfAppRequest and everything it owns. + @param req Pointer to an osrfAppRequest, cast to a void pointer. -/** Frees memory used by an app_request object */ + This function is installed as a callback in the osrfList request_queue, a member + of osrfAppSession. +*/ static void _osrf_app_request_free( void * req ){ - if( req == NULL ) return; - osrfAppRequest* r = (osrfAppRequest*) req; - if( r->payload ) osrfMessageFree( r->payload ); - - /* Free the messages in the result queue */ + if( req ) { + osrfAppRequest* r = (osrfAppRequest*) req; + if( r->payload ) + osrfMessageFree( r->payload ); + + /* Free the messages in the result queue */ + osrfMessage* next_msg; + while( r->result ) { + next_msg = r->result->next; + osrfMessageFree( r->result ); + r->result = next_msg; + } - osrfMessage* next_msg; - while( r->result ) { - next_msg = r->result->next; - osrfMessageFree( r->result ); - r->result = next_msg; + free( r ); } - - free( r ); } -/** Pushes the given message onto the list of 'responses' to this request */ +/** + @brief Append a new message to the list of responses to a request. + @param req Pointer to the osrfAppRequest for the original REQUEST message. + @param result Pointer to an osrfMessage received in response to the request. + + We maintain a linked list of response messages, and traverse it to find the end. +*/ static void _osrf_app_request_push_queue( osrfAppRequest* req, osrfMessage* result ){ - if(req == NULL || result == NULL) return; - osrfLogDebug( OSRF_LOG_MARK, "App Session pushing request [%d] onto request queue", result->thread_trace ); + if(req == NULL || result == NULL) + return; + + osrfLogDebug( OSRF_LOG_MARK, "App Session pushing request [%d] onto request queue", + result->thread_trace ); if(req->result == NULL) { - req->result = result; + req->result = result; // Add the first node } else { + // Find the last node in the list, and append the new node to it osrfMessage* ptr = req->result; osrfMessage* ptr2 = req->result->next; while( ptr2 ) { @@ -101,37 +126,61 @@ static void _osrf_app_request_push_queue( osrfAppRequest* req, osrfMessage* resu } } -/** Removes this app_request from our session request set */ +/** + @brief Remove an osrfAppRequest (identified by request_id) from an osrfAppSession. + @param session Pointer to the osrfAppSession that owns the osrfAppRequest. + @param req_id request_id of the osrfAppRequest to be removed. + + The osrfAppRequest itself is freed by a callback installed in the osrfList where it resides. +*/ void osrf_app_session_request_finish( osrfAppSession* session, int req_id ){ - if(session == NULL) return; - osrfAppRequest* req = OSRF_LIST_GET_INDEX( session->request_queue, req_id ); - if(req == NULL) return; - osrfListRemove( req->session->request_queue, req->request_id ); + if( session ) { + osrfAppRequest* req = OSRF_LIST_GET_INDEX( session->request_queue, req_id ); + if(req) + osrfListRemove( req->session->request_queue, req->request_id ); + } } +/** + @brief Set the timeout for a request to one second. + @param session Pointer to the relevant osrfAppSession. + @param req_id Request ID of the request whose timeout is to be reset. + + The request to be reset is identified by the combination of session and request id. +*/ void osrf_app_session_request_reset_timeout( osrfAppSession* session, int req_id ) { - if(session == NULL) return; + if(session == NULL) + return; osrfLogDebug( OSRF_LOG_MARK, "Resetting request timeout %d", req_id ); osrfAppRequest* req = OSRF_LIST_GET_INDEX( session->request_queue, req_id ); - if(req == NULL) return; - req->reset_timeout = 1; + if( req ) + req->reset_timeout = 1; } /** - Checks the receive queue for messages. If any are found, the first + Checke the receive queue for messages. If any are found, the first is popped off and returned. Otherwise, this method will wait at most timeout seconds for a message to appear in the receive queue. Once it arrives it is returned. If no messages arrive in the timeout provided, null is returned. */ +/** + @brief Return the next response message for a given request, subject to a timeout. + @param req Pointer to the osrfAppRequest representing the request. + @param timeout Maxmimum time to wait, in seconds. + + @return + + If the input queue for this request is not empty, dequeue the next message and return it. +*/ static osrfMessage* _osrf_app_request_recv( osrfAppRequest* req, int timeout ) { if(req == NULL) return NULL; if( req->result != NULL ) { - /* pop off the first message in the list */ + /* Dequeue the next message in the list */ osrfMessage* tmp_msg = req->result; req->result = req->result->next; return tmp_msg; @@ -142,7 +191,8 @@ static osrfMessage* _osrf_app_request_recv( osrfAppRequest* req, int timeout ) { while( remaining >= 0 ) { /* tell the session to wait for stuff */ - osrfLogDebug( OSRF_LOG_MARK, "In app_request receive with remaining time [%d]", (int) remaining ); + osrfLogDebug( OSRF_LOG_MARK, "In app_request receive with remaining time [%d]", + (int) remaining ); osrf_app_session_queue_wait( req->session, 0, NULL ); if(req->session->transport_error) { @@ -152,7 +202,7 @@ static osrfMessage* _osrf_app_request_recv( osrfAppRequest* req, int timeout ) { if( req->result != NULL ) { /* if we received anything */ /* pop off the first message in the list */ - osrfLogDebug( OSRF_LOG_MARK, "app_request_recv received a message, returning it"); + osrfLogDebug( OSRF_LOG_MARK, "app_request_recv received a message, returning it" ); osrfMessage* ret_msg = req->result; req->result = ret_msg->next; if (ret_msg->sender_locale) @@ -212,8 +262,6 @@ static int _osrf_app_request_resend( osrfAppRequest* req ) { } - -// -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // Session API // -------------------------------------------------------------------------- @@ -238,19 +286,35 @@ char* osrf_app_session_set_locale( osrfAppSession* session, const char* locale ) return session->session_locale; } -/** returns a session from the global session hash */ +/** + @brief Find the osrfAppSession for a given session id. + @param session_id The session id to look for. + @return Pointer to the corresponding osrfAppSession if found, or NULL if not. + + Search the global session cache for the specified session id. +*/ osrfAppSession* osrf_app_session_find_session( const char* session_id ) { - if(session_id) return osrfHashGet(osrfAppSessionCache, session_id); + if(session_id) + return osrfHashGet( osrfAppSessionCache, session_id ); return NULL; } -/** adds a session to the global session cache */ +/** + @brief Add a session to the global session cache, keyed by session id. + @param session Pointer to the osrfAppSession to be added. + + If a cache doesn't exist yet, create one. It's an osrfHash using session ids for the + key and osrfAppSessions for the data. +*/ static void _osrf_app_session_push_session( osrfAppSession* session ) { - if(!session) return; - if( osrfAppSessionCache == NULL ) osrfAppSessionCache = osrfNewHash(); - if( osrfHashGet( osrfAppSessionCache, session->session_id ) ) return; - osrfHashSet( osrfAppSessionCache, session, session->session_id ); + if( session ) { + if( osrfAppSessionCache == NULL ) + osrfAppSessionCache = osrfNewHash(); + if( osrfHashGet( osrfAppSessionCache, session->session_id ) ) + return; // A session with this id is already in the cache. Shouldn't happen. + osrfHashSet( osrfAppSessionCache, session, session->session_id ); + } } /** Allocates and initializes a new app_session */ @@ -334,7 +398,6 @@ osrfAppSession* osrfAppSessionClientInit( const char* remote_service ) { session->thread_trace = 0; session->state = OSRF_SESSION_DISCONNECTED; session->type = OSRF_SESSION_CLIENT; - //session->next = NULL; session->userData = NULL; session->userDataFree = NULL; @@ -394,6 +457,30 @@ osrfAppSession* osrf_app_server_session_init( } +/** + @brief Create a REQUEST message, send it, and save it for future reference. + @param session Pointer to the current session, which has the addressing information. + @param params One way of specifying the parameters for the method. + @param method_name The name of the method to be called. + @param protocol Protocol. + @param param_strings Another way of specifying the parameters for the method. + @return The request ID of the resulting REQUEST message, or -1 upon error. + + If @a params is non-NULL, use it to specify the parameters to the method. Otherwise + use @a param_strings. + + If @a params points to a JSON_ARRAY, then pass each element of the array as a separate + parameter. If @a params points to any other kind of jsonObject, pass it as a single + parameter. + + If @a params is NULL, and @a param_strings is not NULL, then each pointer in the + osrfStringArray must point to a JSON string encoding a parameter. Pass them. + + At this writing, all calls to this function use @a params to pass parameters, rather than + @a param_strings. + + This function is a thin wrapper for osrfAppSessionMakeLocaleRequest(). +*/ int osrfAppSessionMakeRequest( osrfAppSession* session, const jsonObject* params, const char* method_name, int protocol, osrfStringArray* param_strings ) { @@ -402,6 +489,21 @@ int osrfAppSessionMakeRequest( method_name, protocol, param_strings, NULL ); } +/** + @brief Create a REQUEST message, send it, and save it for future reference. + @param session Pointer to the current session, which has the addressing information. + @param params One way of specifying the parameters for the method. + @param method_name The name of the method to be called. + @param protocol Protocol. + @param param_strings Another way of specifying the parameters for the method. + @param locale Pointer to a locale string. + @return The request ID of the resulting REQUEST message, or -1 upon error. + + See the discussion of osrfAppSessionMakeRequest(), which at this writing is the only + place that calls this function. + + At this writing, the @a param_strings and @a locale parameters are always NULL. +*/ static int osrfAppSessionMakeLocaleRequest( osrfAppSession* session, const jsonObject* params, const char* method_name, int protocol, osrfStringArray* param_strings, char* locale ) { @@ -435,7 +537,8 @@ static int osrfAppSessionMakeLocaleRequest( osrfAppRequest* req = _osrf_app_request_init( session, req_msg ); if(_osrf_app_session_send( session, req_msg ) ) { - osrfLogWarning( OSRF_LOG_MARK, "Error sending request message [%d]", session->thread_trace ); + osrfLogWarning( OSRF_LOG_MARK, "Error sending request message [%d]", + session->thread_trace ); _osrf_app_request_free(req); return -1; } @@ -657,8 +760,8 @@ static int _osrf_app_session_send( osrfAppSession* session, osrfMessage* msg ){ */ int osrf_app_session_queue_wait( osrfAppSession* session, int timeout, int* recvd ){ if(session == NULL) return 0; - osrfLogDebug(OSRF_LOG_MARK, "AppSession in queue_wait with timeout %d", timeout ); - return osrf_stack_entry_point(session->transport_handle, timeout, recvd); + osrfLogDebug(OSRF_LOG_MARK, "AppSession in queue_wait with timeout %d", timeout ); + return osrf_stack_process(session->transport_handle, timeout, recvd); } /** Disconnects (if client) and removes the given session from the global session cache @@ -729,7 +832,8 @@ int osrfAppRequestRespondComplete( osrfAppSession* ses, int requestId, const jsonObject* data ) { osrfMessage* status = osrf_message_init( STATUS, requestId, 1); - osrf_message_set_status_info( status, "osrfConnectStatus", "Request Complete", OSRF_STATUS_COMPLETE ); + osrf_message_set_status_info( status, "osrfConnectStatus", "Request Complete", + OSRF_STATUS_COMPLETE ); if (data) { osrfMessage* payload = osrf_message_init( RESULT, requestId, 1 ); @@ -768,6 +872,18 @@ int osrfAppSessionStatus( osrfAppSession* ses, int type, return -1; } +/** + @brief Free the global session cache. + + Note that the osrfHash that implements the global session cache does @em not have a + callback function installed for freeing its cargo. As a result, any outstanding + osrfAppSessions are leaked, along with all the osrfAppRequests and osrfMessages they + own. +*/ +void osrfAppSessionCleanup( void ) { + osrfHashFree(osrfAppSessionCache); + osrfAppSessionCache = NULL; +} diff --git a/src/libopensrf/osrf_stack.c b/src/libopensrf/osrf_stack.c index 86a421b..5238db2 100644 --- a/src/libopensrf/osrf_stack.c +++ b/src/libopensrf/osrf_stack.c @@ -5,14 +5,10 @@ #define OSRF_MAX_MSGS_PER_PACKET 256 // ----------------------------------------------------------------------------- -static int osrf_stack_process( transport_client* client, int timeout, int* msg_received ); static void osrf_stack_application_handler( osrfAppSession* session, osrfMessage* msg ); static void _do_client( osrfAppSession*, osrfMessage* ); static void _do_server( osrfAppSession*, osrfMessage* ); -/* tell osrfAppSession where the stack entry is */ -int (*osrf_stack_entry_point) (transport_client*, int, int*) = &osrf_stack_process; - /** @brief Read and process available transport_messages for a transport_client. @param client Pointer to the transport_client whose socket is to be read. @@ -33,7 +29,7 @@ int (*osrf_stack_entry_point) (transport_client*, int, int*) = &osrf_stack_proc if you don't. A timeout is not treated as an error; it just means you must set that boolean to false. */ -static int osrf_stack_process( transport_client* client, int timeout, int* msg_received ) { +int osrf_stack_process( transport_client* client, int timeout, int* msg_received ) { if( !client ) return -1; transport_message* msg = NULL; if(msg_received) *msg_received = 0; @@ -77,7 +73,7 @@ static int osrf_stack_process( transport_client* client, int timeout, int* msg_r transport_message. Pass each one to the appropriate routine for processing, depending on whether you're acting as a client or as a server. */ -osrfAppSession* osrf_stack_transport_handler( transport_message* msg, +struct osrf_app_session_struct* osrf_stack_transport_handler( transport_message* msg, const char* my_service ) { if(!msg) return NULL; -- 2.43.2