浏览代码

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 年之前
父节点
当前提交
9cdc3e7005

+ 261 - 71
modules_k/dispatcher/README

@@ -18,9 +18,9 @@ Carsten Bock
 
 
    Copyright © 2004 FhG FOKUS
    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
    Table of Contents
@@ -48,14 +48,20 @@ Carsten Bock
               3.11. dst_avp (str)
               3.11. dst_avp (str)
               3.12. grp_avp (str)
               3.12. grp_avp (str)
               3.13. cnt_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
         4. Exported Functions
 
 
@@ -67,6 +73,8 @@ Carsten Bock
               4.6. ds_mark_dst("s")
               4.6. ds_mark_dst("s")
               4.7. ds_is_from_list()
               4.7. ds_is_from_list()
               4.8. ds_is_from_list("group")
               4.8. ds_is_from_list("group")
+              4.9. ds_load_update()
+              4.10. ds_load_unset()
 
 
         5. Exported MI Functions
         5. Exported MI Functions
 
 
@@ -96,18 +104,25 @@ Carsten Bock
    1.11. Set the “dst_avp” parameter
    1.11. Set the “dst_avp” parameter
    1.12. Set the “grp_avp” parameter
    1.12. Set the “grp_avp” parameter
    1.13. Set the “cnt_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
 Chapter 1. Admin Guide
 
 
@@ -134,14 +149,20 @@ Chapter 1. Admin Guide
         3.11. dst_avp (str)
         3.11. dst_avp (str)
         3.12. grp_avp (str)
         3.12. grp_avp (str)
         3.13. cnt_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
    4. Exported Functions
 
 
@@ -153,6 +174,8 @@ Chapter 1. Admin Guide
         4.6. ds_mark_dst("s")
         4.6. ds_mark_dst("s")
         4.7. ds_is_from_list()
         4.7. ds_is_from_list()
         4.8. ds_is_from_list("group")
         4.8. ds_is_from_list("group")
+        4.9. ds_load_update()
+        4.10. ds_load_unset()
 
 
    5. Exported MI Functions
    5. Exported MI Functions
 
 
@@ -205,14 +228,20 @@ Chapter 1. Admin Guide
    3.11. dst_avp (str)
    3.11. dst_avp (str)
    3.12. grp_avp (str)
    3.12. grp_avp (str)
    3.13. cnt_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)
 3.1. list_file (string)
 
 
@@ -354,13 +383,13 @@ modparam("dispatcher", "force_dst", 1)
 
 
 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 AVPs.
    Default value is “null” - don't add AVPs.
 
 
    Example 1.11. Set the “dst_avp” parameter
    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)
 3.12. grp_avp (str)
@@ -370,13 +399,13 @@ Note
 
 
 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.
    Default value is “null” - don't add AVP.
 
 
    Example 1.12. Set the “grp_avp” parameter
    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)
 3.13. cnt_avp (str)
@@ -386,16 +415,46 @@ Note
 
 
 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.
    Default value is “null” - don't add AVP.
 
 
    Example 1.13. Set the “cnt_avp” parameter
    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.
    String with PVs used for the hashing algorithm 7.
 
 
@@ -406,29 +465,29 @@ Note
 
 
    Default value is “null” - disabled.
    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)")
  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")
  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
    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.16. Set the “setid_pvar” parameter
+   Example 1.18. Set the “setid_pvar” parameter
  ...
  ...
  modparam("dispatcher", "setid_pvar", "$var(setid)")
  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
    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
@@ -436,12 +495,12 @@ Note
 
 
    Default value is “OPTIONS”.
    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")
  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
    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
@@ -449,12 +508,12 @@ Note
 
 
    Default value is “sip:dispatcher@localhost”.
    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]")
  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
    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.
@@ -463,12 +522,12 @@ Note
 
 
    Default value is “0”.
    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)
  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
    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
    specific number of requests until it will change from "active" to
@@ -476,12 +535,12 @@ Note
 
 
    Default value is “3”.
    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)
  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
    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
@@ -490,12 +549,12 @@ Note
 
 
    Default value is “0”.
    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)
  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
    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
    in FAILURE_ROUTE. If set to 0, script writer has to call
@@ -503,11 +562,62 @@ Note
 
 
    Default value is “1”.
    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)
  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. Exported Functions
 
 
    4.1. ds_select_dst(set, alg)
    4.1. ds_select_dst(set, alg)
@@ -518,6 +628,8 @@ Note
    4.6. ds_mark_dst("s")
    4.6. ds_mark_dst("s")
    4.7. ds_is_from_list()
    4.7. ds_is_from_list()
    4.8. ds_is_from_list("group")
    4.8. ds_is_from_list("group")
+   4.9. ds_load_update()
+   4.10. ds_load_unset()
 
 
 4.1.  ds_select_dst(set, alg)
 4.1.  ds_select_dst(set, alg)
 
 
@@ -541,6 +653,23 @@ Note
           + “7” - hash over the content of PVs string. Note: This works
           + “7” - hash over the content of PVs string. Note: This works
             only when the parameter hash_pvar is set.
             only when the parameter hash_pvar is set.
           + “8” - use first destination (good for failover).
           + “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
           + “X” - if the algorithm is not implemented, the first entry in
             set is chosen.
             set is chosen.
 
 
