PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/runtime/base/server/http_server.cpp

https://github.com/diegoIta/hiphop-php
C++ | 489 lines | 390 code | 62 blank | 37 comment | 78 complexity | 2343783d948ad26953d510eb46e50f74 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010 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. +----------------------------------------------------------------------+
  15. */
  16. #include <runtime/base/server/http_server.h>
  17. #include <runtime/base/server/libevent_server.h>
  18. #include <runtime/base/server/libevent_server_with_takeover.h>
  19. #include <runtime/base/server/http_request_handler.h>
  20. #include <runtime/base/server/admin_request_handler.h>
  21. #include <runtime/base/server/server_stats.h>
  22. #include <runtime/base/runtime_option.h>
  23. #include <runtime/base/server/static_content_cache.h>
  24. #include <runtime/base/class_info.h>
  25. #include <runtime/base/source_info.h>
  26. #include <runtime/base/rtti_info.h>
  27. #include <runtime/base/memory/memory_manager.h>
  28. #include <util/logger.h>
  29. #include <runtime/base/externals.h>
  30. #include <runtime/base/util/http_client.h>
  31. #include <runtime/base/server/replay_transport.h>
  32. #include <runtime/base/program_functions.h>
  33. #include <util/db_conn.h>
  34. #include <util/log_aggregator.h>
  35. #include <runtime/ext/ext_apc.h>
  36. #include <sys/types.h>
  37. #include <signal.h>
  38. using namespace boost;
  39. using namespace std;
  40. namespace HPHP {
  41. ///////////////////////////////////////////////////////////////////////////////
  42. // statics
  43. HttpServerPtr HttpServer::Server;
  44. time_t HttpServer::StartTime;
  45. ///////////////////////////////////////////////////////////////////////////////
  46. HttpServer::HttpServer()
  47. : m_stopped(false),
  48. m_loggerThread(this, &HttpServer::flushLog),
  49. m_watchDog(this, &HttpServer::watchDog) {
  50. // enabling mutex profiling, but it's not turned on
  51. LockProfiler::s_pfunc_profile = server_stats_log_mutex;
  52. if (RuntimeOption::TakeoverFilename.empty()) {
  53. m_pageServer = ServerPtr
  54. (new TypedServer<LibEventServer, HttpRequestHandler>
  55. (RuntimeOption::ServerIP, RuntimeOption::ServerPort,
  56. RuntimeOption::ServerThreadCount,
  57. RuntimeOption::RequestTimeoutSeconds));
  58. } else {
  59. LibEventServerWithTakeover* server =
  60. (new TypedServer<LibEventServerWithTakeover, HttpRequestHandler>
  61. (RuntimeOption::ServerIP, RuntimeOption::ServerPort,
  62. RuntimeOption::ServerThreadCount,
  63. RuntimeOption::RequestTimeoutSeconds));
  64. server->setTransferFilename(RuntimeOption::TakeoverFilename);
  65. server->addTakeoverListener(this);
  66. m_pageServer = ServerPtr(server);
  67. }
  68. if (RuntimeOption::EnableSSL) {
  69. m_pageServer->enableSSL(RuntimeOption::SSLCertificateFile,
  70. RuntimeOption::SSLCertificateKeyFile,
  71. RuntimeOption::SSLPort);
  72. }
  73. m_adminServer = ServerPtr
  74. (new TypedServer<LibEventServer, AdminRequestHandler>
  75. (RuntimeOption::ServerIP, RuntimeOption::AdminServerPort,
  76. RuntimeOption::AdminThreadCount,
  77. RuntimeOption::RequestTimeoutSeconds));
  78. for (unsigned int i = 0; i < RuntimeOption::SatelliteServerInfos.size();
  79. i++) {
  80. SatelliteServerInfoPtr info = RuntimeOption::SatelliteServerInfos[i];
  81. SatelliteServerPtr satellite = SatelliteServer::Create(info);
  82. if (satellite) {
  83. if (info->getType() == SatelliteServer::KindOfDanglingPageServer) {
  84. m_danglings.push_back(satellite);
  85. } else {
  86. m_satellites.push_back(satellite);
  87. }
  88. }
  89. }
  90. if (RuntimeOption::EnableStaticContentCache) {
  91. StaticContentCache::TheCache.load();
  92. }
  93. ClassInfo::Load();
  94. SourceInfo::TheSourceInfo.load();
  95. RTTIInfo::TheRTTIInfo.init(true);
  96. hphp_process_init();
  97. Server::InstallStopSignalHandlers(m_pageServer);
  98. Server::InstallStopSignalHandlers(m_adminServer);
  99. if (!RuntimeOption::StartupDocument.empty()) {
  100. Hdf hdf;
  101. hdf["get"] = 1;
  102. hdf["url"] = RuntimeOption::StartupDocument;
  103. hdf["remote_host"] = RuntimeOption::ServerIP;
  104. ReplayTransport rt;
  105. rt.replayInput(hdf);
  106. HttpRequestHandler handler;
  107. handler.handleRequest(&rt);
  108. int code = rt.getResponseCode();
  109. if (code == 200) {
  110. Logger::Info("StartupDocument %s returned 200 OK: %s",
  111. RuntimeOption::StartupDocument.c_str(),
  112. rt.getResponse().c_str());
  113. } else {
  114. Logger::Error("StartupDocument %s failed %d: %s",
  115. RuntimeOption::StartupDocument.c_str(),
  116. code, rt.getResponse().data());
  117. return;
  118. }
  119. }
  120. for (unsigned int i = 0; i < RuntimeOption::ThreadDocuments.size(); i++) {
  121. ServiceThreadPtr thread
  122. (new ServiceThread(RuntimeOption::ThreadDocuments[i]));
  123. m_serviceThreads.push_back(thread);
  124. }
  125. }
  126. void HttpServer::onServerShutdown() {
  127. // When a new instance of HPHP has taken over our page server socket,
  128. // stop our admin server and satellites so it can acquire those ports.
  129. for (unsigned int i = 0; i < m_satellites.size(); i++) {
  130. string name = m_satellites[i]->getName();
  131. m_satellites[i]->stop();
  132. Logger::Info("satellite server %s stopped", name.c_str());
  133. }
  134. if (RuntimeOption::AdminServerPort) {
  135. m_adminServer->stop();
  136. Logger::Info("admin server stopped");
  137. }
  138. // start dangling servers, so they can serve old version of pages
  139. for (unsigned int i = 0; i < m_danglings.size(); i++) {
  140. string name = m_danglings[i]->getName();
  141. try {
  142. m_danglings[i]->start();
  143. Logger::Info("dangling server %s started", name.c_str());
  144. } catch (Exception &e) {
  145. Logger::Error("Unable to start danglings server %s: %s",
  146. name.c_str(), e.getMessage().c_str());
  147. // it's okay not able to start them
  148. }
  149. }
  150. }
  151. void HttpServer::takeoverShutdown(LibEventServerWithTakeover* server) {
  152. ASSERT(server == m_pageServer.get());
  153. // We want to synchronously shut down our satellite servers to free up ports,
  154. // then asynchronously shut down everything else.
  155. onServerShutdown();
  156. stop();
  157. }
  158. HttpServer::~HttpServer() {
  159. stop();
  160. }
  161. void HttpServer::run() {
  162. StartTime = time(0);
  163. m_loggerThread.start();
  164. m_watchDog.start();
  165. for (unsigned int i = 0; i < m_serviceThreads.size(); i++) {
  166. m_serviceThreads[i]->start();
  167. }
  168. for (unsigned int i = 0; i < m_serviceThreads.size(); i++) {
  169. m_serviceThreads[i]->waitForStarted();
  170. }
  171. if (RuntimeOption::ServerPort) {
  172. if (!startServer(true)) {
  173. Logger::Error("Unable to start page server");
  174. return;
  175. }
  176. Logger::Info("page server started");
  177. }
  178. if (RuntimeOption::AdminServerPort) {
  179. if (!startServer(false)) {
  180. Logger::Error("Unable to start admin server");
  181. abortServers();
  182. return;
  183. }
  184. Logger::Info("admin server started");
  185. }
  186. for (unsigned int i = 0; i < m_satellites.size(); i++) {
  187. string name = m_satellites[i]->getName();
  188. try {
  189. m_satellites[i]->start();
  190. Logger::Info("satellite server %s started", name.c_str());
  191. } catch (Exception &e) {
  192. Logger::Error("Unable to start satellite server %s: %s",
  193. name.c_str(), e.getMessage().c_str());
  194. abortServers();
  195. return;
  196. }
  197. }
  198. {
  199. Logger::Info("all servers started");
  200. createPid();
  201. Lock lock(this);
  202. // continously running until /stop is received on admin server
  203. while (!m_stopped) {
  204. wait();
  205. }
  206. removePid();
  207. Logger::Info("page server stopped");
  208. }
  209. onServerShutdown(); // dangling server already started here
  210. time_t t0 = time(0);
  211. if (RuntimeOption::ServerPort) {
  212. m_pageServer->stop();
  213. }
  214. time_t t1 = time(0);
  215. if (!m_danglings.empty() && RuntimeOption::ServerDanglingWait > 0) {
  216. int elapsed = t1 - t0;
  217. if (RuntimeOption::ServerDanglingWait > elapsed) {
  218. sleep(RuntimeOption::ServerDanglingWait - elapsed);
  219. }
  220. }
  221. for (unsigned int i = 0; i < m_danglings.size(); i++) {
  222. m_danglings[i]->stop();
  223. Logger::Info("dangling server %s stopped",
  224. m_danglings[i]->getName().c_str());
  225. }
  226. m_watchDog.waitForEnd();
  227. m_loggerThread.waitForEnd();
  228. Logger::Info("all servers stopped");
  229. }
  230. static void exit_on_timeout(int sig) {
  231. signal(sig, SIG_DFL);
  232. kill(getpid(), SIGKILL);
  233. exit(0);
  234. }
  235. void HttpServer::stop() {
  236. if (RuntimeOption::ServerGracefulShutdownWait) {
  237. signal(SIGALRM, exit_on_timeout);
  238. alarm(RuntimeOption::ServerGracefulShutdownWait);
  239. }
  240. Lock lock(this);
  241. m_stopped = true;
  242. notify();
  243. }
  244. void HttpServer::abortServers() {
  245. for (unsigned int i = 0; i < m_satellites.size(); i++) {
  246. m_satellites[i]->stop();
  247. }
  248. if (RuntimeOption::AdminServerPort) {
  249. m_adminServer->stop();
  250. }
  251. if (RuntimeOption::ServerPort) {
  252. m_pageServer->stop();
  253. }
  254. }
  255. void HttpServer::createPid() {
  256. if (!RuntimeOption::PidFile.empty()) {
  257. FILE * f = fopen(RuntimeOption::PidFile.c_str(), "w");
  258. if (f) {
  259. pid_t pid = Process::GetProcessId();
  260. char buf[64];
  261. snprintf(buf, sizeof(buf), "%lld", (int64)pid);
  262. fwrite(buf, strlen(buf), 1, f);
  263. fclose(f);
  264. } else {
  265. Logger::Error("Unable to open pid file %s for write",
  266. RuntimeOption::PidFile.c_str());
  267. }
  268. }
  269. }
  270. void HttpServer::removePid() {
  271. if (!RuntimeOption::PidFile.empty()) {
  272. unlink(RuntimeOption::PidFile.c_str());
  273. }
  274. }
  275. void HttpServer::killPid() {
  276. if (!RuntimeOption::PidFile.empty()) {
  277. StringBuffer sb(RuntimeOption::PidFile.c_str());
  278. if (sb.size()) {
  279. int64 pid = sb.detach().toInt64();
  280. if (pid) {
  281. kill((pid_t)pid, SIGKILL);
  282. return;
  283. }
  284. }
  285. Logger::Error("Unable to read pid file %s for any meaningful pid",
  286. RuntimeOption::PidFile.c_str());
  287. }
  288. }
  289. ///////////////////////////////////////////////////////////////////////////////
  290. // logger thread
  291. void HttpServer::flushLog() {
  292. if (!Logger::UseLogAggregator) return;
  293. ServerDataPtr database;
  294. ostream *out = NULL;
  295. if (!RuntimeOption::LogAggregatorDatabase.empty()) {
  296. database = ServerData::Create(RuntimeOption::LogAggregatorDatabase);
  297. } else if (!RuntimeOption::LogAggregatorFile.empty()) {
  298. out = new ofstream(RuntimeOption::LogAggregatorFile.c_str());
  299. } else {
  300. out = &cout;
  301. }
  302. bool stopped = false;
  303. while (!stopped) {
  304. if (database) {
  305. LogAggregator::TheLogAggregator.flush(database);
  306. } else {
  307. LogAggregator::TheLogAggregator.flush(*out);
  308. }
  309. sleep(RuntimeOption::LogAggregatorSleepSeconds);
  310. Lock lock(this);
  311. stopped = m_stopped;
  312. }
  313. if (out != &cout) {
  314. delete out;
  315. }
  316. }
  317. ///////////////////////////////////////////////////////////////////////////////
  318. // watch dog thread
  319. void HttpServer::watchDog() {
  320. int count = 0;
  321. while (!m_stopped) {
  322. if (RuntimeOption::DropCacheCycle > 0 &&
  323. (count % RuntimeOption::DropCacheCycle) == 0) { // every hour
  324. dropCache();
  325. }
  326. sleep(1);
  327. ++count;
  328. if (RuntimeOption::MaxRSSPollingCycle > 0 &&
  329. (count % RuntimeOption::MaxRSSPollingCycle) == 0) { // every minute
  330. checkMemory();
  331. }
  332. }
  333. }
  334. void HttpServer::dropCache() {
  335. FILE *f = fopen("/proc/sys/vm/drop_caches", "w");
  336. if (f) {
  337. // http://www.linuxinsight.com/proc_sys_vm_drop_caches.html
  338. const char *FREE_ALL_CACHES = "3\n";
  339. fwrite(FREE_ALL_CACHES, 2, 1, f);
  340. fclose(f);
  341. }
  342. }
  343. void HttpServer::checkMemory() {
  344. if (RuntimeOption::MaxRSS > 0 &&
  345. Process::GetProcessRSS(Process::GetProcessId()) * 1024 * 1024 >
  346. RuntimeOption::MaxRSS) {
  347. stop();
  348. }
  349. }
  350. ///////////////////////////////////////////////////////////////////////////////
  351. // page server
  352. bool HttpServer::startServer(bool pageServer) {
  353. int port = pageServer ?
  354. RuntimeOption::ServerPort : RuntimeOption::AdminServerPort;
  355. // 1. try something nice
  356. for (unsigned int i = 0; i < 60; i++) {
  357. try {
  358. if (pageServer) {
  359. m_pageServer->start();
  360. } else {
  361. m_adminServer->start();
  362. }
  363. return true;
  364. } catch (FailedToListenException &e) {
  365. if (i == 0) {
  366. Logger::Info("shutting down old HPHP server by /stop command");
  367. }
  368. if (errno == EACCES) {
  369. Logger::Error("Permission denied listening on port %d", port);
  370. return false;
  371. }
  372. HttpClient http;
  373. string url = "http://";
  374. url += RuntimeOption::ServerIP;
  375. url += ":";
  376. url += lexical_cast<string>(RuntimeOption::AdminServerPort);
  377. url += "/stop";
  378. StringBuffer response;
  379. http.get(url.c_str(), response);
  380. sleep(1);
  381. }
  382. }
  383. // 2. try something harsh
  384. if (RuntimeOption::ServerHarshShutdown) {
  385. for (unsigned int i = 0; i < 5; i++) {
  386. try {
  387. if (pageServer) {
  388. m_pageServer->start();
  389. } else {
  390. m_adminServer->start();
  391. }
  392. return true;
  393. } catch (FailedToListenException &e) {
  394. if (i == 0) {
  395. Logger::Info("shutting down old HPHP server by pid file");
  396. }
  397. killPid();
  398. sleep(1);
  399. }
  400. }
  401. }
  402. // 3. try something evil
  403. if (RuntimeOption::ServerEvilShutdown) {
  404. for (unsigned int i = 0; i < 60; i++) {
  405. try {
  406. if (pageServer) {
  407. m_pageServer->start();
  408. } else {
  409. m_adminServer->start();
  410. }
  411. return true;
  412. } catch (FailedToListenException &e) {
  413. if (i == 0) {
  414. Logger::Info("killing anything listening on port %d", port);
  415. }
  416. string cmd = "lsof -t -i :";
  417. cmd += lexical_cast<string>(port);
  418. cmd += " | xargs kill -9";
  419. Util::ssystem(cmd.c_str());
  420. sleep(1);
  421. }
  422. }
  423. }
  424. return false;
  425. }
  426. ///////////////////////////////////////////////////////////////////////////////
  427. }