summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2010-06-21 13:28:55 +0000
committerBenny Prijono <bennylp@teluu.com>2010-06-21 13:28:55 +0000
commit9a61cdc66183f1c4ed0c4a4e27ebc1b6a67ac183 (patch)
tree939edcabf9094e583729718acfe0087bf238c8c3 /pjsip
parent6fa4d964245209d05d9c1cce6e8f12ab993a03a1 (diff)
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. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3215 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c52
-rw-r--r--pjsip/src/pjsip-ua/sip_timer.c98
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c19
3 files changed, 118 insertions, 51 deletions
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index ecfebec3..c58a92f7 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -2393,7 +2393,7 @@ PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
pj_status_t status = PJ_SUCCESS;
/* Verify arguments. */
- PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL);
+ PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
/* Dialog must have been established */
PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
@@ -2406,24 +2406,26 @@ PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
/* Lock dialog. */
pjsip_dlg_inc_lock(inv->dlg);
- /* Process offer */
- if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
- PJ_LOG(4,(inv->dlg->obj_name,
- "Invalid SDP offer/answer state for UPDATE"));
- status = PJ_EINVALIDOP;
- goto on_error;
- }
+ /* Process offer, if any */
+ if (offer) {
+ if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
+ PJ_LOG(4,(inv->dlg->obj_name,
+ "Invalid SDP offer/answer state for UPDATE"));
+ status = PJ_EINVALIDOP;
+ goto on_error;
+ }
- /* Notify negotiator about the new offer. This will fix the offer
- * with correct SDP origin.
- */
- status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov, inv->neg,
- offer);
- if (status != PJ_SUCCESS)
- goto on_error;
+ /* Notify negotiator about the new offer. This will fix the offer
+ * with correct SDP origin.
+ */
+ status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov, inv->neg,
+ offer);
+ if (status != PJ_SUCCESS)
+ goto on_error;
- /* Retrieve the "fixed" offer from negotiator */
- pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
+ /* Retrieve the "fixed" offer from negotiator */
+ pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
+ }
/* Update Contact if required */
if (new_contact) {
@@ -2449,8 +2451,10 @@ PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
goto on_error;
/* Attach SDP body */
- sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
- pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
+ if (offer) {
+ sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
+ pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
+ }
/* Unlock dialog. */
pjsip_dlg_dec_lock(inv->dlg);
@@ -2879,6 +2883,16 @@ static void inv_handle_update_response( pjsip_inv_session *inv,
/* Get/attach invite session's transaction data */
else
{
+ /* Session-Timer needs to see any error responses, to determine
+ * whether peer supports UPDATE with empty body.
+ */
+ if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
+ tsx->role == PJSIP_ROLE_UAC)
+ {
+ status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
+ PJ_FALSE);
+ }
+
tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
if (tsx_inv_data == NULL) {
tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
diff --git a/pjsip/src/pjsip-ua/sip_timer.c b/pjsip/src/pjsip-ua/sip_timer.c
index 34676e0d..bb97c3d0 100644
--- a/pjsip/src/pjsip-ua/sip_timer.c
+++ b/pjsip/src/pjsip-ua/sip_timer.c
@@ -59,6 +59,7 @@ struct pjsip_timer
pj_timer_entry timer; /**< Timer entry */
pj_bool_t use_update; /**< Use UPDATE method to
refresh the session */
+ pj_bool_t with_sdp; /**< SDP in UPDATE? */
pjsip_role_e role; /**< Role in last INVITE/
UPDATE transaction. */
@@ -321,7 +322,7 @@ static void add_timer_headers(pjsip_inv_session *inv, pjsip_tx_data *tdata,
* the session if UA is the refresher, otherwise it is time to end
* the session.
*/
-void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
+static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
{
pjsip_inv_session *inv = (pjsip_inv_session*) entry->user_data;
pjsip_tx_data *tdata = NULL;
@@ -330,38 +331,55 @@ void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
pj_assert(inv);
- PJ_UNUSED_ARG(timer_heap);
-
- /* When there is a pending INVITE transaction, delay/reschedule this timer
- * for five seconds to cover the case that pending INVITE fails and the
- * previous session is still active. If the pending INVITE is successful,
- * timer state will be updated, i.e: restarted or stopped.
- */
- if (inv->invite_tsx != NULL) {
- pj_time_val delay = {5};
+ inv->timer->timer.id = 0;
- inv->timer->timer.id = 1;
- pjsip_endpt_schedule_timer(inv->dlg->endpt, &inv->timer->timer, &delay);
- return;
- }
+ PJ_UNUSED_ARG(timer_heap);
/* Lock dialog. */
pjsip_dlg_inc_lock(inv->dlg);
/* Check our role */
- as_refresher =
+ as_refresher =
(inv->timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
(inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS);
/* Do action based on role, refresher or refreshee */
if (as_refresher) {
-
pj_time_val now;
+ /* As refresher, reshedule the refresh request on the following:
+ * - msut not send re-INVITE if another INVITE or SDP negotiation
+ * is in progress.
+ * - must not send UPDATE with SDP if SDP negotiation is in progress
+ */
+ pjmedia_sdp_neg_state neg_state = pjmedia_sdp_neg_get_state(inv->neg);
+ if ( (!inv->timer->use_update && (
+ inv->invite_tsx != NULL ||
+ neg_state != PJMEDIA_SDP_NEG_STATE_DONE)
+ )
+ ||
+ (inv->timer->use_update && inv->timer->with_sdp &&
+ neg_state != PJMEDIA_SDP_NEG_STATE_DONE
+ )
+ )
+ {
+ pj_time_val delay = {1, 0};
+
+ inv->timer->timer.id = 1;
+ pjsip_endpt_schedule_timer(inv->dlg->endpt, &inv->timer->timer,
+ &delay);
+ pjsip_dlg_dec_lock(inv->dlg);
+ return;
+ }
+
/* Refresher, refresh the session */
if (inv->timer->use_update) {
- /* Create UPDATE request without offer */
- status = pjsip_inv_update(inv, NULL, NULL, &tdata);
+ const pjmedia_sdp_session *offer = NULL;
+
+ if (inv->timer->with_sdp) {
+ pjmedia_sdp_neg_get_active_local(inv->neg, &offer);
+ }
+ status = pjsip_inv_update(inv, NULL, offer, &tdata);
} else {
/* Create re-INVITE without modifying session */
pjsip_msg_body *body;
@@ -384,8 +402,8 @@ void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
}
pj_gettimeofday(&now);
- PJ_LOG(4, (inv->pool->obj_name,
- "Refresh session after %ds (expiration period=%ds)",
+ PJ_LOG(4, (inv->pool->obj_name,
+ "Refreshing session after %ds (expiration period=%ds)",
(now.sec-inv->timer->last_refresh.sec),
inv->timer->setting.sess_expires));
} else {
@@ -414,23 +432,19 @@ void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
/* Print error message, if any */
if (status != PJ_SUCCESS) {
- char errmsg[PJ_ERR_MSG_SIZE];
-
if (tdata)
pjsip_tx_data_dec_ref(tdata);
- pj_strerror(status, errmsg, sizeof(errmsg));
- PJ_LOG(2, (inv->pool->obj_name, "Session timer fails in %s session, "
- "err code=%d (%s)",
- (as_refresher? "refreshing" :
- "terminating"),
- status, errmsg));
+ PJ_PERROR(2, (inv->pool->obj_name, status,
+ "Error in %s session timer",
+ (as_refresher? "refreshing" : "terminating")));
}
}
/* Start Session Timers */
static void start_timer(pjsip_inv_session *inv)
{
+ const pj_str_t UPDATE = { "UPDATE", 6 };
pjsip_timer *timer = inv->timer;
pj_time_val delay = {0};
@@ -438,6 +452,14 @@ static void start_timer(pjsip_inv_session *inv)
stop_timer(inv);
+ inv->timer->use_update =
+ (pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL,
+ &UPDATE) == PJSIP_DIALOG_CAP_SUPPORTED);
+ if (!inv->timer->use_update) {
+ /* INVITE always needs SDP */
+ inv->timer->with_sdp = PJ_TRUE;
+ }
+
pj_timer_entry_init(&timer->timer,
1, /* id */
inv, /* user data */
@@ -837,14 +859,30 @@ PJ_DEF(pj_status_t) pjsip_timer_process_resp(pjsip_inv_session *inv,
*/
inv->timer->refresher = TR_UAC;
- PJ_TODO(CHECK_IF_REMOTE_SUPPORT_UPDATE);
-
/* Remember our role in this transaction */
inv->timer->role = PJSIP_ROLE_UAC;
/* Finally, set active flag and start the Session Timers */
inv->timer->active = PJ_TRUE;
start_timer(inv);
+
+ } else if (pjsip_method_cmp(&rdata->msg_info.cseq->method,
+ &pjsip_update_method) == 0 &&
+ msg->line.status.code >= 400 && msg->line.status.code < 600)
+ {
+ /* This is to handle error response to previous UPDATE that was
+ * sent without SDP. In this case, retry sending UPDATE but
+ * with SDP this time.
+ * Note: the additional expressions are to check that the
+ * UPDATE was really the one sent by us, not by other
+ * call components (e.g. to change codec)
+ */
+ if (inv->timer->timer.id == 0 && inv->timer->use_update &&
+ inv->timer->with_sdp == PJ_FALSE)
+ {
+ inv->timer->with_sdp = PJ_TRUE;
+ timer_cb(NULL, &inv->timer->timer);
+ }
}
return PJ_SUCCESS;
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index 84012080..fd8163a0 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -855,10 +855,25 @@ static void on_ice_complete(pjmedia_transport *tp,
pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name,
&pjsua_var.calls[id].med_rtp_addr))
{
+ pj_bool_t use_update;
+ const pj_str_t STR_UPDATE = { "UPDATE", 6 };
+ pjsip_dialog_cap_status support_update;
+ pjsip_dialog *dlg;
+
+ dlg = pjsua_var.calls[id].inv->dlg;
+ support_update = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_ALLOW,
+ NULL, &STR_UPDATE);
+ use_update = (support_update == PJSIP_DIALOG_CAP_SUPPORTED);
+
PJ_LOG(4,(THIS_FILE,
"ICE default transport address has changed for "
- "call %d, sending UPDATE", id));
- pjsua_call_update(id, 0, NULL);
+ "call %d, sending %s", id,
+ (use_update ? "UPDATE" : "re-INVITE")));
+
+ if (use_update)
+ pjsua_call_update(id, 0, NULL);
+ else
+ pjsua_call_reinvite(id, 0, NULL);
}
}
break;