res_pjsip_session: Add configurable behavior for redirects.
authorJoshua Colp <jcolp@digium.com>
Thu, 28 Nov 2013 00:38:36 +0000 (00:38 +0000)
committerJoshua Colp <jcolp@digium.com>
Thu, 28 Nov 2013 00:38:36 +0000 (00:38 +0000)
The action taken when a redirect occurs is now configurable on a
per-endpoint basis. The redirect can either be treated as a redirect
to a local extension, to a URI that is dialed through the Asterisk
core, or to a URI that is dialed within PJSIP itself.

(closes issue ASTERISK-21710)
Reported by: Matt Jordan

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

Merged revisions 403207 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403208 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/res_pjsip.h
res/res_pjsip.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip_session.c

index b6dd441..9baceb9 100644 (file)
@@ -316,6 +316,15 @@ enum ast_sip_session_media_encryption {
        AST_SIP_MEDIA_ENCRYPT_DTLS,
 };
 
+enum ast_sip_session_redirect {
+       /*! User portion of the target URI should be used as the target in the dialplan */
+       AST_SIP_REDIRECT_USER = 0,
+       /*! Target URI should be used as the target in the dialplan */
+       AST_SIP_REDIRECT_URI_CORE,
+       /*! Target URI should be used as the target within chan_pjsip itself */
+       AST_SIP_REDIRECT_URI_PJSIP,
+};
+
 /*!
  * \brief Session timers options
  */
@@ -574,6 +583,8 @@ struct ast_sip_endpoint {
        unsigned int faxdetect;
        /*! Determines if transfers (using REFER) are allowed by this endpoint */
        unsigned int allowtransfer;
+       /*! Method used when handling redirects */
+       enum ast_sip_session_redirect redirect_method;
 };
 
 /*!
index db4f32f..37762e6 100644 (file)
                                                </enumlist>
                                        </description>
                                </configOption>
+                               <configOption name="redirect_method">
+                                       <synopsis>How redirects received from an endpoint are handled</synopsis>
+                                       <description><para>
+                                               When a redirect is received from an endpoint there are multiple ways it can be handled.
+                                               If this option is set to <literal>user</literal> the user portion of the redirect target
+                                               is treated as an extension within the dialplan and dialed using a Local channel. If this option
+                                               is set to <literal>uri_core</literal> the target URI is returned to the dialing application
+                                               which dials it using the PJSIP channel driver and endpoint originally used. If this option is
+                                               set to <literal>uri_pjsip</literal> the redirect occurs within chan_pjsip itself and is not exposed
+                                               to the core at all. The <literal>uri_pjsip</literal> option has the benefit of being more efficient
+                                               and also supporting multiple potential redirect targets. The con is that since redirection occurs
+                                               within chan_pjsip redirecting information is not forwarded and redirection can not be
+                                               prevented.
+                                               </para>
+                                               <enumlist>
+                                                       <enum name="user" />
+                                                       <enum name="uri_core" />
+                                                       <enum name="uri_pjsip" />
+                                               </enumlist>
+                                       </description>
+                               </configOption>
                                <configOption name="mailboxes">
                                        <synopsis>Mailbox(es) to be associated with</synopsis>
                                </configOption>
index 4642c5e..835dbfb 100644 (file)
@@ -455,6 +455,25 @@ static int ident_to_str(const void *obj, const intptr_t *args, char **buf)
        return 0;
 }
 
+static int redirect_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+       struct ast_sip_endpoint *endpoint = obj;
+
+       if (!strcasecmp(var->value, "user")) {
+               endpoint->redirect_method = AST_SIP_REDIRECT_USER;
+       } else if (!strcasecmp(var->value, "uri_core")) {
+               endpoint->redirect_method = AST_SIP_REDIRECT_URI_CORE;
+       } else if (!strcasecmp(var->value, "uri_pjsip")) {
+               endpoint->redirect_method = AST_SIP_REDIRECT_URI_PJSIP;
+       } else {
+               ast_log(LOG_ERROR, "Unrecognized redirect method %s specified for endpoint %s\n",
+                       var->value, ast_sorcery_object_get_id(endpoint));
+               return -1;
+       }
+
+       return 0;
+}
+
 static int direct_media_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
        struct ast_sip_endpoint *endpoint = obj;
@@ -1353,6 +1372,7 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, dtlscapath_to_str, 0, 0);
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, dtlssetup_to_str, 0, 0);
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "srtp_tag_32", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.srtp_tag_32));
+       ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, 0, 0);
 
        if (ast_sip_initialize_sorcery_transport(sip_sorcery)) {
                ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
index f44ec44..065f40d 100644 (file)
@@ -2065,13 +2065,31 @@ static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t stat
 static pjsip_redirect_op session_inv_on_redirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e)
 {
        struct ast_sip_session *session = inv->mod_data[session_module.id];
+       const pjsip_sip_uri *uri;
 
-       if (PJSIP_URI_SCHEME_IS_SIP(target) || PJSIP_URI_SCHEME_IS_SIPS(target)) {
-               const pjsip_sip_uri *uri = pjsip_uri_get_uri(target);
+       if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_PJSIP) {
+               return PJSIP_REDIRECT_ACCEPT;
+       }
+
+       if (!PJSIP_URI_SCHEME_IS_SIP(target) && !PJSIP_URI_SCHEME_IS_SIPS(target)) {
+               return PJSIP_REDIRECT_STOP;
+       }
+
+       uri = pjsip_uri_get_uri(target);
+
+       if (session->endpoint->redirect_method == AST_SIP_REDIRECT_USER) {
                char exten[AST_MAX_EXTENSION];
 
                ast_copy_pj_str(exten, &uri->user, sizeof(exten));
                ast_channel_call_forward_set(session->channel, exten);
+       } else if (session->endpoint->redirect_method == AST_SIP_REDIRECT_URI_CORE) {
+               char target_uri[PJSIP_MAX_URL_SIZE];
+               /* PJSIP/ + endpoint length + / + max URL size */
+               char forward[8 + strlen(ast_sorcery_object_get_id(session->endpoint)) + PJSIP_MAX_URL_SIZE];
+
+               pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, target_uri, sizeof(target_uri));
+               sprintf(forward, "PJSIP/%s/%s", ast_sorcery_object_get_id(session->endpoint), target_uri);
+               ast_channel_call_forward_set(session->channel, forward);
        }
 
        return PJSIP_REDIRECT_STOP;