فهرست منبع

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 سال پیش
والد
کامیت
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);