[asterisk-commits] file: branch group/pimp_my_sip r383171 - in /team/group/pimp_my_sip: channels...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Mar 15 08:09:39 CDT 2013


Author: file
Date: Fri Mar 15 08:09:35 2013
New Revision: 383171

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383171
Log:
Add location support.

This commit adds the following:
1. Definitions for location related stuff (AORs / contacts)
2. An API to interact with AORs / contacts (retrieving, updating, deleting, adding)
3. Configuration for AORs / contacts
4. A dialplan function which produces a dial string which dials all contacts on an AOR
5. A new res_sip_endpoint_identifier_ip which is configurable and can match groups of addresses or a single address

Review https://reviewboard.asterisk.org/r/2379/

Added:
    team/group/pimp_my_sip/res/res_sip/location.c   (with props)
Modified:
    team/group/pimp_my_sip/channels/chan_gulp.c
    team/group/pimp_my_sip/include/asterisk/res_sip.h
    team/group/pimp_my_sip/include/asterisk/res_sip_session.h
    team/group/pimp_my_sip/res/res_sip.c
    team/group/pimp_my_sip/res/res_sip.exports.in
    team/group/pimp_my_sip/res/res_sip/sip_configuration.c
    team/group/pimp_my_sip/res/res_sip_endpoint_identifier_ip.c
    team/group/pimp_my_sip/res/res_sip_sdp_audio.c
    team/group/pimp_my_sip/res/res_sip_session.c

Modified: team/group/pimp_my_sip/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/channels/chan_gulp.c?view=diff&rev=383171&r1=383170&r2=383171
==============================================================================
--- team/group/pimp_my_sip/channels/chan_gulp.c (original)
+++ team/group/pimp_my_sip/channels/chan_gulp.c Fri Mar 15 08:09:35 2013
@@ -56,6 +56,28 @@
 
 #include "asterisk/res_sip.h"
 #include "asterisk/res_sip_session.h"
+
+/*** DOCUMENTATION
+	<function name="GULP_DIAL_CONTACTS" language="en_US">
+		<synopsis>
+			Return a dial string for dialing all contacts on an AOR.
+		</synopsis>
+		<syntax>
+			<parameter name="endpoint" required="true">
+				<para>Name of the endpoint</para>
+			</parameter>
+			<parameter name="aor" required="false">
+				<para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
+			</parameter>
+			<parameter name="request_user" required="false">
+				<para>Optional request user to use in the request URI</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
+		</description>
+	</function>
+ ***/
 
 static const char desc[] = "Gulp SIP Channel";
 static const char channel_type[] = "Gulp";
@@ -105,6 +127,84 @@
 	.session_end = gulp_session_end,
 	.incoming_request = gulp_incoming_request,
 	.incoming_response = gulp_incoming_response,
+};
+
+/*! \brief Dialplan function for constructing a dial string for calling all contacts */
+static int gulp_dial_contacts(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(endpoint_name);
+		AST_APP_ARG(aor_name);
+		AST_APP_ARG(request_user);
+	);
+	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+	const char *aor_name;
+	char *rest;
+	RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
+
+	AST_STANDARD_APP_ARGS(args, data);
+
+	if (ast_strlen_zero(args.endpoint_name)) {
+		ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
+		return -1;
+	} else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
+		ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
+		return -1;
+	}
+
+	aor_name = S_OR(args.aor_name, endpoint->aors);
+
+	if (ast_strlen_zero(aor_name)) {
+		ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
+		return -1;
+	} else if (!(dial = ast_str_create(len))) {
+		ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
+		return -1;
+	} else if (!(rest = ast_strdupa(aor_name))) {
+		ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
+		return -1;
+	}
+
+	while ((aor_name = strsep(&rest, ","))) {
+		RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
+		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+		struct ao2_iterator it_contacts;
+		struct ast_sip_contact *contact;
+
+		if (!aor) {
+			/* If the AOR provided is not found skip it, there may be more */
+			continue;
+		} else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
+			/* No contacts are available, skip it as well */
+			continue;
+		} else if (!ao2_container_count(contacts)) {
+			/* We were given a container but no contacts are in it... */
+			continue;
+		}
+
+		it_contacts = ao2_iterator_init(contacts, 0);
+		for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
+			ast_str_append(&dial, -1, "Gulp/");
+
+			if (!ast_strlen_zero(args.request_user)) {
+				ast_str_append(&dial, -1, "%s@", args.request_user);
+			}
+			ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
+		}
+		ao2_iterator_destroy(&it_contacts);
+	}
+
+	/* Trim the '&' at the end off */
+	ast_str_truncate(dial, ast_str_strlen(dial) - 1);
+
+	ast_copy_string(buf, ast_str_buffer(dial), len);
+
+	return 0;
+}
+
+static struct ast_custom_function gulp_dial_contacts_function = {
+	.name = "GULP_DIAL_CONTACTS",
+	.read = gulp_dial_contacts,
 };
 
 /*! \brief Function called by RTP engine to get local audio RTP peer */
