Browse Source

modules/lcr: Add support for R-URI matching.

- An additional request_uri column has been introduced. If other than
  NULL, it also needs to match beside prefix and from_uri in order
  for the rule to be selected.
Richard Fuchs 13 years ago
parent
commit
c47d39153c

+ 9 - 0
lib/srdb1/schema/lcr_rule.xml

@@ -52,6 +52,15 @@
         <description>PCRE regular expression that is matched to caller's URI</description>
         <description>PCRE regular expression that is matched to caller's URI</description>
     </column>
     </column>
 
 
+    <column id="request_uri">
+        <name>request_uri</name>
+        <type>string</type>
+        <size>&domain_len;</size>
+        <null/>
+        <default><null/></default>
+        <description>PCRE regular expression that is matched to full request URI</description>
+    </column>
+
     <column id="stopper">
     <column id="stopper">
         <name>stopper</name>
         <name>stopper</name>
         <type>unsigned int</type>
         <type>unsigned int</type>

+ 7 - 0
lib/srdb2/schema/lcr.xml

@@ -24,6 +24,13 @@
 	<size>&uri_len;</size>
 	<size>&uri_len;</size>
   </column>
   </column>
 
 
+  <column id="lcr.request_uri">
+	<name>request_uri</name>
+	<type>string</type>
+	<default>%</default>
+	<size>&uri_len;</size>
+  </column>
+
   <column id="lcr.grp_id">
   <column id="lcr.grp_id">
 	<name>grp_id</name>
 	<name>grp_id</name>
 	<type>int</type>
 	<type>int</type>

+ 164 - 145
modules/lcr/README

@@ -43,25 +43,26 @@ Juha Heinanen
               3.16. lcr_rule_table (string)
               3.16. lcr_rule_table (string)
               3.17. prefix_column (string)
               3.17. prefix_column (string)
               3.18. from_uri_column (string)
               3.18. from_uri_column (string)
-              3.19. stopper_column (string)
-              3.20. enabled_column (string)
-              3.21. lcr_rule_target_table (string)
-              3.22. rule_id_column (string)
-              3.23. gw_id_column (string)
-              3.24. priority_column (string)
-              3.25. weight_column (string)
-              3.26. lcr_count (integer)
-              3.27. gw_uri_avp (AVP string)
-              3.28. ruri_user_avp (AVP string)
-              3.29. tag_avp (AVP string)
-              3.30. flags_avp (AVP string)
-              3.31. defunct_capability (integer)
-              3.32. lcr_id_avp (AVP string)
-              3.33. defunct_gw_avp (AVP string)
-              3.34. lcr_rule_hash_size (integer)
-              3.35. lcr_gw_count (integer)
-              3.36. dont_strip_or_tag_flag (integer)
-              3.37. fetch_rows (integer)
+              3.19. request_uri_column (string)
+              3.20. stopper_column (string)
+              3.21. enabled_column (string)
+              3.22. lcr_rule_target_table (string)
+              3.23. rule_id_column (string)
+              3.24. gw_id_column (string)
+              3.25. priority_column (string)
+              3.26. weight_column (string)
+              3.27. lcr_count (integer)
+              3.28. gw_uri_avp (AVP string)
+              3.29. ruri_user_avp (AVP string)
+              3.30. tag_avp (AVP string)
+              3.31. flags_avp (AVP string)
+              3.32. defunct_capability (integer)
+              3.33. lcr_id_avp (AVP string)
+              3.34. defunct_gw_avp (AVP string)
+              3.35. lcr_rule_hash_size (integer)
+              3.36. lcr_gw_count (integer)
+              3.37. dont_strip_or_tag_flag (integer)
+              3.38. fetch_rows (integer)
 
 
         4. Functions
         4. Functions
 
 
@@ -102,37 +103,38 @@ Juha Heinanen
    1.16. Setting lcr_rule_table module parameter
    1.16. Setting lcr_rule_table module parameter
    1.17. Setting prefix_column module parameter
    1.17. Setting prefix_column module parameter
    1.18. Setting from_uri_column module parameter
    1.18. Setting from_uri_column module parameter
-   1.19. Setting stopper_column module parameter
-   1.20. Setting enabled_column module parameter
-   1.21. Setting lcr_rule_target_table module parameter
-   1.22. Setting rule_id_column module parameter
-   1.23. Setting gw_id_column module parameter
-   1.24. Setting priority_column module parameter
-   1.25. Setting weight_column module parameter
-   1.26. Setting lcr_count module parameter
-   1.27. Setting gw_uri_avp module parameter
-   1.28. Setting ruri_user_avp module parameter
-   1.29. Setting tag_avp module parameter
-   1.30. Setting flags_avp module parameter
-   1.31. Setting defunct_capability module parameter
-   1.32. Setting lcr_id_avp module parameter
-   1.33. Setting defunct_gw_avp module parameter
-   1.34. Setting lcr_rule_hash_size module parameter
-   1.35. Setting lcr_gw_count module parameter
-   1.36. Setting dont_strip_or_tag_flag module parameter
-   1.37. Set fetch_rows parameter
-   1.38. load_gws usage
-   1.39. next_gw usage from a route block
-   1.40. next_gw usage from a failure route block
-   1.41. defunct_gw usage
-   1.42. from_gw usage
+   1.19. Setting request_uri_column module parameter
+   1.20. Setting stopper_column module parameter
+   1.21. Setting enabled_column module parameter
+   1.22. Setting lcr_rule_target_table module parameter
+   1.23. Setting rule_id_column module parameter
+   1.24. Setting gw_id_column module parameter
+   1.25. Setting priority_column module parameter
+   1.26. Setting weight_column module parameter
+   1.27. Setting lcr_count module parameter
+   1.28. Setting gw_uri_avp module parameter
+   1.29. Setting ruri_user_avp module parameter
+   1.30. Setting tag_avp module parameter
+   1.31. Setting flags_avp module parameter
+   1.32. Setting defunct_capability module parameter
+   1.33. Setting lcr_id_avp module parameter
+   1.34. Setting defunct_gw_avp module parameter
+   1.35. Setting lcr_rule_hash_size module parameter
+   1.36. Setting lcr_gw_count module parameter
+   1.37. Setting dont_strip_or_tag_flag module parameter
+   1.38. Set fetch_rows parameter
+   1.39. load_gws usage
+   1.40. next_gw usage from a route block
+   1.41. next_gw usage from a failure route block
+   1.42. defunct_gw usage
    1.43. from_gw usage
    1.43. from_gw usage
-   1.44. to_gw usage
+   1.44. from_gw usage
    1.45. to_gw usage
    1.45. to_gw usage
-   1.46. lcr.reload RPC example
-   1.47. lcr.dump_gws RPC example
-   1.48. lcr.dump_rules RPC example
-   1.49. lcr.defunct_gw RPC example
+   1.46. to_gw usage
+   1.47. lcr.reload RPC example
+   1.48. lcr.dump_gws RPC example
+   1.49. lcr.dump_rules RPC example
+   1.50. lcr.defunct_gw RPC example
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -164,25 +166,26 @@ Chapter 1. Admin Guide
         3.16. lcr_rule_table (string)
         3.16. lcr_rule_table (string)
         3.17. prefix_column (string)
         3.17. prefix_column (string)
         3.18. from_uri_column (string)
         3.18. from_uri_column (string)
-        3.19. stopper_column (string)
-        3.20. enabled_column (string)
-        3.21. lcr_rule_target_table (string)
-        3.22. rule_id_column (string)
-        3.23. gw_id_column (string)
-        3.24. priority_column (string)
-        3.25. weight_column (string)
-        3.26. lcr_count (integer)
-        3.27. gw_uri_avp (AVP string)
-        3.28. ruri_user_avp (AVP string)
-        3.29. tag_avp (AVP string)
-        3.30. flags_avp (AVP string)
-        3.31. defunct_capability (integer)
-        3.32. lcr_id_avp (AVP string)
-        3.33. defunct_gw_avp (AVP string)
-        3.34. lcr_rule_hash_size (integer)
-        3.35. lcr_gw_count (integer)
-        3.36. dont_strip_or_tag_flag (integer)
-        3.37. fetch_rows (integer)
+        3.19. request_uri_column (string)
+        3.20. stopper_column (string)
+        3.21. enabled_column (string)
+        3.22. lcr_rule_target_table (string)
+        3.23. rule_id_column (string)
+        3.24. gw_id_column (string)
+        3.25. priority_column (string)
+        3.26. weight_column (string)
+        3.27. lcr_count (integer)
+        3.28. gw_uri_avp (AVP string)
+        3.29. ruri_user_avp (AVP string)
+        3.30. tag_avp (AVP string)
+        3.31. flags_avp (AVP string)
+        3.32. defunct_capability (integer)
+        3.33. lcr_id_avp (AVP string)
+        3.34. defunct_gw_avp (AVP string)
+        3.35. lcr_rule_hash_size (integer)
+        3.36. lcr_gw_count (integer)
+        3.37. dont_strip_or_tag_flag (integer)
+        3.38. fetch_rows (integer)
 
 
    4. Functions
    4. Functions
 
 