@@ -551,7 +680,7 @@ Note
 
 
    This function can be used from REQUEST_ROUTE.
    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");
 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,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE and ONREPLY_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. Exported MI Functions
 
 
    5.1. ds_set_state
    5.1. ds_set_state
@@ -687,14 +858,33 @@ ds_select_dst("1", "$var(a)");
 
 
 6.1. Destination List File
 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$
 # $Id$
 # dispatcher destination sets
 # dispatcher destination sets
@@ -718,7 +908,7 @@ ds_select_dst("1", "$var(a)");
 
 
    Next picture displays a sample usage of dispatcher.
    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$
 # $Id$
 # sample config file for dispatcher module
 # 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 unsigned short grp_avp_type;
 extern int_str cnt_avp_name;
 extern int_str cnt_avp_name;
 extern unsigned short cnt_avp_type;
 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;
 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_mi_list(struct mi_node* rpl);
 int ds_print_sets(void);
 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);
 int ds_is_from_list(struct sip_msg *_m, int group);
 /*! \brief
 /*! \brief
  * Timer for checking inactive destinations
  * 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 dst_avp_param = {NULL, 0};
 static str grp_avp_param = {NULL, 0};
 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 attrs_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;
@@ -91,6 +93,10 @@ int_str grp_avp_name;
 unsigned short grp_avp_type;
 unsigned short grp_avp_type;
 int_str cnt_avp_name;
 int_str cnt_avp_name;
 unsigned short cnt_avp_type;
 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;
 pv_elem_t * hash_param_model = NULL;
 
 
@@ -103,6 +109,8 @@ int ds_probing_mode  = 0;
 int ds_append_branch = 1;
 int ds_append_branch = 1;
 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_check_interval = 30;
 
 
 /* tm */
 /* tm */
 struct tm_binds tmb;
 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_next_domain(struct sip_msg*, char*, char*);
 static int w_ds_mark_dst0(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_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_list0(struct sip_msg*, char*, char*);
 static int w_ds_is_from_list1(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 int mi_child_init(void);
 
 
 static cmd_export_t cmds[]={
 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}
 	{0,0,0,0,0,0}
 };
 };
 
 
@@ -170,6 +192,8 @@ static param_export_t params[]={
 	{"dst_avp",         STR_PARAM, &dst_avp_param.s},
 	{"dst_avp",         STR_PARAM, &dst_avp_param.s},
 	{"grp_avp",         STR_PARAM, &grp_avp_param.s},
 	{"grp_avp",         STR_PARAM, &grp_avp_param.s},
 	{"cnt_avp",         STR_PARAM, &cnt_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},
 	{"hash_pvar",       STR_PARAM, &hash_pvar_param.s},
 	{"setid_pvname",    STR_PARAM, &ds_setid_pvname.s},
 	{"setid_pvname",    STR_PARAM, &ds_setid_pvname.s},
 	{"ds_probing_threshhold", INT_PARAM, &probing_threshhold},
 	{"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_ping_interval",   INT_PARAM, &ds_ping_interval},
 	{"ds_probing_mode",    INT_PARAM, &ds_probing_mode},
 	{"ds_probing_mode",    INT_PARAM, &ds_probing_mode},
 	{"ds_append_branch",   INT_PARAM, &ds_append_branch},
 	{"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}
 	{0,0,0}
 };
 };
 
 
@@ -226,6 +253,10 @@ static int mod_init(void)
 		grp_avp_param.len = strlen(grp_avp_param.s);
 		grp_avp_param.len = strlen(grp_avp_param.s);
 	if (cnt_avp_param.s)
 	if (cnt_avp_param.s)
 		cnt_avp_param.len = strlen(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)
 	if (hash_pvar_param.s)
 		hash_pvar_param.len = strlen(hash_pvar_param.s);
 		hash_pvar_param.len = strlen(hash_pvar_param.s);
 	if (ds_setid_pvname.s)
 	if (ds_setid_pvname.s)
