📄 intro.sgml
字号:
user:password in URI with a new value. Rewriting password in URI is of historical meaning though, since basic password has been replaced with digest authentication. </entry> <entry> sip:alice:pw@foo.bar:6060 </entry> </row> <row> <entry> <command moreinfo="none">rewriteport("1234")</command> replaces port number in URI </entry> <entry> sip:12345@foo.bar:1234 </entry> </row> <row> <entry> <command moreinfo="none">prefix("9")</command> inserts a string ahead of user part of URI </entry> <entry> sip:912345@foo.bar:6060 </entry> </row> <row> <entry> <command moreinfo="none">strip(2)</command> removes leading characters from user part of URI </entry> <entry> sip:345@foo.bar:6060 </entry> </row> </tbody> </tgroup> </table> </para> <para> You can verify whether you understood URI processing by looking at the following example. It rewrites URI several times. The question is what is the final URI to which the script fill forward any incoming request. <example> <title>URI-rewriting Exercise</title> <programlisting format="linespecific">exec_dset("echo sip:2234@foo.bar; echo > /dev/null");strip(2);if (uri=~"^sip:2") { prefix("0");} else { prefix("1");}; forward(uri:host, uri:port); </programlisting> </example> </para> <para> The correct answer is the resulting URI will be "sip:134@foo.bar". <command moreinfo="none">exec_dset</command> rewrites original URI to "sip:2234@foo.bar", <command moreinfo="none">strip(2)</command> takes two leading characters from username away resulting in "34@iptel.org", the condition does not match because URI does not begin with "2" any more, so the prefix "1" is inserted. </para> </section> <!-- URI rewriting --> <section> <title>Destination Set</title> <para> Whereas needs of many scenarios can by accommodated by maintaining a single request URI, some scenarios are better served by multiple URIs. Consider for example a user with address john.doe@iptel.org. The user wishes to be reachable at his home phone, office phone, cell phone, softphone, etc. However, he still wishes to maintain a single public address on his business card. </para> <para> To enable such scenarios, <application>ser</application> allows translation of a single request URI into multiple outgoing URIs. The ability to forward a request to multiple destinations is known as <emphasis>forking</emphasis> in SIP language. All outgoing URIs (in trivial case one of them) are called <emphasis>destination set</emphasis>. The destination set always includes one default URI, to which additional URIs can be appended. Maximum size of a destination set is limited by a compile-time constant, MAX_BRANCHES, in <filename moreinfo="none">config.h</filename>. </para> <para> Some actions are designed for use with a single URI whereas other actions work with the whole destination set. </para> <para> Actions which are currently available for creating the destination set are <command>lookup</command> from usrloc module and <command>exec_dset</command> from exec module. <command moreinfo="none">lookup</command> fills in the destination set with user contact's registered previously with REGISTER requests. The <command moreinfo="none">exec</command> actions fill in the destination set with output of an external program. In both cases, current destination set is completely rewritten. New URIs can be appended to destination set by a call to the built-in action <command>append_branch(uri)</command>. </para> <para> Currently supported features which utilize destination sets are <emphasis>forking</emphasis> and <emphasis>redirection</emphasis>. Action <command>t_relay</command> (TM module) for stateful forwarding supports forking. If called with a non-trivial destination set, <command moreinfo="none">t_relay</command> forks incoming request to all URIs in current destination set. See <xref linkend="rewriteuri">. If a user previously registered from three locations, the destination set is filled with all of them by <command>lookup</command> and the <command>t_relay</command> command forwards the incoming request to all these destinations. Eventually, all user's phone will be ringing in parallel. </para> <para> SIP redirection is another feature which leverages destination sets. It is a very light-weighted method to establish communication between two parties with minimum burden put on the server. In <application>ser</application>, the action <command>sl_send_reply</command> (SL module) is used for this purpose. This action allows to generate replies to SIP requests without keeping any state. If the status code passed to the action is 3xx, the current destination set is printed in reply's Contact header fields. Such a reply instructs the originating client to retry at these addresses. (See <xref linkend="redirectexample">). </para> <para> Most other <application>ser</application> actions ignore destination sets: they either do not relate to URI processing (<command moreinfo="none"> log</command>, for example) or they work only with the default URI. All URI-rewriting functions such as <command moreinfo="none">rewriteuri</command> belong in this category. URI-comparison operands only refer to the first URI (see <xref linkend="operators">). Also, the built-in action for stateless forwarding, <command>forward</command> works only with the default URI and ignores rest of the destination set. The reason is a proxy server willing to fork must guarantee that the burden of processing multiple replies is not put unexpectedly on upstream client. This is only achievable with stateful processing. Forking cannot be used along with stateless <command>forward</command>, which thus only processes one URI out of the whole destination set. </para> </section> <!-- Destination Set --> <section> <title>User Location</title> <para> Mobility is a key feature of SIP. Users are able to use one one or more SIP devices and be reachable at them. Incoming requests for users are forwarded to all user's devices in use. The key concept is that of soft-state registration. Users can -- if in possession of valid credentials -- link SIP devices to their e-mail like address of record. Their SIP devices do so using a REGISTER request, as in <xref linkend="register">. The request creates a binding between the public address of record (To header field) and SIP device's current address (Contact header field). <example id="register"> <title>REGISTER Request</title> <programlisting format="linespecific">REGISTER sip:192.168.2.16 SIP/2.0Via: SIP/2.0/UDP 192.168.2.16;branch=z9hG4bKd5e5.5a9947e4.0Via: SIP/2.0/UDP 192.168.2.33:5060From: sip:123312@192.168.2.16To: sip:123312@192.168.2.16Call-ID: 00036bb9-0fd30217-491b6aa6-0a7092e9@192.168.2.33Date: Wed, 29 Jan 2003 18:13:15 GMTCSeq: 101 REGISTERUser-Agent: CSCO/4Contact: sip:123312@192.168.2.33:5060Content-Length: 0Expires: 600 </programlisting> </example> Similar requests can be used to query all user's current contacts or to delete them. All Contacts have certain time to live, when the time expires, contact is removed and no longer used for processing of incoming requests. </para> <para> <application moreinfo="none">ser</application> is built to do both: update user location database from received REGISTER requests and look-up these contacts when inbound requests for a user arrive. To achieve high performance, the user location table is stored in memory. In regular intervals (usrloc module's parameter <varname>timer_interval</varname> determines their length), all changes to the in-memory table are backed up in <application moreinfo="none">mysql</application> database to achieve persistence across server reboots. Administrators or application writers can lookup list of current user's contacts stored in memory using the <application moreinfo="none">serctl</application> tool (see <xref linkend="serctl">). <example> <title>Use of <application>serctl</application> Tool to Query User Location</title> <screen format="linespecific"><![CDATA[[jiri@fox jiri]$ sc ul show jiri<sip:jiri@212.202.172.134>;q=0.00;expires=456<sip:7271@gateway.foo.bar>;q=0.00;expires=36000]]> </screen> </example> </para> <para> Building user location in <application moreinfo="none">ser</application> scripts is quite easy. One first needs to determine whether a request is for served domain, as described in <xref linkend="domainmatching">. If that is the case, the script needs to distinguish between REGISTER requests, that update user location table, and all other requests for which next hop is determined from the table. The <command moreinfo="none">save</command> action is used to update user location (i.e., it writes to it). The <command moreinfo="none">lookup</command> actions reads from the user location table and fills in destination set with current user's contacts. <example> <title>Use of User Location Actions</title> <programlisting format="linespecific"># is the request for my domain ?if (uri==myself) { if (method=="REGISTER") { # REGISTERs are used to update save("location"); break; # that's it, we saved the contacts, exit now } else { if (!lookup("location") { # no registered contact sl_send_reply("404", "Not Found"); break; } # ok -- there are some contacts for the user; forward # the incoming request to all of them t_relay(); };}; </programlisting> </example> </para> <para> Note that we used the action for stateful forwarding, <command moreinfo="none">t_relay</command>. That's because stateful forwarding allows to fork an incoming request to multiple destinations. If we used stateless forwarding, the request would be forwarded only to one uri out of all user's contacts. </para> </section> <!-- User Location --> <section> <title>External Modules</title> <para> <application moreinfo="none">ser</application> provides the ability to link the server with external third-party shared libraries. Lot of functionality which is included in the <application moreinfo="none">ser</application> distribution is actually located in modules to keep the server "core" compact and clean. Among others, there are modules for checking max_forwards value in SIP requests (maxfwd), transactional processing (tm), record routing (rr), accounting (acc), authentication (auth), SMS gateway (sms), replying requests (sl), user location (usrloc, registrar) and more. </para> <para> In order to utilize new actions exported by a module, ser must first load it. To load a module, the directive <command moreinfo="none">loadmodule "filename"</command> must be included in beginning of a <application>ser</application> script file. </para> <example> <title>Using Modules</title> <para> This example shows how a script instructs <application moreinfo="none">ser</application> to load a module and use actions exported by it. Particularly, the sl module exports an action <command>sl_send_reply</command> which makes <application>ser</application> act as a stateless user agent and reply all incoming requests with 404. </para> <programlisting format="linespecific"># first of all, load the module!loadmodule "/usr/lib/ser/modules/sl.soroute{ # reply all requests with 404 sl_send_reply("404", "I am so sorry -- user not found");}</programlisting> </example> <note> <para>Note that unlike with core commands, all actions exported by modules must have parameters enclosed in quotation marks in current version of <application moreinfo="none">ser</application>. In the following example, the built-in action <command moreinfo="none">forward</command> for stateless forwarding takes IP address and port numbers as parameters without quotation marks whereas a module action <command moreinfo="none">t_relay</command> for stateful forwarding takes parameters enclosed in quotation marks. <example> <title>Parameters in built-in and exported actions</title> <programlisting format="linespecific"># built-in action doesn't enclose IP addresses and port numbers# in quotation marksforward(192.168.99.100, 5060);# module-exported functions enclose all parameters in quotation# markst_relay_to_udp("192.168.99.100", "5060"); </programlisting> </example> </para> </note> <para> Many modules also allow users to change the way how they work using predefined parameters. For example, the authentication module needs to know location of MySQL database which contains users' security credentials. How module parameters are set using the <command moreinfo="none">modparam</command> directive is shown in <xref linkend="moduleparameters">. <command moreinfo="none">modparam</command> always contains identification of module, parameter name and parameter value. Description of parameters available in modules is available in module documentation. </para> <para> Yet another thing to notice in this example is module dependency. Modules may depend on each other. For example, the authentication modules leverages the mysql module for accessing mysql databases and sl module for generating authentication challenges. We recommend that modules are loaded in dependency order to avoid ambiguous server behavior. </para> <para> <example id="moduleparameters"> <title>Module Parameters</title> <programlisting format="linespecific"># ------------------ module loading ----------------------------------# load first modules on which 'auth' module depends;# sl is used for sending challenges, mysql for storage# of user credentialsloadmodule "modules/sl/sl.so"loadmodule "modules/mysql/mysql.so"loadmodule "modules/auth/auth.so"# ------------------ module parameters -------------------------------# tell the auth module the access data for SQL database:# username, password, hostname and database namemodparam("auth", "db_url","mysql://ser:secret@dbhost/ser")# ------------------------- request routing logic -------------------# authenticate all requests prior to forwarding themroute{ if (!proxy_authorize("foo.bar" /* realm */, "subscriber" /* table name */ )) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -