]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Add stateful PJSIP response API call, and use it for out-of-dialog responses.
authorMark Michelson <mmichelson@digium.com>
Fri, 27 Mar 2015 20:46:55 +0000 (20:46 +0000)
committerMark Michelson <mmichelson@digium.com>
Fri, 27 Mar 2015 20:46:55 +0000 (20:46 +0000)
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

include/asterisk/res_pjsip.h
res/res_pjsip.c
res/res_pjsip/pjsip_options.c
res/res_pjsip_messaging.c
res/res_pjsip_registrar.c

index 442ee72f779fd471d6a17540020e37814a049558..6e3a9ea930a7726f1257ed4c7404f3621b32daae 100644 (file)
@@ -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
  *
+ * 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
@@ -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);
 
+/*!
+ * \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
  *
index e5af28ca8211f772f1f2b5504921e225386f65f8..64cd43e18448ff03d53e29b0b45fef540a285fef 100644 (file)
@@ -3298,7 +3298,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);
@@ -3306,8 +3306,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);
                }
        }
@@ -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);
        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)
 {
index 0b14bed921192b72e5d41e6f6ab4b0806230b9e5..9794827b56864d6cc2c281f3e98386a69340ae35 100644 (file)
@@ -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);
        }
 
index f3ae5e674e94bbe6caf9e27fc29e7e2b9ef9e9e8..5caf8937407592441c393d43b84e3b3c68c7405f 100644 (file)
@@ -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);
        }
 
index 7fe2b77d9f56eec3b8ad23bd2d2a8572fac19e2c..944a6055efaa40932866434839bce0b9b64cc1d1 100644 (file)
@@ -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;
 }