浏览代码

domain: Documentation update

Update domain module documentation. Now it describes all functions
and parameters and also contains description of some of the concepts,
such as virtual domains and domain-level attributes.
Jan Janak 16 年之前
父节点
当前提交
03bb546da5
共有 5 个文件被更改,包括 1022 次插入291 次删除
  1. 409 115
      modules_s/domain/README
  2. 233 68
      modules_s/domain/doc/domain.xml
  3. 5 4
      modules_s/domain/doc/fifo.xml
  4. 116 32
      modules_s/domain/doc/functions.xml
  5. 259 72
      modules_s/domain/doc/params.xml

+ 409 - 115
modules_s/domain/README

@@ -1,170 +1,464 @@
-
-Domain Module
+1. Domain Module
 
 Juha Heinanen
 
-Edited by
-
-Juha Heinanen
+   <[email protected]>
 
    Copyright © 2002, 2003 Juha Heinanen
-     _________________________________________________________
+   Revision History
+   Revision $Revision$ $Date$
+     __________________________________________________________________
 
-   Table of Contents
-   1. User's Guide
+1.1. Overview
 
-        1.1. Overview
-        1.2. Dependencies
-        1.3. Exported Parameters
+   Domain modules, as the name suggests, implements support for multiple
+   independent virtual domains hosted on one SIP server. This is often
+   useful if you have multiple domain names and you want to make them all
+   work and appear as one. Alternatively you might find the module useful
+   if you want to run a shared SIP service for multiple independent
+   customers. The module stores all supported domains and associated
+   configuration in a database table. Most of the information can be
+   cached in memory for performance reasons.
+
+1.1.1. Virtual Domains
+
+   The domain module adds support for so-called virtual domains. A virtual
+   domain is just a collection of domain names and associated
+   configuration information identified by a unique identifier. We refer
+   to the domain identifier as DID elsewhere in the documentation. DID
+   stands for "Domain IDentifier". In traditional POST world the term DID
+   has a different meaning though. Please be aware that this is just pure
+   coincidence.
+
+   All domain names that belong to one virtual domain are interchangeable.
+   From SIP server's perspective there is no difference between them. They
+   can be used in SIP URIs interchangeably and the behavior of the SIP
+   server will not be affected. This is called "domain name normalization"
+   and it is one of the steps performed early during SIP message
+   processing.
+
+   The DID identifier can be anything. To the SIP server DIDs are just
+   opaque strings and what format you choose depends on your requirements
+   and the type of the setup. You can use numbers in smaller setups if the
+   size of the data is a concern. You can set the DID to the canonical
+   domain name of the domain. You can use RFC 4122 style UUIDs if your
+   setup is large and distributed. You can use anything as long as it can
+   be represented as string. The only requirement is that the identifier
+   of each virtual domain must be unique.
+
+   The following example illustrates how one virtual domain can be
+   represented. The iptel.org domain runs a public SIP service. The users
+   of the service can use SIP URIs of form sip:[email protected]. The SIP
+   service is distributed, there is a number of SIP servers. The SIP
+   servers are also available through a number of other domain names, such
+   as sip.iptel.org, proxy.iptel.org and so on. We created one virtual
+   domain in the domain module and added all such domain names to the
+   virtual domain:
+
+   Example 1. Virtual Domain iptel.org
+iptel
+  |
+  +---iptel.org
+  +---sip.iptel.org
+  +---proxy.iptel.org
+  +---213.192.59.75
+
+   In the example above, we chose "iptel" as the unique identifier for the
+   virtual domain. This identifier is permanent. It never changes. Over
+   time we may change domain names assigned to this virtual domain, but
+   this identifier never changes. The main reason why virtual domain
+   identifiers must never change is that because they are referenced from
+   other tables, for example the accounting table. The data in the
+   accounting table is long-lived, usually archived, and this ensures that
+   the data will still reference correct virtual domain, no matter what
+   domain names are assigned to it.
+
+   The virtual domain described above will be stored in the domain table
+   in the database:
+
+   Example 2. Database Representation of Virtual Domain
++-------+-----------------+-------+
+| did   | domain          | flags |
++-------+-----------------+-------+
+| iptel | iptel.org       |    33 |
+| iptel | sip.iptel.org   |    33 |
+| iptel | proxy.iptel.org |    33 |
+| iptel | 213.192.59.75   |    33 |
++-------+-----------------+-------+
+
+   Because all domain names that belong to one particular virtual domain
+   are equal, it does not matter which domain name is used in the host
+   part of the SIP URI. Thus an imaginary user joe with SIP URI
+   sip:[email protected] will also be reachable as sip:[email protected],
+   sip:[email protected], and sip:[email protected]. If we add a new
+   domain name to this virtual domain then joe will also be able to use
+   the new domain name in his SIP URI, without the need to change
+   anything.
+
+1.1.2. Domain-level Configuration Attributes
+
+   In addition to a number of domain names, each virtual domain can also
+   have extra configuration information associated with it. The
+   possibility to configure the SIP server sightly differently in each
+   virtual domain is, in fact, the main reason why we introduced the
+   concept of virtual domains. We wanted to have one SIP server which will
+   provide SIP service to multiple different customers and each of the
+   customers may have slightly different configuration requirements.
+   That's how domain-level configuration attributes were born.
+
+   Because the administrator of the SIP server seldom knows configuration
+   requirements in advance, we decided to implement a generic solution and
+   store all configuration options in named attributes. Named attributes
+   are just like variables, they have a name and they have a value.
+   Attributes are accessible from the configuration script of the SIP
+   server. Domain-level attributes are attributes that are associated with
+   a particular virtual domain. They can be used to store additional
+   configuration for the entire virtual domain, that is all users that
+   belong (or have SIP URI) in that particular virtual domain.
+   Domain-level attributes can be overridden be user-level attributes with
+   the same name configured for a particular user. In other words a domain
+   level attribute will only be effective if no user-level attribute with
+   the same name exists.
+
+   Domain-level attributes are stored in a separate table. The name of the
+   table is domain_attrs and it is defined as follows:
+
+   Example 3. Table domain_attrs
++-------+------------------+------+-----+---------+-------+
+| Field | Type             | Null | Key | Default | Extra |
++-------+------------------+------+-----+---------+-------+
+| did   | varchar(64)      | YES  | MUL | NULL    |       |
+| name  | varchar(32)      | NO   |     | NULL    |       |
+| type  | int(11)          | NO   |     | 0       |       |
+| value | varchar(255)     | YES  |     | NULL    |       |
+| flags | int(10) unsigned | NO   |     | 0       |       |
++-------+------------------+------+-----+---------+-------+
+
+   Each attribute has name, type and value. A single attribute can have
+   multiple values and in that case it will occupy more rows in the table.
+   Each attribute is associated with a particular virtual domain using the
+   DID identifier. Domain-level attributes can contain just about
+   anything. It is a generic configuration mechanism and it is up to you
+   to define a list of attribute that are meaningful in your setup and use
+   those attributes in the routing part of the configuration file.
+
+   Attributes for a particular virtual-domain are made available to script
+   function by the lookup_domain function. This is the function that is
+   used to map domain names to DIDs. One of the side-effects of the
+   function is that it makes domain-level attributes available to script
+   function if a matching virtual domain is found.
+
+   When caching is enabled, all attributes from domain_attrs table are
+   cached in memory, just like virtual domain themselves. If you disable
+   caching then the domain module will attempt to load attributes from the
+   database each time you call lookup_domain. Attributes cached in memory
+   can be realoaded with the domain.reload management function.
+
+1.1.3. Caching
+
+   Domain module operates in caching or non-caching mode depending on
+   value of module parameter db_mode. In caching mode domain module reads
+   the contents of domain table into cache memory when the module is
+   loaded. After that domain table is re-read only when module is given
+   domain_reload fifo command. Any changes in domain table must thus be
+   followed by domain_reload command in order to reflect them in module
+   behavior. In non-caching mode domain module always queries domain table
+   in the database.
+
+   Caching is implemented using a hash table. The size of the hash table
+   is given by HASH_SIZE constant defined in domain_mod.h. Its "factory
+   default" value is 128. Caching mode is highly recommended if you want
+   to use domain-level attributes.
 
