modules_k/dispatcher/dispatcher.c
31ccf6a2
 /**
  * $Id$
  *
  * dispatcher module -- stateless load balancing
  *
ba07eb39
  * Copyright (C) 2004-2005 FhG Fokus
  * Copyright (C) 2006 Voice Sistem SRL
31ccf6a2
  *
27642a08
  * This file is part of Kamailio, a free SIP server.
31ccf6a2
  *
27642a08
  * Kamailio is free software; you can redistribute it and/or modify
31ccf6a2
  * 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,
31ccf6a2
  * 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
  * -------
  * 2004-07-31  first version, by daniel
081b5d4e
  * 2007-01-11  Added a function to check if a specific gateway is in a group
  *				(carsten - Carsten Bock, BASIS AudioNet GmbH)
  * 2007-02-09  Added active probing of failed destinations and automatic
  *				re-enabling of destinations (carsten)
  * 2007-05-08  Ported the changes to SVN-Trunk and renamed ds_is_domain
  *				to ds_is_from_list.  (carsten)
101e9af4
  * 2007-07-18  Added support for load/reload groups from DB 
  * 			   reload triggered from ds_reload MI_Command (ancuta)
31ccf6a2
  */
 
aecdbe9b
 /*! \file
  * \ingroup dispatcher
  * \brief Dispatcher :: Dispatch
  */
 
 /*! \defgroup dispatcher Dispatcher :: Load balancing and failover module
  * 	The dispatcher module implements a set of functions for distributing SIP requests on a 
  *	set of servers, but also grouping of server resources.
  *
  *	- The module has an internal API exposed to other modules.
  *	- The module implements a couple of MI functions for managing the list of server resources
  */
 
31ccf6a2
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
 
c497c466
 #include "../../lib/kmi/mi.h"
31ccf6a2
 #include "../../sr_module.h"
 #include "../../dprint.h"
 #include "../../error.h"
 #include "../../ut.h"
a4ba0359
 #include "../../route.h"
31ccf6a2
 #include "../../mem/mem.h"
dfb0caa1
 #include "../../mod_fix.h"
31ccf6a2
 
59c31fe7
 #include "ds_ht.h"
31ccf6a2
 #include "dispatch.h"
ec903da3
 #include "config.h"
86e03df9
 #include "api.h"
31ccf6a2
 
 MODULE_VERSION
 
9de77c2b
 #define DS_SET_ID_COL			"setid"
 #define DS_DEST_URI_COL			"destination"
 #define DS_DEST_FLAGS_COL		"flags"
 #define DS_DEST_PRIORITY_COL	"priority"
65160302
 #define DS_DEST_ATTRS_COL		"attrs"
9de77c2b
 #define DS_TABLE_NAME			"dispatcher"
101e9af4
 
31ccf6a2
 /** parameters */
 char *dslistfile = CFG_DIR"dispatcher.list";
9a5bc6b1
 int  ds_force_dst   = 1;
a4ba0359
 int  ds_flags       = 0; 
 int  ds_use_default = 0; 
e2cf6343
 static str dst_avp_param = {NULL, 0};
 static str grp_avp_param = {NULL, 0};
 static str cnt_avp_param = {NULL, 0};
9cdc3e70
 static str dstid_avp_param = {NULL, 0};
 static str attrs_avp_param = {NULL, 0};
095ab21d
 str hash_pvar_param = {NULL, 0};
 
8cdef0e8
 int_str dst_avp_name;
 unsigned short dst_avp_type;
 int_str grp_avp_name;
 unsigned short grp_avp_type;
 int_str cnt_avp_name;
 unsigned short cnt_avp_type;
9cdc3e70
 int_str dstid_avp_name;
 unsigned short dstid_avp_type;
 int_str attrs_avp_name;
 unsigned short attrs_avp_type;
8cdef0e8
 
e26079d5
 pv_elem_t * hash_param_model = NULL;
095ab21d
 
081b5d4e
 int probing_threshhold = 3; /* number of failed requests, before a destination
 							   is taken into probing */
101e9af4
 str ds_ping_method = {"OPTIONS",7};
 str ds_ping_from   = {"sip:dispatcher@localhost", 24};
 static int ds_ping_interval = 0;
8381c032
 int ds_probing_mode  = 0;
ec903da3
 
 static str ds_ping_reply_codes_str= {NULL, 0};
 static int** ds_ping_reply_codes = NULL;
 static int* ds_ping_reply_codes_cnt;
 
59c31fe7
 int ds_hash_size = 0;
 int ds_hash_expire = 7200;
