Browse Source

modules/ims_usrloc_scsc, modules/ims_registrar_scscf: overhaul of contact storage, more efficient and clean
NB API's have changed but fortunately no impact to any other modules.

Jason Penton 11 năm trước cách đây
mục cha
commit
0e59fd0c1d

+ 113 - 108
modules/ims_registrar_scscf/lookup.c

@@ -52,129 +52,134 @@
 #define allowed_method(_msg, _c) \
 	( !method_filtering || ((_msg)->REQ_METHOD)&((_c)->methods) )
 
-
 /*! \brief
  * Lookup contact in the database and rewrite Request-URI
  * \return: -1 : not found
  *          -2 : found but method not allowed
  *          -3 : error
  */
-int lookup(struct sip_msg* _m, udomain_t* _d)
-{
-	impurecord_t* r;
-	str aor, uri;
-	ucontact_t* ptr;
-	int res;
-	int ret;
-	str path_dst;
-	flag_t old_bflags;
-
-
-	if (_m->new_uri.s) uri = _m->new_uri;
-	else uri = _m->first_line.u.request.uri;
-
-	if (extract_aor(&uri, &aor) < 0) {
-		LM_ERR("failed to extract address of record\n");
-		return -3;
-	}
-
-	get_act_time();
-
-	ul.lock_udomain(_d, &aor);
-	res = ul.get_impurecord(_d, &aor, &r);
-	if (res > 0) {
-		LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s));
-		ul.unlock_udomain(_d, &aor);
-		return -1;
+int lookup(struct sip_msg* _m, udomain_t* _d) {
+    impurecord_t* r;
+    str aor, uri;
+    ucontact_t* ptr;
+    int res;
+    int ret;
+    str path_dst;
+    flag_t old_bflags;
+    int i = 0;
+
+
+    if (_m->new_uri.s) uri = _m->new_uri;
+    else uri = _m->first_line.u.request.uri;
+
+    if (extract_aor(&uri, &aor) < 0) {
+	LM_ERR("failed to extract address of record\n");
+	return -3;
+    }
+
+    get_act_time();
+
+    ul.lock_udomain(_d, &aor);
+    res = ul.get_impurecord(_d, &aor, &r);
+    if (res > 0) {
+	LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s));
+	ul.unlock_udomain(_d, &aor);
+	return -1;
+    }
+    ret = -1;
+
+    while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) {
+	if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) {
+	    LM_DBG("Found a valid contact [%.*s]\n", ptr->c.len, ptr->c.s);
+	    i++;
+	    break;
 	}
-
-	ptr = r->contacts;
-	ret = -1;
-	/* look first for an un-expired and suported contact */
-	while ( (ptr) &&
-	!(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr)))
-		ptr = ptr->next;
-	if (ptr==0) {
-		/* nothing found */
-		goto done;
+	i++;
+    }
+
+    /* look first for an un-expired and suported contact */
+    if (ptr == 0) {
+	/* nothing found */
+	goto done;
+    }
+
+    ret = 1;
+    if (ptr) {
+	if (rewrite_uri(_m, &ptr->c) < 0) {
+	    LM_ERR("unable to rewrite Request-URI\n");
+	    ret = -3;
+	    goto done;
 	}
 
-	ret = 1;
-	if (ptr) {
-		if (rewrite_uri(_m, &ptr->c) < 0) {
-			LM_ERR("unable to rewrite Request-URI\n");
-			ret = -3;
-			goto done;
-		}
-
-		/* reset next hop address */
-		reset_dst_uri(_m);
-
-		/* If a Path is present, use first path-uri in favour of
-		 * received-uri because in that case the last hop towards the uac
-		 * has to handle NAT. - agranig */
-		if (ptr->path.s && ptr->path.len) {
-			if (get_path_dst_uri(&ptr->path, &path_dst) < 0) {
-				LM_ERR("failed to get dst_uri for Path\n");
-				ret = -3;
-				goto done;
-			}
-			if (set_path_vector(_m, &ptr->path) < 0) {
-				LM_ERR("failed to set path vector\n");
-				ret = -3;
-				goto done;
-			}
-			if (set_dst_uri(_m, &path_dst) < 0) {
-				LM_ERR("failed to set dst_uri of Path\n");
-				ret = -3;
-				goto done;
-			}
-		} else if (ptr->received.s && ptr->received.len) {
-			if (set_dst_uri(_m, &ptr->received) < 0) {
-				ret = -3;
-				goto done;
-			}
-		}
-
-		set_ruri_q(ptr->q);
-
-		old_bflags = 0;
-		getbflagsval(0, &old_bflags);
-		setbflagsval(0, old_bflags|ptr->cflags);
-
-		if (ptr->sock)
-			set_force_socket(_m, ptr->sock);
+	/* reset next hop address */
+	reset_dst_uri(_m);
 
-		ptr = ptr->next;
+	/* If a Path is present, use first path-uri in favour of
+	 * received-uri because in that case the last hop towards the uac
+	 * has to handle NAT. - agranig */
+	if (ptr->path.s && ptr->path.len) {
+	    if (get_path_dst_uri(&ptr->path, &path_dst) < 0) {
+		LM_ERR("failed to get dst_uri for Path\n");
+		ret = -3;
+		goto done;
+	    }
+	    if (set_path_vector(_m, &ptr->path) < 0) {
+		LM_ERR("failed to set path vector\n");
+		ret = -3;
+		goto done;
+	    }
+	    if (set_dst_uri(_m, &path_dst) < 0) {
+		LM_ERR("failed to set dst_uri of Path\n");
+		ret = -3;
+		goto done;
+	    }
+	} else if (ptr->received.s && ptr->received.len) {
+	    if (set_dst_uri(_m, &ptr->received) < 0) {
+		ret = -3;
+		goto done;
+	    }
 	}
 
-	/* Append branches if enabled */
-	if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done;
-
-	for( ; ptr ; ptr = ptr->next ) {
-		if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) {
-			path_dst.len = 0;
-			if(ptr->path.s && ptr->path.len
-			&& get_path_dst_uri(&ptr->path, &path_dst) < 0) {
-				LM_ERR("failed to get dst_uri for Path\n");
-				continue;
-			}
-
-			/* The same as for the first contact applies for branches
-			 * regarding path vs. received. */
-			if (km_append_branch(_m,&ptr->c,path_dst.len?&path_dst:&ptr->received,
-			&ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) {
-				LM_ERR("failed to append a branch\n");
-				/* Also give a chance to the next branches*/
-				continue;
-			}
-		}
+	set_ruri_q(ptr->q);
+
+	old_bflags = 0;
+	getbflagsval(0, &old_bflags);
+	setbflagsval(0, old_bflags | ptr->cflags);
+
+	if (ptr->sock)
+	    set_force_socket(_m, ptr->sock);
+
+	ptr = ptr->next;
+    }
+
+    /* Append branches if enabled */
+    if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done;
+
+    //the last i was the first valid contact we found - let's go through the rest of valid contacts and append the branches.
+    while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) {
+	if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) {
+	    path_dst.len = 0;
+	    if (ptr->path.s && ptr->path.len
+		    && get_path_dst_uri(&ptr->path, &path_dst) < 0) {
+		LM_ERR("failed to get dst_uri for Path\n");
+		continue;
+	    }
+
+	    /* The same as for the first contact applies for branches
+	     * regarding path vs. received. */
+	    if (km_append_branch(_m, &ptr->c, path_dst.len ? &path_dst : &ptr->received,
+		    &ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) {
+		LM_ERR("failed to append a branch\n");
+		/* Also give a chance to the next branches*/
+		continue;
+	    }
 	}
+	i++;
+    }
 
 done:
-	//ul.release_impurecord(r);
-	ul.unlock_udomain(_d, &aor);
-	return ret;
+    ul.unlock_udomain(_d, &aor);
+    return ret;
 }
 
 /*! \brief the impu_registered() function

+ 167 - 164
modules/ims_registrar_scscf/registrar_notify.c

@@ -126,127 +126,127 @@ void notify_destroy() {
     shm_free(notification_list);
 }
 
-
 int can_publish_reg(struct sip_msg *msg, char *_t, char *str2) {
-    
-	int ret = CSCF_RETURN_FALSE;
-	str presentity_uri = {0, 0};
-	str event;
-	str asserted_id;
-	ucontact_t* c = 0;
-	impurecord_t* r;
-	int res;
-	ims_public_identity *pi = 0;
-	int i, j;
 
-	LM_DBG("Checking if allowed to publish reg event\n");
+    int ret = CSCF_RETURN_FALSE;
+    str presentity_uri = {0, 0};
+    str event;
+    str asserted_id;
+    ucontact_t* c = 0;
+    impurecord_t* r;
+    int res;
+    ims_public_identity *pi = 0;
+    int i, j;
 
-	//check that this is a request
-	if (msg->first_line.type != SIP_REQUEST) {
-	    LM_ERR("This message is not a request\n");
-	    goto error;
-	}
+    LM_DBG("Checking if allowed to publish reg event\n");
 
-	//check that this is a subscribe request
-	if (msg->first_line.u.request.method.len != 7 ||
-		memcmp(msg->first_line.u.request.method.s, "PUBLISH", 7) != 0) {
-	    LM_ERR("This message is not a PUBLISH\n");
-	    goto error;
-	}
+    //check that this is a request
+    if (msg->first_line.type != SIP_REQUEST) {
+	LM_ERR("This message is not a request\n");
+	goto error;
+    }
 
-	//check that this is a reg event - currently we only support reg event!
-	event = cscf_get_event(msg);
-	if (event.len != 3 || strncasecmp(event.s, "reg", 3) != 0) {
-	    LM_ERR("Accepting only <Event: reg>. Found: <%.*s>\n",
-		    event.len, event.s);
-	    goto done;
-	}
+    //check that this is a subscribe request
+    if (msg->first_line.u.request.method.len != 7 ||
+	    memcmp(msg->first_line.u.request.method.s, "PUBLISH", 7) != 0) {
+	LM_ERR("This message is not a PUBLISH\n");
+	goto error;
+    }
 
-	asserted_id = cscf_get_asserted_identity(msg, 0);
-	if (!asserted_id.len) {
-	    LM_ERR("P-Asserted-Identity empty.\n");
-	    goto error;
-	}
-	LM_DBG("P-Asserted-Identity <%.*s>.\n", asserted_id.len, asserted_id.s);
+    //check that this is a reg event - currently we only support reg event!
+    event = cscf_get_event(msg);
+    if (event.len != 3 || strncasecmp(event.s, "reg", 3) != 0) {
+	LM_ERR("Accepting only <Event: reg>. Found: <%.*s>\n",
+		event.len, event.s);
+	goto done;
+    }
 
-	//get presentity URI
-	presentity_uri = cscf_get_public_identity_from_requri(msg);
-	
-	LM_DBG("Looking for IMPU in usrloc <%.*s>\n", presentity_uri.len, presentity_uri.s);
+    asserted_id = cscf_get_asserted_identity(msg, 0);
+    if (!asserted_id.len) {
+	LM_ERR("P-Asserted-Identity empty.\n");
+	goto error;
+    }
+    LM_DBG("P-Asserted-Identity <%.*s>.\n", asserted_id.len, asserted_id.s);
 
-	ul.lock_udomain((udomain_t*) _t, &presentity_uri);
-	res = ul.get_impurecord((udomain_t*) _t, &presentity_uri, &r);
+    //get presentity URI
+    presentity_uri = cscf_get_public_identity_from_requri(msg);
 
-	if (res > 0) {
-	    LM_DBG("'%.*s' Not found in usrloc\n", presentity_uri.len, presentity_uri.s);
-	    ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
-	    goto done;
-	}
+    LM_DBG("Looking for IMPU in usrloc <%.*s>\n", presentity_uri.len, presentity_uri.s);
 
-	LM_DBG("<%.*s> found in usrloc\n", presentity_uri.len, presentity_uri.s);
+    ul.lock_udomain((udomain_t*) _t, &presentity_uri);
+    res = ul.get_impurecord((udomain_t*) _t, &presentity_uri, &r);
 
-	//check if the asserted identity is in the same group as that presentity uri
-	if (r->public_identity.len == asserted_id.len &&
-		strncasecmp(r->public_identity.s, asserted_id.s, asserted_id.len) == 0) {
-	    LM_DBG("Identity found as AOR <%.*s>\n",
-		    presentity_uri.len, presentity_uri.s);
-	    ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
-	    ret = CSCF_RETURN_TRUE;
-	    goto done;
-	}
+    if (res > 0) {
+	LM_DBG("'%.*s' Not found in usrloc\n", presentity_uri.len, presentity_uri.s);
+	ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
+	goto done;
+    }
 
-	//check if asserted identity is in service profile
-	lock_get(r->s->lock);
-	if (r->s) {
-	    for (i = 0; i < r->s->service_profiles_cnt; i++)
-		for (j = 0; j < r->s->service_profiles[i].public_identities_cnt; j++) {
-		    pi = &(r->s->service_profiles[i].public_identities[j]);
-		    if (!pi->barring &&
-			    pi->public_identity.len == asserted_id.len &&
-			    strncasecmp(pi->public_identity.s, asserted_id.s, asserted_id.len) == 0) {
-			LM_DBG("Identity found in SP[%d][%d]\n",
-				i, j);
-			ret = CSCF_RETURN_TRUE;
-			ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
-			lock_release(r->s->lock);
-			goto done;
-		    }
+    LM_DBG("<%.*s> found in usrloc\n", presentity_uri.len, presentity_uri.s);
+
+    //check if the asserted identity is in the same group as that presentity uri
+    if (r->public_identity.len == asserted_id.len &&
+	    strncasecmp(r->public_identity.s, asserted_id.s, asserted_id.len) == 0) {
+	LM_DBG("Identity found as AOR <%.*s>\n",
+		presentity_uri.len, presentity_uri.s);
+	ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
+	ret = CSCF_RETURN_TRUE;
+	goto done;
+    }
+
+    //check if asserted identity is in service profile
+    lock_get(r->s->lock);
+    if (r->s) {
+	for (i = 0; i < r->s->service_profiles_cnt; i++)
+	    for (j = 0; j < r->s->service_profiles[i].public_identities_cnt; j++) {
+		pi = &(r->s->service_profiles[i].public_identities[j]);
+		if (!pi->barring &&
+			pi->public_identity.len == asserted_id.len &&
+			strncasecmp(pi->public_identity.s, asserted_id.s, asserted_id.len) == 0) {
+		    LM_DBG("Identity found in SP[%d][%d]\n",
+			    i, j);
+		    ret = CSCF_RETURN_TRUE;
+		    ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
+		    lock_release(r->s->lock);
+		    goto done;
 		}
-	}
-	lock_release(r->s->lock);
-	LM_DBG("Did not find p-asserted-identity <%.*s> in SP\n", asserted_id.len, asserted_id.s);
+	    }
+    }
+    lock_release(r->s->lock);
+    LM_DBG("Did not find p-asserted-identity <%.*s> in SP\n", asserted_id.len, asserted_id.s);
 
-	//check if asserted is present in any of the path headers
-	c = r->contacts;
+    //check if asserted is present in any of the path headers
+    j=0;
 
-	while (c) {
-	    if (c->path.len) {
-		LM_DBG("Path: <%.*s>.\n",
+    while (j<MAX_CONTACTS_PER_IMPU && (c=r->newcontacts[j])) {
+	if (c->path.len) {
+	    LM_DBG("Path: <%.*s>.\n",
 		    c->path.len, c->path.s);
-		for (i = 0; i < c->path.len - (asserted_id.len-4); i++)
-		    //we compare the asserted_id without "sip:" to the path 
-		    if (strncasecmp(c->path.s + i, asserted_id.s+4, asserted_id.len-4) == 0) {
-			LM_DBG("Identity found in Path <%.*s>\n",
-				c->path.len, c->path.s);
-			ret = CSCF_RETURN_TRUE;
-			ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
-			goto done;
-		    }
+	    for (i = 0; i < c->path.len - (asserted_id.len - 4); i++){
+		//we compare the asserted_id without "sip:" to the path 
+		if (strncasecmp(c->path.s + i, asserted_id.s + 4, asserted_id.len - 4) == 0) {
+		    LM_DBG("Identity found in Path <%.*s>\n",
+			    c->path.len, c->path.s);
+		    ret = CSCF_RETURN_TRUE;
+		    ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
+		    goto done;
+		}
 	    }
-	    c = c->next;
 	}
-	LM_DBG("Did not find p-asserted-identity <%.*s> on Path\n", asserted_id.len, asserted_id.s);
-	
-	ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
-	LM_DBG("Publish forbidden\n");
-    
+	j++;
+    }
+    LM_DBG("Did not find p-asserted-identity <%.*s> on Path\n", asserted_id.len, asserted_id.s);
+
+    ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
+    LM_DBG("Publish forbidden\n");
+
 done:
-	if (presentity_uri.s) shm_free(presentity_uri.s); // shm_malloc in cscf_get_public_identity_from_requri
-	return ret;
+    if (presentity_uri.s) shm_free(presentity_uri.s); // shm_malloc in cscf_get_public_identity_from_requri
+    return ret;
 error:
-	if (presentity_uri.s) shm_free(presentity_uri.s); // shm_malloc in cscf_get_public_identity_from_requri
-	ret = CSCF_RETURN_ERROR;
-	return ret;
+    if (presentity_uri.s) shm_free(presentity_uri.s); // shm_malloc in cscf_get_public_identity_from_requri
+    ret = CSCF_RETURN_ERROR;
+    return ret;
 }
 
 int can_subscribe_to_reg(struct sip_msg *msg, char *_t, char *str2) {
@@ -374,24 +374,25 @@ int can_subscribe_to_reg(struct sip_msg *msg, char *_t, char *str2) {
     LM_DBG("Did not find p-asserted-identity <%.*s> in SP\n", asserted_id.len, asserted_id.s);
 
     //check if asserted is present in any of the path headers
-    c = r->contacts;
-
-    while (c) {
+    j = 0;
+    while (j < MAX_CONTACTS_PER_IMPU && (c = r->newcontacts[j])) {
 	if (c->path.len) {
 	    LM_DBG("Path: <%.*s>.\n",
-		c->path.len, c->path.s);
-            for (i = 0; i < c->path.len - (asserted_id.len-4); i++)
+		    c->path.len, c->path.s);
+	    for (i = 0; i < c->path.len - (asserted_id.len - 4); i++) {
 		//we compare the asserted_id without "sip:" to the path 
-                if (strncasecmp(c->path.s + i, asserted_id.s+4, asserted_id.len-4) == 0) {
-                    LM_DBG("Identity found in Path <%.*s>\n",
-                            c->path.len, c->path.s);
-                    ret = CSCF_RETURN_TRUE;
-                    ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
-                    goto done;
-                }
-        }
-        c = c->next;
+		if (strncasecmp(c->path.s + i, asserted_id.s + 4, asserted_id.len - 4) == 0) {
+		    LM_DBG("Identity found in Path <%.*s>\n",
+			    c->path.len, c->path.s);
+		    ret = CSCF_RETURN_TRUE;
+		    ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
+		    goto done;
+		}
+	    }
+	}
+	j++;
     }
+
     LM_DBG("Did not find p-asserted-identity <%.*s> on Path\n", asserted_id.len, asserted_id.s);
     
     ul.unlock_udomain((udomain_t*) _t, &presentity_uri);
@@ -539,10 +540,13 @@ int process_contact(impurecord_t* presentity_impurecord, udomain_t * _d, int exp
 			if (contact_state == STATE_TERMINATED) {
 				//delete contact
 				LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
-				if (ul.delete_ucontact(implicit_impurecord, ucontact) != 0) {
+				ul.lock_contact_slot(&contact_uri);
+				if (ul.unlink_contact_from_impu(implicit_impurecord, ucontact, 1) != 0) {
 				    LM_ERR("Failed to delete ucontact <%.*s> from implicit IMPU\n", contact_uri.len, contact_uri.s);
-				    goto next_implicit_impu;
+				    ul.unlock_contact_slot(&contact_uri);
+				    goto next_implicit_impu;	//TODO: don't need to use goto here...
 				}
+				ul.unlock_contact_slot(&contact_uri);
 			}else {//state is active
 				LM_DBG("This contact: <%.*s> is not in state terminated and is in usrloc, ignore\n", contact_uri.len, contact_uri.s);
 				goto next_implicit_impu;
@@ -568,11 +572,14 @@ next_implicit_impu:
 		if (contact_state == STATE_TERMINATED) {
 			//delete contact
 			LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
-			if (ul.delete_ucontact(presentity_impurecord, ucontact) != 0) {
+			ul.lock_contact_slot(&contact_uri);
+			if (ul.unlink_contact_from_impu(presentity_impurecord, ucontact, 1) != 0) {
 			    LM_ERR("Failed to delete ucontact <%.*s>\n", contact_uri.len, contact_uri.s);
 			    ret = CSCF_RETURN_FALSE;
+    			    ul.unlock_contact_slot(&contact_uri);
 			    goto done;
 			}
+			ul.unlock_contact_slot(&contact_uri);
 		}else {//state is active
 			LM_DBG("This contact: <%.*s> is not in state terminated and is in usrloc, ignore\n", contact_uri.len, contact_uri.s);
 			goto done;
@@ -1434,8 +1441,8 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus) {
     str buf, pad;
     char bufc[MAX_REGINFO_SIZE], padc[MAX_REGINFO_SIZE];
     impurecord_t *r;
-    ucontact_t *c;
-    int i, res;
+    int i, j, res;
+    ucontact_t* ptr;
 
     buf.s = bufc;
     buf.len = 0;
@@ -1472,33 +1479,35 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus) {
         }
         pad.len = strlen(pad.s);
         STR_APPEND(buf, pad);
-        c = r->contacts;
-        LM_DBG("Scrolling through contact for this IMPU");
-        while (c) {
-            if (c->q != -1) {
-                LM_DBG("q value not equal to -1");
-                float q = (float) c->q / 1000;
-                sprintf(pad.s, contact_s_q.s, c, r_active.len, r_active.s,
-                        r_registered.len, r_registered.s, c->expires - act_time,
-                        q);
-            } else {
-                LM_DBG("q value equal to -1");
-                sprintf(pad.s, contact_s.s, c, r_active.len, r_active.s,
-                        r_registered.len, r_registered.s,
-                        c->expires - act_time);
-            }
-            pad.len = strlen(pad.s);
-            STR_APPEND(buf, pad);
-            STR_APPEND(buf, uri_s);
+        
+	j=0;
+	LM_DBG("Scrolling through contact for this IMPU");
+	while (j < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[j])) {
+	    if (ptr->q != -1) {
+		LM_DBG("q value not equal to -1");
+		float q = (float) ptr->q / 1000;
+		sprintf(pad.s, contact_s_q.s, ptr, r_active.len, r_active.s,
+			r_registered.len, r_registered.s, ptr->expires - act_time,
+			q);
+	    } else {
+		LM_DBG("q value equal to -1");
+		sprintf(pad.s, contact_s.s, ptr, r_active.len, r_active.s,
+			r_registered.len, r_registered.s,
+			ptr->expires - act_time);
+	    }
+	    pad.len = strlen(pad.s);
+	    STR_APPEND(buf, pad);
+	    STR_APPEND(buf, uri_s);
 
-            LM_DBG("Appending contact address: <%.*s>", c->c.len, c->c.s);
-	    
-            STR_APPEND(buf, (c->c));
-            STR_APPEND(buf, uri_e);
+	    LM_DBG("Appending contact address: <%.*s>", ptr->c.len, ptr->c.s);
 
-            STR_APPEND(buf, contact_e);
-            c = c->next;
-        }
+	    STR_APPEND(buf, (ptr->c));
+	    STR_APPEND(buf, uri_e);
+
+	    STR_APPEND(buf, contact_e);
+	    j++;
+	}
+	
         STR_APPEND(buf, registration_e);
 
         ul.unlock_udomain(_t, &impu_list[i]);
@@ -1529,14 +1538,12 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus) {
 
 str get_reginfo_partial(impurecord_t *r, ucontact_t *c, int event_type) {
     str x = {0, 0};
+    int i;
     str buf, pad;
     char bufc[MAX_REGINFO_SIZE], padc[MAX_REGINFO_SIZE];
     int expires = -1;
-    
     int terminate_impu = 1;
-    
     ucontact_t *c_tmp;
-
     str state, event;
 
     buf.s = bufc;
@@ -1552,31 +1559,28 @@ str get_reginfo_partial(impurecord_t *r, ucontact_t *c, int event_type) {
 
     if (r) {
         expires = c->expires - act_time;
-        if (r->contacts == c &&
-                //richard we only use expired and unregistered
+        if (//richard we only use expired and unregistered
                 (event_type == IMS_REGISTRAR_CONTACT_EXPIRED ||
                 event_type == IMS_REGISTRAR_CONTACT_UNREGISTERED)
                 ){
 	    //check if impu record has any other active contacts - if not then set this to terminated - if so then keep this active
 	    //check if asserted is present in any of the path headers
-	    c_tmp = r->contacts;
-
-	    while (c_tmp) {
-		if ((strncasecmp(c_tmp->c.s, c->c.s, c_tmp->c.len) != 0)  && ((c_tmp->expires - act_time) > 0)) {
+	    
+	    
+	    i=0;
+	    while (i<MAX_CONTACTS_PER_IMPU && (c_tmp=r->newcontacts[i])) {
+		if ((strncasecmp(c_tmp->c.s, c->c.s, c_tmp->c.len) != 0) && ((c_tmp->expires - act_time) > 0)) {
 		    LM_DBG("IMPU <%.*s> has another active contact <%.*s> so will set its state to active\n",
-			r->public_identity.len, r->public_identity.s, c_tmp->c.len, c_tmp->c.s);
-			terminate_impu = 0;
-			break;
+			    r->public_identity.len, r->public_identity.s, c_tmp->c.len, c_tmp->c.s);
+		    terminate_impu = 0;
+		    break;
 		}
-		c_tmp = c_tmp->next;
+		i++;
 	    }
-	    
-	    if(terminate_impu){
+	    if(terminate_impu)
 		sprintf(pad.s, registration_s.s, r->public_identity.len, r->public_identity.s, r, r_terminated.len, r_terminated.s);
-	    }else
-	    {
+	    else
 		sprintf(pad.s, registration_s.s, r->public_identity.len, r->public_identity.s, r, r_active.len, r_active.s);
-	    }
 	}
         else{
 	    sprintf(pad.s, registration_s.s, r->public_identity.len, r->public_identity.s, r, r_active.len, r_active.s);
@@ -1620,7 +1624,6 @@ str get_reginfo_partial(impurecord_t *r, ucontact_t *c, int event_type) {
             STR_APPEND(buf, uri_s);
             STR_APPEND(buf, (c->c));
             STR_APPEND(buf, uri_e);
-
             STR_APPEND(buf, contact_e);
             STR_APPEND(buf, registration_e);
         }

+ 3 - 3
modules/ims_registrar_scscf/regpv.c

@@ -455,7 +455,7 @@ int pv_fetch_contacts(struct sip_msg* msg, char* table, char* uri,
 		return -1;
 	}
 
-	ptr = r->contacts;
+	ptr = 0;//r->contacts;TODO
 	ptr0 = NULL;
 	n = 0;
 	while(ptr)
@@ -470,8 +470,8 @@ int pv_fetch_contacts(struct sip_msg* msg, char* table, char* uri,
 			goto error;
 		}
 		memcpy(c0, ptr, ilen);
-		c0->domain = NULL;
-		c0->aor = NULL;
+		//c0->domain = {0,0};//NULL;TODO
+		//c0->aor = {0,0};//NULL;
 		c0->next = NULL;
 		c0->prev = NULL;
 

+ 13 - 11
modules/ims_registrar_scscf/reply.c

@@ -88,12 +88,14 @@ static struct {
  * Calculate the length of buffer needed to
  * print contacts
  */