-              1.3.1. db_url (string)
-              1.3.2. db_mode (integer)
-              1.3.3. domain_table (string)
-              1.3.4. domain_column (string)
+1.2. Dependencies
 
-        1.4. Exported Functions
+   The module depends on the following modules (in the other words the
+   listed modules must be loaded before this module):
+     * database - Any database module
 
-              1.4.1. is_from_local()
+1.3. Known Limitations
 
-        1.5. FIFO Commands
+   There is an unlikely race condition on domain list update. If a process
+   uses a table, which is reloaded at the same time twice through FIFO,
+   the second reload will delete the original table still in use by the
+   process.
 
-              1.5.1. domain_reload
-              1.5.2. domain_dump
+1.4. Parameters
 
-        1.6. Known Limitations
+   Revision History
+   Revision $Revision$ $Date$
 
-   2. Developer's Guide
-   3. Frequently Asked Questions
+1.4.1. db_url (string)
 
-   List of Examples
-   1-1. Setting db_url parameter
-   1-2. nonce_expire example
-   1-3. Setting domain_table parameter
-   1-4. Setting domain_column parameter
-   1-5. is_from_local usage
-     _________________________________________________________
+   This is URL of the database to be used.
 
-Chapter 1. User's Guide
+   Default value is "mysql://serro:47serro11@localhost/ser"
 
-1.1. Overview
+   Example 4. Setting db_url parameter
+modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
 
-   Domain module implements checks that based on domain table
-   determine if a host part of an URI is "local" or not. A
-   "local" domain is one that the proxy is responsible for.
-
-   Domain module operates in caching or non-caching mode
-   depending on value of module parameter db_mode. In caching
-   mode domain module reads the contents of domain table into
-   cache memory when the module is loaded. After that domain
-   table is re-read only when module is given domain_reload fifo
-   command. Any changes in domain table must thus be followed by
-   domain_reload command in order to reflect them in module
-   behavior. In non-caching mode domain module always queries
-   domain table in the database.
-
-   Caching is implemented using a hash table. The size of the
-   hash table is given by HASH_SIZE constant defined in
-   domain_mod.h. Its "factory default" value is 128.
-     _________________________________________________________
+1.4.2. db_mode (integer)
 
-1.2. Dependencies
+   Database mode. 0 means non-caching, 1 means caching is enabled. It is
+   highly recommended to enable caching if you want to use domain-level
+   attributes.
 
-   The module depends on the following modules (in the other
-   words the listed modules must be loaded before this module):
+   Default value is 1 (non-caching).
 
-     * database -- Any database module
-     _________________________________________________________
+   Example 5. nonce_expire example
+                                modparam("domain", "db_mode", 1)   # Use caching
 
-1.3. Exported Parameters
+1.4.3. domain_table (string)
 
-1.3.1. db_url (string)
+   Name of table containing names of local domains that the proxy is
+   responsible for. Local users must have in their SIP URI a host part
+   that is equal to one of the domains stored in this table.
 
-   This is URL of the database to be used.
-
-   Default value is "mysql://serro:47serro11@localhost/ser"
+   Default value is "domain".
 
-   Example 1-1. Setting db_url parameter
-modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
-     _________________________________________________________
+   Example 6. Setting domain_table parameter
+modparam("domain", "domain_table", "new_name")
 
-1.3.2. db_mode (integer)
+1.4.4. did_col (string)
 
-   Database mode. 0 means non-caching, 1 means caching.
+   This is the name of the column in domain table that contains the unique
+   identifiers of virtual domains. Domains names found in this table are
+   arranged into virtual domains. Each virtual domain must have a unique
+   identifier and it can contain one or more domain names.
 
-   Default value is 0 (non-caching).
+   Default value is "did".
 
-   Example 1-2. nonce_expire example
-modparam("domain", "db_mode", 1)   # Use caching
-     _________________________________________________________
+   Example 7. Setting did_col parameter
+modparam("domain", "did_col", "did")
 
-1.3.3. domain_table (string)
+1.4.5. domain_col (string)
 
-   Name of table containing names of local domains that the proxy
-   is responsible for. Local users must have in their sip uri a
-   host part that is equal to one of these domains.
+   Name of column containing domain names in the domain table.
 
    Default value is "domain".
 
