Kaynağa Gözat

Merge pull request #206 from smititelu/kamailio-17

rtpengine: changes for mi_fifo_commands
Stefan Mititelu 10 yıl önce
ebeveyn
işleme
e1f2a45fbe
2 değiştirilmiş dosya ile 549 ekleme ve 118 silme
  1. 64 15
      modules/rtpengine/doc/rtpengine_admin.xml
  2. 485 103
      modules/rtpengine/rtpengine.c

+ 64 - 15
modules/rtpengine/doc/rtpengine_admin.xml

@@ -837,21 +837,30 @@ start_recording();
 	<section>
 		<title><acronym>MI</acronym> Commands</title>
 		<section id="rtpengine.m.nh_enable_rtpp">
-			<title><function moreinfo="none">nh_enable_rtpp</function></title>
+			<title><function moreinfo="none">nh_enable_rtpp proxy_url/all 0/1</function></title>
 			<para>
-			Enables a &rtp; proxy if parameter value is greater than 0.
-			Disables it if a zero value is given.
+			Enables a &rtp; proxy if the second parameter value is greater than 0. Disables it if a zero value is given.
+			The first parameter is either a specific &rtp; proxy url (exactly as defined in
+			the config file) or the keyword <emphasis>all</emphasis>.
+			The second parameter value must be a number in decimal.
 			</para>
 			<para>
-			The first parameter is the &rtp; proxy url (exactly as defined in
-			the config file).
+            When try to enable the &rtp; proxy, an application ping command is sent to it.
+            If it fails, the proxy is not enabled.
+            Displays <emphasis>success</emphasis> or <emphasis>fail</emphasis> when try to enable/disable.
 			</para>
 			<para>
-			The second parameter value must be a number in decimal.
+			NOTE: If a &rtp; proxy is defined multiple times (in the same or diferent sets), all of its instances will be enabled/disabled.
+			</para>
+			<para>
+			NOTE: If a &rtp; proxy is in the disabled permanent state and one tries to enable it, even if the ping fails,
+            it is moved to a disabled temporary state and a recheck_ticks are given to it.
+            While the recheck_ticks are grater than 0, the proxy is considered disabled temporary, and it is not taken into consideration for sending data.
+            When the recheck_ticks are 0, the proxy is retested <emphasis>when trying to send data</emphasis>(not automatically retested), and data can be send to it on success.
 			</para>
 			<para>
-			NOTE: if a &rtp; proxy is defined multiple times (in the same or
-			diferente sete), all of its instances will be enables/disabled.
+			NOTE: When specify the IPv6 &rtp; proxy url one must prefix it with <emphasis>::</emphasis>
+            to escape the :: from the IPv6 address. See the example below.
 			</para>
 			<example>
 			<title>
@@ -859,28 +868,68 @@ start_recording();
 			<programlisting format="linespecific">
 ...
 $ &ctltool; fifo nh_enable_rtpp udp:192.168.2.133:8081 0
+$ &ctltool; fifo nh_enable_rtpp ::udp6:fe80::9a90:96ff:fea8:fd99:9999 1
+$ &ctltool; fifo nh_enable_rtpp all 1
 ...
 			</programlisting>
 			</example>
 		</section>
 
-			<section id="rtpengine.m.nh_show_rtpp">
-			<title><function moreinfo="none">nh_show_rtpp</function></title>
+	    <section id="rtpengine.m.nh_show_rtpp">
+			<title><function moreinfo="none">nh_show_rtpp proxy_url/all</function></title>
 			<para>
 			Displays all the &rtp; proxies and their information: set and
-			status (disabled or not, weight and recheck_ticks). If a RTP proxy has been disabled by a mi command
-			a "(permanent)" quote will appear when printing the disabled status. This is to differentiate from
-			a temporary disable due to the proxy being not found responsive by kamailio.
+			status (disabled or not, weight and recheck_ticks). If a &rtp; proxy has been disabled by
+            nh_enable_rtpp mi command a "(permanent)" quote will appear when printing the disabled status.
+            This is to differentiate from a temporary disable due to the proxy being not found responsive
+            by kamailio. In addition, when disabled permanent, recheck_ticks have no meaning and "N\A"
+            is printed instead of the value.
+			</para>
+			<para>
+            It takes either a specific &rtp; proxy url (exactly as defined in
+			the config file) or the keyword <emphasis>all</emphasis> as a parameter.
 			</para>
 			<para>
