Browse Source

Merge branch 'master' of https://github.com/kamailio/kamailio

Patric Marschall 10 years ago
parent
commit
e4ce2a0837

+ 7 - 32
modules/dialog/dlg_hash.c

@@ -42,9 +42,6 @@
 #include "dlg_req_within.h"
 #include "dlg_req_within.h"
 #include "dlg_db_handler.h"
 #include "dlg_db_handler.h"
 
 
-#define MAX_LDG_LOCKS  2048
-#define MIN_LDG_LOCKS  2
-
 extern int dlg_ka_interval;
 extern int dlg_ka_interval;
 
 
 /*! global dialog table */
 /*! global dialog table */
@@ -223,7 +220,7 @@ int dlg_clean_run(ticks_t ti)
 	tm = (unsigned int)time(NULL);
 	tm = (unsigned int)time(NULL);
 	for(i=0; i<d_table->size; i++)
 	for(i=0; i<d_table->size; i++)
 	{
 	{
-		lock_set_get(d_table->locks, d_table->entries[i].lock_idx);
+		dlg_lock(d_table, &d_table->entries[i]);
 		dlg = d_table->entries[i].first;
 		dlg = d_table->entries[i].first;
 		while (dlg) {
 		while (dlg) {
 			tdlg = dlg;
 			tdlg = dlg;
@@ -243,7 +240,7 @@ int dlg_clean_run(ticks_t ti)
 				tdlg->dflags |= DLG_FLAG_CHANGED;
 				tdlg->dflags |= DLG_FLAG_CHANGED;
 			}
 			}
 		}
 		}
-		lock_set_release(d_table->locks, d_table->entries[i].lock_idx);
+		dlg_unlock(d_table, &d_table->entries[i]);
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -288,30 +285,13 @@ int init_dlg_table(unsigned int size)
 	d_table->size = size;
 	d_table->size = size;
 	d_table->entries = (struct dlg_entry*)(d_table+1);
 	d_table->entries = (struct dlg_entry*)(d_table+1);
 
 
-	n = (size<MAX_LDG_LOCKS)?size:MAX_LDG_LOCKS;
-	for(  ; n>=MIN_LDG_LOCKS ; n-- ) {
-		d_table->locks = lock_set_alloc(n);
-		if (d_table->locks==0)
-			continue;
-		if (lock_set_init(d_table->locks)==0) {
-			lock_set_dealloc(d_table->locks);
-			d_table->locks = 0;
-			continue;
-		}
-		d_table->locks_no = n;
-		break;
-	}
-
-	if (d_table->locks==0) {
-		LM_ERR("unable to allocted at least %d locks for the hash table\n",
-			MIN_LDG_LOCKS);
-		goto error1;
-	}
-
 	for( i=0 ; i<size; i++ ) {
 	for( i=0 ; i<size; i++ ) {
 		memset( &(d_table->entries[i]), 0, sizeof(struct dlg_entry) );
 		memset( &(d_table->entries[i]), 0, sizeof(struct dlg_entry) );
+		if(lock_init(&d_table->entries[i].lock)<0) {
+			LM_ERR("failed to init lock for slot: %d\n", i);
+			goto error1;
+		}
 		d_table->entries[i].next_id = rand() % (3*size);
 		d_table->entries[i].next_id = rand() % (3*size);
-		d_table->entries[i].lock_idx = i % d_table->locks_no;
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -411,11 +391,6 @@ void destroy_dlg_table(void)
 	if (d_table==0)
 	if (d_table==0)
 		return;
 		return;
 
 
-	if (d_table->locks) {
-		lock_set_destroy(d_table->locks);
-		lock_set_dealloc(d_table->locks);
-	}
-
 	for( i=0 ; i<d_table->size; i++ ) {
 	for( i=0 ; i<d_table->size; i++ ) {
 		dlg = d_table->entries[i].first;
 		dlg = d_table->entries[i].first;
 		while (dlg) {
 		while (dlg) {
@@ -423,7 +398,7 @@ void destroy_dlg_table(void)
 			dlg = dlg->next;
 			dlg = dlg->next;
 			destroy_dlg(l_dlg);
 			destroy_dlg(l_dlg);
 		}
 		}
-
+		lock_destroy(&d_table->entries[i].lock);
 	}
 	}
 
 
 	shm_free(d_table);
 	shm_free(d_table);

+ 25 - 6
modules/dialog/dlg_hash.h

@@ -33,6 +33,7 @@
 #include "../../locking.h"
 #include "../../locking.h"
 #include "../../lib/kmi/mi.h"
 #include "../../lib/kmi/mi.h"
 #include "../../timer.h"
 #include "../../timer.h"
+#include "../../atomic_ops.h"
 #include "dlg_timer.h"
 #include "dlg_timer.h"
 #include "dlg_cb.h"
 #include "dlg_cb.h"
 
 
@@ -134,7 +135,9 @@ typedef struct dlg_entry
 	struct dlg_cell    *first;	/*!< dialog list */
 	struct dlg_cell    *first;	/*!< dialog list */
 	struct dlg_cell    *last;	/*!< optimisation, end of the dialog list */
 	struct dlg_cell    *last;	/*!< optimisation, end of the dialog list */
 	unsigned int       next_id;	/*!< next id */
 	unsigned int       next_id;	/*!< next id */
-	unsigned int       lock_idx;	/*!< lock index */
+	gen_lock_t lock;     /* mutex to access items in the slot */
+	atomic_t locker_pid; /* pid of the process that holds the lock */
+	int rec_lock_level;  /* recursive lock count */
 } dlg_entry_t;
 } dlg_entry_t;
 
 
 
 
@@ -143,8 +146,6 @@ typedef struct dlg_table
 {
 {
 	unsigned int       size;	/*!< size of the dialog table */
 	unsigned int       size;	/*!< size of the dialog table */
 	struct dlg_entry   *entries;	/*!< dialog hash table */
 	struct dlg_entry   *entries;	/*!< dialog hash table */
-	unsigned int       locks_no;	/*!< number of locks */
-	gen_lock_set_t     *locks;	/*!< lock table */
 } dlg_table_t;
 } dlg_table_t;
 
 
 
 
@@ -160,12 +161,22 @@ extern dlg_table_t *d_table;
 
 
 
 
 /*!
 /*!
- * \brief Set a dialog lock
+ * \brief Set a dialog lock (re-entrant)
  * \param _table dialog table
  * \param _table dialog table
  * \param _entry locked entry
  * \param _entry locked entry
  */
  */
 #define dlg_lock(_table, _entry) \
 #define dlg_lock(_table, _entry) \
-		lock_set_get( (_table)->locks, (_entry)->lock_idx);
+		do { \
+			int mypid; \
+			mypid = my_pid(); \
+			if (likely(atomic_get( &(_entry)->locker_pid) != mypid)) { \
+				lock_get( &(_entry)->lock); \
+				atomic_set( &(_entry)->locker_pid, mypid); \
+			} else { \
+				/* locked within the same process that executed us */ \
+				(_entry)->rec_lock_level++; \
+			} \
+		} while(0)
 
 
 
 
 /*!
 /*!
@@ -174,7 +185,15 @@ extern dlg_table_t *d_table;
  * \param _entry locked entry
  * \param _entry locked entry
  */
  */
 #define dlg_unlock(_table, _entry) \
 #define dlg_unlock(_table, _entry) \
