modules/mi_xmlrpc/xr_server.c
d70cf5d6
 /*
  * $Id$
  *
  * Copyright (C) 2006 Voice Sistem SRL
  *
9b64b9f3
  * This file is part of Kamailio.
d70cf5d6
  *
9b64b9f3
  * Kamailio is free software; you can redistribute it and/or
d70cf5d6
  * 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.
  *
27642a08
  * Kamailio is distributed in the hope that it will be useful,
d70cf5d6
  * 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
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
d70cf5d6
  *
  * History:
  * ---------
  *  2006-11-30  first version (lavinia)
0b305412
  *  2007-02-02  support for asyncronous reply added (bogdan)
d6e664b8
  *  2007-10-05  support for libxmlrpc-c3 version 1.x.x added (dragos)
d70cf5d6
  */
 
 
 #include "../../str.h"
 #include "../../dprint.h"
 #include "../../sr_module.h"
8c126cce
 #include "../../lib/kmi/mi.h"
d70cf5d6
 #include "../../mem/mem.h"
0b305412
 #include "../../mem/shm_mem.h"
 #include "../../locking.h"
 #include "../../ut.h"
b1429aef
 #include "../../cfg/cfg_struct.h"
d70cf5d6
 #include "xr_writer.h"
 #include "xr_parser.h"
 #include "mi_xmlrpc.h"
 #include "xr_server.h"
d6e664b8
 
 #ifdef XMLRPC_OLD_VERSION
d70cf5d6
 #include <xmlrpc_abyss.h>
d6e664b8
 #endif
 
d70cf5d6
 
0b305412
 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);
 	}
 }
 
 
0847d14c
 #define MAX_XMLRPC_WAIT 2*60*4
0b305412
 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) {
387847d7
 			LM_INFO("exiting before receiving reply\n");
0b305412
 			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;
 }
 
 
 
ea306595
 static inline struct mi_handler* build_async_handler(void)
0b305412
 {
 	struct mi_handler *hdl;
 
 	hdl = (struct mi_handler*)shm_malloc( sizeof(struct mi_handler) );
 	if (hdl==0) {
387847d7
 		LM_ERR("no more shm mem\n");
0b305412
 		return 0;
 	}
 
 	hdl->handler_f = xmlrpc_close_async;
 	hdl->param = 0;
 
 	return hdl;
 }
 
 
d6e664b8
 #ifdef XMLRPC_OLD_VERSION
d70cf5d6
 xmlrpc_value*  default_method	(xmlrpc_env* 	env, 
 								char* 			host,
 								char* 			methodName,
 								xmlrpc_value* 	paramArray,
d6e664b8
 								void* 			serverInfo)
 #else
 xmlrpc_value*  default_method	(xmlrpc_env* 	env, 
 								const char* 	host,
 								const char* 	methodName,
 								xmlrpc_value* 	paramArray,
 								void* 			serverInfo)
 #endif
 {
0b305412
 	xmlrpc_value* ret = NULL;
d70cf5d6
 	struct mi_root* mi_cmd = NULL;
 	struct mi_root* mi_rpl = NULL;
0b305412
 	struct mi_handler *hdl = NULL;
 	struct mi_cmd* f;
d70cf5d6
 	char* response = 0;
0b305412
 	int is_shm = 0;
d70cf5d6
 
387847d7
 	LM_DBG("starting up.....\n");
d70cf5d6
 
b1429aef
 	/* update the local config framework structures */
 	cfg_update();
 
d6e664b8
 	f = lookup_mi_cmd((char*)methodName, strlen(methodName));
d70cf5d6
 	
 	if ( f == 0 ) {
387847d7
 		LM_ERR("command %s is not available!\n", methodName);
5b12dad4
 		xmlrpc_env_set_fault_formatted(env, XMLRPC_NO_SUCH_METHOD_ERROR, 
 			"Requested command (%s) is not available!", methodName);
d70cf5d6
 		goto error;
 	}
 
387847d7
 	LM_DBG("done looking the mi command.\n");
d70cf5d6
 
0b305412
 	/* if asyncron cmd, build the async handler */
 	if (f->flags&MI_ASYNC_RPL_FLAG) {
 		hdl = build_async_handler( );
 		if (hdl==0) {
387847d7
 			LM_ERR("failed to build async handler\n");
0b305412
 			if ( !env->fault_occurred )
 				xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR,
 					"Internal server error while processing request");
 			goto error;
 		}
 	} else {
 		hdl = NULL;
 	}
 
