myserver-commit
[Top][All Lists]
Advanced

[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 );






reply via email to

[Prev in Thread] Current Thread [Next in Thread]