1 /* Copyright information is at end of file */
3 #include "xmlrpc_config.h"
10 #include "mallocvar.h"
11 #include "xmlrpc-c/base_int.h"
12 #include "xmlrpc-c/string_int.h"
13 #include "xmlrpc-c/base.h"
14 #include "xmlrpc-c/server.h"
15 #include "system_method.h"
19 /*=========================================================================
20 XML-RPC Server Method Registry
21 ===========================================================================
22 A method registry is a list of XML-RPC methods for a server to
23 implement, along with the details of how to implement each -- most
24 notably a function pointer for a function that executes the method.
26 To build an XML-RPC server, just add a communication facility.
28 The registry object consists principally of an xmlrpc_value. That
29 xmlrpc_value is a struct, with method name as key. Each value in
30 the struct a "method info" array. A method info array has the
33 0: cptr: method function ptr
35 2: array: signature list
38 The signature list array contains one item for each form of call (a
39 single method might have multiple forms, e.g. one takes two integer
40 arguments; another takes a single string). The array for each form
41 represents a signature. It has an item for each parameter and one
42 for the result. Item 0 is for the result, the rest are in order of
43 the parameters. Each item of that array is the name of the XML-RPC
44 element that represents that type, e.g. "int" or
57 The signature list array is empty to indicate that there is no signature
58 information in the registry (it doesn't mean there are no valid forms
59 of calling the method -- just that the registry declines to state).
62 WARNING: there's a basic problem with using xmlrpc_value objects to
63 represent the registry: xmlrpc_value objects are defined to be not
64 thread-safe: you can't use one from two threads at the same time.
65 But XML-RPC servers are often threaded, with multiple threads
66 simultaneously executing multiple RPCs. The normal Xmlrpc-c Abyss
67 server is a good example.
69 As a hack to make this work, we use the old, deprecated "get"
70 functions that don't take a reference in the call dispatching code.
71 Maintaining the reference count is the only way that the the
72 thread-unsafety can manifest itself in our application. Since the
73 registry has at least one reference to each xmlrpc_value as long as
74 the registry exists, we don't really need the exact reference count,
75 so the deprecated functions work fine.
77 =========================================================================*/
82 xmlrpc_registry_new(xmlrpc_env * const envP) {
84 xmlrpc_registry * registryP;
86 XMLRPC_ASSERT_ENV_OK(envP);
90 if (registryP == NULL)
91 xmlrpc_faultf(envP, "Could not allocate memory for registry");
93 registryP->_introspection_enabled = true;
94 registryP->_default_method = NULL;
95 registryP->_preinvoke_method = NULL;
96 registryP->_shutdown_server_fn = NULL;
98 registryP->_methods = xmlrpc_struct_new(envP);
99 if (!envP->fault_occurred) {
100 xmlrpc_installSystemMethods(envP, registryP);
102 if (envP->fault_occurred)
111 xmlrpc_registry_free(xmlrpc_registry * const registryP) {
113 XMLRPC_ASSERT_PTR_OK(registryP);
114 XMLRPC_ASSERT(registryP->_methods != XMLRPC_BAD_POINTER);
116 xmlrpc_DECREF(registryP->_methods);
118 if (registryP->_default_method != NULL)
119 xmlrpc_DECREF(registryP->_default_method);
121 if (registryP->_preinvoke_method != NULL)
122 xmlrpc_DECREF(registryP->_preinvoke_method);
130 xmlrpc_registry_add_method_w_doc(
131 xmlrpc_env * const envP,
132 xmlrpc_registry * const registryP,
133 const char * const host ATTR_UNUSED,
134 const char * const methodName,
135 xmlrpc_method const method,
136 void * const userData,
137 const char * const signatureString,
138 const char * const help) {
140 const char * const helpString =
141 help ? help : "No help is available for this method.";
144 xmlrpc_value * signatureListP;
146 XMLRPC_ASSERT_ENV_OK(envP);
147 XMLRPC_ASSERT_PTR_OK(registryP);
148 XMLRPC_ASSERT(host == NULL);
149 XMLRPC_ASSERT_PTR_OK(methodName);
150 XMLRPC_ASSERT_PTR_OK(method);
152 xmlrpc_env_init(&env);
154 xmlrpc_buildSignatureArray(&env, signatureString, &signatureListP);
155 if (env.fault_occurred)
156 xmlrpc_faultf(envP, "Can't interpret signature string '%s'. %s",
157 signatureString, env.fault_string);
159 xmlrpc_value * methodInfoP;
161 XMLRPC_ASSERT_VALUE_OK(signatureListP);
163 methodInfoP = xmlrpc_build_value(envP, "(ppVs)", (void*) method,
164 userData, signatureListP, helpString);
165 if (!envP->fault_occurred) {
166 xmlrpc_struct_set_value(envP, registryP->_methods,
167 methodName, methodInfoP);
169 xmlrpc_DECREF(methodInfoP);
171 xmlrpc_DECREF(signatureListP);
173 xmlrpc_env_clean(&env);
179 xmlrpc_registry_add_method(xmlrpc_env *env,
180 xmlrpc_registry *registry,
182 const char *method_name,
183 xmlrpc_method method,
186 xmlrpc_registry_add_method_w_doc (env, registry, host, method_name,
187 method, user_data, "?",
188 "No help is available for this method.");
193 /*=========================================================================
194 ** xmlrpc_registry_set_default_method
195 **=========================================================================
196 ** See xmlrpc.h for more documentation.
200 xmlrpc_registry_set_default_method(xmlrpc_env *env,
201 xmlrpc_registry *registry,
202 xmlrpc_default_method handler,
204 xmlrpc_value *method_info;
206 XMLRPC_ASSERT_ENV_OK(env);
207 XMLRPC_ASSERT_PTR_OK(registry);
208 XMLRPC_ASSERT_PTR_OK(handler);
210 /* Error-handling preconditions. */
213 /* Store our method and user data into our hash table. */
214 method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data);
215 XMLRPC_FAIL_IF_FAULT(env);
217 /* Dispose of any pre-existing default method and install ours. */
218 if (registry->_default_method)
219 xmlrpc_DECREF(registry->_default_method);
220 registry->_default_method = method_info;
223 if (env->fault_occurred) {
225 xmlrpc_DECREF(method_info);
233 xmlrpc_registry_set_preinvoke_method(xmlrpc_env *env,
234 xmlrpc_registry *registry,
235 xmlrpc_preinvoke_method handler,
237 xmlrpc_value *method_info;
239 XMLRPC_ASSERT_ENV_OK(env);
240 XMLRPC_ASSERT_PTR_OK(registry);
241 XMLRPC_ASSERT_PTR_OK(handler);
243 /* Error-handling preconditions. */
246 /* Store our method and user data into our hash table. */
247 method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data);
248 XMLRPC_FAIL_IF_FAULT(env);
250 /* Dispose of any pre-existing preinvoke method and install ours. */
251 if (registry->_preinvoke_method)
252 xmlrpc_DECREF(registry->_preinvoke_method);
253 registry->_preinvoke_method = method_info;
256 if (env->fault_occurred) {
258 xmlrpc_DECREF(method_info);
265 xmlrpc_registry_set_shutdown(xmlrpc_registry * const registryP,
266 xmlrpc_server_shutdown_fn * const shutdownFn,
267 void * const context) {
269 XMLRPC_ASSERT_PTR_OK(registryP);
270 XMLRPC_ASSERT_PTR_OK(shutdownFn);
272 registryP->_shutdown_server_fn = shutdownFn;
274 registryP->_shutdown_context = context;
279 /*=========================================================================
281 **=========================================================================
282 ** An internal method which actually does the dispatch. This may get
283 ** prettified and exported at some point in the future.
287 callPreinvokeMethodIfAny(xmlrpc_env * const envP,
288 xmlrpc_registry * const registryP,
289 const char * const methodName,
290 xmlrpc_value * const paramArrayP) {
292 /* Get the preinvoke method, if it is set. */
293 if (registryP->_preinvoke_method) {
294 xmlrpc_preinvoke_method preinvoke_method;
297 xmlrpc_parse_value(envP, registryP->_preinvoke_method, "(pp)",
298 &preinvoke_method, &user_data);
299 if (!envP->fault_occurred)
300 (*preinvoke_method)(envP, methodName,
301 paramArrayP, user_data);
308 callDefaultMethod(xmlrpc_env * const envP,
309 xmlrpc_value * const defaultMethodInfo,
310 const char * const methodName,
311 xmlrpc_value * const paramArrayP,
312 xmlrpc_value ** const resultPP) {
314 xmlrpc_default_method default_method;
317 xmlrpc_parse_value(envP, defaultMethodInfo, "(pp)",
318 &default_method, &user_data);
320 if (!envP->fault_occurred)
321 *resultPP = (*default_method)(envP, NULL, methodName,
322 paramArrayP, user_data);
328 callNamedMethod(xmlrpc_env * const envP,
329 xmlrpc_value * const methodInfo,
330 xmlrpc_value * const paramArrayP,
331 xmlrpc_value ** const resultPP) {
333 xmlrpc_method method;
336 xmlrpc_parse_value(envP, methodInfo, "(pp*)", &method, &user_data);
337 if (!envP->fault_occurred)
338 *resultPP = (*method)(envP, paramArrayP, user_data);
344 xmlrpc_dispatchCall(xmlrpc_env * const envP,
345 xmlrpc_registry * const registryP,
346 const char * const methodName,
347 xmlrpc_value * const paramArrayP,
348 xmlrpc_value ** const resultPP) {
350 callPreinvokeMethodIfAny(envP, registryP, methodName, paramArrayP);
351 if (!envP->fault_occurred) {
352 xmlrpc_value * methodInfoP;
353 xmlrpc_env methodLookupEnv;
355 xmlrpc_env_init(&methodLookupEnv);
357 /* See comments at top of file about why we use the deprecated
358 xmlrpc_struct_get_value() here
360 methodInfoP = xmlrpc_struct_get_value(&methodLookupEnv,
363 if (!methodLookupEnv.fault_occurred)
364 callNamedMethod(envP, methodInfoP, paramArrayP, resultPP);
365 else if (methodLookupEnv.fault_code == XMLRPC_INDEX_ERROR) {
366 if (registryP->_default_method)
367 callDefaultMethod(envP, registryP->_default_method,
368 methodName, paramArrayP,
371 /* No matching method, and no default. */
372 xmlrpc_env_set_fault_formatted(
373 envP, XMLRPC_NO_SUCH_METHOD_ERROR,
374 "Method '%s' not defined", methodName);
377 xmlrpc_faultf(envP, "failed to lookup method in registry's "
378 "internal method struct. %s",
379 methodLookupEnv.fault_string);
380 xmlrpc_env_clean(&methodLookupEnv);
382 /* For backward compatibility, for sloppy users: */
383 if (envP->fault_occurred)
389 /*=========================================================================
390 ** xmlrpc_registry_process_call
391 **=========================================================================
396 xmlrpc_registry_process_call(xmlrpc_env * const envP,
397 xmlrpc_registry * const registryP,
398 const char * const host ATTR_UNUSED,
399 const char * const xml_data,
400 size_t const xml_len) {
402 xmlrpc_mem_block * output;
404 XMLRPC_ASSERT_ENV_OK(envP);
405 XMLRPC_ASSERT_PTR_OK(xml_data);
407 xmlrpc_traceXml("XML-RPC CALL", xml_data, xml_len);
409 /* Allocate our output buffer.
410 ** If this fails, we need to die in a special fashion. */
411 output = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
412 if (!envP->fault_occurred) {
413 const char * methodName;
414 xmlrpc_value * paramArray;
418 xmlrpc_env_init(&fault);
419 xmlrpc_env_init(&parseEnv);
421 xmlrpc_parse_call(&parseEnv, xml_data, xml_len,
422 &methodName, ¶mArray);
424 if (parseEnv.fault_occurred)
425 xmlrpc_env_set_fault_formatted(
426 &fault, XMLRPC_PARSE_ERROR,
427 "Call XML not a proper XML-RPC call. %s",
428 parseEnv.fault_string);
430 xmlrpc_value * result;
432 xmlrpc_dispatchCall(&fault, registryP, methodName, paramArray,
435 if (!fault.fault_occurred) {
436 xmlrpc_serialize_response(envP, output, result);
438 /* A comment here used to say that
439 xmlrpc_serialize_response() could fail and "leave
440 stuff in the buffer." Don't know what that means,
441 but it sounds like something that needs to be
442 fixed. The old code aborted the program here if
443 xmlrpc_serialize_repsonse() failed. 04.11.17
445 xmlrpc_DECREF(result);
447 xmlrpc_strfree(methodName);
448 xmlrpc_DECREF(paramArray);
450 if (!envP->fault_occurred && fault.fault_occurred)
451 xmlrpc_serialize_fault(envP, output, &fault);
453 xmlrpc_env_clean(&parseEnv);
454 xmlrpc_env_clean(&fault);
456 if (envP->fault_occurred)
457 XMLRPC_MEMBLOCK_FREE(char, output);
459 xmlrpc_traceXml("XML-RPC RESPONSE",
460 XMLRPC_MEMBLOCK_CONTENTS(char, output),
461 XMLRPC_MEMBLOCK_SIZE(char, output));
467 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
468 ** Copyright (C) 2001 by Eric Kidd. All rights reserved.
469 ** Copyright (C) 2001 by Luke Howard. All rights reserved.
471 ** Redistribution and use in source and binary forms, with or without
472 ** modification, are permitted provided that the following conditions
474 ** 1. Redistributions of source code must retain the above copyright
475 ** notice, this list of conditions and the following disclaimer.
476 ** 2. Redistributions in binary form must reproduce the above copyright
477 ** notice, this list of conditions and the following disclaimer in the
478 ** documentation and/or other materials provided with the distribution.
479 ** 3. The name of the author may not be used to endorse or promote products
480 ** derived from this software without specific prior written permission.
482 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
483 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
484 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
485 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
486 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
487 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
488 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
489 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
490 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
491 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF