Import 2.4.0-test5pre4
[davej-history.git] / net / khttpd / main.c
blob5c39c59b9db63cdee56d6941d27fa7a002e7b863
1 /*
3 kHTTPd -- the next generation
5 Main program
8 kHTTPd TNG consists of 1 thread, this main-thread handles ALL connections
9 simultanious. It does this by keeping queues with the requests in different
10 stages.
12 The stages are
14 <not accepted> - TCP/IP connection is not accepted yet
15 WaitForHeaders - Connection is accepted, waiting for headers
16 DataSending - Headers decoded, sending file-data
17 Userspace - Requires userspace daemon
18 Logging - The request is finished, cleanup and logging
20 A typical flow for a request would be:
22 <not accepted>
23 WaitForHeaders
24 DataSending
25 Logging
29 <not accepted>
30 WaitForHeaders
31 Userspace
36 /****************************************************************
37 * This program is free software; you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published by
39 * the Free Software Foundation; either version 2, or (at your option)
40 * any later version.
42 * This program is distributed in the hope that it will be useful,
43 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 * GNU General Public License for more details.
47 * You should have received a copy of the GNU General Public License
48 * along with this program; if not, write to the Free Software
49 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
51 ****************************************************************/
54 static int errno;
55 #define __KERNEL_SYSCALLS__
57 #include <linux/config.h>
58 #include <linux/module.h>
59 #include <linux/kernel.h>
60 #include <linux/sched.h>
61 #include <linux/signal.h>
62 #include <linux/init.h>
63 #include <linux/wait.h>
64 #include <linux/smp_lock.h>
65 #include <asm/unistd.h>
67 #include "structure.h"
68 #include "prototypes.h"
69 #include "sysctl.h"
71 struct khttpd_threadinfo threadinfo[CONFIG_KHTTPD_NUMCPU]; /* The actual work-queues */
74 atomic_t ConnectCount;
75 atomic_t DaemonCount;
77 static int ActualThreads; /* The number of actual, active threads */
80 static int ConnectionsPending(int CPUNR)
82 if (threadinfo[CPUNR].DataSendingQueue!=NULL) return O_NONBLOCK;
83 if (threadinfo[CPUNR].WaitForHeaderQueue!=NULL) return O_NONBLOCK;
84 if (threadinfo[CPUNR].LoggingQueue!=NULL) return O_NONBLOCK;
85 if (threadinfo[CPUNR].UserspaceQueue!=NULL) return O_NONBLOCK;
86 return 0;
91 static wait_queue_head_t DummyWQ[CONFIG_KHTTPD_NUMCPU];
92 static atomic_t Running[CONFIG_KHTTPD_NUMCPU];
94 static int MainDaemon(void *cpu_pointer)
96 int CPUNR;
97 sigset_t tmpsig;
99 DECLARE_WAITQUEUE(main_wait,current);
101 MOD_INC_USE_COUNT;
104 current->state |= TASK_EXCLUSIVE;
106 CPUNR=0;
107 if (cpu_pointer!=NULL)
108 CPUNR=(int)*(int*)cpu_pointer;
110 sprintf(current->comm,"khttpd - %i",CPUNR);
111 lock_kernel(); /* This seems to be required for exit_mm */
112 exit_mm(current);
114 init_waitqueue_head(&(DummyWQ[CPUNR]));
117 /* Block all signals except SIGKILL, SIGSTOP and SIGHUP */
118 spin_lock_irq(&current->sigmask_lock);
119 tmpsig = current->blocked;
120 siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)| sigmask(SIGHUP));
121 recalc_sigpending(current);
122 spin_unlock_irq(&current->sigmask_lock);
125 if (MainSocket->sk==NULL)
126 return 0;
127 add_wait_queue_exclusive(MainSocket->sk->sleep,&(main_wait));
128 atomic_inc(&DaemonCount);
129 atomic_set(&Running[CPUNR],1);
131 while (sysctl_khttpd_stop==0)
133 int changes = 0;
137 changes +=AcceptConnections(CPUNR,MainSocket);
138 if (ConnectionsPending(CPUNR))
140 changes +=WaitForHeaders(CPUNR);
141 changes +=DataSending(CPUNR);
142 changes +=Userspace(CPUNR);
143 changes +=Logging(CPUNR);
144 /* Test for incomming connections _again_, because it is possible
145 one came in during the other steps, and the wakeup doesn't happen
146 then.
148 changes +=AcceptConnections(CPUNR,MainSocket);
151 set_current_state(TASK_INTERRUPTIBLE|TASK_EXCLUSIVE);
152 if (changes==0)
154 (void)interruptible_sleep_on_timeout(&(DummyWQ[CPUNR]),1);
155 if (CPUNR==0)
156 UpdateCurrentDate();
159 if (signal_pending(current)!=0)
161 (void)printk(KERN_NOTICE "kHTTPd: Ring Ring - signal received\n");
162 break;
167 remove_wait_queue(MainSocket->sk->sleep,&(main_wait));
169 StopWaitingForHeaders(CPUNR);
170 StopDataSending(CPUNR);
171 StopUserspace(CPUNR);
172 StopLogging(CPUNR);
174 atomic_set(&Running[CPUNR],0);
175 atomic_dec(&DaemonCount);
176 (void)printk(KERN_NOTICE "kHTTPd: Daemon %i has ended\n",CPUNR);
177 MOD_DEC_USE_COUNT;
178 return 0;
181 static int CountBuf[CONFIG_KHTTPD_NUMCPU];
187 The ManagementDaemon has a very simple task: Start the real daemons when the user wants us
188 to, and cleanup when the users wants to unload the module.
190 Initially, kHTTPd didn't have this thread, but it is the only way to have "delayed activation",
191 a feature required to prevent accidental activations resulting in unexpected backdoors.
194 static int ManagementDaemon(void *unused)
196 sigset_t tmpsig;
197 int waitpid_result;
199 DECLARE_WAIT_QUEUE_HEAD(WQ);
202 sprintf(current->comm,"khttpd manager");
203 lock_kernel(); /* This seems to be required for exit_mm */
204 exit_mm(current);
207 /* Block all signals except SIGKILL and SIGSTOP */
208 spin_lock_irq(&current->sigmask_lock);
209 tmpsig = current->blocked;
210 siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
211 recalc_sigpending(current);
212 spin_unlock_irq(&current->sigmask_lock);
215 /* main loop */
216 while (sysctl_khttpd_unload==0)
218 int I;
221 /* First : wait for activation */
223 sysctl_khttpd_start = 0;
225 while ( (sysctl_khttpd_start==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
227 current->state = TASK_INTERRUPTIBLE;
228 interruptible_sleep_on_timeout(&WQ,HZ);
231 if ( (signal_pending(current)) || (sysctl_khttpd_unload!=0) )
232 break;
234 /* Then start listening and spawn the daemons */
236 if (StartListening(sysctl_khttpd_serverport)==0)
238 continue;
241 ActualThreads = sysctl_khttpd_threads;
242 if (ActualThreads<1)
243 ActualThreads = 1;
245 if (ActualThreads>CONFIG_KHTTPD_NUMCPU)
246 ActualThreads = CONFIG_KHTTPD_NUMCPU;
248 /* Write back the actual value */
250 sysctl_khttpd_threads = ActualThreads;
252 InitUserspace(ActualThreads);
254 if (InitDataSending(ActualThreads)!=0)
256 StopListening();
257 continue;
259 if (InitWaitHeaders(ActualThreads)!=0)
261 I=0;
262 while (I<ActualThreads)
264 StopDataSending(I);
265 I++;
267 StopListening();
268 continue;
271 /* Clean all queues */
272 memset(threadinfo, 0, sizeof(struct khttpd_threadinfo));
276 I=0;
277 while (I<ActualThreads)
279 atomic_set(&Running[I],1);
280 (void)kernel_thread(MainDaemon,&(CountBuf[I]), CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
281 I++;
284 /* Then wait for deactivation */
285 sysctl_khttpd_stop = 0;
287 while ( (sysctl_khttpd_stop==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
289 if (atomic_read(&DaemonCount)<ActualThreads)
291 I=0;
292 while (I<ActualThreads)
294 if (atomic_read(&Running[I])==0)
296 atomic_set(&Running[I],1);
297 (void)kernel_thread(MainDaemon,&(CountBuf[I]), CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
298 (void)printk(KERN_CRIT "kHTTPd: Restarting daemon %i \n",I);
300 I++;
303 interruptible_sleep_on_timeout(&WQ,HZ);
305 /* reap the daemons */
306 waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
311 /* The user wants us to stop. So stop listening on the socket. */
312 if (sysctl_khttpd_stop!=0)
314 /* Wait for the daemons to stop, one second per iteration */
315 while (atomic_read(&DaemonCount)>0)
316 interruptible_sleep_on_timeout(&WQ,HZ);
317 StopListening();
324 sysctl_khttpd_stop = 1;
326 /* Wait for the daemons to stop, one second per iteration */
327 while (atomic_read(&DaemonCount)>0)
328 interruptible_sleep_on_timeout(&WQ,HZ);
331 waitpid_result = 1;
332 /* reap the zombie-daemons */
333 while (waitpid_result>0)
334 waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
336 StopListening();
339 (void)printk(KERN_NOTICE "kHTTPd: Management daemon stopped. \n You can unload the module now.\n");
341 MOD_DEC_USE_COUNT;
343 return 0;
346 int __init khttpd_init(void)
348 int I;
350 MOD_INC_USE_COUNT;
352 I=0;
353 while (I<CONFIG_KHTTPD_NUMCPU)
355 CountBuf[I]=I;
357 I++;
360 atomic_set(&ConnectCount,0);
361 atomic_set(&DaemonCount,0);
364 /* Maybe the mime-types will be set-able through sysctl in the future */
366 AddMimeType(".htm","text/html");
367 AddMimeType("html","text/html");
368 AddMimeType(".gif","image/gif");
369 AddMimeType(".jpg","image/jpeg");
370 AddMimeType(".png","image/png");
371 AddMimeType("tiff","image/tiff");
372 AddMimeType(".zip","application/zip");
373 AddMimeType(".pdf","application/pdf");
374 AddMimeType("r.gz","application/x-gtar");
375 AddMimeType(".tgz","application/x-gtar");
376 AddMimeType(".deb","application/x-debian-package");
377 AddMimeType("lass","application/x-java");
378 AddMimeType(".mp3","audio/mpeg");
379 AddMimeType(".txt","text/plain");
381 AddDynamicString("..");
382 AddDynamicString("cgi-bin");
384 StartSysctl();
386 (void)kernel_thread(ManagementDaemon,NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
388 return 0;
391 void khttpd_cleanup(void)
393 EndSysctl();
396 module_init(khttpd_init)
397 module_exit(khttpd_cleanup)