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/cdp/configparser.c

486 lines
13 KiB

/*
* $Id$
*
* Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
* Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
*
* The initial version of this code was written by Dragos Vingarzan
* (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
* Fruanhofer Institute. It was and still is maintained in a separate
* branch of the original SER. We are therefore migrating it to
* Kamailio/SR and look forward to maintaining it from here on out.
* 2011/2012 Smile Communications, Pty. Ltd.
* ported/maintained/improved by
* Jason Penton (jason(dot)penton(at)smilecoms.com and
* Richard Good (richard(dot)good(at)smilecoms.com) as part of an
* effort to add full IMS support to Kamailio/SR using a new and
* improved architecture
*
* NB: Alot of this code was originally part of OpenIMSCore,
* FhG Fokus.
* Copyright (C) 2004-2006 FhG Fokus
* Thanks for great work! This is an effort to
* break apart the various CSCF functions into logically separate
* components. We hope this will drive wider use. We also feel
* that in this way the architecture is more complete and thereby easier
* to manage in the Kamailio/SR environment
*
* This file is part of Kamailio, a free SIP server.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "config.h"
#include <libxml/parser.h>
#include <stdio.h>
#include <string.h>
extern int errno;
static xmlValidCtxt cvp; /**< XML Validation context */
/**
* Initializes the libxml parser
* @returns 1 always
*/
static inline int parser_init()
{
cvp.userData = (void*)stderr;
cvp.error = (xmlValidityErrorFunc) fprintf;
cvp.warning = (xmlValidityWarningFunc) fprintf;
return 1;
}
/**
* Destroys the parser
*/
static inline void parser_destroy()
{
xmlCleanupParser();
}
/**
* Trim the quotes from a string and duplicate it.
* @param dest - destination for the untrimmed and duplicated string
* @param src - source string
*/
static inline void quote_trim_dup(str *dest, char *src)
{
int i=0;
dest->s=0;
dest->len=0;
if (!src) return;
dest->len = strlen(src);
if (src[0]=='\"') {i++;dest->len--;}
if (src[dest->len-1]=='\"') {dest->len--;}
dest->s = shm_malloc(dest->len+1);
if (!dest->s) {
LOG_NO_MEM("shm",dest->len);
dest->len=0;
return;
}
memcpy(dest->s,src+i,dest->len);
dest->s[dest->len]=0;
}
/**
* Parse the cdp configuration from file to xml
* @param filename
* @return the xmlDocPtr or null on error
*/
xmlDocPtr parse_dp_config_file(char* filename)
{
FILE *f=0;
xmlDocPtr doc;
parser_init();
if (!filename){
LM_ERR("ERROR:parse_dp_config_file(): filename parameter is null\n");
goto error;
}
f = fopen(filename,"r");
if (!f){
LM_ERR("ERROR:parse_dp_config_file(): Error opening <%s> file > %s\n",filename,strerror(errno));
goto error;
}
fclose(f);
doc = xmlParseFile(filename);
if (!doc){
LM_ERR("parse_dp_config_file(): This is not a valid XML file <%s>\n",
filename);
goto error;
}
return doc;
error:
return 0;
}
/**
* Parse the cdp configuration from str to xml
* @param filename
* @return the xmlDocPtr or null on error
*/
xmlDocPtr parse_dp_config_str(str config_str)
{
xmlDocPtr doc;
char c = config_str.s[config_str.len];
if (!config_str.len){
LM_ERR("ERROR:parse_dp_config_str(): empty string\n");
goto error;
}
parser_init();
config_str.s[config_str.len] = 0;
doc = xmlParseDoc((xmlChar*)config_str.s);
config_str.s[config_str.len] = c;
if (!doc){
LM_ERR("parse_dp_config_file(): This is not a valid XML string <%.*s>\n",
config_str.len,config_str.s);
goto error;
}
return doc;
error:
return 0;
}
/**
* Parses a DiameterPeer configuration file.
* @param filename - path to the file
* @returns the dp_config* structure containing the parsed configuration
*/
dp_config* parse_dp_config(xmlDocPtr doc)
{
dp_config *x=0;
xmlNodePtr root=0,child=0,nephew=0;
xmlChar *xc=0;
int k;
routing_entry *re,*rei;
routing_realm *rr,*rri;
if (!doc)
goto error;
x = new_dp_config();
root = xmlDocGetRootElement(doc);
if (!root){
LM_ERR("parse_dp_config(): Empty XML \n");
goto error;
}
k = xmlStrlen(root->name);
if (k>12) k = 12;
if (strncasecmp((char*)root->name,"DiameterPeer",k)!=0){
LM_ERR("parse_dp_config(): XML Root is not <DiameterPeer>\n");
goto error;
}
xc = xmlGetProp(root,(xmlChar*)"FQDN");
if (xc){
quote_trim_dup(&(x->fqdn),(char*)xc);
quote_trim_dup(&(x->identity),(char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(root,(xmlChar*)"Realm");
if (xc){
quote_trim_dup(&(x->realm),(char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(root,(xmlChar*)"Vendor_Id");
if (xc) x->vendor_id = atoi((char*)xc);
else x->vendor_id = 0;
xc = xmlGetProp(root,(xmlChar*)"Product_Name");
if (xc){
quote_trim_dup(&(x->product_name),(char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(root,(xmlChar*)"AcceptUnknownPeers");
if (xc) {x->accept_unknown_peers = atoi((char*)xc);xmlFree(xc);}
else x->accept_unknown_peers = 1;
xc = xmlGetProp(root,(xmlChar*)"DropUnknownOnDisconnect");
if (xc) {x->drop_unknown_peers = atoi((char*)xc);xmlFree(xc);}
else x->drop_unknown_peers = 1;
xc = xmlGetProp(root,(xmlChar*)"Tc");
if (xc) {x->tc = atoi((char*)xc);xmlFree(xc);}
else x->tc = 30;
xc = xmlGetProp(root,(xmlChar*)"Workers");
if (xc) {x->workers = atoi((char*)xc);xmlFree(xc);}
else x->workers = 4;
xc = xmlGetProp(root,(xmlChar*)"QueueLength");
if (xc) {x->queue_length = atoi((char*)xc);xmlFree(xc);}
else x->queue_length = 32;
xc = xmlGetProp(root,(xmlChar*)"ConnectTimeout");
if (xc) {x->connect_timeout= atoi((char*)xc);xmlFree(xc);}
else x->connect_timeout = 5;
xc = xmlGetProp(root,(xmlChar*)"TransactionTimeout");
if (xc) {x->transaction_timeout = atoi((char*)xc);xmlFree(xc);}
else x->transaction_timeout = 5;
xc = xmlGetProp(root,(xmlChar*)"SessionsHashSize");
if (xc) {x->sessions_hash_size = atoi((char*)xc);xmlFree(xc);}
else x->sessions_hash_size = 128;
xc = xmlGetProp(root,(xmlChar*)"DefaultAuthSessionTimeout");
if (xc) {x->default_auth_session_timeout = atoi((char*)xc);xmlFree(xc);}
else x->default_auth_session_timeout = 60;
xc = xmlGetProp(root,(xmlChar*)"MaxAuthSessionTimeout");
if (xc) {x->max_auth_session_timeout = atoi((char*)xc);xmlFree(xc);}
else x->max_auth_session_timeout = 300;
for(child = root->children; child; child = child->next)
if (child->type == XML_ELEMENT_NODE)
{
if (xmlStrlen(child->name)==4 && strncasecmp((char*)child->name,"Peer",4)==0){
//PEER
x->peers_cnt++;
}
else if (xmlStrlen(child->name)==8 && strncasecmp((char*)child->name,"Acceptor",8)==0){
//Acceptor
x->acceptors_cnt++;
}
else if (xmlStrlen(child->name)==4 && (strncasecmp((char*)child->name,"Auth",4)==0||
strncasecmp((char*)child->name,"Acct",4)==0)){
//Application
x->applications_cnt++;
}
else if (xmlStrlen(child->name)==15 && (strncasecmp((char*)child->name,"SupportedVendor",15)==0)){
//SupportedVendor
x->supported_vendors_cnt++;
}
}
x->peers = shm_malloc(x->peers_cnt*sizeof(peer_config));
if (!x->peers){
LOG_NO_MEM("shm",x->peers_cnt*sizeof(peer_config));
goto error;
}
memset(x->peers,0,x->peers_cnt*sizeof(peer_config));
x->peers_cnt=0;
x->acceptors = shm_malloc(x->acceptors_cnt*sizeof(acceptor_config));
if (!x->acceptors){
LOG_NO_MEM("shm",x->acceptors_cnt*sizeof(acceptor_config));
goto error;
}
memset(x->acceptors,0,x->acceptors_cnt*sizeof(acceptor_config));
x->acceptors_cnt=0;
x->applications = shm_malloc(x->applications_cnt*sizeof(app_config));
if (!x->applications){
LOG_NO_MEM("shm",x->applications_cnt*sizeof(app_config));
goto error;
}
memset(x->applications,0,x->applications_cnt*sizeof(app_config));
x->applications_cnt=0;
x->supported_vendors = shm_malloc(x->supported_vendors_cnt*sizeof(int));
if (!x->supported_vendors){
LOG_NO_MEM("shm",x->supported_vendors_cnt*sizeof(int));
goto error;
}
memset(x->supported_vendors,0,x->supported_vendors_cnt*sizeof(int));
x->supported_vendors_cnt=0;
for(child = root->children; child; child = child->next)
if (child->type == XML_ELEMENT_NODE)
{
if (xmlStrlen(child->name)==4 && strncasecmp((char*)child->name,"Peer",4)==0){
//PEER
xc = xmlGetProp(child,(xmlChar*)"FQDN");
if (xc){
quote_trim_dup(&(x->peers[x->peers_cnt].fqdn),(char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(child,(xmlChar*)"Realm");
if (xc){
quote_trim_dup(&(x->peers[x->peers_cnt].realm),(char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(child,(xmlChar*)"port");
if (xc){
x->peers[x->peers_cnt].port = atoi((char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(child,(xmlChar*)"src_addr");
if (xc){
quote_trim_dup(&(x->peers[x->peers_cnt].src_addr),(char*)xc);
xmlFree(xc);
}
x->peers_cnt++;
}
else if (xmlStrlen(child->name)==8 && strncasecmp((char*)child->name,"Acceptor",8)==0){
//Acceptor
xc = xmlGetProp(child,(xmlChar*)"bind");
if (xc){
quote_trim_dup(&(x->acceptors[x->acceptors_cnt].bind),(char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(child,(xmlChar*)"port");
if (xc){
x->acceptors[x->acceptors_cnt].port = atoi((char*)xc);
xmlFree(xc);
}
x->acceptors_cnt++;
}
else if (xmlStrlen(child->name)==4 && (strncasecmp((char*)child->name,"Auth",4)==0||
strncasecmp((char*)child->name,"Acct",4)==0)){
//Application
xc = xmlGetProp(child,(xmlChar*)"id");
if (xc){
x->applications[x->applications_cnt].id = atoi((char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(child,(xmlChar*)"vendor");
if (xc){
x->applications[x->applications_cnt].vendor = atoi((char*)xc);
xmlFree(xc);
}
if (child->name[1]=='u'||child->name[1]=='U')
x->applications[x->applications_cnt].type = DP_AUTHORIZATION;
else
x->applications[x->applications_cnt].type = DP_ACCOUNTING;
x->applications_cnt++;
}
else if (xmlStrlen(child->name)==15 && (strncasecmp((char*)child->name,"SupportedVendor",15)==0)){
//SupportedVendor
xc = xmlGetProp(child,(xmlChar*)"vendor");
if (xc){
x->supported_vendors[x->supported_vendors_cnt] = atoi((char*)xc);
xmlFree(xc);
}
x->supported_vendors_cnt++;
}
else if (xmlStrlen(child->name)==12 && (strncasecmp((char*)child->name,"DefaultRoute",12)==0)){
if (!x->r_table) {
x->r_table = shm_malloc(sizeof(routing_table));
memset(x->r_table,0,sizeof(routing_table));
}
re = new_routing_entry();
if (re){
xc = xmlGetProp(child,(xmlChar*)"FQDN");
if (xc){
quote_trim_dup(&(re->fqdn),(char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(child,(xmlChar*)"metric");
if (xc){
re->metric = atoi((char*)xc);
xmlFree(xc);
}
/* add it the list in ascending order */
if (! x->r_table->routes || re->metric <= x->r_table->routes->metric){
re->next = x->r_table->routes;
x->r_table->routes = re;
}else{
for(rei=x->r_table->routes;rei;rei=rei->next)
if (!rei->next){
rei->next = re;
break;
}else{
if (re->metric <= rei->next->metric){
re->next = rei->next;
rei->next = re;
break;
}
}
}
}
}
else if (xmlStrlen(child->name)==5 && (strncasecmp((char*)child->name,"Realm",5)==0)){
if (!x->r_table) {
x->r_table = shm_malloc(sizeof(routing_table));
memset(x->r_table,0,sizeof(routing_table));
}
rr = new_routing_realm();
if (rr){
xc = xmlGetProp(child,(xmlChar*)"name");
quote_trim_dup(&(rr->realm),(char*)xc);
if (!x->r_table->realms) {
x->r_table->realms = rr;
}else{
for(rri=x->r_table->realms;rri->next;rri=rri->next);
rri->next = rr;
}
for(nephew = child->children; nephew; nephew = nephew->next)
if (nephew->type == XML_ELEMENT_NODE){
if (xmlStrlen(nephew->name)==5 && (strncasecmp((char*)nephew->name,"Route",5)==0))
{
re = new_routing_entry();
if (re) {
xc = xmlGetProp(nephew,(xmlChar*)"FQDN");
if (xc){
quote_trim_dup(&(re->fqdn),(char*)xc);
xmlFree(xc);
}
xc = xmlGetProp(nephew,(xmlChar*)"metric");
if (xc){
re->metric = atoi((char*)xc);
xmlFree(xc);
}
/* add it the list in ascending order */
if (! rr->routes || re->metric <= rr->routes->metric){
re->next = rr->routes;
rr->routes = re;
}else{
for(rei=rr->routes;rei;rei=rei->next)
if (!rei->next){
rei->next = re;
break;
}else{
if (re->metric <= rei->next->metric){
re->next = rei->next;
rei->next = re;
break;
}
}
}
}
}
}
}
}
}
if (doc) xmlFreeDoc(doc);
parser_destroy();
return x;
error:
if (doc) xmlFreeDoc(doc);
parser_destroy();
if (x) free_dp_config(x);
return 0;
}