This reverts commit a3f16850cd2a897710cb0a56174e9f64dcc77653.
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 | 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 |