You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules_k/mi_xmlrpc/xr_server.c

311 lines
7.0 KiB

/*
* $Id$
*
* Copyright (C) 2006 Voice Sistem SRL
*
* This file is part of Kamailio.
*
* Kamailio is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* Kamailio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* History:
* ---------
* 2006-11-30 first version (lavinia)
* 2007-02-02 support for asyncronous reply added (bogdan)
* 2007-10-05 support for libxmlrpc-c3 version 1.x.x added (dragos)
*/
#include "../../str.h"
#include "../../dprint.h"
#include "../../sr_module.h"
#include "../../lib/kmi/mi.h"
#include "../../mem/mem.h"
#include "../../mem/shm_mem.h"
#include "../../locking.h"
#include "../../ut.h"
#include "../../cfg/cfg_struct.h"
#include "xr_writer.h"
#include "xr_parser.h"
#include "mi_xmlrpc.h"
#include "xr_server.h"
#ifdef XMLRPC_OLD_VERSION
#include <xmlrpc_abyss.h>
#endif
gen_lock_t *xr_lock;
#define XMLRPC_ASYNC_FAILED ((void*)-2)
#define XMLRPC_ASYNC_EXPIRED ((void*)-3)
static inline void free_async_handler( struct mi_handler *hdl )
{
if (hdl)
shm_free(hdl);
}
static void xmlrpc_close_async( struct mi_root *mi_rpl, struct mi_handler *hdl,
int done)
{
struct mi_root *shm_rpl;
int x;
if (!done) {
/* we do not pass provisional stuff (yet) */
if (mi_rpl)
free_mi_tree( mi_rpl );
return;
}
/* pass the tree via handler back to originating process */
if ( mi_rpl==NULL || (shm_rpl=clone_mi_tree( mi_rpl, 1))==NULL )
shm_rpl = XMLRPC_ASYNC_FAILED;
if (mi_rpl)
free_mi_tree(mi_rpl);
lock_get(xr_lock);
if (hdl->param==NULL) {
hdl->param = shm_rpl;
x = 0;
} else {
x = 1;
}
lock_release(xr_lock);
if (x) {
if (shm_rpl!=XMLRPC_ASYNC_FAILED)
free_shm_mi_tree(shm_rpl);
free_async_handler(hdl);
}
}
#define MAX_XMLRPC_WAIT 2*60*4
static inline struct mi_root* wait_async_reply(struct mi_handler *hdl)
{
struct mi_root *mi_rpl;
int i;
int x;
for( i=0 ; i<MAX_XMLRPC_WAIT ; i++ ) {
if (hdl->param)
break;
sleep_us(1000*500);
}
if (i==MAX_XMLRPC_WAIT) {
/* no more waiting ....*/
lock_get(xr_lock);
if (hdl->param==NULL) {
hdl->param = XMLRPC_ASYNC_EXPIRED;
x = 0;
} else {
x = 1;
}
lock_release(xr_lock);
if (x==0) {
LM_INFO("exiting before receiving reply\n");
return NULL;
}
}
mi_rpl = (struct mi_root *)hdl->param;
if (mi_rpl==XMLRPC_ASYNC_FAILED)
mi_rpl = NULL;
free_async_handler(hdl);
return mi_rpl;
}
static inline struct mi_handler* build_async_handler(void)
{
struct mi_handler *hdl;
hdl = (struct mi_handler*)shm_malloc( sizeof(struct mi_handler) );
if (hdl==0) {
LM_ERR("no more shm mem\n");
return 0;
}
hdl->handler_f = xmlrpc_close_async;
hdl->param = 0;
return hdl;
}
#ifdef XMLRPC_OLD_VERSION
xmlrpc_value* default_method (xmlrpc_env* env,
char* host,
char* methodName,
xmlrpc_value* paramArray,
void* serverInfo)
#else
xmlrpc_value* default_method (xmlrpc_env* env,
const char* host,
const char* methodName,
xmlrpc_value* paramArray,
void* serverInfo)
#endif
{
xmlrpc_value* ret = NULL;
struct mi_root* mi_cmd = NULL;
struct mi_root* mi_rpl = NULL;
struct mi_handler *hdl = NULL;
struct mi_cmd* f;
char* response = 0;
int is_shm = 0;
LM_DBG("starting up.....\n");
/* update the local config framework structures */
cfg_update();
f = lookup_mi_cmd((char*)methodName, strlen(methodName));
if ( f == 0 ) {
LM_ERR("command %s is not available!\n", methodName);
xmlrpc_env_set_fault_formatted(env, XMLRPC_NO_SUCH_METHOD_ERROR,
"Requested command (%s) is not available!", methodName);
goto error;
}
LM_DBG("done looking the mi command.\n");
/* if asyncron cmd, build the async handler */
if (f->flags&MI_ASYNC_RPL_FLAG) {
hdl = build_async_handler( );
if (hdl==0) {
LM_ERR("failed to build async handler\n");
if ( !env->fault_occurred )
xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR,
"Internal server error while processing request");
goto error;
}
} else {
hdl = NULL;
}
if (f->flags&MI_NO_INPUT_FLAG) {
mi_cmd = 0;
} else {
mi_cmd = xr_parse_tree(env, paramArray);
if ( mi_cmd == NULL ){
LM_ERR("failed to parse MI tree\n");
if ( !env->fault_occurred )
xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR,
"The xmlrpc request could not be parsed into a MI tree!");
goto error;
}
mi_cmd->async_hdl = hdl;
}
LM_DBG("done parsing the mi tree.\n");
if ( ( mi_rpl = run_mi_cmd(f, mi_cmd) ) == 0 ){
LM_ERR("command (%s) processing failed.\n", methodName);
xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR,
"Command (%s) processing failed.\n", methodName);
goto error;
} else if (mi_rpl==MI_ROOT_ASYNC_RPL) {
mi_rpl = wait_async_reply(hdl);
hdl = 0;
if (mi_rpl==0) {
xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR,
"Command (%s) processing failed (async).\n", methodName);
goto error;
}
is_shm = 1;
}
LM_DBG("done running the mi command.\n");
if ( rpl_opt == 1 ) {
if ( xr_build_response_array( env, mi_rpl ) != 0 ){
if ( !env->fault_occurred ) {
LM_ERR("failed parsing the xmlrpc response from the mi tree\n");
xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR,
"Failed to parse the xmlrpc response from the mi tree.");
}
goto error;
}
LM_DBG("done building response array.\n");
ret = xr_response;
} else {
if ( (response = xr_build_response( env, mi_rpl )) == 0 ){
if ( !env->fault_occurred ) {
LM_ERR("failed parsing the xmlrpc response from the mi tree\n");
xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR,
"Failed to parse the xmlrpc response from the mi tree.");
}
goto error;
}
LM_DBG("done building response.\n");
ret = xmlrpc_build_value(env, "s", response);
}
error:
free_async_handler(hdl);
if ( mi_cmd ) free_mi_tree( mi_cmd );
if ( mi_rpl ) { is_shm?free_shm_mi_tree(mi_rpl):free_mi_tree(mi_rpl);}
return ret;
}
int set_default_method ( xmlrpc_env * env , xmlrpc_registry * registry)
{
xmlrpc_registry_set_default_method(env, registry, &default_method, NULL);
if ( env->fault_occurred ) {
LM_ERR("failed to add default method: %s\n", env->fault_string);
return -1;
}
return 0;
}
int init_async_lock(void)
{
xr_lock = lock_alloc();
if (xr_lock==NULL) {
LM_ERR("failed to create lock\n");
return -1;
}
if (lock_init(xr_lock)==NULL) {
LM_ERR("failed to init lock\n");
return -1;
}
return 0;
}
void destroy_async_lock(void)
{
if (xr_lock) {
lock_destroy(xr_lock);
lock_dealloc(xr_lock);
}
}