summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-02-08 22:44:25 +0000
committerBenny Prijono <bennylp@teluu.com>2006-02-08 22:44:25 +0000
commite88c16ac16d93a586406bc5503d3110f264c5263 (patch)
treed56410f7f00fc914ed26c1c0442d72040210f146 /pjsip
parent66f9158fa3c12ebd3b2d317cf42e461e0b86a6aa (diff)
Finished invite session UAS implementation
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@160 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/include/pjsip/sip_dialog.h11
-rw-r--r--pjsip/include/pjsip/sip_event.h8
-rw-r--r--pjsip/include/pjsip/sip_transaction.h22
-rw-r--r--pjsip/include/pjsip/sip_types.h4
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c148
-rw-r--r--pjsip/src/pjsip/sip_dialog.c229
-rw-r--r--pjsip/src/pjsip/sip_transaction.c41
-rw-r--r--pjsip/src/pjsip/sip_ua_layer.c34
-rw-r--r--pjsip/src/pjsip/sip_util.c3
-rw-r--r--pjsip/src/pjsua/main.c92
-rw-r--r--pjsip/src/pjsua/pjsua_core.c96
-rw-r--r--pjsip/src/test-pjsip/tsx_uas_test.c6
12 files changed, 453 insertions, 241 deletions
diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h
index e63ba6d1..ede79b26 100644
--- a/pjsip/include/pjsip/sip_dialog.h
+++ b/pjsip/include/pjsip/sip_dialog.h
@@ -49,6 +49,15 @@ typedef struct pjsip_dlg_party
/**
+ * Dialog state.
+ */
+enum pjsip_dialog_state
+{
+ PJSIP_DIALOG_STATE_NULL,
+ PJSIP_DIALOG_STATE_ESTABLISHED,
+};
+
+/**
* This structure describes the dialog structure.
*/
struct pjsip_dialog
@@ -67,7 +76,7 @@ struct pjsip_dialog
void *dlg_set;
/* Dialog's session properties. */
- pj_bool_t established;/**< Dialog is established? */
+ enum pjsip_dialog_state state; /**< Dialog state. */
pjsip_uri *target; /**< Current target. */
pjsip_dlg_party local; /**< Local party info. */
pjsip_dlg_party remote; /**< Remote party info. */
diff --git a/pjsip/include/pjsip/sip_event.h b/pjsip/include/pjsip/sip_event.h
index 268a60e7..caac953f 100644
--- a/pjsip/include/pjsip/sip_event.h
+++ b/pjsip/include/pjsip/sip_event.h
@@ -124,7 +124,6 @@ struct pjsip_event
struct
{
pjsip_tx_data *tdata; /**< The transmit data buffer. */
- pjsip_transaction *tsx; /**< The transaction. */
} tx_msg;
@@ -139,7 +138,6 @@ struct pjsip_event
struct
{
pjsip_rx_data *rdata; /**< The receive data buffer. */
- pjsip_transaction *tsx; /**< The transaction. */
} rx_msg;
/** User event. */
@@ -178,20 +176,18 @@ struct pjsip_event
/**
* Init tx msg event.
*/
-#define PJSIP_EVENT_INIT_TX_MSG(event,ptsx,ptdata) \
+#define PJSIP_EVENT_INIT_TX_MSG(event,ptdata) \
do { \
(event).type = PJSIP_EVENT_TX_MSG; \
- (event).body.tx_msg.tsx = ptsx; \
(event).body.tx_msg.tdata = ptdata; \
} while (0)
/**
* Init rx msg event.
*/
-#define PJSIP_EVENT_INIT_RX_MSG(event,ptsx,prdata) \
+#define PJSIP_EVENT_INIT_RX_MSG(event,prdata) \
do { \
(event).type = PJSIP_EVENT_RX_MSG; \
- (event).body.rx_msg.tsx = ptsx; \
(event).body.rx_msg.rdata = prdata; \
} while (0)
diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h
index 712fa8ad..eece1be0 100644
--- a/pjsip/include/pjsip/sip_transaction.h
+++ b/pjsip/include/pjsip/sip_transaction.h
@@ -175,7 +175,9 @@ PJ_DECL(pj_status_t) pjsip_tsx_create_uac( pjsip_module *tsx_user,
/**
* Create, initialize, and register a new transaction as UAS from the
- * specified incoming request in \c rdata.
+ * specified incoming request in \c rdata. After calling this function,
+ * application MUST call #pjsip_tsx_recv_msg() so that transaction
+ * moves from state NULL.
*
* @param tsx_user Module to be registered as transaction user of the new
* transaction, which will receive notification from the
@@ -189,6 +191,24 @@ PJ_DECL(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user,
pjsip_rx_data *rdata,
pjsip_transaction **p_tsx );
+
+/**
+ * Call this function to manually feed a message to the transaction.
+ * For UAS transaction, application MUST call this function after
+ * UAS transaction has been created.
+ *
+ * This function SHOULD only be called to pass initial request message
+ * to UAS transaction. Before this function returns, on_tsx_state()
+ * callback of the transaction user will be called. If response message
+ * is passed to this function, then on_rx_response() will also be called
+ * before on_tsx_state().
+ *
+ * @param tsx The transaction.
+ * @param rdata The message.
+ */
+PJ_DECL(void) pjsip_tsx_recv_msg( pjsip_transaction *tsx,
+ pjsip_rx_data *rdata);
+
/**
* Transmit message in tdata with this transaction. It is possible to
* pass NULL in tdata for UAC transaction, which in this case the last
diff --git a/pjsip/include/pjsip/sip_types.h b/pjsip/include/pjsip/sip_types.h
index fc79f95a..a77f2550 100644
--- a/pjsip/include/pjsip/sip_types.h
+++ b/pjsip/include/pjsip/sip_types.h
@@ -133,6 +133,10 @@ typedef pjsip_module pjsip_user_agent;
*/
typedef struct pjsip_dialog pjsip_dialog;
+/**
+ * Dialog state (sip_dialog.h).
+ */
+enum pjsip_dialog_state pjsip_dialog_state;
/**
* Transaction role.
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index a05576c3..2a5e14ae 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -109,6 +109,21 @@ static pj_status_t mod_inv_unload(void)
}
/*
+ * Set session state.
+ */
+void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
+ pjsip_event *e)
+{
+ inv->state = state;
+ if (mod_inv.cb.on_state_changed)
+ (*mod_inv.cb.on_state_changed)(inv, e);
+
+ if (inv->state == PJSIP_INV_STATE_DISCONNECTED)
+ pjsip_dlg_dec_session(inv->dlg);
+}
+
+
+/*
* Send ACK for 2xx response.
*/
static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_rx_data *rdata)
@@ -145,11 +160,16 @@ static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_rx_data *rdata)
static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
{
pjsip_method *method;
+ pjsip_dialog *dlg;
+ pjsip_inv_session *inv;
/* Only wants to receive request from a dialog. */
- if (pjsip_rdata_get_dlg(rdata) == NULL)
+ dlg = pjsip_rdata_get_dlg(rdata);
+ if (dlg == NULL)
return PJ_FALSE;
+ inv = dlg->mod_data[mod_inv.mod.id];
+
/* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
* If we need to send response, it will be sent in the state
* handlers.
@@ -158,12 +178,23 @@ static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
if (method->id == PJSIP_INVITE_METHOD ||
method->id == PJSIP_CANCEL_METHOD ||
- method->id == PJSIP_ACK_METHOD ||
method->id == PJSIP_BYE_METHOD)
{
return PJ_TRUE;
}
+ /* On receipt ACK request, when state is CONNECTING,
+ * move state to CONFIRMED.
+ */
+ if (method->id == PJSIP_ACK_METHOD && inv &&
+ inv->state == PJSIP_INV_STATE_CONFIRMED)
+ {
+ pjsip_event event;
+
+ PJSIP_EVENT_INIT_RX_MSG(event, rdata);
+ inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
+ }
+
return PJ_FALSE;
}
@@ -702,7 +733,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_INCOMING;
+ inv->state = PJSIP_INV_STATE_NULL;
inv->dlg = dlg;
inv->options = options;
@@ -1066,19 +1097,6 @@ PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
}
-void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
- pjsip_event *e)
-{
- inv->state = state;
- if (mod_inv.cb.on_state_changed)
- (*mod_inv.cb.on_state_changed)(inv, e);
-
- if (inv->state == PJSIP_INV_STATE_DISCONNECTED)
- pjsip_dlg_dec_session(inv->dlg);
-}
-
-
-
/*
* Respond to incoming CANCEL request.
*/
@@ -1166,6 +1184,52 @@ static void inv_respond_incoming_bye( pjsip_inv_session *inv,
}
/*
+ * Respond to BYE request.
+ */
+static void inv_handle_bye_response( pjsip_inv_session *inv,
+ pjsip_transaction *tsx,
+ pjsip_rx_data *rdata,
+ pjsip_event *e )
+{
+ pj_status_t status;
+
+ if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
+ inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+ return;
+ }
+
+ /* 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,
+ 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);
+ }
+
+}
+
+/*
* State NULL is before anything is sent/received.
*/
static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
@@ -1197,6 +1261,11 @@ static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
case PJSIP_TSX_STATE_TRYING:
inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
break;
+ case PJSIP_TSX_STATE_PROCEEDING:
+ inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
+ if (tsx->status_code > 100)
+ inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
+ break;
default:
pj_assert(!"Unexpected state");
}
@@ -1463,6 +1532,8 @@ 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)
+ inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
break;
case PJSIP_TSX_STATE_TERMINATED:
@@ -1495,7 +1566,18 @@ static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
+ } else if (tsx->method.id == PJSIP_BYE_METHOD &&
+ tsx->role == PJSIP_ROLE_UAC &&
+ tsx->state == PJSIP_TSX_STATE_COMPLETED)
+ {
+
+ /*
+ * Outgoing BYE
+ */
+ inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
+
}
+
}
/*
@@ -1513,39 +1595,15 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
tsx->role == PJSIP_ROLE_UAC &&
tsx->state == PJSIP_TSX_STATE_COMPLETED)
{
+
/*
- * Outgoing BYE.
+ * Outgoing BYE
*/
- pj_status_t status;
-
- /* 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. */
+ if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+ inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
+ else
inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
- }
}
else if (tsx->method.id == PJSIP_BYE_METHOD &&
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
index c6ad91ab..f41b5d53 100644
--- a/pjsip/src/pjsip/sip_dialog.c
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -74,6 +74,7 @@ static pj_status_t create_dialog( pjsip_user_agent *ua,
pj_sprintf(dlg->obj_name, "dlg%p", dlg);
dlg->ua = ua;
dlg->endpt = endpt;
+ dlg->state = PJSIP_DIALOG_STATE_NULL;
status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex);
if (status != PJ_SUCCESS)
@@ -374,6 +375,9 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
PJ_TODO(DIALOG_APP_TIMER);
+ /* Feed the first request to the transaction. */
+ pjsip_tsx_recv_msg(tsx, rdata);
+
/* Done. */
*p_dlg = dlg;
return PJ_SUCCESS;
@@ -407,6 +411,11 @@ PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG,
PJSIP_ENOTRESPONSEMSG);
+ /* Status code MUST be 1xx (but not 100), or 2xx */
+ status = rdata->msg_info.msg->line.status.code;
+ PJ_ASSERT_RETURN( (status/100==1 && status!=100) ||
+ (status/100==2), PJ_EBUG);
+
/* To tag must present in the response. */
PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG);
@@ -444,6 +453,15 @@ PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
/* Initial role is UAC. */
dlg->role = PJSIP_ROLE_UAC;
+ /* Dialog state depends on the response. */
+ status = rdata->msg_info.msg->line.status.code/100;
+ if (status == 1 || status == 2)
+ dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
+ else {
+ pj_assert(!"Invalid status code");
+ dlg->state = PJSIP_DIALOG_STATE_NULL;
+ }
+
/* Secure? */
dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);
@@ -462,7 +480,7 @@ PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
r = r->next;
}
- /* Init client authentication session. */
+ /* Clone client authentication session. */
status = pjsip_auth_clt_clone(dlg->pool, &dlg->auth_sess,
&first_dlg->auth_sess);
if (status != PJ_SUCCESS)
@@ -849,99 +867,54 @@ on_error:
return status;
}
-
-/*
- * Create response.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
- pjsip_rx_data *rdata,
- int st_code,
- const pj_str_t *st_text,
- pjsip_tx_data **p_tdata)
+/* Add standard headers for certain types of response */
+static void dlg_beautify_response(pjsip_dialog *dlg,
+ int st_code,
+ pjsip_tx_data *tdata)
{
- pj_status_t status;
pjsip_cseq_hdr *cseq;
- pjsip_tx_data *tdata;
int st_class;
+ const pjsip_hdr *c_hdr;
+ pjsip_hdr *hdr;
- /* Create generic response. */
- status = pjsip_endpt_create_response(dlg->endpt,
- rdata, st_code, st_text, &tdata);
- if (status != PJ_SUCCESS)
- return status;
-
- /* Lock the dialog. */
- pj_mutex_lock(dlg->mutex);
-
- /* Special treatment for 2xx response to request that establishes
- * dialog.
- *
- * RFC 3261 Section 12.1.1
- *
- * When a UAS responds to a request with a response that establishes
- * a dialog (such as a 2xx to INVITE):
- * - MUST copy all Record-Route header field values from the request
- * into the response (including the URIs, URI parameters, and any
- * Record-Route header field parameters, whether they are known or
- * unknown to the UAS) and MUST maintain the order of those values.
- * - The Contact header field contains an address where the UAS would
- * like to be contacted for subsequent requests in the dialog.
- *
- * Also from Table 3, page 119.
- */
cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
pj_assert(cseq != NULL);
st_class = st_code / 100;
- if (cseq->cseq == dlg->remote.first_cseq &&
- (st_class==1 || st_class==2) && st_code != 100)
- {
- pjsip_hdr *rr, *hdr;
-
- /* Duplicate Record-Route header from the request. */
- rr = (pjsip_hdr*) rdata->msg_info.record_route;
- while (rr) {
- hdr = pjsip_hdr_clone(tdata->pool, rr);
- pjsip_msg_add_hdr(tdata->msg, hdr);
-
- rr = rr->next;
- if (rr == &rdata->msg_info.msg->hdr)
- break;
- rr = pjsip_msg_find_hdr(rdata->msg_info.msg,
- PJSIP_H_RECORD_ROUTE, rr);
- }
- }
-
- /* Contact header. */
+ /* Contact, Allow, Supported header. */
if (pjsip_method_creates_dialog(&cseq->method)) {
/* Add Contact header for 1xx, 2xx, 3xx and 485 response. */
if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) ||
st_code==485)
{
- /* Add contact header. */
- pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact);
- pjsip_msg_add_hdr(tdata->msg, hdr);
+ /* Add contact header only if one is not present. */
+ if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL) == 0) {
+ hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+ }
}
/* Add Allow header in 2xx and 405 response. */
- if (st_class==2 || st_code==405) {
- const pjsip_hdr *c_hdr;
+ if ((st_class==2 || st_code==405) &&
+ pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ALLOW, NULL)==NULL)
+ {
c_hdr = pjsip_endpt_get_capability(dlg->endpt,
PJSIP_H_ALLOW, NULL);
if (c_hdr) {
- pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
+ hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
pjsip_msg_add_hdr(tdata->msg, hdr);
}
}
/* Add Supported header in 2xx response. */
- if (st_class==2) {
- const pjsip_hdr *c_hdr;
+ if (st_class==2 &&
+ pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL)==NULL)
+ {
c_hdr = pjsip_endpt_get_capability(dlg->endpt,
PJSIP_H_SUPPORTED, NULL);
if (c_hdr) {
- pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
+ hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
pjsip_msg_add_hdr(tdata->msg, hdr);
}
}
@@ -949,7 +922,7 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
}
/* Add To tag in all responses except 100 */
- if (st_code != 100 && rdata->msg_info.to->tag.slen == 0) {
+ if (st_code != 100) {
pjsip_to_hdr *to;
to = PJSIP_MSG_TO_HDR(tdata->msg);
@@ -957,6 +930,34 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
to->tag = dlg->local.info->tag;
}
+}
+
+
+/*
+ * Create response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata,
+ int st_code,
+ const pj_str_t *st_text,
+ pjsip_tx_data **p_tdata)
+{
+ pj_status_t status;
+ pjsip_tx_data *tdata;
+
+ /* Create generic response.
+ * This will initialize response's Via, To, From, Call-ID, CSeq
+ * and Record-Route headers from the request.
+ */
+ status = pjsip_endpt_create_response(dlg->endpt,
+ rdata, st_code, st_text, &tdata);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ dlg_beautify_response(dlg, st_code, tdata);
/* Unlock the dialog. */
pj_mutex_unlock(dlg->mutex);
@@ -980,6 +981,9 @@ PJ_DEF(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg,
PJSIP_ENOTRESPONSEMSG);
PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL);
+ pj_mutex_lock(dlg->mutex);
+
+ /* Replace status code and reason */
tdata->msg->line.status.code = st_code;
if (st_text) {
pj_strdup(tdata->pool, &tdata->msg->line.status.reason, st_text);
@@ -987,6 +991,17 @@ PJ_DEF(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg,
tdata->msg->line.status.reason = *pjsip_get_status_text(st_code);
}
+ dlg_beautify_response(dlg, st_code, tdata);
+
+
+ /* Must add reference counter, since tsx_send_msg() will decrement it */
+ pjsip_tx_data_add_ref(tdata);
+
+ /* Force to re-print message. */
+ pjsip_tx_data_invalidate_msg(tdata);
+
+ pj_mutex_unlock(dlg->mutex);
+
return PJ_SUCCESS;
}
@@ -1057,18 +1072,22 @@ PJ_DEF(pj_status_t) pjsip_dlg_respond( pjsip_dialog *dlg,
void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata )
{
pj_status_t status;
- pjsip_transaction *tsx;
+ pjsip_transaction *tsx = NULL;
unsigned i;
/* Lock the dialog. */
pj_mutex_lock(dlg->mutex);
/* Check CSeq */
- if (rdata->msg_info.cseq->cseq <= dlg->remote.cseq) {
+ if (rdata->msg_info.cseq->cseq <= dlg->remote.cseq &&
+ rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD &&
+ rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD)
+ {
/* Invalid CSeq.
* Respond statelessly with 500 (Internal Server Error)
*/
pj_mutex_unlock(dlg->mutex);
+ pj_assert(pjsip_rdata_get_tsx(rdata) == NULL);
pjsip_endpt_respond_stateless(dlg->endpt,
rdata, 500, NULL, NULL, NULL);
return;
@@ -1078,14 +1097,16 @@ void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata )
dlg->remote.cseq = rdata->msg_info.cseq->cseq;
/* Create UAS transaction for this request. */
- status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
- PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;});
+ if (pjsip_rdata_get_tsx(rdata) == NULL) {
+ status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
+ PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;});
- /* Put this dialog in the transaction data. */
- tsx->mod_data[dlg->ua->id] = dlg;
+ /* Put this dialog in the transaction data. */
+ tsx->mod_data[dlg->ua->id] = dlg;
- /* Add transaction count. */
- ++dlg->tsx_count;
+ /* Add transaction count. */
+ ++dlg->tsx_count;
+ }
/* Report the request to dialog usages. */
for (i=0; i<dlg->usage_cnt; ++i) {
@@ -1100,28 +1121,9 @@ void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata )
break;
}
- if (i==dlg->usage_cnt) {
- pjsip_tx_data *tdata;
-
- PJ_LOG(4,(dlg->obj_name,
- "%s is unhandled by dialog usages. "
- "Dialog will response with 500 (Internal Server Error)",
- pjsip_rx_data_get_info(rdata)));
- status = pjsip_endpt_create_response(dlg->endpt,
- rdata,
- PJSIP_SC_INTERNAL_SERVER_ERROR,
- NULL, &tdata);
- if (status == PJ_SUCCESS)
- status = pjsip_tsx_send_msg(tsx, tdata);
-
- if (status != PJ_SUCCESS) {
- char errmsg[PJSIP_ERR_MSG_SIZE];
- pj_strerror(status, errmsg, sizeof(errmsg));
- PJ_LOG(4,(dlg->obj_name,"Error sending %s: %s",
- pjsip_tx_data_get_info(tdata), errmsg));
- pjsip_tsx_terminate(tsx, 500);
- }
- }
+ /* Feed the first request to the transaction. */
+ if (tsx)
+ pjsip_tsx_recv_msg(tsx, rdata);
on_return:
/* Unlock dialog. */
@@ -1142,25 +1144,25 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
/* Check that rdata already has dialog in mod_data. */
pj_assert(pjsip_rdata_get_dlg(rdata) == dlg);
- /* Update the remote tag if it is different. */
- if (pj_strcmp(&dlg->remote.info->tag, &rdata->msg_info.to->tag) != 0) {
-
- pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
-
- /* No need to update remote's tag_hval since its never used. */
- }
-
/* Keep the response's status code */
res_code = rdata->msg_info.msg->line.status.code;
- /* When we receive response that establishes dialog, update the route
- * set and dialog target.
+ /* When we receive response that establishes dialog, update To tag,
+ * route set and dialog target.
*/
- if (!dlg->established &&
+ if (dlg->state == PJSIP_DIALOG_STATE_NULL &&
pjsip_method_creates_dialog(&rdata->msg_info.cseq->method) &&
(res_code > 100 && res_code < 300) &&
rdata->msg_info.to->tag.slen)
{
+ pjsip_hdr *hdr, *end_hdr;
+ pjsip_contact_hdr *contact;
+
+ /* Update To tag. */
+ pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
+ /* No need to update remote's tag_hval since its never used. */
+
+
/* RFC 3271 Section 12.1.2:
* The route set MUST be set to the list of URIs in the Record-Route
* header field from the response, taken in reverse order and
@@ -1169,9 +1171,6 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
* empty set. This route set, even if empty, overrides any pre-existing
* route set for future requests in this dialog.
*/
- pjsip_hdr *hdr, *end_hdr;
- pjsip_contact_hdr *contact;
-
pj_list_init(&dlg->route_set);
end_hdr = &rdata->msg_info.msg->hdr;
@@ -1194,7 +1193,7 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
dlg->target = dlg->remote.contact->uri;
}
- dlg->established = 1;
+ dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
}
/* Update remote target (again) when receiving 2xx response messages
@@ -1251,6 +1250,9 @@ void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg,
if (tsx->state == PJSIP_TSX_STATE_TERMINATED)
--dlg->tsx_count;
+ /* Increment session to prevent usages from destroying dialog. */
+ ++dlg->sess_count;
+
/* Pass to dialog usages. */
for (i=0; i<dlg->usage_cnt; ++i) {
@@ -1260,6 +1262,9 @@ void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg,
(*dlg->usage[i]->on_tsx_state)(tsx, e);
}
+ /* Decrement temporary session. */
+ --dlg->sess_count;
+
if (tsx->state == PJSIP_TSX_STATE_TERMINATED && dlg->tsx_count == 0 &&
dlg->sess_count == 0)
{
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index a84e096b..6dae0370 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -170,8 +170,6 @@ static void tsx_resched_retransmission( pjsip_transaction *tsx );
static pj_status_t tsx_retransmit( pjsip_transaction *tsx, int resched);
static int tsx_send_msg( pjsip_transaction *tsx,
pjsip_tx_data *tdata);
-static void tsx_on_rx_msg( pjsip_transaction *tsx,
- pjsip_rx_data *rdata );
/* State handlers for UAC, indexed by state */
@@ -697,12 +695,12 @@ static pj_bool_t mod_tsx_layer_on_rx_request(pjsip_rx_data *rdata)
/* Race condition!
* Transaction may gets deleted before we have chance to lock it
- * in tsx_on_rx_msg().
+ * in pjsip_tsx_recv_msg().
*/
PJ_TODO(FIX_RACE_CONDITION_HERE);
/* Pass the message to the transaction. */
- tsx_on_rx_msg(tsx, rdata );
+ pjsip_tsx_recv_msg(tsx, rdata );
return PJ_TRUE;
}
@@ -745,12 +743,12 @@ static pj_bool_t mod_tsx_layer_on_rx_response(pjsip_rx_data *rdata)
/* Race condition!
* Transaction may gets deleted before we have chance to lock it
- * in tsx_on_rx_msg().
+ * in pjsip_tsx_recv_msg().
*/
PJ_TODO(FIX_RACE_CONDITION_HERE);
/* Pass the message to the transaction. */
- tsx_on_rx_msg(tsx, rdata );
+ pjsip_tsx_recv_msg(tsx, rdata );
return PJ_TRUE;
}
@@ -965,12 +963,7 @@ static void tsx_set_state( pjsip_transaction *tsx,
pj_assert(rdata != NULL);
- if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG &&
- tsx->tsx_user->on_rx_request)
- {
- (*tsx->tsx_user->on_rx_request)(rdata);
-
- } else if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG &&
+ if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG &&
tsx->tsx_user->on_rx_response)
{
(*tsx->tsx_user->on_rx_response)(rdata);
@@ -1239,11 +1232,11 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user,
tsx->transaction_key.ptr));
- /* Begin with state TRYING.
+ /* Begin with state NULL.
* Manually set-up the state becase we don't want to call the callback.
*/
- tsx->state = PJSIP_TSX_STATE_TRYING;
- tsx->state_handler = &tsx_on_state_trying;
+ tsx->state = PJSIP_TSX_STATE_NULL;
+ tsx->state_handler = &tsx_on_state_null;
/* Get response address. */
status = pjsip_get_response_addr( tsx->pool, rdata, &tsx->res_addr );
@@ -1327,7 +1320,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_send_msg( pjsip_transaction *tsx,
pjsip_tx_data_get_info(tdata),
state_str[tsx->state]));
- PJSIP_EVENT_INIT_TX_MSG(event, tsx, tdata);
+ PJSIP_EVENT_INIT_TX_MSG(event, tdata);
/* Dispatch to transaction. */
lock_tsx(tsx, &lck);
@@ -1349,7 +1342,8 @@ PJ_DEF(pj_status_t) pjsip_tsx_send_msg( pjsip_transaction *tsx,
* This function is called by endpoint when incoming message for the
* transaction is received.
*/
-static void tsx_on_rx_msg( pjsip_transaction *tsx, pjsip_rx_data *rdata)
+PJ_DEF(void) pjsip_tsx_recv_msg( pjsip_transaction *tsx,
+ pjsip_rx_data *rdata)
{
pjsip_event event;
struct tsx_lock_data lck;
@@ -1362,7 +1356,7 @@ static void tsx_on_rx_msg( pjsip_transaction *tsx, pjsip_rx_data *rdata)
rdata->endpt_info.mod_data[mod_tsx_layer.mod.id] = tsx;
/* Init event. */
- PJSIP_EVENT_INIT_RX_MSG(event, tsx, rdata);
+ PJSIP_EVENT_INIT_RX_MSG(event, rdata);
/* Dispatch to transaction. */
lock_tsx(tsx, &lck);
@@ -1716,11 +1710,12 @@ static pj_status_t tsx_on_state_null( pjsip_transaction *tsx,
if (tsx->role == PJSIP_ROLE_UAS) {
- /* UAS doesn't have STATE_NULL.
- * State has moved from NULL after transaction is initialized.
- */
- pj_assert(!"Bug bug bug!!");
- return PJ_EBUG;
+ /* Set state to Trying. */
+ pj_assert(event->type == PJSIP_EVENT_RX_MSG &&
+ event->body.rx_msg.rdata->msg_info.msg->type ==
+ PJSIP_REQUEST_MSG);
+ tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, PJSIP_EVENT_RX_MSG,
+ event->body.rx_msg.rdata);
} else {
pjsip_tx_data *tdata;
diff --git a/pjsip/src/pjsip/sip_ua_layer.c b/pjsip/src/pjsip/sip_ua_layer.c
index c9bcf958..ada14ad2 100644
--- a/pjsip/src/pjsip/sip_ua_layer.c
+++ b/pjsip/src/pjsip/sip_ua_layer.c
@@ -474,9 +474,14 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata)
pj_str_t *from_tag;
pjsip_dialog *dlg;
- /* Optimized path: bail out early if request doesn't have To tag */
- if (rdata->msg_info.to->tag.slen == 0)
+ /* Optimized path: bail out early if request is not CANCEL and it doesn't
+ * have To tag
+ */
+ if (rdata->msg_info.to->tag.slen == 0 &&
+ rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD)
+ {
return PJ_FALSE;
+ }
/* Lock user agent before looking up the dialog hash table. */
pj_mutex_lock(mod_ua.mutex);
@@ -624,17 +629,15 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
// rdata->msg_info.cseq->cseq == dlg_set->dlg_list.next->local.first_cseq)
if (rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD) {
- //pj_str_t *to_tag = &rdata->msg_info.to->tag;
+
+ int st_code = rdata->msg_info.msg->line.status.code;
+ pj_str_t *to_tag = &rdata->msg_info.to->tag;
/* Must hold UA mutex before accessing dialog set. */
pj_mutex_lock(mod_ua.mutex);
dlg = dlg_set->dlg_list.next;
- /* Forking handling is temporarily disabled. */
- PJ_TODO(UA_LAYER_HANDLE_FORKING);
-
-#if 0
while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
/* If there is dialog with no remote tag (i.e. dialog has not
@@ -652,9 +655,12 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
}
/* If no dialog with matching remote tag is found, this must be
- * a forked response.
+ * a forked response. Respond to this ONLY when response is non-100
+ * provisional response OR a 2xx response.
*/
- if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+ if (dlg == (pjsip_dialog*)&dlg_set->dlg_list &&
+ ((st_code/100==1 && st_code!=100) || st_code/100==2))
+ {
/* Report to application about forked condition.
* Application can either create a dialog or ignore the response.
*/
@@ -677,8 +683,16 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
return PJ_TRUE;
}
+
+ } else if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+
+ /* For 100 or non-2xx response which has different To tag,
+ * pass the response to the first dialog.
+ */
+
+ dlg = dlg_set->dlg_list.next;
+
}
-#endif
/* Done with the dialog set. */
pj_mutex_unlock(mod_ua.mutex);
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index 9b48d195..12d140e2 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -1303,6 +1303,9 @@ PJ_DEF(pj_status_t) pjsip_endpt_respond( pjsip_endpoint *endpt,
return status;
}
+ /* Feed the request to the transaction. */
+ pjsip_tsx_recv_msg(tsx, rdata);
+
/* Send the message. */
status = pjsip_tsx_send_msg(tsx, tdata);
if (status != PJ_SUCCESS) {
diff --git a/pjsip/src/pjsua/main.c b/pjsip/src/pjsua/main.c
index 68140d4a..f802799f 100644
--- a/pjsip/src/pjsua/main.c
+++ b/pjsip/src/pjsua/main.c
@@ -18,15 +18,9 @@
*/
#include "pjsua.h"
#include "getopt.h"
+#include <stdlib.h>
-/* For debugging, disable threading. */
-//#define NO_WORKER_THREAD
-
-#ifdef NO_WORKER_THREAD
-#include <conio.h>
-#endif
-
#define THIS_FILE "main.c"
static pjsip_inv_session *inv_session;
@@ -68,35 +62,45 @@ static void ui_help(void)
puts("");
puts("Console keys:");
puts(" m Make a call");
+ puts(" a Answer incoming call");
puts(" h Hangup current call");
puts(" q Quit");
puts("");
fflush(stdout);
}
+static pj_bool_t input(const char *title, char *buf, pj_size_t len)
+{
+ char *p;
+
+ printf("%s (empty to cancel): ", title); fflush(stdout);
+ fgets(buf, len, stdin);
+
+ /* Remove trailing newlines. */
+ for (p=buf; ; ++p) {
+ if (*p=='\r' || *p=='\n') *p='\0';
+ else if (!*p) break;
+ }
+
+ if (!*buf)
+ return PJ_FALSE;
+
+ return PJ_TRUE;
+}
+
static void ui_console_main(void)
{
- char keyin[10];
char buf[128];
- char *p;
pjsip_inv_session *inv;
//ui_help();
for (;;) {
-#ifdef NO_WORKER_THREAD
- pj_time_val timeout = { 0, 10 };
- pjsip_endpt_handle_events (pjsua.endpt, &timeout);
-
- if (kbhit())
- fgets(keyin, sizeof(keyin), stdin);
-#else
ui_help();
- fgets(keyin, sizeof(keyin), stdin);
-#endif
+ fgets(buf, sizeof(buf), stdin);
- switch (keyin[0]) {
+ switch (buf[0]) {
case 'm':
if (inv_session != NULL) {
@@ -106,23 +110,9 @@ static void ui_console_main(void)
}
#if 1
- printf("Enter URL to call: "); fflush(stdout);
- fgets(buf, sizeof(buf), stdin);
-
- if (buf[0]=='\r' || buf[0]=='\n') {
- /* Cancelled. */
- puts("<cancelled>");
- fflush(stdout);
- continue;
- }
-
- /* Remove trailing newlines. */
- for (p=buf; ; ++p) {
- if (*p=='\r' || *p=='\n') *p='\0';
- else if (!*p) break;
- }
/* Make call! : */
-
+ if (!input("Enter URL to call", buf, sizeof(buf)))
+ continue;
pjsua_invite(buf, &inv);
#else
@@ -132,6 +122,33 @@ static void ui_console_main(void)
break;
+ case 'a':
+
+ if (inv_session == NULL || inv_session->role != PJSIP_ROLE_UAS ||
+ inv_session->state >= PJSIP_INV_STATE_CONNECTING)
+ {
+ puts("No pending incoming call");
+ fflush(stdout);
+ continue;
+
+ } else {
+ pj_status_t status;
+ pjsip_tx_data *tdata;
+
+ if (!input("Answer with code (100-699)", buf, sizeof(buf)))
+ continue;
+
+ status = pjsip_inv_answer(inv_session, atoi(buf), NULL, NULL,
+ &tdata);
+ if (status == PJ_SUCCESS)
+ status = pjsip_inv_send_msg(inv_session, tdata, NULL);
+
+ if (status != PJ_SUCCESS)
+ pjsua_perror("Unable to create/send response", status);
+ }
+
+ break;
+
case 'h':
if (inv_session == NULL) {
@@ -672,11 +689,6 @@ int main(int argc, char *argv[])
pjsua_default();
-#ifdef NO_WORKER_THREAD
- pjsua.thread_cnt = 0;
-#endif
-
-
/* Initialize pjsua (to create pool etc).
*/
diff --git a/pjsip/src/pjsua/pjsua_core.c b/pjsip/src/pjsua/pjsua_core.c
index dd4c0c57..46f7fde7 100644
--- a/pjsip/src/pjsua/pjsua_core.c
+++ b/pjsip/src/pjsua/pjsua_core.c
@@ -101,8 +101,99 @@ void pjsua_perror(const char *title, pj_status_t status)
*/
static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata)
{
- PJ_UNUSED_ARG(rdata);
- PJ_TODO(IMPLEMENT_UAS);
+ pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
+ pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
+ pjsip_msg *msg = rdata->msg_info.msg;
+
+ /*
+ * Handle incoming INVITE outside dialog.
+ */
+ if (dlg == NULL && tsx == NULL &&
+ msg->line.req.method.id == PJSIP_INVITE_METHOD)
+ {
+ pj_status_t status;
+ pjsip_tx_data *response = NULL;
+ unsigned options = 0;
+
+ /* Verify that we can handle the request. */
+ status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
+ pjsua.endpt, &response);
+ if (status != PJ_SUCCESS) {
+
+ /*
+ * No we can't handle the incoming INVITE request.
+ */
+
+ if (response) {
+ pjsip_response_addr res_addr;
+
+ pjsip_get_response_addr(response->pool, rdata, &res_addr);
+ pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,
+ NULL, NULL);
+
+ } else {
+
+ /* Respond with 500 (Internal Server Error) */
+ pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
+ NULL, NULL);
+ }
+
+ } else {
+ /*
+ * Yes we can handle the incoming INVITE request.
+ */
+ pjsip_inv_session *inv;
+ pjmedia_sdp_session *answer;
+
+ /* Create dummy SDP answer: */
+
+
+ status = pjmedia_sdp_parse(pjsua.pool, PJSUA_DUMMY_SDP_ANSWER,
+ pj_native_strlen(PJSUA_DUMMY_SDP_ANSWER),
+ &answer);
+ if (status != PJ_SUCCESS) {
+
+ pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL,
+ NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ /* Create dialog: */
+
+ status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
+ &pjsua.contact_uri, &dlg);
+ if (status != PJ_SUCCESS)
+ return PJ_TRUE;
+
+
+ /* Create invite session: */
+
+ status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);
+ if (status != PJ_SUCCESS) {
+
+ status = pjsip_dlg_create_response( dlg, rdata, 500, NULL,
+ &response);
+ if (status == PJ_SUCCESS)
+ status = pjsip_dlg_send_response(dlg,
+ pjsip_rdata_get_tsx(rdata),
+ response);
+ return PJ_TRUE;
+
+ }
+
+ /* Answer with 100 (using the dialog, not invite): */
+
+ status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response);
+ if (status == PJ_SUCCESS)
+ status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), response);
+ }
+
+ /* This INVITE request has been handled. */
+ return PJ_TRUE;
+ }
+
+
+
return PJ_FALSE;
}
@@ -121,7 +212,6 @@ static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata)
static pj_bool_t mod_pjsua_on_rx_response(pjsip_rx_data *rdata)
{
PJ_UNUSED_ARG(rdata);
- PJ_TODO(IMPLEMENT_UAS);
return PJ_FALSE;
}
diff --git a/pjsip/src/test-pjsip/tsx_uas_test.c b/pjsip/src/test-pjsip/tsx_uas_test.c
index ed8f8574..326f2256 100644
--- a/pjsip/src/test-pjsip/tsx_uas_test.c
+++ b/pjsip/src/test-pjsip/tsx_uas_test.c
@@ -709,6 +709,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
test_complete = -110;
return PJ_TRUE;
}
+ pjsip_tsx_recv_msg(tsx, rdata);
save_key(tsx);
send_response(rdata, tsx, status_code);
@@ -749,6 +750,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
test_complete = -120;
return PJ_TRUE;
}
+ pjsip_tsx_recv_msg(tsx, rdata);
save_key(tsx);
@@ -801,6 +803,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
return PJ_TRUE;
}
+ pjsip_tsx_recv_msg(tsx, rdata);
save_key(tsx);
if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
@@ -882,6 +885,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
return PJ_TRUE;
}
+ pjsip_tsx_recv_msg(tsx, rdata);
save_key(tsx);
if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0) {
@@ -966,6 +970,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
return PJ_TRUE;
}
+ pjsip_tsx_recv_msg(tsx, rdata);
save_key(tsx);
send_response(rdata, tsx, TEST9_STATUS_CODE);
@@ -1076,6 +1081,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
return PJ_TRUE;
}
+ pjsip_tsx_recv_msg(tsx, rdata);
save_key(tsx);
schedule_send_response(rdata, &tsx_key, code1, 1000);