소스 검색

Merge branch 'master' into treimann/acc-cdr

* master:
  modules_k/dialog: In docs, fix indention of example to "detect_spirals".
  modules/app_lua, modules/sdpops: Exported sdpops:sdp_with_media() to app_lua
  modules_k/dispatcher: Added new feature that enables routes to be run when destinations fail/recover
  tmx: fixed mix-up between $T(id_index) and $T(id_label)
Timo Reimann 14 년 전
부모
커밋
94338392c1

+ 1 - 0
modules/app_lua/Makefile

@@ -46,5 +46,6 @@ DEFS+=-DOPENSER_MOD_INTERFACE
 
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+LIBS+=-lm
 
 include ../../Makefile.modules

+ 54 - 5
modules/app_lua/app_lua_exp.c

@@ -41,6 +41,7 @@
 #include "../../modules_k/registrar/api.h"
 #include "../../modules_k/dispatcher/api.h"
 #include "../../modules/xhttp/api.h"
+#include "../../modules/sdpops/api.h"
 
 #include "app_lua_api.h"
 
@@ -54,6 +55,7 @@
 #define SR_LUA_EXP_MOD_REGISTRAR  (1<<7)
 #define SR_LUA_EXP_MOD_DISPATCHER (1<<8)
 #define SR_LUA_EXP_MOD_XHTTP      (1<<9)
+#define SR_LUA_EXP_MOD_SDPOPS     (1<<10)
 
 /**
  *
@@ -111,6 +113,11 @@ static tm_xapi_t _lua_xtmb;
  */
 static xhttp_api_t _lua_xhttpb;
 
+/**
+ * sdpops
+ */
+static sdpops_api_t _lua_sdpopsb;
+
 /**
  *
  */
@@ -1224,6 +1231,17 @@ static int lua_sr_dispatcher_is_from(lua_State *L)
 	return app_lua_return_int(L, ret);
 }
 
+/**
+ *
+ */
+static const luaL_reg _sr_dispatcher_Map [] = {
+	{"select",      lua_sr_dispatcher_select},
+	{"next",        lua_sr_dispatcher_next},
+	{"mark",        lua_sr_dispatcher_mark},
+	{"is_from",     lua_sr_dispatcher_is_from},
+	{NULL, NULL}
+};
+
 
 /**
  *
@@ -1276,18 +1294,34 @@ static const luaL_reg _sr_xhttp_Map [] = {
 	{NULL, NULL}
 };
 
+/**
+ *
+ */
+static int lua_sr_sdpops_with_media(lua_State *L)
+{
+	int ret;
+	str media;
+	sr_lua_env_t *env_L;
+
+	env_L = sr_lua_env_get();
+
+	media.s = (char*)lua_tostring(L, -1);
+	media.len = strlen(media.s);
+
+	ret = _lua_sdpopsb.sdp_with_media(env_L->msg, &media);
+
+	return app_lua_return_int(L, ret);
+}
 
 /**
  *
  */
-static const luaL_reg _sr_dispatcher_Map [] = {
-	{"select",      lua_sr_dispatcher_select},
-	{"next",        lua_sr_dispatcher_next},
-	{"mark",        lua_sr_dispatcher_mark},
-	{"is_from",     lua_sr_dispatcher_is_from},
+static const luaL_reg _sr_sdpops_Map [] = {
+	{"sdp_with_media",       lua_sr_sdpops_with_media},
 	{NULL, NULL}
 };
 
+
 /**
  *
  */
@@ -1399,6 +1433,16 @@ int lua_sr_exp_init_mod(void)
 		}
 		LM_DBG("loaded xhttp api\n");
 	}
+	if(_sr_lua_exp_reg_mods&SR_LUA_EXP_MOD_SDPOPS)
+	{
+		/* bind the SDPOPS API */
+		if (sdpops_load_api(&_lua_sdpopsb) < 0)
+		{
+			LM_ERR("cannot bind to SDPOPS API\n");
+			return -1;
+		}
+		LM_DBG("loaded sdpops api\n");
+	}
 	return 0;
 }
 
