port more changes to make PCI work
[linux-2.4.git] / net / khttpd / main.c
1 /*
2
3 kHTTPd -- the next generation
4
5 Main program
6
7
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.
11
12 The stages are
13
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
19
20 A typical flow for a request would be:
21
22 <not accepted>
23 WaitForHeaders
24 DataSending
25 Logging
26
27 or
28
29 <not accepted>
30 WaitForHeaders
31 Userspace
32
33
34
35 */
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.
41  *
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.
46  *
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.
50  *
51  ****************************************************************/
52
53
54 static int errno;
55 #define __KERNEL_SYSCALLS__
56
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>
66
67 #include "structure.h"
68 #include "prototypes.h"
69 #include "sysctl.h"
70
71 struct khttpd_threadinfo threadinfo[CONFIG_KHTTPD_NUMCPU];  /* The actual work-queues */
72
73
74 atomic_t        ConnectCount;
75 atomic_t        DaemonCount;
76
77 static int      ActualThreads; /* The number of actual, active threads */
78
79
80 static int ConnectionsPending(int CPUNR)
81 {
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;
87 }
88
89
90
91 static wait_queue_head_t DummyWQ[CONFIG_KHTTPD_NUMCPU];
92 static atomic_t Running[CONFIG_KHTTPD_NUMCPU]; 
93
94 static int MainDaemon(void *cpu_pointer)
95 {
96         int CPUNR;
97         sigset_t tmpsig;
98         int old_stop_count;
99         
100         DECLARE_WAITQUEUE(main_wait,current);
101         
102         MOD_INC_USE_COUNT;
103
104         /* Remember value of stop count.  If it changes, user must have 
105          * asked us to stop.  Sensing this is much less racy than 
106          * directly sensing sysctl_khttpd_stop. - dank
107          */
108         old_stop_count = atomic_read(&khttpd_stopCount);
109         
110         CPUNR=0;
111         if (cpu_pointer!=NULL)
112         CPUNR=(int)*(int*)cpu_pointer;
113
114         sprintf(current->comm,"khttpd - %i",CPUNR);
115         daemonize();
116         
117         init_waitqueue_head(&(DummyWQ[CPUNR]));
118         
119
120         /* Block all signals except SIGKILL, SIGSTOP and SIGHUP */
121         spin_lock_irq(&current->sigmask_lock);
122         tmpsig = current->blocked;
123         siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)| sigmask(SIGHUP));
124         recalc_sigpending(current);
125         spin_unlock_irq(&current->sigmask_lock);
126         
127         
128         if (MainSocket->sk==NULL)
129                 return 0;
130         add_wait_queue_exclusive(MainSocket->sk->sleep,&(main_wait));
131         atomic_inc(&DaemonCount);
132         atomic_set(&Running[CPUNR],1);
133         
134         while (old_stop_count == atomic_read(&khttpd_stopCount)) 
135         {
136                 int changes = 0;
137                 
138                 changes +=AcceptConnections(CPUNR,MainSocket);
139                 if (ConnectionsPending(CPUNR))
140                 {
141                         changes +=WaitForHeaders(CPUNR);
142                         changes +=DataSending(CPUNR);
143                         changes +=Userspace(CPUNR);
144                         changes +=Logging(CPUNR);
145                         /* Test for incoming connections _again_, because it is possible
146                            one came in during the other steps, and the wakeup doesn't happen
147                            then.
148                         */
149                         changes +=AcceptConnections(CPUNR,MainSocket);
150                 }
151                 
152                 if (changes==0) 
153                 {
154                         (void)interruptible_sleep_on_timeout(&(DummyWQ[CPUNR]),1);      
155                         if (CPUNR==0) 
156                                 UpdateCurrentDate();
157                 }
158                         
159                 if (signal_pending(current)!=0)
160                 {
161                         (void)printk(KERN_NOTICE "kHTTPd: Ring Ring - signal received\n");
162                         break;            
163                 }
164         
165         }
166         
167         remove_wait_queue(MainSocket->sk->sleep,&(main_wait));
168         
169         StopWaitingForHeaders(CPUNR);
170         StopDataSending(CPUNR);
171         StopUserspace(CPUNR);
172         StopLogging(CPUNR);
173         
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;
179 }
180
181 static int CountBuf[CONFIG_KHTTPD_NUMCPU];
182
183
184
185 /*
186
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.
189
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.
192
193 */
194 static int ManagementDaemon(void *unused)
195 {
196         sigset_t tmpsig;
197         int waitpid_result;
198         
199         DECLARE_WAIT_QUEUE_HEAD(WQ);
200         
201         sprintf(current->comm,"khttpd manager");
202         daemonize();
203         
204         /* Block all signals except SIGKILL and SIGSTOP */
205         spin_lock_irq(&current->sigmask_lock);
206         tmpsig = current->blocked;
207         siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
208         recalc_sigpending(current);
209         spin_unlock_irq(&current->sigmask_lock);
210
211         /* main loop */
212         while (sysctl_khttpd_unload==0)
213         {
214                 int I;
215                 int old_stop_count;
216                 
217                 /* First : wait for activation */
218                 while ( (sysctl_khttpd_start==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
219                 {
220                         current->state = TASK_INTERRUPTIBLE;
221                         interruptible_sleep_on_timeout(&WQ,HZ); 
222                 }
223                 if ( (signal_pending(current)) || (sysctl_khttpd_unload!=0) )
224                         break;
225                 sysctl_khttpd_stop = 0;
226                         
227                 /* Then start listening and spawn the daemons */
228                 if (StartListening(sysctl_khttpd_serverport)==0)
229                 {
230                         sysctl_khttpd_start = 0;
231                         continue;
232                 }
233
234                 ActualThreads = sysctl_khttpd_threads;
235                 if (ActualThreads<1) 
236                         ActualThreads = 1;
237                 if (ActualThreads>CONFIG_KHTTPD_NUMCPU) 
238                         ActualThreads = CONFIG_KHTTPD_NUMCPU;
239                 /* Write back the actual value */
240                 sysctl_khttpd_threads = ActualThreads;
241                 
242                 InitUserspace(ActualThreads);
243                 
244                 if (InitDataSending(ActualThreads)!=0)
245                 {
246                         StopListening();
247                         sysctl_khttpd_start = 0;
248                         continue;
249                 }
250                 if (InitWaitHeaders(ActualThreads)!=0)
251                 {
252                         for (I=0; I<ActualThreads; I++) {
253                                 StopDataSending(I);
254                         }
255                         StopListening();
256                         sysctl_khttpd_start = 0;
257                         continue;
258                 }
259         
260                 /* Clean all queues */
261                 memset(threadinfo, 0, sizeof(struct khttpd_threadinfo));
262
263                 for (I=0; I<ActualThreads; I++) {
264                         atomic_set(&Running[I],1);
265                         (void)kernel_thread(MainDaemon,&(CountBuf[I]), CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
266                 }
267                 
268                 /* Then wait for deactivation */
269                 /* Remember value of stop count.  If it changes, user must 
270                  * have asked us to stop.  Sensing this is much less racy 
271                  * than directly sensing sysctl_khttpd_stop. - dank
272                  */
273                 old_stop_count = atomic_read(&khttpd_stopCount);
274                 while ( ( old_stop_count == atomic_read(&khttpd_stopCount)) 
275                          && (!signal_pending(current)) 
276                          && (sysctl_khttpd_unload==0) )
277                 {
278                         /* Used to restart dead threads here, but it was buggy*/
279                         interruptible_sleep_on_timeout(&WQ,HZ);
280                 }
281                 
282                 /* Wait for the daemons to stop, one second per iteration */
283                 while (atomic_read(&DaemonCount)>0)
284                         interruptible_sleep_on_timeout(&WQ,HZ);
285                 StopListening();
286                 sysctl_khttpd_start = 0;
287                 /* reap the zombie-daemons */
288                 do
289                         waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
290                 while (waitpid_result>0);
291         }
292         sysctl_khttpd_start = 0;
293         sysctl_khttpd_stop = 1;
294         atomic_inc(&khttpd_stopCount);
295
296         /* Wait for the daemons to stop, one second per iteration */
297         while (atomic_read(&DaemonCount)>0)
298                 interruptible_sleep_on_timeout(&WQ,HZ);
299         StopListening();
300         /* reap the zombie-daemons */
301         do
302                 waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
303         while (waitpid_result>0);
304         
305         (void)printk(KERN_NOTICE "kHTTPd: Management daemon stopped. \n        You can unload the module now.\n");
306
307         MOD_DEC_USE_COUNT;
308
309         return 0;
310 }
311
312 int __init khttpd_init(void)
313 {
314         int I;
315
316         MOD_INC_USE_COUNT;
317         
318         for (I=0; I<CONFIG_KHTTPD_NUMCPU; I++) {
319                 CountBuf[I]=I;
320         }
321         
322         atomic_set(&ConnectCount,0);
323         atomic_set(&DaemonCount,0);
324         atomic_set(&khttpd_stopCount,0);
325         
326
327         /* Maybe the mime-types will be set-able through sysctl in the future */           
328                 
329         AddMimeType(".htm","text/html");
330         AddMimeType("html","text/html");
331         AddMimeType(".gif","image/gif");
332         AddMimeType(".jpg","image/jpeg");
333         AddMimeType(".png","image/png");
334         AddMimeType("tiff","image/tiff");
335         AddMimeType(".zip","application/zip");
336         AddMimeType(".pdf","application/pdf");
337         AddMimeType("r.gz","application/x-gtar");
338         AddMimeType(".tgz","application/x-gtar");
339         AddMimeType(".deb","application/x-debian-package");
340         AddMimeType("lass","application/x-java");
341         AddMimeType(".mp3","audio/mpeg");
342         AddMimeType(".txt","text/plain");
343         
344         AddDynamicString("..");
345         AddDynamicString("cgi-bin");
346
347         StartSysctl();
348         
349         (void)kernel_thread(ManagementDaemon,NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
350         
351         return 0;
352 }
353
354 void khttpd_cleanup(void)
355 {
356         EndSysctl();
357 }
358
359         module_init(khttpd_init)
360         module_exit(khttpd_cleanup)
361
362         MODULE_LICENSE("GPL");