@@ -647,25 +747,46 @@
 struct request_data {
 	struct ast_sip_session *session;
 	const char *dest;
+	int cause;
 };
 
 static int request(void *obj)
 {
 	struct request_data *req_data = obj;
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sip_endpoint_alloc("constant"), ao2_cleanup);
+	char *tmp = ast_strdupa(req_data->dest), *endpoint_name = NULL, *request_user = NULL;
+	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
 	struct ast_sip_session *session = NULL;
-
-	if (!endpoint) {
-		return -1;
-	}
-
-	/* TODO: This needs to actually grab a proper endpoint and such */
-	ast_string_field_set(endpoint, context, "default");
-	ast_parse_allow_disallow(&endpoint->prefs, endpoint->codecs, "ulaw", 1);
-	endpoint->min_se = 90;
-	endpoint->sess_expires = 1800;
-
-	if (!(session = ast_sip_session_create_outgoing(endpoint, req_data->dest))) {
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(endpoint);
+		AST_APP_ARG(aor);
+	);
+
+	if (ast_strlen_zero(tmp)) {
+		ast_log(LOG_ERROR, "Unable to create Gulp channel with empty destination\n");
+		req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
+		return -1;
+	}
+
+	AST_NONSTANDARD_APP_ARGS(args, tmp, '/');
+
+	/* If a request user has been specified extract it from the endpoint name portion */
+	if ((endpoint_name = strchr(args.endpoint, '@'))) {
+		request_user = args.endpoint;
+		*endpoint_name++ = '\0';
+	} else {
+		endpoint_name = args.endpoint;
+	}
+
+	if (ast_strlen_zero(endpoint_name)) {
+		ast_log(LOG_ERROR, "Unable to create Gulp channel with empty endpoint name\n");
+		req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
+	} else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
+		ast_log(LOG_ERROR, "Unable to create Gulp channel - endpoint '%s' was not found\n", endpoint_name);
+		req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
+		return -1;
+	}
+
+	if (!(session = ast_sip_session_create_outgoing(endpoint, args.aor, request_user))) {
 		return -1;
 	}
 
@@ -682,6 +803,7 @@
 	req_data.dest = data;
 
 	if (ast_sip_push_task_synchronous(NULL, request, &req_data)) {
+		*cause = req_data.cause;
 		return NULL;
 	}
 
