[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