/* 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 #include #include #include #include #include #include #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, struct page *page, unsigned long offset, unsigned long size) { int written; char *kaddr; unsigned long count = desc->count; struct socket *sock = (struct socket *) desc->buf; mm_segment_t old_fs; if (size > count) size = count; old_fs = get_fs(); set_fs(KERNEL_DS); kaddr = kmap(page); written = SendBuffer_async(sock, kaddr + offset, size); kunmap(page); set_fs(old_fs); 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_t(int, 4 * 4096, CurrentRequest->FileLength - CurrentRequest->BytesSent); ReadSize = min_t(int, ReadSize, Space); if (ReadSize>0) { struct inode *inode; inode = CurrentRequest->filp->f_dentry->d_inode; if (inode->i_mapping->a_ops->readpage) { /* 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->tp_pinfo.af_tcp.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 (INext; CleanUpRequest(CurrentRequest); CurrentRequest=Next; } threadinfo[CPUNR].DataSendingQueue = NULL; free_page( (unsigned long)Block[CPUNR]); LeaveFunction("StopDataSending"); }