[asterisk-commits] file: branch file/pimp_sip_registration r382786 - in /team/file/pimp_sip_regi...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Mar 11 09:12:54 CDT 2013


Author: file
Date: Mon Mar 11 09:12:51 2013
New Revision: 382786

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382786
Log:
Properly enforce the max_contacts setting and add a remove_existing setting which removes any existing contacts when a REGISTER comes in.

Modified:
    team/file/pimp_sip_registration/include/asterisk/res_sip.h
    team/file/pimp_sip_registration/res/res_sip/location.c
    team/file/pimp_sip_registration/res/res_sip_registrar.c

Modified: team/file/pimp_sip_registration/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_registration/include/asterisk/res_sip.h?view=diff&rev=382786&r1=382785&r2=382786
==============================================================================
--- team/file/pimp_sip_registration/include/asterisk/res_sip.h (original)
+++ team/file/pimp_sip_registration/include/asterisk/res_sip.h Mon Mar 11 09:12:51 2013
@@ -139,6 +139,8 @@
 	unsigned int default_expiration;
 	/*! Maximum number of external contacts, 0 to disable */
 	unsigned int max_contacts;
+	/*! Whether to remove any existing contacts not related to an incoming REGISTER when it comes in */
+	unsigned int remove_existing;
 	/*! Any statically configured contacts */
 	struct ao2_container *static_contacts;
 };

Modified: team/file/pimp_sip_registration/res/res_sip/location.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_registration/res/res_sip/location.c?view=diff&rev=382786&r1=382785&r2=382786
==============================================================================
--- team/file/pimp_sip_registration/res/res_sip/location.c (original)
+++ team/file/pimp_sip_registration/res/res_sip/location.c Mon Mar 11 09:12:51 2013
@@ -200,6 +200,7 @@
 	ast_sorcery_object_field_register(sorcery, "aor", "default_expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, default_expiration));
 	ast_sorcery_object_field_register(sorcery, "aor", "max_contacts", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, max_contacts));
 	ast_sorcery_object_field_register_custom(sorcery, "aor", "static", "", static_uri_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
 
 	return 0;
 }

Modified: team/file/pimp_sip_registration/res/res_sip_registrar.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_registration/res/res_sip_registrar.c?view=diff&rev=382786&r1=382785&r2=382786
==============================================================================
--- team/file/pimp_sip_registration/res/res_sip_registrar.c (original)
+++ team/file/pimp_sip_registration/res/res_sip_registrar.c Mon Mar 11 09:12:51 2013
@@ -30,68 +30,90 @@
 #include "asterisk/res_sip.h"
 #include "asterisk/module.h"
 
+/*! \brief Internal function which returns the expiration time for a contact */
+static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
+{
+	pjsip_expires_hdr *expires;
+	int expiration = aor->default_expiration;
+
+	if (contact->expires != -1) {
+		/* Expiration was provided with the contact itself */
+		expiration = contact->expires;
+	}
+	else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
+		/* Expiration was provided using the Expires header */
+		expiration = expires->ivalue;
+	}
+
+	/* If the value has explicitly been set to 0, do not enforce */
+	if (!expiration) {
+		return expiration;
+	}
+
+	/* Enforce the range that we will allow for expiration */
+	if (expiration < aor->minimum_expiration) {
+		expiration = aor->minimum_expiration;
+	}
+	else if (expiration > aor->maximum_expiration) {
+		expiration = aor->maximum_expiration;
+	}
+
+	return expiration;
+}
+
+/*! \brief Callback function for finding a contact */
+static int registrar_find_contact(void *obj, void *arg, int flags)
+{
+	struct ast_sip_contact *contact = obj;
+	const char *uri = arg;
+
+	return !strcmp(contact->uri, uri) ? CMP_MATCH | CMP_STOP : 0;
+}
+
 /*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
-static int registrar_validate_contacts(const pjsip_rx_data *rdata)
+static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
 {
 	pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
-	int count = 0;
 
 	while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
+		pjsip_sip_uri *uri;
+		char contact_uri[PJSIP_MAX_URL_SIZE];
+		int expiration;
+		RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);
+
 		if (contact->star) {
 			/* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
 			if ((contact->expires != 0) || previous) {
-				return count;
+				return -1;
 			}
 		} else if (previous && previous->star) {
 			/* If there is a previous contact and it is a '*' this is a deal breaker */