9cdc3e70
 int ds_hash_initexpire = 7200;
 int ds_hash_check_interval = 30;
101e9af4
 
2e561eca
 /* tm */
 struct tm_binds tmb;
 
101e9af4
 /*db */
9de77c2b
 str ds_db_url            = {NULL, 0};
 str ds_set_id_col        = str_init(DS_SET_ID_COL);
 str ds_dest_uri_col      = str_init(DS_DEST_URI_COL);
 str ds_dest_flags_col    = str_init(DS_DEST_FLAGS_COL);
 str ds_dest_priority_col = str_init(DS_DEST_PRIORITY_COL);
65160302
 str ds_dest_attrs_col    = str_init(DS_DEST_ATTRS_COL);
9de77c2b
 str ds_table_name        = str_init(DS_TABLE_NAME);
101e9af4
 
b14bb7d7
 str ds_setid_pvname   = {NULL, 0};
 pv_spec_t ds_setid_pv;
31ccf6a2
 
 /** module functions */
 static int mod_init(void);
 static int child_init(int);
 
ec903da3
 static int ds_parse_reply_codes();
 
31ccf6a2
 static int w_ds_select_dst(struct sip_msg*, char*, char*);
44f3472f
 static int w_ds_select_domain(struct sip_msg*, char*, char*);
a4ba0359
 static int w_ds_next_dst(struct sip_msg*, char*, char*);
 static int w_ds_next_domain(struct sip_msg*, char*, char*);
 static int w_ds_mark_dst0(struct sip_msg*, char*, char*);
 static int w_ds_mark_dst1(struct sip_msg*, char*, char*);
9cdc3e70
 static int w_ds_load_unset(struct sip_msg*, char*, char*);
 static int w_ds_load_update(struct sip_msg*, char*, char*);
31ccf6a2
 
081b5d4e
 static int w_ds_is_from_list0(struct sip_msg*, char*, char*);
 static int w_ds_is_from_list1(struct sip_msg*, char*, char*);
 
e2cf6343
 static void destroy(void);
31ccf6a2
 
ff4dd78e
 static int ds_warn_fixup(void** param, int param_no);
31ccf6a2
 
e2cf6343
 static struct mi_root* ds_mi_set(struct mi_root* cmd, void* param);
 static struct mi_root* ds_mi_list(struct mi_root* cmd, void* param);
 static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param);
351fc577
 static int mi_child_init(void);
a4ba0359
 
