patch-2.3.14 linux/net/khttpd/userspace.c
Next file: linux/net/khttpd/waitheaders.c
Previous file: linux/net/khttpd/sysctl.h
Back to the patch index
Back to the overall index
- Lines: 309
- Date:
Wed Aug 18 09:50:44 1999
- Orig file:
v2.3.13/linux/net/khttpd/userspace.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.13/linux/net/khttpd/userspace.c linux/net/khttpd/userspace.c
@@ -0,0 +1,308 @@
+/*
+
+kHTTPd -- the next generation
+
+Pass connections to userspace-daemons
+
+*/
+/****************************************************************
+ * 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:
+
+Userspace() hands all requests in the queue to the userspace-daemon, if
+such beast exists.
+
+Return value:
+ The number of requests that changed status
+*/
+#include <linux/kernel.h>
+
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/net.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/smp_lock.h>
+#include <linux/un.h>
+#include <linux/unistd.h>
+#include <linux/wait.h>
+
+#include <net/ip.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+#include <linux/file.h>
+
+
+#include "structure.h"
+#include "prototypes.h"
+#include "sysctl.h"
+
+/* prototypes of local, static functions */
+static int AddSocketToAcceptQueue(struct socket *sock,const int Port);
+static void purge_delayed_release(int CPUNR, int All);
+
+static struct khttpd_delayed_release *delayed_release[CONFIG_KHTTPD_NUMCPU];
+
+
+int Userspace(const int CPUNR)
+{
+ struct http_request *CurrentRequest,**Prev,*Next;
+
+ EnterFunction("Userspace");
+
+
+ purge_delayed_release(CPUNR,0);
+
+
+ CurrentRequest = threadinfo[CPUNR].UserspaceQueue;
+ Prev = &(threadinfo[CPUNR].UserspaceQueue);
+
+ while (CurrentRequest!=NULL)
+ {
+
+ /* Clean-up the waitqueue of the socket.. Bad things happen if
+ this is forgotten. */
+ if (CurrentRequest->sock!=NULL)
+ {
+ lock_kernel(); /* Just to be sure (2.3.11) -- Check this for 2.3.13 */
+ if ((CurrentRequest->sock!=NULL)&&(CurrentRequest->sock->sk!=NULL))
+ {
+ /* Some TCP/IP functions call waitqueue-operations without
+ holding the sock-lock. I am not that brave.
+ */
+ lock_sock(CurrentRequest->sock->sk);
+ remove_wait_queue(CurrentRequest->sock->sk->sleep,&(CurrentRequest->sleep));
+ release_sock(CurrentRequest->sock->sk);
+ }
+ unlock_kernel();
+ }
+
+
+ if (AddSocketToAcceptQueue(CurrentRequest->sock,sysctl_khttpd_clientport)>=0)
+ {
+ struct khttpd_delayed_release *delayed;
+
+ (*Prev) = CurrentRequest->Next;
+ Next = CurrentRequest->Next;
+
+
+ delayed = kmalloc(sizeof(struct khttpd_delayed_release),GFP_KERNEL);
+ if (delayed==NULL)
+ {
+ sock_release(CurrentRequest->sock);
+ } else
+ {
+ /* Schedule socket-deletion 120 seconds from now */
+ delayed->Next = delayed_release[CPUNR];
+ delayed->timeout = jiffies+120*HZ;
+ delayed->sock = CurrentRequest->sock;
+ delayed_release[CPUNR]=delayed;
+ }
+
+
+ CurrentRequest->sock = NULL; /* We no longer own it */
+
+ CleanUpRequest(CurrentRequest);
+
+ CurrentRequest = Next;
+ continue;
+
+ }
+ else /* No userspace-daemon present, or other problems with it */
+ {
+ (*Prev) = CurrentRequest->Next;
+ Next = CurrentRequest->Next;
+
+ Send403(CurrentRequest->sock); /* Sorry, no go... */
+
+ CleanUpRequest(CurrentRequest);
+
+ CurrentRequest = Next;
+ continue;
+
+ }
+
+
+ Prev = &(CurrentRequest->Next);
+ CurrentRequest = CurrentRequest->Next;
+ }
+
+ LeaveFunction("Userspace");
+ return 0;
+}
+
+void StopUserspace(const int CPUNR)
+{
+ struct http_request *CurrentRequest,*Next;
+
+ EnterFunction("StopUserspace");
+ CurrentRequest = threadinfo[CPUNR].UserspaceQueue;
+
+ while (CurrentRequest!=NULL)
+ {
+ Next= CurrentRequest->Next;
+ CleanUpRequest(CurrentRequest);
+ CurrentRequest=Next;
+ }
+ threadinfo[CPUNR].UserspaceQueue = NULL;
+ purge_delayed_release(CPUNR,1);
+
+ LeaveFunction("StopUserspace");
+}
+
+extern struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int dif);
+
+
+/*
+ "FindUserspace" returns the struct sock of the userspace-daemon, so that we can
+ "drop" our request in the accept-queue
+*/
+static struct sock *FindUserspace(const unsigned short Port)
+{
+ EnterFunction("FindUserspace");
+
+ return tcp_v4_lookup_listener(INADDR_ANY,Port,0);
+
+ return NULL;
+}
+
+static void dummy_destructor(struct open_request *req)
+{
+}
+
+static struct or_calltable Dummy =
+{
+ NULL,
+ &dummy_destructor,
+ NULL
+};
+
+#define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */
+
+static int AddSocketToAcceptQueue(struct socket *sock,const int Port)
+{
+ struct open_request *req;
+ struct sock *sk;
+ struct tcp_opt *tp;
+
+ EnterFunction("AddSocketToAcceptQueue");
+
+
+ sk = FindUserspace((unsigned short)Port);
+
+ if (sk==NULL) /* No userspace-daemon found */
+ {
+ return -1;
+ }
+
+ lock_sock(sk);
+
+ if (BACKLOG(sk)>128) /* To many pending requests */
+ {
+ return -1;
+ }
+ req = tcp_openreq_alloc();
+
+ if (req==NULL)
+ {
+ release_sock(sk);
+ return -1;
+ }
+
+ req->sk = sock->sk;
+ sock->sk = NULL;
+ sock->state = SS_UNCONNECTED;
+
+
+ if (req->sk==NULL)
+ (void)printk(KERN_CRIT "kHTTPd: Woops, the socket-buffer is NULL \n");
+
+ req->class = &Dummy;
+ req->sk->socket = NULL;
+ req->expires = jiffies + TCP_TIMEOUT_INIT;
+
+ tp =&(sk->tp_pinfo.af_tcp);
+ sk->ack_backlog++;
+
+ tcp_inc_slow_timer(TCP_SLT_SYNACK);
+ tcp_synq_queue(tp,req);
+
+ if (!sk->dead)
+ wake_up_interruptible(sk->sleep);
+
+ release_sock(sk);
+
+ LeaveFunction("AddSocketToAcceptQueue");
+
+ return +1;
+
+
+
+}
+
+void InitUserspace(const int CPUNR)
+{
+ int I;
+
+ I=0;
+ while (I<CPUNR)
+ delayed_release[I++]=NULL;
+}
+
+
+/*
+
+This function checks in the delayed_release queue for candidate-sockets
+to be released. If All != 0, all sockets are released. This is required for
+unloading.
+
+*/
+static void purge_delayed_release(const int CPUNR,int All)
+{
+ struct khttpd_delayed_release *Current,*Next,**Prev;
+
+ Prev = &(delayed_release[CPUNR]);
+
+ Current = delayed_release[CPUNR];
+ while (Current!=NULL)
+ {
+ if ((Current->timeout<=jiffies)||(All))
+ {
+ Next = Current->Next;
+
+ *Prev = Next;
+
+ sock_release(Current->sock);
+ kfree(Current);
+
+ Current = Next;
+ continue;
+ }
+
+ Prev = &Current->Next;
+ Current=Current->Next;
+ }
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)