Browse code

Revert "* Moved lcr module from modules_k to modules and removed it from modules_s."

This reverts commit a3f16850cd2a897710cb0a56174e9f64dcc77653.

Juha Heinanen authored on 10/05/2009 09:40:06
Showing 22 changed files
1 1
similarity index 100%
2 2
rename from modules/lcr/Makefile
3 3
rename to modules_k/lcr/Makefile
4 4
similarity index 100%
5 5
rename from modules/lcr/README
6 6
rename to modules_k/lcr/README
7 7
similarity index 100%
8 8
rename from modules/lcr/doc/Makefile
9 9
rename to modules_k/lcr/doc/Makefile
10 10
similarity index 100%
11 11
rename from modules/lcr/doc/lcr.xml
12 12
rename to modules_k/lcr/doc/lcr.xml
13 13
similarity index 100%
14 14
rename from modules/lcr/doc/lcr_admin.xml
15 15
rename to modules_k/lcr/doc/lcr_admin.xml
16 16
similarity index 100%
17 17
rename from modules/lcr/hash.c
18 18
rename to modules_k/lcr/hash.c
19 19
similarity index 100%
20 20
rename from modules/lcr/hash.h
21 21
rename to modules_k/lcr/hash.h
22 22
similarity index 100%
23 23
rename from modules/lcr/lcr_mod.c
24 24
rename to modules_k/lcr/lcr_mod.c
25 25
similarity index 100%
26 26
rename from modules/lcr/lcr_mod.h
27 27
rename to modules_k/lcr/lcr_mod.h
28 28
similarity index 100%
29 29
rename from modules/lcr/mi.c
30 30
rename to modules_k/lcr/mi.c
31 31
similarity index 100%
32 32
rename from modules/lcr/mi.h
33 33
rename to modules_k/lcr/mi.h
34 34
new file mode 100644
... ...
@@ -0,0 +1,17 @@
1
+#
2
+# Least Cost Routing Module
3
+#
4
+# 
5
+# WARNING: do not run this directly, it should be run by the master Makefile
6
+
7
+include ../../Makefile.defs
8
+auto_gen=
9
+NAME=lcr.so
10
+LIBS=
11
+
12
+DEFS+=-DSER_MOD_INTERFACE
13
+
14
+SERLIBPATH=../../lib
15
+SER_LIBS+=$(SERLIBPATH)/srdb2/srdb2
16
+include ../../Makefile.modules
17
+
0 18
new file mode 100644
... ...
@@ -0,0 +1,259 @@
1
+
2
+Least Cost Routing Module
3
+
4
+Juha Heinanen
5
+
6
+Edited by
7
+
8
+Juha Heinanen
9
+
10
+   Copyright � 2005 Juha Heinanen
11
+     _________________________________________________________
12
+
13
+   Table of Contents
14
+
15
+   1. User's Guide
16
+
17
+        1.1. Overview
18
+        1.2. Dependencies
19
+        1.3. Exported Parameters
20
+        1.4. Exported Functions
21
+        1.5. FIFO Commands
22
+        1.6. Known Limitations
23
+
24
+   2. TODO
25
+     _________________________________________________________
26
+
27
+Chapter 1. User's Guide
28
+
29
+1.1. Overview
30
+
31
+   Least cost routing (LCR) module implements two related capabilities:
32
+
33
+   (1) sequential forwarding of a request to one or more gateways
34
+       (functions load_gws and next_gw),
35
+
36
+   (2) sequential forwarding to contacts if they don't share the
37
+       the same qvalue (functions load_contacts and next_contacts).
38
+
39
+   Gateway selection is based on caller's RPID URI (if available in
40
+   caller's RPID AVP after authentication) or From URI and user part of
41
+   Request-URI (telephone number).  Gateway patterns matching RPID or
42
+   From URI and telephone number are ordered for forwarding purpose (1)
43
+   according to longest user part match, (2) according to priority, and
44
+   (3) randomly.
45
+
46
+   Each gateway belongs to a gateway group either alone or among other
47
+   gateways.  All gateways in a group share the same priority.
48
+
49
+   Gateway and routing information is kept in two tables:  gw and lcr.
50
+
51
+   When a gateway is selected, Request-URI is rewritten with information
52
+   from gw table: URI scheme, prefix, IP address, port, and transport
53
+   protocol.  Valid URI scheme values are NULL = sip, 1 = sip and 2 =
54
+   sips.  Prefix is appended in front of Request-URI user part.
55
+   Currently valid transport protocol values are NULL = none, 1 = udp, 2
56
+   = tcp, and 3 = tls.
57
+
58
+   Table lcr contains prefix of user part of Request-URI, From URI,
59
+   gateway group id, and priority.  From URI can contain special
60
+   characters % and _ matching any number of any characters and any one
61
+   character, respectively.  
62
+
63
+   In addition to gw and lcr tables there is third table gw_grp that is
64
+   used for administrative purposes only to associate names with gateway
65
+   group ids.
66
+   _________________________________________________________
67
+
68
+1.2. Dependencies
69
+
70
+   The module depends on the following modules (in the other
71
+   words the listed modules must be loaded before this module):
72
+
73
+     * tm module
74
+     * mysql module
75
+     _________________________________________________________
76
+
77
+1.3. Exported Parameters
78
+
79
+   LCR module exports the following database related parameters that
80
+   have usual purpose:
81
+
82
+     * db_url (default system default)
83
+     * gw_table (default "gw")
84
+     * gw_name_column (default "gw_name")
85
+     * ip_addr_column (default "ip_addr")
86
+     * port_column (default "port")
87
+     * uri_scheme_column (default "uri_scheme")
88
+     * transport_column (default "transport")
89
+     * grp_id_column (default "grp_id")
90
+     * lcr_table (default "lcr")
91
+     * prefix_column (default "prefix")
92
+     * from_uri_column (default "from_uri")
93
+     * priority_column (default "priority")
94
+
95
+   In addition there are parameters that can be used to override names
96
+   of the AVPs used by LCR module:
97
+
98
+     * gw_uri_avp	  (default "1400")
99
+     * contact_avp	  (default "1401")
100
+     * fr_inv_timer_avp	  (default "fr_inv_timer_avp")
101
+     * rpid_avp		  (default "rpid")
102
+
103
+   If string value of an AVP parameter contains only digits, the name of
104
+   the AVP is int value of the string.
105
+
106
+   Finally, the parameters used by sequential forwarding:
107
+
108
+     * fr_inv_timer		(default 90)
109
+     * fr_inv_timer_next	(default 30)
110
+     * fr_inv_timer_param	(default "")
111
+     * fr_inv_timer_next_param	(default "")
112
+
113
+   Function next_contacts() sets tm fr_inv_timer to fr_inv_timer_next
114
+   value if, after next contacts, there are still lower qvalue
115
+   contacts available, and to fr_inv_timer value if next contacts are
116
+   the last ones left. fr_inv_timer_param can define an AVP
117
+   overwriting fr_inv_timer value, and similarly, AVP defined by
118
+   fr_inv_timer_next_param can overwrite fr_inv_timer_next value.
119
+    _________________________________________________________
120
+
121
+1.4. Exported Functions
122
+
123
+1.4.1. load_gws()
124
+
125
+   Loads URIs of gateways matching RPID AVP (if available) or From URI
126
+   and user part of Request-URI to gw_uri_avp AVPs.  Returns 1 or -1
127
+   depending on success.
128
+
129
+   Example:
130
+
131
+   if (!load_gws()) {
132
+      sl_send_reply("500", "Server Internal Error - Cannot load gateways");
133
+      break;
134
+   };
135
+
136
+1.4.2. next_gw()
137
+
138
+   If called from a route block, replaces Request-URI by the first
139
+   gw_uri_avp AVP value and destroys that AVP.
140
+
141
+   If called from a failure route block, appends a new branch to request,
142
+   whose Request-URI is the first gw_uri_avp AVP value, and destroys that
143
+   AVP.
144
+
145
+   Returns 1 on success and -1 if there were no gateways left or if an
146
+   error occurred (see syslog).
147
+
148
+   Must be preceded by successful load_gws() call.
149
+
150
+   Example from route block:
151
+   
152
+   if (!next_gw()) {
153
+      sl_send_reply("503", "Service not available - No gateways");
154
+      break;
155
+    };
156
+
157
+   Example from failure route block:
158
+
159
+   if (!next_gw()) {
160
+      t_reply("503", "Service not available - No more gateways");
161
+      break;	     
162
+    };
163
+
164
+1.4.3. from_gw()
165
+
166
+   Checks if request came from IP address of a gateway.
167
+
168
+   Example:
169
+   
170
+   if (from_gw()) {
171
+      ...
172
+      break;
173
+   };
174
+
175
+1.4.4. to_gw()
176
+
177
+   Checks if in-dialog request goes to a gateway.
178
+
179
+   Example:
180
+   
181
+   if (to_gw()) {
182
+      ...
183
+      break;
184
+   };
185
+
186
+1.4.5. load_contacts()
187
+
188
+   Loads contacts in destination set in increasing qvalue order as
189
+   values of lcr_contact AVP.  If all contacts in the destination set
190
+   have the same qvalue, load_contacts() does not do anything thus
191
+   minimizing performance impact of sequential forking capability when
192
+   it is not needed.  Returns 1 if loading of contacts succeeded or
193
+   there was nothing to do.  Returns -1 on error (see syslog).
194
+
195
+   Example:
196
+
197
+   if (!load_contacts()) {
198
+      sl_send_reply("500", "Server Internal Error - Cannot load contacts");
199
+      break;
200
+   };
201
+
202
+1.4.6. next_contacts()
203
+
204
+   If called from a route block, replaces Request-URI with the first
205
+   lcr_contact AVP value, adds the remaining lcr_contact AVP values with
206
+   the same qvalue as branches, and destroys those AVPs.  It does
207
+   nothing if there are no lcr_contact AVPs.  Returns 1 if there were no
208
+   errors and -1 if an error occurred (see syslog).
209
+
210
+   If called from a failure route block, adds the first lcr_contact AVP
211
+   value and all following lcr_contact AVP values with the same qvalue
212
+   as new branches to request and destroys those AVPs.  Returns 1 if new
213
+   branches were successfully added and -1 on error (see syslog) or if
214
+   there were no more lcr_contact AVPs.
215
+
216
+   Must be preceded by successful load_contacts() call.
217
+
218
+   Example from route block:
219
+   
220
+   if (!next_contacts()) {
221
+       sl_send_reply("500", "Server Internal Error");
222
+        break;
223
+   } else {
224
+      t_relay();
225
+   };
226
+
227
+   Example from failure route block:
228
+   
229
+   if (next_contacts()) {
230
+       t_relay();
231
+   };
232
+
233
+
234
+1.5. FIFO Commands
235
+
236
+1.5.1. lcr_reload
237
+
238
+   Causes lcr module to re-read the contents of gateway table
239
+   into memory.
240
+
241
+1.5.2. lcr_dump
242
+
243
+   Causes lcr module to dump the contents of its in-memory gateway
244
+   table. 
245
+
246
+1.6. Known Limitations
247
+
248
+   There is an unlikely race condition on lcr reload. If a process uses
249
+   in memory gw table, which is reloaded at the same time twice through
250
+   FIFO, the second reload will delete the original table still in use
251
+   by the process.
252
+   _________________________________________________________
253
+
254
+2.0. TODO
255
+
256
+   Function load_gws() currently makes an SQL query for the matching
257
+   gateways.  In order to avoid the query, also lcr table should be
258
+   read into memory and the corresponding query should be rewritten in
259
+   C.
0 260
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+docs = lcr.xml
2
+
3
+docbook_dir=../../../docbook
4
+include $(docbook_dir)/Makefile.module
0 5
new file mode 100644
... ...
@@ -0,0 +1,17 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
3
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
4
+
5
+<section id="flatstore.functions" xmlns:xi="http://www.w3.org/2001/XInclude">
6
+    <sectioninfo>
7
+	<revhistory>
8
+	    <revision>
9
+		<revnumber>$Revision$</revnumber>
10
+		<date>$Date$</date>
11
+	    </revision>
12
+	</revhistory>
13
+    </sectioninfo>
14
+
15
+    <title>Functions</title>
16
+
17
+</section>
0 18
new file mode 100644
... ...
@@ -0,0 +1,121 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
3
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
4
+
5
+<section id="lcr" xmlns:xi="http://www.w3.org/2001/XInclude">
6
+    <sectioninfo>
7
+	<authorgroup>
8
+	    <author>
9
+		<firstname>Juha</firstname>
10
+		<surname>Heinanen</surname>
11
+		<affiliation><orgname>FhG FOKUS</orgname></affiliation>
12
+		<address>
13
+		    <email></email>
14
+		</address>
15
+	    </author>
16
+	</authorgroup>
17
+	<copyright>
18
+	    <year>2003</year>
19
+	    <holder>FhG FOKUS</holder>
20
+	</copyright>
21
+	<revhistory>
22
+	    <revision>
23
+		<revnumber>$Revision$</revnumber>
24
+		<date>$Date$</date>
25
+	    </revision>
26
+	</revhistory>
27
+    </sectioninfo>
28
+
29
+    <title>LCR Module</title>
30
+
31
+    <section id="lcr.overview">
32
+	<title>Overview</title>
33
+	<para>
34
+         Least cost routing (LCR) module implements two related capabilities:
35
+       <itemizedlist>
36
+            <listitem> LCR may sequentially forward requests to one or more gateways using the load_gws 
37
+            and next_gw functions.
38
+            </listitem>
39
+
40
+            <listitem> LCR may sequentially forward contacts if they don't share the same qvalues.
41
+            Use the functions load_contacts and next_contacts to access and select a contact.
42
+            </listitem>
43
+        </itemizedlist>
44
+
45
+       <para>Gateway selection is based on caller's RPID URI (if available in caller's RPID AVP after 
46
+        authentication) or From URI and user part of Request-URI (telephone number).  Gateway patterns
47
+        matching RPID or From URI and telephone number are ordered for forwarding purposes as follows:
48
+        <itemizedlist>
49
+            <listitem>According to longest user part match
50
+            </listitem>
51
+
52
+            <listitem>According to priority
53
+            </listitem>
54
+
55
+            <listitem>Randomly
56
+            </listitem>
57
+        </itemizedlist>
58
+
59
+        Each gateway belongs to a gateway group either alone or among other gateways.  All gateways in a 
60
+        group share the same priority.  Gateway and routing information is kept in two tables:  
61
+        gw and lcr.
62
+        </para>
63
+
64
+        <para> When a gateway is selected, Request-URI is rewritten with information from gw table: 
65
+         URI scheme, prefix, IP address, port, and transport protocol.  Valid URI scheme values are:
66
+         <itemizedlist>
67
+            <listitem>NULL = sip
68
+            </listitem>
69
+            <listitem>1 = sip 
70
+            </listitem>
71
+            <listitem>2 = sips.  
72
+            </listitem>
73
+        </itemizedlist>
74
+        </para>
75
+
76
+        <para> If a prefix is specified it will be prepended to the Request-URI user part.
77
+        </para>
78
+
79
+        <para>Currently valid transport protocol values are: 
80
+         <itemizedlist>
81
+            <listitem>NULL = none
82
+            </listitem>
83
+            <listitem>1 = udp 
84
+            </listitem>
85
+            <listitem>2 = tcp  
86
+            </listitem>
87
+            <listitem>3 = tls  
88
+            </listitem>
89
+        </itemizedlist>
90
+        </para>
91
+
92
+        <para> Table lcr contains any prefix to be applied to the user part of Request-URI, the From URI,
93
+         the gateway group id, and the priority.  The From URI can contain special characters % and _ 
94
+         matching any number of any characters and any one character, respectively. 
95
+        </para>
96
+
97
+        <para> In addition to gw and lcr tables there is third table gw_grp that is used for 
98
+         administrative purposes only. In this table you may map names to the gateway group ids.
99
+        </para>
100
+
101
+	</para>
102
+    </section>
103
+
104
+    <section id="lcr.dependencies">
105
+	<title>Dependencies</title>
106
+	<para>The module depends on the following modules. These modules must be loaded before the LCR module
107
+         <itemizedlist>
108
+            <listitem>tm module
109
+            </listitem>
110
+            <listitem>mysql module
111
+            </listitem>
112
+        </itemizedlist>
113
+	</para>
114
+    </section>
115
+
116
+    
117
+    <xi:include href="params.xml"/>
118
+    <xi:include href="functions.xml"/>
119
+
120
+</section>
121
+
0 122
new file mode 100644
... ...
@@ -0,0 +1,235 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
3
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
4
+
5
+<section id="lcr.parameters" xmlns:xi="http://www.w3.org/2001/XInclude">
6
+    <sectioninfo>
7
+	<revhistory>
8
+	    <revision>
9
+		<revnumber>$Revision$</revnumber>
10
+		<date>$Date$</date>
11
+	    </revision>
12
+	</revhistory>
13
+    </sectioninfo>
14
+
15
+    <title>Parameters</title>
16
+
17
+    <section id="db_url">
18
+	<title><varname>db_url</varname> (string)</title>
19
+	<para>
20
+	    The URL for accessing the database where the LCR tables reside
21
+	</para>
22
+	<para>
23
+	    Default value is NULL.
24
+	</para>
25
+	<example>
26
+	    <title>Set <varname>db_url</varname> parameter</title>
27
+	    <programlisting>
28
+		...
29
+		modparam("lcr", "db_url", "mysql://ser:pwd@localhost/ser") 
30
+		...
31
+	    </programlisting>
32
+	</example>
33
+    </section>
34
+
35
+    <section id="gw_table">
36
+	<title><varname>gw_table</varname> (string)</title>
37
+	<para>
38
+	    The name of the table containing the list of gateways
39
+	</para>
40
+	<para>
41
+	    Default value is gw.
42
+	</para>
43
+	<example>
44
+	    <title>Set <varname>gw_table</varname> parameter</title>
45
+	    <programlisting>
46
+		...
47
+		modparam("lcr", "gw_table", "mygateways") 
48
+		...
49
+	    </programlisting>
50
+	</example>
51
+    </section>
52
+
53
+    <section id="gw_name_column">
54
+	<title><varname>gw_name_column</varname> (string)</title>
55
+	<para>
56
+	    The name of the column that contains the actual name of the gateway
57
+	</para>
58
+	<para>
59
+	    Default value is gw_name.
60
+	</para>
61
+	<example>
62
+	    <title>Set <varname>gw_name_column</varname> parameter</title>
63
+	    <programlisting>
64
+		...
65
+		modparam("lcr", "gw_name_column", "Agateway") 
66
+		...
67
+	    </programlisting>
68
+	</example>
69
+    </section>
70
+
71
+    <section id="ip_addr_column">
72
+	<title><varname>ip_addr_column</varname> (string)</title>
73
+	<para>
74
+	    The name of the column that contains the IP address for a specific gateway
75
+	</para>
76
+	<para>
77
+	    Default value is ip_addr.
78
+	</para>
79
+	<example>
80
+	    <title>Set <varname>ip_addr_column</varname> parameter</title>
81
+	    <programlisting>
82
+		...
83
+		modparam("lcr", "ip_addr_column", "gatewayIPs") 
84
+		...
85
+	    </programlisting>
86
+	</example>
87
+    </section>
88
+
89
+    <section id="port_column">
90
+	<title><varname>port_column</varname> (string)</title>
91
+	<para>
92
+	    The name of the column that contains the port number through which this gateway communicates
93
+	</para>
94
+	<para>
95
+	    Default value is port.
96
+	</para>
97
+	<example>
98
+	    <title>Set <varname>port_column</varname> parameter</title>
99
+	    <programlisting>
100
+		...
101
+		modparam("lcr", "port_column", "gatewayPort") 
102
+		...
103
+	    </programlisting>
104
+	</example>
105
+    </section>
106
+
107
+    <section id="uri_scheme_column ">
108
+	<title><varname>uri_scheme_column </varname> (string)</title>
109
+	<para>
110
+	    The name of the column that contains the scheme to be used when rewriting the R-URI
111
+	</para>
112
+	<para>
113
+	    Default value is uri_scheme.
114
+	</para>
115
+	<example>
116
+	    <title>Set <varname>uri_scheme_column</varname> parameter</title>
117
+	    <programlisting>
118
+		...
119
+		modparam("lcr", "uri_scheme", "myURIScheme") 
120
+		...
121
+	    </programlisting>
122
+	</example>
123
+    </section>
124
+
125
+    <section id="transport_column ">
126
+	<title><varname>transport_column</varname> (string)</title>
127
+	<para>
128
+	    The name of the column that contains the transport to be used when contacting a gateway
129
+	</para>
130
+	<para>
131
+	    Default value is transport.
132
+	</para>
133
+	<example>
134
+	    <title>Set <varname>transport_column</varname> parameter</title>
135
+	    <programlisting>
136
+		...
137
+		modparam("lcr", "transport", "mySIPXport") 
138
+		...
139
+	    </programlisting>
140
+	</example>
141
+    </section>
142
+
143
+    <section id="grp_id_column ">
144
+	<title><varname>grp_id_column</varname> (string)</title>
145
+	<para>
146
+	    The name of the column that contains the gateway group ID number
147
+	</para>
148
+	<para>
149
+	    Default value is grp_id.
150
+	</para>
151
+	<example>
152
+	    <title>Set <varname>grp_id_column</varname> parameter</title>
153
+	    <programlisting>
154
+		...
155
+		modparam("lcr", "grp_id_column", "GwyGroups") 
156
+		...
157
+	    </programlisting>
158
+	</example>
159
+    </section>
160
+
161
+    <section id="lcr_table ">
162
+	<title><varname>lcr_table</varname> (string)</title>
163
+	<para>
164
+	    The name of the column that contains the LCR table
165
+	</para>
166
+	<para>
167
+	    Default value is lcr.
168
+	</para>
169
+	<example>
170
+	    <title>Set <varname>lcr_table</varname> parameter</title>
171
+	    <programlisting>
172
+		...
173
+		modparam("lcr", "lcr_table", "lcr") 
174
+		...
175
+	    </programlisting>
176
+	</example>
177
+    </section>
178
+
179
+    <section id="prefix_column ">
180
+	<title><varname>prefix_column</varname> (string)</title>
181
+	<para>
182
+	    The name of the column that contains the prefix to be prepended to the R-URI user part.
183
+	</para>
184
+	<para>
185
+	    Default value is prefix.
186
+	</para>
187
+	<example>
188
+	    <title>Set <varname>prefix_column</varname> parameter</title>
189
+	    <programlisting>
190
+		...
191
+		modparam("lcr", "prefix_column", "prefix") 
192
+		...
193
+	    </programlisting>
194
+	</example>
195
+    </section>
196
+
197
+    <section id="from_uri_column ">
198
+	<title><varname>from_uri_column</varname> (string)</title>
199
+	<para>
200
+	    The name of the column that contains the From URI which must match in order to select this gateway.
201
+            Note that the values in this column may contain wildcard characters as mentioned earlier in this 
202
+            document.
203
+	</para>
204
+	<para>
205
+	    Default value is from_uri.
206
+	</para>
207
+	<example>
208
+	    <title>Set <varname>from_uri_column</varname> parameter</title>
209
+	    <programlisting>
210
+		...
211
+		modparam("lcr", "from_uri_column", "FromURI") 
212
+		...
213
+	    </programlisting>
214
+	</example>
215
+    </section>
216
+
217
+    <section id="priority_column ">
218
+	<title><varname>priority_column</varname> (string)</title>
219
+	<para>
220
+	    The name of the column that contains a number indicating the priority of this gateway
221
+	</para>
222
+	<para>
223
+	    Default value is priority.
224
+	</para>
225
+	<example>
226
+	    <title>Set <varname>priority_column</varname> parameter</title>
227
+	    <programlisting>
228
+		...
229
+		modparam("lcr", "priority_column", "priority") 
230
+		...
231
+	    </programlisting>
232
+	</example>
233
+    </section>
234
+
235
+</section>
0 236
new file mode 100644
... ...
@@ -0,0 +1,1113 @@
1
+/*
2
+ * Least Cost Routing module (also implements sequential forking)
3
+ *
4
+ * Copyright (C) 2005 Juha Heinanen
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License
24
+ * along with this program; if not, write to the Free Software
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ *
27
+ * History:
28
+ * -------
29
+ *  2005-02-14: Introduced lcr module (jh)
30
+ *  2005-02-20: Added sequential forking functions (jh)
31
+ *  2005-02-25: Added support for int AVP names, combined addr and port
32
+ *              AVPs (jh)
33
+ *  2005-07-23: Added support for gw URI scheme and transport (jh)
34
+ *  2005-08-20: Added support for gw prefixes (jh)
35
+ */
36
+
37
+#include <stdio.h>
38
+#include <stdlib.h>
39
+#include <string.h>
40
+#include <arpa/inet.h>
41
+#include "../../sr_module.h"
42
+#include "../../dprint.h"
43
+#include "../../ut.h"
44
+#include "../../error.h"
45
+#include "../../mem/mem.h"
46
+#include "../../mem/shm_mem.h"
47
+#include "../../lib/srdb2/db.h"
48
+#include "../../usr_avp.h"
49
+#include "../../parser/parse_uri.h"
50
+#include "../../parser/parse_from.h"
51
+#include "../../parser/msg_parser.h"
52
+#include "../../action.h"
53
+#include "../../modules/tm/tm_load.h"
54
+#include "../../qvalue.h"
55
+#include "../../dset.h"
56
+#include "../../ip_addr.h"
57
+#include "../../config.h"
58
+#include "../../route.h"
59
+#include "lcr_rpc.h"
60
+#include "lcr_mod.h"
61
+
62
+MODULE_VERSION
63
+
64
+/* usr_avp flag for sequential forking */
65
+#define DEF_Q_FLAG	"q_flag"
66
+avp_flags_t	Q_FLAG = 0;
67
+
68
+static void destroy(void);       /* Module destroy function */
69
+static int child_init(int rank); /* Per-child initialization function */
70
+static int mod_init(void);       /* Module initialization function */
71
+
72
+int reload_gws ( void );
73
+
74
+#define LCR_MAX_QUERY_SIZE 512
75
+#define MAX_PREFIX_LEN 16
76
+
77
+/* Default avp names */
78
+#define DEF_GW_URI_AVP "1400"
79
+#define DEF_CONTACT_AVP "1401"
80
+#define DEF_FR_INV_TIMER_AVP "$t.callee_fr_inv_timer"
81
+#define DEF_FR_INV_TIMER 90
82
+#define DEF_FR_INV_TIMER_NEXT 30
83
+#define DEF_RPID_AVP "rpid"
84
+
85
+/*
86
+ * Database variables
87
+ */
88
+db_ctx_t* ctx = NULL;
89
+db_cmd_t *lcr_load = NULL;
90
+db_cmd_t *lcr_reload = NULL;
91
+
92
+/* This is the stack of all used IP addresses, this stack is
93
+ * used to make sure that no IP address (gateway) gets the same
94
+ * request more than once.
95
+ */
96
+static unsigned int addrs[MAX_BRANCHES];
97
+unsigned int addrs_top = 0;
98
+
99
+/*
100
+ * Module parameter variables
101
+ */
102
+static str db_url    = STR_STATIC_INIT(DEFAULT_RODB_URL);
103
+
104
+char* gw_table         = "gw";
105
+char* gw_name_col      = "gw_name";
106
+char* ip_addr_col      = "ip_addr";
107
+char* port_col         = "port";
108
+char* uri_scheme_col   = "uri_scheme";
109
+char* transport_col    = "transport";
110
+char* grp_id_col       = "grp_id";
111
+char* lcr_table        = "lcr";
112
+char* prefix_col       = "prefix";
113
+char* from_uri_col     = "from_uri";
114
+char* priority_col     = "priority";
115
+
116
+str gw_uri_avp       = STR_STATIC_INIT(DEF_GW_URI_AVP);
117
+str contact_avp      = STR_STATIC_INIT(DEF_CONTACT_AVP);
118
+str inv_timer_avp    = STR_STATIC_INIT(DEF_FR_INV_TIMER_AVP);
119
+int inv_timer        = DEF_FR_INV_TIMER;
120
+int inv_timer_next   = DEF_FR_INV_TIMER_NEXT;
121
+str inv_timer_ps     = STR_STATIC_INIT("");
122
+str inv_timer_next_ps = STR_STATIC_INIT("");
123
+str rpid_avp         = STR_STATIC_INIT(DEF_RPID_AVP);
124
+
125
+/*
126
+ * Other module types and variables
127
+ */
128
+
129
+struct contact {
130
+    str uri;
131
+    qvalue_t q;
132
+    unsigned short q_flag;
133
+    struct contact *next;
134
+};
135
+
136
+int_str gw_uri_name, contact_name, rpid_name;
137
+unsigned short gw_uri_avp_name_str;
138
+unsigned short contact_avp_name_str;
139
+unsigned short rpid_avp_name_str;
140
+
141
+static avp_ident_t tm_timer_param;	/* TM module's invite timer avp */
142
+
143
+struct gw_info **gws;	/* Pointer to current gw table pointer */
144
+struct gw_info *gws_1;	/* Pointer to gw table 1 */
145
+struct gw_info *gws_2;	/* Pointer to gw table 2 */
146
+struct tm_binds tmb;
147
+
148
+/* AVPs overwriting the module parameters */
149
+static avp_ident_t *inv_timer_param = NULL;
150
+static avp_ident_t *inv_timer_next_param = NULL;
151
+
152
+/*
153
+ * Module functions that are defined later
154
+ */
155
+int load_gws(struct sip_msg* _m, char* _s1, char* _s2);
156
+int next_gw(struct sip_msg* _m, char* _s1, char* _s2);
157
+int from_gw(struct sip_msg* _m, char* _s1, char* _s2);
158
+int to_gw(struct sip_msg* _m, char* _s1, char* _s2);
159
+int load_contacts (struct sip_msg*, char*, char*);
160
+int next_contacts (struct sip_msg*, char*, char*);
161
+
162
+
163
+/*
164
+ * Exported functions
165
+ */
166
+static cmd_export_t cmds[] = {
167
+	{"load_gws",      load_gws,      0, 0, REQUEST_ROUTE},
168
+	{"next_gw",       next_gw,       0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
169
+	{"from_gw",       from_gw,       0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
170
+	{"to_gw",         to_gw,         0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
171
+	{"load_contacts", load_contacts, 0, 0, REQUEST_ROUTE},
172
+	{"next_contacts", next_contacts, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
173
+	{0, 0, 0, 0, 0}
174
+};
175
+
176
+
177
+/*
178
+ * Exported parameters
179
+ */
180
+static param_export_t params[] = {
181
+	{"db_url",                   PARAM_STR,  &db_url              },
182
+	{"gw_table",                 PARAM_STRING, &gw_table          },
183
+	{"gw_name_column",           PARAM_STRING, &gw_name_col       },
184
+	{"ip_addr_column",           PARAM_STRING, &ip_addr_col       },
185
+	{"port_column",              PARAM_STRING, &port_col          },
186
+	{"uri_scheme_column",        PARAM_STRING, &uri_scheme_col    },
187
+	{"transport_column",         PARAM_STRING, &transport_col     },
188
+	{"grp_id_column",            PARAM_STRING, &grp_id_col        },
189
+	{"lcr_table",                PARAM_STRING, &lcr_table         },
190
+	{"prefix_column",            PARAM_STRING, &prefix_col        },
191
+	{"from_uri_column",          PARAM_STRING, &from_uri_col      },
192
+	{"priority_column",          PARAM_STRING, &priority_col      },
193
+	{"gw_uri_avp",               PARAM_STR,    &gw_uri_avp        },
194
+	{"contact_avp",              PARAM_STR,    &contact_avp       },
195
+	{"fr_inv_timer_avp",         PARAM_STR,    &inv_timer_avp     },
196
+	{"fr_inv_timer",             PARAM_INT,    &inv_timer         },
197
+	{"fr_inv_timer_next",        PARAM_INT,    &inv_timer_next    },
198
+	{"fr_inv_timer_param",       PARAM_STR,    &inv_timer_ps      },
199
+	{"fr_inv_timer_next_param",  PARAM_STR,    &inv_timer_next_ps },
200
+	{"rpid_avp",                 PARAM_STR,    &rpid_avp          },
201
+	{0, 0, 0}
202
+};
203
+
204
+
205
+/*
206
+ * Module interface
207
+ */
208
+struct module_exports exports = {
209
+	"lcr",
210
+	cmds,      /* Exported functions */
211
+	lcr_rpc,   /* RPC methods */
212
+	params,    /* Exported parameters */
213
+	mod_init,  /* module initialization function */
214
+	0,         /* response function */
215
+	destroy,   /* destroy function */
216
+	0,         /* oncancel function */
217
+	child_init /* child initialization function */
218
+};
219
+
220
+
221
+void lcr_db_close()
222
+{
223
+	if (lcr_load) db_cmd_free(lcr_load);
224
+	lcr_load = NULL;
225
+
226
+	if (lcr_reload) db_cmd_free(lcr_reload);
227
+	lcr_reload = NULL;
228
+
229
+	if (ctx) {
230
+		db_disconnect(ctx);
231
+		db_ctx_free(ctx);
232
+		ctx = NULL;
233
+	}
234
+}
235
+
236
+
237
+int lcr_db_init(char* db_url)
238
+{
239
+	int q_len;
240
+    static char query[LCR_MAX_QUERY_SIZE];
241
+	db_fld_t reload_cols[] = {
242
+		{.name = ip_addr_col,    .type = DB_INT},
243
+		{.name = port_col,       .type = DB_INT},
244
+		{.name = uri_scheme_col, .type = DB_INT},
245
+		{.name = transport_col,  .type = DB_INT},
246
+		{.name = prefix_col,     .type = DB_STR},
247
+		{.name = 0}
248
+	};
249
+
250
+	db_fld_t load_cols[] = {
251
+		{.name = "gw.ip_addr",    .type = DB_INT},
252
+		{.name = "gw.port",       .type = DB_INT},
253
+		{.name = "gw.uri_scheme", .type = DB_INT},
254
+		{.name = "gw.transport",  .type = DB_INT},
255
+		{.name = "gw.prefix",     .type = DB_STR},
256
+		{.name = 0}
257
+	};
258
+
259
+	db_fld_t load_match[] = {
260
+		{.name = "lcr.from_uri",      .type = DB_STR},
261
+		{.name = "lcr.ruri_username", .type = DB_STR},
262
+		{.name = 0}
263
+	};
264
+	  
265
+	ctx = db_ctx("lcr");
266
+	if (!ctx) goto err;
267
+	if (db_add_db(ctx, db_url) < 0) goto err;
268
+	if (db_connect(ctx) < 0) goto err;
269
+
270
+    q_len = snprintf(query, LCR_MAX_QUERY_SIZE, 
271
+					 "SELECT %s.%s, %s.%s, %s.%s, %s.%s, %s.%s from %s, %s "
272
+					 "WHERE ? LIKE %s.%s AND ? LIKE CONCAT(%s.%s, '%%') "
273
+					 "AND %s.%s = %s.%s ORDER BY CHAR_LENGTH(%s.%s) DESC, "
274
+					 "%s.%s, RAND()",
275
+					 gw_table, ip_addr_col, gw_table, port_col, 
276
+					 gw_table, uri_scheme_col, gw_table, transport_col, 
277
+					 gw_table, prefix_col, gw_table, lcr_table,
278
+					 lcr_table, from_uri_col, lcr_table, prefix_col,
279
+					 lcr_table, grp_id_col, gw_table, grp_id_col,
280
+					 lcr_table, prefix_col, lcr_table, priority_col);
281
+    if (q_len < 0 || q_len >= LCR_MAX_QUERY_SIZE) {
282
+		ERR("lcr: Database query too long\n");
283
+		return -1;
284
+    }
285
+	
286
+	lcr_load = db_cmd(DB_SQL, ctx, query, load_cols, load_match, NULL);
287
+	if (!lcr_load) goto err;
288
+
289
+	lcr_reload = db_cmd(DB_GET, ctx, gw_table, reload_cols, NULL, NULL);
290
+	if (!lcr_reload) goto err;
291
+    return 0;
292
+
293
+err:
294
+	lcr_db_close();
295
+	ERR("lcr: Error while initializing database layer\n");
296
+	return -1;
297
+}
298
+
299
+
300
+/*
301
+ * Module initialization function callee in each child separately
302
+ */
303
+static int child_init(int rank)
304
+{
305
+	if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
306
+		return 0; /* do nothing for the main or tcp_main processes */
307
+	if (lcr_db_init(db_url.s) < 0) {
308
+		ERR("lcr: Unable to initialize database layer\n");
309
+		return -1;
310
+	}
311
+
312
+	return 0;
313
+}
314
+
315
+/* get AVP module parameter */
316
+static int get_avp_modparam(str *s, avp_ident_t *avp)
317
+{
318
+	if (!s->s || (s->len < 2)) return -1;
319
+
320
+	if (s->s[0] != '$') {
321
+		ERR("lcr: get_avp_modparam(): "
322
+			"unknown AVP identifier: %.*s\n", s->len, s->s);
323
+		return -1;
324
+	}
325
+	s->s++;
326
+	s->len--;
327
+	if (parse_avp_ident(s, avp)) {
328
+		ERR("lcr: get_avp_modparam(): "
329
+			"cannot parse AVP identifier: %.*s\n", s->len, s->s);
330
+		return -1;
331
+	}
332
+	return 0;
333
+}
334
+
335
+/*
336
+ * Module initialization function that is called before the main process forks
337
+ */
338
+static int mod_init(void)
339
+{
340
+	load_tm_f  load_tm;
341
+	int i;
342
+	unsigned int par;
343
+
344
+	DBG("lcr - initializing\n");
345
+
346
+	Q_FLAG = register_avpflag(DEF_Q_FLAG);
347
+	if (Q_FLAG == 0) {
348
+		ERR("lcr: Cannot regirser AVP flag: %s\n", DEF_Q_FLAG);
349
+		return -1;
350
+	}
351
+
352
+	/* import the TM auto-loading function */
353
+	if (!(load_tm = (load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) {
354
+	    ERR("lcr: cannot import load_tm\n");
355
+		goto err;
356
+	}
357
+	/* let the auto-loading function load all TM stuff */
358
+	if (load_tm(&tmb) == -1) goto err;
359
+
360
+	/* Initializing gw tables and gw table pointer variable */
361
+	gws_1 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) * (MAX_NO_OF_GWS + 1));
362
+	if (gws_1 == 0) {
363
+	    ERR("lcr: mod_init(): No memory for gw table\n");
364
+	    goto err;
365
+	}
366
+	gws_2 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) * (MAX_NO_OF_GWS + 1));
367
+	if (gws_2 == 0) {
368
+	    ERR("lcr: mod_init(): No memory for gw table\n");
369
+	    goto err;
370
+	}
371
+	for (i = 0; i < MAX_NO_OF_GWS + 1; i++) {
372
+		gws_1[i].ip_addr = gws_2[i].ip_addr = 0;
373
+	}
374
+	gws = (struct gw_info **)shm_malloc(sizeof(struct gw_info *));
375
+	*gws = gws_1;
376
+
377
+	if (lcr_db_init(db_url.s) < 0) {
378
+		ERR("lcr: Unable to initialize database layer\n");
379
+		return -1;
380
+	}
381
+
382
+	/* First reload */
383
+	if (reload_gws() == -1) {
384
+		LOG(L_CRIT, "lcr: failed to reload gateways\n");
385
+		goto err;
386
+	}
387
+
388
+	lcr_db_close();
389
+
390
+	/* Assign parameter names */
391
+	if (str2int(&gw_uri_avp, &par) == 0) {
392
+	    gw_uri_name.n = par;
393
+	    gw_uri_avp_name_str = 0;
394
+	} else {
395
+	    gw_uri_name.s = gw_uri_avp;
396
+	    gw_uri_avp_name_str = AVP_NAME_STR;
397
+	}
398
+	if (str2int(&contact_avp, &par) == 0) {
399
+	    contact_name.n = par;
400
+	    contact_avp_name_str = 0;
401
+	} else {
402
+	    contact_name.s = contact_avp;
403
+	    contact_avp_name_str = AVP_NAME_STR;
404
+	}
405
+	if (str2int(&rpid_avp, &par) == 0) {
406
+	    rpid_name.n = par;
407
+	    rpid_avp_name_str = 0;
408
+	} else {
409
+	    rpid_name.s = rpid_avp;
410
+	    rpid_avp_name_str = AVP_NAME_STR;
411
+	}
412
+
413
+	if (get_avp_modparam(&inv_timer_avp, &tm_timer_param))
414
+		goto err;
415
+
416
+	if (inv_timer_ps.len) {
417
+		inv_timer_param = (avp_ident_t*)pkg_malloc(sizeof(avp_ident_t));
418
+		if (!inv_timer_param) {
419
+			ERR("lcr: Not enough memory\n");
420
+			return -1;
421
+		}
422
+		if (get_avp_modparam(&inv_timer_ps, inv_timer_param)) 
423
+			goto err;
424
+	}
425
+	
426
+	if (inv_timer_next_ps.len) {
427
+		inv_timer_next_param = (avp_ident_t*)pkg_malloc(sizeof(avp_ident_t));
428
+		if (!inv_timer_next_param) {
429
+			ERR("lcr: Not enough memory\n");
430
+			return -1;
431
+		}
432
+		if (get_avp_modparam(&inv_timer_next_ps, inv_timer_next_param)) 
433
+			goto err;
434
+	}
435
+	
436
+	return 0;
437
+	
438
+ err:
439
+	return -1;
440
+}
441
+
442
+
443
+static void destroy(void)
444
+{
445
+	lcr_db_close();
446
+	
447
+	if (inv_timer_param) pkg_free(inv_timer_param);
448
+	if (inv_timer_next_param) pkg_free(inv_timer_next_param);
449
+}
450
+
451
+
452
+/*
453
+ * Reload gws to unused gw table and when done, make the unused gw table
454
+ * the one in use.
455
+ */
456
+int reload_gws ( void )
457
+{
458
+    int i;
459
+    unsigned int ip_addr, port, prefix_len;
460
+    uri_type scheme;
461
+    uri_transport transport;
462
+    char* prefix;
463
+    db_res_t* res;
464
+    db_rec_t* rec;
465
+	
466
+	res = NULL;
467
+	if (db_exec(&res, lcr_reload) < 0) {
468
+		ERR("lcr: Failed to query gw data\n");
469
+		goto error;
470
+	}
471
+	if (res == NULL) {
472
+		ERR("lcr: Gw table query returned no data\n");
473
+		goto error;
474
+	}
475
+
476
+	for(rec = db_first(res), i = 0; rec; rec = db_next(res), i++) {
477
+		if (i >= MAX_NO_OF_GWS) {
478
+			ERR("lcr: Too many gw entries\n");
479
+			goto error;
480
+		}
481
+
482
+		if (rec->fld[0].flags & DB_NULL) {
483
+			ERR("lcr: IP address of GW is NULL\n");
484
+			goto error;
485
+		}
486
+		ip_addr = (unsigned int)rec->fld[0].v.int4;
487
+
488
+		if (rec->fld[1].flags & DB_NULL) port = 0;
489
+		else port = (unsigned int)rec->fld[1].v.int4;
490
+
491
+		if (port > 65535) {
492
+			ERR("lcr: Port of GW is too large: %u\n", port);
493
+			goto error;
494
+		}
495
+
496
+		if (rec->fld[2].flags & DB_NULL) scheme = SIP_URI_T;
497
+		else {
498
+			scheme = (uri_type)rec->fld[2].v.int4;
499
+			if ((scheme != SIP_URI_T) && (scheme != SIPS_URI_T)) {
500
+				ERR("lcr: Unknown or unsupported URI scheme: %u\n", (unsigned int)scheme);
501
+				goto error;
502
+			}
503
+		}
504
+
505
+		if (rec->fld[3].flags & DB_NULL) transport = PROTO_NONE;
506
+		else {
507
+			transport = (uri_transport)rec->fld[3].v.int4;
508
+			if ((transport != PROTO_UDP) && (transport != PROTO_TCP) &&
509
+				(transport != PROTO_TLS) && (transport != PROTO_SCTP)) {
510
+				ERR("lcr: Unknown or unsupported transport: %u\n", (unsigned int)transport);
511
+				goto error;
512
+			}
513
+		}
514
+
515
+		if (rec->fld[4].flags & DB_NULL) {
516
+			prefix_len = 0;
517
+			prefix = NULL;
518
+		} else {
519
+			prefix = rec->fld[4].v.lstr.s;
520
+			prefix_len = rec->fld[4].v.lstr.len;
521
+			if (prefix_len > MAX_PREFIX_LEN) {
522
+				ERR("lcr: Too long prefix\n");
523
+				goto error;
524
+			}
525
+		}
526
+
527
+		if (*gws == gws_1) {
528
+			gws_2[i].ip_addr = ip_addr;
529
+			gws_2[i].port = port;
530
+			gws_2[i].scheme = scheme;
531
+			gws_2[i].transport = transport;
532
+			gws_2[i].prefix_len = prefix_len;
533
+			if (prefix_len)
534
+				memcpy(&(gws_2[i].prefix[0]), prefix, prefix_len);
535
+		} else {
536
+			gws_1[i].ip_addr = ip_addr;
537
+			gws_1[i].port = port;
538
+			gws_1[i].scheme = scheme;
539
+			gws_1[i].transport = transport;
540
+			gws_1[i].prefix_len = prefix_len;
541
+			if (prefix_len)
542
+				memcpy(&(gws_1[i].prefix[0]), prefix, prefix_len);
543
+		}
544
+	}
545
+
546
+	db_res_free(res);
547
+
548
+    if (*gws == gws_1) {
549
+	    gws_2[i].ip_addr = 0;
550
+	    *gws = gws_2;
551
+    } else {
552
+	    gws_1[i].ip_addr = 0;
553
+	    *gws = gws_1;
554
+    }
555
+    return 1;
556
+
557
+	error:
558
+	if (res) db_res_free(res);
559
+	return -1;
560
+}
561
+
562
+/*
563
+ * Load GW info from database to lcr_gw_addr_port AVPs
564
+ */
565
+int load_gws(struct sip_msg* _m, char* _s1, char* _s2)
566
+{
567
+    db_res_t* res = NULL;
568
+    db_rec_t *rec;
569
+    str ruri_user, from_uri, value, addr_str, port_str;
570
+    static char ruri[MAX_URI_SIZE];
571
+    unsigned int i, j, prefix_len, addr, port;
572
+    uri_type scheme;
573
+    uri_transport transport;
574
+    struct ip_addr address;
575
+    char *at, *prefix;
576
+    int_str val;
577
+
578
+    /* Find Request-URI user */
579
+    if (parse_sip_msg_uri(_m) < 0) {
580
+	    ERR("lcr: Error while parsing R-URI\n");
581
+	    return -1;
582
+    }
583
+    ruri_user = _m->parsed_uri.user;
584
+	
585
+	/* Look for Caller RPID or From URI */
586
+    if (search_first_avp(rpid_avp_name_str, rpid_name, &val, 0) &&
587
+		val.s.s && val.s.len) {
588
+		/* Get URI user from RPID */
589
+		from_uri.len = val.s.len;
590
+		from_uri.s = val.s.s;
591
+    } else {
592
+		/* Get URI from From URI */
593
+		if ((!_m->from) && (parse_headers(_m, HDR_FROM_F, 0) == -1)) {
594
+			ERR("lcr: Error while parsing message\n");
595
+			return -1;
596
+		}
597
+		if (!_m->from) {
598
+			ERR("lcr: FROM header field not found\n");
599
+			return -1;
600
+		}
601
+		if ((!(_m->from)->parsed) && (parse_from_header(_m) < 0)) {
602
+			ERR("lcr: Error while parsing From body\n");
603
+			return -1;
604
+		}
605
+		from_uri = get_from(_m)->uri;
606
+    }
607
+	
608
+	lcr_load->match[0].v.lstr = from_uri;
609
+	lcr_load->match[1].v.lstr = ruri_user;
610
+
611
+    if (db_exec(&res, lcr_load) < 0) {
612
+		ERR("lcr: Failed to query accept data\n");
613
+		return -1;
614
+    }
615
+	if (res == NULL) {
616
+		ERR("lcr: Database query did not return any result\n");
617
+		return -1;
618
+	}
619
+
620
+	addrs_top = 0;
621
+	for(i = 0, rec = db_first(res); rec; rec = db_next(res), i++) {
622
+		if (rec->fld[0].flags & DB_NULL) {
623
+			ERR("lcr: Gateway IP address is NULL\n");
624
+			continue;
625
+		}
626
+      	addr = (unsigned int)rec->fld[0].v.int4;
627
+
628
+		if (addrs_top >= MAX_BRANCHES) {
629
+			INFO("lcr: Too many destinations\n");
630
+			goto end;
631
+		}
632
+		for(j = 0; j < addrs_top; j++) {
633
+			if (addrs[j] == addr) goto skip;
634
+		}
635
+		addrs[addrs_top++] = addr;
636
+
637
+		if (rec->fld[1].flags & DB_NULL) port = 0;
638
+		else port = (unsigned int)rec->fld[1].v.int4;
639
+
640
+		if (rec->fld[2].flags & DB_NULL) scheme = SIP_URI_T;
641
+		else scheme = (uri_type)rec->fld[2].v.int4;
642
+
643
+		if (rec->fld[3].flags & DB_NULL) transport = PROTO_NONE;
644
+		else transport = (uri_transport)rec->fld[3].v.int4;
645
+
646
+		if (rec->fld[4].flags & DB_NULL) {
647
+			prefix = NULL;
648
+			prefix_len = 0;
649
+		} else {
650
+			prefix = rec->fld[4].v.lstr.s;
651
+			prefix_len = rec->fld[4].v.lstr.len;
652
+		}
653
+
654
+		if (5 + prefix_len + ruri_user.len + 1 + 15 + 1 + 5 + 1 + 14 > MAX_URI_SIZE) {
655
+			ERR("lcr: Request URI would be too long\n");
656
+			continue;
657
+		}
658
+
659
+		at = (char *)&(ruri[0]);
660
+		if (scheme == SIP_URI_T) {
661
+			memcpy(at, "sip:", 4); at = at + 4;
662
+		} else if (scheme == SIPS_URI_T) {
663
+			memcpy(at, "sips:", 5); at = at + 5;
664
+		} else {
665
+			ERR("lcr: Unknown or unsupported URI scheme: %u\n", (unsigned int)scheme);
666
+			continue;
667
+		}
668
+
669
+		if (prefix_len) {
670
+			memcpy(at, prefix, prefix_len); at = at + prefix_len;
671
+		}
672
+		memcpy(at, ruri_user.s, ruri_user.len); at = at + ruri_user.len;
673
+		*at = '@'; at = at + 1;
674
+		address.af = AF_INET;
675
+		address.len = 4;
676
+		address.u.addr32[0] = addr;
677
+		addr_str.s = ip_addr2a(&address);
678
+		addr_str.len = strlen(addr_str.s);
679
+		memcpy(at, addr_str.s, addr_str.len); at = at + addr_str.len;
680
+		if (port != 0) {
681
+			if (port > 65535) {
682
+				ERR("lcr: Port of GW is too large: %u\n", port);
683
+				continue;
684
+			}
685
+			*at = ':'; at = at + 1;
686
+			port_str.s = int2str(port, &port_str.len);
687
+			memcpy(at, port_str.s, port_str.len); at = at + port_str.len;
688
+		}
689
+		if (transport != PROTO_NONE) {
690
+			memcpy(at, ";transport=", 11); at = at + 11;
691
+			if (transport == PROTO_UDP) {
692
+				memcpy(at, "udp", 3); at = at + 3;
693
+			} else if (transport == PROTO_TCP) {
694
+				memcpy(at, "tcp", 3); at = at + 3;
695
+			} else if (transport == PROTO_TLS) {
696
+				memcpy(at, "tls", 3); at = at + 3;
697
+			} else if (transport == PROTO_SCTP) {
698