31ccf6a2
 static cmd_export_t cmds[]={
9cdc3e70
 	{"ds_select_dst",    (cmd_function)w_ds_select_dst,    2,
 		fixup_igp_igp, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 	{"ds_select_domain", (cmd_function)w_ds_select_domain, 2,
 		fixup_igp_igp, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 	{"ds_next_dst",      (cmd_function)w_ds_next_dst,      0,
 		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 	{"ds_next_domain",   (cmd_function)w_ds_next_domain,   0,
 		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst0,     0,
 		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst1,     1,
 		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list0, 0,
 		0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list1, 1,
 		fixup_uint_null, 0, ANY_ROUTE},
 	{"ds_load_unset",    (cmd_function)w_ds_load_unset,   0,
 		0, 0, ANY_ROUTE},
 	{"ds_load_update",   (cmd_function)w_ds_load_update,  0,
 		0, 0, ANY_ROUTE},
86e03df9
 	{"bind_dispatcher",   (cmd_function)bind_dispatcher,  0,
 		0, 0, 0},
80998a7f
 	{0,0,0,0,0,0}
31ccf6a2
 };
 
 
 static param_export_t params[]={
101e9af4
 	{"list_file",       STR_PARAM, &dslistfile},
e2cf6343
 	{"db_url",		    STR_PARAM, &ds_db_url.s},
 	{"table_name", 	    STR_PARAM, &ds_table_name.s},
 	{"setid_col",       STR_PARAM, &ds_set_id_col.s},
 	{"destination_col", STR_PARAM, &ds_dest_uri_col.s},
c7d56382
 	{"flags_col",       STR_PARAM, &ds_dest_flags_col.s},
9de77c2b
 	{"priority_col",    STR_PARAM, &ds_dest_priority_col.s},
65160302
 	{"attrs_col",       STR_PARAM, &ds_dest_attrs_col.s},
101e9af4
 	{"force_dst",       INT_PARAM, &ds_force_dst},
 	{"flags",           INT_PARAM, &ds_flags},
 	{"use_default",     INT_PARAM, &ds_use_default},
e2cf6343
 	{"dst_avp",         STR_PARAM, &dst_avp_param.s},
 	{"grp_avp",         STR_PARAM, &grp_avp_param.s},
 	{"cnt_avp",         STR_PARAM, &cnt_avp_param.s},
9cdc3e70
 	{"dstid_avp",       STR_PARAM, &dstid_avp_param.s},
 	{"attrs_avp",       STR_PARAM, &attrs_avp_param.s},
095ab21d
 	{"hash_pvar",       STR_PARAM, &hash_pvar_param.s},
b14bb7d7
 	{"setid_pvname",    STR_PARAM, &ds_setid_pvname.s},
081b5d4e
 	{"ds_probing_threshhold", INT_PARAM, &probing_threshhold},
e2cf6343
 	{"ds_ping_method",     STR_PARAM, &ds_ping_method.s},
 	{"ds_ping_from",       STR_PARAM, &ds_ping_from.s},
081b5d4e
 	{"ds_ping_interval",   INT_PARAM, &ds_ping_interval},
ec903da3
 	{"ds_ping_reply_codes", STR_PARAM, &ds_ping_reply_codes_str},
d1de0cc5
 	{"ds_probing_mode",    INT_PARAM, &ds_probing_mode},
9cdc3e70
 	{"ds_hash_size",       INT_PARAM, &ds_hash_size},
 	{"ds_hash_expire",     INT_PARAM, &ds_hash_expire},
 	{"ds_hash_initexpire", INT_PARAM, &ds_hash_initexpire},
 	{"ds_hash_check_interval", INT_PARAM, &ds_hash_check_interval},
31ccf6a2
 	{0,0,0}
 };
 
 
de26de44
 static mi_export_t mi_cmds[] = {
cd63f545
 	{ "ds_set_state",   ds_mi_set,     0,                 0,  0            },
 	{ "ds_list",        ds_mi_list,    MI_NO_INPUT_FLAG,  0,  0            },
 	{ "ds_reload",      ds_mi_reload,  0,                 0,  mi_child_init},
fcb8aeaf
 	{ 0, 0, 0, 0, 0}
de26de44
 };
 
 
31ccf6a2
 /** module exports */
 struct module_exports exports= {
 	"dispatcher",
51716422
 	DEFAULT_DLFLAGS, /* dlopen flags */
31ccf6a2
 	cmds,
 	params,
739aec8b
 	0,          /* exported statistics */
de26de44
 	mi_cmds,    /* exported MI functions */
71c26efd
 	0,          /* exported pseudo-variables */
3eee3a4e
 	0,          /* extra processes */
31ccf6a2
 	mod_init,   /* module initialization function */
3ed44241
 	0,
31ccf6a2
 	(destroy_function) destroy,
 	child_init  /* per-child init function */
 };
 
 /**
  * init module function
  */
 static int mod_init(void)
 {
c7d56382
 	pv_spec_t avp_spec;
 
9bdaf1a8
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	{
 		LM_ERR("failed to register MI commands\n");
 		return -1;
 	}
 
e2cf6343
 	if (dst_avp_param.s)
c7d56382
 		dst_avp_param.len = strlen(dst_avp_param.s);
e2cf6343
 	if (grp_avp_param.s)
c7d56382
 		grp_avp_param.len = strlen(grp_avp_param.s);
e2cf6343
 	if (cnt_avp_param.s)
c7d56382
 		cnt_avp_param.len = strlen(cnt_avp_param.s);	
9cdc3e70
 	if (dstid_avp_param.s)
 		dstid_avp_param.len = strlen(dstid_avp_param.s);
 	if (attrs_avp_param.s)
 		attrs_avp_param.len = strlen(attrs_avp_param.s);
095ab21d
 	if (hash_pvar_param.s)
b14bb7d7
 		hash_pvar_param.len = strlen(hash_pvar_param.s);
 	if (ds_setid_pvname.s)
 		ds_setid_pvname.len = strlen(ds_setid_pvname.s);
e2cf6343
 	if (ds_ping_from.s) ds_ping_from.len = strlen(ds_ping_from.s);
 	if (ds_ping_method.s) ds_ping_method.len = strlen(ds_ping_method.s);
 
ec903da3
         if(cfg_declare("dispatcher", dispatcher_cfg_def, &default_dispatcher_cfg, cfg_sizeof(dispatcher), &dispatcher_cfg)){
                 LM_ERR("Fail to declare the configuration\n");
                 return -1;
         }
 	/* Initialize the counter */
 	ds_ping_reply_codes = (int**)shm_malloc(sizeof(unsigned int*));
 	*ds_ping_reply_codes = 0;
 	ds_ping_reply_codes_cnt = (int*)shm_malloc(sizeof(int));
 	*ds_ping_reply_codes_cnt = 0;
 	if(ds_ping_reply_codes_str.s) {
 		ds_ping_reply_codes_str.len = strlen(ds_ping_reply_codes_str.s);
 		cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str) = ds_ping_reply_codes_str;
 		if(ds_parse_reply_codes()< 0)
 		{
 			return -1;
 		}
 	}	
 	/* Copy Threshhold to Config */
 	cfg_get(dispatcher, dispatcher_cfg, probing_threshhold) = probing_threshhold;
 
 
101e9af4
 	if(init_data()!= 0)
 		return -1;
 
e2cf6343
 	if(ds_db_url.s)
31ccf6a2
 	{
c7d56382
 		ds_db_url.len     = strlen(ds_db_url.s);
 		ds_table_name.len = strlen(ds_table_name.s);
65160302
 		ds_set_id_col.len        = strlen(ds_set_id_col.s);
 		ds_dest_uri_col.len      = strlen(ds_dest_uri_col.s);
 		ds_dest_flags_col.len    = strlen(ds_dest_flags_col.s);
 		ds_dest_priority_col.len = strlen(ds_dest_priority_col.s);
 		ds_dest_attrs_col.len    = strlen(ds_dest_attrs_col.s);
c7d56382
 
c503d21d
 		if(init_ds_db()!= 0)
101e9af4
 		{
c503d21d
 			LM_ERR("could not initiate a connect to the database\n");
101e9af4
 			return -1;
 		}
 	} else {
ac082a22
 		if(ds_load_list(dslistfile)!=0) {
 			LM_ERR("no dispatching list loaded from file\n");
 			return -1;
 		} else {
 			LM_DBG("loaded dispatching list\n");
 		}
31ccf6a2
 	}
65160302
 
e2cf6343
 	if (dst_avp_param.s && dst_avp_param.len > 0)
101e9af4
 	{
e2cf6343
 		if (pv_parse_spec(&dst_avp_param, &avp_spec)==0
b0a7f212
 				|| avp_spec.type!=PVT_AVP)
101e9af4
 		{
c7d56382
 			LM_ERR("malformed or non AVP %.*s AVP definition\n",
 					dst_avp_param.len, dst_avp_param.s);
8cdef0e8
 			return -1;
 		}
 
b0a7f212
 		if(pv_get_avp_name(0, &(avp_spec.pvp), &dst_avp_name, &dst_avp_type)!=0)
8cdef0e8
 		{
c7d56382
 			LM_ERR("[%.*s]- invalid AVP definition\n", dst_avp_param.len,
 					dst_avp_param.s);
8cdef0e8
 			return -1;
 		}
 	} else {
 		dst_avp_name.n = 0;
 		dst_avp_type = 0;
 	}
e2cf6343
 	if (grp_avp_param.s && grp_avp_param.len > 0)
101e9af4
 	{
e2cf6343
 		if (pv_parse_spec(&grp_avp_param, &avp_spec)==0
b0a7f212
 				|| avp_spec.type!=PVT_AVP)
101e9af4
 		{
c7d56382
 			LM_ERR("malformed or non AVP %.*s AVP definition\n",
 					grp_avp_param.len, grp_avp_param.s);
8cdef0e8
 			return -1;
 		}
 
b0a7f212
 		if(pv_get_avp_name(0, &(avp_spec.pvp), &grp_avp_name, &grp_avp_type)!=0)
8cdef0e8
 		{
c7d56382
 			LM_ERR("[%.*s]- invalid AVP definition\n", grp_avp_param.len,
 					grp_avp_param.s);
8cdef0e8
 			return -1;
 		}
 	} else {
 		grp_avp_name.n = 0;
 		grp_avp_type = 0;
 	}
e2cf6343
 	if (cnt_avp_param.s && cnt_avp_param.len > 0)
101e9af4
 	{
e2cf6343
 		if (pv_parse_spec(&cnt_avp_param, &avp_spec)==0
b0a7f212
 				|| avp_spec.type!=PVT_AVP)
101e9af4
 		{
c7d56382
 			LM_ERR("malformed or non AVP %.*s AVP definition\n",
 					cnt_avp_param.len, cnt_avp_param.s);
8cdef0e8
 			return -1;
 		}
 
b0a7f212
 		if(pv_get_avp_name(0, &(avp_spec.pvp), &cnt_avp_name, &cnt_avp_type)!=0)
8cdef0e8
 		{
c7d56382
 			LM_ERR("[%.*s]- invalid AVP definition\n", cnt_avp_param.len,
 					cnt_avp_param.s);
8cdef0e8
 			return -1;
 		}
 	} else {
 		cnt_avp_name.n = 0;
 		cnt_avp_type = 0;
 	}
9cdc3e70
 	if (dstid_avp_param.s && dstid_avp_param.len > 0)
 	{
 		if (pv_parse_spec(&dstid_avp_param, &avp_spec)==0
 				|| avp_spec.type!=PVT_AVP)
 		{
 			LM_ERR("malformed or non AVP %.*s AVP definition\n",
 					dstid_avp_param.len, dstid_avp_param.s);
 			return -1;
 		}
 
 		if(pv_get_avp_name(0, &(avp_spec.pvp), &dstid_avp_name,
 					&dstid_avp_type)!=0)
 		{
 			LM_ERR("[%.*s]- invalid AVP definition\n", dstid_avp_param.len,
 					dstid_avp_param.s);
 			return -1;
 		}
 	} else {
 		dstid_avp_name.n = 0;
 		dstid_avp_type = 0;
 	}
 
 	if (attrs_avp_param.s && attrs_avp_param.len > 0)
 	{
 		if (pv_parse_spec(&attrs_avp_param, &avp_spec)==0
 				|| avp_spec.type!=PVT_AVP)
 		{
 			LM_ERR("malformed or non AVP %.*s AVP definition\n",
 					attrs_avp_param.len, attrs_avp_param.s);
 			return -1;
 		}
 
 		if(pv_get_avp_name(0, &(avp_spec.pvp), &attrs_avp_name,
 					&attrs_avp_type)!=0)
 		{
 			LM_ERR("[%.*s]- invalid AVP definition\n", attrs_avp_param.len,
 					attrs_avp_param.s);
 			return -1;
 		}
 	} else {
 		attrs_avp_name.n = 0;
 		attrs_avp_type = 0;
 	}
081b5d4e
 
095ab21d
 	if (hash_pvar_param.s && *hash_pvar_param.s) {
 		if(pv_parse_format(&hash_pvar_param, &hash_param_model) < 0
 				|| hash_param_model==NULL) {
 			LM_ERR("malformed PV string: %s\n", hash_pvar_param.s);
 			return -1;
 		}		
 	} else {
 		hash_param_model = NULL;
 	}
b14bb7d7
 	
 	if(ds_setid_pvname.s!=0)
 	{
 		if(pv_parse_spec(&ds_setid_pvname, &ds_setid_pv)==NULL
 				|| !pv_is_w(&ds_setid_pv))
 		{
 			LM_ERR("[%s]- invalid setid_pvname\n", ds_setid_pvname.s);
 			return -1;
 		}
 	}
9cdc3e70
 	if (dstid_avp_param.s && dstid_avp_param.len > 0)
 	{
 		if(ds_hash_size>0)
 		{
 			if(ds_hash_load_init(1<<ds_hash_size, ds_hash_expire,
 						ds_hash_initexpire)<0)
 				return -1;
 			register_timer(ds_ht_timer, NULL, ds_hash_check_interval);
 		} else {
72c052a9
 			LM_ERR("call load dispatching DSTID_AVP set but no size"
 					" for hash table\n");
9cdc3e70
 			return -1;
 		}
 	}
081b5d4e
 	/* Only, if the Probing-Timer is enabled the TM-API needs to be loaded: */
101e9af4
 	if (ds_ping_interval > 0)
 	{
081b5d4e
 		/*****************************************************
 		 * TM-Bindings
 	  	 *****************************************************/
fd5ddfd1
 		if (load_tm_api( &tmb ) == -1)
101e9af4
 		{
fd5ddfd1
 			LM_ERR("could not load the TM-functions - disable DS ping\n");
 			return -1;
081b5d4e
 		}
fd5ddfd1
 		/*****************************************************
 		 * Register the PING-Timer
 		 *****************************************************/
 		register_timer(ds_check_timer, NULL, ds_ping_interval);
081b5d4e
 	}
8cdef0e8
 
31ccf6a2
 	return 0;
 }
 
aecdbe9b
 /*! \brief
31ccf6a2
  * Initialize children
  */
 static int child_init(int rank)
 {
101e9af4
 	srand((11+rank)*getpid()*7);
c503d21d
 
31ccf6a2
 	return 0;
 }
 
351fc577
 static int mi_child_init(void)
c503d21d
 {
2af93c2f
 	
e2cf6343
 	if(ds_db_url.s)
2af93c2f
 		return ds_connect_db();
 	return 0;
c503d21d
 
 }
 
aecdbe9b
 /*! \brief
2af93c2f
  * destroy function
  */
e2cf6343
 static void destroy(void)
2af93c2f
 {
 	ds_destroy_list();
e2cf6343
 	if(ds_db_url.s)
2af93c2f
 		ds_disconnect_db();
9cdc3e70
 	ds_hash_load_destroy();
ec903da3
 	if(ds_ping_reply_codes)
 		shm_free(ds_ping_reply_codes);	
 
2af93c2f
 }
 
31ccf6a2
 /**
  *
  */
 static int w_ds_select_dst(struct sip_msg* msg, char* set, char* alg)
 {
a4ba0359
 	int a, s;
 	
31ccf6a2
 	if(msg==NULL)
 		return -1;
05723a03
 	if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0)
a4ba0359
 	{
101e9af4
 		LM_ERR("no dst set value\n");
a4ba0359
 		return -1;
 	}
05723a03
 	if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0)
a4ba0359
 	{
101e9af4
 		LM_ERR("no alg value\n");
a4ba0359
 		return -1;
 	}
31ccf6a2
 
a4ba0359
 	return ds_select_dst(msg, s, a, 0 /*set dst uri*/);
44f3472f
 }
 
 /**
  *
  */
 static int w_ds_select_domain(struct sip_msg* msg, char* set, char* alg)
 {
a4ba0359
 	int a, s;
44f3472f
 	if(msg==NULL)
 		return -1;
 
05723a03
 	if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0)
