mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-13 00:04:53 +00:00
Merge "res_pjsip: Refactor endpt_send_request to include transaction timeout" into 13
This commit is contained in:
@@ -1257,6 +1257,30 @@ int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg,
|
|||||||
struct ast_sip_endpoint *endpoint, void *token,
|
struct ast_sip_endpoint *endpoint, void *token,
|
||||||
void (*callback)(void *token, pjsip_event *e));
|
void (*callback)(void *token, pjsip_event *e));
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief General purpose method for sending an Out-Of-Dialog SIP request
|
||||||
|
*
|
||||||
|
* This is a companion function for \ref ast_sip_create_request. The request
|
||||||
|
* created there can be passed to this function, though any request may be
|
||||||
|
* passed in.
|
||||||
|
*
|
||||||
|
* This will automatically set up handling outbound authentication challenges if
|
||||||
|
* they arrive.
|
||||||
|
*
|
||||||
|
* \param tdata The request to send
|
||||||
|
* \param endpoint Optional. If specified, the out-of-dialog request is sent to the endpoint.
|
||||||
|
* \param timeout. If non-zero, after the timeout the transaction will be terminated
|
||||||
|
* and the callback will be called with the PJSIP_EVENT_TIMER type.
|
||||||
|
* \param token Data to be passed to the callback upon receipt of out-of-dialog response.
|
||||||
|
* \param callback Callback to be called upon receipt of out-of-dialog response.
|
||||||
|
*
|
||||||
|
* \retval 0 Success
|
||||||
|
* \retval -1 Failure (out-of-dialog callback will not be called.)
|
||||||
|
*/
|
||||||
|
int ast_sip_send_out_of_dialog_request(pjsip_tx_data *tdata,
|
||||||
|
struct ast_sip_endpoint *endpoint, int timeout, void *token,
|
||||||
|
void (*callback)(void *token, pjsip_event *e));
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief General purpose method for creating a SIP response
|
* \brief General purpose method for creating a SIP response
|
||||||
*
|
*
|
||||||
|
159
res/res_pjsip.c
159
res/res_pjsip.c
@@ -21,6 +21,8 @@
|
|||||||
#include <pjsip.h>
|
#include <pjsip.h>
|
||||||
/* Needed for SUBSCRIBE, NOTIFY, and PUBLISH method definitions */
|
/* Needed for SUBSCRIBE, NOTIFY, and PUBLISH method definitions */
|
||||||
#include <pjsip_simple.h>
|
#include <pjsip_simple.h>
|
||||||
|
#include <pjsip/sip_transaction.h>
|
||||||
|
#include <pj/timer.h>
|
||||||
#include <pjlib.h>
|
#include <pjlib.h>
|
||||||
|
|
||||||
#include "asterisk/res_pjsip.h"
|
#include "asterisk/res_pjsip.h"
|
||||||
@@ -2813,6 +2815,128 @@ static pj_bool_t does_method_match(const pj_str_t *message_method, const char *s
|
|||||||
|
|
||||||
/*! Maximum number of challenges before assuming that we are in a loop */
|
/*! Maximum number of challenges before assuming that we are in a loop */
|
||||||
#define MAX_RX_CHALLENGES 10
|
#define MAX_RX_CHALLENGES 10
|
||||||
|
#define TIMER_INACTIVE 0
|
||||||
|
#define TIMEOUT_TIMER2 5
|
||||||
|
|
||||||
|
struct tsx_data {
|
||||||
|
void *token;
|
||||||
|
void (*cb)(void*, pjsip_event*);
|
||||||
|
pjsip_transaction *tsx;
|
||||||
|
pj_timer_entry *timeout_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void send_tsx_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event);
|
||||||
|
|
||||||
|
pjsip_module send_tsx_module = {
|
||||||
|
.name = { "send_tsx_module", 23 },
|
||||||
|
.id = -1,
|
||||||
|
.priority = PJSIP_MOD_PRIORITY_APPLICATION,
|
||||||
|
.on_tsx_state = &send_tsx_on_tsx_state,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief This is the pjsip_tsx_send_msg callback */
|
||||||
|
static void send_tsx_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event)
|
||||||
|
{
|
||||||
|
struct tsx_data *tsx_data;
|
||||||
|
|
||||||
|
if (event->type != PJSIP_EVENT_TSX_STATE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsx_data = (struct tsx_data*) tsx->mod_data[send_tsx_module.id];
|
||||||
|
if (tsx_data == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tsx->status_code < 200) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->body.tsx_state.type == PJSIP_EVENT_TIMER) {
|
||||||
|
ast_debug(1, "PJSIP tsx timer expired\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tsx_data->timeout_timer && tsx_data->timeout_timer->id != TIMER_INACTIVE) {
|
||||||
|
pj_mutex_lock(tsx->mutex_b);
|
||||||
|
pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(tsx->endpt),
|
||||||
|
tsx_data->timeout_timer, TIMER_INACTIVE);
|
||||||
|
pj_mutex_unlock(tsx->mutex_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the callback, if any, and prevent the callback from being called again
|
||||||
|
* by clearing the transaction's module_data.
|
||||||
|
*/
|
||||||
|
tsx->mod_data[send_tsx_module.id] = NULL;
|
||||||
|
|
||||||
|
if (tsx_data->cb) {
|
||||||
|
(*tsx_data->cb)(tsx_data->token, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tsx_timer_callback(pj_timer_heap_t *theap, pj_timer_entry *entry)
|
||||||
|
{
|
||||||
|
struct tsx_data *tsx_data = entry->user_data;
|
||||||
|
|
||||||
|
entry->id = TIMER_INACTIVE;
|
||||||
|
ast_debug(1, "Internal tsx timer expired\n");
|
||||||
|
pjsip_tsx_terminate(tsx_data->tsx, PJSIP_SC_TSX_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pj_status_t endpt_send_transaction(pjsip_endpoint *endpt,
|
||||||
|
pjsip_tx_data *tdata, int timeout, void *token,
|
||||||
|
pjsip_endpt_send_callback cb)
|
||||||
|
{
|
||||||
|
pjsip_transaction *tsx;
|
||||||
|
struct tsx_data *tsx_data;
|
||||||
|
pj_status_t status;
|
||||||
|
pjsip_event event;
|
||||||
|
|
||||||
|
ast_assert(endpt && tdata);
|
||||||
|
|
||||||
|
status = pjsip_tsx_create_uac(&send_tsx_module, tdata, &tsx);
|
||||||
|
if (status != PJ_SUCCESS) {
|
||||||
|
pjsip_tx_data_dec_ref(tdata);
|
||||||
|
ast_log(LOG_ERROR, "Unable to create pjsip uac\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsx_data = PJ_POOL_ALLOC_T(tsx->pool, struct tsx_data);
|
||||||
|
tsx_data->token = token;
|
||||||
|
tsx_data->cb = cb;
|
||||||
|
tsx_data->tsx = tsx;
|
||||||
|
if (timeout > 0) {
|
||||||
|
tsx_data->timeout_timer = PJ_POOL_ALLOC_T(tsx->pool, pj_timer_entry);
|
||||||
|
} else {
|
||||||
|
tsx_data->timeout_timer = NULL;
|
||||||
|
}
|
||||||
|
tsx->mod_data[send_tsx_module.id] = tsx_data;
|
||||||
|
|
||||||
|
PJSIP_EVENT_INIT_TX_MSG(event, tdata);
|
||||||
|
pjsip_tx_data_set_transport(tdata, &tsx->tp_sel);
|
||||||
|
|
||||||
|
if (timeout > 0) {
|
||||||
|
pj_time_val timeout_timer_val = { timeout / 1000, timeout % 1000 };
|
||||||
|
|
||||||
|
pj_timer_entry_init(tsx_data->timeout_timer, TIMEOUT_TIMER2,
|
||||||
|
tsx_data, &tsx_timer_callback);
|
||||||
|
pj_mutex_lock(tsx->mutex_b);
|
||||||
|
pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(tsx->endpt),
|
||||||
|
tsx_data->timeout_timer, TIMER_INACTIVE);
|
||||||
|
pj_timer_heap_schedule(pjsip_endpt_get_timer_heap(tsx->endpt),
|
||||||
|
tsx_data->timeout_timer, &timeout_timer_val);
|
||||||
|
tsx_data->timeout_timer->id = TIMEOUT_TIMER2;
|
||||||
|
pj_mutex_unlock(tsx->mutex_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = (*tsx->state_handler)(tsx, &event);
|
||||||
|
pjsip_tx_data_dec_ref(tdata);
|
||||||
|
if (status != PJ_SUCCESS) {
|
||||||
|
ast_log(LOG_ERROR, "Unable to send message\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Structure to hold information about an outbound request */
|
/*! \brief Structure to hold information about an outbound request */
|
||||||
struct send_request_data {
|
struct send_request_data {
|
||||||
@@ -2872,7 +2996,7 @@ static void endpt_send_request_wrapper(void *token, pjsip_event *e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint,
|
static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint,
|
||||||
pjsip_tx_data *tdata, pj_int32_t timeout, void *token, pjsip_endpt_send_callback cb)
|
pjsip_tx_data *tdata, int timeout, void *token, pjsip_endpt_send_callback cb)
|
||||||
{
|
{
|
||||||
struct send_request_wrapper *req_wrapper;
|
struct send_request_wrapper *req_wrapper;
|
||||||
pj_status_t ret_val;
|
pj_status_t ret_val;
|
||||||
@@ -2888,7 +3012,7 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint,
|
|||||||
req_wrapper->callback = cb;
|
req_wrapper->callback = cb;
|
||||||
|
|
||||||
ao2_ref(req_wrapper, +1);
|
ao2_ref(req_wrapper, +1);
|
||||||
ret_val = pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, timeout,
|
ret_val = endpt_send_transaction(ast_sip_get_pjsip_endpoint(), tdata, timeout,
|
||||||
req_wrapper, endpt_send_request_wrapper);
|
req_wrapper, endpt_send_request_wrapper);
|
||||||
if (ret_val != PJ_SUCCESS) {
|
if (ret_val != PJ_SUCCESS) {
|
||||||
char errmsg[PJ_ERR_MSG_SIZE];
|
char errmsg[PJ_ERR_MSG_SIZE];
|
||||||
@@ -2928,6 +3052,10 @@ static void send_request_cb(void *token, pjsip_event *e)
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
switch(e->body.tsx_state.type) {
|
switch(e->body.tsx_state.type) {
|
||||||
|
case PJSIP_EVENT_USER:
|
||||||
|
/* Map USER (transaction cancelled by timeout) to TIMER */
|
||||||
|
e->body.tsx_state.type = PJSIP_EVENT_TIMER;
|
||||||
|
break;
|
||||||
case PJSIP_EVENT_TRANSPORT_ERROR:
|
case PJSIP_EVENT_TRANSPORT_ERROR:
|
||||||
case PJSIP_EVENT_TIMER:
|
case PJSIP_EVENT_TIMER:
|
||||||
break;
|
break;
|
||||||
@@ -2978,8 +3106,9 @@ static void send_request_cb(void *token, pjsip_event *e)
|
|||||||
ao2_ref(req_data, -1);
|
ao2_ref(req_data, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint,
|
int ast_sip_send_out_of_dialog_request(pjsip_tx_data *tdata,
|
||||||
void *token, void (*callback)(void *token, pjsip_event *e))
|
struct ast_sip_endpoint *endpoint, int timeout, void *token,
|
||||||
|
void (*callback)(void *token, pjsip_event *e))
|
||||||
{
|
{
|
||||||
struct ast_sip_supplement *supplement;
|
struct ast_sip_supplement *supplement;
|
||||||
struct send_request_data *req_data;
|
struct send_request_data *req_data;
|
||||||
@@ -3005,7 +3134,7 @@ static int send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpo
|
|||||||
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);
|
||||||
|
|
||||||
if (endpt_send_request(endpoint, tdata, -1, req_data, send_request_cb)
|
if (endpt_send_request(endpoint, tdata, timeout, req_data, send_request_cb)
|
||||||
!= PJ_SUCCESS) {
|
!= PJ_SUCCESS) {
|
||||||
ao2_cleanup(req_data);
|
ao2_cleanup(req_data);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -3023,7 +3152,7 @@ int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg,
|
|||||||
if (dlg) {
|
if (dlg) {
|
||||||
return send_in_dialog_request(tdata, dlg);
|
return send_in_dialog_request(tdata, dlg);
|
||||||
} else {
|
} else {
|
||||||
return send_out_of_dialog_request(tdata, endpoint, token, callback);
|
return ast_sip_send_out_of_dialog_request(tdata, endpoint, -1, token, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3541,8 +3670,25 @@ static int load_module(void)
|
|||||||
return AST_MODULE_LOAD_DECLINE;
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (internal_sip_register_service(&send_tsx_module)) {
|
||||||
|
ast_log(LOG_ERROR, "Failed to initialize send request module. Aborting load\n");
|
||||||
|
internal_sip_unregister_service(&supplement_module);
|
||||||
|
ast_sip_destroy_distributor();
|
||||||
|
ast_res_pjsip_destroy_configuration();
|
||||||
|
ast_sip_destroy_global_headers();
|
||||||
|
stop_monitor_thread();
|
||||||
|
ast_sip_destroy_system();
|
||||||
|
pj_pool_release(memory_pool);
|
||||||
|
memory_pool = NULL;
|
||||||
|
pjsip_endpt_destroy(ast_pjsip_endpoint);
|
||||||
|
ast_pjsip_endpoint = NULL;
|
||||||
|
pj_caching_pool_destroy(&caching_pool);
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
if (internal_sip_initialize_outbound_authentication()) {
|
if (internal_sip_initialize_outbound_authentication()) {
|
||||||
ast_log(LOG_ERROR, "Failed to initialize outbound authentication. Aborting load\n");
|
ast_log(LOG_ERROR, "Failed to initialize outbound authentication. Aborting load\n");
|
||||||
|
internal_sip_unregister_service(&send_tsx_module);
|
||||||
internal_sip_unregister_service(&supplement_module);
|
internal_sip_unregister_service(&supplement_module);
|
||||||
ast_sip_destroy_distributor();
|
ast_sip_destroy_distributor();
|
||||||
ast_res_pjsip_destroy_configuration();
|
ast_res_pjsip_destroy_configuration();
|
||||||
@@ -3586,6 +3732,7 @@ static int unload_pjsip(void *data)
|
|||||||
ast_res_pjsip_destroy_configuration();
|
ast_res_pjsip_destroy_configuration();
|
||||||
ast_sip_destroy_system();
|
ast_sip_destroy_system();
|
||||||
ast_sip_destroy_global_headers();
|
ast_sip_destroy_global_headers();
|
||||||
|
internal_sip_unregister_service(&send_tsx_module);
|
||||||
internal_sip_unregister_service(&supplement_module);
|
internal_sip_unregister_service(&supplement_module);
|
||||||
if (monitor_thread) {
|
if (monitor_thread) {
|
||||||
stop_monitor_thread();
|
stop_monitor_thread();
|
||||||
|
Reference in New Issue
Block a user