Browse Source

modules_k/domain: added support for domain attributes

- Added new function lookup_domain that in addition to checking if
  domain is local, adds attributes of local domain into AVPs.
- Domain attributes are stored in new table domain_attrs.
- Removed support for db only mode and, as consequence, removed db_mode
  module variable.
Juha Heinanen 13 years ago
parent
commit
b6ce51e2ab

+ 10 - 1
lib/srdb1/schema/domain.xml

@@ -9,7 +9,7 @@
 
 
 <table id="domain" xmlns:db="http://docbook.org/ns/docbook">
 <table id="domain" xmlns:db="http://docbook.org/ns/docbook">
     <name>domain</name>
     <name>domain</name>
-    <version>1</version>
+    <version>2</version>
     <type db="mysql">&MYSQL_TABLE_TYPE;</type>
     <type db="mysql">&MYSQL_TABLE_TYPE;</type>
     <description>
     <description>
         <db:para>This table is used by the domain module to determine if a host part of a URI is "local" or not. More information about the domain module can be found at: &KAMAILIO_MOD_DOC;domain.html
         <db:para>This table is used by the domain module to determine if a host part of a URI is "local" or not. More information about the domain module can be found at: &KAMAILIO_MOD_DOC;domain.html
@@ -35,6 +35,15 @@
         <natural/>
         <natural/>
     </column>
     </column>
 
 
+    <column id="did">
+        <name>did</name>
+        <type>string</type>
+        <size>&domain_len;</size>
+        <description>Domain id</description>
+        <default/>
+        <natural/>
+    </column>
+
     <column>
     <column>
         <name>last_modified</name>
         <name>last_modified</name>
         <type>datetime</type>
         <type>datetime</type>

+ 79 - 0
lib/srdb1/schema/domain_attrs.xml

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE table PUBLIC "-//kamailio.org//DTD DBSchema V1.1//EN" 
+  "http://kamailio.org/pub/kamailio/dbschema/dtd/1.1/dbschema.dtd" [
+
+<!ENTITY % entities SYSTEM "entities.xml">
+%entities;
+
+]>
+
+<table id="domain" xmlns:db="http://docbook.org/ns/docbook">
+    <name>domain_attrs</name>
+    <version>1</version>
+    <type db="mysql">&MYSQL_TABLE_TYPE;</type>
+    <description>
+        <db:para>This table contains attributes of domain ids. More information about the domain module can be found at: &KAMAILIO_MOD_DOC;domain.html
+        </db:para>
+    </description>
+
+    <column id="id">
+        <name>id</name>
+        <type>unsigned int</type>
+        <size>&table_id_len;</size>
+        <autoincrement/>
+        <primary/>
+        <type db="dbtext">int,auto</type>
+        <description>unique ID</description>
+    </column>
+
+    <column id="did">
+        <name>did</name>
+        <type>string</type>
+        <size>&domain_len;</size>
+        <description>Domain id</description>
+        <default/>
+        <natural/>
+    </column>
+
+    <column id="name">
+        <name>name</name>
+        <type>string</type>
+        <size>32</size>
+        <description>Name of attribute</description>
+        <default/>
+        <natural/>
+    </column>
+
+    <column id="type">
+        <name>type</name>
+        <type>unsigned int</type>
+        <description>Type of attribute (0=integer, 2=string)</description>
+        <default/>
+        <natural/>
+    </column>
+
+    <column id="value">
+        <name>value</name>
+        <type>string</type>
+        <size>255</size>
+        <description>Value of attribute</description>
+        <default/>
+        <natural/>
+    </column>
+
+    <column>
+        <name>last_modified</name>
+        <type>datetime</type>
+        <default>&DEFAULT_DATETIME;</default>
+        <default db="oracle">to_date('&DEFAULT_DATETIME;','yyyy-mm-dd hh24:mi:ss')</default>
+        <description>Date and time when this record was last modified.</description>
+    </column>
+
+    <index>
+        <name>domain_attrs_idx</name>
+        <colref linkend="did"/>
+        <colref linkend="name"/>
+        <colref linkend="value"/>
+        <unique/>
+    </index>
+</table>

+ 1 - 0
lib/srdb1/schema/kamailio-domain.xml

@@ -9,4 +9,5 @@
 <database xmlns:xi="http://www.w3.org/2001/XInclude">
 <database xmlns:xi="http://www.w3.org/2001/XInclude">
     <name>Domain</name>
     <name>Domain</name>
     <xi:include href="domain.xml"/>
     <xi:include href="domain.xml"/>
+    <xi:include href="domain_attrs.xml"/>
 </database>
 </database>

+ 129 - 56
modules_k/domain/README

@@ -10,7 +10,7 @@ Juha Heinanen
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2002-2008 Juha Heinanen
+   Copyright © 2002-2012 Juha Heinanen
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -22,16 +22,21 @@ Juha Heinanen
         3. Parameters
         3. Parameters
 
 
               3.1. db_url (string)
               3.1. db_url (string)
-              3.2. db_mode (integer)
-              3.3. domain_table (string)
-              3.4. domain_col (string)
-              3.5. register_myself (integer)
+              3.2. domain_table (string)
+              3.3. domain_attrs_table (string)
+              3.4. did_col (string)
+              3.5. domain_col (string)
+              3.6. name_col (string)
+              3.7. type_col (string)
+              3.8. value_col (string)
+              3.9. register_myself (integer)
 
 
         4. Functions
         4. Functions
 
 
               4.1. is_from_local()
               4.1. is_from_local()
               4.2. is_uri_host_local()
               4.2. is_uri_host_local()
               4.3. is_domain_local(pseudo_variable)
               4.3. is_domain_local(pseudo_variable)
+              4.4. lookup_domain(domain[, prefix])
 
 
         5. MI Commands
         5. MI Commands
 
 
@@ -54,13 +59,18 @@ Juha Heinanen
    List of Examples
    List of Examples
 
 
    1.1. Setting db_url parameter
    1.1. Setting db_url parameter
-   1.2. db_mode example
-   1.3. Setting domain_table parameter
-   1.4. Setting domain_col parameter
-   1.5. register_myself example
-   1.6. is_from_local usage
-   1.7. is_uri_host_local usage
-   1.8. is_domain_local usage
+   1.2. Setting domain_table parameter
+   1.3. Setting domain_attrs_table parameter
+   1.4. Setting did_col parameter
+   1.5. Setting domain_col parameter
+   1.6. Setting name_col parameter
+   1.7. Setting name_col parameter
+   1.8. Setting value_col parameter
+   1.9. register_myself example
+   1.10. is_from_local usage
+   1.11. is_uri_host_local usage
+   1.12. is_domain_local usage
+   1.13. lookup_domain
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -71,16 +81,21 @@ Chapter 1. Admin Guide
    3. Parameters
    3. Parameters
 
 
         3.1. db_url (string)
         3.1. db_url (string)
-        3.2. db_mode (integer)
-        3.3. domain_table (string)
-        3.4. domain_col (string)
-        3.5. register_myself (integer)
+        3.2. domain_table (string)
+        3.3. domain_attrs_table (string)
+        3.4. did_col (string)
+        3.5. domain_col (string)
+        3.6. name_col (string)
+        3.7. type_col (string)
+        3.8. value_col (string)
+        3.9. register_myself (integer)
 
 
    4. Functions
    4. Functions
 
 
         4.1. is_from_local()
         4.1. is_from_local()
         4.2. is_uri_host_local()
         4.2. is_uri_host_local()
         4.3. is_domain_local(pseudo_variable)
         4.3. is_domain_local(pseudo_variable)
+        4.4. lookup_domain(domain[, prefix])
 
 
    5. MI Commands
    5. MI Commands
 
 
@@ -97,17 +112,14 @@ Chapter 1. Admin Guide
 1. Overview
 1. Overview
 
 
    Domain module implements checks that based on domain table determine if
    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.
+   a domain is “local”. A “local” domain is one that the proxy is
+   responsible for. SIP URIs of local users must have hostpart that is
+   equal to one of these domains.
+
+   Domain module reads the contents of domain and domain_attrs tables into
+   cache memory when the module is loaded. Any changes in domain or
+   domain_attrs tables must thus be followed by “domain.reload” rpc
+   command in order to reflect them in module behavior.
 
 
    Caching is implemented using a hash table. The size of the hash table
    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
    is given by HASH_SIZE constant defined in domain_mod.h. Its “factory
@@ -122,10 +134,14 @@ Chapter 1. Admin Guide
 3. Parameters
 3. Parameters
 
 
    3.1. db_url (string)
    3.1. db_url (string)
-   3.2. db_mode (integer)
-   3.3. domain_table (string)
-   3.4. domain_col (string)
-   3.5. register_myself (integer)
+   3.2. domain_table (string)
+   3.3. domain_attrs_table (string)
+   3.4. did_col (string)
+   3.5. domain_col (string)
+   3.6. name_col (string)
+   3.7. type_col (string)
+   3.8. value_col (string)
+   3.9. register_myself (integer)
 
 
 3.1. db_url (string)
 3.1. db_url (string)
 
 
@@ -136,43 +152,80 @@ Chapter 1. Admin Guide
    Example 1.1. Setting db_url parameter
    Example 1.1. Setting db_url parameter
 modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
 modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
 
 
