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 */
sock_send_actor(read_descriptor_t * desc,struct page * page,unsigned long offset,unsigned long size)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
DataSending(const int CPUNR)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
InitDataSending(int ThreadCount)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
StopDataSending(const int CPUNR)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 }
242