a4ba0359
 	{
101e9af4
 		LM_ERR("no dst set value\n");
a4ba0359
 		return -1;
 	}
05723a03
 	if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0)
a4ba0359
 	{
101e9af4
 		LM_ERR("no alg value\n");
a4ba0359
 		return -1;
 	}
 
 	return ds_select_dst(msg, s, a, 1/*set host port*/);
 }
 
 /**
  *
  */
 static int w_ds_next_dst(struct sip_msg *msg, char *str1, char *str2)
 {
 	return ds_next_dst(msg, 0/*set dst uri*/);
 }
 
 /**
  *
  */
 static int w_ds_next_domain(struct sip_msg *msg, char *str1, char *str2)
 {
 	return ds_next_dst(msg, 1/*set host port*/);
 }
 
 /**
  *
  */
 static int w_ds_mark_dst0(struct sip_msg *msg, char *str1, char *str2)
 {
 	return ds_mark_dst(msg, 0);
 }
 
 /**
  *
  */
 static int w_ds_mark_dst1(struct sip_msg *msg, char *str1, char *str2)
 {
 	if(str1 && (str1[0]=='i' || str1[0]=='I' || str1[0]=='0'))
 		return ds_mark_dst(msg, 0);
081b5d4e
 	else if(str1 && (str1[0]=='p' || str1[0]=='P' || str1[0]=='2'))
 		return ds_mark_dst(msg, 2);
a4ba0359
 	else
 		return ds_mark_dst(msg, 1);
31ccf6a2
 }
 
