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">
     <name>domain</name>
-    <version>1</version>
+    <version>2</version>
     <type db="mysql">&MYSQL_TABLE_TYPE;</type>
     <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
@@ -35,6 +35,15 @@
         <natural/>
     </column>
 
+    <column id="did">
+        <name>did</name>
+        <type>string</type>
+        <size>&domain_len;</size>
+        <description>Domain id</description>
+        <default/>
+        <natural/>
+    </column>
+
     <column>
         <name>last_modified</name>
         <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">
     <name>Domain</name>
     <xi:include href="domain.xml"/>
+    <xi:include href="domain_attrs.xml"/>
 </database>

+ 129 - 56
modules_k/domain/README

@@ -10,7 +10,7 @@ Juha Heinanen
 
    <[email protected]>
 
-   Copyright © 2002-2008 Juha Heinanen
+   Copyright © 2002-2012 Juha Heinanen
      __________________________________________________________________
 
    Table of Contents
@@ -22,16 +22,21 @@ Juha Heinanen
         3. Parameters
 
               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.1. is_from_local()
               4.2. is_uri_host_local()
               4.3. is_domain_local(pseudo_variable)
+              4.4. lookup_domain(domain[, prefix])
 
         5. MI Commands
 
@@ -54,13 +59,18 @@ Juha Heinanen
    List of Examples
 
    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
 
@@ -71,16 +81,21 @@ Chapter 1. Admin Guide
    3. Parameters
 
         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.1. is_from_local()
         4.2. is_uri_host_local()
         4.3. is_domain_local(pseudo_variable)
+        4.4. lookup_domain(domain[, prefix])
 
    5. MI Commands
 
@@ -97,17 +112,14 @@ Chapter 1. Admin Guide
 1. Overview
 
    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
    is given by HASH_SIZE constant defined in domain_mod.h. Its “factory
@@ -122,10 +134,14 @@ Chapter 1. Admin Guide
 3. Parameters
 
    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)
 
@@ -136,43 +152,80 @@ Chapter 1. Admin Guide
    Example 1.1. Setting db_url parameter
 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”.
 
-   Example 1.4. Setting domain_col parameter
+   Example 1.5. Setting domain_col parameter
 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
    registration, 1 means enable myself registration.
 
    Default value is 0 (disable).
 
-   Example 1.5. register_myself example
+   Example 1.9. register_myself example
 modparam("domain", "register_myself", 1)
 
 4. Functions
@@ -180,15 +233,17 @@ modparam("domain", "register_myself", 1)
    4.1. is_from_local()
    4.2. is_uri_host_local()
    4.3. is_domain_local(pseudo_variable)
