make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / net / khttpd / datasending.c
1 /*
2
3 kHTTPd -- the next generation
4
5 Send actual file-data to the 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 DataSending does the actual sending of file-data to the socket.
30
31 Note: Since asynchronous reads do not -yet- exists, this might block!
32
33 Return value:
34         The number of requests that changed status (ie: made some progress)
35 */
36
37 #include <linux/config.h>
38 #include <linux/kernel.h>
39 #include <linux/locks.h>
40 #include <linux/skbuff.h>
41
42 #include <net/tcp.h>
43
44 #include <asm/uaccess.h>
45 #include <linux/smp_lock.h>
46
47 #include "structure.h"
48 #include "prototypes.h"
49
50 static  char    *Block[CONFIG_KHTTPD_NUMCPU];
51
52 /*
53
54 This send_actor is for use with do_generic_file_read (ie sendfile())
55 It sends the data to the socket indicated by desc->buf.
56
57 */
58 static int sock_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
59 {
60         int written;
61         char *kaddr;
62         unsigned long count = desc->count;
63         struct socket *sock = (struct socket *) desc->buf;
64         mm_segment_t old_fs;
65
66         if (size > count)
67                 size = count;
68         old_fs = get_fs();
69         set_fs(KERNEL_DS);
70
71         kaddr = kmap(page);
72         written = SendBuffer_async(sock, kaddr + offset, size);
73         kunmap(page);
74         set_fs(old_fs);
75         if (written < 0) {
76                 desc->error = written;
77                 written = 0;
78         }
79         desc->count = count - written;
80         desc->written += written;
81         return written;
82 }
83
84
85
86
87 int DataSending(const int CPUNR)
88 {
89         struct http_request *CurrentRequest,**Prev;
90         int count = 0;
91         
92         EnterFunction("DataSending");
93         
94         Prev = &(threadinfo[CPUNR].DataSendingQueue);
95         CurrentRequest = threadinfo[CPUNR].DataSendingQueue;
96         while (CurrentRequest!=NULL)
97         {
98                 int ReadSize,Space;
99                 int retval;
100
101
102                 /* First, test if the socket has any buffer-space left.
103                    If not, no need to actually try to send something.  */
104                   
105                 
106                 Space = sock_wspace(CurrentRequest->sock->sk);
107                 
108                 ReadSize = min_t(int, 4 * 4096, CurrentRequest->FileLength - CurrentRequest->BytesSent);
109                 ReadSize = min_t(int, ReadSize, Space);
110
111                 if (ReadSize>0)
112                 {                       
113                         struct inode *inode;
114                         
115                         inode = CurrentRequest->filp->f_dentry->d_inode;
116                         
117                         if (inode->i_mapping->a_ops->readpage) {
118                                 /* This does the actual transfer using sendfile */              
119                                 read_descriptor_t desc;
120                                 loff_t *ppos;
121                 
122                                 CurrentRequest->filp->f_pos = CurrentRequest->BytesSent;
123
124                                 ppos = &CurrentRequest->filp->f_pos;
125
126                                 desc.written = 0;
127                                 desc.count = ReadSize;
128                                 desc.buf = (char *) CurrentRequest->sock;
129                                 desc.error = 0;
130                                 do_generic_file_read(CurrentRequest->filp, ppos, &desc, sock_send_actor);
131                                 if (desc.written>0)
132                                 {       
133                                         CurrentRequest->BytesSent += desc.written;
134                                         count++;
135                                 }                       
136                         } 
137                         else  /* FS doesn't support sendfile() */
138                         {
139                                 mm_segment_t oldfs;
140                                 CurrentRequest->filp->f_pos = CurrentRequest->BytesSent;
141                                 
142                                 oldfs = get_fs(); set_fs(KERNEL_DS);
143                                 retval = CurrentRequest->filp->f_op->read(CurrentRequest->filp, Block[CPUNR], ReadSize, &CurrentRequest->filp->f_pos);
144                                 set_fs(oldfs);
145                 
146                                 if (retval>0)
147                                 {
148                                         retval = SendBuffer_async(CurrentRequest->sock,Block[CPUNR],(size_t)retval);
149                                         if (retval>0)
150                                         {
151                                                 CurrentRequest->BytesSent += retval;
152                                                 count++;                                
153                                         }
154                                 }
155                         }
156                 
157                 }
158                 
159                 /* 
160                    If end-of-file or closed connection: Finish this request 
161                    by moving it to the "logging" queue. 
162                 */
163                 if ((CurrentRequest->BytesSent>=CurrentRequest->FileLength)||
164                     (CurrentRequest->sock->sk->state!=TCP_ESTABLISHED
165                      && CurrentRequest->sock->sk->state!=TCP_CLOSE_WAIT))
166                 {
167                         struct http_request *Next;
168                         Next = CurrentRequest->Next;
169
170                         lock_sock(CurrentRequest->sock->sk);
171                         if  (CurrentRequest->sock->sk->state == TCP_ESTABLISHED ||
172                              CurrentRequest->sock->sk->state == TCP_CLOSE_WAIT)
173                         {
174                                 CurrentRequest->sock->sk->tp_pinfo.af_tcp.nonagle = 0;
175                                 tcp_push_pending_frames(CurrentRequest->sock->sk,&(CurrentRequest->sock->sk->tp_pinfo.af_tcp));
176                         }
177                         release_sock(CurrentRequest->sock->sk);
178
179                         (*Prev) = CurrentRequest->Next;
180                         
181                         CurrentRequest->Next = threadinfo[CPUNR].LoggingQueue;
182                         threadinfo[CPUNR].LoggingQueue = CurrentRequest;        
183                                 
184                         CurrentRequest = Next;
185                         continue;
186                 
187                 }
188                 
189
190                 Prev = &(CurrentRequest->Next); 
191                 CurrentRequest = CurrentRequest->Next;
192         }
193         
194         LeaveFunction("DataSending");
195         return count;
196 }
197
198 int InitDataSending(int ThreadCount)
199 {
200         int I,I2;
201         
202         EnterFunction("InitDataSending");
203         I=0;
204         while (I<ThreadCount)
205         {
206                 Block[I] = (char*)get_free_page((int)GFP_KERNEL);
207                 if (Block[I] == NULL) 
208                 {
209                         I2=0;
210                         while (I2<I-1)
211                         {
212                                 free_page((unsigned long)Block[I2++]);
213                         }
214                         LeaveFunction("InitDataSending - abort");
215                         return -1;
216                 }
217                 I++;
218         }
219         LeaveFunction("InitDataSending");
220         return 0;               
221 }
222
223 void StopDataSending(const int CPUNR)
224 {
225         struct http_request *CurrentRequest,*Next;
226         
227         EnterFunction("StopDataSending");
228         CurrentRequest = threadinfo[CPUNR].DataSendingQueue;
229
230         while (CurrentRequest!=NULL)
231         {       
232                 Next = CurrentRequest->Next;
233                 CleanUpRequest(CurrentRequest);
234                 CurrentRequest=Next;            
235         }
236         
237         threadinfo[CPUNR].DataSendingQueue = NULL;
238
239         free_page( (unsigned long)Block[CPUNR]);
240         LeaveFunction("StopDataSending");
241 }