-			No parameter.
+			NOTE: When specify the IPv6 &rtp; proxy url one must prefix it with <emphasis>::</emphasis>
+            to escape the :: from the IPv6 address. See the example below.
 			</para>
 			<example>
 			<title>
 				<function moreinfo="none">nh_show_rtpp</function> usage</title>
 			<programlisting format="linespecific">
 ...
-$ &ctltool; fifo nh_show_rtpp
+$ &ctltool; fifo nh_show_rtpp udp:192.168.2.133:8081
+$ &ctltool; fifo nh_show_rtpp ::udp6:fe80::9a90:96ff:fea8:fd99:9999
+$ &ctltool; fifo nh_show_rtpp all
+...
+			</programlisting>
+			</example>
+		</section>
+
+	    <section id="rtpengine.m.nh_ping_rtpp">
+			<title><function moreinfo="none">nh_ping_rtpp proxy_url/all</function></title>
+			<para>
+            Sends an application ping command to the &rtp; proxy. If the proxy does not respond,
+            it will be disabled, but not permanent. If the proxy responds, no action is taken.
+            Displays the ping result, i.e.
+            <emphasis>success</emphasis> or <emphasis>fail</emphasis> when try to ping.
+			</para>
+			<para>
+            It takes either a specific &rtp; proxy url (exactly as defined in
+			the config file) or the keyword <emphasis>all</emphasis> as a parameter.
+			</para>
+			<para>
+			NOTE: When specify the IPv6 &rtp; proxy url one must prefix it with <emphasis>::</emphasis>
+            to escape the :: from the IPv6 address. See the example below.
+			</para>
+			<example>
+			<title>
+				<function moreinfo="none">nh_ping_rtpp</function> usage</title>
+			<programlisting format="linespecific">
+...
+$ &ctltool; fifo nh_ping_rtpp udp:192.168.2.133:8081
+$ &ctltool; fifo nh_ping_rtpp ::udp6:fe80::9a90:96ff:fea8:fd99:9999
+$ &ctltool; fifo nh_ping_rtpp all
 ...
 			</programlisting>
 			</example>

+ 485 - 103
modules/rtpengine/rtpengine.c

@@ -102,11 +102,12 @@ MODULE_VERSION
 #define MI_SET_NATPING_STATE		"nh_enable_ping"
 #define MI_DEFAULT_NATPING_STATE	1
 
-#define MI_ENABLE_RTP_PROXY			"nh_enable_rtpp"
 #define MI_MIN_RECHECK_TICKS		0
 #define MI_MAX_RECHECK_TICKS		(unsigned int)-1
 
+#define MI_ENABLE_RTP_PROXY			"nh_enable_rtpp"
 #define MI_SHOW_RTP_PROXIES			"nh_show_rtpp"
+#define MI_PING_RTP_PROXY           "nh_ping_rtpp"
 
 #define MI_RTP_PROXY_NOT_FOUND		"RTP proxy not found"
 #define MI_RTP_PROXY_NOT_FOUND_LEN	(sizeof(MI_RTP_PROXY_NOT_FOUND)-1)
@@ -118,6 +119,8 @@ MODULE_VERSION
 #define MI_SET_LEN					(sizeof(MI_SET)-1)
 #define MI_INDEX					"index"
 #define MI_INDEX_LEN				(sizeof(MI_INDEX)-1)
+#define MI_ENABLED					"enabled"
+#define MI_ENABLED_LEN				(sizeof(MI_ENABLED)-1)
 #define MI_DISABLED					"disabled"
 #define MI_DISABLED_LEN				(sizeof(MI_DISABLED)-1)
 #define MI_WEIGHT					"weight"
@@ -125,6 +128,24 @@ MODULE_VERSION
 #define MI_RECHECK_TICKS			"recheck_ticks"
 #define MI_RECHECK_T_LEN			(sizeof(MI_RECHECK_TICKS)-1)
 
+#define MI_ERROR                    "Error when adding rtpp node details"
+#define MI_ERROR_LEN                (sizeof(MI_ERROR)-1)
+#define MI_ALL                      "all"
+#define MI_ALL_LEN           		(sizeof(MI_ALL)-1)
+#define MI_ENABLE                   "enable"
+#define MI_ENABLE_LEN         		(sizeof(MI_ENABLE)-1)
+#define MI_DISABLE                  "disable"
+#define MI_DISABLE_LEN         		(sizeof(MI_DISABLE)-1)
+#define MI_PING                     "ping"
+#define MI_PING_LEN         		(sizeof(MI_PING)-1)
+#define MI_SUCCESS                  "success"
+#define MI_SUCCESS_LEN         		(sizeof(MI_SUCCESS)-1)
+#define MI_FAIL                     "fail"
+#define MI_FAIL_LEN         		(sizeof(MI_FAIL)-1)
+
+#define MI_FOUND_ALL                   2
+#define MI_FOUND_ONE                   1
+#define MI_FOUND_NONE                  0
 
 
 #define	CPORT		"22222"
