26 #include "asterisk/res_pjsip.h"
29 #include "include/res_pjsip_private.h"
32 #define TRANSPORTS_BUCKETS 127
34 #define IDLE_TIMEOUT (pjsip_cfg()->tsx.td)
37 static const pj_str_t keepalive_packet = {
"\r\n\r\n", 4 };
46 static pthread_t keepalive_thread = AST_PTHREADT_NULL;
49 static unsigned int keepalive_interval;
61 pjsip_tpselector selector = {
62 .type = PJSIP_TPSELECTOR_TRANSPORT,
66 pjsip_tpmgr_send_raw(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
71 keepalive_packet.slen,
73 pj_sockaddr_get_len(&monitored->
transport->key.rem_addr),
78 static void *keepalive_transport_thread(
void *data)
81 pj_thread_desc desc = { 0 };
84 if (pj_thread_register(
"Asterisk Keepalive Thread", desc, &thread) != PJ_SUCCESS) {
85 ast_log(LOG_ERROR,
"Could not register keepalive thread with PJLIB, keepalives will not occur.\n");
98 while (keepalive_interval) {
102 sleep(keepalive_interval);
110 for (; (monitored = ao2_iterator_next(&iter));
ao2_ref(monitored, -1)) {
111 keepalive_transport_send_keepalive(monitored);
122 static int idle_sched_init_pj_thread(
void)
124 if (!pj_thread_is_registered()) {
126 pj_thread_desc *desc;
130 ast_log(LOG_ERROR,
"Could not get thread desc from thread-local storage.\n");
134 pj_bzero(*desc,
sizeof(*desc));
136 pj_thread_register(
"Transport Monitor", *desc, &thread);
151 ao2_cleanup(transports);
157 static int idle_sched_cb(
const void *data)
159 char *obj_name = (
char *) data;
162 if (idle_sched_init_pj_thread()) {
167 monitored = get_monitored_transport_by_name(obj_name);
170 ast_log(LOG_NOTICE,
"Shutting down transport '%s' since no request was received in %d seconds\n",
171 monitored->
transport->info, IDLE_TIMEOUT / 1000);
172 pjsip_transport_shutdown(monitored->
transport);
181 static int idle_sched_cleanup(
const void *data)
183 char *obj_name = (
char *) data;
186 if (idle_sched_init_pj_thread()) {
191 monitored = get_monitored_transport_by_name(obj_name);
193 pjsip_transport_shutdown(monitored->
transport);
202 static void monitored_transport_destroy(
void *obj)
206 pjsip_transport_dec_ref(monitored->
transport);
210 static void monitored_transport_state_callback(pjsip_transport *
transport, pjsip_transport_state
state,
211 const pjsip_transport_state_info *info)
216 if (PJSIP_TRANSPORT_IS_RELIABLE(transport)
217 && (transport->dir == PJSIP_TP_DIR_INCOMING || keepalive_interval)
222 case PJSIP_TP_STATE_CONNECTED:
223 monitored = ao2_alloc_options(
sizeof(*monitored),
229 pjsip_transport_add_ref(monitored->
transport);
233 if (transport->dir == PJSIP_TP_DIR_INCOMING) {
234 char *obj_name =
ast_strdup(transport->obj_name);
239 pjsip_transport_shutdown(transport);
245 case PJSIP_TP_STATE_SHUTDOWN:
246 case PJSIP_TP_STATE_DISCONNECTED:
258 monitored_transport_state_callback,
262 static int monitored_transport_hash_fn(
const void *obj,
int flags)
273 key =
object->transport->obj_name;
284 static int monitored_transport_cmp_fn(
void *obj,
void *arg,
int flags)
288 const char *right_key = arg;
293 right_key = object_right->
transport->obj_name;
296 cmp = strcmp(object_left->
transport->obj_name, right_key);
303 cmp = strncmp(object_left->
transport->obj_name, right_key, strlen(right_key));
317 static void keepalive_global_loaded(
const char *object_type)
319 unsigned int new_interval = ast_sip_get_keep_alive_interval();
322 keepalive_interval = new_interval;
323 }
else if (keepalive_interval) {
324 ast_log(LOG_NOTICE,
"Keepalive support can not be disabled once activated.\n");
331 if (keepalive_thread != AST_PTHREADT_NULL) {
335 if (ast_pthread_create(&keepalive_thread, NULL, keepalive_transport_thread, NULL)) {
336 ast_log(LOG_ERROR,
"Could not create thread for sending keepalive messages.\n");
337 keepalive_thread = AST_PTHREADT_NULL;
338 keepalive_interval = 0;
344 .
loaded = keepalive_global_loaded,
353 static pj_bool_t idle_monitor_on_rx_request(pjsip_rx_data *rdata)
357 idle_trans = get_monitored_transport_by_name(rdata->tp_info.transport->obj_name);
366 static pjsip_module idle_monitor_module = {
367 .name = {
"idle monitor module", 19},
368 .priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER + 3,
369 .on_rx_request = idle_monitor_on_rx_request,
372 int ast_sip_initialize_transport_management(
void)
377 monitored_transport_hash_fn, NULL, monitored_transport_cmp_fn);
379 ast_log(LOG_ERROR,
"Could not create container for transports to perform keepalive on.\n");
387 ast_log(LOG_ERROR,
"Failed to create keepalive scheduler context.\n");
393 ast_log(LOG_ERROR,
"Failed to start keepalive scheduler thread\n");
400 ast_sip_register_service(&idle_monitor_module);
410 void ast_sip_destroy_transport_management(
void)
412 if (keepalive_interval) {
413 keepalive_interval = 0;
414 if (keepalive_thread != AST_PTHREADT_NULL) {
415 pthread_kill(keepalive_thread, SIGURG);
416 pthread_join(keepalive_thread, NULL);
417 keepalive_thread = AST_PTHREADT_NULL;
425 ast_sip_unregister_service(&idle_monitor_module);
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
void ast_sched_clean_by_callback(struct ast_sched_context *con, ast_sched_cb match, ast_sched_cb cleanup_cb)
Clean all scheduled events with matching callback.
Asterisk main include file. File version handling, generic pbx functions.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
The arg parameter is a search key, but is not an object.
pjsip_transport * transport
The underlying PJSIP transport.
int sip_received
Non-zero if a PJSIP request was received.
int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result
Adds a scheduled event with rescheduling support.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_strdup(str)
A wrapper for strdup()
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Interface for a sorcery object type observer.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Module has failed to load, may be in an inconsistent state.
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
The arg parameter is an object of the same type.
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Structure for transport to be monitored.
Search option field mask.
void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element)
Unregister a transport state notification callback element.
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
Asterisk module definitions.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element)
Register a transport state notification callback element.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ao2_link(container, obj)
Add an object to a container.