@@ -236,12 +267,6 @@ static int mod_init(void)
 	if(init_data()!= 0)
 	if(init_data()!= 0)
 		return -1;
 		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)
 	if(ds_db_url.s)
 	{
 	{
 		ds_db_url.len     = strlen(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_name.n = 0;
 		cnt_avp_type = 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 (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
@@ -346,6 +414,19 @@ static int mod_init(void)
 			return -1;
 			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: */
 	/* Only, if the Probing-Timer is enabled the TM-API needs to be loaded: */
 	if (ds_ping_interval > 0)
 	if (ds_ping_interval > 0)
 	{
 	{
@@ -393,6 +474,7 @@ static void destroy(void)
 	ds_destroy_list();
 	ds_destroy_list();
 	if(ds_db_url.s)
 	if(ds_db_url.s)
 		ds_disconnect_db();
 		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);
 		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)
 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)
@@ -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_ERR_RELOAD_LEN 		(sizeof(MI_ERR_RELOAD)-1)
 #define MI_NOT_SUPPORTED		"DB mode not configured"
 #define MI_NOT_SUPPORTED		"DB mode not configured"
 #define MI_NOT_SUPPORTED_LEN 	(sizeof(MI_NOT_SUPPORTED)-1)
 #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)
 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_db_url.s) {
 		if (ds_load_list(dslistfile)!=0)
 		if (ds_load_list(dslistfile)!=0)
 			return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
 			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)
 #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;
 	ds_cell_t *cell;
 	unsigned int msize;
 	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);
 	cell = (ds_cell_t*)shm_malloc(msize);
 	if(cell==NULL)
 	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);
 	cell->callid.s = (char*)cell + sizeof(ds_cell_t);
 	memcpy(cell->callid.s, cid->s, cid->len);
 	memcpy(cell->callid.s, cid->s, cid->len);
 	cell->callid.s[cid->len] = '\0';
 	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;
 	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;
 	int i;
 	ds_ht_t *dsht = NULL;
 	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));
 	memset(dsht, 0, sizeof(ds_ht_t));
 	dsht->htsize = htsize;
 	dsht->htsize = htsize;
 	dsht->htexpire = expire;
 	dsht->htexpire = expire;
+	dsht->htinitexpire = initexpire;
 
 
 	dsht->entries = (ds_entry_t*)shm_malloc(dsht->htsize*sizeof(ds_entry_t));
 	dsht->entries = (ds_entry_t*)shm_malloc(dsht->htsize*sizeof(ds_entry_t));
 	if(dsht->entries==NULL)
 	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 idx;
 	unsigned int hid;
 	unsigned int hid;
@@ -152,7 +157,10 @@ int ds_add_cell(ds_ht_t *dsht, str *cid, char *duid, int dset)
 	time_t now;
 	time_t now;
 
 
 	if(dsht==NULL || dsht->entries==NULL)
 	if(dsht==NULL || dsht->entries==NULL)
+	{
+		LM_ERR("invalid parameters.\n");
 		return -1;
 		return -1;
+	}
 
 
 	hid = ds_compute_hash(cid);
 	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)
 				&& strncmp(cid->s, it->callid.s, cid->len)==0)
 		{
 		{
 			lock_release(&dsht->entries[idx].lock);
 			lock_release(&dsht->entries[idx].lock);
+			LM_WARN("call-id already in hash table [%.*s].\n",
+					cid->len, cid->s);
 			return -2;
 			return -2;
 		}
 		}
 		prev = it;
 		prev = it;
@@ -187,6 +197,7 @@ int ds_add_cell(ds_ht_t *dsht, str *cid, char *duid, int dset)
 		return -1;
 		return -1;
 	}
 	}
 	cell->expire = now + dsht->htexpire;
 	cell->expire = now + dsht->htexpire;
+	cell->initexpire = now + dsht->htinitexpire;
 	if(prev==NULL)
 	if(prev==NULL)
 	{
 	{
 		if(dsht->entries[idx].first!=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;
 	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)
 int ds_del_cell(ds_ht_t *dsht, str *cid)
 {
 {
 	unsigned int idx;
 	unsigned int idx;
@@ -264,9 +331,9 @@ int ds_ht_dbg(ds_ht_t *dsht)
 		while(it)
 		while(it)
 		{
 		{
 			LM_ERR("\tcell: %.*s\n", it->callid.len, it->callid.s);
 			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);
 			LM_ERR("\tdset:%d\n", it->dset);
 			it = it->next;
 			it = it->next;
 		}
 		}

+ 10 - 4
modules_k/dispatcher/ds_ht.h

@@ -28,15 +28,18 @@
 #include "../../str.h"
 #include "../../str.h"
 #include "../../locking.h"
 #include "../../locking.h"
 
 
-#define DS_DUID_SIZE	16
+#define DS_LOAD_INIT		0
+#define DS_LOAD_CONFIRMED	1
 
 
 typedef struct _ds_cell
 typedef struct _ds_cell
 {
 {
     unsigned int cellid;
     unsigned int cellid;
 	str callid;
 	str callid;
-	char duid[DS_DUID_SIZE];
+	str duid;
 	int dset;
 	int dset;
+	int state;
 	time_t  expire;
 	time_t  expire;
+	time_t  initexpire;
     struct _ds_cell *prev;
     struct _ds_cell *prev;
     struct _ds_cell *next;
     struct _ds_cell *next;
 } ds_cell_t;
 } ds_cell_t;
@@ -51,15 +54,18 @@ typedef struct _ds_entry
 typedef struct _ds_ht
 typedef struct _ds_ht
 {
 {
 	unsigned int htexpire;
 	unsigned int htexpire;
+	unsigned int htinitexpire;
 	unsigned int htsize;
 	unsigned int htsize;
 	ds_entry_t *entries;
 	ds_entry_t *entries;
 	struct _ds_ht *next;
 	struct _ds_ht *next;
 } ds_ht_t;
 } 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_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);
 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_ht_dbg(ds_ht_t *dsht);
 int ds_cell_free(ds_cell_t *cell);
 int ds_cell_free(ds_cell_t *cell);

部分文件因为文件数量过多而无法显示