浏览代码

modules/dispatcher: added per gateway and global send socket configuration

fcabiddu 11 年之前
父节点
当前提交
aae775859f

+ 142 - 102
modules/dispatcher/README

@@ -50,20 +50,22 @@ Carsten Bock
               3.13. cnt_avp (str)
               3.13. cnt_avp (str)
               3.14. dstid_avp (str)
               3.14. dstid_avp (str)
               3.15. attrs_avp (str)
               3.15. attrs_avp (str)
-              3.16. hash_pvar (str)
-              3.17. setid_pvname (str)
-              3.18. attrs_pvname (str)
-              3.19. ds_ping_method (string)
-              3.20. ds_ping_from (string)
-              3.21. ds_ping_interval (int)
-              3.22. ds_probing_threshold (int)
-              3.23. ds_ping_reply_codes (string)
-              3.24. ds_probing_mode (int)
-              3.25. ds_hash_size (int)
-              3.26. ds_hash_expire (int)
-              3.27. ds_hash_initexpire (int)
-              3.28. ds_hash_check_interval (int)
-              3.29. outbound_proxy (str)
+              3.16. sock_avp (str)
+              3.17. hash_pvar (str)
+              3.18. setid_pvname (str)
+              3.19. attrs_pvname (str)
+              3.20. ds_ping_method (string)
+              3.21. ds_ping_from (string)
+              3.22. ds_ping_interval (int)
+              3.23. ds_probing_threshold (int)
+              3.24. ds_ping_reply_codes (string)
+              3.25. ds_probing_mode (int)
+              3.26. ds_hash_size (int)
+              3.27. ds_hash_expire (int)
+              3.28. ds_hash_initexpire (int)
+              3.29. ds_hash_check_interval (int)
+              3.30. outbound_proxy (str)
+              3.31. ds_default_socket (str)
 
 
         4. Functions
         4. Functions
 
 
@@ -117,27 +119,29 @@ Carsten Bock
    1.13. Set the "cnt_avp" parameter
    1.13. Set the "cnt_avp" parameter
    1.14. Set the "dstid_avp" parameter
    1.14. Set the "dstid_avp" parameter
    1.15. Set the "attrs_avp" parameter
    1.15. Set the "attrs_avp" parameter
-   1.16. Use $avp(i:273) for hashing:
-   1.17. Use combination of PVs for hashing:
-   1.18. Set the "setid_pvname" parameter
-   1.19. Set the "attrs_pvname" parameter
-   1.20. Set the "ds_ping_method" parameter
-   1.21. Set the "ds_ping_from" parameter
-   1.22. Set the "ds_ping_interval" parameter
-   1.23. Set the "ds_probing_threshhold" parameter
-   1.24. Set the "ds_ping_reply_codes" parameter
-   1.25. Set the "ds_probing_mode" parameter
-   1.26. Set the "ds_hash_size" parameter
-   1.27. Set the "ds_hash_expire" parameter
-   1.28. Set the "ds_hash_initexpire" parameter
-   1.29. Set the "ds_hash_check_interval" parameter
-   1.30. Set the "outbound_proxy" parameter
-   1.31. ds_select_dst usage
-   1.32. ds_mark_dst usage
-   1.33. ds_mark_dst usage
-   1.34. ds_load_unset usage
-   1.35. dispatcher list file
-   1.36. Kamailio config script - sample dispatcher usage
+   1.16. Set the "sock_avp" parameter
+   1.17. Use $avp(i:273) for hashing:
+   1.18. Use combination of PVs for hashing:
+   1.19. Set the "setid_pvname" parameter
+   1.20. Set the "attrs_pvname" parameter
+   1.21. Set the "ds_ping_method" parameter
+   1.22. Set the "ds_ping_from" parameter
+   1.23. Set the "ds_ping_interval" parameter
+   1.24. Set the "ds_probing_threshhold" parameter
+   1.25. Set the "ds_ping_reply_codes" parameter
+   1.26. Set the "ds_probing_mode" parameter
+   1.27. Set the "ds_hash_size" parameter
+   1.28. Set the "ds_hash_expire" parameter
+   1.29. Set the "ds_hash_initexpire" parameter
+   1.30. Set the "ds_hash_check_interval" parameter
+   1.31. Set the "outbound_proxy" parameter
+   1.32. Set the "ds_default_socket" parameter
+   1.33. ds_select_dst usage
+   1.34. ds_mark_dst usage
+   1.35. ds_mark_dst usage
+   1.36. ds_load_unset usage
+   1.37. dispatcher list file
+   1.38. Kamailio config script - sample dispatcher usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -166,20 +170,22 @@ Chapter 1. Admin Guide
         3.13. cnt_avp (str)
         3.13. cnt_avp (str)
         3.14. dstid_avp (str)
         3.14. dstid_avp (str)
         3.15. attrs_avp (str)
         3.15. attrs_avp (str)
-        3.16. hash_pvar (str)
-        3.17. setid_pvname (str)
-        3.18. attrs_pvname (str)
-        3.19. ds_ping_method (string)
-        3.20. ds_ping_from (string)
-        3.21. ds_ping_interval (int)
-        3.22. ds_probing_threshold (int)
-        3.23. ds_ping_reply_codes (string)
-        3.24. ds_probing_mode (int)
-        3.25. ds_hash_size (int)
-        3.26. ds_hash_expire (int)
-        3.27. ds_hash_initexpire (int)
-        3.28. ds_hash_check_interval (int)
-        3.29. outbound_proxy (str)
+        3.16. sock_avp (str)
+        3.17. hash_pvar (str)
+        3.18. setid_pvname (str)
+        3.19. attrs_pvname (str)
+        3.20. ds_ping_method (string)
+        3.21. ds_ping_from (string)
+        3.22. ds_ping_interval (int)
+        3.23. ds_probing_threshold (int)
+        3.24. ds_ping_reply_codes (string)
+        3.25. ds_probing_mode (int)
+        3.26. ds_hash_size (int)
+        3.27. ds_hash_expire (int)
+        3.28. ds_hash_initexpire (int)
+        3.29. ds_hash_check_interval (int)
+        3.30. outbound_proxy (str)
+        3.31. ds_default_socket (str)
 
 
    4. Functions
    4. Functions
 
 
