Changeset 3215


Ignore:
Timestamp:
Jun 21, 2010 1:28:55 PM (14 years ago)
Author:
bennylp
Message:

Fixes #1047 (Don't send UPDATE if remote doesn't support it (thanks Bogdan Krakowski for the report)) and fixes #1097 (Support sending UPDATE without SDP). Details:

  • Session timer fixes:
    • will look at remote capability in Allow header
    • if UPDATE is supported, will send UPDATE without SDP first. If this fails, will send UPDATE with SDP
    • otherwise will send re-INVITE
  • PJSUA-LIB will look at dialog's remote capability to determine whether re-INVITE or UPDATE should be sent to change default addresses after ICE negotiation.
  • pjsip_inv_update() now allows NULL offer, in which case the UPDATE will be sent without SDP.
Location:
pjproject/trunk
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c

    r3208 r3215  
    23942394 
    23952395    /* Verify arguments. */ 
    2396     PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL); 
     2396    PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL); 
    23972397 
    23982398    /* Dialog must have been established */ 
     
    24072407    pjsip_dlg_inc_lock(inv->dlg); 
    24082408 
    2409     /* Process offer */ 
    2410     if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) { 
    2411         PJ_LOG(4,(inv->dlg->obj_name,  
    2412                   "Invalid SDP offer/answer state for UPDATE")); 
    2413         status = PJ_EINVALIDOP; 
    2414         goto on_error; 
    2415     } 
    2416  
    2417     /* Notify negotiator about the new offer. This will fix the offer 
    2418      * with correct SDP origin. 
    2419      */ 
    2420     status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov, inv->neg, 
    2421                                                 offer); 
    2422     if (status != PJ_SUCCESS) 
    2423         goto on_error; 
    2424  
    2425     /* Retrieve the "fixed" offer from negotiator */ 
    2426     pjmedia_sdp_neg_get_neg_local(inv->neg, &offer); 
     2409    /* Process offer, if any */ 
     2410    if (offer) { 
     2411        if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) { 
     2412            PJ_LOG(4,(inv->dlg->obj_name, 
     2413                      "Invalid SDP offer/answer state for UPDATE")); 
     2414            status = PJ_EINVALIDOP; 
     2415            goto on_error; 
     2416        } 
     2417 
     2418        /* Notify negotiator about the new offer. This will fix the offer 
     2419         * with correct SDP origin. 
     2420         */ 
     2421        status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov, inv->neg, 
     2422                                                    offer); 
     2423        if (status != PJ_SUCCESS) 
     2424            goto on_error; 
     2425 
     2426        /* Retrieve the "fixed" offer from negotiator */ 
     2427        pjmedia_sdp_neg_get_neg_local(inv->neg, &offer); 
     2428    } 
    24272429 
    24282430    /* Update Contact if required */ 
     
    24502452 
    24512453    /* Attach SDP body */ 
    2452     sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer); 
    2453     pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body); 
     2454    if (offer) { 
     2455        sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer); 
     2456        pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body); 
     2457    } 
    24542458 
    24552459    /* Unlock dialog. */ 
     
    28802884    else  
    28812885    { 
     2886        /* Session-Timer needs to see any error responses, to determine 
     2887         * whether peer supports UPDATE with empty body. 
     2888         */ 
     2889        if (tsx->state == PJSIP_TSX_STATE_COMPLETED && 
     2890            tsx->role == PJSIP_ROLE_UAC) 
     2891        { 
     2892            status = handle_timer_response(inv, e->body.tsx_state.src.rdata, 
     2893                                           PJ_FALSE); 
     2894        } 
     2895 
    28822896        tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id]; 
    28832897        if (tsx_inv_data == NULL) { 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_timer.c

    r2934 r3215  
    6060    pj_bool_t                    use_update;    /**< Use UPDATE method to 
    6161                                                     refresh the session    */ 
     62    pj_bool_t                    with_sdp;      /**< SDP in UPDATE?         */ 
    6263    pjsip_role_e                 role;          /**< Role in last INVITE/ 
    6364                                                     UPDATE transaction.    */ 
     
    322323 * the session. 
    323324 */ 
    324 void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry) 
     325static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry) 
    325326{ 
    326327    pjsip_inv_session *inv = (pjsip_inv_session*) entry->user_data; 
     
    331332    pj_assert(inv); 
    332333 
     334    inv->timer->timer.id = 0; 
     335 
    333336    PJ_UNUSED_ARG(timer_heap); 
    334  
    335     /* When there is a pending INVITE transaction, delay/reschedule this timer 
    336      * for five seconds to cover the case that pending INVITE fails and the 
    337      * previous session is still active. If the pending INVITE is successful,  
    338      * timer state will be updated, i.e: restarted or stopped. 
    339      */ 
    340     if (inv->invite_tsx != NULL) { 
    341         pj_time_val delay = {5}; 
    342  
    343         inv->timer->timer.id = 1; 
    344         pjsip_endpt_schedule_timer(inv->dlg->endpt, &inv->timer->timer, &delay); 
    345         return; 
    346     } 
    347337 
    348338    /* Lock dialog. */ 
     
    350340 
    351341    /* Check our role */ 
    352     as_refresher =  
     342    as_refresher = 
    353343        (inv->timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) || 
    354344        (inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS); 
     
    356346    /* Do action based on role, refresher or refreshee */ 
    357347    if (as_refresher) { 
    358  
    359348        pj_time_val now; 
     349 
     350        /* As refresher, reshedule the refresh request on the following: 
     351         *  - msut not send re-INVITE if another INVITE or SDP negotiation 
     352         *    is in progress. 
     353         *  - must not send UPDATE with SDP if SDP negotiation is in progress 
     354         */ 
     355        pjmedia_sdp_neg_state neg_state = pjmedia_sdp_neg_get_state(inv->neg); 
     356        if ( (!inv->timer->use_update && ( 
     357                        inv->invite_tsx != NULL || 
     358                        neg_state != PJMEDIA_SDP_NEG_STATE_DONE) 
     359             ) 
     360             || 
     361             (inv->timer->use_update && inv->timer->with_sdp && 
     362                     neg_state != PJMEDIA_SDP_NEG_STATE_DONE 
     363             ) 
     364           ) 
     365        { 
     366            pj_time_val delay = {1, 0}; 
     367 
     368            inv->timer->timer.id = 1; 
     369            pjsip_endpt_schedule_timer(inv->dlg->endpt, &inv->timer->timer, 
     370                                       &delay); 
     371            pjsip_dlg_dec_lock(inv->dlg); 
     372            return; 
     373        } 
    360374 
    361375        /* Refresher, refresh the session */ 
    362376        if (inv->timer->use_update) { 
    363             /* Create UPDATE request without offer */ 
    364             status = pjsip_inv_update(inv, NULL, NULL, &tdata); 
     377            const pjmedia_sdp_session *offer = NULL; 
     378 
     379            if (inv->timer->with_sdp) { 
     380                pjmedia_sdp_neg_get_active_local(inv->neg, &offer); 
     381            } 
     382            status = pjsip_inv_update(inv, NULL, offer, &tdata); 
    365383        } else { 
    366384            /* Create re-INVITE without modifying session */ 
     
    385403 
    386404        pj_gettimeofday(&now); 
    387         PJ_LOG(4, (inv->pool->obj_name,  
    388                    "Refresh session after %ds (expiration period=%ds)", 
     405        PJ_LOG(4, (inv->pool->obj_name, 
     406                   "Refreshing session after %ds (expiration period=%ds)", 
    389407                   (now.sec-inv->timer->last_refresh.sec), 
    390408                   inv->timer->setting.sess_expires)); 
     
    415433    /* Print error message, if any */ 
    416434    if (status != PJ_SUCCESS) { 
    417         char errmsg[PJ_ERR_MSG_SIZE]; 
    418  
    419435        if (tdata) 
    420436            pjsip_tx_data_dec_ref(tdata); 
    421437 
    422         pj_strerror(status, errmsg, sizeof(errmsg)); 
    423         PJ_LOG(2, (inv->pool->obj_name, "Session timer fails in %s session, " 
    424                                         "err code=%d (%s)", 
    425                                         (as_refresher? "refreshing" :  
    426                                                        "terminating"), 
    427                                         status, errmsg));                                        
     438        PJ_PERROR(2, (inv->pool->obj_name, status, 
     439                      "Error in %s session timer", 
     440                      (as_refresher? "refreshing" : "terminating"))); 
    428441    } 
    429442} 
     
    432445static void start_timer(pjsip_inv_session *inv) 
    433446{ 
     447    const pj_str_t UPDATE = { "UPDATE", 6 }; 
    434448    pjsip_timer *timer = inv->timer; 
    435449    pj_time_val delay = {0}; 
     
    438452 
    439453    stop_timer(inv); 
     454 
     455    inv->timer->use_update = 
     456            (pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, 
     457                                      &UPDATE) == PJSIP_DIALOG_CAP_SUPPORTED); 
     458    if (!inv->timer->use_update) { 
     459        /* INVITE always needs SDP */ 
     460        inv->timer->with_sdp = PJ_TRUE; 
     461    } 
    440462 
    441463    pj_timer_entry_init(&timer->timer, 
     
    838860            inv->timer->refresher = TR_UAC; 
    839861 
    840         PJ_TODO(CHECK_IF_REMOTE_SUPPORT_UPDATE); 
    841  
    842862        /* Remember our role in this transaction */ 
    843863        inv->timer->role = PJSIP_ROLE_UAC; 
     
    846866        inv->timer->active = PJ_TRUE; 
    847867        start_timer(inv); 
     868 
     869    } else if (pjsip_method_cmp(&rdata->msg_info.cseq->method, 
     870                                &pjsip_update_method) == 0 && 
     871               msg->line.status.code >= 400 && msg->line.status.code < 600) 
     872    { 
     873        /* This is to handle error response to previous UPDATE that was 
     874         * sent without SDP. In this case, retry sending UPDATE but 
     875         * with SDP this time. 
     876         * Note: the additional expressions are to check that the 
     877         *       UPDATE was really the one sent by us, not by other 
     878         *       call components (e.g. to change codec) 
     879         */ 
     880        if (inv->timer->timer.id == 0 && inv->timer->use_update && 
     881            inv->timer->with_sdp == PJ_FALSE) 
     882        { 
     883            inv->timer->with_sdp = PJ_TRUE; 
     884            timer_cb(NULL, &inv->timer->timer); 
     885        } 
    848886    } 
    849887 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r3212 r3215  
    856856                                &pjsua_var.calls[id].med_rtp_addr)) 
    857857            { 
     858                pj_bool_t use_update; 
     859                const pj_str_t STR_UPDATE = { "UPDATE", 6 }; 
     860                pjsip_dialog_cap_status support_update; 
     861                pjsip_dialog *dlg; 
     862 
     863                dlg = pjsua_var.calls[id].inv->dlg; 
     864                support_update = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_ALLOW, 
     865                                                          NULL, &STR_UPDATE); 
     866                use_update = (support_update == PJSIP_DIALOG_CAP_SUPPORTED); 
     867 
    858868                PJ_LOG(4,(THIS_FILE,  
    859869                          "ICE default transport address has changed for " 
    860                           "call %d, sending UPDATE", id)); 
    861                 pjsua_call_update(id, 0, NULL); 
     870                          "call %d, sending %s", id, 
     871                          (use_update ? "UPDATE" : "re-INVITE"))); 
     872 
     873                if (use_update) 
     874                    pjsua_call_update(id, 0, NULL); 
     875                else 
     876                    pjsua_call_reinvite(id, 0, NULL); 
    862877            } 
    863878        } 
Note: See TracChangeset for help on using the changeset viewer.