-   Example 1-3. Setting domain_table parameter
-modparam("domain", "domain_table", "new_name")
-     _________________________________________________________
+   Example 8. Setting domain_col parameter
+modparam("domain", "domain_col", "domain")
 
-1.3.4. domain_column (string)
+1.4.6. flags_col (string)
 
-   Name of column containing domains in domain table.
+   This is the name of the column in domain table which stores various
+   flags. Each row in the table has a bunch of generic flags that can be
+   used mark the row disabled, deleted, etc. The flags allow for more
+   flexible administration of the data in the database and they are
+   present in several other tables too.
 
-   Default value is "domain".
+   Default value is "flags".
 
-   Example 1-4. Setting domain_column parameter
-modparam("domain", "domain_column", "domain_col")
-     _________________________________________________________
+   Example 9. Setting flags_col parameter
+modparam("domain", "flags_col", "domain")
 
-1.4. Exported Functions
+1.4.7. domattr_table (string)
 
-1.4.1. is_from_local()
+   This parameter can be used to configure the name of the table that is
+   used to store domain-level attributes. Domain level attributes are
+   attributes that are associated with a particular virtual domain. They
+   are typically used to store additional domain-wide settings that should
+   apply to all users who belong to the domain.
 
-   Checks based on domain table if host part of From header uri
-   is one of the local domains that the proxy is responsible for
+   Default value is "domain_attrs".
 
-   Example 1-5. is_from_local usage
-...
-if (is_from_local()) {
-    ...
-};
-...
-     _________________________________________________________
+   Example 10. Setting domattrs_table parameter
+modparam("domain", "domattr_table", "domain_attrs")
+
+1.4.8. domattr_did (string)
 
-1.5. FIFO Commands
+   Use this parameter to configure the name of the column in domain_attrs
+   table that is used to store the did of the virtual domain the attribute
+   belongs to. Normally there is no need to configure this parameter,
+   unless you want adapt to module to a different database schema.
 
-1.5.1. domain_reload
+   Default value is "did".
 
-   Causes domain module to re-read the contents of domain table
-   into cache memory.
-     _________________________________________________________
+   Example 11. Setting domattrs_did parameter
+modparam("domain", "domattr_did", "did")
 
-1.5.2. domain_dump
+1.4.9. domattr_name (string)
 
-   Causes domain module to dump hash indexes and domain names in
-   its cache memory.
-     _________________________________________________________
+   Use this parameter to configure the name of the column in domain_attrs
+   table that is used to store the name of the attribute. Normally there
+   is no need to configure this parameter, unless you want adapt to module
+   to a different database schema.
 
-1.6. Known Limitations
+   Default value is "name".
 
-   There is an unlikely race condition on domain list update. If
-   a process uses a table, which is reloaded at the same time
-   twice through FIFO, the second reload will delete the original
-   table still in use by the process.
-     _________________________________________________________
+   Example 12. Setting domattrs_name parameter
+modparam("domain", "domattr_name", "name")
 
-Chapter 2. Developer's Guide
+1.4.10. domattr_type (string)
 
-   To be done.
-     _________________________________________________________
+   Use this parameter to configure the name of the column in domain_attrs
+   table that is used to store the type of the attribute. Normally there
+   is no need to configure this parameter, unless you want adapt to module
+   to a different database schema.
 
-Chapter 3. Frequently Asked Questions
+   Default value is "type".
 
-   3.1. What is the meaning of life ?
+   Example 13. Setting domattrs_type parameter
+modparam("domain", "domattr_type", "type")
 
-   3.1. What is the meaning of life ?
+1.4.11. domattr_value (string)
+
+   Use this parameter to configure the name of the column in domain_attrs
+   table that is used to store the value of the attribute. Normally there
+   is no need to configure this parameter, unless you want adapt to module
+   to a different database schema.
+
+   Default value is "value".
+
+   Example 14. Setting domattrs_value parameter
+modparam("domain", "domattr_value", "value")
+
+1.4.12. domattr_flags (string)
+
+   This is the name of the column in domain_attrs table which stores
+   various flags. Each row in the table has a bunch of generic flags that
+   can be used mark the row disabled, deleted, etc. The flags allow for
+   more flexible administration of the data in the database and they are
+   present in several other tables too. You do not have to touch this
+   parameter under normal circumstances.
+
+   Default value is "flags".
+
+   Example 15. Setting domattrs_flags parameter
+modparam("domain", "domattr_flags", "flags")
+
+1.4.13. load_domain_attrs (integer)
+
+   This parameter can be used to enable/disable user of domain-level
+   attributes. Domain-level attributes are variables that can be used to
+   store additional configuration that applies to the whole virtual domain
+   and all users within the virtual domain. Domain-level attributes are
+   stored in domain_attrs. If you set this parameter to a non-zero value
+   then the server will make domain-level attributes available to the
+   script every time you call function lookup_domain. If you set the
+   parameter to 0 then domain-level attributes will be ignored, the domain
+   module will not load them from the database and the lookup function
+   will not make them available to the script.
+
+   Default value is 0.
+
+   Example 16. Setting load_domain_attrs parameter
+modparam("domain", "load_domain_attrs", 1)
+
+1.5. Functions
+
+   Revision History
+   Revision $Revision$ $Date$
+
+1.5.1. is_local(domain)
+
+   This function can be used to test whether a given domain name in
+   parameter belongs to one of the virtual domains defined in the domain
+   table. Such domain name is said to be local. The function returns 1 if
+   the domain name is found in the domain table and -1 otherwise.
+
+   The first parameter of the function can be anything that returns a
+   string with domain name. In its simplest form it can be a string with
+   domain name: is_local("iptel.org"). You can also test a domain name
+   stored in an attribute: is_local("$my_domain"). And finally you can
+   test a domain name present in the SIP message with selects:
+   is_local("@ruri.host").
+
+   Note: Unlike function lookup_domain, this function does not make domain
+   attributes of the virtual domain available to the script. Domain
+   attributes are simply ignored by this function.
+
+   Example 17. is_uri_host_local_local usage
+...
+if (is_local("@ruri.host")) {
+    /* Domain part of Request-URI is local */
+}
+...
 
