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