Passenger: Process.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List

# Process.h

    00001 /*
    00002  *  Phusion Passenger - http://www.modrails.com/
    00003  *  Copyright (c) 2010 Phusion
    00004  *
    00005  *  "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
    00006  *
    00007  *  Permission is hereby granted, free of charge, to any person obtaining a copy
    00008  *  of this software and associated documentation files (the "Software"), to deal
    00009  *  in the Software without restriction, including without limitation the rights
    00010  *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    00011  *  copies of the Software, and to permit persons to whom the Software is
    00012  *  furnished to do so, subject to the following conditions:
    00013  *
    00014  *  The above copyright notice and this permission notice shall be included in
    00015  *  all copies or substantial portions of the Software.
    00016  *
    00017  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    00018  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    00019  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    00020  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    00021  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    00022  *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    00023  *  THE SOFTWARE.
    00024  */
    00025 #ifndef _PASSENGER_PROCESS_H_
    00026 #define _PASSENGER_PROCESS_H_
    00027
    00028 #include <boost/shared_ptr.hpp>
    00029 #include <boost/function.hpp>
    00030 #include <oxt/system_calls.hpp>
    00031 #include <oxt/backtrace.hpp>
    00032 #include <string>
    00033 #include <map>
    00034
    00035 #include <sys/types.h>
    00036 #include <unistd.h>
    00037 #include <errno.h>
    00038
    00039 #include "Session.h"
    00040 #include "MessageChannel.h"
    00041 #include "Exceptions.h"
    00042 #include "Logging.h"
    00043 #include "Utils.h"
    00044
    00045 namespace Passenger {
    00046
    00047 using namespace std;
    00048 using namespace boost;
    00049
    00050 /**
    00051  * Represents a single application process, as spawned by SpawnManager
    00052  * or by ApplicationPool::Interface::get().
    00053  *
    00054  * @ingroup Support
    00055  */
    00056 class Process {
    00057 public:
    00058         struct SocketInfo {
    00059                 string address;
    00060                 string type;
    00061
    00062                 SocketInfo() {}
    00063
    00064                 SocketInfo(const string &address, const string &type) {
    00065                         this->address = address;
    00066                         this->type    = type;
    00067                 }
    00068         };
    00069
    00070         typedef map<string, SocketInfo> SocketInfoMap;
    00071
    00072 private:
    00073         string appRoot;
    00074         pid_t pid;
    00075         int ownerPipe;
    00076         string detachKey;
    00077         string connectPassword;
    00078         string gupid;
    00079         SocketInfoMap serverSockets;
    00080         SocketInfo *mainServerSocket;
    00081         function<void ()> destructionCallback;
    00082
    00083 public:
    00084         /**
    00085          * Construct a new Process object.
    00086          *
    00087          * @param appRoot The application root of an application.
    00088          *             This must be a valid directory, but the path does not have to be absolute.
    00089          * @param pid The process ID of this application process.
    00090          * @param ownerPipe The owner pipe of this application process.
    00091          * @param serverSockets All the server sockets that this process listens on.
    00092          *                      There must a server socket with the name 'main'.
    00093          * @param detachKey A detach key. Used by the ApplicationPool algorithm.
    00094          * @param connectPassword The password to use when connecting to this process.
    00095          *                        Must be valid ASCII.
    00096          * @param gupid A string which uniquely identifies this process.
    00097          * @param destructionCallback A callback to be called when this Process is destroyed.
    00098          * @throws ArgumentException If serverSockets has no socket named 'main'.
    00099          */
    00100         Process(const string &appRoot, pid_t pid, int ownerPipe, const SocketInfoMap &serverSockets,
    00101                 const string &detachKey, const string &connectPassword, const string &gupid,
    00102                 const function<void ()> &destructionCallback = function<void ()>())
    00103         {
    00104                 this->appRoot         = appRoot;
    00105                 this->pid             = pid;
    00106                 this->ownerPipe       = ownerPipe;
    00107                 this->serverSockets   = serverSockets;
    00108                 this->detachKey       = detachKey;
    00109                 this->connectPassword = connectPassword;
    00110                 this->gupid           = gupid;
    00111                 this->destructionCallback = destructionCallback;
    00112                 if (serverSockets.find("main") == serverSockets.end()) {
    00113                         TRACE_POINT();
    00114                         throw ArgumentException("There must be a server socket named 'main'.");
    00115                 }
    00116                 mainServerSocket = &this->serverSockets["main"];
    00117                 P_TRACE(3, "Application process " << pid << " (" << this << "): created.");
    00118         }
    00119
    00120         virtual ~Process() {
    00121                 TRACE_POINT();
    00122                 SocketInfoMap::const_iterator it;
    00123                 int ret;
    00124
    00125                 if (ownerPipe != -1) {
    00126                         do {
    00127                                 ret = close(ownerPipe);
    00128                         } while (ret == -1 && errno == EINTR);
    00129                 }
    00130                 for (it = serverSockets.begin(); it != serverSockets.end(); it++) {
    00131                         const SocketInfo &info = it->second;
    00132                         if (info.type == "unix") {
    00133                                 do {
    00134                                         ret = unlink(info.address.c_str());
    00135                                 } while (ret == -1 && errno == EINTR);
    00136                         }
    00137                 }
    00138                 P_TRACE(3, "Application process " << pid << " (" << this << "): destroyed.");
    00139
    00140                 if (destructionCallback) {
    00141                         destructionCallback();
    00142                 }
    00143         }
    00144
    00145         /**
    00146          * Returns the application root for this application process. See
    00147          * the constructor for information about the application root.
    00148          */
    00149         string getAppRoot() const {
    00150                 return appRoot;
    00151         }
    00152
    00153         /**
    00154          * Returns the process ID of this application process.
    00155          */
    00156         pid_t getPid() const {
    00157                 return pid;
    00158         }
    00159
    00160         /**
    00161          * Returns this process's detach key.
    00162          */
    00163         string getDetachKey() const {
    00164                 return detachKey;
    00165         }
    00166
    00167         /**
    00168          * Returns this process's connect password. This password is
    00169          * guaranteed to be valid ASCII.
    00170          */
    00171         string getConnectPassword() const {
    00172                 return connectPassword;
    00173         }
    00174
    00175         /**
    00176          * Returns this process's gupid. This is like a PID, but does not rotate
    00177          * and is even unique over multiple servers.
    00178          */
    00179         string getGupid() const {
    00180                 return gupid;
    00181         }
    00182
    00183         /**
    00184          * Returns a map containing all server sockets that this process
    00185          * listens on.
    00186          */
    00187         const SocketInfoMap *getServerSockets() const {
    00188                 return &serverSockets;
    00189         }
    00190
    00191         /**
    00192          * Request a new session from this application process by connecting to its
    00193          * main server socket. This session represents the life time of a single
    00194          * request/response pair, and can be used to send the request data to the
    00195          * application process, as well as receiving the response data.
    00196          *
    00197          * The use of connect() is demonstrated in the following example.
    00198          * @code
    00199          *   // Request a new session from the process.
    00200          *   SessionPtr session = process->newSession(...);
    00201          *
    00202          *   // Send the request headers and request body data.
    00203          *   session->sendHeaders(...);
    00204          *   session->sendBodyBlock(...);
    00205          *   // Done sending data, so we close the writer channel.
    00206          *   session->shutdownWriter();
    00207          *
    00208          *   // Now read the HTTP response.
    00209          *   string responseData = readAllDataFromSocket(session->getReader());
    00210          *   // Done reading data, so we close the reader channel.
    00211          *   session->shutdownReader();
    00212          *
    00213          *   // This session has now finished, so we close the session by resetting
    00214          *   // the smart pointer to NULL (thereby destroying the Session object).
    00215          *   session.reset();
    00216          *
    00217          *   // We can connect to a Process multiple times. Just make sure
    00218          *   // the previous session is closed.
    00219          *   session = process->newSession(...);
    00220          * @endcode
    00221          *
    00222          * You <b>must</b> close a session when you no longer need it. If you
    00223          * call connect() without having properly closed a previous session,
    00224          * you might cause a deadlock because the application process may be
    00225          * waiting for you to close the previous session.
    00226          *
    00227          * @param closeCallback A function which will be called when the session has been closed.
    00228          * @param initiateNow Whether the session should be initiated immediately.
    00229          *                    If set to false then you must call <tt>initiate()</tt> on
    00230          *                    the session before it's usable.
    00231          * @return A smart pointer to a Session object, which represents the created session.
    00232          * @post result->initiated() == initiateNow
    00233          * @throws SystemException Something went wrong during session initiation.
    00234          * @throws IOException Something went wrong during session initiation.
    00235          * @throws boost::thread_interrupted
    00236          */
    00237         SessionPtr newSession(const StandardSession::CloseCallback &closeCallback = StandardSession::CloseCallback(),
    00238                               bool initiateNow = true)
    00239         {
    00240                 SessionPtr session(new StandardSession(pid, closeCallback,
    00241                         mainServerSocket->type, mainServerSocket->address,
    00242                         detachKey, connectPassword, gupid));
    00243                 if (initiateNow) {
    00244                         session->initiate();
    00245                 }
    00246                 return session;
    00247         }
    00248 };
    00249
    00250 /** Convenient alias for Process smart pointer. */
    00251 typedef shared_ptr<Process> ProcessPtr;
    00252
    00253 } // namespace Passenger
    00254
    00255 #endif /* _PASSENGER_PROCESS_H_ */