]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip_outbound_registration: Add virtual line support. 87/287/1
authorJoshua Colp <jcolp@digium.com>
Tue, 4 Nov 2014 12:03:35 +0000 (12:03 +0000)
committerJoshua Colp <jcolp@digium.com>
Wed, 29 Apr 2015 12:48:06 +0000 (09:48 -0300)
Virtual line support establishes a relationship between messages
related to an outbound registration and a local endpoint. This is
accomplished by attaching a parameter to the Contact of the outbound
registration and looking for it on any received requests. If the
parameter exists and can be matched to an outbound registration
the configured endpoint is associated with the request.

ASTERISK-24949 #close
Reported by: Joshua Colp

Change-Id: I7df909d2625479110a83fdd354c21ac539e8615d

CHANGES
configs/samples/pjsip.conf.sample
res/res_pjsip_outbound_registration.c

diff --git a/CHANGES b/CHANGES
index 99ded7c37ed51cbc68e82d80b20be169337e9d05..2261ddeb8e91978935ff855ddff63f563359575b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,12 @@ chan_pjsip
  * The configuration setting 'progressinband' now defaults to 'no', which
    matches the actual behavior of previous versions.
 
+ * New 'line' and 'endpoint' options added on outbound registrations. This allows some
+   identifying information to be added to the Contact of the outbound registration.
+   If this information is present on messages received from the remote server
+   the message will automatically be associated with the configured endpoint on the
+   outbound registration.
+
 res_pjsip
 ------------------
  * A new CLI command has been added: "pjsip show settings", which shows
index 5081794b3449daa92cc4b8ef3a8636ba8b8e06a4..de055f91920fd12cec025864aaa392270f524280 100644 (file)
 ; "contact_user=" sets the SIP contact header's user portion of the SIP URI
 ; this will affect the extension reached in dialplan when the far end calls you at this
 ; registration. The default is 's'.
+;
+; If you would like to enable line support and have incoming calls related to this
+; registration go to an endpoint automatically the "line" and "endpoint" options must
+; be set. The "endpoint" option specifies what endpoint the incoming call should be
+; associated with.
 
 ;[mytrunk]
 ;type=registration
 ;retry_interval=60
 ;forbidden_retry_interval=600
 ;expiration=3600
+;line=yes
+;endpoint=mytrunk
 
 ;[mytrunk_auth]
 ;type=auth
index 0547416cfc439394a0a09b9fd7ca361364435a1e..778fc5f72f656d7d43eea95ff3e70d4d27246911 100644 (file)
                                                <literal>pjsip.conf</literal>. As with other <literal>res_pjsip</literal> modules, this will use the first available transport of the appropriate type if unconfigured.</para></note>
                                        </description>
                                </configOption>
+                               <configOption name="line">
+                                       <synopsis>Whether to add a 'line' parameter to the Contact for inbound call matching</synopsis>
+                                       <description><para>
+                                               When enabled this option will cause a 'line' parameter to be added to the Contact
+                                               header placed into the outgoing registration request. If the remote server sends a call
+                                               this line parameter will be used to establish a relationship to the outbound registration,
+                                               ultimately causing the configured endpoint to be used.
+                                       </para></description>
+                               </configOption>
+                               <configOption name="endpoint">
+                                       <synopsis>Endpoint to use for incoming related calls</synopsis>
+                                       <description><para>
+                                               When line support is enabled this configured endpoint name is used for incoming calls
+                                               that are related to the outbound registration.
+                                       </para></description>
+                               </configOption>
                                <configOption name="type">
                                        <synopsis>Must be of type 'registration'.</synopsis>
                                </configOption>
@@ -354,6 +370,54 @@ static struct ao2_container *get_registrations(void)
        return registrations;
 }
 
+/*! \brief Callback function for matching an outbound registration based on line */
+static int line_identify_relationship(void *obj, void *arg, int flags)
+{
+       struct sip_outbound_registration_state *state = obj;
+       pjsip_param *line = arg;
+
+       return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+/*! \brief Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing registration */
+static struct ast_sip_endpoint *line_identify(pjsip_rx_data *rdata)
+{
+       pjsip_sip_uri *uri;
+       static const pj_str_t LINE_STR = { "line", 4 };
+       pjsip_param *line;
+       RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);
+       RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);
+
+       if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
+               return NULL;
+       }
+       uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
+
+       line = pjsip_param_find(&uri->other_param, &LINE_STR);
+       if (!line) {
+               return NULL;
+       }
+
+       states = ao2_global_obj_ref(current_states);
+       if (!states) {
+               return NULL;
+       }
+
+       state = ao2_callback(states, 0, line_identify_relationship, line);
+       if (!state || ast_strlen_zero(state->registration->endpoint)) {
+               return NULL;
+       }
+
+       ast_debug(3, "Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
+               ast_sorcery_object_get_id(state->registration), state->client_state->line, state->registration->endpoint);
+
+       return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint);
+}
+
+static struct ast_sip_endpoint_identifier line_identifier = {
+       .identify_endpoint = line_identify,
+};
+
 /*! \brief Helper function which cancels the timer on a client */
 static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
 {
@@ -784,7 +848,8 @@ static void *sip_outbound_registration_alloc(const char *name)
 }
 
 /*! \brief Helper function which populates a pj_str_t with a contact header */
-static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user, const pj_str_t *target, pjsip_tpselector *selector)
+static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user, const pj_str_t *target, pjsip_tpselector *selector,
+       const char *line)
 {
        pj_str_t tmp, local_addr;
        pjsip_uri *uri;
@@ -828,7 +893,7 @@ static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const c
 
        contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
        contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
-                                     "<%s:%s@%s%.*s%s:%d%s%s>",
+                                     "<%s:%s@%s%.*s%s:%d%s%s%s%s>",
                                      (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
                                      user,
                                      (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
@@ -837,7 +902,9 @@ static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const c
                                      (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) : "");
+                                     (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
+                                     !ast_strlen_zero(line) ? ";line=" : "",
+                                     S_OR(line, ""));
 
        return 0;
 }
@@ -959,9 +1026,15 @@ static int sip_outbound_registration_regc_alloc(void *data)
                pjsip_regc_set_route_set(state->client_state->client, &route_set);
        }
 
+       if (state->registration->line) {
+               ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
+       }
+
        pj_cstr(&server_uri, registration->server_uri);
 
-       if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client), &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector)) {
+
+       if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client), &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
+               state->client_state->line)) {
                return -1;
        }
 
@@ -1026,6 +1099,14 @@ static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, vo
                ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
                        ast_sorcery_object_get_id(applied));
                return -1;
+       } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
+               ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
+                       ast_sorcery_object_get_id(applied));
+               return -1;
+       } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
+               ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
+                       ast_sorcery_object_get_id(applied));
+               return -1;
        }
 
        if (state && can_reuse_registration(state->registration, applied)) {
@@ -1619,6 +1700,7 @@ static const struct ast_sorcery_instance_observer observer_callbacks_registratio
 
 static int unload_module(void)
 {
+       ast_sip_unregister_endpoint_identifier(&line_identifier);
        ast_sorcery_observer_remove(ast_sip_get_sorcery(), "auth", &observer_callbacks_auth);
        ast_sorcery_instance_observer_remove(ast_sip_get_sorcery(), &observer_callbacks_registrations);
        ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
@@ -1658,6 +1740,9 @@ static int load_module(void)
        ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));
        ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, outbound_auths_to_var_list, 0, 0);
        ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
+       ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
+       ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
+       ast_sip_register_endpoint_identifier(&line_identifier);
 
        ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
        ast_manager_register_xml("PJSIPRegister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_register);