@@ -857,6 +979,10 @@
 {
 	struct pjsip_status_line status = rdata->msg_info.msg->line.status;
 
+	if (!session->channel) {
+		return;
+	}
+
 	switch (status.code) {
 	case 180:
 		ast_queue_control(session->channel, AST_CONTROL_RINGING);
@@ -900,6 +1026,11 @@
 		goto end;
 	}
 
+	if (ast_custom_function_register(&gulp_dial_contacts_function)) {
+		ast_log(LOG_ERROR, "Unable to register GULP_DIAL_CONTACTS dialplan function\n");
+		goto end;
+	}
+
 	if (ast_sip_session_register_supplement(&gulp_supplement)) {
 		ast_log(LOG_ERROR, "Unable to register Gulp supplement\n");
 		goto end;
@@ -908,6 +1039,8 @@
 	return 0;
 
 end:
+	ast_custom_function_unregister(&gulp_dial_contacts_function);
+	ast_channel_unregister(&gulp_tech);
 	ast_rtp_glue_unregister(&gulp_rtp_glue);
 
 	return AST_MODULE_LOAD_FAILURE;
@@ -923,6 +1056,7 @@
 static int unload_module(void)
 {
 	ast_sip_session_unregister_supplement(&gulp_supplement);
+	ast_custom_function_unregister(&gulp_dial_contacts_function);
 	ast_channel_unregister(&gulp_tech);
 	ast_rtp_glue_unregister(&gulp_rtp_glue);
 

Modified: team/group/pimp_my_sip/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/include/asterisk/res_sip.h?view=diff&rev=383171&r1=383170&r2=383171
==============================================================================
--- team/group/pimp_my_sip/include/asterisk/res_sip.h (original)
+++ team/group/pimp_my_sip/include/asterisk/res_sip.h Fri Mar 15 08:09:35 2013
@@ -39,6 +39,7 @@
 struct pjsip_transport;
 struct pjsip_tpfactory;
 struct pjsip_tls_setting;
+struct pjsip_tpselector;
 
 /*!
  * \brief Structure for SIP transport information
@@ -110,31 +111,28 @@
  * \brief Contact associated with an address of record
  */
 struct ast_sip_contact {
+	/*! Sorcery object details, the id is the aor name plus a random string */
+	SORCERY_OBJECT(details);
 	AST_DECLARE_STRING_FIELDS(
-		/* XXX This may work better as an object instead of a string */
 		/*! Full URI of the contact */
 		AST_STRING_FIELD(uri);
 	);
-	/*! Absolute time that this contact expires */
-	time_t expiration_time;
-	/*! Next list item */
-	AST_LIST_ENTRY(ast_sip_contact) next;
+	/*! Absolute time that this contact is no longer valid after */
+	struct timeval expiration_time;
 };
 
 /*!
  * \brief A SIP address of record
  */
 struct ast_sip_aor {
-	AST_DECLARE_STRING_FIELDS(
-		/*! Name of the address of record */
-		AST_STRING_FIELD(name);
-	);
+	/*! Sorcery object details, the id is the AOR name */
+	SORCERY_OBJECT(details);
 	/*! Default contact expiration if one is not provided in the contact */
-	int expiration;
-	/*! Domain for the AOR */
-	struct ast_sip_domain *domain;
-	/*! Contacts bound to this AOR */
-	AST_LIST_HEAD_NOLOCK(, ast_sip_contact) contacts;
+	unsigned int default_expiration;
+	/*! Maximum number of external contacts, 0 to disable */
+	unsigned int max_contacts;
+	/*! Any permanent configured contacts */
+	struct ao2_container *permanent_contacts;
 };
 
 /*!
@@ -223,6 +221,10 @@
 		AST_STRING_FIELD(context);
 		/*! Name of an explicit transport to use */
 		AST_STRING_FIELD(transport);
+		/*! Outbound proxy to use */
+		AST_STRING_FIELD(outbound_proxy);
+		/*! Explicit AORs to dial if none are specified */
+		AST_STRING_FIELD(aors);
                 /*! Musiconhold class to suggest that the other side use when placing on hold */
                 AST_STRING_FIELD(mohsuggest);
 	);
@@ -263,31 +265,6 @@
 };
 
 /*!
- * \brief Given an endpoint, get its IP address
- *
- * \param endpoint The endpoint whose location is desired
- * \param[out] location_buf The IP address and port of the endpoint, as a string
- * \param size The size of the location buffer
- * \return void
- *
- * XXX The usefulness of retrieving an IP address is limited. It's more
- * useful to get a hostname or FQDN so that the location can be resolved.
- */
-void ast_sip_endpoint_get_location(const struct ast_sip_endpoint *endpoint, char *location_buf, size_t size);
-
-/*!
- * \brief Given an IP address, get the SIP endpoint that is located there.
- *
- * The returned endpoint will need to have its reference count decremented with ao2_ref()
- * once the caller has finished using it.
- *
- * \param addr The IP address
- * \retval NULL Could not find an endpoint with this IP address
- * \retval non-NULL The endpoint with this IP address
- */
-struct ast_sip_endpoint *ast_sip_get_endpoint_from_location(const char *addr);
- 
-/*!
  * \brief Possible returns from ast_sip_check_authentication
  */
 enum ast_sip_check_auth_result {
@@ -462,6 +439,78 @@
 int ast_sip_initialize_sorcery_transport(struct ast_sorcery *sorcery);
 
 /*!
+ * \brief Initialize location support on a sorcery instance
+ *
+ * \param sorcery The sorcery instance
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery);
+
+/*!
+ * \brief Retrieve a named AOR
+ *
+ * \param aor_name Name of the AOR
+ *
+ * \retval NULL if not found
+ * \retval non-NULL if found
+ */
+struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name);
+
+/*!
+ * \brief Retrieve all contacts currently available for an AOR
+ *
+ * \param aor Pointer to the AOR
+ *
+ * \param NULL if no contacts available
+ * \param non-NULL if contacts available
+ */
+struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor);
+
+/*!
+ * \brief Retrieve a named contact
+ *
+ * \param contact_name Name of the contact
+ *
+ * \retval NULL if not found
+ * \retval non-NULL if found
+ */
+struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name);
+
+/*!
+ * \brief Add a new contact to an AOR
+ *
+ * \param aor Pointer to the AOR
+ * \param uri Full contact URI
+ * \param expiration_time Optional expiration time of the contact
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time);
+
+/*!
+ * \brief Update a contact
+ *
+ * \param contact New contact object with details
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_location_update_contact(struct ast_sip_contact *contact);
+
+/*!
+* \brief Delete a contact
+*
+* \param contact Contact object to delete
+*
+* \retval -1 failure
+* \retval 0 success
+*/
+int ast_sip_location_delete_contact(struct ast_sip_contact *contact);
+
+/*!
  * \brief Initialize authentication support on a sorcery instance
  *
  * \param sorcery The sorcery instance
@@ -620,6 +669,18 @@
 };
 
 /*!
+ * \brief General purpose method for creating a dialog with an endpoint
+ *
+ * \param endpoint A pointer to the endpoint
+ * \param aor_name Optional name of the AOR to target, may even be an explicit SIP URI
+ * \param request_user Optional user to place into the target URI
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ */
+ pjsip_dialog *ast_sip_create_dialog(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user);
+
+/*!
  * \brief General purpose method for sending a SIP request
  *
  * Its typical use would be to send one-off messages such as an out of dialog

Modified: team/group/pimp_my_sip/include/asterisk/res_sip_session.h
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/include/asterisk/res_sip_session.h?view=diff&rev=383171&r1=383170&r2=383171
==============================================================================
--- team/group/pimp_my_sip/include/asterisk/res_sip_session.h (original)
+++ team/group/pimp_my_sip/include/asterisk/res_sip_session.h Fri Mar 15 08:09:35 2013
@@ -231,9 +231,10 @@
  * this reference when the session is destroyed.
  *
  * \param endpoint The endpoint that this session uses for settings
- * \param uri The URI to call
- */
-struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, const char *uri);
+ * \param location Optional name of the location to call, be it named location or explicit URI
+ * \param request_user Optional request user to place in the request URI if permitted
+ */
+struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, const char *location, const char *request_user);
 
 /*!
  * \brief Register an SDP handler

Modified: team/group/pimp_my_sip/res/res_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip.c?view=diff&rev=383171&r1=383170&r2=383171
==============================================================================
--- team/group/pimp_my_sip/res/res_sip.c (original)
+++ team/group/pimp_my_sip/res/res_sip.c Fri Mar 15 08:09:35 2013
@@ -192,6 +192,153 @@
 	return ast_pjsip_endpoint;
 }
 
+static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, const pj_str_t *target, pjsip_tpselector *selector)
+{
+	pj_str_t tmp, local_addr;
+	pjsip_uri *uri;
+	pjsip_sip_uri *sip_uri;
+	pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
+	int local_port;
+
+	/* Parse the provided target URI so we can determine what transport it will end up using */
+	pj_strdup_with_null(pool, &tmp, target);
+
+	if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
+	    (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
+		return -1;
+	}
+
+	sip_uri = pjsip_uri_get_uri(uri);
+
+	/* Determine the transport type to use */
+	if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
+		type = PJSIP_TRANSPORT_TLS;
+	} else if (!sip_uri->transport_param.slen) {
+		type = PJSIP_TRANSPORT_UDP;
+	} else {
+		type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
+	}
+
+	if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
+		return -1;
+	}
+
+	/* If the host is IPv6 turn the transport into an IPv6 version */
+	if (pj_strchr(&sip_uri->host, ':')) {
+		type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
+	}
+
+	/* Get the local bound address for the transport that will be used when communicating with the provided URI */
+	if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
+							      &local_addr, &local_port) != PJ_SUCCESS) {
+		return -1;
+	}
+
+	/* If IPv6 was not specified in the host but is in the transport, set the proper type */
+	if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
+		type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
+	}
+
+	from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
+	from->slen = pj_ansi_snprintf(from->ptr, PJSIP_MAX_URL_SIZE,
+				      "<%s:%s@%s%.*s%s:%d%s%s>",
+				      (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
+				      user,
+				      (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
+				      (int)local_addr.slen,
+				      local_addr.ptr,
+				      (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
+				      local_port,
+				      (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
+				      (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
+
+	return 0;
+}
+
+pjsip_dialog *ast_sip_create_dialog(const struct ast_sip_endpoint *endpoint, const char *uri, const char *request_user)
+{
+	RAII_VAR(struct ast_uuid *, uuid, ast_uuid_generate(), ast_free_ptr);
+	char uuid_str[AST_UUID_STR_LEN];
+	static pj_str_t local_uri = { "sip:temp at temp", 13 };
+	pj_str_t remote_uri;
+	pjsip_dialog *dlg = NULL;
+	const char *transport_name = endpoint->transport, *outbound_proxy = endpoint->outbound_proxy;
+	pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
+	static const pj_str_t HCONTACT = { "Contact", 7 };
+
+	if (!uuid) {
+		return NULL;
+	}
+
+	pj_cstr(&remote_uri, uri);
+
+	if (pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, NULL, &remote_uri, NULL, &dlg) != PJ_SUCCESS) {
+		return NULL;
+	}
+
+	if (!ast_strlen_zero(transport_name)) {
+		RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_name), ao2_cleanup);
+
+		if (!transport || !transport->state) {
+			pjsip_dlg_terminate(dlg);
+			return NULL;
+		}
+
+		if (transport->type == AST_SIP_TRANSPORT_UDP) {
+			selector.type = PJSIP_TPSELECTOR_TRANSPORT;
+			selector.u.transport = transport->state->transport;
+		} else if (transport->type == AST_SIP_TRANSPORT_TCP || transport->type == AST_SIP_TRANSPORT_TLS) {
+			selector.type = PJSIP_TPSELECTOR_LISTENER;
+			selector.u.listener = transport->state->factory;
+		} else {
+			pjsip_dlg_terminate(dlg);
+			return NULL;
+		}
+	}
+
+	if (sip_dialog_create_from(dlg->pool, &local_uri, ast_uuid_to_str(uuid, uuid_str, AST_UUID_STR_LEN), &remote_uri, &selector)) {
+		pjsip_dlg_terminate(dlg);
+		return NULL;
+	}
+
+	/* Update the dialog with the new local URI, we do it afterwards so we can use the dialog pool for construction */
+	pj_strdup_with_null(dlg->pool, &dlg->local.info_str, &local_uri);
+	dlg->local.info->uri = pjsip_parse_uri(dlg->pool, dlg->local.info_str.ptr, dlg->local.info_str.slen, 0);
+	dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, local_uri.ptr, local_uri.slen, NULL);
+
+	/* If a request user has been specified and we are permitted to change it, do so */
+	if (!ast_strlen_zero(request_user) && (PJSIP_URI_SCHEME_IS_SIP(dlg->target) || PJSIP_URI_SCHEME_IS_SIPS(dlg->target))) {
+		pjsip_sip_uri *target = pjsip_uri_get_uri(dlg->target);
+		pj_strdup2(dlg->pool, &target->user, request_user);
+	}
+
+	/* We have to temporarily bump up the sess_count here so the dialog is not prematurely destroyed */
+	dlg->sess_count++;
+
+	pjsip_dlg_set_transport(dlg, &selector);
+
+	if (!ast_strlen_zero(outbound_proxy)) {
+		pjsip_route_hdr route_set, *route;
+		static const pj_str_t ROUTE_HNAME = { "Route", 5 };
+		pj_str_t tmp;
+
+		pj_list_init(&route_set);
+
+		pj_strdup2_with_null(dlg->pool, &tmp, outbound_proxy);
+		if (!(route = pjsip_parse_hdr(dlg->pool, &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
+			pjsip_dlg_terminate(dlg);
+			return NULL;
+		}
+		pj_list_push_back(&route_set, route);
+
+		pjsip_dlg_set_route_set(dlg, &route_set);
+	}
+
+	dlg->sess_count--;
+
+	return dlg;
+}
+
 /* PJSIP doesn't know about the INFO method, so we have to define it ourselves */
 const pjsip_method pjsip_info_method = {PJSIP_OTHER_METHOD, {"INFO", 4} };
 

Modified: team/group/pimp_my_sip/res/res_sip.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip.exports.in?view=diff&rev=383171&r1=383170&r2=383171
==============================================================================
--- team/group/pimp_my_sip/res/res_sip.exports.in (original)
+++ team/group/pimp_my_sip/res/res_sip.exports.in Fri Mar 15 08:09:35 2013
@@ -24,8 +24,13 @@
 		LINKER_SYMBOL_PREFIXast_sip_endpoint_alloc;
 		LINKER_SYMBOL_PREFIXast_copy_pj_str;
 		LINKER_SYMBOL_PREFIXast_sip_get_sorcery;
-		LINKER_SYMBOL_PREFIXast_sip_get_endpoint_from_location;
-		LINKER_SYMBOL_PREFIXast_sip_endpoint_get_location;
+		LINKER_SYMBOL_PREFIXast_sip_create_dialog;
+		LINKER_SYMBOL_PREFIXast_sip_location_retrieve_aor;
+		LINKER_SYMBOL_PREFIXast_sip_location_retrieve_aor_contacts;
+		LINKER_SYMBOL_PREFIXast_sip_location_retrieve_contact;
+		LINKER_SYMBOL_PREFIXast_sip_location_add_contact;
+		LINKER_SYMBOL_PREFIXast_sip_location_update_contact;
+		LINKER_SYMBOL_PREFIXast_sip_location_delete_contact;
 		LINKER_SYMBOL_PREFIXast_pjsip_rdata_get_endpoint;
 		LINKER_SYMBOL_PREFIXast_sip_thread_is_servant;
 		LINKER_SYMBOL_PREFIXast_sip_dialog_set_serializer;

Added: team/group/pimp_my_sip/res/res_sip/location.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip/location.c?view=auto&rev=383171
==============================================================================
--- team/group/pimp_my_sip/res/res_sip/location.c (added)
+++ team/group/pimp_my_sip/res/res_sip/location.c Fri Mar 15 08:09:35 2013
@@ -1,0 +1,205 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+#undef bzero
+#define bzero bzero
+#include "pjsip.h"
+#include "pjlib.h"
+
+#include "asterisk/res_sip.h"
+#include "asterisk/logger.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/sorcery.h"
+
+/*! \brief Destructor for AOR */
+static void aor_destroy(void *obj)
+{
+	struct ast_sip_aor *aor = obj;
+
+	ao2_cleanup(aor->permanent_contacts);
+}
+
+/*! \brief Allocator for AOR */
+static void *aor_alloc(const char *name)
+{
+	return ao2_alloc_options(sizeof(struct ast_sip_aor), aor_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+}
+
+/*! \brief Destructor for contact */
+static void contact_destroy(void *obj)
+{
+	struct ast_sip_contact *contact = obj;
+
+	ast_string_field_free_memory(contact);
+}
+
+/*! \brief Allocator for contact */
+static void *contact_alloc(const char *name)
+{
+	struct ast_sip_contact *contact = ao2_alloc_options(sizeof(*contact), contact_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+
+	if (!contact) {
+		return NULL;
+	}
+
+	if (ast_string_field_init(contact, 256)) {
+		ao2_cleanup(contact);
+		return NULL;
+	}
+
+	return contact;
+}
+
+struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name)
+{
+	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
+}
+
+/*! \brief Internal callback function which deletes and unlinks any expired contacts */
+static int contact_expire(void *obj, void *arg, int flags)
+{
+	struct ast_sip_contact *contact = obj;
+
+	/* If the contact has not yet expired it is valid */
+	if (ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) > 0) {
+		return 0;
+	}
+
+	ast_sip_location_delete_contact(contact);
+
+	return CMP_MATCH;
+}
+
+/*! \brief Internal callback function which links static contacts into another container */
+static int contact_link_static(void *obj, void *arg, int flags)
+{
+	struct ao2_container *dest = arg;
+
+	ao2_link_flags(dest, obj, OBJ_NOLOCK);
+	return 0;
+}
+
+struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
+{
+	/* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */
+	char regex[strlen(ast_sorcery_object_get_id(aor)) + 4];
+	struct ao2_container *contacts;
+
+	snprintf(regex, sizeof(regex), "^%s;@", ast_sorcery_object_get_id(aor));
+
+	if (!(contacts = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "contact", regex))) {
+		return NULL;
+	}
+
+	/* Prune any expired contacts and delete them, we do this first because static contacts can never expire */
+	ao2_callback(contacts, OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_expire, NULL);
+
+	/* Add any permanent contacts from the AOR */
+	if (aor->permanent_contacts) {
+		ao2_callback(aor->permanent_contacts, OBJ_NOLOCK | OBJ_NODATA, contact_link_static, contacts);
+	}
+
+	return contacts;
+}
+
+struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name)
+{
+	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
+}
+
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time)
+{
+	char name[AST_UUID_STR_LEN];
+	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+
+	snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), uri);
+
+	if (!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name))) {
+		return -1;
+	}
+
+	ast_string_field_set(contact, uri, uri);
+	contact->expiration_time = expiration_time;
+
+	return ast_sorcery_create(ast_sip_get_sorcery(), contact);
+}
+
+int ast_sip_location_update_contact(struct ast_sip_contact *contact)
+{
+	return ast_sorcery_update(ast_sip_get_sorcery(), contact);
+}
+
+int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
+{
+	return ast_sorcery_delete(ast_sip_get_sorcery(), contact);
+}
+
+/*! \brief Custom handler for translating from a string timeval to actual structure */
+static int expiration_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct ast_sip_contact *contact = obj;
+	return ast_get_timeval(var->value, &contact->expiration_time, ast_tv(0, 0), NULL);
+}
+
+/*! \brief Custom handler for translating from an actual structure timeval to string */
+static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf)
+{
+	const struct ast_sip_contact *contact = obj;
+	return (ast_asprintf(buf, "%lu", contact->expiration_time.tv_sec) < 0) ? -1 : 0;
+}
+
+/*! \brief Custom handler for permanent URIs */
+static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct ast_sip_aor *aor = obj;
+	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+
+	if ((!aor->permanent_contacts && !(aor->permanent_contacts = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) ||
+		!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", NULL))) {
+		return -1;
+	}
+
+	ast_string_field_set(contact, uri, var->value);
+	ao2_link_flags(aor->permanent_contacts, contact, OBJ_NOLOCK);
+
+	return 0;
+}
+
+/*! \brief Initialize sorcery with location support */
+int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery)
+{
+	ast_sorcery_apply_default(sorcery, "contact", "memory", NULL);
+	ast_sorcery_apply_default(sorcery, "aor", "config", "res_sip.conf,criteria=type=aor");
+
+	if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, NULL) ||
+		ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, NULL)) {
+		return -1;
+	}
+
+	ast_sorcery_object_field_register(sorcery, "contact", "type", "", OPT_NOOP_T, 0, 0);
+	ast_sorcery_object_field_register(sorcery, "contact", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, uri));
+	ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, 0, 0);
+
+	ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0);
+	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", "contact", "", permanent_uri_handler, NULL, 0, 0);
+
+	return 0;
+}

