Explorar o código

ims_usrloc_pcscf: implementation of db_mode DB_ONLY (value 3) (#3279)

* ims_usrloc_pcscf:   implementation of db_mode DB_ONLY (value 3)
  In order to support a redundant PCSCF configuration - i.e. a logical PCSCF
  consists of 2 physical nodes (node1 and node2) some enhancements were
  introduced for handling of contacts. Redundancy means that SIP messages
  for a client are normally handled by node1 but in case node1 is not
  reachable SIP messages are redirected to node2. Of course the DB_ONLY
  mode must work also for single PCSCF node configuration. Important aspects
  of this implementation are database integrity - i.e. avoid invalid table
  entries (for example data which are expired long time ago or have
  invalid states) - and keeping PCSCF cache in sync with database tables.
* A wrapper was built for method get_pcontact which tries to find the pcontact
  in cache and if search is not successful tries to download and insert from
  db location table - also some effort is added here to find the pcontact if it exists in cache.
  The contact expiry handler was modified to sync contact
  expiry in cache with db location entry and in case of real contact expiry
  sends PUBLISH to SCSCF to let NOTIFY finally delete the contact.
* An audit for older expired pcontacts was introduced which cares for
  getting rid of these contacts.
  Some code was introduced to help registering callbacks for contacts
  which are inserted into cache when being downloaded from database - for
  example ims_qos callback as at the time of insertion the message that triggered
  the original callback registering is long gone.
* changes required for PR #3279
* add modparam db_mode to usrloc_api
* remove unused method db_delete_presentity_uri_from_pua

Co-authored-by: Annemarie Mandl <[email protected]>
petermarianF %!s(int64=2) %!d(string=hai) anos
pai
achega
7a1f2be30e

+ 11 - 0
src/modules/ims_usrloc_pcscf/README

@@ -175,6 +175,17 @@ modparam("ims_usrloc_pcscf", "db_url",
        reflected in the database. This is slow but very reliable. This
        mode will ensure that no registration data is lost as a result of a
        restart or crash.
+     * 3 - DB_ONLY Scheme. All changes to usrloc are immediately
+       reflected in the database and additionally PCSCF usrloc data are downloaded
+       from db and inserted into PCSCF usrloc cache if required - i.e. If 
+       contact data cannot be found in cache a db
+       query for the contact is done in table location and when contact is
+       found there its respective data are inserted in PCSCF usrloc cache.
+       Also an audit had been added for removal of long expired PCSCF usrloc data
+       in table location.
+       Some of the db queries do only support Mysql.
+       This mode will ensure that no registration data is lost as a result of a
+       restart or crash.
 
    Default value is 0.
 

+ 64 - 0
src/modules/ims_usrloc_pcscf/doc/ims_usrloc_pcscf_admin.xml

@@ -142,6 +142,20 @@ modparam("ims_usrloc_pcscf", "db_url",
           reliable. This mode will ensure that no registration data is lost as
           a result of a restart or crash.</para>
         </listitem>
+
+        <listitem>
+          <para>3 - DB_ONLY Scheme. All changes to usrloc are immediately
+          reflected in the database and additionally PCSCF usrloc data are downloaded
+          from db and inserted into PCSCF usrloc cache if required - i.e. If
+          contact data cannot be found in cache a db
+          query for the contact is done in table location and when contact is
+          found there its respective data are inserted in PCSCF usrloc cache.
+          Also an audit had been added for removal of long expired PCSCF usrloc data
+          in table location.
+          This mode will ensure that no registration data is lost as a result of a
+          restart or crash.</para>
+        </listitem>
+
       </itemizedlist>
 
       <para><emphasis>Default value is 0.</emphasis></para>
@@ -198,6 +212,55 @@ modparam("ims_usrloc_pcscf", "match_contact_host_port", 0)
         <programlisting format="linespecific">...
 modparam("ims_usrloc_pcscf", "expires_grace", 1800)
 ...
+</programlisting>
+      </example>
+    </section>
+    
+    <section>
+      <title>audit_expired_pcontacts_interval (int)</title>
+
+      <para>Number of seconds between two audit runs.
+      Note: audit is used for db_mode DB_ONLY (3) only.
+      The module uses this audit to
+      delete expired contacts found in db table location which are expired
+      at least as the audit_expired_pcontacts_timeout value.
+      Such expired contacts in location  may appear when these contacts
+      are not present in usrloc cache because PCSCF crashed before
+      contact expiry.
+      </para>
+
+      <para><emphasis> Default value is 60. </emphasis></para>
+
+      <example>
+        <title>Set audit_expired_pcontacts_interval parameter</title>
+
+        <programlisting format="linespecific">...
+modparam("ims_usrloc_pcscf", "audit_expired_pcontacts_interval", 120)
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>audit_expired_pcontacts_timeout (int)</title>
+
+      <para>Number of seconds the contacts must be already expired before the audit
+      starts working on them.
+      It is recommended to set only values greater than the Default value 40.
+      The module uses this audit to
+      delete expired contacts found in db table location which are expired
+      at least as many seconds as the sum of this timeout parameter value plus
+      the value of the expires_grace parameter.
+      </para>
+
+      <para><emphasis> Default value is 40. </emphasis></para>
+
+      <example>
+        <title>Set audit_expired_pcontacts_timeout parameter</title>
+
+        <programlisting format="linespecific">...
+modparam("ims_usrloc_pcscf", "audit_expired_pcontacts_timeout", 120)
+...
 </programlisting>
       </example>
     </section>
@@ -241,3 +304,4 @@ modparam("ims_usrloc_pcscf", "expires_grace", 1800)
     </section>
   </section>
 </chapter>
+

+ 41 - 10
src/modules/ims_usrloc_pcscf/ims_usrloc_pcscf_mod.c

@@ -40,6 +40,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+ 
 
 #include <stdio.h>
 #include "ims_usrloc_pcscf_mod.h"
@@ -62,6 +63,11 @@ MODULE_VERSION
 #define DEFAULT_DBG_FILE "/var/log/usrloc_debug"
 static FILE *debug_file;
 
+int audit_expired_pcontacts_timeout = 40;
+int audit_expired_pcontacts_interval = 60;
+
+static void audit_usrloc_expired_pcontacts_timer(unsigned int ticks, void* param);
+
 static int mod_init(void);                          /*!< Module initialization function */
 static void destroy(void);                          /*!< Module destroy function */
 static void timer(unsigned int ticks, void* param); /*!< Timer handler */
@@ -110,8 +116,10 @@ static param_export_t params[] = {
 	{"timer_interval",      INT_PARAM, &timer_interval  },
 	{"db_mode",             INT_PARAM, &db_mode         },
 
-	{"match_contact_host_port",		INT_PARAM, &match_contact_host_port	},
-        {"expires_grace",		INT_PARAM, &expires_grace	},
+	{"match_contact_host_port",	                   INT_PARAM, &match_contact_host_port },
+         {"audit_expired_pcontacts_timeout",            INT_PARAM, &audit_expired_pcontacts_timeout },
+         {"audit_expired_pcontacts_interval",           INT_PARAM, &audit_expired_pcontacts_interval },
+         {"expires_grace",       INT_PARAM, &expires_grace },
 
 	{0, 0, 0}
 };
@@ -178,6 +186,11 @@ static int mod_init(void) {
 	LM_DBG("Registering cache timer");
 	register_timer(timer, 0, timer_interval);
 
+        /* Register audit timer */
+        if (db_mode == DB_ONLY)
+            register_timer(audit_usrloc_expired_pcontacts_timer, 0, audit_expired_pcontacts_interval);
+
+
 	/* init the callbacks list */
 	if (init_ulcb_list() < 0) {
 		LM_ERR("usrloc/callbacks initialization failed\n");
@@ -191,10 +204,15 @@ static int mod_init(void) {
 			return -1;
 		}
 
-		if (init_db(&db_url, timer_interval, ul_fetch_rows) != 0) {
-			LM_ERR("Error initializing db connection\n");
-			return -1;
-		}
+                if (db_bind_mod(&db_url, &ul_dbf) < 0) { /* Find database module */
+                        LM_ERR("failed to bind database module\n");
+                        return -1;
+                }
+                if (!DB_CAPABILITY(ul_dbf, DB_CAP_ALL)) {
+                        LM_ERR("database module does not implement all functions"
+                                        " needed by the module\n");
+                        return -1;
+                }
 		LM_DBG("Running in DB mode %i\n", db_mode);
 	}
 
@@ -225,10 +243,12 @@ static int child_init(int _rank)
 	}
 
 	LM_DBG("Connecting to usrloc_pcscf DB for rank %d\n", _rank);
-	if (connect_db(&db_url) != 0) {
-		LM_ERR("child(%d): failed to connect to database\n", _rank);
-		return -1;
-	}
+        ul_dbh = ul_dbf.init(&db_url); /* Get a database connection per child */
+
+        if (!ul_dbh) {
+                LM_ERR("child(%d): failed to connect to database\n", _rank);
+                return -1;
+        }
 	/* _rank==PROC_SIPINIT is used even when fork is disabled */
 	if (_rank==PROC_SIPINIT && db_mode!=DB_ONLY) {
 		// if cache is used, populate domains from DB
@@ -261,6 +281,17 @@ static void destroy(void)
 
 	if (db_mode)
 		destroy_db();
+
+        if (cbp_qos)
+           shm_free(cbp_qos);
+
+        if (cbp_registrar)
+           shm_free(cbp_registrar);            
+}
+
+static void audit_usrloc_expired_pcontacts_timer(unsigned int ticks, void* param) {
+
+     audit_usrloc_expired_pcontacts(root->d);
 }
 
 

+ 1 - 0
src/modules/ims_usrloc_pcscf/ims_usrloc_pcscf_mod.h

@@ -59,5 +59,6 @@ extern int desc_time_order;
 extern int cseq_delay;
 extern int ul_fetch_rows;
 extern int ul_hash_size;
+extern int db_mode;
 
 #endif /* UL_MOD_H */

+ 56 - 10
src/modules/ims_usrloc_pcscf/pcontact.c

@@ -277,6 +277,16 @@ int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, s
 			(*_c)->num_service_routes = _ci->num_service_routes;
 		}
 	}
+	// add the rx session id
+	if ((_ci->rx_regsession_id) && (_ci->rx_regsession_id->len > 0) && (_ci->rx_regsession_id->s)) {
+		(*_c)->rx_session_id.s = shm_malloc(_ci->rx_regsession_id->len);
+		if (!((*_c)->rx_session_id.s)) {
+			LM_ERR("no more shm mem\n");
+			goto out_of_memory;
+		}
+		memcpy((*_c)->rx_session_id.s, _ci->rx_regsession_id->s, _ci->rx_regsession_id->len);
+		(*_c)->rx_session_id.len = _ci->rx_regsession_id->len;
+	}
         
         LM_DBG("New contact host:port [%.*s:%d]\n", (*_c)->contact_host.len, (*_c)->contact_host.s, (*_c)->contact_port);
         LM_DBG("New contact via host:port:proto: [%.*s:%d:%d]\n", (*_c)->via_host.len, (*_c)->via_host.s, (*_c)->via_port, (*_c)->via_proto);
@@ -357,18 +367,54 @@ static inline void nodb_timer(pcontact_t* _c)
         
         if ((_c->expires - act_time) + expires_grace <= 0) {//we've allowed some grace time TODO: add as parameter
         //if ((_c->expires - act_time) <= -10) {//we've allowed some grace time TODO: add as parameter
-		LM_DBG("pcscf contact <%.*s> has expired and will be removed\n", _c->aor.len, _c->aor.s);
-		if (exists_ulcb_type(PCSCF_CONTACT_EXPIRE)) {
-			run_ul_callbacks(PCSCF_CONTACT_EXPIRE, _c);
-		}
-
-		if (db_mode == WRITE_THROUGH && db_delete_pcontact(_c) != 0) {
+        	LM_DBG("pcscf contact <%.*s> has expired and will be removed\n", _c->aor.len, _c->aor.s);
+
+                if (db_mode == DB_ONLY){
+                   if  (db_load_pcontact(_c->slot->d, &_c->aor, 0/*insert_cache*/, &_c, NULL)){
+                        if ((_c->reg_state == PCONTACT_REG_PENDING_AAR) || (_c->reg_state == PCONTACT_REG_PENDING)){
+                           //we do not need expires_grace here as contact is not registered in scscf 
+                           if ((_c->expires - act_time)  <= 0) {
+                               _c->reg_state = PCONTACT_DEREG_PENDING_PUBLISH;
+                               delete_pcontact(_c->slot->d,  _c);
+                               return;
+                           }
+                        }
+                        else{
+                           if ((_c->expires - act_time) + expires_grace >= 0) {
+                               return;
+                           }
+                        }
+                    }
+                    else{
+                        // not found in DB: better delete in cache also
+                        update_stat(_c->slot->d->expired, 1);
+                        mem_delete_pcontact(_c->slot->d, _c);
+                        return;
+                    }
+                    
+                    _c->reg_state = PCONTACT_DEREG_PENDING_PUBLISH;
+		    if(db_delete_pcontact(_c) !=0) {
 			LM_ERR("Error deleting ims_usrloc_pcscf record in DB");
+		    } //delete contact in DB to not process this contact in several units
+                    if (exists_ulcb_type(PCSCF_CONTACT_UPDATE)) {
+                        run_ul_callbacks(PCSCF_CONTACT_UPDATE, _c);
+                        LM_INFO("pcscf contact <%.*s> has expired - sending PUBLISH\n", _c->aor.len, _c->aor.s);
+                        return;
+                    }
+                }
+                else{
+	           if (exists_ulcb_type(PCSCF_CONTACT_EXPIRE)) {
+			        run_ul_callbacks(PCSCF_CONTACT_EXPIRE, _c);
+		       }
+
+		    if (db_mode == WRITE_THROUGH && db_delete_pcontact(_c) != 0) {
+			     LM_ERR("Error deleting ims_usrloc_pcscf record in DB");
+		    }
+
+		    update_stat(_c->slot->d->expired, 1);
+		    mem_delete_pcontact(_c->slot->d, _c);
+		    return;
 		}
-
-		update_stat(_c->slot->d->expired, 1);
-		mem_delete_pcontact(_c->slot->d, _c);
-		return;
 	}
 
 	//TODO: this is just for tmp debugging

+ 355 - 84
src/modules/ims_usrloc_pcscf/udomain.c

@@ -57,12 +57,14 @@
 #include "usrloc.h"
 #include "utime.h"
 #include "usrloc.h"
+#include "ul_callback.h"
 #include "usrloc_db.h"
 #include "../../core/parser/parse_uri.h"
 
 #include "../../lib/ims/useful_defs.h"
 #include "../../modules/presence/presence.h"
-
+extern int expires_grace;
+extern int audit_expired_pcontacts_timeout;
 extern int db_mode;
 extern int db_mode_ext;
 extern int match_contact_host_port;
@@ -406,9 +408,9 @@ int update_pcontact(struct udomain* _d, struct pcontact_info* _ci, struct pconta
 
 	//TODO: update path, etc
 
-	if (db_mode == WRITE_THROUGH && db_update_pcontact(_c) != 0) {
-		LM_ERR("Error updating record in DB");
-		return -1;
+	if (((db_mode == WRITE_THROUGH) || (db_mode == DB_ONLY)) && (db_update_pcontact(_c) != 0)){
+	        LM_ERR("Error updating record in DB");
+	        return -1;
 	}
 
 	run_ul_callbacks(PCSCF_CONTACT_UPDATE, _c);
@@ -428,7 +430,7 @@ int insert_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci
 		run_ul_create_callbacks(*_c);
 	}
 
-	if (db_mode == WRITE_THROUGH && db_insert_pcontact(*_c) != 0) {
+	if (((db_mode == WRITE_THROUGH) || (db_mode == DB_ONLY)) && db_insert_pcontact(*_c) != 0) {
 		LM_ERR("error inserting contact into db");
 		goto error;
 	}
@@ -447,7 +449,7 @@ error:
  * @int reverse_search - reverse search for a contact in the memory
  * @return 0 if found <>0 if not
  */
-int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact** _c, int reverse_search) {
+int get_pcontact_from_cache(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact** _c, int reverse_search) {
 	unsigned int sl, i, j, aorhash, params_len, has_rinstance=0;
 	struct pcontact* c;
 	struct sip_uri needle_uri;
@@ -468,7 +470,7 @@ int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact**
 		LM_DBG("Have an AOR to search for\n");
 		if (parse_uri(contact_info->aor.s, contact_info->aor.len, &needle_uri) != 0) {
 			LM_ERR("Unable to parse contact aor in get_pcontact [%.*s]\n", contact_info->aor.len, contact_info->aor.s);
-			return 0;
+			return 1;
 		}
 		LM_DBG("checking for rinstance");
 		/*check for alias - NAT */
@@ -570,12 +572,33 @@ int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact**
 					LM_DBG("confirming rinstance is the same - search has [%.*s] and proposed found contact has [%.*s]",
 							rinstance.len, rinstance.s,
 							c->rinstance.len, c->rinstance.s);
-					if ((rinstance.len == c->rinstance.len) && memcmp(rinstance.s, c->rinstance.s, rinstance.len) != 0) {
+ 		            if ((rinstance.len != c->rinstance.len) || (memcmp(rinstance.s, c->rinstance.s, rinstance.len) != 0) ) {
 						LM_DBG("rinstance does not match - no match here...\n");
 						c = reverse_search ? c->prev : c->next;
 						continue;
 					}
 				}
+                if ((contact_info->aor.len>0) && (needle_uri.user.len != 0)){
+                   if ((needle_uri.user.len != c->contact_user.len) ||
+                       (memcmp(needle_uri.user.s, c->contact_user.s, needle_uri.user.len) != 0)) {
+                                   LM_ERR("user name does not match - no match here...\n");
+                                   LM_DBG("found pcontact username [%d]: [%.*s]\n", i, c->contact_user.len, c->contact_user.s);
+                                   LM_DBG("incoming contact username: [%.*s]\n", needle_uri.user.len, needle_uri.user.s);
+                                   c = c->next;
+                                   continue;
+                   }
+                   if ((contact_info->aor.len >= 4) && (memcmp(contact_info->aor.s, c->aor.s, 4) != 0)) {   // do not mix up sip- and tel-URIs.
+                                LM_ERR("scheme does not match - no match here...\n");
+                                LM_DBG("found pcontact scheme [%d]: [%.*s]\n", i, 4, c->aor.s);
+                                LM_DBG("incoming contact scheme: [%.*s]\n", 4, contact_info->aor.s);
+                                c = c->next;
+                                continue;
+                   }
+                }
+                else{
+                    LM_DBG("No user name present - abort user name check\n");
+                }
+				
 			
 				if ((contact_info->extra_search_criteria & SEARCH_SERVICE_ROUTES) && contact_info->num_service_routes > 0) {
 					LM_DBG("have %d service routes to search for\n", contact_info->num_service_routes);
@@ -626,7 +649,7 @@ int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact**
 }
 
 int update_security(udomain_t* _d, security_type _t, security_t* _s, struct pcontact* _c) {
-	if (db_mode == WRITE_THROUGH && db_update_pcontact_security(_c, _t, _s) != 0) {
+	if (((db_mode == WRITE_THROUGH) || (db_mode == DB_ONLY)) && db_update_pcontact_security(_c, _t, _s) != 0) {
 		LM_ERR("Error updating security for contact in DB\n");
 		return -1;
 	}
@@ -635,7 +658,7 @@ int update_security(udomain_t* _d, security_type _t, security_t* _s, struct pcon
 }
 
 int update_temp_security(udomain_t* _d, security_type _t, security_t* _s, struct pcontact* _c) {
-	if (db_mode == WRITE_THROUGH && db_update_pcontact_security_temp(_c, _t, _s) != 0) {
+	if (((db_mode == WRITE_THROUGH) || (db_mode == DB_ONLY)) && db_update_pcontact_security_temp(_c, _t, _s) != 0) {
 		LM_ERR("Error updating temp security for contact in DB\n");
 		return -1;
 	}
@@ -698,8 +721,7 @@ int delete_pcontact(udomain_t* _d, /*str* _aor, str* _received_host, int _receiv
 	if (exists_ulcb_type(PCSCF_CONTACT_DELETE)) {
 		run_ul_callbacks(PCSCF_CONTACT_DELETE, _c);
 	}
-
-	if (db_mode == WRITE_THROUGH && db_delete_pcontact(_c) != 0) {
+	if (((db_mode == WRITE_THROUGH) || (db_mode == DB_ONLY)) && db_delete_pcontact(_c) != 0) {
 		LM_ERR("Error deleting contact from DB");
 		return -1;
 	}
@@ -1045,11 +1067,23 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d)
 			if ( (mem_insert_pcontact(_d, &aor, ci, &c)) != 0) {
 				LM_ERR("inserting contact failed\n");
 				unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
+				if(ci->public_ids){
+					pkg_free(ci->public_ids);
+				}
+				if(ci->service_routes){
+					pkg_free(ci->service_routes);	
+				}			
 				goto error1;
 			}
 			//c->flags = c->flags|(1<<FLAG_READFROMDB);
 			//TODO: need to subscribe to s-cscf for first public identity
 			unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
+			if(ci->public_ids){
+				pkg_free(ci->public_ids);
+			}
+			if(ci->service_routes){
+				pkg_free(ci->service_routes);	
+			}			
 		}
 
 		if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
@@ -1077,91 +1111,328 @@ error1:
 	return -1;
 }
 
-pcontact_t* db_load_pcontact(db1_con_t* _c, udomain_t* _d, str *_aor)
+int db_load_pcontact(udomain_t* _d, str *_aor, int insert_cache, struct pcontact** _c, pcontact_info_t* contact_info)
 {
 	pcontact_info_t *ci;
-	db_key_t columns[15];
-	db_key_t keys[1];
-	db_val_t vals[1];
-	db1_res_t* res = NULL;
-	db_row_t *row;
-	int i;
-	str aor;
+        db_key_t columns[15];
+        db_key_t keys[2];
+        db_val_t vals[2];
+        db_op_t op[2];
+        db1_res_t* res = NULL;
+        db_row_t *row;
+        int i;
+        str aor, port={0,0};
+        pcontact_t* c = NULL;
+
+        keys[0] = &aor_col;
+        vals[0].type = DB1_STR;
+        vals[0].nul = 0;
+        vals[0].val.str_val = *_aor;
+        op[0] = OP_EQ;
+        op[1] = OP_EQ;
+
+
+        columns[0] = &domain_col;
+        columns[1] = &aor_col;
+        columns[2] = &host_col;
+        columns[3] = &port_col;
+        columns[4] = &protocol_col;
+        columns[5] = &received_col;
+        columns[6] = &received_port_col;
+        columns[7] = &received_proto_col;
+        columns[8] = &rx_session_id_col;
+        columns[9] = &reg_state_col;
+        columns[10] = &expires_col;
+        columns[11] = &socket_col;
+        columns[12] = &service_routes_col;
+        columns[13] = &public_ids_col;
+        columns[14] = &path_col;
+
+
+
+        if (_aor->len>0 && _aor->s){
+                LM_DBG("Querying database for P-CSCF contact [%.*s]\n", _aor->len, _aor->s);
+        } else {
+                LM_DBG("Querying database for P-CSCF received_host [%.*s] and received_port [%d]\n", contact_info->received_host.len, contact_info->received_host.s, contact_info->received_port);
+                keys[0] = &received_col;
+                vals[0].type = DB1_STR;
+                vals[0].nul = 0;
+                vals[0].val.str_val = contact_info->received_host;
+                keys[1] = &received_port_col;
+                vals[1].type = DB1_INT;
+                vals[1].nul = 0;
+                port.s = int2str(contact_info->received_port, &port.len);
+                vals[1].val.int_val = contact_info->received_port;
+
+        }
+
+        if (ul_dbf.use_table(ul_dbh, _d->name) < 0) {
+                LM_ERR("sql use_table failed\n");
+                return -1;
+        }
+
+
+        if (ul_dbf.query(ul_dbh, keys, op, vals, columns, port.s ? 2 : 1, 15, 0, &res) < 0) {
+                if (!port.s) {
+                        LM_ERR("Unable to query DB for location associated with aor [%.*s]\n", _aor->len, _aor->s);
+                }
+                else {
+                        LM_ERR("Unable to query DB for location associated with host [%.*s] and port [%.*s]\n", contact_info->received_host.len, contact_info->received_host.s, port.len, port.s);
+                }
+                ul_dbf.free_result(ul_dbh, res);
+                return 0;
+        }
+ 
+	if (RES_ROW_N(res) == 0) {
+                if (!port.s) {
+                        LM_DBG("aor [%.*s] not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
+                }
+                else {
+                        LM_DBG("host [%.*s] and port [%.*s] not found in table %.*s\n", contact_info->received_host.len, contact_info->received_host.s, port.len, port.s, _d->name->len, _d->name->s);
+                }
+
+		ul_dbf.free_result(ul_dbh, res);
+                return 0;
+        }
+        LM_DBG("Handling Result for query received\n");
+
+        for(i = 0; i < RES_ROW_N(res); i++) {
+                row = RES_ROWS(res) + i;
+
+                aor.s = (char*) VAL_STRING(ROW_VALUES(row) + 1);
+                if (VAL_NULL(ROW_VALUES(row) + 1) || aor.s == 0 || aor.s[0] == 0) {
+                        LM_ERR("empty aor record in table %s...skipping\n", _d->name->s);
+                        continue;
+                }
+                aor.len = strlen(aor.s);
+
+                if ((_aor->len==0 && !_aor->s) && (VAL_NULL(ROW_VALUES(row) + 5) || VAL_NULL(ROW_VALUES(row) + 6))){
+                        LM_ERR("empty received_host or received_port record in table %s...skipping\n", _d->name->s);
+                        continue;
+                }
+                LM_DBG("Convert database values extracted with AOR.");
+                ci = dbrow2info(ROW_VALUES(row) + 1, &aor);
+                if (!ci) {
+                        LM_WARN("Failed to get contact info from DB.... continuing...\n");
+                        continue;
+                }
+
+                if(!(insert_cache)){
+                       (*_c)->expires = ci->expires;
+                      ul_dbf.free_result(ul_dbh, res);
+					if(ci->public_ids){
+						pkg_free(ci->public_ids);
+					}
+					if(ci->service_routes){
+						pkg_free(ci->service_routes);	
+					}		
+					LM_DBG("Freed memory in db_load_pcontact");
+                      return 1;
+                }
+				if(ci->reg_state==PCONTACT_REGISTERED){
+					if ( (mem_insert_pcontact(_d, &aor, ci, &c)) != 0) {
+							if(ci->public_ids){
+								pkg_free(ci->public_ids);
+							}
+							if(ci->service_routes){
+								pkg_free(ci->service_routes);	
+							}			
+							LM_ERR("inserting contact failed\n");
+							goto error;
+					}
+				}else {
+					if(ci->public_ids){
+						pkg_free(ci->public_ids);
+					}
+					if(ci->service_routes){
+						pkg_free(ci->service_routes);	
+					}
+					LM_ERR("inserting contact failed\n");
+					goto error1;
+				}
+                if (exists_ulcb_type(PCSCF_CONTACT_INSERT)) {
+                        run_ul_create_callbacks(c);
+                }
 
-	pcontact_t* c;
+                register_ulcb(c, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE | PCSCF_CONTACT_UPDATE, cbp_registrar->callback, NULL);
 
-	keys[0] = &aor_col;
-	vals[0].type = DB1_STR;
-	vals[0].nul = 0;
-	vals[0].val.str_val = *_aor;
+                if (c->rx_session_id.len > 0){
+                        register_ulcb(c, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, cbp_qos->callback, NULL);
+                }
+		
+		//c->flags = c->flags|(1<<FLAG_READFROMDB);
+		//TODO: need to subscribe to s-cscf for first public identity
+                
+                LM_DBG("inserting contact done\n");
+                *_c = c;
+				if(ci->public_ids){
+					pkg_free(ci->public_ids);
+				}
+				if(ci->service_routes){
+					pkg_free(ci->service_routes);	
+				}			
 
-	columns[0] = &domain_col;
-	columns[1] = &aor_col;
-	columns[2] = &host_col;
-	columns[3] = &port_col;
-	columns[4] = &protocol_col;
-	columns[5] = &received_col;
-	columns[6] = &received_port_col;
-	columns[7] = &received_proto_col;
-	columns[8] = &rx_session_id_col;
-	columns[9] = &reg_state_col;
-	columns[10] = &expires_col;
-	columns[11] = &socket_col;
-	columns[12] = &service_routes_col;
-	columns[13] = &public_ids_col;
-	columns[14] = &path_col;
-        
-	LM_DBG("Querying database for P-CSCF contact [%.*s]\n", _aor->len, _aor->s);
-        
-	if (ul_dbf.use_table(_c, _d->name) < 0) {
-		LM_ERR("failed to use table %.*s\n", _d->name->len, _d->name->s);
-		return 0;
 	}
 
-	if (ul_dbf.query(_c, keys, 0, vals, columns, 1, 15, 0, &res) < 0) {
-		LM_ERR("db_query failed\n");
-		return 0;
-	}
+        ul_dbf.free_result(ul_dbh, res);
+	return 1;
 
-	if (RES_ROW_N(res) == 0) {
-		LM_DBG("aor %.*s not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
-		ul_dbf.free_result(_c, res);
-		return 0;
-	}
+error:
+               free_pcontact(c);
+error1:
+               ul_dbf.free_result(ul_dbh, res);
+               return 0;
+}
 
-	for(i = 0; i < RES_ROW_N(res); i++) {
-		row = RES_ROWS(res) + i;
-		aor.s = (char*) VAL_STRING(ROW_VALUES(row) + 1);
-		if (VAL_NULL(ROW_VALUES(row) + 1) || aor.s == 0 || aor.s[0] == 0) {
-			LM_CRIT("empty aor record in table %s...skipping\n", _d->name->s);
-			continue;
-		}
-		aor.len = strlen(aor.s);
-		ci = dbrow2info(ROW_VALUES(row) + 1, &aor);
-		if (!ci) {
-			LM_WARN("Failed to get contact info from DB.... continuing...\n");
-			continue;
-		}
-		lock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
-			if ( (mem_insert_pcontact(_d, &aor, ci, &c)) != 0) {
-			LM_ERR("inserting contact failed\n");
-			unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
-			goto error;
-		}
-		//c->flags = c->flags|(1<<FLAG_READFROMDB);
-		//TODO: need to subscribe to s-cscf for first public identity
-		unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
-	}
 
-	ul_dbf.free_result(_c, res);
+int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact** _c, int reverse_search) {
 
-	return c;
+    int ret = get_pcontact_from_cache(_d,  contact_info,  _c, reverse_search);
+
+    if (ret && (db_mode == DB_ONLY)){
+            LM_DBG("contact not found in cache for contact_info->received_port [%d]\n", contact_info->received_port);
+           if (contact_info->searchflag == SEARCH_RECEIVED){
+                   	LM_DBG("Trying contact_info.extra_search_criteria = 0\n");
+                        contact_info->extra_search_criteria = 0;
+                        ret = get_pcontact_from_cache(_d,  contact_info,  _c, reverse_search);
+                        if (ret == 0){
+                                return ret;
+                        }
+                        LM_DBG("contact not found in cache for contact_info->via_port [%d]\n", contact_info->via_port);
+                        contact_info->extra_search_criteria = SEARCH_SERVICE_ROUTES;
+
+                        contact_info->searchflag = SEARCH_NORMAL;
+                        LM_DBG("Trying contact_info.searchflag = SEARCH_NORMAL\n");
+                        ret = get_pcontact_from_cache(_d,  contact_info,  _c, reverse_search);
+                        if (ret == 0){
+                                 return ret;
+                        }
+                        else {
+                                LM_DBG("Trying contact_info.extra_search_criteria = 0\n");
+                                contact_info->extra_search_criteria = 0;
+                                ret = get_pcontact_from_cache(_d,  contact_info,  _c, reverse_search);
+                                if (ret == 0){
+                                         return ret;
+                                }
+                                LM_DBG("contact not found in cache for contact_info->via_port [%d]\n", contact_info->via_port);
+                                contact_info->extra_search_criteria = SEARCH_SERVICE_ROUTES;
+                                contact_info->searchflag = SEARCH_RECEIVED;
+                        }
+           }
+                        else {
+                        LM_DBG("Trying contact_info.extra_search_criteria = 0\n");
+                        contact_info->extra_search_criteria = 0;
+                        ret = get_pcontact_from_cache(_d,  contact_info,  _c, reverse_search);
+                        if (ret == 0){
+                                return ret;
+                        }
+                        LM_DBG("contact not found in cache for contact_info->via_port [%d]\n", contact_info->via_port);
+                        contact_info->extra_search_criteria = SEARCH_SERVICE_ROUTES;
+           }
+           if (db_load_pcontact(_d, &contact_info->aor, 1/*insert_cache*/, _c, contact_info)){
+                   LM_DBG("loaded location from db for  AOR [%.*s]\n", contact_info->aor.len, contact_info->aor.s);
+                   return 0;
+           } else {
+                   LM_DBG("download location DB failed for  AOR [%.*s]\n", contact_info->aor.len, contact_info->aor.s);
+                   return 1;
+           }
+    }
 
-error:
-	free_pcontact(c);
+    return ret;
 
-	ul_dbf.free_result(_c, res);
-	return 0;
 }
 
 
+int audit_usrloc_expired_pcontacts(udomain_t* _d) {
+
+        db1_res_t* location_rs = NULL;
+        pcontact_info_t *ci;
+        db_key_t columns[15];
+        db_key_t keys[1];
+        db_val_t vals[1];
+        db_op_t op[1];
+        db_row_t *row;
+        int i;
+        str aor;
+        pcontact_t* c = NULL;
+
+        keys[0] = &expires_col;
+        vals[0].type = DB1_DATETIME;
+        vals[0].nul = 0;
+        vals[0].val.time_val = time(0) - expires_grace - audit_expired_pcontacts_timeout;;
+        op[0] = OP_LT;
+
+
+        columns[0] = &domain_col;
+        columns[1] = &aor_col;
+        columns[2] = &host_col;
+        columns[3] = &port_col;
+        columns[4] = &protocol_col;
+        columns[5] = &received_col;
+        columns[6] = &received_port_col;
+        columns[7] = &received_proto_col;
+        columns[8] = &rx_session_id_col;
+        columns[9] = &reg_state_col;
+        columns[10] = &expires_col;
+        columns[11] = &socket_col;
+        columns[12] = &service_routes_col;
+        columns[13] = &public_ids_col;
+        columns[14] = &path_col;
+
+        if (ul_dbf.use_table(ul_dbh, _d->name) < 0) {
+                LM_ERR("sql use_table failed\n");
+                return -1;
+        }
+
+        if (ul_dbf.query(ul_dbh, keys, op, vals, columns, 1, 15, 0, &location_rs) < 0) {
+            LM_ERR("Unable to query DB for expired pcontacts\n");
+            ul_dbf.free_result(ul_dbh, location_rs);
+        } else {
+             if (RES_ROW_N(location_rs) == 0) {
+                 LM_DBG("no expired pcontacts found in DB\n");
+                 ul_dbf.free_result(ul_dbh, location_rs);
+                 goto done;
+             }
+
+             for(i = 0; i < RES_ROW_N(location_rs); i++) {
+                 row = RES_ROWS(location_rs) + i;
+
+                 aor.s = (char*) VAL_STRING(ROW_VALUES(row) + 1);
+
+                 if (VAL_NULL(ROW_VALUES(row) + 1) || aor.s == 0 || aor.s[0] == 0) {
+                     LM_ERR("empty aor record in table %s...skipping\n", _d->name->s);
+                     continue;
+                 }
+                 aor.len = strlen(aor.s);
+                 ci = dbrow2info(ROW_VALUES(row) + 1, &aor);
+                 if (!ci) {
+                     LM_ERR("Failed to get contact info from DB.... continuing...\n");
+                     continue;
+                 }
+                 ci->aor = aor;
+                 ci->searchflag = SEARCH_NORMAL;
+                 ci->reg_state = PCONTACT_ANY;
+                 lock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
+                 if (get_pcontact_from_cache(_d, ci, &c, 0) == 0){
+                     LM_DBG("found pcontact [%.*s] in cache.....should have been cleared by expiry handler\n", aor.len, aor.s);
+                 }
+                 else{
+                    // insert pcontact
+                    if (!(db_load_pcontact(_d, &aor, 1/*insert_cache*/, &c, ci))){                   
+                        LM_ERR("could not insert pcontact [%.*s] into cache\n", aor.len, aor.s);
+                    }
+                 }
+                 unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
+	         if(ci->public_ids){
+                     pkg_free(ci->public_ids);
+                 }
+         	 if(ci->service_routes){
+                     pkg_free(ci->service_routes);	
+                 }			
+             }
+             ul_dbf.free_result(ul_dbh, location_rs);
+        }
+done:
+   return 0;
+}
+

+ 3 - 1
src/modules/ims_usrloc_pcscf/udomain.h

@@ -40,6 +40,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+ 
 
 #ifndef UDOMAIN_H
 #define UDOMAIN_H
@@ -82,5 +83,6 @@ int update_security(udomain_t* _d, security_type _t, security_t* _s, struct pcon
 int update_temp_security(udomain_t* _d, security_type _t, security_t* _s, struct pcontact* _c);
 
 int preload_udomain(db1_con_t* _c, udomain_t* _d);
-
+int audit_usrloc_expired_pcontacts(udomain_t* _d);
+int db_load_pcontact(udomain_t* _d, str *_aor, int insert_cache, struct pcontact** _c, pcontact_info_t* contact_info);
 #endif

+ 49 - 3
src/modules/ims_usrloc_pcscf/ul_callback.c

@@ -44,14 +44,14 @@
  * 
  */
 
+
 #include <stdlib.h>
 
 #include "../../core/dprint.h"
 #include "../../core/error.h"
 #include "../../core/mem/shm_mem.h"
-#include "ul_callback.h"
-#include "usrloc.h"
-
+//#include "ul_callback.h"
+#include "../ims_usrloc_pcscf/usrloc.h"
 struct ulcb_head_list* ulcb_list = 0;			/*<! list for create callbacks */
 
 int init_ulcb_list(void)
@@ -98,6 +98,39 @@ void destroy_ul_callbacks_list(struct ul_callback* cb) {
 	}
 }
 
+int register_ulcb_method( struct pcontact *c, int types, ul_cb f, void *param )
+{
+        //struct ul_callback *cbp;
+
+        /* are the callback types valid?... */
+        if ( types<0 || types>PCSCF_MAX ) {
+                LM_CRIT("invalid callback types: mask=%d\n",types);
+                return E_BUG;
+        }
+        /* we don't register null functions */
+        if (f==0) {
+                LM_CRIT("null callback function\n");
+                return E_BUG;
+        }
+
+        /* build a new callback structure */
+        if ( types & PCSCF_CONTACT_UPDATE){
+            if (!(cbp_registrar=(struct ul_callback*)shm_malloc(sizeof( struct ul_callback)))) {
+                LM_ERR("no more share mem\n");
+                return E_OUT_OF_MEM;
+            }
+            cbp_registrar->callback = f;
+        }
+        else{
+            if (!(cbp_qos=(struct ul_callback*)shm_malloc(sizeof( struct ul_callback)))) {
+                LM_ERR("no more share mem\n");
+                return E_OUT_OF_MEM;
+            }
+            cbp_qos->callback = f;
+        }
+        return 1;
+}
+
 int register_ulcb( struct pcontact *c, int types, ul_cb f, void *param )
 {
 	struct ul_callback *cbp;
@@ -182,6 +215,19 @@ void delete_ulcb(struct pcontact* c, int type)
 	LM_DBG("No ulcb has been deleted for contact: aor[%.*s], via port %u, received port %u\n", c->aor.len, c->aor.s, c->via_port, c->received_port);
 }
 
+int is_ulcb_registered( struct pcontact *c, ul_cb f)
+{
+	struct ul_callback *cbp;
+
+  for (cbp=c->cbs.first; cbp; cbp=cbp->next) {
+    if (cbp->callback == f)
+      return 1;
+  }
+  return 0;
+
+};
+
+
 /*! \brief run all transaction callbacks for an event type */
 void run_ul_callbacks( int type , struct pcontact *c)
 {

+ 9 - 0
src/modules/ims_usrloc_pcscf/ul_callback.h

@@ -42,11 +42,17 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  * 
  */
+ 
 
 #ifndef _UL_CALLBACKS_H
 #define _UL_CALLBACKS_H
 
 #include "../../core/dprint.h"
+#include "../../core/parser/msg_parser.h"
+#include "../../core/parser/contact/parse_contact.h" 
+#include "../../core/ut.h"
+#include "../ims_usrloc_pcscf/usrloc.h" 
+#include "../../lib/ims/ims_getters.h"
 
 struct pcontact;
 
@@ -58,6 +64,7 @@ struct pcontact;
 
 typedef void (ul_cb) (struct pcontact *c, int type, void *param);		/*! \brief callback function prototype */
 typedef int (*register_ulcb_t)(struct pcontact *c, int cb_types, ul_cb f, void *param);	/*! \brief register callback function prototype */
+typedef int (*is_ulcb_registered_t)(struct pcontact *c, ul_cb f);
 
 struct ul_callback {
 	int types;                   /*!< types of events that trigger the callback*/
@@ -82,7 +89,9 @@ void destroy_ulcb_list(void);
 void destroy_ul_callbacks_list(struct ul_callback* cb);
 int register_ulcb( struct pcontact *c, int types, ul_cb f, void *param);
 void delete_ulcb(struct pcontact* c, int type);
+int register_ulcb_method( struct pcontact *c, int types, ul_cb f, void *param);
 void run_ul_callbacks( int type , struct pcontact *c);
 void run_ul_create_callbacks(struct pcontact *c);
+int is_ulcb_registered(struct pcontact *c, ul_cb f);
 
 #endif

+ 80 - 76
src/modules/ims_usrloc_pcscf/ul_rpc.c

@@ -42,13 +42,15 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  * 
  */
-
+ 
 #include "../../core/ip_addr.h"
 #include "../../core/dprint.h"
 
 #include "ul_rpc.h"
 #include "dlist.h"
 #include "udomain.h"
+#include "pcontact.h"
+#include "utime.h"
 
 static const char* ul_rpc_dump_doc[2] = {
 	"Dump PCSCF contacts and associated identitites",
@@ -58,13 +60,15 @@ static const char* ul_rpc_dump_doc[2] = {
 static void ul_rpc_dump(rpc_t* rpc, void* ctx) {
 	dlist_t* dl;
 	udomain_t* dom;
-//	time_t t;
+	time_t t;
 	void* th;
 	void* ah;
 	void* sh;
 	int max, n, i;
 
-//	t = time(0);
+        pcontact_t* c;
+
+	t = time(0);
 	for (dl = root; dl; dl = dl->next) {
 		dom = dl->d;
 		if (rpc->add(ctx, "{", &th) < 0) {
@@ -78,82 +82,82 @@ static void ul_rpc_dump(rpc_t* rpc, void* ctx) {
 		}
 
 		for (i = 0, n = 0, max = 0; i < dom->size; i++) {
-//			lock_ulslot(dom, i);
+			lock_ulslot(dom, i);
 			n += dom->table[i].n;
 			if (max < dom->table[i].n)
 				max = dom->table[i].n;
-//			for (c = dom->table[i].first; c; c = c->next) {
-//				if (rpc->struct_add(ah, "S", "AoR", &c->aor) < 0) {
-//					unlock_ulslot(dom, i);
-//					rpc->fault(ctx, 500, "Internal error creating aor struct");
-//					return;
-//				}
-//				if (rpc->struct_add(ah, "s", "State", reg_state_to_string(c->reg_state)) < 0) {
-//					unlock_ulslot(dom, i);
-//					rpc->fault(ctx, 500, "Internal error creating reg state struct");
-//					return;
-//				}
-//				if (c->expires == 0) {
-//					if (rpc->struct_add(ah, "s", "Expires", "permanent") < 0) {
-//						unlock_ulslot(dom, i);
-//						rpc->fault(ctx, 500, "Internal error adding expire");
-//						return;
-//					}
-//				} else if (c->expires == -1/*UL_EXPIRED_TIME*/) {
-//					if (rpc->struct_add(ah, "s", "Expires", "deleted") < 0) {
-//						unlock_ulslot(dom, i);
-//						rpc->fault(ctx, 500, "Internal error adding expire");
-//						return;
-//					}
-//				} else if (t > c->expires) {
-//					if (rpc->struct_add(ah, "s", "Expires", "expired") < 0) {
-//						unlock_ulslot(dom, i);
-//						rpc->fault(ctx, 500, "Internal error adding expire");
-//						return;
-//					}
-//				} else {
-//					if (rpc->struct_add(ah, "d", "Expires", (int) (c->expires - t)) < 0) {
-//						unlock_ulslot(dom, i);
-//						rpc->fault(ctx, 500, "Internal error adding expire");
-//						return;
-//					}
-//				}
-//
-//				if (rpc->struct_add(ah, "S", "Path", &c->path) < 0) {
-//					unlock_ulslot(dom, i);
-//					rpc->fault(ctx, 500, "Internal error creating path struct");
-//					return;
-//				}
-//
-//				if (rpc->struct_add(ah, "{", "Service Routes", &sr) < 0) {
-//					unlock_ulslot(dom, i);
-//					rpc->fault(ctx, 500, "Internal error creating Service Routes");
-//					return;
-//				}
-//
-//				for (j = 0; j < c->num_service_routes; j++) {
-//					if (rpc->struct_add(sr, "S", "Route", &c->service_routes[j]) < 0) {
-//						unlock_ulslot(dom, i);
-//						rpc->fault(ctx, 500, "Internal error creating Service Route struct");
-//						return;
-//					}
-//				}
-//
-//				if (rpc->struct_add(ah, "{", "Public Identities", &ih) < 0) {
-//					unlock_ulslot(dom, i);
-//					rpc->fault(ctx, 500, "Internal error creating IMPU struct");
-//					return;
-//				}
-//
-//				for (p = c->head; p; p = p->next) {
-//					if (rpc->struct_add(ih, "S", "IMPU", &p->public_identity) < 0) {
-//						unlock_ulslot(dom, i);
-//						rpc->fault(ctx, 500, "Internal error creating IMPU struct");
-//						return;
-//					}
-//				}
-//			}
-//			unlock_ulslot(dom, i);
+			for (c = dom->table[i].first; c; c = c->next) {
+				if (rpc->struct_add(ah, "S", "AoR", &c->aor) < 0) {
+					unlock_ulslot(dom, i);
+					rpc->fault(ctx, 500, "Internal error creating aor struct");
+					return;
+				}
+				if (rpc->struct_add(ah, "s", "State", reg_state_to_string(c->reg_state)) < 0) {
+					unlock_ulslot(dom, i);
+					rpc->fault(ctx, 500, "Internal error creating reg state struct");
+					return;
+				}
+				if (c->expires == 0) {
+					if (rpc->struct_add(ah, "s", "Expires", "permanent") < 0) {
+						unlock_ulslot(dom, i);
+						rpc->fault(ctx, 500, "Internal error adding expire");
+						return;
+					}
+				} else if (c->expires == -1/*UL_EXPIRED_TIME*/) {
+					if (rpc->struct_add(ah, "s", "Expires", "deleted") < 0) {
+						unlock_ulslot(dom, i);
+						rpc->fault(ctx, 500, "Internal error adding expire");
+						return;
+					}
+				} else if (t > c->expires) {
+					if (rpc->struct_add(ah, "s", "Expires", "expired") < 0) {
+						unlock_ulslot(dom, i);
+						rpc->fault(ctx, 500, "Internal error adding expire");
+						return;
+					}
+				} else {
+					if (rpc->struct_add(ah, "d", "Expires", (int) (c->expires - t)) < 0) {
+						unlock_ulslot(dom, i);
+						rpc->fault(ctx, 500, "Internal error adding expire");
+						return;
+					}
+				}
+
+				if (rpc->struct_add(ah, "S", "Path", &c->path) < 0) {
+					unlock_ulslot(dom, i);
+					rpc->fault(ctx, 500, "Internal error creating path struct");
+					return;
+				}
+
+		//		if (rpc->struct_add(ah, "{", "Service Routes", &sr) < 0) {
+		//			unlock_ulslot(dom, i);
+		//			rpc->fault(ctx, 500, "Internal error creating Service Routes");
+		//			return;
+		//		}
+
+          //				for (j = 0; j < c->num_service_routes; j++) {
+	//				if (rpc->struct_add(sr, "S", "Route", &c->service_routes[j]) < 0) {
+	//					unlock_ulslot(dom, i);
+	//					rpc->fault(ctx, 500, "Internal error creating Service Route struct");
+	//					return;
+	//				}
+		//		}
+
+	//			if (rpc->struct_add(ah, "{", "Public Identities", &ih) < 0) {
+	//				unlock_ulslot(dom, i);
+	//				rpc->fault(ctx, 500, "Internal error creating IMPU struct");
+	//				return;
+	//			}
+
+	//			for (p = c->head; p; p = p->next) {
+	//				if (rpc->struct_add(ih, "S", "IMPU", &p->public_identity) < 0) {
+	//					unlock_ulslot(dom, i);
+	//					rpc->fault(ctx, 500, "Internal error creating IMPU struct");
+	//					return;
+	//				}
+	//			}
+			}
+			unlock_ulslot(dom, i);
 		}
 		if (rpc->struct_add(ah, "{", "Stats", &sh) > 0) {
 			rpc->fault(ctx, 500, "Internal error creating stats");

+ 10 - 2
src/modules/ims_usrloc_pcscf/usrloc.c

@@ -42,7 +42,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  * 
  */
-
+ 
 #include "usrloc.h"
 #include "dlist.h"
 #include "pcontact.h"
@@ -53,6 +53,10 @@
 
 extern int ims_ulp_init_flag;
 
+struct ul_callback *cbp_registrar = 0;
+struct ul_callback *cbp_qos = 0;
+
+
 int bind_usrloc(usrloc_api_t* api) {
 	if (!api) {
 		LM_ERR("invalid parameter value\n");
@@ -70,7 +74,7 @@ int bind_usrloc(usrloc_api_t* api) {
 	api->unlock_udomain = unlock_udomain;
 	api->insert_pcontact = insert_pcontact;
 	api->delete_pcontact = delete_pcontact;
-    api->unreg_pending_contacts_cb = unreg_pending_contacts_cb;
+        api->unreg_pending_contacts_cb = unreg_pending_contacts_cb;
 	api->get_pcontact = get_pcontact;
 	api->assert_identity = assert_identity;
 	api->update_pcontact = update_pcontact;
@@ -80,6 +84,10 @@ int bind_usrloc(usrloc_api_t* api) {
 	api->update_temp_security = update_temp_security;
 	api->register_ulcb = register_ulcb;
 	api->get_number_of_contacts = get_number_of_contacts;
+	api->is_ulcb_registered = is_ulcb_registered;
+	api->register_ulcb_method = register_ulcb_method;
+
+        api->db_mode    = db_mode;
 
 	return 0;
 }

+ 9 - 1
src/modules/ims_usrloc_pcscf/usrloc.h

@@ -41,6 +41,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+ 
 
 #ifndef USRLOC_H
 #define USRLOC_H
@@ -56,7 +57,7 @@
 #define NO_DB         0
 #define WRITE_THROUGH 1
 #define WRITE_BACK    2		//not implemented yet
-#define DB_ONLY	      3		//not implemented yet
+#define DB_ONLY	      3
 
 #define SEARCH_NORMAL 0
 #define SEARCH_RECEIVED 1
@@ -239,6 +240,9 @@ typedef struct pcontact {
 
 typedef int (*get_pcontact_t)(struct udomain* _d, pcontact_info_t* contact_info, struct pcontact** _c, int reverse_search);
 
+typedef int (*db_load_pcontact_t)(udomain_t* _d, str *_aor, int insert_cache, struct pcontact** _c, pcontact_info_t* contact_info);
+extern struct ul_callback *cbp_registrar; 
+extern struct ul_callback *cbp_qos; 
 typedef int (*assert_identity_t)(struct udomain* _d, str * _host, unsigned short _port, unsigned short _proto, str * _identity);
 
 typedef int (*insert_pcontact_t)(struct udomain* _d, str* _aor, struct pcontact_info* ci, struct pcontact** _c);
@@ -286,6 +290,10 @@ typedef struct usrloc_api {
     register_ulcb_t register_ulcb;
 
 	get_number_of_contacts_t get_number_of_contacts;
+	
+    is_ulcb_registered_t is_ulcb_registered;
+    register_ulcb_t register_ulcb_method;
+    db_load_pcontact_t db_load_pcontact;
 } usrloc_api_t;
 
 /*! usrloc API export bind function */

+ 10 - 4
src/modules/ims_usrloc_pcscf/usrloc_db.c

@@ -122,6 +122,11 @@ int use_location_pcscf_table(str* domain)
 
 	return 0;
 }
+db1_con_t* get_db_handle () 
+{
+    return ul_dbh;
+
+}
 
 int db_update_pcontact(pcontact_t* _c)
 {
@@ -129,7 +134,7 @@ int db_update_pcontact(pcontact_t* _c)
 
 	db_val_t match_values[2];
 	db_key_t match_keys[2] = { &aor_col, &received_port_col };
-    db_op_t op[2];
+        db_op_t op[2];
 	db_key_t update_keys[8] = { &expires_col, &reg_state_col,
 								&service_routes_col, &received_col,
 								&received_port_col, &received_proto_col,
@@ -146,8 +151,8 @@ int db_update_pcontact(pcontact_t* _c)
 	VAL_NULL(match_values + 1)	= 0;
 	VAL_INT(match_values + 1)	= _c->received_port;
 	
-	op[0]=OP_EQ;
-	op[1]=OP_EQ;
+    	op[0]=OP_EQ;
+    	op[1]=OP_EQ;
 
 	if (use_location_pcscf_table(_c->domain) < 0) {
 		LM_ERR("Error trying to use table %.*s\n", _c->domain->len, _c->domain->s);
@@ -200,6 +205,7 @@ int db_update_pcontact(pcontact_t* _c)
 	    return -1;
 	}
 
+
 	if (ul_dbf.affected_rows && ul_dbf.affected_rows(ul_dbh) == 0) {
 		LM_DBG("no existing rows for an update... doing insert\n");
 		if (db_insert_pcontact(_c) != 0) {
@@ -301,7 +307,7 @@ int db_insert_pcontact(struct pcontact* _c)
 	SET_PROPER_NULL_FLAG(_c->rinstance, values, LP_RINSTANCE_IDX);
 	SET_PROPER_NULL_FLAG(_c->rx_session_id, values, LP_RX_SESSION_ID_IDX);
 
-	VAL_DOUBLE(GET_FIELD_IDX(values, LP_REG_STATE_IDX)) = _c->reg_state;
+	VAL_INT(GET_FIELD_IDX(values, LP_REG_STATE_IDX)) = _c->reg_state;
 	VAL_TIME(GET_FIELD_IDX(values, LP_EXPIRES_IDX)) = _c->expires;
 	VAL_NULL(GET_FIELD_IDX(values, LP_REG_STATE_IDX)) = 0;
 	VAL_NULL(GET_FIELD_IDX(values, LP_EXPIRES_IDX)) = 0;

+ 1 - 1
src/modules/ims_usrloc_pcscf/usrloc_db.h

@@ -142,5 +142,5 @@ int db_delete_pcontact(pcontact_t* _c);
 int db_update_pcontact(pcontact_t* _c);
 int db_update_pcontact_security_temp(struct pcontact* _c, security_type _t, security_t* _s);
 int db_update_pcontact_security(struct pcontact* _c, security_type _t, security_t* _s);
-
+db1_con_t* get_db_handle ();
 #endif /* USRLOC_DB_H_ */