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


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10@356690 65c4cc65-6c06-0410-ace0-fbb531ad65f3
10-digiumphones
Richard Mudgett 13 years ago
parent ff7665db86
commit d372c43488

@ -1507,7 +1507,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 */
@ -2485,7 +2485,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.
@ -2516,7 +2516,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;
@ -26269,6 +26269,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)) {
@ -26293,7 +26294,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.
@ -26364,7 +26365,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;
@ -31309,6 +31310,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();
@ -31367,7 +31369,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);
@ -31413,21 +31414,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(&regl, sip_registry_destroy);
@ -31445,6 +31436,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");

@ -1372,6 +1372,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;

@ -128,6 +128,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 */
@ -146,6 +147,7 @@ struct ast_tcptls_session_instance {
int client;
struct ast_sockaddr remote_address;
struct ast_tcptls_session_args *parent;
/*! 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;
};

Loading…
Cancel
Save