Import changeset
[linux-flexiantxendom0-3.2.10.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("WaitHeaders");
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         /* First, read the data */
182
183         msg.msg_name     = 0;
184         msg.msg_namelen  = 0;
185         msg.msg_iov      = &iov;
186         msg.msg_iovlen   = 1;
187         msg.msg_control  = NULL;
188         msg.msg_controllen = 0;
189         msg.msg_flags    = 0;
190         
191         msg.msg_iov->iov_base = &Buffer[CPUNR][0];
192         msg.msg_iov->iov_len  = (size_t)4095;
193         
194         len = 0;
195         oldfs = get_fs(); set_fs(KERNEL_DS);
196         /* 4095 leaves a "0" to terminate the string */
197         
198         len = sock_recvmsg(Request->sock,&msg,4095,MSG_PEEK);
199         set_fs(oldfs);
200
201         if (len<0) {
202                 /* WONDERFUL. NO COMMENTS. --ANK */
203                 Request->IsForUserspace = 1;
204                 return 0;
205         }
206
207         if (len>=4094) /* BIG header, we cannot decode it so leave it to userspace */   
208         {
209                 Request->IsForUserspace = 1;
210                 return 0;
211         }
212         
213         /* Then, decode the header */
214         
215         
216         ParseHeader(Buffer[CPUNR],len,Request);
217         
218         Request->filp = OpenFileForSecurity(Request->FileName);
219         
220         
221         Request->MimeType = ResolveMimeType(Request->FileName,&Request->MimeLength);
222         
223         
224         if (Request->MimeType==NULL) /* Unknown mime-type */
225         {
226                 if (Request->filp!=NULL)
227                 {
228                         fput(Request->filp);
229                         Request->filp = NULL;
230                 }
231                 Request->IsForUserspace = 1;
232                 
233                 return 0;
234         }
235
236         if (Request->filp==NULL)
237         {
238                 Request->IsForUserspace = 1;
239                 return 0;
240         }
241         else
242         {
243                 Request->FileLength = (int)Request->filp->f_dentry->d_inode->i_size;
244                 Request->Time       = Request->filp->f_dentry->d_inode->i_mtime;
245                 Request->IMS_Time   = mimeTime_to_UnixTime(Request->IMS);
246                 sprintf(Request->LengthS,"%i",Request->FileLength);
247                 time_Unix2RFC(min(Request->Time,CurrentTime_i),Request->TimeS);
248                 /* The min() is required by rfc1945, section 10.10:
249                    It is not allowed to send a filetime in the future */
250
251                 if (Request->IMS_Time>Request->Time)
252                 {       /* Not modified since last time */
253                         Send304(Request->sock);
254                         Request->FileLength=0;
255                 }
256                 else   /* Normal Case */
257                 {
258                         Request->sock->sk->tp_pinfo.af_tcp.nonagle = 2; /* this is TCP_CORK */
259                         if (Request->HTTPVER!=9)  /* HTTP/0.9 doesn't allow a header */
260                                 SendHTTPHeader(Request);
261                 }
262                 
263         
264         }
265         
266         LeaveFunction("DecodeHeader");
267         return 0;
268 }
269
270
271 int InitWaitHeaders(int ThreadCount)
272 {
273         int I,I2;
274
275         EnterFunction("InitWaitHeaders");
276         I=0;    
277         while (I<ThreadCount)
278         {
279                 Buffer[I] = (char*)get_free_page((int)GFP_KERNEL);
280                 if (Buffer[I] == NULL) 
281                 {
282                         printk(KERN_CRIT "kHTTPd: Not enough memory for basic needs\n");
283                         I2=0;
284                         while (I2<I-1)
285                         {
286                                 free_page( (unsigned long)Buffer[I2++]);
287                         }
288                         return -1;
289                 }
290                 I++;
291         }
292         
293         LeaveFunction("InitWaitHeaders");       
294         return 0;
295
296 }