-		lock_set_release( (_table)->locks, (_entry)->lock_idx);
+		do { \
+			if (likely((_entry)->rec_lock_level == 0)) { \
+				atomic_set( &(_entry)->locker_pid, 0); \
+				lock_release( &(_entry)->lock); \
+			} else  { \
+				/* recursive locked => decrease lock count */ \
+				(_entry)->rec_lock_level--; \
+			} \
+		} while(0)
 
 
 /*!
 /*!
  * \brief Unlink a dialog from the list without locking
  * \brief Unlink a dialog from the list without locking

+ 119 - 100
modules/lcr/README

@@ -10,7 +10,7 @@ Juha Heinanen
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright (c) 2005-2014 Juha Heinanen
+   Copyright © 2005-2014 Juha Heinanen
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -62,12 +62,13 @@ Juha Heinanen
               3.35. lcr_rule_hash_size (integer)
               3.35. lcr_rule_hash_size (integer)
               3.36. lcr_gw_count (integer)
               3.36. lcr_gw_count (integer)
               3.37. dont_strip_or_tag_flag (integer)
               3.37. dont_strip_or_tag_flag (integer)
-              3.38. fetch_rows (integer)
-              3.39. ping_interval (integer)
-              3.40. ping_inactivate_threshold (integer)
-              3.41. ping_valid_reply_codes (string)
-              3.42. ping_from (string)
-              3.43. ping_socket (string)
+              3.38. priority_ordering (integer)
+              3.39. fetch_rows (integer)
+              3.40. ping_interval (integer)
+              3.41. ping_inactivate_threshold (integer)
+              3.42. ping_valid_reply_codes (string)
+              3.43. ping_from (string)
+              3.44. ping_socket (string)
 
 
         4. Functions
         4. Functions
 
 
@@ -128,25 +129,26 @@ Juha Heinanen
    1.35. Setting lcr_rule_hash_size module parameter
    1.35. Setting lcr_rule_hash_size module parameter
    1.36. Setting lcr_gw_count module parameter
    1.36. Setting lcr_gw_count module parameter
    1.37. Setting dont_strip_or_tag_flag module parameter
    1.37. Setting dont_strip_or_tag_flag module parameter
-   1.38. Set fetch_rows parameter
-   1.39. Set ping_interval parameter
-   1.40. Set ping_inactive_threshold parameter
-   1.41. Set ping_valid_reply_codes parameter
-   1.42. Set ping_from parameter
-   1.43. Set ping_socket parameter
-   1.44. load_gws usage
-   1.45. next_gw usage from a route block
-   1.46. next_gw usage from a failure route block
-   1.47. inactivate_gw usage
-   1.48. defunct_gw usage
-   1.49. from_gw usage
+   1.38. Setting priority_ordering module parameter
+   1.39. Set fetch_rows parameter
+   1.40. Set ping_interval parameter
+   1.41. Set ping_inactivate_threshold parameter
+   1.42. Set ping_valid_reply_codes parameter
+   1.43. Set ping_from parameter
+   1.44. Set ping_socket parameter
+   1.45. load_gws usage
+   1.46. next_gw usage from a route block
+   1.47. next_gw usage from a failure route block
+   1.48. inactivate_gw usage
+   1.49. defunct_gw usage
    1.50. from_gw usage
    1.50. from_gw usage
-   1.51. to_gw usage
+   1.51. from_gw usage
    1.52. to_gw usage
    1.52. to_gw usage
-   1.53. lcr.reload RPC example
-   1.54. lcr.dump_gws RPC example
-   1.55. lcr.dump_rules RPC example
-   1.56. lcr.defunct_gw RPC example
+   1.53. to_gw usage
+   1.54. lcr.reload RPC example
+   1.55. lcr.dump_gws RPC example
+   1.56. lcr.dump_rules RPC example
+   1.57. lcr.defunct_gw RPC example
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -197,12 +199,13 @@ Chapter 1. Admin Guide
         3.35. lcr_rule_hash_size (integer)
         3.35. lcr_rule_hash_size (integer)
         3.36. lcr_gw_count (integer)
         3.36. lcr_gw_count (integer)
         3.37. dont_strip_or_tag_flag (integer)
         3.37. dont_strip_or_tag_flag (integer)
-        3.38. fetch_rows (integer)
-        3.39. ping_interval (integer)
-        3.40. ping_inactivate_threshold (integer)
-        3.41. ping_valid_reply_codes (string)
-        3.42. ping_from (string)
-        3.43. ping_socket (string)
+        3.38. priority_ordering (integer)
+        3.39. fetch_rows (integer)
+        3.40. ping_interval (integer)
+        3.41. ping_inactivate_threshold (integer)
+        3.42. ping_valid_reply_codes (string)
+        3.43. ping_from (string)
+        3.44. ping_socket (string)
 
 
    4. Functions
    4. Functions
 
 
@@ -248,9 +251,14 @@ Chapter 1. Admin Guide
    currently designated as defunct) are ordered for forwarding purposes as
    currently designated as defunct) are ordered for forwarding purposes as
    follows:
    follows:
 
 
-     * (1) according to longest Request-URI user part match
-     * (2) according to tuple's priority
-     * (3) according to tuple's randomized weight
+    1. according to longest Request-URI user part match
+    2. according to tuple's priority
+    3. according to tuple's randomized weight
+
+   or, if priority_ordering parameter is set to value 1, as follows:
+
+    1. according to tuple's priority
+    2. according to tuple's randomized weight
 
 
    A tuple can be marked as a "stopper" tuple. If a "stopper" tuple
    A tuple can be marked as a "stopper" tuple. If a "stopper" tuple
    matches, then matching stops at it and all other tuples with shorter
    matches, then matching stops at it and all other tuples with shorter
@@ -349,18 +357,19 @@ Chapter 1. Admin Guide
    3.35. lcr_rule_hash_size (integer)
    3.35. lcr_rule_hash_size (integer)
    3.36. lcr_gw_count (integer)
    3.36. lcr_gw_count (integer)
    3.37. dont_strip_or_tag_flag (integer)
    3.37. dont_strip_or_tag_flag (integer)
-   3.38. fetch_rows (integer)
-   3.39. ping_interval (integer)
-   3.40. ping_inactivate_threshold (integer)
-   3.41. ping_valid_reply_codes (string)
-   3.42. ping_from (string)
-   3.43. ping_socket (string)
+   3.38. priority_ordering (integer)
+   3.39. fetch_rows (integer)
+   3.40. ping_interval (integer)
+   3.41. ping_inactivate_threshold (integer)
+   3.42. ping_valid_reply_codes (string)
+   3.43. ping_from (string)
+   3.44. ping_socket (string)
 
 
 3.1. db_url (string)
 3.1. db_url (string)
 
 
    URL of the database table to be used.
    URL of the database table to be used.
 
 
-   Default value is "mysql://kamailioro:kamailioro@localhost/kamailio".
+   Default value is “mysql://kamailioro:kamailioro@localhost/kamailio”.
 
 
    Example 1.1. Setting db_url module parameter
    Example 1.1. Setting db_url module parameter
 ...
 ...
@@ -371,7 +380,7 @@ modparam("lcr","db_url","dbdriver://username:password@dbhost/dbname")
 
 
    Name of the table holding gateways definitions.
    Name of the table holding gateways definitions.
 
 
-   Default value is "lcr_gw".
+   Default value is “lcr_gw”.
 
 
    Example 1.2. Setting gw_table module parameter
    Example 1.2. Setting gw_table module parameter
 ...
 ...
@@ -383,7 +392,7 @@ modparam("lcr", "lcr_gw_table","gw")
    Name of the auto-increment, primary key column. Common to all lcr
    Name of the auto-increment, primary key column. Common to all lcr
    module tables.
    module tables.
 
 
-   Default value is "id".
+   Default value is “id”.
 
 
    Example 1.3. Setting id_column module parameter
    Example 1.3. Setting id_column module parameter
 ...
 ...
@@ -397,7 +406,7 @@ modparam("lcr", "id_column", "row_id")
    the column is integer from 1 to lcr_count. In lcr_gw table, value of
    the column is integer from 1 to lcr_count. In lcr_gw table, value of
    the column is from 0 to lcr_count.
    the column is from 0 to lcr_count.
 
 
-   Default value is "lcr_id".
+   Default value is “lcr_id”.
 
 
    Example 1.4. Setting lcr_id_column module parameter
    Example 1.4. Setting lcr_id_column module parameter
 ...
 ...
@@ -408,7 +417,7 @@ modparam("lcr", "lcr_id_column", "lcr_identifier")
 
 
    Name of the column holding gateway's name for documentation purpose.
    Name of the column holding gateway's name for documentation purpose.
 
 
-   Default value is "gw_name".
+   Default value is “gw_name”.
 
 
    Example 1.5. Setting gw_name_column module parameter
    Example 1.5. Setting gw_name_column module parameter
 ...
 ...
@@ -419,7 +428,7 @@ modparam("lcr", "gw_name_column", "name")
 
 
    Name of the column holding the IPv4 or IPv6 address of the gateway.
    Name of the column holding the IPv4 or IPv6 address of the gateway.
 
 
-   Default value is "ip_addr".
+   Default value is “ip_addr”.
 
 
    Example 1.6. Setting ip_addr_column module parameter
    Example 1.6. Setting ip_addr_column module parameter
 ...
 ...
@@ -431,7 +440,7 @@ modparam("lcr", "ip_addr_column", "ip")
    Name of the column holding gateway's hostname that is used in
    Name of the column holding gateway's hostname that is used in
    Request-URI hostpart, when request is sent to the gateway.
    Request-URI hostpart, when request is sent to the gateway.
 
 
-   Default value is "hostname".
+   Default value is “hostname”.
 
 
    Example 1.7. Setting hostname_column module parameter
    Example 1.7. Setting hostname_column module parameter
 ...
 ...
@@ -442,7 +451,7 @@ modparam("lcr", "hostname_column", "host")
 
 
    Name of the column holding the port number of the gateway.
    Name of the column holding the port number of the gateway.
 
 
-   Default value is "port".
+   Default value is “port”.
 
 
    Example 1.8. Setting port_column module parameter
    Example 1.8. Setting port_column module parameter
 ...
 ...
@@ -454,7 +463,7 @@ modparam("lcr", "port_column", "port")
    Name of the column holding gateway's parameters that is used in
    Name of the column holding gateway's parameters that is used in
    Request-URI, when request is sent to the gateway.
    Request-URI, when request is sent to the gateway.
 
 
-   Default value is "params".
+   Default value is “params”.
 
 
    Example 1.9. Setting params_column module parameter
    Example 1.9. Setting params_column module parameter
 ...
 ...
@@ -465,7 +474,7 @@ modparam("lcr", "params_column", "parameters")
 
 
    Name of the column holding the uri scheme of the gateway.
    Name of the column holding the uri scheme of the gateway.
 
 
-   Default value is "uri_scheme".
+   Default value is “uri_scheme”.
 
 
    Example 1.10. Setting uri_scheme_column module parameter
    Example 1.10. Setting uri_scheme_column module parameter
 ...
 ...
@@ -477,7 +486,7 @@ modparam("lcr", "uri_scheme_column", "uri_scheme")
    Name of the column holding the transport protocol to be used for the
    Name of the column holding the transport protocol to be used for the
    gateway.
    gateway.
 
 
-   Default value is "transport".
+   Default value is “transport”.
 
 
    Example 1.11. Setting transport_column module parameter
    Example 1.11. Setting transport_column module parameter
 ...
 ...
@@ -489,7 +498,7 @@ modparam("lcr", "transport_column", "trans")
    Name of the column holding the number of characters to be stripped from
    Name of the column holding the number of characters to be stripped from
    the front of Request-URI user part before inserting tag.
    the front of Request-URI user part before inserting tag.
 
 
-   Default value is "strip".
+   Default value is “strip”.
 
 
    Example 1.12. Setting strip_column module parameter
    Example 1.12. Setting strip_column module parameter
 ...
 ...
@@ -501,7 +510,7 @@ modparam("lcr", "strip_column", "strip_count")
    Name of the column holding gateway specific tag string that is added to
    Name of the column holding gateway specific tag string that is added to
    Request URI userpart after stripping.
    Request URI userpart after stripping.
 
 
-   Default value is "tag".
+   Default value is “tag”.
 
 
    Example 1.13. Setting tag_column module parameter
    Example 1.13. Setting tag_column module parameter
 ...
 ...
@@ -512,7 +521,7 @@ modparam("lcr", "tag_column", "gw_tag")
 
 
    Name of the column holding gateway specific flag values.
    Name of the column holding gateway specific flag values.
 
 
-   Default value is "flags".
+   Default value is “flags”.
 
 
    Example 1.14. Setting flags_column module parameter
    Example 1.14. Setting flags_column module parameter
 ...
 ...
@@ -526,7 +535,7 @@ modparam("lcr", "flags_column", "gw_flags")
    max UNIX timestamp value) or greater, gw is considered currently unused
    max UNIX timestamp value) or greater, gw is considered currently unused
    and is not loaded into memory at all.
    and is not loaded into memory at all.
 
 
-   Default value is "defunct".
+   Default value is “defunct”.
 
 
    Example 1.15. Setting defunct_column module parameter
    Example 1.15. Setting defunct_column module parameter
 ...
 ...
@@ -537,7 +546,7 @@ modparam("lcr", "defunct_column", "defunct_until")
 
 
    Name of the table holding the LCR rules.
    Name of the table holding the LCR rules.
 
 
-   Default value is "lcr_rule".
+   Default value is “lcr_rule”.
 
 
    Example 1.16. Setting lcr_rule_table module parameter
    Example 1.16. Setting lcr_rule_table module parameter
 ...
 ...
@@ -549,7 +558,7 @@ modparam("lcr", "lcr_rule_table", "rules")
    Name of the column holding prefix of Request-URI user part and prefix
    Name of the column holding prefix of Request-URI user part and prefix
    of gateway.
    of gateway.
 
 
-   Default value is "prefix".
+   Default value is “prefix”.
 
 
    Example 1.17. Setting prefix_column module parameter
    Example 1.17. Setting prefix_column module parameter
 ...
 ...
@@ -560,7 +569,7 @@ modparam("lcr", "prefix_column", "number_prefix")
 
 
    Name of the column holding the From (caller's) URI.
    Name of the column holding the From (caller's) URI.
 
 
-   Default value is "from_uri".
+   Default value is “from_uri”.
 
 
    Example 1.18. Setting from_uri_column module parameter
    Example 1.18. Setting from_uri_column module parameter
 ...
 ...
@@ -572,7 +581,7 @@ modparam("lcr", "from_uri_column", "caller_uri")
    Name of the column holding the regular expression to match against the
    Name of the column holding the regular expression to match against the
    complete request URI (including the "sip:" prefix).
    complete request URI (including the "sip:" prefix).
 
 
-   Default value is "request_uri".
+   Default value is “request_uri”.
 
 
    Example 1.19. Setting request_uri_column module parameter
    Example 1.19. Setting request_uri_column module parameter
 ...
 ...
@@ -583,7 +592,7 @@ modparam("lcr", "request_uri_column", "callee_uri")
 
 
    Name of the column holding rule's stopper attribute.
    Name of the column holding rule's stopper attribute.
 
 
-   Default value is "stopper".
+   Default value is “stopper”.
 
 
    Example 1.20. Setting stopper_column module parameter
    Example 1.20. Setting stopper_column module parameter
 ...
 ...
@@ -595,7 +604,7 @@ modparam("lcr", "stopper_column", "stop")
    Name of the column telling is the rule is currently enabled or
    Name of the column telling is the rule is currently enabled or
    disabled.
    disabled.
 
 
-   Default value is "enabled".
+   Default value is “enabled”.
 
 
    Example 1.21. Setting enabled_column module parameter
    Example 1.21. Setting enabled_column module parameter
 ...
 ...
@@ -607,7 +616,7 @@ modparam("lcr", "enabled_column", "in_use")
    Name of the table holding information about the LCR rule targets
    Name of the table holding information about the LCR rule targets
    (gateways).
    (gateways).
 
 
-   Default value is "lcr_rule_target".
+   Default value is “lcr_rule_target”.
 
 
    Example 1.22. Setting lcr_rule_target_table module parameter
    Example 1.22. Setting lcr_rule_target_table module parameter
 ...
 ...
@@ -619,7 +628,7 @@ modparam("lcr", "lcr_rule_target_table", "rules")
    Name of lcr_rule_target_table column containing an id of lcr_rule
    Name of lcr_rule_target_table column containing an id of lcr_rule
    table.
    table.
 
 
-   Default value is "rule_id".
+   Default value is “rule_id”.
 
 
    Example 1.23. Setting rule_id_column module parameter
    Example 1.23. Setting rule_id_column module parameter
 ...
 ...
@@ -630,7 +639,7 @@ modparam("lcr", "rule_id_column", "rule")
 
 
    Name of lcr_rule_target_table column containing an id of lcr_gw table.
    Name of lcr_rule_target_table column containing an id of lcr_gw table.
 
 
-   Default value is "gw_id".
+   Default value is “gw_id”.
 
 
    Example 1.24. Setting gw_id_column module parameter
    Example 1.24. Setting gw_id_column module parameter
 ...
 ...
@@ -641,7 +650,7 @@ modparam("lcr", "gw_id_column", "gw")
 
 
    Name of the column holding the priority of the rule target.
    Name of the column holding the priority of the rule target.
 
 
-   Default value is "priority".
+   Default value is “priority”.
 
 
    Example 1.25. Setting priority_column module parameter
    Example 1.25. Setting priority_column module parameter
 ...
 ...
@@ -652,7 +661,7 @@ modparam("lcr", "priority_column", "priority")
 
 
    Name of the column holding weight of rule target.
    Name of the column holding weight of rule target.
 
 
-   Default value is "weight".
+   Default value is “weight”.
 
 
    Example 1.26. Setting weight_column module parameter
    Example 1.26. Setting weight_column module parameter
 ...
 ...
@@ -796,7 +805,18 @@ modparam("lcr", "lcr_gw_count", 1024)
 modparam("lcr", "dont_strip_or_tag_flag", 10)
 modparam("lcr", "dont_strip_or_tag_flag", 10)
 ...
 ...
 
 
-3.38. fetch_rows (integer)
+3.38. priority_ordering (integer)
+
+   Defines how matching gateways are ordered (see Overview section).
+
+   Default value is 0.
+
+   Example 1.38.  Setting priority_ordering module parameter
+...
+modparam("lcr", "priority_ordering", 1)
+...
+
+3.39. fetch_rows (integer)
 
 
    The number of the rows to be fetched at once from database when loading
    The number of the rows to be fetched at once from database when loading
    data from lcr_rule table. This value can be used to tune the load time
    data from lcr_rule table. This value can be used to tune the load time
@@ -804,14 +824,14 @@ modparam("lcr", "dont_strip_or_tag_flag", 10)
    3750. In order for this parameter to have effect, the database driver
    3750. In order for this parameter to have effect, the database driver
    must support fetch_result() capability.
    must support fetch_result() capability.
 
 
-   Default value is "1024".
+   Default value is “1024”.
 
 
-   Example 1.38. Set fetch_rows parameter
+   Example 1.39. Set fetch_rows parameter
 ...
 ...
 modparam("lcr", "fetch_rows", 3000)
 modparam("lcr", "fetch_rows", 3000)
 ...
 ...
 
 
-3.39. ping_interval (integer)
+3.40. ping_interval (integer)
 
 
    Interval in seconds for sending OPTIONS ping requests to gateways that,
    Interval in seconds for sending OPTIONS ping requests to gateways that,
    due to failures, have been marked as inactive by inactivate_gw()
    due to failures, have been marked as inactive by inactivate_gw()
@@ -821,62 +841,61 @@ modparam("lcr", "fetch_rows", 3000)
 
 
    If value of this parameter is greater than zero, tm module must have
    If value of this parameter is greater than zero, tm module must have
    been loaded and parameters lcr_id_avp and defunct_gw_avp must have been
    been loaded and parameters lcr_id_avp and defunct_gw_avp must have been
-   defined. Value "0" disables sending of OPTIONS ping requests to failed
+   defined. Value “0” disables sending of OPTIONS ping requests to failed
    gateways.
    gateways.
 
 
-   Default value is "0".
+   Default value is “0”.
 
 
-   Example 1.39.  Set ping_interval parameter
+   Example 1.40.  Set ping_interval parameter
 ...
 ...
 modparam("lcr", "ping_interval", 15)
 modparam("lcr", "ping_interval", 15)
 ...
 ...
 
 
-3.40. ping_inactivate_threshold (integer)
+3.41. ping_inactivate_threshold (integer)
 
 
    Tells after how many failures (= inactivate_gw() function calls) a
    Tells after how many failures (= inactivate_gw() function calls) a
    gateway is marked as inactive.
    gateway is marked as inactive.
 
 
-   Default value is "1", i.e., gateway is marked inactive after first
-   failure.
+   Default value is “1”, i.e., gateway is inactivated after first failure.
 
 
-   Example 1.40.  Set ping_inactive_threshold parameter
+   Example 1.41.  Set ping_inactivate_threshold parameter
 ...
 ...
-modparam("lcr", "ping_inactive_threshold", 3)
+modparam("lcr", "ping_inactivate_threshold", 3)
 ...
 ...
 
 
-3.41. ping_valid_reply_codes (string)
+3.42. ping_valid_reply_codes (string)
 
 
    A comma separated list of SIP reply codes, which are accepted as valid
    A comma separated list of SIP reply codes, which are accepted as valid
    replies to OPTIONS ping requests. Reply codes 2xx are by default
    replies to OPTIONS ping requests. Reply codes 2xx are by default
    accepted as valid replies and they don't need to be listed here.
    accepted as valid replies and they don't need to be listed here.
 
 
-   Default value is "", i.e., only 2xx replies are considered as valid
+   Default value is “”, i.e., only 2xx replies are considered as valid
    replies.
    replies.
 
 
-   Example 1.41.  Set ping_valid_reply_codes parameter
+   Example 1.42.  Set ping_valid_reply_codes parameter
 ...
 ...
 modparam("lcr", "ping_valid_reply_codes", "403,405,501")
 modparam("lcr", "ping_valid_reply_codes", "403,405,501")
 ...
 ...
 
 
-3.42. ping_from (string)
+3.43. ping_from (string)
 
 
    From URI used in OPTIONS ping requests.
    From URI used in OPTIONS ping requests.
 
 
-   Default value is "sip:pinger@localhost".
+   Default value is “sip:pinger@localhost”.
 
 
-   Example 1.42.  Set ping_from parameter
+   Example 1.43.  Set ping_from parameter
 ...
 ...
 modparam("lcr", "ping_from", "sip:proxy.operator.com")
 modparam("lcr", "ping_from", "sip:proxy.operator.com")
 ...
 ...
 
 
-3.43. ping_socket (string)
+3.44. ping_socket (string)
 
 
    Socket to be used for sending OPTIONS ping request. If not set or set
    Socket to be used for sending OPTIONS ping request. If not set or set
-   to "", default socket is used.
+   to “”, default socket is used.
 
 
-   Default value is "".
+   Default value is “”.
 
 
-   Example 1.43.  Set ping_socket parameter
+   Example 1.44.  Set ping_socket parameter
 ...
 ...
 modparam("lcr", "ping_socket", "192.98.102.10:5060")
 modparam("lcr", "ping_socket", "192.98.102.10:5060")
 ...
 ...
@@ -912,7 +931,7 @@ modparam("lcr", "ping_socket", "192.98.102.10:5060")
 
 
    This function can be used from REQUEST_ROUTE.
    This function can be used from REQUEST_ROUTE.
 
 
-   Example 1.44. load_gws usage
+   Example 1.45. load_gws usage
 ...
 ...
 if (!load_gws(1, $rU, $var(caller_uri))) {
 if (!load_gws(1, $rU, $var(caller_uri))) {
         sl_send_reply("500", "Server Internal Error - Cannot load gateways");
         sl_send_reply("500", "Server Internal Error - Cannot load gateways");
@@ -942,7 +961,7 @@ if (!load_gws(1, $rU, $var(caller_uri))) {
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.45. next_gw usage from a route block
+   Example 1.46. next_gw usage from a route block
 ...
 ...
 if (!next_gw()) {
 if (!next_gw()) {
         sl_send_reply("503", "Service not available - No gateways");
         sl_send_reply("503", "Service not available - No gateways");
@@ -950,7 +969,7 @@ if (!next_gw()) {
 };
 };
 ...
 ...
 
 
-   Example 1.46. next_gw usage from a failure route block
+   Example 1.47. next_gw usage from a failure route block
 ...
 ...
 if (!next_gw()) {
 if (!next_gw()) {
         t_reply("503", "Service not available - No more gateways");
         t_reply("503", "Service not available - No more gateways");
@@ -970,7 +989,7 @@ if (!next_gw()) {
 
 
    This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.
 
 
-   Example 1.47. inactivate_gw usage
+   Example 1.48. inactivate_gw usage
 ...
 ...
 failure_route [GW_FAILURE] {
 failure_route [GW_FAILURE] {
 ...
 ...
@@ -991,7 +1010,7 @@ failure_route [GW_FAILURE] {
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.48. defunct_gw usage
+   Example 1.49. defunct_gw usage
 ...
 ...
 defunct_gw(60);
 defunct_gw(60);
 ...
 ...
@@ -1023,7 +1042,7 @@ defunct_gw(60);
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE.
    ONREPLY_ROUTE.
 
 
-   Example 1.49. from_gw usage
+   Example 1.50. from_gw usage
 ...
 ...
 if (from_gw(1, $avp(s:real_source_addr), 2) {
 if (from_gw(1, $avp(s:real_source_addr), 2) {
         ...
         ...
@@ -1053,7 +1072,7 @@ if (from_gw(1, $avp(s:real_source_addr), 2) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE.
    ONREPLY_ROUTE.
 
 
-   Example 1.50. from_gw usage
+   Example 1.51. from_gw usage
 ...
 ...
 $var(lcr_id) = from_any_gw("192.168.1.1", 3);
 $var(lcr_id) = from_any_gw("192.168.1.1", 3);
 ...
 ...
@@ -1074,7 +1093,7 @@ $var(lcr_id) = from_any_gw("192.168.1.1", 3);
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.51. to_gw usage
+   Example 1.52. to_gw usage
 ...
 ...
 if (to_gw("1")) {
 if (to_gw("1")) {
         ...
         ...
@@ -1100,7 +1119,7 @@ if (to_gw("1")) {
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.52. to_gw usage
+   Example 1.53. to_gw usage
 ...
 ...
 if (to_any_gw("192.55.66.2", 1)) {
 if (to_any_gw("192.55.66.2", 1)) {
         ...
         ...
@@ -1123,7 +1142,7 @@ if (to_any_gw("192.55.66.2", 1)) {
 
 
    Parameters: none
    Parameters: none
 
 
-   Example 1.53. lcr.reload RPC example
+   Example 1.54. lcr.reload RPC example
                 $ kamcmd lcr.reload
                 $ kamcmd lcr.reload
 
 
 5.2. lcr.dump_gws
 5.2. lcr.dump_gws
@@ -1132,7 +1151,7 @@ if (to_any_gw("192.55.66.2", 1)) {
 
 
    Parameters: none
    Parameters: none
 
 
-   Example 1.54. lcr.dump_gws RPC example
+   Example 1.55. lcr.dump_gws RPC example
                 $ kamcmd lcr.dump_gws
                 $ kamcmd lcr.dump_gws
 
 
 5.3. lcr.dump_rules
 5.3. lcr.dump_rules
@@ -1142,7 +1161,7 @@ if (to_any_gw("192.55.66.2", 1)) {
 
 
    Parameters: none
    Parameters: none
 
 
-   Example 1.55. lcr.dump_rules RPC example
+   Example 1.56. lcr.dump_rules RPC example
                 $ kamcmd lcr.dump_rules
                 $ kamcmd lcr.dump_rules
 
 
 5.4. lcr.defunct_gw
 5.4. lcr.defunct_gw
@@ -1155,7 +1174,7 @@ if (to_any_gw("192.55.66.2", 1)) {
 
 
    Parameters: lcr_id gw_id period
    Parameters: lcr_id gw_id period
 
 
-   Example 1.56. lcr.defunct_gw RPC example
+   Example 1.57. lcr.defunct_gw RPC example
                 $ kamcmd lcr.defunct_gw 1 4 120
                 $ kamcmd lcr.defunct_gw 1 4 120
 
 
 6. Known Limitations
 6. Known Limitations

+ 43 - 5
modules/lcr/doc/lcr_admin.xml

@@ -44,20 +44,35 @@
 	are ordered for forwarding purposes as follows:
 	are ordered for forwarding purposes as follows:
 	</para>
 	</para>
 	<para>
 	<para>
-	<itemizedlist>
+	<orderedlist>
             <listitem>
             <listitem>
-                <para>(1) according to longest Request-URI user part match
+                <para>according to longest Request-URI user part match
                 </para>
                 </para>
             </listitem>
             </listitem>
             <listitem>
             <listitem>
-                <para>(2) according to tuple's priority
+                <para>according to tuple's priority
                 </para>
                 </para>
             </listitem>
             </listitem>
             <listitem>
             <listitem>
-                <para>(3) according to tuple's randomized weight
+                <para>according to tuple's randomized weight
                 </para>
                 </para>
             </listitem>
             </listitem>
-        </itemizedlist>
+        </orderedlist>
+	</para>
+	<para>
+    or, if priority_ordering parameter is set to value 1, as follows:
+	</para>
+	<para>
+	<orderedlist>
+            <listitem>
+                <para>according to tuple's priority
+                </para>
+            </listitem>
+            <listitem>
+                <para>according to tuple's randomized weight
+                </para>
+            </listitem>
+        </orderedlist>
 	</para>
 	</para>
 	<para>
 	<para>
 	A tuple can be marked as a "stopper" tuple.  If a "stopper"
 	A tuple can be marked as a "stopper" tuple.  If a "stopper"
@@ -970,6 +985,29 @@ modparam("lcr", "dont_strip_or_tag_flag", 10)
                 </example>
                 </example>
 	</section>
 	</section>
 
 
+	<section>
+		<title><varname>priority_ordering</varname> (integer)</title>
+		<para>
+		Defines how matching gateways are ordered (see Overview section).
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0.
+		</emphasis>
+		</para>
+		<example>
+		<title>
+		Setting <varname>priority_ordering</varname> module
+		parameter
+		</title>
+		<programlisting format="linespecific">
+...
+modparam("lcr", "priority_ordering", 1)
+...
+</programlisting>
+                </example>
+	</section>
+
 	<section>
 	<section>
 		<title><varname>fetch_rows</varname> (integer)</title>
 		<title><varname>fetch_rows</varname> (integer)</title>
 		<para>
 		<para>

+ 21 - 2
modules/lcr/lcr_mod.c

@@ -218,6 +218,9 @@ str ping_valid_reply_codes_param = {"", 0};
 str ping_socket_param = {"", 0};
 str ping_socket_param = {"", 0};
 str ping_from_param = {"sip:pinger@localhost", 20};
 str ping_from_param = {"sip:pinger@localhost", 20};
 
 
+/* use priority as main ordering criteria */
+static unsigned int priority_ordering_param = 0;
+
 /*
 /*
  * Other module types and variables
  * Other module types and variables
  */
  */
@@ -345,6 +348,7 @@ static param_export_t params[] = {
     {"lcr_rule_hash_size",       INT_PARAM, &lcr_rule_hash_size_param},
     {"lcr_rule_hash_size",       INT_PARAM, &lcr_rule_hash_size_param},
     {"lcr_gw_count",             INT_PARAM, &lcr_gw_count_param},
     {"lcr_gw_count",             INT_PARAM, &lcr_gw_count_param},
     {"dont_strip_or_prefix_flag",INT_PARAM, &dont_strip_or_prefix_flag_param},
     {"dont_strip_or_prefix_flag",INT_PARAM, &dont_strip_or_prefix_flag_param},
+    {"priority_ordering",        INT_PARAM, &priority_ordering_param},
     {"fetch_rows",               INT_PARAM, &fetch_rows_param},
     {"fetch_rows",               INT_PARAM, &fetch_rows_param},
     {"ping_interval",            INT_PARAM, &ping_interval_param},
     {"ping_interval",            INT_PARAM, &ping_interval_param},
     {"ping_inactivate_threshold",  INT_PARAM, &ping_inactivate_threshold_param},
     {"ping_inactivate_threshold",  INT_PARAM, &ping_inactivate_threshold_param},
@@ -465,6 +469,12 @@ static int mod_init(void)
 	return -1;
 	return -1;
     }
     }
 
 
