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
99 DECLARE_WAITQUEUE(main_wait,current);
100
101 MOD_INC_USE_COUNT;
102
103
104 CPUNR=0;
105 if (cpu_pointer!=NULL)
106 CPUNR=(int)*(int*)cpu_pointer;
107
108 sprintf(current->comm,"khttpd - %i",CPUNR);
109 daemonize();
110
111 init_waitqueue_head(&(DummyWQ[CPUNR]));
112
113
114 /* Block all signals except SIGKILL, SIGSTOP and SIGHUP */
115 spin_lock_irq(¤t->sigmask_lock);
116 tmpsig = current->blocked;
117 siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)| sigmask(SIGHUP));
118 recalc_sigpending(current);
119 spin_unlock_irq(¤t->sigmask_lock);
120
121
122 if (MainSocket->sk==NULL)
123 return 0;
124 add_wait_queue_exclusive(MainSocket->sk->sleep,&(main_wait));
125 atomic_inc(&DaemonCount);
126 atomic_set(&Running[CPUNR],1);
127
128 while (sysctl_khttpd_stop==0)
129 {
130 int changes = 0;
131
132
133
134 changes +=AcceptConnections(CPUNR,MainSocket);
135 if (ConnectionsPending(CPUNR))
136 {
137 changes +=WaitForHeaders(CPUNR);
138 changes +=DataSending(CPUNR);
139 changes +=Userspace(CPUNR);
140 changes +=Logging(CPUNR);
141 /* Test for incomming connections _again_, because it is possible
142 one came in during the other steps, and the wakeup doesn't happen
143 then.
144 */
145 changes +=AcceptConnections(CPUNR,MainSocket);
146 }
147
148 if (changes==0)
149 {
150 (void)interruptible_sleep_on_timeout(&(DummyWQ[CPUNR]),1);
151 if (CPUNR==0)
152 UpdateCurrentDate();
153 }
154
155 if (signal_pending(current)!=0)
156 {
157 (void)printk(KERN_NOTICE "kHTTPd: Ring Ring - signal received\n");
158 break;
159 }
160
161 }
162
163 remove_wait_queue(MainSocket->sk->sleep,&(main_wait));
164
165 StopWaitingForHeaders(CPUNR);
166 StopDataSending(CPUNR);
167 StopUserspace(CPUNR);
168 StopLogging(CPUNR);
169
170 atomic_set(&Running[CPUNR],0);
171 atomic_dec(&DaemonCount);
172 (void)printk(KERN_NOTICE "kHTTPd: Daemon %i has ended\n",CPUNR);
173 MOD_DEC_USE_COUNT;
174 return 0;
175 }
176
177 static int CountBuf[CONFIG_KHTTPD_NUMCPU];
178
179
180
181 /*
182
183 The ManagementDaemon has a very simple task: Start the real daemons when the user wants us
184 to, and cleanup when the users wants to unload the module.
185
186 Initially, kHTTPd didn't have this thread, but it is the only way to have "delayed activation",
187 a feature required to prevent accidental activations resulting in unexpected backdoors.
188
189 */
190 static int ManagementDaemon(void *unused)
191 {
192 sigset_t tmpsig;
193 int waitpid_result;
194
195 DECLARE_WAIT_QUEUE_HEAD(WQ);
196
197
198 sprintf(current->comm,"khttpd manager");
199 daemonize();
200
201
202 /* Block all signals except SIGKILL and SIGSTOP */
203 spin_lock_irq(¤t->sigmask_lock);
204 tmpsig = current->blocked;
205 siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
206 recalc_sigpending(current);
207 spin_unlock_irq(¤t->sigmask_lock);
208
209
210 /* main loop */
211 while (sysctl_khttpd_unload==0)
212 {
213 int I;
214
215
216 /* First : wait for activation */
217
218 sysctl_khttpd_start = 0;
219
220 while ( (sysctl_khttpd_start==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
221 {
222 current->state = TASK_INTERRUPTIBLE;
223 interruptible_sleep_on_timeout(&WQ,HZ);
224 }
225
226 if ( (signal_pending(current)) || (sysctl_khttpd_unload!=0) )
227 break;
228
229 /* Then start listening and spawn the daemons */
230
231 if (StartListening(sysctl_khttpd_serverport)==0)
232 {
233 continue;
234 }
235
236 ActualThreads = sysctl_khttpd_threads;
237 if (ActualThreads<1)
238 ActualThreads = 1;
239
240 if (ActualThreads>CONFIG_KHTTPD_NUMCPU)
241 ActualThreads = CONFIG_KHTTPD_NUMCPU;
242
243 /* Write back the actual value */
244
245 sysctl_khttpd_threads = ActualThreads;
246
247 InitUserspace(ActualThreads);
248
249 if (InitDataSending(ActualThreads)!=0)
250 {
251 StopListening();
252 continue;
253 }
254 if (InitWaitHeaders(ActualThreads)!=0)
255 {
256 I=0;
257 while (I<ActualThreads)
258 {
259 StopDataSending(I);
260 I++;
261 }
262 StopListening();
263 continue;
264 }
265
266 /* Clean all queues */
267 memset(threadinfo, 0, sizeof(struct khttpd_threadinfo));
268
269
270
271 I=0;
272 while (I<ActualThreads)
273 {
274 atomic_set(&Running[I],1);
275 (void)kernel_thread(MainDaemon,&(CountBuf[I]), CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
276 I++;
277 }
278
279 /* Then wait for deactivation */
280 sysctl_khttpd_stop = 0;
281
282 while ( (sysctl_khttpd_stop==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
283 {
284 if (atomic_read(&DaemonCount)<ActualThreads)
285 {
286 I=0;
287 while (I<ActualThreads)
288 {
289 if (atomic_read(&Running[I])==0)
290 {
291 atomic_set(&Running[I],1);
292 (void)kernel_thread(MainDaemon,&(CountBuf[I]), CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
293 (void)printk(KERN_CRIT "kHTTPd: Restarting daemon %i \n",I);
294 }
295 I++;
296 }
297 }
298 interruptible_sleep_on_timeout(&WQ,HZ);
299
300 /* reap the daemons */
301 waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
302
303 }
304
305
306 /* The user wants us to stop. So stop listening on the socket. */
307 if (sysctl_khttpd_stop!=0)
308 {
309 /* Wait for the daemons to stop, one second per iteration */
310 while (atomic_read(&DaemonCount)>0)
311 interruptible_sleep_on_timeout(&WQ,HZ);
312 StopListening();
313 }
314
315
316
317 }
318
319 sysctl_khttpd_stop = 1;
320
321 /* Wait for the daemons to stop, one second per iteration */
322 while (atomic_read(&DaemonCount)>0)
323 interruptible_sleep_on_timeout(&WQ,HZ);
324
325
326 waitpid_result = 1;
327 /* reap the zombie-daemons */
328 while (waitpid_result>0)
329 waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
330
331 StopListening();
332
333
334 (void)printk(KERN_NOTICE "kHTTPd: Management daemon stopped. \n You can unload the module now.\n");
335
336 MOD_DEC_USE_COUNT;
337
338 return 0;
339 }
340
341 int __init khttpd_init(void)
342 {
343 int I;
344
345 MOD_INC_USE_COUNT;
346
347 I=0;
348 while (I<CONFIG_KHTTPD_NUMCPU)
349 {
350 CountBuf[I]=I;
351
352 I++;
353 }
354
355 atomic_set(&ConnectCount,0);
356 atomic_set(&DaemonCount,0);
357
358
359 /* Maybe the mime-types will be set-able through sysctl in the future */
360
361 AddMimeType(".htm","text/html");
362 AddMimeType("html","text/html");
363 AddMimeType(".gif","image/gif");
364 AddMimeType(".jpg","image/jpeg");
365 AddMimeType(".png","image/png");
366 AddMimeType("tiff","image/tiff");
367 AddMimeType(".zip","application/zip");
368 AddMimeType(".pdf","application/pdf");
369 AddMimeType("r.gz","application/x-gtar");
370 AddMimeType(".tgz","application/x-gtar");
371 AddMimeType(".deb","application/x-debian-package");
372 AddMimeType("lass","application/x-java");
373 AddMimeType(".mp3","audio/mpeg");
374 AddMimeType(".txt","text/plain");
375
376 AddDynamicString("..");
377 AddDynamicString("cgi-bin");
378
379 StartSysctl();
380
381 (void)kernel_thread(ManagementDaemon,NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
382
383 return 0;
384 }
385
386 void khttpd_cleanup(void)
387 {
388 EndSysctl();
389 }
390
391 module_init(khttpd_init)
392 module_exit(khttpd_cleanup)
393
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.