~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/khttpd/main.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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(&current->sigmask_lock);
116         tmpsig = current->blocked;
117         siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)| sigmask(SIGHUP));
118         recalc_sigpending(current);
119         spin_unlock_irq(&current->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(&current->sigmask_lock);
204         tmpsig = current->blocked;
205         siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
206         recalc_sigpending(current);
207         spin_unlock_irq(&current->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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.