-3.2. db_mode (integer)
+3.2. domain_table (string)
+
+   Name of table containing names of local domains that the proxy is
+   responsible for.
 
 
-   Database mode: 0 means non-caching, 1 means caching.
+   Default value is “domain”.
 
 
-   Default value is 0 (non-caching).
+   Example 1.2. Setting domain_table parameter
+modparam("domain", "domain_table", "new_name")
 
 
-   Example 1.2. db_mode example
-modparam("domain", "db_mode", 1)   # Use caching
+3.3. domain_attrs_table (string)
 
 
-3.3. domain_table (string)
+   Name of table containing attributes of local domains.
 
 
-   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.
+   Default value is “domain_attrs”.
 
 
-   Default value is “domain”.
+   Example 1.3. Setting domain_attrs_table parameter
+modparam("domain", "domain_attrs_table", "local_domain_attributes")
 
 
-   Example 1.3. Setting domain_table parameter
-modparam("domain", "domain_table", "new_name")
+3.4. did_col (string)
 
 
-3.4. domain_col (string)
+   Name of column containing domain id (did) of domain in domain and
+   domain_attrs tables.
 
 
-   Name of column containing domains in domain table.
+   Default value is “did”.
+
+   Example 1.4. Setting did_col parameter
+modparam("domain", "did_col", "domain_did")
+
+3.5. domain_col (string)
+
+   Name of column containing domain name in domain table.
 
 
    Default value is “domain”.
    Default value is “domain”.
 
 
-   Example 1.4. Setting domain_col parameter
+   Example 1.5. Setting domain_col parameter
 modparam("domain", "domain_col", "domain_name")
 modparam("domain", "domain_col", "domain_name")
 
 
-3.5. register_myself (integer)
+3.6. name_col (string)
+
+   Name of column containing attribute name in domain_attrs table.
+
+   Default value is “name”.
+
+   Example 1.6. Setting name_col parameter
+modparam("domain", "name_col", "attr_name")
+
+3.7. type_col (string)
+
+   Name of column containing attribute type in domain_attrs table. Type
+   value 0 is integer and type value 2 is string.
+
+   Default value is “type”.
+
+   Example 1.7. Setting name_col parameter
+modparam("domain", "type_col", "attr_type")
+
+3.8. value_col (string)
+
+   Name of column containing attribute value in domain_attrs table.
+
+   Default value is “value”.
+
+   Example 1.8. Setting value_col parameter
+modparam("domain", "value_col", "attr_value")
+
+3.9. register_myself (integer)
 
 
    Register the list of domains to match 'myself' check: 0 means no myself
    Register the list of domains to match 'myself' check: 0 means no myself
    registration, 1 means enable myself registration.
    registration, 1 means enable myself registration.
 
 
    Default value is 0 (disable).
    Default value is 0 (disable).
 
 
-   Example 1.5. register_myself example
+   Example 1.9. register_myself example
 modparam("domain", "register_myself", 1)
 modparam("domain", "register_myself", 1)
 
 
 4. Functions
 4. Functions
@@ -180,15 +233,17 @@ modparam("domain", "register_myself", 1)
    4.1. is_from_local()
    4.1. is_from_local()
    4.2. is_uri_host_local()
    4.2. is_uri_host_local()
    4.3. is_domain_local(pseudo_variable)
    4.3. is_domain_local(pseudo_variable)
+   4.4. lookup_domain(domain[, prefix])
 
 
 4.1. is_from_local()
 4.1. is_from_local()
 
 
    Checks based on domain table if host part of From header uri is one of
    Checks based on domain table if host part of From header uri is one of
    the local domains that the proxy is responsible for
    the local domains that the proxy is responsible for
 
 
