main.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2. kHTTPd -- the next generation
  3. Main program
  4. kHTTPd TNG consists of 1 thread, this main-thread handles ALL connections
  5. simultanious. It does this by keeping queues with the requests in different
  6. stages.
  7. The stages are
  8. <not accepted>  - TCP/IP connection is not accepted yet
  9. WaitForHeaders - Connection is accepted, waiting for headers
  10. DataSending - Headers decoded, sending file-data
  11. Userspace - Requires userspace daemon 
  12. Logging - The request is finished, cleanup and logging
  13. A typical flow for a request would be:
  14. <not accepted>
  15. WaitForHeaders
  16. DataSending
  17. Logging
  18. or
  19. <not accepted>
  20. WaitForHeaders
  21. Userspace
  22. */
  23. /****************************************************************
  24.  * This program is free software; you can redistribute it and/or modify
  25.  * it under the terms of the GNU General Public License as published by
  26.  * the Free Software Foundation; either version 2, or (at your option)
  27.  * any later version.
  28.  *
  29.  * This program is distributed in the hope that it will be useful,
  30.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  31.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  32.  * GNU General Public License for more details.
  33.  *
  34.  * You should have received a copy of the GNU General Public License
  35.  * along with this program; if not, write to the Free Software
  36.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  37.  *
  38.  ****************************************************************/
  39. static int errno;
  40. #define __KERNEL_SYSCALLS__
  41. #include <linux/config.h>
  42. #include <linux/module.h>
  43. #include <linux/kernel.h>
  44. #include <linux/sched.h>
  45. #include <linux/signal.h>
  46. #include <linux/init.h>
  47. #include <linux/wait.h>
  48. #include <linux/smp_lock.h>
  49. #include <asm/unistd.h>
  50. #include "structure.h"
  51. #include "prototypes.h"
  52. #include "sysctl.h"
  53. struct khttpd_threadinfo threadinfo[CONFIG_KHTTPD_NUMCPU];  /* The actual work-queues */
  54. atomic_t ConnectCount;
  55. atomic_t DaemonCount;
  56. static int ActualThreads; /* The number of actual, active threads */
  57. static int ConnectionsPending(int CPUNR)
  58. {
  59. if (threadinfo[CPUNR].DataSendingQueue!=NULL) return O_NONBLOCK;
  60. if (threadinfo[CPUNR].WaitForHeaderQueue!=NULL) return O_NONBLOCK;
  61. if (threadinfo[CPUNR].LoggingQueue!=NULL) return O_NONBLOCK;
  62. if (threadinfo[CPUNR].UserspaceQueue!=NULL) return O_NONBLOCK;
  63.   return 0;
  64. }
  65. static wait_queue_head_t DummyWQ[CONFIG_KHTTPD_NUMCPU];
  66. static atomic_t Running[CONFIG_KHTTPD_NUMCPU]; 
  67. static int MainDaemon(void *cpu_pointer)
  68. {
  69. int CPUNR;
  70. sigset_t tmpsig;
  71. int old_stop_count;
  72. DECLARE_WAITQUEUE(main_wait,current);
  73. MOD_INC_USE_COUNT;
  74. /* Remember value of stop count.  If it changes, user must have 
  75.  * asked us to stop.  Sensing this is much less racy than 
  76.  * directly sensing sysctl_khttpd_stop. - dank
  77.  */
  78. old_stop_count = atomic_read(&khttpd_stopCount);
  79. CPUNR=0;
  80. if (cpu_pointer!=NULL)
  81. CPUNR=(int)*(int*)cpu_pointer;
  82. sprintf(current->comm,"khttpd - %i",CPUNR);
  83. daemonize();
  84. init_waitqueue_head(&(DummyWQ[CPUNR]));
  85. /* Block all signals except SIGKILL, SIGSTOP and SIGHUP */
  86. spin_lock_irq(&current->sigmask_lock);
  87. tmpsig = current->blocked;
  88. siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)| sigmask(SIGHUP));
  89. recalc_sigpending(current);
  90. spin_unlock_irq(&current->sigmask_lock);
  91. if (MainSocket->sk==NULL)
  92.   return 0;
  93. add_wait_queue_exclusive(MainSocket->sk->sleep,&(main_wait));
  94. atomic_inc(&DaemonCount);
  95. atomic_set(&Running[CPUNR],1);
  96. while (old_stop_count == atomic_read(&khttpd_stopCount)) 
  97. {
  98. int changes = 0;
  99. changes +=AcceptConnections(CPUNR,MainSocket);
  100. if (ConnectionsPending(CPUNR))
  101. {
  102. changes +=WaitForHeaders(CPUNR);
  103. changes +=DataSending(CPUNR);
  104. changes +=Userspace(CPUNR);
  105. changes +=Logging(CPUNR);
  106. /* Test for incoming connections _again_, because it is possible
  107.    one came in during the other steps, and the wakeup doesn't happen
  108.    then.
  109. */
  110. changes +=AcceptConnections(CPUNR,MainSocket);
  111. }
  112. if (changes==0) 
  113. {
  114. (void)interruptible_sleep_on_timeout(&(DummyWQ[CPUNR]),1);
  115. if (CPUNR==0) 
  116. UpdateCurrentDate();
  117. }
  118. if (signal_pending(current)!=0)
  119. {
  120. (void)printk(KERN_NOTICE "kHTTPd: Ring Ring - signal receivedn");
  121. break;   
  122. }
  123. }
  124. remove_wait_queue(MainSocket->sk->sleep,&(main_wait));
  125. StopWaitingForHeaders(CPUNR);
  126. StopDataSending(CPUNR);
  127. StopUserspace(CPUNR);
  128. StopLogging(CPUNR);
  129. atomic_set(&Running[CPUNR],0);
  130. atomic_dec(&DaemonCount);
  131. (void)printk(KERN_NOTICE "kHTTPd: Daemon %i has endedn",CPUNR);
  132. MOD_DEC_USE_COUNT;
  133. return 0;
  134. }
  135. static int CountBuf[CONFIG_KHTTPD_NUMCPU];
  136. /*
  137. The ManagementDaemon has a very simple task: Start the real daemons when the user wants us
  138. to, and cleanup when the users wants to unload the module.
  139. Initially, kHTTPd didn't have this thread, but it is the only way to have "delayed activation",
  140. a feature required to prevent accidental activations resulting in unexpected backdoors.
  141. */
  142. static int ManagementDaemon(void *unused)
  143. {
  144. sigset_t tmpsig;
  145. int waitpid_result;
  146. DECLARE_WAIT_QUEUE_HEAD(WQ);
  147. sprintf(current->comm,"khttpd manager");
  148. daemonize();
  149. /* Block all signals except SIGKILL and SIGSTOP */
  150. spin_lock_irq(&current->sigmask_lock);
  151. tmpsig = current->blocked;
  152. siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) );
  153. recalc_sigpending(current);
  154. spin_unlock_irq(&current->sigmask_lock);
  155. /* main loop */
  156. while (sysctl_khttpd_unload==0)
  157. {
  158. int I;
  159. int old_stop_count;
  160. /* First : wait for activation */
  161. while ( (sysctl_khttpd_start==0) && (!signal_pending(current)) && (sysctl_khttpd_unload==0) )
  162. {
  163. current->state = TASK_INTERRUPTIBLE;
  164. interruptible_sleep_on_timeout(&WQ,HZ); 
  165. }
  166. if ( (signal_pending(current)) || (sysctl_khttpd_unload!=0) )
  167.   break;
  168. sysctl_khttpd_stop = 0;
  169.  
  170. /* Then start listening and spawn the daemons */
  171. if (StartListening(sysctl_khttpd_serverport)==0)
  172. {
  173. sysctl_khttpd_start = 0;
  174. continue;
  175. }
  176. ActualThreads = sysctl_khttpd_threads;
  177. if (ActualThreads<1) 
  178. ActualThreads = 1;
  179. if (ActualThreads>CONFIG_KHTTPD_NUMCPU) 
  180. ActualThreads = CONFIG_KHTTPD_NUMCPU;
  181. /* Write back the actual value */
  182. sysctl_khttpd_threads = ActualThreads;
  183. InitUserspace(ActualThreads);
  184. if (InitDataSending(ActualThreads)!=0)
  185. {
  186. StopListening();
  187. sysctl_khttpd_start = 0;
  188. continue;
  189. }
  190. if (InitWaitHeaders(ActualThreads)!=0)
  191. {
  192. for (I=0; I<ActualThreads; I++) {
  193. StopDataSending(I);
  194. }
  195. StopListening();
  196. sysctl_khttpd_start = 0;
  197. continue;
  198. }
  199. /* Clean all queues */
  200. memset(threadinfo, 0, sizeof(struct khttpd_threadinfo));
  201. for (I=0; I<ActualThreads; I++) {
  202. atomic_set(&Running[I],1);
  203. (void)kernel_thread(MainDaemon,&(CountBuf[I]), CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
  204. }
  205. /* Then wait for deactivation */
  206. /* Remember value of stop count.  If it changes, user must 
  207.  * have asked us to stop.  Sensing this is much less racy 
  208.  * than directly sensing sysctl_khttpd_stop. - dank
  209.  */
  210. old_stop_count = atomic_read(&khttpd_stopCount);
  211. while ( ( old_stop_count == atomic_read(&khttpd_stopCount)) 
  212.  && (!signal_pending(current)) 
  213.  && (sysctl_khttpd_unload==0) )
  214. {
  215. /* Used to restart dead threads here, but it was buggy*/
  216. interruptible_sleep_on_timeout(&WQ,HZ);
  217. }
  218. /* Wait for the daemons to stop, one second per iteration */
  219. while (atomic_read(&DaemonCount)>0)
  220. interruptible_sleep_on_timeout(&WQ,HZ);
  221. StopListening();
  222. sysctl_khttpd_start = 0;
  223. /* reap the zombie-daemons */
  224. do
  225. waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
  226. while (waitpid_result>0);
  227. }
  228. sysctl_khttpd_start = 0;
  229. sysctl_khttpd_stop = 1;
  230. atomic_inc(&khttpd_stopCount);
  231. /* Wait for the daemons to stop, one second per iteration */
  232. while (atomic_read(&DaemonCount)>0)
  233.   interruptible_sleep_on_timeout(&WQ,HZ);
  234. StopListening();
  235. /* reap the zombie-daemons */
  236. do
  237. waitpid_result = waitpid(-1,NULL,__WCLONE|WNOHANG);
  238. while (waitpid_result>0);
  239. (void)printk(KERN_NOTICE "kHTTPd: Management daemon stopped. n        You can unload the module now.n");
  240. MOD_DEC_USE_COUNT;
  241. return 0;
  242. }
  243. int __init khttpd_init(void)
  244. {
  245. int I;
  246. MOD_INC_USE_COUNT;
  247. for (I=0; I<CONFIG_KHTTPD_NUMCPU; I++) {
  248. CountBuf[I]=I;
  249. }
  250. atomic_set(&ConnectCount,0);
  251. atomic_set(&DaemonCount,0);
  252. atomic_set(&khttpd_stopCount,0);
  253. /* Maybe the mime-types will be set-able through sysctl in the future */    
  254.   AddMimeType(".htm","text/html");
  255.   AddMimeType("html","text/html");
  256.   AddMimeType(".gif","image/gif");
  257.   AddMimeType(".jpg","image/jpeg");
  258.   AddMimeType(".png","image/png");
  259.   AddMimeType("tiff","image/tiff");
  260.   AddMimeType(".zip","application/zip");
  261. AddMimeType(".pdf","application/pdf");
  262.   AddMimeType("r.gz","application/x-gtar");
  263.   AddMimeType(".tgz","application/x-gtar");
  264. AddMimeType(".deb","application/x-debian-package");
  265. AddMimeType("lass","application/x-java");
  266. AddMimeType(".mp3","audio/mpeg");
  267. AddMimeType(".txt","text/plain");
  268. AddDynamicString("..");
  269. AddDynamicString("cgi-bin");
  270. StartSysctl();
  271. (void)kernel_thread(ManagementDaemon,NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
  272. return 0;
  273. }
  274. void khttpd_cleanup(void)
  275. {
  276. EndSysctl();
  277. }
  278. module_init(khttpd_init)
  279. module_exit(khttpd_cleanup)
  280. MODULE_LICENSE("GPL");