@@ -135,6 +156,7 @@ enum rtpe_operation {
 	OP_DELETE,
 	OP_START_RECORDING,
 	OP_QUERY,
+	OP_PING,
 };
 
 struct ng_flags_parse {
@@ -148,6 +170,7 @@ static const char *command_strings[] = {
 	[OP_DELETE]		= "delete",
 	[OP_START_RECORDING]	= "start recording",
 	[OP_QUERY]		= "query",
+	[OP_PING]		= "ping",
 };
 
 static char *gencookie();
@@ -179,14 +202,22 @@ static int get_ip_type(char *str_addr);
 static int get_ip_scope(char *str_addr); // useful for link-local ipv6
 static int bind_force_send_ip(int sock_idx);
 
+static int add_rtpp_node_info(struct mi_node *node,
+                              struct rtpp_node *crt_rtpp,
+                              struct rtpp_set *rtpp_list);
+
+static int rtpp_test_ping(struct rtpp_node *node);
+
 /* Pseudo-Variables */
 static int pv_get_rtpstat_f(struct sip_msg *, pv_param_t *, pv_value_t *);
 
 /*mi commands*/
 static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree,
 		void* param );
-static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree,
+static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree,
 		void* param);
+static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree,
+        void* param);
 
 
 static int rtpengine_disable_tout = 60;
@@ -303,8 +334,9 @@ static param_export_t params[] = {
 };
 
 static mi_export_t mi_cmds[] = {
-	{MI_ENABLE_RTP_PROXY,     mi_enable_rtp_proxy,  0,                0, 0},
-	{MI_SHOW_RTP_PROXIES,     mi_show_rtpproxies,   MI_NO_INPUT_FLAG, 0, 0},
+	{MI_ENABLE_RTP_PROXY,     mi_enable_rtp_proxy,  0,  0,  0},
+	{MI_SHOW_RTP_PROXIES,     mi_show_rtp_proxy,    0,  0,  0},
+	{MI_PING_RTP_PROXY,       mi_ping_rtp_proxy,    0,  0,  0},
 	{ 0, 0, 0, 0, 0}
 };
 
@@ -423,7 +455,7 @@ static int bind_force_send_ip(int sock_idx)
 			memset(&tmp, 0, sizeof(tmp));
 			getsockname(rtpp_socks[sock_idx], (struct sockaddr *) &tmp, &sock_len);
 			inet_ntop(AF_INET, &tmp.sin_addr, str_addr, INET_ADDRSTRLEN);
-			LM_INFO("Binding on %s:%d\n", str_addr, ntohs(tmp.sin_port));
+			LM_DBG("Binding on %s:%d\n", str_addr, ntohs(tmp.sin_port));
 
 			break;
 
@@ -447,7 +479,7 @@ static int bind_force_send_ip(int sock_idx)
 			memset(&tmp6, 0, sizeof(tmp6));
 			getsockname(rtpp_socks[sock_idx], (struct sockaddr *) &tmp6, &sock_len);
 			inet_ntop(AF_INET6, &tmp6.sin6_addr, str_addr6, INET6_ADDRSTRLEN);
-			LM_INFO("Binding on ipv6 %s:%d\n", str_addr6, ntohs(tmp6.sin6_port));
+			LM_DBG("Binding on ipv6 %s:%d\n", str_addr6, ntohs(tmp6.sin6_port));
 
 			break;
 
@@ -779,67 +811,204 @@ static int fixup_set_id(void ** param, int param_no)
 	return 0;
 }
 