-   This function can be used from REQUEST_ROUTE.
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   BRANCH_ROUTE, and LOCAL_ROUTE.
 
 
-   Example 1.6. is_from_local usage
+   Example 1.10. is_from_local usage
 ...
 ...
 if (is_from_local()) {
 if (is_from_local()) {
         ...
         ...
@@ -204,9 +259,9 @@ if (is_from_local()) {
    to the transaction before is_uri_host_local() is called.
    to the transaction before is_uri_host_local() is called.
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-   BRANCH_ROUTE.
+   BRANCH_ROUTE, and LOCAL_ROUTE.
 
 
-   Example 1.7. is_uri_host_local usage
+   Example 1.11. is_uri_host_local usage
 ...
 ...
 if (is_uri_host_local()) {
 if (is_uri_host_local()) {
         ...
         ...
@@ -226,9 +281,9 @@ if (is_uri_host_local()) {
      * is_domain_local("$fd") is same as is_from_local()
      * is_domain_local("$fd") is same as is_from_local()
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-   BRANCH_ROUTE.
+   BRANCH_ROUTE, and LOCAL_ROUTE.
 
 
-   Example 1.8. is_domain_local usage
+   Example 1.12. is_domain_local usage
 ...
 ...
 if (is_domain_local("$rd")) {
 if (is_domain_local("$rd")) {
         ...
         ...
@@ -247,6 +302,24 @@ if (is_domain_local("$avp(s:some_avp)")) {
 };
 };
 ...
 ...
 
 
+4.4. lookup_domain(domain[, prefix])
+
+   This function checks if domain given in domain argument (pseudo
+   variable) is local and, if so, adds attributes associated with domain's
+   id (did) to AVPs. If prefix argument (string) is given, names of
+   attributes are prefixes by it. In addition to attributes given in
+   domain_attrs table, AVP did containing did of domain is added.
+
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   BRANCH_ROUTE, and LOCAL_ROUTE.
+
+   Example 1.13. lookup_domain
+...
+if (lookup_domain("$fd", "from_")) {
+    xlog("L_INFO", "did of domain $fd is $avp(from_did)\n");
+}
+...
+
 5. MI Commands
 5. MI Commands
 
 
    5.1. domain_reload
    5.1. domain_reload
@@ -308,8 +381,8 @@ if (is_domain_local("$avp(s:some_avp)")) {
 
 
 7. Known Limitations
 7. Known Limitations
 
 
-   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,
+   There is an unlikely race condition on domain reload. If a process uses
+   a table, which is reloaded at the same time twice through FIFO or RPC,
    the second reload will delete the original table still in use by the
    the second reload will delete the original table still in use by the
    process.
    process.
 
 

+ 1 - 1
modules_k/domain/doc/domain.xml

@@ -24,7 +24,7 @@
 	    </editor>
 	    </editor>
 	</authorgroup>
 	</authorgroup>
 	<copyright>
 	<copyright>
-	    <year>2002-2008</year>
+	    <year>2002-2012</year>
 	    <holder>Juha Heinanen</holder>
 	    <holder>Juha Heinanen</holder>
 	</copyright>
 	</copyright>
     </bookinfo>
     </bookinfo>

+ 120 - 34
modules_k/domain/doc/domain_admin.xml

@@ -16,26 +16,23 @@
 	<section>
 	<section>
 	<title>Overview</title>
 	<title>Overview</title>
 	<para>
 	<para>
-		Domain module implements checks that based on domain table determine 
-		if a host part of an <acronym>URI</acronym> is <quote>local</quote> or 
-		not.  A <quote>local</quote> domain is one that the proxy is responsible 
-		for.
+		Domain module implements checks that based on domain table
+		determine if a domain is <quote>local</quote>.
+		A <quote>local</quote> domain is one that the proxy is
+		responsible for.  SIP URIs of local users must have hostpart
+		that is equal to one of these domains.
 	</para>
 	</para>
 	<para>
 	<para>
-		Domain module operates in caching or non-caching mode depending on 
-		value of module parameter <parameter moreinfo="none">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 
-		<quote>domain_reload</quote> command in order to reflect them in 
-		module behavior. In non-caching mode domain module always queries domain
-		table in the database.
+		Domain module reads the contents of domain and domain_attrs
+		tables into cache memory when the module is loaded.
+		Any changes in domain or domain_attrs tables must thus be
+		followed by <quote>domain.reload</quote> rpc command in
+		order to reflect them in module behavior.
 	</para>
 	</para>
 	<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 <quote>factory default</quote> value is 128.
+		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 <quote>factory default</quote> value is 128.
 	</para>
 	</para>
 	</section>
 	</section>
 
 
@@ -71,41 +68,56 @@ modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
 		</example>
 		</example>
 	</section>
 	</section>
 	<section>
 	<section>
-		<title><varname>db_mode</varname> (integer)</title>
+		<title><varname>domain_table</varname> (string)</title>
 		<para>
 		<para>
-		Database mode: 0 means non-caching, 1 means caching.
+		Name of table containing names of local domains that the proxy is 
+		responsible for.
 		</para>
 		</para>
 		<para>
 		<para>
-		Default value is 0 (non-caching).
+		Default value is <quote>domain</quote>.
 		</para>
 		</para>
 		<example>
 		<example>
-		<title>db_mode example</title>
+		<title>Setting domain_table parameter</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
-modparam("domain", "db_mode", 1)   # Use caching
+modparam("domain", "domain_table", "new_name")
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
 	<section>
 	<section>
-		<title><varname>domain_table</varname> (string)</title>
+		<title><varname>domain_attrs_table</varname> (string)</title>
 		<para>
 		<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.
+		Name of table containing attributes of local domains.
 		</para>
 		</para>
 		<para>
 		<para>
-		Default value is <quote>domain</quote>.
+		Default value is <quote>domain_attrs</quote>.
 		</para>
 		</para>
 		<example>
 		<example>
-		<title>Setting domain_table parameter</title>
+		<title>Setting domain_attrs_table parameter</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
-modparam("domain", "domain_table", "new_name")
+modparam("domain", "domain_attrs_table", "local_domain_attributes")
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>did_col</varname> (string)</title>
+		<para>
+		Name of column containing domain id (did) of domain in domain
+		and domain_attrs tables.
+		</para>
+		<para>
+		Default value is <quote>did</quote>.
+		</para>
+		<example>
+		<title>Setting did_col parameter</title>
+		<programlisting format="linespecific">
+modparam("domain", "did_col", "domain_did")
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
 	<section>
 	<section>
 		<title><varname>domain_col</varname> (string)</title>
 		<title><varname>domain_col</varname> (string)</title>
 		<para>
 		<para>
-		Name of column containing domains in domain table.
+		Name of column containing domain name in domain table.
 		</para>
 		</para>
 		<para>
 		<para>
 		Default value is <quote>domain</quote>.
 		Default value is <quote>domain</quote>.
@@ -114,6 +126,52 @@ modparam("domain", "domain_table", "new_name")
 		<title>Setting domain_col parameter</title>
 		<title>Setting domain_col parameter</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 modparam("domain", "domain_col", "domain_name")
 modparam("domain", "domain_col", "domain_name")
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>name_col</varname> (string)</title>
+		<para>
+		Name of column containing attribute name in domain_attrs table.
+		</para>
+		<para>
+		Default value is <quote>name</quote>.
+		</para>
+		<example>
+		<title>Setting name_col parameter</title>
+		<programlisting format="linespecific">
+modparam("domain", "name_col", "attr_name")
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>type_col</varname> (string)</title>
+		<para>
+		Name of column containing attribute type in domain_attrs table.
+		Type value 0 is integer and type value 2 is string.
+		</para>
+		<para>
+		Default value is <quote>type</quote>.
+		</para>
+		<example>
+		<title>Setting name_col parameter</title>
+		<programlisting format="linespecific">
+modparam("domain", "type_col", "attr_type")
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>value_col</varname> (string)</title>
+		<para>
+		Name of column containing attribute value in domain_attrs table.
+		</para>
+		<para>
+		Default value is <quote>value</quote>.
+		</para>
+		<example>
+		<title>Setting value_col parameter</title>
+		<programlisting format="linespecific">
+modparam("domain", "value_col", "attr_value")
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
@@ -146,7 +204,8 @@ modparam("domain", "register_myself", 1)
 		one of the local domains that the proxy is responsible for
 		one of the local domains that the proxy is responsible for
 		</para>
 		</para>
 		<para>
 		<para>
-		This function can be used from REQUEST_ROUTE.
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+		BRANCH_ROUTE, and LOCAL_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
 		<title>is_from_local usage</title>
 		<title>is_from_local usage</title>
@@ -172,7 +231,7 @@ if (is_from_local()) {
 		</para>
 		</para>
 		<para>
 		<para>
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-		BRANCH_ROUTE.
+		BRANCH_ROUTE, and LOCAL_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
 		<title>is_uri_host_local usage</title>
 		<title>is_uri_host_local usage</title>
@@ -208,7 +267,7 @@ if (is_uri_host_local()) {
 		</itemizedlist>
 		</itemizedlist>
 		<para>
 		<para>
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-		BRANCH_ROUTE.
+		BRANCH_ROUTE, and LOCAL_ROUTE.
 		</para>
 		</para>
 		<example>
 		<example>
 		<title>is_domain_local usage</title>
 		<title>is_domain_local usage</title>
@@ -229,6 +288,32 @@ if (is_domain_local("$avp(i:850)")) {
 if (is_domain_local("$avp(s:some_avp)")) {
 if (is_domain_local("$avp(s:some_avp)")) {
 	...
 	...
 };
 };
+...
+		</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><function moreinfo="none">lookup_domain(domain[, prefix])</function></title>
+		<para>
+		This function checks if domain given in
+		domain argument (pseudo variable) is local and, if so,
+		adds attributes
+		associated with domain's id (did) to AVPs.  If prefix
+		argument (string) is given, names of attributes are prefixes by
+		it.  In addition to attributes given in domain_attrs
+		table, AVP did containing did of domain is added.
+		</para>
+		<para>
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+		BRANCH_ROUTE, and LOCAL_ROUTE.
+		</para>
+		<example>
+		<title>lookup_domain</title>
+		<programlisting format="linespecific">
+...
+if (lookup_domain("$fd", "from_")) {
+    xlog("L_INFO", "did of domain $fd is $avp(from_did)\n");
+}
 ...
 ...
 		</programlisting>
 		</programlisting>
 		</example>
 		</example>
@@ -314,9 +399,10 @@ if (is_domain_local("$avp(s:some_avp)")) {
 	<section>
 	<section>
 	<title>Known Limitations</title>
 	<title>Known Limitations</title>
 	<para>
 	<para>
-		There is an unlikely race condition on domain list update.  If a 
+		There is an unlikely race condition on domain reload.  If a 
 		process uses a table, which is reloaded at the same time twice 
 		process uses a table, which is reloaded at the same time twice 
-		through <acronym>FIFO</acronym>, the second reload will delete the 
+		through <acronym>FIFO</acronym> or <acronym>RPC</acronym>,
+		the second reload will delete the  
 		original table still in use by the process.
 		original table still in use by the process.
 	</para>
 	</para>
 	</section>
 	</section>

+ 309 - 122
modules_k/domain/domain.c

@@ -3,7 +3,7 @@
  *
  *
  * Domain table related functions
  * Domain table related functions
  *
  *
- * Copyright (C) 2002-2003 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -96,53 +96,15 @@ int domain_db_ver(str* name, int version)
 }
 }
 
 
 
 
-
 /*
 /*
  * Check if domain is local
  * Check if domain is local
  */
  */
 int is_domain_local(str* _host)
 int is_domain_local(str* _host)
 {
 {
-	if (db_mode == 0) {
-		db_key_t keys[1];
-		db_val_t vals[1];
-		db_key_t cols[1]; 
-		db1_res_t* res = NULL;
-
-		keys[0] = &domain_col;
-		cols[0] = &domain_col;
-		
-		if (domain_dbf.use_table(db_handle, &domain_table) < 0) {
-			LM_ERR("Error while trying to use domain table\n");
-			return -1;
-		}
-
-		VAL_TYPE(vals) = DB1_STR;
-		VAL_NULL(vals) = 0;
-		
-		VAL_STR(vals).s = _host->s;
-		VAL_STR(vals).len = _host->len;
-
-		if (domain_dbf.query(db_handle, keys, 0, vals, cols, 1, 1, 0, &res) < 0
-				) {
-			LM_ERR("Error while querying database\n");
-			return -1;
-		}
+    str did;
+    struct attr_list *attrs;
 
 
-		if (RES_ROW_N(res) == 0) {
-			LM_DBG("Realm '%.*s' is not local\n", 
-			       _host->len, ZSW(_host->s));
-			domain_dbf.free_result(db_handle, res);
-			return -1;
-		} else {
-			LM_DBG("Realm '%.*s' is local\n", 
-			       _host->len, ZSW(_host->s));
-			domain_dbf.free_result(db_handle, res);
-			return 1;
-		}
-	} else {
-		return hash_table_lookup (_host);
-	}
-			
+    return hash_table_lookup(_host, &did, &attrs);
 }
 }
 
 
 /*
 /*
@@ -151,14 +113,15 @@ int is_domain_local(str* _host)
 int is_from_local(struct sip_msg* _msg, char* _s1, char* _s2)
 int is_from_local(struct sip_msg* _msg, char* _s1, char* _s2)
 {
 {
 	struct sip_uri *puri;
 	struct sip_uri *puri;
+	str did;
+	struct attr_list *attrs;
 
 
 	if ((puri=parse_from_uri(_msg))==NULL) {
 	if ((puri=parse_from_uri(_msg))==NULL) {
 		LM_ERR("Error while parsing From header\n");
 		LM_ERR("Error while parsing From header\n");
 		return -2;
 		return -2;
 	}
 	}
 
 
-	return is_domain_local(&(puri->host));
-
+	return hash_table_lookup(&(puri->host), &did, &attrs);
 }
 }
 
 
 /*
 /*
@@ -166,133 +129,357 @@ int is_from_local(struct sip_msg* _msg, char* _s1, char* _s2)
  */
  */
 int is_uri_host_local(struct sip_msg* _msg, char* _s1, char* _s2)
 int is_uri_host_local(struct sip_msg* _msg, char* _s1, char* _s2)
 {
 {
-	str branch;
-	qvalue_t q;
-	struct sip_uri puri;
-
-	if ( is_route_type(REQUEST_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE) ) {
-		if (parse_sip_msg_uri(_msg) < 0) {
-			LM_ERR("Error while parsing R-URI\n");
-			return -1;
-		}
-		return is_domain_local(&(_msg->parsed_uri.host));
-	} else if (is_route_type(FAILURE_ROUTE)) {
-			branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0);
-			if (branch.s) {
-				if (parse_uri(branch.s, branch.len, &puri) < 0) {
-					LM_ERR("Error while parsing branch URI\n");
-					return -1;
-				}
-				return is_domain_local(&(puri.host));
-			} else {
-				LM_ERR("Branch is missing, error in script\n");
-				return -1;
-			}
-	} else {
-		LM_ERR("Unsupported route type\n");
+    str branch;
+    qvalue_t q;
+    struct sip_uri puri;
+    struct attr_list *attrs;
+    str did;
+
+    if ( is_route_type(REQUEST_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE) ) {
+	if (parse_sip_msg_uri(_msg) < 0) {
+	    LM_ERR("error while parsing R-URI\n");
+	    return -1;
+	}
+	return hash_table_lookup(&(_msg->parsed_uri.host), &did, &attrs);
+    } else if (is_route_type(FAILURE_ROUTE)) {
+	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0);
+	if (branch.s) {
+	    if (parse_uri(branch.s, branch.len, &puri) < 0) {
+		LM_ERR("error while parsing branch URI\n");
 		return -1;
 		return -1;
+	    }
+	    return hash_table_lookup(&(puri.host), &did, &attrs);
+	} else {
+	    LM_ERR("branch is missing, error in script\n");
+	    return -1;
 	}
 	}
+    } else {
+	LM_ERR("unsupported route type\n");
+	return -1;
+    }
 }
 }
 
 
 
 
 /*
 /*
- * Check if domain given as value of pseudo variable parameter is local
+ * Check if domain given as value of pseudo variable parameter is local.
  */
  */
 int w_is_domain_local(struct sip_msg* _msg, char* _sp, char* _s2)
 int w_is_domain_local(struct sip_msg* _msg, char* _sp, char* _s2)
 {
 {
     pv_spec_t *sp;
     pv_spec_t *sp;
     pv_value_t pv_val;
     pv_value_t pv_val;
+    struct attr_list *attrs;
+    str did;
 
 
     sp = (pv_spec_t *)_sp;
     sp = (pv_spec_t *)_sp;
 
 
     if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
     if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
 	if (pv_val.flags & PV_VAL_STR) {
 	if (pv_val.flags & PV_VAL_STR) {
 	    if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
 	    if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
-		LM_DBG("Missing domain name\n");
+		LM_DBG("missing domain name\n");
 		return -1;
 		return -1;
 	    }
 	    }
-	    return is_domain_local(&(pv_val.rs));
+	    return hash_table_lookup(&(pv_val.rs), &did, &attrs);
 	} else {
 	} else {
-	   LM_DBG("Pseudo variable value is not string\n");
+	   LM_DBG("domain pseudo variable value is not string\n");
 	   return -1;
 	   return -1;
 	}
 	}
     } else {
     } else {
-	LM_DBG("Cannot get pseudo variable value\n");
+	LM_DBG("cannot get domain pseudo variable value\n");
 	return -1;
 	return -1;
     }
     }
 }
 }
 
 
-int domain_check_self(str* host, unsigned short port, unsigned short proto)
+/*
+ * Check if domain is local and, if it is, add attributes as AVPs
+ */
+int w_lookup_domain(struct sip_msg* _msg, char* _sp, char* _prefix)
 {
 {
-	if(is_domain_local(host)>0)
+    pv_spec_t *sp;
+    pv_value_t pv_val;
+    int_str name, val;
+    struct attr_list *attrs;
+    str *prefix, did;
+    unsigned short flags;
+
+    sp = (pv_spec_t *)_sp;
+    prefix = (str *)_prefix;
+
+    if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
+	if (pv_val.flags & PV_VAL_STR) {
+	    if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
+		LM_DBG("domain name pseudo variable is missing\n");
+		return -1;
+	    }
+	    if (hash_table_lookup(&(pv_val.rs), &did, &attrs) == 1) {
+		while (attrs) {
+		    if (attrs->type == 2)
+			flags = AVP_NAME_STR | AVP_VAL_STR;
+		    else
+			flags = AVP_NAME_STR;
+		    if (_prefix) {
+			name.s.len = prefix->len + attrs->name.len;
+			name.s.s = pkg_malloc(name.s.len);
+			if (name.s.s == NULL) {
+			    ERR("no pkg memory for avp name\n");
+			    return -1;
+			}
+			memcpy(name.s.s, prefix->s, prefix->len);
+			memcpy(name.s.s + prefix->len, attrs->name.s,
+			       attrs->name.len);
+		    } else {
+			name.s = attrs->name;
+		    }
+		    if (add_avp(flags, name, attrs->val) < 0) {
+			LM_ERR("unable to add a new AVP '%.*s'\n",
+			       name.s.len, name.s.s);
+			if (_prefix) pkg_free(name.s.s);
+			return -1;
+		    }
+		    LM_DBG("added AVP '%.*s'\n", name.s.len, name.s.s);
+		    if (prefix) pkg_free(name.s.s);
+		    attrs = attrs->next;
+		}
+		flags = AVP_NAME_STR | AVP_VAL_STR;
+		if (_prefix) {
+		    name.s.len = prefix->len + 3;
+		    name.s.s = pkg_malloc(name.s.len);
+		    if (name.s.s == NULL) {
+			ERR("no pkg memory for avp name\n");
+			return -1;
+		    }
+		    memcpy(name.s.s, prefix->s, prefix->len);
+		    memcpy(name.s.s + prefix->len, "did", 3);
+		} else {
+		    name.s.s = "did";
+		    name.s.len = 3;
+		}
+		val.s = did;
+		if (add_avp(flags, name, val) < 0) {
+		    LM_ERR("unable to add a new AVP '%.*s'\n",
+			   name.s.len, name.s.s);
+		    if (_prefix) pkg_free(name.s.s);
+		    return -1;
+		}		
+		LM_DBG("added AVP '%.*s'\n", name.s.len, name.s.s);
+		if (_prefix) pkg_free(name.s.s);
 		return 1;
 		return 1;
-	return 0;
+	    } else {
+		return -1;
+	    }
+	} else {
+	   LM_DBG("domain name pseudo variable value is not string\n");
+	   return -1;
+	}
+    } else {
+	LM_DBG("cannot get domain name pseudo variable value\n");
+	return -1;
+    }
+}
+
+/*
+ * Check if domain is local and, if it is, add attributes as AVPs
+ */
+int w_lookup_domain_no_prefix(struct sip_msg* _msg, char* _domain, char* _str)
+{
+    return w_lookup_domain(_msg, _domain, NULL);
+}
+
+int domain_check_self(str* host, unsigned short port, unsigned short proto)
+{
+    struct attr_list *attrs;
+    str did;
+    if (hash_table_lookup(host, &did, &attrs) > 0)
+	return 1;
+    return 0;
 }
 }
 
 
 /*
 /*
  * Reload domain table to new hash table and when done, make new hash table
  * Reload domain table to new hash table and when done, make new hash table
  * current one.
  * current one.
  */
  */
-int reload_domain_table ( void )
+int reload_tables ( void )
 {
 {
-	db_val_t vals[1];
-	db_key_t cols[1];
-	db1_res_t* res = NULL;
-	db_row_t* row;
-	db_val_t* val;
+    db_key_t cols[4];
+    db1_res_t* res = NULL;
+    db_row_t* row;
+    struct domain_list **new_hash_table;
+    int i;
+    short type;
+    str did, domain, name, value;
+    int_str val;
+
+    /* Choose new hash table and free its old contents */
+    if (*hash_table == hash_table_1) {
+	LM_INFO("new hash table is 2\n");
+	hash_table_free(hash_table_2);
+	new_hash_table = hash_table_2;
+    } else {
+	LM_INFO("new hash table is 1\n");
+	hash_table_free(hash_table_1);
+	new_hash_table = hash_table_1;
+    }
 
 
-	struct domain_list **new_hash_table;
-	int i;
+    cols[0] = &did_col;
+    cols[1] = &name_col;
+    cols[2] = &type_col;
+    cols[3] = &value_col;
 
 
-	cols[0] = &domain_col;
+    if (domain_db_init(&db_url) < 0) {
+	LM_ERR("unable to open database connection\n");
+	return -1;
+    }
 
 
-	if (domain_dbf.use_table(db_handle, &domain_table) < 0) {
-		LM_ERR("Error while trying to use domain table\n");
-		return -1;
+    if (domain_dbf.use_table(db_handle, &domain_attrs_table) < 0) {
+	LM_ERR("error while trying to use domain_attrs table\n");
+	goto err;
+    }
+
+    if (domain_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 4, 0, &res) < 0) {
+	LM_ERR("error while querying database\n");
+	goto err;
+    }
+
+    row = RES_ROWS(res);
+
+    LM_DBG("number of rows in domain_attrs table: %d\n", RES_ROW_N(res));
+    
+    for (i = 0; i < RES_ROW_N(res); i++) {
+
+	row = RES_ROWS(res) + i;
+
+	if ((VAL_NULL(ROW_VALUES(row)) == 1) ||
+	    (VAL_TYPE(ROW_VALUES(row)) != DB1_STRING)) {
+	    LM_ERR("did at row <%u> is null or not string\n", i);
+	    goto err;
+	}
+	did.s = (char *)VAL_STRING(ROW_VALUES(row));
+	did.len = strlen(did.s);
+	if (did.len == 0) {
+	    LM_ERR("did at row <%u> is empty string\n", i);
+	    goto err;
 	}
 	}
 
 
-	VAL_TYPE(vals) = DB1_STR;
-	VAL_NULL(vals) = 0;
+	if ((VAL_NULL(ROW_VALUES(row) + 1) == 1) ||
+	    (VAL_TYPE(ROW_VALUES(row) + 1) != DB1_STRING)) {
+	    LM_ERR("name at row <%u> is null or not string\n", i);
+	    goto err;
+	}
+	name.s = (char *)VAL_STRING(ROW_VALUES(row) + 1);
+	name.len = strlen(name.s);
+	if (name.len == 0) {
+	    LM_ERR("name at row <%u> is empty string\n", i);
+	    goto err;
+	}
 
 
-	if (domain_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 1, 0, &res) < 0) {
-		LM_ERR("Error while querying database\n");
-		return -1;
+	if ((VAL_NULL(ROW_VALUES(row) + 2) == 1) ||
+	    (VAL_TYPE(ROW_VALUES(row) + 2) != DB1_INT)) {
+	    LM_ERR("type at row <%u> is null or not int\n", i);
+	    goto err;
+	}
+	type = (int)VAL_INT(ROW_VALUES(row) + 2);
+	if ((type != 0) && (type != 2)) {
+	    LM_ERR("unknown type <%d> at row <%u>\n", type, i);
+	    goto err;
 	}
 	}
 
 
-	/* Choose new hash table and free its old contents */
-	if (*hash_table == hash_table_1) {
-		hash_table_free(hash_table_2);
-		new_hash_table = hash_table_2;
-	} else {
-		hash_table_free(hash_table_1);
-		new_hash_table = hash_table_1;
+	if ((VAL_NULL(ROW_VALUES(row) + 3) == 1) ||
+	    (VAL_TYPE(ROW_VALUES(row) + 3) != DB1_STRING)) {
+	    LM_ERR("value at row <%u> is null or not string\n", i);
+	    goto err;
 	}
 	}
+	value.s = (char *)VAL_STRING(ROW_VALUES(row) + 3);
+	value.len = strlen(value.s);
 
 
-	row = RES_ROWS(res);
+	if (type == 0) {
+	    if (str2sint(&value, &(val.n)) == -1) {
+		LM_ERR("value at row <%u> is invalid int\n", i);
+		goto err;
+	    }
+	} else {
+	    val.s = value;
+	}
 
 
-	LM_DBG("Number of rows in domain table: %d\n", RES_ROW_N(res));
+	if (type == 0) 
+	    LM_DBG("inserting <did/name/type/value> = <%s/%s/%d/%d> into attribute list\n", did.s, name.s, type, val.n);
+	else
+	    LM_DBG("inserting <did/name/type/value> = <%s/%s/%d/%s> into attribute list\n", did.s, name.s, type, val.s.s);
 		
 		
-	for (i = 0; i < RES_ROW_N(res); i++) {
-		val = ROW_VALUES(row + i);
-		if ((ROW_N(row) == 1) && (VAL_TYPE(val) == DB1_STRING)) {
-			
-			LM_DBG("Value: %s inserted into domain hash table\n",VAL_STRING(val));
-
-			if (hash_table_install(new_hash_table,(char*)VAL_STRING(val))==-1){
-				LM_ERR("Hash table problem\n");
-				domain_dbf.free_result(db_handle, res);
-				return -1;
-			}
-		} else {
-			LM_ERR("Database problem\n");
-			domain_dbf.free_result(db_handle, res);
-			return -1;
-		}
+	if (hash_table_attr_install(new_hash_table, &did, &name, type,
+				    &val) == -1) {
+	    LM_ERR("could not install attribute into hash table\n");
+	    goto err;
 	}
 	}
-	domain_dbf.free_result(db_handle, res);
+    }
+
+    domain_dbf.free_result(db_handle, res);
+    res = NULL;
 
 
-	*hash_table = new_hash_table;
+    cols[0] = &did_col;
+    cols[1] = &domain_col;
+    
+    if (domain_dbf.use_table(db_handle, &domain_table) < 0) {
+	LM_ERR("error while trying to use domain table\n");
+	goto err;
+    }
+
+    if (domain_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 2, 0, &res) < 0) {
+	LM_ERR("error while querying database\n");
+	goto err;
+    }
+
+    row = RES_ROWS(res);
+
+    LM_DBG("number of rows in domain table: %d\n", RES_ROW_N(res));
+		
+    for (i = 0; i < RES_ROW_N(res); i++) {
 	
 	
-	return 1;
-}
+	row = RES_ROWS(res) + i;
+
+	if ((VAL_NULL(ROW_VALUES(row)) == 1) ||
+	    (VAL_TYPE(ROW_VALUES(row)) != DB1_STRING)) {
+	    LM_ERR("did at row <%u> is null or not string\n", i);
+	    goto err;
+	}
+	did.s = (char *)VAL_STRING(ROW_VALUES(row));
+	did.len = strlen(did.s);
+	if (did.len == 0) {
+	    LM_ERR("did at row <%u> is empty string\n", i);
+	    goto err;
+	}
+
+	if ((VAL_NULL(ROW_VALUES(row) + 1) == 1) ||
+	    (VAL_TYPE(ROW_VALUES(row) + 1) != DB1_STRING)) {
+	    LM_ERR("domain at row <%u> is null or not string\n", i);
+	    goto err;
+	}
+	domain.s = (char *)VAL_STRING(ROW_VALUES(row) + 1);
+	domain.len = strlen(domain.s);
+	if (domain.len == 0) {
+	    LM_ERR("domain at row <%u> is empty string\n", i);
+	    goto err;
+	}
 
 
+	LM_INFO("inserting <did/domain> = <%s/%s> into hash table\n",
+	       did.s, domain.s);
+
+	if (hash_table_install(new_hash_table, &did, &domain) == -1) {
+	    LM_ERR("could not install domain into hash table\n");
+	    domain_dbf.free_result(db_handle, res);
+	    goto err;
+	}
+    }
+
+    domain_dbf.free_result(db_handle, res);
+    res = NULL;
+    
+    *hash_table = new_hash_table;
+
+    domain_db_close();
+    return 1;
+
+ err:
+    domain_dbf.free_result(db_handle, res);
+    res = NULL;
+    domain_db_close();
+    return -1;
+}

