From 89a3961658e651ecc040c78b130045c2325e90b3 Mon Sep 17 00:00:00 2001 From: scottmk Date: Mon, 8 Mar 2010 03:26:03 +0000 Subject: [PATCH] Miscellaneous minor changes. mostly for clarity: 1. Changed return type of _osrfAppRegisterSysMethods from int to void, since we never looked at the return code anyway. 2. In osrfAppRegisterApplication(): 0pen the shared object before allocating an osrfApplication, so that we don't have to free the osrfApplication if the open fails. 3. In osrfAppRegisterExtendedMethod(): when creating an atomic method, pass the userData pointer to _osrfAppBuildMethod() instead of installing it on a separate line. 4. In _osrfAppBuildMethod(): for an atomic method, build the method name correctly the first time, instead of building it incorrectly and later replacing it. 5. In osrfAppRunMethod(): rearranged things a bit for clarity. Simplified the declaration and dereferencing of the meth pointer. 6. In osrfAppIntrospect(): Introduced an early return in order to reduce the level of indentation of the rest of the function. Moved some declarations closer to their first uses. 7. In osrfAppIntrospectAll(): moved the declaration of resp into the loop where it is used. 8. Finished adding doxygen-style comments to document the functions. Touched up the white space here and there. M src/libopensrf/osrf_application.c git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@1935 9efc2488-bf62-4759-914b-345cdb29e865 --- src/libopensrf/osrf_application.c | 407 ++++++++++++++++++++++-------- 1 file changed, 295 insertions(+), 112 deletions(-) diff --git a/src/libopensrf/osrf_application.c b/src/libopensrf/osrf_application.c index 62eec67..e90f64d 100644 --- a/src/libopensrf/osrf_application.c +++ b/src/libopensrf/osrf_application.c @@ -12,7 +12,7 @@ methods, using an osrfHash keyed on method name. */ -// The following macro is commented out because it appears to be unused. +// The following macro is commented out because it ia no longer used. // Used internally to make sure the method description provided is OK /* @@ -35,13 +35,18 @@ d->returnNotes = ""; */ -/* Some well known parameters */ +/** + @name Well known method names + @brief These methods are automatically implemented for every application. +*/ +/*@{*/ #define OSRF_SYSMETHOD_INTROSPECT "opensrf.system.method" #define OSRF_SYSMETHOD_INTROSPECT_ATOMIC "opensrf.system.method.atomic" #define OSRF_SYSMETHOD_INTROSPECT_ALL "opensrf.system.method.all" #define OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC "opensrf.system.method.all.atomic" #define OSRF_SYSMETHOD_ECHO "opensrf.system.echo" #define OSRF_SYSMETHOD_ECHO_ATOMIC "opensrf.system.echo.atomic" +/*@}*/ /** @brief Represent an Application. @@ -55,22 +60,35 @@ typedef struct { static osrfMethod* _osrfAppBuildMethod( const char* methodName, const char* symbolName, const char* notes, int argc, int options, void* ); static void osrfAppSetOnExit(osrfApplication* app, const char* appName); -static int _osrfAppRegisterSysMethods( const char* app ); +static void _osrfAppRegisterSysMethods( const char* app ); static inline osrfApplication* _osrfAppFindApplication( const char* name ); static inline osrfMethod* osrfAppFindMethod( osrfApplication* app, const char* methodName ); static int _osrfAppRespond( osrfMethodContext* context, const jsonObject* data, int complete ); static int _osrfAppPostProcess( osrfMethodContext* context, int retcode ); static int _osrfAppRunSystemMethod(osrfMethodContext* context); +static void _osrfAppSetIntrospectMethod( osrfMethodContext* ctx, const osrfMethod* method, + jsonObject* resp ); static int osrfAppIntrospect( osrfMethodContext* ctx ); static int osrfAppIntrospectAll( osrfMethodContext* ctx ); static int osrfAppEcho( osrfMethodContext* ctx ); /** - Registry of applications. The key of the hash is the application name, and the associated - data is an osrfApplication. + @brief Registry of applications. + + The key of the hash is the application name, and the associated data is an osrfApplication. */ static osrfHash* _osrfAppHash = NULL; +/** + @brief Register an application. + @param appName Name of the application. + @param soFile Name of the shared object file to be loaded for this application. + @return Zero if successful, or -1 upon error. + + Open the shared object file and call its osrfAppInitialize() function, if it has one. + Register the standard system methods for it. Arrange for the application name to + appear in subsequent log messages. +*/ int osrfAppRegisterApplication( const char* appName, const char* soFile ) { if(!appName || ! soFile) return -1; char* error; @@ -80,17 +98,16 @@ int osrfAppRegisterApplication( const char* appName, const char* soFile ) { osrfLogInfo( OSRF_LOG_MARK, "Registering application %s with file %s", appName, soFile ); - osrfApplication* app = safe_malloc(sizeof(osrfApplication)); - app->handle = dlopen (soFile, RTLD_NOW); - app->onExit = NULL; - - if(!app->handle) { - osrfLogWarning( OSRF_LOG_MARK, "Failed to dlopen library file %s: %s", soFile, dlerror() ); - dlerror(); /* clear the error */ - free(app); + void* handle = dlopen( soFile, RTLD_NOW ); + if( ! handle ) { + const char* msg = dlerror(); + osrfLogWarning( OSRF_LOG_MARK, "Failed to dlopen library file %s: %s", soFile, msg ); return -1; } + osrfApplication* app = safe_malloc(sizeof(osrfApplication)); + app->handle = handle; + app->onExit = NULL; app->methods = osrfNewHash(); osrfHashSet( _osrfAppHash, app, appName ); @@ -101,7 +118,7 @@ int osrfAppRegisterApplication( const char* appName, const char* soFile ) { if( (error = dlerror()) != NULL ) { osrfLogWarning( OSRF_LOG_MARK, "! Unable to locate method symbol [osrfAppInitialize] for app %s: %s", - appName, error ); + appName, error ); } else { @@ -127,7 +144,15 @@ int osrfAppRegisterApplication( const char* appName, const char* soFile ) { return 0; } +/** + @brief Save a pointer to the application's exit function. + @param app Pointer to the osrfApplication. + @param appName Application name (used only for log messages). + Look in the shared object for a symbol named "osrfAppChildExit". If you find one, save + it as a pointer to the application's exit function. If present, this function will be + called when a server's child process (a so-called "drone") is shutting down. +*/ static void osrfAppSetOnExit(osrfApplication* app, const char* appName) { if(!(app && appName)) return; @@ -145,7 +170,6 @@ static void osrfAppSetOnExit(osrfApplication* app, const char* appName) { app->onExit = (*onExit); } - /** @brief Run the application-specific child initialization function for a given application. @param appname Name of the application. @@ -179,9 +203,11 @@ int osrfAppRunChildInit(const char* appname) { return 0; } - /** @brief Call the exit handler for every application that has one. + + Normally a server's child process (a so-called "drone") calls this function just before + shutting down. */ void osrfAppRunExitCode( void ) { osrfHashIterator* itr = osrfNewHashIterator(_osrfAppHash); @@ -196,7 +222,30 @@ void osrfAppRunExitCode( void ) { osrfHashIteratorFree(itr); } +/** + @brief Register a method for a specified application. + + @param appName Name of the application that implements the method. + @param methodName The fully qualified name of the method. + @param symbolName The symbol name (function name) that implements the method. + @param notes Public documentation for this method. + @param argc The minimum number of arguments for the function. + @param options Bit switches setting various options. + @return Zero on success, or -1 on error. + + Registering a method enables us to call the right function when a client requests a + method call. + + The @a options parameter is zero or more of the following macros, OR'd together: + - OSRF_METHOD_SYSTEM + - OSRF_METHOD_STREAMING + - OSRF_METHOD_ATOMIC + - OSRF_METHOD_CACHABLE + + If the OSRF_METHOD_STREAMING bit is set, also register an ".atomic" version of + the method. +*/ int osrfAppRegisterMethod( const char* appName, const char* methodName, const char* symbolName, const char* notes, int argc, int options ) { @@ -211,6 +260,22 @@ int osrfAppRegisterMethod( const char* appName, const char* methodName, ); } +/** + @brief Register a method for a specified application. + + @param appName Name of the application that implements the method. + @param methodName The fully qualified name of the method. + @param symbolName The symbol name (function name) that implements the method. + @param notes Public documentation for this method. + @param argc How many arguments this method expects. + @param options Bit switches setting various options. + @param user_data Opaque pointer to be passed to the dynamically called function. + @return Zero on success, or -1 on error. + + This function is identical to osrfAppRegisterMethod(), except that it also installs + a method-specific opaque pointer. When we call the corresponding function at + run time, this pointer will be available to the function via the method context. +*/ int osrfAppRegisterExtendedMethod( const char* appName, const char* methodName, const char* symbolName, const char* notes, int argc, int options, void * user_data ) { @@ -234,25 +299,40 @@ int osrfAppRegisterExtendedMethod( const char* appName, const char* methodName, if( options & OSRF_METHOD_STREAMING ) { /* build the atomic counterpart */ int newops = options | OSRF_METHOD_ATOMIC; osrfMethod* atomicMethod = _osrfAppBuildMethod( - methodName, symbolName, notes, argc, newops, NULL ); + methodName, symbolName, notes, argc, newops, user_data ); osrfHashSet( app->methods, atomicMethod, atomicMethod->name ); - atomicMethod->userData = method->userData; } return 0; } - - +/** + @brief Allocate and populate an osrfMethod. + @param methodName Name of the method. + @param symbolName Name of the function that implements the method. + @param notes Remarks documenting the method. + @param argc Minimum number of arguments to the method. + @param options Bit switches setting various options. + @param user_data An opaque pointer to be passed in the method context. + @return Pointer to the newly allocated osrfMethod. +*/ static osrfMethod* _osrfAppBuildMethod( const char* methodName, const char* symbolName, const char* notes, int argc, int options, void* user_data ) { osrfMethod* method = safe_malloc(sizeof(osrfMethod)); - if(methodName) + if( !methodName ) + methodName = ""; // should never happen + + if( options & OSRF_METHOD_ATOMIC ) { + // Append ".atomic" to the name, and make the method streaming + char mb[ strlen( methodName ) + 8 ]; + sprintf( mb, "%s.atomic", methodName ); + method->name = strdup( mb ); + options |= OSRF_METHOD_STREAMING; + } else { method->name = strdup(methodName); - else - method->name = NULL; + } if(symbolName) method->symbol = strdup(symbolName); @@ -264,29 +344,24 @@ static osrfMethod* _osrfAppBuildMethod( const char* methodName, const char* symb else method->notes = NULL; - if(user_data) - method->userData = user_data; - method->argc = argc; method->options = options; - if(options & OSRF_METHOD_ATOMIC) { /* add ".atomic" to the end of the name */ - char mb[strlen(method->name) + 8]; - sprintf(mb, "%s.atomic", method->name); - free(method->name); - method->name = strdup(mb); - method->options |= OSRF_METHOD_STREAMING; - } + if(user_data) + method->userData = user_data; return method; } - /** - Register all of the system methods for this app so that they may be - treated the same as other methods. + @brief Register all of the system methods for this application. + @param app Application name. + + A client can call these methods the same way it calls application-specific methods, + but they are implemented by functions here in this module, not by functions in the + shared object. */ -static int _osrfAppRegisterSysMethods( const char* app ) { +static void _osrfAppRegisterSysMethods( const char* app ) { osrfAppRegisterMethod( app, OSRF_SYSMETHOD_INTROSPECT, NULL, @@ -303,8 +378,6 @@ static int _osrfAppRegisterSysMethods( const char* app ) { app, OSRF_SYSMETHOD_ECHO, NULL, "Echos all data sent to the server back to the client. PARAMS([a, b, ...])", 0, OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING ); - - return 0; } /** @@ -332,49 +405,60 @@ static inline osrfMethod* osrfAppFindMethod( osrfApplication* app, const char* m @param appName Name of the osrfApplication. @param methodName Name of the method to find. @return Pointer to the corresponding osrfMethod if found, or NULL if not. - */ +*/ osrfMethod* _osrfAppFindMethod( const char* appName, const char* methodName ) { if( !appName ) return NULL; return osrfAppFindMethod( _osrfAppFindApplication(appName), methodName ); } - +/** + @brief Call the function that implements a specified method. + @param appName Name of the application. + @param methodName Name of the method. + @param ses Pointer to the current application session. + @param reqId The request id of the request invoking the method. + @param params Pointer to a jsonObject encoding the parameters to the method. + @return Zero if successful, or -1 upon failure. + + If we can't find a function corresponding to the method, or if we call it and it returns + a negative return code, send a STATUS message to the client to report an exception. + + A return code of -1 means that the @a appName, @a methodName, or @a ses parameter was NULL. +*/ int osrfAppRunMethod( const char* appName, const char* methodName, osrfAppSession* ses, int reqId, jsonObject* params ) { if( !(appName && methodName && ses) ) return -1; - char* error; - osrfApplication* app; - osrfMethod* method; - osrfMethodContext context; - - context.session = ses; - context.params = params; - context.request = reqId; - context.responses = NULL; - - /* this is the method we're gonna run */ - int (*meth) (osrfMethodContext*); - - if( !(app = _osrfAppFindApplication(appName)) ) + // Find the application, and then find the method for it + osrfApplication* app = _osrfAppFindApplication(appName); + if( !app ) return osrfAppRequestRespondException( ses, reqId, "Application not found: %s", appName ); - if( !(method = osrfAppFindMethod( app, methodName )) ) + osrfMethod* method = osrfAppFindMethod( app, methodName ); + if( !method ) return osrfAppRequestRespondException( ses, reqId, "Method [%s] not found for service %s", methodName, appName ); - context.method = method; - #ifdef OSRF_STRICT_PARAMS if( method->argc > 0 ) { + // Make sure that the client has passed at least the minimum number of arguments. if(!params || params->type != JSON_ARRAY || params->size < method->argc ) return osrfAppRequestRespondException( ses, reqId, "Not enough params for method %s / service %s", methodName, appName ); } #endif + // Build an osrfMethodContext, which we will pass by pointer to the function. + osrfMethodContext context; + + context.session = ses; + context.method = method; + context.params = params; + context.request = reqId; + context.responses = NULL; + int retcode = 0; if( method->options & OSRF_METHOD_SYSTEM ) { @@ -382,15 +466,20 @@ int osrfAppRunMethod( const char* appName, const char* methodName, } else { - /* open and now run the method */ - *(void **) (&meth) = dlsym(app->handle, method->symbol); + // Function pointer through which we will call the function dynamically + int (*meth) (osrfMethodContext*); - if( (error = dlerror()) != NULL ) { + // Open the function that implements the method + meth = dlsym(app->handle, method->symbol); + + const char* error = dlerror(); + if( error != NULL ) { return osrfAppRequestRespondException( ses, reqId, - "Unable to execute method [%s] for service %s", methodName, appName ); + "Unable to execute method [%s] for service %s", methodName, appName ); } - retcode = (*meth) (&context); + // Run it + retcode = meth( &context ); } if(retcode < 0) @@ -398,18 +487,65 @@ int osrfAppRunMethod( const char* appName, const char* methodName, ses, reqId, "An unknown server error occurred" ); return _osrfAppPostProcess( &context, retcode ); - } - +/** + @brief Either send or enqueue a response to a client. + @param ctx Pointer to the current method context. + @param data Pointer to the response, in the form of a jsonObject. + @return Zero if successful, or -1 upon error. The only recognized errors are if either + the @a context pointer or its method pointer is NULL. + + For an atomic method, add a copy of the response data to a cache within the method + context, to be sent later. Otherwise, send a RESULT message to the client, with the + results in @a data. + + Note that, for an atomic method, this function is equivalent to osrfAppRespondComplete(): + we send the STATUS message after the method returns, and not before. +*/ int osrfAppRespond( osrfMethodContext* ctx, const jsonObject* data ) { return _osrfAppRespond( ctx, data, 0 ); } +/** + @brief Either send or enqueue a response to a client, with a completion notice. + @param context Pointer to the current method context. + @param data Pointer to the response, in the form of a jsonObject. + @return Zero if successful, or -1 upon error. The only recognized errors are if either + the @a context pointer or its method pointer is NULL. + + For an atomic method, add a copy of the response data to a cache within the method + context, to be sent later. Otherwise, send a RESULT message to the client, with the + results in @a data. Also send a STATUS message to indicate that the response is complete. + + Note that, for an atomic method, this function is equivalent to osrfAppRespond(): we + send the STATUS message after the method returns, and not before. +*/ int osrfAppRespondComplete( osrfMethodContext* context, const jsonObject* data ) { return _osrfAppRespond( context, data, 1 ); } +/** + @brief Either send or enqueue a response to a client, optionally with a completion notice. + @param ctx Pointer to the method context. + @param data Pointer to the response, in the form of a jsonObject. + @param complete Boolean: if true, we will accompany the RESULT message with a STATUS + message indicating that the response is complete. + @return Zero if successful, or -1 upon error. The only recognized errors are if either + the @a ctx pointer or its method pointer is NULL. + + For an atomic method, add a copy of the response data to a cache within the method + context, to be sent later. In this case the @a complete parameter has no effect, + because we'll send the STATUS message later when we send the cached results. + + If the method is cachable but not atomic, do nothing, ignoring the results in @a data. + Apparently there are no cachable methods at this writing. If we ever invent some, we + may need to revisit this function. + + If the method is neither atomic nor cachable, then send a RESULT message to the client, + with the results in @a data. If @a complete is true, also send a STATUS message to + indicate that the response is complete. +*/ static int _osrfAppRespond( osrfMethodContext* ctx, const jsonObject* data, int complete ) { if(!(ctx && ctx->method)) return -1; @@ -417,14 +553,15 @@ static int _osrfAppRespond( osrfMethodContext* ctx, const jsonObject* data, int osrfLogDebug( OSRF_LOG_MARK, "Adding responses to stash for atomic method %s", ctx->method->name ); + // If we don't already have one, create a JSON_ARRAY to serve as a cache. if( ctx->responses == NULL ) ctx->responses = jsonNewObjectType( JSON_ARRAY ); + // Add a copy of the data object to the cache. if ( data != NULL ) jsonObjectPush( ctx->responses, jsonObjectClone(data) ); } - if( !(ctx->method->options & OSRF_METHOD_ATOMIC ) && !(ctx->method->options & OSRF_METHOD_CACHABLE) ) { @@ -432,28 +569,42 @@ static int _osrfAppRespond( osrfMethodContext* ctx, const jsonObject* data, int osrfAppRequestRespondComplete( ctx->session, ctx->request, data ); else osrfAppRequestRespond( ctx->session, ctx->request, data ); - return 0; } return 0; } +/** + @brief Finish up the processing of a request. + @param ctx Pointer to the method context. + @param retcode The return code from the method's function. + @return 0 if successfull, or -1 upon error. + + For an atomic method: send whatever responses we have been saving up, together with a + STATUS message to say that we're finished. + For a non-atomic method: if the return code from the method is greater than zero, just + send the STATUS message. If the return code is zero, do nothing; the method presumably + sent the STATUS message on its own. +*/ static int _osrfAppPostProcess( osrfMethodContext* ctx, int retcode ) { if(!(ctx && ctx->method)) return -1; - osrfLogDebug( OSRF_LOG_MARK, "Postprocessing method %s with retcode %d", + osrfLogDebug( OSRF_LOG_MARK, "Postprocessing method %s with retcode %d", ctx->method->name, retcode ); - if(ctx->responses) { /* we have cached responses to return (no responses have been sent) */ - + if(ctx->responses) { + // We have cached responses to return, collected in a JSON ARRAY (we haven't sent + // any responses yet). Now send them all at once, followed by a STATUS message + // to say that we're finished. osrfAppRequestRespondComplete( ctx->session, ctx->request, ctx->responses ); jsonObjectFree(ctx->responses); ctx->responses = NULL; } else { - + // We have no cached responses to return. if( retcode > 0 ) + // Send a STATUS message to say that we're finished. osrfAppSessionStatus( ctx->session, OSRF_STATUS_COMPLETE, "osrfConnectStatus", ctx->request, "Request Complete" ); } @@ -461,6 +612,15 @@ static int _osrfAppPostProcess( osrfMethodContext* ctx, int retcode ) { return 0; } +/** + @brief Send a STATUS message to the client, notifying it of an error. + @param ses Pointer to the current application session. + @param request Request ID of the request. + @param msg A printf-style format string defining an explanatory message to be sent to + the client. Subsequent parameters, if any, will be formatted and inserted into the + resulting output string. + @return -1 if the @a ses parameter is NULL; otherwise zero. +*/ int osrfAppRequestRespondException( osrfAppSession* ses, int request, const char* msg, ... ) { if(!ses) return -1; if(!msg) msg = ""; @@ -470,8 +630,17 @@ int osrfAppRequestRespondException( osrfAppSession* ses, int request, const char return 0; } +/** + @brief Introspect a specified method. + @param ctx Pointer to the method context. + @param method Pointer to the osrfMethod for the specified method. + @param resp Pointer to the jsonObject into which method information will be placed. -static void _osrfAppSetIntrospectMethod( osrfMethodContext* ctx, const osrfMethod* method, jsonObject* resp ) { + Treating the @a resp object as a JSON_HASH, insert entries for various bits of information + about the specified method. +*/ +static void _osrfAppSetIntrospectMethod( osrfMethodContext* ctx, const osrfMethod* method, + jsonObject* resp ) { if(!(ctx && resp)) return; jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name)); @@ -489,14 +658,14 @@ static void _osrfAppSetIntrospectMethod( osrfMethodContext* ctx, const osrfMetho } /** - Tries to run the requested method as a system method. - A system method is a well known method that all - servers implement. - @param context The current method context - @return 0 if the method is run successfully, return < 0 means - the method was not run, return > 0 means the method was run - and the application code now needs to send a 'request complete' - message + @brief Run the requested system method. + @param ctx The method context. + @return Zero if the method is run successfully; -1 if the method was not run; 1 if the + method was run and the application code now needs to send a 'request complete' message. + + A system method is a well known method implemented here for all servers. Instead of + looking in the shared object, branch on the method name and call the corresponding + function. */ static int _osrfAppRunSystemMethod(osrfMethodContext* ctx) { if( osrfMethodVerifyContext( ctx ) < 0 ) { @@ -506,84 +675,97 @@ static int _osrfAppRunSystemMethod(osrfMethodContext* ctx) { if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL ) || !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC )) { - return osrfAppIntrospectAll(ctx); } - if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT ) || !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ATOMIC )) { - return osrfAppIntrospect(ctx); } if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_ECHO ) || !strcmp(ctx->method->name, OSRF_SYSMETHOD_ECHO_ATOMIC )) { - return osrfAppEcho(ctx); } - osrfAppRequestRespondException( ctx->session, ctx->request, "System method implementation not found"); return 0; } +/** + @brief Run the introspect method for a specified method or group of methods. + @param ctx Pointer to the method context. + @return 1 if successful, or if no search target is specified as a parameter; -1 if unable + to find a pointer to the application. + Traverse the list of methods, and report on each one whose name starts with the specified + search target. In effect, the search target ends with an implicit wild card. +*/ static int osrfAppIntrospect( osrfMethodContext* ctx ) { - jsonObject* resp = NULL; + // Get the name of the method to introspect const char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) ); - osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service ); - int len = 0; + if( !methodSubstring ) + return 1; /* respond with no methods */ - if(!methodSubstring) return 1; /* respond with no methods */ - - if(app) { + // Get a pointer to the application + osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service ); + if( !app ) + return -1; // Oops, no application... - osrfHashIterator* itr = osrfNewHashIterator(app->methods); - osrfMethod* method; + int len = 0; + osrfHashIterator* itr = osrfNewHashIterator(app->methods); + osrfMethod* method; - while( (method = osrfHashIteratorNext(itr)) ) { - if( (len = strlen(methodSubstring)) <= strlen(method->name) ) { - if( !strncmp( method->name, methodSubstring, len) ) { - resp = jsonNewObject(NULL); - _osrfAppSetIntrospectMethod( ctx, method, resp ); - osrfAppRespond(ctx, resp); - jsonObjectFree(resp); - } + while( (method = osrfHashIteratorNext(itr)) ) { + if( (len = strlen(methodSubstring)) <= strlen(method->name) ) { + if( !strncmp( method->name, methodSubstring, len) ) { + jsonObject* resp = jsonNewObject(NULL); + _osrfAppSetIntrospectMethod( ctx, method, resp ); + osrfAppRespond(ctx, resp); + jsonObjectFree(resp); } } - osrfHashIteratorFree(itr); - return 1; } - return -1; - + osrfHashIteratorFree(itr); + return 1; } +/** + @brief Run the implement_all method. + @param ctx Pointer to the method context. + @return 1 if successful, or -1 if unable to find a pointer to the application. + Report on all of the methods of the application. +*/ static int osrfAppIntrospectAll( osrfMethodContext* ctx ) { - jsonObject* resp = NULL; osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service ); if(app) { osrfHashIterator* itr = osrfNewHashIterator(app->methods); osrfMethod* method; while( (method = osrfHashIteratorNext(itr)) ) { - resp = jsonNewObject(NULL); + jsonObject* resp = jsonNewObject(NULL); _osrfAppSetIntrospectMethod( ctx, method, resp ); osrfAppRespond(ctx, resp); jsonObjectFree(resp); } osrfHashIteratorFree(itr); return 1; - } - - return -1; + } else + return -1; } +/** + @brief Run the echo method. + @param ctx Pointer to the method context. + @return -1 if the method context is invalid or corrupted; otherwise 1. + + Send the client a copy of each parameter. +*/ static int osrfAppEcho( osrfMethodContext* ctx ) { if( osrfMethodVerifyContext( ctx ) < 0 ) { osrfLogError( OSRF_LOG_MARK, "osrfAppEcho: Received invalid method context" ); @@ -599,8 +781,9 @@ static int osrfAppEcho( osrfMethodContext* ctx ) { } /** - Determine whether the context looks healthy. - Return 0 if it does, or -1 if it doesn't. + @brief Perform a series of sanity tests on an osrfMethodContext. + @param ctx Pointer to the osrfMethodContext to be checked. + @return Zero if the osrfMethodContext passes all tests, or -1 if it doesn't. */ int osrfMethodVerifyContext( osrfMethodContext* ctx ) { -- 2.43.2