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_writer.c

218 lines
5.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)
*/
#include <string.h>
#include "../../str.h"
#include "../../dprint.h"
#include "../../mem/mem.h"
#include "xr_writer.h"
#include "mi_xmlrpc.h"
static char *reply_buffer = 0;
static unsigned int reply_buffer_len = 0;
static xmlrpc_value* reply_item;
int xr_writer_init( unsigned int size )
{
reply_buffer_len = size;
reply_buffer = pkg_malloc(size);
if(!reply_buffer){
LM_ERR("pkg_malloc cannot allocate any more memory!\n");
return -1;
}
return 0;
}
static int xr_write_node(str * buf, struct mi_node * node)
{
char *end;
char *p;
struct mi_attr* attr;
p = buf->s;
end = buf->s + buf->len -1;
/* name and value */
if ( node->name.s != NULL ) {
if ( p+node->name.len+3 > end )
return -1;
memcpy(p, node->name.s, node->name.len);
p += node->name.len;
*(p++) = ':';
*(p++) = ':';
*(p++) = ' ';
}
if ( node->value.s != NULL ) {
if ( p+node->value.len > end )
return -1;
memcpy(p, node->value.s, node->value.len);
p += node->value.len;
}
/* attributes */
for( attr=node->attributes ; attr!=NULL ; attr=attr->next ) {
if ( attr->name.s != NULL ) {
if ( p+attr->name.len+2 > end )
return -1;
*(p++) = ' ';
memcpy(p,attr->name.s,attr->name.len);
p += attr->name.len;
*(p++) = '=';
}
if (attr->value.s!=NULL) {
if (p+attr->value.len>end)
return -1;
memcpy(p,attr->value.s,attr->value.len);
p += attr->value.len;
}
}
if ( p+1 > end )
return -1;
*(p++) = '\n';
buf->len -= p-buf->s;
buf->s = p;
return 0;
}
static int recur_build_response_array( xmlrpc_env * env, struct mi_node * tree, str * buf )
{
for ( ; tree ; tree = tree->next ) {
if ( xr_write_node( buf, tree ) != 0 ) {
LM_ERR("failed to get MI node data!\n");
return -1;
}
reply_buffer[reply_buffer_len-buf->len] = 0;
reply_item = xmlrpc_build_value(env, "s", reply_buffer);
xmlrpc_array_append_item(env, xr_response, reply_item);
buf->s = reply_buffer;
buf->len = reply_buffer_len;
if ( tree->kids ) {
if ( recur_build_response_array(env, tree->kids, buf) != 0 )
return -1;
}
}
return 0;
}
int xr_build_response_array( xmlrpc_env * env, struct mi_root * tree )
{
str buf;
buf.s = reply_buffer;
buf.len = reply_buffer_len;
/* test if mi root value is 200 OK (if not no point to continue) */
if ( tree->code<200 || tree->code>=300 ){
LM_DBG("command processing failure: %s\n", tree->reason.s);
if (tree->reason.s)
xmlrpc_env_set_fault(env, tree->code, tree->reason.s);
else
xmlrpc_env_set_fault(env, tree->code, "Error");
goto error;
}
if ( recur_build_response_array(env, (&tree->node)->kids, &buf) != 0 ) {
LM_ERR("failed to read from the MI tree!\n");
xmlrpc_env_set_fault(env, 500, "Failed to write reply");
goto error;
}
return 0;
error:
if ( reply_buffer ) pkg_free(reply_buffer);
return -1;
}
static int recur_build_response( xmlrpc_env * env, struct mi_node * tree, str * buf )
{
for ( ; tree ; tree = tree->next ) {
if ( xr_write_node( buf, tree ) != 0 ) {
reply_buffer = (char*) pkg_realloc ( reply_buffer, 2*reply_buffer_len);
if ( !reply_buffer ){
LM_ERR("pkg_realloc cannot reallocate any more memory!\n");
return -1;
}
buf->s = reply_buffer +(reply_buffer_len - buf->len);
buf->len += reply_buffer_len;
reply_buffer_len *=2 ;
if ( xr_write_node( buf, tree ) != 0 ) {
LM_ERR("failed to get MI node data!\n");
return -1;
}
}
if ( tree->kids ) {
if ( recur_build_response(env, tree->kids, buf) != 0 )
return -1;
}
}
return 0;
}
char* xr_build_response( xmlrpc_env * env, struct mi_root * tree )
{
str buf;
buf.s = reply_buffer;
buf.len = reply_buffer_len;
if ( tree->code<200 || tree->code>=300 ){
LM_DBG("command processing failure: %s\n", tree->reason.s);
if (tree->reason.s)
xmlrpc_env_set_fault(env, tree->code, tree->reason.s);
else
xmlrpc_env_set_fault(env, tree->code, "Error");
return 0;
}
if ( recur_build_response(env, (&tree->node)->kids, &buf) != 0 ) {
LM_ERR("failed to read from the MI tree!\n");
xmlrpc_env_set_fault(env, 500, "Failed to build reply");
return 0;
}
reply_buffer[reply_buffer_len-buf.len] = 0;
return reply_buffer;
}