patch-2.3.14 linux/net/khttpd/main.c
Next file: linux/net/khttpd/make_times_h.c
Previous file: linux/net/khttpd/logging.c
Back to the patch index
Back to the overall index
- Lines: 395
- Date:
Wed Aug 18 09:50:01 1999
- Orig file:
v2.3.13/linux/net/khttpd/main.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.13/linux/net/khttpd/main.c linux/net/khttpd/main.c
@@ -0,0 +1,394 @@
+/*
+
+kHTTPd -- the next generation
+
+Main program
+
+
+kHTTPd TNG consists of 1 thread, this main-thread handles ALL connections
+simultanious. It does this by keeping queues with the requests in different
+stages.
+
+The stages are
+
+<not accepted> - TCP/IP connection is not accepted yet
+WaitForHeaders - Connection is accepted, waiting for headers
+DataSending - Headers decoded, sending file-data
+Userspace - Requires userspace daemon
+Logging - The request is finished, cleanup and logging
+
+A typical flow for a request would be:
+
+<not accepted>
+WaitForHeaders
+DataSending
+Logging
+
+or
+
+<not accepted>
+WaitForHeaders
+Userspace
+
+
+
+*/
+/****************************************************************
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <asm/unistd.h>
+
+#include "structure.h"
+#include "prototypes.h"
+#include "sysctl.h"
+
+struct khttpd_threadinfo threadinfo[CONFIG_KHTTPD_NUMCPU]; /* The actual work-queues */
+
+
+atomic_t ConnectCount;
+atomic_t DaemonCount;
+
+static int ActualThreads; /* The number of actual, active threads */
+
+
+static int ConnectionsPending(int CPUNR)
+{
+ if (threadinfo[CPUNR].DataSendingQueue!=NULL) return O_NONBLOCK;
+ if (threadinfo[CPUNR].WaitForHeaderQueue!=NULL) return O_NONBLOCK;
+ if (threadinfo[CPUNR].LoggingQueue!=NULL) return O_NONBLOCK;
+ if (threadinfo[CPUNR].UserspaceQueue!=NULL) return O_NONBLOCK;
+ return 0;
+}
+
+
+
+static wait_queue_head_t DummyWQ[CONFIG_KHTTPD_NUMCPU];
+static atomic_t Running[CONFIG_KHTTPD_NUMCPU];
+
+static int MainDaemon(void *cpu_pointer)
+{
+ int CPUNR;
+ sigset_t tmpsig;
+
+ DECLARE_WAITQUEUE(main_wait,current);
+
+ MOD_INC_USE_COUNT;
+
+
+ current->state |= TASK_EXCLUSIVE;
+
+ CPUNR=0;
+ if (cpu_pointer!=NULL)
+ CPUNR=(int)*(int*)cpu_pointer;
+
+ sprintf(current->comm,"khttpd - %i",CPUNR);
+ lock_kernel(); /* This seems to be required for exit_mm */
+ exit_mm(current);
+
+ init_waitqueue_head(&(DummyWQ[CPUNR]));
+
+
+ /* Block all signals except SIGKILL, SIGSTOP and SIGHUP */
+ spin_lock_irq(¤t->sigmask_lock);
+ tmpsig = current->blocked;
+ siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)| sigmask(SIGHUP));
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+
+ if (MainSocket->sk==NULL)
+ return 0;
+ add_wait_queue_exclusive(MainSocket->sk->sleep,&(main_wait));
+ atomic_inc(&DaemonCount);
+ atomic_set(&Running[CPUNR],1);
+
+ while (sysctl_khttpd_stop==0)
+ {
+ int changes = 0;
+
+
+
+ changes +=AcceptConnections(CPUNR,MainSocket);
+ if (ConnectionsPending(CPUNR))
+ {
+ changes +=WaitForHeaders(CPUNR);
+ changes +=DataSending(CPUNR);
+ changes +=Userspace(CPUNR);
+ changes +=Logging(CPUNR);
+ /* Test for incomming connections _again_, because it is possible
+ one came in during the other steps, and the wakeup doesn't happen
+ then.
+ */
+ changes +=AcceptConnections(CPUNR,MainSocket);
+ }
+
+ current->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ if (changes==0)
+ {
+ (void)interruptible_sleep_on_timeout(&(DummyWQ[CPUNR]),1);
+ if (CPUNR==0)
+ UpdateCurrentDate();
+ }
+
+ if (signal_pending(current)!=0)
+ {
+ (void)printk(KERN_NOTICE "kHTTPd: Ring Ring - signal received\n");
+ break;
+ }
+
+ }
+
+ remove_wait_queue(MainSocket->sk->sleep,&(main_wait));
+
+ StopWaitingForHeaders(CPUNR);
+ StopDataSending(CPUNR);
+ StopUserspace(CPUNR);
+ StopLogging(CPUNR);
+
+ atomic_set(&Running[CPUNR],0);
+ atomic_dec(&DaemonCount);
+ (void)printk(KERN_NOTICE "kHTTPd: Daemon %i has ended\n",CPUNR);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int CountBuf[CONFIG_KHTTPD_NUMCPU];
+
+static int errno;
+inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options);
+
+
+
+/*
+
+The ManagementDaemon has a very simple task: Start the real daemons when the user wants us
+to, and cleanup when the users wants to unload the module.
+
+Initially, kHTTPd didn't have this thread, but it is the only way to have "delayed activation",
+a feature required to prevent accidental activations resulting in unexpected backdoors.
+
+*/
+static int ManagementDaemon(void *unused)
+{
+ sigset_t tmpsig;
+ int waitpid_result;
+
+ DECLARE_WAIT_QUEUE_HEAD(WQ);
+
+ MOD_INC_USE_COUNT;
+
+ sprintf(current->comm,"khttpd manager");
+ lock_kernel(); /* This seems to be required for exit_mm */
+ exit_mm(current);
+
+
+ /* Block all signals except SIGKILL and SIGSTOP */
+ spin_lock_irq(¤t->sigmask_lock);
+ tmpsig = current->blocked;
+ siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+
+ /* main loop */
+ while (sysctl_khttpd_unload==0)
+ {
+ int I;
+
+
+ /* First : wait for activation */
+
+ sysctl_khttpd_start = 0;
+
+ while ( (sysctl_khttpd_start==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
+ {
+ current->state = TASK_INTERRUPTIBLE;
+ interruptible_sleep_on_timeout(&WQ,HZ);
+ }
+
+ if ( (signal_pending(current)) || (sysctl_khttpd_unload!=0) )
+ break;
+
+ /* Then start listening and spawn the daemons */
+
+ if (StartListening(sysctl_khttpd_serverport)==0)
+ {
+ continue;
+ }
+
+ ActualThreads = sysctl_khttpd_threads;
+ if (ActualThreads<1)
+ ActualThreads = 1;
+
+ if (ActualThreads>CONFIG_KHTTPD_NUMCPU)
+ ActualThreads = CONFIG_KHTTPD_NUMCPU;
+
+ /* Write back the actual value */
+
+ sysctl_khttpd_threads = ActualThreads;
+
+ InitUserspace(ActualThreads);
+
+ if (InitDataSending(ActualThreads)!=0)
+ {
+ StopListening();
+ continue;
+ }
+ if (InitWaitHeaders(ActualThreads)!=0)
+ {
+ I=0;
+ while (I<ActualThreads)
+ {
+ StopDataSending(I);
+ I++;
+ }
+ StopListening();
+ continue;
+ }
+
+ /* Clean all queues */
+ memset(threadinfo, 0, sizeof(struct khttpd_threadinfo));
+
+
+
+ I=0;
+ while (I<ActualThreads)
+ {
+ atomic_set(&Running[I],1);
+ (void)kernel_thread(MainDaemon,&(CountBuf[I]),0);
+ I++;
+ }
+
+ /* Then wait for deactivation */
+ sysctl_khttpd_stop = 0;
+
+ while ( (sysctl_khttpd_stop==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
+ {
+ if (atomic_read(&DaemonCount)<ActualThreads)
+ {
+ I=0;
+ while (I<ActualThreads)
+ {
+ if (atomic_read(&Running[I])==0)
+ {
+ atomic_set(&Running[I],1);
+ (void)kernel_thread(MainDaemon,&(CountBuf[I]),0);
+ (void)printk(KERN_CRIT "kHTTPd: Restarting daemon %i \n",I);
+ }
+ I++;
+ }
+ }
+ interruptible_sleep_on_timeout(&WQ,HZ);
+
+ /* reap the daemons */
+ waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
+
+ }
+
+
+ /* The user wants us to stop. So stop listening on the socket. */
+ if (sysctl_khttpd_stop!=0)
+ {
+ /* Wait for the daemons to stop, one second per iteration */
+ while (atomic_read(&DaemonCount)>0)
+ interruptible_sleep_on_timeout(&WQ,HZ);
+ StopListening();
+ }
+
+
+
+ }
+
+ sysctl_khttpd_stop = 1;
+
+ /* Wait for the daemons to stop, one second per iteration */
+ while (atomic_read(&DaemonCount)>0)
+ interruptible_sleep_on_timeout(&WQ,HZ);
+
+
+ waitpid_result = 1;
+ /* reap the zombie-daemons */
+ while (waitpid_result>0)
+ waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
+
+ StopListening();
+
+
+ (void)printk(KERN_NOTICE "kHTTPd: Management daemon stopped. \n You can unload the module now.\n");
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+int __init khttpd_init(void)
+{
+ int I;
+
+ I=0;
+ while (I<CONFIG_KHTTPD_NUMCPU)
+ {
+ CountBuf[I]=I;
+
+ I++;
+ }
+
+ atomic_set(&ConnectCount,0);
+ atomic_set(&DaemonCount,0);
+
+
+ /* Maybe the mime-types will be set-able through sysctl in the future */
+
+ AddMimeType(".htm","text/html");
+ AddMimeType("html","text/html");
+ AddMimeType(".gif","image/gif");
+ AddMimeType(".jpg","image/jpeg");
+ AddMimeType(".png","image/png");
+ AddMimeType("tiff","image/tiff");
+ AddMimeType(".zip","application/zip");
+ AddMimeType(".pdf","application/pdf");
+ AddMimeType("r.gz","application/x-gtar");
+ AddMimeType(".tgz","application/x-gtar");
+ AddMimeType(".deb","application/x-debian-package");
+ AddMimeType("lass","application/x-java");
+ AddMimeType(".mp3","audio/mpeg");
+ AddMimeType(".txt","text/plain");
+
+ AddDynamicString("..");
+ AddDynamicString("cgi-bin");
+
+ StartSysctl();
+
+ (void)kernel_thread(ManagementDaemon,NULL,0);
+
+ return 0;
+}
+
+void khttpd_cleanup(void)
+{
+ EndSysctl();
+}
+
+ module_init(khttpd_init)
+ module_exit(khttpd_cleanup)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)