@@ -1442,6 +1486,9 @@ int lua_sr_exp_register_mod(char *mname)
 	} else 	if(len==5 && strcmp(mname, "xhttp")==0) {
 		_sr_lua_exp_reg_mods |= SR_LUA_EXP_MOD_XHTTP;
 		return 0;
+	} else 	if(len==6 && strcmp(mname, "sdpops")==0) {
+		_sr_lua_exp_reg_mods |= SR_LUA_EXP_MOD_SDPOPS;
+		return 0;
 	}
 
 	return -1;
@@ -1472,5 +1519,7 @@ void lua_sr_exp_openlibs(lua_State *L)
 		luaL_openlib(L, "sr.dispatcher", _sr_dispatcher_Map,  0);
 	if(_sr_lua_exp_reg_mods&SR_LUA_EXP_MOD_XHTTP)
 		luaL_openlib(L, "sr.xhttp",      _sr_xhttp_Map,       0);
+	if(_sr_lua_exp_reg_mods&SR_LUA_EXP_MOD_SDPOPS)
+		luaL_openlib(L, "sr.sdpops",     _sr_sdpops_Map,      0);
 }
 

+ 5 - 1
modules/app_lua/app_lua_sr.c

@@ -91,7 +91,11 @@ static int lua_sr_log (lua_State *L)
 		{
 			LM_ERR("%s", txt);
 		} else {
-			if(strcasecmp(level, "warn")==0) {
+			if(strcasecmp(level, "dbg")==0) {
+				LM_DBG("%s", txt);
+			} else if(strcasecmp(level, "info")==0) {
+				LM_INFO("%s", txt);
+			} else if(strcasecmp(level, "warn")==0) {
 				LM_WARN("%s", txt);
 			} else if(strcasecmp(level, "crit")==0) {
 				LM_CRIT("%s", txt);

+ 26 - 0
modules/sdpops/api.h

@@ -0,0 +1,26 @@
+#ifndef SDPOPS_API_H
+#define SDPOPS_API_H
+#include "../../str.h"
+
+typedef int (*sdp_with_media_t)(struct sip_msg*, str*);
+
+typedef struct sdpops_binds {
+	sdp_with_media_t sdp_with_media;
+} sdpops_api_t;
+
+typedef int (*bind_sdpops_f)(sdpops_api_t*);
+
+int bind_sdpops(struct sdpops_binds*);
+
+inline static int sdpops_load_api(sdpops_api_t *sob)
+{
+	bind_sdpops_f bind_sdpops_exports;
+	if (!(bind_sdpops_exports = (bind_sdpops_f)find_export("bind_sdpops", 0, 0)))
+	{
+		LM_ERR("Failed to import bind_sdpops\n");
+		return -1;
+	}
+	return bind_sdpops_exports(sob);
+}
+
+#endif /*SDPOPS_API_H*/

+ 14 - 2
modules/sdpops/sdpops_mod.c

@@ -34,6 +34,7 @@
 #include "../../trim.h"
 #include "../../data_lump.h"
 
+#include "api.h"
 #include "sdpops_data.h"
 
 MODULE_VERSION
@@ -54,7 +55,9 @@ static cmd_export_t cmds[] = {
 		1, fixup_spve_null,  0, ANY_ROUTE},
 	{"sdp_print",                  (cmd_function)w_sdp_print,
 		1, fixup_igp_null,  0, ANY_ROUTE},
-	{0, 0, 0, 0, 0}
+	{"bind_sdpops",                (cmd_function)bind_sdpops,
+		0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0}
 };
 
 static pv_export_t mod_pvs[] = {
@@ -360,7 +363,7 @@ static int sdp_with_media(sip_msg_t *msg, str *media)
 		return -1;
 	}
 
-	LM_ERR("attempting to search for media type: [%.*s]\n",
+	LM_DBG("attempting to search for media type: [%.*s]\n",
 			media->len, media->s);
 
 	sdp = (sdp_info_t*)msg->body;
@@ -437,3 +440,12 @@ static int w_sdp_print(sip_msg_t* msg, char* level, char *bar)
 	print_sdp(sdp, llevel);
 	return 1;
 }
+
+int bind_sdpops(struct sdpops_binds *sob){
+	if (sob == NULL) {
+		LM_WARN("bind_sdpops: Cannot load sdpops API into a NULL pointer\n");
+		return -1;
+	}
+	sob->sdp_with_media = sdp_with_media;
+	return 0;
+}

+ 3 - 3
modules_k/dialog/doc/dialog_admin.xml

@@ -341,9 +341,9 @@ modparam("dialog", "dlg_match_mode", 1)
 		<example>
 			<title>Set <varname>detect_spirals</varname> parameter</title>
 			<programlisting format="linespecific">
-				...
-				modparam("dialog", "detect_spirals", 1)
-				...
+...
+modparam("dialog", "detect_spirals", 1)
+...
 			</programlisting>
 		</example>
 	</section>

+ 82 - 32
modules_k/dispatcher/README

@@ -62,6 +62,8 @@ Carsten Bock
               3.25. ds_hash_expire (int)
               3.26. ds_hash_initexpire (int)
               3.27. ds_hash_check_interval (int)
+              3.28. ds_dst_unavailable_route (string)
+              3.29. ds_dst_available_route (string)
 
         4. Exported Functions
 
@@ -125,10 +127,12 @@ Carsten Bock
    1.26. Set the “ds_hash_expire” parameter
    1.27. Set the “ds_hash_initexpire” parameter
    1.28. Set the “ds_hash_check_interval” parameter
-   1.29. ds_select_dst usage
-   1.30. ds_load_unset usage
-   1.31. dispatcher list file
-   1.32. Kamailio config script - sample dispatcher usage
+   1.29. Set the “ds_dst_unavailable_route” parameter
+   1.30. Set the “ds_dst_available_route” parameter
+   1.31. ds_select_dst usage
+   1.32. ds_load_unset usage
+   1.33. dispatcher list file
+   1.34. Kamailio config script - sample dispatcher usage
 
 Chapter 1. Admin Guide
 
@@ -169,6 +173,8 @@ Chapter 1. Admin Guide
         3.25. ds_hash_expire (int)
         3.26. ds_hash_initexpire (int)
         3.27. ds_hash_check_interval (int)
+        3.28. ds_dst_unavailable_route (string)
+        3.29. ds_dst_available_route (string)
 
    4. Exported Functions
 
@@ -263,6 +269,8 @@ Chapter 1. Admin Guide
    3.25. ds_hash_expire (int)
    3.26. ds_hash_initexpire (int)
    3.27. ds_hash_check_interval (int)
+   3.28. ds_dst_unavailable_route (string)
+   3.29. ds_dst_available_route (string)
 
 3.1. list_file (string)
 
@@ -646,6 +654,48 @@ Note
  modparam("dispatcher", "ds_hash_check_interval", 60)
  ...
 
+3.28. ds_dst_unavailable_route (string)
+
+   Optional parameter that specifies a route to run when a destination is
+   marked as PROBING. Destinations are marked PROBING after threshhold
+   number of OPTIONS ping failures or calls to ds_mark_dst("p").
+
+   This setting can be used to log desination failures. It may be used (in
+   conjunction with other modules like exec) to run external commands to
+   update NMC equipment, generate SNMP traps, and so on.
+
+   Default value is “null”.
+
+   Example 1.29. Set the “ds_dst_unavailable_route” parameter
+ ...
+ modparam("dispatcher", "ds_dst_unavailable_route", "DST_FAILED")
+ ...
+ route[DST_FAILED] {
+     xlog("L_ERR", "Destination failed: $rm $ru ($du)\n");
+ }
+ ...
+
+3.29. ds_dst_available_route (string)
+
+   Optional parameter that specifies a route to run when a destination
+   leaves the PROBING state. Destinations leave the PROBING state after an
+   OPTIONS ping succeeds.
+
+   This setting can be used to log desination recoveries. It may be used
+   (in conjunction with other modules like exec) to run external commands
+   to update NMC equipment, generate SNMP traps, and so on.
+
+   Default value is “null”.
+
+   Example 1.30. Set the “ds_dst_available_route” parameter
+ ...
+ modparam("dispatcher", "ds_dst_available_route", "DST_RESTORED")
+ ...
+ route[DST_RESTORED] {
+     xlog("L_ERR", "Destination restored: $rm $ru ($du)\n");
+ }
+ ...
+
 4. Exported Functions
 
    4.1. ds_select_dst(set, alg)
@@ -708,7 +758,7 @@ Note
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.29. ds_select_dst usage
+   Example 1.31. ds_select_dst usage
 ...
 ds_select_dst("1", "0");
 ...
@@ -805,7 +855,7 @@ ds_select_dst("1", "$var(a)");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE and ONREPLY_ROUTE.
 
-   Example 1.30. ds_load_unset usage
+   Example 1.32. ds_load_unset usage
 ...
 route {
     ...
@@ -969,7 +1019,7 @@ setid(int) destination(sip uri) flags(int,opt) priority(int,opt) attrs(str,opt)
    For database, each element of a line resides in a different column.
    Next is a dispatcher.list file example:
 
-   Example 1.31. dispatcher list file
+   Example 1.33. dispatcher list file
 ...
 # $Id$
 # dispatcher destination sets
@@ -994,7 +1044,7 @@ r,opt)
 
    Next picture displays a sample usage of dispatcher.
 
-   Example 1.32. Kamailio config script - sample dispatcher usage
+   Example 1.34. Kamailio config script - sample dispatcher usage
 ...
 # $Id$
 # sample config file for dispatcher module
@@ -1080,46 +1130,46 @@ Chapter 2. Frequently Asked Questions
 
    2.1.
 
-       Does dispatcher provide a fair distribution?
+   Does dispatcher provide a fair distribution?
 
-       There is no guarantee of that. You should do some measurements to
-       decide what distribution algorithm fits better in your environment.
+   There is no guarantee of that. You should do some measurements to
+   decide what distribution algorithm fits better in your environment.
 
    2.2.
 
-       Is dispatcher dialog stateful?
+   Is dispatcher dialog stateful?
 
-       No. Dispatcher is stateless, although some distribution algorithms are
-       designed to select same destination for subsequent requests of the same
-       dialog (e.g., hashing the call-id).
+   No. Dispatcher is stateless, although some distribution algorithms are
+   designed to select same destination for subsequent requests of the same
+   dialog (e.g., hashing the call-id).
 
    2.3.
 
-       Where can I find more about Kamailio?
+   Where can I find more about Kamailio?
 
-       Take a look at http://www.kamailio.org/.
+   Take a look at http://www.kamailio.org/.
 
    2.4.
 
-       Where can I post a question about this module?
+   Where can I post a question about this module?
 
-       First at all check if your question was already answered on one of our
-       mailing lists:
-         * User Mailing List -
-           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
-         * Developer Mailing List -
-           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
+   First at all check if your question was already answered on one of our
+   mailing lists:
+     * User Mailing List -
+       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
+     * Developer Mailing List -
+       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
 
-       E-mails regarding any stable version should be sent to
-       <[email protected]> and e-mail regarding development
-       versions or CVS snapshots should be send to
-       <[email protected]>.
+   E-mails regarding any stable version should be sent to
+   <[email protected]> and e-mail regarding development
+   versions or CVS snapshots should be send to
+   <[email protected]>.
 
-       If you want to keep the mail private, send it to
-       <[email protected]>.
+   If you want to keep the mail private, send it to
+   <[email protected]>.
 
    2.5.
 
-       How can I report a bug?
+   How can I report a bug?
 
-       Please follow the guidelines provided at: http://sip-router.org/tracker
+   Please follow the guidelines provided at: http://sip-router.org/tracker

+ 56 - 8
modules_k/dispatcher/dispatch.c

@@ -69,6 +69,7 @@
 #include "../../lib/srdb1/db.h"
 #include "../../lib/srdb1/db_res.h"
 #include "../../str.h"
+#include "../../script_cb.h"
 
 #include "ds_ht.h"
 #include "api.h"
@@ -98,9 +99,13 @@ int *ds_list_nr = NULL;
 int *crt_idx    = NULL;
 int *next_idx   = NULL;
 
+int ds_tmp_msg_no = 1;
+
 #define _ds_list 	(ds_lists[*crt_idx])
 #define _ds_list_nr (*ds_list_nr)
 
+static void ds_run_route(struct sip_msg *msg, int route);
+
 void destroy_list(int);
 
 /**
@@ -1964,15 +1969,15 @@ int ds_mark_dst(struct sip_msg *msg, int mode)
 	
 	if(mode==1) {
 		ret = ds_set_state(group, &avp_value.s,
-				DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0);
+				DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0, msg);
 	} else if(mode==2) {
-		ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1);
+		ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1, msg);
 		if (ret == 0) ret = ds_set_state(group, &avp_value.s,
-				DS_INACTIVE_DST, 0);
+				DS_INACTIVE_DST, 0, msg);
 	} else {
-		ret = ds_set_state(group, &avp_value.s, DS_INACTIVE_DST, 1);
+		ret = ds_set_state(group, &avp_value.s, DS_INACTIVE_DST, 1, msg);
 		if (ret == 0) ret = ds_set_state(group, &avp_value.s,
-				DS_PROBING_DST, 0);
+				DS_PROBING_DST, 0, msg);
 	}
 	
 	LM_DBG("mode [%d] grp [%d] dst [%.*s]\n", mode, group, avp_value.s.len,
@@ -1984,7 +1989,7 @@ int ds_mark_dst(struct sip_msg *msg, int mode)
 /**
  *
  */
-int ds_set_state(int group, str *address, int state, int type)
+int ds_set_state(int group, str *address, int state, int type, struct sip_msg *msg)
 {
 	int i=0;
 	ds_set_t *idx = NULL;
@@ -2044,9 +2049,20 @@ int ds_set_state(int group, str *address, int state, int type)
 			}
 			
 			if(type)
+			{
+				if (state & DS_PROBING_DST && !(idx->dlist[i].flags & state))
+					ds_run_route(msg, ds_dst_unav_route);
+
 				idx->dlist[i].flags |= state;
+			}
 			else
+			{
+				if (state & DS_PROBING_DST && idx->dlist[i].flags & state)
+					ds_run_route(msg, ds_dst_av_route);
+
 				idx->dlist[i].flags &= ~state;
+
+			}
 				
 			return 0;
 		}
@@ -2056,6 +2072,32 @@ int ds_set_state(int group, str *address, int state, int type)
 	return -1;
 }
 
+static void ds_run_route(struct sip_msg *msg, int route)
+{
+	int backup_route_type = get_route_type();
+
+	LM_DBG("ds_run_route\n");
+
+	if (route == -1)
+		return;
+
+	if (exec_pre_script_cb(msg, LOCAL_CB_TYPE) == 0)
+	{
+		LM_ERR("exec_pre_script_cb failed\n");
+		goto error;
+	}
+	set_route_type(LOCAL_ROUTE);
+	if (run_top_route(main_rt.rlist[route], msg, 0) < 0)
+	{
+		LM_ERR("run_top_route failed\n");
+		goto error;
+	}
+	exec_post_script_cb(msg, LOCAL_CB_TYPE);
+
+error:
+	set_route_type(backup_route_type);
+}
+
 /**
  *
  */
@@ -2282,10 +2324,13 @@ static void ds_options_callback( struct cell *t, int type,
 	 * We accept both a "200 OK" or the configured reply as a valid response */
 	if ((ps->code == 200) || ds_ping_check_rplcode(ps->code))
 	{
+		ds_tmp_msg.new_uri = uri;
+		ds_tmp_msg.id = ds_tmp_msg_no++;
+	
 		/* Set the according entry back to "Active":
 		 *  remove the Probing/Inactive Flag and reset the failure counter. */
 		if (ds_set_state(group, &uri,
-					DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 2) != 0)
+					DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 2, &ds_tmp_msg) != 0)
 		{
 			LM_ERR("Setting the state failed (%.*s, group %d)\n", uri.len,
 					uri.s, group);
@@ -2293,7 +2338,10 @@ static void ds_options_callback( struct cell *t, int type,
 	}
 	if(ds_probing_mode==1 && ps->code == 408)
 	{
-		if (ds_set_state(group, &uri, DS_PROBING_DST, 1) != 0)
+
+		ds_tmp_msg.new_uri = uri;
+		ds_tmp_msg.id = ds_tmp_msg_no++;
+		if (ds_set_state(group, &uri, DS_PROBING_DST, 1, &ds_tmp_msg) != 0)
 		{
 			LM_ERR("Setting the probing state failed (%.*s, group %d)\n",
 					uri.len, uri.s, group);

+ 4 - 1
modules_k/dispatcher/dispatch.h

@@ -88,6 +88,9 @@ extern str ds_ping_from;
 extern int probing_threshhold; /*!< number of failed requests,
 						before a destination is taken into probing */ 
 extern int ds_probing_mode;
+extern struct sip_msg ds_tmp_msg;
+extern int ds_dst_unav_route;
+extern int ds_dst_av_route;
 
 int init_data(void);
 int init_ds_db(void);
@@ -98,7 +101,7 @@ int ds_load_db(void);
 int ds_destroy_list(void);
 int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode);
 int ds_next_dst(struct sip_msg *msg, int mode);
-int ds_set_state(int group, str *address, int state, int type);
+int ds_set_state(int group, str *address, int state, int type, struct sip_msg *msg);
 int ds_reinit_state(int group, str *address, int state);
 int ds_mark_dst(struct sip_msg *msg, int mode);
 int ds_print_list(FILE *fout);

+ 94 - 0
modules_k/dispatcher/dispatcher.c

@@ -119,6 +119,15 @@ int ds_hash_size = 0;
 int ds_hash_expire = 7200;
 int ds_hash_initexpire = 7200;
 int ds_hash_check_interval = 30;
+char *ds_dst_unavailable_route = NULL;
+int ds_dst_unav_route = -1;
+char *ds_dst_available_route = NULL;
+int ds_dst_av_route = -1;
+
+#define DS_TMP_MSG "OPTIONS sip:[email protected] SIP/2.0\r\nVia: SIP/2.0/UDP 127.0.0.1\r\nFrom: <[email protected]>;tag=123\r\nTo: <[email protected]>\r\nCall-ID: 123\r\nCSeq: 1 OPTIONS\r\nContent-Length: 0\r\n\r\n"
+#define DS_TMP_MSG_LEN (sizeof(DS_TMP_MSG)-1)
+struct sip_msg ds_tmp_msg;
+char ds_tmp_msg_buf[DS_TMP_MSG_LEN + 1];
 
 /* tm */
 struct tm_binds tmb;
@@ -219,6 +228,8 @@ static param_export_t params[]={
 	{"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},
+	{"ds_dst_unavailable_route", STR_PARAM, &ds_dst_unavailable_route},
+	{"ds_dst_available_route", STR_PARAM, &ds_dst_available_route},
 	{0,0,0}
 };
 
@@ -470,6 +481,8 @@ static int mod_init(void)
 	/* Only, if the Probing-Timer is enabled the TM-API needs to be loaded: */
 	if (ds_ping_interval > 0)
 	{
+		int c;
+
 		/*****************************************************
 		 * TM-Bindings
 	  	 *****************************************************/
@@ -482,6 +495,87 @@ static int mod_init(void)
 		 * Register the PING-Timer
 		 *****************************************************/
 		register_timer(ds_check_timer, NULL, ds_ping_interval);
+
+		/* Build a temporary message for later use */
+		memcpy(ds_tmp_msg_buf, DS_TMP_MSG, DS_TMP_MSG_LEN);
+		ds_tmp_msg_buf[DS_TMP_MSG_LEN] = '\0';
+		memset(&ds_tmp_msg, 0, sizeof(struct sip_msg));
+		ds_tmp_msg.buf = ds_tmp_msg_buf;
+		ds_tmp_msg.len = DS_TMP_MSG_LEN;
+		ds_tmp_msg.set_global_address = default_global_address;
+		ds_tmp_msg.set_global_port = default_global_port;
+		if (parse_msg(ds_tmp_msg.buf, ds_tmp_msg.len, &ds_tmp_msg) != 0)
+		{
+			LM_ERR("parse_msg failed\n");
+			return -1;
+		}
+		ds_tmp_msg.parsed_orig_ruri = ds_tmp_msg.parsed_uri;
+		ds_tmp_msg.parsed_orig_ruri_ok = 0;
+
+		if (ds_dst_unavailable_route != NULL)
+		{
+			int length = strlen(ds_dst_unavailable_route);
+			c = ds_dst_unavailable_route[length];
+			ds_dst_unavailable_route[length] = '\0';
+			ds_dst_unav_route = route_get(&main_rt, ds_dst_unavailable_route);
+			ds_dst_unavailable_route[length] = c;
+
+			if (ds_dst_unav_route == -1)
+			{
+				LM_ERR("failed to determine destination unavailable route\n");
+				return -1;
+			}
+
+			if (main_rt.rlist[ds_dst_unav_route] == 0)
+			{
+				LM_WARN("route[%s] is empty\n", ds_dst_unavailable_route);
+				ds_dst_unav_route = -1;
+			}
+			else
+			{
+				LM_INFO("destination unavailable route: route[%s] (%d)\n",
+					ds_dst_unavailable_route, ds_dst_unav_route);
+			}
+
+		}
+		else
+		{
+			LM_INFO("No destination unavailable route configured\n");
+			ds_dst_unav_route = -1;
+		}
+
+		if (ds_dst_available_route != NULL)
+		{
+			int length = strlen(ds_dst_available_route);
+			c = ds_dst_available_route[length];
+			ds_dst_available_route[length] = '\0';
+			ds_dst_av_route = route_get(&main_rt, ds_dst_available_route);
+			ds_dst_available_route[length] = c;
+
+			if (ds_dst_av_route == -1)
+			{
+				LM_ERR("failed to determine destination available route\n");
+				return -1;
+			}
+
+			if (main_rt.rlist[ds_dst_av_route] == 0)
+			{
+				LM_WARN("route[%s] is empty\n", ds_dst_available_route);
+				ds_dst_av_route = -1;
+			}
+			else
+			{
+				LM_INFO("destination available route: route[%s] (%d)\n",
+					ds_dst_available_route, ds_dst_av_route);
+			}
+
+		}
+		else
+		{
+			LM_INFO("No destination available route configured\n");
+			ds_dst_av_route = -1;
+		}
+
 	}
 
 	return 0;

+ 63 - 1
modules_k/dispatcher/doc/dispatcher_admin.xml

@@ -688,7 +688,69 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section>
-
+ 	<section>
+ 		<title><varname>ds_dst_unavailable_route</varname> (string)</title>
+ 		<para>
+		Optional parameter that specifies a route to run when a destination
+		is marked as PROBING.  Destinations are marked PROBING after threshhold
+                number of OPTIONS ping failures or calls to
+		<emphasis>ds_mark_dst("p")</emphasis>.
+ 		</para>
+		<para>
+		This setting can be used to log desination failures.  It may be used
+		(in conjunction with other modules like <emphasis>exec</emphasis>) to
+		run external commands to update NMC equipment, generate SNMP traps,
+		and so on.
+		</para>
+ 		<para>
+ 		<emphasis>
+ 			Default value is <quote>null</quote>.
+ 		</emphasis>
+ 		</para>
+ 		<example>
+ 		<title>Set the <quote>ds_dst_unavailable_route</quote> parameter</title>
+ <programlisting format="linespecific">
+ ...
+ modparam("dispatcher", "ds_dst_unavailable_route", "DST_FAILED")
+ ...
+ route[DST_FAILED] {
+     xlog("L_ERR", "Destination failed: $rm $ru ($du)\n");
+ }
+ ...
+ </programlisting>
+ 		</example>
+	</section>
+ 	<section>
+ 		<title><varname>ds_dst_available_route</varname> (string)</title>
+ 		<para>
+		Optional parameter that specifies a route to run when a destination
+		leaves the PROBING state.  Destinations leave the PROBING state after
+                an OPTIONS ping succeeds.
+ 		</para>
+		<para>
+		This setting can be used to log desination recoveries.  It may be used
+		(in conjunction with other modules like <emphasis>exec</emphasis>) to
+		run external commands to update NMC equipment, generate SNMP traps,
+		and so on.
+		</para>
+ 		<para>
+ 		<emphasis>
+ 			Default value is <quote>null</quote>.
+ 		</emphasis>
+ 		</para>
+ 		<example>
+ 		<title>Set the <quote>ds_dst_available_route</quote> parameter</title>
+ <programlisting format="linespecific">
+ ...
+ modparam("dispatcher", "ds_dst_available_route", "DST_RESTORED")
+ ...
+ route[DST_RESTORED] {
+     xlog("L_ERR", "Destination restored: $rm $ru ($du)\n");
+ }
+ ...
+ </programlisting>
+ 		</example>
+	</section>
 	</section>
 
 	<section>

+ 2 - 2
modules_k/tmx/t_var.c

@@ -507,8 +507,8 @@ int pv_get_t(struct sip_msg *msg,  pv_param_t *param,
 	switch(param->pvn.u.isname.name.n)
 	{
 		case 1:
-			return pv_get_uintval(msg, param, res, t->label);
-		default:
 			return pv_get_uintval(msg, param, res, t->hash_index);
+		default:
+			return pv_get_uintval(msg, param, res, t->label);
 	}
 }