Browse Source

registrar(k): added initial support for GRUU - RFC 5627

- save() and lookup() recognize now the GRUU cases
- save() generates both pub-gruu and temp-gruu, sending them in the
  Contact headers for 200 reply
- lookup() will match on GRUU if it is the case, resulting to a Contact
  address only (no additional branches)
Daniel-Constantin Mierla 13 years ago
parent
commit
fd9fe6e683

+ 1 - 0
modules_k/registrar/Makefile

@@ -14,4 +14,5 @@ DEFS+=-DOPENSER_MOD_INTERFACE
 
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
 include ../../Makefile.modules

+ 14 - 0
modules_k/registrar/README

@@ -26,6 +26,7 @@ Bogdan-Andre Iancu
         1. Overview
 
               1.1. PATH support
+              1.2. GRUU Support
 
         2. Dependencies
 
@@ -118,6 +119,7 @@ Chapter 1. Admin Guide
    1. Overview
 
         1.1. PATH support
+        1.2. GRUU Support
 
    2. Dependencies
 
@@ -173,6 +175,7 @@ Chapter 1. Admin Guide
 1. Overview
 
    1.1. PATH support
+   1.2. GRUU Support
 
    The module contains REGISTER processing logic.
 
@@ -204,6 +207,17 @@ Chapter 1. Admin Guide
    required beside setting the registrar-parameters "use_path" and
    "path_mode".
 
+1.2. GRUU Support
+
+   GRUU (RFC5627) is supported with both public and temporary addresses.
+
+   The public GRUU is build based on '+sip.instance' parameter as
+   recommended by RFC.
+
+   The temporary GRUU is built based on internal SRUID (unique id
+   generator) and it is kept the same for the duration of contact
+   validity.
+
 2. Dependencies
 
    2.1. Kamailio Modules

+ 21 - 16
modules_k/registrar/common.c

@@ -36,7 +36,6 @@
 
 #include <string.h> 
 #include "../../dprint.h"
-#include "../../parser/parse_uri.h"
 #include "rerrno.h"
 #include "reg_mod.h"
 #include "common.h"
@@ -47,11 +46,12 @@
 /*! \brief
  * Extract Address of Record
  */
