summaryrefslogtreecommitdiffstats
path: root/net/khttpd/datasending.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /net/khttpd/datasending.c
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'net/khttpd/datasending.c')
-rw-r--r--net/khttpd/datasending.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/net/khttpd/datasending.c b/net/khttpd/datasending.c
new file mode 100644
index 000000000..d435af64d
--- /dev/null
+++ b/net/khttpd/datasending.c
@@ -0,0 +1,235 @@
+/*
+
+kHTTPd -- the next generation
+
+Send actual file-data to the connections
+
+*/
+/****************************************************************
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************/
+
+/*
+
+Purpose:
+
+DataSending does the actual sending of file-data to the socket.
+
+Note: Since asynchronous reads do not -yet- exists, this might block!
+
+Return value:
+ The number of requests that changed status (ie: made some progress)
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/locks.h>
+#include <linux/skbuff.h>
+
+#include <net/tcp.h>
+
+#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
+
+#include "structure.h"
+#include "prototypes.h"
+
+static char *Block[CONFIG_KHTTPD_NUMCPU];
+
+/*
+
+This send_actor is for use with do_generic_file_read (ie sendfile())
+It sends the data to the socket indicated by desc->buf.
+
+*/
+static int sock_send_actor(read_descriptor_t * desc, const char *area, unsigned long size)
+{
+ int written;
+ unsigned long count = desc->count;
+ struct socket *sock = (struct socket *) desc->buf;
+
+ if (size > count)
+ size = count;
+ written = SendBuffer_async(sock,(char *)area,size);
+
+ if (written < 0) {
+ desc->error = written;
+ written = 0;
+ }
+ desc->count = count - written;
+ desc->written += written;
+ return written;
+}
+
+
+
+
+int DataSending(const int CPUNR)
+{
+ struct http_request *CurrentRequest,**Prev;
+ int count = 0;
+
+ EnterFunction("DataSending");
+
+ Prev = &(threadinfo[CPUNR].DataSendingQueue);
+ CurrentRequest = threadinfo[CPUNR].DataSendingQueue;
+ while (CurrentRequest!=NULL)
+ {
+ int ReadSize,Space;
+ int retval;
+
+
+ /* First, test if the socket has any buffer-space left.
+ If not, no need to actually try to send something. */
+
+
+ Space = sock_wspace(CurrentRequest->sock->sk);
+
+ ReadSize = min(4*4096,CurrentRequest->FileLength - CurrentRequest->BytesSent);
+ ReadSize = min(ReadSize , Space );
+
+ if (ReadSize>0)
+ {
+ struct inode *inode;
+
+ inode = CurrentRequest->filp->f_dentry->d_inode;
+
+ if ( (inode!=NULL)&&(inode->i_op!=NULL)&&(inode->i_op->readpage!=NULL))
+ {
+ /* This does the actual transfer using sendfile */
+ read_descriptor_t desc;
+ loff_t *ppos;
+
+ CurrentRequest->filp->f_pos = CurrentRequest->BytesSent;
+
+ ppos = &CurrentRequest->filp->f_pos;
+
+ desc.written = 0;
+ desc.count = ReadSize;
+ desc.buf = (char *) CurrentRequest->sock;
+ desc.error = 0;
+ do_generic_file_read(CurrentRequest->filp, ppos, &desc, sock_send_actor);
+ if (desc.written>0)
+ {
+ CurrentRequest->BytesSent += desc.written;
+ count++;
+ }
+ }
+ else /* FS doesn't support sendfile() */
+ {
+ mm_segment_t oldfs;
+ CurrentRequest->filp->f_pos = CurrentRequest->BytesSent;
+
+ oldfs = get_fs(); set_fs(KERNEL_DS);
+ retval = CurrentRequest->filp->f_op->read(CurrentRequest->filp, Block[CPUNR], ReadSize, &CurrentRequest->filp->f_pos);
+ set_fs(oldfs);
+
+ if (retval>0)
+ {
+ retval = SendBuffer_async(CurrentRequest->sock,Block[CPUNR],(size_t)retval);
+ if (retval>0)
+ {
+ CurrentRequest->BytesSent += retval;
+ count++;
+ }
+ }
+ }
+
+ }
+
+ /*
+ If end-of-file or closed connection: Finish this request
+ by moving it to the "logging" queue.
+ */
+ if ((CurrentRequest->BytesSent>=CurrentRequest->FileLength)||
+ (CurrentRequest->sock->sk->state!=TCP_ESTABLISHED
+ && CurrentRequest->sock->sk->state!=TCP_CLOSE_WAIT))
+ {
+ struct http_request *Next;
+ Next = CurrentRequest->Next;
+
+ lock_sock(CurrentRequest->sock->sk);
+ if (CurrentRequest->sock->sk->state == TCP_ESTABLISHED ||
+ CurrentRequest->sock->sk->state == TCP_CLOSE_WAIT)
+ {
+ CurrentRequest->sock->sk->nonagle = 0;
+ tcp_push_pending_frames(CurrentRequest->sock->sk,&(CurrentRequest->sock->sk->tp_pinfo.af_tcp));
+ }
+ release_sock(CurrentRequest->sock->sk);
+
+ (*Prev) = CurrentRequest->Next;
+
+ CurrentRequest->Next = threadinfo[CPUNR].LoggingQueue;
+ threadinfo[CPUNR].LoggingQueue = CurrentRequest;
+
+ CurrentRequest = Next;
+ continue;
+
+ }
+
+
+ Prev = &(CurrentRequest->Next);
+ CurrentRequest = CurrentRequest->Next;
+ }
+
+ LeaveFunction("DataSending");
+ return count;
+}
+
+int InitDataSending(int ThreadCount)
+{
+ int I,I2;
+
+ EnterFunction("InitDataSending");
+ I=0;
+ while (I<ThreadCount)
+ {
+ Block[I] = (char*)get_free_page((int)GFP_KERNEL);
+ if (Block[I] == NULL)
+ {
+ I2=0;
+ while (I2<I-1)
+ {
+ free_page((unsigned long)Block[I2++]);
+ }
+ LeaveFunction("InitDataSending - abort");
+ return -1;
+ }
+ I++;
+ }
+ LeaveFunction("InitDataSending");
+ return 0;
+}
+
+void StopDataSending(const int CPUNR)
+{
+ struct http_request *CurrentRequest,*Next;
+
+ EnterFunction("StopDataSending");
+ CurrentRequest = threadinfo[CPUNR].DataSendingQueue;
+
+ while (CurrentRequest!=NULL)
+ {
+ Next = CurrentRequest->Next;
+ CleanUpRequest(CurrentRequest);
+ CurrentRequest=Next;
+ }
+
+ threadinfo[CPUNR].DataSendingQueue = NULL;
+
+ free_page( (unsigned long)Block[CPUNR]);
+ LeaveFunction("StopDataSending");
+}