Просмотр исходного кода

dispatcher(k): fixes to call load dispatching

- this alg implementation was not completed before
- exported some functions and parameters to cfg in order to cope with
  stateless proxy mode
Daniel-Constantin Mierla 15 лет назад
Родитель
Сommit
9cdc3e7005

+ 261 - 71
modules_k/dispatcher/README

@@ -18,9 +18,9 @@ Carsten Bock
 
    Copyright © 2004 FhG FOKUS
 
-   Copyright © 2005 Voice-System.RO
-   Revision History
-   Revision $Revision$ $Date$
+   Copyright © 2005 Voice Sistem
+
+   Copyright © 2010 Daniel-Constantin Mierla (asipto.com)
      __________________________________________________________________
 
    Table of Contents
@@ -48,14 +48,20 @@ Carsten Bock
               3.11. dst_avp (str)
               3.12. grp_avp (str)
               3.13. cnt_avp (str)
-              3.14. hash_pvar (str)
-              3.15. setid_pvar (str)
-              3.16. ds_ping_method (string)
-              3.17. ds_ping_from (string)
-              3.18. ds_ping_interval (int)
-              3.19. ds_probing_threshhold (int)
-              3.20. ds_probing_mode (int)
-              3.21. ds_append_branch (int)
+              3.14. dstid_avp (str)
+              3.15. attrs_avp (str)
+              3.16. hash_pvar (str)
+              3.17. setid_pvar (str)
+              3.18. ds_ping_method (string)
+              3.19. ds_ping_from (string)
+              3.20. ds_ping_interval (int)
+              3.21. ds_probing_threshhold (int)
+              3.22. ds_probing_mode (int)
+              3.23. ds_append_branch (int)
+              3.24. ds_hash_size (int)
+              3.25. ds_hash_expire (int)
+              3.26. ds_hash_initexpire (int)
+              3.27. ds_hash_check_interval (int)
 
         4. Exported Functions
 
@@ -67,6 +73,8 @@ Carsten Bock
               4.6. ds_mark_dst("s")
               4.7. ds_is_from_list()
               4.8. ds_is_from_list("group")
+              4.9. ds_load_update()
+              4.10. ds_load_unset()
 
         5. Exported MI Functions
 
@@ -96,18 +104,25 @@ Carsten Bock
    1.11. Set the “dst_avp” parameter
    1.12. Set the “grp_avp” parameter
    1.13. Set the “cnt_avp” parameter
-   1.14. Use $avp(i:273) for hashing:
-   1.15. Use combination of PVs for hashing:
-   1.16. Set the “setid_pvar” parameter
-   1.17. Set the “ds_ping_method” parameter
-   1.18. Set the “ds_ping_from” parameter
-   1.19. Set the “ds_ping_interval” parameter
-   1.20. Set the “ds_probing_threshhold” parameter
-   1.21. Set the “ds_probing_mode” parameter
-   1.22. Set the “ds_append_branch” parameter
-   1.23. ds_select_dst usage
-   1.24. dispatcher list file
-   1.25. Kamailio config script - sample dispatcher usage
+   1.14. Set the “dstid_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_pvar” parameter
+   1.19. Set the “ds_ping_method” parameter
+   1.20. Set the “ds_ping_from” parameter
+   1.21. Set the “ds_ping_interval” parameter
+   1.22. Set the “ds_probing_threshhold” parameter
+   1.23. Set the “ds_probing_mode” parameter
+   1.24. Set the “ds_append_branch” parameter
+   1.25. Set the “ds_hash_size” parameter
+   1.26. Set the “ds_hash_expire” parameter
+   1.27. Set the “ds_hash_initexpire” parameter
+   1.28. Set the “ds_hash_check_interval” parameter
+   1.29. ds_select_dst usage
+   1.30. ds_load_unset usage
+   1.31. dispatcher list file
+   1.32. Kamailio config script - sample dispatcher usage
 
 Chapter 1. Admin Guide
 
@@ -134,14 +149,20 @@ Chapter 1. Admin Guide
         3.11. dst_avp (str)
         3.12. grp_avp (str)
         3.13. cnt_avp (str)
-        3.14. hash_pvar (str)
-        3.15. setid_pvar (str)
-        3.16. ds_ping_method (string)
-        3.17. ds_ping_from (string)
-        3.18. ds_ping_interval (int)
-        3.19. ds_probing_threshhold (int)
-        3.20. ds_probing_mode (int)
-        3.21. ds_append_branch (int)
+        3.14. dstid_avp (str)
+        3.15. attrs_avp (str)
+        3.16. hash_pvar (str)
+        3.17. setid_pvar (str)
+        3.18. ds_ping_method (string)
+        3.19. ds_ping_from (string)
+        3.20. ds_ping_interval (int)
+        3.21. ds_probing_threshhold (int)
+        3.22. ds_probing_mode (int)
+        3.23. ds_append_branch (int)
+        3.24. ds_hash_size (int)
+        3.25. ds_hash_expire (int)
+        3.26. ds_hash_initexpire (int)
+        3.27. ds_hash_check_interval (int)
 
    4. Exported Functions
 
@@ -153,6 +174,8 @@ Chapter 1. Admin Guide
         4.6. ds_mark_dst("s")
         4.7. ds_is_from_list()
         4.8. ds_is_from_list("group")
+        4.9. ds_load_update()
+        4.10. ds_load_unset()
 
    5. Exported MI Functions
 
@@ -205,14 +228,20 @@ Chapter 1. Admin Guide
    3.11. dst_avp (str)
    3.12. grp_avp (str)
    3.13. cnt_avp (str)
-   3.14. hash_pvar (str)
-   3.15. setid_pvar (str)
-   3.16. ds_ping_method (string)
-   3.17. ds_ping_from (string)
-   3.18. ds_ping_interval (int)
-   3.19. ds_probing_threshhold (int)
-   3.20. ds_probing_mode (int)
-   3.21. ds_append_branch (int)
+   3.14. dstid_avp (str)
+   3.15. attrs_avp (str)
+   3.16. hash_pvar (str)
+   3.17. setid_pvar (str)
+   3.18. ds_ping_method (string)
+   3.19. ds_ping_from (string)
+   3.20. ds_ping_interval (int)
+   3.21. ds_probing_threshhold (int)
+   3.22. ds_probing_mode (int)
+   3.23. ds_append_branch (int)
+   3.24. ds_hash_size (int)
+   3.25. ds_hash_expire (int)
+   3.26. ds_hash_initexpire (int)
+   3.27. ds_hash_check_interval (int)
 
 3.1. list_file (string)
 
@@ -354,13 +383,13 @@ modparam("dispatcher", "force_dst", 1)
 
 Note
 
-   You must set this parameter if you want do do load balancing fail over.
+   You must set this parameter if you want to do load balancing fail over.
 
    Default value is “null” - don't add AVPs.
 
    Example 1.11. Set the “dst_avp” parameter
  ...
- modparam("dispatcher", "dst_avp", "$avp(i:271)")
+ modparam("dispatcher", "dst_avp", "$avp(dsdst)")
  ...
 
 3.12. grp_avp (str)
@@ -370,13 +399,13 @@ Note
 
 Note
 
-   You must set this parameter if you want do do load balancing fail over.
+   You must set this parameter if you want to do load balancing fail over.
 
    Default value is “null” - don't add AVP.
 
    Example 1.12. Set the “grp_avp” parameter
  ...
- modparam("dispatcher", "grp_avp", "$avp(i:272)")
+ modparam("dispatcher", "grp_avp", "$avp(dsgrp)")
  ...
 
 3.13. cnt_avp (str)
@@ -386,16 +415,46 @@ Note
 
 Note
 
-   You must set this parameter if you want do do load balancing fail over.
+   You must set this parameter if you want to do load balancing fail over.
 
    Default value is “null” - don't add AVP.
 
    Example 1.13. Set the “cnt_avp” parameter
  ...
- modparam("dispatcher", "cnt_avp", "$avp(i:273)")
+ modparam("dispatcher", "cnt_avp", "$avp(dscnt)")
+ ...
+
+3.14. dstid_avp (str)
+
+   The name of the avp storing the destination unique ID used for call
+   load based dispatching.
+
+Note
+
+   You must set this parameter if you want to do load balancing on call
+   load (alg 10).
+
+   Default value is “null” - don't add AVP.
+
+   Example 1.14. Set the “dstid_avp” parameter
+ ...
+ modparam("dispatcher", "dstid_avp", "$avp(dsdstid)")
  ...
 
-3.14. hash_pvar (str)
+3.15. attrs_avp (str)
+
+   The name of the avp storing destination's attributes value.
+
+Note
+
+   Default value is “null” - don't add AVP.
+
+   Example 1.15. Set the “attrs_avp” parameter
+ ...
+ modparam("dispatcher", "attrs_avp", "$avp(dsattrs)")
+ ...
+
+3.16. hash_pvar (str)
 
    String with PVs used for the hashing algorithm 7.
 
@@ -406,29 +465,29 @@ Note
 
    Default value is “null” - disabled.
 
-   Example 1.14. Use $avp(i:273) for hashing:
+   Example 1.16. Use $avp(i:273) for hashing:
  ...
  modparam("dispatcher", "hash_pvar", "$avp(i:273)")
  ...
 
-   Example 1.15. Use combination of PVs for hashing:
+   Example 1.17. Use combination of PVs for hashing:
  ...
  modparam("dispatcher", "hash_pvar", "hash the $fU@$ci")
  ...
 
-3.15. setid_pvar (str)
+3.17. setid_pvar (str)
 
    The name of the PV where to store the set ID (group ID) when calling
    ds_is_from_list() with no parameter.
 
    Default value is “null” - don't set PV.
 
-   Example 1.16. Set the “setid_pvar” parameter
+   Example 1.18. Set the “setid_pvar” parameter
  ...
  modparam("dispatcher", "setid_pvar", "$var(setid)")
  ...
 
-3.16. ds_ping_method (string)
+3.18. ds_ping_method (string)
 
    With this Method you can define, with which method you want to probe
    the gateways. Pinging gateways feature depends on ds_ping_interval
@@ -436,12 +495,12 @@ Note
 
    Default value is “OPTIONS”.
 
-   Example 1.17. Set the “ds_ping_method” parameter
+   Example 1.19. Set the “ds_ping_method” parameter
  ...
  modparam("dispatcher", "ds_ping_method", "INFO")
  ...
 
-3.17. ds_ping_from (string)
+3.19. ds_ping_from (string)
 
    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
@@ -449,12 +508,12 @@ Note
 
    Default value is “sip:dispatcher@localhost”.
 
-   Example 1.18. Set the “ds_ping_from” parameter
+   Example 1.20. Set the “ds_ping_from” parameter
  ...
  modparam("dispatcher", "ds_ping_from", "sip:[email protected]")
  ...
 
-3.18. ds_ping_interval (int)
+3.20. ds_ping_interval (int)
 
    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.
@@ -463,12 +522,12 @@ Note
 
    Default value is “0”.
 
-   Example 1.19. Set the “ds_ping_interval” parameter
+   Example 1.21. Set the “ds_ping_interval” parameter
  ...
  modparam("dispatcher", "ds_ping_interval", 30)
  ...
 
-3.19. ds_probing_threshhold (int)
+3.21. ds_probing_threshhold (int)
 
    If you want to set a gateway into probing mode, you will need a
    specific number of requests until it will change from "active" to
@@ -476,12 +535,12 @@ Note
 
    Default value is “3”.
 
-   Example 1.20. Set the “ds_probing_threshhold” parameter
+   Example 1.22. Set the “ds_probing_threshhold” parameter
  ...
  modparam("dispatcher", "ds_probing_threshhold", 10)
  ...
 
-3.20. ds_probing_mode (int)
+3.22. ds_probing_mode (int)
 
    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
@@ -490,12 +549,12 @@ Note
 
    Default value is “0”.
 
-   Example 1.21. Set the “ds_probing_mode” parameter
+   Example 1.23. Set the “ds_probing_mode” parameter
  ...
  modparam("dispatcher", "ds_probing_mode", 1)
  ...
 
-3.21. ds_append_branch (int)
+3.23. ds_append_branch (int)
 
    If set to 1, functions will automaticall append a new branch if called
    in FAILURE_ROUTE. If set to 0, script writer has to call
@@ -503,11 +562,62 @@ Note
 
    Default value is “1”.
 
-   Example 1.22. Set the “ds_append_branch” parameter
+   Example 1.24. Set the “ds_append_branch” parameter
  ...
  modparam("dispatcher", "ds_append_branch", 0)
  ...
 
+3.24. ds_hash_size (int)
+
+   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
+   a hash table with 256 slots). It must be greater than 0 to enable call
+   load dispatching feature (alg 10).
+
+   Default value is “0”.
+
+   Example 1.25. Set the “ds_hash_size” parameter
+ ...
+ modparam("dispatcher", "ds_hash_size", 9)
+ ...
+
+3.25. ds_hash_expire (int)
+
+   Expiration time in seconds to remove the load on a destination if no
+   BYE was received meanwhile.
+
+   Default value is “7200”.
+
+   Example 1.26. Set the “ds_hash_expire” parameter
+ ...
+ modparam("dispatcher", "ds_hash_expire", 3600)
+ ...
+
+3.26. ds_hash_initexpire (int)
+
+   Expiration time in seconds to remove the load on a destination if no
+   200 for INVITE was received meanwhile and state updated with
+   ds_load_update().
+
+   Default value is “7200”.
+
+   Example 1.27. Set the “ds_hash_initexpire” parameter
+ ...
+ modparam("dispatcher", "ds_hash_initexpire", 60)
+ ...
+
+3.27. ds_hash_check_interval (int)
+
+   Time interval in seconds to scan internal hash table with call load
+   dispatching data for expired items.
+
+   Default value is “30”.
+
+   Example 1.28. Set the “ds_hash_check_interval” parameter
+ ...
+ modparam("dispatcher", "ds_hash_check_interval", 60)
+ ...
+
 4. Exported Functions
 
    4.1. ds_select_dst(set, alg)
@@ -518,6 +628,8 @@ Note
    4.6. ds_mark_dst("s")
    4.7. ds_is_from_list()
    4.8. ds_is_from_list("group")
+   4.9. ds_load_update()
+   4.10. ds_load_unset()
 
 4.1.  ds_select_dst(set, alg)
 
