Use custom AssemblyAnnotationWriter to improve vasm/llvm printing
[hiphop-php.git] / hphp / runtime / debugger / debugger_server.cpp
blob4600972eef10bff6fa5c1294d2cd6f2017005c2a
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 +----------------------------------------------------------------------+
16 #include "hphp/runtime/debugger/debugger_server.h"
18 #include <poll.h>
19 #include <exception>
21 #include "hphp/runtime/debugger/debugger_client.h"
22 #include "hphp/runtime/debugger/debugger.h"
23 #include "hphp/runtime/base/runtime-option.h"
24 #include "hphp/util/network.h"
25 #include "hphp/util/logger.h"
27 #define POLLING_SECONDS 1
29 namespace HPHP { namespace Eval {
30 ///////////////////////////////////////////////////////////////////////////////
31 TRACE_SET_MOD(debugger);
33 DebuggerServer DebuggerServer::s_debugger_server;
35 bool DebuggerServer::Start() {
36 TRACE(2, "DebuggerServer::Start\n");
37 if (RuntimeOption::EnableDebuggerServer) {
38 if (RuntimeOption::EnableDebuggerColor) {
39 Debugger::SetTextColors();
41 // Some server commands pre-formatted texts with color for clients.
42 // Loading a set of default colors for better display.
43 IniSetting::Map ini = IniSetting::Map::object;
44 Hdf hdf;
45 DebuggerClient::LoadColors(ini, hdf);
48 return s_debugger_server.start();
50 return true;
53 void DebuggerServer::Stop() {
54 TRACE(2, "DebuggerServer::Stop\n");
55 if (RuntimeOption::EnableDebuggerServer) {
56 s_debugger_server.stop();
60 ///////////////////////////////////////////////////////////////////////////////
62 DebuggerServer::DebuggerServer()
63 : m_serverThread(this, &DebuggerServer::accept), m_stopped(false) {
64 TRACE(2, "DebuggerServer::DebuggerServer\n");
67 DebuggerServer::~DebuggerServer() {
68 TRACE(2, "DebuggerServer::~DebuggerServer\n");
69 m_stopped = true;
70 m_serverThread.waitForEnd();
73 bool DebuggerServer::start() {
74 TRACE(2, "DebuggerServer::start\n");
75 int port = RuntimeOption::DebuggerServerPort;
76 int backlog = 128;
78 struct addrinfo hint;
79 struct addrinfo *ai;
80 memset(&hint, 0, sizeof(hint));
81 hint.ai_family = AF_UNSPEC;
82 hint.ai_socktype = SOCK_STREAM;
83 hint.ai_flags = AI_PASSIVE;
84 if (RuntimeOption::DebuggerDisableIPv6) {
85 hint.ai_family = AF_INET;
88 if (getaddrinfo(nullptr, std::to_string(port).c_str(), &hint, &ai)) {
89 Logger::Error("unable to get address information");
90 return false;
93 SCOPE_EXIT {
94 freeaddrinfo(ai);
97 /* use a cur pointer so we still have ai to be able to free the struct */
98 struct addrinfo *cur;
99 for (cur = ai; cur; cur = cur->ai_next) {
100 SmartPtr<Socket> m_sock;
101 int s_fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
102 if (s_fd < 0 && errno == EAFNOSUPPORT) {
103 continue;
105 m_sock = new Socket(s_fd, cur->ai_family, cur->ai_addr->sa_data, port);
107 int yes = 1;
108 setsockopt(m_sock->fd(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
110 if (!m_sock->valid()) {
111 Logger::Error("unable to create debugger server socket");
112 return false;
115 if (cur->ai_family == AF_INET6) {
116 int on = 1;
117 setsockopt(m_sock->fd(), IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
120 if (bind(m_sock->fd(), cur->ai_addr, cur->ai_addrlen) < 0) {
121 Logger::Error("unable to bind to port %d for debugger server", port);
122 return false;
124 if (listen(m_sock->fd(), backlog) < 0) {
125 Logger::Error("unable to listen on port %d for debugger server", port);
126 return false;
129 m_socks.push_back(m_sock);
132 if (m_socks.size() == 0) {
133 Logger::Error("Did not bind to any sockets on port %d", port);
134 return false;
137 m_serverThread.start();
138 return true;
141 void DebuggerServer::stop() {
142 TRACE(2, "DebuggerServer::stop\n");
143 m_stopped = true;
144 m_serverThread.waitForEnd();
145 m_socks.clear();
148 void DebuggerServer::accept() {
149 TRACE(2, "DebuggerServer::accept\n");
150 // Setup server-side usage logging before accepting any connections.
151 Debugger::InitUsageLogging();
152 // server loop
153 unsigned int count = m_socks.size();
154 struct pollfd fds[count];
156 unsigned int i = 0;
157 for (auto& m_sock : m_socks) {
158 fds[i].fd = m_sock->fd();
159 fds[i].events = POLLIN|POLLERR|POLLHUP;
160 i++;
163 while (!m_stopped) {
164 int ret = poll(fds, count, POLLING_SECONDS * 1000);
165 for (unsigned int i = 0; ret > 0 && i < count; i++) {
166 bool in = (fds[i].revents & POLLIN);
167 if (in) {
168 struct sockaddr sa;
169 socklen_t salen = sizeof(sa);
170 try {
171 Socket *new_sock = new Socket(::accept(m_socks[i]->fd(), &sa, &salen),
172 m_socks[i]->getType());
173 SmartPtr<Socket> ret(new_sock);
174 if (new_sock->valid()) {
175 Debugger::CreateProxy(ret, false);
176 } else {
177 Logger::Error("unable to accept incoming debugger request");
179 } catch (Exception &e) {
180 Logger::Error("%s", e.getMessage().c_str());
181 } catch (std::exception &e) {
182 Logger::Error("%s", e.what());
183 } catch (...) {
184 Logger::Error("(unknown exception was thrown)");
188 fds[i].revents = 0; // reset the POLLIN flag
189 } // else timed out, then we have a chance to check m_stopped bit
191 // A chance for some housekeeping...
192 Debugger::CleanupRetiredProxies();
195 for(auto &m_sock : m_socks) {
196 m_sock.reset();
200 ///////////////////////////////////////////////////////////////////////////////