diff --git a/modules/uac_registrant/doc/uac_registrant_admin.xml b/modules/uac_registrant/doc/uac_registrant_admin.xml
index 86fe926f2f2..eb39f2f84fc 100644
--- a/modules/uac_registrant/doc/uac_registrant_admin.xml
+++ b/modules/uac_registrant/doc/uac_registrant_admin.xml
@@ -181,6 +181,47 @@ modparam("uac_registrant", "enable_clustering", 1)
+
+
db_url (string)
diff --git a/modules/uac_registrant/registrant.c b/modules/uac_registrant/registrant.c
index 7c4fbe9b8a2..14f0d3dfe57 100644
--- a/modules/uac_registrant/registrant.c
+++ b/modules/uac_registrant/registrant.c
@@ -110,6 +110,8 @@ uac_auth_api_t uac_auth_api;
unsigned int default_expires = 3600;
unsigned int timer_interval = 100;
+enum uri_match_flags match_contact = URI_MATCH_NONE;
+str match_contact_str = str_init("all");
reg_table_t reg_htable = NULL;
unsigned int reg_hsize = 1;
@@ -140,6 +142,7 @@ static const param_export_t params[]= {
{"default_expires", INT_PARAM, &default_expires},
{"timer_interval", INT_PARAM, &timer_interval},
{"enable_clustering", INT_PARAM, &enable_clustering},
+ {"match_contact", STR_PARAM, &match_contact_str.s},
{"db_url", STR_PARAM, &db_url.s},
{"table_name", STR_PARAM, ®_table_name.s},
{"registrar_column", STR_PARAM, ®istrar_column.s},
@@ -258,6 +261,11 @@ static int mod_init(void)
return -1;
}
+ if(match_contact_str.s) {
+ match_contact = parse_uri_options(&match_contact_str);
+ }
+ LM_DBG("Match contact value: [%d]\n", (unsigned)match_contact);
+
reg_table_name.len = strlen(reg_table_name.s);
registrar_column.len = strlen(registrar_column.s);
proxy_column.len = strlen(proxy_column.s);
@@ -481,8 +489,7 @@ int run_reg_tm_cback(void *e_data, void *data, void *r_data)
contact = ((contact_body_t*)msg->contact->parsed)->contacts;
while (contact) {
/* Check for binding */
- if (contact->uri.len==rec->contact_uri.len &&
- strncmp(contact->uri.s,rec->contact_uri.s,contact->uri.len)==0){
+ if (compare_uris_parts(&contact->uri, &rec->contact_uri, match_contact) == 0) {
if (contact->expires && contact->expires->body.len) {
if (str2int(&contact->expires->body, &exp)<0) {
LM_ERR("Unable to extract expires from [%.*s]"
diff --git a/parser/parse_uri.c b/parser/parse_uri.c
index 937ea70cec1..26da08d199b 100644
--- a/parser/parse_uri.c
+++ b/parser/parse_uri.c
@@ -53,6 +53,52 @@ static const str uri_type_names[7] = {
str_init("urn:nena:service")
};
+struct uri_match_part uri_match_parts[] = {
+ { str_const_init("type"), URI_MATCH_TYPE },
+ { str_const_init("user"), URI_MATCH_USER },
+ { str_const_init("password"), URI_MATCH_PASSWD },
+ { str_const_init("host"), URI_MATCH_HOST },
+ { str_const_init("port"), URI_MATCH_PORT },
+ { str_const_init("transport"), URI_MATCH_TRANSPORT },
+ { str_const_init("ttl"), URI_MATCH_TTL },
+ { str_const_init("userparam"), URI_MATCH_USERPARAM },
+ { str_const_init("maddr"), URI_MATCH_MADDR },
+ { str_const_init("method"), URI_MATCH_METHOD },
+ { str_const_init("lr"), URI_MATCH_LR },
+ { str_const_init("r2"), URI_MATCH_R2 },
+ { str_const_init("all"), URI_MATCH_ALL },
+};
+
+enum uri_match_flags parse_uri_options(str *options_str)
+{
+ enum uri_match_flags flags = URI_MATCH_NONE;
+ char *p, *e;
+ str *s = options_str;
+ int i;
+
+ if (options_str == NULL || options_str->s == NULL || options_str->len == 0) {
+ return flags;
+ }
+ e = s->s + strlen(s->s);
+ while (s->s < e) {
+ p = strchr(s->s, ';');
+ s->len = (p ? (p - s->s) : strlen(s->s));
+ str_trim_spaces_lr(*s);
+ /* check if this is among the possible options */
+ for(i = 0; i< (sizeof(uri_match_parts)/sizeof(uri_match_parts[0])); i++) {
+ if (s->len == uri_match_parts[i].name.len &&
+ strncasecmp(s->s, uri_match_parts[i].name.s,
+ uri_match_parts[i].name.len) == 0)
+ flags |= uri_match_parts[i].flag;
+ }
+ if (p)
+ s->s = p + 1;
+ else
+ break;
+ }
+ return flags;
+}
+
char* uri_type2str(const uri_type type, char *result)
{
if (type == ERROR_URI_T)
@@ -1855,3 +1901,89 @@ int compare_uris(str *raw_uri_a,struct sip_uri* parsed_uri_a,
compare_uri_val(headers,strncasecmp);
return 0;
}
+
+/* Compare 2 SIP URIs by parts according to opts
+ *
+ * Return value : 0 if URIs match
+ * 1 if URIs don't match
+ * -1 if errors have occurred
+ */
+int compare_uris_parts(str *raw_uri_a, str *raw_uri_b, enum uri_match_flags opts)
+{
+ #define UNESCAPED_BUF_LEN 1024
+ char unescaped_a[UNESCAPED_BUF_LEN], unescaped_b[UNESCAPED_BUF_LEN];
+
+ str unescaped_userA={unescaped_a, UNESCAPED_BUF_LEN};
+ str unescaped_userB={unescaped_b, UNESCAPED_BUF_LEN};
+
+ struct sip_uri first;
+ struct sip_uri second;
+
+ if ( (!raw_uri_a) || (!raw_uri_b) )
+ {
+ LM_ERR("Provide either a raw form of a SIP URI\n");
+ return -1;
+ }
+
+ /* maybe we're lucky and straight-forward comparison succeeds */
+ if ((opts & URI_MATCH_ALL) && (raw_uri_a->len == raw_uri_b->len))
+ if (strncasecmp(raw_uri_a->s,raw_uri_b->s,raw_uri_a->len) == 0)
+ {
+ LM_DBG("straight-forward URI match\n");
+ return 0;
+ }
+
+ if (parse_uri(raw_uri_a->s,raw_uri_a->len,&first) < 0)
+ {
+ LM_ERR("Failed to parse first URI\n");
+ return -1;
+ }
+
+ if (parse_uri(raw_uri_b->s,raw_uri_b->len,&second) < 0)
+ {
+ LM_ERR("Failed to parse second URI\n");
+ return -1;
+ }
+
+ if (opts & URI_MATCH_TYPE)
+ if (first.type != second.type)
+ {
+ LM_DBG("Different uri types\n");
+ return 1;
+ }
+
+ if (unescape_user(&first.user, &unescaped_userA) < 0 ||
+ unescape_user(&second.user, &unescaped_userB) < 0) {
+ LM_ERR("Failed to unescape user!\n");
+ return -1;
+ }
+
+ first.user = unescaped_userA;
+ second.user = unescaped_userB;
+
+ if (opts & URI_MATCH_USER)
+ compare_uri_val(user,strncmp);
+ if (opts & URI_MATCH_PASSWD)
+ compare_uri_val(passwd,strncmp);
+ if (opts & URI_MATCH_HOST)
+ compare_uri_val(host,strncasecmp);
+ if (opts & URI_MATCH_PORT)
+ compare_uri_val(port,strncmp);
+
+ if (opts & URI_MATCH_TRANSPORT)
+ compare_uri_val(transport_val,strncasecmp);
+ if (opts & URI_MATCH_TTL)
+ compare_uri_val(ttl_val,strncasecmp);
+ if (opts & URI_MATCH_USERPARAM)
+ compare_uri_val(user_param_val,strncasecmp);
+ if (opts & URI_MATCH_MADDR)
+ compare_uri_val(maddr_val,strncasecmp);
+ if (opts & URI_MATCH_METHOD)
+ compare_uri_val(method_val,strncasecmp);
+ if (opts & URI_MATCH_LR)
+ compare_uri_val(lr_val,strncasecmp);
+ if (opts & URI_MATCH_R2)
+ compare_uri_val(r2_val,strncasecmp);
+
+ return 0;
+}
diff --git a/parser/parse_uri.h b/parser/parse_uri.h
index f9c700e57d2..0fa88bdceaa 100644
--- a/parser/parse_uri.h
+++ b/parser/parse_uri.h
@@ -42,6 +42,35 @@
#define URN_NENA_SERVICE_STR ":nena:service:"
#define URN_NENA_SERVICE_STR_LEN (sizeof(URN_NENA_SERVICE_STR) - 1)
+/* The possible values of the URI parts used for compare URIs
+ */
+enum uri_match_flags {
+ URI_MATCH_NONE = 0,
+ URI_MATCH_TYPE = (1<<0),
+ URI_MATCH_USER = (1<<1),
+ URI_MATCH_PASSWD = (1<<2),
+ URI_MATCH_HOST = (1<<3),
+ URI_MATCH_PORT = (1<<4),
+ URI_MATCH_TRANSPORT = (1<<5),
+ URI_MATCH_TTL = (1<<6),
+ URI_MATCH_USERPARAM = (1<<7),
+ URI_MATCH_MADDR = (1<<8),
+ URI_MATCH_METHOD = (1<<9),
+ URI_MATCH_LR = (1<<10),
+ URI_MATCH_R2 = (1<<11),
+ URI_MATCH_ALL = (URI_MATCH_TYPE | URI_MATCH_USER | URI_MATCH_PASSWD | URI_MATCH_HOST | URI_MATCH_PORT | URI_MATCH_TRANSPORT |
+ URI_MATCH_TTL | URI_MATCH_USERPARAM | URI_MATCH_MADDR | URI_MATCH_METHOD | URI_MATCH_LR | URI_MATCH_R2),
+};
+struct uri_match_part {
+ str_const name;
+ enum uri_match_flags flag;
+};
+
+/* options_str= options to match Contact URI for uac_registrant
+ * returns: binary flags to match URI
+ */
+enum uri_match_flags parse_uri_options(str *options_str);
+
/* buf= pointer to beginning of uri (sip:x@foo.bar:5060;a=b?h=i)
* len= len of uri
* returns: fills uri & returns <0 on error or 0 if ok
@@ -69,6 +98,7 @@ int parse_sip_msg_uri(struct sip_msg* msg);
int parse_orig_ruri(struct sip_msg* msg);
int compare_uris(str *raw_uri_a,struct sip_uri* parsed_uri_a,
str *raw_uri_b,struct sip_uri *parsed_uri_b);
+int compare_uris_parts(str *raw_uri_a, str *raw_uri_b, enum uri_match_flags opts);
static inline int get_uri_param_val(const struct sip_uri *uri,
const str *param, str *val);
static inline int get_uri_param_idx(const str *param,