-			return count;
+			return -1;
 		}
 		previous = contact;
-		count++;
+
+		if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
+			continue;
+		}
+
+		uri = pjsip_uri_get_uri(contact->uri);
+		pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, uri, contact_uri, sizeof(contact_uri));
+		expiration = registrar_get_expiration(aor, contact, rdata);
+
+		/* Determine if this is an add, update, or delete for policy enforcement purposes */
+		if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, contact_uri))) {
+			if (expiration) {
+				(*added)++;
+			}
+		} else if (expiration) {
+			(*updated)++;
+		} else {
+			(*deleted)++;
+		}
 	}
 
 	/* The provided contacts are acceptable, huzzah! */
-	return count;
-}
-
-/*! \brief Internal function which returns the expiration time for a contact */
-static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
-{
-	pjsip_expires_hdr *expires;
-	int expiration = aor->default_expiration;
-
-	if (contact->expires != -1) {
-		/* Expiration was provided with the contact itself */
-		expiration = contact->expires;
-	}
-	else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
-		/* Expiration was provided using the Expires header */
-		expiration = expires->ivalue;
-	}
-
-	/* If the value has explicitly been set to 0, do not enforce */
-	if (!expiration) {
-		return expiration;
-	}
-
-	/* Enforce the range that we will allow for expiration */
-	if (expiration < aor->minimum_expiration) {
-		expiration = aor->minimum_expiration;
-	}
-	else if (expiration > aor->maximum_expiration) {
-		expiration = aor->maximum_expiration;
-	}
-
-	return expiration;
-}
-
-/*! \brief Callback function for finding a contact */
-static int registrar_find_contact(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	const char *uri = arg;
-
-	return !strcmp(contact->uri, uri) ? CMP_MATCH | CMP_STOP : 0;
+	return 0;
 }
 
 /*! \brief Callback function which prunes static contacts */
@@ -149,8 +171,8 @@
 	char user_name[64], domain_name[64];
 	char *configured_aors, *aor_name;
 	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
-	int count;
 	RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+	int added = 0, updated = 0, deleted = 0;
 	pjsip_contact_hdr *contact_hdr = NULL;
 	pjsip_tx_data *tdata;
 	pjsip_response_addr addr;
@@ -202,20 +224,20 @@
 		/* Registration is not permitted for this AOR */
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
 		return PJ_TRUE;
-	} else if ((count = registrar_validate_contacts(rdata)) == -1) {
+	}
+
+	/* Retrieve the current contacts, we'll need to know whether to update or not */
+	contacts = ast_sip_location_retrieve_aor_contacts(aor);
+
+	/* So we don't count static contacts against max_contacts we prune them out from the container */
+	ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
+
+	if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
 		/* The provided Contact headers do not conform to the specification */
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
 		return PJ_TRUE;
-	}
-
-	/* Retrieve the current contacts, we'll need to know whether to update or not */
-	contacts = ast_sip_location_retrieve_aor_contacts(aor);
-
-	/* So we don't count static contacts against max_contacts we prune them out from the container */
-	ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
-
-	/* Don't let this REGISTER exceed the number of contacts permitted for the AOR */
-	if ((ao2_container_count(contacts) + count) > aor->max_contacts) {
+	} else if ((MIN(0, added - deleted) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) {
+		/* Enforce the maximum number of contacts */
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
 		return PJ_TRUE;
 	}
@@ -239,7 +261,7 @@
 		uri = pjsip_uri_get_uri(contact_hdr->uri);
 		pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, uri, contact_uri, sizeof(contact_uri));
 
-		if (!(contact = ao2_callback(contacts, 0, registrar_find_contact, contact_uri))) {
+		if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, contact_uri))) {
 			/* If they are actually trying to delete a contact that does not exist... be forgiving */
 			if (!expiration) {
 				ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
@@ -264,6 +286,13 @@
 		}
 	}
 
+	/* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
+	 * do so
+	 */
+	if (aor->remove_existing) {
+		ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
+	}
+
 	/* Update the contacts as things will probably have changed */
 	ao2_cleanup(contacts);
 	contacts = ast_sip_location_retrieve_aor_contacts(aor);




More information about the asterisk-commits mailing list