-   42
+1.5.2. lookup_domain(attr_group, domain)
+
+   This is the main function of the domain module. It can be used to
+   implement support for virtual domains in the SIP server. Each virtual
+   domain is identified by a unique identifier (opaque string) and it can
+   have one or more associated domain names. Given a domain name in the
+   second parameter, this function finds the associated virtual domain
+   identifier (known as DID) and stores it in an attribute for later user.
+   In addition to that the function also loads all domain-level attributes
+   for the virtual domain and makes them available to the configuration
+   script.
+
+   The first parameter of the function identifies the group of attributes
+   where the DID and domain-level attributes shall be stored. The value of
+   the first parameter can be either "$fd" for the domain-level attribute
+   group that belongs to the calling party (From), or "$td" for the
+   domain-level attribute group that belongs to the called party
+   (Request-URI).
+
+   The value of the second parameter can be a simple string, an attribute
+   name, or a select. See the documentation of function is_local for more
+   details.
+
+   If a match is found then the DID of the virtual domain will be stored
+   either in $fd.did or in $td.did, depending on the value of the first
+   parameter. In addition to that domain-level attributes, if any, will be
+   available as either $fd.<name> or $td.</name>.
+
+   The function returns 1 when a matching virtual domain for the given
+   domain name was found and -1 otherwise.
+
+   The following example shows a typical use of the function. In a multi
+   domain setup, one has to typically figure out where the both the
+   calling and the called domains are local (i.e. configured on the server
+   as the domains the server is responsible for). This is typically done
+   by calling function lookup_domain twice, once with the hostname part of
+   the From header as parameter and secondly with the hostname part of the
+   Request-URI as parameter.
+
+   The type of the situation can be then determined from the value of
+   corresponding attributes ($t.did and $f.did). A non-existing attribute
+   value indicates that the domain name is not local (it does not belong
+   to any virtual domain configured in the domain table).
+
+   Example 18. lookup_domain usage
+lookup_domain("$fd", "@from.uri.host");
+lookup_domain("$td", "@ruri.host");
+
+if (strempty($f.did) && strempty($t.did)) {
+    # Neither the calling nor the called domain is local
+    # This is a relaying attempt which should be forbidden
+    sl_reply("403", "Relaying Forbidden");
+    drop;
+}
+if (strempty($f.did) && $t.did) {
+    # The calling domain is not local and the called domain
+    # is local, this is an inbound call from a 3rd party
+    # user to one of local users
+}
+if ($f.did && strempty($t.did)) {
+    # The calling domain is local and the called domain
+    # is not local, this is an outbound call from one of
+    # our users to a 3rd party user
+}
+if ($f.did && $t.did) {
+    # Both the calling and the called domains are local,
+    # one of our local users calls another local user,
+    # either in the same virtual domain or in another
+    # virtual domain hosted on the same server
+}
+
+1.6. FIFO Interface
+
+   Revision History
+   Revision $Revision$ $Date$
+
+1.6.1. domain.reload
+
+   Causes domain module to re-read the contents of domain table into cache
+   memory. If domain-level attributes are used then it will also re-load
+   the contents of the domain_attrs table in the memory cache.
+
+1.6.2. domain.dump
+
+   Causes domain module to dump hash indexes and domain names in its cache
+   memory.

+ 233 - 68
modules_s/domain/doc/domain.xml

@@ -3,78 +3,243 @@
    "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <section id="domain" xmlns:xi="http://www.w3.org/2001/XInclude">
-    <sectioninfo>
-	<authorgroup>
-	    <author>
-		<firstname>Juha</firstname>
-		<surname>Heinanen</surname>
-		<email>[email protected]</email>
-	    </author>
-	</authorgroup>
-	<copyright>
-	    <year>2002</year>
-	    <year>2003</year>
-	    <holder>Juha Heinanen</holder>
-	</copyright>
-	<revhistory>
-	    <revision>
-		<revnumber>$Revision$</revnumber>
-		<date>$Date$</date>
-	    </revision>
-	</revhistory>
-    </sectioninfo>
+	<sectioninfo>
+		<authorgroup>
+			<author>
+				<firstname>Juha</firstname>
+				<surname>Heinanen</surname>
+				<email>[email protected]</email>
+			</author>
+		</authorgroup>
+		<copyright>
+			<year>2002</year>
+			<year>2003</year>
+			<holder>Juha Heinanen</holder>
+		</copyright>
+		<revhistory>
+			<revision>
+				<revnumber>$Revision$</revnumber>
+				<date>$Date$</date>
+			</revision>
+		</revhistory>
+	</sectioninfo>
+	
+	<title>Domain Module</title>
+	
+	<section id="domain.overview">
+		<title>Overview</title>
+		<para>Domain modules, as the name suggests, implements support for
+		multiple independent virtual domains hosted on one SIP server. This is
+		often useful if you have multiple domain names and you want to make
+		them all work and appear as one. Alternatively you might find the
+		module useful if you want to run a shared SIP service for multiple
+		independent customers. The module stores all supported domains and
+		associated configuration in a database table. Most of the information
+		can be cached in memory for performance reasons.</para>
 
-    <title>Domain Module</title>
+		<section>
+			<title>Virtual Domains</title>
+			<para>The domain module adds support for so-called virtual
+			domains. A virtual domain is just a collection of domain names and
+			associated configuration information identified by a unique
+			identifier. We refer to the domain identifier as DID elsewhere in
+			the documentation. DID stands for "Domain IDentifier". In
+			traditional POST world the term DID has a different meaning
+			though. Please be aware that this is just pure coincidence.</para>
+			
+			<para>All domain names that belong to one virtual domain are
+			interchangeable. From SIP server's perspective there is no
+			difference between them. They can be used in SIP URIs
+			interchangeably and the behavior of the SIP server will not be
+			affected. This is called "domain name normalization" and it is one
+			of the steps performed early during SIP message processing.</para>
 