+    if ((priority_ordering_param != 0) && (priority_ordering_param != 1)) {
+        LM_ERR("invalid priority_ordering value <%d>\n",
+	       priority_ordering_param);
+	return -1;
+    }
+
     /* Process AVP params */
     /* Process AVP params */
 
 
     if (gw_uri_avp_param && *gw_uri_avp_param) {
     if (gw_uri_avp_param && *gw_uri_avp_param) {
@@ -780,6 +790,17 @@ static int comp_matched(const void *m1, const void *m2)
     struct matched_gw_info *mi1 = (struct matched_gw_info *) m1;
     struct matched_gw_info *mi1 = (struct matched_gw_info *) m1;
     struct matched_gw_info *mi2 = (struct matched_gw_info *) m2;
     struct matched_gw_info *mi2 = (struct matched_gw_info *) m2;
 
 
+    if (priority_ordering_param) {
+        /* Sort by priority */
+	if (mi1->priority < mi2->priority) return 1;
+	if (mi1->priority == mi2->priority) {
+	    /* Sort by randomized weigth */
+	    if (mi1->weight > mi2->weight) return 1;
+	    if (mi1->weight == mi2->weight) return 0;
+	}
+	return -1;
+    }
+
     /* Sort by prefix_len */
     /* Sort by prefix_len */
     if (mi1->prefix_len > mi2->prefix_len) return 1;
     if (mi1->prefix_len > mi2->prefix_len) return 1;
     if (mi1->prefix_len == mi2->prefix_len) {
     if (mi1->prefix_len == mi2->prefix_len) {
@@ -789,9 +810,7 @@ static int comp_matched(const void *m1, const void *m2)
 	    /* Sort by randomized weigth */
 	    /* Sort by randomized weigth */
 	    if (mi1->weight > mi2->weight) return 1;
 	    if (mi1->weight > mi2->weight) return 1;
 	    if (mi1->weight == mi2->weight) return 0;
 	    if (mi1->weight == mi2->weight) return 0;
-	    return -1;
 	}
 	}
-	return -1;
     }
     }
     return -1;
     return -1;
 }
 }

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

