2 +----------------------------------------------------------------------+
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"
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
;
45 DebuggerClient::LoadColors(ini
, hdf
);
48 return s_debugger_server
.start();
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");
70 m_serverThread
.waitForEnd();
73 bool DebuggerServer::start() {
74 TRACE(2, "DebuggerServer::start\n");
75 int port
= RuntimeOption::DebuggerServerPort
;
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");
97 /* use a cur pointer so we still have ai to be able to free the struct */
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
) {
105 m_sock
= new Socket(s_fd
, cur
->ai_family
, cur
->ai_addr
->sa_data
, port
);
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");
115 if (cur
->ai_family
== AF_INET6
) {
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
);
124 if (listen(m_sock
->fd(), backlog
) < 0) {
125 Logger::Error("unable to listen on port %d for debugger server", port
);
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
);
137 m_serverThread
.start();
141 void DebuggerServer::stop() {
142 TRACE(2, "DebuggerServer::stop\n");
144 m_serverThread
.waitForEnd();
148 void DebuggerServer::accept() {
149 TRACE(2, "DebuggerServer::accept\n");
150 // Setup server-side usage logging before accepting any connections.
151 Debugger::InitUsageLogging();
153 unsigned int count
= m_socks
.size();
154 struct pollfd fds
[count
];
157 for (auto& m_sock
: m_socks
) {
158 fds
[i
].fd
= m_sock
->fd();
159 fds
[i
].events
= POLLIN
|POLLERR
|POLLHUP
;
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
);
169 socklen_t salen
= sizeof(sa
);
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);
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());
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
) {
200 ///////////////////////////////////////////////////////////////////////////////