/*
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/slab.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);
int Userspace(const int CPUNR)
{
struct http_request *CurrentRequest,**Prev,*Next;
EnterFunction("Userspace");
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)
{
if ((CurrentRequest->sock!=NULL)&&(CurrentRequest->sock->sk!=NULL))
{
remove_wait_queue(CurrentRequest->sock->sk->sleep,&(CurrentRequest->sleep));
}
}
if (AddSocketToAcceptQueue(CurrentRequest->sock,sysctl_khttpd_clientport)>=0)
{
(*Prev) = CurrentRequest->Next;
Next = CurrentRequest->Next;
sock_release(CurrentRequest->sock);
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;
LeaveFunction("StopUserspace");
}
/*
"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)
{
struct sock *sk;
EnterFunction("FindUserspace");
local_bh_disable();
sk = tcp_v4_lookup_listener(INADDR_ANY,Port,0);
local_bh_enable();
return sk;
}
static void dummy_destructor(struct open_request *req)
{
}
static struct or_calltable Dummy =
{
0,
NULL,
NULL,
&dummy_destructor,
NULL
};
static int AddSocketToAcceptQueue(struct socket *sock,const int Port)
{
struct open_request *req;
struct sock *sk, *nsk;
EnterFunction("AddSocketToAcceptQueue");
sk = FindUserspace((unsigned short)Port);
if (sk==NULL) /* No userspace-daemon found */
{
return -1;
}
lock_sock(sk);
if (sk->state != TCP_LISTEN || tcp_acceptq_is_full(sk))
{
release_sock(sk);
sock_put(sk);
return -1;
}
req = tcp_openreq_alloc();
if (req==NULL)
{
release_sock(sk);
sock_put(sk);
return -1;
}
nsk = sock->sk;
sock->sk = NULL;
sock->state = SS_UNCONNECTED;
req->class = &Dummy;
write_lock_bh(&nsk->callback_lock);
nsk->socket = NULL;
nsk->sleep = NULL;
write_unlock_bh(&nsk->callback_lock);
tcp_acceptq_queue(sk, req, nsk);
sk->data_ready(sk, 0);
release_sock(sk);
sock_put(sk);
LeaveFunction("AddSocketToAcceptQueue");
return +1;
}
void InitUserspace(const int CPUNR)
{
}