Skip to content
Snippets Groups Projects
Commit 21dcf57b authored by rswindell's avatar rswindell
Browse files

Fix race-condition during shutdown or recycle that could cause crash:

active_clients (protected integer) could be 0 at the time of recycle because
there can be delay at the beginning of the FTP ctrl thread (e.g. looking up
filtered IPs/hostnames) before the active_clients is incremented which could
be during/after it was destroyed by the cleanup() function. Now tracking
number of threads using protected integer which increments immediately upon
child thread creation and is not destroyed until the main thread terminates.
There is currently *not* timeout while waiting for child threads to terminate
upon shutdown/recycle, so this could result in a hung server thread if a child
thread is indefinitely hung - consider using a timeout.
parent d0230054
No related branches found
No related tags found
No related merge requests found
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* * * *
* Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html * * Copyright 2012 Rob Swindell - http://www.synchro.net/copyright.html *
* * * *
* This program is free software; you can redistribute it and/or * * This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License * * modify it under the terms of the GNU General Public License *
...@@ -80,6 +80,7 @@ static ftp_startup_t* startup=NULL; ...@@ -80,6 +80,7 @@ static ftp_startup_t* startup=NULL;
static scfg_t scfg; static scfg_t scfg;
static SOCKET server_socket=INVALID_SOCKET; static SOCKET server_socket=INVALID_SOCKET;
static protected_int32_t active_clients; static protected_int32_t active_clients;
static protected_int32_t thread_count;
static volatile time_t uptime=0; static volatile time_t uptime=0;
static volatile ulong served=0; static volatile ulong served=0;
static volatile BOOL terminate_server=FALSE; static volatile BOOL terminate_server=FALSE;
...@@ -205,16 +206,20 @@ static void client_off(SOCKET sock) ...@@ -205,16 +206,20 @@ static void client_off(SOCKET sock)
startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE); startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE);
} }
static void thread_up(BOOL setuid) static int32_t thread_up(BOOL setuid)
{ {
int32_t count = protected_int32_adjust(&thread_count,1);
if(startup!=NULL && startup->thread_up!=NULL) if(startup!=NULL && startup->thread_up!=NULL)
startup->thread_up(startup->cbdata,TRUE, setuid); startup->thread_up(startup->cbdata,TRUE, setuid);
return count;
} }
static void thread_down(void) static int32_t thread_down(void)
{ {
int32_t count = protected_int32_adjust(&thread_count,-1);
if(startup!=NULL && startup->thread_up!=NULL) if(startup!=NULL && startup->thread_up!=NULL)
startup->thread_up(startup->cbdata,FALSE, FALSE); startup->thread_up(startup->cbdata,FALSE, FALSE);
return count;
} }
static SOCKET ftp_open_socket(int type) static SOCKET ftp_open_socket(int type)
...@@ -4473,12 +4478,12 @@ static void ctrl_thread(void* arg) ...@@ -4473,12 +4478,12 @@ static void ctrl_thread(void* arg)
ftp_close_socket(&tmp_sock,__LINE__); ftp_close_socket(&tmp_sock,__LINE__);
{ {
int32_t remain = protected_int32_adjust(&active_clients, -1); int32_t clients = protected_int32_adjust(&active_clients, -1);
int32_t threads = thread_down();
update_clients(); update_clients();
thread_down(); lprintf(LOG_INFO,"%04d CTRL thread terminated (%ld clients and %ld threads remain, %lu served)"
lprintf(LOG_INFO,"%04d CTRL thread terminated (%ld clients remain, %lu served)" ,sock, clients, threads, served);
,sock, remain, served);
} }
} }
...@@ -4497,6 +4502,13 @@ static void cleanup(int code, int line) ...@@ -4497,6 +4502,13 @@ static void cleanup(int code, int line)
if(server_socket!=INVALID_SOCKET) if(server_socket!=INVALID_SOCKET)
ftp_close_socket(&server_socket,__LINE__); ftp_close_socket(&server_socket,__LINE__);
if(thread_count.value > 1) {
lprintf(LOG_DEBUG,"#### Waiting for %d child threads to terminate", thread_count.value-1);
while(thread_count.value > 1) {
mswait(100);
}
}
if(active_clients.value) if(active_clients.value)
lprintf(LOG_WARNING,"#### !FTP Server terminating with %ld active clients", active_clients.value); lprintf(LOG_WARNING,"#### !FTP Server terminating with %ld active clients", active_clients.value);
else else
...@@ -4615,6 +4627,7 @@ void DLLCALL ftp_server(void* arg) ...@@ -4615,6 +4627,7 @@ void DLLCALL ftp_server(void* arg)
startup->recycle_now=FALSE; startup->recycle_now=FALSE;
startup->shutdown_now=FALSE; startup->shutdown_now=FALSE;
terminate_server=FALSE; terminate_server=FALSE;
protected_int32_init(&thread_count, 0);
do { do {
...@@ -4641,7 +4654,7 @@ void DLLCALL ftp_server(void* arg) ...@@ -4641,7 +4654,7 @@ void DLLCALL ftp_server(void* arg)
if(!winsock_startup()) { if(!winsock_startup()) {
cleanup(1,__LINE__); cleanup(1,__LINE__);
return; break;
} }
t=time(NULL); t=time(NULL);
...@@ -4660,7 +4673,7 @@ void DLLCALL ftp_server(void* arg) ...@@ -4660,7 +4673,7 @@ void DLLCALL ftp_server(void* arg)
lprintf(LOG_CRIT,"!ERROR %s",error); lprintf(LOG_CRIT,"!ERROR %s",error);
lprintf(LOG_CRIT,"!Failed to load configuration files"); lprintf(LOG_CRIT,"!Failed to load configuration files");
cleanup(1,__LINE__); cleanup(1,__LINE__);
return; break;
} }
if(startup->host_name[0]==0) if(startup->host_name[0]==0)
...@@ -4683,7 +4696,7 @@ void DLLCALL ftp_server(void* arg) ...@@ -4683,7 +4696,7 @@ void DLLCALL ftp_server(void* arg)
if(!isdir(scfg.temp_dir)) { if(!isdir(scfg.temp_dir)) {
lprintf(LOG_CRIT,"!Invalid temp directory: %s", scfg.temp_dir); lprintf(LOG_CRIT,"!Invalid temp directory: %s", scfg.temp_dir);
cleanup(1,__LINE__); cleanup(1,__LINE__);
return; break;
} }
if(!startup->max_clients) { if(!startup->max_clients) {
...@@ -4724,7 +4737,7 @@ void DLLCALL ftp_server(void* arg) ...@@ -4724,7 +4737,7 @@ void DLLCALL ftp_server(void* arg)
if((server_socket=ftp_open_socket(SOCK_STREAM))==INVALID_SOCKET) { if((server_socket=ftp_open_socket(SOCK_STREAM))==INVALID_SOCKET) {
lprintf(LOG_CRIT,"!ERROR %d opening socket", ERROR_VALUE); lprintf(LOG_CRIT,"!ERROR %d opening socket", ERROR_VALUE);
cleanup(1,__LINE__); cleanup(1,__LINE__);
return; break;
} }
lprintf(LOG_DEBUG,"%04d FTP Server socket opened",server_socket); lprintf(LOG_DEBUG,"%04d FTP Server socket opened",server_socket);
...@@ -4751,14 +4764,14 @@ void DLLCALL ftp_server(void* arg) ...@@ -4751,14 +4764,14 @@ void DLLCALL ftp_server(void* arg)
if(result!=0) { if(result!=0) {
lprintf(LOG_CRIT,"%04d %s", server_socket, BIND_FAILURE_HELP); lprintf(LOG_CRIT,"%04d %s", server_socket, BIND_FAILURE_HELP);
cleanup(1,__LINE__); cleanup(1,__LINE__);
return; break;
} }
if((result=listen(server_socket, 1))!= 0) { if((result=listen(server_socket, 1))!= 0) {
lprintf(LOG_CRIT,"%04d !ERROR %d (%d) listening on socket" lprintf(LOG_CRIT,"%04d !ERROR %d (%d) listening on socket"
,server_socket, result, ERROR_VALUE); ,server_socket, result, ERROR_VALUE);
cleanup(1,__LINE__); cleanup(1,__LINE__);
return; break;
} }
lprintf(LOG_INFO,"%04d FTP Server listening on port %u",server_socket,startup->port); lprintf(LOG_INFO,"%04d FTP Server listening on port %u",server_socket,startup->port);
...@@ -4782,7 +4795,7 @@ void DLLCALL ftp_server(void* arg) ...@@ -4782,7 +4795,7 @@ void DLLCALL ftp_server(void* arg)
while(server_socket!=INVALID_SOCKET && !terminate_server) { while(server_socket!=INVALID_SOCKET && !terminate_server) {
if(active_clients.value==0) { if(thread_count.value <= 1) {
if(!(startup->options&FTP_OPT_NO_RECYCLE)) { if(!(startup->options&FTP_OPT_NO_RECYCLE)) {
if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) { if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
lprintf(LOG_INFO,"0000 Recycle semaphore file (%s) detected",p); lprintf(LOG_INFO,"0000 Recycle semaphore file (%s) detected",p);
...@@ -4907,4 +4920,6 @@ void DLLCALL ftp_server(void* arg) ...@@ -4907,4 +4920,6 @@ void DLLCALL ftp_server(void* arg)
} }
} while(!terminate_server); } while(!terminate_server);
protected_int32_destroy(thread_count);
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment