2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/server/fastcgi/fastcgi-server.h"
19 #include "hphp/runtime/server/http-server.h"
20 #include "hphp/util/configs/server.h"
24 ////////////////////////////////////////////////////////////////////////////////
26 bool FastCGIAcceptor::canAccept(const folly::SocketAddress
& /*address*/) {
27 // TODO: Support server IP whitelist.
28 auto const cons
= m_server
->getLibEventConnectionCount();
29 return (Cfg::Server::ConnectionLimit
== 0 ||
30 cons
< Cfg::Server::ConnectionLimit
);
33 void FastCGIAcceptor::onNewConnection(
34 folly::AsyncTransportWrapper::UniquePtr sock
,
35 const folly::SocketAddress
* peerAddress
,
36 const std::string
& /*nextProtocolName*/,
37 SecureTransportType
/*secureProtocolType*/,
38 const ::wangle::TransportInfo
& /*tinfo*/) {
39 folly::SocketAddress localAddress
;
41 sock
->getLocalAddress(&localAddress
);
42 } catch (std::system_error
&) {
43 // If getSockName fails it's bad news; abort the connection
47 // Will delete itself when it gets a closing callback
48 auto session
= new FastCGISession(
49 m_server
->getEventBaseManager()->getExistingEventBase(),
50 m_server
->getDispatcher(),
56 // NB: ~ManagedConnection will call removeConnection() before the session
58 Acceptor::addConnection(session
);
61 void FastCGIAcceptor::onConnectionsDrained() {
62 m_server
->onConnectionsDrained();
65 ////////////////////////////////////////////////////////////////////////////////
67 FastCGIServer::FastCGIServer(const std::string
&address
,
71 : Server(address
, port
),
72 m_worker(&m_eventBaseManager
),
73 m_dispatcher(workers
, workers
,
74 Cfg::Server::ThreadDropCacheTimeoutSeconds
,
75 Cfg::Server::ThreadDropStack
,
77 Cfg::Server::ThreadJobLIFOSwitchThreshold
,
78 Cfg::Server::ThreadJobMaxQueuingMilliSeconds
,
79 RequestPriority::k_numPriorities
) {
80 folly::SocketAddress sock_addr
;
82 sock_addr
.setFromPath(address
);
83 } else if (address
.empty()) {
84 sock_addr
.setFromHostPort("localhost", port
);
85 assert(sock_addr
.isLoopbackAddress());
87 sock_addr
.setFromHostPort(address
, port
);
89 auto accConfig
= std::make_shared
<wangle::ServerSocketConfig
>();
90 accConfig
->bindAddress
= sock_addr
;
91 accConfig
->acceptBacklog
= Cfg::Server::Backlog
;
92 std::chrono::seconds timeout
;
93 if (Cfg::Server::ConnectionTimeoutSeconds
>= 0) {
94 timeout
= std::chrono::seconds(Cfg::Server::ConnectionTimeoutSeconds
);
96 // default to 2 minutes
97 timeout
= std::chrono::seconds(120);
99 accConfig
->connectionIdleTimeout
= timeout
;
100 m_socketConfig
= std::move(accConfig
);
103 void FastCGIServer::start() {
104 // It's not safe to call this function more than once
105 m_socket
.reset(new folly::AsyncServerSocket(m_worker
.getEventBase()));
107 m_socket
->bind(m_socketConfig
->bindAddress
);
108 } catch (const std::system_error
& ex
) {
109 Logger::Error(std::string(ex
.what()));
110 if (m_socketConfig
->bindAddress
.getFamily() == AF_UNIX
) {
111 throw FailedToListenException(m_socketConfig
->bindAddress
.getPath());
113 throw FailedToListenException(m_socketConfig
->bindAddress
.getAddressStr(),
114 m_socketConfig
->bindAddress
.getPort());
116 if (m_socketConfig
->bindAddress
.getFamily() == AF_UNIX
) {
117 auto path
= m_socketConfig
->bindAddress
.getPath();
118 chmod(path
.c_str(), 0760);
120 m_acceptor
.reset(new FastCGIAcceptor(m_socketConfig
, this));
121 m_acceptor
->init(m_socket
.get(), m_worker
.getEventBase());
122 m_worker
.getEventBase()->runInEventBaseThread([&] {
124 // Someone called stop before we got here. With the exception of a
125 // second call to start being made this should be safe as any place
126 // we mutate m_socket is done within the event base.
129 m_socket
->listen(m_socketConfig
->acceptBacklog
);
130 m_socket
->startAccepting();
132 setStatus(RunStatus::RUNNING
);
133 folly::AsyncTimeout::attachEventBase(m_worker
.getEventBase());
135 m_dispatcher
.start();
138 void FastCGIServer::waitForEnd() {
139 // When m_worker stops the server has stopped accepting new requests, there
140 // may be pedning vm jobs. wait() is always safe to call regardless of thread
144 void FastCGIServer::stop() {
145 if (getStatus() != RunStatus::RUNNING
) return; // nothing to do
147 setStatus(RunStatus::STOPPING
);
148 HttpServer::MarkShutdownStat(ShutdownEvent::SHUTDOWN_DRAIN_READS
);
150 m_worker
.getEventBase()->runInEventBaseThread([&] {
151 // Shutdown the server socket. Unfortunately, we will drop all unaccepted
152 // connections; there is no way to do a partial shutdown of a server socket
153 m_socket
->stopAccepting();
155 if (Cfg::Server::GracefulShutdownWait
> 0) {
156 // Gracefully drain any incomplete requests. We cannot go offline until
157 // they are finished as we own their dispatcher and event base.
159 m_acceptor
->startDrainingAllConnections();
162 std::chrono::seconds
s(Cfg::Server::GracefulShutdownWait
);
163 std::chrono::milliseconds
m(s
);
166 // Drop all connections. We cannot shutdown until they stop because we
167 // own their dispatcher and event base.
169 m_acceptor
->forceStop();
177 void FastCGIServer::onConnectionsDrained() {
178 // NOTE: called from FastCGIAcceptor::onConnectionsDrained()
183 void FastCGIServer::timeoutExpired() noexcept
{
184 // Acceptor failed to drain connections on time; drop them so that we can
187 m_acceptor
->forceStop();
193 void FastCGIServer::terminateServer() {
194 if (getStatus() != RunStatus::STOPPING
) {
195 setStatus(RunStatus::STOPPING
);
197 // Wait for the server socket thread to stop running
198 m_worker
.stopWhenIdle();
200 HttpServer::MarkShutdownStat(ShutdownEvent::SHUTDOWN_DRAIN_DISPATCHER
);
201 // Wait for VMs to shutdown
204 setStatus(RunStatus::STOPPED
);
205 HttpServer::MarkShutdownStat(ShutdownEvent::SHUTDOWN_DONE
);
207 // Notify HttpServer that we've shutdown
208 for (auto listener
: m_listeners
) {
209 listener
->serverStopped(this);
213 ////////////////////////////////////////////////////////////////////////////////