summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-06-20 04:19:46 +0000
committerBenny Prijono <bennylp@teluu.com>2007-06-20 04:19:46 +0000
commit80bfcc379cb70228d0ad6c85fd9fee3362f02240 (patch)
tree6f6dc0645cd65e3c59f9824851f5253018d7349a /pjsip
parentbbee07a12eee6f6a55f60a4ce59cf8057b46e155 (diff)
Ticket #339: Respond correctly to incoming INVITE/re-INVITE without offer and receive answer in ACK
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1377 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c76
1 files changed, 72 insertions, 4 deletions
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index 13feb457..984501f6 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -62,6 +62,14 @@ static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e);
static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e);
static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e);
+static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
+ pjsip_transaction *tsx,
+ pjsip_rx_data *rdata);
+static pj_status_t process_answer( pjsip_inv_session *inv,
+ int st_code,
+ pjsip_tx_data *tdata,
+ const pjmedia_sdp_session *local_sdp);
+
static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
{
&inv_on_state_null,
@@ -141,6 +149,27 @@ void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
pjsip_event *e)
{
pjsip_inv_state prev_state = inv->state;
+ pj_status_t status;
+
+
+ /* If state is confirmed, check that SDP negotiation is done,
+ * otherwise disconnect the session.
+ */
+ if (state == PJSIP_INV_STATE_CONFIRMED) {
+ if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
+ pjsip_tx_data *bye;
+
+ PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
+ "session"));
+
+ status = pjsip_inv_end_session(inv, PJSIP_SC_NOT_ACCEPTABLE,
+ NULL, &bye);
+ if (status == PJ_SUCCESS && bye)
+ status = pjsip_inv_send_msg(inv, bye);
+
+ return;
+ }
+ }
/* Set state. */
inv->state = state;
@@ -267,6 +296,12 @@ static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
if (inv->invite_tsx &&
inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
{
+ /* Before we terminate INVITE transaction, process the SDP
+ * in the ACK request, if any.
+ */
+ inv_check_sdp_in_incoming_msg(inv, inv->invite_tsx, rdata);
+
+ /* Now we can terminate the INVITE transaction */
pj_assert(inv->invite_tsx->status_code >= 200);
pjsip_tsx_terminate(inv->invite_tsx,
inv->invite_tsx->status_code);
@@ -2173,7 +2208,8 @@ static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
break;
case PJSIP_TSX_STATE_CONFIRMED:
- /* For some reason can go here */
+ /* For some reason can go here (maybe when ACK for 2xx has
+ * the same branch value as the INVITE transaction) */
case PJSIP_TSX_STATE_TERMINATED:
/* INVITE transaction can be terminated either because UAC
@@ -2261,8 +2297,17 @@ static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
switch (tsx->state) {
case PJSIP_TSX_STATE_CONFIRMED:
- if (tsx->status_code/100 == 2)
+ /* It can only go here if incoming ACK request has the same Via
+ * branch parameter as the INVITE transaction.
+ */
+ if (tsx->status_code/100 == 2) {
+ if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
+ inv_check_sdp_in_incoming_msg(inv, tsx,
+ e->body.tsx_state.src.rdata);
+ }
+
inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
+ }
break;
case PJSIP_TSX_STATE_TERMINATED:
@@ -2452,8 +2497,20 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
if (status != PJ_SUCCESS)
return;
- /* Process SDP in the answer */
- status = process_answer(inv, 200, tdata, NULL);
+ /* If the INVITE request has SDP body, send answer.
+ * Otherwise generate offer from local active SDP.
+ */
+ if (rdata->msg_info.msg->body != NULL) {
+ status = process_answer(inv, 200, tdata, NULL);
+ } else {
+ const pjmedia_sdp_session *active_sdp;
+ status = pjmedia_sdp_neg_send_local_offer(dlg->pool,
+ inv->neg,
+ &active_sdp);
+ if (status == PJ_SUCCESS) {
+ tdata->msg->body = create_sdp_body(tdata->pool, active_sdp);
+ }
+ }
if (status != PJ_SUCCESS) {
/*
@@ -2488,6 +2545,17 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
/* Send 2xx regardless of the status of negotiation */
status = pjsip_inv_send_msg(inv, tdata);
+ } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
+ /* This is the case where ACK has the same branch as
+ * the INVITE request.
+ */
+ if (tsx->status_code/100 == 2 &&
+ e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+ {
+ inv_check_sdp_in_incoming_msg(inv, tsx,
+ e->body.tsx_state.src.rdata);
+ }
+
}
}