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
ConnectionsPending(int CPUNR)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
MainDaemon(void * cpu_pointer)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(¤t->sigmask_lock);
122 tmpsig = current->blocked;
123 siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)| sigmask(SIGHUP));
124 recalc_sigpending(current);
125 spin_unlock_irq(¤t->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 */
ManagementDaemon(void * unused)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(¤t->sigmask_lock);
206 tmpsig = current->blocked;
207 siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
208 recalc_sigpending(current);
209 spin_unlock_irq(¤t->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
khttpd_init(void)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
khttpd_cleanup(void)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");
363