summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2015-03-27 20:30:18 +0000
committerMark Michelson <mmichelson@digium.com>2015-03-27 20:30:18 +0000
commit85feac857c659c8ddff3af67099f0b0bd34fb2b2 (patch)
treeb825a9916fe72408833484ed5ceb305e1772c2a7
parentdc2cf21144b81800329bad4596ded07ed0882ed7 (diff)
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/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@433619 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--include/asterisk/res_pjsip.h23
-rw-r--r--res/res_pjsip.c30
-rw-r--r--res/res_pjsip/pjsip_options.c12
-rw-r--r--res/res_pjsip_messaging.c10
-rw-r--r--res/res_pjsip_registrar.c7
5 files changed, 53 insertions, 29 deletions
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 523b1b4ce..fcad28878 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -1279,6 +1279,11 @@ int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
/*!
* \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 tdata The response to send
* \param endpoint The ast_sip_endpoint associated with this response
@@ -1289,6 +1294,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);
/*!
+ * \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
*
* This calls into the registered authenticator's requires_authentication callback
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index c0e00d731..e632817d5 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -3292,7 +3292,7 @@ static pj_bool_t supplement_on_rx_request(pjsip_rx_data *rdata)
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;
pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
@@ -3300,8 +3300,7 @@ int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, s
AST_RWLIST_RDLOCK(&supplements);
AST_LIST_TRAVERSE(&supplements, supplement, next) {
- if (supplement->outgoing_response
- && does_method_match(&cseq->method.name, supplement->method)) {
+ if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
supplement->outgoing_response(sip_endpoint, contact, tdata);
}
}
@@ -3309,10 +3308,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);
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);
}
+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,
struct ast_sip_contact *contact, pjsip_tx_data **tdata)
{
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index 0b14bed92..9794827b5 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -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_tx_data *tdata;
const pjsip_hdr *hdr;
- pjsip_response_addr res_addr;
pj_status_t status;
/* Make the response object */
@@ -611,17 +610,8 @@ static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
} else {
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);
- status = ast_sip_send_response(&res_addr, tdata, endpoint);
+ status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
ao2_cleanup(endpoint);
}
diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c
index f3ae5e674..5caf89374 100644
--- a/res/res_pjsip_messaging.c
+++ b/res/res_pjsip_messaging.c
@@ -610,7 +610,6 @@ static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code co
{
pjsip_tx_data *tdata;
pj_status_t status;
- pjsip_response_addr res_addr;
status = ast_sip_create_response(rdata, code, NULL, &tdata);
if (status != PJ_SUCCESS) {
@@ -623,15 +622,8 @@ static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code co
} else {
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);
- status = ast_sip_send_response(&res_addr, tdata, endpoint);
+ status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
ao2_cleanup(endpoint);
}
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index 4b55b2ded..e1eaf6905 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -418,7 +418,6 @@ static int rx_task(void *data)
pjsip_contact_hdr *contact_hdr = NULL;
struct registrar_contact_details details = { 0, };
pjsip_tx_data *tdata;
- pjsip_response_addr addr;
const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
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);
}
- if (pjsip_get_response_addr(tdata->pool, task_data->rdata, &addr) == PJ_SUCCESS) {
- ast_sip_send_response(&addr, tdata, task_data->endpoint);
- } else {
- pjsip_tx_data_dec_ref(tdata);
- }
+ ast_sip_send_stateful_response(task_data->rdata, tdata, task_data->endpoint);
return PJ_TRUE;
}