diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index d1c3efc475..bd35c20df8 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,45 @@ 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")) { + qCDebug(assignment_client) << "Invalid WebRTC signaling echo message received."; + 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/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 c49f175866..b844615c6d 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(); @@ -731,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, @@ -846,6 +854,72 @@ void DomainServer::setupNodeListAndAssignments() { addStaticAssignmentsToQueue(); } + +#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); + 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); + + // 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) { + qWarning() << NodeType::getNodeTypeName(destinationNodeType) << "not found for WebRTC signaling message."; + 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 + + 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..53f2aec85b 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" @@ -148,6 +150,10 @@ private slots: void tokenGrantFinished(); void profileRequestFinished(); +#if defined(WEBRTC_DATA_CHANNELS) + void forwardAssignmentClientSignalingMessageToUserClient(QSharedPointer message); +#endif + void aboutToQuit(); signals: @@ -155,6 +161,12 @@ signals: void userConnected(); void userDisconnected(); +#if defined(WEBRTC_DATA_CHANNELS) + void webrtcSignalingMessageForDomainServer(const QJsonObject& json); + void webrtcSignalingMessageForUserClient(const QJsonObject& json); +#endif + + private: QUuid getID(); @@ -235,6 +247,12 @@ private: std::initializer_list optionalData = { }, bool requireAccessToken = true); +#if defined(WEBRTC_DATA_CHANNELS) + void setUpWebRTCSignalingServer(); + void routeWebRTCSignalingMessage(const QJsonObject& json); + void sendWebRTCSignalingMessageToAssignmentClient(const QJsonObject& json); +#endif + QString operationToString(const QNetworkAccessManager::Operation &op); SubnetList _acSubnetWhitelist; @@ -312,6 +330,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..872913082a 100644 --- a/libraries/networking/src/BaseAssetScriptingInterface.cpp +++ b/libraries/networking/src/BaseAssetScriptingInterface.cpp @@ -3,14 +3,16 @@ // 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 #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..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"); @@ -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..2ee863da07 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; } @@ -413,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/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/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/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/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/NetworkSocket.cpp b/libraries/networking/src/udt/NetworkSocket.cpp index 4fdb4e83ff..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); @@ -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..887e73b32b 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. @@ -91,7 +90,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 +110,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 +118,13 @@ public: /// @return The description of the error that last occurred. QString errorString(SocketType socketType) const; + +#if defined(WEBRTC_DATA_CHANNELS) + /// @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/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; } diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8cac4b44c6..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) { @@ -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..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); } @@ -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/WebRTCDataChannels.cpp b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp index 974cef2997..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. @@ -452,12 +451,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..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(); @@ -319,7 +318,7 @@ private: QObject* _parent; - NodeType_t _nodeType; + NodeType_t _nodeType { NodeType::Unassigned }; std::unique_ptr _rtcNetworkThread { nullptr }; std::unique_ptr _rtcWorkerThread { nullptr }; diff --git a/libraries/networking/src/webrtc/WebRTCSocket.cpp b/libraries/networking/src/webrtc/WebRTCSocket.cpp index b9eee027a1..69b97ebf94 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) : +WebRTCSocket::WebRTCSocket(QObject* parent) : QObject(parent), - _signalingServer(this /*, QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT*/), - _dataChannels(this, nodeType) + _dataChannels(this) { - // 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..8e429673e1 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 /// @{ @@ -32,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. @@ -52,13 +50,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 +131,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 };