@@ -837,21 +837,30 @@ start_recording();
 	<section>
 	<section>
 		<title><acronym>MI</acronym> Commands</title>
 		<title><acronym>MI</acronym> Commands</title>
 		<section id="rtpengine.m.nh_enable_rtpp">
 		<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>
 			<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>
 			<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>
 			<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>
 			<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>
 			</para>
 			<example>
 			<example>
 			<title>
 			<title>
@@ -859,28 +868,68 @@ start_recording();
 			<programlisting format="linespecific">
 			<programlisting format="linespecific">
 ...
 ...
 $ &ctltool; fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 $ &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>
 			</programlisting>
 			</example>
 			</example>
 		</section>
 		</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>
 			<para>
 			Displays all the &rtp; proxies and their information: set and
 			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>
 			<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>
 			</para>
 			<example>
 			<example>
 			<title>
 			<title>
 				<function moreinfo="none">nh_show_rtpp</function> usage</title>
 				<function moreinfo="none">nh_show_rtpp</function> usage</title>
 			<programlisting format="linespecific">
 			<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>
 			</programlisting>
 			</example>
 			</example>

+ 500 - 107
modules/rtpengine/rtpengine.c

@@ -102,11 +102,12 @@ MODULE_VERSION
 #define MI_SET_NATPING_STATE		"nh_enable_ping"
 #define MI_SET_NATPING_STATE		"nh_enable_ping"
 #define MI_DEFAULT_NATPING_STATE	1
 #define MI_DEFAULT_NATPING_STATE	1
 
 
