00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef _PASSENGER_SPAWN_MANAGER_H_
00026 #define _PASSENGER_SPAWN_MANAGER_H_
00027
00028 #include <string>
00029 #include <vector>
00030 #include <boost/shared_ptr.hpp>
00031 #include <boost/thread.hpp>
00032 #include <boost/function.hpp>
00033 #include <oxt/system_calls.hpp>
00034 #include <oxt/backtrace.hpp>
00035
00036 #include <sys/types.h>
00037 #include <sys/wait.h>
00038 #include <sys/stat.h>
00039 #include <arpa/inet.h>
00040 #include <cstdio>
00041 #include <cstdarg>
00042 #include <unistd.h>
00043 #include <errno.h>
00044 #include <grp.h>
00045 #include <pwd.h>
00046 #include <signal.h>
00047
00048 #include "AbstractSpawnManager.h"
00049 #include "ServerInstanceDir.h"
00050 #include "FileDescriptor.h"
00051 #include "Constants.h"
00052 #include "MessageChannel.h"
00053 #include "AccountsDatabase.h"
00054 #include "RandomGenerator.h"
00055 #include "Exceptions.h"
00056 #include "Logging.h"
00057 #include "Utils/Base64.h"
00058 #include "Utils/SystemTime.h"
00059
00060 namespace Passenger {
00061
00062 using namespace std;
00063 using namespace boost;
00064 using namespace oxt;
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 class SpawnManager: public AbstractSpawnManager {
00094 private:
00095 static const int SERVER_SOCKET_FD = 3;
00096 static const int OWNER_SOCKET_FD = 4;
00097 static const int HIGHEST_FD = OWNER_SOCKET_FD;
00098
00099 string spawnServerCommand;
00100 ServerInstanceDir::GenerationPtr generation;
00101 AccountsDatabasePtr accountsDatabase;
00102 string rubyCommand;
00103 AnalyticsLoggerPtr analyticsLogger;
00104
00105 boost::mutex lock;
00106 RandomGenerator random;
00107
00108 pid_t pid;
00109 FileDescriptor ownerSocket;
00110 string socketFilename;
00111 string socketPassword;
00112 bool serverNeedsRestart;
00113
00114 static void deleteAccount(AccountsDatabasePtr accountsDatabase, const string &username) {
00115 accountsDatabase->remove(username);
00116 }
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 void restartServer() {
00127 TRACE_POINT();
00128 if (pid != 0) {
00129 UPDATE_TRACE_POINT();
00130 ownerSocket.close();
00131
00132
00133
00134
00135
00136 time_t begin = syscalls::time(NULL);
00137 bool done = false;
00138 while (!done && syscalls::time(NULL) - begin < 5) {
00139 if (syscalls::waitpid(pid, NULL, WNOHANG) > 0) {
00140 done = true;
00141 } else {
00142 syscalls::usleep(100000);
00143 }
00144 }
00145 UPDATE_TRACE_POINT();
00146 if (!done) {
00147 UPDATE_TRACE_POINT();
00148 P_TRACE(2, "Spawn server did not exit in time, killing it...");
00149 syscalls::kill(pid, SIGTERM);
00150 begin = syscalls::time(NULL);
00151 while (syscalls::time(NULL) - begin < 5) {
00152 if (syscalls::waitpid(pid, NULL, WNOHANG) > 0) {
00153 break;
00154 } else {
00155 syscalls::usleep(100000);
00156 }
00157 }
00158 }
00159 pid = 0;
00160 }
00161
00162 FileDescriptor serverSocket;
00163 string socketFilename;
00164 string socketPassword;
00165 int ret, fds[2];
00166
00167 UPDATE_TRACE_POINT();
00168 socketFilename = generation->getPath() + "/spawn-server/socket." +
00169 toString(getpid()) + "." +
00170 toString((unsigned long long) this);
00171 socketPassword = Base64::encode(random.generateByteString(32));
00172 serverSocket = createUnixServer(socketFilename.c_str());
00173 do {
00174 ret = chmod(socketFilename.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
00175 } while (ret == -1 && errno == EINTR);
00176 if (ret == -1) {
00177 int e = errno;
00178 syscalls::unlink(socketFilename.c_str());
00179 throw FileSystemException("Cannot set permissions on '" + socketFilename + "'",
00180 e, socketFilename);
00181 }
00182
00183 if (syscalls::socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
00184 int e = errno;
00185 syscalls::unlink(socketFilename.c_str());
00186 throw SystemException("Cannot create a Unix socket", e);
00187 }
00188
00189 UPDATE_TRACE_POINT();
00190 pid = syscalls::fork();
00191 if (pid == 0) {
00192 dup2(serverSocket, HIGHEST_FD + 1);
00193 dup2(fds[1], HIGHEST_FD + 2);
00194 dup2(HIGHEST_FD + 1, SERVER_SOCKET_FD);
00195 dup2(HIGHEST_FD + 2, OWNER_SOCKET_FD);
00196
00197
00198 for (long i = sysconf(_SC_OPEN_MAX) - 1; i > HIGHEST_FD; i--) {
00199 close(i);
00200 }
00201
00202 execlp(rubyCommand.c_str(),
00203 rubyCommand.c_str(),
00204 spawnServerCommand.c_str(),
00205
00206
00207
00208
00209
00210
00211
00212 " ",
00213 (char *) NULL);
00214 int e = errno;
00215 fprintf(stderr, "*** Passenger ERROR (%s:%d):\n"
00216 "Could not start the spawn server: %s: %s (%d)\n",
00217 __FILE__, __LINE__,
00218 rubyCommand.c_str(), strerror(e), e);
00219 fflush(stderr);
00220 _exit(1);
00221 } else if (pid == -1) {
00222 int e = errno;
00223 syscalls::unlink(socketFilename.c_str());
00224 syscalls::close(fds[0]);
00225 syscalls::close(fds[1]);
00226 pid = 0;
00227 throw SystemException("Unable to fork a process", e);
00228 } else {
00229 FileDescriptor ownerSocket = fds[0];
00230 syscalls::close(fds[1]);
00231 serverSocket.close();
00232
00233
00234 MessageChannel ownerSocketChannel(ownerSocket);
00235 ownerSocketChannel.writeRaw(socketFilename + "\n");
00236 ownerSocketChannel.writeRaw(socketPassword + "\n");
00237 ownerSocketChannel.writeRaw(generation->getPath() + "\n");
00238 if (analyticsLogger != NULL) {
00239 ownerSocketChannel.writeRaw(analyticsLogger->getAddress() + "\n");
00240 ownerSocketChannel.writeRaw(analyticsLogger->getUsername() + "\n");
00241 ownerSocketChannel.writeRaw(Base64::encode(analyticsLogger->getPassword()) + "\n");
00242 ownerSocketChannel.writeRaw(analyticsLogger->getNodeName() + "\n");
00243 } else {
00244 ownerSocketChannel.writeRaw("\n");
00245 ownerSocketChannel.writeRaw("\n");
00246 ownerSocketChannel.writeRaw("\n");
00247 ownerSocketChannel.writeRaw("\n");
00248 }
00249
00250 this->ownerSocket = ownerSocket;
00251 this->socketFilename = socketFilename;
00252 this->socketPassword = socketPassword;
00253 spawnServerStarted();
00254 }
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264 FileDescriptor connect() const {
00265 TRACE_POINT();
00266 FileDescriptor fd = connectToUnixServer(socketFilename.c_str());
00267 MessageChannel channel(fd);
00268 UPDATE_TRACE_POINT();
00269 channel.writeScalar(socketPassword);
00270 return fd;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 ProcessPtr sendSpawnCommand(const PoolOptions &options) {
00283 TRACE_POINT();
00284 FileDescriptor connection;
00285 MessageChannel channel;
00286
00287 try {
00288 connection = connect();
00289 channel = MessageChannel(connection);
00290 } catch (const SystemException &e) {
00291 throw SpawnException(string("Could not connect to the spawn server: ") +
00292 e.sys());
00293 } catch (const std::exception &e) {
00294 throw SpawnException(string("Could not connect to the spawn server: ") +
00295 e.what());
00296 }
00297
00298 UPDATE_TRACE_POINT();
00299 vector<string> args;
00300 string appRoot;
00301 pid_t appPid;
00302 int i, nServerSockets, ownerPipe;
00303 Process::SocketInfoMap serverSockets;
00304 string detachKey = Base64::encode(random.generateByteString(32));
00305
00306
00307 string connectPassword = Base64::encodeForUrl(random.generateByteString(32));
00308 string gupid = random.generateAsciiString(11) + "-" + toString(SystemTime::get());
00309 AccountPtr account;
00310 function<void ()> destructionCallback;
00311
00312 try {
00313 args.push_back("spawn_application");
00314 options.toVector(args);
00315
00316 args.push_back("detach_key");
00317 args.push_back(detachKey);
00318 args.push_back("connect_password");
00319 args.push_back(connectPassword);
00320 if (accountsDatabase != NULL) {
00321 string username = "_backend-" + toString(accountsDatabase->getUniqueNumber());
00322 string password = random.generateByteString(MESSAGE_SERVER_MAX_PASSWORD_SIZE);
00323 account = accountsDatabase->add(username, password, false, options.rights);
00324 destructionCallback = boost::bind(&SpawnManager::deleteAccount,
00325 accountsDatabase, username);
00326
00327 args.push_back("pool_account_username");
00328 args.push_back(username);
00329 args.push_back("pool_account_password_base64");
00330 args.push_back(Base64::encode(password));
00331 }
00332
00333 channel.write(args);
00334 } catch (const SystemException &e) {
00335 throw SpawnException(string("Could not write 'spawn_application' "
00336 "command to the spawn server: ") + e.sys());
00337 }
00338
00339 try {
00340 UPDATE_TRACE_POINT();
00341
00342 if (!channel.read(args)) {
00343 throw SpawnException("The spawn server has exited unexpectedly.");
00344 }
00345 if (args.size() != 1) {
00346 throw SpawnException("The spawn server sent an invalid message.");
00347 }
00348 if (args[0] == "error_page") {
00349 UPDATE_TRACE_POINT();
00350 string errorPage;
00351
00352 if (!channel.readScalar(errorPage)) {
00353 throw SpawnException("The spawn server has exited unexpectedly.");
00354 }
00355 throw SpawnException("An error occured while spawning the application.",
00356 errorPage);
00357 } else if (args[0] != "ok") {
00358 throw SpawnException("The spawn server sent an invalid message.");
00359 }
00360
00361
00362 UPDATE_TRACE_POINT();
00363 if (!channel.read(args)) {
00364 throw SpawnException("The spawn server has exited unexpectedly.");
00365 }
00366 if (args.size() != 3) {
00367 throw SpawnException("The spawn server sent an invalid message.");
00368 }
00369
00370 appRoot = args[0];
00371 appPid = (pid_t) atoll(args[1].c_str());
00372 nServerSockets = atoi(args[2]);
00373
00374 UPDATE_TRACE_POINT();
00375 for (i = 0; i < nServerSockets; i++) {
00376 if (!channel.read(args)) {
00377 throw SpawnException("The spawn server has exited unexpectedly.");
00378 }
00379 if (args.size() != 3) {
00380 throw SpawnException("The spawn server sent an invalid message.");
00381 }
00382 serverSockets[args[0]] = Process::SocketInfo(args[1], args[2]);
00383 }
00384 if (serverSockets.find("main") == serverSockets.end()) {
00385 UPDATE_TRACE_POINT();
00386 throw SpawnException("The spawn server sent an invalid message.");
00387 }
00388 } catch (const SystemException &e) {
00389 throw SpawnException(string("Could not read from the spawn server: ") + e.sys());
00390 }
00391
00392 UPDATE_TRACE_POINT();
00393 try {
00394 ownerPipe = channel.readFileDescriptor();
00395 } catch (const SystemException &e) {
00396 throw SpawnException(string("Could not receive the spawned "
00397 "application's owner pipe from the spawn server: ") +
00398 e.sys());
00399 } catch (const IOException &e) {
00400 throw SpawnException(string("Could not receive the spawned "
00401 "application's owner pipe from the spawn server: ") +
00402 e.what());
00403 }
00404
00405 UPDATE_TRACE_POINT();
00406 return ProcessPtr(new Process(appRoot, appPid, ownerPipe, serverSockets,
00407 detachKey, connectPassword, gupid, destructionCallback));
00408 }
00409
00410
00411
00412
00413
00414 ProcessPtr
00415 handleSpawnException(const SpawnException &e, const PoolOptions &options) {
00416 TRACE_POINT();
00417 bool restarted;
00418 try {
00419 P_DEBUG("Spawn server died. Attempting to restart it...");
00420 this_thread::disable_syscall_interruption dsi;
00421 restartServer();
00422 P_DEBUG("Restart seems to be successful.");
00423 restarted = true;
00424 } catch (const IOException &e) {
00425 P_DEBUG("Restart failed: " << e.what());
00426 restarted = false;
00427 } catch (const SystemException &e) {
00428 P_DEBUG("Restart failed: " << e.what());
00429 restarted = false;
00430 }
00431 if (restarted) {
00432 return sendSpawnCommand(options);
00433 } else {
00434 throw SpawnException("The spawn server died unexpectedly, and restarting it failed.");
00435 }
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 void sendReloadCommand(const string &appRoot) {
00447 TRACE_POINT();
00448 FileDescriptor connection;
00449 MessageChannel channel;
00450
00451 try {
00452 connection = connect();
00453 channel = MessageChannel(connection);
00454 } catch (SystemException &e) {
00455 e.setBriefMessage("Could not connect to the spawn server");
00456 throw;
00457 } catch (const RuntimeException &e) {
00458 throw RuntimeException(string("Could not connect to the spawn server: ") +
00459 e.what());
00460 }
00461
00462 try {
00463 channel.write("reload", appRoot.c_str(), NULL);
00464 } catch (SystemException &e) {
00465 e.setBriefMessage("Could not write 'reload' command to the spawn server");
00466 throw;
00467 }
00468 }
00469
00470 void handleReloadException(const SystemException &e, const string &appRoot) {
00471 TRACE_POINT();
00472 bool restarted;
00473 try {
00474 P_DEBUG("Spawn server died. Attempting to restart it...");
00475 restartServer();
00476 P_DEBUG("Restart seems to be successful.");
00477 restarted = true;
00478 } catch (const IOException &e) {
00479 P_DEBUG("Restart failed: " << e.what());
00480 restarted = false;
00481 } catch (const SystemException &e) {
00482 P_DEBUG("Restart failed: " << e.what());
00483 restarted = false;
00484 }
00485 if (restarted) {
00486 return sendReloadCommand(appRoot);
00487 } else {
00488 throw SpawnException("The spawn server died unexpectedly, and restarting it failed.");
00489 }
00490 }
00491
00492 IOException prependMessageToException(const IOException &e, const string &message) {
00493 return IOException(message + ": " + e.what());
00494 }
00495
00496 SystemException prependMessageToException(const SystemException &e, const string &message) {
00497 return SystemException(message + ": " + e.brief(), e.code());
00498 }
00499
00500 protected:
00501
00502
00503
00504
00505 virtual void spawnServerStarted() { }
00506
00507 public:
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 SpawnManager(const string &spawnServerCommand,
00525 const ServerInstanceDir::GenerationPtr &generation,
00526 const AccountsDatabasePtr &accountsDatabase = AccountsDatabasePtr(),
00527 const string &rubyCommand = "ruby",
00528 const AnalyticsLoggerPtr &analyticsLogger = AnalyticsLoggerPtr()
00529 ) {
00530 TRACE_POINT();
00531 this->spawnServerCommand = spawnServerCommand;
00532 this->generation = generation;
00533 this->accountsDatabase = accountsDatabase;
00534 this->rubyCommand = rubyCommand;
00535 this->analyticsLogger = analyticsLogger;
00536 pid = 0;
00537 this_thread::disable_interruption di;
00538 this_thread::disable_syscall_interruption dsi;
00539 try {
00540 restartServer();
00541 } catch (const IOException &e) {
00542 throw prependMessageToException(e, "Could not start the spawn server");
00543 } catch (const SystemException &e) {
00544 throw prependMessageToException(e, "Could not start the spawn server");
00545 }
00546 }
00547
00548 virtual ~SpawnManager() {
00549 TRACE_POINT();
00550 if (pid != 0) {
00551 UPDATE_TRACE_POINT();
00552 this_thread::disable_interruption di;
00553 this_thread::disable_syscall_interruption dsi;
00554 syscalls::unlink(socketFilename.c_str());
00555 ownerSocket.close();
00556 syscalls::waitpid(pid, NULL, 0);
00557 }
00558 }
00559
00560 virtual ProcessPtr spawn(const PoolOptions &options) {
00561 TRACE_POINT();
00562 AnalyticsScopeLog scope(options.log, "spawn app process");
00563 ProcessPtr result;
00564 boost::mutex::scoped_lock l(lock);
00565
00566 try {
00567 result = sendSpawnCommand(options);
00568 } catch (const SpawnException &e) {
00569 if (e.hasErrorPage()) {
00570 throw;
00571 } else {
00572 result = handleSpawnException(e, options);
00573 }
00574 }
00575 scope.success();
00576 return result;
00577 }
00578
00579 virtual void reload(const string &appRoot) {
00580 TRACE_POINT();
00581 this_thread::disable_interruption di;
00582 this_thread::disable_syscall_interruption dsi;
00583 try {
00584 return sendReloadCommand(appRoot);
00585 } catch (const SystemException &e) {
00586 return handleReloadException(e, appRoot);
00587 }
00588 }
00589
00590 virtual void killSpawnServer() const {
00591 kill(pid, SIGKILL);
00592 }
00593
00594 virtual pid_t getServerPid() const {
00595 return pid;
00596 }
00597 };
00598
00599
00600 typedef shared_ptr<SpawnManager> SpawnManagerPtr;
00601
00602 }
00603
00604 #endif