From b538a34e8929fdc7ca8bd7d24da513327fd53a06 Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 28 Jan 2014 15:33:17 -0800 Subject: [PATCH] Support for UNIX sockets Add a new config param, Server.FileSocket. When Server.FileSocket is set it will be used inplace of a network socket for the primary server. This uses a new parameter to ServerOptions, m_useFileSocket, to toggle between treating the address as a socket path or a network address. To initialize a socket connection thrift expects the socket file to not exist. To support this the 'something nice' retry in startServer will unlink an existing socket only if fuser claims it is unused. Server.EvilShutdown enables unlinking the socket regardless of current users. Closes #1594 Reviewed By: @ptarjan Differential Revision: D1135876 Pulled By: @sgolemon --- hphp/runtime/base/runtime-option.cpp | 2 + hphp/runtime/base/runtime-option.h | 1 + .../server/fastcgi/fastcgi-server-factory.cpp | 3 +- .../runtime/server/fastcgi/fastcgi-server.cpp | 15 +++-- hphp/runtime/server/fastcgi/fastcgi-server.h | 3 +- hphp/runtime/server/http-server.cpp | 59 +++++++++++++++---- hphp/runtime/server/server.h | 7 ++- 7 files changed, 71 insertions(+), 19 deletions(-) diff --git a/hphp/runtime/base/runtime-option.cpp b/hphp/runtime/base/runtime-option.cpp index 8129495ad..5099f1a8c 100644 --- a/hphp/runtime/base/runtime-option.cpp +++ b/hphp/runtime/base/runtime-option.cpp @@ -107,6 +107,7 @@ std::string RuntimeOption::Host; std::string RuntimeOption::DefaultServerNameSuffix; std::string RuntimeOption::ServerType = "libevent"; std::string RuntimeOption::ServerIP; +std::string RuntimeOption::ServerFileSocket; std::string RuntimeOption::ServerPrimaryIP; int RuntimeOption::ServerPort; int RuntimeOption::ServerPortFd = -1; @@ -721,6 +722,7 @@ void RuntimeOption::Load(Hdf &config, DefaultServerNameSuffix = server["DefaultServerNameSuffix"].getString(); ServerType = server["Type"].getString(ServerType); ServerIP = server["IP"].getString(); + ServerFileSocket = server["FileSocket"].getString(); ServerPrimaryIP = Util::GetPrimaryIP(); ServerPort = server["Port"].getUInt16(80); ServerBacklog = server["Backlog"].getInt16(128); diff --git a/hphp/runtime/base/runtime-option.h b/hphp/runtime/base/runtime-option.h index 51df0e3da..2384abb08 100644 --- a/hphp/runtime/base/runtime-option.h +++ b/hphp/runtime/base/runtime-option.h @@ -109,6 +109,7 @@ public: static std::string DefaultServerNameSuffix; static std::string ServerType; static std::string ServerIP; + static std::string ServerFileSocket; static std::string ServerPrimaryIP; static int ServerPort; static int ServerPortFd; diff --git a/hphp/runtime/server/fastcgi/fastcgi-server-factory.cpp b/hphp/runtime/server/fastcgi/fastcgi-server-factory.cpp index 012902d0a..2b2fdc095 100644 --- a/hphp/runtime/server/fastcgi/fastcgi-server-factory.cpp +++ b/hphp/runtime/server/fastcgi/fastcgi-server-factory.cpp @@ -25,7 +25,8 @@ public: virtual ServerPtr createServer(const ServerOptions& options) override { return std::make_shared(options.m_address, options.m_port, - options.m_numThreads); + options.m_numThreads, + options.m_useFileSocket); } }; diff --git a/hphp/runtime/server/fastcgi/fastcgi-server.cpp b/hphp/runtime/server/fastcgi/fastcgi-server.cpp index 1e7287a93..b8001ea7f 100644 --- a/hphp/runtime/server/fastcgi/fastcgi-server.cpp +++ b/hphp/runtime/server/fastcgi/fastcgi-server.cpp @@ -183,7 +183,8 @@ void FastCGIConnection::handleRequest(int transport_id) { FastCGIServer::FastCGIServer(const std::string &address, int port, - int workers) + int workers, + bool useFileSocket) : Server(address, port, workers), m_worker(&m_eventBaseManager), m_dispatcher(workers, @@ -195,7 +196,9 @@ FastCGIServer::FastCGIServer(const std::string &address, RuntimeOption::ServerThreadJobMaxQueuingMilliSeconds, RequestPriority::k_numPriorities) { TSocketAddress sock_addr; - if (address.empty()) { + if (useFileSocket) { + sock_addr.setFromPath(address); + } else if (address.empty()) { sock_addr.setFromLocalPort(port); } else { sock_addr.setFromHostPort(address, port); @@ -226,8 +229,12 @@ void FastCGIServer::start() { m_socket->bind(m_socketConfig.getAddress()); } catch (const apache::thrift::transport::TTransportException& ex) { LOG(ERROR) << ex.what(); - throw FailedToListenException(m_socketConfig.getAddress().getAddressStr(), - m_socketConfig.getAddress().getPort()); + if (m_socketConfig.getAddress().getFamily() == AF_UNIX) { + throw FailedToListenException(m_socketConfig.getAddress().getPath()); + } else { + throw FailedToListenException(m_socketConfig.getAddress().getAddressStr(), + m_socketConfig.getAddress().getPort()); + } } m_acceptor.reset(new FastCGIAcceptor(m_socketConfig, this)); m_acceptor->init(m_socket.get(), m_worker.getEventBase()); diff --git a/hphp/runtime/server/fastcgi/fastcgi-server.h b/hphp/runtime/server/fastcgi/fastcgi-server.h index 5163a59f7..94a66a626 100644 --- a/hphp/runtime/server/fastcgi/fastcgi-server.h +++ b/hphp/runtime/server/fastcgi/fastcgi-server.h @@ -128,7 +128,8 @@ class FastCGIServer : public Server, public: FastCGIServer(const std::string &address, int port, - int workers); + int workers, + bool useFileSocket); ~FastCGIServer() { if (!m_done) { waitForEnd(); diff --git a/hphp/runtime/server/http-server.cpp b/hphp/runtime/server/http-server.cpp index 047033c70..d877d998c 100644 --- a/hphp/runtime/server/http-server.cpp +++ b/hphp/runtime/server/http-server.cpp @@ -77,9 +77,11 @@ HttpServer::HttpServer() auto serverFactory = ServerFactoryRegistry::getInstance()->getFactory (RuntimeOption::ServerType); - ServerOptions options - (RuntimeOption::ServerIP, RuntimeOption::ServerPort, - startingThreadCount); + const std::string address = RuntimeOption::ServerFileSocket.empty() + ? RuntimeOption::ServerIP : RuntimeOption::ServerFileSocket; + ServerOptions options( + address, RuntimeOption::ServerPort, startingThreadCount); + options.m_useFileSocket = !RuntimeOption::ServerFileSocket.empty(); options.m_serverFD = RuntimeOption::ServerPortFd; options.m_sslFD = RuntimeOption::SSLPortFd; options.m_takeoverFilename = RuntimeOption::TakeoverFilename; @@ -498,7 +500,12 @@ bool HttpServer::startServer(bool pageServer) { } if (errno == EACCES) { - Logger::Error("Permission denied listening on port %d", port); + if (pageServer && !RuntimeOption::ServerFileSocket.empty()) { + Logger::Error("Permission denied opening socket at %s", + RuntimeOption::ServerFileSocket.c_str()); + } else { + Logger::Error("Permission denied listening on port %d", port); + } return false; } @@ -511,6 +518,22 @@ bool HttpServer::startServer(bool pageServer) { StringBuffer response; http.get(url.c_str(), response); + if (pageServer && !RuntimeOption::ServerFileSocket.empty()) { + if (i == 0) { + Logger::Info("Unlinking unused socket at %s", + RuntimeOption::ServerFileSocket.c_str()); + } + struct stat stat_buf; + if (stat(RuntimeOption::ServerFileSocket.c_str(), &stat_buf) == 0 + && S_ISSOCK(stat_buf.st_mode)) { + std::string cmd = "bash -c '! fuser "; + cmd += RuntimeOption::ServerFileSocket; + cmd += "'"; + if (Util::ssystem(cmd.c_str()) == 0) { + unlink(RuntimeOption::ServerFileSocket.c_str()); + } + } + } sleep(1); } } @@ -546,15 +569,27 @@ bool HttpServer::startServer(bool pageServer) { } return true; } catch (FailedToListenException &e) { - if (i == 0) { - Logger::Info("killing anything listening on port %d", port); + if (pageServer && !RuntimeOption::ServerFileSocket.empty()) { + if (i == 0) { + Logger::Info("unlinking socket at %s", + RuntimeOption::ServerFileSocket.c_str()); + } + + struct stat stat_buf; + if (stat(RuntimeOption::ServerFileSocket.c_str(), &stat_buf) == 0 + && S_ISSOCK(stat_buf.st_mode)) { + unlink(RuntimeOption::ServerFileSocket.c_str()); + } + } else { + if (i == 0) { + Logger::Info("killing anything listening on port %d", port); + } + + std::string cmd = "lsof -t -i :"; + cmd += lexical_cast(port); + cmd += " | xargs kill -9"; + Util::ssystem(cmd.c_str()); } - - std::string cmd = "lsof -t -i :"; - cmd += lexical_cast(port); - cmd += " | xargs kill -9"; - Util::ssystem(cmd.c_str()); - sleep(1); } } diff --git a/hphp/runtime/server/server.h b/hphp/runtime/server/server.h index 56de10519..c8d7d2758 100644 --- a/hphp/runtime/server/server.h +++ b/hphp/runtime/server/server.h @@ -265,7 +265,8 @@ public: m_numThreads(numThreads), m_serverFD(-1), m_sslFD(-1), - m_takeoverFilename() { + m_takeoverFilename(), + m_useFileSocket(false) { } std::string m_address; @@ -274,6 +275,7 @@ public: int m_serverFD; int m_sslFD; std::string m_takeoverFilename; + bool m_useFileSocket; }; /** @@ -327,6 +329,9 @@ public: class FailedToListenException : public ServerException { public: + explicit FailedToListenException(const std::string &addr) + : ServerException("Failed to listen to unix socket at %s", addr.c_str()) { + } FailedToListenException(const std::string &addr, int port) : ServerException("Failed to listen on %s:%d", addr.c_str(), port) { }