@@ -265,20 +271,22 @@ Chapter 1. Admin Guide
    3.13. cnt_avp (str)
    3.13. cnt_avp (str)
    3.14. dstid_avp (str)
    3.14. dstid_avp (str)
    3.15. attrs_avp (str)
    3.15. attrs_avp (str)
-   3.16. hash_pvar (str)
-   3.17. setid_pvname (str)
-   3.18. attrs_pvname (str)
-   3.19. ds_ping_method (string)
-   3.20. ds_ping_from (string)
-   3.21. ds_ping_interval (int)
-   3.22. ds_probing_threshold (int)
-   3.23. ds_ping_reply_codes (string)
-   3.24. ds_probing_mode (int)
-   3.25. ds_hash_size (int)
-   3.26. ds_hash_expire (int)
-   3.27. ds_hash_initexpire (int)
-   3.28. ds_hash_check_interval (int)
-   3.29. outbound_proxy (str)
+   3.16. sock_avp (str)
+   3.17. hash_pvar (str)
+   3.18. setid_pvname (str)
+   3.19. attrs_pvname (str)
+   3.20. ds_ping_method (string)
+   3.21. ds_ping_from (string)
+   3.22. ds_ping_interval (int)
+   3.23. ds_probing_threshold (int)
+   3.24. ds_ping_reply_codes (string)
+   3.25. ds_probing_mode (int)
+   3.26. ds_hash_size (int)
+   3.27. ds_hash_expire (int)
+   3.28. ds_hash_initexpire (int)
+   3.29. ds_hash_check_interval (int)
+   3.30. outbound_proxy (str)
+   3.31. ds_default_socket (str)
 
 
 3.1. list_file (string)
 3.1. list_file (string)
 
 
@@ -492,7 +500,24 @@ Note
  modparam("dispatcher", "attrs_avp", "$avp(dsattrs)")
  modparam("dispatcher", "attrs_avp", "$avp(dsattrs)")
  ...
  ...
 
 
-3.16. hash_pvar (str)
+3.16. sock_avp (str)
+
+   The name of the avp which will hold the list with the sockets
+   associated to the addresses stored in dst_avp avp.
+
+Note
+
+   If you want to do load balancing fail over, you have to set this
+   parameter to use the correct socket for each gateway.
+
+   Default value is "null" - don't add AVPs.
+
+   Example 1.16. Set the "sock_avp" parameter
+ ...
+ modparam("dispatcher", "sock_avp", "$avp(dssocket)")
+ ...
+
+3.17. hash_pvar (str)
 
 
    String with PVs used for the hashing algorithm 7.
    String with PVs used for the hashing algorithm 7.
 
 
@@ -503,41 +528,41 @@ Note
 
 
    Default value is "null" - disabled.
    Default value is "null" - disabled.
 
 
-   Example 1.16. Use $avp(i:273) for hashing:
+   Example 1.17. Use $avp(i:273) for hashing:
  ...
  ...
  modparam("dispatcher", "hash_pvar", "$avp(i:273)")
  modparam("dispatcher", "hash_pvar", "$avp(i:273)")
  ...
  ...
 
 
-   Example 1.17. Use combination of PVs for hashing:
+   Example 1.18. Use combination of PVs for hashing:
  ...
  ...
  modparam("dispatcher", "hash_pvar", "hash the $fU@$ci")
  modparam("dispatcher", "hash_pvar", "hash the $fU@$ci")
  ...
  ...
 
 
-3.17. setid_pvname (str)
+3.18. setid_pvname (str)
 
 
    The name of the PV where to store the set ID (group ID) when calling
    The name of the PV where to store the set ID (group ID) when calling
    ds_is_from_list() with no parameter.
    ds_is_from_list() with no parameter.
 
 
    Default value is "null" - don't set PV.
    Default value is "null" - don't set PV.
 
 
-   Example 1.18. Set the "setid_pvname" parameter
+   Example 1.19. Set the "setid_pvname" parameter
  ...
  ...
  modparam("dispatcher", "setid_pvname", "$var(setid)")
  modparam("dispatcher", "setid_pvname", "$var(setid)")
  ...
  ...
 
 
-3.18. attrs_pvname (str)
+3.19. attrs_pvname (str)
 
 
    The name of the PV where to store the attributes of matching address
    The name of the PV where to store the attributes of matching address
    when calling ds_is_from_list().
    when calling ds_is_from_list().
 
 
    Default value is "null" - don't set PV.
    Default value is "null" - don't set PV.
 
 
-   Example 1.19. Set the "attrs_pvname" parameter
+   Example 1.20. Set the "attrs_pvname" parameter
  ...
  ...
  modparam("dispatcher", "attrs_pvname", "$var(attrs)")
  modparam("dispatcher", "attrs_pvname", "$var(attrs)")
  ...
  ...
 
 
-3.19. ds_ping_method (string)
+3.20. ds_ping_method (string)
 
 
    With this method you can define, with which method you want to probe
    With this method you can define, with which method you want to probe
    the gateways. Pinging gateways feature depends on ds_ping_interval
    the gateways. Pinging gateways feature depends on ds_ping_interval
@@ -545,12 +570,12 @@ Note
 
 
    Default value is "OPTIONS".
    Default value is "OPTIONS".
 
 
-   Example 1.20. Set the "ds_ping_method" parameter
+   Example 1.21. Set the "ds_ping_method" parameter
  ...
  ...
  modparam("dispatcher", "ds_ping_method", "INFO")
  modparam("dispatcher", "ds_ping_method", "INFO")
  ...
  ...
 
 
-3.20. ds_ping_from (string)
+3.21. ds_ping_from (string)
 
 
    With this Method you can define the "From:"-Line for the request, sent
    With this Method you can define the "From:"-Line for the request, sent
    to the failed gateways. This method is only available, if compiled with
    to the failed gateways. This method is only available, if compiled with
@@ -558,12 +583,12 @@ Note
 
 
    Default value is "sip:dispatcher@localhost".
    Default value is "sip:dispatcher@localhost".
 
 
-   Example 1.21. Set the "ds_ping_from" parameter
+   Example 1.22. Set the "ds_ping_from" parameter
  ...
  ...
  modparam("dispatcher", "ds_ping_from", "sip:[email protected]")
  modparam("dispatcher", "ds_ping_from", "sip:[email protected]")
  ...
  ...
 
 
