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 #include <signal.h>
00030
00031 #include "MessageChannel.h"
00032 #include "ApplicationPool.h"
00033 #include "Application.h"
00034 #include "Exceptions.h"
00035 #include "Logging.h"
00036
00037 namespace Passenger {
00038
00039 using namespace std;
00040 using namespace boost;
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
00122 class ApplicationPoolServer {
00123 private:
00124
00125
00126
00127
00128
00129
00130
00131 struct SharedData {
00132
00133
00134
00135
00136 int server;
00137
00138 ~SharedData() {
00139 close(server);
00140 }
00141 };
00142
00143 typedef shared_ptr<SharedData> SharedDataPtr;
00144
00145
00146
00147
00148 class RemoteSession: public Application::Session {
00149 private:
00150 SharedDataPtr data;
00151 int id;
00152 int reader;
00153 int writer;
00154 pid_t pid;
00155 public:
00156 RemoteSession(SharedDataPtr data, pid_t pid, int id, int reader, int writer) {
00157 this->data = data;
00158 this->pid = pid;
00159 this->id = id;
00160 this->reader = reader;
00161 this->writer = writer;
00162 }
00163
00164 virtual ~RemoteSession() {
00165 closeReader();
00166 closeWriter();
00167 MessageChannel(data->server).write("close", toString(id).c_str(), NULL);
00168 }
00169
00170 virtual int getReader() const {
00171 return reader;
00172 }
00173
00174 virtual void closeReader() {
00175 if (reader != -1) {
00176 close(reader);
00177 reader = -1;
00178 }
00179 }
00180
00181 virtual int getWriter() const {
00182 return writer;
00183 }
00184
00185 virtual void closeWriter() {
00186 if (writer != -1) {
00187 close(writer);
00188 writer = -1;
00189 }
00190 }
00191
00192 virtual pid_t getPid() const {
00193 return pid;
00194 }
00195 };
00196
00197
00198
00199
00200
00201
00202 class Client: public ApplicationPool {
00203 private:
00204 SharedDataPtr data;
00205
00206 public:
00207
00208
00209
00210
00211
00212 Client(int sock) {
00213 data = ptr(new SharedData());
00214 data->server = sock;
00215 }
00216
00217 virtual void clear() {
00218 MessageChannel channel(data->server);
00219 channel.write("clear", NULL);
00220 }
00221
00222 virtual void setMaxIdleTime(unsigned int seconds) {
00223 MessageChannel channel(data->server);
00224 channel.write("setMaxIdleTime", toString(seconds).c_str(), NULL);
00225 }
00226
00227 virtual void setMax(unsigned int max) {
00228 MessageChannel channel(data->server);
00229 channel.write("setMax", toString(max).c_str(), NULL);
00230 }
00231
00232 virtual unsigned int getActive() const {
00233 MessageChannel channel(data->server);
00234 vector<string> args;
00235
00236 channel.write("getActive", NULL);
00237 channel.read(args);
00238 return atoi(args[0].c_str());
00239 }
00240
00241 virtual unsigned int getCount() const {
00242 MessageChannel channel(data->server);
00243 vector<string> args;
00244
00245 channel.write("getCount", NULL);
00246 channel.read(args);
00247 return atoi(args[0].c_str());
00248 }
00249
00250 virtual pid_t getSpawnServerPid() const {
00251 MessageChannel channel(data->server);
00252 vector<string> args;
00253
00254 channel.write("getSpawnServerPid", NULL);
00255 channel.read(args);
00256 return atoi(args[0].c_str());
00257 }
00258
00259 virtual Application::SessionPtr get(const string &appRoot, bool lowerPrivilege = true,
00260 const string &lowestUser = "nobody") {
00261 MessageChannel channel(data->server);
00262 vector<string> args;
00263 int reader, writer;
00264
00265 channel.write("get", appRoot.c_str(),
00266 (lowerPrivilege) ? "true" : "false",
00267 lowestUser.c_str(), NULL);
00268 if (!channel.read(args)) {
00269 throw IOException("The ApplicationPool server unexpectedly closed the connection.");
00270 }
00271 if (args[0] == "ok") {
00272 reader = channel.readFileDescriptor();
00273 writer = channel.readFileDescriptor();
00274 return ptr(new RemoteSession(data, atoi(args[1]), atoi(args[2]), reader, writer));
00275 } else if (args[0] == "SpawnException") {
00276 if (args[2] == "true") {
00277 string errorPage;
00278
00279 if (!channel.readScalar(errorPage)) {
00280 throw IOException("The ApplicationPool server unexpectedly closed the connection.");
00281 }
00282 throw SpawnException(args[1], errorPage);
00283 } else {
00284 throw SpawnException(args[1]);
00285 }
00286 } else if (args[0] == "IOException") {
00287 throw IOException(args[1]);
00288 } else {
00289 throw IOException("The ApplicationPool server returned an unknown message.");
00290 }
00291 }
00292 };
00293
00294
00295 static const int SERVER_SOCKET_FD = 3;
00296
00297 string m_serverExecutable;
00298 string m_spawnServerCommand;
00299 string m_logFile;
00300 string m_environment;
00301 string m_rubyCommand;
00302 string m_user;
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 pid_t serverPid;
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 int serverSocket;
00323
00324
00325
00326
00327
00328
00329
00330 void shutdownServer() {
00331 time_t begin;
00332 bool done;
00333 int ret;
00334
00335 do {
00336 ret = close(serverSocket);
00337 } while (ret == -1 && errno == EINTR);
00338
00339 P_DEBUG("Waiting for existing ApplicationPoolServerExecutable to exit...");
00340 begin = time(NULL);
00341 while (!done && time(NULL) < begin + 5) {
00342 done = waitpid(serverPid, NULL, WNOHANG) > 0;
00343 usleep(100000);
00344 }
00345 if (done) {
00346 P_DEBUG("ApplicationPoolServerExecutable exited.");
00347 } else {
00348 P_DEBUG("ApplicationPoolServerExecutable not exited in time. Killing it...");
00349 kill(serverPid, SIGTERM);
00350 waitpid(serverPid, NULL, 0);
00351 }
00352 serverSocket = -1;
00353 serverPid = 0;
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363 void restartServer() {
00364 int fds[2];
00365 pid_t pid;
00366
00367 if (serverPid != 0) {
00368 shutdownServer();
00369 }
00370
00371 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
00372 throw SystemException("Cannot create a Unix socket pair", errno);
00373 }
00374
00375 pid = fork();
00376 if (pid == 0) {
00377 dup2(fds[0], 3);
00378
00379
00380 for (long i = sysconf(_SC_OPEN_MAX) - 1; i > SERVER_SOCKET_FD; i--) {
00381 close(i);
00382 }
00383
00384 execlp(
00385 #if 0
00386 "valgrind",
00387 "valgrind",
00388 #else
00389 m_serverExecutable.c_str(),
00390 #endif
00391 m_serverExecutable.c_str(),
00392 m_spawnServerCommand.c_str(),
00393 m_logFile.c_str(),
00394 m_environment.c_str(),
00395 m_rubyCommand.c_str(),
00396 m_user.c_str(),
00397 NULL);
00398 int e = errno;
00399 fprintf(stderr, "*** Passenger ERROR: Cannot execute %s: %s (%d)\n",
00400 m_serverExecutable.c_str(), strerror(e), e);
00401 fflush(stderr);
00402 _exit(1);
00403 } else if (pid == -1) {
00404 close(fds[0]);
00405 close(fds[1]);
00406 throw SystemException("Cannot create a new process", errno);
00407 } else {
00408 close(fds[0]);
00409 serverSocket = fds[1];
00410 serverPid = pid;
00411 }
00412 }
00413
00414 public:
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
00440 ApplicationPoolServer(const string &serverExecutable,
00441 const string &spawnServerCommand,
00442 const string &logFile = "",
00443 const string &environment = "production",
00444 const string &rubyCommand = "ruby",
00445 const string &user = "")
00446 : m_serverExecutable(serverExecutable),
00447 m_spawnServerCommand(spawnServerCommand),
00448 m_logFile(logFile),
00449 m_environment(environment),
00450 m_rubyCommand(rubyCommand),
00451 m_user(user) {
00452 serverSocket = -1;
00453 serverPid = 0;
00454 restartServer();
00455 }
00456
00457 ~ApplicationPoolServer() {
00458 if (serverSocket != -1) {
00459 shutdownServer();
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
00491 ApplicationPoolPtr connect() {
00492 MessageChannel channel(serverSocket);
00493 int clientConnection;
00494
00495
00496 channel.writeRaw("x", 1);
00497
00498 clientConnection = channel.readFileDescriptor();
00499 return ptr(new Client(clientConnection));
00500 }
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 void detach() {
00517 close(serverSocket);
00518 serverSocket = -1;
00519 }
00520 };
00521
00522 typedef shared_ptr<ApplicationPoolServer> ApplicationPoolServerPtr;
00523
00524 }
00525
00526 #endif