Explorar o código

modules/ims_usrloc_pcscf: hash now on IP only and some contact search changes
- hash on IP required, considering with IPSEC/TLS there could be multiple contacts per IP... - these all need to resolve to the same contact
- the contact searches updated accordingly and simplified using uri parser
- new contact search returns a contact regardless of state the contact is in... up to consumer to test the state the are/are not interested in

Jason Penton %!s(int64=11) %!d(string=hai) anos
pai
achega
f802733daf

+ 17 - 6
modules/ims_usrloc_pcscf/pcontact.c

@@ -56,6 +56,7 @@
 #include "usrloc.h"
 #include "../../lib/ims/useful_defs.h"
 #include "usrloc_db.h"
+#include "../../parser/parse_uri.h"
 
 extern int db_mode;
 extern int hashing_type;
@@ -115,7 +116,8 @@ int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, s
 	int i;
 	ppublic_t* ppublic_ptr;
 	int is_default = 1;
-	str contact_host_port;
+	struct sip_uri sip_uri;
+
 
 	*_c = (pcontact_t*)shm_malloc(sizeof(pcontact_t));
 	if (*_c == 0) {
@@ -140,14 +142,23 @@ int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, s
 	(*_c)->aor.len = _contact->len;
 	(*_c)->domain = (str*)_d;
 
+	if (parse_uri((*_c)->aor.s, (*_c)->aor.len, &sip_uri) != 0) {
+		LM_ERR("unable to determine contact host from uri [%.*s\n", (*_c)->aor.len, (*_c)->aor.s);
+		shm_free((*_c)->aor.s);
+		shm_free(*_c);
+		*_c = 0;
+		return -2;
+	}
+	(*_c)->contact_host.s = sip_uri.host.s;
+	(*_c)->contact_host.len = sip_uri.host.len;
+	(*_c)->contact_port = sip_uri.port_no;
+	(*_c)->contact_user.s = sip_uri.user.s;
+	(*_c)->contact_user.len = sip_uri.user.len;
 
-	if ((hashing_type==0) || aor_to_contact(_contact, &contact_host_port) != 0) {
-		if (hashing_type != 0){
-			LM_DBG("failed to clean contact to host:port, falling back to full AOR - [%.*s]\n", _contact->len, _contact->s);
-		}
+	if (hashing_type==0) {
 		(*_c)->aorhash = core_hash(_contact, 0, 0);
 	} else {
-		(*_c)->aorhash = core_hash(&contact_host_port, 0, 0);
+		(*_c)->aorhash = core_hash(&(*_c)->contact_host, 0, 0);
 	}
 	(*_c)->expires = _ci->expires;
 	(*_c)->reg_state = _ci->reg_state;

+ 113 - 112
modules/ims_usrloc_pcscf/udomain.c

@@ -57,6 +57,7 @@
 #include "utime.h"
 #include "usrloc.h"
 #include "usrloc_db.h"
+#include "../../parser/parse_uri.h"
 
 #include "../../lib/ims/useful_defs.h"
 
@@ -441,11 +442,24 @@ error:
     return -1;
 }
 
+/*
+ * search for P-CSCF contact in usrloc
+ * @udomain_t* _d - domain to search in
+ * @str* _contact - contact to search for - should be a SIP URI
+ * @struct pontact** _c - contact to return to if found (null if not found)
+ * @return 0 if found <>0 if not
+ */
 int get_pcontact(udomain_t* _d, str* _contact, struct pcontact** _c) {
-	unsigned int sl, i, aorhash, len, len2;
+	unsigned int sl, i, aorhash;
 	struct pcontact* c;
-	char *ptr, *ptr2;
 	ppublic_t* impu;
+	struct sip_uri needle_uri, impu_uri;
+	int port_match = 0;
+
+	if (parse_uri(_contact->s, _contact->len, &needle_uri) != 0 ) {
+		LM_ERR("failed to parse search URI [%.*s]\n", _contact->len, _contact->s);
+		return 1;
+	}
 
 	/* search in cache */
 	aorhash = get_aor_hash(_d, _contact);
@@ -463,131 +477,118 @@ int get_pcontact(udomain_t* _d, str* _contact, struct pcontact** _c) {
 			return 0;
 		}
 
-		/* hash is correct, but contacts differ. Let's check if maybe the UA is using a different user part
-		 * which was part of his implicit set
-		 */
-		ptr2 = ptr = _contact->s;
-
-		if ((c->aorhash == aorhash)) {
-			len2 = len = _contact->len;
-
-			/* double check domain part is the same - this is to ensure that we don't false match on a collision that has a similar
-			 * userpart in the list of impus... (very unlikely but safer this way).
-			 */
-			ptr = memchr(_contact->s, '@', _contact->len);
-			if (ptr) {
-				len = (ptr - _contact->s);
-				ptr2 = ptr + 1;
-				len2 = _contact->len - (ptr2 - _contact->s);
-			}
+		LM_DBG("Searching for [%.*s] and comparing to [%.*s]\n", _contact->len, _contact->s, c->aor.len, c->aor.s);
 
-			ptr = memchr(c->aor.s, '@', c->aor.len);
-			if (!ptr)
-				ptr = c->aor.s;
-			else
-				ptr = ptr + 1;
-
-			if ((len2 <= c->aor.len) && (memcmp(ptr2, ptr, len2)==0)) {
-				impu = c->head;
-				while (impu) {
-					LM_DBG("comparing first %d chars of impu [%.*s] for contact [%.*s]\n",
-							len,
-							impu->public_identity.len, impu->public_identity.s,
-							_contact->len, _contact->s);
-					if (memcmp(impu->public_identity.s, _contact->s, len) == 0) {
-						//match
-						*_c = c;
-						return 0;
-					}
-					impu = impu->next;
-				}
-			}
+		/* hosts HAVE to match */
+		if ((needle_uri.host.len != c->received_host.len) || (memcmp(needle_uri.host.s, c->contact_host.s, needle_uri.host.len)!=0)) {
+			//can't possibly match
+			continue;
 		}
-		c = c->next;
-	}
-	return 1; /* Nothing found */
-}
-
-/* can't assume we are locked here */
-int get_pcontact_by_src(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c) {
-	int i;
-	struct pcontact* c;
-	unsigned int aorhash, sl;
-	char c_contact[256], *p;
-	str s_contact;
-
-	if (hashing_type == 1) {//we hash on IP:PORT - so no need to search sequentially..
-		/* get_aor_hash in this mode expects to see contact as host:port */
-		memset(c_contact, 0, 256);
-		memcpy(c_contact, _host->s, _host->len);
-		p = c_contact + _host->len;
-		*p = ':';
-		p++;
-		sprintf(p,"%d", _port);
-		s_contact.s = c_contact;
-		s_contact.len = strlen(c_contact);
-
-		aorhash = get_aor_hash(_d, &s_contact);
-		sl = aorhash & (_d->size - 1);
-		c = _d->table[sl].first;
-
-		for (i = 0; i < _d->table[sl].n; i++) {
-			lock_ulslot(_d, i);
-			LM_DBG("Searching for contact in P-CSCF usrloc [%.*s]\n",
-					s_contact.len,
-					s_contact.s);
-
-			// First check, if Proto and Port matches:
-			if ((c->received_port == _port) && (c->received_proto == _proto)) {
-				LM_DBG("Received host len %d (search %d)\n", c->received_host.len, _host->len);
-				// Then check the length:
-				if (c->received_host.len == _host->len) {
-					LM_DBG("Received host %.*s (search %.*s)\n",
-							c->received_host.len, c->received_host.s,
-							_host->len, _host->s);
 
-					// Finally really compare the "received_host"
-					if (!memcmp(c->received_host.s, _host->s, _host->len)) {
-						*_c = c;
-						return 0;
+		/* one of the ports must match, either the initial registered port, the received port, or one if the security ports (server) */
+		if ((needle_uri.port_no != c->contact_port)
+				&& (needle_uri.port_no != c->received_proto)) {
+			//check security ports
+			if (c->security) {
+				switch (c->security->type) {
+				case SECURITY_IPSEC: {
+					ipsec_t* ipsec = c->security->data.ipsec;
+					if (ipsec) {
+						LM_DBG("security server port is %d\n", ipsec->port_us);
+						LM_DBG("security client port is %d\n", ipsec->port_uc);
+						if (ipsec->port_us == needle_uri.port_no) {
+							LM_DBG("security port mathes contact\n");
+							port_match = 1;
+						}
 					}
+					break;
+				}
+				case SECURITY_TLS:
+				case SECURITY_NONE:
+					LM_WARN("not implemented\n");
+					break;
 				}
 			}
-			unlock_ulslot(_d, i);
-		}
-	} else {
-		/* search sequentially */
-		for(i=0; i<_d->size; i++)
-		{
-			c = _d->table[i].first;
-			while(c) {
-				LM_DBG("Port %d (search %d), Proto %d (search %d), reg_state %s (search %s)\n",
-					c->received_port, _port, c->received_proto, _proto,
-					reg_state_to_string(c->reg_state), reg_state_to_string(PCONTACT_REGISTERED)
-					);
-				// First check, if Proto and Port matches:
-				if ((c->received_port == _port) && (c->received_proto == _proto)) {
-					LM_DBG("Received host len %d (search %d)\n", c->received_host.len, _host->len);
-					// Then check the length:
-					if (c->received_host.len == _host->len) {
-						LM_DBG("Received host %.*s (search %.*s)\n",
-							c->received_host.len, c->received_host.s,
-							_host->len, _host->s);
-
-						// Finally really compare the "received_host"
-						if (!memcmp(c->received_host.s, _host->s, _host->len)) {
-							*_c = c;
-							return 0;
+			if (!port_match && c->security_temp) {
+				switch (c->security_temp->type) {
+				case SECURITY_IPSEC: {
+					ipsec_t* ipsec = c->security_temp->data.ipsec;
+					if (ipsec) {
+						LM_DBG("temp security server port is %d\n", ipsec->port_us);
+						LM_DBG("temp security client port is %d\n", ipsec->port_uc);
+						if (ipsec->port_us == needle_uri.port_no) {
+							LM_DBG("temp security port mathes contact\n");
+							port_match = 1;
 						}
 					}
+					break;
+				}
+				case SECURITY_TLS:
+				case SECURITY_NONE:
+					LM_WARN("not implemented\n");
+					break;
 				}
-				c = c->next;
 			}
+		} else {
+			port_match = 1;
 		}
+
+		if (!port_match)
+			continue;
+
+		/* user parts must match (if not wildcarded) with either primary contact OR with any userpart in the implicit set (associated URIs).. */
+		if (((needle_uri.user.len == 1)
+				&& (memcmp(needle_uri.user.s, "*", 1) == 0))
+				|| ((needle_uri.user.len == c->contact_user.len)
+						&& (memcmp(needle_uri.user.s, c->contact_user.s,
+								needle_uri.user.len) == 0))) {
+			*_c = c;
+			return 0;
+		}
+
+		/* check impus user parts */
+		impu = c->head;
+		while (impu) {
+			if (parse_uri(impu->public_identity.s, impu->public_identity.len, &impu_uri) != 0) {
+				LM_ERR("failed to parse IMPU URI [%.*s]...continuing\n", impu->public_identity.len, impu->public_identity.s);
+				continue;
+			}
+			LM_DBG("comparing first %d chars of impu [%.*s] for contact userpart [%.*s]\n",
+					needle_uri.user.len,
+					impu->public_identity.len, impu->public_identity.s,
+					needle_uri.user.len, needle_uri.user.s);
+			if (needle_uri.user.len == impu_uri.user.len && (memcmp(needle_uri.user.s, impu_uri.user.s, impu_uri.user.len)==0)) {
+				*_c = c;
+				return 0;
+			}
+			impu = impu->next;
+		}
+
+		c = c->next;
 	}
 	return 1; /* Nothing found */
 }
 
+int get_pcontact_by_src(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c) {
+	char c_contact[256], *p;
+	str s_contact;
+	int ret;
+
+	memset(c_contact, 0, 256);
+	strncpy(c_contact, "sip:*@", 6);	//prepend *@ to host to wildcard on user search
+	p = c_contact + 6;
+	memcpy(p, _host->s, _host->len);
+	p = p + _host->len;
+	*p = ':';
+	p++;
+	sprintf(p, "%d", _port);
+	s_contact.s = c_contact;
+	s_contact.len = strlen(c_contact);
+
+	ret = get_pcontact(_d, &s_contact, _c);
+
+	return ret;
+}
 
 int assert_identity(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, str * _identity) {
 	int i;

+ 10 - 40
modules/ims_usrloc_pcscf/usrloc.c

@@ -49,6 +49,7 @@
 #include "udomain.h"
 #include "../../sr_module.h"
 #include "ul_mod.h"
+#include "../../parser/parse_uri.h"
 
 extern unsigned int init_flag;
 extern int hashing_type;
@@ -68,79 +69,48 @@ int bind_usrloc(usrloc_api_t* api) {
 	api->get_udomain = get_udomain;
 	api->lock_udomain = lock_udomain;
 	api->unlock_udomain = unlock_udomain;
-
 	api->insert_pcontact = insert_pcontact;
 	api->delete_pcontact = delete_pcontact;
 	api->get_pcontact = get_pcontact;
 	api->get_pcontact_by_src = get_pcontact_by_src;
 	api->assert_identity = assert_identity;
-
 	api->update_pcontact = update_pcontact;
 	api->update_rx_regsession = update_rx_regsession;
-
 	api->get_all_ucontacts = get_all_ucontacts;
-
 	api->register_ulcb = register_ulcb;
 
 	return 0;
 }
 
-/* function to convert contact aor to only have data after @ - ie strip user part */
-int aor_to_contact(str* aor, str* contact) {
-	char* p;
-	int ret = 0;	//success
-
-	contact->s = aor->s;
-	contact->len = aor->len;
-	if (memcmp(aor->s, "sip:", 4) == 0) {
-		contact->s = aor->s + 4;
-		contact->len-=4;
-	}
-
-	if ((p=memchr(contact->s, '@', contact->len))) {
-		contact->len -= (p - contact->s + 1);
-		contact->s = p+1;
-	}
-
-	if ((p=memchr(contact->s, ';', contact->len))) {
-		contact->len = p - contact->s;
-	}
-
-	if ((p=memchr(contact->s, '>', contact->len))) {
-		contact->len = p - contact->s;
-	}
-
-	return ret;
-}
-
 /* return the slot id for inserting contacts in the hash */
 unsigned int get_hash_slot(udomain_t* _d, str* _aor){
-	str contact;
+	struct sip_uri contact_uri;
 	unsigned int sl;
 
-	if ((hashing_type == 0) /*use full AOR for hash*/ || (aor_to_contact(_aor, &contact) != 0)) {
+	if ((hashing_type == 0) /*use full AOR for hash*/ || (parse_uri(_aor->s, _aor->len, &contact_uri) != 0)) {
 		if (hashing_type!=0) {
-			LM_DBG("Unable to get contact host:port from contact header... falling back to full AOR\n");
+			LM_DBG("Unable to get contact host:port from contact header [%.*s]... falling back to full AOR\n", _aor->len, _aor->s);
 		}
 		sl = core_hash(_aor, 0, _d->size);
 	} else {
-		sl = core_hash(&contact, 0, _d->size);
+		sl = core_hash(&contact_uri.host, 0, _d->size);
 	}
 
 	return sl;
 }
 
 unsigned int get_aor_hash(udomain_t* _d, str* _aor) {
-	str contact;
+	struct sip_uri contact_uri;
 	unsigned int aorhash;
 
-	if ((hashing_type == 0) || (aor_to_contact(_aor, &contact) != 0)) {
+	if ((hashing_type == 0) || (parse_uri(_aor->s, _aor->len, &contact_uri) != 0)) {
 		if (hashing_type !=0) {
-			LM_DBG("Unable to get contact host:port from contact header... falling back to full AOR\n");
+			LM_DBG("Unable to get contact host:port from contact header [%.*s]... falling back to full AOR\n", _aor->len, _aor->s);
 		}
 		aorhash = core_hash(_aor, 0, 0);
 	} else {
-		aorhash = core_hash(&contact, 0, 0);
+		LM_DBG("using host in lookup [%.*s]\n", contact_uri.host.len, contact_uri.host.s);
+		aorhash = core_hash(&contact_uri.host, 0, 0);
 	}
 	return aorhash;
 }

+ 7 - 6
modules/ims_usrloc_pcscf/usrloc.h

@@ -186,10 +186,13 @@ typedef struct pcontact {
 	struct hslot* slot; 					/*!< Collision slot in the hash table array we belong to */
 	str* domain; 							/*!< Pointer to domain we belong to (null terminated string) */
 	str aor;			 					/*!< Address of record */
-	// str received;           				/*!< IP+port+protocol we received the REGISTER from */
-	str received_host;
-	unsigned short received_port;
-	unsigned short received_proto; /*!< from transport */ ;
+	str contact_host;						/*!< host part of contact */
+	str contact_user;						/*!< user part of contact */
+	unsigned short contact_port;			/*!< port part of contact */
+	str callid;								/*!< Call-ID */
+	str received_host;						/*!< host part of src address where register came from */
+	unsigned short received_port;			/*!< port register was received from */
+	unsigned short received_proto; 			/*!< from transport */ ;
 	str path;               				/*!< Path header */
 	str rx_session_id;						/*!< Rx Session ID for registration Rx AF session - not used if not using diameter_rx */
 	enum pcontact_reg_states reg_state;		/*!< Reg state of contact */
@@ -249,6 +252,4 @@ typedef struct usrloc_api {
 /*! usrloc API export bind function */
 typedef int (*bind_usrloc_t)(usrloc_api_t* api);
 
-int aor_to_contact(str* aor, str* contact);
-
 #endif