-3.21. ds_ping_interval (int)
+3.22. ds_ping_interval (int)
 
 
    With this parameter you can define the interval for sending a request
    With this parameter you can define the interval for sending a request
    to a gateway marked as inactive upon a failed request routing to it.
    to a gateway marked as inactive upon a failed request routing to it.
@@ -572,12 +597,12 @@ Note
 
 
    Default value is "0".
    Default value is "0".
 
 
-   Example 1.22. Set the "ds_ping_interval" parameter
+   Example 1.23. Set the "ds_ping_interval" parameter
  ...
  ...
  modparam("dispatcher", "ds_ping_interval", 30)
  modparam("dispatcher", "ds_ping_interval", 30)
  ...
  ...
 
 
-3.22. ds_probing_threshold (int)
+3.23. ds_probing_threshold (int)
 
 
    If you want to set a gateway into inactive mode, there can be a
    If you want to set a gateway into inactive mode, there can be a
    specific number of failed requests until it will change from "active"
    specific number of failed requests until it will change from "active"
@@ -588,12 +613,12 @@ Note
 
 
    Default value is "1" (set inactive with first failure).
    Default value is "1" (set inactive with first failure).
 
 
-   Example 1.23. Set the "ds_probing_threshhold" parameter
+   Example 1.24. Set the "ds_probing_threshhold" parameter
  ...
  ...
  modparam("dispatcher", "ds_probing_threshhold", 10)
  modparam("dispatcher", "ds_probing_threshhold", 10)
  ...
  ...
 
 
-3.23. ds_ping_reply_codes (string)
+3.24. ds_ping_reply_codes (string)
 
 
    This parameter defines the valid response codes, which are accepted as
    This parameter defines the valid response codes, which are accepted as
    a valid reply to the PING-Method. It is a list separated by colons,
    a valid reply to the PING-Method. It is a list separated by colons,
@@ -605,13 +630,13 @@ Note
 
 
    Default value is "" (only 200 OK is accepted).
    Default value is "" (only 200 OK is accepted).
 
 