-#define MI_ENABLE_RTP_PROXY			"nh_enable_rtpp"
 #define MI_MIN_RECHECK_TICKS		0
 #define MI_MIN_RECHECK_TICKS		0
 #define MI_MAX_RECHECK_TICKS		(unsigned int)-1
 #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_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		"RTP proxy not found"
 #define MI_RTP_PROXY_NOT_FOUND_LEN	(sizeof(MI_RTP_PROXY_NOT_FOUND)-1)
 #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_SET_LEN					(sizeof(MI_SET)-1)
 #define MI_INDEX					"index"
 #define MI_INDEX					"index"
 #define MI_INDEX_LEN				(sizeof(MI_INDEX)-1)
 #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					"disabled"
 #define MI_DISABLED_LEN				(sizeof(MI_DISABLED)-1)
 #define MI_DISABLED_LEN				(sizeof(MI_DISABLED)-1)
 #define MI_WEIGHT					"weight"
 #define MI_WEIGHT					"weight"
@@ -125,6 +128,24 @@ MODULE_VERSION
 #define MI_RECHECK_TICKS			"recheck_ticks"
 #define MI_RECHECK_TICKS			"recheck_ticks"
 #define MI_RECHECK_T_LEN			(sizeof(MI_RECHECK_TICKS)-1)
 #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"
 #define	CPORT		"22222"