Propchange: team/group/pimp_my_sip/res/res_sip/location.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/pimp_my_sip/res/res_sip/location.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/pimp_my_sip/res/res_sip/location.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/group/pimp_my_sip/res/res_sip/sip_configuration.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip/sip_configuration.c?view=diff&rev=383171&r1=383170&r2=383171
==============================================================================
--- team/group/pimp_my_sip/res/res_sip/sip_configuration.c (original)
+++ team/group/pimp_my_sip/res/res_sip/sip_configuration.c Fri Mar 15 08:09:35 2013
@@ -19,17 +19,6 @@
 
 static struct ast_sorcery *sip_sorcery;
 
-/*!
- * \brief Structure used to map an IP address to an endpoint.
- *
- * This is useful for determining if an incoming request
- * is coming from a particular endpoint.
- */
-struct sip_location_to_endpoint {
-	SORCERY_OBJECT(details);
-	const char *endpoint_name;
-};
-
 static char *handle_cli_show_endpoints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
@@ -70,71 +59,6 @@
 static struct ast_cli_entry cli_commands[] = {
 	AST_CLI_DEFINE(handle_cli_show_endpoints, "Show SIP Endpoints"),
 };
-
-static void sip_location_to_endpoint_destroy(void *obj)
-{
-	struct sip_location_to_endpoint *location_to_endpoint = obj;
-	ast_free((char *)location_to_endpoint->endpoint_name);
-}
-
-static void *sip_location_to_endpoint_alloc(const char *name)
-{
-	return ao2_alloc(sizeof(struct sip_location_to_endpoint), sip_location_to_endpoint_destroy);
-}
-/*!
- * \brief Structure used to map an endpoint name to its location
- *
- * Location is stored as a string so that a FQDN may be stored
- * and the location may be resolved.
- *
- * This is useful for determining the destination for an outgoing
- * request to a specific endpoint
- */
-struct sip_endpoint_to_location {
-	SORCERY_OBJECT(details);
-	const char *host;
-};
-
-static void sip_endpoint_to_location_destroy(void *obj)
-{
-	struct sip_endpoint_to_location *endpoint_to_location = obj;
-	ast_free((char *) endpoint_to_location->host);
-}
-
-static void *sip_endpoint_to_location_alloc(const char *name)
-{
-	return ao2_alloc(sizeof(struct sip_endpoint_to_location), sip_endpoint_to_location_destroy);
-}
-
-static int host_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	RAII_VAR(struct sip_location_to_endpoint *, location_to_endpoint, NULL, ao2_cleanup);
-	RAII_VAR(struct sip_endpoint_to_location *, endpoint_to_location, NULL, ao2_cleanup);
-	const char *host = var->value;
-	const char *name = ast_sorcery_object_get_id(obj);
-
-	location_to_endpoint = ast_sorcery_alloc(sip_sorcery, "location_to_endpoint", host);
-	if (!location_to_endpoint) {
-		return -1;
-	}
-	endpoint_to_location = ast_sorcery_alloc(sip_sorcery, "endpoint_to_location", name);
-	if (!endpoint_to_location) {
-		return -1;
-	}
-
-	location_to_endpoint->endpoint_name = ast_strdup(name);
-	endpoint_to_location->host = ast_strdup(host);
-
-	if (ast_sorcery_create(sip_sorcery, location_to_endpoint)) {
-		return -1;
-	}
-	if (ast_sorcery_create(sip_sorcery, endpoint_to_location)) {
-		ast_sorcery_delete(sip_sorcery, location_to_endpoint);
-		return -1;
-	}
-
-	return 0;
-}
 
 static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
