[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[myserver-commit] [2950] Added class `ForkServer'.
From: |
Giuseppe Scrivano |
Subject: |
[myserver-commit] [2950] Added class `ForkServer'. |
Date: |
Sun, 09 Nov 2008 19:44:52 +0000 |
Revision: 2950
http://svn.sv.gnu.org/viewvc/?view=rev&root=myserver&revision=2950
Author: gscrivano
Date: 2008-11-09 19:44:52 +0000 (Sun, 09 Nov 2008)
Log Message:
-----------
Added class `ForkServer'. it is used in `ProcessServerManager' to spawn new
processes.
Modified Paths:
--------------
trunk/myserver/documentation/process_security.texi
trunk/myserver/include/base/process/Makefile.am
trunk/myserver/include/base/process/process.h
trunk/myserver/include/base/process/process_server_manager.h
trunk/myserver/src/base/process/Makefile.am
trunk/myserver/src/base/process/process.cpp
trunk/myserver/src/base/process/process_server_manager.cpp
trunk/myserver/src/http_handler/fastcgi/fastcgi.cpp
trunk/myserver/src/myserver.cpp
trunk/myserver/src/server/server.cpp
trunk/myserver/tests/Makefile.am
Added Paths:
-----------
trunk/myserver/include/base/process/fork_server.h
trunk/myserver/src/base/process/fork_server.cpp
trunk/myserver/tests/test_fork_server.cpp
Modified: trunk/myserver/documentation/process_security.texi
===================================================================
--- trunk/myserver/documentation/process_security.texi 2008-11-08 20:06:42 UTC
(rev 2949)
+++ trunk/myserver/documentation/process_security.texi 2008-11-09 19:44:52 UTC
(rev 2950)
@@ -1,5 +1,5 @@
@c -*-texinfo-*-
-On POSIX it is possible to change the MyServer process user identifier
+Under POSIX it is possible to change the MyServer process user identifier
and group identifier after it has bound the necessary ports (only the
root user can bind ports < 1024).
@@ -21,3 +21,19 @@
auto-reboot because it will not be possible to get back old
permissions.
address@hidden Fork Server
+In a POSIX environment the @code{fork} syscall is used to execute new
+processes. It clones the caller process keeping any open file or
+connection in the child process too. To avoid this problem a fork
+server is present in MyServer.
+The communication between the MyServer process and the
+fork server is done trought a socket. When MyServer wants to execute
+a new process two connections are opened to the fork server, for
+the stdin and stdout streams, and the fork server will fork itself and
+execute the process using these connections as its I/O streams.
+
+It is not configurable in any configuration file as the MyServer
+process is forked to create it before any file or connection is
+active.
+
+It is enabled passing the @code{-f} switch to the myserver process.
Modified: trunk/myserver/include/base/process/Makefile.am
===================================================================
--- trunk/myserver/include/base/process/Makefile.am 2008-11-08 20:06:42 UTC
(rev 2949)
+++ trunk/myserver/include/base/process/Makefile.am 2008-11-09 19:44:52 UTC
(rev 2950)
@@ -1,4 +1,4 @@
processincludedir=$(includedir)/myserver/include/base/process
-processinclude_HEADERS = process.h process_server_manager.h
+processinclude_HEADERS = fork_server.h process.h process_server_manager.h
SUBDIRS =
Added: trunk/myserver/include/base/process/fork_server.h
===================================================================
--- trunk/myserver/include/base/process/fork_server.h
(rev 0)
+++ trunk/myserver/include/base/process/fork_server.h 2008-11-09 19:44:52 UTC
(rev 2950)
@@ -0,0 +1,62 @@
+/*
+ MyServer
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <unistd.h>
+#include <include/base/socket/socket.h>
+#include <include/base/sync/mutex.h>
+
+#ifndef FORK_SERVER_H
+#define FORK_SERVER_H
+
+struct StartProcInfo;
+
+class ForkServer
+{
+ public:
+ const static int FLAG_USE_OUT = 1;
+ const static int FLAG_USE_IN = 2;
+ const static int FLAG_STDIN_SOCKET = 4;
+
+ ForkServer () {initialized = false; serverLock.init ();}
+ ~ForkServer () {serverLock.destroy ();}
+
+ void killServer ();
+ int startForkServer ();
+
+ int writeInt (Socket *socket, int num);
+ int writeString (Socket *socket, const char* str, u_long len);
+ int readInt (Socket *sock, int *dest);
+ int readString (Socket *sock, char **out);
+
+ int handleRequest (Socket sin, Socket sout);
+ int forkServerLoop (Socket *socket);
+
+ int getConnection (Socket *socket, Socket *socket2);
+ int executeProcess (StartProcInfo *spi, Socket *sin, Socket *sout,
+ int flags, int *pid, int *port);
+
+ u_short getPort (){return port;}
+ bool isInitialized (){return initialized;}
+ int generateListenerSocket (Socket &socket, u_short *port);
+ private:
+ Mutex serverLock;
+ u_short port;
+ bool initialized;
+};
+
+#endif
Modified: trunk/myserver/include/base/process/process.h
===================================================================
--- trunk/myserver/include/base/process/process.h 2008-11-08 20:06:42 UTC
(rev 2949)
+++ trunk/myserver/include/base/process/process.h 2008-11-09 19:44:52 UTC
(rev 2950)
@@ -23,6 +23,7 @@
#include <include/base/file/file.h>
#include <include/base/sync/mutex.h>
+#include <include/base/process/fork_server.h>
#include <include/base/string/stringutils.h>
#include <string>
@@ -73,9 +74,15 @@
/*! Return the process ID. */
int getPid (){return pid;}
+ /*! Change the process ID. */
+ void setPid (int pid){this->pid = pid;}
+
static int generateEnvString (const char **envp, char *envString);
static int generateArgList (const char **args, const char *proc, string
&additionalArgs);
+
+ static ForkServer *getForkServer (){return &forkServer;}
private:
int pid;
+ static ForkServer forkServer;
};
#endif
Modified: trunk/myserver/include/base/process/process_server_manager.h
===================================================================
--- trunk/myserver/include/base/process/process_server_manager.h
2008-11-08 20:06:42 UTC (rev 2949)
+++ trunk/myserver/include/base/process/process_server_manager.h
2008-11-09 19:44:52 UTC (rev 2950)
@@ -1,7 +1,7 @@
/* -*- mode: c++ -*- */
/*
MyServer
-Copyright (C) 2007 Free Software Foundation, Inc.
+Copyright (C) 2007, 2008 Free Software Foundation, Inc.
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 3 of the License, or
@@ -83,8 +83,6 @@
int connect(Socket* sock, Server* server);
void setMaxServers(int max){maxServers = max;}
int getMaxServers(){return maxServers;}
- void setInitialPort(u_short port){initialPort = port;}
- u_short getInitialPort(){return initialPort;}
void removeServer(const char* domain, const char* name);
void removeDomain(const char* domain);
int domainServers(const char* domain);
@@ -95,7 +93,6 @@
const char* host, u_short port);
private:
int maxServers;
- u_short initialPort;
int nServers;
Mutex mutex;
HashMap<string, ServerDomain*> domains;
Modified: trunk/myserver/src/base/process/Makefile.am
===================================================================
--- trunk/myserver/src/base/process/Makefile.am 2008-11-08 20:06:42 UTC (rev
2949)
+++ trunk/myserver/src/base/process/Makefile.am 2008-11-09 19:44:52 UTC (rev
2950)
@@ -1,5 +1,5 @@
lib_LIBRARIES = libprocess.a
-libprocess_a_SOURCES = process.cpp process_server_manager.cpp
+libprocess_a_SOURCES = fork_server.cpp process.cpp process_server_manager.cpp
SUBDIRS =
INCLUDES = $(all_includes)
Added: trunk/myserver/src/base/process/fork_server.cpp
===================================================================
--- trunk/myserver/src/base/process/fork_server.cpp
(rev 0)
+++ trunk/myserver/src/base/process/fork_server.cpp 2008-11-09 19:44:52 UTC
(rev 2950)
@@ -0,0 +1,501 @@
+/*
+ MyServer
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <include/base/process/fork_server.h>
+#include <include/base/process/process.h>
+
+#ifdef NOT_WIN
+#include <unistd.h>
+#endif
+
+/*!
+ *Write an integer on the specified socket.
+ *\param socket Socket to use.
+ *\param num Integer to write.
+ */
+int ForkServer::writeInt (Socket *socket, int num)
+{
+ u_long nbw;
+
+ if (socket->write ((const char*)&num, sizeof (num), &nbw))
+ return 1;
+
+ return 0;
+}
+
+/*!
+ *Write a string to the socket.
+ *The string length is sent before the content.
+ *
+ *\param socket Socket where write.
+ *\param str string to write.
+ *\param len string length.
+ */
+int ForkServer::writeString (Socket *socket, const char* str, u_long len)
+{
+ u_long nbw;
+
+ if (str == NULL)
+ len = 0;
+
+ if (socket->write ((const char*)&len, sizeof (len), &nbw))
+ return 1;
+
+ if (len && socket->write (str, len, &nbw))
+ return 1;
+
+ return 0;
+}
+
+/*!
+ *Read an integer from the socket.
+ *
+ *\param sock Socket where read.
+ *\param dest integer where write
+ *\return 0 on success.
+ */
+int ForkServer::readInt (Socket *sock, int *dest)
+{
+ u_long nbr;
+
+ if (sock->read ((char*)dest, 4, &nbr) || nbr < 4)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ *Read a string from the socket.
+ *The destination buffer is allocated here.
+ *It must be freed by the caller.
+ *
+ *\param sock socket to use for read.
+ *\param out destination buffer pointer.
+ *\return 0 on success.
+ */
+int ForkServer::readString (Socket *sock, char **out)
+{
+ u_long len;
+ u_long nbr;
+
+ if (sock->read ((char*)&len, 4, &nbr) || nbr < 4)
+ {
+ return -1;
+ }
+
+ *out = new char[len];
+
+ if (!len)
+ {
+ *out = NULL;
+ return 0;
+ }
+
+ if (sock->read (*out, len, &nbr) || nbr < len)
+ {
+ delete [] *out;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ *Handle a request on the socket.
+ */
+int ForkServer::handleRequest (Socket sin, Socket sout)
+{
+#ifdef NOT_WIN
+ int ret, flags, stdIn, stdOut, stdErr;
+ char *exec;
+ char *cwd;
+ char *arg;
+ char *env;
+
+ if (readInt (&sin, &flags) ||
+ readInt (&sin, &stdIn) ||
+ readInt (&sin, &stdOut) ||
+ readInt (&sin, &stdErr))
+ {
+ return -1;
+ }
+
+ if (readString (&sin, &exec))
+ {
+ return -1;
+ }
+
+ if (readString (&sin, &cwd))
+ {
+ delete [] exec;
+ return -1;
+ }
+
+ if (readString (&sin, &arg))
+ {
+ delete [] exec;
+ delete [] cwd;
+ return -1;
+ }
+ string argS (arg);
+
+
+ if (readString (&sin, &env))
+ {
+ delete [] exec;
+ delete [] cwd;
+ delete [] arg;
+ return -1;
+ }
+
+ FileHandle stdHandles[3] = {flags & FLAG_USE_IN ? sin.getHandle () : -1,
+ flags & FLAG_USE_OUT ? sout.getHandle () : -1,
+ -1};
+
+ Socket socketIn;
+ int stdInPort = 0;
+
+ if (flags & FLAG_STDIN_SOCKET)
+ {
+ u_short stdInPortS;
+ if (generateListenerSocket (socketIn, &stdInPortS) ||
+ socketIn.listen (SOMAXCONN))
+ {
+ delete [] exec;
+ delete [] cwd;
+ delete [] arg;
+ return -1;
+ }
+ stdInPort = (int) stdInPortS;
+
+ stdHandles[0] = socketIn.getHandle ();
+ stdHandles[1] = stdHandles[2] = (FileHandle) -1;
+ }
+
+ StartProcInfo spi;
+
+ spi.envString = (env && env[0]) ? env : NULL;
+
+ spi.stdIn = stdHandles[0];
+ spi.stdOut = stdHandles[1];
+ spi.stdError = stdHandles[2];
+
+ spi.cmd.assign (exec);
+ spi.arg.assign (arg);
+ spi.cwd.assign (cwd);
+ /* spi.cmdLine is used only under Windows and
+ * the fork server doesn't work there. */
+
+ ret = fork ();
+
+ if (ret)
+ {
+ writeInt (&sout, ret);
+ writeInt (&sout, stdInPort);
+
+ /* Synchronize with the child process. It avoids that the
+ * child process starts to write on `sout' before the process
+ * information are sent back. */
+ writeInt (&sin, 1);
+ }
+
+ /* Code already present in process.cpp, refactoring needed. */
+ if (ret == 0) // child
+ {
+ int syncInt;
+ const char *envp[100];
+ const char *args[100];
+
+ /* The parent process sent an ack when the child can start its
execution. */
+ readInt (&sin, &syncInt);
+
+ if (Process::generateArgList (args, spi.cmd.c_str (), spi.arg))
+ exit (1);
+
+ if (Process::generateEnvString (envp, (char*) spi.envString))
+ exit (1);
+
+ if (spi.cwd.length ())
+ {
+ ret = chdir ((const char*)(spi.cwd.c_str()));
+ if (ret == -1)
+ exit (1);
+ }
+ if ((long)spi.stdIn == -1)
+ spi.stdIn = (FileHandle)open ("/dev/null", O_RDONLY);
+ if ((long)spi.stdOut == -1)
+ spi.stdOut = (FileHandle)open ("/dev/null", O_WRONLY);
+
+ ret = close(0);
+ if (ret == -1)
+ exit (1);
+ ret = dup2(spi.stdIn, 0);
+ if (ret == -1)
+ exit (1);
+ ret = close(spi.stdIn);
+ if (ret == -1)
+ exit (1);
+ ret = close (1);
+ if (ret == -1)
+ exit (1);
+ ret = dup2(spi.stdOut, 1);
+ if (ret == -1)
+ exit (1);
+ ret = close (spi.stdOut);
+ if (ret == -1)
+ exit (1);
+
+ execve ((const char*)args[0],
+ (char* const*)args, (char* const*) envp);
+ exit (0);
+
+ }
+
+ delete [] exec;
+ delete [] cwd;
+ delete [] arg;
+ delete [] env;
+
+ return ret == -1 ? -1 : 0;
+#endif
+ return 0;
+}
+
+/*!
+ *Entry point for the fork server.
+ *Listen for new connections on the specified socket.
+ *
+ *\param socket Socket where wait for new connections.
+ *\return 0 on success.
+ */
+int ForkServer::forkServerLoop (Socket *socket)
+{
+#ifdef NOT_WIN
+ for (;;)
+ {
+ char command;
+ u_long nbr;
+ MYSERVER_SOCKADDR_STORAGE sockaddr;
+ int len = sizeof (sockaddr);
+
+ if (!socket->dataOnRead(5, 0))
+ continue;
+
+ Socket sin = socket->accept (&sockaddr, &len);
+ Socket sout = socket->accept (&sockaddr, &len);
+
+ //if (sin.getHandle () == -1 || sout.getHandle ())
+ // {
+ // continue;
+ // }
+
+ if (sin.read (&command, 1, &nbr))
+ {
+ sin.shutdown (2);
+ sin.close ();
+ sout.shutdown (2);
+ sout.close ();
+ continue;
+ }
+
+ switch (command)
+ {
+ case 'e': //exit process
+ exit (0);
+ return 0;
+ case 'r':
+ if (handleRequest (sin, sout))
+ {
+ sin.shutdown (2);
+ sin.close ();
+ sout.shutdown (2);
+ sout.close ();
+ }
+ }
+
+ }
+#endif
+ return 0;
+}
+
+/*!
+ *Get a connection to the fork server on the specified sockets.
+ *
+ *\param sin Socket where obtain the input connection.
+ *\param sout Socket where obtain the output connection.
+ *\return 0 on success.
+ */
+int ForkServer::getConnection (Socket *sin, Socket *sout)
+{
+ int len = sizeof(sockaddr_in);
+ MYSERVER_SOCKADDR_STORAGE sockaddr = { 0 };
+ ((sockaddr_in*)(&sockaddr))->sin_family = AF_INET;
+ ((sockaddr_in*)(&sockaddr))->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ ((sockaddr_in*)(&sockaddr))->sin_port = htons (port);
+
+ sin->socket (AF_INET, SOCK_STREAM, 0);
+ sout->socket (AF_INET, SOCK_STREAM, 0);
+
+ serverLock.lock ();
+
+ int ret = sin->connect ((MYSERVER_SOCKADDR*)&sockaddr, len);
+ ret |= sout->connect ((MYSERVER_SOCKADDR*)&sockaddr, len) ;
+
+ serverLock.unlock ();
+
+ return ret;
+}
+
+
+/*!
+ *Execute a process using the fork server.
+ *\param spi New process information.
+ *\param sin Socket to use for the process stdin.
+ *\param sout Socket to use for the process stdout.
+ *\param flags Flags.
+ *\param pid The new process ID.
+ *\param port if FLAG_STDIN_SOCKET was specified.
+ */
+int ForkServer::executeProcess (StartProcInfo *spi, Socket *sin, Socket *sout,
+ int flags, int *pid, int *port)
+{
+ u_long nbw;
+ int len = 0;
+ const char * env = (const char *) spi->envString;
+
+ if (getConnection (sin, sout))
+ {
+ return 1;
+ }
+
+ sin->write ("r", 1, &nbw);
+
+ writeInt (sin, flags);
+ writeInt (sin, spi->stdIn);
+ writeInt (sin, spi->stdOut);
+ writeInt (sin, spi->stdError);
+
+ writeString (sin, spi->cmd.c_str (), spi->cmd.length () + 1);
+ writeString (sin, spi->cwd.c_str (), spi->cwd.length () + 1);
+ writeString (sin, spi->arg.c_str (), spi->arg.length () + 1);
+
+ if (env)
+ {
+ for (len = 0; env[len] != '\0' || env[len + 1] != '\0' ; len++);
+ }
+
+ writeString (sin, env, len + 1);
+
+ readInt (sout, pid);
+ readInt (sout, port);
+
+ return 0;
+}
+
+/*!
+ *Terminate the fork server execution.
+ */
+void ForkServer::killServer ()
+{
+ Socket sin;
+ Socket sout;
+ u_long nbw;
+
+ if (getConnection (&sin, &sout))
+ {
+ return;
+ }
+
+ sin.write ("e", 1, &nbw);
+ sin.shutdown (2);
+ sout.shutdown (2);
+ sin.close ();
+ sout.close ();
+}
+
+/*!
+ *Initialize the fork server.
+ *
+ *\return 0 on success.
+ */
+int ForkServer::startForkServer ()
+{
+#ifdef NOT_WIN
+ Socket socket;
+
+ if (generateListenerSocket (socket, &port))
+ return 1;
+
+ if (socket.listen (2))
+ return -1;
+
+ switch (fork ())
+ {
+ case -1:
+ return -1;
+ case 0:
+ initialized = true;
+ forkServerLoop (&socket);
+ break;
+
+ default:
+ initialized = true;
+ socket.close ();
+ break;
+ }
+#endif
+ return 0;
+}
+
+/*!
+ *Create a listener without specify a port.
+ *
+ *\param socket The socket to generate.
+ *\param port the obtained port.
+ */
+int ForkServer::generateListenerSocket (Socket &socket, u_short *port)
+{
+ int optvalReuseAddr = 1;
+ int len = sizeof(sockaddr_in);
+
+ socket.socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (socket.getHandle() == (FileHandle)INVALID_SOCKET)
+ return -1;
+
+ MYSERVER_SOCKADDR_STORAGE sockaddr = { 0 };
+ ((sockaddr_in*)(&sockaddr))->sin_family = AF_INET;
+ ((sockaddr_in*)(&sockaddr))->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ ((sockaddr_in*)(&sockaddr))->sin_port = 0;
+
+ if (socket.bind (&sockaddr, sizeof (sockaddr_in)) != 0)
+ return -1;
+
+ if (socket.getsockname (&sockaddr, &len))
+ return -1;
+
+ *port = ntohs (((sockaddr_in*)(&sockaddr))->sin_port);
+
+ if(socket.setsockopt (SOL_SOCKET, SO_REUSEADDR, (const char
*)&optvalReuseAddr,
+ sizeof (optvalReuseAddr)) < 0)
+ return -1;
+
+ return 0;
+}
Modified: trunk/myserver/src/base/process/process.cpp
===================================================================
--- trunk/myserver/src/base/process/process.cpp 2008-11-08 20:06:42 UTC (rev
2949)
+++ trunk/myserver/src/base/process/process.cpp 2008-11-09 19:44:52 UTC (rev
2950)
@@ -46,6 +46,8 @@
Mutex Process::forkMutex;
#endif
+ForkServer Process::forkServer;
+
/*!
*Generate the arguments vector for execve.
*\param args The output arguments vector to fill.
@@ -213,7 +215,7 @@
if (generateArgList (args, spi->cmd.c_str (), spi->arg))
exit (1);
-
+
if (generateEnvString (envp, (char*) spi->envString))
exit (1);
Modified: trunk/myserver/src/base/process/process_server_manager.cpp
===================================================================
--- trunk/myserver/src/base/process/process_server_manager.cpp 2008-11-08
20:06:42 UTC (rev 2949)
+++ trunk/myserver/src/base/process/process_server_manager.cpp 2008-11-09
19:44:52 UTC (rev 2950)
@@ -28,7 +28,6 @@
{
mutex.init();
nServers = 0;
- initialPort = 3333;
maxServers = 25;
}
@@ -88,6 +87,7 @@
if(name.size() && domain.size())
{
u_short portN = 0;
+
if(port.size())
portN = atoi(port.c_str());
@@ -211,6 +211,9 @@
s->process.terminateProcess();
if(!s->path.length())
s->path.assign(name);
+
+ s->port = 0;
+
if(runServer(s, s->path.c_str(), s->port))
{
sd->servers.remove(name);
@@ -374,6 +377,8 @@
{
StartProcInfo spi;
MYSERVER_SOCKADDRIN serverSockAddrIn;
+ int addrLen = sizeof (serverSockAddrIn);
+
server->host.assign("localhost");
server->isLocal = true;
@@ -389,116 +394,99 @@
if(port)
server->port = port;
else
- server->port = (initialPort + nServers++);
+ server->port = 0;
- server->socket.socket(AF_INET,SOCK_STREAM,0);
- if(server->socket.getHandle() != (FileHandle)INVALID_SOCKET)
- {
- ((sockaddr_in *)(&serverSockAddrIn))->sin_family = AF_INET;
+ string tmpCgiPath;
+ string moreArg;
+ int subString = path[0] == '"';
+ int i;
+ int len = strlen(path);
- ((sockaddr_in *)(&serverSockAddrIn))->sin_addr.s_addr =
- htonl(INADDR_LOOPBACK);
- ((sockaddr_in *)(&serverSockAddrIn))->sin_port =
- htons(server->port);
- if ( !server->socket.bind(&serverSockAddrIn,
- sizeof(sockaddr_in)) )
+ for(i = 1; i < len; i++)
{
- if( !server->socket.listen(SOMAXCONN) )
- {
- string tmpCgiPath;
- string moreArg;
- int subString = path[0] == '"';
- int i;
- int len = strlen(path);
- for(i = 1; i < len; i++)
- {
- if(!subString && path[i] == ' ')
- break;
- if(path[i] == '"' && path[i - 1] != '\\')
- subString = !subString;
- }
+ if(!subString && path[i] == ' ')
+ break;
- if(i < len)
- {
- string tmpString(path);
- int begin = tmpString[0] == '"' ? 1 : 0;
- int end = tmpString[i] == '"' ? i + 1 : i ;
- tmpCgiPath.assign(tmpString.substr(begin, end));
- moreArg.assign(tmpString.substr(i, len));
- }
- else
- {
- int begin = (path[0] == '"') ? 1 : 0;
- int end = (path[len] == '"') ? len-1 : len;
- tmpCgiPath.assign(&path[begin], end-begin);
- moreArg.assign("");
- }
+ if(path[i] == '"' && path[i - 1] != '\\')
+ subString = !subString;
+ }
+
+ if(i < len)
+ {
+ string tmpString(path);
+ int begin = tmpString[0] == '"' ? 1 : 0;
+ int end = tmpString[i] == '"' ? i + 1 : i ;
+ tmpCgiPath.assign(tmpString.substr(begin, end));
+ moreArg.assign(tmpString.substr(i, len));
+ }
+ else
+ {
+ int begin = (path[0] == '"') ? 1 : 0;
+ int end = (path[len] == '"') ? len-1 : len;
+ tmpCgiPath.assign(&path[begin], end-begin);
+ moreArg.assign("");
+ }
+
+ spi.envString = 0;
+ spi.stdOut = spi.stdError = (FileHandle) -1;
+
+ spi.cmd.assign(tmpCgiPath);
+ spi.arg.assign(moreArg);
+ spi.cmdLine.assign(path);
+ server->path.assign(path);
+ if (Process::getForkServer ()->isInitialized ())
+ {
+ Socket forkSockIn, forkSockOut;
+ int ret, port, pid;
+ ret = Process::getForkServer ()->executeProcess (&spi,
+ &forkSockIn,
+ &forkSockOut,
+
ForkServer::FLAG_STDIN_SOCKET,
+ &pid,
+ &port);
- server->DESCRIPTOR.fileHandle = (unsigned long)
server->socket.getHandle();
- spi.envString = 0;
- spi.stdIn = (FileHandle)server->DESCRIPTOR.fileHandle;
- spi.cmd.assign(tmpCgiPath);
- spi.arg.assign(moreArg);
- spi.cmdLine.assign(path);
- server->path.assign(path);
-
- spi.stdOut = spi.stdError = (FileHandle) -1;
- if (server->process.exec (&spi) == -1)
+ if (ret == 0)
{
- server->socket.close();
+ server->port = port;
+ server->process.setPid (pid);
+ server->DESCRIPTOR.fileHandle = 0;
+ return 0;
}
-
- }
- else
- {
- server->socket.close();
+
}
- }
- else
+
+ server->socket.socket (AF_INET, SOCK_STREAM, 0);
+
+ if(server->socket.getHandle () == (FileHandle)INVALID_SOCKET)
+ return 1;
+
+ ((sockaddr_in *)(&serverSockAddrIn))->sin_family = AF_INET;
+
+ ((sockaddr_in *)(&serverSockAddrIn))->sin_addr.s_addr =
+ htonl(INADDR_LOOPBACK);
+ ((sockaddr_in *)(&serverSockAddrIn))->sin_port =
+ htons(server->port);
+
+ if ( server->socket.bind (&serverSockAddrIn,
+ sizeof(sockaddr_in)) ||
+ server->socket.listen(SOMAXCONN) )
{
- server->socket.close();
+ server->socket.close ();
+ return 1;
}
- }
- else
- {
-#if HAVE_IPV6 && 0
- server->socket.socket(AF_INET6, SOCK_STREAM, 0);
- if(server->socket.getHandle() != (FileHandle)INVALID_SOCKET)
- {
- ((sockaddr_in6 *)(&serverSockAddrIn))->sin6_family = AF_INET6;
- /*! The FastCGI server accepts connections only by the localhost. */
- ((sockaddr_in6 *)(&serverSockAddrIn))->sin6_addr=in6addr_any;
- ((sockaddr_in6 *)(&serverSockAddrIn))->sin6_port=htons(server->port);
- if(server->socket.bind(&serverSockAddrIn,
- sizeof(sockaddr_in6)))
- {
- server->socket.close();
- return 1;
- }
- if(server->socket.listen(SOMAXCONN))
- {
- server->socket.close();
- return 1;
- }
- server->DESCRIPTOR.fileHandle = server->socket.getHandle();
- spi.envString = 0;
- spi.stdIn = (FileHandle)server->DESCRIPTOR.fileHandle;
- spi.cmd.assign(path);
- spi.cmdLine.assign(path);
- server->path.assign(path);
+ server->DESCRIPTOR.fileHandle = (unsigned long) server->socket.getHandle();
+ spi.stdIn = (FileHandle)server->DESCRIPTOR.fileHandle;
- spi.stdOut = spi.stdError =(FileHandle) -1;
+ if (server->socket.getsockname (&serverSockAddrIn, &addrLen))
+ return -1;
- if(server->process.exec (&spi) == -1)
- {
- server->socket.close();
- return 1;
- }
- }
-#endif
- }
+ server->port = ntohs (((sockaddr_in *)&serverSockAddrIn)->sin_port);
+
+ server->process.exec (&spi);
+ server->socket.close();
+
return 0;
}
@@ -512,8 +500,11 @@
{
MYSERVER_SOCKADDRIN serverSock = { 0 };
socklen_t nLength = sizeof(MYSERVER_SOCKADDRIN);
- getsockname((SOCKET) server->socket.getHandle(), (sockaddr *)&serverSock,
&nLength);
- if(serverSock.ss_family == AF_INET || !server->isLocal)
+
+ if (server->socket.getHandle())
+ getsockname(server->socket.getHandle(), (sockaddr *)&serverSock, &nLength);
+
+ if(!serverSock.ss_family || serverSock.ss_family == AF_INET ||
!server->isLocal)
{
/*! Try to create the socket. */
if(sock->socket(AF_INET, SOCK_STREAM, 0) == -1)
Modified: trunk/myserver/src/http_handler/fastcgi/fastcgi.cpp
===================================================================
--- trunk/myserver/src/http_handler/fastcgi/fastcgi.cpp 2008-11-08 20:06:42 UTC
(rev 2949)
+++ trunk/myserver/src/http_handler/fastcgi/fastcgi.cpp 2008-11-09 19:44:52 UTC
(rev 2950)
@@ -15,7 +15,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*!
+/*
*To get more info about the FastCGI protocol please visit the official
*FastCGI site at: http://www.fastcgi.com.
*On that site you can find samples and all the supported languages.
@@ -248,6 +248,7 @@
{
exit = 1;
ret = 1;
+ td->http->raiseHTTPError(500);
break;
}
@@ -325,9 +326,9 @@
}while (!exit);
/* Send the last null chunk if needed. */
- if((td->response.getStatusType () == HttpResponseHeader::SUCCESSFUL) &&
- con.useChunks && chain.write("0\r\n\r\n", 5, &nbw))
- return 0;
+ if(con.useChunks &&
+ (td->response.getStatusType () == HttpResponseHeader::SUCCESSFUL))
+ chain.write("0\r\n\r\n", 5, &nbw);
chain.clearAllFilters();
con.sock.close();
Modified: trunk/myserver/src/myserver.cpp
===================================================================
--- trunk/myserver/src/myserver.cpp 2008-11-08 20:06:42 UTC (rev 2949)
+++ trunk/myserver/src/myserver.cpp 2008-11-09 19:44:52 UTC (rev 2950)
@@ -19,6 +19,7 @@
#include <include/server/server.h>
#include <include/base/file/files_utility.h>
#include <include/base/string/stringutils.h>
+#include <include/base/process/process.h>
extern "C" {
#ifdef WIN32
@@ -125,6 +126,7 @@
/* Define how run the server. */
int runas;
char* pidFileName;
+ int useForkServer;
};
static char doc[] = "GNU MyServer ";
@@ -137,7 +139,8 @@
{"version", 'v', "VERSION", OPTION_ARG_OPTIONAL , "Print the version for the
application"},
{"run", 'r', "RUN", OPTION_ARG_OPTIONAL, "Specify how run the server (by
default console mode)"},
{"log", 'l', "location", 0, "Specify the location (in the format
protocol://resource) to use to log main myserver messages"},
- {"pidfile", 'p', "pidfile", OPTION_HIDDEN, "Specify the file where write the
PID"},
+ {"pidfile", 'p', "pidfile", 0, "Specify the file where write the PID"},
+ {"fork_server", 'f', "", OPTION_ARG_OPTIONAL, "Specify if use a fork
server"},
{0}
};
@@ -166,6 +169,10 @@
in->logFileName = arg;
break;
+ case 'f':
+ in->useForkServer = 1;
+ break;
+
case 'p':
in->pidFileName = arg;
break;
@@ -480,6 +487,8 @@
input.logFileName = 0;
input.runas = MYSERVER_RUNAS_CONSOLE;
input.pidFileName = 0;
+ input.useForkServer = 0;
+
/* Call the parser. */
argp_parse(&myserverArgp, argn, argv, 0, 0, &input);
runas=input.runas;
@@ -545,6 +554,17 @@
}
}
#endif
+
+#ifdef ARGP
+
+#ifdef NOT_WIN
+ setpgid (0, 0);
+#endif
+
+ if (input.useForkServer)
+ Process::getForkServer ()->startForkServer ();
+#endif
+
/*
*Start here the MyServer execution.
*/
@@ -619,6 +639,12 @@
{
return 1;
};
+
+#ifdef ARGP
+ if (input.useForkServer)
+ Process::getForkServer ()->killServer ();
+#endif
+
return 0;
}
Modified: trunk/myserver/src/server/server.cpp
===================================================================
--- trunk/myserver/src/server/server.cpp 2008-11-08 20:06:42 UTC (rev
2949)
+++ trunk/myserver/src/server/server.cpp 2008-11-09 19:44:52 UTC (rev
2950)
@@ -725,7 +725,7 @@
string softwareSignature;
softwareSignature.assign("************ GNU MyServer ");
softwareSignature.append(MYSERVER_VERSION);
- softwareSignature.append("************");
+ softwareSignature.append(" ************");
length = softwareSignature.length();
logWriteNTimes("*", length);
@@ -1169,14 +1169,7 @@
getProcessServerManager()->setMaxServers(maxServersProcesses);
}
- data = configurationFileManager.getValue("SERVERS_PROCESSES_INITIAL_PORT");
- if(data)
{
- int serversProcessesInitialPort = atoi(data);
- getProcessServerManager()->setInitialPort(serversProcessesInitialPort);
- }
-
- {
xmlNodePtr node =
xmlDocGetRootElement(configurationFileManager.getDoc())->xmlChildrenNode;
for(;node; node = node->next)
Modified: trunk/myserver/tests/Makefile.am
===================================================================
--- trunk/myserver/tests/Makefile.am 2008-11-08 20:06:42 UTC (rev 2949)
+++ trunk/myserver/tests/Makefile.am 2008-11-09 19:44:52 UTC (rev 2950)
@@ -2,5 +2,5 @@
#
bin_PROGRAMS = tests_suite
-tests_suite_SOURCES = main.cpp test_connection.cpp test_ftp.cpp
test_log_manager.cpp test_mime_manager.cpp test_mutex.cpp
test_security_domain.cpp test_validator.cpp test_auth_domain.cpp
test_connections_scheduler.cpp test_gzip.cpp test_log_stream_factory.cpp
test_pipe.cpp test_security_manager.cpp test_validator_factory.cpp
test_base64.cpp test_file_stream.cpp test_hashmap.cpp test_md5.cpp
test_recursive_mutex.cpp test_semaphore.cpp test_xml.cpp
test_cached_file_buffer.cpp test_file_stream_creator.cpp test_homedir.cpp
test_mem_buff.cpp test_regex.cpp test_socket_stream_creator.cpp
test_cached_file.cpp test_files_utility.cpp test_http_request.cpp
test_http_req_security_domain.cpp test_mem_stream.cpp test_safetime.cpp
test_thread.cpp test_cached_file_factory.cpp test_filter_chain.cpp
test_http_response.cpp test_multicast.cpp test_security_cache.cpp
test_security_token.cpp test_utility.cpp test_xml_validator.cpp test_ip.cpp
test_plugin_info.cpp
+tests_suite_SOURCES = main.cpp test_connection.cpp test_ftp.cpp
test_log_manager.cpp test_mime_manager.cpp test_mutex.cpp
test_security_domain.cpp test_validator.cpp test_auth_domain.cpp
test_connections_scheduler.cpp test_gzip.cpp test_log_stream_factory.cpp
test_pipe.cpp test_security_manager.cpp test_validator_factory.cpp
test_base64.cpp test_file_stream.cpp test_hashmap.cpp test_md5.cpp
test_recursive_mutex.cpp test_semaphore.cpp test_xml.cpp
test_cached_file_buffer.cpp test_file_stream_creator.cpp test_homedir.cpp
test_mem_buff.cpp test_regex.cpp test_socket_stream_creator.cpp
test_cached_file.cpp test_files_utility.cpp test_http_request.cpp
test_http_req_security_domain.cpp test_mem_stream.cpp test_safetime.cpp
test_thread.cpp test_cached_file_factory.cpp test_filter_chain.cpp
test_http_response.cpp test_multicast.cpp test_security_cache.cpp
test_security_token.cpp test_utility.cpp test_xml_validator.cpp test_ip.cpp
test_plugin_info.cpp test_fork_server.cpp
tests_suite_LDADD = ../src/libmyserver.a $(CPPUNIT_LDFLAGS) $(PTHREAD_LIB)
$(IDN_LIB) $(XNET_LIB) $(EVENT_LIB) $(DL_LIB) $(SSL_LIB) $(ZLIB_LIB)
$(XML_LIBS) $(LDFLAGS)
Added: trunk/myserver/tests/test_fork_server.cpp
===================================================================
--- trunk/myserver/tests/test_fork_server.cpp (rev 0)
+++ trunk/myserver/tests/test_fork_server.cpp 2008-11-09 19:44:52 UTC (rev
2950)
@@ -0,0 +1,103 @@
+/*
+ MyServer
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <include/base/process/fork_server.h>
+#include <include/base/process/process.h>
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <string.h>
+class TestForkServer : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE( TestForkServer );
+ CPPUNIT_TEST (testStartKillLoop);
+ CPPUNIT_TEST( testExecuteProcess );
+ CPPUNIT_TEST_SUITE_END();
+
+ ForkServer *fs;
+
+public:
+ void setUp()
+ {
+ fs = new ForkServer;
+ }
+
+ void tearDown()
+ {
+ delete fs;
+ }
+
+ void testStartKillLoop ()
+ {
+#ifndef WIN32
+ CPPUNIT_ASSERT_EQUAL (fs->isInitialized (), false);
+
+ int ret = fs->startForkServer ();
+
+ CPPUNIT_ASSERT_EQUAL (ret, 0);
+
+ CPPUNIT_ASSERT_EQUAL (fs->isInitialized (), true);
+
+ CPPUNIT_ASSERT (fs->getPort ());
+
+ fs->killServer ();
+#endif
+ }
+
+ void testExecuteProcess()
+ {
+#ifndef WIN32
+ int pid = 0;
+ int port = 0;
+ StartProcInfo spi;
+ Socket sin, sout;
+ char buffer [32];
+ const char *msg = "ForkServer";
+ u_long nbr;
+ int ret = fs->startForkServer ();
+ CPPUNIT_ASSERT_EQUAL (ret, 0);
+
+ spi.stdIn = spi.stdOut = spi.stdError = -1;
+
+ spi.cmd.assign ("/bin/echo");
+ spi.arg.assign (msg);
+ spi.cwd.assign ("");
+
+ ret = fs->executeProcess (&spi, &sin, &sout, ForkServer::FLAG_USE_OUT,
&pid, &port);
+ sin.shutdown(2);
+ sin.close ();
+
+ CPPUNIT_ASSERT_EQUAL (ret, 0);
+
+ ret = sout.read (buffer, 32, &nbr);
+
+ sout.close();
+
+ CPPUNIT_ASSERT_EQUAL (ret, 0);
+
+ printf ("letto %s\n", buffer);
+
+ CPPUNIT_ASSERT_EQUAL (strncmp (buffer, msg, strlen (msg)), 0);
+
+ fs->killServer ();
+ #endif
+ }
+
+};
+CPPUNIT_TEST_SUITE_REGISTRATION( TestForkServer );
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [myserver-commit] [2950] Added class `ForkServer'.,
Giuseppe Scrivano <=