@@ -217,15 +220,17 @@ Chapter 1. Admin Guide
 
 
    For the purpose of facilitating least cost routing of requests, each
    For the purpose of facilitating least cost routing of requests, each
    gateway of an LCR instance is associated with one or more <prefix, from
    gateway of an LCR instance is associated with one or more <prefix, from
-   pattern, priority, weight> tuples. A gateway matches a request if user
-   part of the Request-URI matches a "prefix" and the caller's URI matches
-   a "from" pattern in a tuple that is associated with the gateway.
+   uri pattern, request uri pattern, priority, weight> tuples. A gateway
+   matches a request if user part of the Request-URI matches a "prefix",
+   the caller's URI matches a "From-URI" pattern and the callee's URI
+   matches a "Request-URI" pattern in a tuple that is associated with the
+   gateway.
 
 
    When the function load_gws() is called, matching gateways (that are not
    When the function load_gws() is called, matching gateways (that are not
    currently designated as defunct) are ordered for forwarding purposes as
    currently designated as defunct) are ordered for forwarding purposes as
    follows:
    follows:
 
 
-     * (1) according to longest user part match
+     * (1) according to longest Request-URI user part match
      * (2) according to tuple's priority
      * (2) according to tuple's priority
      * (3) according to tuple's randomized weight
      * (3) according to tuple's randomized weight
 
 
@@ -233,11 +238,12 @@ Chapter 1. Admin Guide
    matches, then matching stops at it and all other tuples with shorter
    matches, then matching stops at it and all other tuples with shorter
    prefixes are not considered.
    prefixes are not considered.
 
 
-   Prefix is a string of characters or NULL. From pattern is a regular
-   expression (see 'man pcresyntax' for syntax), an empty string, or NULL.
-   An empty or NULL from pattern or prefix matches anything. Smaller
-   priority value means higher priority (highest priority value being 0
-   and lowest being 255).
+   Prefix is a string of characters or NULL. From-URI pattern and
+   Request-URI pattern are regular expressions (see 'man pcresyntax' for
+   syntax), an empty string, or NULL. An empty or NULL From-URI pattern,
+   Request-URI pattern or prefix matches anything. Smaller priority value
+   means higher priority (highest priority value being 0 and lowest being
+   255).
 
 
    Weight is an integer value from 1 to 254. Weight implementation is
    Weight is an integer value from 1 to 254. Weight implementation is
    fast, but unfair favoring larger weight values at the expense smaller
    fast, but unfair favoring larger weight values at the expense smaller
@@ -306,25 +312,26 @@ Chapter 1. Admin Guide
    3.16. lcr_rule_table (string)
    3.16. lcr_rule_table (string)
    3.17. prefix_column (string)
    3.17. prefix_column (string)
    3.18. from_uri_column (string)
    3.18. from_uri_column (string)
-   3.19. stopper_column (string)
-   3.20. enabled_column (string)
-   3.21. lcr_rule_target_table (string)
-   3.22. rule_id_column (string)
-   3.23. gw_id_column (string)
-   3.24. priority_column (string)
-   3.25. weight_column (string)
-   3.26. lcr_count (integer)
-   3.27. gw_uri_avp (AVP string)
-   3.28. ruri_user_avp (AVP string)
-   3.29. tag_avp (AVP string)
-   3.30. flags_avp (AVP string)
-   3.31. defunct_capability (integer)
-   3.32. lcr_id_avp (AVP string)
-   3.33. defunct_gw_avp (AVP string)
-   3.34. lcr_rule_hash_size (integer)
-   3.35. lcr_gw_count (integer)
-   3.36. dont_strip_or_tag_flag (integer)
-   3.37. fetch_rows (integer)
+   3.19. request_uri_column (string)
+   3.20. stopper_column (string)
+   3.21. enabled_column (string)
+   3.22. lcr_rule_target_table (string)
+   3.23. rule_id_column (string)
+   3.24. gw_id_column (string)
+   3.25. priority_column (string)
+   3.26. weight_column (string)
+   3.27. lcr_count (integer)
+   3.28. gw_uri_avp (AVP string)
+   3.29. ruri_user_avp (AVP string)
+   3.30. tag_avp (AVP string)
+   3.31. flags_avp (AVP string)
+   3.32. defunct_capability (integer)
+   3.33. lcr_id_avp (AVP string)
+   3.34. defunct_gw_avp (AVP string)
+   3.35. lcr_rule_hash_size (integer)
+   3.36. lcr_gw_count (integer)
+   3.37. dont_strip_or_tag_flag (integer)
+   3.38. fetch_rows (integer)
 
 
 3.1. db_url (string)
 3.1. db_url (string)
 
 
@@ -537,98 +544,110 @@ modparam("lcr", "prefix_column", "number_prefix")
 modparam("lcr", "from_uri_column", "caller_uri")
 modparam("lcr", "from_uri_column", "caller_uri")
 ...
 ...
 
 
-3.19. stopper_column (string)
+3.19. request_uri_column (string)
+
+   Name of the column holding the regular expression to match against the
+   complete request URI (including the "sip:" prefix).
+
+   Default value is “request_uri”.
+
+   Example 1.19. Setting request_uri_column module parameter
+...
+modparam("lcr", "request_uri_column", "callee_uri")
+...
+
+3.20. stopper_column (string)
 
 
    Name of the column holding rule's stopper attribute.
    Name of the column holding rule's stopper attribute.
 
 
    Default value is “stopper”.
    Default value is “stopper”.
 
 
-   Example 1.19. Setting stopper_column module parameter
+   Example 1.20. Setting stopper_column module parameter
 ...
 ...
 modparam("lcr", "stopper_column", "stop")
 modparam("lcr", "stopper_column", "stop")
 ...
 ...
 
 
-3.20. enabled_column (string)
+3.21. enabled_column (string)
 
 
    Name of the column telling is the rule is currently enabled or
    Name of the column telling is the rule is currently enabled or
    disabled.
    disabled.
 
 
    Default value is “enabled”.
    Default value is “enabled”.
 
 
-   Example 1.20. Setting enabled_column module parameter
+   Example 1.21. Setting enabled_column module parameter
 ...
 ...
 modparam("lcr", "enabled_column", "in_use")
 modparam("lcr", "enabled_column", "in_use")
 ...
 ...
 
 
-3.21. lcr_rule_target_table (string)
+3.22. lcr_rule_target_table (string)
 
 
    Name of the table holding information about the LCR rule targets
    Name of the table holding information about the LCR rule targets
    (gateways).
    (gateways).
 
 
    Default value is “lcr_rule_target”.
    Default value is “lcr_rule_target”.
 
 
-   Example 1.21. Setting lcr_rule_target_table module parameter
+   Example 1.22. Setting lcr_rule_target_table module parameter
 ...
 ...
 modparam("lcr", "lcr_rule_target_table", "rules")
 modparam("lcr", "lcr_rule_target_table", "rules")
 ...
 ...
 
 
-3.22. rule_id_column (string)
+3.23. rule_id_column (string)
 
 
    Name of lcr_rule_target_table column containing an id of lcr_rule
    Name of lcr_rule_target_table column containing an id of lcr_rule
    table.
    table.
 
 
    Default value is “rule_id”.
    Default value is “rule_id”.
 
 
-   Example 1.22. Setting rule_id_column module parameter
+   Example 1.23. Setting rule_id_column module parameter
 ...
 ...
 modparam("lcr", "rule_id_column", "rule")
 modparam("lcr", "rule_id_column", "rule")
 ...
 ...
 
 
-3.23. gw_id_column (string)
+3.24. gw_id_column (string)
 
 
    Name of lcr_rule_target_table column containing an id of lcr_gw table.
    Name of lcr_rule_target_table column containing an id of lcr_gw table.
 
 
    Default value is “gw_id”.
    Default value is “gw_id”.
 
 
-   Example 1.23. Setting gw_id_column module parameter
+   Example 1.24. Setting gw_id_column module parameter
 ...
 ...
 modparam("lcr", "gw_id_column", "gw")
 modparam("lcr", "gw_id_column", "gw")
 ...
 ...
 
 
-3.24. priority_column (string)
+3.25. priority_column (string)
 
 
    Name of the column holding the priority of the rule target.
    Name of the column holding the priority of the rule target.
 
 
    Default value is “priority”.
    Default value is “priority”.
 
 
-   Example 1.24. Setting priority_column module parameter
+   Example 1.25. Setting priority_column module parameter
 ...
 ...
 modparam("lcr", "priority_column", "priority")
 modparam("lcr", "priority_column", "priority")
 ...
 ...
 
 
-3.25. weight_column (string)
+3.26. weight_column (string)
 
 
    Name of the column holding weight of rule target.
    Name of the column holding weight of rule target.
 
 
    Default value is “weight”.
    Default value is “weight”.
 
 
-   Example 1.25. Setting weight_column module parameter
+   Example 1.26. Setting weight_column module parameter
 ...
 ...
 modparam("lcr","weight_column", "target_weight")
 modparam("lcr","weight_column", "target_weight")
 ...
 ...
 
 
-3.26. lcr_count (integer)
+3.27. lcr_count (integer)
 
 
    Number of LCR instances.
    Number of LCR instances.
 
 
    Default value is 1.
    Default value is 1.
 
 
-   Example 1.26.  Setting lcr_count module parameter
+   Example 1.27.  Setting lcr_count module parameter
 ...
 ...
 modparam("lcr", "lcr_count", 10)
 modparam("lcr", "lcr_count", 10)
 ...
 ...
 
 
-3.27. gw_uri_avp (AVP string)
+3.28. gw_uri_avp (AVP string)
 
 
    Internal AVP that load_gws() function uses to store information of
    Internal AVP that load_gws() function uses to store information of
    matching gateways.
    matching gateways.
@@ -636,12 +655,12 @@ modparam("lcr", "lcr_count", 10)
    There is NO default value, thus this variable must be defined in
    There is NO default value, thus this variable must be defined in
    sip-router.cfg.
    sip-router.cfg.
 
 
-   Example 1.27. Setting gw_uri_avp module parameter
+   Example 1.28. Setting gw_uri_avp module parameter
 ...
 ...
 modparam("lcr", "gw_uri_avp", "$avp(i:709)")
 modparam("lcr", "gw_uri_avp", "$avp(i:709)")
 ...
 ...
 
 
-3.28. ruri_user_avp (AVP string)
+3.29. ruri_user_avp (AVP string)
 
 
    Internal AVP that next_gw function uses to store Request-URI user for
    Internal AVP that next_gw function uses to store Request-URI user for
    subsequent next_gw calls.
    subsequent next_gw calls.
@@ -649,12 +668,12 @@ modparam("lcr", "gw_uri_avp", "$avp(i:709)")
    There is NO default value, thus this variable must be defined in
    There is NO default value, thus this variable must be defined in
    sip-router.cfg.
    sip-router.cfg.
 
 
-   Example 1.28. Setting ruri_user_avp module parameter
+   Example 1.29. Setting ruri_user_avp module parameter
 ...
 ...
 modparam("lcr", "ruri_user_avp", "$avp(i:500)")
 modparam("lcr", "ruri_user_avp", "$avp(i:500)")
 ...
 ...
 
 
-3.29. tag_avp (AVP string)
+3.30. tag_avp (AVP string)
 
 
    If defined, an AVP where successful next_gw and from_gw functions store
    If defined, an AVP where successful next_gw and from_gw functions store
    gateway's tag.
    gateway's tag.
@@ -662,12 +681,12 @@ modparam("lcr", "ruri_user_avp", "$avp(i:500)")
    There is NO default value, i.e, if not defined, gateway's tag is not
    There is NO default value, i.e, if not defined, gateway's tag is not
    stored anywhere.
    stored anywhere.
 
 
-   Example 1.29. Setting tag_avp module parameter
+   Example 1.30. Setting tag_avp module parameter
 ...
 ...
 modparam("lcr", "tag_avp", "$avp(lcr_tag)")
 modparam("lcr", "tag_avp", "$avp(lcr_tag)")
 ...
 ...
 
 
-3.30. flags_avp (AVP string)
+3.31. flags_avp (AVP string)
 
 
    If defined, an AVP where successful next_gw and from_gw functions store
    If defined, an AVP where successful next_gw and from_gw functions store
    gateway's flags.
    gateway's flags.
@@ -675,24 +694,24 @@ modparam("lcr", "tag_avp", "$avp(lcr_tag)")
    There is NO default value, i.e, if not defined, gateway's flags are not
    There is NO default value, i.e, if not defined, gateway's flags are not
    stored anywhere.
    stored anywhere.
 
 
-   Example 1.30. Setting flags_avp module parameter
+   Example 1.31. Setting flags_avp module parameter
 ...
 ...
 modparam("lcr", "flags_avp", "$avp(i:712)")
 modparam("lcr", "flags_avp", "$avp(i:712)")
 ...
 ...
 
 
-3.31. defunct_capability (integer)
+3.32. defunct_capability (integer)
 
 
    Tells if defunct capability of (non-responsive) gateways is supported.
    Tells if defunct capability of (non-responsive) gateways is supported.
    Non-zero value turns on defunct capability.
    Non-zero value turns on defunct capability.
 
 
    Default value is 0.
    Default value is 0.
 
 
-   Example 1.31.  Setting defunct_capability module parameter
+   Example 1.32.  Setting defunct_capability module parameter
 ...
 ...
 modparam("lcr", "defunct_capability", 1)
 modparam("lcr", "defunct_capability", 1)
 ...
 ...
 
 
-3.32. lcr_id_avp (AVP string)
+3.33. lcr_id_avp (AVP string)
 
 
    Internal AVP that load_gws() function uses to store LCR instance
    Internal AVP that load_gws() function uses to store LCR instance
    identifier of loaded gateways. Only needed if gateway defunct
    identifier of loaded gateways. Only needed if gateway defunct
@@ -700,12 +719,12 @@ modparam("lcr", "defunct_capability", 1)
 
 
    There is NO default value.
    There is NO default value.
 
 
-   Example 1.32. Setting lcr_id_avp module parameter
+   Example 1.33. Setting lcr_id_avp module parameter
 ...
 ...
 modparam("lcr", "lcr_id_avp", "$avp(s:lcr_id_avp)")
 modparam("lcr", "lcr_id_avp", "$avp(s:lcr_id_avp)")
 ...
 ...
 
 
-3.33. defunct_gw_avp (AVP string)
+3.34. defunct_gw_avp (AVP string)
 
 
    Internal AVP that next_gw() function uses to store internal index of
    Internal AVP that next_gw() function uses to store internal index of
    the selected gateway for later use by defunct_gw() function. Only
    the selected gateway for later use by defunct_gw() function. Only
@@ -713,12 +732,12 @@ modparam("lcr", "lcr_id_avp", "$avp(s:lcr_id_avp)")
 
 
    There is NO default value.
    There is NO default value.
 
 
-   Example 1.33. Setting defunct_gw_avp module parameter
+   Example 1.34. Setting defunct_gw_avp module parameter
 ...
 ...
 modparam("lcr", "defunct_gw_avp", "$avp(s:defunct_gw_avp)")
 modparam("lcr", "defunct_gw_avp", "$avp(s:defunct_gw_avp)")
 ...
 ...
 
 
-3.34. lcr_rule_hash_size (integer)
+3.35. lcr_rule_hash_size (integer)
 
 
    Defines the size of hash table used to store LCR rules. Hashing is done
    Defines the size of hash table used to store LCR rules. Hashing is done
    based on rule's prefix. Larger value means less collisions with other
    based on rule's prefix. Larger value means less collisions with other
@@ -726,35 +745,35 @@ modparam("lcr", "defunct_gw_avp", "$avp(s:defunct_gw_avp)")
 
 
    Default value is 128.
    Default value is 128.
 
 
-   Example 1.34.  Setting lcr_rule_hash_size module parameter
+   Example 1.35.  Setting lcr_rule_hash_size module parameter
 ...
 ...
 modparam("lcr", "lcr_rule_hash_size", 1024)
 modparam("lcr", "lcr_rule_hash_size", 1024)
 ...
 ...
 
 
