[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