@@ -135,6 +156,7 @@ enum rtpe_operation {
 	OP_DELETE,
 	OP_DELETE,
 	OP_START_RECORDING,
 	OP_START_RECORDING,
 	OP_QUERY,
 	OP_QUERY,
+	OP_PING,
 };
 };
 
 
 struct ng_flags_parse {
 struct ng_flags_parse {
@@ -148,6 +170,7 @@ static const char *command_strings[] = {
 	[OP_DELETE]		= "delete",
 	[OP_DELETE]		= "delete",
 	[OP_START_RECORDING]	= "start recording",
 	[OP_START_RECORDING]	= "start recording",
 	[OP_QUERY]		= "query",
 	[OP_QUERY]		= "query",
+	[OP_PING]		= "ping",
 };
 };
 
 
 static char *gencookie();
 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 get_ip_scope(char *str_addr); // useful for link-local ipv6
 static int bind_force_send_ip(int sock_idx);
 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 */
 /* Pseudo-Variables */
 static int pv_get_rtpstat_f(struct sip_msg *, pv_param_t *, pv_value_t *);
 static int pv_get_rtpstat_f(struct sip_msg *, pv_param_t *, pv_value_t *);
 
 
 /*mi commands*/
 /*mi commands*/
 static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree,
 static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree,
 		void* param );
 		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);
 		void* param);
+static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree,
+        void* param);
 
 
 
 
 static int rtpengine_disable_tout = 60;
 static int rtpengine_disable_tout = 60;
@@ -224,6 +255,8 @@ static int_str setid_avp;
 static str            write_sdp_pvar_str = {NULL, 0};
 static str            write_sdp_pvar_str = {NULL, 0};
 static pv_spec_t*     write_sdp_pvar = NULL;
 static pv_spec_t*     write_sdp_pvar = NULL;
 
 
+#define RTPENGINE_SESS_LIMIT_MSG "Parallel session limit reached"
+#define RTPENGINE_SESS_LIMIT_MSG_LEN (sizeof(RTPENGINE_SESS_LIMIT_MSG)-1)
 
 
 char* force_send_ip_str="";
 char* force_send_ip_str="";
 int force_send_ip_af = AF_UNSPEC;
 int force_send_ip_af = AF_UNSPEC;
@@ -303,8 +336,9 @@ static param_export_t params[] = {
 };
 };
 
 
 static mi_export_t mi_cmds[] = {
 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}
 	{ 0, 0, 0, 0, 0}
 };
 };
 
 
@@ -423,7 +457,7 @@ static int bind_force_send_ip(int sock_idx)
 			memset(&tmp, 0, sizeof(tmp));
 			memset(&tmp, 0, sizeof(tmp));
 			getsockname(rtpp_socks[sock_idx], (struct sockaddr *) &tmp, &sock_len);
 			getsockname(rtpp_socks[sock_idx], (struct sockaddr *) &tmp, &sock_len);
 			inet_ntop(AF_INET, &tmp.sin_addr, str_addr, INET_ADDRSTRLEN);
 			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;
 			break;
 
 