+ 5 - 2
modules_k/domain/domain.h

@@ -2,7 +2,7 @@
  *
  *
  * Header file for domain table relates functions
  * Header file for domain table relates functions
  *
  *
- * Copyright (C) 2002-2003 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -52,6 +52,9 @@ int is_uri_host_local(struct sip_msg* _msg, char* _s1, char* _s2);
  */
  */
 int w_is_domain_local(struct sip_msg* _msg, char* _s1, char* _s2);
 int w_is_domain_local(struct sip_msg* _msg, char* _s1, char* _s2);
 
 
+int w_lookup_domain(struct sip_msg* _msg, char* _s1, char* _s2);
+int w_lookup_domain_no_prefix(struct sip_msg* _msg, char* _s1, char* _s2);
+
 int is_domain_local(str* domain);
 int is_domain_local(str* domain);
 
 
 int domain_check_self(str* host, unsigned short port, unsigned short proto);
 int domain_check_self(str* host, unsigned short port, unsigned short proto);
@@ -61,6 +64,6 @@ int domain_db_init(const str* db_url);
 void domain_db_close(void);
 void domain_db_close(void);
 int domain_db_ver(str* name, int version);
 int domain_db_ver(str* name, int version);
 
 
-int reload_domain_table(void);
+int reload_tables(void);
 
 
 #endif /* DOMAIN_H */
 #endif /* DOMAIN_H */