@@ -274,35 +198,30 @@
 
 	ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "res_sip.conf,criteria=type=endpoint");
 
-	ast_sorcery_apply_default(sip_sorcery, "location_to_endpoint", "memory", NULL);
-	ast_sorcery_apply_default(sip_sorcery, "endpoint_to_location", "memory", NULL);
-
 	if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, NULL)) {
 		ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
 		ast_sorcery_unref(sip_sorcery);
 		sip_sorcery = NULL;
 		return -1;
 	}
-
-	ast_sorcery_object_register(sip_sorcery, "location_to_endpoint", sip_location_to_endpoint_alloc, NULL, NULL);
-	ast_sorcery_object_register(sip_sorcery, "endpoint_to_location", sip_endpoint_to_location_alloc, NULL, NULL);
 
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, prefs, codecs));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, prefs, codecs));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_endpoint, qualify_frequency), 0, 86400);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "host", "", host_handler, NULL, 0, 0);
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmfmode", "rfc4733", dtmf_handler, NULL, 0, 0);
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, rtp_ipv6));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, rtp_symmetric));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_ptime", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, use_ptime));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mohsuggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest));
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, NULL, 0, 0);
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, NULL, 0, 0);
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_min_se", "90", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, min_se));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_sess_expires", "1800", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, sess_expires));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors));
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", auth_handler, NULL, 0, 0);
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username,location", ident_handler, NULL, 0, 0);
 