-int extract_aor(str* _uri, str* _a)
+int extract_aor(str* _uri, str* _a, sip_uri_t *_pu)
 {
 	static char aor_buf[MAX_AOR_LEN];
 	str tmp;
-	struct sip_uri puri;
+	sip_uri_t turi;
+	sip_uri_t *puri;
 	int user_len;
 	str *uri;
 	str realm_prefix;
@@ -59,24 +59,29 @@ int extract_aor(str* _uri, str* _a)
 	memset(aor_buf, 0, MAX_AOR_LEN);
 	uri=_uri;
 
-	if (parse_uri(uri->s, uri->len, &puri) < 0) {
+	if(_pu!=NULL)
+		puri = _pu;
+	else
+		puri = &turi;
+
+	if (parse_uri(uri->s, uri->len, puri) < 0) {
 		rerrno = R_AOR_PARSE;
 		LM_ERR("failed to parse Address of Record\n");
 		return -1;
 	}
 	
-	if ( (puri.user.len + puri.host.len + 1) > MAX_AOR_LEN
-	|| puri.user.len > USERNAME_MAX_SIZE
-	||  puri.host.len > DOMAIN_MAX_SIZE ) {
+	if ( (puri->user.len + puri->host.len + 1) > MAX_AOR_LEN
+	|| puri->user.len > USERNAME_MAX_SIZE
+	||  puri->host.len > DOMAIN_MAX_SIZE ) {
 		rerrno = R_AOR_LEN;
 		LM_ERR("Address Of Record too long\n");
 		return -2;
 	}
 
 	_a->s = aor_buf;
-	_a->len = puri.user.len;
+	_a->len = puri->user.len;
 
-	if (un_escape(&puri.user, _a) < 0) {
+	if (un_escape(&puri->user, _a) < 0) {
 		rerrno = R_UNESCAPE;
 		LM_ERR("failed to unescape username\n");
 		return -3;
@@ -90,14 +95,14 @@ int extract_aor(str* _uri, str* _a)
 		/* strip prefix (if defined) */
 		realm_prefix.s = cfg_get(registrar, registrar_cfg, realm_pref);
 		realm_prefix.len = strlen(realm_prefix.s);
-		if (realm_prefix.len && realm_prefix.len<puri.host.len &&
-		(memcmp(realm_prefix.s, puri.host.s, realm_prefix.len)==0) ) {
-			memcpy(aor_buf + _a->len, puri.host.s + realm_prefix.len,
-					puri.host.len - realm_prefix.len);
-			_a->len += puri.host.len - realm_prefix.len;
+		if (realm_prefix.len && realm_prefix.len<puri->host.len &&
+		(memcmp(realm_prefix.s, puri->host.s, realm_prefix.len)==0) ) {
+			memcpy(aor_buf + _a->len, puri->host.s + realm_prefix.len,
+					puri->host.len - realm_prefix.len);
+			_a->len += puri->host.len - realm_prefix.len;
 		} else {
-			memcpy(aor_buf + _a->len, puri.host.s, puri.host.len);
-			_a->len += puri.host.len;
+			memcpy(aor_buf + _a->len, puri->host.s, puri->host.len);
+			_a->len += puri->host.len;
 		}
 	}
 

+ 3 - 1
modules_k/registrar/common.h

@@ -33,12 +33,14 @@
 #define COMMON_H
 
 #include "../../str.h"
+#include "../../parser/parse_uri.h"
 
+#define REG_GRUU_SEP	'-'
 
 /*! \brief
  * Extract Address Of Record
  */
-int extract_aor(str* _uri, str* _a);
+int extract_aor(str* _uri, str* _a, sip_uri_t *_pu);
 
 
 #endif /* COMMON_H */

+ 17 - 0
modules_k/registrar/doc/registrar_admin.xml

@@ -69,6 +69,23 @@
 		<quote>path_mode</quote>.
 		</para>
 	</section>
+	<section>
+		<title>GRUU Support</title>
+		<para>
+			GRUU (RFC5627) is supported with both public and temporary
+			addresses.
+		</para>
+		<para>
+			The public GRUU is build based on '+sip.instance'
+			parameter as recommended by RFC.
+		</para>
+		<para>
+			The temporary GRUU is built based on internal SRUID (unique
+			id generator) and it is kept the same for the duration of
+			contact validity.
+		</para>
+	</section>
+	
 	</section>
 
 

+ 121 - 20
modules_k/registrar/lookup.c

@@ -51,6 +51,35 @@
 	( !method_filtering || ((_msg)->REQ_METHOD)&((_c)->methods) )
 
 
+/**
+ * compare two instances, by skipping '<' & '>'
+ */
+int reg_cmp_instances(str *i1, str *i2)
+{
+	str inst1;
+	str inst2;
+
+	if(i1==NULL || i2==NULL || i1->len<=0 || i2->len<=0)
+		return -1;
+
+	inst1 = *i1;
+	inst2 = *i2;
+	if(inst1.len>2 && inst1.s[0]=='<' && inst1.s[inst1.len-1]=='>')
+	{
+		inst1.s++;
+		inst1.len -=2;
+	}
+	if(inst2.len>2 && inst2.s[0]=='<' && inst2.s[inst2.len-1]=='>')
+	{
+		inst2.s++;
+		inst2.len -=2;
+	}
+	if(inst1.len>0 && inst1.len==inst2.len
+						&& memcmp(inst1.s, inst2.s, inst2.len)==0)
+		return 0;
+	return -1;
+}
+
 /*! \brief
  * Lookup contact in the database and rewrite Request-URI
  * \return: -1 : not found
@@ -61,40 +90,109 @@ int lookup(struct sip_msg* _m, udomain_t* _d, str* _uri)
 {
 	urecord_t* r;
 	str aor, uri;
-	ucontact_t* ptr;
+	sip_uri_t puri;
+	ucontact_t* ptr = 0;
 	int res;
 	int ret;
 	str path_dst;
 	flag_t old_bflags;
+	int i;
+	str inst = {0};
+	unsigned int ahash = 0;
 
 
 	if (_m->new_uri.s) uri = _m->new_uri;
 	else uri = _m->first_line.u.request.uri;
 	
-	if (extract_aor((_uri)?_uri:&uri, &aor) < 0) {
+	if (extract_aor((_uri)?_uri:&uri, &aor, &puri) < 0) {
 		LM_ERR("failed to extract address of record\n");
 		return -3;
 	}
-	
+	/* check if gruu */
+	if(puri.gr.s!=NULL)
+	{
+		if(puri.gr_val.len>0) {
+			/* pub-gruu */
+			inst = puri.gr_val;
+			LM_DBG("looking up pub gruu [%.*s]\n", inst.len, inst.s);
+		} else {
+			/* temp-gruu */
+			ahash = 0;
+			inst = puri.user;
+			for(i=inst.len-1; i>=0; i--)
+			{
+				if(inst.s[i]==REG_GRUU_SEP)
+					break;
+				ahash <<= 4;
+				if(inst.s[i] >='0' && inst.s[i] <='9') ahash+=inst.s[i] -'0';
+				else if (inst.s[i] >='a' && inst.s[i] <='f') ahash+=inst.s[i] -'a'+10;
+				else if (inst.s[i] >='A' && inst.s[i] <='F') ahash+=inst.s[i] -'A'+10;
+				else {
+					LM_ERR("failed to extract temp gruu - invalid hash\n");
+					return -3;
+				}
+			}
+			if(i<0) {
+				LM_ERR("failed to extract temp gruu - invalid format\n");
+				return -3;
+			}
+			inst.len = i;
+			LM_DBG("looking up temp gruu [%u / %.*s]\n", ahash, inst.len, inst.s);
+		}
+	}
+
 	get_act_time();
 
-	ul.lock_udomain(_d, &aor);
-	res = ul.get_urecord(_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;
-	}
+	if(puri.gr.s==NULL || puri.gr_val.len>0)
+	{
+		/* aor or pub-gruu lookup */
+		ul.lock_udomain(_d, &aor);
+		res = ul.get_urecord(_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;
+		}
 
-	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;
+		ptr = r->contacts;
+		ret = -1;
+		/* look first for an un-expired and suported contact */
+		while (ptr) {
+			if(VALID_CONTACT(ptr,act_time)) {
+				if(allowed_method(_m,ptr)) {
+					/* match on instance, if pub-gruu */
+					if(inst.len>0
+							&& reg_cmp_instances(&inst, &ptr->instance)==0)
+					{
+						/* found by instance */
+						LM_DBG("contact for [%.*s] found by pub gruu [%.*s]\n",
+							aor.len, ZSW(aor.s), inst.len, inst.s);
+						break;
+					}
+				} else {
+					ret = -2;
+				}
+			}
+			ptr = ptr->next;
+		}
+		if (ptr==0) {
+			/* nothing found */
+			goto done;
+		}
+	} else {
+		/* temp-gruu lookup */
+		res = ul.get_urecord_by_ruid(_d, ahash, &inst, &r, &ptr);
+		if(res<0) {
+			LM_DBG("temp gruu '%.*s' not found in usrloc\n", aor.len, ZSW(aor.s));
+			return -1;
+		}
+		aor = *ptr->aor;
+		/* test if un-expired and suported contact */
+		if( (ptr) && !(VALID_CONTACT(ptr,act_time)
+					&& (ret=-2) && allowed_method(_m,ptr)))
+			goto done;
+		LM_DBG("contact for [%.*s] found by temp gruu [%.*s / %u]\n",
+							aor.len, ZSW(aor.s), inst.len, inst.s);
 	}
 
 	ret = 1;
@@ -146,6 +244,9 @@ int lookup(struct sip_msg* _m, udomain_t* _d, str* _uri)
 		ptr = ptr->next;
 	}
 
+	/* if was gruu, no more branches */
+	if(inst.len>0) goto done;
+
 	/* Append branches if enabled */
 	if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done;
 
@@ -197,7 +298,7 @@ int registered(struct sip_msg* _m, udomain_t* _d, str* _uri)
 		else uri = _m->first_line.u.request.uri;
 	}
 	
-	if (extract_aor(&uri, &aor) < 0) {
+	if (extract_aor(&uri, &aor, NULL) < 0) {
 		LM_ERR("failed to extract address of record\n");
 		return -1;
 	}

+ 9 - 0
modules_k/registrar/reg_mod.c

@@ -68,6 +68,7 @@
 #include "../../pvar.h"
 #include "../../modules_k/usrloc/usrloc.h"
 #include "../../lib/kcore/statistics.h"
+#include "../../lib/srutils/sruid.h"
 #include "../../modules/sl/sl.h"
 #include "../../mod_fix.h"
 
@@ -113,6 +114,9 @@ int path_mode = PATH_MODE_STRICT;		/*!< if the Path HF should be inserted in the
 int path_use_params = 0;			/*!< if the received- and nat-parameters of last Path uri should be used
  						 * to determine if UAC is nat'ed */
 
+/* sruid to get internal uid */
+sruid_t _reg_sruid;
+
 /* Populate this AVP if testing for specific registration instance. */
 char *reg_callid_avp_param = 0;
 unsigned short reg_callid_avp_type = 0;
@@ -257,6 +261,9 @@ static int mod_init(void)
 	qvalue_t dq;
 
 
+	if(sruid_init(&_reg_sruid, '-', "uloc", SRUID_INC)<0)
+		return -1;
+
 #ifdef STATISTICS
 	/* register statistics */
 	if (register_module_stats( exports.name, mod_stats)!=0 ) {
@@ -371,6 +378,8 @@ static int mod_init(void)
 
 static int child_init(int rank)
 {
+	if(sruid_init(&_reg_sruid, '-', "uloc", SRUID_INC)<0)
+		return -1;
 	if (rank==1) {
 		/* init stats */
 		//TODO if parameters are modified via cfg framework do i change them?

+ 1 - 1
modules_k/registrar/regpv.c

@@ -428,7 +428,7 @@ int pv_fetch_contacts(struct sip_msg* msg, char* table, char* uri,
 		return -1;
 	}
 
-	if (extract_aor(&u, &aor) < 0) {
+	if (extract_aor(&u, &aor, NULL) < 0) {
 		LM_ERR("failed to extract Address Of Record\n");
 		return -1;
 	}

+ 118 - 3
modules_k/registrar/reply.c

@@ -64,6 +64,17 @@
 #define CONTACT_SEP ", "
 #define CONTACT_SEP_LEN (sizeof(CONTACT_SEP) - 1)
 
+#define GR_PARAM ";gr="
+#define GR_PARAM_LEN (sizeof(GR_PARAM) - 1)
+
+#define SIP_INSTANCE_PARAM	";+sip.instance="
+#define SIP_INSTANCE_PARAM_LEN	(sizeof(SIP_INSTANCE_PARAM) - 1)
+
+#define PUB_GRUU_PARAM ";pub-gruu="
+#define PUB_GRUU_PARAM_LEN (sizeof(PUB_GRUU_PARAM) - 1)
+
+#define TMP_GRUU_PARAM ";temp-gruu="
+#define TMP_GRUU_PARAM_LEN (sizeof(TMP_GRUU_PARAM) - 1)
 
 /*! \brief
  * Buffer for Contact header field
@@ -79,7 +90,7 @@ 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(ucontact_t* c, str *host)
 {
 	unsigned int len;
 	int qlen;
@@ -101,6 +112,38 @@ static inline unsigned int calc_buf_len(ucontact_t* c)
 					+ 1 /* dquote */
 					;
 			}
+			if (c->instance.len>0) {
+				/* pub-gruu */
+				len += PUB_GRUU_PARAM_LEN
+					+ 1 /* " */
+					+ 4 /* sip: */
+					+ c->aor->len
+					+ 1 /* @ */
+					+ host->len
+					+ GR_PARAM_LEN
+					+ c->instance.len
+					+ 1 /* " */
+					;
+				/* temp-gruu */
+				len += TMP_GRUU_PARAM_LEN
+					+ 1 /* " */
+					+ 4 /* sip: */
+					+ c->ruid.len
+					+ 1 /* 'sep' */
+					+ 8 /* max hex int */
+					+ 1 /* @ */
+					+ host->len
+					+ GR_PARAM_LEN
+					- 1 /* = */
+					+ 1 /* " */
+					;
+				/* +sip-instance */
+				len += SIP_INSTANCE_PARAM_LEN
+					+ 1 /* " */
+					+ c->instance.len
+					+ 1 /* " */
+					;
+			}
 		}
 		c = c->next;
 	}
@@ -114,12 +157,18 @@ static inline unsigned int calc_buf_len(ucontact_t* c)
  * Allocate a memory buffer and print Contact
  * header fields into it
  */
-int build_contact(ucontact_t* c)
+int build_contact(ucontact_t* c, str *host)
 {
 	char *p, *cp;
+	char *a;
 	int fl, len;
+	str user;
+	str inst;
+	unsigned int ahash;
+	unsigned short digit;
 
-	contact.data_len = calc_buf_len(c);
+
+	contact.data_len = calc_buf_len(c, host);
 	if (!contact.data_len) return 0;
 
 	if (!contact.buf || (contact.buf_len < contact.data_len)) {
@@ -179,6 +228,72 @@ int build_contact(ucontact_t* c)
 				p += c->received.len;
 				*p++ = '\"';
 			}
+			if (c->instance.len>0) {
+				user.s = c->aor->s;
+				a = memchr(c->aor->s, '@', c->aor->len);
+				if(a!=NULL) {
+					user.len = a - user.s;
+				} else {
+					user.len = c->aor->len;
+				}
+				/* pub-gruu */
+				memcpy(p, PUB_GRUU_PARAM, PUB_GRUU_PARAM_LEN);
+				p += PUB_GRUU_PARAM_LEN;
+				*p++ = '\"';
+				memcpy(p, "sip:", 4);
+				p += 4;
+				if(a!=NULL) {
+					memcpy(p, c->aor->s, c->aor->len);
+					p += c->aor->len;
+				} else {
+					memcpy(p, user.s, user.len);
+					p += user.len;
+					*p++ = '@';
+					memcpy(p, host->s, host->len);
+					p += host->len;
+				}
+				memcpy(p, GR_PARAM, GR_PARAM_LEN);
+				p += GR_PARAM_LEN;
+				inst = c->instance;
+				if(inst.s[0]=='<' && inst.s[inst.len-1]=='>') {
+					inst.s++;
+					inst.len -= 2;
+				}
+				memcpy(p, inst.s, inst.len);
+				p += inst.len;
+				*p++ = '\"';
+				/* temp-gruu */
+				memcpy(p, TMP_GRUU_PARAM, TMP_GRUU_PARAM_LEN);
+				p += TMP_GRUU_PARAM_LEN;
+				*p++ = '\"';
+				memcpy(p, "sip:", 4);
+				p += 4;
+				memcpy(p, c->ruid.s, c->ruid.len);
+				p += c->ruid.len;
+				*p++ = '-';
+				ahash = ul.get_aorhash(c->aor);
+				while(ahash!=0)
+				{
+					digit =  ahash & 0x0f;
+					*p++ = (digit >= 10) ? digit + 'a' - 10 : digit + '0';
+					ahash >>= 4;
+				}
+				*p++ = '@';
+				memcpy(p, host->s, host->len);
+				p += host->len;
+				memcpy(p, GR_PARAM, GR_PARAM_LEN);
+				p += GR_PARAM_LEN - 1;
+				*p++ = '\"';
+
+				/* +sip-instance */
+				memcpy(p, SIP_INSTANCE_PARAM, SIP_INSTANCE_PARAM_LEN);
+				p += SIP_INSTANCE_PARAM_LEN;
+				*p++ = '\"';
+				memcpy(p, c->instance.s, c->instance.len);
+				p += c->instance.len;
+				*p++ = '\"';
+			}
+
 		}
 
 		c = c->next;

+ 1 - 1
modules_k/registrar/reply.h

@@ -44,7 +44,7 @@ int reg_send_reply(struct sip_msg* _m);
 /*! \brief
  * Build Contact HF for reply
  */
-int build_contact(ucontact_t* c);
+int build_contact(ucontact_t* c, str* host);
 
 
 /*! \brief

+ 50 - 19
modules_k/registrar/save.c

@@ -59,6 +59,7 @@
 #include "../../dset.h"
 #include "../../xavp.h"
 #include "../../mod_fix.h"
+#include "../../lib/srutils/sruid.h"
 #include "../../lib/kcore/cmpapi.h"
 #include "../../lib/kcore/statistics.h"
 #ifdef USE_TCP
@@ -77,12 +78,14 @@
 
 static int mem_only = 0;
 
+extern sruid_t _reg_sruid;
+
 /*! \brief
  * Process request that contained a star, in that case, 
  * we will remove all bindings with the given username 
  * from the usrloc and return 200 OK response
  */
-static inline int star(udomain_t* _d, str* _a)
+static inline int star(udomain_t* _d, str* _a, str *_h)
 {
 	urecord_t* r;
 	ucontact_t* c;
@@ -112,7 +115,7 @@ static inline int star(udomain_t* _d, str* _a)
 		      */
 		rerrno = R_UL_DEL_R;
 		if (!ul.get_urecord(_d, _a, &r)) {
-			build_contact(r->contacts);
+			build_contact(r->contacts, _h);
 			ul.release_urecord(r);
 		}
 		ul.unlock_udomain(_d, _a);
@@ -183,7 +186,7 @@ static struct socket_info *get_sock_hdr(struct sip_msg *msg)
  * containing a list of all existing bindings for the
  * given username (in To HF)
  */
-static inline int no_contacts(udomain_t* _d, str* _a)
+static inline int no_contacts(udomain_t* _d, str* _a, str* _h)
 {
 	urecord_t* r;
 	int res;
@@ -198,10 +201,10 @@ static inline int no_contacts(udomain_t* _d, str* _a)
 	}
 	
 	if (res == 0) {  /* Contacts found */
-		build_contact(r->contacts);
+		build_contact(r->contacts, _h);
 		ul.release_urecord(r);
 	} else {  /* No contacts found */
-		build_contact(NULL);
+		build_contact(NULL, _h);
 	}
 	ul.unlock_udomain(_d, _a);
 	return 0;
@@ -354,7 +357,11 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
 				ci.received = received;
 			}
 		}
-
+		if(_c->instance)
+			ci.instance = _c->instance->body;
+		if(sruid_next(&_reg_sruid)<0)
+			goto error;
+		ci.ruid = _reg_sruid.uid;
 	}
 
 	return &ci;
@@ -407,7 +414,7 @@ int reg_get_crt_max_contacts(void)
 static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
 {
 	ucontact_info_t* ci;
-	urecord_t* r;
+	urecord_t* r = NULL;
 	ucontact_t* c;
 	contact_t* _c;
 	unsigned int flags;
@@ -417,6 +424,11 @@ static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
 	int e_max, tcp_check;
 	struct sip_uri uri;
 #endif
+	sip_uri_t *u;
+
+	u = parse_to_uri(_m);
+	if(u==NULL)
+		goto error;
 
 	flags = mem_only;
 #ifdef USE_TCP
@@ -461,7 +473,8 @@ static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
 		}
 
 		if ( r->contacts==0 ||
-		ul.get_ucontact(r, &_c->uri, ci->callid, ci->path, ci->cseq+1, &c) != 0) {
+		ul.get_ucontact_by_instance(r, &_c->uri, ci->callid, ci->path, ci->cseq+1,
+					&ci->instance, &c) != 0) {
 			if (ul.insert_ucontact( r, &_c->uri, ci, &c) < 0) {
 				rerrno = R_UL_INS_C;
 				LM_ERR("failed to insert contact\n");
@@ -494,10 +507,10 @@ static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
 
 	if (r) {
 		if (r->contacts)
-			build_contact(r->contacts);
+			build_contact(r->contacts, &u->host);
 		ul.release_urecord(r);
 	} else { /* No contacts found */
-		build_contact(NULL);
+		build_contact(NULL, &u->host);
 	}
 
 #ifdef USE_TCP
@@ -538,7 +551,8 @@ static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c,
 		/* calculate expires */
 		calc_contact_expires(_m, _c->expires, &e);
 
-		ret = ul.get_ucontact( _r, &_c->uri, ci->callid, ci->path, ci->cseq, &cont);
+		ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci->callid, ci->path, ci->cseq,
+				&ci->instance, &cont);
 		if (ret==-1) {
 			LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
 			rerrno = R_INV_CSEQ;
@@ -627,7 +641,8 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
 		calc_contact_expires(_m, _c->expires, &expires);
 
 		/* search for the contact*/
-		ret = ul.get_ucontact( _r, &_c->uri, ci->callid, ci->path, ci->cseq, &c);
+		ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci->callid, ci->path,
+				ci->cseq, &ci->instance, &c);
 		if (ret==-1) {
 			LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
 			rerrno = R_INV_CSEQ;
@@ -754,6 +769,11 @@ static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
 	int res;
 	int ret;
 	urecord_t* r;
+	sip_uri_t *u;
+
+	u = parse_to_uri(_m);
+	if(u==NULL)
+		return -2;
 
 	ret = 0;
 	ul.lock_udomain(_d, _a);
@@ -767,12 +787,12 @@ static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
 
 	if (res == 0) { /* Contacts found */
 		if ((ret=update_contacts(_m, r, _mode)) < 0) {
-			build_contact(r->contacts);
+			build_contact(r->contacts, &u->host);
 			ul.release_urecord(r);
 			ul.unlock_udomain(_d, _a);
 			return -3;
 		}
-		build_contact(r->contacts);
+		build_contact(r->contacts, &u->host);
 		ul.release_urecord(r);
 	} else {
 		if (insert_contacts(_m, _d, _a) < 0) {
@@ -796,6 +816,11 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 	int st, mode;
 	str aor;
 	int ret;
+	sip_uri_t *u;
+
+	u = parse_to_uri(_m);
+	if(u==NULL)
+		goto error;
 
 	rerrno = R_FINE;
 	ret = 1;
@@ -811,7 +836,7 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 	get_act_time();
 	c = get_first_contact(_m);
 
-	if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor) < 0) {
+	if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) {
 		LM_ERR("failed to extract Address Of Record\n");
 		goto error;
 	}
@@ -820,10 +845,10 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 
 	if (c == 0) {
 		if (st) {
-			if (star((udomain_t*)_d, &aor) < 0) goto error;
+			if (star((udomain_t*)_d, &aor, &u->host) < 0) goto error;
 			else ret=3;
 		} else {
-			if (no_contacts((udomain_t*)_d, &aor) < 0) goto error;
+			if (no_contacts((udomain_t*)_d, &aor, &u->host) < 0) goto error;
 			else ret=4;
 		}
 	} else {
@@ -851,13 +876,19 @@ error:
 int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri)
 {
 	str aor = {0, 0};
+	sip_uri_t *u;
+
+	u = parse_to_uri(_m);
+	if(u==NULL)
+		return -2;
+
 
-	if (extract_aor(_uri, &aor) < 0) {
+	if (extract_aor(_uri, &aor, NULL) < 0) {
 		LM_ERR("failed to extract Address Of Record\n");
 		return -1;
 	}
 
-	if (star(_d, &aor) < 0)
+	if (star(_d, &aor, &u->host) < 0)
 	{
 		LM_ERR("error unregistering user [%.*s]\n", aor.len, aor.s);
 		return -1;