-static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree,
-												void* param )
-{	struct mi_node* node;
-	str rtpp_url;
+static int rtpp_test_ping(struct rtpp_node *node)
+{
+    bencode_buffer_t bencbuf;
+    bencode_item_t *dict;
+    char *cp;
+    int ret;
+
+    if (bencode_buffer_init(&bencbuf)) {
+        return -1;
+    }
+    dict = bencode_dictionary(&bencbuf);
+    bencode_dictionary_add_string(dict, "command", command_strings[OP_PING]);
+
+    if (bencbuf.error) {
+        goto error;
+    }
+
+    cp = send_rtpp_command(node, dict, &ret);
+    if (!cp) {
+        goto error;
+    }
+
+    dict = bencode_decode_expect(&bencbuf, cp, ret, BENCODE_DICTIONARY);
+    if (!dict || bencode_dictionary_get_strcmp(dict, "result", "pong")) {
+        goto error;
+    }
+
+    bencode_buffer_free(&bencbuf);
+    return 0;
+
+error:
+    bencode_buffer_free(&bencbuf);
+    return -1;
+}
+
+static struct mi_root* mi_enable_rtp_proxy(struct mi_root *cmd_tree,
+												void *param )
+{
+	struct mi_node *node, *crt_node;
+	struct rtpp_set *rtpp_list;
+	struct rtpp_node *crt_rtpp, *found_rtpp;
+	struct mi_root *root;
+	struct mi_attr *attr;
 	unsigned int enable;
-	struct rtpp_set * rtpp_list;
-	struct rtpp_node * crt_rtpp;
-	int found;
+	int found, found_rtpp_disabled;
+	str rtpp_url;
+	str snode, sattr, svalue;
 
-	found = 0;
+	found = MI_FOUND_NONE;
+	found_rtpp_disabled = 0;
+	found_rtpp = NULL;
+	enable = 0;
 
-	if(rtpp_set_list ==NULL)
-		goto end;
+	if (rtpp_set_list == NULL) {
+	    return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN);
+	}
 
 	node = cmd_tree->node.kids;
-	if(node == NULL)
-		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	if (node == NULL) {
+		return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	}
 
-	if(node->value.s == NULL || node->value.len ==0)
-		return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
+	if (node->value.s == NULL || node->value.len ==0) {
+		return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
+	}
 
+	/* get proxy */
 	rtpp_url = node->value;
 
 	node = node->next;
-	if(node == NULL)
-		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	if (node == NULL) {
+		return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	}
 
-	enable = 0;
-	if( strno2int( &node->value, &enable) <0)
+	if (node->value.s == NULL || node->value.len ==0) {
+		return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
+	}
+
+	/* get value (enable/disable) */
+	if(strno2int(&node->value, &enable) < 0) {
 		goto error;
+	}
+
+	node = node->next;
+	if (node != NULL) {
+		return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	}
+
+    /* found a matching all - show all rtpp */
+    if (strncmp(MI_ALL, rtpp_url.s, MI_ALL_LEN) == 0) {
+        found = MI_FOUND_ALL;
+    }
 
 	for(rtpp_list = rtpp_set_list->rset_first; rtpp_list != NULL;
-					rtpp_list = rtpp_list->rset_next){
+					rtpp_list = rtpp_list->rset_next) {
 
 		for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL;
-						crt_rtpp = crt_rtpp->rn_next){
-			/*found a matching rtpp*/
+						crt_rtpp = crt_rtpp->rn_next) {
+
+	        /* found a matching rtpp - show it */
+	        if (found == MI_FOUND_ALL ||
+                    (crt_rtpp->rn_url.len == rtpp_url.len &&
+	                strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0)) {
+	            /* do ping when try to enable the rtpp */
+	            if (enable) {
+
+	                /* if ping success, enable the rtpp and reset ticks */
+	                if (rtpp_test_ping(crt_rtpp) == 0) {
+					    crt_rtpp->rn_disabled = 0;
+	                    crt_rtpp->rn_recheck_ticks = MI_MIN_RECHECK_TICKS;
+
+	                /* if ping fail, disable the rtpps but _not_ permanently*/
+	                } else {
+	                    crt_rtpp->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout;
+					    crt_rtpp->rn_disabled = 1;
+	                    found_rtpp_disabled = 1;
+	                }
+
+	            /* do not ping when disable the rtpp; disable it permanenty */
+	            } else {
+					crt_rtpp->rn_disabled = 1;
+	                crt_rtpp->rn_recheck_ticks = MI_MAX_RECHECK_TICKS;
+	            }
+
+                if (found == MI_FOUND_NONE) {
+                        found = MI_FOUND_ONE;
+                        found_rtpp = crt_rtpp;
+                }
+	        }
+		}
+	}
 
