patch-2.3.14 linux/net/khttpd/waitheaders.c

Next file: linux/net/netrom/af_netrom.c
Previous file: linux/net/khttpd/userspace.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.13/linux/net/khttpd/waitheaders.c linux/net/khttpd/waitheaders.c
@@ -0,0 +1,300 @@
+/*
+
+kHTTPd -- the next generation
+
+Wait for headers on the accepted 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:
+
+WaitForHeaders polls all connections in "WaitForHeaderQueue" to see if
+headers have arived. If so, the headers are decoded and the request is
+moved to either the "SendingDataQueue" or the "UserspaceQueue".
+
+Return value:
+	The number of requests that changed status
+*/
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/smp_lock.h>
+#include <linux/file.h>
+
+#include <asm/uaccess.h>
+
+#include "structure.h"
+#include "prototypes.h"
+
+static	char			*Buffer[CONFIG_KHTTPD_NUMCPU];
+
+
+static int DecodeHeader(const int CPUNR, struct http_request *Request);
+
+
+int WaitForHeaders(const int CPUNR)
+{
+	struct http_request *CurrentRequest,**Prev;
+	struct sock *sk;
+	int count = 0;
+	
+	EnterFunction("WaitForHeaders");
+	
+	CurrentRequest = threadinfo[CPUNR].WaitForHeaderQueue;
+	
+	Prev = &(threadinfo[CPUNR].WaitForHeaderQueue);
+	
+	while (CurrentRequest!=NULL)
+	{
+		
+		/* If the connection is lost, remove from queue */
+		
+		lock_sock(CurrentRequest->sock->sk);
+		if (CurrentRequest->sock->sk->state!=TCP_ESTABLISHED)
+		{
+			struct http_request *Next;
+			
+			Next = CurrentRequest->Next;
+			
+			*Prev = CurrentRequest->Next;
+			CurrentRequest->Next = NULL;
+			release_sock(CurrentRequest->sock->sk);
+			
+		
+			CleanUpRequest(CurrentRequest);
+			CurrentRequest = Next;
+			continue;
+		}
+		
+		
+		
+		/* If data pending, take action */	
+		
+		sk = CurrentRequest->sock->sk;
+		
+		if (atomic_read(&(sk->rmem_alloc))>0) /* Do we have data ? */
+		{
+			struct http_request *Next;
+			
+			
+			release_sock(CurrentRequest->sock->sk);
+			
+			/* Decode header */
+			
+			if (DecodeHeader(CPUNR,CurrentRequest)<0)
+			{
+				CurrentRequest = CurrentRequest->Next;
+				continue;
+			} 
+			
+			
+			/* Remove from WaitForHeaderQueue */		
+			
+			Next= CurrentRequest->Next;
+		
+			*Prev = Next;
+			count++;
+			
+			/* Add to either the UserspaceQueue or the DataSendingQueue */
+			
+			if (CurrentRequest->IsForUserspace!=0)
+			{
+				CurrentRequest->Next = threadinfo[CPUNR].UserspaceQueue;
+				threadinfo[CPUNR].UserspaceQueue = CurrentRequest;	
+			} else
+			{
+				CurrentRequest->Next = threadinfo[CPUNR].DataSendingQueue;
+				threadinfo[CPUNR].DataSendingQueue = CurrentRequest;	
+			} 	
+			
+			CurrentRequest = Next;
+			continue;
+		
+		}	
+		else
+			release_sock(CurrentRequest->sock->sk);
+
+		
+		Prev = &(CurrentRequest->Next);
+		CurrentRequest = CurrentRequest->Next;
+	}
+
+	LeaveFunction("WaitHeaders");
+	return count;
+}
+
+void StopWaitingForHeaders(const int CPUNR)
+{
+	struct http_request *CurrentRequest,*Next;
+	
+	EnterFunction("StopWaitingForHeaders");
+	CurrentRequest = threadinfo[CPUNR].WaitForHeaderQueue;
+
+	while (CurrentRequest!=NULL)
+	{
+		Next = CurrentRequest->Next;
+		CleanUpRequest(CurrentRequest);
+		CurrentRequest=Next;		
+	}
+	
+	threadinfo[CPUNR].WaitForHeaderQueue = NULL; /* The queue is empty now */
+	
+	free_page((unsigned long)Buffer[CPUNR]);
+	Buffer[CPUNR]=NULL;
+	
+	EnterFunction("StopWaitingForHeaders");
+}
+
+
+/* 
+
+DecodeHeader peeks at the TCP/IP data, determines what the request is, 
+fills the request-structure and sends the HTTP-header when apropriate.
+
+*/
+
+static int DecodeHeader(const int CPUNR, struct http_request *Request)
+{
+	struct msghdr		msg;
+	struct iovec		iov;
+	int			len;
+
+	mm_segment_t		oldfs;
+	
+	EnterFunction("DecodeHeader");
+	
+	/* First, read the data */
+
+	msg.msg_name     = 0;
+	msg.msg_namelen  = 0;
+	msg.msg_iov	 = &iov;
+	msg.msg_iovlen   = 1;
+	msg.msg_control  = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags    = 0;
+	
+	msg.msg_iov->iov_base = &Buffer[CPUNR][0];
+	msg.msg_iov->iov_len  = (size_t)4095;
+	
+	len = 0;
+	oldfs = get_fs(); set_fs(KERNEL_DS);
+	/* 4095 leaves a "0" to terminate the string */
+	
+	len = sock_recvmsg(Request->sock,&msg,4095,MSG_PEEK);
+	set_fs(oldfs);
+
+	if (len>=4094) /* BIG header, we cannot decode it so leave it to userspace */	
+	{
+		Request->IsForUserspace = 1;
+		return 0;
+	}
+	
+	/* Then, decode the header */
+	
+	
+	ParseHeader(Buffer[CPUNR],len,Request);
+	
+	Request->filp = OpenFileForSecurity(Request->FileName);
+	
+	
+	Request->MimeType = ResolveMimeType(Request->FileName,&Request->MimeLength);
+	
+	
+	if (Request->MimeType==NULL) /* Unknown mime-type */
+	{
+		if (Request->filp!=NULL)
+		{
+			fput(Request->filp);
+			Request->filp = NULL;
+		}
+		Request->IsForUserspace = 1;
+		
+		return 0;
+	}
+
+	if (Request->filp==NULL)
+	{
+		Request->IsForUserspace = 1;
+		return 0;
+	}
+	else
+	if ((Request->filp->f_dentry!=NULL)&&(Request->filp->f_dentry->d_inode!=NULL))
+	{
+		Request->FileLength = (int)Request->filp->f_dentry->d_inode->i_size;
+		Request->Time       = Request->filp->f_dentry->d_inode->i_mtime;
+		Request->IMS_Time   = mimeTime_to_UnixTime(Request->IMS);
+		sprintf(Request->LengthS,"%i",Request->FileLength);
+		time_Unix2RFC(min(Request->Time,CurrentTime_i),Request->TimeS);
+   	        /* The min() is required by rfc1945, section 10.10:
+   	           It is not allowed to send a filetime in the future */
+
+		if (Request->IMS_Time>Request->Time)
+		{	/* Not modified since last time */
+			Send304(Request->sock);
+			Request->FileLength=0;
+		}
+		else   /* Normal Case */
+		{
+			Request->sock->sk->nonagle = 2; /* this is TCP_CORK */
+			if (Request->HTTPVER!=9)  /* HTTP/0.9 doesn't allow a header */
+				SendHTTPHeader(Request);
+		}
+		
+	
+	} else 
+	{
+		/* Ehhh... */
+		
+		printk(KERN_CRIT "kHTTPd: Unexpected filesystem response\n");
+		return -1;	
+	}
+	
+	LeaveFunction("DecodeHeader");
+	return 0;
+}
+
+
+int InitWaitHeaders(int ThreadCount)
+{
+	int I,I2;
+
+	EnterFunction("InitWaitHeaders");
+	I=0;	
+	while (I<ThreadCount)
+	{
+		Buffer[I] = (char*)get_free_page((int)GFP_KERNEL);
+		if (Buffer[I] == NULL) 
+		{
+			printk(KERN_CRIT "kHTTPd: Not enough memory for basic needs\n");
+			I2=0;
+			while (I2<I-1)
+			{
+				free_page( (unsigned long)Buffer[I2++]);
+			}
+			return -1;
+		}
+		I++;
+	}
+	
+	LeaveFunction("InitWaitHeaders");	
+	return 0;
+
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)