datasending.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
- /*
- 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, 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 (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");
- }