Changeset 2315


Ignore:
Timestamp:
Sep 24, 2008 10:10:15 AM (11 years ago)
Author:
bennylp
Message:

Ticket #635: Disconnect the other call leg when multiple 2xx/OK responses to INVITE are received due to forking

Location:
pjproject/trunk/pjsip
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r2301 r2315  
    12311231#endif 
    12321232 
     1233    /** 
     1234     * Disconnect other call legs when more than one 2xx responses for  
     1235     * outgoing INVITE are received due to forking. Currently the library 
     1236     * is not able to handle simultaneous forked media, so disconnecting 
     1237     * the other call legs is necessary.  
     1238     * 
     1239     * With this setting enabled, the library will handle only one of the 
     1240     * connected call leg, and the other connected call legs will be 
     1241     * disconnected.  
     1242     * 
     1243     * Default: PJ_TRUE (only disable this setting for testing purposes). 
     1244     */ 
     1245    pj_bool_t        hangup_forked_call; 
     1246 
    12331247} pjsua_config; 
    12341248 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r2301 r2315  
    499499                           pjsip_tpselector *sel); 
    500500 
    501  
     501pjsip_dialog* on_dlg_forked(pjsip_dialog *first_set, pjsip_rx_data *res); 
    502502pj_status_t acquire_call(const char *title, 
    503503                         pjsua_call_id call_id, 
  • pjproject/trunk/pjsip/src/pjsip/sip_dialog.c

    r2271 r2315  
    581581{ 
    582582    pjsip_dialog *dlg; 
    583     const pjsip_route_hdr *r; 
     583    const pjsip_msg *msg = rdata->msg_info.msg; 
     584    const pjsip_hdr *end_hdr, *hdr; 
     585    const pjsip_contact_hdr *contact; 
    584586    pj_status_t status; 
    585587 
     
    588590     
    589591    /* rdata must be response message. */ 
    590     PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG, 
     592    PJ_ASSERT_RETURN(msg->type == PJSIP_RESPONSE_MSG, 
    591593                     PJSIP_ENOTRESPONSEMSG); 
    592594 
    593595    /* Status code MUST be 1xx (but not 100), or 2xx */ 
    594     status = rdata->msg_info.msg->line.status.code; 
     596    status = msg->line.status.code; 
    595597    PJ_ASSERT_RETURN( (status/100==1 && status!=100) || 
    596598                      (status/100==2), PJ_EBUG); 
     
    598600    /* To tag must present in the response. */ 
    599601    PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG); 
     602 
     603    /* Find Contact header in the response */ 
     604    contact = (const pjsip_contact_hdr*) 
     605              pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL); 
     606    if (contact == NULL) 
     607        return PJSIP_EMISSINGHDR; 
    600608 
    601609    /* Create the dialog. */ 
     
    604612        return status; 
    605613 
    606     /* Clone remote target. */ 
    607     dlg->target = (pjsip_uri*) pjsip_uri_clone(dlg->pool, first_dlg->target); 
     614    /* Set remote target from the response. */ 
     615    dlg->target = (pjsip_uri*) pjsip_uri_clone(dlg->pool, contact->uri); 
    608616 
    609617    /* Clone local info. */ 
     
    637645 
    638646    /* Dialog state depends on the response. */ 
    639     status = rdata->msg_info.msg->line.status.code/100; 
     647    status = msg->line.status.code/100; 
    640648    if (status == 1 || status == 2) 
    641649        dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED; 
     
    652660                   pjsip_hdr_clone(dlg->pool, first_dlg->call_id); 
    653661 
    654     /* Duplicate Route-Set. */ 
     662    /* Get route-set from the response. */ 
    655663    pj_list_init(&dlg->route_set); 
    656     r = first_dlg->route_set.next; 
    657     while (r != &first_dlg->route_set) { 
    658         pjsip_route_hdr *h; 
    659  
    660         h = (pjsip_route_hdr*) pjsip_hdr_clone(dlg->pool, r); 
    661         pj_list_push_back(&dlg->route_set, h); 
    662  
    663         r = r->next; 
    664     } 
     664    end_hdr = &msg->hdr; 
     665    for (hdr=msg->hdr.prev; hdr!=end_hdr; hdr=hdr->prev) { 
     666        if (hdr->type == PJSIP_H_RECORD_ROUTE) { 
     667            pjsip_route_hdr *r; 
     668            r = (pjsip_route_hdr*) pjsip_hdr_clone(dlg->pool, hdr); 
     669            pjsip_routing_hdr_set_route(r); 
     670            pj_list_push_back(&dlg->route_set, r); 
     671        } 
     672    } 
     673 
    665674    //dlg->route_set_frozen = PJ_TRUE; 
    666675 
     
    18141823    } 
    18151824 
     1825    /* Handle the case of forked response, when the application creates 
     1826     * the forked dialog but not the invite session. In this case, the 
     1827     * forked 200/OK response will be unhandled, and we must send ACK 
     1828     * here. 
     1829     */ 
     1830    if (dlg->usage_cnt==0) { 
     1831        pj_status_t status; 
     1832 
     1833        if (rdata->msg_info.cseq->method.id==PJSIP_INVITE_METHOD &&  
     1834            rdata->msg_info.msg->line.status.code/100 == 2)  
     1835        { 
     1836            pjsip_tx_data *ack; 
     1837 
     1838            status = pjsip_dlg_create_request(dlg, &pjsip_ack_method, 
     1839                                              rdata->msg_info.cseq->cseq, 
     1840                                              &ack); 
     1841            if (status == PJ_SUCCESS) 
     1842                status = pjsip_dlg_send_request(dlg, ack, -1, NULL); 
     1843        } else if (rdata->msg_info.msg->line.status.code==401 || 
     1844                   rdata->msg_info.msg->line.status.code==407) 
     1845        { 
     1846            pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); 
     1847            pjsip_tx_data *tdata; 
     1848             
     1849            status = pjsip_auth_clt_reinit_req( &dlg->auth_sess,  
     1850                                                rdata, tsx->last_tx, 
     1851                                                &tdata); 
     1852             
     1853            if (status == PJ_SUCCESS) { 
     1854                /* Re-send request. */ 
     1855                status = pjsip_dlg_send_request(dlg, tdata, -1, NULL); 
     1856            } 
     1857        } 
     1858    } 
     1859 
    18161860    /* Unhandled response does not necessarily mean error because 
    18171861       dialog usages may choose to process the transaction state instead. 
  • pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c

    r2039 r2315  
    833833                dlg = (*mod_ua.param.on_dlg_forked)(dlg_set->dlg_list.next,  
    834834                                                    rdata); 
     835                if (dlg == NULL) { 
     836                    pj_mutex_unlock(mod_ua.mutex); 
     837                    return PJ_TRUE; 
     838                } 
    835839            } else { 
    836840                dlg = dlg_set->dlg_list.next; 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r2301 r2315  
    29442944 
    29452945/* 
     2946 * Callback from UA layer when forked dialog response is received. 
     2947 */ 
     2948pjsip_dialog* on_dlg_forked(pjsip_dialog *dlg, pjsip_rx_data *res) 
     2949{ 
     2950    if (dlg->uac_has_2xx &&  
     2951        res->msg_info.cseq->method.id == PJSIP_INVITE_METHOD && 
     2952        pjsip_rdata_get_tsx(res) == NULL && 
     2953        res->msg_info.msg->line.status.code/100 == 2)  
     2954    { 
     2955        pjsip_dialog *forked_dlg; 
     2956        pjsip_tx_data *bye; 
     2957        pj_status_t status; 
     2958 
     2959        /* Create forked dialog */ 
     2960        status = pjsip_dlg_fork(dlg, res, &forked_dlg); 
     2961        if (status != PJ_SUCCESS) 
     2962            return NULL; 
     2963 
     2964        pjsip_dlg_inc_lock(forked_dlg); 
     2965 
     2966        /* Disconnect the call */ 
     2967        status = pjsip_dlg_create_request(forked_dlg, &pjsip_bye_method, 
     2968                                          -1, &bye); 
     2969        if (status == PJ_SUCCESS) { 
     2970            status = pjsip_dlg_send_request(forked_dlg, bye, -1, NULL); 
     2971        } 
     2972 
     2973        pjsip_dlg_dec_lock(forked_dlg); 
     2974 
     2975        if (status != PJ_SUCCESS) { 
     2976            return NULL; 
     2977        } 
     2978 
     2979        return forked_dlg; 
     2980 
     2981    } else { 
     2982        return dlg; 
     2983    } 
     2984} 
     2985 
     2986/* 
    29462987 * Disconnect call upon error. 
    29472988 */ 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r2301 r2315  
    9797    cfg->srtp_secure_signaling = PJSUA_DEFAULT_SRTP_SECURE_SIGNALING; 
    9898#endif 
     99    cfg->hangup_forked_call = PJ_TRUE; 
    99100} 
    100101 
     
    623624    pjsua_media_config   default_media_cfg; 
    624625    const pj_str_t       STR_OPTIONS = { "OPTIONS", 7 }; 
     626    pjsip_ua_init_param  ua_init_param; 
    625627    pj_status_t status; 
    626628 
     
    695697 
    696698    /* Initialize UA layer module: */ 
    697     status = pjsip_ua_init_module( pjsua_var.endpt, NULL ); 
     699    pj_bzero(&ua_init_param, sizeof(ua_init_param)); 
     700    if (ua_cfg->hangup_forked_call) { 
     701        ua_init_param.on_dlg_forked = &on_dlg_forked; 
     702    } 
     703    status = pjsip_ua_init_module( pjsua_var.endpt, &ua_init_param); 
    698704    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    699705 
Note: See TracChangeset for help on using the changeset viewer.