summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-02-08 11:16:05 +0000
committerBenny Prijono <bennylp@teluu.com>2006-02-08 11:16:05 +0000
commite546a129f57c7360db0cc7b4f68c4662aeaed164 (patch)
treeadaa5cf0196bbcc90c29d3c44963189950e18a2d
parent2c311b76b30a8d5d9530179c53f1abd602160f4f (diff)
Initial UAS implementation in invite session
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@156 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip/build/pjsua.dsp8
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c510
-rw-r--r--pjsip/src/pjsip/sip_util.c6
3 files changed, 368 insertions, 156 deletions
diff --git a/pjsip/build/pjsua.dsp b/pjsip/build/pjsua.dsp
index b5787bd1..73e9df16 100644
--- a/pjsip/build/pjsua.dsp
+++ b/pjsip/build/pjsua.dsp
@@ -99,15 +99,7 @@ SOURCE=..\src\pjsua\main.c
# Begin Source File
SOURCE=..\src\pjsua\main_old.c
-
-!IF "$(CFG)" == "pjsua - Win32 Release"
-
-!ELSEIF "$(CFG)" == "pjsua - Win32 Debug"
-
# PROP Exclude_From_Build 1
-
-!ENDIF
-
# End Source File
# Begin Source File
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index 56d0f144..a05576c3 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -26,6 +26,7 @@
#include <pj/string.h>
#include <pj/pool.h>
#include <pj/assert.h>
+#include <pj/os.h>
#define THIS_FILE "sip_invite_session.c"
@@ -38,16 +39,15 @@ static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata);
static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata);
static void mod_inv_on_tsx_state(pjsip_transaction*, pjsip_event*);
-static void inv_on_state_null( pjsip_inv_session *s, pjsip_event *e);
-static void inv_on_state_calling( pjsip_inv_session *s, pjsip_event *e);
-static void inv_on_state_incoming( pjsip_inv_session *s, pjsip_event *e);
-static void inv_on_state_early( pjsip_inv_session *s, pjsip_event *e);
-static void inv_on_state_connecting( pjsip_inv_session *s, pjsip_event *e);
-static void inv_on_state_confirmed( pjsip_inv_session *s, pjsip_event *e);
-static void inv_on_state_disconnected( pjsip_inv_session *s, pjsip_event *e);
-static void inv_on_state_terminated( pjsip_inv_session *s, pjsip_event *e);
+static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e);
+static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e);
+static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e);
+static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e);
+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 void (*inv_state_handler[])( pjsip_inv_session *s, pjsip_event *e) =
+static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
{
&inv_on_state_null,
&inv_on_state_calling,
@@ -56,7 +56,6 @@ static void (*inv_state_handler[])( pjsip_inv_session *s, pjsip_event *e) =
&inv_on_state_connecting,
&inv_on_state_confirmed,
&inv_on_state_disconnected,
- &inv_on_state_terminated,
};
static struct mod_inv
@@ -86,7 +85,9 @@ static struct mod_inv
};
-
+/*
+ * Module load()
+ */
static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
{
pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6}};
@@ -98,38 +99,19 @@ static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
return PJ_SUCCESS;
}
+/*
+ * Module unload()
+ */
static pj_status_t mod_inv_unload(void)
{
/* Should remove capability here */
return PJ_SUCCESS;
}
-static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
-{
- pjsip_dialog *dlg;
-
- /* Ignore requests outside dialog */
- dlg = pjsip_rdata_get_dlg(rdata);
- if (dlg == NULL)
- return PJ_FALSE;
-
- /* Answer BYE with 200/OK. */
- if (rdata->msg_info.msg->line.req.method.id == PJSIP_BYE_METHOD) {
- pj_status_t status;
- pjsip_tx_data *tdata;
-
- status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
- if (status == PJ_SUCCESS)
- status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata),
- tdata);
-
- return status==PJ_SUCCESS ? PJ_TRUE : PJ_FALSE;
- }
-
- return PJ_FALSE;
-}
-
-static pj_status_t send_ack(pjsip_inv_session *inv, pjsip_rx_data *rdata)
+/*
+ * Send ACK for 2xx response.
+ */
+static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_rx_data *rdata)
{
pjsip_tx_data *tdata;
pj_status_t status;
@@ -152,6 +134,47 @@ static pj_status_t send_ack(pjsip_inv_session *inv, pjsip_rx_data *rdata)
return PJ_SUCCESS;
}
+/*
+ * Module on_rx_request()
+ *
+ * This callback is called for these events:
+ * - endpoint receives request which was unhandled by higher priority
+ * modules (e.g. transaction layer, dialog layer).
+ * - dialog distributes incoming request to its usages.
+ */
+static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
+{
+ pjsip_method *method;
+
+ /* Only wants to receive request from a dialog. */
+ if (pjsip_rdata_get_dlg(rdata) == NULL)
+ return PJ_FALSE;
+
+ /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
+ * If we need to send response, it will be sent in the state
+ * handlers.
+ */
+ method = &rdata->msg_info.msg->line.req.method;
+
+ if (method->id == PJSIP_INVITE_METHOD ||
+ method->id == PJSIP_CANCEL_METHOD ||
+ method->id == PJSIP_ACK_METHOD ||
+ method->id == PJSIP_BYE_METHOD)
+ {
+ return PJ_TRUE;
+ }
+
+ return PJ_FALSE;
+}
+
+/*
+ * Module on_rx_response().
+ *
+ * This callback is called for these events:
+ * - dialog distributes incoming 2xx response to INVITE (outside
+ * transaction) to its usages.
+ * - endpoint distributes strayed responses.
+ */
static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
{
pjsip_dialog *dlg;
@@ -175,7 +198,7 @@ static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 &&
rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD) {
- send_ack(inv, rdata);
+ inv_send_ack(inv, rdata);
return PJ_TRUE;
}
@@ -184,6 +207,12 @@ static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
return PJ_FALSE;
}
+/*
+ * Module on_tsx_state()
+ *
+ * This callback is called by dialog framework for all transactions
+ * inside the dialog for all its dialog usages.
+ */
static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
{
pjsip_dialog *dlg;
@@ -209,6 +238,10 @@ static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
inv->invite_tsx = NULL;
}
+
+/*
+ * Initialize the invite module.
+ */
PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
pjsip_module *app_module,
const pjsip_inv_callback *cb)
@@ -236,19 +269,26 @@ PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
return status;
}
+/*
+ * Get the instance of invite module.
+ */
PJ_DEF(pjsip_module*) pjsip_inv_usage_instance(void)
{
return &mod_inv.mod;
}
+/*
+ * Return the invite session for the specified dialog.
+ */
PJ_DEF(pjsip_inv_session*) pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
{
return dlg->mod_data[mod_inv.mod.id];
}
+
/*
- * Create UAC session.
+ * Create UAC invite session.
*/
PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
const pjmedia_sdp_session *local_sdp,
@@ -348,7 +388,7 @@ PJ_DEF(pj_status_t) pjsip_inv_verify_request(pjsip_rx_data *rdata,
/* Init response header list */
pj_list_init(&res_hdr_list);
- /* Check the request body, see if it's something that we support
+ /* Check the request body, see if it'inv something that we support
* (i.e. SDP).
*/
if (msg->body) {
@@ -623,7 +663,7 @@ on_return:
}
/*
- * Create UAS session.
+ * Create UAS invite session.
*/
PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
pjsip_rx_data *rdata,
@@ -662,7 +702,7 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
inv->pool = dlg->pool;
inv->role = PJSIP_ROLE_UAS;
- inv->state = PJSIP_INV_STATE_NULL;
+ inv->state = PJSIP_INV_STATE_INCOMING;
inv->dlg = dlg;
inv->options = options;
@@ -854,7 +894,7 @@ PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
;
}
- /* Do we need to increment tdata's reference counter? */
+ /* Do we need to increment tdata'inv reference counter? */
PJ_TODO(INV_ANSWER_MAY_HAVE_TO_INCREMENT_REF_COUNTER);
*p_tdata = last_res;
@@ -1037,7 +1077,98 @@ void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
pjsip_dlg_dec_session(inv->dlg);
}
-static void inv_on_state_null( pjsip_inv_session *s, pjsip_event *e)
+
+
+/*
+ * Respond to incoming CANCEL request.
+ */
+static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
+ pjsip_transaction *cancel_tsx,
+ pjsip_rx_data *rdata)
+{
+ pjsip_tx_data *tdata;
+ pjsip_transaction *invite_tsx;
+ pj_str_t key;
+ pj_status_t status;
+
+ /* See if we have matching INVITE server transaction: */
+
+ pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
+ &pjsip_invite_method, rdata);
+ invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
+
+ if (invite_tsx == NULL) {
+
+ /* Invite transaction not found!
+ * Respond CANCEL with 491 (RFC 3261 Section 9.2 page 42)
+ */
+ status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
+ &tdata);
+
+ } else {
+ /* Always answer CANCEL will 200 (OK) regardless of
+ * the state of the INVITE transaction.
+ */
+ status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
+ &tdata);
+ }
+
+ /* See if we have created the response successfully. */
+ if (status != PJ_SUCCESS) return;
+
+ /* Send the CANCEL response */
+ status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
+ if (status != PJ_SUCCESS) return;
+
+
+ /* See if we need to terminate the UAS INVITE transaction
+ * with 487 (Request Terminated) response.
+ */
+ if (invite_tsx && invite_tsx->status_code < 200) {
+
+ pj_assert(invite_tsx->last_tx != NULL);
+
+ tdata = invite_tsx->last_tx;
+
+ status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
+ if (status == PJ_SUCCESS)
+ pjsip_dlg_send_response(inv->dlg, invite_tsx, tdata);
+ }
+
+ if (invite_tsx)
+ pj_mutex_unlock(invite_tsx->mutex);
+}
+
+
+/*
+ * Respond to incoming BYE request.
+ */
+static void inv_respond_incoming_bye( pjsip_inv_session *inv,
+ pjsip_transaction *bye_tsx,
+ pjsip_rx_data *rdata,
+ pjsip_event *e )
+{
+ pj_status_t status;
+ pjsip_tx_data *tdata;
+
+ /* Respond BYE with 200: */
+
+ status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
+ if (status != PJ_SUCCESS) return;
+
+ status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
+ if (status != PJ_SUCCESS) return;
+
+ /* Terminate session: */
+
+ if (inv->state != PJSIP_INV_STATE_DISCONNECTED)
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+}
+
+/*
+ * State NULL is before anything is sent/received.
+ */
+static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
@@ -1049,12 +1180,12 @@ static void inv_on_state_null( pjsip_inv_session *s, pjsip_event *e)
if (dlg->role == PJSIP_ROLE_UAC) {
/* Keep the initial INVITE transaction. */
- if (s->invite_tsx == NULL)
- s->invite_tsx = tsx;
+ if (inv->invite_tsx == NULL)
+ inv->invite_tsx = tsx;
switch (tsx->state) {
case PJSIP_TSX_STATE_CALLING:
- inv_set_state(s, PJSIP_INV_STATE_CALLING, e);
+ inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
break;
default:
pj_assert(!"Unexpected state");
@@ -1064,7 +1195,7 @@ static void inv_on_state_null( pjsip_inv_session *s, pjsip_event *e)
} else {
switch (tsx->state) {
case PJSIP_TSX_STATE_TRYING:
- inv_set_state(s, PJSIP_INV_STATE_INCOMING, e);
+ inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
break;
default:
pj_assert(!"Unexpected state");
@@ -1076,7 +1207,11 @@ static void inv_on_state_null( pjsip_inv_session *s, pjsip_event *e)
}
}
-static void inv_on_state_calling( pjsip_inv_session *s, pjsip_event *e)
+/*
+ * State CALLING is after sending initial INVITE request but before
+ * any response (with tag) is received.
+ */
+static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
@@ -1084,13 +1219,13 @@ static void inv_on_state_calling( pjsip_inv_session *s, pjsip_event *e)
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
- if (tsx == s->invite_tsx) {
+ if (tsx == inv->invite_tsx) {
switch (tsx->state) {
case PJSIP_TSX_STATE_PROCEEDING:
if (dlg->remote.info->tag.slen) {
- inv_set_state(s, PJSIP_INV_STATE_EARLY, e);
+ inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
} else {
/* Ignore 100 (Trying) response, as it doesn't change
* session state. It only ceases retransmissions.
@@ -1105,7 +1240,7 @@ static void inv_on_state_calling( pjsip_inv_session *s, pjsip_event *e)
* When transaction receives 2xx, it should be terminated
*/
pj_assert(0);
- inv_set_state(s, PJSIP_INV_STATE_CONNECTING, e);
+ inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
} else if (tsx->status_code==401 || tsx->status_code==407) {
@@ -1114,7 +1249,7 @@ static void inv_on_state_calling( pjsip_inv_session *s, pjsip_event *e)
*/
pjsip_tx_data *tdata;
- status = pjsip_auth_clt_reinit_req(&s->dlg->auth_sess,
+ status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
e->body.tsx_state.src.rdata,
tsx->last_tx,
&tdata);
@@ -1124,21 +1259,21 @@ static void inv_on_state_calling( pjsip_inv_session *s, pjsip_event *e)
/* Does not have proper credentials.
* End the session.
*/
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
} else {
/* Restart session. */
- s->state = PJSIP_INV_STATE_NULL;
- s->invite_tsx = NULL;
+ inv->state = PJSIP_INV_STATE_NULL;
+ inv->invite_tsx = NULL;
/* Send the request. */
- status = pjsip_inv_send_msg(s, tdata, NULL );
+ status = pjsip_inv_send_msg(inv, tdata, NULL );
}
} else {
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
@@ -1152,79 +1287,116 @@ static void inv_on_state_calling( pjsip_inv_session *s, pjsip_event *e)
/* This must be receipt of 2xx response */
/* Set state to CONNECTING */
- inv_set_state(s, PJSIP_INV_STATE_CONNECTING, e);
+ inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
/* Send ACK */
pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
- send_ack(s, e->body.tsx_state.src.rdata);
+ inv_send_ack(inv, e->body.tsx_state.src.rdata);
} else {
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
- default:
- pj_assert(!"Unexpected state");
}
-
- } else {
- pj_assert(!"Unexpected transaction type");
}
}
-static void inv_on_state_incoming( pjsip_inv_session *s, pjsip_event *e)
+/*
+ * State INCOMING is after we received the request, but before
+ * responses with tag are sent.
+ */
+static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
- if (tsx == s->invite_tsx) {
+ if (tsx == inv->invite_tsx) {
+
+ /*
+ * Handle the INVITE state transition.
+ */
+
switch (tsx->state) {
+
case PJSIP_TSX_STATE_PROCEEDING:
+ /*
+ * Transaction sent provisional response.
+ */
if (tsx->status_code > 100)
- inv_set_state(s, PJSIP_INV_STATE_EARLY, e);
+ inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
break;
+
case PJSIP_TSX_STATE_COMPLETED:
+ /*
+ * Transaction sent final response.
+ */
if (tsx->status_code/100 == 2)
- inv_set_state(s, PJSIP_INV_STATE_CONNECTING, e);
+ inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
else
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
break;
+
case PJSIP_TSX_STATE_TERMINATED:
- /* This happens on transport error */
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
+ /*
+ * This happens on transport error (e.g. failed to send
+ * response)
+ */
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
break;
+
default:
- pj_assert(!"Unexpected state");
+ pj_assert(!"Unexpected INVITE state");
+ break;
}
- } else {
- pj_assert(!"Unexpected transaction type");
+
+ } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
+ tsx->role == PJSIP_ROLE_UAS &&
+ tsx->state < PJSIP_TSX_STATE_COMPLETED &&
+ e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
+ {
+
+ /*
+ * Handle incoming CANCEL request.
+ */
+
+ inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
+
}
}
-static void inv_on_state_early( pjsip_inv_session *s, pjsip_event *e)
+/*
+ * State EARLY is for both UAS and UAC, after response with To tag
+ * is sent/received.
+ */
+static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
- if (tsx == s->invite_tsx) {
+ if (tsx == inv->invite_tsx) {
+
+ /*
+ * Handle the INVITE state progress.
+ */
switch (tsx->state) {
case PJSIP_TSX_STATE_PROCEEDING:
/* Send/received another provisional response. */
- inv_set_state(s, PJSIP_INV_STATE_EARLY, e);
+ inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
break;
case PJSIP_TSX_STATE_COMPLETED:
if (tsx->status_code/100 == 2)
- inv_set_state(s, PJSIP_INV_STATE_CONNECTING, e);
+ inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
else
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
break;
case PJSIP_TSX_STATE_TERMINATED:
@@ -1237,75 +1409,57 @@ static void inv_on_state_early( pjsip_inv_session *s, pjsip_event *e)
/* This must be receipt of 2xx response */
/* Set state to CONNECTING */
- inv_set_state(s, PJSIP_INV_STATE_CONNECTING, e);
+ inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
/* if UAC, send ACK and move state to confirmed. */
if (tsx->role == PJSIP_ROLE_UAC) {
pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
- send_ack(s, e->body.tsx_state.src.rdata);
+ inv_send_ack(inv, e->body.tsx_state.src.rdata);
- inv_set_state(s, PJSIP_INV_STATE_CONFIRMED, e);
+ inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
}
} else {
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
default:
- pj_assert(!"Unexpected state");
+ pj_assert(!"Unexpected INVITE tsx state");
}
- } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
-
- /* Handle incoming CANCEL request. */
- if (tsx->role == PJSIP_ROLE_UAS && s->role == PJSIP_ROLE_UAS &&
- e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
- {
-
- pj_status_t status;
- pjsip_tx_data *tdata;
-
- /* Respond CANCEL with 200 (OK) */
- status = pjsip_dlg_create_response(dlg, e->body.tsx_state.src.rdata,
- 200, NULL, &tdata);
- if (status == PJ_SUCCESS) {
- pjsip_dlg_send_response(dlg, tsx, tdata);
- }
-
- /* Respond the original UAS transaction with 487 (Request
- * Terminated) response.
- */
- pj_assert(s->invite_tsx && s->invite_tsx->last_tx);
- tdata = s->invite_tsx->last_tx;
-
- status = pjsip_dlg_modify_response(dlg, tdata, 487, NULL);
- if (status == PJ_SUCCESS) {
- pjsip_dlg_send_response(dlg, s->invite_tsx, tdata);
- }
- }
-
- } else if (tsx->method.id == PJSIP_INVITE_METHOD) {
+ } else if (inv->role == PJSIP_ROLE_UAS &&
+ tsx->role == PJSIP_ROLE_UAS &&
+ tsx->method.id == PJSIP_CANCEL_METHOD &&
+ tsx->state < PJSIP_TSX_STATE_COMPLETED &&
+ e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
+ {
- /* Ignore previously failed INVITE transaction event
- * (e.g. when rejected with 401/407)
+ /*
+ * Handle incoming CANCEL request.
*/
- } else {
- pj_assert(!"Unexpected transaction type");
+ inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
+
}
}
-static void inv_on_state_connecting( pjsip_inv_session *s, pjsip_event *e)
+/*
+ * State CONNECTING is after 2xx response to INVITE is sent/received.
+ */
+static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
- if (tsx == s->invite_tsx) {
+ if (tsx == inv->invite_tsx) {
+ /*
+ * Handle INVITE state progression.
+ */
switch (tsx->state) {
case PJSIP_TSX_STATE_CONFIRMED:
@@ -1317,7 +1471,7 @@ static void inv_on_state_connecting( pjsip_inv_session *s, pjsip_event *e)
* error.
*/
if (tsx->status_code/100 != 2) {
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
break;
@@ -1329,50 +1483,110 @@ static void inv_on_state_connecting( pjsip_inv_session *s, pjsip_event *e)
pj_assert(!"Unexpected state");
}
- } else {
- pj_assert(!"Unexpected transaction type");
+ } else if (tsx->role == PJSIP_ROLE_UAS &&
+ tsx->method.id == PJSIP_BYE_METHOD &&
+ tsx->status_code < 200 &&
+ e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+ {
+
+ /*
+ * Handle incoming BYE.
+ */
+
+ inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
+
}
}
-static void inv_on_state_confirmed( pjsip_inv_session *s, pjsip_event *e)
+/*
+ * State CONFIRMED is after ACK is sent/received.
+ */
+static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
{
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
PJ_ASSERT_ON_FAIL(tsx && dlg, return);
- if (tsx->method.id == PJSIP_BYE_METHOD) {
- inv_set_state(s, PJSIP_INV_STATE_DISCONNECTED, e);
- } else if (tsx == s->invite_tsx) {
+ if (tsx->method.id == PJSIP_BYE_METHOD &&
+ tsx->role == PJSIP_ROLE_UAC &&
+ tsx->state == PJSIP_TSX_STATE_COMPLETED)
+ {
+ /*
+ * Outgoing BYE.
+ */
+ pj_status_t status;
- switch (tsx->state) {
- case PJSIP_TSX_STATE_TERMINATED:
- case PJSIP_TSX_STATE_DESTROYED:
- break;
- default:
- pj_assert(!"Unexpected state");
- break;
+ /* Handle 401/407 challenge. */
+ if (tsx->status_code == 401 || tsx->status_code == 407) {
+
+ pjsip_tx_data *tdata;
+
+ status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
+ e->body.tsx_state.src.rdata,
+ tsx->last_tx,
+ &tdata);
+
+ if (status != PJ_SUCCESS) {
+
+ /* Does not have proper credentials.
+ * End the session anyway.
+ */
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+
+ } else {
+ /* Re-send BYE. */
+ status = pjsip_inv_send_msg(inv, tdata, NULL );
+ }
+
+ } else {
+
+ /* End the session. */
+
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
}
- } else if (tsx->method.id == PJSIP_INVITE_METHOD) {
+ }
+ else if (tsx->method.id == PJSIP_BYE_METHOD &&
+ tsx->role == PJSIP_ROLE_UAS &&
+ tsx->status_code < 200 &&
+ e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+ {
- /* Re-INVITE */
+ /*
+ * Handle incoming BYE.
+ */
+
+ inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
- } else {
- pj_assert(!"Unexpected transaction type");
}
}
-static void inv_on_state_disconnected( pjsip_inv_session *s, pjsip_event *e)
+/*
+ * After session has been terminated, but before dialog is destroyed
+ * (because dialog has other usages, or because dialog is waiting for
+ * the last transaction to terminate).
+ */
+static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
{
- PJ_UNUSED_ARG(s);
- PJ_UNUSED_ARG(e);
-}
+ pjsip_transaction *tsx = e->body.tsx_state.tsx;
+ pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
-static void inv_on_state_terminated( pjsip_inv_session *s, pjsip_event *e)
-{
- PJ_UNUSED_ARG(s);
- PJ_UNUSED_ARG(e);
+ PJ_ASSERT_ON_FAIL(tsx && dlg, return);
+
+ if (tsx->method.id == PJSIP_BYE_METHOD &&
+ tsx->role == PJSIP_ROLE_UAS &&
+ tsx->status_code < 200 &&
+ e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+ {
+
+ /*
+ * Be nice, handle incoming BYE.
+ */
+
+ inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
+
+ }
}
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index 1a3fc3b6..9b48d195 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -536,6 +536,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
const pjsip_cid_hdr *cid_hdr;
const pjsip_cseq_hdr *cseq_hdr;
const pjsip_hdr *hdr;
+ pjsip_hdr *via;
pj_status_t status;
/* The transmit buffer must INVITE request. */
@@ -572,6 +573,11 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
if (status != PJ_SUCCESS)
return status;
+ /* Clear Via headers in the new request. */
+ while ((via=pjsip_msg_find_hdr(cancel_tdata->msg, PJSIP_H_VIA, NULL)) != NULL)
+ pj_list_erase(via);
+
+
/* Must only have single Via which matches the top-most Via in the
* request being cancelled.
*/