@@ -313,6 +232,13 @@
 		return -1;
 	}
 
+	if (ast_sip_initialize_sorcery_location(sip_sorcery)) {
+		ast_log(LOG_ERROR, "Failed to register SIP location support with sorcery\n");
+		ast_sorcery_unref(sip_sorcery);
+		sip_sorcery = NULL;
+		return -1;
+	}
+
 	ast_sorcery_load(sip_sorcery);
 
 	return 0;
@@ -361,30 +287,6 @@
 	return endpoint;
 }
 
-void ast_sip_endpoint_get_location(const struct ast_sip_endpoint *endpoint, char *location_buf, size_t size)
-{
-	struct sip_endpoint_to_location *endpoint_to_location;
-	endpoint_to_location = ast_sorcery_retrieve_by_id(sip_sorcery, "endpoint_to_location", ast_sorcery_object_get_id(endpoint));
-	if (!endpoint_to_location) {
-		return;
-	}
-	ast_copy_string(location_buf, endpoint_to_location->host, size);
-	ao2_ref(endpoint_to_location, -1);
-}
-
-struct ast_sip_endpoint *ast_sip_get_endpoint_from_location(const char *location)
-{
-	struct sip_location_to_endpoint *location_to_endpoint;
-	struct ast_sip_endpoint *endpoint;
-	location_to_endpoint = ast_sorcery_retrieve_by_id(sip_sorcery, "location_to_endpoint", location);
-	if (!location_to_endpoint) {
-		return NULL;
-	}
-	endpoint = ast_sorcery_retrieve_by_id(sip_sorcery, "endpoint", location_to_endpoint->endpoint_name);
-	ao2_ref(location_to_endpoint, -1);
-	return endpoint;
-}
-
 struct ao2_container *ast_res_sip_get_endpoints(void)
 {
 	struct ao2_container *endpoints;

Modified: team/group/pimp_my_sip/res/res_sip_endpoint_identifier_ip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip_endpoint_identifier_ip.c?view=diff&rev=383171&r1=383170&r2=383171
==============================================================================
--- team/group/pimp_my_sip/res/res_sip_endpoint_identifier_ip.c (original)
+++ team/group/pimp_my_sip/res/res_sip_endpoint_identifier_ip.c Fri Mar 15 08:09:35 2013
@@ -27,39 +27,114 @@
 
 #include "asterisk/res_sip.h"
 #include "asterisk/module.h"
+#include "asterisk/acl.h"
+
+/*! \brief Structure for an IP identification matching object */
+struct ip_identify_match {
+	/*! \brief Sorcery object details */
+	SORCERY_OBJECT(details);
+	/*! \brief Stringfields */
+	AST_DECLARE_STRING_FIELDS(

[... 418 lines stripped ...]



More information about the asterisk-commits mailing list