-    <section id="domain.overview">
-	<title>Overview</title>
-	<para>
-	    Domain module implements checks that based on domain table
-	    determine if a host part of an <acronym>URI</acronym> is
-	    "local" or not.  A "local" domain is one
-	    that the proxy is responsible for.
-	</para>
-	<para>
-	    Domain module operates in caching or non-caching mode depending on
-	    value of module parameter <parameter>db_mode</parameter>. In
-	    caching mode domain module reads the contents of domain table into
-	    cache memory when the module is loaded.  After that domain table is
-	    re-read only when module is given domain_reload fifo command.  Any
-	    changes in domain table must thus be followed by domain_reload
-	    command in order to reflect them in module behavior. In non-caching
-	    mode domain module always queries domain table in the database.
-	</para>
-	<para>
-	    Caching is implemented using a hash table. The size of the hash
-	    table is given by HASH_SIZE constant defined in domain_mod.h. Its
-	    "factory default" value is 128.
-	</para>
-    </section>
+			<para>The DID identifier can be anything. To the SIP server DIDs
+			are just opaque strings and what format you choose depends on your
+			requirements and the type of the setup. You can use numbers in
+			smaller setups if the size of the data is a concern. You can set
+			the DID to the canonical domain name of the domain. You can use
+			RFC 4122 style UUIDs if your setup is large and distributed. You
+			can use anything as long as it can be represented as string. The
+			only requirement is that the identifier of each virtual domain
+			must be unique.</para>
+		
+			<para>The following example illustrates how one virtual domain can
+			be represented. The iptel.org domain runs a public SIP
+			service. The users of the service can use SIP URIs of form
+			sip:[email protected]. The SIP service is distributed, there is a
+			number of SIP servers. The SIP servers are also available through
+			a number of other domain names, such as sip.iptel.org,
+			proxy.iptel.org and so on. We created one virtual domain in the
+			domain module and added all such domain names to the virtual
+			domain:</para>
 
-    <section id="domain.dep">
-	<title>Dependencies</title>
-	<para>
-	    The module depends on the following modules (in the other words the listed modules
-	    must be loaded before this module):
-	    <itemizedlist>
-		<listitem>
-		    <para><emphasis>database</emphasis> - Any database module</para>
-		</listitem>
-	    </itemizedlist>
-	</para>
-    </section>
+			<example>
+				<title>Virtual Domain iptel.org</title>
+				<programlisting>
+iptel
+  |
+  +---iptel.org
+  +---sip.iptel.org
+  +---proxy.iptel.org
+  +---213.192.59.75
+				</programlisting>
+			</example>
+			
+			<para>In the example above, we chose "iptel" as the unique
+			identifier for the virtual domain. This identifier is
+			permanent. It never changes. Over time we may change domain names
+			assigned to this virtual domain, but this identifier never
+			changes. The main reason why virtual domain identifiers must never
+			change is that because they are referenced from other tables, for
+			example the accounting table. The data in the accounting table is
+			long-lived, usually archived, and this ensures that the data will
+			still reference correct virtual domain, no matter what domain
+			names are assigned to it.</para>
+
+			<para>The virtual domain described above will be stored in the
+			domain table in the database:</para>
+			<example>
+				<title>Database Representation of Virtual Domain</title>
+				<programlisting>
++-------+-----------------+-------+
+| did   | domain          | flags |
++-------+-----------------+-------+
+| iptel | iptel.org       |    33 | 
+| iptel | sip.iptel.org   |    33 | 
+| iptel | proxy.iptel.org |    33 | 
+| iptel | 213.192.59.75   |    33 | 
++-------+-----------------+-------+
+				</programlisting>
+			</example>
+
+			<para>Because all domain names that belong to one particular
+			virtual domain are equal, it does not matter which domain name is
+			used in the host part of the SIP URI. Thus an imaginary user joe
+			with SIP URI sip:[email protected] will also be reachable as
+			sip:[email protected], sip:[email protected], and
+			sip:[email protected]. If we add a new domain name to this virtual
+			domain then joe will also be able to use the new domain name in
+			his SIP URI, without the need to change anything.</para>
+		</section>
+		
+		<section>
+			<title>Domain-level Configuration Attributes</title>
+			<para>In addition to a number of domain names, each virtual domain
+			can also have extra configuration information associated with
+			it. The possibility to configure the SIP server sightly
+			differently in each virtual domain is, in fact, the main reason
+			why we introduced the concept of virtual domains. We wanted to
+			have one SIP server which will provide SIP service to multiple
+			different customers and each of the customers may have slightly
+			different configuration requirements. That's how domain-level
+			configuration attributes were born.</para>
+		
+			<para>Because the administrator of the SIP server seldom knows
+			configuration requirements in advance, we decided to implement a
+			generic solution and store all configuration options in named
+			attributes. Named attributes are just like variables, they have a
+			name and they have a value. Attributes are accessible from the
+			configuration script of the SIP server. Domain-level attributes
+			are attributes that are associated with a particular virtual
+			domain. They can be used to store additional configuration for the
+			entire virtual domain, that is all users that belong (or have SIP
+			URI) in that particular virtual domain. Domain-level attributes
+			can be overridden be user-level attributes with the same name
+			configured for a particular user. In other words a domain level
+			attribute will only be effective if no user-level attribute with
+			the same name exists.</para>
+			
+			<para>Domain-level attributes are stored in a separate table. The
+			name of the table is domain_attrs and it is defined as follows:
+			</para>
+
+			<example>
+				<title>Table domain_attrs</title>
+				<programlisting>
++-------+------------------+------+-----+---------+-------+
+| Field | Type             | Null | Key | Default | Extra |
++-------+------------------+------+-----+---------+-------+
+| did   | varchar(64)      | YES  | MUL | NULL    |       | 
+| name  | varchar(32)      | NO   |     | NULL    |       | 
+| type  | int(11)          | NO   |     | 0       |       | 
+| value | varchar(255)     | YES  |     | NULL    |       | 
+| flags | int(10) unsigned | NO   |     | 0       |       | 
++-------+------------------+------+-----+---------+-------+
+				</programlisting>
+			</example>
 
-    <section id="known_limitations">
-	<title>Known Limitations</title>
-	<para>
-	    There is an unlikely race condition on domain list update.  If a process uses a table,
-	    which is reloaded at the same time twice through <acronym>FIFO</acronym>, the second
-	    reload will delete the original table still in use by the process.
-	</para>
-    </section>
+			<para>Each attribute has name, type and value. A single attribute
+			can have multiple values and in that case it will occupy more rows
+			in the table. Each attribute is associated with a particular
+			virtual domain using the DID identifier. Domain-level attributes
+			can contain just about anything. It is a generic configuration
+			mechanism and it is up to you to define a list of attribute that
+			are meaningful in your setup and use those attributes in the
+			routing part of the configuration file.
+			</para>
 
