Changeset 2370


Ignore:
Timestamp:
Nov 27, 2008 12:06:46 AM (11 years ago)
Author:
bennylp
Message:

Ticket #10: handle redirection response in the invite session

Location:
pjproject/trunk
Files:
3 added
10 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r2316 r2370  
    6363    pjsua_transport_config  udp_cfg; 
    6464    pjsua_transport_config  rtp_cfg; 
     65    pjsip_redirect_op       redir_op; 
    6566 
    6667    unsigned                acc_cnt; 
     
    279280    puts  ("  --use-compact-form  Minimize SIP message size"); 
    280281    puts  ("  --no-force-lr       Allow strict-route to be used (i.e. do not force lr)"); 
     282    puts  ("  --accept-redirect=N Specify how to handle call redirect (3xx) response."); 
     283    puts  ("                      0: reject, 1: follow automatically (default), 2: ask"); 
    281284 
    282285    puts  (""); 
     
    304307    pjsua_transport_config_default(&cfg->rtp_cfg); 
    305308    cfg->rtp_cfg.port = 4000; 
     309    cfg->redir_op = PJSIP_REDIRECT_ACCEPT; 
    306310    cfg->duration = NO_LIMIT; 
    307311    cfg->wav_id = PJSUA_INVALID_ID; 
     
    473477           OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS,  
    474478           OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP, OPT_THREAD_CNT, 
    475            OPT_NOREFERSUB, 
     479           OPT_NOREFERSUB, OPT_ACCEPT_REDIRECT, 
    476480           OPT_USE_TLS, OPT_TLS_CA_FILE, OPT_TLS_CERT_FILE, OPT_TLS_PRIV_FILE, 
    477481           OPT_TLS_PASSWORD, OPT_TLS_VERIFY_SERVER, OPT_TLS_VERIFY_CLIENT, 
     
    516520        { "auto-update-nat",    1, 0, OPT_AUTO_UPDATE_NAT}, 
    517521        { "use-compact-form",   0, 0, OPT_USE_COMPACT_FORM}, 
     522        { "accept-redirect", 1, 0, OPT_ACCEPT_REDIRECT}, 
    518523        { "no-force-lr",0, 0, OPT_NO_FORCE_LR}, 
    519524        { "realm",      1, 0, OPT_REALM}, 
     
    841846            break; 
    842847 
     848        case OPT_ACCEPT_REDIRECT: 
     849            cfg->redir_op = my_atoi(pj_optarg); 
     850            if (cfg->redir_op<0 || cfg->redir_op>PJSIP_REDIRECT_STOP) { 
     851                PJ_LOG(1,(THIS_FILE,  
     852                          "Error: accept-redirect value '%s' ", pj_optarg)); 
     853                return PJ_EINVAL; 
     854            } 
     855            break; 
     856 
    843857        case OPT_NO_FORCE_LR: 
    844858            cfg->cfg.force_lr = PJ_FALSE; 
     
    17861800    } 
    17871801 
     1802    /* accept-redirect */ 
     1803    if (config->redir_op != PJSIP_REDIRECT_ACCEPT) { 
     1804        pj_ansi_sprintf(line, "--accept-redirect %d\n", 
     1805                        config->redir_op); 
     1806        pj_strcat2(&cfg, line); 
     1807    } 
     1808 
    17881809    /* Max calls. */ 
    17891810    pj_ansi_sprintf(line, "--max-calls %d\n", 
     
    18411862 * as the logger can accept. 
    18421863 */ 
    1843 static void log_call_dump(int call_id) { 
     1864static void log_call_dump(int call_id)  
     1865{ 
    18441866    unsigned call_dump_len; 
    18451867    unsigned part_len; 
     
    23672389{ 
    23682390    PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c", call_id, dtmf)); 
     2391} 
     2392 
     2393/* 
     2394 * Redirection handler. 
     2395 */ 
     2396static void call_on_redirected(pjsua_call_id call_id, const pjsip_uri *target, 
     2397                               pjsip_redirect_op *cmd, const pjsip_event *e) 
     2398{ 
     2399    *cmd = app_config.redir_op; 
     2400 
     2401    PJ_UNUSED_ARG(e); 
     2402 
     2403    if (*cmd == PJSIP_REDIRECT_PENDING) { 
     2404        char uristr[PJSIP_MAX_URL_SIZE]; 
     2405        int len; 
     2406 
     2407        len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, target, uristr,  
     2408                              sizeof(uristr)); 
     2409        if (len < 1) { 
     2410            pj_ansi_strcpy(uristr, "--URI too long--"); 
     2411        } 
     2412 
     2413        PJ_LOG(3,(THIS_FILE, "Call %d is being redirected to %.*s. " 
     2414                  "Press 'Ra' to accept, 'Rr' to reject, or 'Rd' to " 
     2415                  "disconnect.", 
     2416                  call_id, len, uristr)); 
     2417    } 
    23692418} 
    23702419 
     
    39163965 
    39173966 
     3967        case 'R': 
     3968            if (!pjsua_call_is_active(current_call)) { 
     3969                PJ_LOG(1,(THIS_FILE, "Call %d has gone", current_call)); 
     3970            } else if (menuin[1] == 'a') { 
     3971                pjsua_call_process_redirect(current_call,  
     3972                                            PJSIP_REDIRECT_ACCEPT); 
     3973            } else if (menuin[1] == 'r') { 
     3974                pjsua_call_process_redirect(current_call, 
     3975                                            PJSIP_REDIRECT_REJECT); 
     3976            } else { 
     3977                pjsua_call_process_redirect(current_call, 
     3978                                            PJSIP_REDIRECT_STOP); 
     3979            } 
     3980            break; 
     3981 
    39183982        default: 
    39193983            if (menuin[0] != '\n' && menuin[0] != '\r') { 
     
    39634027    app_config.cfg.cb.on_call_tsx_state = &on_call_tsx_state; 
    39644028    app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback; 
     4029    app_config.cfg.cb.on_call_redirected = &call_on_redirected; 
    39654030    app_config.cfg.cb.on_reg_state = &on_reg_state; 
    39664031    app_config.cfg.cb.on_incoming_subscribe = &on_incoming_subscribe; 
  • pjproject/trunk/pjsip-apps/src/test-pjsua/mod_recvfrom.py

    r2110 r2370  
    1 # $Id:$ 
     1# $Id$ 
    22import imp 
    33import sys 
     
    6868                                raise TestError("Excluded pattern " + pat + " found" + tname) 
    6969                # Create response 
    70                 response = dlg.create_response(request, t.resp_code, "Status reason") 
    71                 # Add headers to response 
    72                 for h in t.resp_hdr: 
    73                         response = response + h + "\r\n" 
    74                 # Add message body if required 
    75                 if t.body: 
    76                         response = response + t.body 
    77                 # Send response 
    78                 dlg.send_msg(response, src_addr) 
     70                if t.resp_code!=0: 
     71                        response = dlg.create_response(request, t.resp_code, "Status reason") 
     72                        # Add headers to response 
     73                        for h in t.resp_hdr: 
     74                                response = response + h + "\r\n" 
     75                        # Add message body if required 
     76                        if t.body: 
     77                                response = response + t.body 
     78                        # Send response 
     79                        dlg.send_msg(response, src_addr) 
     80 
    7981                # Expect something to happen in pjsua 
    8082                if t.expect != "": 
  • pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h

    r2039 r2370  
    116116    void (*on_state_changed)(pjsip_inv_session *inv, pjsip_event *e); 
    117117 
    118  
    119118    /** 
    120119     * This callback is called when the invite usage module has created  
     
    214213     */ 
    215214    void (*on_send_ack)(pjsip_inv_session *inv, pjsip_rx_data *rdata); 
     215 
     216    /** 
     217     * This callback is called when the session is about to resend the  
     218     * INVITE request to the specified target, following the previously 
     219     * received redirection response. 
     220     * 
     221     * Application may accept the redirection to the specified target  
     222     * (the default behavior if this callback is implemented), reject  
     223     * this target only and make the session continue to try the next  
     224     * target in the list if such target exists, stop the whole 
     225     * redirection process altogether and cause the session to be 
     226     * disconnected, or defer the decision to ask for user confirmation. 
     227     * 
     228     * This callback is optional. If this callback is not implemented, 
     229     * the default behavior is to NOT follow the redirection response. 
     230     * 
     231     * @param inv       The invite session. 
     232     * @param target    The current target to be tried. 
     233     * @param cmd       Action to be performed for the target. Set this 
     234     *                  parameter to one of the value below: 
     235     *                  - PJSIP_REDIRECT_ACCEPT: immediately accept the 
     236     *                    redirection (default value). When set, the 
     237     *                    session will immediately resend INVITE request 
     238     *                    to the target. 
     239     *                  - PJSIP_REDIRECT_REJECT: immediately reject this 
     240     *                    target. The session will continue retrying with 
     241     *                    next target if present, or disconnect the call 
     242     *                    if there is no more target to try. 
     243     *                  - PJSIP_REDIRECT_STOP: stop the whole redirection 
     244     *                    process and immediately disconnect the call. The 
     245     *                    on_state_changed() callback will be called with 
     246     *                    PJSIP_INV_STATE_DISCONNECTED state immediately 
     247     *                    after this callback returns. 
     248     *                  - PJSIP_REDIRECT_PENDING: set to this value if 
     249     *                    no decision can be made immediately (for example 
     250     *                    to request confirmation from user). Application 
     251     *                    then MUST call #pjsip_inv_process_redirect() 
     252     *                    to either accept or reject the redirection upon 
     253     *                    getting user decision. 
     254     * @param e         The event that caused this callback to be called. 
     255     *                  This could be the receipt of 3xx response, or 
     256     *                  4xx/5xx response received for the INVITE sent to 
     257     *                  subsequent targets, or NULL if this callback is 
     258     *                  called from within #pjsip_inv_process_redirect() 
     259     *                  context. 
     260     */ 
     261    void (*on_redirected)(pjsip_inv_session *inv, const pjsip_uri *target, 
     262                          pjsip_redirect_op *cmd, const pjsip_event *e); 
    216263 
    217264} pjsip_inv_callback; 
     
    277324    pjmedia_sdp_neg     *neg;                       /**< Negotiator.        */ 
    278325    pjsip_transaction   *invite_tsx;                /**< 1st invite tsx.    */ 
     326    pjsip_tx_data       *invite_req;                /**< Saved invite req   */ 
    279327    pjsip_tx_data       *last_answer;               /**< Last INVITE resp.  */ 
    280328    pjsip_tx_data       *last_ack;                  /**< Last ACK request   */ 
     
    473521                                          int st_code, 
    474522                                          pj_bool_t notify ); 
     523 
     524 
     525/** 
     526 * Restart UAC session and prepare the session for a new initial INVITE. 
     527 * This function can be called for example when the application wants to 
     528 * follow redirection response with a new call reusing this session so 
     529 * that the new call will have the same Call-ID and From headers. After 
     530 * the session is restarted, application may create and send a new INVITE 
     531 * request. 
     532 * 
     533 * @param inv           The invite session. 
     534 * @param new_offer     Should be set to PJ_TRUE since the application will 
     535 *                      restart the session. 
     536 * 
     537 * @return              PJ_SUCCESS on successful operation. 
     538 */ 
     539PJ_DECL(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv, 
     540                                           pj_bool_t new_offer); 
     541 
     542 
     543/** 
     544 * Accept or reject redirection response. Application MUST call this function 
     545 * after it signaled PJSIP_REDIRECT_PENDING in the \a on_redirected()  
     546 * callback, to notify the invite session whether to accept or reject the 
     547 * redirection to the current target. Application can use the combination of 
     548 * PJSIP_REDIRECT_PENDING command in \a on_redirected() callback and this 
     549 * function to ask for user permission before redirecting the call. 
     550 * 
     551 * Note that if the application chooses to reject or stop redirection (by  
     552 * using PJSIP_REDIRECT_REJECT or PJSIP_REDIRECT_STOP respectively), the 
     553 * session disconnection callback will be called before this function returns. 
     554 * And if the application rejects the target, the \a on_redirected() callback 
     555 * may also be called before this function returns if there is another target 
     556 * to try. 
     557 * 
     558 * @param inv           The invite session. 
     559 * @param cmd           Redirection operation. The semantic of this argument 
     560 *                      is similar to the description in the \a on_redirected() 
     561 *                      callback, except that the PJSIP_REDIRECT_PENDING is 
     562 *                      not accepted here. 
     563 * @param e             Should be set to NULL. 
     564 * 
     565 * @return              PJ_SUCCESS on successful operation. 
     566 */ 
     567PJ_DECL(pj_status_t) pjsip_inv_process_redirect(pjsip_inv_session *inv, 
     568                                                pjsip_redirect_op cmd, 
     569                                                pjsip_event *e); 
    475570 
    476571 
  • pjproject/trunk/pjsip/include/pjsip/sip_dialog.h

    r2039 r2370  
    3030#include <pjsip/sip_errno.h> 
    3131#include <pjsip/sip_transport.h> 
     32#include <pjsip/sip_util.h> 
    3233#include <pj/sock.h> 
    3334#include <pj/assert.h> 
     
    122123    pjsip_dialog_state  state;      /**< Dialog state.                      */ 
    123124    pjsip_uri          *target;     /**< Current target.                    */ 
     125    pjsip_target_set    target_set; /**< Target set, for UAC only.          */ 
    124126    pjsip_hdr           inv_hdr;    /**< Headers from hparam in dest URL    */ 
    125127    pjsip_dlg_party     local;      /**< Local party info.                  */ 
  • pjproject/trunk/pjsip/include/pjsip/sip_util.h

    r2039 r2370  
    2525 
    2626PJ_BEGIN_DECL 
     27 
     28/** 
     29 * @defgroup PJSIP_ENDPT_TARGET_URI Target URI Management 
     30 * @ingroup PJSIP_CORE_CORE 
     31 * @brief Management of target URI's in case of redirection 
     32 * @{ 
     33 * This module provides utility functions to manage target set for UAC. 
     34 * The target set is provided as pjsip_target_set structure. Initially, 
     35 * the target set for UAC contains only one target, that is the target of 
     36 * the initial request. When 3xx/redirection class response is received,  
     37 * the UAC can use the functionality of this module to add the URI's listed 
     38 * in the Contact header(s) in the response to the target set, and retry  
     39 * sending the request to the next destination/target. The UAC may retry  
     40 * this sequentially until one of the target answers with succesful/2xx  
     41 * response, or one target returns global error/6xx response, or all targets 
     42 * are exhausted. 
     43 * 
     44 * This module is currently used by the \ref PJSIP_INV. 
     45 */ 
     46 
     47/** 
     48 * This structure describes a target, which can be chained together to form 
     49 * a target set. Each target contains an URI, priority (as q-value), and  
     50 * the last status code and reason phrase received from the target, if the  
     51 * target has been contacted. If the target has not been contacted, the  
     52 * status code field will be zero. 
     53 */ 
     54typedef struct pjsip_target 
     55{ 
     56    PJ_DECL_LIST_MEMBER(struct pjsip_target);/**< Standard list element */ 
     57    pjsip_uri          *uri;    /**< The target URI                 */ 
     58    int                 q1000;  /**< q-value multiplied by 1000     */ 
     59    pjsip_status_code   code;   /**< Last status code received      */ 
     60    pj_str_t            reason; /**< Last reason phrase received    */ 
     61} pjsip_target; 
     62 
     63 
     64/** 
     65 * This describes a target set. A target set contains a linked-list of 
     66 * pjsip_target. 
     67 */ 
     68typedef struct pjsip_target_set 
     69{ 
     70    pjsip_target     head;          /**< Target linked-list head    */ 
     71    pjsip_target    *current;       /**< Current target.            */ 
     72} pjsip_target_set; 
     73 
     74 
     75/** 
     76 * These enumerations specify the action to be performed to a redirect 
     77 * response. 
     78 */ 
     79typedef enum pjsip_redirect_op 
     80{ 
     81    /** 
     82     * Reject the redirection to the current target. The UAC will 
     83     * select the next target from the target set if exists. 
     84     */ 
     85    PJSIP_REDIRECT_REJECT, 
     86 
     87    /** 
     88     * Accept the redirection to the current target. The INVITE request 
     89     * will be resent to the current target. 
     90     */ 
     91    PJSIP_REDIRECT_ACCEPT, 
     92 
     93    /** 
     94     * Defer the redirection decision, for example to request permission 
     95     * from the end user. 
     96     */ 
     97    PJSIP_REDIRECT_PENDING, 
     98 
     99    /** 
     100     * Stop the whole redirection process altogether. This will cause 
     101     * the invite session to be disconnected. 
     102     */ 
     103    PJSIP_REDIRECT_STOP 
     104 
     105} pjsip_redirect_op; 
     106 
     107 
     108/** 
     109 * Initialize target set. This will empty the list of targets in the 
     110 * target set. 
     111 * 
     112 * @param tset      The target set. 
     113 */ 
     114PJ_INLINE(void) pjsip_target_set_init(pjsip_target_set *tset) 
     115{ 
     116    pj_list_init(&tset->head); 
     117    tset->current = NULL; 
     118} 
     119 
     120 
     121/** 
     122 * Add an URI to the target set, if the URI is not already in the target set. 
     123 * The URI comparison rule of pjsip_uri_cmp() will be used to determine the 
     124 * equality of this URI compared to existing URI's in the target set. The 
     125 * URI will be cloned using the specified memory pool before it is added to 
     126 * the list. 
     127 * 
     128 * The first URI added to the target set will also be made current target 
     129 * by this function. 
     130 * 
     131 * @param tset      The target set. 
     132 * @param pool      The memory pool to be used to duplicate the URI. 
     133 * @param uri       The URI to be checked and added. 
     134 * @param q1000     The q-value multiplied by 1000. 
     135 * 
     136 * @return          PJ_SUCCESS if the URI was added to the target set, 
     137 *                  or PJ_EEXISTS if the URI already exists in the target 
     138 *                  set, or other error codes. 
     139 */ 
     140PJ_DECL(pj_status_t) pjsip_target_set_add_uri(pjsip_target_set *tset, 
     141                                              pj_pool_t *pool, 
     142                                              const pjsip_uri *uri, 
     143                                              int q1000); 
     144 
     145/** 
     146 * Extract URI's in the Contact headers of the specified (response) message 
     147 * and add them to the target set. This function will also check if the  
     148 * URI's already exist in the target set before adding them to the list. 
     149 * 
     150 * @param tset      The target set. 
     151 * @param pool      The memory pool to be used to duplicate the URI's. 
     152 * @param msg       SIP message from which the Contact headers will be 
     153 *                  scanned and the URI's to be extracted, checked, and 
     154 *                  added to the target set. 
     155 * 
     156 * @return          PJ_SUCCESS if at least one URI was added to the  
     157 *                  target set, or PJ_EEXISTS if all URI's in the message  
     158 *                  already exists in the target set or if the message 
     159 *                  doesn't contain usable Contact headers, or other error 
     160 *                  codes. 
     161 */ 
     162PJ_DECL(pj_status_t) pjsip_target_set_add_from_msg(pjsip_target_set *tset, 
     163                                                   pj_pool_t *pool, 
     164                                                   const pjsip_msg *msg); 
     165 
     166/** 
     167 * Get the next target to be retried. This function will scan the target set 
     168 * for target which hasn't been tried, and return one target with the 
     169 * highest q-value, if such target exists. This function will return NULL 
     170 * if there is one target with 2xx or 6xx code or if all targets have been 
     171 * tried. 
     172 * 
     173 * @param tset      The target set. 
     174 * 
     175 * @return          The next target to be tried, or NULL if all targets have 
     176 *                  been tried or at least one target returns 2xx or 6xx 
     177 *                  response. 
     178 */ 
     179PJ_DECL(pjsip_target*)  
     180pjsip_target_set_get_next(const pjsip_target_set *tset); 
     181 
     182 
     183/** 
     184 * Set the specified target as the current target in the target set. The 
     185 * current target may be used by application to keep track on which target 
     186 * is currently being operated on. 
     187 * 
     188 * @param tset      The target set. 
     189 * @param target    The target to be set as current target. 
     190 * 
     191 * @return          PJ_SUCCESS or the appropriate error code. 
     192 */ 
     193PJ_DECL(pj_status_t) pjsip_target_set_set_current(pjsip_target_set *tset, 
     194                                                  pjsip_target *target); 
     195 
     196 
     197/** 
     198 * Set the status code and reason phrase of the specified target. 
     199 * 
     200 * @param target    The target. 
     201 * @param pool      The memory pool to be used to duplicate the reason phrase. 
     202 * @param code      The SIP status code to be set to the target. 
     203 * @param reason    The reason phrase  to be set to the target. 
     204 * 
     205 * @return          PJ_SUCCESS on successful operation or the appropriate 
     206 *                  error code. 
     207 */ 
     208PJ_DECL(pj_status_t) pjsip_target_assign_status(pjsip_target *target, 
     209                                                pj_pool_t *pool, 
     210                                                int status_code, 
     211                                                const pj_str_t *reason); 
     212 
     213/** 
     214 * @} 
     215 */ 
    27216 
    28217/** 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r2351 r2370  
    10631063    void (*on_nat_detect)(const pj_stun_nat_detect_result *res); 
    10641064 
     1065    /** 
     1066     * This callback is called when the call is about to resend the  
     1067     * INVITE request to the specified target, following the previously 
     1068     * received redirection response. 
     1069     * 
     1070     * Application may accept the redirection to the specified target  
     1071     * (the default behavior if this callback is implemented), reject  
     1072     * this target only and make the session continue to try the next  
     1073     * target in the list if such target exists, stop the whole 
     1074     * redirection process altogether and cause the session to be 
     1075     * disconnected, or defer the decision to ask for user confirmation. 
     1076     * 
     1077     * This callback is optional. If this callback is not implemented, 
     1078     * the default behavior is to NOT follow the redirection response. 
     1079     * 
     1080     * @param call_id   The call ID. 
     1081     * @param target    The current target to be tried. 
     1082     * @param cmd       Action to be performed for the target. Set this 
     1083     *                  parameter to one of the value below: 
     1084     *                  - PJSIP_REDIRECT_ACCEPT: immediately accept the 
     1085     *                    redirection (default value). When set, the 
     1086     *                    call will immediately resend INVITE request 
     1087     *                    to the target. 
     1088     *                  - PJSIP_REDIRECT_REJECT: immediately reject this 
     1089     *                    target. The call will continue retrying with 
     1090     *                    next target if present, or disconnect the call 
     1091     *                    if there is no more target to try. 
     1092     *                  - PJSIP_REDIRECT_STOP: stop the whole redirection 
     1093     *                    process and immediately disconnect the call. The 
     1094     *                    on_call_state() callback will be called with 
     1095     *                    PJSIP_INV_STATE_DISCONNECTED state immediately 
     1096     *                    after this callback returns. 
     1097     *                  - PJSIP_REDIRECT_PENDING: set to this value if 
     1098     *                    no decision can be made immediately (for example 
     1099     *                    to request confirmation from user). Application 
     1100     *                    then MUST call #pjsua_call_process_redirect() 
     1101     *                    to either accept or reject the redirection upon 
     1102     *                    getting user decision. 
     1103     * @param e         The event that caused this callback to be called. 
     1104     *                  This could be the receipt of 3xx response, or 
     1105     *                  4xx/5xx response received for the INVITE sent to 
     1106     *                  subsequent targets, or NULL if this callback is 
     1107     *                  called from within #pjsua_call_process_redirect() 
     1108     *                  context. 
     1109     */ 
     1110    void (*on_call_redirected)(pjsua_call_id call_id, const pjsip_uri *target, 
     1111                               pjsip_redirect_op *cmd, const pjsip_event *e); 
     1112 
    10651113} pjsua_callback; 
    10661114 
     
    31333181                                       const pjsua_msg_data *msg_data); 
    31343182 
     3183/** 
     3184 * Accept or reject redirection response. Application MUST call this function 
     3185 * after it signaled PJSIP_REDIRECT_PENDING in the \a on_call_redirected()  
     3186 * callback, to notify the call whether to accept or reject the redirection 
     3187 * to the current target. Application can use the combination of 
     3188 * PJSIP_REDIRECT_PENDING command in \a on_call_redirected() callback and  
     3189 * this function to ask for user permission before redirecting the call. 
     3190 * 
     3191 * Note that if the application chooses to reject or stop redirection (by  
     3192 * using PJSIP_REDIRECT_REJECT or PJSIP_REDIRECT_STOP respectively), the 
     3193 * call disconnection callback will be called before this function returns. 
     3194 * And if the application rejects the target, the \a on_call_redirected()  
     3195 * callback may also be called before this function returns if there is  
     3196 * another target to try. 
     3197 * 
     3198 * @param call_id       The call ID. 
     3199 * @param cmd           Redirection operation to be applied to the current 
     3200 *                      target. The semantic of this argument is similar 
     3201 *                      to the description in the \a on_call_redirected() 
     3202 *                      callback, except that the PJSIP_REDIRECT_PENDING is 
     3203 *                      not accepted here. 
     3204 * 
     3205 * @return              PJ_SUCCESS on successful operation. 
     3206 */ 
     3207PJ_DECL(pj_status_t) pjsua_call_process_redirect(pjsua_call_id call_id, 
     3208                                                 pjsip_redirect_op cmd); 
    31353209 
    31363210/** 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c

    r2362 r2370  
    226226            inv->last_ack = NULL; 
    227227        } 
     228        if (inv->invite_req) { 
     229            pjsip_tx_data_dec_ref(inv->invite_req); 
     230            inv->invite_req = NULL; 
     231        } 
    228232        pjsip_100rel_end_session(inv); 
    229233        pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); 
     
    12201224 
    12211225 
     1226/* 
     1227 * Restart UAC session, possibly because app or us wants to re-send the  
     1228 * INVITE request due to 401/407 challenge or 3xx response. 
     1229 */ 
     1230PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv, 
     1231                                          pj_bool_t new_offer) 
     1232{ 
     1233    PJ_ASSERT_RETURN(inv, PJ_EINVAL); 
     1234 
     1235    inv->state = PJSIP_INV_STATE_NULL; 
     1236    inv->invite_tsx = NULL; 
     1237    if (inv->last_answer) { 
     1238        pjsip_tx_data_dec_ref(inv->last_answer); 
     1239        inv->last_answer = NULL; 
     1240    } 
     1241 
     1242    if (new_offer && inv->neg) { 
     1243        pjmedia_sdp_neg_state neg_state; 
     1244 
     1245        neg_state = pjmedia_sdp_neg_get_state(inv->neg); 
     1246        if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) { 
     1247            pjmedia_sdp_neg_cancel_offer(inv->neg); 
     1248        } 
     1249    } 
     1250 
     1251    return PJ_SUCCESS; 
     1252} 
     1253 
     1254 
    12221255static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len) 
    12231256{ 
     
    18901923 
    18911924    return PJ_SUCCESS; 
     1925} 
     1926 
     1927/* Following redirection recursion, get next target from the target set and 
     1928 * notify user. 
     1929 * 
     1930 * Returns PJ_FALSE if recursion fails (either because there's no more target 
     1931 * or user rejects the recursion). If we return PJ_FALSE, caller should 
     1932 * disconnect the session. 
     1933 * 
     1934 * Note: 
     1935 *   the event 'e' argument may be NULL. 
     1936 */ 
     1937static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code, 
     1938                                 const pj_str_t *reason, pjsip_event *e) 
     1939{ 
     1940    pjsip_redirect_op op = PJSIP_REDIRECT_ACCEPT; 
     1941    pjsip_target *target; 
     1942 
     1943    /* Won't redirect if the callback is not implemented. */ 
     1944    if (mod_inv.cb.on_redirected == NULL) 
     1945        return PJ_FALSE; 
     1946 
     1947    if (reason == NULL) 
     1948        reason = pjsip_get_status_text(code); 
     1949 
     1950    /* Set status of current target */ 
     1951    pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool, 
     1952                               code, reason); 
     1953 
     1954    /* Fetch next target from the target set. We only want to 
     1955     * process SIP/SIPS URI for now. 
     1956     */ 
     1957    for (;;) { 
     1958        target = pjsip_target_set_get_next(&inv->dlg->target_set); 
     1959        if (target == NULL) { 
     1960            /* No more target. */ 
     1961            return PJ_FALSE; 
     1962        } 
     1963 
     1964        if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) && 
     1965            !PJSIP_URI_SCHEME_IS_SIPS(target->uri)) 
     1966        { 
     1967            code = PJSIP_SC_UNSUPPORTED_URI_SCHEME; 
     1968            reason = pjsip_get_status_text(code); 
     1969 
     1970            /* Mark this target as unusable and fetch next target. */ 
     1971            pjsip_target_assign_status(target, inv->dlg->pool, code, reason); 
     1972        } else { 
     1973            /* Found a target */ 
     1974            break; 
     1975        } 
     1976    } 
     1977 
     1978    /* We have target in 'target'. Set this target as current target 
     1979     * and notify callback.  
     1980     */ 
     1981    pjsip_target_set_set_current(&inv->dlg->target_set, target); 
     1982 
     1983    (*mod_inv.cb.on_redirected)(inv, target->uri, &op, e); 
     1984 
     1985 
     1986    /* Check what the application wants to do now */ 
     1987    switch (op) { 
     1988    case PJSIP_REDIRECT_ACCEPT: 
     1989    case PJSIP_REDIRECT_STOP: 
     1990        /* Must increment session counter, that's the convention of the  
     1991         * pjsip_inv_process_redirect(). 
     1992         */ 
     1993        pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod); 
     1994 
     1995        /* Act on the recursion */ 
     1996        pjsip_inv_process_redirect(inv, op, e); 
     1997        return PJ_TRUE; 
     1998 
     1999    case PJSIP_REDIRECT_PENDING: 
     2000        /* Increment session so that the dialog/session is not destroyed  
     2001         * while we're waiting for user confirmation. 
     2002         */ 
     2003        pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod); 
     2004 
     2005        /* Also clear the invite_tsx variable, otherwise when this tsx is 
     2006         * terminated, it will also terminate the session. 
     2007         */ 
     2008        inv->invite_tsx = NULL; 
     2009 
     2010        /* Done. The processing will continue once the application calls 
     2011         * pjsip_inv_process_redirect(). 
     2012         */ 
     2013        return PJ_TRUE; 
     2014 
     2015    case PJSIP_REDIRECT_REJECT: 
     2016        /* Recursively call  this function again to fetch next target, if any. 
     2017         */ 
     2018        return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e); 
     2019 
     2020    } 
     2021 
     2022    pj_assert(!"Should not reach here"); 
     2023    return PJ_FALSE; 
     2024} 
     2025 
     2026 
     2027/* Process redirection/recursion */ 
     2028PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv, 
     2029                                                pjsip_redirect_op op, 
     2030                                                pjsip_event *e) 
     2031{ 
     2032    const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED; 
     2033    pjsip_event usr_event; 
     2034    pj_status_t status = PJ_SUCCESS; 
     2035 
     2036    PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL); 
     2037 
     2038    if (e == NULL) { 
     2039        PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL); 
     2040        e = &usr_event; 
     2041    } 
     2042 
     2043    pjsip_dlg_inc_lock(inv->dlg); 
     2044 
     2045    /* Decrement session. That's the convention here to prevent the dialog  
     2046     * or session from being destroyed while we're waiting for user 
     2047     * confirmation. 
     2048     */ 
     2049    pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); 
     2050 
     2051    /* See what the application wants to do now */ 
     2052    switch (op) { 
     2053    case PJSIP_REDIRECT_ACCEPT: 
     2054        /* User accept the redirection. Reset the session and resend the  
     2055         * INVITE request. 
     2056         */ 
     2057        { 
     2058            pjsip_tx_data *tdata; 
     2059            pjsip_via_hdr *via; 
     2060 
     2061            /* Get the original INVITE request. */ 
     2062            tdata = inv->invite_req; 
     2063            pjsip_tx_data_add_ref(tdata); 
     2064 
     2065            /* Restore strict route set. 
     2066             * See http://trac.pjsip.org/repos/ticket/492 
     2067             */ 
     2068            pjsip_restore_strict_route_set(tdata); 
     2069 
     2070            /* Set target */ 
     2071            tdata->msg->line.req.uri =  
     2072               pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri); 
     2073 
     2074            /* Remove branch param in Via header. */ 
     2075            via = (pjsip_via_hdr*)  
     2076                  pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); 
     2077            via->branch_param.slen = 0; 
     2078 
     2079            /* Must invalidate the message! */ 
     2080            pjsip_tx_data_invalidate_msg(tdata); 
     2081 
     2082            /* Reset the session */ 
     2083            pjsip_inv_uac_restart(inv, PJ_FALSE); 
     2084 
     2085            /* (re)Send the INVITE request */ 
     2086            status = pjsip_inv_send_msg(inv, tdata); 
     2087        } 
     2088        break; 
     2089 
     2090    case PJSIP_REDIRECT_STOP: 
     2091        /* User doesn't want the redirection. Disconnect the session now. */ 
     2092        inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code)); 
     2093        inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     2094 
     2095        /* Caller should expect that the invite session is gone now, so 
     2096         * we don't need to set status to PJSIP_ESESSIONTERMINATED here. 
     2097         */ 
     2098        break; 
     2099 
     2100    case PJSIP_REDIRECT_REJECT: 
     2101        /* Current target is rejected. Fetch next target if any. */ 
     2102        if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) { 
     2103            inv_set_cause(inv, cancel_code,  
     2104                          pjsip_get_status_text(cancel_code)); 
     2105            inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     2106 
     2107            /* Tell caller that the invite session is gone now */ 
     2108            status = PJSIP_ESESSIONTERMINATED; 
     2109        } 
     2110        break; 
     2111 
     2112 
     2113    case PJSIP_REDIRECT_PENDING: 
     2114        pj_assert(!"Should not happen"); 
     2115        break; 
     2116    } 
     2117 
     2118 
     2119    pjsip_dlg_dec_lock(inv->dlg); 
     2120 
     2121    return status; 
    18922122} 
    18932123 
     
    25532783        if (dlg->role == PJSIP_ROLE_UAC) { 
    25542784 
     2785            /* Save the original INVITE request, if on_redirected() callback 
     2786             * is implemented. We may need to resend the INVITE if we receive 
     2787             * redirection response. 
     2788             */ 
     2789            if (mod_inv.cb.on_redirected) { 
     2790                if (inv->invite_req) { 
     2791                    pjsip_tx_data_dec_ref(inv->invite_req); 
     2792                    inv->invite_req = NULL; 
     2793                } 
     2794                inv->invite_req = tsx->last_tx; 
     2795                pjsip_tx_data_add_ref(inv->invite_req); 
     2796            } 
     2797 
    25552798            switch (tsx->state) { 
    25562799            case PJSIP_TSX_STATE_CALLING: 
     
    26742917 
    26752918 
     2919/* Handle call rejection, especially with regard to processing call 
     2920 * redirection. We need to handle the following scenarios: 
     2921 *  - 3xx response is received -- see if on_redirected() callback is 
     2922 *    implemented. If so, add the Contact URIs in the response to the 
     2923 *    target set and notify user. 
     2924 *  - 4xx - 6xx resposne is received -- see if we're currently recursing, 
     2925 *    if so fetch the next target if any and notify the on_redirected() 
     2926 *    callback. 
     2927 *  - for other cases -- disconnect the session. 
     2928 */ 
     2929static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e) 
     2930{ 
     2931    pjsip_transaction *tsx = e->body.tsx_state.tsx; 
     2932    pj_status_t status; 
     2933     
     2934    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) { 
     2935 
     2936        if (mod_inv.cb.on_redirected == NULL) { 
     2937 
     2938            /* Redirection callback is not implemented, disconnect the 
     2939             * call. 
     2940             */ 
     2941            goto terminate_session; 
     2942 
     2943        } else { 
     2944            const pjsip_msg *res_msg; 
     2945 
     2946            res_msg = e->body.tsx_state.src.rdata->msg_info.msg; 
     2947 
     2948            /* Gather all Contact URI's in the response and add them 
     2949             * to target set. The function will take care of removing 
     2950             * duplicate URI's. 
     2951             */ 
     2952            pjsip_target_set_add_from_msg(&inv->dlg->target_set,  
     2953                                          inv->dlg->pool, res_msg); 
     2954 
     2955            /* Recurse to alternate targets if application allows us */ 
     2956            if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) 
     2957            { 
     2958                /* Recursion fails, terminate session now */ 
     2959                goto terminate_session; 
     2960            } 
     2961 
     2962            /* Done */ 
     2963        } 
     2964 
     2965    } else if ((tsx->status_code==401 || tsx->status_code==407) && 
     2966                !inv->cancelling)  
     2967    { 
     2968 
     2969        /* Handle authentication failure: 
     2970         * Resend the request with Authorization header. 
     2971         */ 
     2972        pjsip_tx_data *tdata; 
     2973 
     2974        status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,  
     2975                                           e->body.tsx_state.src.rdata, 
     2976                                           tsx->last_tx, 
     2977                                           &tdata); 
     2978 
     2979        if (status != PJ_SUCCESS) { 
     2980 
     2981            /* Does not have proper credentials. If we are currently  
     2982             * recursing, try the next target. Otherwise end the session. 
     2983             */ 
     2984            if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) 
     2985            { 
     2986                /* Recursion fails, terminate session now */ 
     2987                goto terminate_session; 
     2988            } 
     2989 
     2990        } else { 
     2991 
     2992            /* Restart session. */ 
     2993            pjsip_inv_uac_restart(inv, PJ_FALSE); 
     2994 
     2995            /* Send the request. */ 
     2996            status = pjsip_inv_send_msg(inv, tdata); 
     2997        } 
     2998 
     2999    } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) { 
     3000        /* Global error */ 
     3001        goto terminate_session; 
     3002 
     3003    } else { 
     3004        /* See if we have alternate target to try */ 
     3005        if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) { 
     3006            /* Recursion fails, terminate session now */ 
     3007            goto terminate_session; 
     3008        } 
     3009    } 
     3010    return; 
     3011 
     3012terminate_session: 
     3013    inv_set_cause(inv, tsx->status_code, &tsx->status_text); 
     3014    inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     3015} 
     3016 
     3017 
    26763018/* 
    26773019 * State CALLING is after sending initial INVITE request but before 
     
    27363078                                              e->body.tsx_state.src.rdata); 
    27373079 
    2738             } else if ((tsx->status_code==401 || tsx->status_code==407) && 
    2739                         !inv->cancelling)  
    2740             { 
    2741  
    2742                 /* Handle authentication failure: 
    2743                  * Resend the request with Authorization header. 
    2744                  */ 
    2745                 pjsip_tx_data *tdata; 
    2746  
    2747                 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,  
    2748                                                    e->body.tsx_state.src.rdata, 
    2749                                                    tsx->last_tx, 
    2750                                                    &tdata); 
    2751  
    2752                 if (status != PJ_SUCCESS) { 
    2753  
    2754                     /* Does not have proper credentials.  
    2755                      * End the session. 
    2756                      */ 
    2757                     inv_set_cause(inv, tsx->status_code, &tsx->status_text); 
    2758                     inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
    2759  
    2760                 } else { 
    2761  
    2762                     /* Restart session. */ 
    2763                     inv->state = PJSIP_INV_STATE_NULL; 
    2764                     inv->invite_tsx = NULL; 
    2765                     if (inv->last_answer) { 
    2766                         pjsip_tx_data_dec_ref(inv->last_answer); 
    2767                         inv->last_answer = NULL; 
    2768                     } 
    2769  
    2770                     /* Send the request. */ 
    2771                     status = pjsip_inv_send_msg(inv, tdata); 
    2772                 } 
    2773  
    27743080            } else { 
    2775  
    2776                 inv_set_cause(inv, tsx->status_code, &tsx->status_text); 
    2777                 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
    2778  
     3081                handle_uac_call_rejection(inv, e); 
    27793082            } 
    27803083            break; 
     
    29423245                                                  e->body.tsx_state.src.rdata); 
    29433246                } 
     3247 
     3248            } else if (tsx->role == PJSIP_ROLE_UAC) { 
     3249 
     3250                handle_uac_call_rejection(inv, e); 
    29443251 
    29453252            } else { 
  • pjproject/trunk/pjsip/src/pjsip/sip_dialog.c

    r2315 r2370  
    9292        goto on_error; 
    9393 
     94    pjsip_target_set_init(&dlg->target_set); 
    9495 
    9596    *p_dlg = dlg; 
     
    182183        pj_list_init(&uri->header_param); 
    183184    } 
     185 
     186    /* Add target to the target set */ 
     187    pjsip_target_set_add_uri(&dlg->target_set, dlg->pool, dlg->target, 0); 
    184188 
    185189    /* Init local info. */ 
  • pjproject/trunk/pjsip/src/pjsip/sip_util.c

    r2103 r2370  
    4949static pj_str_t str_TEXT = { "text", 4}, 
    5050                str_PLAIN = { "plain", 5 }; 
     51 
     52/* Add URI to target-set */ 
     53PJ_DEF(pj_status_t) pjsip_target_set_add_uri( pjsip_target_set *tset, 
     54                                              pj_pool_t *pool, 
     55                                              const pjsip_uri *uri, 
     56                                              int q1000) 
     57{ 
     58    pjsip_target *t, *pos = NULL; 
     59 
     60    PJ_ASSERT_RETURN(tset && pool && uri, PJ_EINVAL); 
     61 
     62    /* Set q-value to 1 if it is not set */ 
     63    if (q1000 <= 0) 
     64        q1000 = 1000; 
     65 
     66    /* Scan all the elements to see for duplicates, and at the same time 
     67     * get the position where the new element should be inserted to 
     68     * based on the q-value. 
     69     */ 
     70    t = tset->head.next; 
     71    while (t != &tset->head) { 
     72        if (pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, t->uri, uri)==PJ_SUCCESS) 
     73            return PJ_EEXISTS; 
     74        if (pos==NULL && t->q1000 < q1000) 
     75            pos = t; 
     76        t = t->next; 
     77    } 
     78 
     79    /* Create new element */ 
     80    t = PJ_POOL_ZALLOC_T(pool, pjsip_target); 
     81    t->uri = pjsip_uri_clone(pool, uri); 
     82    t->q1000 = q1000; 
     83 
     84    /* Insert */ 
     85    if (pos == NULL) 
     86        pj_list_push_back(&tset->head, t); 
     87    else 
     88        pj_list_insert_before(pos, t); 
     89 
     90    /* Set current target if this is the first URI */ 
     91    if (tset->current == NULL) 
     92        tset->current = t; 
     93 
     94    return PJ_SUCCESS; 
     95} 
     96 
     97/* Add URI's in the Contact header in the message to target-set */ 
     98PJ_DEF(pj_status_t) pjsip_target_set_add_from_msg( pjsip_target_set *tset, 
     99                                                   pj_pool_t *pool, 
     100                                                   const pjsip_msg *msg) 
     101{ 
     102    const pjsip_hdr *hdr; 
     103    unsigned added = 0; 
     104 
     105    PJ_ASSERT_RETURN(tset && pool && msg, PJ_EINVAL); 
     106 
     107    /* Scan for Contact headers and add the URI */ 
     108    hdr = msg->hdr.next; 
     109    while (hdr != &msg->hdr) { 
     110        if (hdr->type == PJSIP_H_CONTACT) { 
     111            const pjsip_contact_hdr *cn_hdr = (const pjsip_contact_hdr*)hdr; 
     112 
     113            if (!cn_hdr->star) { 
     114                pj_status_t rc; 
     115                rc = pjsip_target_set_add_uri(tset, pool, cn_hdr->uri,  
     116                                              cn_hdr->q1000); 
     117                if (rc == PJ_SUCCESS) 
     118                    ++added; 
     119            } 
     120        } 
     121        hdr = hdr->next; 
     122    } 
     123 
     124    return added ? PJ_SUCCESS : PJ_EEXISTS; 
     125} 
     126 
     127 
     128/* Get next target, if any */ 
     129PJ_DEF(pjsip_target*) pjsip_target_set_get_next(const pjsip_target_set *tset) 
     130{ 
     131    const pjsip_target *t, *next = NULL; 
     132 
     133    t = tset->head.next; 
     134    while (t != &tset->head) { 
     135        if (PJSIP_IS_STATUS_IN_CLASS(t->code, 200)) { 
     136            /* No more target since one target has been successful */ 
     137            return NULL; 
     138        } 
     139        if (PJSIP_IS_STATUS_IN_CLASS(t->code, 600)) { 
     140            /* No more target since one target returned global error */ 
     141            return NULL; 
     142        } 
     143        if (t->code==0 && next==NULL) { 
     144            /* This would be the next target as long as we don't find 
     145             * targets with 2xx or 6xx status after this. 
     146             */ 
     147            next = t; 
     148        } 
     149        t = t->next; 
     150    } 
     151 
     152    return (pjsip_target*)next; 
     153} 
     154 
     155 
     156/* Set current target */ 
     157PJ_DEF(pj_status_t) pjsip_target_set_set_current( pjsip_target_set *tset, 
     158                                                  pjsip_target *target) 
     159{ 
     160    PJ_ASSERT_RETURN(tset && target, PJ_EINVAL); 
     161    PJ_ASSERT_RETURN(pj_list_find_node(tset, target) != NULL, PJ_ENOTFOUND); 
     162 
     163    tset->current = target; 
     164 
     165    return PJ_SUCCESS; 
     166} 
     167 
     168 
     169/* Assign status to a target */ 
     170PJ_DEF(pj_status_t) pjsip_target_assign_status( pjsip_target *target, 
     171                                                pj_pool_t *pool, 
     172                                                int status_code, 
     173                                                const pj_str_t *reason) 
     174{ 
     175    PJ_ASSERT_RETURN(target && pool && status_code && reason, PJ_EINVAL); 
     176 
     177    target->code = status_code; 
     178    pj_strdup(pool, &target->reason, reason); 
     179 
     180    return PJ_SUCCESS; 
     181} 
     182 
     183 
    51184 
    52185/* 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r2315 r2370  
    6565                                            pjsip_transaction *tsx, 
    6666                                            pjsip_event *e); 
     67 
     68/* 
     69 * Redirection handler. 
     70 */ 
     71static void pjsua_call_on_redirected(pjsip_inv_session *inv,  
     72                                     const pjsip_uri *target, 
     73                                     pjsip_redirect_op *cmd,  
     74                                     const pjsip_event *e); 
    6775 
    6876 
     
    157165    inv_cb.on_create_offer = &pjsua_call_on_create_offer; 
    158166    inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed; 
    159  
     167    inv_cb.on_redirected = &pjsua_call_on_redirected; 
    160168 
    161169    /* Initialize invite session module: */ 
     
    14311439 
    14321440    return PJ_SUCCESS; 
     1441} 
     1442 
     1443 
     1444/* 
     1445 * Accept or reject redirection. 
     1446 */ 
     1447PJ_DEF(pj_status_t) pjsua_call_process_redirect( pjsua_call_id call_id, 
     1448                                                 pjsip_redirect_op cmd) 
     1449{ 
     1450    pjsua_call *call; 
     1451    pjsip_dialog *dlg; 
     1452    pj_status_t status; 
     1453 
     1454    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     1455                     PJ_EINVAL); 
     1456 
     1457    status = acquire_call("pjsua_call_process_redirect()", call_id,  
     1458                          &call, &dlg); 
     1459    if (status != PJ_SUCCESS) 
     1460        return status; 
     1461 
     1462    status = pjsip_inv_process_redirect(call->inv, cmd, NULL); 
     1463 
     1464    pjsip_dlg_dec_lock(dlg); 
     1465 
     1466    return status; 
    14331467} 
    14341468 
     
    28282862            if (call->res_time.sec == 0) 
    28292863                pj_gettimeofday(&call->res_time); 
    2830             if (e->body.tsx_state.tsx->status_code > call->last_code) { 
     2864            if (e->type == PJSIP_EVENT_TSX_STATE &&  
     2865                e->body.tsx_state.tsx->status_code > call->last_code)  
     2866            { 
    28312867                call->last_code = (pjsip_status_code)  
    28322868                                  e->body.tsx_state.tsx->status_code; 
    28332869                pj_strncpy(&call->last_text,  
    28342870                           &e->body.tsx_state.tsx->status_text, 
     2871                           sizeof(call->last_text_buf_)); 
     2872            } else { 
     2873                call->last_code = PJSIP_SC_REQUEST_TERMINATED; 
     2874                pj_strncpy(&call->last_text, 
     2875                           pjsip_get_status_text(call->last_code), 
    28352876                           sizeof(call->last_text_buf_)); 
    28362877            } 
     
    37713812    PJSUA_UNLOCK(); 
    37723813} 
     3814 
     3815 
     3816/* Redirection handler */ 
     3817static void pjsua_call_on_redirected(pjsip_inv_session *inv,  
     3818                                     const pjsip_uri *target, 
     3819                                     pjsip_redirect_op *cmd,  
     3820                                     const pjsip_event *e) 
     3821{ 
     3822    pjsua_call *call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id]; 
     3823 
     3824    PJSUA_LOCK(); 
     3825 
     3826    if (pjsua_var.ua_cfg.cb.on_call_redirected) { 
     3827        (*pjsua_var.ua_cfg.cb.on_call_redirected)(call->index, target, cmd, e); 
     3828    } else { 
     3829        PJ_LOG(4,(THIS_FILE, "Unhandled redirection for call %d " 
     3830                  "(callback not implemented by application). Disconnecting " 
     3831                  "call.", 
     3832                  call->index)); 
     3833        *cmd = PJSIP_REDIRECT_STOP; 
     3834    } 
     3835 
     3836    PJSUA_UNLOCK(); 
     3837} 
     3838 
Note: See TracChangeset for help on using the changeset viewer.