-3.35. lcr_gw_count (integer)
+3.36. lcr_gw_count (integer)
 
 
    Defines the maximum number of gateways in lcr_gw table.
    Defines the maximum number of gateways in lcr_gw table.
 
 
    Default value is 128.
    Default value is 128.
 
 
-   Example 1.35.  Setting lcr_gw_count module parameter
+   Example 1.36.  Setting lcr_gw_count module parameter
 ...
 ...
 modparam("lcr", "lcr_gw_count", 1024)
 modparam("lcr", "lcr_gw_count", 1024)
 ...
 ...
 
 
-3.36. dont_strip_or_tag_flag (integer)
+3.37. dont_strip_or_tag_flag (integer)
 
 
    Defines the flag number used to tell if stripping and tagging is done
    Defines the flag number used to tell if stripping and tagging is done
    for the selected gateway.
    for the selected gateway.
 
 
    Default value is -1 meaning that the flag is not defined.
    Default value is -1 meaning that the flag is not defined.
 
 
-   Example 1.36.  Setting dont_strip_or_tag_flag module parameter
+   Example 1.37.  Setting dont_strip_or_tag_flag module parameter
 ...
 ...
 modparam("lcr", "dont_strip_or_tag_flag", 10)
 modparam("lcr", "dont_strip_or_tag_flag", 10)
 ...
 ...
 
 
-3.37. fetch_rows (integer)
+3.38. fetch_rows (integer)
 
 
    The number of the rows to be fetched at once from database when loading
    The number of the rows to be fetched at once from database when loading
    data from lcr_rule table. This value can be used to tune the load time
    data from lcr_rule table. This value can be used to tune the load time
@@ -764,7 +783,7 @@ modparam("lcr", "dont_strip_or_tag_flag", 10)
 
 
    Default value is “1024”.
    Default value is “1024”.
 
 
-   Example 1.37. Set fetch_rows parameter
+   Example 1.38. Set fetch_rows parameter
 ...
 ...
 modparam("lcr", "fetch_rows", 3000)
 modparam("lcr", "fetch_rows", 3000)
 ...
 ...
@@ -799,7 +818,7 @@ modparam("lcr", "fetch_rows", 3000)
 
 
    This function can be used from REQUEST_ROUTE.
    This function can be used from REQUEST_ROUTE.
 
 