+   4.4. lookup_domain(domain[, prefix])
 
 4.1. is_from_local()
 
    Checks based on domain table if host part of From header uri is one of
    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()) {
         ...
@@ -204,9 +259,9 @@ if (is_from_local()) {
    to the transaction before is_uri_host_local() is called.
 
    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()) {
         ...
@@ -226,9 +281,9 @@ if (is_uri_host_local()) {
      * is_domain_local("$fd") is same as is_from_local()
 
    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")) {
         ...
@@ -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.1. domain_reload
@@ -308,8 +381,8 @@ if (is_domain_local("$avp(s:some_avp)")) {
 
 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
    process.
 

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

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

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

@@ -16,26 +16,23 @@
 	<section>
 	<title>Overview</title>
 	<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>
-		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>
-		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>
 	</section>
 
@@ -71,41 +68,56 @@ modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")
 		</example>
 	</section>
 	<section>
-		<title><varname>db_mode</varname> (integer)</title>
+		<title><varname>domain_table</varname> (string)</title>
 		<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>
-		Default value is 0 (non-caching).
+		Default value is <quote>domain</quote>.
 		</para>
 		<example>
-		<title>db_mode example</title>
+		<title>Setting domain_table parameter</title>
 		<programlisting format="linespecific">
-modparam("domain", "db_mode", 1)   # Use caching
+modparam("domain", "domain_table", "new_name")
 </programlisting>
 		</example>
 	</section>
 	<section>
-		<title><varname>domain_table</varname> (string)</title>
+		<title><varname>domain_attrs_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.
+		Name of table containing attributes of local domains.
 		</para>
 		<para>
-		Default value is <quote>domain</quote>.
+		Default value is <quote>domain_attrs</quote>.
 		</para>
 		<example>
-		<title>Setting domain_table parameter</title>
+		<title>Setting domain_attrs_table parameter</title>
 		<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>
 		</example>
 	</section>
 	<section>
 		<title><varname>domain_col</varname> (string)</title>
 		<para>
-		Name of column containing domains in domain table.
+		Name of column containing domain name in domain table.
 		</para>
 		<para>
 		Default value is <quote>domain</quote>.
@@ -114,6 +126,52 @@ modparam("domain", "domain_table", "new_name")
 		<title>Setting domain_col parameter</title>
 		<programlisting format="linespecific">
 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>
 		</example>
 	</section>
@@ -146,7 +204,8 @@ modparam("domain", "register_myself", 1)
 		one of the local domains that the proxy is responsible for
 		</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>
 		<example>
 		<title>is_from_local usage</title>
@@ -172,7 +231,7 @@ if (is_from_local()) {
 		</para>
 		<para>
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-		BRANCH_ROUTE.
+		BRANCH_ROUTE, and LOCAL_ROUTE.
 		</para>
 		<example>
 		<title>is_uri_host_local usage</title>
@@ -208,7 +267,7 @@ if (is_uri_host_local()) {
 		</itemizedlist>
 		<para>
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-		BRANCH_ROUTE.
+		BRANCH_ROUTE, and LOCAL_ROUTE.
 		</para>
 		<example>
 		<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)")) {
 	...
 };
+...
+		</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>
 		</example>
@@ -314,9 +399,10 @@ if (is_domain_local("$avp(s:some_avp)")) {
 	<section>
 	<title>Known Limitations</title>
 	<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 
-		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.
 	</para>
 	</section>

+ 309 - 122
modules_k/domain/domain.c

@@ -3,7 +3,7 @@
  *
  * 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.
  *
@@ -96,53 +96,15 @@ int domain_db_ver(str* name, int version)
 }
 
 
-
 /*
  * Check if domain is local
  */
 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)
 {
 	struct sip_uri *puri;
+	str did;
+	struct attr_list *attrs;
 
 	if ((puri=parse_from_uri(_msg))==NULL) {
 		LM_ERR("Error while parsing From header\n");
 		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)
 {
-	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 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)
 {
     pv_spec_t *sp;
     pv_value_t pv_val;
+    struct attr_list *attrs;
+    str did;
 
     sp = (pv_spec_t *)_sp;
 
     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("Missing domain name\n");
+		LM_DBG("missing domain name\n");
 		return -1;
 	    }
-	    return is_domain_local(&(pv_val.rs));
+	    return hash_table_lookup(&(pv_val.rs), &did, &attrs);
 	} else {
-	   LM_DBG("Pseudo variable value is not string\n");
+	   LM_DBG("domain pseudo variable value is not string\n");
 	   return -1;
 	}
     } else {
-	LM_DBG("Cannot get pseudo variable value\n");
+	LM_DBG("cannot get domain pseudo variable value\n");
 	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 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
  * 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
  *
- * Copyright (C) 2002-2003 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  * 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_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 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);
 int domain_db_ver(str* name, int version);
 
-int reload_domain_table(void);
+int reload_tables(void);
 
 #endif /* DOMAIN_H */

+ 195 - 156
modules_k/domain/domain_mod.c

@@ -3,7 +3,7 @@
  *
  * Domain module
  *
- * Copyright (C) 2002-2008 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -48,6 +48,7 @@
 #include "mi.h"
 #include "hash.h"
 #include "api.h"
+#include "../../locking.h"
 
 /*
  * Module management function prototypes
@@ -55,7 +56,6 @@
 static int mod_init(void);
 static void destroy(void);
 static int child_init(int rank);
-static int mi_child_init(void);
 
 MODULE_VERSION
 
@@ -64,23 +64,43 @@ MODULE_VERSION
  * increment this value if you change the table in
  * 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_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_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);
 
 /*
  * 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_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 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;
 
 /*
@@ -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_1 = 0;	/* Pointer to hash table 1 */
 struct domain_list **hash_table_2 = 0;	/* Pointer to hash table 2 */
-
+gen_lock_t *reload_lock;
 
 /*
  * Exported functions
@@ -102,6 +122,12 @@ static cmd_export_t cmds[] = {
 	{"is_domain_local", (cmd_function)w_is_domain_local, 1, fixup_pvar_null,
 	 fixup_free_pvar_null,
 	 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},
 	{0, 0, 0, 0, 0, 0}
 };
@@ -112,9 +138,12 @@ static cmd_export_t cmds[] = {
  */
 static param_export_t params[] = {
 	{"db_url",         STR_PARAM, &db_url.s      },
-	{"db_mode",        INT_PARAM, &db_mode       },
 	{"domain_table",   STR_PARAM, &domain_table.s},
+	{"did_col",        STR_PARAM, &did_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},
 	{0, 0, 0}
 };
@@ -124,9 +153,9 @@ static param_export_t params[] = {
  * Exported MI functions
  */
 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)
 {
-	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:
-	domain_db_close();
-	return -1;
+    destroy();
+    return -1;
 }
 
 
 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)
 {
-	/* 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] = {
-	"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)
 {
-	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] = {
-	"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)
 {
-	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[] = {
-	{"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)
 {
-	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
  *
- * Copyright (C) 2002-2003 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -48,8 +48,17 @@
  * Type definitions
  */
 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 {
@@ -62,10 +71,14 @@ typedef struct param_source {
 /*
  * 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_attrs_table;	/* Domain attributes table name */
+extern str did_col;   	        /* Domain id 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
@@ -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_2; /* Hash table for domains */
 extern struct domain_list ***hash_table;  /* Current hash table */
-
+extern gen_lock_t *reload_lock;
 
 #endif /* DOMAIN_MOD_H */

+ 170 - 50
modules_k/domain/hash.c

@@ -3,7 +3,7 @@
  *
  * 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.
  *
@@ -36,28 +36,132 @@
 
 #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 */
-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;
-
+	    
 	np = (struct domain_list *) shm_malloc(sizeof(*np));
 	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;
 	}
 
-	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);
 		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);
 	np->next = hash_table[hash_val];
 	hash_table[hash_val] = np;
@@ -65,62 +169,78 @@ int hash_table_install (struct domain_list **hash_table, char *domain)
 	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 i;
 	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++) {
 		np = hash_table[i];
 		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 = 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;
 }
 
 /* Free contents of 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
  *
- * Copyright (C) 2002-2003 Juha Heinanen
+ * Copyright (C) 2002-2012 Juha Heinanen
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -30,8 +30,10 @@
 #include "domain_mod.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);
 void hash_table_free (struct domain_list **hash_table);
 

+ 18 - 22
modules_k/domain/mi.c

@@ -4,6 +4,7 @@
  * Domain MI functions
  *
  * Copyright (C) 2006 Voice Sistem SRL
+ * Copyright (C) 2012 Juha Heinanen
  *
  * 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)
 {
-	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* 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;
 }