mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
Add stateful PJSIP response API call, and use it for out-of-dialog responses.
Asterisk had an issue where retransmissions of MESSAGE requests resulted in Asterisk processing the retransmission as if it were a new MESSAGE request. This patch fixes the issue by creating a transaction in PJSIP on the incoming request. This way, if a retransmission arrives, the PJSIP transaction layer will resend the response and Asterisk will not ever see the retransmission. ASTERISK-24920 #close Reported by Mark Michelson Review: https://reviewboard.asterisk.org/r/4532/ ........ Merged revisions 433619 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@433620 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -1281,6 +1281,11 @@ int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
|
|||||||
/*!
|
/*!
|
||||||
* \brief Send a response to an out of dialog request
|
* \brief Send a response to an out of dialog request
|
||||||
*
|
*
|
||||||
|
* Use this function sparingly, since this does not create a transaction
|
||||||
|
* within PJSIP. This means that if the request is retransmitted, it is
|
||||||
|
* your responsibility to detect this and not process the same request
|
||||||
|
* twice, and to send the same response for each retransmission.
|
||||||
|
*
|
||||||
* \param res_addr The response address for this response
|
* \param res_addr The response address for this response
|
||||||
* \param tdata The response to send
|
* \param tdata The response to send
|
||||||
* \param endpoint The ast_sip_endpoint associated with this response
|
* \param endpoint The ast_sip_endpoint associated with this response
|
||||||
@@ -1290,6 +1295,24 @@ int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
|
|||||||
*/
|
*/
|
||||||
int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint);
|
int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send a stateful response to an out of dialog request
|
||||||
|
*
|
||||||
|
* This creates a transaction within PJSIP, meaning that if the request
|
||||||
|
* that we are responding to is retransmitted, we will not attempt to
|
||||||
|
* re-handle the request.
|
||||||
|
*
|
||||||
|
* \param rdata The request that is being responded to
|
||||||
|
* \param tdata The response to send
|
||||||
|
* \param endpoint The ast_sip_endpoint associated with this response
|
||||||
|
*
|
||||||
|
* \since 13.4.0
|
||||||
|
*
|
||||||
|
* \retval 0 Success
|
||||||
|
* \retval -1 Failure
|
||||||
|
*/
|
||||||
|
int ast_sip_send_stateful_response(pjsip_rx_data *rdata, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Determine if an incoming request requires authentication
|
* \brief Determine if an incoming request requires authentication
|
||||||
*
|
*
|
||||||
|
@@ -3298,7 +3298,7 @@ static pj_bool_t supplement_on_rx_request(pjsip_rx_data *rdata)
|
|||||||
return PJ_FALSE;
|
return PJ_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
|
static void supplement_outgoing_response(pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
|
||||||
{
|
{
|
||||||
struct ast_sip_supplement *supplement;
|
struct ast_sip_supplement *supplement;
|
||||||
pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
|
pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
|
||||||
@@ -3306,8 +3306,7 @@ int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, s
|
|||||||
|
|
||||||
AST_RWLIST_RDLOCK(&supplements);
|
AST_RWLIST_RDLOCK(&supplements);
|
||||||
AST_LIST_TRAVERSE(&supplements, supplement, next) {
|
AST_LIST_TRAVERSE(&supplements, supplement, next) {
|
||||||
if (supplement->outgoing_response
|
if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
|
||||||
&& does_method_match(&cseq->method.name, supplement->method)) {
|
|
||||||
supplement->outgoing_response(sip_endpoint, contact, tdata);
|
supplement->outgoing_response(sip_endpoint, contact, tdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3315,10 +3314,35 @@ int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, s
|
|||||||
|
|
||||||
ast_sip_mod_data_set(tdata->pool, tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT, NULL);
|
ast_sip_mod_data_set(tdata->pool, tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT, NULL);
|
||||||
ao2_cleanup(contact);
|
ao2_cleanup(contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
|
||||||
|
{
|
||||||
|
supplement_outgoing_response(tdata, sip_endpoint);
|
||||||
|
|
||||||
return pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), res_addr, tdata, NULL, NULL);
|
return pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), res_addr, tdata, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ast_sip_send_stateful_response(pjsip_rx_data *rdata, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
|
||||||
|
{
|
||||||
|
pjsip_transaction *tsx;
|
||||||
|
|
||||||
|
if (pjsip_tsx_create_uas(NULL, rdata, &tsx) != PJ_SUCCESS) {
|
||||||
|
pjsip_tx_data_dec_ref(tdata);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pjsip_tsx_recv_msg(tsx, rdata);
|
||||||
|
|
||||||
|
supplement_outgoing_response(tdata, sip_endpoint);
|
||||||
|
|
||||||
|
if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
|
||||||
|
pjsip_tx_data_dec_ref(tdata);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
|
int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
|
||||||
struct ast_sip_contact *contact, pjsip_tx_data **tdata)
|
struct ast_sip_contact *contact, pjsip_tx_data **tdata)
|
||||||
{
|
{
|
||||||
|
@@ -577,7 +577,6 @@ static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
|
|||||||
pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
|
pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
|
||||||
pjsip_tx_data *tdata;
|
pjsip_tx_data *tdata;
|
||||||
const pjsip_hdr *hdr;
|
const pjsip_hdr *hdr;
|
||||||
pjsip_response_addr res_addr;
|
|
||||||
pj_status_t status;
|
pj_status_t status;
|
||||||
|
|
||||||
/* Make the response object */
|
/* Make the response object */
|
||||||
@@ -611,17 +610,8 @@ static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
|
|||||||
} else {
|
} else {
|
||||||
struct ast_sip_endpoint *endpoint;
|
struct ast_sip_endpoint *endpoint;
|
||||||
|
|
||||||
/* Get where to send response. */
|
|
||||||
status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
|
|
||||||
if (status != PJ_SUCCESS) {
|
|
||||||
ast_log(LOG_ERROR, "Unable to get response address (%d)\n", status);
|
|
||||||
|
|
||||||
pjsip_tx_data_dec_ref(tdata);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoint = ast_pjsip_rdata_get_endpoint(rdata);
|
endpoint = ast_pjsip_rdata_get_endpoint(rdata);
|
||||||
status = ast_sip_send_response(&res_addr, tdata, endpoint);
|
status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
|
||||||
ao2_cleanup(endpoint);
|
ao2_cleanup(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -610,7 +610,6 @@ static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code co
|
|||||||
{
|
{
|
||||||
pjsip_tx_data *tdata;
|
pjsip_tx_data *tdata;
|
||||||
pj_status_t status;
|
pj_status_t status;
|
||||||
pjsip_response_addr res_addr;
|
|
||||||
|
|
||||||
status = ast_sip_create_response(rdata, code, NULL, &tdata);
|
status = ast_sip_create_response(rdata, code, NULL, &tdata);
|
||||||
if (status != PJ_SUCCESS) {
|
if (status != PJ_SUCCESS) {
|
||||||
@@ -623,15 +622,8 @@ static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code co
|
|||||||
} else {
|
} else {
|
||||||
struct ast_sip_endpoint *endpoint;
|
struct ast_sip_endpoint *endpoint;
|
||||||
|
|
||||||
/* Get where to send response. */
|
|
||||||
status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
|
|
||||||
if (status != PJ_SUCCESS) {
|
|
||||||
ast_log(LOG_ERROR, "Unable to get response address (%d)\n", status);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoint = ast_pjsip_rdata_get_endpoint(rdata);
|
endpoint = ast_pjsip_rdata_get_endpoint(rdata);
|
||||||
status = ast_sip_send_response(&res_addr, tdata, endpoint);
|
status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
|
||||||
ao2_cleanup(endpoint);
|
ao2_cleanup(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -418,7 +418,6 @@ static int rx_task(void *data)
|
|||||||
pjsip_contact_hdr *contact_hdr = NULL;
|
pjsip_contact_hdr *contact_hdr = NULL;
|
||||||
struct registrar_contact_details details = { 0, };
|
struct registrar_contact_details details = { 0, };
|
||||||
pjsip_tx_data *tdata;
|
pjsip_tx_data *tdata;
|
||||||
pjsip_response_addr addr;
|
|
||||||
const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
|
const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
|
||||||
RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
|
RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
|
||||||
struct ast_sip_contact *response_contact;
|
struct ast_sip_contact *response_contact;
|
||||||
@@ -603,11 +602,7 @@ static int rx_task(void *data)
|
|||||||
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
|
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pjsip_get_response_addr(tdata->pool, task_data->rdata, &addr) == PJ_SUCCESS) {
|
ast_sip_send_stateful_response(task_data->rdata, tdata, task_data->endpoint);
|
||||||
ast_sip_send_response(&addr, tdata, task_data->endpoint);
|
|
||||||
} else {
|
|
||||||
pjsip_tx_data_dec_ref(tdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PJ_TRUE;
|
return PJ_TRUE;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user