blob: 8935089695a535aa52aac6aeb522bcc91b31210e [file] [log] [blame]
/*
* Copyright (C) 2019 Sony Interactive Entertainment Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "RemoteInspectorServer.h"
#if ENABLE(REMOTE_INSPECTOR)
#include <wtf/JSONValues.h>
#include <wtf/MainThread.h>
namespace Inspector {
Optional<PlatformSocketType> RemoteInspectorServer::connect()
{
if (!m_server) {
LOG_ERROR("Inspector server is not running");
return WTF::nullopt;
}
if (auto sockets = Socket::createPair()) {
if (auto id = m_server->createClient(sockets->at(0))) {
LockHolder lock(m_connectionsLock);
m_inspectorConnections.append(id.value());
return sockets->at(1);
}
}
return WTF::nullopt;
}
Optional<uint16_t> RemoteInspectorServer::listenForTargets()
{
if (!m_server) {
LOG_ERROR("Inspector server is not running");
return WTF::nullopt;
}
if (m_inspectorListener) {
LOG_ERROR("Inspector server is already listening for targets.");
return WTF::nullopt;
}
if (auto connection = m_server->listenInet("127.0.0.1", 0)) {
m_inspectorListener = connection;
return m_server->getPort(*connection);
}
return WTF::nullopt;
}
void RemoteInspectorServer::didAccept(ConnectionID acceptedID, ConnectionID listenerID, Socket::Domain type)
{
ASSERT(!isMainThread());
if (type == Socket::Domain::Local || (m_inspectorListener && listenerID == *m_inspectorListener)) {
LockHolder lock(m_connectionsLock);
m_inspectorConnections.append(acceptedID);
} else if (type == Socket::Domain::Network) {
if (m_clientConnection) {
LOG_ERROR("Inspector server can accept only 1 client");
return;
}
m_clientConnection = acceptedID;
}
}
void RemoteInspectorServer::didClose(ConnectionID id)
{
ASSERT(!isMainThread());
if (id == m_clientConnection) {
// Connection from the remote client closed.
callOnMainThread([this] {
clientConnectionClosed();
});
return;
}
// Connection from WebProcess closed.
callOnMainThread([this, id] {
connectionClosed(id);
});
}
HashMap<String, RemoteInspectorConnectionClient::CallHandler>& RemoteInspectorServer::dispatchMap()
{
static NeverDestroyed<HashMap<String, CallHandler>> dispatchMap = HashMap<String, CallHandler>({
{ "SetTargetList"_s, reinterpret_cast<CallHandler>(&RemoteInspectorServer::setTargetList) },
{ "SetupInspectorClient"_s, reinterpret_cast<CallHandler>(&RemoteInspectorServer::setupInspectorClient) },
{ "Setup"_s, reinterpret_cast<CallHandler>(&RemoteInspectorServer::setup) },
{ "FrontendDidClose"_s, reinterpret_cast<CallHandler>(&RemoteInspectorServer::close) },
{ "SendMessageToFrontend"_s, reinterpret_cast<CallHandler>(&RemoteInspectorServer::sendMessageToFrontend) },
{ "SendMessageToBackend"_s, reinterpret_cast<CallHandler>(&RemoteInspectorServer::sendMessageToBackend) },
});
return dispatchMap;
}
void RemoteInspectorServer::sendWebInspectorEvent(ConnectionID id, const String& event)
{
const CString message = event.utf8();
m_server->send(id, reinterpret_cast<const uint8_t*>(message.data()), message.length());
}
RemoteInspectorServer& RemoteInspectorServer::singleton()
{
static NeverDestroyed<RemoteInspectorServer> server;
return server;
}
bool RemoteInspectorServer::start(uint16_t port)
{
m_server = RemoteInspectorSocketEndpoint::create(this, "RemoteInspectorServer");
if (!m_server->listenInet(nullptr, port)) {
m_server = nullptr;
return false;
}
return true;
}
void RemoteInspectorServer::setTargetList(const Event& event)
{
ASSERT(isMainThread());
if (!m_clientConnection || !event.message)
return;
auto targetListEvent = JSON::Object::create();
targetListEvent->setString("event"_s, "SetTargetList"_s);
targetListEvent->setInteger("connectionID"_s, event.clientID);
targetListEvent->setString("message"_s, event.message.value());
sendWebInspectorEvent(m_clientConnection.value(), targetListEvent->toJSONString());
}
void RemoteInspectorServer::setupInspectorClient(const Event&)
{
ASSERT(isMainThread());
auto setupEvent = JSON::Object::create();
setupEvent->setString("event"_s, "GetTargetList"_s);
LockHolder lock(m_connectionsLock);
for (auto connection : m_inspectorConnections)
sendWebInspectorEvent(connection, setupEvent->toJSONString());
}
void RemoteInspectorServer::setup(const Event& event)
{
ASSERT(isMainThread());
if (!event.targetID || !event.connectionID)
return;
m_inspectionTargets.add(std::make_pair(event.connectionID.value(), event.targetID.value()));
auto setupEvent = JSON::Object::create();
setupEvent->setString("event"_s, "Setup"_s);
setupEvent->setInteger("targetID"_s, event.targetID.value());
sendWebInspectorEvent(event.connectionID.value(), setupEvent->toJSONString());
}
void RemoteInspectorServer::sendCloseEvent(ConnectionID connectionID, TargetID targetID)
{
ASSERT(isMainThread());
auto closeEvent = JSON::Object::create();
closeEvent->setString("event"_s, "FrontendDidClose"_s);
closeEvent->setInteger("targetID"_s, targetID);
sendWebInspectorEvent(connectionID, closeEvent->toJSONString());
}
void RemoteInspectorServer::close(const Event& event)
{
ASSERT(isMainThread());
sendCloseEvent(event.connectionID.value(), event.targetID.value());
m_inspectionTargets.remove(std::make_pair(event.connectionID.value(), event.targetID.value()));
}
void RemoteInspectorServer::clientConnectionClosed()
{
ASSERT(isMainThread());
for (auto connectionTargetPair : m_inspectionTargets)
sendCloseEvent(connectionTargetPair.first, connectionTargetPair.second);
m_inspectionTargets.clear();
m_clientConnection = WTF::nullopt;
}
void RemoteInspectorServer::connectionClosed(ConnectionID clientID)
{
ASSERT(isMainThread());
LockHolder lock(m_connectionsLock);
if (m_inspectorConnections.removeFirst(clientID) && m_clientConnection) {
auto closedEvent = JSON::Object::create();
closedEvent->setString("event"_s, "SetTargetList"_s);
closedEvent->setInteger("connectionID"_s, clientID);
auto targetList = JSON::Array::create();
closedEvent->setString("message"_s, targetList->toJSONString());
sendWebInspectorEvent(m_clientConnection.value(), closedEvent->toJSONString());
}
}
void RemoteInspectorServer::sendMessageToBackend(const Event& event)
{
ASSERT(isMainThread());
if (!event.connectionID || !event.targetID || !event.message)
return;
auto sendEvent = JSON::Object::create();
sendEvent->setString("event"_s, "SendMessageToTarget"_s);
sendEvent->setInteger("targetID"_s, event.targetID.value());
sendEvent->setString("message"_s, event.message.value());
sendWebInspectorEvent(event.connectionID.value(), sendEvent->toJSONString());
}
void RemoteInspectorServer::sendMessageToFrontend(const Event& event)
{
if (!m_clientConnection)
return;
ASSERT(isMainThread());
if (!event.targetID || !event.message)
return;
auto sendEvent = JSON::Object::create();
sendEvent->setString("event"_s, "SendMessageToFrontend"_s);
sendEvent->setInteger("targetID"_s, event.targetID.value());
sendEvent->setInteger("connectionID"_s, event.clientID);
sendEvent->setString("message"_s, event.message.value());
sendWebInspectorEvent(m_clientConnection.value(), sendEvent->toJSONString());
}
} // namespace Inspector
#endif // ENABLE(REMOTE_INSPECTOR)