-			if(crt_rtpp->rn_url.len == rtpp_url.len){
+	root = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
+	if (!root) {
+		LM_ERR("the MI tree cannot be initialized!\n");
+		return 0;
+	}
+	node = &root->node;
 
-				if(strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0){
-					/*set the enabled/disabled status*/
-					found = 1;
-					crt_rtpp->rn_recheck_ticks =
-						enable? MI_MIN_RECHECK_TICKS : MI_MAX_RECHECK_TICKS;
-					crt_rtpp->rn_disabled = enable?0:1;
-				}
-			}
-		}
+	switch (found) {
+	    case MI_FOUND_ALL:
+	        snode.s = MI_ALL;
+	        snode.len = MI_ALL_LEN;
+            break;
+	    case MI_FOUND_ONE:
+	        snode.s = found_rtpp->rn_url.s;
+	        snode.len = found_rtpp->rn_url.len;
+	        break;
+	    default:
+	        if (root) {
+	            free_mi_tree(root);
+	        }
+	        return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN);
+	}
+
+    svalue.s = MI_SUCCESS;
+    svalue.len = MI_SUCCESS_LEN;
+
+    if (enable) {
+        sattr.s = MI_ENABLE;
+        sattr.len = MI_ENABLE_LEN;
+
+        if (found_rtpp_disabled) {
+            svalue.s = MI_FAIL;
+            svalue.len = MI_FAIL_LEN;
+        }
+    } else {
+        sattr.s = MI_DISABLE;
+        sattr.len = MI_DISABLE_LEN;
+    }
+
+	if (!(crt_node = add_mi_node_child(node, 0,
+	                                   snode.s, snode.len,
+	                                   0, 0)) ) {
+	    LM_ERR("cannot add the child node to the tree\n");
+	    goto error;
 	}
 
-end:
-	if(found)
-		return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
-	return init_mi_tree(404,MI_RTP_PROXY_NOT_FOUND,MI_RTP_PROXY_NOT_FOUND_LEN);
+	if ((attr = add_mi_attr(crt_node, MI_DUP_VALUE,
+	                        sattr.s, sattr.len,
+	                        svalue.s, svalue.len)) == 0) {
+	    LM_ERR("cannot add attributes to the node\n");
+	    goto error;
+	}
+
+
+	return root;
+
 error:
-	return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
+	if (root) {
+	    free_mi_tree(root);
+	}
+	return init_mi_tree(404, MI_ERROR, MI_ERROR_LEN);
 }
 
 
 
+
 #define add_rtpp_node_int_info(_parent, _name, _name_len, _value, _child,\
 								_len, _string, _error)\
 	do {\
@@ -853,86 +1022,294 @@ error:
 			goto _error;\
 	}while(0);
 
