From 46d00ed35ff1aa268e0a6caa616d0ad64c1066f8 Mon Sep 17 00:00:00 2001 From: scottmk Date: Sun, 3 Jan 2010 19:28:02 +0000 Subject: [PATCH 1/1] Finished adding doxygen-style comments to document the app session functions. Removed comments from the header so that they wouldn't override more complete comments in the implementation file. Tweaked the white space here and there. Changed the return code in a few cases, for consistency. A couple of functions seemed unable to decide whether 0 was good and 1 was bad, or vice versa. M include/opensrf/osrf_app_session.h M src/libopensrf/osrf_app_session.c git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@1883 9efc2488-bf62-4759-914b-345cdb29e865 --- include/opensrf/osrf_app_session.h | 44 +---- src/libopensrf/osrf_app_session.c | 261 +++++++++++++++++++++++------ 2 files changed, 209 insertions(+), 96 deletions(-) diff --git a/include/opensrf/osrf_app_session.h b/include/opensrf/osrf_app_session.h index b71f078..2ffcad0 100644 --- a/include/opensrf/osrf_app_session.h +++ b/include/opensrf/osrf_app_session.h @@ -90,95 +90,57 @@ struct osrf_app_session_struct { }; typedef struct osrf_app_session_struct osrfAppSession; - - // -------------------------------------------------------------------------- // PUBLIC API *** // -------------------------------------------------------------------------- -/** Allocates a initializes a new app_session */ osrfAppSession* osrfAppSessionClientInit( const char* remote_service ); -/** Allocates and initializes a new server session. The global session cache - is checked to see if this session already exists, if so, it's returned -*/ osrfAppSession* osrf_app_server_session_init( const char* session_id, const char* our_app, const char* remote_id ); -/** sets the default locale for a session **/ char* osrf_app_session_set_locale( osrfAppSession*, const char* ); -/** returns a session from the global session hash */ osrfAppSession* osrf_app_session_find_session( const char* session_id ); -/** Builds a new app_request object with the given payload and returns - the id of the request. This id is then used to perform work on the - request. DEPRECATED; use osrfAppSessionSendRequest() instead. -*/ +/* DEPRECATED; use osrfAppSessionSendRequest() instead. */ int osrfAppSessionMakeRequest( osrfAppSession* session, const jsonObject* params, const char* method_name, int protocol, osrfStringArray* param_strings); -/** Builds a new app_request object with the given payload and returns - the id of the request. This id is then used to perform work on the - request. -*/ int osrfAppSessionSendRequest( osrfAppSession* session, const jsonObject* params, const char* method_name, int protocol ); -/** Sets the given request to complete state */ void osrf_app_session_set_complete( osrfAppSession* session, int request_id ); -/** Returns true if the given request is complete */ int osrf_app_session_request_complete( const osrfAppSession* session, int request_id ); -/** Does a recv call on the given request */ osrfMessage* osrfAppSessionRequestRecv( osrfAppSession* session, int request_id, int timeout ); -/** Removes the request from the request set and frees the reqest */ void osrf_app_session_request_finish( osrfAppSession* session, int request_id ); -/** Resends the orginal request with the given request id */ int osrf_app_session_request_resend( osrfAppSession*, int request_id ); -/** Resets the remote connection target to that of the original*/ void osrf_app_session_reset_remote( osrfAppSession* ); -/** Sets the remote target to 'remote_id' */ void osrf_app_session_set_remote( osrfAppSession* session, const char* remote_id ); -/** pushes the given message into the result list of the app_request - whose request_id matches the messages thread_trace -*/ -int osrf_app_session_push_queue( osrfAppSession*, osrfMessage* msg ); +void osrf_app_session_push_queue( osrfAppSession*, osrfMessage* msg ); -/** Attempts to connect to the remote service. Returns 1 on successful - connection, 0 otherwise. -*/ 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. - Any data that arrives will be processed according to its - payload and message type. This method will return after - any data has arrived. -*/ int osrf_app_session_queue_wait( osrfAppSession*, int timeout, int* recvd ); -/** Disconnects (if client), frees any attached app_reuqests, removes the session from the - global session cache and frees the session. Needless to say, only call this when the - session is completely done. -*/ void osrfAppSessionFree( osrfAppSession* ); -/** Tells the request to reset its wait timeout */ void osrf_app_session_request_reset_timeout( osrfAppSession* session, int req_id ); int osrfAppRequestRespond( osrfAppSession* ses, int requestId, const jsonObject* data ); + int osrfAppRequestRespondComplete( osrfAppSession* ses, int requestId, const jsonObject* data ); diff --git a/src/libopensrf/osrf_app_session.c b/src/libopensrf/osrf_app_session.c index 60aef96..dacb497 100644 --- a/src/libopensrf/osrf_app_session.c +++ b/src/libopensrf/osrf_app_session.c @@ -105,7 +105,8 @@ static void _osrf_app_request_free( osrfAppRequest * req ) { @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. + For each osrfAppRequest 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) @@ -212,10 +213,13 @@ static void add_app_request( osrfAppSession* session, osrfAppRequest* req ) { } /** - @brief Set the timeout for a request to one second. + @brief Request a reset of the timeout period for a request. @param session Pointer to the relevant osrfAppSession. @param req_id Request ID of the request whose timeout is to be reset. + This happens when a client receives a STATUS message with a status code + OSRF_STATUS_CONTINUE; in effect the server is asking for more time. + 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 ) { @@ -228,21 +232,20 @@ void osrf_app_session_request_reset_timeout( osrfAppSession* session, int req_id } /** - Checks 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. + @brief Fetch the next response message to a given previous request, subject to a timeout. @param req Pointer to the osrfAppRequest representing the request. @param timeout Maxmimum time to wait, in seconds. @return Pointer to the next osrfMessage for this request, if one is available, or if it becomes available before the end of the timeout; otherwise NULL; - If there is already a request available in the input queue, dequeuand return it - immediately. + If there is already a message available in the input queue for this request, dequeue and + return it immediately. Otherwise wait up to timeout seconds until you either get an + input message for the specified request, run out of time, or encounter an error. + + You may also receive other messages for other requests, and other sessions. These other + messages will be wholly or partially processed behind the scenes while you wait for the + one you want. */ static osrfMessage* _osrf_app_request_recv( osrfAppRequest* req, int timeout ) { @@ -258,19 +261,25 @@ static osrfMessage* _osrf_app_request_recv( osrfAppRequest* req, int timeout ) { time_t start = time(NULL); time_t remaining = (time_t) timeout; + // Wait repeatedly for input messages until you either receive one for the request + // you're interested in, run out of time, or encounter an error. + // Wait repeatedly because you may also receive messages for other requests, or for + // other sessions, and process them behind the scenes. These are not the messages + // you're looking for. while( remaining >= 0 ) { /* tell the session to wait for stuff */ 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) { osrfLogError(OSRF_LOG_MARK, "Transport error in recv()"); return NULL; } - if( req->result != NULL ) { /* if we received anything */ - /* pop off the first message in the list */ + if( req->result != NULL ) { /* if we received any results for this request */ + /* dequeue the first message in the list */ osrfLogDebug( OSRF_LOG_MARK, "app_request_recv received a message, returning it" ); osrfMessage* ret_msg = req->result; req->result = ret_msg->next; @@ -290,8 +299,8 @@ static osrfMessage* _osrf_app_request_recv( osrfAppRequest* req, int timeout ) { return NULL; } - if( req->result != NULL ) { /* if we received anything */ - /* pop off the first message in the list */ + if( req->result != NULL ) { /* if we received any results for this request */ + /* dequeue the first message in the list */ osrfLogDebug( OSRF_LOG_MARK, "app_request_recv received a message, returning it"); osrfMessage* ret_msg = req->result; req->result = ret_msg->next; @@ -300,10 +309,16 @@ static osrfMessage* _osrf_app_request_recv( osrfAppRequest* req, int timeout ) { return ret_msg; } + if( req->complete ) return NULL; + // Determine how much time is left if(req->reset_timeout) { + // We got a reprieve. This happens when a client receives a STATUS message + // with a status code OSRF_STATUS_CONTINUE. We restart the timer from the + // beginning -- but only once. We reset reset_timeout to zero. so that a + // second attempted reprieve will allow, at most, only one more second. remaining = (time_t) timeout; req->reset_timeout = 0; osrfLogDebug( OSRF_LOG_MARK, "Received a timeout reset"); @@ -312,6 +327,7 @@ static osrfMessage* _osrf_app_request_recv( osrfAppRequest* req, int timeout ) { } } + // Timeout exhausted; no messages for the request in question char* paramString = jsonObjectToJSON(req->payload->_params); osrfLogInfo( OSRF_LOG_MARK, "Returning NULL from app_request_recv after timeout: %s %s", req->payload->method_name, paramString); @@ -387,11 +403,11 @@ static void _osrf_app_session_push_session( osrfAppSession* session ) { Allocate memory for an osrfAppSession, and initialize it as follows: - - For talking with Jabber, grab an existing transport_client that must have been + - For talking with Jabber, grab an existing transport_client. It must have been already set up by a prior call to osrfSystemBootstrapClientResc(). - Build a Jabber ID for addressing the service. - Build a session ID based on a fine-grained timestamp and a process ID. This ID is - expected to be unique across the system, but uniqueness is not strictly guaranteed. + intended to be unique across the system, but uniqueness is not strictly guaranteed. - Initialize various other bits and scraps. - Add the session to the global session cache. @@ -499,12 +515,12 @@ osrfAppSession* osrfAppSessionClientInit( const char* remote_service ) { @param remote_id Jabber ID of the client. @return Pointer to the newly created osrfAppSession if successful, or NULL upon failure. - First, look in the global session cache for session with the specified session ID. IF - you find one, return it immediately, ignoring the values of the @a our_app and @a + First, look in the global session cache for a session with the specified session ID. + If you find one, return it immediately, ignoring the values of the @a our_app and @a remote_id parameters. Otherwise: - Allocate memory for an osrfAppSession. - - For talking with Jabber, grab an existing transport_client that must have been + - For talking with Jabber, grab an existing transport_client. It should have been already set up by a prior call to osrfSystemBootstrapClientResc(). - Install a copy of the @a our_app string as remote_service. - Install copies of the @a remote_id string as remote_id and orig_remote_id. @@ -692,25 +708,41 @@ static int osrfAppSessionMakeLocaleRequest( return req->request_id; } +/** + @brief Mark an osrfAppRequest (identified by session and ID) as complete. + @param session Pointer to the osrfAppSession that owns the request. + @param request_id Request ID of the osrfAppRequest. +*/ void osrf_app_session_set_complete( osrfAppSession* session, int request_id ) { if(session == NULL) return; osrfAppRequest* req = find_app_request( session, request_id ); - if(req) req->complete = 1; + if(req) + req->complete = 1; } +/** + @brief Determine whether a osrfAppRequest, identified by session and ID, is complete. + @param session Pointer to the osrfAppSession that owns the request. + @param request_id Request ID of the osrfAppRequest. + @return Non-zero if the request is complete; zero if it isn't, or if it can't be found. +*/ int osrf_app_session_request_complete( const osrfAppSession* session, int request_id ) { if(session == NULL) return 0; + osrfAppRequest* req = find_app_request( session, request_id ); if(req) return req->complete; + return 0; } - -/** Resets the remote connection id to that of the original*/ +/** + @brief Reset the remote ID of a session to its original remote ID. + @param session Pointer to the osrfAppSession to be reset. +*/ void osrf_app_session_reset_remote( osrfAppSession* session ){ if( session==NULL ) return; @@ -721,8 +753,13 @@ void osrf_app_session_reset_remote( osrfAppSession* session ){ osrf_app_session_set_remote( session, session->orig_remote_id ); } +/** + @brief Set a session's remote ID to a specified value. + @param session Pointer to the osrfAppSession whose remote ID is to be set. + @param remote_id Pointer to the new remote id. +*/ void osrf_app_session_set_remote( osrfAppSession* session, const char* remote_id ) { - if(session == NULL) + if( session == NULL || remote_id == NULL ) return; if( session->remote_id ) { @@ -738,21 +775,31 @@ void osrf_app_session_set_remote( osrfAppSession* session, const char* remote_id } /** - pushes the given message into the result list of the app_request - with the given request_id + @brief Append an osrfMessage to the list of responses to an osrfAppRequest. + @param session Pointer to the osrfAppSession that owns the request. + @param msg Pointer to the osrfMessage to be added. + + The thread_trace member of the osrfMessage is the request_id of the osrfAppRequest. + Find the corresponding request in the session and append the osrfMessage to its list. */ -int osrf_app_session_push_queue( - osrfAppSession* session, osrfMessage* msg ){ - if(session == NULL || msg == NULL) return 0; +void osrf_app_session_push_queue( osrfAppSession* session, osrfMessage* msg ) { + if( session && msg ) { + osrfAppRequest* req = find_app_request( session, msg->thread_trace ); + if( req ) + _osrf_app_request_push_queue( req, msg ); + } +} - osrfAppRequest* req = find_app_request( session, msg->thread_trace ); - if(req == NULL) return 0; - _osrf_app_request_push_queue( req, msg ); +/** + @brief Connect to the remote service. + @param session Pointer to the osrfAppSession for the service. + @return 1 if successful, or 0 if not. - return 0; -} + If already connected, exit immediately, reporting success. Otherwise, build a CONNECT + message and send it to the service. Wait for up to five seconds for an acknowledgement. -/** Attempts to connect to the remote service */ + The timeout value is currently hard-coded. Perhaps it should be configurable. +*/ int osrfAppSessionConnect( osrfAppSession* session ) { if(session == NULL) @@ -778,6 +825,8 @@ int osrfAppSessionConnect( osrfAppSession* session ) { time_t start = time(NULL); time_t remaining = (time_t) timeout; + // Wait for the acknowledgement. We look for it repeatedly because, under the covers, + // we may receive and process messages other than the one we're looking for. while( session->state != OSRF_SESSION_CONNECTED && remaining >= 0 ) { osrf_app_session_queue_wait( session, remaining, NULL ); if(session->transport_error) { @@ -796,9 +845,15 @@ int osrfAppSessionConnect( osrfAppSession* session ) { return 1; } +/** + @brief Disconnect from the remote service. No response is expected. + @param session Pointer to the osrfAppSession to be disconnected. + @return 1 in all cases. - -/** Disconnects from the remote service */ + If we're already disconnected, return immediately without doing anything. Likewise if + we have a stateless session and we're in the process of connecting. Otherwise, send a + DISCONNECT message to the service. +*/ int osrf_app_session_disconnect( osrfAppSession* session){ if(session == NULL) return 1; @@ -824,7 +879,16 @@ int osrf_app_session_disconnect( osrfAppSession* session){ return 1; } -/** Resend a request message, as specified by session and request id. */ +/** + @brief Resend a request message, as specified by session and request id. + @param session Pointer to the osrfAppSession. + @param req_id Request ID for the request to be resent. + @return Zero if successful, or if the specified request cannot be found; 1 if the + request is already complete, or if the attempt to resend the message fails. + + The choice of return codes may seem seem capricious, but at this writing nothing + pays any attention to the return code anyway. +*/ int osrf_app_session_request_resend( osrfAppSession* session, int req_id ) { osrfAppRequest* req = find_app_request( session, req_id ); @@ -832,7 +896,7 @@ int osrf_app_session_request_resend( osrfAppSession* session, int req_id ) { if(req == NULL) { rc = 0; } else if(!req->complete) { - osrfLogDebug( OSRF_LOG_MARK, "Resending request [%d]", req->request_id ); + osrfLogDebug( OSRF_LOG_MARK, "Resending request [%d]", req->request_id ); rc = _osrf_app_session_send( req->session, req->payload ); } else { rc = 1; @@ -841,15 +905,26 @@ int osrf_app_session_request_resend( osrfAppSession* session, int req_id ) { return rc; } +/** + @brief Send one or more osrfMessages to the remote service or client. + @param session Pointer to the osrfAppSession responsible for sending the message(s). + @param msgs Pointer to an array of pointers to osrfMessages. + @param size How many messages to send. + @return 0 upon success, or -1 upon failure. +*/ static int osrfAppSessionSendBatch( osrfAppSession* session, osrfMessage* msgs[], int size ) { - if( !(session && msgs && size > 0) ) return 0; + if( !(session && msgs && size > 0) ) return -1; int retval = 0; osrfMessage* msg = msgs[0]; if(msg) { + // First grab and process any input messages, for any app session. This gives us + // a chance to see any CONNECT or DISCONNECT messages that may have arrived. We + // may also see some unrelated messages, but we have to process those sooner or + // later anyway, so we might as well do it now. osrf_app_session_queue_wait( session, 0, NULL ); if(session->state != OSRF_SESSION_CONNECTED) { @@ -866,12 +941,13 @@ static int osrfAppSessionSendBatch( osrfAppSession* session, osrfMessage* msgs[] (session->state != OSRF_SESSION_CONNECTED) ) { if(!osrfAppSessionConnect( session )) - return 0; + return -1; } } } } + // Bundle all the osrfMessages into a single transport_message, then send it. char* string = osrfMessageSerializeBatch(msgs, size); if( string ) { @@ -881,8 +957,8 @@ static int osrfAppSessionSendBatch( osrfAppSession* session, osrfMessage* msgs[] message_set_osrf_xid( t_msg, osrfLogGetXid() ); retval = client_send_message( session->transport_handle, t_msg ); - - if( retval ) osrfLogError(OSRF_LOG_MARK, "client_send_message failed"); + if( retval ) + osrfLogError(OSRF_LOG_MARK, "client_send_message failed"); osrfLogInfo(OSRF_LOG_MARK, "[%s] sent %d bytes of data to %s", session->remote_service, strlen(string), t_msg->recipient ); @@ -896,21 +972,47 @@ static int osrfAppSessionSendBatch( osrfAppSession* session, osrfMessage* msgs[] return retval; } +/** + @brief Send a single osrfMessage to the remote service or client. + @param session Pointer to the osrfAppSession. + @param msg Pointer to the osrfMessage to be sent. + @return zero upon success, or 1 upon failure. - + A thin wrapper. Create an array of one element, and pass it to osrfAppSessionSendBatch(). +*/ static int _osrf_app_session_send( osrfAppSession* session, osrfMessage* msg ){ - if( !(session && msg) ) return 0; + if( !(session && msg) ) + return 1; osrfMessage* a[1]; a[0] = msg; - return osrfAppSessionSendBatch( session, a, 1 ); + return - osrfAppSessionSendBatch( session, a, 1 ); } /** - 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. + @brief Wait for any input messages to arrive, and process them as needed. + @param session Pointer to the osrfAppSession whose transport_session we will use. + @param timeout How many seconds to wait for the first input message. + @param recvd Pointer to an boolean int. If you receive at least one message, set the boolean + to true; otherwise set it to false. + @return 0 upon success (even if a timeout occurs), or -1 upon failure. + + A thin wrapper for osrf_stack_process(). The timeout applies only to the first + message; process subsequent messages if they are available, but don't wait for them. + + The first parameter identifies an osrfApp session, but all we really use it for is to + get a pointer to the transport_session. Typically, if not always, a given process + opens only a single transport_session (to talk to the Jabber server), and all app + sessions in that process use the same transport_session. + + Hence this function indiscriminately waits for input messages for all osrfAppSessions, + not just the one specified. + + Dispatch each message to the appropriate processing routine, depending on its type + and contents, and on whether we're acting as a client or as a server for that message. + For example, a response to a request may be appended to the input queue of the + relevant request. A server session receiving a REQUEST message may execute the + requested method. And so forth. */ int osrf_app_session_queue_wait( osrfAppSession* session, int timeout, int* recvd ){ if(session == NULL) return 0; @@ -935,8 +1037,9 @@ void osrfAppSessionFree( osrfAppSession* session ){ osrfLogDebug(OSRF_LOG_MARK, "AppSession [%s] [%s] destroying self and deleting requests", session->remote_service, session->session_id ); + /* disconnect if we're a client */ if(session->type == OSRF_SESSION_CLIENT - && session->state != OSRF_SESSION_DISCONNECTED ) { /* disconnect if we're a client */ + && session->state != OSRF_SESSION_DISCONNECTED ) { osrfMessage* dis_msg = osrf_message_init( DISCONNECT, session->thread_trace, 1 ); _osrf_app_session_send( session, dis_msg ); osrfMessageFree(dis_msg); @@ -972,6 +1075,16 @@ void osrfAppSessionFree( osrfAppSession* session ){ free(session); } +/** + @brief Wait for a response to a given request, subject to a timeout. + @param session Pointer to the osrfAppSession that owns the request. + @param req_id Request ID for the request. + @param timeout How many seconds to wait. + @return A pointer to the received osrfMessage if one arrives; otherwise NULL. + + A thin wrapper. Given a session and a request ID, look up the corresponding request + and pass it to _osrf_app_request_recv(). +*/ osrfMessage* osrfAppSessionRequestRecv( osrfAppSession* session, int req_id, int timeout ) { if(req_id < 0 || session == NULL) @@ -980,8 +1093,20 @@ osrfMessage* osrfAppSessionRequestRecv( return _osrf_app_request_recv( req, timeout ); } +/** + @brief In response to a specified request, send a payload of data to a client. + @param ses Pointer to the osrfAppSession that owns the request. + @param requestId Request ID of the osrfAppRequest. + @param data Pointer to a jsonObject containing the data payload. + @return 0 upon success, or -1 upon failure. + + Translate the jsonObject to a JSON string, and send it wrapped in a RESULT message. + + The only failure detected is if either of the two pointer parameters is NULL. +*/ int osrfAppRequestRespond( osrfAppSession* ses, int requestId, const jsonObject* data ) { - if(!ses || ! data ) return -1; + if( !ses || ! data ) + return -1; osrfMessage* msg = osrf_message_init( RESULT, requestId, 1 ); osrf_message_set_status_info( msg, NULL, "OK", OSRF_STATUS_OK ); @@ -997,6 +1122,21 @@ int osrfAppRequestRespond( osrfAppSession* ses, int requestId, const jsonObject* } +/** + @brief Send one or two messages to a client in response to a specified request. + @param ses Pointer to the osrfAppSession that owns the request. + @param requestId Request ID of the osrfAppRequest. + @param data Pointer to a jsonObject containing the data payload. + @return Zero in all cases. + + If the @a data parameter is not NULL, translate the jsonObject into a JSON string, and + incorporate that string into a RESULT message as as the payload . Also build a STATUS + message indicating that the response is complete. Send both messages bundled together + in the same transport_message. + + If the @a data parameter is NULL, send only a STATUS message indicating that the response + is complete. +*/ int osrfAppRequestRespondComplete( osrfAppSession* ses, int requestId, const jsonObject* data ) { @@ -1028,6 +1168,17 @@ int osrfAppRequestRespondComplete( return 0; } +/** + @brief Send a STATUS message, for a specified request, back to the client. + @param ses Pointer to the osrfAppSession connected to the client. + @param type A numeric code denoting the status. + @param name A string naming the status. + @param reqId The request ID of the request. + @param message A brief message describing the status. + @return 0 upon success, or -1 upon failure. + + The only detected failure is when the @a ses parameter is NULL. +*/ int osrfAppSessionStatus( osrfAppSession* ses, int type, const char* name, int reqId, const char* message ) { @@ -1037,15 +1188,15 @@ int osrfAppSessionStatus( osrfAppSession* ses, int type, _osrf_app_session_send( ses, msg ); osrfMessageFree( msg ); return 0; - } - return -1; + } else + 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 + callback function installed for freeing its cargo. As a result, any remaining osrfAppSessions are leaked, along with all the osrfAppRequests and osrfMessages they own. */ -- 2.43.2