-   Example 1.38. load_gws usage
+   Example 1.39. load_gws usage
 ...
 ...
 if (!load_gws(1, $rU, $var(caller_uri))) {
 if (!load_gws(1, $rU, $var(caller_uri))) {
         sl_send_reply("500", "Server Internal Error - Cannot load gateways");
         sl_send_reply("500", "Server Internal Error - Cannot load gateways");
@@ -829,7 +848,7 @@ if (!load_gws(1, $rU, $var(caller_uri))) {
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.39. next_gw usage from a route block
+   Example 1.40. next_gw usage from a route block
 ...
 ...
 if (!next_gw()) {
 if (!next_gw()) {
         sl_send_reply("503", "Service not available - No gateways");
         sl_send_reply("503", "Service not available - No gateways");
@@ -837,7 +856,7 @@ if (!next_gw()) {
 };
 };
 ...
 ...
 
 
-   Example 1.40. next_gw usage from a failure route block
+   Example 1.41. next_gw usage from a failure route block
 ...
 ...
 if (!next_gw()) {
 if (!next_gw()) {
         t_reply("503", "Service not available - No more gateways");
         t_reply("503", "Service not available - No more gateways");
@@ -857,7 +876,7 @@ if (!next_gw()) {
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.41. defunct_gw usage
+   Example 1.42. defunct_gw usage
 ...
 ...
 defunct_gw(60);
 defunct_gw(60);
 ...
 ...
@@ -889,7 +908,7 @@ defunct_gw(60);
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE.
    ONREPLY_ROUTE.
 
 
-   Example 1.42. from_gw usage
+   Example 1.43. from_gw usage
 ...
 ...
 if (from_gw(1, $avp(s:real_source_addr), 2) {
 if (from_gw(1, $avp(s:real_source_addr), 2) {
         ...
         ...
@@ -919,7 +938,7 @@ if (from_gw(1, $avp(s:real_source_addr), 2) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE.
    ONREPLY_ROUTE.
 
 
-   Example 1.43. from_gw usage
+   Example 1.44. from_gw usage
 ...
 ...
 $var(lcr_id) = from_any_gw("192.168.1.1", 3);
 $var(lcr_id) = from_any_gw("192.168.1.1", 3);
 ...
 ...
@@ -940,7 +959,7 @@ $var(lcr_id) = from_any_gw("192.168.1.1", 3);
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.44. to_gw usage
+   Example 1.45. to_gw usage
 ...
 ...
 if (to_gw("1")) {
 if (to_gw("1")) {
         ...
         ...
@@ -966,7 +985,7 @@ if (to_gw("1")) {
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
-   Example 1.45. to_gw usage
+   Example 1.46. to_gw usage
 ...
 ...
 if (to_any_gw("192.55.66.2", 1)) {
 if (to_any_gw("192.55.66.2", 1)) {
         ...
         ...
@@ -989,7 +1008,7 @@ if (to_any_gw("192.55.66.2", 1)) {
 
 
    Parameters: none
    Parameters: none
 
 
-   Example 1.46. lcr.reload RPC example
+   Example 1.47. lcr.reload RPC example
                 $ sercmd lcr.reload
                 $ sercmd lcr.reload
 
 
 5.2. lcr.dump_gws
 5.2. lcr.dump_gws
@@ -998,7 +1017,7 @@ if (to_any_gw("192.55.66.2", 1)) {
 
 
    Parameters: none
    Parameters: none
 
 
-   Example 1.47. lcr.dump_gws RPC example
+   Example 1.48. lcr.dump_gws RPC example
                 $ sercmd lcr.dump_gws
                 $ sercmd lcr.dump_gws
 
 
 5.3. lcr.dump_rules
 5.3. lcr.dump_rules
@@ -1008,7 +1027,7 @@ if (to_any_gw("192.55.66.2", 1)) {
 
 
    Parameters: none
    Parameters: none
 
 
-   Example 1.48. lcr.dump_rules RPC example
+   Example 1.49. lcr.dump_rules RPC example
                 $ sercmd lcr.dump_rules
                 $ sercmd lcr.dump_rules
 
 
 5.4. lcr.defunct_gw
 5.4. lcr.defunct_gw
@@ -1021,7 +1040,7 @@ if (to_any_gw("192.55.66.2", 1)) {
 
 
    Parameters: lcr_id gw_id period
    Parameters: lcr_id gw_id period
 
 
-   Example 1.49. lcr.defunct_gw RPC example
+   Example 1.50. lcr.defunct_gw RPC example
                 $ sercmd lcr.defunct_gw 1 4 120
                 $ sercmd lcr.defunct_gw 1 4 120
 
 
 6. Known Limitations
 6. Known Limitations

+ 29 - 7
modules/lcr/doc/lcr_admin.xml

@@ -32,10 +32,11 @@
 	<para>
 	<para>
 	For the purpose of facilitating least cost routing of requests,
 	For the purpose of facilitating least cost routing of requests,
 	each gateway of an LCR instance is associated with one or more 
 	each gateway of an LCR instance is associated with one or more 
-	&lt;prefix, from pattern, priority, weight&gt;
+	&lt;prefix, from uri pattern, request uri pattern, priority, weight&gt;
 	tuples.  A gateway matches a request if user part of the Request-URI
 	tuples.  A gateway matches a request if user part of the Request-URI
-	matches a "prefix" and the caller's URI matches a "from" pattern in a
-	tuple that is associated with the gateway.
+	matches a "prefix", the caller's URI matches a "From-URI" pattern and
+	the callee's URI matches a "Request-URI" pattern in a tuple that is
+	associated with the gateway.
 	</para>
 	</para>
 	<para>
 	<para>
 	When the function <emphasis>load_gws()</emphasis> is called,
 	When the function <emphasis>load_gws()</emphasis> is called,
@@ -45,7 +46,7 @@
 	<para>
 	<para>
 	<itemizedlist>
 	<itemizedlist>
             <listitem>
             <listitem>
-                <para>(1) according to longest user part match
+                <para>(1) according to longest Request-URI user part match
                 </para>
                 </para>
             </listitem>
             </listitem>
             <listitem>
             <listitem>
@@ -64,10 +65,10 @@
 	with shorter prefixes are not considered.
 	with shorter prefixes are not considered.
 	</para>
 	</para>
 	<para>
 	<para>
-	Prefix is a string of characters or NULL.  From
-	pattern is a regular expression (see 'man 
+	Prefix is a string of characters or NULL.  From-URI
+	pattern and Request-URI pattern are regular expressions (see 'man 
 	pcresyntax' for syntax), an empty string, or NULL.  An empty or
 	pcresyntax' for syntax), an empty string, or NULL.  An empty or
-	NULL from pattern or prefix matches anything.
+	NULL From-URI pattern, Request-URI pattern or prefix matches anything.
 	Smaller priority value means higher priority (highest priority
 	Smaller priority value means higher priority (highest priority
 	value being 0 and lowest being 255).
 	value being 0 and lowest being 255).
 	</para>
 	</para>
@@ -535,6 +536,27 @@ modparam("lcr", "from_uri_column", "caller_uri")
 		</example>
 		</example>
 	</section>
 	</section>
 
 
+	<section>
+		<title><varname>request_uri_column</varname> (string)</title>
+		<para>
+		Name of the column holding the regular expression to match
+		against the complete request URI (including the "sip:" prefix).
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>request_uri</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Setting <varname>request_uri_column</varname> module parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("lcr", "request_uri_column", "callee_uri")
+...
+</programlisting>
+		</example>
+	</section>
+
 	<section>
 	<section>
 		<title><varname>stopper_column</varname> (string)</title>
 		<title><varname>stopper_column</varname> (string)</title>
 		<para>
 		<para>

+ 14 - 3
modules/lcr/hash.c

@@ -38,7 +38,9 @@ int rule_hash_table_insert(struct rule_info **hash_table,
 			   unsigned int lcr_id, unsigned int rule_id,
 			   unsigned int lcr_id, unsigned int rule_id,
 			   unsigned short prefix_len, char *prefix,
 			   unsigned short prefix_len, char *prefix,
 			   unsigned short from_uri_len, char *from_uri,
 			   unsigned short from_uri_len, char *from_uri,
-			   pcre *from_uri_re, unsigned short stopper)
+			   pcre *from_uri_re, unsigned short request_uri_len,
+			   char *request_uri, pcre *request_uri_re,
+			   unsigned short stopper)
 {
 {
     struct rule_info *rule;
     struct rule_info *rule;
     str prefix_str;
     str prefix_str;
@@ -48,6 +50,7 @@ int rule_hash_table_insert(struct rule_info **hash_table,
     if (rule == NULL) {
     if (rule == NULL) {
 	LM_ERR("Cannot allocate memory for rule hash table entry\n");
 	LM_ERR("Cannot allocate memory for rule hash table entry\n");
 	if (from_uri_re) shm_free(from_uri_re);
 	if (from_uri_re) shm_free(from_uri_re);
+	if (request_uri_re) shm_free(request_uri_re);
 	return 0;
 	return 0;
     }
     }
     memset(rule, 0, sizeof(struct rule_info));
     memset(rule, 0, sizeof(struct rule_info));
@@ -63,6 +66,12 @@ int rule_hash_table_insert(struct rule_info **hash_table,
 	(rule->from_uri)[from_uri_len] = '\0';
 	(rule->from_uri)[from_uri_len] = '\0';
 	rule->from_uri_re = from_uri_re;
 	rule->from_uri_re = from_uri_re;
     }
     }
+    rule->request_uri_len = request_uri_len;
+    if (request_uri_len) {
+	memcpy(rule->request_uri, request_uri, request_uri_len);
+	(rule->request_uri)[request_uri_len] = '\0';
+	rule->request_uri_re = request_uri_re;
+    }
     rule->stopper = stopper;
     rule->stopper = stopper;
     rule->targets = (struct target *)NULL;
     rule->targets = (struct target *)NULL;
 
 
@@ -73,9 +82,9 @@ int rule_hash_table_insert(struct rule_info **hash_table,
     rule->next = hash_table[hash_val];
     rule->next = hash_table[hash_val];
     hash_table[hash_val] = rule;
     hash_table[hash_val] = rule;
     
     
-    LM_DBG("inserted rule <%u>, prefix <%.*s>, from_uri <%.*s>, stopper <%u>, "
+    LM_DBG("inserted rule <%u>, prefix <%.*s>, from_uri <%.*s>, request_uri <%.*s>, stopper <%u>, "
 	   "into index <%u>\n",
 	   "into index <%u>\n",
-	   rule_id, prefix_len, prefix, from_uri_len, from_uri, stopper,
+	   rule_id, prefix_len, prefix, from_uri_len, from_uri, request_uri_len, request_uri, stopper,
 	   hash_val);
 	   hash_val);
 
 
     return 1;
     return 1;
@@ -177,6 +186,8 @@ void rule_hash_table_contents_free(struct rule_info **hash_table)
 	    if (r->from_uri_re) {
 	    if (r->from_uri_re) {
 		shm_free(r->from_uri_re);
 		shm_free(r->from_uri_re);
 	    }
 	    }
+	    if (r->request_uri_re)
+		shm_free(r->request_uri_re);
 	    t = r->targets;
 	    t = r->targets;
 	    while (t) {
 	    while (t) {
 		next_t = t->next;
 		next_t = t->next;

+ 3 - 1
modules/lcr/hash.h

@@ -36,7 +36,9 @@ int rule_hash_table_insert(struct rule_info **hash_table,
 			   unsigned int lcr_id, unsigned int rule_id,
 			   unsigned int lcr_id, unsigned int rule_id,
 			   unsigned short prefix_len, char *prefix,
 			   unsigned short prefix_len, char *prefix,
 			   unsigned short from_uri_len, char *from_uri,
 			   unsigned short from_uri_len, char *from_uri,
-			   pcre *from_uri_re, unsigned short stopper);
+			   pcre *from_uri_re, unsigned short request_uri_len,
+			   char *request_uri, pcre *request_uri_re,
+			   unsigned short stopper);
 
 
 int rule_hash_table_insert_target(struct rule_info **hash_table,
 int rule_hash_table_insert_target(struct rule_info **hash_table,
 				  struct gw_info *gws,
 				  struct gw_info *gws,

+ 94 - 44
modules/lcr/lcr_mod.c

@@ -89,7 +89,7 @@ MODULE_VERSION
 /*
 /*
  * versions of database tables required by the module.
  * versions of database tables required by the module.
  */
  */
-#define LCR_RULE_TABLE_VERSION 1
+#define LCR_RULE_TABLE_VERSION 2
 #define LCR_RULE_TARGET_TABLE_VERSION 1
 #define LCR_RULE_TARGET_TABLE_VERSION 1
 #define LCR_GW_TABLE_VERSION 2
 #define LCR_GW_TABLE_VERSION 2
 
 
@@ -103,6 +103,7 @@ MODULE_VERSION
 #define LCR_ID_COL "lcr_id"
 #define LCR_ID_COL "lcr_id"
 #define PREFIX_COL "prefix"
 #define PREFIX_COL "prefix"
 #define FROM_URI_COL "from_uri"
 #define FROM_URI_COL "from_uri"
+#define REQUEST_URI_COL "request_uri"
 #define STOPPER_COL "stopper"
 #define STOPPER_COL "stopper"
 #define ENABLED_COL "enabled"
 #define ENABLED_COL "enabled"
 #define RULE_ID_COL "rule_id"
 #define RULE_ID_COL "rule_id"
@@ -164,6 +165,7 @@ static str id_col           = str_init(ID_COL);
 static str lcr_id_col       = str_init(LCR_ID_COL);
 static str lcr_id_col       = str_init(LCR_ID_COL);
 static str prefix_col       = str_init(PREFIX_COL);
 static str prefix_col       = str_init(PREFIX_COL);
 static str from_uri_col     = str_init(FROM_URI_COL);
 static str from_uri_col     = str_init(FROM_URI_COL);
+static str request_uri_col  = str_init(REQUEST_URI_COL);
 static str stopper_col      = str_init(STOPPER_COL);
 static str stopper_col      = str_init(STOPPER_COL);
 static str enabled_col      = str_init(ENABLED_COL);
 static str enabled_col      = str_init(ENABLED_COL);
 static str rule_id_col      = str_init(RULE_ID_COL);
 static str rule_id_col      = str_init(RULE_ID_COL);
@@ -293,6 +295,7 @@ static param_export_t params[] = {
     {"id_column",                STR_PARAM, &id_col.s},
     {"id_column",                STR_PARAM, &id_col.s},
     {"prefix_column",            STR_PARAM, &prefix_col.s},
     {"prefix_column",            STR_PARAM, &prefix_col.s},
     {"from_uri_column",          STR_PARAM, &from_uri_col.s},
     {"from_uri_column",          STR_PARAM, &from_uri_col.s},
+    {"request_uri_column",       STR_PARAM, &request_uri_col.s},
     {"stopper_column",           STR_PARAM, &stopper_col.s},
     {"stopper_column",           STR_PARAM, &stopper_col.s},
     {"enabled_column",           STR_PARAM, &enabled_col.s},
     {"enabled_column",           STR_PARAM, &enabled_col.s},
     {"rule_id_column",           STR_PARAM, &rule_id_col.s},
     {"rule_id_column",           STR_PARAM, &rule_id_col.s},
@@ -416,6 +419,7 @@ static int mod_init(void)
     lcr_id_col.len = strlen(lcr_id_col.s);
     lcr_id_col.len = strlen(lcr_id_col.s);
     prefix_col.len = strlen(prefix_col.s);
     prefix_col.len = strlen(prefix_col.s);
     from_uri_col.len = strlen(from_uri_col.s);
     from_uri_col.len = strlen(from_uri_col.s);
+    request_uri_col.len = strlen(request_uri_col.s);
     stopper_col.len = strlen(stopper_col.s);
     stopper_col.len = strlen(stopper_col.s);
     enabled_col.len = strlen(enabled_col.s);
     enabled_col.len = strlen(enabled_col.s);
     rule_id_col.len = strlen(rule_id_col.s);
     rule_id_col.len = strlen(rule_id_col.s);
@@ -1127,18 +1131,19 @@ static int insert_gws(db1_res_t *res, struct gw_info *gws,
  */
  */
 int reload_tables()
 int reload_tables()
 {
 {
-    unsigned int i, n, lcr_id, rule_id, gw_id, from_uri_len, stopper,
-	prefix_len, enabled, gw_cnt, null_gw_ip_addr, priority, weight, tmp;
-    char *prefix, *from_uri;
+    unsigned int i, n, lcr_id, rule_id, gw_id, from_uri_len, request_uri_len,
+	stopper, prefix_len, enabled, gw_cnt, null_gw_ip_addr, priority,
+	weight, tmp;
+    char *prefix, *from_uri, *request_uri;
     db1_res_t* res = NULL;
     db1_res_t* res = NULL;
     db_row_t* row;
     db_row_t* row;
     db_key_t key_cols[1];
     db_key_t key_cols[1];
     db_op_t op[1];
     db_op_t op[1];
     db_val_t vals[1];
     db_val_t vals[1];
     db_key_t gw_cols[13];
     db_key_t gw_cols[13];
-    db_key_t rule_cols[5];
+    db_key_t rule_cols[6];
     db_key_t target_cols[4];
     db_key_t target_cols[4];
-    pcre *from_uri_re;
+    pcre *from_uri_re, *request_uri_re;
     struct gw_info *gws, *gw_pt_tmp;
     struct gw_info *gws, *gw_pt_tmp;
     struct rule_info **rules, **rule_pt_tmp;
     struct rule_info **rules, **rule_pt_tmp;
 
 
@@ -1152,6 +1157,7 @@ int reload_tables()
     rule_cols[2] = &from_uri_col;
     rule_cols[2] = &from_uri_col;
     rule_cols[3] = &stopper_col;
     rule_cols[3] = &stopper_col;
     rule_cols[4] = &enabled_col;
     rule_cols[4] = &enabled_col;
+    rule_cols[5] = &request_uri_col;
 	
 	
     gw_cols[0] = &gw_name_col;
     gw_cols[0] = &gw_name_col;
     gw_cols[1] = &ip_addr_col;
     gw_cols[1] = &ip_addr_col;
@@ -1172,7 +1178,7 @@ int reload_tables()
     target_cols[2] = &priority_col;
     target_cols[2] = &priority_col;
     target_cols[3] = &weight_col;
     target_cols[3] = &weight_col;
 
 
-    from_uri_re = 0;
+    request_uri_re = from_uri_re = 0;
 
 
     if (lcr_db_init(&db_url) < 0) {
     if (lcr_db_init(&db_url) < 0) {
 	LM_ERR("unable to open database connection\n");
 	LM_ERR("unable to open database connection\n");
@@ -1193,7 +1199,7 @@ int reload_tables()
 
 
 	VAL_INT(vals) = lcr_id;
 	VAL_INT(vals) = lcr_id;
 	if (DB_CAPABILITY(lcr_dbf, DB_CAP_FETCH)) {
 	if (DB_CAPABILITY(lcr_dbf, DB_CAP_FETCH)) {
-	    if (lcr_dbf.query(dbh, key_cols, op, vals, rule_cols, 1, 5, 0, 0)
+	    if (lcr_dbf.query(dbh, key_cols, op, vals, rule_cols, 1, 6, 0, 0)
 		< 0) {
 		< 0) {
 		LM_ERR("db query on lcr_rule table failed\n");
 		LM_ERR("db query on lcr_rule table failed\n");
 		goto err;
 		goto err;
@@ -1203,7 +1209,7 @@ int reload_tables()
 		goto err;
 		goto err;
 	    }
 	    }
 	} else {
 	} else {
-	    if (lcr_dbf.query(dbh, key_cols, op, vals, rule_cols, 1, 5, 0, &res)
+	    if (lcr_dbf.query(dbh, key_cols, op, vals, rule_cols, 1, 6, 0, &res)
 		< 0) {
 		< 0) {
 		LM_ERR("db query on lcr_rule table failed\n");
 		LM_ERR("db query on lcr_rule table failed\n");
 		goto err;
 		goto err;
@@ -1211,13 +1217,13 @@ int reload_tables()
 	}
 	}
 
 
 	n = 0;
 	n = 0;
-	from_uri_re = 0;
+	request_uri_re = from_uri_re = 0;
     
     
 	do {
 	do {
 	    LM_DBG("loading, cycle %d with <%d> rows", n++, RES_ROW_N(res));
 	    LM_DBG("loading, cycle %d with <%d> rows", n++, RES_ROW_N(res));
 	    for (i = 0; i < RES_ROW_N(res); i++) {
 	    for (i = 0; i < RES_ROW_N(res); i++) {
 
 
-		from_uri_re = 0;
+		request_uri_re = from_uri_re = 0;
 		row = RES_ROWS(res) + i;
 		row = RES_ROWS(res) + i;
 
 
 		if ((VAL_NULL(ROW_VALUES(row)) == 1) ||
 		if ((VAL_NULL(ROW_VALUES(row)) == 1) ||
@@ -1299,9 +1305,37 @@ int reload_tables()
 		    from_uri_re = 0;
 		    from_uri_re = 0;
 		}
 		}
 
 
+		if (VAL_NULL(ROW_VALUES(row) + 5) == 1) {
+		    request_uri_len = 0;
+		    request_uri = 0;
+		} else {
+		    if (VAL_TYPE(ROW_VALUES(row) + 5) != DB1_STRING) {
+			LM_ERR("lcr rule <%u> request_uri is not string\n",
+			       rule_id);
+			goto err;
+		    }
+		    request_uri = (char *)VAL_STRING(ROW_VALUES(row) + 5);
+		    request_uri_len = strlen(request_uri);
+		}
+		if (request_uri_len > MAX_URI_LEN) {
+		    LM_ERR("lcr rule <%u> request_uri is too long\n", rule_id);
+		    goto err;
+		}
+		if (request_uri_len > 0) {
+		    request_uri_re = reg_ex_comp(request_uri);
+		    if (request_uri_re == 0) {
+			LM_ERR("failed to compile lcr rule <%u> request_uri "
+			       "<%s>\n", rule_id, request_uri);
+			goto err;
+		    }
+		} else {
+		    request_uri_re = 0;
+		}
+
 		if (!rule_hash_table_insert(rules, lcr_id, rule_id, prefix_len,
 		if (!rule_hash_table_insert(rules, lcr_id, rule_id, prefix_len,
 					    prefix, from_uri_len, from_uri,
 					    prefix, from_uri_len, from_uri,
-					    from_uri_re, stopper) ||
+					    from_uri_re, request_uri_len,
+					    request_uri, request_uri_re, stopper) ||
 		    !prefix_len_insert(rules, prefix_len)) {
 		    !prefix_len_insert(rules, prefix_len)) {
 		    goto err;
 		    goto err;
 		}
 		}
@@ -1757,7 +1791,7 @@ void add_gws_into_avps(struct gw_info *gws, struct matched_gw_info *matched_gws,
  */
  */
 static int load_gws(struct sip_msg* _m, int argc, action_u_t argv[])
 static int load_gws(struct sip_msg* _m, int argc, action_u_t argv[])
 {
 {
-    str ruri_user, from_uri;
+    str ruri_user, from_uri, *request_uri;
     int i, j, lcr_id;
     int i, j, lcr_id;
     unsigned int gw_index, now, dex;
     unsigned int gw_index, now, dex;
     int_str val;
     int_str val;
@@ -1803,6 +1837,8 @@ static int load_gws(struct sip_msg* _m, int argc, action_u_t argv[])
     LM_DBG("load_gws(%u, %.*s, %.*s)\n", lcr_id, ruri_user.len, ruri_user.s,
     LM_DBG("load_gws(%u, %.*s, %.*s)\n", lcr_id, ruri_user.len, ruri_user.s,
 	   from_uri.len, from_uri.s);
 	   from_uri.len, from_uri.s);
 
 
+    request_uri = GET_RURI(_m);
+
     /* Use rules and gws with index lcr_id */
     /* Use rules and gws with index lcr_id */
     rules = rule_pt[lcr_id];
     rules = rule_pt[lcr_id];
     gws = gw_pt[lcr_id];
     gws = gw_pt[lcr_id];
@@ -1831,38 +1867,52 @@ static int load_gws(struct sip_msg* _m, int argc, action_u_t argv[])
 	rule = rule_hash_table_lookup(rules, pl->prefix_len, ruri_user.s);
 	rule = rule_hash_table_lookup(rules, pl->prefix_len, ruri_user.s);
 	while (rule) {
 	while (rule) {
 	    /* Match prefix */
 	    /* Match prefix */
-	    if ((rule->prefix_len == pl->prefix_len) && 
-		(strncmp(rule->prefix, ruri_user.s, pl->prefix_len) == 0)) {
-		/* Match from uri */
-		if ((rule->from_uri_len == 0) ||
-		    (pcre_exec(rule->from_uri_re, NULL, from_uri.s,
-			       from_uri.len, 0, 0, NULL, 0) >= 0)) {
-		    /* Load gws associated with this rule */
-		    t = rule->targets;
-		    while (t) {
-                        /* If this gw is defunct, skip it */
-		        if (gws[t->gw_index].defunct_until > now) goto skip_gw;
-			matched_gws[gw_index].gw_index = t->gw_index;
-			matched_gws[gw_index].prefix_len = pl->prefix_len;
-			matched_gws[gw_index].priority = t->priority;
-			matched_gws[gw_index].weight = t->weight *
-			    (rand() >> 8);
-			matched_gws[gw_index].duplicate = 0;
-			LM_DBG("added matched_gws[%d]=[%u, %u, %u, %u]\n",
-			       gw_index, t->gw_index, pl->prefix_len,
-			       t->priority, matched_gws[gw_index].weight);
-			gw_index++;
-		    skip_gw:
-			t = t->next;
-		    }
-		    /* Do not look further if this matching rule was stopper */
-		    if (rule->stopper == 1) goto done;
-		} else {
-		    LM_DBG("from uri <%.*s> did not match to from regex <%.*s>",
-			   from_uri.len, from_uri.s, rule->from_uri_len,
-			   rule->from_uri);
-		}
+	    if ((rule->prefix_len != pl->prefix_len) ||
+		(strncmp(rule->prefix, ruri_user.s, pl->prefix_len)))
+		    goto next;
+
+	    /* Match from uri */
+	    if ((rule->from_uri_len != 0) &&
+		(pcre_exec(rule->from_uri_re, NULL, from_uri.s,
+			   from_uri.len, 0, 0, NULL, 0) < 0)) {
+		LM_DBG("from uri <%.*s> did not match to from regex <%.*s>",
+		       from_uri.len, from_uri.s, rule->from_uri_len,
+		       rule->from_uri);
+		goto next;
 	    }
 	    }
+
+	    /* Match request uri */
+	    if ((rule->request_uri_len != 0) &&
+		(pcre_exec(rule->request_uri_re, NULL, request_uri->s,
+			   request_uri->len, 0, 0, NULL, 0) < 0)) {
+		LM_DBG("request uri <%.*s> did not match to request regex <%.*s>",
+		       request_uri->len, request_uri->s, rule->request_uri_len,
+		       rule->request_uri);
+		goto next;
+	    }
+
+	    /* Load gws associated with this rule */
+	    t = rule->targets;
+	    while (t) {
+		/* If this gw is defunct, skip it */
+		if (gws[t->gw_index].defunct_until > now) goto skip_gw;
+		matched_gws[gw_index].gw_index = t->gw_index;
+		matched_gws[gw_index].prefix_len = pl->prefix_len;
+		matched_gws[gw_index].priority = t->priority;
+		matched_gws[gw_index].weight = t->weight *
+		    (rand() >> 8);
+		matched_gws[gw_index].duplicate = 0;
+		LM_DBG("added matched_gws[%d]=[%u, %u, %u, %u]\n",
+		       gw_index, t->gw_index, pl->prefix_len,
+		       t->priority, matched_gws[gw_index].weight);
+		gw_index++;
+	    skip_gw:
+		t = t->next;
+	    }
+	    /* Do not look further if this matching rule was stopper */
+	    if (rule->stopper == 1) goto done;
+
+next:
 	    rule = rule->next;
 	    rule = rule->next;
 	}
 	}
 	pl = pl->next;
 	pl = pl->next;

+ 3 - 0
modules/lcr/lcr_mod.h

@@ -62,6 +62,9 @@ struct rule_info {
     char from_uri[MAX_URI_LEN + 1];
     char from_uri[MAX_URI_LEN + 1];
     unsigned short from_uri_len;
     unsigned short from_uri_len;
     pcre *from_uri_re;
     pcre *from_uri_re;
+    char request_uri[MAX_URI_LEN + 1];
+    unsigned short request_uri_len;
+    pcre *request_uri_re;
     unsigned short stopper;
     unsigned short stopper;
     unsigned int enabled;
     unsigned int enabled;
     struct target *targets;
     struct target *targets;

+ 5 - 2
modules/lcr/lcr_rpc.c

@@ -160,7 +160,7 @@ static void dump_rules(rpc_t* rpc, void* c)
     struct rule_info **rules, *rule;
     struct rule_info **rules, *rule;
     struct target *t;
     struct target *t;
     void* st;
     void* st;
-    str prefix, from_uri;
+    str prefix, from_uri, request_uri;
 
 
     for (j = 1; j <= lcr_count_param; j++) {
     for (j = 1; j <= lcr_count_param; j++) {
 	    
 	    
@@ -174,11 +174,14 @@ static void dump_rules(rpc_t* rpc, void* c)
 		prefix.len=rule->prefix_len;
 		prefix.len=rule->prefix_len;
 		from_uri.s=rule->from_uri;
 		from_uri.s=rule->from_uri;
 		from_uri.len=rule->from_uri_len;
 		from_uri.len=rule->from_uri_len;
-		rpc->struct_add(st, "ddSSd",
+		request_uri.s=rule->request_uri;
+		request_uri.len=rule->request_uri_len;
+		rpc->struct_add(st, "ddSSSd",
 				"lcr_id", j,
 				"lcr_id", j,
 				"rule_id", rule->rule_id,
 				"rule_id", rule->rule_id,
 				"prefix", &prefix,
 				"prefix", &prefix,
 				"from_uri", &from_uri,
 				"from_uri", &from_uri,
+				"request_uri", &request_uri,
 				"stopper", rule->stopper
 				"stopper", rule->stopper
 				);
 				);
 		t = rule->targets;
 		t = rule->targets;

+ 2 - 2
utils/kamctl/db_berkeley/kamailio/lcr_rule

@@ -1,5 +1,5 @@
 METADATA_COLUMNS
 METADATA_COLUMNS
-id(int) lcr_id(int) prefix(str) from_uri(str) stopper(int) enabled(int)
+id(int) lcr_id(int) prefix(str) request_uri(str) from_uri(str) stopper(int) enabled(int)
 METADATA_KEY
 METADATA_KEY
 2 
 2 
 METADATA_READONLY
 METADATA_READONLY
@@ -7,4 +7,4 @@ METADATA_READONLY
 METADATA_LOGFLAGS
 METADATA_LOGFLAGS
 0
 0
 METADATA_DEFAULTS
 METADATA_DEFAULTS
-NIL|NIL|NULL|NULL|0|1
+NIL|NIL|NULL|NULL|NULL|0|1

+ 1 - 1
utils/kamctl/db_berkeley/kamailio/version

@@ -63,7 +63,7 @@ imc_rooms|1
 lcr_gw|
 lcr_gw|
 lcr_gw|2
 lcr_gw|2
 lcr_rule|
 lcr_rule|
-lcr_rule|1
+lcr_rule|2
 lcr_rule_target|
 lcr_rule_target|
 lcr_rule_target|1
 lcr_rule_target|1
 location|
 location|

+ 3 - 2
utils/kamctl/db_sqlite/lcr-create.sql

@@ -31,14 +31,15 @@ CREATE TABLE lcr_rule_target (
 
 
 CREATE INDEX lcr_rule_target_lcr_id_idx ON lcr_rule_target (lcr_id);
 CREATE INDEX lcr_rule_target_lcr_id_idx ON lcr_rule_target (lcr_id);
 
 
-INSERT INTO version (table_name, table_version) values ('lcr_rule','1');
+INSERT INTO version (table_name, table_version) values ('lcr_rule','2');
 CREATE TABLE lcr_rule (
 CREATE TABLE lcr_rule (
     id INTEGER PRIMARY KEY NOT NULL,
     id INTEGER PRIMARY KEY NOT NULL,
     lcr_id SMALLINT NOT NULL,
     lcr_id SMALLINT NOT NULL,
     prefix VARCHAR(16) DEFAULT NULL,
     prefix VARCHAR(16) DEFAULT NULL,
+    request_uri VARCHAR(64) DEFAULT NULL,
     from_uri VARCHAR(64) DEFAULT NULL,
     from_uri VARCHAR(64) DEFAULT NULL,
     stopper INTEGER DEFAULT 0 NOT NULL,
     stopper INTEGER DEFAULT 0 NOT NULL,
     enabled INTEGER DEFAULT 1 NOT NULL,
     enabled INTEGER DEFAULT 1 NOT NULL,
-    CONSTRAINT lcr_rule_lcr_id_prefix_from_uri_idx UNIQUE (lcr_id, prefix, from_uri)
+    CONSTRAINT lcr_rule_lcr_id_prefix_from_uri_idx UNIQUE (lcr_id, prefix, request_uri, from_uri)
 );
 );
 
 

+ 1 - 1
utils/kamctl/dbtext/kamailio/lcr_rule

@@ -1 +1 @@
-id(int,auto) lcr_id(int) prefix(string,null) from_uri(string,null) stopper(int) enabled(int) 
+id(int,auto) lcr_id(int) prefix(string,null) request_uri(string,null) from_uri(string,null) stopper(int) enabled(int) 

+ 1 - 1
utils/kamctl/dbtext/kamailio/version

@@ -26,7 +26,7 @@ htable:2
 imc_members:1
 imc_members:1
 imc_rooms:1
 imc_rooms:1
 lcr_gw:2
 lcr_gw:2
-lcr_rule:1
+lcr_rule:2
 lcr_rule_target:1
 lcr_rule_target:1
 location:5
 location:5
 matrix:1
 matrix:1

+ 3 - 2
utils/kamctl/mysql/lcr-create.sql

@@ -31,14 +31,15 @@ CREATE TABLE lcr_rule_target (
 
 
 CREATE INDEX lcr_id_idx ON lcr_rule_target (lcr_id);
 CREATE INDEX lcr_id_idx ON lcr_rule_target (lcr_id);
 
 
-INSERT INTO version (table_name, table_version) values ('lcr_rule','1');
+INSERT INTO version (table_name, table_version) values ('lcr_rule','2');
 CREATE TABLE lcr_rule (
 CREATE TABLE lcr_rule (
     id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
     id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
     lcr_id SMALLINT UNSIGNED NOT NULL,
     lcr_id SMALLINT UNSIGNED NOT NULL,
     prefix VARCHAR(16) DEFAULT NULL,
     prefix VARCHAR(16) DEFAULT NULL,
+    request_uri VARCHAR(64) DEFAULT NULL,
     from_uri VARCHAR(64) DEFAULT NULL,
     from_uri VARCHAR(64) DEFAULT NULL,
     stopper INT UNSIGNED DEFAULT 0 NOT NULL,
     stopper INT UNSIGNED DEFAULT 0 NOT NULL,
     enabled INT UNSIGNED DEFAULT 1 NOT NULL,
     enabled INT UNSIGNED DEFAULT 1 NOT NULL,
-    CONSTRAINT lcr_id_prefix_from_uri_idx UNIQUE (lcr_id, prefix, from_uri)
+    CONSTRAINT lcr_id_prefix_from_uri_idx UNIQUE (lcr_id, prefix, request_uri, from_uri)
 ) ENGINE=MyISAM;
 ) ENGINE=MyISAM;
 
 

+ 3 - 2
utils/kamctl/oracle/lcr-create.sql

@@ -47,15 +47,16 @@ BEGIN map2users('lcr_rule_target'); END;
 /
 /
 CREATE INDEX lcr_rule_target_lcr_id_idx  ON lcr_rule_target (lcr_id);
 CREATE INDEX lcr_rule_target_lcr_id_idx  ON lcr_rule_target (lcr_id);
 
 
-INSERT INTO version (table_name, table_version) values ('lcr_rule','1');
+INSERT INTO version (table_name, table_version) values ('lcr_rule','2');
 CREATE TABLE lcr_rule (
 CREATE TABLE lcr_rule (
     id NUMBER(10) PRIMARY KEY,
     id NUMBER(10) PRIMARY KEY,
     lcr_id NUMBER(5),
     lcr_id NUMBER(5),
     prefix VARCHAR2(16) DEFAULT NULL,
     prefix VARCHAR2(16) DEFAULT NULL,
+    request_uri VARCHAR2(64) DEFAULT NULL,
     from_uri VARCHAR2(64) DEFAULT NULL,
     from_uri VARCHAR2(64) DEFAULT NULL,
     stopper NUMBER(10) DEFAULT 0 NOT NULL,
     stopper NUMBER(10) DEFAULT 0 NOT NULL,
     enabled NUMBER(10) DEFAULT 1 NOT NULL,
     enabled NUMBER(10) DEFAULT 1 NOT NULL,
-    CONSTRAINT ORA_lcr_id_prefix_from_uri_idx  UNIQUE (lcr_id, prefix, from_uri)
+    CONSTRAINT ORA_lcr_id_prefix_from_uri_idx  UNIQUE (lcr_id, prefix, request_uri, from_uri)
 );
 );
 
 
 CREATE OR REPLACE TRIGGER lcr_rule_tr
 CREATE OR REPLACE TRIGGER lcr_rule_tr

+ 3 - 2
utils/kamctl/postgres/lcr-create.sql

@@ -31,14 +31,15 @@ CREATE TABLE lcr_rule_target (
 
 
 CREATE INDEX lcr_rule_target_lcr_id_idx ON lcr_rule_target (lcr_id);
 CREATE INDEX lcr_rule_target_lcr_id_idx ON lcr_rule_target (lcr_id);
 
 
-INSERT INTO version (table_name, table_version) values ('lcr_rule','1');
+INSERT INTO version (table_name, table_version) values ('lcr_rule','2');
 CREATE TABLE lcr_rule (
 CREATE TABLE lcr_rule (
     id SERIAL PRIMARY KEY NOT NULL,
     id SERIAL PRIMARY KEY NOT NULL,
     lcr_id SMALLINT NOT NULL,
     lcr_id SMALLINT NOT NULL,
     prefix VARCHAR(16) DEFAULT NULL,
     prefix VARCHAR(16) DEFAULT NULL,
+    request_uri VARCHAR(64) DEFAULT NULL,
     from_uri VARCHAR(64) DEFAULT NULL,
     from_uri VARCHAR(64) DEFAULT NULL,
     stopper INTEGER DEFAULT 0 NOT NULL,
     stopper INTEGER DEFAULT 0 NOT NULL,
     enabled INTEGER DEFAULT 1 NOT NULL,
     enabled INTEGER DEFAULT 1 NOT NULL,
-    CONSTRAINT lcr_rule_lcr_id_prefix_from_uri_idx UNIQUE (lcr_id, prefix, from_uri)
+    CONSTRAINT lcr_rule_lcr_id_prefix_from_uri_idx UNIQUE (lcr_id, prefix, request_uri, from_uri)
 );
 );