5b12dad4
 	if (f->flags&MI_NO_INPUT_FLAG) {
 		mi_cmd = 0;
 	} else {
 		mi_cmd = xr_parse_tree(env, paramArray);
 		if ( mi_cmd == NULL ){
387847d7
 			LM_ERR("failed to parse MI tree\n");
5b12dad4
 			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;
 		}
0b305412
 		mi_cmd->async_hdl = hdl;
d70cf5d6
 	}
 
387847d7
 	LM_DBG("done parsing the mi tree.\n");
d70cf5d6
 
 	if ( ( mi_rpl = run_mi_cmd(f, mi_cmd) ) == 0 ){
387847d7
 		LM_ERR("command (%s) processing failed.\n", methodName);
5b12dad4
 		xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, 
 			"Command (%s) processing failed.\n", methodName);
 		goto error;
0b305412
 	} 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;
d70cf5d6
 	}
 
387847d7
 	LM_DBG("done running the mi command.\n");
5b12dad4
 
d70cf5d6
 	if ( rpl_opt == 1 ) {
 		if ( xr_build_response_array( env, mi_rpl ) != 0 ){
0b305412
 			if ( !env->fault_occurred ) {
387847d7
 				LM_ERR("failed parsing the xmlrpc response from the mi tree\n");
5b12dad4
 				xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR, 
 					"Failed to parse the xmlrpc response from the mi tree.");
0b305412
 				}
5b12dad4
 			goto error;
d70cf5d6
 		}
387847d7
 		LM_DBG("done building response array.\n");
d70cf5d6
 
0b305412
 		ret = xr_response;
d70cf5d6
 	} else {
 		if ( (response = xr_build_response( env, mi_rpl )) == 0 ){
0b305412
 			if ( !env->fault_occurred ) {
387847d7
 				LM_ERR("failed parsing the xmlrpc response from the mi tree\n");
5b12dad4
 				xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR,
 					"Failed to parse the xmlrpc response from the mi tree.");
0b305412
 			}
5b12dad4
 			goto error;
d70cf5d6
 		}
387847d7
 		LM_DBG("done building response.\n");
d70cf5d6
 
0b305412
 		ret = xmlrpc_build_value(env, "s", response);
d70cf5d6
 	}
 
 error:
0b305412
 	free_async_handler(hdl);
d70cf5d6
 	if ( mi_cmd ) free_mi_tree( mi_cmd );
0b305412
 	if ( mi_rpl ) { is_shm?free_shm_mi_tree(mi_rpl):free_mi_tree(mi_rpl);}
 	return ret;
d70cf5d6
 }
 
5b12dad4
 
d6e664b8
 int set_default_method ( xmlrpc_env * env , 	xmlrpc_registry * registry)
d70cf5d6
 {
 	xmlrpc_registry_set_default_method(env, registry, &default_method, NULL);
 
 	if ( env->fault_occurred ) {
387847d7
 		LM_ERR("failed to add default method: %s\n", env->fault_string);
d70cf5d6
 		return -1;
 	}
 
 	return 0;
 }
0b305412
 
ea306595
 int init_async_lock(void)
0b305412
 {
 	xr_lock = lock_alloc();
 	if (xr_lock==NULL) {
387847d7
 		LM_ERR("failed to create lock\n");
0b305412
 		return -1;
 	}
 	if (lock_init(xr_lock)==NULL) {
387847d7
 		LM_ERR("failed to init lock\n");
0b305412
 		return -1;
 	}
 
 	return 0;
 }
 
ea306595
 void destroy_async_lock(void)
0b305412
 {
 	if (xr_lock) {
 		lock_destroy(xr_lock);
 		lock_dealloc(xr_lock);
 	}
 }