-    <xi:include href="params.xml"/>
-    <xi:include href="functions.xml"/>
-    <xi:include href="fifo.xml"/>
+			<para>Attributes for a particular virtual-domain are made
+			available to script function by the lookup_domain function. This
+			is the function that is used to map domain names to DIDs. One of
+			the side-effects of the function is that it makes domain-level
+			attributes available to script function if a matching virtual
+			domain is found.
+			</para>
 
+			<para>When caching is enabled, all attributes from domain_attrs
+			table are cached in memory, just like virtual domain
+			themselves. If you disable caching then the domain module will
+			attempt to load attributes from the database each time you call
+			lookup_domain. Attributes cached in memory can be realoaded with
+			the domain.reload management function.</para>
+		</section>
+
+		<section>
+			<title>Caching</title>
+
+			<para>Domain module operates in caching or non-caching mode
+			depending on value of module parameter
+			<parameter>db_mode</parameter>. In caching mode domain module
+			reads the contents of domain table into cache memory when the
+			module is loaded.  After that domain table is re-read only when
+			module is given domain_reload fifo command.  Any changes in domain
+			table must thus be followed by domain_reload command in order to
+			reflect them in module behavior. In non-caching mode domain module
+			always queries domain table in the database.</para>
+
+			<para>Caching is implemented using a hash table. The size of the
+			hash table is given by HASH_SIZE constant defined in
+			domain_mod.h. Its "factory default" value is 128. Caching mode is
+			highly recommended if you want to use domain-level
+			attributes.</para>
+		</section>
+	</section>
+	
+	<section id="domain.dep">
+		<title>Dependencies</title>
+		<para>
+			The module depends on the following modules (in the other words
+			the listed modules must be loaded before this module):
+			<itemizedlist>
+				<listitem>
+					<para><emphasis>database</emphasis> - Any database module</para>
+				</listitem>
+	    </itemizedlist>
+		</para>
+	</section>
+	
+	<section id="known_limitations">
+		<title>Known Limitations</title>
+		<para>
+			There is an unlikely race condition on domain list update.  If a process uses a table,
+			which is reloaded at the same time twice through <acronym>FIFO</acronym>, the second
+			reload will delete the original table still in use by the process.
+		</para>
+	</section>
+	
+	<xi:include href="params.xml"/>
+	<xi:include href="functions.xml"/>
+	<xi:include href="fifo.xml"/>
+	
 </section>

+ 5 - 4
modules_s/domain/doc/fifo.xml

@@ -15,15 +15,16 @@
     <title>FIFO Interface</title>
 
     <section id="domain_reload">
-	<title><function>domain_reload</function></title>
+	<title><function>domain.reload</function></title>
 	<para>
-	    Causes domain module to re-read the contents of domain table
-	    into cache memory.
+	    Causes domain module to re-read the contents of domain table into
+	    cache memory. If domain-level attributes are used then it will also
+	    re-load the contents of the domain_attrs table in the memory cache.
 	</para>
     </section>
 
     <section id="domain_dump">
-	<title><function>domain_dump</function></title>
+	<title><function>domain.dump</function></title>
 	<para>
 	    Causes domain module to dump hash indexes and domain names in its
 	    cache memory.

+ 116 - 32
modules_s/domain/doc/functions.xml

@@ -14,39 +14,123 @@
 
     <title>Functions</title>
 
-    <section id="is_from_local">
-	<title><function>is_from_local()</function></title>
-	<para>
-	    Checks based on domain table if host part of From header uri is one
-	    of the local domains that the proxy is responsible for
-	</para>
-	<example>
-	    <title>is_from_local usage</title>
-	    <programlisting>
+	<section id="is_local">
+		<title><function>is_local(domain)</function></title>
+		<para>
+			This function can be used to test whether a given domain name in
+			parameter belongs to one of the virtual domains defined in the
+			domain table. Such domain name is said to be local. The function
+			returns 1 if the domain name is found in the domain table and -1
+			otherwise.
+		</para>
+		<para>
+			The first parameter of the function can be anything that returns a
+			string with domain name. In its simplest form it can be a string
+			with domain name: is_local("iptel.org"). You can also test a
+			domain name stored in an attribute: is_local("$my_domain"). And
+			finally you can test a domain name present in the SIP message with
+			selects: is_local("@ruri.host").
+		</para>
+		<para>
+			Note: Unlike function <function>lookup_domain</function>, this
+			function does not make domain attributes of the virtual domain
+			available to the script. Domain attributes are simply ignored by
+			this function.
+		</para>
+		<example>
+			<title>is_uri_host_local_local usage</title>
+			<programlisting>
 ...
-if (is_from_local()) {
-    ...
-};
+if (is_local("@ruri.host")) {
+    /* Domain part of Request-URI is local */
+}
 ...
-	    </programlisting>
-	</example>
-    </section>
+			</programlisting>
+		</example>
+	</section>
 
