Skip to content
Snippets Groups Projects
websrvr.c 161 KiB
Newer Older
	/* host_ip wasn't defined in http_session_thread */
	if(trashcan(&scfg,session.host_ip,"ip")) {
		lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", session.socket, session.host_ip);
		close_socket(&session.socket);
		sem_wait(&session.output_thread_terminated);
deuce's avatar
deuce committed
		sem_destroy(&session.output_thread_terminated);
		RingBufDispose(&session.outbuf);
	protected_int32_adjust(&active_clients, 1);
	SAFECOPY(session.username,unknown);

	SAFECOPY(session.client.addr,session.host_ip);
	SAFECOPY(session.client.host,session.host_name);
	session.client.port=ntohs(session.addr.sin_port);
	session.client.time=time(NULL);
	session.client.user=session.username;
	session.client.size=sizeof(session.client);
	client_on(session.socket, &session.client, /* update existing client record? */FALSE);
	session.subscan=(subscan_t*)alloca(sizeof(subscan_t)*scfg.total_subs);
	    memset(&(session.req), 0, sizeof(session.req));
deuce's avatar
deuce committed
		if(session.req.ld) {
			FREE_AND_NULL(session.req.ld->hostname);
			FREE_AND_NULL(session.req.ld->ident);
			FREE_AND_NULL(session.req.ld->user);
			FREE_AND_NULL(session.req.ld->request);
			FREE_AND_NULL(session.req.ld->referrer);
			FREE_AND_NULL(session.req.ld->agent);
			FREE_AND_NULL(session.req.ld->vhost);
			FREE_AND_NULL(session.req.ld);
		}
		if(startup->options&WEB_OPT_HTTP_LOGGING) {
			/* FREE()d in http_logging_thread... passed there by close_request() */
			if((session.req.ld=(struct log_data*)malloc(sizeof(struct log_data)))==NULL)
				lprintf(LOG_ERR,"%04d Cannot allocate memory for log data!",session.socket);
		}
		if(session.req.ld!=NULL) {
			memset(session.req.ld,0,sizeof(struct log_data));
			/* FREE()d in http_logging_thread */
			session.req.ld->hostname=strdup(session.host_name);
		}
		while((redirp==NULL || session.req.send_location >= MOVED_TEMP)
				 && !session.finished && !session.req.finished 
				 && session.socket!=INVALID_SOCKET) {
			SAFECOPY(session.req.status,"200 OK");
			session.req.send_location=NO_LOCATION;
			if(session.req.headers==NULL) {
deuce's avatar
deuce committed
				/* FREE()d in close_request() */
				if((session.req.headers=strListInit())==NULL) {
					lprintf(LOG_ERR,"%04d !ERROR allocating memory for header list",session.socket);
					init_error=TRUE;
				}
deuce's avatar
deuce committed
			}
			if(session.req.cgi_env==NULL) {
deuce's avatar
deuce committed
				/* FREE()d in close_request() */
				if((session.req.cgi_env=strListInit())==NULL) {
					lprintf(LOG_ERR,"%04d !ERROR allocating memory for CGI environment list",session.socket);
					init_error=TRUE;
				}
			if(session.req.dynamic_heads==NULL) {
deuce's avatar
deuce committed
				/* FREE()d in close_request() */
				if((session.req.dynamic_heads=strListInit())==NULL) {
					lprintf(LOG_ERR,"%04d !ERROR allocating memory for dynamic header list",session.socket);
					init_error=TRUE;
				}
			if(get_req(&session,redirp)) {
				if(init_error) {
					send_error(&session, error_500);
				}
				/* At this point, if redirp is non-NULL then the headers have already been parsed */
				if((session.http_ver<HTTP_1_0)||redirp!=NULL||parse_headers(&session)) {
					if(check_request(&session)) {
						if(session.req.send_location < MOVED_TEMP || session.req.virtual_path[0]!='/' || loop_count++ >= MAX_REDIR_LOOPS) {
							if(read_post_data(&session))
								respond(&session);
							safe_snprintf(redir_req,sizeof(redir_req),"%s %s%s%s",methods[session.req.method]
								,session.req.virtual_path,session.http_ver<HTTP_1_0?"":" ",http_vers[session.http_ver]);
							lprintf(LOG_DEBUG,"%04d Internal Redirect to: %s",socket,redir_req);
							redirp=redir_req;
						}
					}
			else {
				session.req.keep_alive=FALSE;
				break;
			}
	http_logoff(&session,socket,__LINE__);
		lprintf(LOG_DEBUG,"%04d JavaScript: Destroying context",socket);
		JS_DestroyContext(session.js_cx);	/* Free Context */
	if(session.js_runtime!=NULL) {
		lprintf(LOG_DEBUG,"%04d JavaScript: Destroying runtime",socket);
		jsrt_Release(session.js_runtime);
deuce's avatar
deuce committed
		session.js_runtime=NULL;
#ifdef _WIN32
	if(startup->hangup_sound[0] && !(startup->options&BBS_OPT_MUTE)) 
		PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
#endif

	close_socket(&session.socket);
	sem_wait(&session.output_thread_terminated);
	sem_destroy(&session.output_thread_terminated);
	RingBufDispose(&session.outbuf);
	clients_remain=protected_int32_adjust(&active_clients, -1);

	if(startup->index_file_name==NULL || startup->cgi_ext==NULL)
		lprintf(LOG_DEBUG,"%04d !!! ALL YOUR BASE ARE BELONG TO US !!!", socket);

	lprintf(LOG_INFO,"%04d Session thread terminated (%u clients, %u threads remain, %lu served)"
		,socket, clients_remain, thread_count, served);
   	lprintf(LOG_INFO,"%04d Web Server terminate",server_socket);
	terminate_server=TRUE;
	while(session_threads) {
		lprintf(LOG_INFO,"#### Web Server waiting on %d active session threads",session_threads);
		SLEEP(1000);
	}
	mime_types=iniFreeNamedStringList(mime_types);

	cgi_handlers=iniFreeNamedStringList(cgi_handlers);
	xjs_handlers=iniFreeNamedStringList(xjs_handlers);

	semfile_list_free(&recycle_semfiles);
	semfile_list_free(&shutdown_semfiles);

	if(server_socket!=INVALID_SOCKET) {
		close_socket(&server_socket);
	if(active_clients.value)
		lprintf(LOG_WARNING,"#### Web Server terminating with %ld active clients", active_clients.value);
	else
		protected_int32_destroy(active_clients);
	update_clients();

#ifdef _WINSOCKAPI_
	if(WSAInitialized && WSACleanup()!=0) 
		lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
#endif

	thread_down();
	status("Down");
	if(terminate_server || code)
		lprintf(LOG_INFO,"#### Web Server thread terminated (%lu clients served)", served);
	if(thread_count)
		lprintf(LOG_WARNING,"#### !Web Server threads (%u) remain after termination", thread_count);
	if(startup!=NULL && startup->terminated!=NULL)
		startup->terminated(startup->cbdata,code);
}

const char* DLLCALL web_ver(void)
{
	static char ver[256];
	char compiler[32];

	DESCRIBE_COMPILER(compiler);

	sscanf("$Revision$", "%*s %s", revision);

	sprintf(ver,"%s %s%s  "
		"Compiled %s %s with %s"
		,server_name
		,revision
#ifdef _DEBUG
		," Debug"
#else
		,""
#endif
		,__DATE__, __TIME__, compiler);

	return(ver);
}

	char	base[MAX_PATH+1];
	char	filename[MAX_PATH+1];
	char	newfilename[MAX_PATH+1];
	http_logging_thread_running=TRUE;
	terminate_http_logging_thread=FALSE;

		SAFEPRINTF(base,"%slogs/http-",scfg.logs_dir);
	SetThreadName("HTTP Logging");
	filename[0]=0;
	newfilename[0]=0;

	thread_up(TRUE /* setuid */);

	lprintf(LOG_INFO,"%04d HTTP logging thread started", server_socket);
		char	timestr[128];
		if(!listSemTryWait(&log_list)) {
			if(logfile!=NULL)
				fflush(logfile);
			listSemWait(&log_list);
		}
rswindell's avatar
rswindell committed
		ld=listShiftNode(&log_list);
		/*
		 * Because the sem is posted when terminate_http_logging_thread is set, this will
		 * ensure that all pending log entries are written to disk
		 */
			if(terminate_http_logging_thread)
				break;
			lprintf(LOG_ERR,"%04d HTTP logging thread received NULL linked list log entry"
		if(startup->options&WEB_OPT_VIRTUAL_HOSTS && ld->vhost!=NULL) {
			strcat(newfilename,ld->vhost);
			if(ld->vhost[0])
				strcat(newfilename,"-");
		}
		strftime(strchr(newfilename,0),15,"%Y-%m-%d.log",&ld->completed);
		if(logfile==NULL || strcmp(newfilename,filename)) {
deuce's avatar
deuce committed
			if(logfile!=NULL)
				fclose(logfile);
			SAFECOPY(filename,newfilename);
			logfile=fopen(filename,"ab");
			if(logfile)
				lprintf(LOG_INFO,"%04d HTTP logfile is now: %s",server_socket,filename);
			if(ld->status) {
				sprintf(sizestr,"%d",ld->size);
				strftime(timestr,sizeof(timestr),"%d/%b/%Y:%H:%M:%S %z",&ld->completed);
				/*
				 * In case of a termination, do no block for a lock... just discard
				 * the output.
				 */
				while(lock(fileno(logfile),0,1) && !terminate_http_logging_thread) {
					SLEEP(10);
				}
				fprintf(logfile,"%s %s %s [%s] \"%s\" %d %s \"%s\" \"%s\"\n"
						,ld->hostname?(ld->hostname[0]?ld->hostname:"-"):"-"
						,ld->ident?(ld->ident[0]?ld->ident:"-"):"-"
						,ld->user?(ld->user[0]?ld->user:"-"):"-"
						,timestr
						,ld->request?(ld->request[0]?ld->request:"-"):"-"
						,ld->status
						,ld->size?sizestr:"-"
						,ld->referrer?(ld->referrer[0]?ld->referrer:"-"):"-"
						,ld->agent?(ld->agent[0]?ld->agent:"-"):"-");
				unlock(fileno(logfile),0,1);
			lprintf(LOG_ERR,"%04d HTTP server failed to open logfile %s (%d)!",server_socket,filename,errno);
		FREE_AND_NULL(ld->hostname);
		FREE_AND_NULL(ld->ident);
		FREE_AND_NULL(ld->user);
		FREE_AND_NULL(ld->request);
		FREE_AND_NULL(ld->referrer);
		FREE_AND_NULL(ld->agent);
		FREE_AND_NULL(ld->vhost);
		FREE_AND_NULL(ld);
deuce's avatar
deuce committed
	if(logfile!=NULL) {
deuce's avatar
deuce committed
		logfile=NULL;
	}
	lprintf(LOG_INFO,"%04d HTTP logging thread terminated",server_socket);

	http_logging_thread_running=FALSE;
void DLLCALL web_server(void* arg)
{
	int				i;
	int				result;
	time_t			start;
	WORD			host_port;
	char			path[MAX_PATH+1];
	char			logstr[256];
	char			mime_types_ini[MAX_PATH+1];
	char			web_handler_ini[MAX_PATH+1];
	SOCKADDR_IN		server_addr={0};
	SOCKADDR_IN		client_addr;
	socklen_t		client_addr_len;
	SOCKET			client_socket;
	SOCKET			high_socket_set;
	fd_set			socket_set;
	time_t			t;
	time_t			initialized=0;
	http_session_t *	session=NULL;
#ifdef ONE_JS_RUNTIME
	JSRuntime*      js_runtime;
#endif
#ifdef SO_ACCEPTFILTER
	struct accept_filter_arg afa;
#endif

deuce's avatar
deuce committed
	startup=(web_startup_t*)arg;
deuce's avatar
deuce committed
	SetThreadName("Web Server");
rswindell's avatar
rswindell committed
	web_ver();	/* get CVS revision */

    if(startup==NULL) {
    	sbbs_beep(100,500);
    	fprintf(stderr, "No startup structure passed!\n");
    	return;
    }

rswindell's avatar
rswindell committed
	if(startup->size!=sizeof(web_startup_t)) {	/* verify size */
		sbbs_beep(100,500);
		sbbs_beep(300,500);
		sbbs_beep(100,500);
		fprintf(stderr, "Invalid startup structure!\n");
		return;
	}

	if(thread_suid_broken)
		startup->seteuid(TRUE);
	/* Setup intelligent defaults */
	if(startup->port==0)					startup->port=IPPORT_HTTP;
	if(startup->root_dir[0]==0)				SAFECOPY(startup->root_dir,WEB_DEFAULT_ROOT_DIR);
	if(startup->error_dir[0]==0)			SAFECOPY(startup->error_dir,WEB_DEFAULT_ERROR_DIR);
	if(startup->default_auth_list[0]==0)	SAFECOPY(startup->default_auth_list,WEB_DEFAULT_AUTH_LIST);
	if(startup->cgi_dir[0]==0)				SAFECOPY(startup->cgi_dir,WEB_DEFAULT_CGI_DIR);
	if(startup->default_cgi_content[0]==0)	SAFECOPY(startup->default_cgi_content,WEB_DEFAULT_CGI_CONTENT);
	if(startup->max_inactivity==0) 			startup->max_inactivity=120; /* seconds */
	if(startup->max_cgi_inactivity==0) 		startup->max_cgi_inactivity=120; /* seconds */
	if(startup->sem_chk_freq==0)			startup->sem_chk_freq=2; /* seconds */
	if(startup->js.max_bytes==0)			startup->js.max_bytes=JAVASCRIPT_MAX_BYTES;
	if(startup->js.cx_stack==0)				startup->js.cx_stack=JAVASCRIPT_CONTEXT_STACK;
	if(startup->ssjs_ext[0]==0)				SAFECOPY(startup->ssjs_ext,".ssjs");
	if(startup->js_ext[0]==0)				SAFECOPY(startup->js_ext,".bbs");
	ZERO_VAR(js_server_props);
	SAFEPRINTF2(js_server_props.version,"%s %s",server_name,revision);
	js_server_props.version_detail=web_ver();
	js_server_props.clients=&active_clients.value;
	js_server_props.options=&startup->options;
	js_server_props.interface_addr=&startup->interface_addr;

	startup->recycle_now=FALSE;
	do {

		thread_up(FALSE /* setuid */);

		status("Initializing");

		/* Copy html directories */
		SAFECOPY(root_dir,startup->root_dir);
		SAFECOPY(error_dir,startup->error_dir);
		SAFECOPY(default_auth_list,startup->default_auth_list);
		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));

rswindell's avatar
rswindell committed
			,server_name
			,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_CRIT,"!ERROR %s",logstr);
			lprintf(LOG_CRIT,"!FAILED to load configuration files");
		lprintf(LOG_DEBUG,"Temporary file directory: %s", temp_dir);
		MKDIR(temp_dir);
		if(!isdir(temp_dir)) {
			lprintf(LOG_CRIT,"!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);

		iniFileName(mime_types_ini,sizeof(mime_types_ini),scfg.ctrl_dir,"mime_types.ini");
		mime_types=read_ini_list(mime_types_ini,NULL /* root section */,"MIME types"
		iniFileName(web_handler_ini,sizeof(web_handler_ini),scfg.ctrl_dir,"web_handler.ini");
		if((cgi_handlers=read_ini_list(web_handler_ini,"CGI."PLATFORM_DESC,"CGI content handlers"
			,cgi_handlers))==NULL)
			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"
		/* Don't do this for *each* CGI request, just once here during [re]init */
		iniFileName(cgi_env_ini,sizeof(cgi_env_ini),scfg.ctrl_dir,"cgi_env.ini");
		if((fp=iniOpenFile(cgi_env_ini,/* create? */FALSE)) != NULL) {
			cgi_env = iniReadFile(fp);
			iniCloseFile(fp);
		}
		if(startup->host_name[0]==0)
			SAFECOPY(startup->host_name,scfg.sys_inetaddr);

			uptime=time(NULL);	/* this must be done *after* setting the timezone */
		protected_int32_init(&active_clients,0);
		/* open a socket and wait for a client */

		server_socket = open_socket(SOCK_STREAM);

		if(server_socket == INVALID_SOCKET) {
			lprintf(LOG_CRIT,"!ERROR %d creating HTTP socket", ERROR_VALUE);
/*
 *		i=1;
 *		if(setsockopt(server_socket, IPPROTO_TCP, TCP_NOPUSH, &i, sizeof(i)))
 *			lprintf("Cannot set TCP_NOPUSH socket option");
 */

#ifdef SO_ACCEPTFILTER
		memset(&afa, 0, sizeof(afa));
		strcpy(afa.af_name, "httpready");
		setsockopt(server_socket, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa));
#endif

		lprintf(LOG_DEBUG,"%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->port < IPPORT_RESERVED) {
			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->port < IPPORT_RESERVED) {
			if(startup->seteuid!=NULL)
				startup->seteuid(TRUE);
		}
			lprintf(LOG_CRIT,"%s",BIND_FAILURE_HELP);
		result = listen(server_socket, 64);
			lprintf(LOG_CRIT,"%04d !ERROR %d (%d) listening on socket"
				,server_socket, result, ERROR_VALUE);
rswindell's avatar
rswindell committed
		lprintf(LOG_INFO,"%04d Web Server listening on port %u"
			,server_socket, startup->port);
		listInit(&log_list,/* flags */ LINK_LIST_MUTEX|LINK_LIST_SEMAPHORE);
		if(startup->options&WEB_OPT_HTTP_LOGGING) {
			/********************/
			/* Start log thread */
			/********************/
			_beginthread(http_logging_thread, 0, startup->logfile_base);
		}
#ifdef ONE_JS_RUNTIME
	    if(js_runtime == NULL) {
    	    lprintf(LOG_DEBUG,"%04d JavaScript: Creating runtime: %lu bytes"
        	    ,server_socket,startup->js.max_bytes);

    	    if((js_runtime=jsrt_GetNew(startup->js.max_bytes, 0, __FILE__, __LINE__))==NULL) {
        	    lprintf(LOG_ERR,"%04d !ERROR creating JavaScript runtime",server_socket);
				/* Sleep 15 seconds then try again */
				/* ToDo: Something better should be used here. */
				SLEEP(15000);
				continue;
        	}
    	}
#endif

		/* 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);
		semfile_list_add(&recycle_semfiles,mime_types_ini);
		semfile_list_add(&recycle_semfiles,web_handler_ini);
		semfile_list_add(&recycle_semfiles,cgi_env_ini);
			initialized=time(NULL);
			semfile_list_check(&initialized,recycle_semfiles);
			semfile_list_check(&initialized,shutdown_semfiles);
		/* signal caller that we've started up successfully */
		if(startup->started!=NULL)
rswindell's avatar
rswindell committed
		lprintf(LOG_INFO,"%04d Web Server thread started", server_socket);

		while(server_socket!=INVALID_SOCKET && !terminate_server) {
			/* check for re-cycle/shutdown semaphores */
			if(active_clients.value==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);
						if(session!=NULL) {
							pthread_mutex_unlock(&session->struct_filled);
							session=NULL;
						}
						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);
						if(session!=NULL) {
							pthread_mutex_unlock(&session->struct_filled);
							session=NULL;
						}
				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;
					if(session!=NULL) {
						pthread_mutex_unlock(&session->struct_filled);
						session=NULL;
					}
			/* Startup next session thread */
				/* FREE()d at the start of the session thread */
				if((session=malloc(sizeof(http_session_t)))==NULL) {
					lprintf(LOG_CRIT,"%04d !ERROR allocating %u bytes of memory for http_session_t"
rswindell's avatar
rswindell committed
						,server_socket, sizeof(http_session_t));
					mswait(3000);
					continue;
				}
				memset(session, 0, sizeof(http_session_t));
   				session->socket=INVALID_SOCKET;
deuce's avatar
deuce committed
				/* Destroyed in http_session_thread */
				pthread_mutex_init(&session->struct_filled,NULL);
				pthread_mutex_lock(&session->struct_filled);
				_beginthread(http_session_thread, 0, session);
			/* 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) {
				if(ERROR_VALUE==EINTR)
					lprintf(LOG_DEBUG,"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);
			if(server_socket==INVALID_SOCKET) {	/* terminated */
				pthread_mutex_unlock(&session->struct_filled);
			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);
				if(WSAGetLastError()==WSAENOBUFS) {	/* recycle (re-init WinSock) on this error */
					pthread_mutex_unlock(&session->struct_filled);
			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);
			if(startup->max_clients && active_clients.value>=startup->max_clients) {
runderwo's avatar
 
runderwo committed
				lprintf(LOG_WARNING,"%04d !MAXIMUM CLIENTS (%d) reached, access denied"
					,client_socket, startup->max_clients);
				mswait(3000);
				close_socket(&client_socket);
			host_port=ntohs(client_addr.sin_port);

			lprintf(LOG_INFO,"%04d HTTP connection accepted from: %s port %u"
			SAFECOPY(session->host_ip,host_ip);
   			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;
#ifdef ONE_JS_RUNTIME
			session->js_runtime=js_runtime;
#endif
			pthread_mutex_unlock(&session->struct_filled);
deuce's avatar
deuce committed
		if(session) {
			pthread_mutex_unlock(&session->struct_filled);
			session=NULL;
		}

		/* Wait for active clients to terminate */
			lprintf(LOG_DEBUG,"%04d Waiting for %d active clients to disconnect..."
				,server_socket, active_clients.value);
			while(active_clients.value) {
				if(time(NULL)-start>startup->max_inactivity) {
					lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for %d active clients"
						,server_socket, active_clients.value);
		if(http_logging_thread_running) {
			terminate_http_logging_thread=TRUE;
			listSemPost(&log_list);
			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);
deuce's avatar
deuce committed
    	if(js_runtime!=NULL) {
        	lprintf(LOG_DEBUG,"%04d JavaScript: Destroying runtime",server_socket);
			lprintf(LOG_INFO,"Recycling server...");
			if(startup->recycle!=NULL)
				startup->recycle(startup->cbdata);