-static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree,
-												void* param)
+
+static int add_rtpp_node_info (struct mi_node *node,
+	                           struct rtpp_node *crt_rtpp,
+	                           struct rtpp_set *rtpp_list)
 {
-	struct mi_node* node, *crt_node, *child;
-	struct mi_root* root;
-	struct mi_attr * attr;
-	struct rtpp_set * rtpp_list;
-	struct rtpp_node * crt_rtpp;
-	char * string, *id;
 	int id_len, len;
+    int rtpp_ticks;
+	struct mi_node *crt_node, *child;
+	struct mi_attr *attr;
+	char *string, *id;
 
 	string = id = 0;
 
+	id = int2str(rtpp_list->id_set, &id_len);
+	if(!id) {
+	    LM_ERR("cannot convert set id\n");
+	    goto error;
+	}
+
+	if(!(crt_node = add_mi_node_child(node, 0, crt_rtpp->rn_url.s,
+	        crt_rtpp->rn_url.len, 0,0)) ) {
+	    LM_ERR("cannot add the child node to the tree\n");
+	    goto error;
+	}
+
+	LM_DBG("adding node name %s \n",crt_rtpp->rn_url.s );
+
+	if((attr = add_mi_attr(crt_node, MI_DUP_VALUE, MI_SET, MI_SET_LEN,
+	                        id, id_len))== 0) {
+	    LM_ERR("cannot add attributes to the node\n");
+	    goto error;
+	}
+
+	add_rtpp_node_int_info(crt_node, MI_INDEX, MI_INDEX_LEN,
+	    crt_rtpp->idx, child, len, string, error);
+
+	if ((1 == crt_rtpp->rn_disabled ) && (crt_rtpp->rn_recheck_ticks == MI_MAX_RECHECK_TICKS)) {
+	    if( !(child = add_mi_node_child(crt_node, MI_DUP_VALUE, MI_DISABLED, MI_DISABLED_LEN,
+	                    MI_DISABLED_PERMANENT, MI_DISABLED_PERMANENT_LEN))) {
+	        LM_ERR("cannot add disabled (permanent) message\n");
+	        goto error;
+	    }
+	}
+	else {
+	    add_rtpp_node_int_info(crt_node, MI_DISABLED, MI_DISABLED_LEN,
+	        crt_rtpp->rn_disabled, child, len, string, error);
+	}
+
+	add_rtpp_node_int_info(crt_node, MI_WEIGHT, MI_WEIGHT_LEN,
+	    crt_rtpp->rn_weight, child, len, string, error);
+
+	if (crt_rtpp->rn_recheck_ticks == MI_MAX_RECHECK_TICKS) {
+	    if( !(child = add_mi_node_child(crt_node, MI_DUP_VALUE,
+	                  MI_RECHECK_TICKS, MI_RECHECK_T_LEN,
+	                  "N/A", sizeof("N/A") - 1))) {
+	        LM_ERR("cannot add MAX recheck_ticks value\n");
+	        goto error;
+	    }
+	} else {
+        rtpp_ticks = crt_rtpp->rn_recheck_ticks - get_ticks();
+        rtpp_ticks = rtpp_ticks < 0 ? 0 : rtpp_ticks;
+	    add_rtpp_node_int_info(crt_node, MI_RECHECK_TICKS, MI_RECHECK_T_LEN,
+	        rtpp_ticks, child, len, string, error);
+	}
+
+	return 0;
+
+error:
+	return -1;
+}
+
+static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree,
+												void* param)
+{
+	struct mi_node *node;
+	struct mi_root *root;
+	struct rtpp_set *rtpp_list;
+	struct rtpp_node *crt_rtpp;
+	int found;
+	str rtpp_url;
+
+	found = MI_FOUND_NONE;
+
+	if (rtpp_set_list == NULL) {
+	    return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN);
+	}
+
+	node = cmd_tree->node.kids;
+	if (node == NULL) {
+		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	}
+
+	if (node->value.s == NULL || node->value.len ==0) {
+		return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
+	}
+
+	rtpp_url = node->value;
+	if (strncmp(MI_ALL, rtpp_url.s, MI_ALL_LEN) != 0 && rtpp_set_list == NULL) {
+	    return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN);
+	}
+
+	node = node->next;
+	if (node != NULL) {
+		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	}
+
 	root = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 	if (!root) {
 		LM_ERR("the MI tree cannot be initialized!\n");
 		return 0;
 	}
 
-	if(rtpp_set_list ==NULL)
-		return root;
-
 	node = &root->node;
 
+    /* found a matching all - show all rtpp */
+    if (strncmp(MI_ALL, rtpp_url.s, MI_ALL_LEN) == 0) {
+        found = MI_FOUND_ALL;
+    }
+
 	for(rtpp_list = rtpp_set_list->rset_first; rtpp_list != NULL;
-					rtpp_list = rtpp_list->rset_next){
+					rtpp_list = rtpp_list->rset_next) {
 
 		for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL;
-						crt_rtpp = crt_rtpp->rn_next){
+						crt_rtpp = crt_rtpp->rn_next) {
 
-			id =  int2str(rtpp_list->id_set, &id_len);
-			if(!id){
-				LM_ERR("cannot convert set id\n");
-				goto error;
-			}
+	        /* found a matching rtpp - show it */
+	        if (found == MI_FOUND_ALL ||
+                    (crt_rtpp->rn_url.len == rtpp_url.len &&
+	                strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0)) {
 
-			if(!(crt_node = add_mi_node_child(node, 0, crt_rtpp->rn_url.s,
-					crt_rtpp->rn_url.len, 0,0)) ) {
-				LM_ERR("cannot add the child node to the tree\n");
-				goto error;
-			}
+	            if (add_rtpp_node_info(node, crt_rtpp, rtpp_list) < 0) {
+	                goto error;
+	            }
 
-			LM_DBG("adding node name %s \n",crt_rtpp->rn_url.s );
+                if (found == MI_FOUND_NONE) {
+                        found = MI_FOUND_ONE;
+                }
+	        }
+		}
+	}
 
-			if((attr = add_mi_attr(crt_node, MI_DUP_VALUE, MI_SET, MI_SET_LEN,
-									id, id_len))== 0){
-				LM_ERR("cannot add attributes to the node\n");
-				goto error;
-			}
+	switch (found) {
+	    case MI_FOUND_ALL:
+	    case MI_FOUND_ONE:
+	        break;
+	    default:
+	        if (root) {
+	            free_mi_tree(root);
+	        }
+	        return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN);
+	}
 
