diff options
author | Richard Mudgett <rmudgett@digium.com> | 2012-02-24 18:33:04 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2012-02-24 18:33:04 +0000 |
commit | ebe2c33b7239b2881007efa3efd8d8a859f0b653 (patch) | |
tree | 1ea2be16f26726b316809648cdd7f71fe24239ba | |
parent | 8e1f841dde99b00e0581e8d5f2859bc503d70aed (diff) |
Fix worker thread resource leak in SIP TCP/TLS.
The SIP TCP/TLS worker threads were created joinable but noone could join
them if they died on their own.
* Fix the SIP TCP/TLS worker threads to not be created joinable.
* _sip_tcp_helper_thread() only needs one parameter since the pvt
parameter is only passed in as NULL and never used.
(closes issue ASTERISK-19203)
Reported by: Steve Davies
Review: https://reviewboard.asterisk.org/r/1714/
........
Merged revisions 356677 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
Merged revisions 356690 from http://svn.asterisk.org/svn/asterisk/branches/10
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@356697 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r-- | channels/chan_sip.c | 48 | ||||
-rw-r--r-- | channels/sip/include/sip.h | 1 | ||||
-rw-r--r-- | include/asterisk/tcptls.h | 2 |
3 files changed, 30 insertions, 21 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index cb4365298..417e7e347 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1510,7 +1510,7 @@ static int get_domain(const char *str, char *domain, int len); static void get_realm(struct sip_pvt *p, const struct sip_request *req); /*-- TCP connection handling ---*/ -static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session); +static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_session); static void *sip_tcp_worker_fn(void *); /*--- Constructing requests and responses */ @@ -2488,7 +2488,7 @@ static void *sip_tcp_worker_fn(void *data) { struct ast_tcptls_session_instance *tcptls_session = data; - return _sip_tcp_helper_thread(NULL, tcptls_session); + return _sip_tcp_helper_thread(tcptls_session); } /*! \brief Check if the authtimeout has expired. @@ -2519,7 +2519,7 @@ static int sip_check_authtimeout(time_t start) /*! \brief SIP TCP thread management function This function reads from the socket, parses the packet into a request */ -static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session) +static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_session) { int res, cl, timeout = -1, authenticated = 0, flags, after_poll = 0, need_poll = 1; time_t start; @@ -26483,6 +26483,7 @@ static int sip_prepare_socket(struct sip_pvt *p) struct ast_tcptls_session_instance *tcptls_session; struct ast_tcptls_session_args *ca; struct ast_sockaddr sa_tmp; + pthread_t launched; /* check to see if a socket is already active */ if ((s->fd != -1) && (s->type == SIP_TRANSPORT_UDP)) { @@ -26507,7 +26508,7 @@ static int sip_prepare_socket(struct sip_pvt *p) } /* At this point we are dealing with a TCP/TLS connection - * 1. We need to check to see if a connectin thread exists + * 1. We need to check to see if a connection thread exists * for this address, if so use that. * 2. If a thread does not exist for this address, but the tcptls_session * exists on the socket, the connection was closed. @@ -26578,7 +26579,7 @@ static int sip_prepare_socket(struct sip_pvt *p) /* Give the new thread a reference to the tcptls_session */ ao2_ref(s->tcptls_session, +1); - if (ast_pthread_create_background(&ca->master, NULL, sip_tcp_worker_fn, s->tcptls_session)) { + if (ast_pthread_create_detached_background(&launched, NULL, sip_tcp_worker_fn, s->tcptls_session)) { ast_debug(1, "Unable to launch '%s'.", ca->name); ao2_ref(s->tcptls_session, -1); /* take away the thread ref we just gave it */ goto create_tcptls_session_fail; @@ -31578,6 +31579,7 @@ static int unload_module(void) struct sip_threadinfo *th; struct ast_context *con; struct ao2_iterator i; + int wait_count; network_change_event_unsubscribe(); @@ -31636,7 +31638,6 @@ static int unload_module(void) pthread_t thread = th->threadid; th->stop = 1; pthread_kill(thread, SIGURG); - pthread_join(thread, NULL); ao2_t_ref(th, -1, "decrement ref from iterator"); } ao2_iterator_destroy(&i); @@ -31682,21 +31683,11 @@ static int unload_module(void) sip_epa_unregister_all(); destroy_escs(); - if (default_tls_cfg.certfile) { - ast_free(default_tls_cfg.certfile); - } - if (default_tls_cfg.pvtfile) { - ast_free(default_tls_cfg.pvtfile); - } - if (default_tls_cfg.cipher) { - ast_free(default_tls_cfg.cipher); - } - if (default_tls_cfg.cafile) { - ast_free(default_tls_cfg.cafile); - } - if (default_tls_cfg.capath) { - ast_free(default_tls_cfg.capath); - } + ast_free(default_tls_cfg.certfile); + ast_free(default_tls_cfg.pvtfile); + ast_free(default_tls_cfg.cipher); + ast_free(default_tls_cfg.cafile); + ast_free(default_tls_cfg.capath); cleanup_all_regs(); ASTOBJ_CONTAINER_DESTROYALL(®l, sip_registry_destroy); @@ -31714,6 +31705,21 @@ static int unload_module(void) ASTOBJ_CONTAINER_DESTROYALL(&submwil, sip_subscribe_mwi_destroy); ASTOBJ_CONTAINER_DESTROY(&submwil); + /* + * Wait awhile for the TCP/TLS thread container to become empty. + * + * XXX This is a hack, but the worker threads cannot be created + * joinable. They can die on their own and remove themselves + * from the container thus resulting in a huge memory leak. + */ + wait_count = 1000; + while (ao2_container_count(threadt) && --wait_count) { + sched_yield(); + } + if (!wait_count) { + ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); + } + ao2_t_ref(peers, -1, "unref the peers table"); ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table"); ao2_t_ref(dialogs, -1, "unref the dialogs table"); diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 0ae8be8f8..2f9beff84 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -1393,6 +1393,7 @@ struct tcptls_packet { }; /*! \brief Definition of a thread that handles a socket */ struct sip_threadinfo { + /*! TRUE if the thread needs to kill itself. (The module is being unloaded.) */ int stop; int alert_pipe[2]; /*! Used to alert tcptls thread when packet is ready to be written */ pthread_t threadid; diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h index e9b2371fb..c60501397 100644 --- a/include/asterisk/tcptls.h +++ b/include/asterisk/tcptls.h @@ -136,6 +136,7 @@ struct ast_tcptls_session_args { struct ast_tls_config *tls_cfg; /*!< points to the SSL configuration if any */ int accept_fd; int poll_timeout; + /*! Server accept_fn thread ID used for external shutdown requests. */ pthread_t master; void *(*accept_fn)(void *); /*!< the function in charge of doing the accept */ void (*periodic_fn)(void *);/*!< something we may want to run before after select on the accept socket */ @@ -154,6 +155,7 @@ struct ast_tcptls_session_instance { int client; struct ast_sockaddr remote_address; struct ast_tcptls_session_args *parent; + /*! \todo XXX Why do we still use this lock when this struct is allocated as an ao2 object which has its own lock? */ ast_mutex_t lock; }; |