-    <section id="is_uri_host_local">
-	<title><function>is_uri_host_local()</function></title>
-	<para>
-	    Checks based on domain table if host part of Request-URI is one of
-	    the local domains that the proxy is responsible for
-	</para>
-	<example>
-	    <title>is_uri_host_local_local usage</title>
-	    <programlisting>
-...
-if (is_uri_host_local()) {
-    ...
-};
-...
-	    </programlisting>
-	</example>
-    </section>
+	<section id="lookup_domain">
+		<title><function>lookup_domain(attr_group, domain)</function></title>
+		<para>
+			This is the main function of the domain module. It can be used to
+			implement support for virtual domains in the SIP server. Each
+			virtual domain is identified by a unique identifier (opaque
+			string) and it can have one or more associated domain names. Given
+			a domain name in the second parameter, this function finds the
+			associated virtual domain identifier (known as DID) and stores it
+			in an attribute for later user. In addition to that the function
+			also loads all domain-level attributes for the virtual domain and
+			makes them available to the configuration script.
+		</para>
+		<para>
+			The first parameter of the function identifies the group of
+			attributes where the DID and domain-level attributes shall be
+			stored. The value of the first parameter can be either "$fd" for
+			the domain-level attribute group that belongs to the calling party
+			(From), or "$td" for the domain-level attribute group that belongs
+			to the called party (Request-URI).
+		</para>
+		<para>
+			The value of the second parameter can be a simple string, an
+			attribute name, or a select. See the documentation of function
+			<function>is_local</function> for more details.
+		</para>
+		<para>
+			If a match is found then the DID of the virtual domain will be
+			stored either in $fd.did or in $td.did, depending on the value of
+			the first parameter. In addition to that domain-level attributes,
+			if any, will be available as either $fd.<name> or $td.</name>.
+		</para>
+		<para>
+			The function returns 1 when a matching virtual domain for the
+			given domain name was found and -1 otherwise.
+		</para>
+		<para>
+			The following example shows a typical use of the function. In a
+			multi domain setup, one has to typically figure out where the both
+			the calling and the called domains are local (i.e. configured on
+			the server as the domains the server is responsible for). This is
+			typically done by calling function
+			<function>lookup_domain</function> twice, once with the hostname
+			part of the From header as parameter and secondly with the
+			hostname part of the Request-URI as parameter.
+		</para>
+		<para>
+			The type of the situation can be then determined from the value of
+			corresponding attributes ($t.did and $f.did). A non-existing
+			attribute value indicates that the domain name is not local (it
+			does not belong to any virtual domain configured in the domain
+			table).
+		</para>
+		<example>
+			<title>lookup_domain usage</title>
+			<programlisting>
+lookup_domain("$fd", "@from.uri.host");
+lookup_domain("$td", "@ruri.host");
+
+if (strempty($f.did) &amp;&amp; strempty($t.did)) {
+    # Neither the calling nor the called domain is local
+    # This is a relaying attempt which should be forbidden
+    sl_reply("403", "Relaying Forbidden");
+    drop;
+}
+if (strempty($f.did) &amp;&amp; $t.did) {
+    # The calling domain is not local and the called domain
+    # is local, this is an inbound call from a 3rd party
+    # user to one of local users
+}
+if ($f.did &amp;&amp; strempty($t.did)) {
+    # The calling domain is local and the called domain
+    # is not local, this is an outbound call from one of
+    # our users to a 3rd party user
+}
+if ($f.did &amp;&amp; $t.did) {
+    # Both the calling and the called domains are local,
+    # one of our local users calls another local user,
+    # either in the same virtual domain or in another
+    # virtual domain hosted on the same server
+}
+			</programlisting>
+		</example>
+	</section>
 </section>

+ 259 - 72
modules_s/domain/doc/params.xml

@@ -3,80 +3,267 @@
    "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <section id="domain.parameters" xmlns:xi="http://www.w3.org/2001/XInclude">
-    <sectioninfo>
-	<revhistory>
-	    <revision>
-		<revnumber>$Revision$</revnumber>
-		<date>$Date$</date>
-	    </revision>
-	</revhistory>
-    </sectioninfo>
+	<sectioninfo>
+		<revhistory>
+			<revision>
+				<revnumber>$Revision$</revnumber>
+				<date>$Date$</date>
+			</revision>
+		</revhistory>
+	</sectioninfo>
+	
+	<title>Parameters</title>
+	
+	<section id="domain.db_url">
+		<title><varname>db_url</varname> (string)</title>
+		<para>
+			This is <acronym>URL</acronym> of the database to be used.
+		</para>
+		<para>
+			Default value is "mysql://serro:47serro11@localhost/ser"
+		</para>
+		<example>
+			<title>Setting db_url parameter</title>
+			<programlisting>
+modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
+			</programlisting>
+		</example>
+	</section>
+	
+	<section id="db_mode">
+		<title><varname>db_mode</varname> (integer)</title>
+		<para>
+			Database mode. 0 means non-caching, 1 means caching is enabled. It
+			is highly recommended to enable caching if you want to use
+			domain-level attributes.
+		</para>
+		<para>
+			Default value is 1 (non-caching).
+		</para>
+		<example>
+			<title>nonce_expire example</title>
+			<programlisting>
+				modparam("domain", "db_mode", 1)   # Use caching
+			</programlisting>
+		</example>
+	</section>
+	
+	<section id="domain_table">
+		<title><varname>domain_table</varname> (string)</title>
+		<para>
+			Name of table containing names of local domains that the proxy is
+			responsible for.  Local users must have in their SIP URI a host
+			part that is equal to one of the domains stored in this table.
+		</para>
+		<para>
+			Default value is "domain".
+		</para>
+		<example>
+			<title>Setting domain_table parameter</title>
+			<programlisting>
+modparam("domain", "domain_table", "new_name")
+			</programlisting>
+		</example>
+	</section>
 
-    <title>Parameters</title>
+	<section id="domain.did_column">
+		<title><varname>did_col</varname> (string)</title>
+		<para>
+			This is the name of the column in domain table that contains the
+			unique identifiers of virtual domains. Domains names found in this
+			table are arranged into virtual domains. Each virtual domain must
+			have a unique identifier and it can contain one or more domain
+			names.
+		</para>
+		<para>
+			Default value is "did".
+		</para>
+		<example>
+			<title>Setting did_col parameter</title>
+			<programlisting>
+modparam("domain", "did_col", "did")
+			</programlisting>
+		</example>
+	</section>
+	
+	<section id="domain.domain_col">
+		<title><varname>domain_col</varname> (string)</title>
+		<para>
+			Name of column containing domain names in the domain table.
+		</para>
+		<para>
+			Default value is "domain".
+		</para>
+		<example>
+			<title>Setting domain_col parameter</title>
+			<programlisting>
+modparam("domain", "domain_col", "domain")
+			</programlisting>
+		</example>
+	</section>
 
-    <section id="domain.db_url">
-	<title><varname>db_url</varname> (string)</title>
-	<para>
-	    This is <acronym>URL</acronym> of the database to be used.
-	</para>
-	<para>
-	    Default value is "mysql://serro:47serro11@localhost/ser"
-	</para>
-	<example>
-	    <title>Setting db_url parameter</title>
-	    <programlisting>
-modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
-	    </programlisting>
-	</example>
-    </section>
+	<section id="domain.flags_col">
+		<title><varname>flags_col</varname> (string)</title>
+		<para>
+			This is the name of the column in domain table which stores
+			various flags. Each row in the table has a bunch of generic flags
+			that can be used mark the row disabled, deleted, etc. The flags
+			allow for more flexible administration of the data in the database
+			and they are present in several other tables too.
+		</para>
+		<para>
+			Default value is "flags".
+		</para>
+		<example>
+			<title>Setting flags_col parameter</title>
+			<programlisting>
+modparam("domain", "flags_col", "domain")
+			</programlisting>
+		</example>
+	</section>
 