9cdc3e70
 
 /**
  *
  */
 static int w_ds_load_unset(struct sip_msg *msg, char *str1, char *str2)
 {
 	if(ds_load_unset(msg)<0)
 		return -1;
 	return 1;
 }
 
 /**
  *
  */
 static int w_ds_load_update(struct sip_msg *msg, char *str1, char *str2)
 {
 	if(ds_load_update(msg)<0)
 		return -1;
 	return 1;
 }
 
 /**
  *
  */
ff4dd78e
 static int ds_warn_fixup(void** param, int param_no)
 {
e2cf6343
 	if(!dst_avp_param.s || !grp_avp_param.s || !cnt_avp_param.s)
ff4dd78e
 	{
101e9af4
 		LM_ERR("failover functions used, but AVPs paraamters required"
 				" are NULL -- feature disabled\n");
ff4dd78e
 	}
 	return 0;
 }
ba07eb39
 
 /************************** MI STUFF ************************/
 
e2cf6343
 static struct mi_root* ds_mi_set(struct mi_root* cmd_tree, void* param)
ba07eb39
 {
 	str sp;
 	int ret;
 	unsigned int group, state;
 	struct mi_node* node;
 
33393fd3
 	node = cmd_tree->node.kids;
ba07eb39
 	if(node == NULL)
241a05bc
 		return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
ba07eb39
 	sp = node->value;
e2cf6343
 	if(sp.len<=0 || !sp.s)
ba07eb39
 	{
101e9af4
 		LM_ERR("bad state value\n");
241a05bc
 		return init_mi_tree(500, "bad state value", 15);
ba07eb39
 	}
 
241a05bc
 	state = 0;
 	if(sp.s[0]=='0' || sp.s[0]=='I' || sp.s[0]=='i') {
 		/* set inactive */
 		state |= DS_INACTIVE_DST;
 		if((sp.len>1) && (sp.s[1]=='P' || sp.s[1]=='p'))
 			state |= DS_PROBING_DST;
 	} else if(sp.s[0]=='1' || sp.s[0]=='A' || sp.s[0]=='a') {
 		/* set active */
 		if((sp.len>1) && (sp.s[1]=='P' || sp.s[1]=='p'))
 			state |= DS_PROBING_DST;
 	} else if(sp.s[0]=='2' || sp.s[0]=='D' || sp.s[0]=='d') {
 		/* set disabled */
 		state |= DS_DISABLED_DST;
 	} else {
 		LM_ERR("unknow state value\n");
 		return init_mi_tree(500, "unknown state value", 19);
 	}
ba07eb39
 	node = node->next;
 	if(node == NULL)
241a05bc
 		return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
ba07eb39
 	sp = node->value;
 	if(sp.s == NULL)
 	{
33393fd3
 		return init_mi_tree(500, "group not found", 15);
ba07eb39
 	}
 
 	if(str2int(&sp, &group))
 	{
101e9af4
 		LM_ERR("bad group value\n");
33393fd3
 		return init_mi_tree( 500, "bad group value", 16);
ba07eb39
 	}
 
 	node= node->next;
 	if(node == NULL)
33393fd3
 		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
ba07eb39
 
 	sp = node->value;
 	if(sp.s == NULL)
 	{
33393fd3
 		return init_mi_tree(500,"address not found", 18 );
ba07eb39
 	}
 
241a05bc
 	ret = ds_reinit_state(group, &sp, state);
ba07eb39
 
 	if(ret!=0)
 	{
101e9af4
 		return init_mi_tree(404, "destination not found", 21);
ba07eb39
 	}
 
33393fd3
 	return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
ba07eb39
 }
 
 
 
 
