Skip to content
Snippets Groups Projects
websrvr.c 203 KiB
Newer Older
					free_crypt_attrstr(ssl_estr);
deuce's avatar
deuce committed

		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);
		}
			uptime=time(NULL);	/* this must be done *after* setting the timezone */
		/* open a socket and wait for a client */
deuce's avatar
deuce committed
		ws_set = xpms_create(startup->bind_retry_count, startup->bind_retry_delay, lprintf);
deuce's avatar
deuce committed
		if(ws_set == NULL) {
			lprintf(LOG_CRIT,"!ERROR %d creating HTTP socket set", ERROR_VALUE);
deuce's avatar
deuce committed
		lprintf(LOG_DEBUG,"Web Server socket set created");
deuce's avatar
deuce committed
		/*
		 * Add interfaces
		 */
		xpms_add_list(ws_set, PF_UNSPEC, SOCK_STREAM, 0, startup->interfaces, startup->port, "Web Server", open_socket, startup->seteuid, NULL);
		if(scfg.tls_certificate != -1 && startup->options&WEB_OPT_ALLOW_TLS) {
			if(do_cryptInit())
				xpms_add_list(ws_set, PF_UNSPEC, SOCK_STREAM, 0, startup->tls_interfaces, startup->tls_port, "Secure Web Server", open_socket, startup->seteuid, "TLS");
		}
		listInit(&log_list,/* flags */ LINK_LIST_MUTEX|LINK_LIST_SEMAPHORE);
		if(startup->options&WEB_OPT_HTTP_LOGGING) {
			/********************/
			/* Start log thread */
			/********************/
			http_logging_thread_running=TRUE;
			(void)protected_uint32_adjust(&thread_count,1);
			_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");
		semfile_list_add(&recycle_semfiles,startup->ini_fname);
		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)
deuce's avatar
deuce committed
		lprintf(LOG_INFO,"Web Server thread started");
		status("Listening");
deuce's avatar
deuce committed
		while(!terminated && !terminate_server) {
			/* check for re-cycle/shutdown semaphores */
			if(protected_uint32_value(thread_count) <= (unsigned int)(2 /* web_server() and http_output_thread() */ + (http_logging_thread_running?1:0))) {
				if(!(startup->options&BBS_OPT_NO_RECYCLE)) {
					if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
deuce's avatar
deuce committed
						lprintf(LOG_INFO,"Recycle semaphore file (%s) detected",p);
						if(session!=NULL) {
							pthread_mutex_unlock(&session->struct_filled);
							session=NULL;
						}
						break;
					}
					if(startup->recycle_now==TRUE) {
deuce's avatar
deuce committed
						lprintf(LOG_INFO,"Recycle semaphore signaled");
						if(session!=NULL) {
							pthread_mutex_unlock(&session->struct_filled);
							session=NULL;
						}
				if(((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL
deuce's avatar
deuce committed
						&& lprintf(LOG_INFO,"Shutdown semaphore file (%s) detected",p))
					|| (startup->shutdown_now==TRUE
deuce's avatar
deuce committed
						&& lprintf(LOG_INFO,"Shutdown semaphore signaled"))) {
					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,"!ERROR allocating %lu bytes of memory for http_session_t", (ulong)sizeof(http_session_t));
					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);
				(void)protected_uint32_adjust(&thread_count,1);
				_beginthread(http_session_thread, 0, session);
			/* now wait for connection */
deuce's avatar
deuce committed
			client_addr_len = sizeof(client_addr);
			client_socket = xpms_accept(ws_set, &client_addr, &client_addr_len, startup->sem_chk_freq*1000, XPMS_FLAGS_NONE, &acc_type);
deuce's avatar
deuce committed
			if(client_socket == INVALID_SOCKET)
deuce's avatar
deuce committed
			if(terminated) {	/* terminated */
				pthread_mutex_unlock(&session->struct_filled);
			if(startup->socket_open!=NULL)
				startup->socket_open(startup->cbdata,TRUE);

deuce's avatar
deuce committed
			inet_addrtop(&client_addr, host_ip, sizeof(host_ip));

			if(trashcan(&scfg,host_ip,"ip-silent")) {
				close_socket(&client_socket);
			if((count = protected_uint32_value(active_clients)) > client_highwater) {
				client_highwater = count;
				lprintf(LOG_NOTICE, "%04d New active client highwater mark: %lu"
					,client_socket, client_highwater);
			}
			if(startup->max_clients && protected_uint32_value(active_clients)>=startup->max_clients) {
runderwo's avatar
 
runderwo committed
				lprintf(LOG_WARNING,"%04d !MAXIMUM CLIENTS (%d) reached, access denied"
					,client_socket, startup->max_clients);
deuce's avatar
deuce committed
				if (!len_503)
					len_503 = strlen(error_503);
				sendsocket(client_socket, error_503, len_503);
				close_socket(&client_socket);
deuce's avatar
deuce committed
            }
deuce's avatar
deuce committed
			host_port=inet_addrport(&client_addr);
deuce's avatar
deuce committed
			if (acc_type != NULL && !strcmp(acc_type, "TLS"))
				session->is_tls=TRUE;
			lprintf(LOG_INFO,"%04d %s connection accepted from: %s port %u"
				,session->is_tls ? "HTTPS":"HTTP"
			SAFECOPY(session->host_ip,host_ip);
deuce's avatar
deuce committed
			memcpy(&session->addr, &client_addr, sizeof(session->addr));
			session->addr_len=client_addr_len;
   			session->socket=client_socket;
			session->js_callback.auto_terminate=TRUE;
			session->js_callback.terminated=&terminate_server;
			session->js_callback.limit=startup->js.time_limit;
			session->js_callback.gc_interval=startup->js.gc_interval;
			session->js_callback.yield_interval=startup->js.yield_interval;
Deucе's avatar
Deucе committed
			session->js_callback.events_supported = FALSE;
			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 */
		if(protected_uint32_value(active_clients)) {
			lprintf(LOG_INFO, "Waiting for %d active clients to disconnect..."
deuce's avatar
deuce committed
				, protected_uint32_value(active_clients));
			while(protected_uint32_value(active_clients)) {
				if(time(NULL)-start>startup->max_inactivity) {
deuce's avatar
deuce committed
					lprintf(LOG_WARNING,"!TIMEOUT waiting for %d active clients"
						, protected_uint32_value(active_clients));
			lprintf(LOG_INFO, "Done waiting for active clients to disconnect");
		if(http_logging_thread_running) {
			terminate_http_logging_thread=TRUE;
			listSemPost(&log_list);
			mswait(100);
		}
		if(http_logging_thread_running) {
			lprintf(LOG_INFO, "Waiting for HTTP logging thread to terminate...");
			start=time(NULL);
			while(http_logging_thread_running) {
				if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
deuce's avatar
deuce committed
					lprintf(LOG_WARNING,"!TIMEOUT waiting for HTTP logging thread to "
            			"terminate");
			lprintf(LOG_INFO, "Done waiting for HTTP logging thread to terminate");
			lprintf(LOG_INFO,"Recycling server...");
			if(startup->recycle!=NULL)
				startup->recycle(startup->cbdata);
	protected_uint32_destroy(thread_count);