@@ -447,7 +481,7 @@ static int bind_force_send_ip(int sock_idx)
 			memset(&tmp6, 0, sizeof(tmp6));
 			memset(&tmp6, 0, sizeof(tmp6));
 			getsockname(rtpp_socks[sock_idx], (struct sockaddr *) &tmp6, &sock_len);
 			getsockname(rtpp_socks[sock_idx], (struct sockaddr *) &tmp6, &sock_len);
 			inet_ntop(AF_INET6, &tmp6.sin6_addr, str_addr6, INET6_ADDRSTRLEN);
 			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;
 			break;
 
 
@@ -779,67 +813,204 @@ static int fixup_set_id(void ** param, int param_no)
 	return 0;
 	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;
 	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;
 	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;
 	rtpp_url = node->value;
 
 
 	node = node->next;
 	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;
 		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;
 	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;
 		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:
 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,\
 #define add_rtpp_node_int_info(_parent, _name, _name_len, _value, _child,\
 								_len, _string, _error)\
 								_len, _string, _error)\
 	do {\
 	do {\
@@ -853,86 +1024,294 @@ error:
 			goto _error;\
 			goto _error;\
 	}while(0);
 	}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 id_len, len;
+    int rtpp_ticks;
+	struct mi_node *crt_node, *child;
+	struct mi_attr *attr;
+	char *string, *id;
 
 
 	string = id = 0;
 	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);
 	root = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 	if (!root) {
 	if (!root) {
 		LM_ERR("the MI tree cannot be initialized!\n");
 		LM_ERR("the MI tree cannot be initialized!\n");
 		return 0;
 		return 0;
 	}
 	}
 
 
-	if(rtpp_set_list ==NULL)
-		return root;
-
 	node = &root->node;
 	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;
 	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;
 		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;
 	return root;
+
 error:
 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
 static int
 mod_init(void)
 mod_init(void)
 {
 {
@@ -1505,6 +1884,7 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_
 		active_rtpp_set = default_rtpp_set;
 		active_rtpp_set = default_rtpp_set;
 
 
 	queried_nodes = 0;
 	queried_nodes = 0;
+select_node:
 	do {
 	do {
 		if (++queried_nodes > queried_nodes_limit) {
 		if (++queried_nodes > queried_nodes_limit) {
 			LM_ERR("queried nodes limit reached\n");
 			LM_ERR("queried nodes limit reached\n");
@@ -1516,6 +1896,10 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_
 			goto error;
 			goto error;
 		}
 		}
 		cp = send_rtpp_command(node, ng_flags.dict, &ret);
 		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);
 	} while (cp == NULL);
 	LM_DBG("proxy reply: %.*s\n", ret, cp);
 	LM_DBG("proxy reply: %.*s\n", ret, cp);
 
 
@@ -1528,11 +1912,19 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_
 		goto error;
 		goto error;
 	}
 	}
 	if (!bencode_dictionary_get_strcmp(resp, "result", "error")) {
 	if (!bencode_dictionary_get_strcmp(resp, "result", "error")) {
-		if (!bencode_dictionary_get_str(resp, "error-reason", &error))
-			LM_ERR("proxy return error but didn't give an error reason: %.*s\n", ret, cp);
-		else
+		if (!bencode_dictionary_get_str(resp, "error-reason", &error)) {
+		    LM_ERR("proxy return error but didn't give an error reason: %.*s\n", ret, cp);
+		}
+		else {
+			if ((RTPENGINE_SESS_LIMIT_MSG_LEN == error.len) && 
+			    (strncmp(error.s, RTPENGINE_SESS_LIMIT_MSG, RTPENGINE_SESS_LIMIT_MSG_LEN) == 0))
+			{
+				LM_WARN("proxy %.*s: %.*s", node->rn_url.len, node->rn_url.s , error.len, error.s);
+				goto select_node;
+			}
 			LM_ERR("proxy replied with error: %.*s\n", error.len, error.s);
 			LM_ERR("proxy replied with error: %.*s\n", error.len, error.s);
-		goto error;
+		}
+        goto error;
 	}
 	}
 
 
 	if (body_out)
 	if (body_out)
@@ -1606,6 +1998,8 @@ rtpp_test(struct rtpp_node *node, int isdisabled, int force)
 
 
 	cp = send_rtpp_command(node, dict, &ret);
 	cp = send_rtpp_command(node, dict, &ret);
 	if (!cp) {
 	if (!cp) {
+	    node->rn_disabled = 1;
+    	node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout;
 		LM_ERR("proxy did not respond to ping\n");
 		LM_ERR("proxy did not respond to ping\n");
 		goto error;
 		goto error;
 	}
 	}
@@ -1638,6 +2032,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 	static char buf[0x10000];
 	static char buf[0x10000];
 	struct pollfd fds[1];
 	struct pollfd fds[1];
 	struct iovec *v;
 	struct iovec *v;
+    str out = STR_NULL;
 
 
 	v = bencode_iovec(dict, &vcnt, 1, 0);
 	v = bencode_iovec(dict, &vcnt, 1, 0);
 	if (!v) {
 	if (!v) {
@@ -1663,7 +2058,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 		}
 		}
 		if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 		if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 			close(fd);
 			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;
 			goto badproxy;
 		}
 		}
 
 
@@ -1672,7 +2067,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 		} while (len == -1 && errno == EINTR);
 		} while (len == -1 && errno == EINTR);
 		if (len <= 0) {
 		if (len <= 0) {
 			close(fd);
 			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;
 			goto badproxy;
 		}
 		}
 		do {
 		do {
@@ -1680,7 +2075,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 		} while (len == -1 && errno == EINTR);
 		} while (len == -1 && errno == EINTR);
 		close(fd);
 		close(fd);
 		if (len <= 0) {
 		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;
 			goto badproxy;
 		}
 		}
 	} else {
 	} else {
@@ -1700,7 +2095,8 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 				len = writev(rtpp_socks[node->idx], v, vcnt + 1);
 				len = writev(rtpp_socks[node->idx], v, vcnt + 1);
 			} while (len == -1 && (errno == EINTR || errno == ENOBUFS));
 			} while (len == -1 && (errno == EINTR || errno == ENOBUFS));
 			if (len <= 0) {
 			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;
 				goto badproxy;
 			}
 			}
 			while ((poll(fds, 1, rtpengine_tout_ms) == 1) &&
 			while ((poll(fds, 1, rtpengine_tout_ms) == 1) &&
@@ -1709,7 +2105,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);
 					len = recv(rtpp_socks[node->idx], buf, sizeof(buf)-1, 0);
 				} while (len == -1 && errno == EINTR);
 				} while (len == -1 && errno == EINTR);
 				if (len <= 0) {
 				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;
 					goto badproxy;
 				}
 				}
 				if (len >= (v[0].iov_len - 1) &&
 				if (len >= (v[0].iov_len - 1) &&
@@ -1726,7 +2122,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
 			}
 			}
 		}
 		}
 		if (i == rtpengine_retr) {
 		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;
 			goto badproxy;
 		}
 		}
 	}
 	}
@@ -1735,11 +2131,8 @@ out:
 	cp[len] = '\0';
 	cp[len] = '\0';
 	*outlen = len;
 	*outlen = len;
 	return cp;
 	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;
 	return NULL;
 }
 }