// The 'self' parameter is for keeping the current Group object alive while this thread is running. void Group::spawnThreadOOBWRequest(GroupPtr self, ProcessPtr process) { TRACE_POINT(); this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; Socket *socket; Connection connection; Pool *pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; UPDATE_TRACE_POINT(); P_DEBUG("Performing OOBW request for process " << process->inspect()); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request about to start"); debug->messages->recv("Proceed with OOBW request"); } UPDATE_TRACE_POINT(); { // Standard resource management boilerplate stuff... boost::unique_lock<boost::mutex> lock(pool->syncher); if (OXT_UNLIKELY(!process->isAlive() || process->enabled == Process::DETACHED || !isAlive())) { return; } if (process->enabled != Process::DISABLED) { UPDATE_TRACE_POINT(); P_INFO("Out-of-Band Work canceled: process " << process->inspect() << " was concurrently re-enabled."); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request canceled"); } return; } assert(process->oobwStatus == Process::OOBW_IN_PROGRESS); assert(process->sessions == 0); socket = process->findSessionSocketWithLowestBusyness(); } UPDATE_TRACE_POINT(); unsigned long long timeout = 1000 * 1000 * 60; // 1 min try { this_thread::restore_interruption ri(di); this_thread::restore_syscall_interruption rsi(dsi); // Grab a connection. The connection is marked as fail in order to // ensure it is closed / recycled after this request (otherwise we'd // need to completely read the response). connection = socket->checkoutConnection(); connection.fail = true; ScopeGuard guard(boost::bind(&Socket::checkinConnection, socket, connection)); // This is copied from RequestHandler when it is sending data using the // "session" protocol. char sizeField[sizeof(boost::uint32_t)]; SmallVector<StaticString, 10> data; data.push_back(StaticString(sizeField, sizeof(boost::uint32_t))); data.push_back(P_STATIC_STRING_WITH_NULL("REQUEST_METHOD")); data.push_back(P_STATIC_STRING_WITH_NULL("OOBW")); data.push_back(P_STATIC_STRING_WITH_NULL("PASSENGER_CONNECT_PASSWORD")); data.push_back(getSecret()); data.push_back(StaticString("", 1)); boost::uint32_t dataSize = 0; for (unsigned int i = 1; i < data.size(); i++) { dataSize += (boost::uint32_t) data[i].size(); } Uint32Message::generate(sizeField, dataSize); gatheredWrite(connection.fd, &data[0], data.size(), &timeout); // We do not care what the actual response is ... just wait for it. UPDATE_TRACE_POINT(); waitUntilReadable(connection.fd, &timeout); } catch (const SystemException &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); } catch (const TimeoutException &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); } UPDATE_TRACE_POINT(); boost::container::vector<Callback> actions; { // Standard resource management boilerplate stuff... Pool *pool = getPool(); boost::unique_lock<boost::mutex> lock(pool->syncher); if (OXT_UNLIKELY(!process->isAlive() || !isAlive())) { return; } process->oobwStatus = Process::OOBW_NOT_ACTIVE; if (process->enabled == Process::DISABLED) { enable(process, actions); assignSessionsToGetWaiters(actions); } pool->fullVerifyInvariants(); initiateNextOobwRequest(); } UPDATE_TRACE_POINT(); runAllActions(actions); actions.clear(); UPDATE_TRACE_POINT(); P_DEBUG("Finished OOBW request for process " << process->inspect()); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request finished"); } }
dataSize += state.environmentVariablesSize; } return dataSize + 1; } bool Controller::constructHeaderForSessionProtocol(Request *req, char * restrict buffer, unsigned int &size, const SessionProtocolWorkingState &state, string delta_monotonic) { char *pos = buffer; const char *end = buffer + size; pos += sizeof(boost::uint32_t); pos = appendData(pos, end, P_STATIC_STRING_WITH_NULL("REQUEST_URI")); pos = appendData(pos, end, req->path.start->data, req->path.size); pos = appendData(pos, end, "", 1); pos = appendData(pos, end, P_STATIC_STRING_WITH_NULL("PATH_INFO")); pos = appendData(pos, end, state.path.data(), state.path.size()); pos = appendData(pos, end, "", 1); pos = appendData(pos, end, P_STATIC_STRING_WITH_NULL("SCRIPT_NAME")); if (state.hasBaseURI) { pos = appendData(pos, end, req->options.baseURI); pos = appendData(pos, end, "", 1); } else { pos = appendData(pos, end, P_STATIC_STRING_WITH_NULL("")); }