make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / net / khttpd / waitheaders.c
1 /*
2
3 kHTTPd -- the next generation
4
5 Wait for headers on the accepted connections
6
7 */
8 /****************************************************************
9  *      This program is free software; you can redistribute it and/or modify
10  *      it under the terms of the GNU General Public License as published by
11  *      the Free Software Foundation; either version 2, or (at your option)
12  *      any later version.
13  *
14  *      This program is distributed in the hope that it will be useful,
15  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *      GNU General Public License for more details.
18  *
19  *      You should have received a copy of the GNU General Public License
20  *      along with this program; if not, write to the Free Software
21  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  ****************************************************************/
24
25 /*
26
27 Purpose:
28
29 WaitForHeaders polls all connections in "WaitForHeaderQueue" to see if
30 headers have arived. If so, the headers are decoded and the request is
31 moved to either the "SendingDataQueue" or the "UserspaceQueue".
32
33 Return value:
34         The number of requests that changed status
35 */
36
37 #include <linux/config.h>
38 #include <linux/kernel.h>
39 #include <linux/skbuff.h>
40 #include <linux/smp_lock.h>
41 #include <linux/file.h>
42
43 #include <asm/uaccess.h>
44
45 #include "structure.h"
46 #include "prototypes.h"
47
48 static  char                    *Buffer[CONFIG_KHTTPD_NUMCPU];
49
50
51 static int DecodeHeader(const int CPUNR, struct http_request *Request);
52
53
54 int WaitForHeaders(const int CPUNR)
55 {
56         struct http_request *CurrentRequest,**Prev;
57         struct sock *sk;
58         int count = 0;
59         
60         EnterFunction("WaitForHeaders");
61         
62         CurrentRequest = threadinfo[CPUNR].WaitForHeaderQueue;
63         
64         Prev = &(threadinfo[CPUNR].WaitForHeaderQueue);
65         
66         while (CurrentRequest!=NULL)
67         {
68                 
69                 /* If the connection is lost, remove from queue */
70                 
71                 if (CurrentRequest->sock->sk->state != TCP_ESTABLISHED
72                     && CurrentRequest->sock->sk->state != TCP_CLOSE_WAIT)
73                 {
74                         struct http_request *Next;
75                         
76                         Next = CurrentRequest->Next;
77                         
78                         *Prev = CurrentRequest->Next;
79                         CurrentRequest->Next = NULL;
80                         
81                 
82                         CleanUpRequest(CurrentRequest);
83                         CurrentRequest = Next;
84                         continue;
85                 }
86                 
87                 
88                 
89                 /* If data pending, take action */      
90                 
91                 sk = CurrentRequest->sock->sk;
92                 
93                 if (!skb_queue_empty(&(sk->receive_queue))) /* Do we have data ? */
94                 {
95                         struct http_request *Next;
96                         
97                         
98                         
99                         /* Decode header */
100                         
101                         if (DecodeHeader(CPUNR,CurrentRequest)<0)
102                         {
103                                 CurrentRequest = CurrentRequest->Next;
104                                 continue;
105                         } 
106                         
107                         
108                         /* Remove from WaitForHeaderQueue */            
109                         
110                         Next= CurrentRequest->Next;
111                 
112                         *Prev = Next;
113                         count++;
114                         
115                         /* Add to either the UserspaceQueue or the DataSendingQueue */
116                         
117                         if (CurrentRequest->IsForUserspace!=0)
118                         {
119                                 CurrentRequest->Next = threadinfo[CPUNR].UserspaceQueue;
120                                 threadinfo[CPUNR].UserspaceQueue = CurrentRequest;      
121                         } else
122                         {
123                                 CurrentRequest->Next = threadinfo[CPUNR].DataSendingQueue;
124                                 threadinfo[CPUNR].DataSendingQueue = CurrentRequest;    
125                         }       
126                         
127                         CurrentRequest = Next;
128                         continue;
129                 
130                 }       
131
132                 
133                 Prev = &(CurrentRequest->Next);
134                 CurrentRequest = CurrentRequest->Next;
135         }
136
137         LeaveFunction("WaitForHeaders");
138         return count;
139 }
140
141 void StopWaitingForHeaders(const int CPUNR)
142 {
143         struct http_request *CurrentRequest,*Next;
144         
145         EnterFunction("StopWaitingForHeaders");
146         CurrentRequest = threadinfo[CPUNR].WaitForHeaderQueue;
147
148         while (CurrentRequest!=NULL)
149         {
150                 Next = CurrentRequest->Next;
151                 CleanUpRequest(CurrentRequest);
152                 CurrentRequest=Next;            
153         }
154         
155         threadinfo[CPUNR].WaitForHeaderQueue = NULL; /* The queue is empty now */
156         
157         free_page((unsigned long)Buffer[CPUNR]);
158         Buffer[CPUNR]=NULL;
159         
160         EnterFunction("StopWaitingForHeaders");
161 }
162
163
164 /* 
165
166 DecodeHeader peeks at the TCP/IP data, determines what the request is, 
167 fills the request-structure and sends the HTTP-header when apropriate.
168
169 */
170
171 static int DecodeHeader(const int CPUNR, struct http_request *Request)
172 {
173         struct msghdr           msg;
174         struct iovec            iov;
175         int                     len;
176
177         mm_segment_t            oldfs;
178         
179         EnterFunction("DecodeHeader");
180         
181         if (Buffer[CPUNR] == NULL) {
182                 /* see comments in main.c regarding buffer managemnet - dank */
183                 printk(KERN_CRIT "khttpd: lost my buffer");
184                 BUG();
185         }
186
187         /* First, read the data */
188
189         msg.msg_name     = 0;
190         msg.msg_namelen  = 0;
191         msg.msg_iov      = &iov;
192         msg.msg_iovlen   = 1;
193         msg.msg_control  = NULL;
194         msg.msg_controllen = 0;
195         msg.msg_flags    = 0;
196         
197         msg.msg_iov->iov_base = &Buffer[CPUNR][0];
198         msg.msg_iov->iov_len  = (size_t)4095;
199         
200         len = 0;
201         oldfs = get_fs(); set_fs(KERNEL_DS);
202         /* 4095 leaves a "0" to terminate the string */
203         
204         len = sock_recvmsg(Request->sock,&msg,4095,MSG_PEEK);
205         set_fs(oldfs);
206
207         if (len<0) {
208                 /* WONDERFUL. NO COMMENTS. --ANK */
209                 Request->IsForUserspace = 1;
210                 return 0;
211         }
212
213         if (len>=4094) /* BIG header, we cannot decode it so leave it to userspace */   
214         {
215                 Request->IsForUserspace = 1;
216                 return 0;
217         }
218         
219         /* Then, decode the header */
220         
221         
222         ParseHeader(Buffer[CPUNR],len,Request);
223         
224         Request->filp = OpenFileForSecurity(Request->FileName);
225         
226         
227         Request->MimeType = ResolveMimeType(Request->FileName,&Request->MimeLength);
228         
229         
230         if (Request->MimeType==NULL) /* Unknown mime-type */
231         {
232                 if (Request->filp!=NULL)
233                 {
234                         fput(Request->filp);
235                         Request->filp = NULL;
236                 }
237                 Request->IsForUserspace = 1;
238                 
239                 return 0;
240         }
241
242         if (Request->filp==NULL)
243         {
244                 Request->IsForUserspace = 1;
245                 return 0;
246         }
247         else
248         {
249                 Request->FileLength = (int)Request->filp->f_dentry->d_inode->i_size;
250                 Request->Time       = Request->filp->f_dentry->d_inode->i_mtime;
251                 Request->IMS_Time   = mimeTime_to_UnixTime(Request->IMS);
252                 sprintf(Request->LengthS,"%i",Request->FileLength);
253                 time_Unix2RFC(min_t(unsigned int, Request->Time,CurrentTime_i),Request->TimeS);
254                 /* The min() is required by rfc1945, section 10.10:
255                    It is not allowed to send a filetime in the future */
256
257                 if (Request->IMS_Time>Request->Time)
258                 {       /* Not modified since last time */
259                         Send304(Request->sock);
260                         Request->FileLength=0;
261                 }
262                 else   /* Normal Case */
263                 {
264                         Request->sock->sk->tp_pinfo.af_tcp.nonagle = 2; /* this is TCP_CORK */
265                         if (Request->HTTPVER!=9)  /* HTTP/0.9 doesn't allow a header */
266                                 SendHTTPHeader(Request);
267                 }
268                 
269         
270         }
271         
272         LeaveFunction("DecodeHeader");
273         return 0;
274 }
275
276
277 int InitWaitHeaders(int ThreadCount)
278 {
279         int I,I2;
280
281         EnterFunction("InitWaitHeaders");
282         I=0;    
283         while (I<ThreadCount)
284         {
285                 Buffer[I] = (char*)get_free_page((int)GFP_KERNEL);
286                 if (Buffer[I] == NULL) 
287                 {
288                         printk(KERN_CRIT "kHTTPd: Not enough memory for basic needs\n");
289                         I2=0;
290                         while (I2<I-1)
291                         {
292                                 free_page( (unsigned long)Buffer[I2++]);
293                         }
294                         return -1;
295                 }
296                 I++;
297         }
298         
299         LeaveFunction("InitWaitHeaders");       
300         return 0;
301
302 }