-   Example 1.24. Set the "ds_ping_reply_codes" parameter
+   Example 1.25. Set the "ds_ping_reply_codes" parameter
  ...
  ...
  modparam("dispatcher", "ds_ping_reply_codes", "class=2;code=403;code=488;class=
  modparam("dispatcher", "ds_ping_reply_codes", "class=2;code=403;code=488;class=
 3")
 3")
  ...
  ...
 
 
-3.24. ds_probing_mode (int)
+3.25. ds_probing_mode (int)
 
 
    Controls what gateways are tested to see if they are reachable. If set
    Controls what gateways are tested to see if they are reachable. If set
    to 0, only the gateways with state PROBING are tested; if set to 1, all
    to 0, only the gateways with state PROBING are tested; if set to 1, all
@@ -621,12 +646,12 @@ Note
 
 
    Default value is "0".
    Default value is "0".
 
 
-   Example 1.25. Set the "ds_probing_mode" parameter
+   Example 1.26. Set the "ds_probing_mode" parameter
  ...
  ...
  modparam("dispatcher", "ds_probing_mode", 1)
  modparam("dispatcher", "ds_probing_mode", 1)
  ...
  ...
 
 
-3.25. ds_hash_size (int)
+3.26. ds_hash_size (int)
 
 
    The value to be used as power of two to set the number of slots to hash
    The value to be used as power of two to set the number of slots to hash
    table storing data for call load dispatching (e.g., value 8 will create
    table storing data for call load dispatching (e.g., value 8 will create
@@ -635,24 +660,24 @@ Note
 
 
    Default value is "0".
    Default value is "0".
 
 
-   Example 1.26. Set the "ds_hash_size" parameter
+   Example 1.27. Set the "ds_hash_size" parameter
  ...
  ...
  modparam("dispatcher", "ds_hash_size", 9)
  modparam("dispatcher", "ds_hash_size", 9)
  ...
  ...
 
 
-3.26. ds_hash_expire (int)
+3.27. ds_hash_expire (int)
 
 
    Expiration time in seconds to remove the load on a destination if no
    Expiration time in seconds to remove the load on a destination if no
    BYE was received meanwhile.
    BYE was received meanwhile.
 
 
    Default value is "7200".
    Default value is "7200".
 
 
-   Example 1.27. Set the "ds_hash_expire" parameter
+   Example 1.28. Set the "ds_hash_expire" parameter
  ...
  ...
  modparam("dispatcher", "ds_hash_expire", 3600)
  modparam("dispatcher", "ds_hash_expire", 3600)
  ...
  ...
 
 
-3.27. ds_hash_initexpire (int)
+3.28. ds_hash_initexpire (int)
 
 
    Expiration time in seconds to remove the load on a destination if no
    Expiration time in seconds to remove the load on a destination if no
    200 for INVITE was received meanwhile and state updated with
    200 for INVITE was received meanwhile and state updated with
@@ -660,34 +685,47 @@ Note
 
 
    Default value is "7200".
    Default value is "7200".
 
 
-   Example 1.28. Set the "ds_hash_initexpire" parameter
+   Example 1.29. Set the "ds_hash_initexpire" parameter
  ...
  ...
  modparam("dispatcher", "ds_hash_initexpire", 60)
  modparam("dispatcher", "ds_hash_initexpire", 60)
  ...
  ...
 
 
-3.28. ds_hash_check_interval (int)
+3.29. ds_hash_check_interval (int)
 
 
    Time interval in seconds to scan internal hash table with call load
    Time interval in seconds to scan internal hash table with call load
    dispatching data for expired items.
    dispatching data for expired items.
 
 
    Default value is "30".
    Default value is "30".
 
 
-   Example 1.29. Set the "ds_hash_check_interval" parameter
+   Example 1.30. Set the "ds_hash_check_interval" parameter
  ...
  ...
  modparam("dispatcher", "ds_hash_check_interval", 60)
  modparam("dispatcher", "ds_hash_check_interval", 60)
  ...
  ...
 
 
-3.29. outbound_proxy (str)
+3.30. outbound_proxy (str)
 
 
    SIP URI of outbound proxy to be used when sending pings.
    SIP URI of outbound proxy to be used when sending pings.
 
 
    By default no outbound proxy is defined.
    By default no outbound proxy is defined.
 
 
-   Example 1.30. Set the "outbound_proxy" parameter
+   Example 1.31. Set the "outbound_proxy" parameter
  ...
  ...
  modparam("dispatcher", "outbound_proxy", "sip:outbound.example.com")
  modparam("dispatcher", "outbound_proxy", "sip:outbound.example.com")
  ...
  ...
 
 
+3.31. ds_default_socket (str)
+
+   Default socket to be used for sending pings and dispatching requests
+   when a gateway has no send socket configured.
+
+   By default no default socket is defined, the first configuration script
+   listen directive is used.
+
+   Example 1.32. Set the "ds_default_socket" parameter
+ ...
+ modparam("dispatcher", "ds_default_socket", "udp:192.168.0.125:5060")
+ ...
+
 4. Functions
 4. Functions
 
 
    4.1. ds_select_dst(set, alg[, limit])
    4.1. ds_select_dst(set, alg[, limit])
@@ -760,7 +798,7 @@ Note
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.31. ds_select_dst usage
+   Example 1.33. ds_select_dst usage
 ...
 ...
 ds_select_dst("1", "0");
 ds_select_dst("1", "0");
 ...
 ...
@@ -824,7 +862,7 @@ ds_select_dst("1", "4", "3");
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.32. ds_mark_dst usage
+   Example 1.34. ds_mark_dst usage
 ...
 ...
 failure_route[tryagain] {
 failure_route[tryagain] {
 ...
 ...
@@ -870,7 +908,7 @@ failure_route[tryagain] {
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.33. ds_mark_dst usage
+   Example 1.35. ds_mark_dst usage
 ...
 ...
 if(ds_is_from_list()) {
 if(ds_is_from_list()) {
     ...
     ...
@@ -901,7 +939,7 @@ if(ds_is_from_list("10", "sip:127.0.0.1:5080", "3")) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE and ONREPLY_ROUTE.
    BRANCH_ROUTE and ONREPLY_ROUTE.
 
 
-   Example 1.34. ds_load_unset usage
+   Example 1.36. ds_load_unset usage
 ...
 ...
 route {
 route {
     ...
     ...
@@ -1056,9 +1094,11 @@ kamcmd dispatcher.set_state ip 2 sip:127.0.0.1:5080
        probing destination (sending keep alives);
        probing destination (sending keep alives);
      * priority: sets the priority in destination list (based on it is
      * priority: sets the priority in destination list (based on it is
        done the initial ordering inside the set)
        done the initial ordering inside the set)
-     * attributes: extra filed in form of name1=value1;...;nameN=valueN.
-       There are some predefined names that are used of weight and call
-       load dispatching.
+     * attributes: extra field in form of name1=value1;...;nameN=valueN.
+       There are some predefined names:
+          + 'duid' - used for call load dispatching
+          + 'weight' - used for weight based load distribution
+          + 'socket' - used to set the sending socket for the gateway
 
 
    Line format is:
    Line format is:
 ...
 ...
@@ -1067,13 +1107,13 @@ setid(int) destination(sip uri) flags(int,opt) priority(int,opt) attrs(str,opt)
 
 
    Full line example:
    Full line example:
 ...
 ...
-1 sip:127.0.0.1:5080 0 0 duid=abc;my=xyz
+1 sip:127.0.0.1:5080 0 0 duid=abc;socket=udp:192.168.0.125:5060;my=xyz
 ...
 ...
 
 
    For database, each element of a line resides in a different column.
    For database, each element of a line resides in a different column.
    Next is a dispatcher.list file example:
    Next is a dispatcher.list file example:
 
 
-   Example 1.35. dispatcher list file
+   Example 1.37. dispatcher list file
 ...
 ...
 # $Id$
 # $Id$
 # dispatcher destination sets
 # dispatcher destination sets
@@ -1098,7 +1138,7 @@ r,opt)
 
 
    Next picture shows a sample usage of the dispatcher module.
    Next picture shows a sample usage of the dispatcher module.
 
 
-   Example 1.36. Kamailio config script - sample dispatcher usage
+   Example 1.38. Kamailio config script - sample dispatcher usage
 ...
 ...
 #!KAMAILIO
 #!KAMAILIO
 #
 #

+ 95 - 5
modules/dispatcher/dispatch.c

@@ -232,6 +232,9 @@ int ds_set_attrs(ds_dest_t *dest, str *attrs)
 		} else if(pit->name.len==7
 		} else if(pit->name.len==7
 				&& strncasecmp(pit->name.s, "maxload", 7)==0) {
 				&& strncasecmp(pit->name.s, "maxload", 7)==0) {
 			str2sint(&pit->body, &dest->attrs.maxload);
 			str2sint(&pit->body, &dest->attrs.maxload);
+		} else if(pit->name.len==6
+				&& strncasecmp(pit->name.s, "socket", 6)==0) {
+			dest->attrs.socket = pit->body;
 		}
 		}
 	}
 	}
 	return 0;
 	return 0;
@@ -253,6 +256,8 @@ int add_dest2list(int id, str uri, int flags, int priority, str *attrs,
 	struct hostent* he;
 	struct hostent* he;
 	struct sip_uri puri;
 	struct sip_uri puri;
 	int orig_id = 0, orig_nr = 0;
 	int orig_id = 0, orig_nr = 0;
+	str host;
+	int port, proto;
 	ds_set_t *orig_ds_lists = ds_lists[list_idx];
 	ds_set_t *orig_ds_lists = ds_lists[list_idx];
 
 
 	/* check uri */
 	/* check uri */
@@ -315,6 +320,7 @@ int add_dest2list(int id, str uri, int flags, int priority, str *attrs,
 	strncpy(dp->uri.s, uri.s, uri.len);
 	strncpy(dp->uri.s, uri.s, uri.len);
 	dp->uri.s[uri.len]='\0';
 	dp->uri.s[uri.len]='\0';
 	dp->uri.len = uri.len;
 	dp->uri.len = uri.len;
+
 	dp->flags = flags;
 	dp->flags = flags;
 	dp->priority = priority;
 	dp->priority = priority;
 
 
@@ -324,6 +330,22 @@ int add_dest2list(int id, str uri, int flags, int priority, str *attrs,
 		goto err;
 		goto err;
 	}
 	}
 
 
+	/* check socket attribute */
+	if (dp->attrs.socket.s && dp->attrs.socket.len > 0) {
+		if (parse_phostport(dp->attrs.socket.s, &host.s, &host.len,
+				&port, &proto)!=0) {
+			LM_ERR("bad socket <%.*s>\n", dp->attrs.socket.len, dp->attrs.socket.s);
+			goto err;
+		}
+		dp->sock = grep_sock_info( &host, (unsigned short)port, proto);
+		if (dp->sock==0) {
+			LM_ERR("non-local socket <%.*s>\n", dp->attrs.socket.len, dp->attrs.socket.s);
+			goto err;
+		}
+	} else if (ds_default_sockinfo) {
+		dp->sock = ds_default_sockinfo;
+	}
+
 	/* The Hostname needs to be \0 terminated for resolvehost, so we
 	/* The Hostname needs to be \0 terminated for resolvehost, so we
 	 * make a copy here. */
 	 * make a copy here. */
 	strncpy(hn, puri.host.s, puri.host.len);
 	strncpy(hn, puri.host.s, puri.host.len);
@@ -580,11 +602,11 @@ int ds_load_list(char *lfile)
 		while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
 		while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
 			p++;
 			p++;
 		if(*p=='\0' || *p=='#')
 		if(*p=='\0' || *p=='#')
-			goto add_destination; /* no priority given */
+			goto add_destination; /* no attrs given */
 
 
 		/* get attributes */
 		/* get attributes */
 		attrs.s = p;
 		attrs.s = p;
-		while(*p && *p!=' ' && *p!='\t' && *p!='\r' && *p!='\n' && *p!='#')
+		while(*p && *p!=' ' && *p!='\t' && *p!='\r' && *p!='\n')
 			p++;
 			p++;
 		attrs.len = p-attrs.s;
 		attrs.len = p-attrs.s;
 
 
@@ -1556,7 +1578,8 @@ int ds_load_unset(struct sip_msg *msg)
 /**
 /**
  *
  *
  */
  */
-static inline int ds_update_dst(struct sip_msg *msg, str *uri, int mode)
+static inline int ds_update_dst(struct sip_msg *msg, str *uri,
+								struct socket_info *sock, int mode)
 {
 {
 	struct action act;
 	struct action act;
 	struct run_act_ctx ra_ctx;
 	struct run_act_ctx ra_ctx;
@@ -1587,6 +1610,8 @@ static inline int ds_update_dst(struct sip_msg *msg, str *uri, int mode)
 			ruri_mark_new(); /* re-use uri for serial forking */
 			ruri_mark_new(); /* re-use uri for serial forking */
 			break;
 			break;
 	}
 	}
+	if (sock)
+		msg->force_send_socket = sock;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1604,6 +1629,7 @@ int ds_select_dst_limit(struct sip_msg *msg, int set, int alg, unsigned int limi
 	unsigned int hash;
 	unsigned int hash;
 	int_str avp_val;
 	int_str avp_val;
 	ds_set_t *idx = NULL;
 	ds_set_t *idx = NULL;
+	char buf[2+16+1];
 
 
 	if(msg==NULL)
 	if(msg==NULL)
 	{
 	{
@@ -1773,7 +1799,7 @@ int ds_select_dst_limit(struct sip_msg *msg, int set, int alg, unsigned int limi
 
 
 	hash = i;
 	hash = i;
 
 
-	if(ds_update_dst(msg, &idx->dlist[hash].uri, mode)!=0)
+	if(ds_update_dst(msg, &idx->dlist[hash].uri, idx->dlist[hash].sock, mode)!=0)
 	{
 	{
 		LM_ERR("cannot set dst addr\n");
 		LM_ERR("cannot set dst addr\n");
 		return -1;
 		return -1;
@@ -1804,6 +1830,17 @@ int ds_select_dst_limit(struct sip_msg *msg, int set, int alg, unsigned int limi
 							avp_val)!=0)
 							avp_val)!=0)
 					return -1;
 					return -1;
 			}
 			}
+
+			/* only add sock_avp if dst_avp is set */
+			if(sock_avp_name.n!=0 && idx->dlist[idx->nr-1].sock)
+			{
+				avp_val.s.len = 1 + sprintf(buf, "%p", idx->dlist[idx->nr-1].sock);
+				avp_val.s.s = buf;
+				if(add_avp(AVP_VAL_STR|sock_avp_type, sock_avp_name,
+							avp_val)!=0)
+					return -1;
+			}
+
 			if(alg==DS_ALG_LOAD)
 			if(alg==DS_ALG_LOAD)
 			{
 			{
 				if(idx->dlist[idx->nr-1].attrs.duid.len<=0)
 				if(idx->dlist[idx->nr-1].attrs.duid.len<=0)
@@ -1840,6 +1877,16 @@ int ds_select_dst_limit(struct sip_msg *msg, int set, int alg, unsigned int limi
 							avp_val)!=0)
 							avp_val)!=0)
 					return -1;
 					return -1;
 			}
 			}
+
+			if(sock_avp_name.n!=0 && idx->dlist[i].sock)
+			{
+				avp_val.s.len = 1 + sprintf(buf, "%p", idx->dlist[i].sock);
+				avp_val.s.s = buf;
+				if(add_avp(AVP_VAL_STR|sock_avp_type, sock_avp_name,
+							avp_val)!=0)
+					return -1;
+			}
+
 			if(alg==DS_ALG_LOAD)
 			if(alg==DS_ALG_LOAD)
 			{
 			{
 				if(idx->dlist[i].attrs.duid.len<=0)
 				if(idx->dlist[i].attrs.duid.len<=0)
@@ -1874,6 +1921,16 @@ int ds_select_dst_limit(struct sip_msg *msg, int set, int alg, unsigned int limi
 							avp_val)!=0)
 							avp_val)!=0)
 					return -1;
 					return -1;
 			}
 			}
+
+			if(sock_avp_name.n!=0 && idx->dlist[i].sock)
+			{
+				avp_val.s.len = 1 + sprintf(buf, "%p", idx->dlist[i].sock);
+				avp_val.s.s = buf;
+				if(add_avp(AVP_VAL_STR|sock_avp_type, sock_avp_name,
+							avp_val)!=0)
+					return -1;
+			}
+
 			if(alg==DS_ALG_LOAD)
 			if(alg==DS_ALG_LOAD)
 			{
 			{
 				if(idx->dlist[i].attrs.duid.len<=0)
 				if(idx->dlist[i].attrs.duid.len<=0)
@@ -1903,6 +1960,15 @@ int ds_select_dst_limit(struct sip_msg *msg, int set, int alg, unsigned int limi
 						avp_val)!=0)
 						avp_val)!=0)
 				return -1;
 				return -1;
 		}
 		}
