From 9b2c77380599bb1619b996b4b3a3da423917ceeb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 17 Aug 2021 22:37:43 +1200 Subject: [PATCH 1/6] Move WebRTCSignalingServer into Domain Server --- domain-server/src/DomainServer.cpp | 40 +++++++++++++++++++ domain-server/src/DomainServer.h | 16 ++++++++ ice-server/src/IceServer.cpp | 1 + .../src/BaseAssetScriptingInterface.cpp | 3 +- libraries/networking/src/LimitedNodeList.cpp | 8 +++- libraries/networking/src/LimitedNodeList.h | 5 ++- .../networking/src/udt/NetworkSocket.cpp | 7 ++++ libraries/networking/src/udt/NetworkSocket.h | 11 ++++- libraries/networking/src/udt/Socket.cpp | 6 +++ libraries/networking/src/udt/Socket.h | 4 ++ .../networking/src/webrtc/WebRTCSocket.cpp | 13 +++--- .../networking/src/webrtc/WebRTCSocket.h | 25 ++++++++---- 12 files changed, 119 insertions(+), 20 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index c49f175866..341c658ce7 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -167,6 +167,10 @@ DomainServer::DomainServer(int argc, char* argv[]) : _gatekeeper(this), _httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this) +#if defined(WEBRTC_DATA_CHANNELS) + , + _webrtcSignalingServer(this) +#endif { if (_parentPID != -1) { watchParentProcess(_parentPID); @@ -248,6 +252,10 @@ DomainServer::DomainServer(int argc, char* argv[]) : updateDownstreamNodes(); updateUpstreamNodes(); +#if defined(WEBRTC_DATA_CHANNELS) + setUpWebRTCSignalingServer(); +#endif + if (_type != NonMetaverse) { // if we have a metaverse domain, we'll use an access token for API calls resetAccountManagerAccessToken(); @@ -846,6 +854,38 @@ void DomainServer::setupNodeListAndAssignments() { addStaticAssignmentsToQueue(); } + +#if defined(WEBRTC_DATA_CHANNELS) + +void DomainServer::setUpWebRTCSignalingServer() { + // Bind the WebRTC signaling server's WebSocket to its port. + bool isBound = _webrtcSignalingServer.bind(QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT); + if (!isBound) { + qWarning() << "WebRTC signaling server not bound to port. WebRTC connections are not supported."; + return; + } + + auto limitedNodeList = DependencyManager::get(); + + // Route inbound WebRTC signaling messages received from user clients. + connect(&_webrtcSignalingServer, &WebRTCSignalingServer::messageReceived, + this, &DomainServer::routeWebRTCSignalingMessage); + + // Route domain server signaling messages. + auto webrtcSocket = limitedNodeList->getWebRTCSocket(); + connect(this, &DomainServer::webrtcSignalingMessageForDomainServer, webrtcSocket, &WebRTCSocket::onSignalingMessage); + connect(webrtcSocket, &WebRTCSocket::sendSignalingMessage, &_webrtcSignalingServer, &WebRTCSignalingServer::sendMessage); +} + +void DomainServer::routeWebRTCSignalingMessage(const QJsonObject& json) { + if (json.value("to").toString() == NodeType::DomainServer) { + emit webrtcSignalingMessageForDomainServer(json); + } +} + +#endif + + bool DomainServer::resetAccountManagerAccessToken() { if (!_oauthProviderURL.isEmpty()) { // check for an access-token in our settings, can optionally be overidden by env value diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index bfcc867630..3f509b232d 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "AssetsBackupHandler.h" #include "DomainGatekeeper.h" @@ -155,6 +157,11 @@ signals: void userConnected(); void userDisconnected(); +#if defined(WEBRTC_DATA_CHANNELS) + void webrtcSignalingMessageForDomainServer(const QJsonObject& json); +#endif + + private: QUuid getID(); @@ -235,6 +242,11 @@ private: std::initializer_list optionalData = { }, bool requireAccessToken = true); +#if defined(WEBRTC_DATA_CHANNELS) + void setUpWebRTCSignalingServer(); + void routeWebRTCSignalingMessage(const QJsonObject& json); +#endif + QString operationToString(const QNetworkAccessManager::Operation &op); SubnetList _acSubnetWhitelist; @@ -312,6 +324,10 @@ private: std::unordered_map> _pendingContentFiles; QThread _assetClientThread; + +#if defined(WEBRTC_DATA_CHANNELS) + WebRTCSignalingServer _webrtcSignalingServer; +#endif }; diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 6a6290f7b2..b4542e12a0 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include diff --git a/libraries/networking/src/BaseAssetScriptingInterface.cpp b/libraries/networking/src/BaseAssetScriptingInterface.cpp index d7d14496ba..f9dd12b279 100644 --- a/libraries/networking/src/BaseAssetScriptingInterface.cpp +++ b/libraries/networking/src/BaseAssetScriptingInterface.cpp @@ -9,8 +9,9 @@ #include "BaseAssetScriptingInterface.h" -#include #include +#include +#include #include #include diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 32e63d4b9a..e742363373 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -74,7 +74,7 @@ LimitedNodeList::LimitedNodeList(char ownerType, int socketListenPort, int dtlsL qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); } - _nodeSocket.bind(SocketType::WebRTC, QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT); + _nodeSocket.bind(SocketType::WebRTC, QHostAddress::AnyIPv4); // check for local socket updates every so often const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000; @@ -241,6 +241,12 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { return *_dtlsSocket; } +#if defined(WEBRTC_DATA_CHANNELS) +const WebRTCSocket* LimitedNodeList::getWebRTCSocket() { + return _nodeSocket.getWebRTCSocket(); +} +#endif + bool LimitedNodeList::isPacketVerifiedWithSource(const udt::Packet& packet, Node* sourceNode) { // We track bandwidth when doing packet verification to avoid needing to do a node lookup // later when we already do it in packetSourceAndHashMatchAndTrackBandwidth. A node lookup diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 9e6458225f..81d93bf935 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -37,7 +37,6 @@ #include #include -#include "DomainHandler.h" #include "NetworkingConstants.h" #include "Node.h" #include "NLPacket.h" @@ -139,6 +138,10 @@ public: Q_INVOKABLE void setSocketLocalPort(SocketType socketType, quint16 socketLocalPort); QUdpSocket& getDTLSSocket(); +#if defined(WEBRTC_DATA_CHANNELS) + const WebRTCSocket* getWebRTCSocket(); +#endif + PacketReceiver& getPacketReceiver() { return *_packetReceiver; } diff --git a/libraries/networking/src/udt/NetworkSocket.cpp b/libraries/networking/src/udt/NetworkSocket.cpp index 4fdb4e83ff..c882f6dbe3 100644 --- a/libraries/networking/src/udt/NetworkSocket.cpp +++ b/libraries/networking/src/udt/NetworkSocket.cpp @@ -267,6 +267,13 @@ QString NetworkSocket::errorString(SocketType socketType) const { } +#if defined(WEBRTC_DATA_CHANNELS) +const WebRTCSocket* NetworkSocket::getWebRTCSocket() { + return &_webrtcSocket; +} +#endif + + void NetworkSocket::onUDPStateChanged(QAbstractSocket::SocketState socketState) { emit stateChanged(SocketType::UDP, socketState); } diff --git a/libraries/networking/src/udt/NetworkSocket.h b/libraries/networking/src/udt/NetworkSocket.h index 64805282ec..d5891cbde7 100644 --- a/libraries/networking/src/udt/NetworkSocket.h +++ b/libraries/networking/src/udt/NetworkSocket.h @@ -91,7 +91,7 @@ public: bool hasPendingDatagrams() const; /// @brief Gets the size of the next pending datagram, alternating between socket types if both have datagrams to read. - /// @return The size of the next pendign datagram. + /// @return The size of the next pending datagram. qint64 pendingDatagramSize(); /// @brief Reads the next datagram per the most recent pendingDatagramSize call if made, otherwise alternating between @@ -111,7 +111,7 @@ public: /// @brief Gets the type of error that last occurred. /// @param socketType The type of socket for which to get the last error. - /// @return The type of error that last occurred + /// @return The type of error that last occurred. QAbstractSocket::SocketError error(SocketType socketType) const; /// @brief Gets the description of the error that last occurred. @@ -119,6 +119,13 @@ public: /// @return The description of the error that last occurred. QString errorString(SocketType socketType) const; + +#if defined(WEBRTC_DATA_CHANNELS) + /// @brief @brief Gets a pointer to the WebRTC socket object. + /// @return A pointer to the WebRTC socket object. + const WebRTCSocket* getWebRTCSocket(); +#endif + signals: /// @brief Emitted each time new data becomes available for reading. diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8cac4b44c6..810948d742 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -91,6 +91,12 @@ void Socket::rebind(SocketType socketType, quint16 localPort) { bind(socketType, QHostAddress::AnyIPv4, localPort); } +#if defined(WEBRTC_DATA_CHANNELS) +const WebRTCSocket* Socket::getWebRTCSocket() { + return _networkSocket.getWebRTCSocket(); +} +#endif + void Socket::setSystemBufferSizes(SocketType socketType) { for (int i = 0; i < 2; i++) { QAbstractSocket::SocketOption bufferOpt; diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index b92f3fe48d..5c93d96676 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -90,6 +90,10 @@ public: StatsVector sampleStatsForAllConnections(); +#if defined(WEBRTC_DATA_CHANNELS) + const WebRTCSocket* getWebRTCSocket(); +#endif + #if (PR_BUILD || DEV_BUILD) void sendFakedHandshakeRequest(const SockAddr& sockAddr); #endif diff --git a/libraries/networking/src/webrtc/WebRTCSocket.cpp b/libraries/networking/src/webrtc/WebRTCSocket.cpp index b9eee027a1..2247ad8615 100644 --- a/libraries/networking/src/webrtc/WebRTCSocket.cpp +++ b/libraries/networking/src/webrtc/WebRTCSocket.cpp @@ -10,20 +10,19 @@ #if defined(WEBRTC_DATA_CHANNELS) +#include + #include "../NetworkLogging.h" #include "../udt/Constants.h" WebRTCSocket::WebRTCSocket(QObject* parent, NodeType_t nodeType) : QObject(parent), - _signalingServer(this /*, QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT*/), _dataChannels(this, nodeType) { - // Connect WebRTC signaling server and data channels. - connect(&_signalingServer, &WebRTCSignalingServer::messageReceived, - &_dataChannels, &WebRTCDataChannels::onSignalingMessage); - connect(&_dataChannels, &WebRTCDataChannels::signalingMessage, - &_signalingServer, &WebRTCSignalingServer::sendMessage); + // Route signaling messages. + connect(this, &WebRTCSocket::onSignalingMessage, &_dataChannels, &WebRTCDataChannels::onSignalingMessage); + connect(&_dataChannels, &WebRTCDataChannels::signalingMessage, this, &WebRTCSocket::sendSignalingMessage); // Route received data channel messages. connect(&_dataChannels, &WebRTCDataChannels::dataMessage, this, &WebRTCSocket::onDataChannelReceivedMessage); @@ -63,7 +62,7 @@ QVariant WebRTCSocket::socketOption(QAbstractSocket::SocketOption option) { bool WebRTCSocket::bind(const QHostAddress& address, quint16 port, QAbstractSocket::BindMode mode) { // WebRTC data channels aren't bound to ports so just treat this as a successful operation. auto wasBound = _isBound; - _isBound = _signalingServer.bind(address, port); + _isBound = true; if (_isBound != wasBound) { emit stateChanged(_isBound ? QAbstractSocket::BoundState : QAbstractSocket::UnconnectedState); } diff --git a/libraries/networking/src/webrtc/WebRTCSocket.h b/libraries/networking/src/webrtc/WebRTCSocket.h index 8d5d5fc347..9a1d6442d7 100644 --- a/libraries/networking/src/webrtc/WebRTCSocket.h +++ b/libraries/networking/src/webrtc/WebRTCSocket.h @@ -18,7 +18,6 @@ #include #include "WebRTCDataChannels.h" -#include "WebRTCSignalingServer.h" /// @addtogroup Networking /// @{ @@ -52,13 +51,14 @@ public: /// @return The value of the socket option. QVariant socketOption(QAbstractSocket::SocketOption option); - /// @brief Binds the WebRTC socket's signaling server to an address and port. - /// @details Note: WebRTC data connections aren't bound to an address or port. Their ports are negotiated as part of the + /// @brief Nominally binds the WebRTC socket to an address and port. + /// @details WebRTC data connections aren't actually bound to an address or port. Their ports are negotiated as part of the /// WebRTC peer connection process. - /// @param address The address to use for the signaling server. - /// @param port The port to use for the signaling server. - /// @param mode The bind mode. (Not used: included for compatibility with the QUdpSocket interface.) - /// @return true if the signaling server was successfully bound, false if it wasn't. + /// Included for compatibility with the QUdpSocket interface. + /// @param address The address. + /// @param port The port. + /// @param mode The bind mode. + /// @return true. bool bind(const QHostAddress& address, quint16 port = 0, QAbstractSocket::BindMode mode = QAbstractSocket::DefaultForPlatform); @@ -132,17 +132,26 @@ public slots: signals: /// @brief Emitted when the state of the socket changes. + /// @param socketState The new state of the socket. void stateChanged(QAbstractSocket::SocketState socketState); /// @brief Emitted each time new data becomes available for reading. void readyRead(); + /// @brief Emitted when a WebRTC signaling message has been received from the signaling server for this WebRTCSocket. + /// @param json The signaling message. + void onSignalingMessage(const QJsonObject& json); + + /// @brief Emitted when there's a WebRTC signaling message to send via the signaling server. + /// @param json The signaling message. + void sendSignalingMessage(const QJsonObject& message); + + private: void setError(QAbstractSocket::SocketError errorType, QString errorString); void clearError(); - WebRTCSignalingServer _signalingServer; WebRTCDataChannels _dataChannels; bool _isBound { false }; From a3c1d504784f1b5fbda1b32a8ab2afb1bfd84940 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 18 Aug 2021 20:10:11 +1200 Subject: [PATCH 2/6] WebRTC signaling with assignment clients via domain server --- assignment-client/src/AssignmentClient.cpp | 54 ++++++++++++++++++++ assignment-client/src/AssignmentClient.h | 19 +++++-- domain-server/src/DomainServer.cpp | 33 ++++++++++++ domain-server/src/DomainServer.h | 6 +++ libraries/networking/src/Node.cpp | 19 +++++++ libraries/networking/src/NodeType.h | 1 + libraries/networking/src/udt/PacketHeaders.h | 3 +- 7 files changed, 129 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index d1c3efc475..cfe940133f 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -125,6 +126,18 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri PacketReceiver::makeUnsourcedListenerReference(this, &AssignmentClient::handleCreateAssignmentPacket)); packetReceiver.registerListener(PacketType::StopNode, PacketReceiver::makeUnsourcedListenerReference(this, &AssignmentClient::handleStopNodePacket)); + +#if defined(WEBRTC_DATA_CHANNELS) + auto webrtcSocket = nodeList->getWebRTCSocket(); + + // Route inbound WebRTC signaling messages from the Domain Server. + packetReceiver.registerListener(PacketType::WebRTCSignaling, + PacketReceiver::makeUnsourcedListenerReference(this, &AssignmentClient::handleWebRTCSignalingPacket)); + connect(this, &AssignmentClient::webrtcSignalingMessageFromUserClient, webrtcSocket, &WebRTCSocket::onSignalingMessage); + + // Route outbound WebRTC signaling messages via the Domain Server to the user client. + connect(webrtcSocket, &WebRTCSocket::sendSignalingMessage, this, &AssignmentClient::sendSignalingMessageToUserClient); +#endif } void AssignmentClient::stopAssignmentClient() { @@ -333,3 +346,44 @@ void AssignmentClient::assignmentCompleted() { _isAssigned = false; } + +#if defined(WEBRTC_DATA_CHANNELS) + +void AssignmentClient::handleWebRTCSignalingPacket(QSharedPointer message) { + auto messageString = message->readString(); + auto json = QJsonDocument::fromJson(messageString.toUtf8()).object(); + if (json.keys().contains("echo")) { + // Echo message back to sender. + + if (!json.keys().contains("to") || !json.keys().contains("from")) { + return; + } + + // Swap to/from. + auto to = json.value("to"); + json.insert("to", json.value("from")); + json.insert("from", to); + + // Send back to sender via the Domain Server. + auto packetList = NLPacketList::create(PacketType::WebRTCSignaling, QByteArray(), true, true); + packetList->writeString(QJsonDocument(json).toJson(QJsonDocument::Compact)); + auto nodeList = DependencyManager::get(); + auto domainServerAddress = nodeList->getDomainHandler().getSockAddr(); + nodeList->sendPacketList(std::move(packetList), domainServerAddress); + + } else { + // WebRTC signaling message. + emit webrtcSignalingMessageFromUserClient(json); + } +} + +// Sends a signaling message from the assignment client to the user client via the Domain Server. +void AssignmentClient::sendSignalingMessageToUserClient(const QJsonObject& json) { + auto packetList = NLPacketList::create(PacketType::WebRTCSignaling, QByteArray(), true, true); + packetList->writeString(QJsonDocument(json).toJson(QJsonDocument::Compact)); + auto nodeList = DependencyManager::get(); + auto domainServerAddress = nodeList->getDomainHandler().getSockAddr(); + nodeList->sendPacketList(std::move(packetList), domainServerAddress); +} + +#endif diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index c70baf11fd..58e0e8cda1 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -16,6 +16,8 @@ #include #include +#include + #include "ThreadedAssignment.h" class QSharedMemory; @@ -29,19 +31,26 @@ public: quint16 assignmentMonitorPort); ~AssignmentClient(); +public slots: + void aboutToQuit(); + private slots: void sendAssignmentRequest(); void assignmentCompleted(); void handleAuthenticationRequest(); void sendStatusPacketToACM(); void stopAssignmentClient(); - -public slots: - void aboutToQuit(); - -private slots: void handleCreateAssignmentPacket(QSharedPointer message); void handleStopNodePacket(QSharedPointer message); +#if defined(WEBRTC_DATA_CHANNELS) + void handleWebRTCSignalingPacket(QSharedPointer message); + void sendSignalingMessageToUserClient(const QJsonObject& json); +#endif + +signals: +#if defined(WEBRTC_DATA_CHANNELS) + void webrtcSignalingMessageFromUserClient(const QJsonObject& json); +#endif private: void setUpStatusToMonitor(); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 341c658ce7..185250e809 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -857,6 +857,7 @@ void DomainServer::setupNodeListAndAssignments() { #if defined(WEBRTC_DATA_CHANNELS) +// Sets up the WebRTC signaling server that's hosted by the domain server. void DomainServer::setUpWebRTCSignalingServer() { // Bind the WebRTC signaling server's WebSocket to its port. bool isBound = _webrtcSignalingServer.bind(QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT); @@ -875,14 +876,46 @@ void DomainServer::setUpWebRTCSignalingServer() { auto webrtcSocket = limitedNodeList->getWebRTCSocket(); connect(this, &DomainServer::webrtcSignalingMessageForDomainServer, webrtcSocket, &WebRTCSocket::onSignalingMessage); connect(webrtcSocket, &WebRTCSocket::sendSignalingMessage, &_webrtcSignalingServer, &WebRTCSignalingServer::sendMessage); + + // Forward signaling messages received from assignment clients to user client. + PacketReceiver& packetReceiver = limitedNodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::WebRTCSignaling, + PacketReceiver::makeUnsourcedListenerReference(this, + &DomainServer::forwardAssignmentClientSignalingMessageToUserClient)); + connect(this, &DomainServer::webrtcSignalingMessageForUserClient, + &_webrtcSignalingServer, &WebRTCSignalingServer::sendMessage); } +// Routes an inbound WebRTC signaling message received from a client app to the appropriate recipient. void DomainServer::routeWebRTCSignalingMessage(const QJsonObject& json) { if (json.value("to").toString() == NodeType::DomainServer) { emit webrtcSignalingMessageForDomainServer(json); + } else { + sendWebRTCSignalingMessageToAssignmentClient(json); } } +// Sends a WebRTC signaling message to the target AC contained in the message. +void DomainServer::sendWebRTCSignalingMessageToAssignmentClient(const QJsonObject& json) { + NodeType_t destinationNodeType = NodeType::fromChar(json.value("to").toString().at(0)); + auto limitedNodeList = DependencyManager::get(); + auto destinationNode = limitedNodeList->soloNodeOfType(destinationNodeType); + if (!destinationNode) { + return; + } + // Use an NLPacketList because the signaling message is not necessarily small. + auto packetList = NLPacketList::create(PacketType::WebRTCSignaling, QByteArray(), true, true); + packetList->writeString(QJsonDocument(json).toJson(QJsonDocument::Compact)); + limitedNodeList->sendPacketList(std::move(packetList), *destinationNode); +} + +// Forwards a WebRTC signaling message received from an assignment client to the relevant user client. +void DomainServer::forwardAssignmentClientSignalingMessageToUserClient(QSharedPointer message) { + auto messageString = message->readString(); + auto json = QJsonDocument::fromJson(messageString.toUtf8()).object(); + emit webrtcSignalingMessageForUserClient(json); +} + #endif diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 3f509b232d..53f2aec85b 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -150,6 +150,10 @@ private slots: void tokenGrantFinished(); void profileRequestFinished(); +#if defined(WEBRTC_DATA_CHANNELS) + void forwardAssignmentClientSignalingMessageToUserClient(QSharedPointer message); +#endif + void aboutToQuit(); signals: @@ -159,6 +163,7 @@ signals: #if defined(WEBRTC_DATA_CHANNELS) void webrtcSignalingMessageForDomainServer(const QJsonObject& json); + void webrtcSignalingMessageForUserClient(const QJsonObject& json); #endif @@ -245,6 +250,7 @@ private: #if defined(WEBRTC_DATA_CHANNELS) void setUpWebRTCSignalingServer(); void routeWebRTCSignalingMessage(const QJsonObject& json); + void sendWebRTCSignalingMessageToAssignmentClient(const QJsonObject& json); #endif QString operationToString(const QNetworkAccessManager::Operation &op); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index aa13dd6565..a90da4a929 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -46,6 +46,22 @@ static const QHash TYPE_NAME_HASH { { NodeType::Unassigned, "Unassigned" } }; +static const QHash TYPE_CHAR_HASH { + { NodeType::DomainServer, "D" }, + { NodeType::EntityServer, "o" }, + { NodeType::Agent, "I" }, + { NodeType::AudioMixer, "M" }, + { NodeType::AvatarMixer, "W" }, + { NodeType::AssetServer, "A" }, + { NodeType::MessagesMixer, "m" }, + { NodeType::EntityScriptServer, "S" }, + { NodeType::UpstreamAudioMixer, "B" }, + { NodeType::UpstreamAvatarMixer, "C" }, + { NodeType::DownstreamAudioMixer, "a" }, + { NodeType::DownstreamAvatarMixer, "w" }, + { NodeType::Unassigned, QChar(1) } +}; + const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { const auto matchedTypeName = TYPE_NAME_HASH.find(nodeType); return matchedTypeName != TYPE_NAME_HASH.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME; @@ -85,6 +101,9 @@ NodeType_t NodeType::fromString(QString type) { return TYPE_NAME_HASH.key(type, NodeType::Unassigned); } +NodeType_t NodeType::fromChar(QChar type) { + return TYPE_CHAR_HASH.key(type, NodeType::Unassigned); +} Node::Node(const QUuid& uuid, NodeType_t type, const SockAddr& publicSocket, const SockAddr& localSocket, QObject* parent) : diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index 8539ce8fb3..55754888c4 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -43,6 +43,7 @@ namespace NodeType { NodeType_t downstreamType(NodeType_t primaryType); NodeType_t fromString(QString type); + NodeType_t fromChar(QChar type); } typedef QSet NodeSet; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index d57fa9f663..6fc1b6c157 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -139,6 +139,7 @@ public: BulkAvatarTraitsAck, StopInjector, AvatarZonePresence, + WebRTCSignaling, NUM_PACKET_TYPE }; @@ -190,7 +191,7 @@ public: << PacketTypeEnum::Value::ReplicatedMicrophoneAudioWithEcho << PacketTypeEnum::Value::ReplicatedInjectAudio << PacketTypeEnum::Value::ReplicatedSilentAudioFrame << PacketTypeEnum::Value::ReplicatedAvatarIdentity << PacketTypeEnum::Value::ReplicatedKillAvatar << PacketTypeEnum::Value::ReplicatedBulkAvatarData - << PacketTypeEnum::Value::AvatarZonePresence; + << PacketTypeEnum::Value::AvatarZonePresence << PacketTypeEnum::Value::WebRTCSignaling; return NON_SOURCED_PACKETS; } From 5d15ebb7237d37fdc49e8e19dacb4574b03f157d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 18 Aug 2021 20:21:56 +1200 Subject: [PATCH 3/6] WebRTC data channel with assignment clients --- libraries/networking/src/webrtc/WebRTCDataChannels.cpp | 8 +++++++- libraries/networking/src/webrtc/WebRTCDataChannels.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/webrtc/WebRTCDataChannels.cpp b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp index 974cef2997..c62bca72c4 100644 --- a/libraries/networking/src/webrtc/WebRTCDataChannels.cpp +++ b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp @@ -452,12 +452,18 @@ void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) { const int MAX_DEBUG_DETAIL_LENGTH = 64; auto data = message.value("data").isObject() ? message.value("data").toObject() : QJsonObject(); int from = message.value("from").isDouble() ? (quint16)(message.value("from").toInt()) : 0; - if (from <= 0 || from > MAXUINT16 || !data.contains("description") && !data.contains("candidate")) { + auto to = NodeType::fromChar(message.value("to").toString().at(0)); + + if (from <= 0 || from > MAXUINT16 || to == NodeType::Unassigned + || !data.contains("description") && !data.contains("candidate")) { qCWarning(networking_webrtc) << "Unexpected signaling message:" << QJsonDocument(message).toJson(QJsonDocument::Compact).left(MAX_DEBUG_DETAIL_LENGTH); return; } + // Remember this node's type for the reply. + _nodeType = to; + // Find or create a connection. WDCConnection* connection; if (_connectionsByWebSocket.contains(from)) { diff --git a/libraries/networking/src/webrtc/WebRTCDataChannels.h b/libraries/networking/src/webrtc/WebRTCDataChannels.h index ec6f67b3c7..f6287c3717 100644 --- a/libraries/networking/src/webrtc/WebRTCDataChannels.h +++ b/libraries/networking/src/webrtc/WebRTCDataChannels.h @@ -319,7 +319,7 @@ private: QObject* _parent; - NodeType_t _nodeType; + NodeType_t _nodeType { NodeType::Unassigned }; std::unique_ptr _rtcNetworkThread { nullptr }; std::unique_ptr _rtcWorkerThread { nullptr }; From ace612d038d4a613089e2c8c0dc1a25aab58117a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 18 Aug 2021 21:27:35 +1200 Subject: [PATCH 4/6] Assignment client type is not known at construction --- assignment-client/src/AssignmentClientMonitor.cpp | 2 +- domain-server/src/DomainServer.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 4 ++-- libraries/networking/src/LimitedNodeList.h | 3 +-- libraries/networking/src/NodeList.cpp | 2 +- libraries/networking/src/NodeList.h | 2 +- libraries/networking/src/udt/NetworkSocket.cpp | 4 ++-- libraries/networking/src/udt/NetworkSocket.h | 3 +-- libraries/networking/src/udt/Socket.cpp | 4 ++-- libraries/networking/src/udt/Socket.h | 4 ++-- libraries/networking/src/webrtc/WebRTCDataChannels.cpp | 7 +++---- libraries/networking/src/webrtc/WebRTCDataChannels.h | 3 +-- libraries/networking/src/webrtc/WebRTCSocket.cpp | 4 ++-- libraries/networking/src/webrtc/WebRTCSocket.h | 3 +-- 14 files changed, 21 insertions(+), 26 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index a2e4d4a697..221a922a4b 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -70,7 +70,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen // create a NodeList so we can receive stats from children DependencyManager::registerInheritance(); auto addressManager = DependencyManager::set(); - auto nodeList = DependencyManager::set(NodeType::Unassigned, listenPort); + auto nodeList = DependencyManager::set(listenPort); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssignmentClientStatus, diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 185250e809..569e662ae0 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -739,7 +739,7 @@ void DomainServer::setupNodeListAndAssignments() { // check for scripts the user wants to persist from their domain-server config populateStaticScriptedAssignmentsFromSettings(); - auto nodeList = DependencyManager::set(NodeType::DomainServer, domainServerPort, domainServerDTLSPort); + auto nodeList = DependencyManager::set(domainServerPort, domainServerDTLSPort); // no matter the local port, save it to shared mem so that local assignment clients can ask what it is nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this, diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index e742363373..8a551f55cb 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -50,8 +50,8 @@ static Setting::Handle LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.Loc using namespace std::chrono_literals; static const std::chrono::milliseconds CONNECTION_RATE_INTERVAL_MS = 1s; -LimitedNodeList::LimitedNodeList(char ownerType, int socketListenPort, int dtlsListenPort) : - _nodeSocket(this, true, ownerType), +LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) : + _nodeSocket(this, true), _packetReceiver(new PacketReceiver(this)) { qRegisterMetaType("ConnectionStep"); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 81d93bf935..2ee863da07 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -416,8 +416,7 @@ protected: QUuid connectionSecretUUID; }; - LimitedNodeList(char ownerType = NodeType::DomainServer, int socketListenPort = INVALID_PORT, - int dtlsListenPort = INVALID_PORT); + LimitedNodeList(int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT); LimitedNodeList(LimitedNodeList const&) = delete; // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&) = delete; // Don't implement, needed to avoid copies of singleton diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 97080a349a..b8e6cdf80a 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -50,7 +50,7 @@ const int KEEPALIVE_PING_INTERVAL_MS = 1000; const int MAX_SYSTEM_INFO_SIZE = 1000; NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) : - LimitedNodeList(newOwnerType, socketListenPort, dtlsListenPort), + LimitedNodeList(socketListenPort, dtlsListenPort), _ownerType(newOwnerType), _nodeTypesOfInterest(), _domainHandler(this), diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index d3999c31f6..7af0dc405f 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -154,7 +154,7 @@ private slots: void maybeSendIgnoreSetToNode(SharedNodePointer node); private: - NodeList() : LimitedNodeList(NodeType::Unassigned, INVALID_PORT, INVALID_PORT) { + NodeList() : LimitedNodeList(INVALID_PORT, INVALID_PORT) { assert(false); // Not implemented, needed for DependencyManager templates compile } NodeList(char ownerType, int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT); diff --git a/libraries/networking/src/udt/NetworkSocket.cpp b/libraries/networking/src/udt/NetworkSocket.cpp index c882f6dbe3..fd646fe317 100644 --- a/libraries/networking/src/udt/NetworkSocket.cpp +++ b/libraries/networking/src/udt/NetworkSocket.cpp @@ -11,13 +11,13 @@ #include "../NetworkLogging.h" -NetworkSocket::NetworkSocket(QObject* parent, NodeType_t nodeType) : +NetworkSocket::NetworkSocket(QObject* parent) : QObject(parent), _parent(parent), _udpSocket(this) #if defined(WEBRTC_DATA_CHANNELS) , - _webrtcSocket(this, nodeType) + _webrtcSocket(this) #endif { connect(&_udpSocket, &QUdpSocket::readyRead, this, &NetworkSocket::readyRead); diff --git a/libraries/networking/src/udt/NetworkSocket.h b/libraries/networking/src/udt/NetworkSocket.h index d5891cbde7..2670fa40b8 100644 --- a/libraries/networking/src/udt/NetworkSocket.h +++ b/libraries/networking/src/udt/NetworkSocket.h @@ -33,8 +33,7 @@ public: /// @brief Constructs a new NetworkSocket object. /// @param parent Qt parent object. - /// @param nodeType The type of node that the NetworkSocket object is being used in. - NetworkSocket(QObject* parent, NodeType_t nodeType); + NetworkSocket(QObject* parent); /// @brief Set the value of a UDP or WebRTC socket option. diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 810948d742..8313a87bbf 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -40,9 +40,9 @@ using namespace udt; #endif -Socket::Socket(QObject* parent, bool shouldChangeSocketOptions, NodeType_t nodeType) : +Socket::Socket(QObject* parent, bool shouldChangeSocketOptions) : QObject(parent), - _networkSocket(parent, nodeType), + _networkSocket(parent), _readyReadBackupTimer(new QTimer(this)), _shouldChangeSocketOptions(shouldChangeSocketOptions) { diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 5c93d96676..ab9699bb8f 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -55,8 +55,8 @@ class Socket : public QObject { public: using StatsVector = std::vector>; - - Socket(QObject* object = 0, bool shouldChangeSocketOptions = true, NodeType_t nodeType = NodeType::Unassigned); + + Socket(QObject* object = 0, bool shouldChangeSocketOptions = true); quint16 localPort(SocketType socketType) const { return _networkSocket.localPort(socketType); } diff --git a/libraries/networking/src/webrtc/WebRTCDataChannels.cpp b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp index c62bca72c4..3f7b84086d 100644 --- a/libraries/networking/src/webrtc/WebRTCDataChannels.cpp +++ b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp @@ -373,13 +373,12 @@ void WDCConnection::closePeerConnection() { } -WebRTCDataChannels::WebRTCDataChannels(QObject* parent, NodeType_t nodeType) : +WebRTCDataChannels::WebRTCDataChannels(QObject* parent) : QObject(parent), - _parent(parent), - _nodeType(nodeType) + _parent(parent) { #ifdef WEBRTC_DEBUG - qCDebug(networking_webrtc) << "WebRTCDataChannels::WebRTCDataChannels()" << nodeType << NodeType::getNodeTypeName(nodeType); + qCDebug(networking_webrtc) << "WebRTCDataChannels::WebRTCDataChannels()"; #endif // Create a peer connection factory. diff --git a/libraries/networking/src/webrtc/WebRTCDataChannels.h b/libraries/networking/src/webrtc/WebRTCDataChannels.h index f6287c3717..b1751093d5 100644 --- a/libraries/networking/src/webrtc/WebRTCDataChannels.h +++ b/libraries/networking/src/webrtc/WebRTCDataChannels.h @@ -227,8 +227,7 @@ public: /// @brief Constructs a new WebRTCDataChannels object. /// @param parent The parent Qt object. - /// @param nodeType The type of node that the WebRTCDataChannels object is being used in. - WebRTCDataChannels(QObject* parent, NodeType_t nodeType); + WebRTCDataChannels(QObject* parent); /// @brief Destroys a WebRTCDataChannels object. ~WebRTCDataChannels(); diff --git a/libraries/networking/src/webrtc/WebRTCSocket.cpp b/libraries/networking/src/webrtc/WebRTCSocket.cpp index 2247ad8615..69b97ebf94 100644 --- a/libraries/networking/src/webrtc/WebRTCSocket.cpp +++ b/libraries/networking/src/webrtc/WebRTCSocket.cpp @@ -16,9 +16,9 @@ #include "../udt/Constants.h" -WebRTCSocket::WebRTCSocket(QObject* parent, NodeType_t nodeType) : +WebRTCSocket::WebRTCSocket(QObject* parent) : QObject(parent), - _dataChannels(this, nodeType) + _dataChannels(this) { // Route signaling messages. connect(this, &WebRTCSocket::onSignalingMessage, &_dataChannels, &WebRTCDataChannels::onSignalingMessage); diff --git a/libraries/networking/src/webrtc/WebRTCSocket.h b/libraries/networking/src/webrtc/WebRTCSocket.h index 9a1d6442d7..8e429673e1 100644 --- a/libraries/networking/src/webrtc/WebRTCSocket.h +++ b/libraries/networking/src/webrtc/WebRTCSocket.h @@ -31,8 +31,7 @@ public: /// @brief Constructs a new WebRTCSocket object. /// @param parent Qt parent object. - /// @param nodeType The type of node that the WebRTCsocket object is being used in. - WebRTCSocket(QObject* parent, NodeType_t nodeType); + WebRTCSocket(QObject* parent); /// @brief Nominally sets the value of a socket option. From 1605039929c6d88b616700c9e643d4ec5d05658b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 21 Aug 2021 21:11:42 +1200 Subject: [PATCH 5/6] Tidying --- libraries/networking/src/BaseAssetScriptingInterface.cpp | 1 + libraries/networking/src/NetworkPeer.cpp | 2 +- libraries/networking/src/udt/NetworkSocket.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/BaseAssetScriptingInterface.cpp b/libraries/networking/src/BaseAssetScriptingInterface.cpp index f9dd12b279..872913082a 100644 --- a/libraries/networking/src/BaseAssetScriptingInterface.cpp +++ b/libraries/networking/src/BaseAssetScriptingInterface.cpp @@ -3,6 +3,7 @@ // libraries/networking/src // // Copyright 2017 High Fidelity, Inc. +// Copyright 2021 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index e76b8c31a6..0b3b82ca65 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -117,7 +117,7 @@ void NetworkPeer::setActiveSocket(SockAddr* discoveredSocket) { // we have an active socket, stop our ping timer stopPingTimer(); - // we're now considered connected to this peer - reset the number of connection attemps + // we're now considered connected to this peer - reset the number of connection attempts resetConnectionAttempts(); if (_activeSocket) { diff --git a/libraries/networking/src/udt/NetworkSocket.h b/libraries/networking/src/udt/NetworkSocket.h index 2670fa40b8..887e73b32b 100644 --- a/libraries/networking/src/udt/NetworkSocket.h +++ b/libraries/networking/src/udt/NetworkSocket.h @@ -120,7 +120,7 @@ public: #if defined(WEBRTC_DATA_CHANNELS) - /// @brief @brief Gets a pointer to the WebRTC socket object. + /// @brief Gets a pointer to the WebRTC socket object. /// @return A pointer to the WebRTC socket object. const WebRTCSocket* getWebRTCSocket(); #endif From adc94a280ec7a021d424f4475a71a37fe4835e1f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 29 Aug 2021 14:19:39 +1200 Subject: [PATCH 6/6] Log some warnings --- assignment-client/src/AssignmentClient.cpp | 1 + domain-server/src/DomainServer.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index cfe940133f..bd35c20df8 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -356,6 +356,7 @@ void AssignmentClient::handleWebRTCSignalingPacket(QSharedPointer(); auto destinationNode = limitedNodeList->soloNodeOfType(destinationNodeType); if (!destinationNode) { + qWarning() << NodeType::getNodeTypeName(destinationNodeType) << "not found for WebRTC signaling message."; return; } // Use an NLPacketList because the signaling message is not necessarily small.