-    <section id="db_mode">
-	<title><varname>db_mode</varname> (integer)</title>
-	<para>
-	    Database mode. 0 means non-caching, 1 means caching.
-	</para>
-	<para>
-	    Default value is 0 (non-caching).
-	</para>
-	<example>
-	    <title>nonce_expire example</title>
-	    <programlisting>
-modparam("domain", "db_mode", 1)   # Use caching
-	    </programlisting>
-	</example>
-    </section>
+	<section id="domattr_table">
+		<title><varname>domattr_table</varname> (string)</title>
+		<para>
+			This parameter can be used to configure the name of the table that
+			is used to store domain-level attributes. Domain level attributes
+			are attributes that are associated with a particular virtual
+			domain. They are typically used to store additional domain-wide
+			settings that should apply to all users who belong to the domain.
+		</para>
+		<para>
+			Default value is "domain_attrs".
+		</para>
+		<example>
+			<title>Setting domattrs_table parameter</title>
+			<programlisting>
+modparam("domain", "domattr_table", "domain_attrs")
+			</programlisting>
+		</example>
+	</section>
 
-    <section id="domain_table">
-	<title><varname>domain_table</varname> (string)</title>
-	<para>
-	    Name of table containing names of local domains that the proxy is
-	    responsible for.  Local users must have in their sip uri a host
-	    part that is equal to one of these domains.
-	</para>
-	<para>
-	    Default value is "domain".
-	</para>
-	<example>
-	    <title>Setting domain_table parameter</title>
-	    <programlisting>
-modparam("domain", "domain_table", "new_name")
-	    </programlisting>
-	</example>
-    </section>
-    
-    <section id="domain.domain_column">
-	<title><varname>domain_column</varname> (string)</title>
-	<para>
-	    Name of column containing domains in domain table.
-	</para>
-	<para>
-	    Default value is "domain".
-	</para>
-	<example>
-	    <title>Setting domain_column parameter</title>
-	    <programlisting>
-modparam("domain", "domain_column", "domain_col")
-	    </programlisting>
-	</example>
-    </section>
+	<section id="domattr_did">
+		<title><varname>domattr_did</varname> (string)</title>
+		<para>
+			Use this parameter to configure the name of the column in
+			domain_attrs table that is used to store the did of the virtual
+			domain the attribute belongs to. Normally there is no need to
+			configure this parameter, unless you want adapt to module to a
+			different database schema.
+		</para>
+		<para>
+			Default value is "did".
+		</para>
+		<example>
+			<title>Setting domattrs_did parameter</title>
+			<programlisting>
+modparam("domain", "domattr_did", "did")
+			</programlisting>
+		</example>
+	</section>
+
+	<section id="domattr_name">
+		<title><varname>domattr_name</varname> (string)</title>
+		<para>
+			Use this parameter to configure the name of the column in
+			domain_attrs table that is used to store the name of the
+			attribute. Normally there is no need to configure this parameter,
+			unless you want adapt to module to a different database schema.
+		</para>
+		<para>
+			Default value is "name".
+		</para>
+		<example>
+			<title>Setting domattrs_name parameter</title>
+			<programlisting>
+modparam("domain", "domattr_name", "name")
+			</programlisting>
+		</example>
+	</section>
+
+	<section id="domattr_type">
+		<title><varname>domattr_type</varname> (string)</title>
+		<para>
+			Use this parameter to configure the name of the column in
+			domain_attrs table that is used to store the type of the
+			attribute. Normally there is no need to configure this parameter,
+			unless you want adapt to module to a different database schema.
+		</para>
+		<para>
+			Default value is "type".
+		</para>
+		<example>
+			<title>Setting domattrs_type parameter</title>
+			<programlisting>
+modparam("domain", "domattr_type", "type")
+			</programlisting>
+		</example>
+	</section>
+
+	<section id="domattr_value">
+		<title><varname>domattr_value</varname> (string)</title>
+		<para>
+			Use this parameter to configure the name of the column in
+			domain_attrs table that is used to store the value of the
+			attribute. Normally there is no need to configure this parameter,
+			unless you want adapt to module to a different database schema.
+		</para>
+		<para>
+			Default value is "value".
+		</para>
+		<example>
+			<title>Setting domattrs_value parameter</title>
+			<programlisting>
+modparam("domain", "domattr_value", "value")
+			</programlisting>
+		</example>
+	</section>
+
+	<section id="domattr_flags">
+		<title><varname>domattr_flags</varname> (string)</title>
+		<para>
+			This is the name of the column in domain_attrs table which stores
+			various flags. Each row in the table has a bunch of generic flags
+			that can be used mark the row disabled, deleted, etc. The flags
+			allow for more flexible administration of the data in the database
+			and they are present in several other tables too. You do not have
+			to touch this parameter under normal circumstances.
+		</para>
+
+		<para>
+			Default value is "flags".
+		</para>
+		<example>
+			<title>Setting domattrs_flags parameter</title>
+			<programlisting>
+modparam("domain", "domattr_flags", "flags")
+			</programlisting>
+		</example>
+	</section>
+
+	<section id="load_domain_attrs">
+		<title><varname>load_domain_attrs</varname> (integer)</title>
+		<para>
+			This parameter can be used to enable/disable user of domain-level
+			attributes. Domain-level attributes are variables that can be used
+			to store additional configuration that applies to the whole
+			virtual domain and all users within the virtual
+			domain. Domain-level attributes are stored in domain_attrs. If you
+			set this parameter to a non-zero value then the server will make
+			domain-level attributes available to the script every time you
+			call function <function>lookup_domain</function>. If you set the
+			parameter to 0 then domain-level attributes will be ignored, the
+			domain module will not load them from the database and the lookup
+			function will not make them available to the script.
+		</para>
+		<para>
+			Default value is 0.
+		</para>
+		<example>
+			<title>Setting load_domain_attrs parameter</title>
+			<programlisting>
+modparam("domain", "load_domain_attrs", 1)
+			</programlisting>
+		</example>
+	</section>
 </section>