e2cf6343
 static struct mi_root* ds_mi_list(struct mi_root* cmd_tree, void* param)
ba07eb39
 {
33393fd3
 	struct mi_root* rpl_tree;
ba07eb39
 
33393fd3
 	rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 	if (rpl_tree==NULL)
ba07eb39
 		return 0;
 
33393fd3
 	if( ds_print_mi_list(&rpl_tree->node)< 0 )
ba07eb39
 	{
789504a6
 		LM_ERR("failed to add node\n");
33393fd3
 		free_mi_tree(rpl_tree);
ba07eb39
 		return 0;
 	}
 
33393fd3
 	return rpl_tree;
ba07eb39
 }
 
101e9af4
 #define MI_ERR_RELOAD 			"ERROR Reloading data"
 #define MI_ERR_RELOAD_LEN 		(sizeof(MI_ERR_RELOAD)-1)
 #define MI_NOT_SUPPORTED		"DB mode not configured"
 #define MI_NOT_SUPPORTED_LEN 	(sizeof(MI_NOT_SUPPORTED)-1)
9cdc3e70
 #define MI_ERR_DSLOAD			"No reload support for call load dispatching"
 #define MI_ERR_DSLOAD_LEN		(sizeof(MI_ERR_DSLOAD)-1)
101e9af4
 