+		if(sock_avp_name.n!=0 && idx->dlist[hash].sock)
+		{
+			avp_val.s.len = 1 + sprintf(buf, "%p", idx->dlist[hash].sock);
+			avp_val.s.s = buf;
+			if(add_avp(AVP_VAL_STR|sock_avp_type, sock_avp_name,
+						avp_val)!=0)
+				return -1;
+		}
+
 		if(alg==DS_ALG_LOAD)
 		if(alg==DS_ALG_LOAD)
 		{
 		{
 			if(idx->dlist[hash].attrs.duid.len<=0)
 			if(idx->dlist[hash].attrs.duid.len<=0)
@@ -1944,7 +2010,9 @@ int ds_next_dst(struct sip_msg *msg, int mode)
 	struct search_state st;
 	struct search_state st;
 	struct usr_avp *avp;
 	struct usr_avp *avp;
 	struct usr_avp *prev_avp;
 	struct usr_avp *prev_avp;
+	struct socket_info *sock;
 	int_str avp_value;
 	int_str avp_value;
+	int_str sock_avp_value;
 	int alg = 0;
 	int alg = 0;
 
 
 	if(!(ds_flags&DS_FAILOVER_ON) || dst_avp_name.n==0)
 	if(!(ds_flags&DS_FAILOVER_ON) || dst_avp_name.n==0)
@@ -1976,6 +2044,20 @@ int ds_next_dst(struct sip_msg *msg, int mode)
 		}
 		}
 	}
 	}
 
 