-			add_rtpp_node_int_info(crt_node, MI_INDEX, MI_INDEX_LEN,
-				crt_rtpp->idx, child, len,string,error);
-			
-			if (( 1 == crt_rtpp->rn_disabled ) && ( crt_rtpp->rn_recheck_ticks == MI_MAX_RECHECK_TICKS)) {
-				if( !(child = add_mi_node_child(crt_node, MI_DUP_VALUE, MI_DISABLED, MI_DISABLED_LEN,
-								MI_DISABLED_PERMANENT, MI_DISABLED_PERMANENT_LEN))) {
-					LM_ERR("cannot add disabled (permanent) message\n");
-					goto error;
-				}
-			}
-			else {
-				add_rtpp_node_int_info(crt_node, MI_DISABLED, MI_DISABLED_LEN,
-					crt_rtpp->rn_disabled, child, len,string,error);
-			}
+	return root;
 
-			add_rtpp_node_int_info(crt_node, MI_WEIGHT, MI_WEIGHT_LEN,
-				crt_rtpp->rn_weight,  child, len, string,error);
-			add_rtpp_node_int_info(crt_node, MI_RECHECK_TICKS,MI_RECHECK_T_LEN,
-				crt_rtpp->rn_recheck_ticks, child, len, string, error);
-		}
+error:
+	if (root) {
+		free_mi_tree(root);
+	}
+	return init_mi_tree(404, MI_ERROR, MI_ERROR_LEN);
+}
+
+static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree,
+												void* param)
+{
+	struct mi_node *node, *crt_node;
+	struct mi_attr *attr;
+	struct mi_root *root;
+	struct rtpp_set *rtpp_list;
+	struct rtpp_node *crt_rtpp, *found_rtpp;
+	int found, found_rtpp_disabled;
+	str rtpp_url;
+	str snode, sattr, svalue;
+
+	found = 0;
+	found_rtpp_disabled = 0;
+	found_rtpp = NULL;
+
+	if (rtpp_set_list == NULL) {
+	    return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN);
+	}
+
+	node = cmd_tree->node.kids;
+	if (node == NULL) {
+		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	}
+
+	if (node->value.s == NULL || node->value.len ==0) {
+		return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
+	}
+
+	rtpp_url = node->value;
+
+	node = node->next;
+	if (node != NULL) {
+		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+	}
+
+    /* found a matching all - ping all rtpp */
+    if (strncmp(MI_ALL, rtpp_url.s, MI_ALL_LEN) == 0) {
+        found = MI_FOUND_ALL;
+    }
+
+	for (rtpp_list = rtpp_set_list->rset_first; rtpp_list != NULL;
+					rtpp_list = rtpp_list->rset_next) {
+
+		for (crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL;
+						crt_rtpp = crt_rtpp->rn_next) {
+
+	        /* found a matching rtpp - ping it */
+	        if (found == MI_FOUND_ALL ||
+                    (crt_rtpp->rn_url.len == rtpp_url.len &&
+	                strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0)) {
+
+	            /* if ping fail */
+	            if (rtpp_test_ping(crt_rtpp) < 0) {
+	                crt_rtpp->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout;
+	                found_rtpp_disabled = 1;
+	                crt_rtpp->rn_disabled = 1;
+	            }
+
+                if (found == MI_FOUND_NONE) {
+    	            found = MI_FOUND_ONE;
+	                found_rtpp = crt_rtpp;
+                }
+		    }
+	    }
+	}
+
+	root = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
+	if (!root) {
+		LM_ERR("the MI tree cannot be initialized!\n");
+		return 0;
+	}
+
+	node = &root->node;
+
+	switch (found) {
+	    case MI_FOUND_ALL:
+	        snode.s = MI_ALL;
+	        snode.len = MI_ALL_LEN;
+	        break;
+	    case MI_FOUND_ONE:
+	        snode.s = found_rtpp->rn_url.s;
+	        snode.len = found_rtpp->rn_url.len;
+	        break;
+	    default:
+	        if (root) {
+	            free_mi_tree(root);
+	        }
+	        return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN);
+	}
+
+    sattr.s = MI_PING;
+    sattr.len = MI_PING_LEN;
+
+    if (found_rtpp_disabled) {
+        svalue.s = MI_FAIL;
+        svalue.len = MI_FAIL_LEN;
+    } else {
+        svalue.s = MI_SUCCESS;
+        svalue.len = MI_SUCCESS_LEN;
+    }
+
+	if (!(crt_node = add_mi_node_child(node, 0,
+	                                   snode.s, snode.len,
+	                                   0, 0)) ) {
+	    LM_ERR("cannot add the child node to the tree\n");
+	    goto error;
+	}
+
+	if ((attr = add_mi_attr(crt_node, MI_DUP_VALUE,
+	                        sattr.s, sattr.len,
+	                        svalue.s, svalue.len)) == 0) {
+	    LM_ERR("cannot add attributes to the node\n");
+	    goto error;
 	}
 
 	return root;