@@ -541,6 +653,23 @@ Note
           + “7” - hash over the content of PVs string. Note: This works
             only when the parameter hash_pvar is set.
           + “8” - use first destination (good for failover).
+          + “9” - use weight based load distribution. You have to set the
+            attribute 'weight' per each address in destination set.
+          + “10” - use call load distribution. You have to set the
+            attribute 'duid' (as an unique string id) per each address in
+            destination set. Also, you must set parameters 'dstid_avp' and
+            'ds_hash_size'.
+            The algorithm can be used even with stateless proxy mode,
+            there is no SIP dialog tracking depending on other modules,
+            just an internal lightweight call tracking by Call-Id, thus is
+            fast and suitable even for embedded systems.
+            The first destination selected by this algorithm is the one
+            that has the least number of calls associated. The rest of the
+            destination list is taken in order of the entries in set -
+            anyhow, until a re-route to next destination happens, the load
+            on each address can change.
+            This algorithm can be used only for dispatching INVITE
+            requests as it is the only SIP method creating a SIP call.
           + “X” - if the algorithm is not implemented, the first entry in
             set is chosen.
 
@@ -551,7 +680,7 @@ Note
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.23. ds_select_dst usage
+   Example 1.29. ds_select_dst usage
 ...
 ds_select_dst("1", "0");
 ...
@@ -629,6 +758,48 @@ ds_select_dst("1", "$var(a)");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE and ONREPLY_ROUTE.
 