-static inline unsigned int calc_buf_len(ucontact_t* c) {
+static inline unsigned int calc_buf_len(impurecord_t* impurec) {
     unsigned int len;
     int qlen;
+    int i=0;
+    ucontact_t* c;
 
     len = 0;
-    while (c) {
+    while (i<MAX_CONTACTS_PER_IMPU && (c=impurec->newcontacts[i])) {
         if (VALID_CONTACT(c, act_time)) {
             if (len) len += CONTACT_SEP_LEN;
             len += 2 /* < > */ + c->c.len;
@@ -110,7 +112,7 @@ static inline unsigned int calc_buf_len(ucontact_t* c) {
                         ;
             }
         }
-        c = c->next;
+	i++;
     }
 
     if (len) len += CONTACT_BEGIN_LEN + CRLF_LEN;
@@ -395,12 +397,12 @@ int build_expired_contact(contact_t* chi, contact_for_header_t** contact_header)
 
 //We use shared memory for this so we can use it when we use async diameter
 
-int build_contact(ucontact_t* c, contact_for_header_t** contact_header) {
-
+int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header) {
     char *p, *cp;
     int fl, len;
-
+    ucontact_t* c;
     *contact_header = 0;
+    int i=0;
 
     contact_for_header_t* tmp_contact_header = shm_malloc(sizeof (contact_for_header_t));
     if (!tmp_contact_header) {
@@ -409,7 +411,7 @@ int build_contact(ucontact_t* c, contact_for_header_t** contact_header) {
     }
     memset(tmp_contact_header, 0, sizeof (contact_for_header_t));
 
-    tmp_contact_header->data_len = calc_buf_len(c);
+    tmp_contact_header->data_len = calc_buf_len(impurec);
     tmp_contact_header->buf = (char*)shm_malloc(tmp_contact_header->data_len);
 
     if (tmp_contact_header->data_len) {
@@ -419,7 +421,8 @@ int build_contact(ucontact_t* c, contact_for_header_t** contact_header) {
         p += CONTACT_BEGIN_LEN;
 
         fl = 0;
-        while (c) {
+	    
+        while (i<MAX_CONTACTS_PER_IMPU && (c=impurec->newcontacts[i])) {
             if (VALID_CONTACT(c, act_time)) {
                 if (fl) {
                     memcpy(p, CONTACT_SEP, CONTACT_SEP_LEN);
@@ -458,8 +461,7 @@ int build_contact(ucontact_t* c, contact_for_header_t** contact_header) {
                     *p++ = '\"';
                 }
             }
-
-            c = c->next;
+	    i++;
         }
 
         memcpy(p, CRLF, CRLF_LEN);
@@ -666,7 +668,7 @@ int reg_send_reply(struct sip_msg* _m, contact_for_header_t* contact_header) {
     str msg = str_init(MSG_200); /* makes gcc shut up */
     char* buf;
 
-    if (contact_header && contact_header->buf && contact_header->data_len > 0) {
+    if (contact_header && contact_header->buf && (contact_header->buf_len > 0) && (contact_header->data_len > 0)) {
     	LM_DBG("Contacts: %.*s\n", contact_header->data_len, contact_header->buf);
         add_lump_rpl(_m, contact_header->buf, contact_header->data_len, LUMP_RPL_HDR | LUMP_RPL_NODUP | LUMP_RPL_NOFREE);
         contact_header->data_len = 0;

+ 1 - 1
modules/ims_registrar_scscf/reply.h

@@ -64,7 +64,7 @@ int reg_send_reply_transactional(struct sip_msg* _m, contact_for_header_t* conta
 /*! \brief
  * Build Contact HF for reply
  */
-int build_contact(ucontact_t* c, contact_for_header_t** contact_header);
+int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header);
 int build_expired_contact(contact_t* chi, contact_for_header_t** contact_header); //this is for building the expired response - ie reply to dereg
 
 int build_p_associated_uri(ims_subscription* s);

+ 22 - 18
modules/ims_registrar_scscf/save.c

@@ -134,16 +134,9 @@ end:
  */
 static inline int star(udomain_t* _d, str* _a) {
     impurecord_t* r;
-    ucontact_t* c = 0;
 
     ul.lock_udomain(_d, _a);
 
-    if (!ul.get_impurecord(_d, _a, &r)) {
-        c = r->contacts;
-    } else {
-        r = NULL;
-    }
-
     if (ul.delete_impurecord(_d, _a, r) < 0) {
         LM_ERR("failed to remove record from usrloc\n");
 
@@ -155,7 +148,7 @@ static inline int star(udomain_t* _d, str* _a) {
 
         if (!ul.get_impurecord(_d, _a, &r)) {
             contact_for_header_t** contact_header = 0;
-            build_contact(c, contact_header);
+            build_contact(r, contact_header);
             free_contact_buf(*contact_header);
         }
         ul.unlock_udomain(_d, _a);
@@ -485,7 +478,7 @@ static inline int is_impu_registered(udomain_t* _d, str* public_identity) {
         }
 	
 	//check valid contacts
-        if(impu->contacts == 0)
+        if((impu->num_contacts <=0) || (impu->newcontacts[0]==0))
 	{
 	    LM_DBG("IMPU <%.*s> has no valid contacts\n", public_identity->len, public_identity->s);
             ret = 0;
@@ -561,22 +554,29 @@ static inline int update_contacts_helper(struct sip_msg* msg, impurecord_t* impu
 
                         LM_DBG("adding/updating contact based on prior existence\n");
                         //stick the contacts into usrloc
+//			ul.lock_contact_slot(&chi->uri);
                         if (ul.get_ucontact(impu_rec, &chi->uri, ci->callid,
-                                ci->path, ci->cseq, &ucontact) != 0) {
+                                ci->path, ci->cseq, &ucontact) != 0) {	//get_contact returns with lock
                             LM_DBG("inserting new contact\n");
                             if (ul.insert_ucontact(impu_rec, &chi->uri, ci,
                                     &ucontact) != 0) {
                                 LM_ERR("Error inserting contact <%.*s>\n", chi->uri.len, chi->uri.s);
+//				ul.unlock_contact_slot(&chi->uri);
                                 goto error;
                             }
                         } else {
                             LM_DBG("Contact already exists - updating\n");
                             if (ul.update_ucontact(impu_rec, ucontact, ci) != 0) {
                                 LM_ERR("Error updating contact <%.*s>\n", chi->uri.len, chi->uri.s);
+				ul.release_ucontact(ucontact);
+//				ul.unlock_contact_slot(&chi->uri);
                                 goto error;
                             }
+			    ul.release_ucontact(ucontact);
                         }
-
+			
+			
+//			ul.unlock_contact_slot(&chi->uri);
                     }
                 }
             }
@@ -628,10 +628,14 @@ static inline int unregister_contact(udomain_t* _d, str* public_identity, contac
 	}
     }
     
-    if (ul.delete_ucontact(impu_rec, ucontact) != 0) {
+//    if (ul.delete_ucontact(impu_rec, ucontact) != 0) {
+    ul.lock_contact_slot_i(ucontact->contact_hash);
+    if (ul.unlink_contact_from_impu(impu_rec, ucontact, 1) != 0) {
         LM_ERR("Failed to delete ucontact <%.*s>\n", chi->uri.len, chi->uri.s);
     }
-    LM_DBG("Contact deleted successfully <%.*s>\n", chi->uri.len, chi->uri.s);
+    ul.unlock_contact_slot_i(ucontact->contact_hash);
+    ul.release_ucontact(ucontact);
+    LM_DBG("Contact unlinked successfully <%.*s>\n", chi->uri.len, chi->uri.s);
     return 0;
 
 error:
@@ -705,7 +709,7 @@ int update_contacts_new(struct sip_msg* msg, udomain_t* _d,
                 goto error;
             }
             //now build the contact buffer to be include in the reply message and unlock
-            build_contact(impu_rec->contacts, contact_header);
+            build_contact(impu_rec, contact_header);
             ul.unlock_udomain(_d, public_identity);
             break;
         case AVP_IMS_SAR_RE_REGISTRATION:
@@ -727,7 +731,7 @@ int update_contacts_new(struct sip_msg* msg, udomain_t* _d,
                 goto error;
             }
             //build the contact buffer for all registered contacts on explicit IMPU
-            build_contact(impu_rec->contacts, contact_header);
+            build_contact(impu_rec, contact_header);
 
             subscription = impu_rec->s;
             if (!subscription) {
@@ -738,7 +742,7 @@ int update_contacts_new(struct sip_msg* msg, udomain_t* _d,
                     LM_ERR("Unable to update explicit impurecord for <%.*s>\n", public_identity->len, public_identity->s);
                 }
                 ul.unlock_udomain(_d, public_identity);
-                build_contact(impu_rec->contacts, contact_header);
+                build_contact(impu_rec, contact_header);
                 break;
             }
 
@@ -830,7 +834,7 @@ int update_contacts_new(struct sip_msg* msg, udomain_t* _d,
                 goto error;
             }
 
-            if (impu_rec->contacts) {
+            if (impu_rec->num_contacts>=0 && impu_rec->newcontacts[0]) {
                 LM_DBG("contacts still available\n");
                 //TODO: add all other remaining contacts to reply message (contacts still registered for this IMPU)
                 ret = 1;
@@ -898,7 +902,7 @@ int update_contacts_new(struct sip_msg* msg, udomain_t* _d,
                             continue;
                         }
 
-                        if (impu_rec->contacts)
+                        if (impu_rec->num_contacts && impu_rec->newcontacts[0])
                             LM_DBG("contacts still available after implicit dereg for IMPU: <%.*s>\n", pi->public_identity.len, pi->public_identity.s);
                         else {
                             LM_DBG("no contacts left after implicit dereg for IMPU: <%.*s>\n", pi->public_identity.len, pi->public_identity.s);

+ 221 - 0
modules/ims_usrloc_scscf/contact_hslot.c

@@ -0,0 +1,221 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ */
+
+#include "contact_hslot.h"
+
+/*! number of locks */
+int contacts_locks_no=4;
+/*! global list of locks */
+gen_lock_set_t* contacts_locks=0;
+
+
+/*!
+ * \brief Initialize locks for the hash table
+ * \return 0 on success, -1 on failure
+ */
+int init_contacts_locks(void)
+{
+	int i;
+	i = contacts_locks_no;
+	do {
+		if ((( contacts_locks=lock_set_alloc(i))!=0)&&
+				(lock_set_init(contacts_locks)!=0))
+		{
+			contacts_locks_no = i;
+			LM_INFO("locks array size %d\n", contacts_locks_no);
+			return 0;
+
+		}
+		if (contacts_locks){
+			lock_set_dealloc(contacts_locks);
+			contacts_locks=0;
+		}
+		i--;
+		if(i==0)
+		{
+			LM_ERR("failed to allocate locks\n");
+			return -1;
+		}
+	} while (1);
+}
+
+
+/*!
+ * \brief Unlock all locks on the list
+ */
+void unlock_contacts_locks(void)
+{
+	unsigned int i;
+
+	if (contacts_locks==0)
+		return;
+
+	for (i=0;i<contacts_locks_no;i++) {
+#ifdef GEN_LOCK_T_PREFERED
+		lock_release(&contacts_locks->locks[i]);
+#else
+		ul_release_idx(i);
+#endif
+	};
+}
+
+
+/*!
+ * \brief Destroy all locks on the list
+ */
+void destroy_contacts_locks(void)
+{
+	if (contacts_locks !=0){
+		lock_set_destroy(contacts_locks);
+		lock_set_dealloc(contacts_locks);
+	};
+}
+
+#ifndef GEN_LOCK_T_PREFERED
+/*!
+ * \brief Lock a lock with a certain index
+ * \param idx lock index
+ */
+void lock_contacts_idx(int idx)
+{
+	lock_set_get(contacts_locks, idx);
+}
+
+
+/*!
+ * \brief Release a lock with a certain index
+ * \param idx lock index
+ */
+void release_contacts_idx(int idx)
+{
+	lock_set_release(contacts_locks, idx);
+}
+#endif
+
+/*!
+ * \brief Initialize cache slot structure
+ * \param _d domain for the hash slot
+ * \param _s hash slot
+ * \param n used to get the slot number (modulo number or locks)
+ */
+void init_contact_slot(contact_hslot_t* _s, int n)
+{
+	_s->n = 0;
+	_s->first = 0;
+	_s->last = 0;
+//	_s->d = _d;
+
+#ifdef GEN_LOCK_T_PREFERED
+	_s->lock = &contacts_locks->locks[n%contacts_locks_no];
+#else
+	_s->lockidx = n%contacts_locks_no;
+#endif
+}
+
+
+/*!
+ * \brief Deinitialize given slot structure
+ * \param _s hash slot
+ */
+void deinit_contact_slot(contact_hslot_t* _s)
+{
+	struct ucontact* ptr;
+	
+	     /* Remove all elements */
+	while(_s->first) {
+		ptr = _s->first;
+		_s->first = _s->first->next;
+		free_ucontact(ptr);
+	}
+	
+	_s->n = 0;
+	_s->last = 0;
+//    _s->d = 0;
+}
+
+
+/*!
+ * \brief Add an element to an slot's linked list
+ * \param _s hash slot
+ * \param _r added record
+ */
+void contact_slot_add(contact_hslot_t* _s, struct ucontact* _c)
+{
+	if (_s->n == 0) {
+		_s->first = _s->last = _c;
+	} else {
+		_c->prev = _s->last;
+		_s->last->next = _c;
+		_s->last = _c;
+	}
+	_s->n++;
+	_c->slot = _s;
+}
+
+
+/*!
+ * \brief Remove an element from slot linked list
+ * \param _s hash slot
+ * \param _r removed record
+ */
+void contact_slot_rem(contact_hslot_t* _s, struct ucontact* _c)
+{
+	if (_c->prev) {
+		_c->prev->next = _c->next;
+	} else {
+		_s->first = _c->next;
+	}
+
+	if (_c->next) {
+		_c->next->prev = _c->prev;
+	} else {
+		_s->last = _c->prev;
+	}
+
+	_c->prev = _c->next = 0;
+	_c->slot = 0;
+	_s->n--;
+}
+

+ 107 - 0
modules/ims_usrloc_scscf/contact_hslot.h

@@ -0,0 +1,107 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ */
+
+#ifndef CONTACT_HSLOT_H
+#define	CONTACT_HSLOT_H
+
+#include "../../locking.h"
+#include "ucontact.h"
+struct ucontact;
+
+typedef struct contact_hslot {
+	int n;                  /*!< Number of elements in the collision slot */
+	struct ucontact* first;  /*!< First element in the list */
+	struct ucontact* last;   /*!< Last element in the list */
+#ifdef GEN_LOCK_T_PREFERED
+	gen_lock_t *lock;       /*!< Lock for hash entry - fastlock */
+#else
+	int lockidx;            /*!< Lock index for hash entry - the rest*/
+#endif
+} contact_hslot_t;
+
+/*! \brief
+ * Initialize slot structure
+ */
+void init_contact_slot(contact_hslot_t* _s, int n);
+
+
+/*! \brief
+ * Deinitialize given slot structure
+ */
+void deinit_contact_slot(contact_hslot_t* _s);
+
+
+/*! \brief
+ * Add an element to slot linked list
+ */
+void contact_slot_add(contact_hslot_t* _s, struct ucontact* _c);
+
+
+/*! \brief
+ * Remove an element from slot linked list
+ */
+void contact_slot_rem(contact_hslot_t* _s, struct ucontact* _c);
+
+
+/*!
+ * \brief Initialize locks for the hash table
+ * \return 0 on success, -1 on failure
+ */
+int init_contacts_locks(void);
+
+
+/*!
+ * \brief Destroy all locks on the list
+ */
+void unlock_contacts_locks(void);
+void destroy_contacts_locks(void);
+
+#ifndef GEN_LOCK_T_PREFERED
+void lock_contacts_idx(int idx);
+void release_contacts_idx(int idx);
+#endif
+
+#endif	/* CONTACT_HSLOT_H */
+

+ 93 - 92
modules/ims_usrloc_scscf/dlist.c

@@ -87,7 +87,6 @@ static inline int find_dlist(str* _n, dlist_t** _d)
 	return 1;
 }
 
-
 /*!
  * \brief Get all contacts from the memory, in partitions if wanted
  * \see get_all_ucontacts
@@ -99,104 +98,106 @@ static inline int find_dlist(str* _n, dlist_t** _d)
  * \return 0 on success, positive if buffer size was not sufficient, negative on failure
  */
 static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags,
-								unsigned int part_idx, unsigned int part_max)
-{
-	dlist_t *p;
-	impurecord_t *r;
-	ucontact_t *c;
-	void *cp;
-	int shortage;
-	int needed;
-	int i = 0;
-	cp = buf;
-	shortage = 0;
-	/* Reserve space for terminating 0000 */
-	len -= sizeof(c->c.len);
-
-	for (p = root; p != NULL; p = p->next) {
-
-		for(i=0; i<p->d->size; i++) {
-
-			if ( (i % part_max) != part_idx )
-				continue;
-
-			lock_ulslot(p->d, i);
-			if(p->d->table[i].n<=0)
-			{
-				unlock_ulslot(p->d, i);
-				continue;
+	unsigned int part_idx, unsigned int part_max) {
+    dlist_t *p;
+    impurecord_t *r;
+    ucontact_t *c;
+    void *cp;
+    int shortage;
+    int needed;
+    int i,j;
+    cp = buf;
+    shortage = 0;
+    /* Reserve space for terminating 0000 */
+    len -= sizeof (c->c.len);
+
+    for (p = root; p != NULL; p = p->next) {
+
+	for (i = 0; i < p->d->size; i++) {
+
+	    if ((i % part_max) != part_idx)
+		continue;
+	    LM_DBG("LOCKING ULSLOT %d\n", i);
+	    lock_ulslot(p->d, i);
+	    if (p->d->table[i].n <= 0) {
+	    	LM_DBG("UNLOCKING ULSLOT %d\n", i);
+		unlock_ulslot(p->d, i);
+		continue;
+	    }
+	    for (r = p->d->table[i].first; r != NULL; r = r->next) {
+		while (j<MAX_CONTACTS_PER_IMPU && (c = r->newcontacts[j++])) {
+		    if (c->c.len <= 0)
+			continue;
+		    /*
+		     * List only contacts that have all requested
+		     * flags set
+		     */
+		    if ((c->cflags & flags) != flags)
+			continue;
+		    if (c->received.s) {
+			needed = (int) (sizeof (c->received.len)
+				+ c->received.len + sizeof (c->sock)
+				+ sizeof (c->cflags) + sizeof (c->path.len)
+				+ c->path.len);
+			if (len >= needed) {
+			    memcpy(cp, &c->received.len, sizeof (c->received.len));
+			    cp = (char*) cp + sizeof (c->received.len);
+			    memcpy(cp, c->received.s, c->received.len);
+			    cp = (char*) cp + c->received.len;
+			    memcpy(cp, &c->sock, sizeof (c->sock));
+			    cp = (char*) cp + sizeof (c->sock);
+			    memcpy(cp, &c->cflags, sizeof (c->cflags));
+			    cp = (char*) cp + sizeof (c->cflags);
+			    memcpy(cp, &c->path.len, sizeof (c->path.len));
+			    cp = (char*) cp + sizeof (c->path.len);
+			    memcpy(cp, c->path.s, c->path.len);
+			    cp = (char*) cp + c->path.len;
+			    len -= needed;
+			} else {
+			    shortage += needed;
 			}
-			for (r = p->d->table[i].first; r != NULL; r = r->next) {
-				for (c = r->contacts; c != NULL; c = c->next) {
-					if (c->c.len <= 0)
-						continue;
-					/*
-					 * List only contacts that have all requested
-					 * flags set
-					 */
-					if ((c->cflags & flags) != flags)
-						continue;
-					if (c->received.s) {
-						needed = (int)(sizeof(c->received.len)
-								+ c->received.len + sizeof(c->sock)
-								+ sizeof(c->cflags) + sizeof(c->path.len)
-								+ c->path.len);
-						if (len >= needed) {
-							memcpy(cp,&c->received.len,sizeof(c->received.len));
-							cp = (char*)cp + sizeof(c->received.len);
-							memcpy(cp, c->received.s, c->received.len);
-							cp = (char*)cp + c->received.len;
-							memcpy(cp, &c->sock, sizeof(c->sock));
-							cp = (char*)cp + sizeof(c->sock);
-							memcpy(cp, &c->cflags, sizeof(c->cflags));
-							cp = (char*)cp + sizeof(c->cflags);
-							memcpy(cp, &c->path.len, sizeof(c->path.len));
-							cp = (char*)cp + sizeof(c->path.len);
-							memcpy(cp, c->path.s, c->path.len);
-							cp = (char*)cp + c->path.len;
-							len -= needed;
-						} else {
-							shortage += needed;
-						}
-					} else {
-						needed = (int)(sizeof(c->c.len) + c->c.len +
-							sizeof(c->sock) + sizeof(c->cflags) +
-							sizeof(c->path.len) + c->path.len);
-						if (len >= needed) {
-							memcpy(cp, &c->c.len, sizeof(c->c.len));
-							cp = (char*)cp + sizeof(c->c.len);
-							memcpy(cp, c->c.s, c->c.len);
-							cp = (char*)cp + c->c.len;
-							memcpy(cp, &c->sock, sizeof(c->sock));
-							cp = (char*)cp + sizeof(c->sock);
-							memcpy(cp, &c->cflags, sizeof(c->cflags));
-							cp = (char*)cp + sizeof(c->cflags);
-							memcpy(cp, &c->path.len, sizeof(c->path.len));
-							cp = (char*)cp + sizeof(c->path.len);
-							memcpy(cp, c->path.s, c->path.len);
-							cp = (char*)cp + c->path.len;
-							len -= needed;
-						} else {
-							shortage += needed;
-						}
-					}
-				}
+		    } else {
+			needed = (int) (sizeof (c->c.len) + c->c.len +
+				sizeof (c->sock) + sizeof (c->cflags) +
+				sizeof (c->path.len) + c->path.len);
+			if (len >= needed) {
+			    memcpy(cp, &c->c.len, sizeof (c->c.len));
+			    cp = (char*) cp + sizeof (c->c.len);
+			    memcpy(cp, c->c.s, c->c.len);
+			    cp = (char*) cp + c->c.len;
+			    memcpy(cp, &c->sock, sizeof (c->sock));
+			    cp = (char*) cp + sizeof (c->sock);
+			    memcpy(cp, &c->cflags, sizeof (c->cflags));
+			    cp = (char*) cp + sizeof (c->cflags);
+			    memcpy(cp, &c->path.len, sizeof (c->path.len));
+			    cp = (char*) cp + sizeof (c->path.len);
+			    memcpy(cp, c->path.s, c->path.len);
+			    cp = (char*) cp + c->path.len;
+			    len -= needed;
+			} else {
+			    shortage += needed;
 			}
-			unlock_ulslot(p->d, i);
+		    }
 		}
+	    }
+#ifdef EXTRA_DEBUG
+	    LM_DBG("UN-LOCKING ULSLOT %d\n", i);
+#endif
+	    unlock_ulslot(p->d, i);
 	}
-	/* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */
-	if (len >= 0)
-		memset(cp, 0, sizeof(c->c.len));
+    }
+    /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */
+    if (len >= 0)
+	memset(cp, 0, sizeof (c->c.len));
 
-	/* Shouldn't happen */
-	if (shortage > 0 && len > shortage) {
-		abort();
-	}
+    /* Shouldn't happen */
+    if (shortage > 0 && len > shortage) {
+	abort();
+    }
 
-	shortage -= len;
+    shortage -= len;
 
-	return shortage > 0 ? shortage : 0;
+    return shortage > 0 ? shortage : 0;
 }
 
 

+ 2 - 2
modules/ims_usrloc_scscf/hslot_sp.h

@@ -95,8 +95,8 @@ int subs_init_locks(void);
 /*!
  * \brief Destroy all locks on the list
  */
-void subs__unlock_locks(void);
-void subs__destroy_locks(void);
+void subs_unlock_locks(void);
+void subs_destroy_locks(void);
 
 #ifndef GEN_LOCK_T_PREFERED
 void subs__lock_idx(int idx);

+ 237 - 131
modules/ims_usrloc_scscf/impurecord.c

@@ -60,6 +60,8 @@
 #include "../../lib/ims/useful_defs.h"
 #include "../../modules/dialog_ng/dlg_load.h"
 #include "../../modules/dialog_ng/dlg_hash.h"
+#include "contact_hslot.h"
+#include "dlist.h"
 
 /*! contact matching mode */
 int matching_mode = CONTACT_ONLY;
@@ -73,6 +75,7 @@ extern int db_mode;
 
 extern int sub_dialog_hash_size;
 extern shtable_t sub_dialog_table;
+extern struct contact_list* contact_list;
 
 extern struct dlg_binds dlgb;
 
@@ -147,16 +150,9 @@ out_of_memory:
  * \param _r freed record list
  */
 void free_impurecord(impurecord_t* _r) {
-    ucontact_t* ptr;
     struct ul_callback *cbp, *cbp_tmp;
     struct _reg_subscriber* subscriber, *s_tmp;
 
-    while (_r->contacts) {
-        ptr = _r->contacts;
-        _r->contacts = _r->contacts->next;
-        free_ucontact(ptr);
-    }
-
     //free IMS specific extensions
     if (_r->ccf1.s)
         shm_free(_r->ccf1.s);
@@ -211,7 +207,8 @@ void free_impurecord(impurecord_t* _r) {
  */
 void print_impurecord(FILE* _f, impurecord_t* _r) {
     ucontact_t* ptr;
-
+    int i;
+    
     fprintf(_f, "...Record(%p)...\n", _r);
     fprintf(_f, "domain : '%.*s'\n", _r->domain->len, ZSW(_r->domain->s));
     fprintf(_f, "public_identity    : '%.*s'\n", _r->public_identity.len, ZSW(_r->public_identity.s));
@@ -240,11 +237,9 @@ void print_impurecord(FILE* _f, impurecord_t* _r) {
         subscriber = subscriber->next;
     }
 
-    if (_r->contacts) {
-        ptr = _r->contacts;
-        while (ptr) {
+    if (_r->newcontacts[0]) {
+        while ((ptr=_r->newcontacts[i++])) {
             print_ucontact(_f, ptr);
-            ptr = ptr->next;
         }
     }
 
@@ -262,41 +257,21 @@ void print_impurecord(FILE* _f, impurecord_t* _r) {
  * \return pointer to new created contact on success, 0 on failure
  */
 ucontact_t* mem_insert_ucontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci) {
-    ucontact_t* ptr, *prev = 0;
     ucontact_t* c;
-
+    int sl;
+    
     if ((c = new_ucontact(_r->domain, &_r->public_identity, _c, _ci)) == 0) {
         LM_ERR("failed to create new contact\n");
         return 0;
     }
     if_update_stat(_r->slot, _r->slot->d->contacts, 1);
-
-    ptr = _r->contacts;
-
-    while (ptr) {//make sure our contacts are ordered oldest(first) to newest(last)
-        if (ptr->expires > c->expires)
-            break;
-        prev = ptr;
-        ptr = ptr->next;
-    }
-
-    if (ptr) {
-        if (!ptr->prev) {
-            ptr->prev = c;
-            c->next = ptr;
-            _r->contacts = c;
-        } else {
-            c->next = ptr;
-            c->prev = ptr->prev;
-            ptr->prev->next = c;
-            ptr->prev = c;
-        }
-    } else if (prev) {
-        prev->next = c;
-        c->prev = prev;
-    } else {
-        _r->contacts = c;
-    }
+    
+    LM_DBG("Created new contact in memory with AOR: [%.*s] and hash [%d]\n", _c->len, _c->s, c->contact_hash);
+    
+    sl = (c->contact_hash);// & (contact_list->size - 1);
+    lock_contact_slot_i(sl);
+    contact_slot_add(&contact_list->slot[sl], c);
+    unlock_contact_slot_i(sl);
 
     return c;
 }
@@ -306,18 +281,9 @@ ucontact_t* mem_insert_ucontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci)
  * \param _r record this contact belongs to
  * \param _c removed contact
  */
-void mem_remove_ucontact(impurecord_t* _r, ucontact_t* _c) {
-    if (_c->prev) {
-        _c->prev->next = _c->next;
-        if (_c->next) {
-            _c->next->prev = _c->prev;
-        }
-    } else {
-        _r->contacts = _c->next;
-        if (_c->next) {
-            _c->next->prev = 0;
-        }
-    }
+void mem_remove_ucontact(ucontact_t* _c) {
+    LM_DBG("removing contact [%.*s] from slot %d\n", _c->c.len, _c->c.s, _c->contact_hash);
+    contact_slot_rem(&contact_list->slot[_c->contact_hash], _c);
 }
 
 /*!
@@ -325,7 +291,7 @@ void mem_remove_ucontact(impurecord_t* _r, ucontact_t* _c) {
  * \param _r record this contact belongs to
  * \param _c deleted contact
  */
-void mem_delete_ucontact(impurecord_t* _r, ucontact_t* _c) {
+void mem_delete_ucontact(ucontact_t* _c) {
     
     struct contact_dialog_data *dialog_data;
     //tear down dialogs in dialog data list
@@ -334,8 +300,9 @@ void mem_delete_ucontact(impurecord_t* _r, ucontact_t* _c) {
         dialog_data = dialog_data->next;
     }
     
-    mem_remove_ucontact(_r, _c);
-    if_update_stat(_r->slot, _r->slot->d->contacts, -1);
+    mem_remove_ucontact(_c);
+    //TODO: fix stats
+//    if_update_stat(_r->slot, _r->slot->d->contacts, -1);
     free_ucontact(_c);
 }
 
@@ -347,15 +314,16 @@ void mem_delete_ucontact(impurecord_t* _r, ucontact_t* _c) {
  * \param _r processed record
  */
 static inline void nodb_timer(impurecord_t* _r) {
-    ucontact_t* ptr, *t;
-    
+    ucontact_t* ptr;
+    int i, flag, mustdeleteimpu=1;
+    udomain_t* udomain;
     unsigned int hash_code = 0;
 
     reg_subscriber *s;
     subs_t* sub_dialog;
 
     get_act_time();
-
+    
     s = _r->shead;
     LM_DBG("Checking validity of IMPU: <%.*s> registration subscriptions\n", _r->public_identity.len, _r->public_identity.s);
     while (s) {
@@ -364,6 +332,7 @@ static inline void nodb_timer(impurecord_t* _r) {
                     s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s);
             delete_subscriber(_r, s);
         } else {
+	    mustdeleteimpu = 0;
             LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> is valid and expires in %d seconds.\n",
                     s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s,
                     (unsigned int) (s->expires - time(NULL)));
@@ -385,38 +354,36 @@ static inline void nodb_timer(impurecord_t* _r) {
         s = s->next;
     }
 
-    ptr = _r->contacts;
-    LM_DBG("Checking validity of IMPU: <%.*s> contacts\n", _r->public_identity.len, _r->public_identity.s);
-
-    while (ptr) {
-        if (!VALID_CONTACT(ptr, act_time)) {
-            /* run callbacks for EXPIRE event */
-            if (exists_ulcb_type(ptr->cbs, UL_CONTACT_EXPIRE))
-                run_ul_callbacks(ptr->cbs, UL_CONTACT_EXPIRE, _r, ptr);
-
-            if (exists_ulcb_type(_r->cbs, UL_IMPU_EXPIRE_CONTACT)) {
-                run_ul_callbacks(_r->cbs, UL_IMPU_EXPIRE_CONTACT, _r, ptr);
-            }
-
-            LM_DBG("Binding '%.*s','%.*s' has expired\n",
-                    ptr->aor->len, ZSW(ptr->aor->s),
-                    ptr->c.len, ZSW(ptr->c.s));
-
-            t = ptr;
-            ptr = ptr->next;
-
-			if (db_mode == WRITE_THROUGH && db_delete_ucontact(_r, t) != 0) {
-				LM_ERR("error removing contact from DB [%.*s]... will still remove from memory\n", t->c.len, t->c.s);
-			}
-
-            mem_delete_ucontact(_r, t);
-            update_stat(_r->slot->d->expires, 1);
-        } else {
-            LM_DBG("IMPU:<%.*s> - contact:<%.*s> is valid and expires in %d seconds\n", _r->public_identity.len, _r->public_identity.s,
+    LM_DBG("Checking validity of IMPU: <%.*s> contacts (#%d contacts)\n", _r->public_identity.len, _r->public_identity.s, _r->num_contacts);
+    flag = 0;
+    
+    for (i=0; i<MAX_CONTACTS_PER_IMPU; i++) {
+	if ((ptr = _r->newcontacts[i])) {
+	    flag=1;
+	    if (!VALID_CONTACT(ptr, act_time)) {
+		LM_DBG("IMPU:<%.*s> - contact:<%.*s> has expired\n", _r->public_identity.len, _r->public_identity.s, ptr->c.len, ptr->c.s);
+		lock_contact_slot_i(ptr->contact_hash); //TODO, this maybe should be a lock on the strcuture itself and not the slot
+		unlink_contact_from_impu(_r, ptr, 1);
+		unlock_contact_slot_i(ptr->contact_hash);
+	    } else {
+		LM_DBG("IMPU:<%.*s> - contact:<%.*s> is valid and expires in %d seconds\n", _r->public_identity.len, _r->public_identity.s,
                     ptr->c.len, ptr->c.s,
                     (unsigned int) (ptr->expires - time(NULL)));
-            ptr = ptr->next;
-        }
+		mustdeleteimpu = 0;
+	    }
+	    
+	} else {
+	    break;
+	}
+    }
+    
+    if (!flag)
+        LM_DBG("no contacts\n");
+
+    
+    register_udomain("location", &udomain);
+    if (mustdeleteimpu) {
+	delete_impurecord(udomain, &_r->public_identity, _r);
     }
 }
 
@@ -428,7 +395,18 @@ static inline void nodb_timer(impurecord_t* _r) {
  * \param _r processed record
  */
 void timer_impurecord(impurecord_t* _r) {
-    nodb_timer(_r);
+        nodb_timer(_r);
+}
+
+int get_contacts_count(impurecord_t* _r) {
+    ucontact_t* ptr;
+    int i = 0;
+    
+    while (i<MAX_CONTACTS_PER_IMPU && (ptr=_r->newcontacts[i])) {
+	i++;
+    }
+    
+    return i;
 }
 
 /*!
@@ -442,12 +420,7 @@ void timer_impurecord(impurecord_t* _r) {
 int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucontact_t** _c) {
     //First check our constraints
     if (maxcontact > 0 && maxcontact_behaviour > 0) {
-        ucontact_t* contact = _r->contacts;
-        int numcontacts = 0;
-        while (contact) {
-            numcontacts++;
-            contact = contact->next;
-        }
+        int numcontacts = get_contacts_count(_r);
         if (numcontacts >= maxcontact) {
             switch (maxcontact_behaviour) {
                 case 1://reject
@@ -456,7 +429,7 @@ int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucont
                 case 2://overwrite oldest
                     LM_DBG("Too many contacts already registered, overwriting oldest for IMPU <%.*s>\n", _r->public_identity.len, _r->public_identity.s);
                     //we can just remove the first one seeing the contacts are ordered on insertion with newest last and oldest first
-                    mem_delete_ucontact(_r, _r->contacts);
+                    //TODO:mem_delete_ucontact(_r, _r->contacts);
                     break;
                 default://unknown
                     LM_ERR("unknown maxcontact behaviour..... ignoring\n");
@@ -472,12 +445,19 @@ int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucont
         return -1;
     }
 
-    /*DB?*/
+
+
+//    /*DB?*/
 	if (db_mode == WRITE_THROUGH && db_insert_ucontact(_r, *_c) != 0) {
 		LM_ERR("error inserting contact into db");
 		return -1;
 	}
 
+//make sure IMPU is linked to this contact
+    link_contact_to_impu(_r, *_c, 1);
+    
+    release_ucontact(*_c);
+
     if (exists_ulcb_type(NULL, UL_CONTACT_INSERT)) {
         run_ul_callbacks(NULL, UL_CONTACT_INSERT, _r, *_c);
     }
@@ -494,23 +474,27 @@ int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucont
  * \param _c deleted contact
  * \return 0 on success, -1 on failure
  */
-int delete_ucontact(impurecord_t* _r, struct ucontact* _c) {
+int delete_ucontact(struct ucontact* _c) {
     int ret = 0;
     
-    if (exists_ulcb_type(_c->cbs, UL_CONTACT_DELETE)) {
-        run_ul_callbacks(_c->cbs, UL_CONTACT_DELETE, _r, _c);
-    }
-    if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE_CONTACT)) {
-        run_ul_callbacks(_r->cbs, UL_IMPU_DELETE_CONTACT, _r, _c);
-    }
+    LM_DBG("Deleting contact: [%.*s]\n", _c->c.len, _c->c.s);
+    //TODO: restore callbacks
+//    if (exists_ulcb_type(_c->cbs, UL_CONTACT_DELETE)) {
+//        run_ul_callbacks(_c->cbs, UL_CONTACT_DELETE, _r, _c);
+//    }
+    
+    //TODO: following callbacks need to move to unlink contact from impu functions
+//    if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE_CONTACT)) {
+//        run_ul_callbacks(_r->cbs, UL_IMPU_DELETE_CONTACT, _r, _c);
+//    }
 
 	/*DB?*/
-	if (db_mode == WRITE_THROUGH && db_delete_ucontact(_r, _c) != 0) {
+	if (db_mode == WRITE_THROUGH && db_delete_ucontact(_c) != 0) {
 		LM_ERR("error removing contact from DB [%.*s]... will still remove from memory\n", _c->c.len, _c->c.s);
 
 	}
 
-    mem_delete_ucontact(_r, _c);
+    mem_delete_ucontact(_c);
 
     return ret;
 }
@@ -550,12 +534,13 @@ inline int aor_to_contact(str* aor, str* contact) {
  * \param _c contact string
  * \return ptr on successfull match, 0 when they not match
  */
-static inline struct ucontact* contact_match(ucontact_t* ptr, str* _c) {
+static inline struct ucontact* contact_match(unsigned int slot, str* _c) {
+    ucontact_t* ptr = contact_list->slot[slot].first;
+    
     while (ptr) {
-        if ((_c->len == ptr->c.len) && !memcmp(_c->s, ptr->c.s, _c->len)) {
+        if ((_c->len == ptr->c.len) && !memcmp(_c->s, ptr->c.s, _c->len) && VALID_CONTACT(ptr, act_time)) {//check validity
             return ptr;
         }
-
         ptr = ptr->next;
     }
     return 0;
@@ -567,13 +552,14 @@ static inline struct ucontact* contact_match(ucontact_t* ptr, str* _c) {
  * \param _c contact string
  * \return ptr on successfull match, 0 when they not match
  */
-static inline struct ucontact* contact_port_ip_match(ucontact_t* ptr, str* _c) {
+static inline struct ucontact* contact_port_ip_match(unsigned int slot, str* _c) {
+    ucontact_t* ptr = contact_list->slot[slot].first;
     str string_ip_port, contact_ip_port;
     aor_to_contact(_c, &string_ip_port);//strip userpart from test contact
 
     while (ptr) {
 	aor_to_contact(&ptr->c, &contact_ip_port);//strip userpart from contact
-	if ((string_ip_port.len == contact_ip_port.len) && !memcmp(string_ip_port.s, contact_ip_port.s, string_ip_port.len)) {
+	if ((string_ip_port.len == contact_ip_port.len) && !memcmp(string_ip_port.s, contact_ip_port.s, string_ip_port.len) && VALID_CONTACT(ptr, act_time)) {
             return ptr;
         }
 
@@ -589,16 +575,17 @@ static inline struct ucontact* contact_port_ip_match(ucontact_t* ptr, str* _c) {
  * \param _callid callid
  * \return ptr on successfull match, 0 when they not match
  */
-static inline struct ucontact* contact_callid_match(ucontact_t* ptr,
+static inline struct ucontact* contact_callid_match(unsigned int slot,
         str* _c, str *_callid) {
+    ucontact_t* ptr = contact_list->slot[slot].first;
+    
     while (ptr) {
         if ((_c->len == ptr->c.len) && (_callid->len == ptr->callid.len)
                 && !memcmp(_c->s, ptr->c.s, _c->len)
                 && !memcmp(_callid->s, ptr->callid.s, _callid->len)
-                ) {
+                && VALID_CONTACT(ptr, act_time)) {
             return ptr;
         }
-
         ptr = ptr->next;
     }
     return 0;
@@ -611,16 +598,18 @@ static inline struct ucontact* contact_callid_match(ucontact_t* ptr,
 + * \param _path path
 + * \return ptr on successfull match, 0 when they not match
 + */
-static inline struct ucontact* contact_path_match(ucontact_t* ptr, str* _c, str *_path) {
+static inline struct ucontact* contact_path_match(unsigned int slot, str* _c, str *_path) {
+    ucontact_t* ptr = contact_list->slot[slot].first;
     /* if no path is preset (in REGISTER request) or use_path is not configured
        in registrar module, default to contact_match() */
-    if (_path == NULL) return contact_match(ptr, _c);
+    if (_path == NULL) return contact_match(slot, _c);
 
     while (ptr) {
         if ((_c->len == ptr->c.len) && (_path->len == ptr->path.len)
                 && !memcmp(_c->s, ptr->c.s, _c->len)
                 && !memcmp(_path->s, ptr->path.s, _path->len)
-                ) {
+                && VALID_CONTACT(ptr, act_time)
+		) {
             return ptr;
         }
 
@@ -638,47 +627,65 @@ static inline struct ucontact* contact_path_match(ucontact_t* ptr, str* _c, str
  * \param _cseq CSEQ number
  * \param _co found contact
  * \return 0 - found, 1 - not found, -1 - invalid found,
- * -2 - found, but to be skipped (same cseq)
+ * -2 - found, but to be skipped (same cseq) - don't forget to release_ucontact so dec. the ref counter
  */
 int get_ucontact(impurecord_t* _r, str* _c, str* _callid, str* _path, int _cseq, struct ucontact** _co) {
+    unsigned int sl;
     ucontact_t* ptr;
     int no_callid;
-
     ptr = 0;
     no_callid = 0;
     *_co = 0;
 
+    sl = core_hash(_c, 0, contact_list->size);
+    LM_DBG("looking for contact [%.*s] in slot %d\n", _c->len, _c->s, sl);
+    lock_contact_slot_i(sl);
+    
+    get_act_time();
+    
     switch (matching_mode) {
         case CONTACT_ONLY:
-            ptr = contact_match(_r->contacts, _c);
+            ptr = contact_match(sl, _c);
             break;
         case CONTACT_CALLID:
-            ptr = contact_callid_match(_r->contacts, _c, _callid);
+            ptr = contact_callid_match(sl, _c, _callid);
             no_callid = 1;
             break;
         case CONTACT_PATH:
-            ptr = contact_path_match(_r->contacts, _c, _path);
+            ptr = contact_path_match(sl, _c, _path);
             break;
 	case CONTACT_PORT_IP_ONLY:
-	    ptr = contact_port_ip_match(_r->contacts, _c);
+	    ptr = contact_port_ip_match(sl, _c);
 	    break;
         default:
             LM_CRIT("unknown matching_mode %d\n", matching_mode);
-            return -1;
+            unlock_contact_slot_i(sl);
+	    return -1;
     }
+    
+    unlock_contact_slot_i(sl);	/*TODO: we probably need to ref count here..... */
 
     if (ptr) {
+	LM_DBG("have partially found a contact\n");
         /* found -> check callid and cseq */
         if (no_callid || (ptr->callid.len == _callid->len
                 && memcmp(_callid->s, ptr->callid.s, _callid->len) == 0)) {
-            if (_cseq < ptr->cseq)
-                return -1;
-            if (_cseq == ptr->cseq) {
-                get_act_time();
-                return (ptr->last_modified + cseq_delay > act_time) ? -2 : -1;
-            }
+            if (_cseq < ptr->cseq) {
+		LM_DBG("cseq less than expected\n");
+//                return -1;
+	    }
+//            if (_cseq == ptr->cseq) {
+//                get_act_time();
+//                return (ptr->last_modified + cseq_delay > act_time) ? -2 : -1;
+//            }
+	    
+	    
         }
+	LM_DBG("contact found p=[%p], aor:[%.*s] and contact:[%.*s]\n", ptr, ptr->aor.len, ptr->aor.s, ptr->c.len, ptr->c.s);
+	
+	ptr->ref_count++;
         *_co = ptr;
+	
         return 0;
     }
 
@@ -849,9 +856,108 @@ int update_impurecord(struct udomain* _d, str* public_identity, int reg_state, i
     }
 
     run_ul_callbacks((*_r)->cbs, UL_IMPU_UPDATE, *_r, NULL);
+    
+    if (db_mode == WRITE_THROUGH && db_insert_impurecord(_d, public_identity, reg_state, barring, s, ccf1, ccf2, ecf1, ecf2, _r) != 0) {
+	LM_ERR("error inserting IMPU [%.*s] into db... continuing", (*_r)->public_identity.len, (*_r)->public_identity.s);
+    }
+    
     return 0;
 
 out_of_memory:
     unlock_udomain(_d, public_identity);
     return -1;
 }
+
+/* link contact to impu 
+    must be called with lock on domain (IMPU) as well as lock on contact_slot 
+ */
+int link_contact_to_impu(impurecord_t* impu, ucontact_t* contact, int write_to_db)
+{
+    ucontact_t* ptr;
+    int i;
+    i=0;
+    int overwrite=0;
+    ptr=impu->newcontacts[i];
+
+    
+    
+    while (i<MAX_CONTACTS_PER_IMPU && ptr) {
+	if (ptr == contact) {
+	    LM_DBG("contact [%.*s] already linked to impu [%.*s]\n", contact->c.len, contact->c.s, impu->public_identity.len, impu->public_identity.s);
+	    return 0;
+	}
+	i++;
+	ptr = impu->newcontacts[i];
+    }
+    
+    if ((maxcontact_behaviour>0) && (maxcontact>0) && (maxcontact < (i+1))) {
+	LM_DBG("Need to overwrite oldest contact at position %d\n", i);
+	i = maxcontact-1;
+	overwrite = 1;
+    }
+    
+    if (i<MAX_CONTACTS_PER_IMPU) {
+	LM_DBG("contact [%.*s] needs to be linked to impu [%.*s] at position %d\n", contact->c.len, contact->c.s, impu->public_identity.len, impu->public_identity.s, i);
+	if (overwrite)
+	    unlink_contact_from_impu(impu, impu->newcontacts[i], write_to_db);    //unlink the contact we are overwriting
+	else
+	    impu->num_contacts = i+1;
+	
+	impu->newcontacts[i] = contact;
+	
+	contact->ref_count++;
+	LM_DBG("number of contacts for IMPU [%.*s] is %d\n", impu->public_identity.len, impu->public_identity.s, impu->num_contacts);
+	if (write_to_db && db_mode == WRITE_THROUGH && db_link_contact_to_impu(impu, contact) !=0) {
+	    LM_ERR("Failed to update DB linking contact [%.*s] to IMPU [%.*s]...continuing but db will be out of sync!\n", contact->c.len, contact->c.s, impu->public_identity.len, impu->public_identity.s);
+	};
+    } else {
+	LM_DBG("unable to link contact to impu as too many links already > %d\n", MAX_CONTACTS_PER_IMPU);
+	return -1;
+    }
+    
+    return 0;
+}
+
+/* link contact to impu 
+    must be called with lock on domain (IMPU) as well as lock on contact_slot 
+ */
+int unlink_contact_from_impu(impurecord_t* impu, ucontact_t* contact, int write_to_db)
+{
+    ucontact_t* ptr;
+    int i;
+    i=0;
+    int found=0;
+    ptr=impu->newcontacts[i];
+
+    LM_DBG("asked to unlink contact [%.*s] from impu [%.*s]\n", contact->c.len, contact->c.s, impu->public_identity.len, impu->public_identity.s);    
+    
+    while (i<MAX_CONTACTS_PER_IMPU && ptr) {
+	if (found) {
+	    //shift all later pointers forward by 1
+	    impu->newcontacts[i-1] = impu->newcontacts[i];
+	} else {
+	    if (ptr == contact) {
+		LM_DBG("unlinking contact [%.*s] from impu [%.*s]\n", contact->c.len, contact->c.s, impu->public_identity.len, impu->public_identity.s);
+		found = 1;
+		impu->newcontacts[i]=0;
+		impu->num_contacts--;
+		LM_DBG("decrementing ref count on contact [%.*s] to %d\n", contact->c.len, contact->c.s, contact->ref_count);
+		contact->ref_count--;	//TODO - should we lock the actual ucontact struct?
+		if (write_to_db && db_mode == WRITE_THROUGH && db_unlink_contact_from_impu(impu, contact) != 0) {
+		    LM_ERR("Failed to un-link DB contact [%.*s] from IMPU [%.*s]...continuing but db will be out of sync!\n", contact->c.len, contact->c.s, impu->public_identity.len, impu->public_identity.s);
+		}
+	    }
+	}
+	i++;
+	ptr = impu->newcontacts[i];
+    }
+
+    if (found && i < MAX_CONTACTS_PER_IMPU) {
+	LM_DBG("zero'ing last pointer to contact in the list\n");
+	impu->newcontacts[i-1]=0;
+    } else {
+	LM_DBG("contact [%.*s] did not exist in IMPU list [%.*s] while trying to unlink\n", contact->c.len, contact->c.s, impu->public_identity.len, impu->public_identity.s);
+    }
+    
+    return 0;
+}

+ 9 - 7
modules/ims_usrloc_scscf/impurecord.h

@@ -102,18 +102,16 @@ ucontact_t* mem_insert_ucontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci)
 
 /*!
  * \brief Remove the contact from lists in memory
- * \param _r record this contact belongs to
- * \param _c removed contact
+  * \param _c contact to remove
  */
-void mem_remove_ucontact(impurecord_t* _r, ucontact_t* _c);
+void mem_remove_ucontact(ucontact_t* _c);
 
 
 /*!
  * \brief Remove contact in memory from the list and delete it
- * \param _r record this contact belongs to
- * \param _c deleted contact
+ * \param _c contact to delete
  */
-void mem_delete_ucontact(impurecord_t* _r, ucontact_t* _c);
+void mem_delete_ucontact(ucontact_t* _c);
 
 
 /*!
@@ -154,7 +152,7 @@ int insert_ucontact(impurecord_t* _r, str* _contact,
  * \param _c deleted contact
  * \return 0 on success, -1 on failure
  */
-int delete_ucontact(impurecord_t* _r, struct ucontact* _c);
+int delete_ucontact(struct ucontact* _c);
 
 
 /*!
@@ -174,4 +172,8 @@ int get_ucontact(impurecord_t* _r, str* _c, str* _callid, str* _path,
 
 int update_impurecord(struct udomain* _d, str* public_identity, int reg_state, int send_sar_on_delete, int barring, int is_primary, ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2, struct impurecord** _r);
 
+int link_contact_to_impu(impurecord_t* impu, ucontact_t* contact, int write_to_db);
+int unlink_contact_from_impu(impurecord_t* impu, ucontact_t* contact, int write_to_db);
+
 #endif
+

+ 42 - 40
modules/ims_usrloc_scscf/ucontact.c

@@ -64,6 +64,11 @@
 #include "impurecord.h"
 #include "ucontact.h"
 #include "usrloc.h"
+#include "usrloc_db.h"
+#include "../../hashes.h"
+#include "contact_hslot.h"
+
+extern struct contact_list* contact_list;
 
 /*!
  * \brief Create a new contact structure
@@ -82,6 +87,9 @@ ucontact_t* new_ucontact(str* _dom, str* _aor, str* _contact, ucontact_info_t* _
         return 0;
     }
     memset(c, 0, sizeof (ucontact_t));
+    
+    c->lock = lock_alloc();
+    c->lock = lock_init(c->lock);
 
     //setup callback list
     c->cbs = (struct ulcb_head_list*) shm_malloc(sizeof (struct ulcb_head_list));
@@ -95,21 +103,23 @@ ucontact_t* new_ucontact(str* _dom, str* _aor, str* _contact, ucontact_info_t* _
     if (shm_str_dup(&c->c, _contact) < 0) goto error;
     if (shm_str_dup(&c->callid, _ci->callid) < 0) goto error;
     if (shm_str_dup(&c->user_agent, _ci->user_agent) < 0) goto error;
-
+    if (shm_str_dup(&c->aor, _aor) < 0) goto error;
+    if (shm_str_dup(&c->domain, _dom) < 0) goto error;
+    
     if (_ci->received.s && _ci->received.len) {
         if (shm_str_dup(&c->received, &_ci->received) < 0) goto error;
     }
     if (_ci->path && _ci->path->len) {
         if (shm_str_dup(&c->path, _ci->path) < 0) goto error;
     }
-
-    c->domain = _dom;
-    c->aor = _aor;
+    
+    LM_DBG("generating hash based on [%.*s]\n", _contact->len, _contact->s);
+    c->contact_hash = core_hash(_contact, 0, contact_list->size);
+    c->ref_count = 1;
     c->expires = _ci->expires;
     c->q = _ci->q;
     c->sock = _ci->sock;
     c->cseq = _ci->cseq;
-    c->state = CS_NEW;
     c->flags = _ci->flags;
     c->cflags = _ci->cflags;
     c->methods = _ci->methods;
@@ -123,6 +133,8 @@ error:
     if (c->user_agent.s) shm_free(c->user_agent.s);
     if (c->callid.s) shm_free(c->callid.s);
     if (c->c.s) shm_free(c->c.s);
+    if (c->domain.s) shm_free(c->domain.s);
+    if (c->aor.s) shm_free(c->aor.s);
     shm_free(c);
     return 0;
 }
@@ -136,17 +148,20 @@ void free_ucontact(ucontact_t* _c) {
     struct contact_dialog_data *dialog_data, *tmp_dialog_data; 
 
     if (!_c) return;
+    LM_DBG("Freeing ucontact [%.*s]\n", _c->aor.len, _c->aor.s);    
     if (_c->path.s) shm_free(_c->path.s);
     if (_c->received.s) shm_free(_c->received.s);
     if (_c->user_agent.s) shm_free(_c->user_agent.s);
     if (_c->callid.s) shm_free(_c->callid.s);
     if (_c->c.s) shm_free(_c->c.s);
+    if (_c->domain.s) shm_free(_c->domain.s);
+    if (_c->aor.s) shm_free(_c->aor.s);
 
     //free dialog data
     for (dialog_data = _c->first_dialog_data; dialog_data;) {
         tmp_dialog_data = dialog_data;
         dialog_data = dialog_data->next;
-	shm_free(tmp_dialog_data);
+		shm_free(tmp_dialog_data);
     }
     
     //free callback list
@@ -158,6 +173,8 @@ void free_ucontact(ucontact_t* _c) {
         shm_free(cbp_tmp);
     }
     shm_free(_c->cbs);
+    lock_dealloc(_c->lock);
+    lock_destroy(_c->lock);
     shm_free(_c);
 }
 
@@ -168,22 +185,11 @@ void free_ucontact(ucontact_t* _c) {
  */
 void print_ucontact(FILE* _f, ucontact_t* _c) {
     time_t t = time(0);
-    char* st;
-
-    switch (_c->state) {
-        case CS_NEW: st = "CS_NEW";
-            break;
-        case CS_SYNC: st = "CS_SYNC";
-            break;
-        case CS_DIRTY: st = "CS_DIRTY";
-            break;
-        default: st = "CS_UNKNOWN";
-            break;
-    }
+    char* st = "";
 
     fprintf(_f, "~~~Contact(%p)~~~\n", _c);
-    fprintf(_f, "domain    : '%.*s'\n", _c->domain->len, ZSW(_c->domain->s));
-    fprintf(_f, "aor       : '%.*s'\n", _c->aor->len, ZSW(_c->aor->s));
+    fprintf(_f, "domain    : '%.*s'\n", _c->domain.len, ZSW(_c->domain.s));
+    fprintf(_f, "aor       : '%.*s'\n", _c->aor.len, ZSW(_c->aor.s));
     fprintf(_f, "Contact   : '%.*s'\n", _c->c.len, ZSW(_c->c.s));
     fprintf(_f, "Expires   : ");
     if (_c->expires == 0) {
@@ -278,25 +284,6 @@ int mem_update_ucontact(ucontact_t* _c, ucontact_info_t* _ci) {
     return 0;
 }
 
-/*!
- * \brief Remove a contact from list belonging to a certain record
- * \param _r record the contact belongs
- * \param _c removed contact
- */
-static inline void unlink_contact(struct impurecord* _r, ucontact_t* _c) {
-    if (_c->prev) {
-        _c->prev->next = _c->next;
-        if (_c->next) {
-            _c->next->prev = _c->prev;
-        }
-    } else {
-        _r->contacts = _c->next;
-        if (_c->next) {
-            _c->next->prev = 0;
-        }
-    }
-}
-
 /*!
  * \brief Insert a new contact into the list at the correct position
  * \param _r record that holds the sorted contacts
@@ -345,10 +332,19 @@ static inline void update_contact_pos(struct impurecord* _r, ucontact_t* _c) {
 int update_ucontact(struct impurecord* _r, ucontact_t* _c, ucontact_info_t* _ci) {
     /* we have to update memory in any case, but database directly
      * only in db_mode 1 */
+    LM_DBG("Updating contact aor: [%.*s] and contact uri: [%.*s]\n", _c->aor.len, _c->aor.s, _c->c.len, _c->c.s);
     if (mem_update_ucontact(_c, _ci) < 0) {
         LM_ERR("failed to update memory\n");
         return -1;
     }
+    
+    if (db_insert_ucontact(_r, _c) != 0) {  /* this is an insert/update */
+	LM_ERR("failed to update contact in DB [%.*s]\n", _c->aor.len, _c->aor.s);
+	return -1;
+    }
+    
+    //make sure IMPU is linked to this contact
+    link_contact_to_impu(_r, _c, 1);
 
     /* run callbacks for UPDATE event */
     if (exists_ulcb_type(_c->cbs, UL_CONTACT_UPDATE)) {
@@ -359,7 +355,7 @@ int update_ucontact(struct impurecord* _r, ucontact_t* _c, ucontact_info_t* _ci)
         run_ul_callbacks(_r->cbs, UL_IMPU_UPDATE_CONTACT, _r, _c);
     }
 
-    update_contact_pos(_r, _c);
+//    update_contact_pos(_r, _c);
 
     return 0;
 }
@@ -428,3 +424,9 @@ int remove_dialog_data_from_contact(ucontact_t* _c, unsigned int h_entry, unsign
     LM_DBG("Did not find dialog data to remove from contact");
     return 0;
 }
+
+void release_ucontact(struct ucontact* _c) {
+    lock_contact_slot_i(_c->contact_hash);
+    _c->ref_count--;
+    unlock_contact_slot_i(_c->contact_hash);
+}

+ 2 - 0
modules/ims_usrloc_scscf/ucontact.h

@@ -111,4 +111,6 @@ int remove_dialog_data_from_contact(ucontact_t* _c, unsigned int h_entry, unsign
 
 int add_dialog_data_to_contact(ucontact_t* _c, unsigned int h_entry, unsigned int h_id);
 
+void release_ucontact(struct ucontact* _c);
+
 #endif

+ 456 - 398
modules/ims_usrloc_scscf/udomain.c

@@ -65,34 +65,35 @@
 #include "usrloc.h"
 #include "bin_utils.h"
 #include "usrloc_db.h"
+#include "contact_hslot.h"
 
 extern int unreg_validity;
 extern int db_mode;
+struct contact_list* contact_list;
 
 #ifdef STATISTICS
-static char *build_stat_name( str* domain, char *var_name)
-{
-	int n;
-	char *s;
-	char *p;
-
-	n = domain->len + 1 + strlen(var_name) + 1;
-	s = (char*)shm_malloc( n );
-	if (s==0) {
-		LM_ERR("no more shm mem\n");
-		return 0;
-	}
-	memcpy( s, domain->s, domain->len);
-	p = s + domain->len;
-	*(p++) = '-';
-	memcpy( p , var_name, strlen(var_name));
-	p += strlen(var_name);
-	*(p++) = 0;
-	return s;
+
+static char *build_stat_name(str* domain, char *var_name) {
+    int n;
+    char *s;
+    char *p;
+
+    n = domain->len + 1 + strlen(var_name) + 1;
+    s = (char*) shm_malloc(n);
+    if (s == 0) {
+	LM_ERR("no more shm mem\n");
+	return 0;
+    }
+    memcpy(s, domain->s, domain->len);
+    p = s + domain->len;
+    *(p++) = '-';
+    memcpy(p, var_name, strlen(var_name));
+    p += strlen(var_name);
+    *(p++) = 0;
+    return s;
 }
 #endif
 
-
 /*!
  * \brief Create a new domain structure
  * \param  _n is pointer to str representing name of the domain, the string is
@@ -101,166 +102,156 @@ static char *build_stat_name( str* domain, char *var_name)
  * \param _d new created domain
  * \return 0 on success, -1 on failure
  */
-int new_udomain(str* _n, int _s, udomain_t** _d)
-{
-	int i;
+int new_udomain(str* _n, int _s, udomain_t** _d) {
+    int i;
 #ifdef STATISTICS
-	char *name;
+    char *name;
 #endif
 
-	/* Must be always in shared memory, since
-	 * the cache is accessed from timer which
-	 * lives in a separate process
-	 */
-	*_d = (udomain_t*)shm_malloc(sizeof(udomain_t));
-	if (!(*_d)) {
-		LM_ERR("new_udomain(): No memory left\n");
-		goto error0;
-	}
-	memset(*_d, 0, sizeof(udomain_t));
+    /* Must be always in shared memory, since
+     * the cache is accessed from timer which
+     * lives in a separate process
+     */
+    *_d = (udomain_t*) shm_malloc(sizeof (udomain_t));
+    if (!(*_d)) {
+	LM_ERR("new_udomain(): No memory left\n");
+	goto error0;
+    }
+    memset(*_d, 0, sizeof (udomain_t));
 
-	(*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s);
-	if (!(*_d)->table) {
-		LM_ERR("no memory left 2\n");
-		goto error1;
-	}
+    (*_d)->table = (hslot_t*) shm_malloc(sizeof (hslot_t) * _s);
+    if (!(*_d)->table) {
+	LM_ERR("no memory left 2\n");
+	goto error1;
+    }
 
-	(*_d)->name = _n;
+    (*_d)->name = _n;
 
-	for(i = 0; i < _s; i++) {
-		init_slot(*_d, &((*_d)->table[i]), i);
-	}
+    for (i = 0; i < _s; i++) {
+	init_slot(*_d, &((*_d)->table[i]), i);
+    }
 
-	(*_d)->size = _s;
+    (*_d)->size = _s;
 
 #ifdef STATISTICS
-	/* register the statistics */
-	if ( (name=build_stat_name(_n,"users"))==0 || register_stat("usrloc",
-	name, &(*_d)->users, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
-		LM_ERR("failed to add stat variable\n");
-		goto error2;
-	}
-	if ( (name=build_stat_name(_n,"contacts"))==0 || register_stat("usrloc",
-	name, &(*_d)->contacts, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
-		LM_ERR("failed to add stat variable\n");
-		goto error2;
-	}
-	if ( (name=build_stat_name(_n,"expires"))==0 || register_stat("usrloc",
-	name, &(*_d)->expires, STAT_SHM_NAME)!=0 ) {
-		LM_ERR("failed to add stat variable\n");
-		goto error2;
-	}
+    /* register the statistics */
+    if ((name = build_stat_name(_n, "users")) == 0 || register_stat("usrloc",
+	    name, &(*_d)->users, STAT_NO_RESET | STAT_SHM_NAME) != 0) {
+	LM_ERR("failed to add stat variable\n");
+	goto error2;
+    }
+    if ((name = build_stat_name(_n, "contacts")) == 0 || register_stat("usrloc",
+	    name, &(*_d)->contacts, STAT_NO_RESET | STAT_SHM_NAME) != 0) {
+	LM_ERR("failed to add stat variable\n");
+	goto error2;
+    }
+    if ((name = build_stat_name(_n, "expires")) == 0 || register_stat("usrloc",
+	    name, &(*_d)->expires, STAT_SHM_NAME) != 0) {
+	LM_ERR("failed to add stat variable\n");
+	goto error2;
+    }
 #endif
 
-	return 0;
+    return 0;
 #ifdef STATISTICS
 error2:
-	shm_free((*_d)->table);
+    shm_free((*_d)->table);
 #endif
 error1:
-	shm_free(*_d);
+    shm_free(*_d);
 error0:
-	return -1;
+    return -1;
 }
 
-
 /*!
  * \brief Free all memory allocated for the domain
  * \param _d freed domain
  */
-void free_udomain(udomain_t* _d)
-{
-	int i;
-
-	if (_d->table) {
-		for(i = 0; i < _d->size; i++) {
-			lock_ulslot(_d, i);
-			deinit_slot(_d->table + i);
-			unlock_ulslot(_d, i);
-		}
-		shm_free(_d->table);
+void free_udomain(udomain_t* _d) {
+    int i;
+
+    if (_d->table) {
+	for (i = 0; i < _d->size; i++) {
+	    lock_ulslot(_d, i);
+	    deinit_slot(_d->table + i);
+	    unlock_ulslot(_d, i);
 	}
-	shm_free(_d);
+	shm_free(_d->table);
+    }
+    shm_free(_d);
 }
 
-
 /*!
  * \brief Returns a static dummy impurecord for temporary usage
  * \param _d domain (needed for the name)
  * \param _aor address of record
  * \param _r new created urecord
  */
-static inline void get_static_impurecord(udomain_t* _d, str* _aor,	struct impurecord** _r)
-{
-	static struct impurecord r;
-
-	memset( &r, 0, sizeof(struct impurecord) );
-	r.public_identity = *_aor;
-	r.domain = _d->name;
-	*_r = &r;
-}
+static inline void get_static_impurecord(udomain_t* _d, str* _aor, struct impurecord** _r) {
+    static struct impurecord r;
 
+    memset(&r, 0, sizeof (struct impurecord));
+    r.public_identity = *_aor;
+    r.domain = _d->name;
+    *_r = &r;
+}
 
 /*!
  * \brief Debugging helper function
  */
-void print_udomain(FILE* _f, udomain_t* _d)
-{
-	int i;
-	int max=0, slot=0, n=0;
-	struct impurecord* r;
-	fprintf(_f, "---Domain---\n");
-	fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
-	fprintf(_f, "size : %d\n", _d->size);
-	fprintf(_f, "table: %p\n", _d->table);
-	/*fprintf(_f, "lock : %d\n", _d->lock); -- can be a structure --andrei*/
-	fprintf(_f, "\n");
-	for(i=0; i<_d->size; i++)
-	{
-		r = _d->table[i].first;
-		n += _d->table[i].n;
-		if(max<_d->table[i].n){
-			max= _d->table[i].n;
-			slot = i;
-		}
-		while(r) {
-			print_impurecord(_f, r);
-			r = r->next;
-		}
+void print_udomain(FILE* _f, udomain_t* _d) {
+    int i;
+    int max = 0, slot = 0, n = 0;
+    struct impurecord* r;
+    fprintf(_f, "---Domain---\n");
+    fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
+    fprintf(_f, "size : %d\n", _d->size);
+    fprintf(_f, "table: %p\n", _d->table);
+    /*fprintf(_f, "lock : %d\n", _d->lock); -- can be a structure --andrei*/
+    fprintf(_f, "\n");
+    for (i = 0; i < _d->size; i++) {
+	r = _d->table[i].first;
+	n += _d->table[i].n;
+	if (max < _d->table[i].n) {
+	    max = _d->table[i].n;
+	    slot = i;
 	}
-	fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n);
-	fprintf(_f, "\n---/Domain---\n");
+	while (r) {
+	    print_impurecord(_f, r);
+	    r = r->next;
+	}
+    }
+    fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n);
+    fprintf(_f, "\n---/Domain---\n");
 }
 
+inline int time2str(time_t _v, char* _s, int* _l) {
+    struct tm* t;
+    int l;
 
-inline int time2str(time_t _v, char* _s, int* _l)
-{
-	struct tm* t;
-	int l;
-
-	if ((!_s) || (!_l) || (*_l < 2)) {
-		LM_ERR("Invalid parameter value\n");
-		return -1;
-	}
+    if ((!_s) || (!_l) || (*_l < 2)) {
+	LM_ERR("Invalid parameter value\n");
+	return -1;
+    }
 
-	*_s++ = '\'';
+    *_s++ = '\'';
 
-	/* Convert time_t structure to format accepted by the database */
-	t = localtime(&_v);
-	l = strftime(_s, *_l -1, "%Y-%m-%d %H:%M:%S", t);
+    /* Convert time_t structure to format accepted by the database */
+    t = localtime(&_v);
+    l = strftime(_s, *_l - 1, "%Y-%m-%d %H:%M:%S", t);
 
-	if (l == 0) {
-		LM_ERR("Error during time conversion\n");
-		/* the value of _s is now unspecified */
-		_s = NULL;
-		_l = 0;
-		return -1;
-	}
-	*_l = l;
+    if (l == 0) {
+	LM_ERR("Error during time conversion\n");
+	/* the value of _s is now unspecified */
+	_s = NULL;
+	_l = 0;
+	return -1;
+    }
+    *_l = l;
 
-	*(_s + l) = '\'';
-	*_l = l + 2;
-	return 0;
+    *(_s + l) = '\'';
+    *_l = l + 2;
+    return 0;
 }
 
 /*!
@@ -271,159 +262,197 @@ inline int time2str(time_t _v, char* _s, int* _l)
  * \return 0 on success, -1 on failure
  */
 int mem_insert_impurecord(struct udomain* _d, str* public_identity, int reg_state, int barring,
-		ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2,
-		struct impurecord** _r) {
-	int sl;
-
-	if (new_impurecord(_d->name, public_identity, reg_state, barring, s, ccf1, ccf2, ecf1,
-			ecf2, _r) < 0) {
-		LM_ERR("creating impurecord failed\n");
-		return -1;
-	}
-	LM_DBG("Successfully parsed user data\n");
+	ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2,
+	struct impurecord** _r) {
+    int sl;
 
-	sl = ((*_r)->aorhash) & (_d->size - 1);
-	slot_add(&_d->table[sl], *_r);
-	update_stat( _d->users, 1);
-	return 0;
-}
+    if (new_impurecord(_d->name, public_identity, reg_state, barring, s, ccf1, ccf2, ecf1,
+	    ecf2, _r) < 0) {
+	LM_ERR("creating impurecord failed\n");
+	return -1;
+    }
+    LM_DBG("Successfully parsed user data\n");
 
+    sl = ((*_r)->aorhash) & (_d->size - 1);
+    slot_add(&_d->table[sl], *_r);
+    update_stat(_d->users, 1);
+
+    LM_DBG("inserted new impurecord into memory [%.*s]\n", (*_r)->public_identity.len, (*_r)->public_identity.s);
+    return 0;
+}
 
 /*!
  * \brief Remove a record from domain in memory
  * \param _d domain the record belongs to
  * \param _r deleted record
  */
-void mem_delete_impurecord(udomain_t* _d, struct impurecord* _r)
-{
-	slot_rem(_r->slot, _r);
-	free_impurecord(_r);
-	update_stat( _d->users, -1);
+void mem_delete_impurecord(udomain_t* _d, struct impurecord* _r) {
+    LM_DBG("deleting impurecord from memory [%.*s]\n", _r->public_identity.len, _r->public_identity.s);
+    slot_rem(_r->slot, _r);
+    free_impurecord(_r);
+    update_stat(_d->users, -1);
 }
 
-
 /*!
  * \brief Run timer handler for given domain
  * \param _d domain
  */
-void mem_timer_udomain(udomain_t* _d)
-{
-	struct impurecord* ptr, *t, *temp_impu;
-	int i, j, k;
-	ims_public_identity* impu;
-	unsigned int sl;
-
-	time_t time_now = time(NULL);
-
-	for(i=0; i<_d->size; i++)
-	{
-		lock_ulslot(_d, i);
-
-		ptr = _d->table[i].first;
-
-		while(ptr) {
-			timer_impurecord(ptr);
-			t = ptr;
-			ptr = ptr->next;
-
-			if (t->reg_state == IMPU_NOT_REGISTERED && t->shead == 0) {
-				//remove it - housekeeping - not sure why its still here...?
-				if (exists_ulcb_type(t->cbs, UL_IMPU_NR_DELETE))
-					run_ul_callbacks(t->cbs, UL_IMPU_NR_DELETE, t, NULL);
-					delete_impurecord(_d, &t->public_identity, t);
-			} else if (t->reg_state == IMPU_UNREGISTERED) {//Remove IMPU record if it is in state IMPU_UNREGISTERED and has expired
-			    
-				if (time_now >= t->expires) {//check here and only remove if no subscribes - if there is a subscribe then bump the validity by unreg_validity
-				    if(t->shead != 0){
-					LM_DBG("This impurecord still has subscriptions - extending the expiry");
-					t->expires = time(NULL) + unreg_validity;
-				    } else {
-					if (exists_ulcb_type(t->cbs, UL_IMPU_UNREG_EXPIRED))
-						run_ul_callbacks(t->cbs, UL_IMPU_UNREG_EXPIRED, t, NULL);
-					delete_impurecord(_d, &t->public_identity, t);
-				    }
-				}
-			//} else if (t->reg_state != IMPU_UNREGISTERED && t->contacts == 0) { /* Remove the entire record if it is empty IFF it is not an UNREGISTERED RECORD */
-			} else if (t->reg_state != IMPU_UNREGISTERED && t->contacts == 0 && t->shead == 0) { /* Remove the entire record if it is empty IFF it is not an UNREGISTERED RECORD */
-																								/* TS 23.228 5.3.2.1 (release 11) */
-				//need a way of distinguishing between deletes that need a SAR (expired) and deletes that do not need a SAR (explicit de reg)
-				//we only want to send one SAR for each implicit IMPU set
-				//make sure all IMPU's associated with this set are de-registered before calling the callbacks
-				int first=1;
-				int this_is_first = 0;
-
-				lock_get(t->s->lock);
-				for (k = 0; k < t->s->service_profiles_cnt; k++){
-					for (j = 0;j < t->s->service_profiles[k].public_identities_cnt;j++) {
-						impu = &(t->s->service_profiles[k].public_identities[j]);
-
-						sl = core_hash(&impu->public_identity, 0, _d->size);
-						if (sl != i)
-							lock_udomain(_d, &impu->public_identity);
-
-						if (first) {
-							first = 0; //dont do anything - we will leave this impu to be processed as normal
-							if (!strncmp(impu->public_identity.s, t->public_identity.s, t->public_identity.len)) {
-								//we are the first in the implicit set
-								this_is_first = 1;
-							}
-						} else {
-							//set all other implicits to not registered
-							if (update_impurecord(_d, &impu->public_identity, IMPU_NOT_REGISTERED,
-														-1/*barring*/, -1 /*do not change send sar on delete */, 0/*is_primary*/, NULL, NULL, NULL, NULL, NULL, &temp_impu) != 0) {
-								LM_ERR("Unable to update impurecord for <%.*s>\n", impu->public_identity.len, impu->public_identity.s);
-							}
-						}
-						if (sl != i)
-							unlock_udomain(_d, &impu->public_identity);
-					}
-				}
-				lock_release(t->s->lock);
-
-				if (this_is_first) {
-					//now run a normal callback on our
-					if (exists_ulcb_type(t->cbs, UL_IMPU_REG_NC_DELETE))
-						run_ul_callbacks(t->cbs, UL_IMPU_REG_NC_DELETE, t, NULL);
-						delete_impurecord(_d, &t->public_identity, t);
-				}
-			}
-		}
-		unlock_ulslot(_d, i);
+void mem_timer_udomain(udomain_t* _d) {
+    struct impurecord* ptr, *t;
+    struct ucontact* contact_ptr, *tmp_contact_ptr;
+    int i;
+
+    //go through contacts first
+    LM_DBG("*** mem_timer_udomain - checking contacts - START ***\n");
+    
+    for (i = 0; i < contact_list->size; i++) {
+#ifdef EXTRA_DEBUG
+	LM_DBG("looking for contacts in slot %d\n", i);
+#endif
+	lock_contact_slot_i(i);
+	contact_ptr = contact_list->slot[i].first;
+	while (contact_ptr) {
+	    LM_DBG("We have a contact in the new contact list in slot %d = [%.*s] (%.*s) which expires in %lf seconds and has a ref count of %d\n", i, contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s, (double) contact_ptr->expires - time(NULL), contact_ptr->ref_count);
+	    if (contact_ptr->ref_count <= 0) {
+		LM_DBG("Deleting contact [%.*s]\n", contact_ptr->c.len, contact_ptr->c.s);
+		tmp_contact_ptr = contact_ptr->next;
+		delete_ucontact(contact_ptr);
+		contact_ptr = tmp_contact_ptr;
+	    } else {
+		contact_ptr = contact_ptr->next;
+	    }
+	}
+	unlock_contact_slot_i(i);
+    }
+    
+    LM_DBG("*** mem_timer_udomain - checking contacts - FINISHED ***\n");
+
+    int temp = 0;
+
+    LM_DBG("*** mem_timer_udomain - checking IMPUs - START ***\n");
+    for (i = 0; i < _d->size; i++) {
+	lock_ulslot(_d, i);
+	ptr = _d->table[i].first;
+	temp = 0;
+	while (ptr) {
+	    temp = 1;
+#ifdef EXTRA_DEBUG
+	    LM_DBG("ULSLOT %d LOCKED\n", i);
+#endif
+	    timer_impurecord(ptr);
+	    t = ptr;
+	    ptr = ptr->next;
+
+	    			if (t->reg_state == IMPU_NOT_REGISTERED && t->shead == 0) {
+	    				//remove it - housekeeping - not sure why its still here...?
+	    				if (exists_ulcb_type(t->cbs, UL_IMPU_NR_DELETE))
+	    					run_ul_callbacks(t->cbs, UL_IMPU_NR_DELETE, t, NULL);
+	    					    
+	    				LM_DBG("about to delete impurecord\n");
+	    				delete_impurecord(_d, &t->public_identity, t);
+	    			} //else if (t->reg_state == IMPU_UNREGISTERED) {//Remove IMPU record if it is in state IMPU_UNREGISTERED and has expired
+	    //			    
+	    //				if (time_now >= t->expires) {//check here and only remove if no subscribes - if there is a subscribe then bump the validity by unreg_validity
+	    //				    if(t->shead != 0){
+	    //					LM_DBG("This impurecord still has subscriptions - extending the expiry");
+	    //					t->expires = time(NULL) + unreg_validity;
+	    //				    } else {
+	    //					if (exists_ulcb_type(t->cbs, UL_IMPU_UNREG_EXPIRED))
+	    //						run_ul_callbacks(t->cbs, UL_IMPU_UNREG_EXPIRED, t, NULL);
+	    //					LM_DBG("about to delete impurecord\n");
+	    //					delete_impurecord(_d, &t->public_identity, t);
+	    //				    }
+	    //				}
+	    //			//} else if (t->reg_state != IMPU_UNREGISTERED && t->contacts == 0) { /* Remove the entire record if it is empty IFF it is not an UNREGISTERED RECORD */
+	    //			} else if (t->reg_state != IMPU_UNREGISTERED && t->num_contacts == 0 && t->shead == 0) { /* Remove the entire record if it is empty IFF it is not an UNREGISTERED RECORD */
+	    //																								/* TS 23.228 5.3.2.1 (release 11) */
+	    //				//need a way of distinguishing between deletes that need a SAR (expired) and deletes that do not need a SAR (explicit de reg)
+	    //				//we only want to send one SAR for each implicit IMPU set
+	    //				//make sure all IMPU's associated with this set are de-registered before calling the callbacks
+	    //				int first=1;
+	    //				int this_is_first = 0;
+	    //
+	    //				lock_get(t->s->lock);
+	    //				for (k = 0; k < t->s->service_profiles_cnt; k++){
+	    //					for (j = 0;j < t->s->service_profiles[k].public_identities_cnt;j++) {
+	    //						impu = &(t->s->service_profiles[k].public_identities[j]);
+	    //
+	    //						sl = core_hash(&impu->public_identity, 0, _d->size);
+	    //						if (sl != i)
+	    //							lock_udomain(_d, &impu->public_identity);
+	    //
+	    //						if (first) {
+	    //							first = 0; //dont do anything - we will leave this impu to be processed as normal
+	    //							if (!strncmp(impu->public_identity.s, t->public_identity.s, t->public_identity.len)) {
+	    //								//we are the first in the implicit set
+	    //								this_is_first = 1;
+	    //							}
+	    //						} else {
+	    //							//set all other implicits to not registered
+	    //							if (update_impurecord(_d, &impu->public_identity, IMPU_NOT_REGISTERED,
+	    //														-1/*barring*/, -1 /*do not change send sar on delete */, 0/*is_primary*/, NULL, NULL, NULL, NULL, NULL, &temp_impu) != 0) {
+	    //								LM_ERR("Unable to update impurecord for <%.*s>\n", impu->public_identity.len, impu->public_identity.s);
+	    //							}
+	    //						}
+	    //						if (sl != i)
+	    //							unlock_udomain(_d, &impu->public_identity);
+	    //					}
+	    //				}
+	    //				lock_release(t->s->lock);
+	    //
+	    //				if (this_is_first) {
+	    //					//now run a normal callback on our
+	    //					if (exists_ulcb_type(t->cbs, UL_IMPU_REG_NC_DELETE))
+	    //						run_ul_callbacks(t->cbs, UL_IMPU_REG_NC_DELETE, t, NULL);
+	    //					LM_DBG("about to delete impurecord\n");
+	    //						delete_impurecord(_d, &t->public_identity, t);
+	    //				}
+	    //			}
 	}
+	if (temp) {
+#ifdef EXTRA_DEBUG
+	    LM_DBG("ULSLOT %d UN-LOCKED\n", i);
+#endif
+	}
+	unlock_ulslot(_d, i);
+    }
+    LM_DBG("*** mem_timer_udomain - checking IMPUs - FINISHED ***\n");
 }
 
-
 /*!
  * \brief Get lock for a domain
  * \param _d domain
  * \param _aor adress of record, used as hash source for the lock slot
  */
-void lock_udomain(udomain_t* _d, str* _aor)
-{
-	unsigned int sl;
-	sl = core_hash(_aor, 0, _d->size);
+void lock_udomain(udomain_t* _d, str* _aor) {
+    unsigned int sl;
+    sl = core_hash(_aor, 0, _d->size);
+#ifdef EXTRA_DEBUG
+    LM_DBG("LOCKING UDOMAIN SLOT [%d]\n", sl);
+#endif
 
 #ifdef GEN_LOCK_T_PREFERED
-	lock_get(_d->table[sl].lock);
+    lock_get(_d->table[sl].lock);
 #else
-	ul_lock_idx(_d->table[sl].lockidx);
+    ul_lock_idx(_d->table[sl].lockidx);
 #endif
 }
 
-
 /*!
  * \brief Release lock for a domain
  * \param _d domain
  * \param _aor address of record, uses as hash source for the lock slot
  */
-void unlock_udomain(udomain_t* _d, str* _aor)
-{
-	unsigned int sl;
-	sl = core_hash(_aor, 0, _d->size);
+void unlock_udomain(udomain_t* _d, str* _aor) {
+    unsigned int sl;
+    sl = core_hash(_aor, 0, _d->size);
+#ifdef EXTRA_DEBUG
+    LM_DBG("UN-LOCKING UDOMAIN SLOT [%d]\n", sl);
+#endif
 #ifdef GEN_LOCK_T_PREFERED
-	lock_release(_d->table[sl].lock);
+    lock_release(_d->table[sl].lock);
 #else
-	ul_release_idx(_d->table[sl].lockidx);
+    ul_release_idx(_d->table[sl].lockidx);
 #endif
 }
 
@@ -432,30 +461,61 @@ void unlock_udomain(udomain_t* _d, str* _aor)
  * \param _d domain
  * \param i slot number
  */
-void lock_ulslot(udomain_t* _d, int i)
-{
+void lock_ulslot(udomain_t* _d, int i) {
 #ifdef GEN_LOCK_T_PREFERED
-	lock_get(_d->table[i].lock);
+    lock_get(_d->table[i].lock);
 #else
-	ul_lock_idx(_d->table[i].lockidx);
+    ul_lock_idx(_d->table[i].lockidx);
 #endif
 }
 
-
 /*!
  * \brief Release lock for a slot
  * \param _d domain
  * \param i slot number
  */
-void unlock_ulslot(udomain_t* _d, int i)
-{
+void unlock_ulslot(udomain_t* _d, int i) {
+#ifdef GEN_LOCK_T_PREFERED
+    lock_release(_d->table[i].lock);
+#else
+    ul_release_idx(_d->table[i].lockidx);
+#endif
+}
+
+void lock_contact_slot(str* contact_uri) {
+    unsigned int sl;
+    sl = core_hash(contact_uri, 0, contact_list->size);
+    lock_contact_slot_i(sl);
+}
+
+void unlock_contact_slot(str* contact_uri) {
+    unsigned int sl;
+    sl = core_hash(contact_uri, 0, contact_list->size);
+
+    unlock_contact_slot_i(sl);
+}
+
+void lock_contact_slot_i(int i) {
+#ifdef EXTRA_DEBUG
+    LM_DBG("LOCKING CONTACT SLOT [%d]\n", i);
+#endif
 #ifdef GEN_LOCK_T_PREFERED
-	lock_release(_d->table[i].lock);
+    lock_get(contact_list->slot[i].lock);
 #else
-	ul_release_idx(_d->table[i].lockidx);
+    lock_contacts_idx(contact_list->slot[i].lockidx);
 #endif
 }
 
+void unlock_contact_slot_i(int i) {
+#ifdef EXTRA_DEBUG
+    LM_DBG("UN-LOCKING CONTACT SLOT [%d]\n", i);
+#endif
+#ifdef GEN_LOCK_T_PREFERED
+    lock_release(contact_list->slot[i].lock);
+#else
+    release_contact_idx(contact_list->slot[i].lockidx);
+#endif
+}
 
 /*!
  * \brief Create and insert a new record
@@ -465,39 +525,38 @@ void unlock_ulslot(udomain_t* _d, int i)
  * \return return 0 on success, -1 on failure
  */
 int insert_impurecord(struct udomain* _d, str* public_identity, int reg_state, int barring,
-		ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2,
-		struct impurecord** _r) {
-
-//	ims_subscription* s = 0;
-//	/*check we can parse XML user data*/
-//	if (xml_data->s && xml_data->len > 0) {
-//		s = parse_user_data(*xml_data);
-//		if (!s) {
-//			LM_ERR("Unable to parse XML user data from SAA\n");
-//			goto error;
-//		}
-//	}
+	ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2,
+	struct impurecord** _r) {
+
+    //	ims_subscription* s = 0;
+    //	/*check we can parse XML user data*/
+    //	if (xml_data->s && xml_data->len > 0) {
+    //		s = parse_user_data(*xml_data);
+    //		if (!s) {
+    //			LM_ERR("Unable to parse XML user data from SAA\n");
+    //			goto error;
+    //		}
+    //	}
     if (mem_insert_impurecord(_d, public_identity, reg_state, barring, s, ccf1, ccf2, ecf1, ecf2, _r) < 0) {
-        LM_ERR("inserting record failed\n");
-        goto error;
+	LM_ERR("inserting record failed\n");
+	goto error;
     }
 
     /*DB?*/
-	if (db_mode == WRITE_THROUGH && db_insert_impurecord(_d, public_identity, reg_state, barring, s, ccf1, ccf2, ecf1, ecf2, _r) != 0) {
-		LM_ERR("error inserting contact into db");
-		goto error;
-	}
+    if (db_mode == WRITE_THROUGH && db_insert_impurecord(_d, public_identity, reg_state, barring, s, ccf1, ccf2, ecf1, ecf2, _r) != 0) {
+	LM_ERR("error inserting contact into db");
+	goto error;
+    }
 
     return 0;
 
 error:
-//    if (s) {
-//    	free_ims_subscription_data(s);
-//    }
+    //    if (s) {
+    //    	free_ims_subscription_data(s);
+    //    }
     return -1;
 }
 
-
 /*!
  * \brief Obtain a impurecord pointer if the impurecord exists in domain
  * \param _d domain to search the record
@@ -506,24 +565,24 @@ error:
  * \return 0 if a record was found, 1 if nothing could be found
  */
 int get_impurecord(udomain_t* _d, str* public_identity, struct impurecord** _r) {
-	unsigned int sl, i, aorhash;
-	impurecord_t* r;
-
-	/* search in cache */
-	aorhash = core_hash(public_identity, 0, 0);
-	sl = aorhash & (_d->size - 1);
-	r = _d->table[sl].first;
-
-	for (i = 0; i < _d->table[sl].n; i++) {
-		if ((r->aorhash == aorhash) && (r->public_identity.len == public_identity->len)
-				&& !memcmp(r->public_identity.s, public_identity->s, public_identity->len)) {
-			*_r = r;
-			return 0;
-		}
-
-		r = r->next;
+    unsigned int sl, i, aorhash;
+    impurecord_t* r;
+
+    /* search in cache */
+    aorhash = core_hash(public_identity, 0, 0);
+    sl = aorhash & (_d->size - 1);
+    r = _d->table[sl].first;
+
+    for (i = 0; i < _d->table[sl].n; i++) {
+	if ((r->aorhash == aorhash) && (r->public_identity.len == public_identity->len)
+		&& !memcmp(r->public_identity.s, public_identity->s, public_identity->len)) {
+	    *_r = r;
+	    return 0;
 	}
-	return 1; /* Nothing found */
+
+	r = r->next;
+    }
+    return 1; /* Nothing found */
 }
 
 /*!
@@ -533,41 +592,41 @@ int get_impurecord(udomain_t* _d, str* public_identity, struct impurecord** _r)
  * \param _r deleted record
  * \return 0 on success, -1 if the record could not be deleted
  */
-int delete_impurecord(udomain_t* _d, str* _aor, struct impurecord* _r)
-{
-	struct ucontact* c, *t;
+int delete_impurecord(udomain_t* _d, str* _aor, struct impurecord* _r) {
+    //    struct ucontact* c;//, *t;
 
     LM_DBG("Deleting IMPURECORD [%.*s]\n", _r->public_identity.len, _r->public_identity.s);
 
-	if (_r==0) {
-		if (get_impurecord(_d, _aor, &_r) > 0) {
-			return 0;
-		}
-	}
-
-    c = _r->contacts;
-	while(c) {
-		t = c;
-		c = c->next;
-		if (delete_ucontact(_r, t) < 0) {
-			LM_ERR("deleting contact failed [%.*s]\n", c->aor->len, c->aor->s);
-			return -1;
-		}
-	}
-
-	if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE)) {
-	        run_ul_callbacks(_r->cbs, UL_IMPU_DELETE, _r, 0);
+    if (_r == 0) {
+	if (get_impurecord(_d, _aor, &_r) > 0) {
+	    return 0;
 	}
+    }
 
-	/*DB?*/
-	if (db_mode == WRITE_THROUGH
-			&& db_delete_impurecord(_d, _r) != 0) {
-		LM_ERR("error deleting IMPU record from db");
-		return 0;
-	}
+    //TODO: need to unref the contacts in the contact list (not delete them), the timer should delete all contacts that are unreffed
+    //    c = _r->contacts;
+    //    while (c) {
+    //	t = c;
+    //	c = c->next;
+    //	if (delete_ucontact(_r, t) < 0) {
+    //	    LM_ERR("deleting contact failed [%.*s]\n", c->aor.len, c->aor.s);
+    //	    return -1;
+    //	}
+    //    }
+
+    if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE)) {
+	run_ul_callbacks(_r->cbs, UL_IMPU_DELETE, _r, 0);
+    }
 
-	mem_delete_impurecord(_d, _r);
+    /*DB?*/
+    if (db_mode == WRITE_THROUGH
+	    && db_delete_impurecord(_d, _r) != 0) {
+	LM_ERR("error deleting IMPU record from db");
 	return 0;
+    }
+
+    mem_delete_impurecord(_d, _r);
+    return 0;
 }
 
 /*
@@ -577,82 +636,81 @@ int delete_impurecord(udomain_t* _d, str* _aor, struct impurecord* _r)
  * barring-(-1) get all records
  * NB. Remember to free the block of memory pointed to by impus (pkg_malloc)
  */
-int get_impus_from_subscription_as_string(udomain_t* _d, impurecord_t* impu_rec, int barring, str** impus, int* num_impus)
-{
-	int i, j, count;
-	*num_impus = 0;
-	*impus = 0;
-	ims_public_identity* impi;
-	int bytes_needed = 0;
-	int len = 0;
-
-	LM_DBG("getting IMPU subscription set\n");
-
-	if (!impu_rec){
-		LM_ERR("no impu record provided\n");
-		return 1;
-	}
+int get_impus_from_subscription_as_string(udomain_t* _d, impurecord_t* impu_rec, int barring, str** impus, int* num_impus) {
+    int i, j, count;
+    *num_impus = 0;
+    *impus = 0;
+    ims_public_identity* impi;
+    int bytes_needed = 0;
+    int len = 0;
+
+    LM_DBG("getting IMPU subscription set\n");
+
+    if (!impu_rec) {
+	LM_ERR("no impu record provided\n");
+	return 1;
+    }
 
-	if (!impu_rec->s) {
-		LM_DBG("no subscription associated with impu\n");
-		return 0;
-	}
+    if (!impu_rec->s) {
+	LM_DBG("no subscription associated with impu\n");
+	return 0;
+    }
 
-	lock_get(impu_rec->s->lock);
-	for (i = 0; i < impu_rec->s->service_profiles_cnt; i++) {
-		for (j = 0; j < impu_rec->s->service_profiles[i].public_identities_cnt; j++) {
-			impi = &(impu_rec->s->service_profiles[i].public_identities[j]);
-			if (barring<0) {
-				//get all records
-				bytes_needed += impi->public_identity.len;
-				(*num_impus)++;
-			} else {
-				if (impi->barring == barring) {
-					//add the record to the list
-					bytes_needed += impi->public_identity.len;
-					(*num_impus)++;
-				}
-			}
+    lock_get(impu_rec->s->lock);
+    for (i = 0; i < impu_rec->s->service_profiles_cnt; i++) {
+	for (j = 0; j < impu_rec->s->service_profiles[i].public_identities_cnt; j++) {
+	    impi = &(impu_rec->s->service_profiles[i].public_identities[j]);
+	    if (barring < 0) {
+		//get all records
+		bytes_needed += impi->public_identity.len;
+		(*num_impus)++;
+	    } else {
+		if (impi->barring == barring) {
+		    //add the record to the list
+		    bytes_needed += impi->public_identity.len;
+		    (*num_impus)++;
 		}
+	    }
 	}
-	LM_DBG("num of records returned is %d and we need %d bytes\n", *num_impus, bytes_needed);
-
-	len = (sizeof(str)*(*num_impus)) + bytes_needed;
-	*impus = (str*)pkg_malloc(len);
-	char* ptr = (char*)(*impus + *num_impus);
-
-	//now populate the data
-	count=0;
-	for (i = 0; i < impu_rec->s->service_profiles_cnt; i++) {
-		for (j = 0; j < impu_rec->s->service_profiles[i].public_identities_cnt; j++) {
-			impi = &(impu_rec->s->service_profiles[i].public_identities[j]);
-			if (barring < 0) {
-				//get all records
-				(*impus)[count].s = ptr;
-				memcpy(ptr, impi->public_identity.s, impi->public_identity.len);
-				(*impus)[count].len = impi->public_identity.len;
-				ptr += impi->public_identity.len;
-				count++;
-			} else {
-				if (impi->barring == barring) {
-					//add the record to the list
-					(*impus)[count].s = ptr;
-					memcpy(ptr, impi->public_identity.s, impi->public_identity.len);
-					(*impus)[count].len = impi->public_identity.len;
-					ptr += impi->public_identity.len;
-					count++;
-				}
-			}
+    }
+    LM_DBG("num of records returned is %d and we need %d bytes\n", *num_impus, bytes_needed);
+
+    len = (sizeof (str)*(*num_impus)) + bytes_needed;
+    *impus = (str*) pkg_malloc(len);
+    char* ptr = (char*) (*impus + *num_impus);
+
+    //now populate the data
+    count = 0;
+    for (i = 0; i < impu_rec->s->service_profiles_cnt; i++) {
+	for (j = 0; j < impu_rec->s->service_profiles[i].public_identities_cnt; j++) {
+	    impi = &(impu_rec->s->service_profiles[i].public_identities[j]);
+	    if (barring < 0) {
+		//get all records
+		(*impus)[count].s = ptr;
+		memcpy(ptr, impi->public_identity.s, impi->public_identity.len);
+		(*impus)[count].len = impi->public_identity.len;
+		ptr += impi->public_identity.len;
+		count++;
+	    } else {
+		if (impi->barring == barring) {
+		    //add the record to the list
+		    (*impus)[count].s = ptr;
+		    memcpy(ptr, impi->public_identity.s, impi->public_identity.len);
+		    (*impus)[count].len = impi->public_identity.len;
+		    ptr += impi->public_identity.len;
+		    count++;
 		}
+	    }
 	}
+    }
 
-	if (ptr != ((char*)*impus + len)) {
-		LM_CRIT("buffer overflow\n");
-		return 1;
-	}
+    if (ptr != ((char*) *impus + len)) {
+	LM_CRIT("buffer overflow\n");
+	return 1;
+    }
 
-	lock_release(impu_rec->s->lock);
+    lock_release(impu_rec->s->lock);
 
-	return 0;
+    return 0;
 }
 

+ 15 - 11
modules/ims_usrloc_scscf/udomain.h

@@ -62,21 +62,20 @@
 #include "hslot.h"
 #include "usrloc.h"
 
-struct hslot;   /*!< Hash table slot */
+struct hslot; /*!< Hash table slot */
 struct impurecord; /*!< Usrloc record */
 
-
 /*! \brief
  * The structure represents a usrloc domain
  */
 struct udomain {
-	str* name;                 /*!< Domain name (NULL terminated) */
-	int size;                  /*!< Hash table size */
-	struct hslot* table;       /*!< Hash table - array of collision slots */
-	/* statistics */
-	stat_var *users;           /*!< no of registered users */
-	stat_var *contacts;        /*!< no of registered contacts */
-	stat_var *expires;         /*!< no of expires */
+    str* name; /*!< Domain name (NULL terminated) */
+    int size; /*!< Hash table size */
+    struct hslot* table; /*!< Hash table - array of collision slots */
+    /* statistics */
+    stat_var *users; /*!< no of registered users */
+    stat_var *contacts; /*!< no of registered contacts */
+    stat_var *expires; /*!< no of expires */
 };
 
 
@@ -159,6 +158,11 @@ void lock_ulslot(udomain_t* _d, int i);
  */
 void unlock_ulslot(udomain_t* _d, int i);
 
+void lock_contact_slot(str* contact_uri);
+void unlock_contact_slot(str* contact_uri);
+void lock_contact_slot_i(int i);
+void unlock_contact_slot_i(int i);
+
 /* ===== module interface ======= */
 
 
@@ -170,8 +174,8 @@ void unlock_ulslot(udomain_t* _d, int i);
  * \return return 0 on success, -1 on failure
  */
 int insert_impurecord(struct udomain* _d, str* public_identity, int reg_state, int barring,
-		ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2,
-		struct impurecord** _r);
+        ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2,
+        struct impurecord** _r);
 
 
 /*!

+ 1 - 4
modules/ims_usrloc_scscf/ul_callback.h

@@ -82,15 +82,13 @@ struct ul_callback {
 	struct ul_callback* next;
 };
 
-struct ulcb_head_list {
+    struct ulcb_head_list {
 	struct ul_callback *first;
 	int reg_types;
 };
 
-
 extern struct ulcb_head_list*  ulcb_list;
 
-
 static inline int exists_ulcb_type(struct ulcb_head_list* list, int types) {
 	if (list==NULL)
 		return (ulcb_list->reg_types|types);
@@ -102,7 +100,6 @@ int init_ulcb_list(void);
 
 void destroy_ulcb_list(void);
 
-
 /*! \brief register a callback for several types of events */
 int register_ulcb( struct impurecord* r, struct ucontact* c, int types, ul_cb f, void *param );
 

+ 35 - 4
modules/ims_usrloc_scscf/ul_mod.c

@@ -60,10 +60,9 @@
 #include "usrloc.h"
 #include "hslot_sp.h"
 #include "usrloc_db.h"
-
+#include "contact_hslot.h"
 #include "../presence/bind_presence.h"
 #include "../presence/hash.h"
-
 #include "../../modules/dialog_ng/dlg_load.h"
 #include "../../modules/dialog_ng/dlg_hash.h"
 
@@ -81,6 +80,7 @@ static int child_init(int rank);                    /*!< Per-child init function
 extern int bind_usrloc(usrloc_api_t* api);
 extern int ul_locks_no;
 extern int subs_locks_no;
+extern int contacts_locks_no;
 /*
  * Module parameters and their default values
  */
@@ -98,6 +98,9 @@ int maxcontact_behaviour = 0;			/*!< max contact behaviour - 0-disabled(default)
 int ul_fetch_rows = 2000;				/*!< number of rows to fetch from result */
 int ul_hash_size = 9;
 int subs_hash_size = 9;					/*!<number of ims subscription slots*/
+int contacts_hash_size = 9;
+
+struct contact_list* contact_list;
 
 int db_mode = 0;						/*!<database mode*/
 db1_con_t* ul_dbh = 0;
@@ -188,7 +191,7 @@ struct module_exports exports = {
  * Module initialization function
  */
 static int mod_init(void) {
-
+	int i;
 	load_dlg_f load_dlg;
 	if (usrloc_debug){
 		LM_INFO("Logging usrloc records to %.*s\n", usrloc_debug_file.len, usrloc_debug_file.s);
@@ -221,6 +224,12 @@ static int mod_init(void) {
 	else
 		subs_hash_size = 1 << subs_hash_size;
 	subs_locks_no = subs_hash_size;
+	
+	if (contacts_hash_size <= 1)
+		contacts_hash_size = 512;
+	else
+		contacts_hash_size = 1 << contacts_hash_size;
+	contacts_locks_no = contacts_hash_size;
 
 	/* check matching mode */
 	switch (matching_mode) {
@@ -242,7 +251,27 @@ static int mod_init(void) {
 		LM_ERR("IMS Subscription locks array initialization failed\n");
 		return -1;
 	}
-
+	
+	/* create hash table for storing registered contacts */
+	if (init_contacts_locks() !=0) {
+	    LM_ERR("failed to initialise locks array for contacts\n");
+	    return -1;
+	}
+	contact_list = (struct contact_list*)shm_malloc(sizeof(struct contact_list));
+	if (!contact_list) {
+	    LM_ERR("no more memory to create contact list structure\n");
+	    return -1;
+	}
+	contact_list->slot = (struct contact_hslot*) shm_malloc(sizeof(struct contact_hslot) * contacts_hash_size);
+	if (!contact_list->slot) {
+	    LM_ERR("no more memory to create contact list structure\n");
+	    return -1;
+	}
+	for (i=0; i<contacts_hash_size;i++) {
+	    init_contact_slot(&contact_list->slot[i], i);
+	} 
+	contact_list->size = contacts_hash_size;
+	
 	/* presence binding for subscribe processing*/
 	presence_api_t pres;
 	bind_presence_t bind_presence;
@@ -395,6 +424,8 @@ static void destroy(void) {
 
 	free_all_udomains();
 	ul_destroy_locks();
+	subs_destroy_locks();
+	destroy_contacts_locks();
 
 	/* free callbacks list */
 	destroy_ulcb_list();

+ 124 - 123
modules/ims_usrloc_scscf/ul_rpc.c

@@ -32,146 +32,147 @@ static const char* ul_rpc_showimpu_doc[2] = {"Dump SCSCF IMPU information", 0 };
 static unsigned int contact_buflen = 0;
 static str contact_buf = {0,0};
 
-static void ul_rpc_show_impu(rpc_t* rpc, void* ctx)
-{
-	int i, j;
-	str impu;
-	int res;
-	udomain_t* domain;
-	struct impurecord* impu_rec;
-	ucontact_t* contact;
-	void *ah, *sh, *ch, *cdh, *sdh, *sph, *spi;
-	char numstr[21+16]; //enough for all numbers up to 64bits + longest length of field name (16)
-
-	if (rpc->scan(ctx, "S", &impu) < 1) {
-		rpc->fault(ctx, 400, "required IMPU argument");
-		return;
-	}
-
-	LM_DBG("searching for impu <%.*s>\n", impu.len, impu.s);
-
-	res = get_udomain("location", &domain);
-	if (res != 0) {
-		LM_ERR("Failed to get domain\n");
-		return;
-	}
+static void ul_rpc_show_impu(rpc_t* rpc, void* ctx) {
+    int i, j;
+    str impu;
+    int res;
+    udomain_t* domain;
+    struct impurecord* impu_rec;
+    ucontact_t* contact;
+    void *ah, *sh, *ch, *cdh, *sdh, *sph, *spi;
+    char numstr[21 + 16]; //enough for all numbers up to 64bits + longest length of field name (16)
+
+    if (rpc->scan(ctx, "S", &impu) < 1) {
+	rpc->fault(ctx, 400, "required IMPU argument");
+	return;
+    }
+
+    LM_DBG("searching for impu <%.*s>\n", impu.len, impu.s);
+
+    res = get_udomain("location", &domain);
+    if (res != 0) {
+	LM_ERR("Failed to get domain\n");
+	return;
+    }
+
+    lock_udomain(domain, &impu);
+    res = get_impurecord(domain, &impu, &impu_rec);
+    if (res != 0) {
+	unlock_udomain(domain, &impu);
+	return;
+    }
 
-	lock_udomain(domain, &impu);
-	res = get_impurecord(domain, &impu, &impu_rec);
-	if (res != 0) {
-		unlock_udomain(domain, &impu);
-		return;
-	}
+    //now print the data for this IMPU record
+    if (rpc->add(ctx, "{", &ah) < 0) {
+	rpc->fault(ctx, 500, "Internal error creating IMPU struct");
+	unlock_udomain(domain, &impu);
+	return;
+    }
+
+    if (rpc->struct_add(ah, "SsdSSSS",
+	    "impu", &impu,
+	    "state", get_impu_regstate_as_string(impu_rec->reg_state),
+	    "barring", impu_rec->barring,
+	    "ccf1", &impu_rec->ccf1,
+	    "ccf2", &impu_rec->ccf2,
+	    "ecf1", &impu_rec->ecf1,
+	    "ecf2", &impu_rec->ecf2
+	    ) < 0) {
+	rpc->fault(ctx, 500, "Internal error adding impu data");
+	unlock_udomain(domain, &impu);
+	return;
+    }
 
-	//now print the data for this IMPU record
-	if (rpc->add(ctx, "{", &ah) < 0) {
-		rpc->fault(ctx, 500, "Internal error creating IMPU struct");
-		unlock_udomain(domain, &impu);
-		return;
+    if (rpc->struct_add(ah, "{", "subscription", &sh) < 0) {
+	rpc->fault(ctx, 500, "Internal error adding impu subscription data");
+	unlock_udomain(domain, &impu);
+	return;
+    }
+
+    ims_subscription* subscription = impu_rec->s;
+    lock_get(subscription->lock);
+    //add subscription data
+    if (rpc->struct_add(sh, "S{", "impi", &subscription->private_identity, "service profiles", &sph) < 0) {
+	rpc->fault(ctx, 500, "Internal error adding impu subscription data");
+	lock_release(subscription->lock);
+	unlock_udomain(domain, &impu);
+	return;
+    }
+
+    //add subscription detail information
+    for (i = 0; i < subscription->service_profiles_cnt; i++) {
+	sprintf(numstr, "%d", i + 1);
+	if (rpc->struct_add(sph, "{", numstr, &sdh) < 0) {
+	    rpc->fault(ctx, 500, "Internal error adding impu subscription detail data");
+	    lock_release(subscription->lock);
+	    unlock_udomain(domain, &impu);
+	    return;
 	}
-
-	if (rpc->struct_add(ah, "SsdSSSS",
-			"impu", &impu,
-			"state", get_impu_regstate_as_string(impu_rec->reg_state),
-			"barring", impu_rec->barring,
-			"ccf1", &impu_rec->ccf1,
-			"ccf2", &impu_rec->ccf2,
-			"ecf1", &impu_rec->ecf1,
-			"ecf2", &impu_rec->ecf2
-			) < 0) {
-		rpc->fault(ctx, 500, "Internal error adding impu data");
-		unlock_udomain(domain, &impu);
-		return;
+	if (rpc->struct_add(sdh, "{", "impus", &spi) < 0) {
+	    rpc->fault(ctx, 500, "Internal error adding impu subscription data");
+	    lock_release(subscription->lock);
+	    unlock_udomain(domain, &impu);
+	    return;
 	}
 
-	if (rpc->struct_add(ah, "{", "subscription", &sh) < 0) {
-		rpc->fault(ctx, 500, "Internal error adding impu subscription data");
-		unlock_udomain(domain, &impu);
-		return;
-	}
-
-	ims_subscription* subscription = impu_rec->s;
-	lock_get(subscription->lock);
-	//add subscription data
-	if (rpc->struct_add(sh, "S{", "impi", &subscription->private_identity, "service profiles", &sph) < 0) {
-		rpc->fault(ctx, 500, "Internal error adding impu subscription data");
+	for (j = 0; j < subscription->service_profiles[i].public_identities_cnt; j++) {
+	    sprintf(numstr, "%d", j + 1);
+	    if (rpc->struct_add(spi, "S", numstr, &subscription->service_profiles[i].public_identities[j].public_identity) < 0) {
+		rpc->fault(ctx, 500, "Internal error adding impu subscription detail data");
 		lock_release(subscription->lock);
 		unlock_udomain(domain, &impu);
 		return;
+	    }
 	}
+    }
 
-	//add subscription detail information
-	for (i=0; i<subscription->service_profiles_cnt; i++) {
-		sprintf(numstr, "%d", i+1);
-		if (rpc->struct_add(sph, "{", numstr, &sdh) < 0) {
-			rpc->fault(ctx, 500, "Internal error adding impu subscription detail data");
-			lock_release(subscription->lock);
-			unlock_udomain(domain, &impu);
-			return;
-		}
-		if (rpc->struct_add(sdh, "{", "impus", &spi) < 0) {
-				rpc->fault(ctx, 500, "Internal error adding impu subscription data");
-				lock_release(subscription->lock);
-				unlock_udomain(domain, &impu);
-				return;
-		}
+    lock_release(subscription->lock);
 
-		for (j=0; j<subscription->service_profiles[i].public_identities_cnt; j++) {
-			sprintf(numstr, "%d", j+1);
-			if (rpc->struct_add(spi, "S", numstr, &subscription->service_profiles[i].public_identities[j].public_identity) < 0) {
-					rpc->fault(ctx, 500, "Internal error adding impu subscription detail data");
-					lock_release(subscription->lock);
-					unlock_udomain(domain, &impu);
-					return;
-			}
+    //add contact data
+    if (rpc->struct_add(ah, "{", "contacts", &ch) < 0) {
+	rpc->fault(ctx, 500, "Internal error adding impu contact data");
+	unlock_udomain(domain, &impu);
+	return;
+    }
+
+    if (impu_rec->num_contacts > 0 && impu_rec->newcontacts[0]) {
+	while (i < MAX_CONTACTS_PER_IMPU && (contact = impu_rec->newcontacts[i++])) {
+	    //contact is not null terminated so we need to create a null terminated version
+	    if (!contact_buf.s || (contact_buf.len <= contact->c.len)) {
+		if (contact_buf.s && contact_buf.len <= contact->c.len) {
+		    pkg_free(contact_buf.s);
 		}
-	}
-
-	lock_release(subscription->lock);
-
-	//add contact data
-	if (rpc->struct_add(ah, "{", "contacts", &ch) < 0) {
+		contact_buflen = contact->c.len + 1;
+		contact_buf.s = (char*) pkg_malloc(contact_buflen);
+		if (!contact_buf.s) {
+		    LM_ERR("no more pkg memory");
+		    rpc->fault(ctx, 500, "Internal error adding impu contact header");
+		    unlock_udomain(domain, &impu);
+		    return;
+		}
+	    }
+	    memcpy(contact_buf.s, contact->c.s, contact->c.len);
+	    contact_buf.s[contact->c.len] = '\0';
+	    contact_buf.len = contact->c.len;
+
+	    LM_DBG("contact is %s\n", contact_buf.s);
+	    if (rpc->struct_add(ch, "{", contact_buf.s, &cdh) < 0) {
+		rpc->fault(ctx, 500, "Internal error adding impu contact header");
+		unlock_udomain(domain, &impu);
+		return;
+	    }
+	    if (rpc->struct_add(cdh, "dS",
+		    "expires", contact->expires - time(NULL),
+		    "client", &contact->user_agent) < 0) {
 		rpc->fault(ctx, 500, "Internal error adding impu contact data");
 		unlock_udomain(domain, &impu);
 		return;
+	    }
+	    contact = contact->next;
 	}
-	contact = impu_rec->contacts;
-	while (contact) {
-		//contact is not null terminated so we need to create a null terminated version
-		if (!contact_buf.s || (contact_buf.len <= contact->c.len)) {
-			if (contact_buf.s && contact_buf.len <= contact->c.len){
-				pkg_free(contact_buf.s);
-			}
-			contact_buflen = contact->c.len + 1;
-			contact_buf.s = (char*)pkg_malloc(contact_buflen);
-			if (!contact_buf.s) {
-				LM_ERR("no more pkg memory");
-				rpc->fault(ctx, 500, "Internal error adding impu contact header");
-				unlock_udomain(domain, &impu);
-				return;
-			}
-		}
-		memcpy(contact_buf.s, contact->c.s, contact->c.len);
-		contact_buf.s[contact->c.len] = '\0';
-		contact_buf.len = contact->c.len;
-
-		LM_DBG("contact is %s\n", contact_buf.s);
-		if (rpc->struct_add(ch, "{", contact_buf.s, &cdh) < 0) {
-			rpc->fault(ctx, 500, "Internal error adding impu contact header");
-			unlock_udomain(domain, &impu);
-			return;
-		}
-		if (rpc->struct_add(cdh, "dS",
-				"expires", contact->expires - time(NULL),
-				"client", &contact->user_agent) < 0) {
-			rpc->fault(ctx, 500, "Internal error adding impu contact data");
-			unlock_udomain(domain, &impu);
-			return;
-		}
-		contact = contact->next;
-	}
+    }
 
-	unlock_udomain(domain, &impu);
+    unlock_udomain(domain, &impu);
 
 }
 

+ 8 - 2
modules/ims_usrloc_scscf/usrloc.c

@@ -84,14 +84,20 @@ int bind_usrloc(usrloc_api_t* api) {
 	api->lock_udomain = lock_udomain;
 	api->unlock_udomain = unlock_udomain;
 
+	api->lock_contact_slot = lock_contact_slot;
+	api->unlock_contact_slot = unlock_contact_slot;
+	api->lock_contact_slot_i = lock_contact_slot_i;
+	api->unlock_contact_slot_i = unlock_contact_slot_i;	
 	api->get_all_ucontacts = get_all_ucontacts;
 	api->insert_ucontact = insert_ucontact;
 	api->delete_ucontact = delete_ucontact;
 	api->get_ucontact = get_ucontact;
+	api->release_ucontact = release_ucontact;
 	api->update_ucontact = update_ucontact;
 	api->add_dialog_data_to_contact = add_dialog_data_to_contact;
 	api->remove_dialog_data_from_contact = remove_dialog_data_from_contact;
-
+	api->unlink_contact_from_impu = unlink_contact_from_impu;
+	api->link_contact_to_impu = link_contact_to_impu;
 	api->get_subscriber = get_subscriber;
 	api->add_subscriber = add_subscriber;
 	api->external_delete_subscriber = external_delete_subscriber;
@@ -101,7 +107,7 @@ int bind_usrloc(usrloc_api_t* api) {
 	
 	api->get_presentity_from_subscriber_dialog = get_presentity_from_subscriber_dialog;
         
-    api->register_ulcb = register_ulcb;
+	api->register_ulcb = register_ulcb;
 
 	//api->update_user_profile = update_user_profile;
 	api->nat_flag = nat_bflag;

+ 44 - 5
modules/ims_usrloc_scscf/usrloc.h

@@ -54,6 +54,7 @@
 #include "../cdp/diameter_ims_code_avp.h"
 
 #define DEFAULT_DBG_FILE "/var/log/usrloc_debug"
+#define MAX_CONTACTS_PER_IMPU 100
 
 /* DB modes */
 #define NO_DB         0
@@ -140,6 +141,12 @@ typedef enum cstate {
     CS_DIRTY /*!< Update contact - not flushed yet */
 } cstate_t;
 
+typedef enum contact_state {
+    CONTACT_VALID,
+    CONTACT_EXPIRED,
+    CONTACT_DELETED
+} contact_state_t;
+
 /*! \brief Valid contact is a contact that either didn't expire yet or is permanent */
 #define VALID_CONTACT(c, t)   ((c->expires>t) || (c->expires==0))
 
@@ -286,8 +293,13 @@ typedef struct contact_dialog_data {
 
 /*! \brief Main structure for handling of registered Contact data */
 typedef struct ucontact {
-    str* domain; /*!< Pointer to domain name (NULL terminated) */
-    str* aor; /*!< Pointer to the AOR string in record structure*/
+    gen_lock_t *lock;           /**< we have to lock the contact as it is shared by many impu structs and has reference conting	*/
+    struct contact_hslot* slot; /*!< Collision slot in the hash table array we belong to */
+    unsigned int contact_hash; 			/*!< Hash over contact */
+    int ref_count;
+    contact_state_t state;
+    str domain; /*!< Pointer to domain name (NULL terminated) */
+    str aor; /*!< Pointer to the AOR string in record structure*/
     str c; /*!< Contact address */
     str received; /*!< IP+port+protocol we received the REGISTER from */
     str path; /*!< Path header */
@@ -295,7 +307,7 @@ typedef struct ucontact {
     qvalue_t q; /*!< q parameter */
     str callid; /*!< Call-ID header field of registration */
     int cseq; /*!< CSeq value */
-    cstate_t state; /*!< State of the contact (\ref cstate) */
+//    cstate_t state; /*!< State of the contact (\ref cstate) */
     unsigned int flags; /*!< Various flags (NAT, ping type, etc) */
     unsigned int cflags; /*!< Custom contact flags (from script) */
     str user_agent; /*!< User-Agent header field */
@@ -370,7 +382,8 @@ typedef struct impurecord {
     enum pi_reg_states reg_state;
     ims_subscription *s; 			/**< subscription to which it belongs 		*/
     str ccf1, ccf2, ecf1, ecf2; 	/**< charging functions						*/
-    ucontact_t* contacts; 			/*!< One or more contact fields */
+    ucontact_t* newcontacts[MAX_CONTACTS_PER_IMPU];
+    int num_contacts;
     reg_subscriber *shead, *stail; 	/**< list of subscribers attached			*/
     time_t expires; 				/*!< timer when this IMPU expires - currently only used for unreg IMPU */
     int send_sar_on_delete;			/* used to distinguish between explicit contact removal and contact expiry - SAR only sent on contact expiry*/
@@ -389,6 +402,11 @@ typedef struct impurecord_info {
     str *ccf1, *ccf2, *ecf1, *ecf2;
 } impurecord_info_t;
 
+typedef struct contact_list {
+    struct contact_hslot* slot;
+    int size;
+//    stat_var *contacts;        /*!< no of contacts in table */
+}contact_list_t;
 
 typedef int (*insert_impurecord_t)(struct udomain* _d, str* public_identity, int reg_state, int barring,
         ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2,
@@ -400,14 +418,28 @@ typedef int (*delete_impurecord_t)(struct udomain* _d, str* _aor, struct impurec
 
 typedef int (*update_impurecord_t)(struct udomain* _d, str* public_identity, int reg_state, int send_sar_on_delete, int barring, int is_primary, ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2, struct impurecord** _r);
 
+typedef void (*lock_contact_slot_t)(str* contact_uri);
+
+typedef void (*unlock_contact_slot_t)(str* contact_uri);
+
+typedef void (*lock_contact_slot_i_t)(int sl);
+
+typedef void (*unlock_contact_slot_i_t)(int sl);
+
 typedef int (*update_ucontact_t)(struct impurecord* _r, struct ucontact* _c, struct ucontact_info* _ci);
 
+typedef int (*unlink_contact_from_impu_t)(struct impurecord* _r, struct ucontact* _c, int write_to_db);
+
+typedef int (*link_contact_to_impu_t)(struct impurecord* _r, struct ucontact* _c, int wirte_to_db);
+
 typedef int (*insert_ucontact_t)(struct impurecord* _r, str* _contact, struct ucontact_info* _ci, struct ucontact** _c);
 
-typedef int (*delete_ucontact_t)(struct impurecord* _r, struct ucontact* _c);
+typedef int (*delete_ucontact_t)(struct ucontact* _c);
 
 typedef int (*get_ucontact_t)(struct impurecord* _r, str* _c, str* _callid, str* _path, int _cseq, struct ucontact** _co);
 
+typedef void (*release_ucontact_t)(struct ucontact* _c);
+
 typedef int (*add_dialog_data_to_contact_t)(struct ucontact* _c, unsigned int h_entry, unsigned int h_id);
 
 typedef int (*remove_dialog_data_from_contact_t)(struct ucontact* _c, unsigned int h_entry, unsigned int h_id);
@@ -452,11 +484,18 @@ typedef struct usrloc_api {
     get_impurecord_t get_impurecord;
     update_impurecord_t update_impurecord;
 
+    lock_contact_slot_t lock_contact_slot;
+    unlock_contact_slot_t unlock_contact_slot;
+    lock_contact_slot_i_t lock_contact_slot_i;
+    unlock_contact_slot_i_t unlock_contact_slot_i;
     insert_ucontact_t insert_ucontact;
     delete_ucontact_t delete_ucontact;
     get_ucontact_t get_ucontact;
+    release_ucontact_t release_ucontact;
     get_all_ucontacts_t get_all_ucontacts;
     update_ucontact_t update_ucontact;
+    unlink_contact_from_impu_t unlink_contact_from_impu;
+    link_contact_to_impu_t link_contact_to_impu;
     //update_user_profile_t update_user_profile;
     
     add_dialog_data_to_contact_t add_dialog_data_to_contact;

+ 400 - 484
modules/ims_usrloc_scscf/usrloc_db.c

@@ -62,6 +62,10 @@ str subscriber_id_col = str_init(SUBSCRIBER_ID_COL);
 str query_buffer 		= { 0, 0 };
 int query_buffer_len		= 0;
 
+char* impu_contact_insert_query = "INSERT INTO impu_contact (impu_id, contact_id) (SELECT I.id, C.id FROM impu I, contact C WHERE I.impu='%.*s' and C.contact='%.*s')";
+int impu_contact_insert_query_len;
+char* impu_contact_delete_query = "DELETE FROM impu_contact WHERE impu_id in (select impu.id from impu where impu.impu='%.*s') AND contact_id in (select contact.id from contact where contact.contact='%.*s')";
+int impu_contact_delete_query_len;
 
 
 extern db1_con_t* ul_dbh;
@@ -134,19 +138,23 @@ int db_insert_impurecord(struct udomain* _d, str* public_identity,
 	db_key_t key[8];
 	db_val_t val[8];
 	str bin_str;
+	
+	LM_DBG("DB: Inserting/Updating IMPU [%.*s]\n", public_identity->len, public_identity->s);
 
 	//serialise ims_subscription
-	if (!bin_alloc(&x, 256)) {
-		LM_DBG("unable to allocate buffer for binary serialisation\n");
-		return -1;
-	}
-	if (!bin_encode_ims_subscription(&x, (*s))) {
-		LM_DBG("Unable to serialise ims_subscription data\n");
-		bin_free(&x);
-		return -1;
+	if (s) {
+	    if (!bin_alloc(&x, 256)) {
+		    LM_DBG("unable to allocate buffer for binary serialisation\n");
+		    return -1;
+	    }
+	    if (!bin_encode_ims_subscription(&x, (*s))) {
+		    LM_DBG("Unable to serialise ims_subscription data\n");
+		    bin_free(&x);
+		    return -1;
+	    }
+	    bin_str.s = x.s;
+	    bin_str.len = x.len;
 	}
-	bin_str.s = x.s;
-	bin_str.len = x.len;
 
 	key[0] = &impu_col;
 	key[1] = &barring_col;
@@ -194,8 +202,13 @@ int db_insert_impurecord(struct udomain* _d, str* public_identity,
 	}
 	key[i] = &ims_sub_data_col;
 	val[i].type = DB1_BLOB;
-	val[i].nul = 0;
-	val[i].val.blob_val = bin_str;
+	if (s) {
+	    val[i].nul = 0;
+	    val[i].val.blob_val = bin_str;
+	} else {
+	    val[i].nul = 1;
+	}
+	
 	i++;
 
 	if (ul_dbf.use_table(ul_dbh, &impu_table) != 0) {
@@ -208,7 +221,9 @@ int db_insert_impurecord(struct udomain* _d, str* public_identity,
 		bin_free(&x);
 		return -1;
 	}
-	bin_free(&x);
+	
+	if (s)
+	    bin_free(&x);
 
 	return 0;
 }
@@ -216,6 +231,8 @@ int db_insert_impurecord(struct udomain* _d, str* public_identity,
 int db_delete_impurecord(udomain_t* _d, struct impurecord* _r) {
 	db_key_t key[1];
 	db_val_t val[1];
+	
+	LM_DBG("DB: deleting IMPU [%.*s]\n", _r->public_identity.len, _r->public_identity.s);
 
 	key[0] = &impu_col;
 	val[0].type = DB1_STR;
@@ -229,15 +246,10 @@ int db_delete_impurecord(udomain_t* _d, struct impurecord* _r) {
 }
 
 int db_insert_ucontact(impurecord_t* _r, ucontact_t* _c) {
-	db1_res_t* _rs;
-	int contact_id;
-	int impu_id;
 	db_key_t key[6];
 	db_val_t val[6];
-	db_key_t key_return[1];
-	db_val_t* ret_val;
-
-	key_return[0] = &id_col;
+	
+	LM_DBG("DB: inserting ucontact [%.*s]\n", _c->c.len, _c->c.s);
 
 	key[0] = &contact_col;
 	key[1] = &path_col;
@@ -278,128 +290,15 @@ int db_insert_ucontact(impurecord_t* _r, ucontact_t* _c) {
 		LM_ERR("Failed to insert/update contact record for [%.*s]\n", _c->c.len, _c->c.s);
 		return -1;
 	}
-	contact_id = ul_dbf.last_inserted_id(ul_dbh);
-	if (contact_id <= 0) {
-		/* search for the ID if the contact just entered */
-		if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
-			LM_ERR("Unable to find contact [%.*s] in DB to complete IMPU-contact mapping\n", _c->c.len, _c->c.s);
-			ul_dbf.free_result(ul_dbh, _rs);
-			return -1;
-		}
-
-		if (RES_ROW_N(_rs) == 0) {
-			LM_DBG("Contact %.*s not found in DB\n",_c->c.len, _c->c.s);
-			ul_dbf.free_result(ul_dbh, _rs);
-			return -1;
-		}
-
-		if (RES_ROW_N(_rs) > 1) {
-			LM_WARN("more than one contact found in DB for contact [%.*s] - this should not happen... proceeding with first entry\n",
-				_c->c.len, _c->c.s);
-		}
-
-		ret_val = ROW_VALUES(RES_ROWS(_rs));
-		contact_id = ret_val[0].val.int_val;
-		ul_dbf.free_result(ul_dbh, _rs);
-	}
-	LM_DBG("contact ID is %d\n", contact_id);
-
-	/* search for ID of the associated IMPU */
-	key[0] = &impu_col;
-	val[0].nul = 0;
-	val[0].type = DB1_STR;
-	val[0].val.str_val = _r->public_identity;
-
-	if (ul_dbf.use_table(ul_dbh, &impu_table) != 0) {
-		LM_ERR("Unable to use table [%.*s]\n", impu_table.len, impu_table.s);
-		return -1;
-	}
-	if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
-		LM_ERR("Unable to find IMPU [%.*s] in DB to complete IMPU-contact mapping\n", _r->public_identity.len, _r->public_identity.s);
-		return -1;
-	}
-	if (RES_ROW_N(_rs) == 0) {
-		LM_DBG("IMPU %.*s not found in DB\n", _r->public_identity.len, _r->public_identity.s);
-		ul_dbf.free_result(ul_dbh, _rs);
-		return -1;
-	}
-
-	if (RES_ROW_N(_rs) > 1) {
-		LM_WARN("more than one IMPU found in DB for contact [%.*s] - this should not happen... proceeding with first entry\n",
-				_r->public_identity.len, _r->public_identity.s);
-	}
-	ret_val = ROW_VALUES(RES_ROWS(_rs));
-	impu_id = ret_val[0].val.int_val;
-
-	ul_dbf.free_result(ul_dbh, _rs);
-	LM_DBG("IMPU ID is %d\n", impu_id);
-
-	/* update mapping table between contact and IMPU */
-	key[0] = &impu_id_col;
-	key[1] = &contact_id_col;
-	val[0].nul = 0;
-	val[0].type = DB1_INT;
-	val[0].val.int_val = impu_id;
-	val[1].nul = 0;
-	val[1].type = DB1_INT;
-	val[1].val.int_val = contact_id;
-
-	if (ul_dbf.use_table(ul_dbh, &impu_contact_table) != 0) {
-		LM_ERR("Unable to use table [%.*s]\n", impu_table.len, impu_table.s);
-		return -1;
-	}
-
-	if (ul_dbf.insert_update(ul_dbh, key, val, 2) != 0) {
-		LM_ERR("Failed to insert/update impu-contact mapping record for contact [%.*s] and impu [%.*s]\n",
-				_c->c.len, _c->c.s,
-				_r->public_identity.len, _r->public_identity.s);
-		return -1;
-	}
 
 	return 0;
 }
 
-int db_delete_ucontact(impurecord_t* _r, ucontact_t* _c) {
-	db_key_t key[2];
-	db_val_t val[2];
-	db_key_t key_return[1];
-	db_val_t* ret_val;
-	db1_res_t* _rs;
-	int impu_id, contact_id;
-
-	LM_DBG("Deleting contact binding [%.*s] on impu [%.*s]\n",
-			_c->c.len, _c->c.s,
-			_r->public_identity.len, _r->public_identity.s);
-
-	/* get id of IMPU entry */
-	key[0] = &impu_col;
-	val[0].type = DB1_STR;
-	val[0].nul = 0;
-	val[0].val.str_val = _r->public_identity;
-	key_return[0] = &id_col;
-
-	if (ul_dbf.use_table(ul_dbh, &impu_table) != 0) {
-		LM_ERR("Unable to use table [%.*s]\n", impu_table.len, impu_table.s);
-		return -1;
-	}
-	if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
-		LM_ERR("Unable to find IMPU [%.*s] in DB to complete IMPU-contact mapping\n", _r->public_identity.len, _r->public_identity.s);
-		return -1;
-	}
-	if (RES_ROW_N(_rs) == 0) {
-		LM_DBG("IMPU %.*s not found in DB\n", _r->public_identity.len, _r->public_identity.s);
-		ul_dbf.free_result(ul_dbh, _rs);
-		return -1;
-	}
-	if (RES_ROW_N(_rs) > 1) {
-		LM_WARN("more than one IMPU found in DB for contact [%.*s] - this should not happen... proceeding with first entry\n",
-				_r->public_identity.len, _r->public_identity.s);
-	}
-	ret_val = ROW_VALUES(RES_ROWS(_rs));
-	impu_id = ret_val[0].val.int_val;
+int db_delete_ucontact(ucontact_t* _c) {
+	db_key_t key[1];
+	db_val_t val[1];
 
-	ul_dbf.free_result(ul_dbh, _rs);
-	LM_DBG("IMPU ID is %d\n", impu_id);
+	LM_DBG("Deleting ucontact [%.*s]\n",_c->c.len, _c->c.s);
 
 	/* get contact id from DB */
 	if (ul_dbf.use_table(ul_dbh, &contact_table) != 0) {
@@ -410,69 +309,9 @@ int db_delete_ucontact(impurecord_t* _r, ucontact_t* _c) {
 	val[0].type = DB1_STR;
 	val[0].nul = 0;
 	val[0].val.str_val = _c->c;
-	if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
-		LM_ERR("Unable to find contact [%.*s] in DB to complete IMPU-contact mapping removal\n", _c->c.len, _c->c.s);
-		return -1;
-	}
-	if (RES_ROW_N(_rs) == 0) {
-		LM_DBG("Contact %.*s not found in DB\n",_c->c.len, _c->c.s);
-		ul_dbf.free_result(ul_dbh, _rs);
-		return -1;
-	}
-	if (RES_ROW_N(_rs) > 1) {
-		LM_WARN("more than one contact found in DB for contact [%.*s] - this should not happen... proceeding with first entry\n",
-				_c->c.len, _c->c.s);
-	}
-	ret_val = ROW_VALUES(RES_ROWS(_rs));
-	contact_id = ret_val[0].val.int_val;
-	ul_dbf.free_result(ul_dbh, _rs);
-	LM_DBG("contact ID is %d\n", contact_id);
-
-	LM_DBG("need to remove contact-impu mapping %d:%d\n", impu_id, contact_id);
-
-	/* update impu-contact mapping table */
-	if (ul_dbf.use_table(ul_dbh, &impu_contact_table) != 0) {
-		LM_ERR("Unable to use table [%.*s]\n", impu_contact_table.len, impu_contact_table.s);
-		return -1;
-	}
-	key[0] = &contact_id_col;
-	key[1] = &impu_id_col;
-	val[0].type = DB1_INT;
-	val[0].nul = 0;
-	val[0].val.int_val = contact_id;
-	val[1].type = DB1_INT;
-	val[1].nul = 0;
-	val[1].val.int_val = impu_id;
-
-	if (ul_dbf.delete(ul_dbh, key, 0, val, 2) != 0) {
-		LM_ERR("unable to remove impu-contact mapping from DB for contact [%.*s], impu [%.*s]  ..... continuing\n",
-				_c->c.len, _c->c.s,
-				_r->public_identity.len, _r->public_identity.s);
-	}
-
-	/* delete contact from contact table - IFF there are no more mappings for it to impus */
-	if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
-		LM_WARN("error searching for impu-contact mappings in DB\n");
-	}
-	if (RES_ROW_N(_rs) > 0) {
-		ul_dbf.free_result(ul_dbh, _rs);
-		LM_DBG("impu-contact mappings still exist, not removing contact from DB\n");
-		return 0;
-	}
-	ul_dbf.free_result(ul_dbh, _rs);
-
-	key[0] = &contact_col;
-	val[0].type = DB1_STR;
-	val[0].nul = 0;
-	val[0].val.str_val = _c->c;
-
-	if (ul_dbf.use_table(ul_dbh, &contact_table) != 0) {
-		LM_ERR("Unable to use table [%.*s]\n", contact_table.len, contact_table.s);
-		return -1;
-	}
-
 	if (ul_dbf.delete(ul_dbh, key, 0, val, 1) != 0) {
-		LM_ERR("unable to remove contact from DB [%.*s]\n", _c->c.len, _c->c.s);
+		LM_ERR("Unable to delete contact [%.*s] from DB\n", _c->c.len, _c->c.s);
+		return -1;
 	}
 
 	return 0;
@@ -937,306 +776,383 @@ static inline int dbrow2subscriber(db_val_t* val, subscriber_data_t* subscriber_
 }
 
 int preload_udomain(db1_con_t* _c, udomain_t* _d) {
-	db_key_t col[9];
-	db_row_t* row;
-	db_row_t* contact_row;
-	db_row_t* subscriber_row;
-	db1_res_t* rs;
-	db1_res_t* contact_rs;
-	db1_res_t* subscriber_rs;
-	db_val_t* vals;
-	db_val_t* contact_vals;
-	db_val_t* subscriber_vals;
-	int barring = 0, reg_state = 0, impu_id, n, nn, i, j, len;
-	str query_contact, query_subscriber, impu, ccf1 = { 0, 0 }, ecf1 = { 0, 0 }, ccf2 = { 0, 0 }, ecf2 = {
-			0, 0 }, blob = { 0, 0 }, contact={0,0}, presentity_uri={0,0};
-	bin_data x;
-	ims_subscription* subscription = 0;
-	impurecord_t* impurecord;
-	int impu_id_len;
-	ucontact_t* c;
-	ucontact_info_t contact_data;
-	subscriber_data_t subscriber_data;
-	reg_subscriber *reg_subscriber;
-
-	/*
-	 * the two queries - get the IMPUs, then get associated contacts for each IMPU:
-	 * SELECT impu.impu,impu.barring,impu.reg_state,impu.ccf1,impu.ccf2,impu.ecf1,impu.ecf2,impu.ims_subscription_data FROM impu;
-	 * SELECT c.contact,c.path,c.user_agent,c.received,c.expires FROM impu_contact m LEFT JOIN contact c ON c.id=m.contact_id WHERE m.impu_id=20;
-	 */
-
-	char *p_contact =
-			"SELECT c.contact,c.path,c.user_agent,c.received,c.expires,c.callid FROM impu_contact m LEFT JOIN contact c ON c.id=m.contact_id WHERE m.impu_id=";
-	
-	char *p_subscriber =
-			"SELECT s.presentity_uri,s.watcher_uri,s.watcher_contact,s.event,s.expires,s.version,s.local_cseq,s.call_id,s.from_tag,"
-	"s.to_tag,s.record_route,s.sockinfo_str FROM impu_subscriber m LEFT JOIN subscriber s ON s.id=m.subscriber_id WHERE m.impu_id=";
+    db_key_t col[9];
+    db_row_t* row;
+    db_row_t* contact_row;
+    db_row_t* subscriber_row;
+    db1_res_t* rs;
+    db1_res_t* contact_rs;
+    db1_res_t* subscriber_rs;
+    db_val_t* vals;
+    db_val_t* contact_vals;
+    db_val_t* subscriber_vals;
+    int barring = 0, reg_state = 0, impu_id, n, nn, i, j, len;
+    str query_contact, query_subscriber, impu, ccf1 = {0, 0}, ecf1 = {0, 0}, ccf2 = {0, 0}, ecf2 = {
+	0, 0
+    }, blob = {0, 0}, contact = {0, 0}, presentity_uri = {0, 0};
+    bin_data x;
+    ims_subscription* subscription = 0;
+    impurecord_t* impurecord;
+    int impu_id_len;
+    ucontact_t* c;
+    ucontact_info_t contact_data;
+    subscriber_data_t subscriber_data;
+    reg_subscriber *reg_subscriber;
+
+    /*
+     * the two queries - get the IMPUs, then get associated contacts for each IMPU:
+     * SELECT impu.impu,impu.barring,impu.reg_state,impu.ccf1,impu.ccf2,impu.ecf1,impu.ecf2,impu.ims_subscription_data FROM impu;
+     * SELECT c.contact,c.path,c.user_agent,c.received,c.expires FROM impu_contact m LEFT JOIN contact c ON c.id=m.contact_id WHERE m.impu_id=20;
+     */
+
+    char *p_contact =
+	    "SELECT c.contact,c.path,c.user_agent,c.received,c.expires,c.callid FROM impu_contact m LEFT JOIN contact c ON c.id=m.contact_id WHERE m.impu_id=";
+
+    char *p_subscriber =
+	    "SELECT s.presentity_uri,s.watcher_uri,s.watcher_contact,s.event,s.expires,s.version,s.local_cseq,s.call_id,s.from_tag,"
+	    "s.to_tag,s.record_route,s.sockinfo_str FROM impu_subscriber m LEFT JOIN subscriber s ON s.id=m.subscriber_id WHERE m.impu_id=";
+
+    query_contact.s = p_contact;
+    query_contact.len = strlen(query_contact.s);
+
+    query_subscriber.s = p_subscriber;
+    query_subscriber.len = strlen(query_subscriber.s);
+
+
+    col[0] = &impu_col;
+    col[1] = &barring_col;
+    col[2] = &reg_state_col;
+    col[3] = &ccf1_col;
+    col[4] = &ecf1_col;
+    col[5] = &ccf2_col;
+    col[6] = &ecf2_col;
+    col[7] = &ims_sub_data_col;
+    col[8] = &id_col;
+
+    if (ul_dbf.use_table(_c, &impu_table) != 0) {
+	LM_ERR("SQL use table failed\n");
+	return -1;
+    }
+    if (ul_dbf.query(_c, NULL, 0, NULL, col, 0, 9, NULL, &rs) != 0) {
+	LM_ERR("Unable to query DB to preload S-CSCF usrloc\n");
+	return -1;
+    }
+
+    if (RES_ROW_N(rs) == 0) {
+	LM_DBG("table is empty\n");
+	ul_dbf.free_result(_c, rs);
+	return 0;
+    }
+
+    LM_DBG("preloading S-CSCF usrloc...\n");
+    LM_DBG("%d rows returned in preload\n", RES_ROW_N(rs));
+
+    n = 0;
+    do {
+	n++;
+	LM_DBG("loading S-CSCF usrloc records - cycle [%d]\n", n);
+	for (i = 0; i < RES_ROW_N(rs); i++) {
+	    impu_id = -1;
+
+	    row = RES_ROWS(rs) + i;
+	    LM_DBG("Fetching IMPU row %d\n", i + 1);
+	    vals = ROW_VALUES(row);
+
+	    impu.s = (char*) VAL_STRING(vals);
+	    if (VAL_NULL(vals) || !impu.s || !impu.s[0]) {
+		impu.len = 0;
+		impu.s = 0;
+	    } else {
+		impu.len = strlen(impu.s);
+	    }
+	    LM_DBG("IMPU from DB is [%.*s]\n", impu.len, impu.s);
+	    if (!VAL_NULL(vals + 1)) {
+		barring = VAL_INT(vals + 1);
+	    }
+	    if (!VAL_NULL(vals + 2)) {
+		reg_state = VAL_INT(vals + 2);
+	    }
+	    if (!VAL_NULL(vals + 3)) {
+		ccf1.s = (char*) VAL_STRING(vals + 3);
+		ccf1.len = strlen(ccf1.s);
+	    }
+	    LM_DBG("CCF1 from DB is [%.*s]\n", ccf1.len, ccf1.s);
+	    if (!VAL_NULL(vals + 4)) {
+		ecf1.s = (char*) VAL_STRING(vals + 3);
+		ecf1.len = strlen(ecf1.s);
+	    }
+	    LM_DBG("ECF1 from DB is [%.*s]\n", ecf1.len, ecf1.s);
+	    if (!VAL_NULL(vals + 5)) {
+		ccf2.s = (char*) VAL_STRING(vals + 5);
+		ccf2.len = strlen(ccf2.s);
+	    }
+	    LM_DBG("CCF2 from DB is [%.*s]\n", ccf2.len, ccf2.s);
+	    if (!VAL_NULL(vals + 6)) {
+		ecf2.s = (char*) VAL_STRING(vals + 6);
+		ecf2.len = strlen(ecf2.s);
+	    }
+	    LM_DBG("ECF2 from DB is [%.*s]\n", ecf2.len, ecf2.s);
+
+	    if (!VAL_NULL(vals + 7)) {
+		blob = VAL_BLOB(vals + 7);
+		bin_alloc(&x, blob.len);
+		memcpy(x.s, blob.s, blob.len);
+		x.len = blob.len;
+		x.max = 0;
+		subscription = bin_decode_ims_subscription(&x);
+		bin_free(&x);
+	    }
+	    if (!VAL_NULL(vals + 8)) {
+		impu_id = VAL_INT(vals + 8);
+	    }
+
+	    /* insert impu into memory */
+	    lock_udomain(_d, &impu);
+	    if (get_impurecord(_d, &impu, &impurecord) != 0) {
+		if (mem_insert_impurecord(_d, &impu, reg_state, barring,
+			&subscription, &ccf1, &ccf2, &ecf1, &ecf2, &impurecord)
+			!= 0) {
+		    LM_ERR("Unable to insert IMPU into memory [%.*s]\n", impu.len, impu.s);
+		}
+	    }
+
+	    /* add contacts */
+	    if (impu_id < 0) {
+		LM_ERR("impu_id has not been set [%.*s] - we cannot read contacts or subscribers from DB....aborting preload\n", impu.len, impu.s);
+		//TODO: check frees
+		unlock_udomain(_d, &impu);
+		continue;
+	    }
+	    impu_id_len = int_to_str_len(impu_id);
+	    len = query_contact.len + impu_id_len + 1/*nul*/;
+	    if (!query_buffer_len || query_buffer_len < len) {
+		if (query_buffer.s) {
+		    pkg_free(query_buffer.s);
+		}
+		query_buffer.s = (char*) pkg_malloc(len);
+		if (!query_buffer.s) {
+		    LM_ERR("mo more pkg mem\n");
+		    //TODO: check free
+		    unlock_udomain(_d, &impu);
+		    return -1;
+		}
+		query_buffer_len = len;
+	    }
+	    memcpy(query_buffer.s, query_contact.s, query_contact.len);
+	    p_contact = query_buffer.s + query_contact.len;
+	    snprintf(p_contact, impu_id_len + 1, "%d", impu_id);
+	    query_buffer.len = query_contact.len + impu_id_len;
+	    if (ul_dbf.raw_query(_c, &query_buffer, &contact_rs) != 0) {
+		LM_ERR("Unable to query DB for contacts associated with impu [%.*s]\n",
+			impu.len, impu.s);
+		ul_dbf.free_result(_c, contact_rs);
+	    } else {
+		if (RES_ROW_N(contact_rs) == 0) {
+		    LM_DBG("no contacts associated with impu [%.*s]\n", impu.len, impu.s);
+		    ul_dbf.free_result(_c, contact_rs);
+		} else {
+		    nn = 0;
+		    do {
+			nn++;
+			LM_DBG("loading S-CSCF contact - cycle [%d]\n", nn);
+			for (j = 0; j < RES_ROW_N(contact_rs); j++) {
+			    contact_row = RES_ROWS(contact_rs) + j;
+			    contact_vals = ROW_VALUES(contact_row);
+
+			    if (!VAL_NULL(contact_vals)) {
+				contact.s = (char*) VAL_STRING(contact_vals);
+				contact.len = strlen(contact.s);
+			    }
+			    if (dbrow2contact(contact_vals, &contact_data) != 0) {
+				LM_ERR("unable to convert contact row from DB into valid data... moving on\n");
+				continue;
+			    }
 
-	query_contact.s = p_contact;
-	query_contact.len = strlen(query_contact.s);
-	
-	query_subscriber.s = p_subscriber;
-	query_subscriber.len = strlen(query_subscriber.s);
-	
+			    if (get_ucontact(impurecord, &contact, contact_data.callid, contact_data.path, contact_data.cseq, &c) != 0) {
+				LM_DBG("Contact doesn't exist yet, creating new one [%.*s]\n", contact.len, contact.s);
+				if ((c = mem_insert_ucontact(impurecord, &contact, &contact_data)) == 0) {
+				    LM_ERR("Unable to insert contact [%.*s] for IMPU [%.*s] into memory... continuing...\n",
+					    contact.len, contact.s,
+					    impu.len, impu.s);
+				    continue;
+				}
+			    }
+			    link_contact_to_impu(impurecord, c, 0);
+			    release_ucontact(c);
+			}
+			if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
+			    if (ul_dbf.fetch_result(_c, &contact_rs, ul_fetch_rows) < 0) {
+				LM_ERR("fetching rows failed\n");
+				ul_dbf.free_result(_c, contact_rs);
+				unlock_udomain(_d, &impu);
+				return -1;
+			    }
+			} else {
+			    break;
+			}
+		    } while (RES_ROW_N(contact_rs) > 0);
+		    ul_dbf.free_result(_c, contact_rs);
+		}
+	    }
+
+	    /* add subscriber */
+	    impu_id_len = int_to_str_len(impu_id);
+	    len = query_subscriber.len + impu_id_len + 1/*nul*/;
+	    if (!query_buffer_len || query_buffer_len < len) {
+		if (query_buffer.s) {
+		    pkg_free(query_buffer.s);
+		}
+		query_buffer.s = (char*) pkg_malloc(len);
+		if (!query_buffer.s) {
+		    LM_ERR("mo more pkg mem\n");
+		    //TODO: check free
+		    unlock_udomain(_d, &impu);
+		    return -1;
+		}
+		query_buffer_len = len;
+	    }
+	    memcpy(query_buffer.s, query_subscriber.s, query_subscriber.len);
+	    p_subscriber = query_buffer.s + query_subscriber.len;
+	    snprintf(p_subscriber, impu_id_len + 1, "%d", impu_id);
+	    query_buffer.len = query_subscriber.len + impu_id_len;
+	    if (ul_dbf.raw_query(_c, &query_buffer, &subscriber_rs) != 0) {
+		LM_ERR("Unable to query DB for subscriber associated with impu [%.*s]\n",
+			impu.len, impu.s);
+		ul_dbf.free_result(_c, subscriber_rs);
+		unlock_udomain(_d, &impu);
+		continue;
+	    }
+	    if (RES_ROW_N(subscriber_rs) == 0) {
+		LM_DBG("no subscriber associated with impu [%.*s]\n", impu.len, impu.s);
+		ul_dbf.free_result(_c, subscriber_rs);
+		unlock_udomain(_d, &impu);
+		continue;
+	    }
+
+	    nn = 0;
+	    do {
+		nn++;
+		LM_DBG("loading S-CSCF subscriber - cycle [%d]\n", nn);
+		for (j = 0; j < RES_ROW_N(subscriber_rs); j++) {
+		    subscriber_row = RES_ROWS(subscriber_rs) + j;
+		    subscriber_vals = ROW_VALUES(subscriber_row);
+
+		    /*presentity uri*/
+		    if (!VAL_NULL(subscriber_vals)) {
+			presentity_uri.s = (char*) VAL_STRING(subscriber_vals);
+			presentity_uri.len = strlen(presentity_uri.s);
+		    }
+
+		    if (dbrow2subscriber(subscriber_vals, &subscriber_data) != 0) {
+			LM_ERR("unable to convert subscriber row from DB into valid subscriberdata... moving on\n");
+			continue;
+		    }
+
+		    if (add_subscriber(impurecord, &subscriber_data, &reg_subscriber, 1 /*db_load*/) != 0) {
+			LM_ERR("Unable to insert subscriber with presentity_uri [%.*s] for IMPU [%.*s] into memory... continuing...\n",
+				presentity_uri.len, presentity_uri.s,
+				impu.len, impu.s);
+		    }
+		}
+		if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
+		    if (ul_dbf.fetch_result(_c, &subscriber_rs, ul_fetch_rows) < 0) {
+			LM_ERR("fetching rows failed\n");
+			ul_dbf.free_result(_c, subscriber_rs);
+			unlock_udomain(_d, &impu);
+			return -1;
+		    }
+		} else {
+		    break;
+		}
+	    } while (RES_ROW_N(subscriber_rs) > 0);
+	    ul_dbf.free_result(_c, subscriber_rs);
+
+	    unlock_udomain(_d, &impu);
 
-	col[0] = &impu_col;
-	col[1] = &barring_col;
-	col[2] = &reg_state_col;
-	col[3] = &ccf1_col;
-	col[4] = &ecf1_col;
-	col[5] = &ccf2_col;
-	col[6] = &ecf2_col;
-	col[7] = &ims_sub_data_col;
-	col[8] = &id_col;
-
-	if (ul_dbf.use_table(_c, &impu_table) != 0) {
-		LM_ERR("SQL use table failed\n");
-		return -1;
-	}
-	if (ul_dbf.query(_c, NULL, 0, NULL, col, 0, 9, NULL, &rs) != 0) {
-		LM_ERR("Unable to query DB to preload S-CSCF usrloc\n");
-		return -1;
 	}
 
-	if (RES_ROW_N(rs) == 0) {
-		LM_DBG("table is empty\n");
+	if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
+	    if (ul_dbf.fetch_result(_c, &rs, ul_fetch_rows) < 0) {
+		LM_ERR("fetching rows (1) failed\n");
 		ul_dbf.free_result(_c, rs);
-		return 0;
+		return -1;
+	    }
+	} else {
+	    break;
 	}
+    } while (RES_ROW_N(rs) > 0);
 
-	LM_DBG("preloading S-CSCF usrloc...\n");
-	LM_DBG("%d rows returned in preload\n", RES_ROW_N(rs));
+    ul_dbf.free_result(_c, rs);
 
-	n = 0;
-	do {
-		n++;		
-		LM_DBG("loading S-CSCF usrloc records - cycle [%d]\n", n);
-		for (i = 0; i < RES_ROW_N(rs); i++) {
-			impu_id = -1;
+    LM_DBG("Completed preload_udomain");
 
-			row = RES_ROWS(rs) + i;
-			LM_DBG("Fetching IMPU row %d\n", i+1);
-			vals = ROW_VALUES(row);
+    return 0;
+}
 
-			impu.s = (char*) VAL_STRING(vals);
-			if (VAL_NULL(vals) || !impu.s || !impu.s[0]) {
-				impu.len = 0;
-				impu.s = 0;
-			} else {
-				impu.len = strlen(impu.s);
-			}
-			LM_DBG("IMPU from DB is [%.*s]\n", impu.len, impu.s);
-			if (!VAL_NULL(vals + 1)) {
-				barring = VAL_INT(vals + 1);
-			}
-			if (!VAL_NULL(vals + 2)) {
-				reg_state = VAL_INT(vals + 2);
-			}
-			if (!VAL_NULL(vals + 3)) {
-				ccf1.s = (char*) VAL_STRING(vals + 3);
-				ccf1.len = strlen(ccf1.s);
-			}
-			LM_DBG("CCF1 from DB is [%.*s]\n", ccf1.len, ccf1.s);
-			if (!VAL_NULL(vals + 4)) {
-				ecf1.s = (char*) VAL_STRING(vals + 3);
-				ecf1.len = strlen(ecf1.s);
-			}
-			LM_DBG("ECF1 from DB is [%.*s]\n", ecf1.len, ecf1.s);
-			if (!VAL_NULL(vals + 5)) {
-				ccf2.s = (char*) VAL_STRING(vals + 5);
-				ccf2.len = strlen(ccf2.s);
-			}
-			LM_DBG("CCF2 from DB is [%.*s]\n", ccf2.len, ccf2.s);
-			if (!VAL_NULL(vals + 6)) {
-				ecf2.s = (char*) VAL_STRING(vals + 6);
-				ecf2.len = strlen(ecf2.s);
-			}
-			LM_DBG("ECF2 from DB is [%.*s]\n", ecf2.len, ecf2.s);
-
-			if (!VAL_NULL(vals + 7)) {
-				blob = VAL_BLOB(vals + 7);
-				bin_alloc(&x, blob.len);
-				memcpy(x.s, blob.s, blob.len);
-				x.len = blob.len;
-				x.max = 0;
-				subscription = bin_decode_ims_subscription(&x);
-				bin_free(&x);
-			}
-			if (!VAL_NULL(vals + 8)) {
-				impu_id = VAL_INT(vals + 8);
-			}
+int db_link_contact_to_impu(impurecord_t* _r, ucontact_t* _c) {
+    int len;
+    db1_res_t* rs;
 
-			/* insert impu into memory */
-			lock_udomain(_d, &impu);
-			if (mem_insert_impurecord(_d, &impu, reg_state, barring,
-					&subscription, &ccf1, &ccf2, &ecf1, &ecf2, &impurecord)
-					!= 0) {
-				LM_ERR("Unable to insert IMPU into memory [%.*s]\n", impu.len, impu.s);
-			}
+    LM_DBG("DB: linking contact to IMPU\n");
 
-			/* add contacts */
-			if (impu_id < 0) {
-				LM_ERR("impu_id has not been set [%.*s] - we cannot read contacts or subscribers from DB....aborting preload\n", impu.len, impu.s);
-				//TODO: check frees
-				unlock_udomain(_d, &impu);
-				continue;
-			}
-			impu_id_len = int_to_str_len(impu_id);
-			len = query_contact.len + impu_id_len + 1/*nul*/;
-			if (!query_buffer_len || query_buffer_len < len) {
-				if (query_buffer.s) {
-					pkg_free(query_buffer.s);
-				}
-				query_buffer.s = (char*) pkg_malloc(len);
-				if (!query_buffer.s) {
-					LM_ERR("mo more pkg mem\n");
-					//TODO: check free
-					unlock_udomain(_d, &impu);
-					return -1;
-				}
-				query_buffer_len = len;
-			}
-			memcpy(query_buffer.s, query_contact.s, query_contact.len);
-			p_contact = query_buffer.s + query_contact.len;
-			snprintf(p_contact, impu_id_len + 1, "%d", impu_id);
-			query_buffer.len = query_contact.len + impu_id_len;
-			if (ul_dbf.raw_query(_c, &query_buffer, &contact_rs) != 0) {
-				LM_ERR("Unable to query DB for contacts associated with impu [%.*s]\n",
-						impu.len, impu.s);
-				ul_dbf.free_result(_c, contact_rs);
-			} else {
-			    if (RES_ROW_N(contact_rs) == 0) {
-				    LM_DBG("no contacts associated with impu [%.*s]\n",impu.len, impu.s);
-				    ul_dbf.free_result(_c, contact_rs);
-			    } else {
-				nn = 0;
-				do {
-					nn++;
-					LM_DBG("loading S-CSCF contact - cycle [%d]\n", nn);
-					for (j = 0; j < RES_ROW_N(contact_rs); j++) {
-						contact_row = RES_ROWS(contact_rs) + j;
-						contact_vals = ROW_VALUES(contact_row);
-
-						if (!VAL_NULL(contact_vals)) {
-							contact.s = (char*) VAL_STRING(contact_vals);
-							contact.len = strlen(contact.s);
-						}
-						if (dbrow2contact(contact_vals, &contact_data) != 0) {
-							LM_ERR("unable to convert contact row from DB into valid data... moving on\n");
-							continue;
-						}
-
-						if ((c = mem_insert_ucontact(impurecord, &contact, &contact_data)) == 0) {
-							LM_ERR("Unable to insert contact [%.*s] for IMPU [%.*s] into memory... continuing...\n",
-									contact.len, contact.s,
-									impu.len, impu.s);
-						}
-					}
-					if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
-						if (ul_dbf.fetch_result(_c, &contact_rs, ul_fetch_rows) < 0) {
-							LM_ERR("fetching rows failed\n");
-							ul_dbf.free_result(_c, contact_rs);
-							unlock_udomain(_d, &impu);
-							return -1;
-						}
-					} else {
-						break;
-					}
-				} while (RES_ROW_N(contact_rs) > 0);
-				ul_dbf.free_result(_c, contact_rs);
-			    }
-			}
-						
-			/* add subscriber */
-			impu_id_len = int_to_str_len(impu_id);
-			len = query_subscriber.len + impu_id_len + 1/*nul*/;
-			if (!query_buffer_len || query_buffer_len < len) {
-				if (query_buffer.s) {
-					pkg_free(query_buffer.s);
-				}
-				query_buffer.s = (char*) pkg_malloc(len);
-				if (!query_buffer.s) {
-					LM_ERR("mo more pkg mem\n");
-					//TODO: check free
-					unlock_udomain(_d, &impu);
-					return -1;
-				}
-				query_buffer_len = len;
-			}
-			memcpy(query_buffer.s, query_subscriber.s, query_subscriber.len);
-			p_subscriber = query_buffer.s + query_subscriber.len;
-			snprintf(p_subscriber, impu_id_len + 1, "%d", impu_id);
-			query_buffer.len = query_subscriber.len + impu_id_len;
-			if (ul_dbf.raw_query(_c, &query_buffer, &subscriber_rs) != 0) {
-				LM_ERR("Unable to query DB for subscriber associated with impu [%.*s]\n",
-						impu.len, impu.s);
-				ul_dbf.free_result(_c, subscriber_rs);
-				unlock_udomain(_d, &impu);
-				continue;
-			}
-			if (RES_ROW_N(subscriber_rs) == 0) {
-				LM_DBG("no subscriber associated with impu [%.*s]\n",impu.len, impu.s);
-				ul_dbf.free_result(_c, subscriber_rs);
-				unlock_udomain(_d, &impu);
-				continue;
-			}
+    len = strlen(impu_contact_insert_query) + _r->public_identity.len + _c->c.len + 1;
 
-			nn = 0;
-			do {
-				nn++;				
-				LM_DBG("loading S-CSCF subscriber - cycle [%d]\n", nn);
-				for (j = 0; j < RES_ROW_N(subscriber_rs); j++) {
-					subscriber_row = RES_ROWS(subscriber_rs) + j;
-					subscriber_vals = ROW_VALUES(subscriber_row);
-
-					/*presentity uri*/
-					if (!VAL_NULL(subscriber_vals)) {
-					    presentity_uri.s = (char*) VAL_STRING(subscriber_vals);
-					    presentity_uri.len = strlen(presentity_uri.s);
-					}
-
-					if (dbrow2subscriber(subscriber_vals, &subscriber_data) != 0) {
-						LM_ERR("unable to convert subscriber row from DB into valid subscriberdata... moving on\n");
-						continue;
-					}
-					
-					if (add_subscriber(impurecord, &subscriber_data, &reg_subscriber, 1 /*db_load*/) != 0) {
-						LM_ERR("Unable to insert subscriber with presentity_uri [%.*s] for IMPU [%.*s] into memory... continuing...\n",
-								presentity_uri.len, presentity_uri.s,
-								impu.len, impu.s);
-					}
-				}
-				if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
-					if (ul_dbf.fetch_result(_c, &subscriber_rs, ul_fetch_rows) < 0) {
-						LM_ERR("fetching rows failed\n");
-						ul_dbf.free_result(_c, subscriber_rs);
-						unlock_udomain(_d, &impu);
-						return -1;
-					}
-				} else {
-					break;
-				}
-			} while (RES_ROW_N(subscriber_rs) > 0);
-			ul_dbf.free_result(_c, subscriber_rs);
-						
-			unlock_udomain(_d, &impu);
-			
-		}
+    if (!query_buffer_len || query_buffer_len < len) {
+	if (query_buffer.s) {
+	    pkg_free(query_buffer.s);
+	}
+	query_buffer.s = (char*) pkg_malloc(len);
+	if (!query_buffer.s) {
+	    LM_ERR("no more pkg mem\n");
+	    return -1;
+	}
+	query_buffer_len = len;
+	
+    }
 
-		if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
-			if (ul_dbf.fetch_result(_c, &rs, ul_fetch_rows) < 0) {
-				LM_ERR("fetching rows (1) failed\n");
-				ul_dbf.free_result(_c, rs);
-				return -1;
-			}
-		} else {
-			break;
-		}
-	} while (RES_ROW_N(rs) > 0);
+    snprintf(query_buffer.s, query_buffer_len, impu_contact_insert_query, _r->public_identity.len, _r->public_identity.s, _c->c.len, _c->c.s);
+    query_buffer.len = strlen(query_buffer.s);//len;
 
-	ul_dbf.free_result(_c, rs);
+    LM_DBG("QUERY IS [%.*s] and len is %d\n", query_buffer.len, query_buffer.s, query_buffer.len);
+    if (ul_dbf.raw_query(ul_dbh, &query_buffer, &rs) != 0) {
+	LM_ERR("Unable to link impu-contact in DB - impu [%.*s], contact [%.*s]\n", _r->public_identity.len, _r->public_identity.s, _c->c.len, _c->c.s);
+	return -1;
+    }
+    LM_DBG("Query success\n");
+
+    return 0;
+}
+
+int db_unlink_contact_from_impu(impurecord_t* _r, ucontact_t* _c) {
+    int len;
+    db1_res_t* rs;
+
+    LM_DBG("DB: un-linking contact to IMPU\n");
+
+    len = strlen(impu_contact_delete_query) + _r->public_identity.len + _c->c.len + 1;
+
+    if (!query_buffer_len || query_buffer_len < len) {
+	if (query_buffer.s) {
+	    pkg_free(query_buffer.s);
+	}
+	query_buffer.s = (char*) pkg_malloc(len);
+	if (!query_buffer.s) {
+	    LM_ERR("no more pkg mem\n");
+	    return -1;
+	}
+	query_buffer_len = len;
 	
-	LM_DBG("Completed preload_udomain");
+    }
 
-	return 0;
+    snprintf(query_buffer.s, query_buffer_len, impu_contact_delete_query, _r->public_identity.len, _r->public_identity.s, _c->c.len, _c->c.s);
+    query_buffer.len = strlen(query_buffer.s);//len;
+
+    if (ul_dbf.raw_query(ul_dbh, &query_buffer, &rs) != 0) {
+	LM_ERR("Unable to un-link impu-contact in DB - impu [%.*s], contact [%.*s]\n", _r->public_identity.len, _r->public_identity.s, _c->c.len, _c->c.s);
+	return -1;
+    }
+    LM_DBG("Delete query success\n");
+
+    return 0;
 }
+

+ 4 - 2
modules/ims_usrloc_scscf/usrloc_db.h

@@ -64,8 +64,10 @@ int db_insert_impurecord(struct udomain* _d, str* public_identity, int reg_state
 		struct impurecord** _r);
 int db_delete_impurecord(udomain_t* _d, struct impurecord* _r);
 int db_insert_ucontact(impurecord_t* _r, ucontact_t* _c);
-int db_delete_ucontact(impurecord_t* _r, ucontact_t* _c);
-
+int db_update_ucontact(impurecord_t* _r, ucontact_t* _c);
+int db_delete_ucontact(ucontact_t* _c);
+int db_link_contact_to_impu(impurecord_t* _r, ucontact_t* _c);
+int db_unlink_contact_from_impu(impurecord_t* _r, ucontact_t* _c);
 int db_insert_subscriber(impurecord_t* _r, reg_subscriber* _reg_subscriber);
 int db_delete_subscriber(impurecord_t* _r, reg_subscriber* _reg_subscriber);