+
 error:
-	if (root)
-		free_mi_tree(root);
-	return 0;
+	if (root) {
+	    free_mi_tree(root);
+	}
+	return init_mi_tree(404, MI_ERROR, MI_ERROR_LEN);
 }
 
 
+
 static int
 mod_init(void)
 {
@@ -1516,6 +1893,10 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_
 			goto error;
 		}
 		cp = send_rtpp_command(node, ng_flags.dict, &ret);
+        if (cp == NULL) {
+    	    node->rn_disabled = 1;
+        	node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout;
+        }
 	} while (cp == NULL);
 	LM_DBG("proxy reply: %.*s\n", ret, cp);
 
@@ -1606,6 +1987,8 @@ rtpp_test(struct rtpp_node *node, int isdisabled, int force)
 
 	cp = send_rtpp_command(node, dict, &ret);
 	if (!cp) {
+	    node->rn_disabled = 1;
+    	node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout;
 		LM_ERR("proxy did not respond to ping\n");
 		goto error;
 	}
@@ -1638,6 +2021,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 	static char buf[0x10000];
 	struct pollfd fds[1];
 	struct iovec *v;
+    str out = STR_NULL;
 
 	v = bencode_iovec(dict, &vcnt, 1, 0);
 	if (!v) {
@@ -1663,7 +2047,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 		}
 		if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 			close(fd);
-			LM_ERR("can't connect to RTP proxy\n");
+			LM_ERR("can't connect to RTP proxy <%s>\n", node->rn_url.s);
 			goto badproxy;
 		}
 
@@ -1672,7 +2056,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 		} while (len == -1 && errno == EINTR);
 		if (len <= 0) {
 			close(fd);
-			LM_ERR("can't send command to a RTP proxy\n");
+			LM_ERR("can't send command to RTP proxy <%s>\n", node->rn_url.s);
 			goto badproxy;
 		}
 		do {
@@ -1680,7 +2064,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 		} while (len == -1 && errno == EINTR);
 		close(fd);
 		if (len <= 0) {
-			LM_ERR("can't read reply from a RTP proxy\n");
+			LM_ERR("can't read reply from RTP proxy <%s>\n", node->rn_url.s);
 			goto badproxy;
 		}
 	} else {
@@ -1700,7 +2084,8 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 				len = writev(rtpp_socks[node->idx], v, vcnt + 1);
 			} while (len == -1 && (errno == EINTR || errno == ENOBUFS));
 			if (len <= 0) {
-				LM_ERR("can't send command to a RTP proxy\n");
+                bencode_get_str(bencode_dictionary_get(dict, "command"), &out);
+				LM_ERR("can't send command \"%.*s\" to RTP proxy <%s>\n", out.len, out.s, node->rn_url.s);
 				goto badproxy;
 			}
 			while ((poll(fds, 1, rtpengine_tout_ms) == 1) &&
@@ -1709,7 +2094,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 					len = recv(rtpp_socks[node->idx], buf, sizeof(buf)-1, 0);
 				} while (len == -1 && errno == EINTR);
 				if (len <= 0) {
-					LM_ERR("can't read reply from a RTP proxy\n");
+					LM_ERR("can't read reply from RTP proxy <%s>\n", node->rn_url.s);
 					goto badproxy;
 				}
 				if (len >= (v[0].iov_len - 1) &&
@@ -1726,7 +2111,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 			}
 		}
 		if (i == rtpengine_retr) {
-			LM_ERR("timeout waiting reply from a RTP proxy\n");
+			LM_ERR("timeout waiting reply from RTP proxy <%s>\n", node->rn_url.s);
 			goto badproxy;
 		}
 	}
@@ -1735,11 +2120,8 @@ out:
 	cp[len] = '\0';
 	*outlen = len;
 	return cp;
-badproxy:
-	LM_ERR("proxy <%s> does not respond, disable it\n", node->rn_url.s);
-	node->rn_disabled = 1;
-	node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout;
 
+badproxy:
 	return NULL;
 }