e2cf6343
 static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param)
101e9af4
 {
9cdc3e70
 	if(dstid_avp_name.n!=0) {
72c052a9
 		LM_ERR("No reload support when call load dispatching is enabled."
 				" Do not set dstid_avp param if you do not use alg 10.\n");
9cdc3e70
 		return init_mi_tree(500, MI_ERR_DSLOAD, MI_ERR_DSLOAD_LEN);
 	}
 
e2cf6343
 	if(!ds_db_url.s) {
081630ba
 		if (ds_load_list(dslistfile)!=0)
 			return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
 	} else {
 		if(ds_load_db()<0)
 			return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
 	}
101e9af4
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 }
 
081b5d4e
 
 static int w_ds_is_from_list0(struct sip_msg *msg, char *str1, char *str2)
 {
 	return ds_is_from_list(msg, -1);
 }
 
 
 static int w_ds_is_from_list1(struct sip_msg *msg, char *set, char *str2)
 {
cfc67d90
 	return ds_is_from_list(msg, (int)(long)set);
081b5d4e
 }
ec903da3
 
 static int ds_parse_reply_codes() {
 	param_t* params_list = NULL;
 	param_t *pit=NULL;
 	int list_size = 0;
 	int i = 0;
 	int pos = 0;
 	int code = 0;
 	str input = {0, 0};
 	int* ds_ping_reply_codes_new = NULL;
 	int* ds_ping_reply_codes_old = NULL;
 
 	/* Validate String: */
 	if (cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str).s == 0 
 		|| cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str).len<=0)
 		return 0;
 
 	/* parse_params will modify the string pointer of .s, so we need to make a copy. */
 	input.s = cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str).s;
 	input.len = cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str).len;
 	
 	/* Parse the parameters: */
 	if (parse_params(&input, CLASS_ANY, 0, &params_list)<0)
 		return -1;
 
 	/* Get the number of entries in the list */
 	for (pit = params_list; pit; pit=pit->next)
 	{
 		if (pit->name.len==4
 				&& strncasecmp(pit->name.s, "code", 4)==0) {
 			str2sint(&pit->body, &code);
 			if ((code >= 100) && (code < 700))
 				list_size += 1;
 		} else if (pit->name.len==5
 				&& strncasecmp(pit->name.s, "class", 5)==0) {
 			str2sint(&pit->body, &code);
 			if ((code >= 1) && (code < 7))
 				list_size += 100;
 		}
 	}