+ 195 - 156
modules_k/domain/domain_mod.c

@@ -3,7 +3,7 @@
  *
  *
  * Domain module
  * Domain module
  *
  *
- * Copyright (C) 2002-2008 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -48,6 +48,7 @@
 #include "mi.h"
 #include "mi.h"
 #include "hash.h"
 #include "hash.h"
 #include "api.h"
 #include "api.h"
+#include "../../locking.h"
 
 
 /*
 /*
  * Module management function prototypes
  * Module management function prototypes
@@ -55,7 +56,6 @@
 static int mod_init(void);
 static int mod_init(void);
 static void destroy(void);
 static void destroy(void);
 static int child_init(int rank);
 static int child_init(int rank);
-static int mi_child_init(void);
 
 
 MODULE_VERSION
 MODULE_VERSION
 
 
@@ -64,23 +64,43 @@ MODULE_VERSION
  * increment this value if you change the table in
  * increment this value if you change the table in
  * an backwards incompatible way
  * an backwards incompatible way
  */
  */
-#define TABLE_VERSION 1
+#define DOMAIN_TABLE_VERSION 2
+#define DOMAIN_ATTRS_TABLE_VERSION 1
 
 
 #define DOMAIN_TABLE "domain"
 #define DOMAIN_TABLE "domain"
 #define DOMAIN_TABLE_LEN (sizeof(DOMAIN_TABLE) - 1)
 #define DOMAIN_TABLE_LEN (sizeof(DOMAIN_TABLE) - 1)
 
 
+#define DOMAIN_ATTRS_TABLE "domain_attrs"
+#define DOMAIN_ATTRS_TABLE_LEN (sizeof(DOMAIN_ATTRS_TABLE) - 1)
+
+#define DID_COL "did"
+#define DID_COL_LEN (sizeof(DID_COL) - 1)
+
 #define DOMAIN_COL "domain"
 #define DOMAIN_COL "domain"
 #define DOMAIN_COL_LEN (sizeof(DOMAIN_COL) - 1)
 #define DOMAIN_COL_LEN (sizeof(DOMAIN_COL) - 1)
 
 
+#define NAME_COL "name"
+#define NAME_COL_LEN (sizeof(NAME_COL) - 1)
+
+#define TYPE_COL "type"
+#define TYPE_COL_LEN (sizeof(TYPE_COL) - 1)
+
+#define VALUE_COL "value"
+#define VALUE_COL_LEN (sizeof(VALUE_COL) - 1)
+
 static int domain_init_rpc(void);
 static int domain_init_rpc(void);
 
 
 /*
 /*
  * Module parameter variables
  * Module parameter variables
  */
  */
-static str db_url = {DEFAULT_RODB_URL, DEFAULT_RODB_URL_LEN};
-int db_mode = 0;			/* Database usage mode: 0 = no cache, 1 = cache */
+str db_url = {DEFAULT_RODB_URL, DEFAULT_RODB_URL_LEN};
 str domain_table = {DOMAIN_TABLE, DOMAIN_TABLE_LEN}; /* Name of domain table */
 str domain_table = {DOMAIN_TABLE, DOMAIN_TABLE_LEN}; /* Name of domain table */
+str domain_attrs_table = {DOMAIN_ATTRS_TABLE, DOMAIN_ATTRS_TABLE_LEN};
+str did_col = {DID_COL, DID_COL_LEN};       /* Name of domain id column */
 str domain_col = {DOMAIN_COL, DOMAIN_COL_LEN};       /* Name of domain column */
 str domain_col = {DOMAIN_COL, DOMAIN_COL_LEN};       /* Name of domain column */
+str name_col = {NAME_COL, NAME_COL_LEN};   /* Name of attribute name column */
+str type_col = {TYPE_COL, TYPE_COL_LEN};   /* Name of attribute type column */
+str value_col = {VALUE_COL, VALUE_COL_LEN}; /* Name of attribute value column */
 int domain_reg_myself = 0;
 int domain_reg_myself = 0;
 
 
 /*
 /*
@@ -89,7 +109,7 @@ int domain_reg_myself = 0;
 struct domain_list ***hash_table = 0;	/* Pointer to current hash table pointer */
 struct domain_list ***hash_table = 0;	/* Pointer to current hash table pointer */
 struct domain_list **hash_table_1 = 0;	/* Pointer to hash table 1 */
 struct domain_list **hash_table_1 = 0;	/* Pointer to hash table 1 */
 struct domain_list **hash_table_2 = 0;	/* Pointer to hash table 2 */
 struct domain_list **hash_table_2 = 0;	/* Pointer to hash table 2 */
