Newer
Older
thread_up(FALSE /* setuid */);
status("Initializing");
/* Copy html directories */
SAFECOPY(root_dir,startup->root_dir);
SAFECOPY(error_dir,startup->error_dir);
SAFECOPY(cgi_dir,startup->cgi_dir);
if(startup->temp_dir[0])
SAFECOPY(temp_dir,startup->temp_dir);
else
SAFECOPY(temp_dir,"../temp");
/* Change to absolute path */
prep_dir(startup->ctrl_dir, root_dir, sizeof(root_dir));
prep_dir(startup->ctrl_dir, temp_dir, sizeof(temp_dir));
prep_dir(root_dir, error_dir, sizeof(error_dir));
prep_dir(root_dir, cgi_dir, sizeof(cgi_dir));
/* Trim off trailing slash/backslash */
if(IS_PATH_DELIM(*(p=lastchar(root_dir)))) *p=0;
memset(&scfg, 0, sizeof(scfg));
lprintf(LOG_INFO,"%s Revision %s%s"
,revision
#ifdef _DEBUG
," Debug"
#else
,""
#endif
);
DESCRIBE_COMPILER(compiler);
lprintf(LOG_INFO,"Compiled %s %s with %s", __DATE__, __TIME__, compiler);
if(!winsock_startup()) {
cleanup(1);
return;
}
t=time(NULL);
lprintf(LOG_INFO,"Initializing on %.24s with options: %lx"
,CTIME_R(&t,logstr),startup->options);
if(chdir(startup->ctrl_dir)!=0)
lprintf(LOG_ERR,"!ERROR %d changing directory to: %s", 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(logstr,UNKNOWN_LOAD_ERROR);
if(!load_cfg(&scfg, NULL, TRUE, logstr)) {
lprintf(LOG_ERR,"!ERROR %s",logstr);
lprintf(LOG_ERR,"!FAILED to load configuration files");
cleanup(1);
return;
}
scfg_reloaded=TRUE;
lprintf(LOG_DEBUG,"Temporary file directory: %s", temp_dir);
MKDIR(temp_dir);
if(!isdir(temp_dir)) {
lprintf(LOG_ERR,"!Invalid temp directory: %s", temp_dir);
cleanup(1);
return;
}
lprintf(LOG_DEBUG,"Root directory: %s", root_dir);
lprintf(LOG_DEBUG,"Error directory: %s", error_dir);
lprintf(LOG_DEBUG,"CGI directory: %s", cgi_dir);
mime_types=read_ini_list("mime_types.ini",NULL /* root section */,"MIME types"
,mime_types);
cgi_handlers=read_ini_list("web_handler.ini","CGI","CGI content handlers"
,cgi_handlers);
xjs_handlers=read_ini_list("web_handler.ini","JavaScript","JavaScript content handlers"
,xjs_handlers);
if(startup->host_name[0]==0)
SAFECOPY(startup->host_name,scfg.sys_inetaddr);
if(!(scfg.sys_misc&SM_LOCAL_TZ) && !(startup->options&BBS_OPT_LOCAL_TIMEZONE)) {
if(putenv("TZ=UTC0"))
lprintf(LOG_WARNING,"!putenv() FAILED");
tzset();
}
if(uptime==0)
uptime=time(NULL); /* this must be done *after* setting the timezone */
active_clients=0;
update_clients();
/* open a socket and wait for a client */
server_socket = open_socket(SOCK_STREAM);
if(server_socket == INVALID_SOCKET) {
lprintf(LOG_ERR,"!ERROR %d creating HTTP socket", ERROR_VALUE);
cleanup(1);
return;
}
/*
* i=1;
* if(setsockopt(server_socket, IPPROTO_TCP, TCP_NOPUSH, &i, sizeof(i)))
* lprintf("Cannot set TCP_NOPUSH socket option");
*/
lprintf(LOG_INFO,"%04d Web Server socket opened",server_socket);
/*****************************/
/* Listen for incoming calls */
/*****************************/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(startup->port);
if(startup->seteuid!=NULL)
startup->seteuid(FALSE);
result = retry_bind(server_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
,startup->bind_retry_count,startup->bind_retry_delay,"Web Server",lprintf);
if(startup->seteuid!=NULL)
startup->seteuid(TRUE);
if(result != 0) {
lprintf(LOG_NOTICE,"%s",BIND_FAILURE_HELP);
cleanup(1);
return;
}
result = listen(server_socket, 64);
if(result != 0) {
lprintf(LOG_ERR,"%04d !ERROR %d (%d) listening on socket"
,server_socket, result, ERROR_VALUE);
cleanup(1);
return;
}
lprintf(LOG_INFO,"%04d Web Server listening on port %d"
,server_socket, startup->port);
status("Listening");
lprintf(LOG_INFO,"%04d Web Server thread started", server_socket);
listInit(&log_list,/* flags */ 0);
if(startup->options&WEB_OPT_HTTP_LOGGING) {
/********************/
/* Start log thread */
/********************/
sem_init(&log_sem,0,0);
_beginthread(http_logging_thread, 0, startup->logfile_base);
}
/* Setup recycle/shutdown semaphore file lists */
shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","web");
recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","web");
SAFEPRINTF(path,"%swebsrvr.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);
while(server_socket!=INVALID_SOCKET && !terminate_server) {
/* check for re-cycle/shutdown semaphores */
if(active_clients==0) {
if(!(startup->options&BBS_OPT_NO_RECYCLE)) {
if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
lprintf(LOG_INFO,"%04d Recycle semaphore file (%s) detected"
,server_socket,p);
break;
}
#if 0 /* unused */
if(startup->recycle_sem!=NULL && sem_trywait(&startup->recycle_sem)==0)
startup->recycle_now=TRUE;
#endif
if(startup->recycle_now==TRUE) {
lprintf(LOG_INFO,"%04d Recycle semaphore signaled",server_socket);
startup->recycle_now=FALSE;
break;
}
if(((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL
&& lprintf(LOG_INFO,"%04d Shutdown semaphore file (%s) detected"
,server_socket,p))
|| (startup->shutdown_now==TRUE
&& lprintf(LOG_INFO,"%04d Shutdown semaphore signaled"
,server_socket))) {
startup->shutdown_now=FALSE;
terminate_server=TRUE;
/* now wait for connection */
FD_ZERO(&socket_set);
FD_SET(server_socket,&socket_set);
high_socket_set=server_socket+1;
tv.tv_sec=startup->sem_chk_freq;
tv.tv_usec=0;
if((i=select(high_socket_set,&socket_set,NULL,NULL,&tv))<1) {
continue;
if(ERROR_VALUE==EINTR)
lprintf(LOG_INFO,"Web Server listening interrupted");
else if(ERROR_VALUE == ENOTSOCK)
lprintf(LOG_INFO,"Web Server socket closed");
lprintf(LOG_WARNING,"!ERROR %d selecting socket",ERROR_VALUE);
continue;
if(server_socket==INVALID_SOCKET) /* terminated */
break;
client_addr_len = sizeof(client_addr);
if(server_socket!=INVALID_SOCKET
&& FD_ISSET(server_socket,&socket_set)) {
client_socket = accept(server_socket, (struct sockaddr *)&client_addr
,&client_addr_len);
lprintf(LOG_NOTICE,"!NO SOCKETS set by select");
continue;
}
if(client_socket == INVALID_SOCKET) {
lprintf(LOG_WARNING,"!ERROR %d accepting connection", ERROR_VALUE);
#ifdef _WIN32
if(WSAGetLastError()==WSAENOBUFS) /* recycle (re-init WinSock) on this error */
break;
#endif
if(startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,TRUE);
SAFECOPY(host_ip,inet_ntoa(client_addr.sin_addr));
if(trashcan(&scfg,host_ip,"ip-silent")) {
close_socket(client_socket);
continue;
}
if(startup->max_clients && active_clients>=startup->max_clients) {
,client_socket, startup->max_clients);
mswait(3000);
close_socket(client_socket);
continue;
}
host_port=ntohs(client_addr.sin_port);
lprintf(LOG_INFO,"%04d HTTP connection accepted from: %s port %u"
,host_ip, host_port);
if((session=malloc(sizeof(http_session_t)))==NULL) {
lprintf(LOG_CRIT,"%04d !ERROR allocating %u bytes of memory for http_session_t"
,client_socket, sizeof(http_session_t));
mswait(3000);
close_socket(client_socket);
continue;
}
memset(session, 0, sizeof(http_session_t));
SAFECOPY(session->host_ip,host_ip);
session->addr=client_addr;
session->socket=client_socket;
session->js_branch.auto_terminate=TRUE;
session->js_branch.terminated=&terminate_server;
session->js_branch.limit=startup->js.branch_limit;
session->js_branch.gc_interval=startup->js.gc_interval;
session->js_branch.yield_interval=startup->js.yield_interval;
_beginthread(http_session_thread, 0, session);
served++;
/* Wait for active clients to terminate */
if(active_clients) {
lprintf(LOG_DEBUG,"%04d Waiting for %d active clients to disconnect..."
,server_socket, active_clients);
start=time(NULL);
while(active_clients) {
if(time(NULL)-start>startup->max_inactivity) {
lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for %d active clients"
,server_socket, active_clients);
break;
}
mswait(100);
}
}
if(http_logging_thread_running) {
terminate_http_logging_thread=TRUE;
sem_post(&log_sem);
mswait(100);
}
if(http_logging_thread_running) {
lprintf(LOG_DEBUG,"%04d Waiting for HTTP logging thread to terminate..."
,server_socket);
start=time(NULL);
while(http_logging_thread_running) {
if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for HTTP logging thread to "
"terminate", server_socket);
break;
}
mswait(100);
}
}
if(!terminate_server) {
lprintf(LOG_INFO,"Recycling server...");
if(startup->recycle!=NULL)
startup->recycle(startup->cbdata);
} while(!terminate_server);