3f367560
 	LM_DBG("Should be %d Destinations.\n", list_size);
ec903da3
 
 	if (list_size > 0) {
 		/* Allocate Memory for the new list: */
 		ds_ping_reply_codes_new = (int*)shm_malloc(list_size * sizeof(int));
 		if(ds_ping_reply_codes_new== NULL)
 		{
 			free_params(params_list);
 			LM_ERR("no more memory\n");
 			return -1;
 		}
 	 
 		/* Now create the list of valid reply-codes: */
 		for (pit = params_list; pit; pit=pit->next)
 		{
 			if (pit->name.len==4
 					&& strncasecmp(pit->name.s, "code", 4)==0) {
 				str2sint(&pit->body, &code);
 				if ((code >= 100) && (code < 700))
 					ds_ping_reply_codes_new[pos++] = code;
 			} else if (pit->name.len==5
 					&& strncasecmp(pit->name.s, "class", 5)==0) {
 				str2sint(&pit->body, &code);
 				if ((code >= 1) && (code < 7)) {
 					/* Add every code from this class, e.g. 100 to 199 */
 					for (i = (code*100); i <= ((code*100)+99); i++) 
 						ds_ping_reply_codes_new[pos++] = i;
 				}
 			}
 		}
 	} else {
 		ds_ping_reply_codes_new = 0;
 	}
 	free_params(params_list);
 
 	/* More reply-codes? Change Pointer and then set number of codes. */
 	if (list_size > *ds_ping_reply_codes_cnt) {
 		// Copy Pointer
 		ds_ping_reply_codes_old = *ds_ping_reply_codes;
 		*ds_ping_reply_codes = ds_ping_reply_codes_new;
 		// Done: Set new Number of entries:
 		*ds_ping_reply_codes_cnt = list_size;
 		// Free the old memory area:
 		if(ds_ping_reply_codes_old)
 			shm_free(ds_ping_reply_codes_old);	
 	/* Less or equal? Set the number of codes first. */
 	} else {
 		// Done:
 		*ds_ping_reply_codes_cnt = list_size;
 		// Copy Pointer
 		ds_ping_reply_codes_old = *ds_ping_reply_codes;
 		*ds_ping_reply_codes = ds_ping_reply_codes_new;
 		// Free the old memory area:
 		if(ds_ping_reply_codes_old)
 			shm_free(ds_ping_reply_codes_old);	
 	}
 	/* Print the list as INFO: */
 	for (i =0; i< *ds_ping_reply_codes_cnt; i++)
 	{
3f367560
 		LM_DBG("Dispatcher: Now accepting Reply-Code %d (%d/%d) as valid\n",
ec903da3
 			(*ds_ping_reply_codes)[i], (i+1), *ds_ping_reply_codes_cnt);
 	}
 	return 0;
 }
 
 int ds_ping_check_rplcode(int code)
 {
 	int i;
 	
 	for (i =0; i< *ds_ping_reply_codes_cnt; i++)
 	{
 		if((*ds_ping_reply_codes)[i] == code)
 			return 1;
 	}
 
 	return 0;
 }
 
 void ds_ping_reply_codes_update(str* gname, str* name){
 	ds_parse_reply_codes();
 }