+4.9.  ds_load_update()
+
+   Updates the load state:
+     * if it is a BYE or CANCEL - remove the load from destination address
+       used to forward the INVITE
+     * if it is a reply to INVITE - set internal state to confirmed for
+       call load structure when reply code is 2xx.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   BRANCH_ROUTE and ONREPLY_ROUTE.
+
+4.10.  ds_load_unset()
+
+   Remove the call load for the destination that routed the call.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   BRANCH_ROUTE and ONREPLY_ROUTE.
+
+   Example 1.30. ds_load_unset usage
+...
+route {
+    ...
+        if(is_method("BYE|CANCEL"))
+        ds_load_update();
+    ...
+        ds_select_dst("1", "10");
+    ...
+}
+
+onreply_route {
+    ...
+    if(is_method("INVITE")
+        {
+        if(status=~"2[0-9][0-9]")
+            ds_load_update();
+        else if(status=~"[3-7][0-9][0-9]")
+            ds_load_unset();
+    }
+    ...
+}
+...
+
 5. Exported MI Functions
 
    5.1. ds_set_state
@@ -687,14 +858,33 @@ ds_select_dst("1", "$var(a)");
 
 6.1. Destination List File
 
-   Each destination point must be on one line. First token is the set id,
-   followed by destination address. Optionally, the third field can be
-   flags value (1 - destination inactive, 2 - destination in probing mod
-   -- you can do bitwise OR to set both flags). The set id must be an
-   integer value. Destination address must be a valid SIP URI. Empty lines
-   or lines starting with “#” are ignored.
+   Each destination point must be on one line. First token is the set id
+   (an integer value), followed by destination address (s string value in
+   SIP URI format).
+
+   Optionally, these fields can be followed by:
+     * flags: 1 - destination inactive, 2 - destination in probing mode --
+       you can do bitwise OR to set both flags
+     * priority: sets the priority in destination list (based on it is
+       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.
+
+   Line format is:
+...
+setid(int) destination(sip uri) flags(int,opt) priority(int,opt) attrs(str,opt)
+...
+
+   Full line example:
+...
+1 sip:127.0.0.1:5080 0 0 duid=abc;my=xyz
+...
+
+   For database, each element of a line resides in a different column.
+   Next is a dispatcher.list file example:
 
-   Example 1.24. dispatcher list file
+   Example 1.31. dispatcher list file
 ...
 # $Id$
 # dispatcher destination sets
@@ -718,7 +908,7 @@ ds_select_dst("1", "$var(a)");
 
    Next picture displays a sample usage of dispatcher.
 
-   Example 1.25. Kamailio config script - sample dispatcher usage
+   Example 1.32. Kamailio config script - sample dispatcher usage
 ...
 # $Id$
 # sample config file for dispatcher module

Разница между файлами не показана из-за своего большого размера
+ 548 - 68
modules_k/dispatcher/dispatch.c


+ 10 - 0
modules_k/dispatcher/dispatch.h

@@ -70,6 +70,10 @@ extern int_str grp_avp_name;
 extern unsigned short grp_avp_type;
 extern int_str cnt_avp_name;
 extern unsigned short cnt_avp_type;
+extern int_str dstid_avp_name;
+extern unsigned short dstid_avp_type;
+extern int_str attrs_avp_name;
+extern unsigned short attrs_avp_type;
 
 extern pv_elem_t * hash_param_model;
 
@@ -100,6 +104,12 @@ int ds_print_list(FILE *fout);
 int ds_print_mi_list(struct mi_node* rpl);
 int ds_print_sets(void);
 
+int ds_load_unset(struct sip_msg *msg);
+int ds_load_update(struct sip_msg *msg);
+
+int ds_hash_load_init(unsigned int htsize, int expire, int initexpire);
+int ds_hash_load_destroy(void);
+
 int ds_is_from_list(struct sip_msg *_m, int group);
 /*! \brief
  * Timer for checking inactive destinations

+ 127 - 15
modules_k/dispatcher/dispatcher.c

@@ -83,6 +83,8 @@ int  ds_use_default = 0;
 static str dst_avp_param = {NULL, 0};
 static str grp_avp_param = {NULL, 0};
 static str cnt_avp_param = {NULL, 0};
+static str dstid_avp_param = {NULL, 0};
+static str attrs_avp_param = {NULL, 0};
 str hash_pvar_param = {NULL, 0};
 
 int_str dst_avp_name;
@@ -91,6 +93,10 @@ int_str grp_avp_name;
 unsigned short grp_avp_type;
 int_str cnt_avp_name;
 unsigned short cnt_avp_type;
+int_str dstid_avp_name;
+unsigned short dstid_avp_type;
+int_str attrs_avp_name;
+unsigned short attrs_avp_type;
 
 pv_elem_t * hash_param_model = NULL;
 
@@ -103,6 +109,8 @@ int ds_probing_mode  = 0;
 int ds_append_branch = 1;
 int ds_hash_size = 0;
 int ds_hash_expire = 7200;
+int ds_hash_initexpire = 7200;
+int ds_hash_check_interval = 30;
 
 /* tm */
 struct tm_binds tmb;
@@ -129,6 +137,8 @@ static int w_ds_next_dst(struct sip_msg*, char*, char*);
 static int w_ds_next_domain(struct sip_msg*, char*, char*);
 static int w_ds_mark_dst0(struct sip_msg*, char*, char*);
 static int w_ds_mark_dst1(struct sip_msg*, char*, char*);
+static int w_ds_load_unset(struct sip_msg*, char*, char*);
+static int w_ds_load_update(struct sip_msg*, char*, char*);
 
 static int w_ds_is_from_list0(struct sip_msg*, char*, char*);
 static int w_ds_is_from_list1(struct sip_msg*, char*, char*);
@@ -143,14 +153,26 @@ static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param);
 static int mi_child_init(void);
 
 static cmd_export_t cmds[]={
-	{"ds_select_dst",    (cmd_function)w_ds_select_dst,    2, fixup_igp_igp, 0, REQUEST_ROUTE|FAILURE_ROUTE},
-	{"ds_select_domain", (cmd_function)w_ds_select_domain, 2, fixup_igp_igp, 0, REQUEST_ROUTE|FAILURE_ROUTE},
-	{"ds_next_dst",      (cmd_function)w_ds_next_dst,      0, ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
-	{"ds_next_domain",   (cmd_function)w_ds_next_domain,   0, ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
-	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst0,     0, ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
-	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst1,     1, ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
-	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list0, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
-	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list1, 1, fixup_uint_null, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
+	{"ds_select_dst",    (cmd_function)w_ds_select_dst,    2,
+		fixup_igp_igp, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"ds_select_domain", (cmd_function)w_ds_select_domain, 2,
+		fixup_igp_igp, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"ds_next_dst",      (cmd_function)w_ds_next_dst,      0,
+		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"ds_next_domain",   (cmd_function)w_ds_next_domain,   0,
+		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst0,     0,
+		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst1,     1,
+		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list0, 0,
+		0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
+	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list1, 1,
+		fixup_uint_null, 0, ANY_ROUTE},
+	{"ds_load_unset",    (cmd_function)w_ds_load_unset,   0,
+		0, 0, ANY_ROUTE},
+	{"ds_load_update",   (cmd_function)w_ds_load_update,  0,
+		0, 0, ANY_ROUTE},
 	{0,0,0,0,0,0}
 };
 
@@ -170,6 +192,8 @@ static param_export_t params[]={
 	{"dst_avp",         STR_PARAM, &dst_avp_param.s},
 	{"grp_avp",         STR_PARAM, &grp_avp_param.s},
 	{"cnt_avp",         STR_PARAM, &cnt_avp_param.s},
+	{"dstid_avp",       STR_PARAM, &dstid_avp_param.s},
+	{"attrs_avp",       STR_PARAM, &attrs_avp_param.s},
 	{"hash_pvar",       STR_PARAM, &hash_pvar_param.s},
 	{"setid_pvname",    STR_PARAM, &ds_setid_pvname.s},
 	{"ds_probing_threshhold", INT_PARAM, &probing_threshhold},
@@ -178,7 +202,10 @@ static param_export_t params[]={
 	{"ds_ping_interval",   INT_PARAM, &ds_ping_interval},
 	{"ds_probing_mode",    INT_PARAM, &ds_probing_mode},
 	{"ds_append_branch",   INT_PARAM, &ds_append_branch},
-	{"ds_hash_sixe",       INT_PARAM, &ds_hash_size},
+	{"ds_hash_size",       INT_PARAM, &ds_hash_size},
+	{"ds_hash_expire",     INT_PARAM, &ds_hash_expire},
+	{"ds_hash_initexpire", INT_PARAM, &ds_hash_initexpire},
+	{"ds_hash_check_interval", INT_PARAM, &ds_hash_check_interval},
 	{0,0,0}
 };
 
@@ -226,6 +253,10 @@ static int mod_init(void)
 		grp_avp_param.len = strlen(grp_avp_param.s);
 	if (cnt_avp_param.s)
 		cnt_avp_param.len = strlen(cnt_avp_param.s);	
+	if (dstid_avp_param.s)
+		dstid_avp_param.len = strlen(dstid_avp_param.s);
+	if (attrs_avp_param.s)
+		attrs_avp_param.len = strlen(attrs_avp_param.s);
 	if (hash_pvar_param.s)
 		hash_pvar_param.len = strlen(hash_pvar_param.s);
 	if (ds_setid_pvname.s)
@@ -236,12 +267,6 @@ static int mod_init(void)
 	if(init_data()!= 0)
 		return -1;
 
-	if(ds_hash_size>0)
-	{
-		if(ds_ht_init(1<<ds_hash_size, ds_hash_expire)<0)
-			return -1;
-		register_timer(ds_ht_timer, NULL, 10);
-	}
 	if(ds_db_url.s)
 	{
 		ds_db_url.len     = strlen(ds_db_url.s);
@@ -326,6 +351,49 @@ static int mod_init(void)
 		cnt_avp_name.n = 0;
 		cnt_avp_type = 0;
 	}
+	if (dstid_avp_param.s && dstid_avp_param.len > 0)
+	{
+		if (pv_parse_spec(&dstid_avp_param, &avp_spec)==0
+				|| avp_spec.type!=PVT_AVP)
+		{
+			LM_ERR("malformed or non AVP %.*s AVP definition\n",
+					dstid_avp_param.len, dstid_avp_param.s);
+			return -1;
+		}
+
+		if(pv_get_avp_name(0, &(avp_spec.pvp), &dstid_avp_name,
+					&dstid_avp_type)!=0)
+		{
+			LM_ERR("[%.*s]- invalid AVP definition\n", dstid_avp_param.len,
+					dstid_avp_param.s);
+			return -1;
+		}
+	} else {
+		dstid_avp_name.n = 0;
+		dstid_avp_type = 0;
+	}
+
+	if (attrs_avp_param.s && attrs_avp_param.len > 0)
+	{
+		if (pv_parse_spec(&attrs_avp_param, &avp_spec)==0
+				|| avp_spec.type!=PVT_AVP)
+		{
+			LM_ERR("malformed or non AVP %.*s AVP definition\n",
+					attrs_avp_param.len, attrs_avp_param.s);
+			return -1;
+		}
+
+		if(pv_get_avp_name(0, &(avp_spec.pvp), &attrs_avp_name,
+					&attrs_avp_type)!=0)
+		{
+			LM_ERR("[%.*s]- invalid AVP definition\n", attrs_avp_param.len,
+					attrs_avp_param.s);
+			return -1;
+		}
+	} else {
+		attrs_avp_name.n = 0;
+		attrs_avp_type = 0;
+	}
 
 	if (hash_pvar_param.s && *hash_pvar_param.s) {
 		if(pv_parse_format(&hash_pvar_param, &hash_param_model) < 0
@@ -346,6 +414,19 @@ static int mod_init(void)
 			return -1;
 		}
 	}
+	if (dstid_avp_param.s && dstid_avp_param.len > 0)
+	{
+		if(ds_hash_size>0)
+		{
+			if(ds_hash_load_init(1<<ds_hash_size, ds_hash_expire,
+						ds_hash_initexpire)<0)
+				return -1;
+			register_timer(ds_ht_timer, NULL, ds_hash_check_interval);
+		} else {
+			LM_ERR("call load dispatching AVP set but no size of hash table\n");
+			return -1;
+		}
+	}
 	/* Only, if the Probing-Timer is enabled the TM-API needs to be loaded: */
 	if (ds_ping_interval > 0)
 	{
@@ -393,6 +474,7 @@ static void destroy(void)
 	ds_destroy_list();
 	if(ds_db_url.s)
 		ds_disconnect_db();
+	ds_hash_load_destroy();
 }
 
 /**
@@ -478,6 +560,30 @@ static int w_ds_mark_dst1(struct sip_msg *msg, char *str1, char *str2)
 		return ds_mark_dst(msg, 1);
 }
 
+
+/**
+ *
+ */
+static int w_ds_load_unset(struct sip_msg *msg, char *str1, char *str2)
+{
+	if(ds_load_unset(msg)<0)
+		return -1;
+	return 1;
+}
+
+/**
+ *
+ */
+static int w_ds_load_update(struct sip_msg *msg, char *str1, char *str2)
+{
+	if(ds_load_update(msg)<0)
+		return -1;
+	return 1;
+}
+
+/**
+ *
+ */
 static int ds_warn_fixup(void** param, int param_no)
 {
 	if(!dst_avp_param.s || !grp_avp_param.s || !cnt_avp_param.s)
@@ -573,9 +679,15 @@ static struct mi_root* ds_mi_list(struct mi_root* cmd_tree, void* param)
 #define MI_ERR_RELOAD_LEN 		(sizeof(MI_ERR_RELOAD)-1)
 #define MI_NOT_SUPPORTED		"DB mode not configured"
 #define MI_NOT_SUPPORTED_LEN 	(sizeof(MI_NOT_SUPPORTED)-1)
+#define MI_ERR_DSLOAD			"No reload support for call load dispatching"
+#define MI_ERR_DSLOAD_LEN		(sizeof(MI_ERR_DSLOAD)-1)
 
 static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param)
 {
+	if(dstid_avp_name.n!=0) {
+		return init_mi_tree(500, MI_ERR_DSLOAD, MI_ERR_DSLOAD_LEN);
+	}
+
 	if(!ds_db_url.s) {
 		if (ds_load_list(dslistfile)!=0)
 			return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);

+ 75 - 8
modules_k/dispatcher/ds_ht.c

@@ -35,12 +35,12 @@
 #define ds_get_entry(_h,_size)    (_h)&((_size)-1)
 
 
-ds_cell_t* ds_cell_new(str *cid, char *did, int dset, unsigned int cellid)
+ds_cell_t* ds_cell_new(str *cid, str *duid, int dset, unsigned int cellid)
 {
 	ds_cell_t *cell;
 	unsigned int msize;
 
-	msize = sizeof(ds_cell_t) + (cid->len + 1)*sizeof(char);
+	msize = sizeof(ds_cell_t) + (cid->len + duid->len + 2)*sizeof(char);
 
 	cell = (ds_cell_t*)shm_malloc(msize);
 	if(cell==NULL)
@@ -56,7 +56,11 @@ ds_cell_t* ds_cell_new(str *cid, char *did, int dset, unsigned int cellid)
 	cell->callid.s = (char*)cell + sizeof(ds_cell_t);
 	memcpy(cell->callid.s, cid->s, cid->len);
 	cell->callid.s[cid->len] = '\0';
-	strcpy(cell->duid, did);
+
+	cell->duid.len = duid->len;
+	cell->duid.s = cell->callid.s + cell->callid.len + 1;
+	memcpy(cell->duid.s, duid->s, duid->len);
+	cell->duid.s[duid->len] = '\0';
 	return cell;
 }
 
@@ -70,7 +74,7 @@ int ds_cell_free(ds_cell_t *cell)
 
 
 
-ds_ht_t *ds_ht_init(unsigned int htsize, int expire)
+ds_ht_t *ds_ht_init(unsigned int htsize, int expire, int initexpire)
 {
 	int i;
 	ds_ht_t *dsht = NULL;
@@ -84,6 +88,7 @@ ds_ht_t *ds_ht_init(unsigned int htsize, int expire)
 	memset(dsht, 0, sizeof(ds_ht_t));
 	dsht->htsize = htsize;
 	dsht->htexpire = expire;
+	dsht->htinitexpire = initexpire;
 
 	dsht->entries = (ds_entry_t*)shm_malloc(dsht->htsize*sizeof(ds_entry_t));
 	if(dsht->entries==NULL)
@@ -144,7 +149,7 @@ int ds_ht_destroy(ds_ht_t *dsht)
 }
 
 
-int ds_add_cell(ds_ht_t *dsht, str *cid, char *duid, int dset)
+int ds_add_cell(ds_ht_t *dsht, str *cid, str *duid, int dset)
 {
 	unsigned int idx;
 	unsigned int hid;
@@ -152,7 +157,10 @@ int ds_add_cell(ds_ht_t *dsht, str *cid, char *duid, int dset)
 	time_t now;
 
 	if(dsht==NULL || dsht->entries==NULL)
+	{
+		LM_ERR("invalid parameters.\n");
 		return -1;
+	}
 
 	hid = ds_compute_hash(cid);
 	
@@ -173,6 +181,8 @@ int ds_add_cell(ds_ht_t *dsht, str *cid, char *duid, int dset)
 				&& strncmp(cid->s, it->callid.s, cid->len)==0)
 		{
 			lock_release(&dsht->entries[idx].lock);
+			LM_WARN("call-id already in hash table [%.*s].\n",
+					cid->len, cid->s);
 			return -2;
 		}
 		prev = it;
@@ -187,6 +197,7 @@ int ds_add_cell(ds_ht_t *dsht, str *cid, char *duid, int dset)
 		return -1;
 	}
 	cell->expire = now + dsht->htexpire;
+	cell->initexpire = now + dsht->htinitexpire;
 	if(prev==NULL)
 	{
 		if(dsht->entries[idx].first!=NULL)
@@ -207,6 +218,62 @@ int ds_add_cell(ds_ht_t *dsht, str *cid, char *duid, int dset)
 	return 0;
 }
 
+int ds_unlock_cell(ds_ht_t *dsht, str *cid)
+{
+	unsigned int idx;
+	unsigned int hid;
+
+	if(dsht==NULL || dsht->entries==NULL)
+		return -1;
+
+	hid = ds_compute_hash(cid);
+	
+	idx = ds_get_entry(hid, dsht->htsize);
+
+	/* head test and return */
+	if(dsht->entries[idx].first==NULL)
+		return 0;
+	
+	lock_release(&dsht->entries[idx].lock);
+	return 0;
+}
+
+ds_cell_t* ds_get_cell(ds_ht_t *dsht, str *cid)
+{
+	unsigned int idx;
+	unsigned int hid;
+	ds_cell_t *it;
+
+	if(dsht==NULL || dsht->entries==NULL)
+		return 0;
+
+	hid = ds_compute_hash(cid);
+	
+	idx = ds_get_entry(hid, dsht->htsize);
+
+	/* head test and return */
+	if(dsht->entries[idx].first==NULL)
+		return 0;
+	
+	lock_get(&dsht->entries[idx].lock);
+	it = dsht->entries[idx].first;
+	while(it!=NULL && it->cellid < hid)
+		it = it->next;
+	while(it!=NULL && it->cellid == hid)
+	{
+		if(cid->len==it->callid.len 
+				&& strncmp(cid->s, it->callid.s, cid->len)==0)
+		{
+			/* found */
+			return it;
+		}
+		it = it->next;
+	}
+	lock_release(&dsht->entries[idx].lock);
+	return 0;
+}
+
+
 int ds_del_cell(ds_ht_t *dsht, str *cid)
 {
 	unsigned int idx;
@@ -264,9 +331,9 @@ int ds_ht_dbg(ds_ht_t *dsht)
 		while(it)
 		{
 			LM_ERR("\tcell: %.*s\n", it->callid.len, it->callid.s);
-			LM_ERR("\tduid: %s\n", it->duid);
-			LM_ERR("\thid: %u expire: %u\n", it->cellid,
-					(unsigned int)it->expire);
+			LM_ERR("\tduid: %.*s\n", it->duid.len, it->duid.s);
+			LM_ERR("\thid: %u expire: %u initexpire: %u\n", it->cellid,
+					(unsigned int)it->expire, (unsigned int)it->initexpire);
 			LM_ERR("\tdset:%d\n", it->dset);
 			it = it->next;
 		}

+ 10 - 4
modules_k/dispatcher/ds_ht.h

@@ -28,15 +28,18 @@
 #include "../../str.h"
 #include "../../locking.h"
 
-#define DS_DUID_SIZE	16
+#define DS_LOAD_INIT		0
+#define DS_LOAD_CONFIRMED	1
 
 typedef struct _ds_cell
 {
     unsigned int cellid;
 	str callid;
-	char duid[DS_DUID_SIZE];
+	str duid;
 	int dset;
+	int state;
 	time_t  expire;
+	time_t  initexpire;
     struct _ds_cell *prev;
     struct _ds_cell *next;
 } ds_cell_t;
@@ -51,15 +54,18 @@ typedef struct _ds_entry
 typedef struct _ds_ht
 {
 	unsigned int htexpire;
+	unsigned int htinitexpire;
 	unsigned int htsize;
 	ds_entry_t *entries;
 	struct _ds_ht *next;
 } ds_ht_t;
 
-ds_ht_t *ds_ht_init(unsigned int htsize, int expire);
+ds_ht_t *ds_ht_init(unsigned int htsize, int expire, int initexpire);
 int ds_ht_destroy(ds_ht_t *dsht);
-int ds_add_cell(ds_ht_t *dsht, str *cid, char *did, int dset);
+int ds_add_cell(ds_ht_t *dsht, str *cid, str *did, int dset);
 int ds_del_cell(ds_ht_t *dsht, str *cid);
+ds_cell_t* ds_get_cell(ds_ht_t *dsht, str *cid);
+int ds_unlock_cell(ds_ht_t *dsht, str *cid);
 
 int ds_ht_dbg(ds_ht_t *dsht);
 int ds_cell_free(ds_cell_t *cell);

Некоторые файлы не были показаны из-за большого количества измененных файлов