+	if(sock_avp_name.n!=0)
+	{
+		prev_avp = search_first_avp(sock_avp_type,
+				attrs_avp_name, &avp_value, &st);
+		if(prev_avp!=NULL)
+		{
+			if (sscanf( sock_avp_value.s.s, "%p", (void**)&sock ) != 1)
+				sock = NULL;
+			destroy_avp(prev_avp);
+		} else {
+			sock = NULL;
+		}
+	}
+
 	prev_avp = search_first_avp(dst_avp_type, dst_avp_name, &avp_value, &st);
 	prev_avp = search_first_avp(dst_avp_type, dst_avp_name, &avp_value, &st);
 	if(prev_avp==NULL)
 	if(prev_avp==NULL)
 		return -1; /* used avp deleted -- strange */
 		return -1; /* used avp deleted -- strange */
@@ -1985,7 +2067,7 @@ int ds_next_dst(struct sip_msg *msg, int mode)
 	if(avp==NULL || !(avp->flags&AVP_VAL_STR))
 	if(avp==NULL || !(avp->flags&AVP_VAL_STR))
 		return -1; /* no more avps or value is int */
 		return -1; /* no more avps or value is int */
 
 
-	if(ds_update_dst(msg, &avp_value.s, mode)!=0)
+	if(ds_update_dst(msg, &avp_value.s, sock, mode)!=0)
 	{
 	{
 		LM_ERR("cannot set dst addr\n");
 		LM_ERR("cannot set dst addr\n");
 		return -1;
 		return -1;
@@ -2381,6 +2463,9 @@ int ds_print_mi_list(struct mi_node* rpl)
 			if(node == NULL)
 			if(node == NULL)
 				return -1;
 				return -1;
 
 
+			if(attr == 0)
+				return -1;
+
 			memset(&c, 0, sizeof(c));
 			memset(&c, 0, sizeof(c));
 			if (list->dlist[j].flags & DS_INACTIVE_DST)
 			if (list->dlist[j].flags & DS_INACTIVE_DST)
 				c[0] = 'I';
 				c[0] = 'I';
@@ -2519,6 +2604,11 @@ void ds_check_timer(unsigned int ticks, void* param)
 				set_uac_req(&uac_r, &ds_ping_method, 0, 0, 0,
 				set_uac_req(&uac_r, &ds_ping_method, 0, 0, 0,
 						TMCB_LOCAL_COMPLETED, ds_options_callback,
 						TMCB_LOCAL_COMPLETED, ds_options_callback,
 						(void*)(long)list->id);
 						(void*)(long)list->id);
+				if (list->dlist[j].attrs.socket.s != NULL && list->dlist[j].attrs.socket.len > 0) {
+					uac_r.ssock = &list->dlist[j].attrs.socket;
+				} else if (ds_default_socket.s != NULL && ds_default_socket.len > 0) {
+					uac_r.ssock = &ds_default_socket;
+				}
 				if (tmb.t_request(&uac_r,
 				if (tmb.t_request(&uac_r,
 							&list->dlist[j].uri,
 							&list->dlist[j].uri,
 							&list->dlist[j].uri,
 							&list->dlist[j].uri,

+ 6 - 0
modules/dispatcher/dispatch.h

@@ -86,6 +86,8 @@ extern int_str dstid_avp_name;
 extern unsigned short dstid_avp_type;
 extern unsigned short dstid_avp_type;
 extern int_str attrs_avp_name;
 extern int_str attrs_avp_name;
 extern unsigned short attrs_avp_type;
 extern unsigned short attrs_avp_type;
+extern int_str sock_avp_name;
+extern unsigned short sock_avp_type;
 
 
 extern pv_elem_t * hash_param_model;
 extern pv_elem_t * hash_param_model;
 
 
@@ -102,6 +104,8 @@ extern int probing_threshhold; /*!< number of failed requests,
 								 before a destination is taken into probing */ 
 								 before a destination is taken into probing */ 
 extern int ds_probing_mode;
 extern int ds_probing_mode;
 extern str ds_outbound_proxy;
 extern str ds_outbound_proxy;
+extern str ds_default_socket;
+extern struct socket_info * ds_default_sockinfo;
 
 
 int init_data(void);
 int init_data(void);
 int init_ds_db(void);
 int init_ds_db(void);
@@ -150,6 +154,7 @@ typedef struct _ds_attrs
 {
 {
 	str body;
 	str body;
 	str duid;
 	str duid;
+	str socket;
 	int maxload;
 	int maxload;
 	int weight;
 	int weight;
 } ds_attrs_t;
 } ds_attrs_t;
@@ -161,6 +166,7 @@ typedef struct _ds_dest
 	int priority;
 	int priority;
 	int dload;
 	int dload;
 	ds_attrs_t attrs;
 	ds_attrs_t attrs;
+	struct socket_info * sock;
 	struct ip_addr ip_address; 	/*!< IP-Address of the entry */
 	struct ip_addr ip_address; 	/*!< IP-Address of the entry */
 	unsigned short int port; 	/*!< Port of the URI */
 	unsigned short int port; 	/*!< Port of the URI */
 	unsigned short int proto; 	/*!< Protocol of the URI */
 	unsigned short int proto; 	/*!< Protocol of the URI */

+ 52 - 4
modules/dispatcher/dispatcher.c

@@ -89,6 +89,7 @@ static str grp_avp_param = {NULL, 0};
 static str cnt_avp_param = {NULL, 0};
 static str cnt_avp_param = {NULL, 0};
 static str dstid_avp_param = {NULL, 0};
 static str dstid_avp_param = {NULL, 0};
 static str attrs_avp_param = {NULL, 0};
 static str attrs_avp_param = {NULL, 0};
+static str sock_avp_param = {NULL, 0};
 str hash_pvar_param = {NULL, 0};
 str hash_pvar_param = {NULL, 0};
 
 
 int_str dst_avp_name;
 int_str dst_avp_name;
@@ -101,6 +102,8 @@ int_str dstid_avp_name;
 unsigned short dstid_avp_type;
 unsigned short dstid_avp_type;
 int_str attrs_avp_name;
 int_str attrs_avp_name;
 unsigned short attrs_avp_type;
 unsigned short attrs_avp_type;
+int_str sock_avp_name;
+unsigned short sock_avp_type;
 
 
 pv_elem_t * hash_param_model = NULL;
 pv_elem_t * hash_param_model = NULL;
 
 
@@ -115,6 +118,9 @@ static str ds_ping_reply_codes_str= {NULL, 0};
 static int** ds_ping_reply_codes = NULL;
 static int** ds_ping_reply_codes = NULL;
 static int* ds_ping_reply_codes_cnt;
 static int* ds_ping_reply_codes_cnt;
 
 
+str ds_default_socket       = {NULL, 0};
+struct socket_info * ds_default_sockinfo = NULL;
+
 int ds_hash_size = 0;
 int ds_hash_size = 0;
 int ds_hash_expire = 7200;
 int ds_hash_expire = 7200;
 int ds_hash_initexpire = 7200;
 int ds_hash_initexpire = 7200;
@@ -224,6 +230,7 @@ static param_export_t params[]={
 	{"cnt_avp",         PARAM_STR, &cnt_avp_param},
 	{"cnt_avp",         PARAM_STR, &cnt_avp_param},
 	{"dstid_avp",       PARAM_STR, &dstid_avp_param},
 	{"dstid_avp",       PARAM_STR, &dstid_avp_param},
 	{"attrs_avp",       PARAM_STR, &attrs_avp_param},
 	{"attrs_avp",       PARAM_STR, &attrs_avp_param},
+	{"sock_avp",        PARAM_STR, &sock_avp_param},
 	{"hash_pvar",       PARAM_STR, &hash_pvar_param},
 	{"hash_pvar",       PARAM_STR, &hash_pvar_param},
 	{"setid_pvname",    PARAM_STR, &ds_setid_pvname},
 	{"setid_pvname",    PARAM_STR, &ds_setid_pvname},
 	{"attrs_pvname",    PARAM_STR, &ds_attrs_pvname},
 	{"attrs_pvname",    PARAM_STR, &ds_attrs_pvname},
@@ -238,6 +245,7 @@ static param_export_t params[]={
 	{"ds_hash_initexpire", INT_PARAM, &ds_hash_initexpire},
 	{"ds_hash_initexpire", INT_PARAM, &ds_hash_initexpire},
 	{"ds_hash_check_interval", INT_PARAM, &ds_hash_check_interval},
 	{"ds_hash_check_interval", INT_PARAM, &ds_hash_check_interval},
 	{"outbound_proxy",  PARAM_STR, &ds_outbound_proxy},
 	{"outbound_proxy",  PARAM_STR, &ds_outbound_proxy},
+	{"ds_default_socket",  PARAM_STR, &ds_default_socket},
 	{0,0,0}
 	{0,0,0}
 };
 };
 
 
@@ -272,6 +280,8 @@ struct module_exports exports= {
 static int mod_init(void)
 static int mod_init(void)
 {
 {
 	pv_spec_t avp_spec;
 	pv_spec_t avp_spec;
+	str host;
+	int port, proto;
 
 
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	{
 	{
@@ -432,6 +442,28 @@ static int mod_init(void)
 		attrs_avp_type = 0;
 		attrs_avp_type = 0;
 	}
 	}
 
 
+	if (sock_avp_param.s && sock_avp_param.len > 0)
+	{
+		if (pv_parse_spec(&sock_avp_param, &avp_spec)==0
+				|| avp_spec.type!=PVT_AVP)
+		{
+			LM_ERR("malformed or non AVP %.*s AVP definition\n",
+					sock_avp_param.len, sock_avp_param.s);
+			return -1;
+		}
+
+		if(pv_get_avp_name(0, &(avp_spec.pvp), &sock_avp_name,
+					&sock_avp_type)!=0)
+		{
+			LM_ERR("[%.*s]- invalid AVP definition\n", sock_avp_param.len,
+					sock_avp_param.s);
+			return -1;
+		}
+	} else {
+		sock_avp_name.n = 0;
+		sock_avp_type = 0;
+	}
+
 	if (hash_pvar_param.s && *hash_pvar_param.s) {
 	if (hash_pvar_param.s && *hash_pvar_param.s) {
 		if(pv_parse_format(&hash_pvar_param, &hash_param_model) < 0
 		if(pv_parse_format(&hash_pvar_param, &hash_param_model) < 0
 				|| hash_param_model==NULL) {
 				|| hash_param_model==NULL) {
@@ -493,11 +525,25 @@ static int mod_init(void)
 		register_timer(ds_check_timer, NULL, ds_ping_interval);
 		register_timer(ds_check_timer, NULL, ds_ping_interval);
 	}
 	}
 
 
+	if (ds_default_socket.s && ds_default_socket.len > 0) {
+		if (parse_phostport( ds_default_socket.s, &host.s, &host.len,
+				&port, &proto)!=0) {
+			LM_ERR("bad socket <%.*s>\n", ds_default_socket.len, ds_default_socket.s);
+			return -1;
+		}
+		ds_default_sockinfo = grep_sock_info( &host, (unsigned short)port, proto);
+		if (ds_default_sockinfo==0) {
+			LM_WARN("non-local socket <%.*s>\n", ds_default_socket.len, ds_default_socket.s);
+			return -1;
+		}
+		LM_INFO("default dispatcher socket set to <%.*s>\n", ds_default_socket.len, ds_default_socket.s);
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
 /*! \brief
 /*! \brief
- * Initialize children
+ * Initialize childreng
  */
  */
 static int child_init(int rank)
 static int child_init(int rank)
 {
 {
@@ -720,7 +766,7 @@ static int w_ds_load_update(struct sip_msg *msg, char *str1, char *str2)
  */
  */
 static int ds_warn_fixup(void** param, int param_no)
 static int ds_warn_fixup(void** param, int param_no)
 {
 {
-	if(!dst_avp_param.s || !grp_avp_param.s || !cnt_avp_param.s)
+	if(!dst_avp_param.s || !grp_avp_param.s || !cnt_avp_param.s || !sock_avp_param.s)
 	{
 	{
 		LM_ERR("failover functions used, but AVPs paraamters required"
 		LM_ERR("failover functions used, but AVPs paraamters required"
 				" are NULL -- feature disabled\n");
 				" are NULL -- feature disabled\n");
@@ -1149,12 +1195,14 @@ static void dispatcher_rpc_list(rpc_t* rpc, void* ctx)
 					rpc->fault(ctx, 500, "Internal error creating dest struct");
 					rpc->fault(ctx, 500, "Internal error creating dest struct");
 					return;
 					return;
 				}
 				}
-				if(rpc->struct_add(wh, "SSdd",
+				if(rpc->struct_add(wh, "SSddS",
 							"BODY", &(list->dlist[j].attrs.body),
 							"BODY", &(list->dlist[j].attrs.body),
 							"DUID", (list->dlist[j].attrs.duid.s)?
 							"DUID", (list->dlist[j].attrs.duid.s)?
 							&(list->dlist[j].attrs.duid):&data,
 							&(list->dlist[j].attrs.duid):&data,
 							"MAXLOAD", list->dlist[j].attrs.maxload,
 							"MAXLOAD", list->dlist[j].attrs.maxload,
-							"WEIGHT", list->dlist[j].attrs.weight)<0)
+							"WEIGHT", list->dlist[j].attrs.weight,
+							"SOCKET", (list->dlist[j].attrs.socket.s)?
+							&(list->dlist[j].attrs.socket):&data)<0)
 				{
 				{
 					rpc->fault(ctx, 500, "Internal error creating attrs struct");
 					rpc->fault(ctx, 500, "Internal error creating attrs struct");
 					return;
 					return;

+ 59 - 4
modules/dispatcher/doc/dispatcher_admin.xml

@@ -421,6 +421,30 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  </programlisting>
  		</example>
  		</example>
  	</section>
  	</section>
+	<section id="dispatcher.p.sock_avp">
+		<title><varname>sock_avp</varname> (str)</title>
+		<para>
+			The name of the avp which will hold the list with the sockets associated to the addresses stored in dst_avp avp.
+		</para>
+		<note>
+		<para>
+			If you want to do load balancing fail over, you have to set this parameter to use the correct socket for each gateway.
+		</para>
+		</note>
+		<para>
+		<emphasis>
+			Default value is <quote>null</quote> - don't add AVPs.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set the <quote>sock_avp</quote> parameter</title>
+ <programlisting format="linespecific">
+ ...
+ modparam("dispatcher", "sock_avp", "$avp(dssocket)")
+ ...
+ </programlisting>
+		</example>
+	</section>
  	<section id="dispatcher.p.hash_pvar">
  	<section id="dispatcher.p.hash_pvar">
  		<title><varname>hash_pvar</varname> (str)</title>
  		<title><varname>hash_pvar</varname> (str)</title>
  		<para>
  		<para>
@@ -731,6 +755,26 @@ modparam("dispatcher", "force_dst", 1)
  		</example>
  		</example>
 	</section>
 	</section>
 
 
+	<section id="dispatcher.p.ds_default_socket">
+		<title><varname>ds_default_socket</varname> (str)</title>
+		<para>
+		Default socket to be used for sending pings and dispatching requests when a gateway has no send socket configured.
+		</para>
+		<para>
+		<emphasis>
+			By default no default socket is defined, the first configuration script <emphasis>listen</emphasis> directive is used.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set the <quote>ds_default_socket</quote> parameter</title>
+ <programlisting format="linespecific">
+ ...
+ modparam("dispatcher", "ds_default_socket", "udp:192.168.0.125:5060")
+ ...
+ </programlisting>
+		</example>
+	</section>
+
 	</section>
 	</section>
 
 
 	<section>
 	<section>
@@ -1321,9 +1365,20 @@ onreply_route {
 			is done the initial ordering inside the set)</para>
 			is done the initial ordering inside the set)</para>
 			</listitem>
 			</listitem>
 			<listitem>
 			<listitem>
-			<para>attributes: extra filed in form of
-			name1=value1;...;nameN=valueN. There are some predefined names
-			that are used of weight and call load dispatching.</para>
+			<para>attributes: extra fields in form of
+				name1=value1;...;nameN=valueN. There are some predefined names:
+				<itemizedlist>
+					<listitem>
+						'duid' - used for call load dispatching
+					</listitem>
+					<listitem>
+						'weight' - used for weight based load distribution
+					</listitem>
+					<listitem>
+						'socket' - used to set the sending socket for the gateway
+					</listitem>
+				</itemizedlist>
+			</para>
 			</listitem>
 			</listitem>
 		</itemizedlist>
 		</itemizedlist>
 		<para>
 		<para>
@@ -1340,7 +1395,7 @@ setid(int) destination(sip uri) flags(int,opt) priority(int,opt) attrs(str,opt)
 		</para>
 		</para>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 ...
 ...
-1 sip:127.0.0.1:5080 0 0 duid=abc;my=xyz
+1 sip:127.0.0.1:5080 0 0 duid=abc;socket=udp:192.168.0.125:5060;my=xyz
 ...
 ...
 </programlisting>
 </programlisting>