diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /net/khttpd/datasending.c | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'net/khttpd/datasending.c')
-rw-r--r-- | net/khttpd/datasending.c | 235 |
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"); +} |