-
+gen_lock_t *reload_lock;
 
 
 /*
 /*
  * Exported functions
  * Exported functions
@@ -102,6 +122,12 @@ static cmd_export_t cmds[] = {
 	{"is_domain_local", (cmd_function)w_is_domain_local, 1, fixup_pvar_null,
 	{"is_domain_local", (cmd_function)w_is_domain_local, 1, fixup_pvar_null,
 	 fixup_free_pvar_null,
 	 fixup_free_pvar_null,
 	 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
 	 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+	{"lookup_domain", (cmd_function)w_lookup_domain_no_prefix, 1,
+	 fixup_pvar_null, fixup_free_pvar_null,
+	 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
+	{"lookup_domain", (cmd_function)w_lookup_domain, 2, fixup_pvar_str,
+	 fixup_free_pvar_str,
+	 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
 	{"bind_domain", (cmd_function)bind_domain, 0, 0, 0, 0},
 	{"bind_domain", (cmd_function)bind_domain, 0, 0, 0, 0},
 	{0, 0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0, 0}
 };
 };
@@ -112,9 +138,12 @@ static cmd_export_t cmds[] = {
  */
  */
 static param_export_t params[] = {
 static param_export_t params[] = {
 	{"db_url",         STR_PARAM, &db_url.s      },
 	{"db_url",         STR_PARAM, &db_url.s      },
-	{"db_mode",        INT_PARAM, &db_mode       },
 	{"domain_table",   STR_PARAM, &domain_table.s},
 	{"domain_table",   STR_PARAM, &domain_table.s},
+	{"did_col",        STR_PARAM, &did_col.s  },
 	{"domain_col",     STR_PARAM, &domain_col.s  },
 	{"domain_col",     STR_PARAM, &domain_col.s  },
+	{"name_col",       STR_PARAM, &name_col.s  },
+	{"type_col",       STR_PARAM, &type_col.s  },
+	{"value_col",      STR_PARAM, &value_col.s  },
 	{"register_myself",INT_PARAM, &domain_reg_myself},
 	{"register_myself",INT_PARAM, &domain_reg_myself},
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
@@ -124,9 +153,9 @@ static param_export_t params[] = {
  * Exported MI functions
  * Exported MI functions
  */
  */
 static mi_export_t mi_cmds[] = {
 static mi_export_t mi_cmds[] = {
-	{ MI_DOMAIN_RELOAD, mi_domain_reload, MI_NO_INPUT_FLAG, 0, mi_child_init },
-	{ MI_DOMAIN_DUMP,   mi_domain_dump,   MI_NO_INPUT_FLAG, 0, 0             },
-	{ 0, 0, 0, 0, 0}
+    { MI_DOMAIN_RELOAD, mi_domain_reload, MI_NO_INPUT_FLAG, 0, 0 },
+    { MI_DOMAIN_DUMP,   mi_domain_dump,   MI_NO_INPUT_FLAG, 0, 0 },
+    { 0, 0, 0, 0, 0}
 };
 };
 
 
 
 
@@ -151,130 +180,133 @@ struct module_exports exports = {
 
 
 static int mod_init(void)
 static int mod_init(void)
 {
 {
-	int i;
-
-	LM_DBG("Initializing\n");
+    LM_DBG("initializing\n");
 	
 	
-	if(register_mi_mod(exports.name, mi_cmds)!=0)
-	{
-		LM_ERR("failed to register MI commands\n");
-		return -1;
-	}
-	if(domain_init_rpc()!=0)
-	{
-		LM_ERR("failed to register RPC commands\n");
-		return -1;
-	}
+    if (register_mi_mod(exports.name, mi_cmds) != 0) {
+	LM_ERR("failed to register MI commands\n");
+	return -1;
+    }
+    if (domain_init_rpc() != 0) {
+	LM_ERR("failed to register RPC commands\n");
+	return -1;
+    }
 
 
-	if(domain_reg_myself!=0)
-	{
-		if(register_check_self_func(domain_check_self)<0)
-		{
-			LM_ERR("failed to register check self function\n");
-			return -1;
-		}
+    if (domain_reg_myself !=0 ) {
+	if (register_check_self_func(domain_check_self) <0 ) {
+	    LM_ERR("failed to register check self function\n");
+	    return -1;
 	}
 	}
+    }
+
+    db_url.len = strlen(db_url.s);
+    domain_table.len = strlen(domain_table.s);
+    did_col.len = strlen(did_col.s);
+    domain_col.len = strlen(domain_col.s);
+    name_col.len = strlen(name_col.s);
+    type_col.len = strlen(type_col.s);
+    value_col.len = strlen(value_col.s);
+
+    /* Bind database */
+    if (domain_db_bind(&db_url)) {
+	LM_ERR("no database module found\n");
+	return -1;
+    }
 
 
-	db_url.len = strlen(db_url.s);
-	domain_table.len = strlen(domain_table.s);
-	domain_col.len = strlen(domain_col.s);
-
-	/* Check if database module has been loaded */
-	if (domain_db_bind(&db_url) < 0)  return -1;
-
-	/* Check if cache needs to be loaded from domain table */
-	if (db_mode != 0) {
-
-		if (domain_db_init(&db_url)<0) return -1;
-
-		/* Check table version */
-		if (domain_db_ver(&domain_table, TABLE_VERSION) < 0) {
-		    LM_ERR("error during check of domain table version\n");
-		    goto error;
-		}
-
-		/* Initializing hash tables and hash table variable */
-		hash_table_1 = (struct domain_list **)shm_malloc
-			(sizeof(struct domain_list *) * DOM_HASH_SIZE);
-		if (hash_table_1 == 0) {
-			LM_ERR("No memory for hash table\n");
-			goto error;
-		}
-
-		hash_table_2 = (struct domain_list **)shm_malloc
-			(sizeof(struct domain_list *) * DOM_HASH_SIZE);
-		if (hash_table_2 == 0) {
-			LM_ERR("No memory for hash table\n");
-			goto error;
-		}
-		for (i = 0; i < DOM_HASH_SIZE; i++) {
-			hash_table_1[i] = hash_table_2[i] = (struct domain_list *)0;
-		}
-
-		hash_table = (struct domain_list ***)shm_malloc
-			(sizeof(struct domain_list *));
-		*hash_table = hash_table_1;
-
-		if (reload_domain_table() == -1) {
-			LM_ERR("Domain table reload failed\n");
-			goto error;
-		}
-
-		domain_db_close();
-	}
+    /* Check table versions */
+    if (domain_db_init(&db_url) < 0) {
+	LM_ERR("unable to open database connection\n");
+	return -1;
+    }
+    if (domain_db_ver(&domain_table, DOMAIN_TABLE_VERSION) < 0) {
+	LM_ERR("error during check of domain table version\n");
+	domain_db_close();
+	goto error;
+    }
+    if (domain_db_ver(&domain_attrs_table,
+		      DOMAIN_ATTRS_TABLE_VERSION) < 0) {
+	LM_ERR("error during check of domain_attrs table version\n");
+	domain_db_close();
+	goto error;
+    }
+    domain_db_close();
+
+    /* Initializing hash tables and hash table variable */
+    hash_table = (struct domain_list ***)shm_malloc
+	(sizeof(struct domain_list *));
+    hash_table_1 = (struct domain_list **)shm_malloc
+	(sizeof(struct domain_list *) * (DOM_HASH_SIZE + 1));
+    hash_table_2 = (struct domain_list **)shm_malloc
+	(sizeof(struct domain_list *) * (DOM_HASH_SIZE + 1));
+    if ((hash_table == 0) || (hash_table_1 == 0) || (hash_table_2 == 0)) {
+	LM_ERR("no memory for hash table\n");
+	goto error;
+    }
+    memset(hash_table_1, 0, sizeof(struct domain_list *) *
+	   DOM_HASH_SIZE + 1);
+    memset(hash_table_2, 0, sizeof(struct domain_list *) *
+	   DOM_HASH_SIZE + 1);
+    *hash_table = hash_table_1;
+
+    /* Allocate and initialize locks */
+    reload_lock = lock_alloc();
+    if (reload_lock == NULL) {
+	LM_ERR("cannot allocate reload_lock\n");
+	goto error;
+    }
+    if (lock_init(reload_lock) == NULL) {
+	LM_ERR("cannot init reload_lock\n");
+	goto error;
+    }
+
+    /* First reload */
+    lock_get(reload_lock);
+    if (reload_tables() == -1) {
+	lock_release(reload_lock);
+	LM_CRIT("domain reload failed\n");
+	goto error;
+    }
+    lock_release(reload_lock);
+
+    return 0;
 
 
-	return 0;
 error:
 error:
-	domain_db_close();
-	return -1;
+    destroy();
+    return -1;
 }
 }
 
 
 
 
 static int child_init(int rank)
 static int child_init(int rank)
 {
 {
-	/* Check if database is needed by child */
-	if ( (db_mode==0 && rank>0) || (rank==PROC_RPC) ) {
-		if (domain_db_init(&db_url)<0) {
-			LM_ERR("Unable to connect to the database\n");
-			return -1;
-		}
-	}
-	return 0;
-}
-
-
-static int mi_child_init(void)
-{
-	return domain_db_init(&db_url);
+    return 0;
 }
 }
 
 
 
 
 static void destroy(void)
 static void destroy(void)
 {
 {
-	/* Destroy is called from the main process only,
-	 * there is no need to close database here because
-	 * it is closed in mod_init already
-	 */
-	if (hash_table) {
-		shm_free(hash_table);
-		hash_table = 0;
-	}
-	if (hash_table_1) {
-		hash_table_free(hash_table_1);
-		shm_free(hash_table_1);
-		hash_table_1 = 0;
-	}
-	if (hash_table_2) {
-		hash_table_free(hash_table_2);
-		shm_free(hash_table_2);
-		hash_table_2 = 0;
-	}
+    /* Destroy is called from the main process only,
+     * there is no need to close database here because
+     * it is closed in mod_init already
+     */
+    if (hash_table) {
+	shm_free(hash_table);
+	hash_table = 0;
+    }
+    if (hash_table_1) {
+	hash_table_free(hash_table_1);
+	shm_free(hash_table_1);
+	hash_table_1 = 0;
+    }
+    if (hash_table_2) {
+	hash_table_free(hash_table_2);
+	shm_free(hash_table_2);
+	hash_table_2 = 0;
+    }
 }
 }
 
 
 
 
 static const char* domain_rpc_reload_doc[2] = {
 static const char* domain_rpc_reload_doc[2] = {
-	"Reload domain table from database",
-	0
+    "Reload domain tables from database",
+    0
 };
 };
 
 
 
 
@@ -283,21 +315,17 @@ static const char* domain_rpc_reload_doc[2] = {
  */
  */
 static void domain_rpc_reload(rpc_t* rpc, void* ctx)
 static void domain_rpc_reload(rpc_t* rpc, void* ctx)
 {
 {
-	if (!db_mode) {
-		rpc->fault(ctx, 500, "Server Domain Cache Disabled");
-		return;
-	}
-
-	if (reload_domain_table() < 0) {
-		rpc->fault(ctx, 400, "Domain Table Reload Failed");
-	}
+    lock_get(reload_lock);
+    if (reload_tables() < 0) {
+	rpc->fault(ctx, 400, "Reload of domain tables failed");
+    }
+    lock_release(reload_lock);
 }
 }
 
 
 
 
-
 static const char* domain_rpc_dump_doc[2] = {
 static const char* domain_rpc_dump_doc[2] = {
-	"Return the contents of domain table",
-	0
+    "Return the contents of domain and domain_attrs tables",
+    0
 };
 };
 
 
 
 
@@ -306,45 +334,56 @@ static const char* domain_rpc_dump_doc[2] = {
  */
  */
 static void domain_rpc_dump(rpc_t* rpc, void* ctx)
 static void domain_rpc_dump(rpc_t* rpc, void* ctx)
 {
 {
-	int i;
-	struct domain_list *np;
-	struct domain_list **ht;
-
-	if (!db_mode) {
-		rpc->fault(ctx, 400, "Server Domain Cache Disabled");
-		return;
-	}
-
-	if(hash_table==0 || *hash_table==0) {
-		rpc->fault(ctx, 404, "Server Domain Cache Empty");
-		return;
+    int i;
+    struct domain_list *np;
+    struct attr_list *ap;
+    struct domain_list **ht;
+    void* st;
+
+    if(hash_table==0 || *hash_table==0) {
+	rpc->fault(ctx, 404, "Server Domain Cache Empty");
+	return;
+    }
+    ht = *hash_table;
+    for (i = 0; i < DOM_HASH_SIZE; i++) {
+	np = ht[i];
+	while (np) {
+	    if (rpc->add(ctx, "{", &st) < 0) return;
+	    rpc->struct_add(st, "SS",
+			    "domain", &np->domain,
+			    "did", &np->did);
+	    np = np->next;
 	}
 	}
-	ht = *hash_table;
-	for (i = 0; i < DOM_HASH_SIZE; i++) {
-		np = ht[i];
-		while (np) {
-			if (rpc->add(ctx, "S", &np->domain) < 0)
-				return;
-
-			np = np->next;
-		}
+    }
+    np = ht[DOM_HASH_SIZE];
+    while (np) {
+	if (rpc->add(ctx, "{", &st) < 0) return;
+	rpc->struct_add(st, "S",
+			"did", &np->did);
+	ap = np->attrs;
+	while (ap) {
+	    rpc->struct_add(st, "S",
+			    "attr", &ap->name);
+	    ap = ap->next;
 	}
 	}
-	return;
+	np = np->next;
+    }
+
+    return;
 }
 }
 
 
 
 
 rpc_export_t domain_rpc_list[] = {
 rpc_export_t domain_rpc_list[] = {
-	{"domain.reload", domain_rpc_reload, domain_rpc_reload_doc, 0},
-	{"domain.dump",   domain_rpc_dump,   domain_rpc_dump_doc,   0},
-	{0, 0, 0, 0}
+    {"domain.reload", domain_rpc_reload, domain_rpc_reload_doc, 0},
+    {"domain.dump",   domain_rpc_dump,   domain_rpc_dump_doc,   0},
+    {0, 0, 0, 0}
 };
 };
 
 
 static int domain_init_rpc(void)
 static int domain_init_rpc(void)
 {
 {
-	if (rpc_register_array(domain_rpc_list)!=0)
-	{
-		LM_ERR("failed to register RPC commands\n");
-		return -1;
-	}
-	return 0;
+    if (rpc_register_array(domain_rpc_list) != 0) {
+	LM_ERR("failed to register RPC commands\n");
+	return -1;
+    }
+    return 0;
 }
 }

+ 19 - 6
modules_k/domain/domain_mod.h

@@ -3,7 +3,7 @@
  *
  *
  * Domain module headers
  * Domain module headers
  *
  *
- * Copyright (C) 2002-2003 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -48,8 +48,17 @@
  * Type definitions
  * Type definitions
  */
  */
 struct domain_list {
 struct domain_list {
-	str domain;
-	struct domain_list *next;
+    str domain;
+    str did;
+    struct attr_list *attrs;
+    struct domain_list *next;
+};
+
+struct attr_list {
+    str name;
+    short type;
+    int_str val;
+    struct attr_list *next;
 };
 };
 
 
 typedef struct param_source {
 typedef struct param_source {
@@ -62,10 +71,14 @@ typedef struct param_source {
 /*
 /*
  * Module parameters variables
  * Module parameters variables
  */
  */
-extern int db_mode;             /* Database usage mode: 0 = no cache, 1 = cache */
+extern str db_url;
 extern str domain_table;	/* Domain table name */
 extern str domain_table;	/* Domain table name */
+extern str domain_attrs_table;	/* Domain attributes table name */
+extern str did_col;   	        /* Domain id column name */
 extern str domain_col;   	/* Domain column name */
 extern str domain_col;   	/* Domain column name */
-
+extern str name_col;   	        /* Attribute name column name */
+extern str type_col;   	        /* Attribute type column name */
+extern str value_col;  	        /* Attribute value column name */
 
 
 /*
 /*
  * Other module variables
  * Other module variables
@@ -73,6 +86,6 @@ extern str domain_col;   	/* Domain column name */
 extern struct domain_list **hash_table_1; /* Hash table for domains */
 extern struct domain_list **hash_table_1; /* Hash table for domains */
 extern struct domain_list **hash_table_2; /* Hash table for domains */
 extern struct domain_list **hash_table_2; /* Hash table for domains */
 extern struct domain_list ***hash_table;  /* Current hash table */
 extern struct domain_list ***hash_table;  /* Current hash table */
-
+extern gen_lock_t *reload_lock;
 
 
 #endif /* DOMAIN_MOD_H */
 #endif /* DOMAIN_MOD_H */

+ 170 - 50
modules_k/domain/hash.c

@@ -3,7 +3,7 @@
  *
  *
  * Hash functions for cached domain table
  * Hash functions for cached domain table
  *
  *
- * Copyright (C) 2002-2008 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -36,28 +36,132 @@
 
 
 #define dom_hash(_s)  core_case_hash( _s, 0, DOM_HASH_SIZE)
 #define dom_hash(_s)  core_case_hash( _s, 0, DOM_HASH_SIZE)
 
 
+/* Check if domain exists in hash table */
+int hash_table_lookup (str *domain, str *did, struct attr_list **attrs)
+{
+	struct domain_list *np;
+
+	for (np = (*hash_table)[dom_hash(domain)]; np != NULL; np = np->next) {
+		if ((np->domain.len == domain->len) && 
+		    (strncasecmp(np->domain.s, domain->s, domain->len) == 0)) {
+		    *did = np->did;
+		    *attrs = np->attrs;
+		    return 1;
+		}
+	}
+
+	return -1;
+}
+
+/* Add did attribute to hash table */
+int hash_table_attr_install (struct domain_list **hash_table, str* did,
+			     str *name, short type, int_str *val)
+{
+    struct attr_list *attr;
+    struct domain_list *np;
+
+    attr = (struct attr_list *)shm_malloc(sizeof(struct attr_list));
+    if (attr == NULL) {
+	LM_ERR("no shm memory left for attribute\n");
+	return -1;
+    }
+    attr->name.s = (char *)shm_malloc(name->len);
+    if (attr->name.s == NULL) {
+	LM_ERR("no shm memory left for attribute name\n");
+	shm_free(attr);
+	return -1;
+    }
+    memcpy(attr->name.s, name->s, name->len);
+    attr->name.len = name->len;
+    attr->type = type;
+    attr->val.n = val->n;
+    attr->val.s = val->s;
+    if (type == 2) {
+	attr->val.s.s = (char *)shm_malloc(val->s.len);
+	if (attr->val.s.s == NULL) {
+	    LM_ERR("no shm memory left for attribute value\n");
+	    shm_free(attr->name.s);
+	    shm_free(attr);
+	}
+	memcpy(attr->val.s.s, val->s.s, val->s.len);
+	attr->val.s.len = val->s.len;
+    }
+    attr->next = NULL;
+
+    np = hash_table[DOM_HASH_SIZE];
+    while (np) {
+	if ((np->did.len == did->len) && 
+	    (strncasecmp(np->did.s, did->s, did->len) == 0)) {
+	    if (np->attrs) attr->next = np->attrs;
+	    np->attrs = attr;
+	    return 1;
+	}
+	np = np->next;
+    }
+    np = (struct domain_list *)shm_malloc(sizeof(struct domain_list));
+    if (np == NULL) {
+	LM_ERR("no shm memory left for domain list\n");
+	if (type == 2) shm_free(attr->name.s);
+	shm_free(attr);
+	return -1;
+    }
+    np->did.s = (char *)shm_malloc(did->len);
+    if (np->did.s == NULL) {
+	LM_ERR("no shm memory left for did\n");
+	if (type == 2) shm_free(attr->name.s);
+	shm_free(attr);
+	shm_free(np);
+	return -1;
+    }
+    memcpy(np->did.s, did->s, did->len);
+    np->did.len = did->len;
+    np->attrs = attr;
+    np->next = hash_table[DOM_HASH_SIZE];
+    hash_table[DOM_HASH_SIZE] = np;
+	
+    return 1;
+}
 
 
 /* Add domain to hash table */
 /* Add domain to hash table */
-int hash_table_install (struct domain_list **hash_table, char *domain)
+int hash_table_install (struct domain_list **hash_table, str* did, str *domain)
 {
 {
-	struct domain_list *np;
+        struct domain_list *np, *dl;
 	unsigned int hash_val;
 	unsigned int hash_val;
-
+	    
 	np = (struct domain_list *) shm_malloc(sizeof(*np));
 	np = (struct domain_list *) shm_malloc(sizeof(*np));
 	if (np == NULL) {
 	if (np == NULL) {
-		LM_ERR("Cannot allocate memory for hash table entry\n");
+		LM_ERR("no shared memory for hash table entry\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
-	np->domain.len = strlen(domain);
-	np->domain.s = (char *) shm_malloc(np->domain.len);
-	if (np->domain.s == NULL) {
-		LM_ERR("Cannot allocate memory for domain string\n");
+	np->did.len = did->len;
+	np->did.s = (char *)shm_malloc(did->len);
+	if (np->did.s == NULL) {
+		LM_ERR("no shared memeory for did\n");
 	        shm_free(np);
 	        shm_free(np);
 		return -1;
 		return -1;
 	}
 	}
-	(void) strncpy(np->domain.s, domain, np->domain.len);
+	(void)memcpy(np->did.s, did->s, did->len);
 
 
+	np->domain.len = domain->len;
+	np->domain.s = (char *) shm_malloc(domain->len);
+	if (np->domain.s == NULL) {
+		LM_ERR("no shared memory for domain\n");
+	        shm_free(np);
+		return -1;
+	}
+	(void)strncpy(np->domain.s, domain->s, domain->len);
+
+	np->attrs = NULL;
+	dl = hash_table[DOM_HASH_SIZE];
+	while (dl) {
+	    if ((dl->did.len == did->len) && 
+		(strncasecmp(dl->did.s, did->s, did->len) == 0)) {
+		np->attrs = dl->attrs;
+		break;
+	    }
+	    dl = dl->next;
+	}
 	hash_val = dom_hash(&np->domain);
 	hash_val = dom_hash(&np->domain);
 	np->next = hash_table[hash_val];
 	np->next = hash_table[hash_val];
 	hash_table[hash_val] = np;
 	hash_table[hash_val] = np;
@@ -65,62 +169,78 @@ int hash_table_install (struct domain_list **hash_table, char *domain)
 	return 1;
 	return 1;
 }
 }
 
 
-
-/* Check if domain exists in hash table */
-int hash_table_lookup (str *domain)
-{
-	struct domain_list *np;
-
-	for (np = (*hash_table)[dom_hash(domain)]; np != NULL; np = np->next) {
-		if ((np->domain.len == domain->len) && 
-		    (strncasecmp(np->domain.s, domain->s, domain->len) == 0)) {
-			return 1;
-		}
-	}
-
-	return -1;
-}
-
-
 int hash_table_mi_print(struct domain_list **hash_table, struct mi_node* rpl)
 int hash_table_mi_print(struct domain_list **hash_table, struct mi_node* rpl)
 {
 {
 	int i;
 	int i;
 	struct domain_list *np;
 	struct domain_list *np;
-	struct mi_node* node;
+	struct attr_list *ap;
+	struct mi_node *dnode, *node;
 
 
-	if(hash_table==0)
-		return -1;
+	if(hash_table==0) return -1;
 	for (i = 0; i < DOM_HASH_SIZE; i++) {
 	for (i = 0; i < DOM_HASH_SIZE; i++) {
 		np = hash_table[i];
 		np = hash_table[i];
 		while (np) {
 		while (np) {
-			node = add_mi_node_child(rpl, 0, 0, 0, 
-					np->domain.s, np->domain.len);
-			if(node == 0)
-				return -1;
-
+			dnode = add_mi_node_child(rpl, 0, "domain", 6, 
+						  np->domain.s, np->domain.len);
+			if (dnode == 0) return -1;
+			node = add_mi_node_child(dnode, 0, "did", 3, 
+						 np->did.s, np->did.len);
+			if (node == 0) return -1;
 			np = np->next;
 			np = np->next;
 		}
 		}
 	}
 	}
+	np = hash_table[DOM_HASH_SIZE];
+	while (np) {
+	    dnode = add_mi_node_child(rpl, 0, "did", 3, 
+				      np->did.s, np->did.len);
+	    if (dnode == 0) return -1;
+	    ap = np->attrs;
+	    while (ap) {
+		node = add_mi_node_child(dnode, 0, "attr", 4, 
+					 ap->name.s, ap->name.len);
+		if (node == 0) return -1;
+		ap = ap->next;
+	    }
+	    np = np->next;
+	}
 	return 0;
 	return 0;
 }
 }
 
 
 /* Free contents of hash table */
 /* Free contents of hash table */
 void hash_table_free (struct domain_list **hash_table)
 void hash_table_free (struct domain_list **hash_table)
 {
 {
-	int i;
-	struct domain_list *np, *next;
-	
-	if(hash_table==0)
-		return;
-
-	for (i = 0; i < DOM_HASH_SIZE; i++) {
-		np = hash_table[i];
-		while (np) {
-			shm_free(np->domain.s);
-			next = np->next;
-			shm_free(np);
-			np = next;
-		}
-		hash_table[i] = NULL;
+    int i;
+    struct domain_list *np, *next;
+    struct attr_list *ap, *next_ap;
+
+    if (hash_table == 0) return;
+
+    for (i = 0; i < DOM_HASH_SIZE; i++) {
+	np = hash_table[i];
+	while (np) {
+	    shm_free(np->did.s);
+	    shm_free(np->domain.s);
+	    next = np->next;
+	    shm_free(np);
+	    np = next;
+	}
+	hash_table[i] = NULL;
+    }
+
+    np = hash_table[DOM_HASH_SIZE];
+    while (np) {
+	shm_free(np->did.s);
+	ap = np->attrs;
+	while (ap) {
+	    shm_free(ap->name.s);
+	    if (ap->type == 2) shm_free(ap->val.s.s);
+	    next_ap = ap->next;
+	    shm_free(ap);
+	    ap = next_ap;
 	}
 	}
+	np = np->next;
+    }
+
+    hash_table[DOM_HASH_SIZE] = NULL;
+    return;
 }
 }

+ 5 - 3
modules_k/domain/hash.h

@@ -3,7 +3,7 @@
  *
  *
  * Header file for hash table functions
  * Header file for hash table functions
  *
  *
- * Copyright (C) 2002-2003 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -30,8 +30,10 @@
 #include "domain_mod.h"
 #include "domain_mod.h"
 #include "../../lib/kmi/mi.h"
 #include "../../lib/kmi/mi.h"
 
 
-int hash_table_install (struct domain_list **hash_table, char *domain);
-int hash_table_lookup (str *domain);
+int hash_table_install (struct domain_list **hash_table, str *did, str *domain);
+int hash_table_attr_install (struct domain_list **hash_table, str* did,
+			     str *name, short type, int_str *val);
+int hash_table_lookup (str *domain, str *did, struct attr_list **attrs);
 int hash_table_mi_print(struct domain_list **hash_table, struct mi_node* rpl);
 int hash_table_mi_print(struct domain_list **hash_table, struct mi_node* rpl);
 void hash_table_free (struct domain_list **hash_table);
 void hash_table_free (struct domain_list **hash_table);
 
 

+ 18 - 22
modules_k/domain/mi.c

@@ -4,6 +4,7 @@
  * Domain MI functions
  * Domain MI functions
  *
  *
  * Copyright (C) 2006 Voice Sistem SRL
  * Copyright (C) 2006 Voice Sistem SRL
+ * Copyright (C) 2012 Juha Heinanen
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -40,14 +41,14 @@
  */
  */
 struct mi_root* mi_domain_reload(struct mi_root *cmd_tree, void *param)
 struct mi_root* mi_domain_reload(struct mi_root *cmd_tree, void *param)
 {
 {
-	if(db_mode==0)
-		return init_mi_tree( 500, "command not activated", 21);
-
-	if (reload_domain_table () == 1) {
-		return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
-	} else {
-		return init_mi_tree( 500, "Domain table reload failed", 26);
-	}
+    lock_get(reload_lock);
+    if (reload_tables() == 1) {
+	lock_release(reload_lock);
+	return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
+    } else {
+	lock_release(reload_lock);
+	return init_mi_tree( 500, "Domain table reload failed", 26);
+    }
 }
 }
 
 
 
 
@@ -56,21 +57,16 @@ struct mi_root* mi_domain_reload(struct mi_root *cmd_tree, void *param)
  */
  */
 struct mi_root* mi_domain_dump(struct mi_root *cmd_tree, void *param)
 struct mi_root* mi_domain_dump(struct mi_root *cmd_tree, void *param)
 {
 {
-	struct mi_root* rpl_tree;
-
-	if(db_mode==0)
-		return init_mi_tree( 500, "command not activated", 21);
+    struct mi_root* rpl_tree;
 
 
-	rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
-	if (rpl_tree==NULL)
-		return 0;
+    rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
+    if (rpl_tree == NULL) return 0;
 
 
-	if(hash_table_mi_print(*hash_table, &rpl_tree->node)< 0)
-	{
-		LM_ERR("Error while adding node\n");
-		free_mi_tree(rpl_tree);
-		return 0;
-	}
+    if(hash_table_mi_print(*hash_table, &rpl_tree->node) < 0) {
+	LM_ERR("failed to add node\n");
+	free_mi_tree(rpl_tree);
+	return 0;
+    }
 
 
-	return rpl_tree;
+    return rpl_tree;
 }
 }