... | ... |
@@ -1,3 +1,4 @@ |
1 |
+ |
|
1 | 2 |
------------------------------------------------------------------------- |
2 | 3 |
IMPORTANT NOTES |
3 | 4 |
|
... | ... |
@@ -19,7 +20,7 @@ IMPORTANT NOTES |
19 | 20 |
for a detailed explanation) |
20 | 21 |
|
21 | 22 |
3) Note that the GPL bellow is copyrighted by the Free Software Foundation, |
22 |
- but the ser software is copyrighted by iptel.org. |
|
23 |
+ but the ser software is copyrighted by FhG |
|
23 | 24 |
|
24 | 25 |
|
25 | 26 |
------------------------------------------------------------------------- |
... | ... |
@@ -81,7 +82,7 @@ patent must be licensed for everyone's free use or not licensed at all. |
81 | 82 |
|
82 | 83 |
The precise terms and conditions for copying, distribution and |
83 | 84 |
modification follow. |
84 |
- |
|
85 |
+ |
|
85 | 86 |
GNU GENERAL PUBLIC LICENSE |
86 | 87 |
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
87 | 88 |
|
... | ... |
@@ -136,7 +137,7 @@ above, provided that you also meet all of these conditions: |
136 | 137 |
License. (Exception: if the Program itself is interactive but |
137 | 138 |
does not normally print such an announcement, your work based on |
138 | 139 |
the Program is not required to print an announcement.) |
139 |
- |
|
140 |
+ |
|
140 | 141 |
These requirements apply to the modified work as a whole. If |
141 | 142 |
identifiable sections of that work are not derived from the Program, |
142 | 143 |
and can be reasonably considered independent and separate works in |
... | ... |
@@ -194,7 +195,7 @@ access to copy from a designated place, then offering equivalent |
194 | 195 |
access to copy the source code from the same place counts as |
195 | 196 |
distribution of the source code, even though third parties are not |
196 | 197 |
compelled to copy the source along with the object code. |
197 |
- |
|
198 |
+ |
|
198 | 199 |
4. You may not copy, modify, sublicense, or distribute the Program |
199 | 200 |
except as expressly provided under this License. Any attempt |
200 | 201 |
otherwise to copy, modify, sublicense or distribute the Program is |
... | ... |
@@ -251,7 +252,7 @@ impose that choice. |
251 | 252 |
|
252 | 253 |
This section is intended to make thoroughly clear what is believed to |
253 | 254 |
be a consequence of the rest of this License. |
254 |
- |
|
255 |
+ |
|
255 | 256 |
8. If the distribution and/or use of the Program is restricted in |
256 | 257 |
certain countries either by patents or by copyrighted interfaces, the |
257 | 258 |
original copyright holder who places the Program under this License |
... | ... |
@@ -304,63 +305,3 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
304 | 305 |
POSSIBILITY OF SUCH DAMAGES. |
305 | 306 |
|
306 | 307 |
END OF TERMS AND CONDITIONS |
307 |
- |
|
308 |
- How to Apply These Terms to Your New Programs |
|
309 |
- |
|
310 |
- If you develop a new program, and you want it to be of the greatest |
|
311 |
-possible use to the public, the best way to achieve this is to make it |
|
312 |
-free software which everyone can redistribute and change under these terms. |
|
313 |
- |
|
314 |
- To do so, attach the following notices to the program. It is safest |
|
315 |
-to attach them to the start of each source file to most effectively |
|
316 |
-convey the exclusion of warranty; and each file should have at least |
|
317 |
-the "copyright" line and a pointer to where the full notice is found. |
|
318 |
- |
|
319 |
- <one line to give the program's name and a brief idea of what it does.> |
|
320 |
- Copyright (C) <year> <name of author> |
|
321 |
- |
|
322 |
- This program is free software; you can redistribute it and/or modify |
|
323 |
- it under the terms of the GNU General Public License as published by |
|
324 |
- the Free Software Foundation; either version 2 of the License, or |
|
325 |
- (at your option) any later version. |
|
326 |
- |
|
327 |
- This program is distributed in the hope that it will be useful, |
|
328 |
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
329 |
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
330 |
- GNU General Public License for more details. |
|
331 |
- |
|
332 |
- You should have received a copy of the GNU General Public License |
|
333 |
- along with this program; if not, write to the Free Software |
|
334 |
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
335 |
- |
|
336 |
- |
|
337 |
-Also add information on how to contact you by electronic and paper mail. |
|
338 |
- |
|
339 |
-If the program is interactive, make it output a short notice like this |
|
340 |
-when it starts in an interactive mode: |
|
341 |
- |
|
342 |
- Gnomovision version 69, Copyright (C) year name of author |
|
343 |
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
|
344 |
- This is free software, and you are welcome to redistribute it |
|
345 |
- under certain conditions; type `show c' for details. |
|
346 |
- |
|
347 |
-The hypothetical commands `show w' and `show c' should show the appropriate |
|
348 |
-parts of the General Public License. Of course, the commands you use may |
|
349 |
-be called something other than `show w' and `show c'; they could even be |
|
350 |
-mouse-clicks or menu items--whatever suits your program. |
|
351 |
- |
|
352 |
-You should also get your employer (if you work as a programmer) or your |
|
353 |
-school, if any, to sign a "copyright disclaimer" for the program, if |
|
354 |
-necessary. Here is a sample; alter the names: |
|
355 |
- |
|
356 |
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program |
|
357 |
- `Gnomovision' (which makes passes at compilers) written by James Hacker. |
|
358 |
- |
|
359 |
- <signature of Ty Coon>, 1 April 1989 |
|
360 |
- Ty Coon, President of Vice |
|
361 |
- |
|
362 |
-This General Public License does not permit incorporating your program into |
|
363 |
-proprietary programs. If your program is a subroutine library, you may |
|
364 |
-consider it more useful to permit linking proprietary applications with the |
|
365 |
-library. If this is what you want to do, use the GNU Library General |
|
366 |
-Public License instead of this License. |
... | ... |
@@ -7,6 +7,14 @@ |
7 | 7 |
<!ENTITY redirectexample SYSTEM "../../examples/redirect.cfg"> |
8 | 8 |
<!ENTITY replyexample SYSTEM "../../examples/onr.cfg"> |
9 | 9 |
<!ENTITY statefuluaexample SYSTEM "../../examples/uas.cfg"> |
10 |
+<!ENTITY gpllicense SYSTEM "../../COPYING"> |
|
11 |
+<!ENTITY sendim SYSTEM "../../examples/web_im/send_im.php"> |
|
12 |
+<!ENTITY gatewayacl SYSTEM "../../examples/pstn.cfg"> |
|
13 |
+<!ENTITY accountingexample SYSTEM "../../examples/acc.cfg"> |
|
14 |
+<!ENTITY replicateexample SYSTEM "../../examples/replicate.cfg"> |
|
15 |
+<!ENTITY defscr SYSTEM "../../etc/ser.cfg"> |
|
16 |
+ |
|
17 |
+ |
|
10 | 18 |
|
11 | 19 |
]> |
12 | 20 |
|
... | ... |
@@ -15,8 +23,8 @@ |
15 | 23 |
|
16 | 24 |
<?dbhtml filename="index.html"> |
17 | 25 |
|
18 |
- |
|
19 |
- <title>iptel.org SIP Express Router v0.8.8 -- User's Guide</title> |
|
26 |
+ |
|
27 |
+ <title>iptel.org SIP Express Router v0.8.10 -- Admin's Guide</title> |
|
20 | 28 |
<bookinfo> |
21 | 29 |
<authorgroup> |
22 | 30 |
<author> |
... | ... |
@@ -79,12 +87,13 @@ |
79 | 87 |
</para> |
80 | 88 |
</abstract> |
81 | 89 |
<releaseinfo> |
82 |
- This is a pre-release documentation of the SER SIP Server. |
|
83 |
- For the latest and most complete documentation, visit our |
|
84 |
- site at <ulink url="http://www.iptel.org/ser/">http://www.iptel.org/ser</ulink> |
|
90 |
+ This documentation is continuously updated. For the latest and most complete |
|
91 |
+ version, visit our site at |
|
92 |
+ <ulink url="http://www.iptel.org/ser/">http://www.iptel.org/ser</ulink>. |
|
93 |
+ Version of this document is $Id$. |
|
85 | 94 |
</releaseinfo> |
86 | 95 |
</bookinfo> |
87 |
- |
|
96 |
+ |
|
88 | 97 |
<toc></toc> |
89 | 98 |
|
90 | 99 |
<chapter id="general"> |
... | ... |
@@ -93,7 +102,7 @@ |
93 | 102 |
<title>About <acronym>SIP</acronym> Express Router (<acronym>SER</acronym>)</title> |
94 | 103 |
<para> |
95 | 104 |
SIP Express Router (<acronym>SER</acronym>) is an industrial-strength, free VoIP |
96 |
- server based on the session initiation protocol (<acronym>SIP</acronym> RFC3261). |
|
105 |
+ server based on the Session Initiation Protocol (<acronym>SIP</acronym>, RFC3261). |
|
97 | 106 |
It is engineered to power <acronym>IP</acronym> telephony infrastructures up to large |
98 | 107 |
scale. The server keeps track of users, sets up VoIP sessions, |
99 | 108 |
relays instant messages and creates space for new plug-in applications. |
... | ... |
@@ -113,12 +122,12 @@ |
113 | 122 |
</para> |
114 | 123 |
<para> |
115 | 124 |
Its performance and robustness allows it to serve millions of users |
116 |
- and accommodate needs of very large operators. With a $3000 dual-CPU, the |
|
125 |
+ and accommodate needs of very large operators. With a $3000 dual-CPU PC, the |
|
117 | 126 |
<acronym>SIP</acronym> Express Router is able to power <acronym>IP</acronym> telephony services in an area |
118 | 127 |
as large as the Bay Area during peak hours. Even on an IPAQ <acronym>PDA</acronym>, the server |
119 | 128 |
withstands 150 calls per second (<acronym>CPS</acronym>)! The server has been powering our |
120 | 129 |
iptel.org free <acronym>SIP</acronym> site withstanding heavy daily load that is further |
121 |
- increasing with the popularity of Microsoft's Messenger. |
|
130 |
+ increasing with the popularity of Microsoft's Windows Messenger. |
|
122 | 131 |
</para> |
123 | 132 |
<para> |
124 | 133 |
The <acronym>SIP</acronym> Express Router is extremely configurable to allow the creation of |
... | ... |
@@ -131,12 +140,11 @@ |
131 | 140 |
<application moreinfo="none">ser</application> can be also |
132 | 141 |
used with contributed applications. Currently, |
133 | 142 |
<application moreinfo="none">serweb</application>, a |
134 |
- <application moreinfo="none">ser</application> web interface |
|
143 |
+ <application moreinfo="none">ser</application> web interface, |
|
135 | 144 |
and <application moreinfo="none">SIPSak</application> |
136 |
- diagnostic tools are available. Visit our site, |
|
137 |
- <ulink url="http://www.iptel.org/">http://www.iptel.org/</ulink> |
|
138 |
- , for more information on |
|
139 |
- contributed packages. |
|
145 |
+ diagnostic tool are available. Visit our site, |
|
146 |
+ <ulink url="http://www.iptel.org/">http://www.iptel.org/</ulink>, |
|
147 |
+ for more information on contributed packages. |
|
140 | 148 |
</para> |
141 | 149 |
</section> |
142 | 150 |
|
... | ... |
@@ -154,6 +162,13 @@ |
154 | 162 |
technological information, is a best proof of interest. Thousands |
155 | 163 |
of hits come every day from the whole Internet. |
156 | 164 |
</para> |
165 |
+ <para> |
|
166 |
+ The iptel.org site, powered by SER, offers SIP services on the public |
|
167 |
+ Internet. Feel free to apply for a free SIP account at |
|
168 |
+ <ulink url="http://www.iptel.org/user/">http://www.iptel.org/user/ |
|
169 |
+ </ulink> |
|
170 |
+ </para> |
|
171 |
+ |
|
157 | 172 |
|
158 | 173 |
</section> <!-- iptel --> |
159 | 174 |
<section id="serfeatures"> |
... | ... |
@@ -161,34 +176,44 @@ |
161 | 176 |
<para> |
162 | 177 |
Based on the latest standards, the <acronym>SIP</acronym> Express Router (<acronym>SER</acronym>) includes |
163 | 178 |
support for registrar, proxy and redirect mode. Further it acts as |
164 |
- an application server with support for <acronym>CPL</acronym>, instant messaging and |
|
165 |
- presence including a <acronym>2G/SMS</acronym> gateway, a call control policy |
|
179 |
+ an application server with support for instant messaging and |
|
180 |
+ presence including a <acronym>2G/SMS</acronym> and Jabber gateway, a call control policy |
|
166 | 181 |
language, call number translation, private dial plans and accounting, |
167 |
- authorization and authentication (<acronym>AAA</acronym>) services. <acronym>SER</acronym> runs on Sun/Solaris, |
|
168 |
- PC/Linux, IPAQ/Linux platforms and supports both <acronym>IPv4</acronym> and <acronym>IPv6</acronym>. |
|
182 |
+ authorization and authentication (<acronym>AAA</acronym>) services. <application>SER</application> runs on Sun/Solaris, |
|
183 |
+ PC/Linux, PC/BSD, IPAQ/Linux platforms and supports both <acronym>IPv4</acronym> and <acronym>IPv6</acronym>. |
|
169 | 184 |
Hosting multiple domains and database redundancy is supported. |
170 | 185 |
</para> |
171 | 186 |
<para> |
172 | 187 |
Other extensions are underway: presence server, firewall control and more. |
173 | 188 |
</para> |
174 | 189 |
<para> |
175 |
- ser has been carefully engineered with the following design objectives in mind: |
|
190 |
+ <application>ser</application> has been carefully engineered with the following |
|
191 |
+ design objectives in mind: |
|
176 | 192 |
<itemizedlist> |
177 | 193 |
<listitem> |
178 | 194 |
<para> |
179 |
- <emphasis>Speed</emphasis> - With SER, thousands of calls per seconds are achievable |
|
195 |
+ <emphasis>Speed</emphasis> - With <application>ser</application>, |
|
196 |
+ thousands of calls per seconds are achievable |
|
180 | 197 |
even on low-cost platforms. This competitive capacity allows |
181 | 198 |
setting up networks which are inexpensive and easy to manage |
182 |
- due to low number of devices required. The speed has been |
|
183 |
- achieved by extensive code optimization, usage of customized code, |
|
199 |
+ due to low number of devices required. The processing capacity |
|
200 |
+ makes dealing with many stress factors easier. The stress |
|
201 |
+ factors may include but are not limited to broken configurations and implementations, |
|
202 |
+ boot avalanches on power-up, high-traffic applications such as presence, |
|
203 |
+ redundancy replications and denial-of-service attacks. |
|
204 |
+ </para> |
|
205 |
+ <para> The speed has been achieved by extensive code optimization, use of customized code, |
|
184 | 206 |
<acronym>ANSI C</acronym> combined with assembly instructions and leveraging latest |
185 |
- <acronym>SIP</acronym> improvements. When powered by a dual-CPU Linux PC, <application>ser</application> is able |
|
186 |
-to serve call signaling Bay Area population. |
|
207 |
+ <acronym>SIP</acronym> improvements. When powered by a dual-CPU Linux PC, |
|
208 |
+ <application>ser</application> is able to process thousands of calls per second, |
|
209 |
+ capacity needed to serve call signaling demands of Bay Area population. |
|
210 |
+ |
|
187 | 211 |
</para> |
188 | 212 |
</listitem> |
189 | 213 |
<listitem> |
190 | 214 |
<para> |
191 |
- <emphasis>Flexibility</emphasis> - <acronym>SER</acronym> allows its users to define its behavior. |
|
215 |
+ <emphasis>Flexibility</emphasis> - <application>SER</application> allows its users |
|
216 |
+ to define its behavior. |
|
192 | 217 |
Administrators may write textual scripts which determine <acronym>SIP</acronym> routing |
193 | 218 |
decisions, the main job of a proxy server. They may use the script to |
194 | 219 |
configure numerous parameters and introduce additional logic. For example, |
... | ... |
@@ -200,12 +225,12 @@ to serve call signaling Bay Area population. |
200 | 225 |
</listitem> |
201 | 226 |
<listitem> |
202 | 227 |
<para> |
203 |
- <acronym>Extensibility</acronym> - <acronym>SER</acronym>'s extensibility allows linking of |
|
228 |
+ <emphasis>Extensibility</emphasis> - <application>SER</application>'s extensibility allows linking of |
|
204 | 229 |
new C code to ser to |
205 | 230 |
redefine or extend its logic. The new code can be developed independently |
206 |
- on <acronym>SER</acronym> core and linked to it in run-time. The concept is similar to |
|
231 |
+ on <application>SER</application> core and linked to it in run-time. The concept is similar to |
|
207 | 232 |
the module concept known for example in Apache Web server. Even such essential parts such |
208 |
- as transaction management have been developed as modules to keep the <acronym>SER</acronym> core |
|
233 |
+ as transaction management have been developed as modules to keep the <application>SER</application> core |
|
209 | 234 |
compact and fast. |
210 | 235 |
</para> |
211 | 236 |
</listitem> |
... | ... |
@@ -214,8 +239,8 @@ to serve call signaling Bay Area population. |
214 | 239 |
<emphasis> |
215 | 240 |
Portability. |
216 | 241 |
</emphasis> |
217 |
- Ser has been written in ANSI C. It has been extensively tested on PC/Linux and |
|
218 |
- Sun/Solaris. |
|
242 |
+ <application>ser</application> has been written in ANSI C. It has been extensively tested |
|
243 |
+ on PC/Linux and Sun/Solaris. Ports to BSD and IPAQ/Linux exist. |
|
219 | 244 |
</para> |
220 | 245 |
</listitem> |
221 | 246 |
<listitem> |
... | ... |
@@ -223,11 +248,19 @@ to serve call signaling Bay Area population. |
223 | 248 |
<emphasis> |
224 | 249 |
Interoperability. |
225 | 250 |
</emphasis> |
226 |
- Ser is based on open SIP standard. It has undergone extensive testing with |
|
227 |
- products of other vendors. It powers the public iptel.org site 24 hours a day, 356 days a year |
|
251 |
+ <application>ser</application> is based on the open <acronym>SIP</acronym> standard. |
|
252 |
+ It has undergone extensive tests with products of other vendors both in iptel.org |
|
253 |
+ labs and in the SIP Interoperability Tests (SIPIT). <application>ser</application> |
|
254 |
+ powers the public iptel.org site 24 hours a day, 356 days a year |
|
228 | 255 |
serving numerous SIP implementations using this site. |
229 | 256 |
</para> |
230 | 257 |
</listitem> |
258 |
+ <listitem> |
|
259 |
+ <para> |
|
260 |
+ <emphasis>Small size.</emphasis> |
|
261 |
+ Footprint of the core is 300k, add-on modules take up to 630k. |
|
262 |
+ </para> |
|
263 |
+ </listitem> |
|
231 | 264 |
</itemizedlist> |
232 | 265 |
</para> |
233 | 266 |
</section> <!-- serfeatures --> |
... | ... |
@@ -254,9 +287,9 @@ to serve call signaling Bay Area population. |
254 | 287 |
SIP Express Router has been engineered to power large scale networks: its capacity can deal |
255 | 288 |
with large number of customers under high load caused by modern applications. Premium |
256 | 289 |
performance allows deploying a low number of boxes while keeping investments and operational |
257 |
- expenses extremely low. ISPs can start by providing instant messaging services on this |
|
258 |
- standardized platform. This can be combined with the SIP-to-SMS gateway service also supported |
|
259 |
- by SER. In a second step VoIP services can be added in addition to voicemail services and UMS. |
|
290 |
+ expenses extremely low. ISPs can offer SIP-based instant messaging services and interface |
|
291 |
+ them to other instant messaging systems (Jabber, SMS). VoIP can be easily integrated along |
|
292 |
+ with added-value services, such as voicemail. |
|
260 | 293 |
</para> |
261 | 294 |
</section> <!-- Added-value ISP --> |
262 | 295 |
<section> |
... | ... |
@@ -264,12 +297,13 @@ to serve call signaling Bay Area population. |
264 | 297 |
<para> |
265 | 298 |
Internet Telephony Service Providers (ITSPs) offer the service of interconnecting |
266 | 299 |
Internet telephony users using PC softphone or appliances to PSTN. Particularly with |
267 |
- long-distance and international calls, substantial savings can be achieved by |
|
300 |
+ long-distance and international calls, competitive pricing can be achieved by |
|
268 | 301 |
routing the calls over the Internet. |
269 | 302 |
</para> |
270 | 303 |
<para> |
271 | 304 |
SIP Express Router can be easily configured to serve pc2phone users, distribute |
272 |
- calls to geographically appropriate PSTN gateway, act as a security barrier and keep track of charging. |
|
305 |
+ calls to geographically appropriate PSTN gateway, act as a security barrier and keep |
|
306 |
+ track of charging. |
|
273 | 307 |
</para> |
274 | 308 |
</section> |
275 | 309 |
<section> |
... | ... |
@@ -296,15 +330,15 @@ to serve call signaling Bay Area population. |
296 | 330 |
<section id="aboutsip"> |
297 | 331 |
<title>About SIP Technology</title> |
298 | 332 |
<para> |
299 |
- The SIP protocol family is the technology which has succeeded in realizing the vision of the |
|
300 |
- integrated services. With SIP, Internet users can easily contact each other; figure out |
|
333 |
+ The SIP protocol family is the technology which integrates services. |
|
334 |
+ With SIP, Internet users can easily contact each other; figure out |
|
301 | 335 |
willingness to have a conversation and couple different applications such as VoIP, video |
302 | 336 |
and instant messaging. Integration with added-value services is seamless and easy. Examples |
303 | 337 |
include integration with web (click-to-dial), E-mail (voice2email, UMS), and PSTN-like |
304 | 338 |
services (conditional forwarding). |
305 | 339 |
</para> |
306 | 340 |
<para> |
307 |
- The core piece of the technology is the Session Initiation Protocol (SIP) standardized by IETF. |
|
341 |
+ The core piece of the technology is the Session Initiation Protocol (SIP, RFC3261) standardized by IETF. |
|
308 | 342 |
Its main function is to establish communication sessions between users connected to the public |
309 | 343 |
Internet and identified by e-mail-like addresses. One of SIP's greatest features is its transparent |
310 | 344 |
support for multiple applications: the same infrastructure may be used for voice, video, gaming |
... | ... |
@@ -329,11 +363,6 @@ to serve call signaling Bay Area population. |
329 | 363 |
TCP transport |
330 | 364 |
</para> |
331 | 365 |
</listitem> |
332 |
- <listitem> |
|
333 |
- <para> |
|
334 |
- Loose routing |
|
335 |
- </para> |
|
336 |
- </listitem> |
|
337 | 366 |
<listitem> |
338 | 367 |
<para> |
339 | 368 |
Script processing of multiple branches on forking |
... | ... |
@@ -341,14 +370,17 @@ to serve call signaling Bay Area population. |
341 | 370 |
|
342 | 371 |
<warning> |
343 | 372 |
<para> |
344 |
- ser's request processing language allows to make request decisions based on current URI. |
|
373 |
+ <application>ser</application>'s request processing language allows |
|
374 |
+ to make request decisions based on current URI. |
|
345 | 375 |
When a request if forked to multiple destinations, only the first branch's URI is used as |
346 | 376 |
input for script processing. This might lead to unexpected results. Whenever a URI resolves |
347 | 377 |
to multiple different next-hop URIs, only the first is processed which may result in handling |
348 | 378 |
not appropriate for the other branch. For example, a URI might resolve to an IP phone SIP |
349 | 379 |
address and PSTN gateway SIP address. If the IP phone address is the first, then script |
350 |
- execution ignores the second branch and vice versa. That might result in ignoring of |
|
351 |
- gateway admission control rules or applying them unnecessarily to non-gateway destinations. |
|
380 |
+ execution ignores the second branch. If a script includes checking gateway address in |
|
381 |
+ request URI, the checks never match. That might result in ignoring of |
|
382 |
+ gateway admission control rules or applying them unnecessarily to non-gateway |
|
383 |
+ destinations. |
|
352 | 384 |
</para> |
353 | 385 |
</warning> |
354 | 386 |
</listitem> |
... | ... |
@@ -361,16 +393,108 @@ to serve call signaling Bay Area population. |
361 | 393 |
</ulink>. |
362 | 394 |
</para> |
363 | 395 |
</section> <!-- limitations --> |
364 |
- <section id="contact"> |
|
365 |
- <title>Contact and Licencing</title> |
|
396 |
+ <section id="licensing"> |
|
397 |
+ <title>Licensing</title> |
|
366 | 398 |
<para> |
367 |
- For any additional information, send an inquiry to info@iptel.org. |
|
368 |
- Licensing conditions other than GPL are available on request. If |
|
369 |
- you need a help with ser, send an email to serhelp@iptel.org. |
|
370 |
- Report bugs at |
|
371 |
- <ulink url="http://developer.berlios.de/bugs/?group_id=480"> |
|
372 |
- http://developer.berlios.de/bugs/?group_id=480 |
|
373 |
- </ulink> |
|
399 |
+ <application>ser</application> is freely available under terms and |
|
400 |
+ conditions of the GNU General Public License. |
|
401 |
+ </para> |
|
402 |
+ <!-- COPYING --> |
|
403 |
+ <screen> |
|
404 |
+ &gpllicense; |
|
405 |
+ </screen> |
|
406 |
+ |
|
407 |
+ </section> |
|
408 |
+ <section id="support"> |
|
409 |
+ <title>Obtaining Technical Assistance</title> |
|
410 |
+ <para> |
|
411 |
+ We offer best-effort free support for <application>ser</application>. |
|
412 |
+ "best-effort" means that we try to solve your problems via email |
|
413 |
+ as soon as we can, subject to available manpower. If you need |
|
414 |
+ commercial support, contact info@iptel.org. |
|
415 |
+ </para> |
|
416 |
+ <para> |
|
417 |
+ To receive feedback to your inquiries, we recommend you to subscribe |
|
418 |
+ to the <emphasis>serusers</emphasis> mailing list and post your |
|
419 |
+ queries there. This mailing list is set up for mutual help by |
|
420 |
+ the community of <application>ser</application> users and developers. |
|
421 |
+ </para> |
|
422 |
+ <itemizedlist> |
|
423 |
+ <title>Mailing List Instructions</title> |
|
424 |
+ <listitem> |
|
425 |
+ <para> |
|
426 |
+ Public archives and subscription form: |
|
427 |
+ <ulink url="http://mail.iptel.org/mailman/listinfo/serusers"> |
|
428 |
+ http://mail.iptel.org/mailman/listinfo/serusers |
|
429 |
+ </ulink> |
|
430 |
+ </para> |
|
431 |
+ </listitem> |
|
432 |
+ <listitem> |
|
433 |
+ <para> |
|
434 |
+ To post, send an email to serusers@iptel.org |
|
435 |
+ </para> |
|
436 |
+ </listitem> |
|
437 |
+ <listitem> |
|
438 |
+ <para> |
|
439 |
+ If you think you encountered an error, please submit the |
|
440 |
+ following information to avoid unnecessary round-trip times: |
|
441 |
+ <itemizedlist> |
|
442 |
+ <listitem> |
|
443 |
+ <para> |
|
444 |
+ Name and version of your operating system -- |
|
445 |
+ you can obtain it by calling |
|
446 |
+ <command>uname -a</command> |
|
447 |
+ </para> |
|
448 |
+ </listitem> |
|
449 |
+ <listitem> |
|
450 |
+ <para> |
|
451 |
+ <application>ser</application> distribution: |
|
452 |
+ release number and package |
|
453 |
+ </para> |
|
454 |
+ </listitem> |
|
455 |
+ <listitem> |
|
456 |
+ <para> |
|
457 |
+ <application>ser</application> build -- |
|
458 |
+ you can obtain it by calling |
|
459 |
+ <command moreinfo="none">ser -V</command> |
|
460 |
+ </para> |
|
461 |
+ </listitem> |
|
462 |
+ <listitem> |
|
463 |
+ <para> |
|
464 |
+ Your <application>ser</application> configuration file |
|
465 |
+ </para> |
|
466 |
+ </listitem> |
|
467 |
+ <listitem> |
|
468 |
+ <para> |
|
469 |
+ <application>ser</application> logs -- with default settings |
|
470 |
+ few logs are printed to <command>syslog</command> facility which |
|
471 |
+ typically dumps them to |
|
472 |
+ <filename moreinfo="none">/var/log/messages</filename>. To |
|
473 |
+ enable detailed logs dumped to <filename>stderr</filename>, |
|
474 |
+ apply the following configuration options: <command moreinfo="none"> |
|
475 |
+ debug=8, log_stderror=yes, fork=no</command>. |
|
476 |
+ </para> |
|
477 |
+ </listitem> |
|
478 |
+ <listitem> |
|
479 |
+ <para> |
|
480 |
+ Captured SIP messages -- you can obtain them |
|
481 |
+ using tools such as <application>ngrep</application> |
|
482 |
+ or <application moreinfo="none">ethereal</application>. |
|
483 |
+ </para> |
|
484 |
+ </listitem> |
|
485 |
+ </itemizedlist> |
|
486 |
+ </para> |
|
487 |
+ |
|
488 |
+ </listitem> |
|
489 |
+ </itemizedlist> |
|
490 |
+ |
|
491 |
+ <para> |
|
492 |
+ If you are concerned about your privacy and do not wish your |
|
493 |
+ queries to be posted and archived publicly, you may post to |
|
494 |
+ serhelp@iptel.org. E-mails to this address are only forwarded |
|
495 |
+ to iptel.org's <application>ser</application> development team. |
|
496 |
+ However, as the team is quite busy you should not be surprised |
|
497 |
+ to get replies with considerable delay. |
|
374 | 498 |
|
375 | 499 |
</para> |
376 | 500 |
</section> |
... | ... |
@@ -380,7 +504,7 @@ to serve call signaling Bay Area population. |
380 | 504 |
<para> |
381 | 505 |
Most up-to-date information including latest and most complete version |
382 | 506 |
of this documentation is always available at our website, |
383 |
- <ulink url="http://www.iptel.org/ser/">http://www.iptel.org/ser/</ulink> |
|
507 |
+ <ulink url="http://www.iptel.org/ser/">http://www.iptel.org/ser/</ulink>. |
|
384 | 508 |
For information on how to install ser, read INSTALL. |
385 | 509 |
SGML documentation is available in the 'doc' directory. |
386 | 510 |
A SIP tutorial (slide set) is available at |
... | ... |
@@ -401,130 +525,79 @@ to serve call signaling Bay Area population. |
401 | 525 |
location service or enforce static routing to a gateway. Real-world |
402 | 526 |
deployments actually ask for quite complex routing logic, which |
403 | 527 |
needs to reflex static routes to PSTN gateways, dynamic routes |
404 |
- to registered users, authentication policy, etc. |
|
528 |
+ to registered users, authentication policy, capabilities of |
|
529 |
+ SIP devices, etc. |
|
405 | 530 |
</para> |
406 | 531 |
<para> |
407 | 532 |
SER's answer to this need for routing flexibility is a routing |
408 |
- language, which allows administrators to define the SIP routing |
|
409 |
- logic in a detailed manner. They can for example easily |
|
533 |
+ language, which allows administrators to define the SIP request |
|
534 |
+ processing logic in a detailed manner. They can for example easily |
|
410 | 535 |
split SIP traffic by method or destination, perform user location, |
411 | 536 |
trigger authentication, verify access permissions, and so on. |
412 | 537 |
</para> |
413 | 538 |
<para> |
414 |
- The primary building block of the routing language are actions. There are |
|
415 |
- built-in actions (like forward for stateless forwarding) as |
|
416 |
- well as external actions supplied in shared library modules. The actions can be combined in composed statements |
|
417 |
- ({a1(); a2();}). The language includes conditional statements and subroutines (recursive too). |
|
539 |
+ The primary building block of the routing language are <emphasis>actions</emphasis>. |
|
540 |
+ There are built-in actions (like <command>forward</command> for stateless forwarding |
|
541 |
+ or <command>strip</command> for stripping URIs) as |
|
542 |
+ well as external actions imported from shared library modules. All actions can |
|
543 |
+ be combined in compound actions by enclosing them in braces, |
|
544 |
+ e.g. <command>{a1(); a2();}</command>. |
|
545 |
+ Actions are aggregated in one or more <emphasis>route blocks</emphasis>. |
|
546 |
+ Initially, only the default routing block denoted by <command>route[0]</command> |
|
547 |
+ is called. Other routing blocks can be called by the action |
|
548 |
+ <command>route(blocknumber)</command>, recursion is permitted. |
|
549 |
+ The language includes <emphasis>conditional statements</emphasis>. |
|
418 | 550 |
</para> |
419 | 551 |
|
420 | 552 |
<para> |
421 |
- The routing script is executed for every received request in sequential order. Actions may return |
|
422 |
- positive/negative/zero value. |
|
553 |
+ The routing script is executed for every received request in sequential order. |
|
554 |
+ Actions may return positive/negative/zero value. |
|
423 | 555 |
|
424 | 556 |
Positive values are considered success and evaluated as |
425 | 557 |
TRUE in conditional expressions. Negative values are considered FALSE. |
426 |
- Script processing may be explicitly exited |
|
427 |
- by calling "break". |
|
428 |
- |
|
429 |
- Zero value means error and stops processing the script. |
|
430 | 558 |
|
431 |
- One might jump to another route[x] block by calling route(x) (similar to function calling). |
|
559 |
+ Zero value means error and leaves execution of currently processed |
|
560 |
+ route block. The route block is left too, if <command>break</command> is explicitly |
|
561 |
+ called from it. |
|
432 | 562 |
|
433 | 563 |
</para> |
434 | 564 |
<para> |
435 |
- The easiest way for ser users to affect routing logic is |
|
436 |
- to determine next hop statically. A useful scenario is |
|
437 |
- routing to a gateway whose static IP address is well known. |
|
438 |
- To configure static routing, simply use the commands |
|
439 |
- forward( IP_address, port_number>) for stateless |
|
440 |
- forwarding or t_relay_to( IP_address, port_number ) |
|
441 |
- for stateful forwarding. |
|
565 |
+ The easiest and still very useful way for <application>ser</application> |
|
566 |
+ users to affect request routing logic is |
|
567 |
+ to determine next hop statically. An example is |
|
568 |
+ routing to a PSTN gateway whose static IP address is well known. |
|
569 |
+ To configure static routing, simply use the action |
|
570 |
+ <command>forward( IP_address, port_number)</command>. |
|
571 |
+ This action forwards an incoming request "as is" to the |
|
572 |
+ destination described in action's parameters. |
|
442 | 573 |
</para> |
443 | 574 |
|
444 | 575 |
<example> |
445 |
- <title>Stateless versus stateful forwarding</title> |
|
576 |
+ <title>Static Forwarding</title> |
|
446 | 577 |
<programlisting format="linespecific"> |
447 | 578 |
# if requests URI is numerical and starts with |
448 |
-# zero, forward statelessly, otherwise forward |
|
449 |
-# statefully |
|
579 |
+# zero, forward statelessly to a static destination |
|
450 | 580 |
|
451 | 581 |
if (uri=~"^sip:0[0-9]*@iptel.org) { |
452 |
- # statelessly |
|
453 | 582 |
forward( 192.168.99.3, 5080 ); |
454 |
-} else { |
|
455 |
- # statefully |
|
456 |
- t_relay_to( "192.168.99.3", "5080" ); |
|
457 |
-} |
|
583 |
+} |
|
458 | 584 |
</programlisting> |
459 | 585 |
</example> |
460 |
- </section> |
|
461 |
- |
|
462 |
- <section> |
|
463 |
- <title>URI Rewriting</title> |
|
464 | 586 |
|
465 | 587 |
<para> |
466 |
- A powerful tool for affecting routing logic is changing |
|
467 |
- request URI. This can be done with any of built-in commands |
|
468 |
- <command>rewriteuri</command>, |
|
469 |
- <command>rewritehost</command>, |
|
470 |
- <command>rewritehostport</command>, |
|
471 |
- <command>rewriteuser</command>, |
|
472 |
- <command>rewriteuserpass</command> and |
|
473 |
- <command>rewriteport</command>. All these commands |
|
474 |
- rewrite request URI or a part of it. When later in a ser script |
|
475 |
- a forwarding command is encountered, the command forwards |
|
476 |
- the request to address in the rewritten URI. |
|
588 |
+ However, static forwarding is not sufficient in many cases. |
|
589 |
+ Users desire mobility and change their location frequently. |
|
590 |
+ Lowering costs for termination of calls in PSTN requires |
|
591 |
+ locating a least-cost gateway. Which next-hop is taken may |
|
592 |
+ depend on user's preferences. These and many other scenarios |
|
593 |
+ need the routing logic to be more dynamic. We describe in |
|
594 |
+ <xref linkend="conditions"> how to make request processing |
|
595 |
+ subject to various conditions and in |
|
596 |
+ <xref linkend="urirewriting"> how to determine next SIP hop. |
|
477 | 597 |
</para> |
478 |
- <para>Two URI-rewriting commands are of special importance |
|
479 |
- for implementation of dialing plans. <command>prefix(s) |
|
480 |
- </command>, inserts |
|
481 |
- a string "s" in front of SIP address and |
|
482 |
- <command>strip(n)</command> takes |
|
483 |
- away the first "n" characters of a SIP address. |
|
484 |
- </para> |
|
485 |
- |
|
486 |
- <example> |
|
487 |
- <title>Rewriting URIs</title> |
|
488 |
- <programlisting format="linespecific"> |
|
489 |
-if (uri=~"dan@foo.bar") { |
|
490 |
- rewriteuri("sip:bla@somewherelse.com") |
|
491 |
- # forward statelessly |
|
492 |
- forward( dst:uri, dst:port); |
|
493 |
-} |
|
494 |
- </programlisting> |
|
495 |
- </example> |
|
496 |
- |
|
497 |
- <para> |
|
498 |
- Commands exported by external modules can change URI too. |
|
499 |
- The most important application is changing URI using the |
|
500 |
- user location database. The command |
|
501 |
- <command>lookup(table)</command> rewrites |
|
502 |
- current URI with a value stored previously during SIP |
|
503 |
- registration. If there is no registration, the |
|
504 |
- command returns negative value. |
|
505 |
- </para> |
|
506 |
- <example> |
|
507 |
- <title>Rewriting URIs Using User Location Database</title> |
|
508 |
- <programlisting format="linespecific"> |
|
509 |
-# store user location if a REGISTER appears |
|
510 |
-if (method=="REGISTER") { |
|
511 |
- save("mydomain1"); |
|
512 |
-} else { |
|
513 |
-# try to use the previously registered contacts to |
|
514 |
-# determine next hop |
|
515 |
- if(lookup("mydomain1")) { |
|
516 |
- # if found, forward there... |
|
517 |
- t_relay(); |
|
518 |
- } else { |
|
519 |
- sl_send_reply("404", "Not Found" ); |
|
520 |
- }; |
|
521 |
-}; |
|
522 |
- </programlisting> |
|
523 |
- </example> |
|
524 |
- |
|
525 |
- </section> <!-- URI rewriting --> |
|
598 |
+ </section> |
|
526 | 599 |
|
527 |
- <section> |
|
600 |
+ <section id="conditions"> |
|
528 | 601 |
<title>Conditional Statements</title> |
529 | 602 |
<para> |
530 | 603 |
A very useful feature is the ability to make routing |
... | ... |
@@ -533,55 +606,92 @@ if (method=="REGISTER") { |
533 | 606 |
served and foreign domains, IP and PSTN routes, |
534 | 607 |
it may split traffic by method or username, it |
535 | 608 |
may determine whether a request should be authenticated |
536 |
- or not, etc. |
|
609 |
+ or not, etc. <application moreinfo="none">ser</application> |
|
610 |
+ allows administrators to form conditions based on |
|
611 |
+ properties of processed request, such as method or uri, |
|
612 |
+ as well as on virtually any piece of data on the |
|
613 |
+ Internet. |
|
537 | 614 |
</para> |
538 | 615 |
<example> |
539 | 616 |
<title>Conditional Statement</title> |
540 | 617 |
<para> |
541 | 618 |
This example shows how a conditional statement is |
542 |
- used to selectively authenticate REGISTER requests. |
|
619 |
+ used to split incoming requests between a PSTN |
|
620 |
+ gateway and a user location server based on |
|
621 |
+ request URI. |
|
543 | 622 |
</para> |
544 | 623 |
<programlisting format="linespecific"> |
545 |
-# we want to authentication only registrations; |
|
546 |
-# no other request, such as INVITE, will be authenticated |
|
547 |
-# because we want to accept anonymous incoming calls |
|
548 |
-if (method=="REGISTER") { |
|
549 |
- |
|
550 |
- # are authentication credential valid ? ... |
|
551 |
- if (!www_authorize("iptel.org", "subscriber")) { |
|
552 |
- # .... they are not, challenge user and stop processing |
|
553 |
- |
|
554 |
- www_challenge("iptel.org", "0"); |
|
555 |
- break; |
|
556 |
- }; |
|
557 |
- |
|
558 |
-# ... credentials valid -> save a new entry |
|
559 |
-# in user location database |
|
560 |
- |
|
561 |
- save("location"); |
|
624 |
+# if request URI is numerical, forward the request to PSTN gateway... |
|
625 |
+if (uri=~"^sip:[0-9]+@foo.bar") { # match using a regular expression |
|
626 |
+ forward( gateway.foo.bar, 5060 ); |
|
627 |
+} else { # ... forward the request to user location server otherwise |
|
628 |
+ forward( userloc.foo.bar, 5060 ); |
|
562 | 629 |
}; |
563 | 630 |
</programlisting> |
564 | 631 |
</example> |
565 |
- |
|
566 |
- <section> |
|
632 |
+ |
|
633 |
+ <para> |
|
634 |
+ Conditional statements in <application>ser</application> scripts may depend |
|
635 |
+ on a variety of expressions. The simplest expressions are |
|
636 |
+ action calls. They return true if they completed successfully or false otherwise. |
|
637 |
+ An example of an action frequently used in conditional statements is |
|
638 |
+ <command moreinfo="none">search</command> imported from textops module. |
|
639 |
+ <command moreinfo="none">search</command> action leverages textual |
|
640 |
+ nature of SIP and compares SIP requests against a regular expression. |
|
641 |
+ The action returns true if the expression matched, false otherwise. |
|
642 |
+ <example> |
|
643 |
+ <title>Use of <command>search</command> Action in Conditional Expression</title> |
|
644 |
+ <programlisting format="linespecific"> |
|
645 |
+# prevent strangers from claiming to belong to our domain; |
|
646 |
+# if sender claims to be in our domain in From header field, |
|
647 |
+# better authenticate him |
|
648 |
+if (search("(f|From): .*@mydomain.com)) { |
|
649 |
+ if (!(proxy_authorize("mydomain.com" /* realm */,"subscriber" /* table name */ ))) { |
|
650 |
+ proxy_challenge("mydomain.com /* ream */, "1" /* use qop */ ); |
|
651 |
+ break; |
|
652 |
+ } |
|
653 |
+} |
|
654 |
+ </programlisting> |
|
655 |
+ </example> |
|
656 |
+ </para> |
|
657 |
+ <para> |
|
658 |
+ As modules may be created, which export new functions, there is virtually |
|
659 |
+ no limitation on what functionality <application moreinfo="none">ser</application> |
|
660 |
+ conditions are based on. Implementers may introduce new actions whose |
|
661 |
+ return status depends on request content or any external data as well. Such actions |
|
662 |
+ can query SQL, web, local file systems or any other place which can provide |
|
663 |
+ information wanted for request processing. |
|
664 |
+ </para> |
|
665 |
+ <para> |
|
666 |
+ Furthermore, many request properties may be examined using existing built-in operands |
|
667 |
+ and operators. Available left-hand-side operands and legal combination with |
|
668 |
+ operators and right-hand-side operands are described in <xref linkend="logicalexpr">. |
|
669 |
+ Expressions may be grouped together using logical operators: |
|
670 |
+ negation (<command>!</command>), AND (<command>&&</command>), OR (<command moreinfo="none"> |
|
671 |
+ ||</command> and precedence parentheses (<command>()</command>). |
|
672 |
+ </para> |
|
673 |
+ |
|
674 |
+ <section id="operators"> |
|
567 | 675 |
<title>Operators and Operands</title> |
568 | 676 |
<para> |
569 | 677 |
There is a set of predefined operators and operands |
570 |
- in ser, which in addition to actions, may be evaluated |
|
678 |
+ in ser, which in addition to actions may be evaluated |
|
571 | 679 |
in conditional expressions. |
572 | 680 |
</para> |
573 | 681 |
<para> |
574 |
- Operands, which ser understands are the following: |
|
682 |
+ Left hand-side operands, which <application>ser</application> |
|
683 |
+ understands are the following: |
|
575 | 684 |
<itemizedlist> |
576 | 685 |
<listitem> |
577 | 686 |
<para> |
578 |
- method, which refers to requests method |
|
687 |
+ <emphasis>method</emphasis>, which refers to |
|
688 |
+ request method |
|
579 | 689 |
such as REGISTER or INVITE |
580 | 690 |
</para> |
581 | 691 |
</listitem> |
582 | 692 |
<listitem> |
583 | 693 |
<para> |
584 |
- uri, which refers to current request URI, i |
|
694 |
+ <emphasis>uri</emphasis>, which refers to current request URI, |
|
585 | 695 |
such as |
586 | 696 |
"sip:john.doe@foo.bar" |
587 | 697 |
<note> |
... | ... |
@@ -595,10 +705,16 @@ if (method=="REGISTER") { |
595 | 705 |
</listitem> |
596 | 706 |
<listitem> |
597 | 707 |
<para> |
598 |
- scr_ip, which referes to IP address from |
|
708 |
+ <emphasis>scr_ip</emphasis>, which refers to IP address from |
|
599 | 709 |
which a request came. |
600 | 710 |
</para> |
601 | 711 |
</listitem> |
712 |
+ <listitem> |
|
713 |
+ <para> |
|
714 |
+ <emphasis>dst_ip</emphasis> refers to server's IP address |
|
715 |
+ at which a request was received |
|
716 |
+ </para> |
|
717 |
+ </listitem> |
|
602 | 718 |
</itemizedlist> |
603 | 719 |
</para> |
604 | 720 |
<para> |
... | ... |
@@ -612,20 +728,133 @@ if (method=="REGISTER") { |
612 | 728 |
</listitem> |
613 | 729 |
<listitem> |
614 | 730 |
<para> |
615 |
- =~ stand for regular expression match |
|
731 |
+ =~ stands for regular expression matching |
|
616 | 732 |
</para> |
617 | 733 |
</listitem> |
618 | 734 |
<listitem> |
619 | 735 |
<para> |
620 |
- logical operators: and, or, negation |
|
736 |
+ logical operators: and, or, negation, parentheses |
|
621 | 737 |
(C-notation for the operators may be used too) |
622 | 738 |
</para> |
623 | 739 |
</listitem> |
624 | 740 |
</itemizedlist> |
625 | 741 |
</para> |
742 |
+ |
|
743 |
+ <table id="logicalexpr"> |
|
744 |
+ <title>Valid Combinations of Operands and Operators in Expressions</title> |
|
745 |
+ <tgroup cols="4"> |
|
746 |
+ <thead> |
|
747 |
+ <row> |
|
748 |
+ <entry> |
|
749 |
+ left-hand-side operand |
|
750 |
+ </entry> |
|
751 |
+ <entry> |
|
752 |
+ valid operators |
|
753 |
+ </entry> |
|
754 |
+ <entry> |
|
755 |
+ valid right-hand side operators |
|
756 |
+ </entry> |
|
757 |
+ <entry> |
|
758 |
+ examples/comments |
|
759 |
+ </entry> |
|
760 |
+ </row> |
|
761 |
+ |
|
762 |
+ </thead> |
|
763 |
+ <tbody> |
|
764 |
+ |
|
765 |
+ <row> |
|
766 |
+ <entry> |
|
767 |
+ method |
|
768 |
+ </entry> |
|
769 |
+ <entry> |
|
770 |
+ == (exact match), =~ (regular expression matching) |
|
771 |
+ </entry> |
|
772 |
+ <entry> |
|
773 |
+ string |
|
774 |
+ </entry> |
|
775 |
+ <entry> |
|
776 |
+ method=="INVITE" || method=="ACK" || method=="CANCEL" |
|
777 |
+ </entry> |
|
778 |
+ </row> |
|
779 |
+ |
|
780 |
+ <row> |
|
781 |
+ <entry> |
|
782 |
+ uri |
|
783 |
+ </entry> |
|
784 |
+ <entry> |
|
785 |
+ == (exact match), =~ (regular expression matching) |
|
786 |
+ </entry> |
|
787 |
+ <entry> |
|
788 |
+ string |
|
789 |
+ </entry> |
|
790 |
+ <entry> |
|
791 |
+ uri=="sip:foo@bar.com" matches only if exactly this uri |
|
792 |
+ is in request URI |
|
793 |
+ |
|
794 |
+ </entry> |
|
795 |
+ </row> |
|
796 |
+ |
|
797 |
+ <row> |
|
798 |
+ <entry> |
|
799 |
+ |
|
800 |
+ </entry> |
|
801 |
+ <entry> |
|
802 |
+ == (exact match) |
|
803 |
+ </entry> |
|
804 |
+ <entry> |
|
805 |
+ myself |
|
806 |
+ </entry> |
|
807 |
+ <entry> |
|
808 |
+ |
|
809 |
+ the expression uri==myself is true if the host part in |
|
810 |
+ request URI equals a server name or a server alias (set using |
|
811 |
+ the alias option in configuration file) |
|
812 |
+ |
|
813 |
+ </entry> |
|
814 |
+ </row> |
|
815 |
+ |
|
816 |
+ <row> |
|
817 |
+ <entry> |
|
818 |
+ src_ip |
|
819 |
+ </entry> |
|
820 |
+ <entry> |
|
821 |
+ == (match) |
|
822 |
+ </entry> |
|
823 |
+ <entry> |
|
824 |
+ IP, IP/mask_length, IP/mask, hostname, myself |
|
825 |
+ </entry> |
|
826 |
+ <entry> |
|
827 |
+ src_ip==192.168.0.0/16 matches requests coming from |
|
828 |
+ a private network |
|
829 |
+ </entry> |
|
830 |
+ </row> |
|
831 |
+ |
|
832 |
+ <row> |
|
833 |
+ <entry> |
|
834 |
+ dst_ip |
|
835 |
+ by <application moreinfo="none">ser</application> |
|
836 |
+ </entry> |
|
837 |
+ <entry> |
|
838 |
+ == (match) |
|
839 |
+ </entry> |
|
840 |
+ <entry> |
|
841 |
+ IP, IP/mask_length, IP/mask, hostname, myself |
|
842 |
+ </entry> |
|
843 |
+ <entry> |
|
844 |
+ dst_ip==127.0.0.1 matches if a request was received |
|
845 |
+ via loopback interface |
|
846 |
+ </entry> |
|
847 |
+ </row> |
|
848 |
+ |
|
849 |
+ |
|
850 |
+ </tbody> |
|
851 |
+ </tgroup> |
|
852 |
+ </table> |
|
853 |
+ |
|
854 |
+ |
|
626 | 855 |
<example> |
627 | 856 |
<title> |
628 |
- Use of ser operators and operands in conditional |
|
857 |
+ More examples of use of <application>ser</application> operators and operands in conditional |
|
629 | 858 |
statements |
630 | 859 |
</title> |
631 | 860 |
<programlisting format="linespecific"> |
... | ... |
@@ -652,15 +881,516 @@ if (search("^(Contact|m): .*@(192\.168\.|10\.|172\.16)")) { |
652 | 881 |
# ... |
653 | 882 |
</programlisting> |
654 | 883 |
</example> |
884 |
+ </section> <!-- operators and operands --> |
|
885 |
+ <section> |
|
886 |
+ <title>URI Matching</title> |
|
887 |
+ <para>URI matching expressions have a broad use in a SIP server |
|
888 |
+ and deserve more explanation. Typical uses of |
|
889 |
+ URI matching include implementation of numbering plans, |
|
890 |
+ domain matching, |
|
891 |
+ binding external applications to specific URIs, |
|
892 |
+ etc. This section shows examples of typical applications |
|
893 |
+ of URI-matching. |
|
894 |
+ </para> |
|
895 |
+ <section id="domainmatching"> |
|
896 |
+ <title>Domain Matching</title> |
|
897 |
+ <para> |
|
898 |
+ One of most important uses of URI matching is deciding |
|
899 |
+ whether a request is targeted to a served or outside domain. |
|
900 |
+ Typically, different request |
|
901 |
+ processing applies. Requests for outside domains |
|
902 |
+ are simply forwarded to them, whereas |
|
903 |
+ more complex logic applies to requests for a served domain. |
|
904 |
+ The logic may include saving user's contacts |
|
905 |
+ when REGISTER requests are received, forwarding requests |
|
906 |
+ to current user's location or a PSTN gateways, |
|
907 |
+ interaction with external applications, etc. |
|
908 |
+ </para> |
|
909 |
+ <para> |
|
910 |
+ The easiest way to decide whether a request belongs |
|
911 |
+ a served domain is using the <command moreinfo="none">myself</command> |
|
912 |
+ operand. |
|
913 |
+ The expression "uri==myself" returns true if domain name |
|
914 |
+ in request URI matches name of the host at which |
|
915 |
+ <application moreinfo="none">ser</application> is |
|
916 |
+ running. This may be insufficient in cases when |
|
917 |
+ server name is not equal to domain name for which the server |
|
918 |
+ is responsible. For example, the "uri==myself" condition |
|
919 |
+ does not match if a server "sipserver.foo.bar" |
|
920 |
+ receives a request for "sip:john.doe@foo.bar". To |
|
921 |
+ match other names in URI than server's own, |
|
922 |
+ set up the <varname>alias</varname> configuration |
|
923 |
+ option. The option may be used multiple times, |
|
924 |
+ each its use adds a new item to a list of aliases. |
|
925 |
+ The myself condition returns then true |
|
926 |
+ also for any hostname on the list of aliases. |
|
927 |
+ <example> |
|
928 |
+ <title>Use of uri==myself Expression</title> |
|
929 |
+ <programlisting format="linespecific"> |
|
930 |
+# ser powers a domain "foo.bar" and runs at host sipserver.foo.bar; |
|
931 |
+# Names of served domains need to be stated in the aliases |
|
932 |
+# option; myself would not match them otherwise and would only |
|
933 |
+# match requests with "sipserver.foo.bar" in request-URI |
|
934 |
+alias="foo.bar" |
|
935 |
+alias="sales.foo.bar" |
|
936 |
+route[0] { |
|
937 |
+ if (uri==myself) { |
|
938 |
+ # the request either has server name or some of the |
|
939 |
+ # aliases in its URI |
|
940 |
+ log(1,"request for served domain") |
|
941 |
+ # some domain-specific logic follows here .... |
|
942 |
+ } else { |
|
943 |
+ # aha -- the server is not responsible for this |
|
944 |
+ # requests; that happens for example with the following URIs |
|
945 |
+ # - sip:a@marketing.foo.bar |
|
946 |
+ # - sip:a@otherdomain.bar |
|
947 |
+ log(1,"request for outbound domain"); |
|
948 |
+ # outbound forwarding |
|
949 |
+ t_relay(); |
|
950 |
+ }; |
|
951 |
+} </programlisting> |
|
952 |
+ </example> |
|
953 |
+ </para> |
|
954 |
+ <para> |
|
955 |
+ It is possible to recognize whether a request belongs to |
|
956 |
+ a domain using regular expressions too. Care needs to |
|
957 |
+ be paid to construction of regular expressions. URI |
|
958 |
+ syntax is rich and an incorrect expression would result |
|
959 |
+ in incorrect call processing. The following example shows |
|
960 |
+ how an expression for domain matching can be formed. |
|
961 |
+ <example id="redomainmatching"> |
|
962 |
+ <title>Domain Matching Using Regular Expressions</title> |
|
963 |
+ <para> |
|
964 |
+ In this example, server named "sip.foo.bar" with |
|
965 |
+ IP address 192.168.0.10 is responsible for the |
|
966 |
+ "foo.bar" domain. That means, requests with the |
|
967 |
+ following hostnames in URI should be matched: |
|
968 |
+ <itemizedlist> |
|
969 |
+ <listitem> |
|
970 |
+ <para> |
|
971 |
+ foo.bar, which is the name of server domain |
|
972 |
+ </para> |
|
973 |
+ </listitem> |
|
974 |
+ <listitem> |
|
975 |
+ <para> |
|
976 |
+ sip.foo.bar, since it is server's name and some |
|
977 |
+ devices put server's name in request URI |
|
978 |
+ </para> |
|
979 |
+ </listitem> |
|
980 |
+ <listitem> |
|
981 |
+ <para> |
|
982 |
+ 192.168.0.10, since it is server's IP address and |
|
983 |
+ some devices put server's IP address in request URI |
|
984 |
+ </para> |
|
985 |
+ </listitem> |
|
986 |
+ </itemizedlist> |
|
987 |
+ Note how this regular expression is constructed. In particular: |
|
988 |
+ <itemizedlist> |
|
989 |
+ <listitem> |
|
990 |
+ <para> |
|
991 |
+ User name is optional (it is for example never included |
|
992 |
+ in REGISTER requests) and there are no restrictions on |
|
993 |
+ what characters it contains. That is what |
|
994 |
+ <emphasis>(.+@)?</emphasis> mandates. |
|
995 |
+ </para> |
|
996 |
+ </listitem> |
|
997 |
+ <listitem> |
|
998 |
+ <para> |
|
999 |
+ Hostname must be followed by port number, parameters |
|
1000 |
+ or headers -- that is what the delimiters |
|
1001 |
+ <emphasis>[:;\?]</emphasis> are good for. If none |
|
1002 |
+ it these follows, the URI must be ended |
|
1003 |
+ (<emphasis>$</emphasis>). Otherwise, longer hostnames |
|
1004 |
+ such as 192.168.0.101 or foo.bar.otherdomain.com would |
|
1005 |
+ mistakenly match. |
|
1006 |
+ </para> |
|
1007 |
+ </listitem> |
|
1008 |
+ <listitem> |
|
1009 |
+ <para> |
|
1010 |
+ Matches are case-insensitive. All hostnames "foo.bar", "FOO.BAR" |
|
1011 |
+ and "FoO.bAr" match. |
|
1012 |
+ </para> |
|
1013 |
+ </listitem> |
|
1014 |
+ </itemizedlist> |
|
1015 |
+ </para> |
|
1016 |
+ <programlisting> |
|
1017 |
+if (uri=~"^sip:(.+@)?(192\.168\.0\.10|(sip\.)?foo\.bar)([:;\?].*)?$") |
|
1018 |
+ log(1, "yes, it is a request for our domain"); |
|
1019 |
+ break; |
|
1020 |
+ }; |
|
1021 |
+ </programlisting> |
|
1022 |
+ </example> |
|
1023 |
+ </para> |
|
1024 |
+ </section> <!-- domain matching --> |
|
1025 |
+ <section id="numberingplans"> |
|
1026 |
+ <title>Numbering Plans</title> |
|
1027 |
+ |
|
1028 |
+ <para> |
|
1029 |
+ Other use of URI matching is implementation of dialing |
|
1030 |
+ plans. A typical task when designing a dialing plan for SIP networks |
|
1031 |
+ is to distinguish between "pure-IP" and PSTN destinations. |
|
1032 |
+ IP users typically have either alphanumerical or numerical |
|
1033 |
+ usernames. The numerical usernames are convenient for PSTN |
|
1034 |
+ callers who can only |
|
1035 |
+ use numeric keypads. Next-hop destination of IP users is looked up dynamically |
|
1036 |
+ using user location database. On the other hand, PSTN destinations are |
|
1037 |
+ always indicated by nummerical usernames. Requests to PSTN are statically |
|
1038 |
+ forwarded to well-known PSTN gateways. |
|
1039 |
+ </para> |
|
1040 |
+ <example> |
|
1041 |
+ <title>A simple Numbering Plan</title> |
|
1042 |
+ <para> |
|
1043 |
+ This example shows a simple dialing plan which reserves |
|
1044 |
+ dialing prefix "8" for IP users, other numbers |
|
1045 |
+ are used for PSTN destinations and all other non-nummerical |
|
1046 |
+ usernames are used for IP users. |
|
1047 |
+ </para> |
|
1048 |
+ <programlisting format="linespecific"> |
|
1049 |
+# is it a PSTN destination? (is username nummerical and does not begin with 8?) |
|
1050 |
+if (uri=~"^sip:[0-79][0-9]*@") { # ... forward to gateways then; |
|
1051 |
+ # check first to which PSTN destination the requests goes; |
|
1052 |
+ # if it is US (prefix "1"), use the gateway 192.168.0.1... |
|
1053 |
+ if (uri=~"^sip:1") { |
|
1054 |
+ # strip the leading "1" |
|
1055 |
+ strip(1); |
|
1056 |
+ forward(192.168.0.1, 5060); |
|
1057 |
+ } else { |
|
1058 |
+ # ... use the gateway 10.0.0.1 for all other destinations |
|
1059 |
+ forward(10.0.0.1, 5060); |
|
1060 |
+ } |
|
1061 |
+ break; |
|
1062 |
+} else { |
|
1063 |
+ # it is an IP destination -- try to lookup it up in user location DB |
|
1064 |
+ if (!lookup("location")) { |
|
1065 |
+ # bad luck ... user off-line |
|
1066 |
+ sl_send_reply("404", "Not Found"); |
|
1067 |
+ break; |
|
1068 |
+ } |
|
1069 |
+ # user on-line...forward to his current destination |
|
1070 |
+ forward(uri:host,uri:port); |
|
1071 |
+} |
|
1072 |
+ </programlisting> |
|
1073 |
+ </example> |
|
1074 |
+ </section> <!-- numbering plans --> |
|
655 | 1075 |
</section> |
656 | 1076 |
</section> <!-- conditional statements --> |
657 | 1077 |
|
1078 |
+ <section id="urirewriting"> |
|
1079 |
+ <title>Request URI Rewriting</title> |
|
1080 |
+ |
|
1081 |
+ <para> |
|
1082 |
+ The ability to give users and services a unique name using URI |
|
1083 |
+ is a powerful tool. It allows users to advertise how to reach |
|
1084 |
+ them, to state to whom they wish to communicate and what services |
|
1085 |
+ they wish to use. |
|
1086 |
+ Thus, the ability to change URIs is very important and is |
|
1087 |
+ used for implementation of many services. |
|
1088 |
+ "Unconditional forwarding" from user "boss" to user |
|
1089 |
+ "secretary" is a typical example of application relying |
|
1090 |
+ on change of URI address. |
|
1091 |
+ </para> |
|
1092 |
+ <para> |
|
1093 |
+ <application moreinfo="none">ser</application> has the ability |
|
1094 |
+ to change request URI in many ways. |
|
1095 |
+ A script can use any of the following |
|
1096 |
+ built-in actions to change request URI or a part of it: |
|
1097 |
+ |
|
1098 |
+ <command>rewriteuri</command>, |
|
1099 |
+ <command>rewritehost</command>, |
|
1100 |
+ <command>rewritehostport</command>, |
|
1101 |
+ <command>rewriteuser</command>, |
|
1102 |
+ <command>rewriteuserpass</command> and |
|
1103 |
+ <command>rewriteport</command>. |
|
1104 |
+ When later in the script |
|
1105 |
+ a forwarding action is encountered, the action forwards |
|
1106 |
+ the request to address in the rewritten URI. |
|
1107 |
+ <example> |
|
1108 |
+ <title>Rewriting URIs</title> |
|
1109 |
+ <programlisting format="linespecific"> |
|
1110 |
+if (uri=~"dan@foo.bar") { |
|
1111 |
+ rewriteuri("sip:bla@somewherelse.com") |
|
1112 |
+ # forward statelessly to the destination in current URI, i.e., |
|
1113 |
+ # to sip:bla@somewherelese.com:5060 |
|
1114 |
+ forward( uri:host, uri:port); |
|
1115 |
+} |
|
1116 |
+ </programlisting> |
|
1117 |
+ </example> |
|
1118 |
+ </para> |
|
1119 |
+ <para>Two more built-in URI-rewriting commands are of special importance |
|
1120 |
+ for implementation of dialing plans and manipulation of dialing |
|
1121 |
+ prefixes. <command>prefix(s) |
|
1122 |
+ </command>, inserts |
|
1123 |
+ a string "s" in front of SIP address and |
|
1124 |
+ <command>strip(n)</command> takes |
|
1125 |
+ away the first "n" characters of a SIP address. |
|
1126 |
+ See <xref linkend="urirewritingexamples"> for examples of use of |
|
1127 |
+ built-in URI-rewriting actions. |
|
1128 |
+ </para> |
|
1129 |
+ |
|
1130 |
+ <para> |
|
1131 |
+ Commands exported by external modules can change URI too |
|
1132 |
+ and many do so. |
|
1133 |
+ The most important application is changing URI using the |
|
1134 |
+ user location database. The command |
|
1135 |
+ <command>lookup(table)</command> looks up current |
|
1136 |
+ user's location and rewrites user's address with it. |
|
1137 |
+ If there is no registered contact, the command returns a negative value. |
|
1138 |
+ |
|
1139 |
+ |
|
1140 |
+ <example id=rewriteuri> |
|
1141 |
+ <title>Rewriting URIs Using User Location Database</title> |
|
1142 |
+ <programlisting format="linespecific"> |
|
1143 |
+# store user location if a REGISTER appears |
|
1144 |
+if (method=="REGISTER") { |
|
1145 |
+ save("mydomain1"); |
|
1146 |
+} else { |
|
1147 |
+# try to use the previously registered contacts to |
|
1148 |
+# determine next hop |
|
1149 |
+ if(lookup("mydomain1")) { |
|
1150 |
+ # if found, forward there... |
|
1151 |
+ t_relay(); |
|
1152 |
+ } else { |
|
1153 |
+ # ... if no contact on-line, tell it upstream |
|
1154 |
+ sl_send_reply("404", "Not Found" ); |
|
1155 |
+ }; |
|
1156 |
+}; |
|
1157 |
+ </programlisting> |
|
1158 |
+ </example> |
|
1159 |
+ </para> |
|
1160 |
+ <para> |
|
1161 |
+ External applications can be used to rewrite URI too. |
|
1162 |
+ The "exec" module provides script actions, which start external programs |
|
1163 |
+ and read new URI value from their output. <command moreinfo="none">exec_uri</command> |
|
1164 |
+ and <command moreinfo="none">exec_user</command> both call an external program, |
|
1165 |
+ pass current URI or its user part to it respectively, wait until it completes, |
|
1166 |
+ and eventually rewrite current URI with its output. |
|
1167 |
+ </para> |
|
1168 |
+ <para> |
|
1169 |
+ It is important to realize that <application moreinfo="none">ser</application> |
|
1170 |
+ operates over <emphasis>current URI</emphasis> all the time. If an original |
|
1171 |
+ URI is rewritten by a new one, the original will will be forgotten and the new one will |
|
1172 |
+ be used in any further processing. In particular, the uri matching operand |
|
1173 |
+ and the user location action <command moreinfo="none">lookup</command> |
|
1174 |
+ always take current URI as input, regardless what the original URI was. |
|
1175 |
+ </para> |
|
1176 |
+ <para> |
|
1177 |
+ <xref linkend="urirewritingexamples"> shows how URI-rewriting actions affect |
|
1178 |
+ an example URI, sip:12345@foo.bar:6060. |
|
1179 |
+ <table id="urirewritingexamples"> |
|
1180 |
+ <title>URI-rewriting Using Built-In Actions</title> |
|
1181 |
+ <tgroup cols="2"> |
|
1182 |
+ <thead> |
|
1183 |
+ <row> |
|
1184 |
+ <entry> |
|
1185 |
+ Example Action |
|
1186 |
+ </entry> |
|
1187 |
+ <entry> |
|
1188 |
+ Resulting URI |
|
1189 |
+ </entry> |
|
1190 |
+ </row> |
|
1191 |
+ </thead> |
|
1192 |
+ <tbody> |
|
1193 |
+ <row> |
|
1194 |
+ <entry> |
|
1195 |
+ <command moreinfo="none">rewritehost("192.168.0.10")</command> rewrites |
|
1196 |
+ the hostname in URI, other parts (including port number) remain unaffected. |
|
1197 |
+ </entry> |
|
1198 |
+ <entry> |
|
1199 |
+ sip:12345@192.168.10:6060 |
|
1200 |
+ </entry> |
|
1201 |
+ </row> |
|
1202 |
+ <row> |
|
1203 |
+ <entry> |
|
1204 |
+ <command moreinfo="none">rewriteuri("sip:alice@foo.bar");</command> rewrites |
|
1205 |
+ the whole URI completely. |
|
1206 |
+ </entry> |
|
1207 |
+ <entry> |
|
1208 |
+ sip:alice@foo.bar |
|
1209 |
+ </entry> |
|
1210 |
+ </row> |
|
1211 |
+ <row> |
|
1212 |
+ <entry> |
|
1213 |
+ <command moreinfo="none">rewritehostport("192.168.0.10:3040")</command>rewrites |
|
1214 |
+ both hostname and port number in URI. |
|
1215 |
+ </entry> |
|
1216 |
+ <entry> |
|
1217 |
+ sip:12345@192.168.0.10:3040 |
|
1218 |
+ </entry> |
|
1219 |
+ </row> |
|
1220 |
+ <row> |
|
1221 |
+ <entry> |
|
1222 |
+ <command moreinfo="none">rewriteuser("alice")</command> rewrites user part of URI. |
|
1223 |
+ </entry> |
|
1224 |
+ <entry> |
|
1225 |
+ sip:alice@foo.bar:6060 |
|
1226 |
+ </entry> |
|
1227 |
+ </row> |
|
1228 |
+ <row> |
|
1229 |
+ <entry> |
|
1230 |
+ <command moreinfo="none">rewriteuserpass("alice:pw")</command> replaces the pair |
|
1231 |
+ user:password in URI with a new value. |
|
1232 |
+ </entry> |
|
1233 |
+ <entry> |
|
1234 |
+ sip:alice:pw@foo.bar:6060 |
|
1235 |
+ </entry> |
|
1236 |
+ </row> |
|
1237 |
+ <row> |
|
1238 |
+ <entry> |
|
1239 |
+ <command moreinfo="none">rewriteport("1234")</command> replaces port number in URI |
|
1240 |
+ </entry> |
|
1241 |
+ <entry> |
|
1242 |
+ sip:12345@foo.bar:1234 |
|
1243 |
+ </entry> |
|
1244 |
+ </row> |
|
1245 |
+ <row> |
|
1246 |
+ <entry> |
|
1247 |
+ <command moreinfo="none">prefix("9")</command> inserts a string ahead of user part of URI |
|
1248 |
+ </entry> |
|
1249 |
+ <entry> |
|
1250 |
+ sip:912345@foo.bar:6060 |
|
1251 |
+ </entry> |
|
1252 |
+ </row> |
|
1253 |
+ <row> |
|
1254 |
+ <entry> |
|
1255 |
+ <command moreinfo="none">strip(2)</command> removes leading characters from user part of URI |
|
1256 |
+ </entry> |
|
1257 |
+ <entry> |
|
1258 |
+ sip:345@foo.bar:6060 |
|
1259 |
+ </entry> |
|
1260 |
+ </row> |
|
1261 |
+ |
|
1262 |
+ |
|
1263 |
+ </tbody> |
|
1264 |
+ </tgroup> |
|
1265 |
+ </table> |
|
1266 |
+ </para> |
|
1267 |
+ <para> |
|
1268 |
+ You can verify whether you understood URI processing by |
|
1269 |
+ looking at the following example. It rewrites URI |
|
1270 |
+ several times. The question is what is the final URI to which |
|
1271 |
+ the script fill forward any incoming request. |
|
1272 |
+ <example> |
|
1273 |
+ <title>URI-rewriting Quiz</title> |
|
1274 |
+ <programlisting format="linespecific"> |
|
1275 |
+exec_uri("echo sip:2234@foo.bar; echo > /dev/null"); |
|
1276 |
+strip(2); |
|
1277 |
+if (uri=~"^sip:2") { |
|
1278 |
+ prefix("0"); |
|
1279 |
+} else { |
|
1280 |
+ prefix("1"); |
|
1281 |
+}; |
|
1282 |
+forward(uri:host, uri:port); |
|
1283 |
+ </programlisting> |
|
1284 |
+ </example> |
|
1285 |
+ </para> |
|
1286 |
+ <para> |
|
1287 |
+ The correct answer is the resulting URI will be |
|
1288 |
+ "sip:134@foo.bar". <command moreinfo="none">exec_uri</command> |
|
1289 |
+ rewrites original URI to "sip:2234@foo.bar", |
|
1290 |
+ <command moreinfo="none">strip(2)</command> takes |
|
1291 |
+ two leading characters from username away resulting |
|
1292 |
+ in "34@iptel.org", the condition does not match |
|
1293 |
+ because URI does not begin with "2" any more, |
|
1294 |
+ so the prefix "1" is inserted. |
|
1295 |
+ </para> |
|
1296 |
+ |
|
1297 |
+ |
|
1298 |
+ </section> <!-- URI rewriting --> |
|
1299 |
+ |
|
1300 |
+ <section> |
|
1301 |
+ <title>Destination Set</title> |
|
1302 |
+ <para> |
|
1303 |
+ Whereas needs of many scenarios can by accommodated by maintaining |
|
1304 |
+ a single request URI, some scenarios are better served by |