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