00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifndef _PASSENGER_APPLICATION_POOL_SERVER_H_
00019 #define _PASSENGER_APPLICATION_POOL_SERVER_H_
00020
00021 #include <boost/shared_ptr.hpp>
00022
00023 #include <sys/types.h>
00024 #include <sys/wait.h>
00025 #include <sys/socket.h>
00026 #include <cstdlib>
00027 #include <errno.h>
00028 #include <unistd.h>
00029
00030 #include "MessageChannel.h"
00031 #include "ApplicationPool.h"
00032 #include "Application.h"
00033 #include "Exceptions.h"
00034 #include "Logging.h"
00035
00036 namespace Passenger {
00037
00038 using namespace std;
00039 using namespace boost;
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 class ApplicationPoolServer {
00122 private:
00123
00124
00125
00126
00127
00128
00129
00130 struct SharedData {
00131
00132
00133
00134
00135 int server;
00136
00137 ~SharedData() {
00138 close(server);
00139 }
00140 };
00141
00142 typedef shared_ptr<SharedData> SharedDataPtr;
00143
00144
00145
00146
00147 class RemoteSession: public Application::Session {
00148 private:
00149 SharedDataPtr data;
00150 int id;
00151 int reader;
00152 int writer;
00153 pid_t pid;
00154 public:
00155 RemoteSession(SharedDataPtr data, pid_t pid, int id, int reader, int writer) {
00156 this->data = data;
00157 this->pid = pid;
00158 this->id = id;
00159 this->reader = reader;
00160 this->writer = writer;
00161 }
00162
00163 virtual ~RemoteSession() {
00164 closeReader();
00165 closeWriter();
00166 MessageChannel(data->server).write("close", toString(id).c_str(), NULL);
00167 }
00168
00169 virtual int getReader() const {
00170 return reader;
00171 }
00172
00173 virtual void closeReader() {
00174 if (reader != -1) {
00175 close(reader);
00176 reader = -1;
00177 }
00178 }
00179
00180 virtual int getWriter() const {
00181 return writer;
00182 }
00183
00184 virtual void closeWriter() {
00185 if (writer != -1) {
00186 close(writer);
00187 writer = -1;
00188 }
00189 }
00190
00191 virtual pid_t getPid() const {
00192 return pid;
00193 }
00194 };
00195
00196
00197
00198
00199
00200
00201 class Client: public ApplicationPool {
00202 private:
00203 SharedDataPtr data;
00204
00205 public:
00206
00207
00208
00209
00210
00211 Client(int sock) {
00212 data = ptr(new SharedData());
00213 data->server = sock;
00214 }
00215
00216 virtual void clear() {
00217 MessageChannel channel(data->server);
00218 channel.write("clear", NULL);
00219 }
00220
00221 virtual void setMaxIdleTime(unsigned int seconds) {
00222 MessageChannel channel(data->server);
00223 channel.write("setMaxIdleTime", toString(seconds).c_str(), NULL);
00224 }
00225
00226 virtual void setMax(unsigned int max) {
00227 MessageChannel channel(data->server);
00228 channel.write("setMax", toString(max).c_str(), NULL);
00229 }
00230
00231 virtual unsigned int getActive() const {
00232 MessageChannel channel(data->server);
00233 vector<string> args;
00234
00235 channel.write("getActive", NULL);
00236 channel.read(args);
00237 return atoi(args[0].c_str());
00238 }
00239
00240 virtual unsigned int getCount() const {
00241 MessageChannel channel(data->server);
00242 vector<string> args;
00243
00244 channel.write("getCount", NULL);
00245 channel.read(args);
00246 return atoi(args[0].c_str());
00247 }
00248
00249 virtual pid_t getSpawnServerPid() const {
00250 MessageChannel channel(data->server);
00251 vector<string> args;
00252
00253 channel.write("getSpawnServerPid", NULL);
00254 channel.read(args);
00255 return atoi(args[0].c_str());
00256 }
00257
00258 virtual Application::SessionPtr get(const string &appRoot, bool lowerPrivilege = true,
00259 const string &lowestUser = "nobody") {
00260 MessageChannel channel(data->server);
00261 vector<string> args;
00262 int reader, writer;
00263
00264 channel.write("get", appRoot.c_str(),
00265 (lowerPrivilege) ? "true" : "false",
00266 lowestUser.c_str(), NULL);
00267 if (!channel.read(args)) {
00268 throw IOException("The ApplicationPool server unexpectedly closed the connection.");
00269 }
00270 if (args[0] == "ok") {
00271 reader = channel.readFileDescriptor();
00272 writer = channel.readFileDescriptor();
00273 return ptr(new RemoteSession(data, atoi(args[1]), atoi(args[2]), reader, writer));
00274 } else if (args[0] == "SpawnException") {
00275 if (args[2] == "true") {
00276 string errorPage;
00277
00278 if (!channel.readScalar(errorPage)) {
00279 throw IOException("The ApplicationPool server unexpectedly closed the connection.");
00280 }
00281 throw SpawnException(args[1], errorPage);
00282 } else {
00283 throw SpawnException(args[1]);
00284 }
00285 } else if (args[0] == "IOException") {
00286 throw IOException(args[1]);
00287 } else {
00288 throw IOException("The ApplicationPool server returned an unknown message.");
00289 }
00290 }
00291 };
00292
00293
00294 static const int SERVER_SOCKET_FD = 3;
00295
00296 string m_serverExecutable;
00297 string m_spawnServerCommand;
00298 string m_logFile;
00299 string m_environment;
00300 string m_rubyCommand;
00301 string m_user;
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 pid_t serverPid;
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 int serverSocket;
00322
00323
00324
00325
00326
00327
00328
00329 void shutdownServer() {
00330 time_t begin;
00331 bool done;
00332 int ret;
00333
00334 do {
00335 ret = close(serverSocket);
00336 } while (ret == -1 && errno == EINTR);
00337
00338 P_DEBUG("Waiting for existing ApplicationPoolServerExecutable to exit...");
00339 begin = time(NULL);
00340 while (!done && time(NULL) < begin + 5) {
00341 done = waitpid(serverPid, NULL, WNOHANG) > 0;
00342 usleep(100000);
00343 }
00344 if (done) {
00345 P_DEBUG("ApplicationPoolServerExecutable exited.");
00346 } else {
00347 P_DEBUG("ApplicationPoolServerExecutable not exited in time. Killing it...");
00348 kill(serverPid, SIGTERM);
00349 waitpid(serverPid, NULL, 0);
00350 }
00351 serverSocket = -1;
00352 serverPid = 0;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361
00362 void restartServer() {
00363 int fds[2];
00364 pid_t pid;
00365
00366 if (serverPid != 0) {
00367 shutdownServer();
00368 }
00369
00370 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
00371 throw SystemException("Cannot create a Unix socket pair", errno);
00372 }
00373
00374 pid = fork();
00375 if (pid == 0) {
00376 dup2(fds[0], 3);
00377
00378
00379 for (long i = sysconf(_SC_OPEN_MAX) - 1; i > SERVER_SOCKET_FD; i--) {
00380 close(i);
00381 }
00382
00383 execlp(
00384 #if 0
00385 "valgrind",
00386 "valgrind",
00387 #else
00388 m_serverExecutable.c_str(),
00389 #endif
00390 m_serverExecutable.c_str(),
00391 m_spawnServerCommand.c_str(),
00392 m_logFile.c_str(),
00393 m_environment.c_str(),
00394 m_rubyCommand.c_str(),
00395 m_user.c_str(),
00396 NULL);
00397 int e = errno;
00398 fprintf(stderr, "*** Passenger ERROR: Cannot execute %s: %s (%d)\n",
00399 m_serverExecutable.c_str(), strerror(e), e);
00400 fflush(stderr);
00401 _exit(1);
00402 } else if (pid == -1) {
00403 close(fds[0]);
00404 close(fds[1]);
00405 throw SystemException("Cannot create a new process", errno);
00406 } else {
00407 close(fds[0]);
00408 serverSocket = fds[1];
00409 serverPid = pid;
00410 }
00411 }
00412
00413 public:
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 ApplicationPoolServer(const string &serverExecutable,
00440 const string &spawnServerCommand,
00441 const string &logFile = "",
00442 const string &environment = "production",
00443 const string &rubyCommand = "ruby",
00444 const string &user = "")
00445 : m_serverExecutable(serverExecutable),
00446 m_spawnServerCommand(spawnServerCommand),
00447 m_logFile(logFile),
00448 m_environment(environment),
00449 m_rubyCommand(rubyCommand),
00450 m_user(user) {
00451 serverSocket = -1;
00452 serverPid = 0;
00453 restartServer();
00454 }
00455
00456 ~ApplicationPoolServer() {
00457 if (serverSocket != -1) {
00458 shutdownServer();
00459 }
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 ApplicationPoolPtr connect() {
00491 MessageChannel channel(serverSocket);
00492 int clientConnection;
00493
00494
00495 channel.writeRaw("x", 1);
00496
00497 clientConnection = channel.readFileDescriptor();
00498 return ptr(new Client(clientConnection));
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 void detach() {
00516 close(serverSocket);
00517 serverSocket = -1;
00518 }
00519 };
00520
00521 typedef shared_ptr<ApplicationPoolServer> ApplicationPoolServerPtr;
00522
00523 }
00524
00525 #endif