Newer
Older
socket_debug[sock]&=~SOCKET_DEBUG_TERMINATE;
#endif
tmp_sock=sock;
int32_t clients = protected_uint32_adjust_fetch(&active_clients, -1);
int32_t threads = thread_down();
update_clients();
lprintf(LOG_INFO,"%04d CTRL thread terminated (%d clients and %d threads remain, %lu served)"
,sock, clients, threads, served);
lprintf(LOG_DEBUG,"0000 cleanup called from line %d",line);
if(protected_uint32_value(thread_count) > 1) {
lprintf(LOG_INFO, "0000 Waiting for %d child threads to terminate", protected_uint32_value(thread_count)-1);
while(protected_uint32_value(thread_count) > 1) {
mswait(100);
}
lprintf(LOG_INFO, "0000 Done waiting for child threads to terminate");
}
free_text(text);
semfile_list_free(&recycle_semfiles);
semfile_list_free(&shutdown_semfiles);
if(ftp_set != NULL) {
xpms_destroy(ftp_set, ftp_close_socket_cb, NULL);
ftp_set = NULL;
}
update_clients(); /* active_clients is destroyed below */
listFree(¤t_connections);
if(protected_uint32_value(active_clients))
lprintf(LOG_WARNING,"!!!! Terminating with %d active clients", protected_uint32_value(active_clients));
protected_uint32_destroy(active_clients);
#ifdef _WINSOCKAPI_
if(WSAInitialized && WSACleanup()!=0)
lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
if(terminate_server || code)
lprintf(LOG_INFO,"#### FTP Server thread terminated (%lu clients served)", served);
if(startup!=NULL && startup->terminated!=NULL)
startup->terminated(startup->cbdata,code);
const char* DLLCALL ftp_ver(void)
{
static char ver[256];
char compiler[32];
safe_snprintf(ver, sizeof(ver), "%s %s%c%s "
"Compiled %s/%s %s %s with %s"
,VERSION, REVISION
#ifdef _DEBUG
," Debug"
#else
,""
#endif
,git_branch, git_hash
,__DATE__, __TIME__, compiler);
return(ver);
}
void DLLCALL ftp_server(void* arg)
char* p;
char path[MAX_PATH+1];
char error[256];
char str[256];
socklen_t client_addr_len;
SOCKET client_socket;
int i;
time_t t;
time_t start;
time_t initialized=0;
startup=(ftp_startup_t*)arg;
SetThreadName("sbbs/ftpServer");
#ifdef _THREAD_SUID_BROKEN
if(thread_suid_broken)
startup->seteuid(TRUE);
#endif
sbbs_beep(100,500);
fprintf(stderr, "No startup structure passed!\n");
return;
}
if(startup->size!=sizeof(ftp_startup_t)) { /* verify size */
sbbs_beep(100,500);
sbbs_beep(300,500);
sbbs_beep(100,500);
fprintf(stderr, "Invalid startup structure!\n");
return;
}
uptime=0;
served=0;
startup->recycle_now=FALSE;
startup->shutdown_now=FALSE;
terminate_server=FALSE;
protected_uint32_init(&thread_count, 0);
listInit(¤t_connections, LINK_LIST_MUTEX);
protected_uint32_init(&active_clients, 0);
/* Setup intelligent defaults */
if(startup->port==0) startup->port=IPPORT_FTP;
if(startup->qwk_timeout==0) startup->qwk_timeout=FTP_DEFAULT_QWK_TIMEOUT; /* seconds */
if(startup->max_inactivity==0) startup->max_inactivity=FTP_DEFAULT_MAX_INACTIVITY; /* seconds */
if(startup->sem_chk_freq==0) startup->sem_chk_freq=DEFAULT_SEM_CHK_FREQ; /* seconds */
if(startup->index_file_name[0]==0) SAFECOPY(startup->index_file_name,"00index");
(void)protected_uint32_adjust(&thread_count,1);
thread_up(FALSE /* setuid */);
status("Initializing");
memset(&scfg, 0, sizeof(scfg));
lprintf(LOG_INFO,"Synchronet FTP Server Version %s%c%s"
,VERSION, REVISION
#ifdef _DEBUG
," Debug"
lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", git_branch, git_hash, __DATE__, __TIME__, compiler);
sbbs_srand(); /* Seed random number generator */

rswindell
committed
if(!winsock_startup()) {
break;

rswindell
committed
}
t=time(NULL);
lprintf(LOG_INFO,"Initializing on %.24s with options: %x"
if(chdir(startup->ctrl_dir)!=0)
lprintf(LOG_ERR,"!ERROR %d (%s) changing directory to: %s", errno, strerror(errno), startup->ctrl_dir);
/* Initial configuration and load from CNF files */
SAFECOPY(scfg.ctrl_dir, startup->ctrl_dir);
lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir);
scfg.size=sizeof(scfg);
SAFECOPY(error,UNKNOWN_LOAD_ERROR);
if(!load_cfg(&scfg, text, /* prep: */TRUE, /* node: */FALSE, error, sizeof(error))) {
lprintf(LOG_CRIT,"!ERROR %s",error);
lprintf(LOG_CRIT,"!Failed to load configuration files");
break;
if((t=checktime())!=0) { /* Check binary time */
lprintf(LOG_ERR,"!TIME PROBLEM (%ld)",t);
}
if(uptime==0)
uptime=time(NULL); /* this must be done *after* setting the timezone */
if(startup->temp_dir[0])
SAFECOPY(scfg.temp_dir,startup->temp_dir);
else
SAFECOPY(scfg.temp_dir,"../temp");
prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
if((i = md(scfg.temp_dir)) != 0) {
lprintf(LOG_CRIT,"!ERROR %d (%s) creating directory: %s", i, strerror(i), scfg.temp_dir);
cleanup(1,__LINE__);
break;
}
lprintf(LOG_DEBUG,"Temporary file directory: %s", scfg.temp_dir);
if(!startup->max_clients) {
startup->max_clients=scfg.sys_nodes;
if(startup->max_clients<10)
startup->max_clients=10;
}
lprintf(LOG_DEBUG,"Maximum clients: %d",startup->max_clients);
/* Sanity-check the passive port range */
if(startup->pasv_port_low || startup->pasv_port_high) {
if(startup->pasv_port_low > startup->pasv_port_high
|| startup->pasv_port_high-startup->pasv_port_low < (startup->max_clients-1)) {
lprintf(LOG_WARNING,"!Correcting Passive Port Range (Low: %u, High: %u)"
,startup->pasv_port_low,startup->pasv_port_high);
if(startup->pasv_port_low)
startup->pasv_port_high = startup->pasv_port_low+(startup->max_clients-1);
else
startup->pasv_port_low = startup->pasv_port_high-(startup->max_clients-1);
}
lprintf(LOG_DEBUG,"Passive Port Low: %u",startup->pasv_port_low);
lprintf(LOG_DEBUG,"Passive Port High: %u",startup->pasv_port_high);
}
lprintf(LOG_DEBUG,"Maximum inactivity: %d seconds",startup->max_inactivity);
update_clients();
strlwr(scfg.sys_id); /* Use lower-case unix-looking System ID for group name */
for(i=0;i<scfg.total_libs;i++) {
strlwr(scfg.lib[i]->sname);
dotname(scfg.lib[i]->sname,scfg.lib[i]->sname);
}
/* open a socket and wait for a client */
ftp_set = xpms_create(startup->bind_retry_count, startup->bind_retry_delay, lprintf);
if(ftp_set == NULL) {
lprintf(LOG_CRIT,"!ERROR %d creating FTP socket set", ERROR_VALUE);
cleanup(1, __LINE__);
return;
xpms_add_list(ftp_set, PF_UNSPEC, SOCK_STREAM, 0, startup->interfaces, startup->port, "FTP Server", ftp_open_socket_cb, startup->seteuid, NULL);
status(STATUS_WFC);
/* Setup recycle/shutdown semaphore file lists */
shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","ftp");
recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","ftp");
semfile_list_add(&recycle_semfiles,startup->ini_fname);
SAFEPRINTF(path,"%sftpsrvr.rec",scfg.ctrl_dir); /* legacy */
semfile_list_add(&recycle_semfiles,path);
if(!initialized) {
semfile_list_check(&initialized,recycle_semfiles);
semfile_list_check(&initialized,shutdown_semfiles);
/* signal caller that we've started up successfully */
if(startup->started!=NULL)
startup->started(startup->cbdata);
YIELD();
if(protected_uint32_value(thread_count) <= 1) {
if(!(startup->options&FTP_OPT_NO_RECYCLE)) {
if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
lprintf(LOG_INFO,"0000 Recycle semaphore file (%s) detected",p);
break;
}
if(startup->recycle_now==TRUE) {
lprintf(LOG_NOTICE,"0000 Recycle semaphore signaled");
startup->recycle_now=FALSE;
break;
}
if(((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL
&& lprintf(LOG_INFO,"0000 Shutdown semaphore file (%s) detected",p))
|| (startup->shutdown_now==TRUE
&& lprintf(LOG_INFO,"0000 Shutdown semaphore signaled"))) {
startup->shutdown_now=FALSE;
terminate_server=TRUE;
break;
}

rswindell
committed
client_addr_len = sizeof(client_addr);
client_socket = xpms_accept(ftp_set, &client_addr, &client_addr_len, startup->sem_chk_freq*1000, XPMS_FLAGS_NONE, NULL);
if(client_socket == INVALID_SOCKET)
continue;
if(startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,TRUE);
if(startup->max_concurrent_connections > 0) {
int ip_len = strlen(client_ip) + 1;
uint connections = listCountMatches(¤t_connections, client_ip, ip_len);
if(connections >= startup->max_concurrent_connections
&& !is_host_exempt(&scfg, client_ip, /* host_name */NULL)) {
lprintf(LOG_NOTICE, "%04d [%s] !Maximum concurrent connections (%u) exceeded"
,client_socket, client_ip, startup->max_concurrent_connections);
sockprintf(client_socket, -1, "421 Maximum connections (%u) exceeded", startup->max_concurrent_connections);
ftp_close_socket(&client_socket,&none,__LINE__);
continue;
}
}
continue;
}
if(protected_uint32_value(active_clients)>=startup->max_clients) {
,client_socket, startup->max_clients);
sockprintf(client_socket,-1,"421 Maximum active clients reached, please try again later.");
ftp_close_socket(&client_socket,&none,__LINE__);
continue;
}
if((ftp=malloc(sizeof(ftp_t)))==NULL) {
lprintf(LOG_CRIT,"%04d !ERROR allocating %d bytes of memory for ftp_t"
,client_socket,(int)sizeof(ftp_t));
sockprintf(client_socket,-1,"421 System error, please try again later.");
ftp_close_socket(&client_socket,&none,__LINE__);
continue;
}
ftp->socket=client_socket;
memcpy(&ftp->client_addr, &client_addr, client_addr_len);
ftp->client_addr_len = client_addr_len;
(void)protected_uint32_adjust(&thread_count,1);
_beginthread(ctrl_thread, 0, ftp);
served++;
lprintf(LOG_DEBUG,"0000 terminate_server: %d",terminate_server);
#endif
if(protected_uint32_value(active_clients)) {
lprintf(LOG_INFO,"0000 Waiting for %d active clients to disconnect..."
start=time(NULL);
while(protected_uint32_value(active_clients)) {
if(time(NULL)-start > startup->max_inactivity * 2) {
lprintf(LOG_WARNING,"0000 !TIMEOUT waiting for %d active clients"
break;
}
mswait(100);
lprintf(LOG_INFO, "0000 Done waiting for active clients to disconnect");
if(!terminate_server) {
lprintf(LOG_INFO,"Recycling server...");
if(startup->recycle!=NULL)
startup->recycle(startup->cbdata);
} while(!terminate_server);
protected_uint32_destroy(thread_count);