/*
|
/*
|
|
|
kHTTPd -- the next generation
|
kHTTPd -- the next generation
|
|
|
Pass connections to userspace-daemons
|
Pass connections to userspace-daemons
|
|
|
*/
|
*/
|
/****************************************************************
|
/****************************************************************
|
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
* the Free Software Foundation; either version 2, or (at your option)
|
* the Free Software Foundation; either version 2, or (at your option)
|
* any later version.
|
* any later version.
|
*
|
*
|
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
*
|
*
|
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
*
|
*
|
****************************************************************/
|
****************************************************************/
|
|
|
/*
|
/*
|
|
|
Purpose:
|
Purpose:
|
|
|
Userspace() hands all requests in the queue to the userspace-daemon, if
|
Userspace() hands all requests in the queue to the userspace-daemon, if
|
such beast exists.
|
such beast exists.
|
|
|
Return value:
|
Return value:
|
The number of requests that changed status
|
The number of requests that changed status
|
*/
|
*/
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
|
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/slab.h>
|
#include <linux/slab.h>
|
#include <linux/net.h>
|
#include <linux/net.h>
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
#include <linux/smp_lock.h>
|
#include <linux/smp_lock.h>
|
#include <linux/un.h>
|
#include <linux/un.h>
|
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
#include <linux/wait.h>
|
#include <linux/wait.h>
|
|
|
#include <net/ip.h>
|
#include <net/ip.h>
|
#include <net/sock.h>
|
#include <net/sock.h>
|
#include <net/tcp.h>
|
#include <net/tcp.h>
|
|
|
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
#include <asm/semaphore.h>
|
#include <asm/semaphore.h>
|
#include <asm/processor.h>
|
#include <asm/processor.h>
|
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
|
|
#include <linux/file.h>
|
#include <linux/file.h>
|
|
|
|
|
#include "structure.h"
|
#include "structure.h"
|
#include "prototypes.h"
|
#include "prototypes.h"
|
#include "sysctl.h"
|
#include "sysctl.h"
|
|
|
/* prototypes of local, static functions */
|
/* prototypes of local, static functions */
|
static int AddSocketToAcceptQueue(struct socket *sock,const int Port);
|
static int AddSocketToAcceptQueue(struct socket *sock,const int Port);
|
|
|
|
|
int Userspace(const int CPUNR)
|
int Userspace(const int CPUNR)
|
{
|
{
|
struct http_request *CurrentRequest,**Prev,*Next;
|
struct http_request *CurrentRequest,**Prev,*Next;
|
|
|
EnterFunction("Userspace");
|
EnterFunction("Userspace");
|
|
|
|
|
|
|
|
|
CurrentRequest = threadinfo[CPUNR].UserspaceQueue;
|
CurrentRequest = threadinfo[CPUNR].UserspaceQueue;
|
Prev = &(threadinfo[CPUNR].UserspaceQueue);
|
Prev = &(threadinfo[CPUNR].UserspaceQueue);
|
|
|
while (CurrentRequest!=NULL)
|
while (CurrentRequest!=NULL)
|
{
|
{
|
|
|
/* Clean-up the waitqueue of the socket.. Bad things happen if
|
/* Clean-up the waitqueue of the socket.. Bad things happen if
|
this is forgotten. */
|
this is forgotten. */
|
if (CurrentRequest->sock!=NULL)
|
if (CurrentRequest->sock!=NULL)
|
{
|
{
|
if ((CurrentRequest->sock!=NULL)&&(CurrentRequest->sock->sk!=NULL))
|
if ((CurrentRequest->sock!=NULL)&&(CurrentRequest->sock->sk!=NULL))
|
{
|
{
|
remove_wait_queue(CurrentRequest->sock->sk->sleep,&(CurrentRequest->sleep));
|
remove_wait_queue(CurrentRequest->sock->sk->sleep,&(CurrentRequest->sleep));
|
}
|
}
|
}
|
}
|
|
|
|
|
if (AddSocketToAcceptQueue(CurrentRequest->sock,sysctl_khttpd_clientport)>=0)
|
if (AddSocketToAcceptQueue(CurrentRequest->sock,sysctl_khttpd_clientport)>=0)
|
{
|
{
|
|
|
(*Prev) = CurrentRequest->Next;
|
(*Prev) = CurrentRequest->Next;
|
Next = CurrentRequest->Next;
|
Next = CurrentRequest->Next;
|
|
|
|
|
sock_release(CurrentRequest->sock);
|
sock_release(CurrentRequest->sock);
|
CurrentRequest->sock = NULL; /* We no longer own it */
|
CurrentRequest->sock = NULL; /* We no longer own it */
|
|
|
CleanUpRequest(CurrentRequest);
|
CleanUpRequest(CurrentRequest);
|
|
|
CurrentRequest = Next;
|
CurrentRequest = Next;
|
continue;
|
continue;
|
|
|
}
|
}
|
else /* No userspace-daemon present, or other problems with it */
|
else /* No userspace-daemon present, or other problems with it */
|
{
|
{
|
(*Prev) = CurrentRequest->Next;
|
(*Prev) = CurrentRequest->Next;
|
Next = CurrentRequest->Next;
|
Next = CurrentRequest->Next;
|
|
|
Send403(CurrentRequest->sock); /* Sorry, no go... */
|
Send403(CurrentRequest->sock); /* Sorry, no go... */
|
|
|
CleanUpRequest(CurrentRequest);
|
CleanUpRequest(CurrentRequest);
|
|
|
CurrentRequest = Next;
|
CurrentRequest = Next;
|
continue;
|
continue;
|
|
|
}
|
}
|
|
|
|
|
Prev = &(CurrentRequest->Next);
|
Prev = &(CurrentRequest->Next);
|
CurrentRequest = CurrentRequest->Next;
|
CurrentRequest = CurrentRequest->Next;
|
}
|
}
|
|
|
LeaveFunction("Userspace");
|
LeaveFunction("Userspace");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void StopUserspace(const int CPUNR)
|
void StopUserspace(const int CPUNR)
|
{
|
{
|
struct http_request *CurrentRequest,*Next;
|
struct http_request *CurrentRequest,*Next;
|
|
|
EnterFunction("StopUserspace");
|
EnterFunction("StopUserspace");
|
CurrentRequest = threadinfo[CPUNR].UserspaceQueue;
|
CurrentRequest = threadinfo[CPUNR].UserspaceQueue;
|
|
|
while (CurrentRequest!=NULL)
|
while (CurrentRequest!=NULL)
|
{
|
{
|
Next= CurrentRequest->Next;
|
Next= CurrentRequest->Next;
|
CleanUpRequest(CurrentRequest);
|
CleanUpRequest(CurrentRequest);
|
CurrentRequest=Next;
|
CurrentRequest=Next;
|
}
|
}
|
threadinfo[CPUNR].UserspaceQueue = NULL;
|
threadinfo[CPUNR].UserspaceQueue = NULL;
|
|
|
LeaveFunction("StopUserspace");
|
LeaveFunction("StopUserspace");
|
}
|
}
|
|
|
|
|
/*
|
/*
|
"FindUserspace" returns the struct sock of the userspace-daemon, so that we can
|
"FindUserspace" returns the struct sock of the userspace-daemon, so that we can
|
"drop" our request in the accept-queue
|
"drop" our request in the accept-queue
|
*/
|
*/
|
|
|
static struct sock *FindUserspace(const unsigned short Port)
|
static struct sock *FindUserspace(const unsigned short Port)
|
{
|
{
|
struct sock *sk;
|
struct sock *sk;
|
|
|
EnterFunction("FindUserspace");
|
EnterFunction("FindUserspace");
|
|
|
local_bh_disable();
|
local_bh_disable();
|
sk = tcp_v4_lookup_listener(INADDR_ANY,Port,0);
|
sk = tcp_v4_lookup_listener(INADDR_ANY,Port,0);
|
local_bh_enable();
|
local_bh_enable();
|
return sk;
|
return sk;
|
}
|
}
|
|
|
static void dummy_destructor(struct open_request *req)
|
static void dummy_destructor(struct open_request *req)
|
{
|
{
|
}
|
}
|
|
|
static struct or_calltable Dummy =
|
static struct or_calltable Dummy =
|
{
|
{
|
0,
|
0,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
&dummy_destructor,
|
&dummy_destructor,
|
NULL
|
NULL
|
};
|
};
|
|
|
static int AddSocketToAcceptQueue(struct socket *sock,const int Port)
|
static int AddSocketToAcceptQueue(struct socket *sock,const int Port)
|
{
|
{
|
struct open_request *req;
|
struct open_request *req;
|
struct sock *sk, *nsk;
|
struct sock *sk, *nsk;
|
|
|
EnterFunction("AddSocketToAcceptQueue");
|
EnterFunction("AddSocketToAcceptQueue");
|
|
|
|
|
sk = FindUserspace((unsigned short)Port);
|
sk = FindUserspace((unsigned short)Port);
|
|
|
if (sk==NULL) /* No userspace-daemon found */
|
if (sk==NULL) /* No userspace-daemon found */
|
{
|
{
|
return -1;
|
return -1;
|
}
|
}
|
|
|
lock_sock(sk);
|
lock_sock(sk);
|
|
|
if (sk->state != TCP_LISTEN || tcp_acceptq_is_full(sk))
|
if (sk->state != TCP_LISTEN || tcp_acceptq_is_full(sk))
|
{
|
{
|
release_sock(sk);
|
release_sock(sk);
|
sock_put(sk);
|
sock_put(sk);
|
return -1;
|
return -1;
|
}
|
}
|
|
|
req = tcp_openreq_alloc();
|
req = tcp_openreq_alloc();
|
|
|
if (req==NULL)
|
if (req==NULL)
|
{
|
{
|
release_sock(sk);
|
release_sock(sk);
|
sock_put(sk);
|
sock_put(sk);
|
return -1;
|
return -1;
|
}
|
}
|
|
|
nsk = sock->sk;
|
nsk = sock->sk;
|
sock->sk = NULL;
|
sock->sk = NULL;
|
sock->state = SS_UNCONNECTED;
|
sock->state = SS_UNCONNECTED;
|
|
|
req->class = &Dummy;
|
req->class = &Dummy;
|
write_lock_bh(&nsk->callback_lock);
|
write_lock_bh(&nsk->callback_lock);
|
nsk->socket = NULL;
|
nsk->socket = NULL;
|
nsk->sleep = NULL;
|
nsk->sleep = NULL;
|
write_unlock_bh(&nsk->callback_lock);
|
write_unlock_bh(&nsk->callback_lock);
|
|
|
tcp_acceptq_queue(sk, req, nsk);
|
tcp_acceptq_queue(sk, req, nsk);
|
|
|
sk->data_ready(sk, 0);
|
sk->data_ready(sk, 0);
|
|
|
release_sock(sk);
|
release_sock(sk);
|
sock_put(sk);
|
sock_put(sk);
|
|
|
LeaveFunction("AddSocketToAcceptQueue");
|
LeaveFunction("AddSocketToAcceptQueue");
|
|
|
return +1;
|
return +1;
|
|
|
|
|
|
|
}
|
}
|
|
|
void InitUserspace(const int CPUNR)
|
void InitUserspace(const int CPUNR)
|
{
|
{
|
}
|
}
|
|
|
|
|
|
|