diff --git a/domain-server/src/NodeConnectionData.cpp b/domain-server/src/NodeConnectionData.cpp index 60a8d6878c..d7d813e3df 100644 --- a/domain-server/src/NodeConnectionData.cpp +++ b/domain-server/src/NodeConnectionData.cpp @@ -17,7 +17,7 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, const SockAddr& senderSockAddr, bool isConnectRequest) { NodeConnectionData newHeader; - + if (isConnectRequest) { dataStream >> newHeader.connectUUID; @@ -51,23 +51,28 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c dataStream >> newHeader.lastPingTimestamp; + SocketType publicSocketType, localSocketType; dataStream >> newHeader.nodeType - >> newHeader.publicSockAddr >> newHeader.localSockAddr + >> publicSocketType >> newHeader.publicSockAddr >> localSocketType >> newHeader.localSockAddr >> newHeader.interestList >> newHeader.placeName; + newHeader.publicSockAddr.setType(publicSocketType); + newHeader.localSockAddr.setType(localSocketType); - // A WebRTC web client doesn't necessarily know it's public Internet or local network addresses, and for WebRTC they aren't - // needed: for WebRTC, the data channel ID is the important thing. The client's public Internet IP address still needs to - // be known for domain access permissions, though, and this can be obtained from the WebSocket signaling connection. - if (senderSockAddr.getSocketType() == SocketType::WebRTC) { - // WEBRTC TODO: Rather than setting the SocketType here, serialize and deserialize the SocketType in the leading byte of - // the 5 bytes used to encode the IP address. - newHeader.publicSockAddr.setSocketType(SocketType::WebRTC); - newHeader.localSockAddr.setSocketType(SocketType::WebRTC); + // For WebRTC connections, the user client's signaling channel WebSocket address is used instead of the actual data + // channel's address. + if (senderSockAddr.getType() == SocketType::WebRTC) { + if (newHeader.publicSockAddr.getType() != SocketType::WebRTC + || newHeader.localSockAddr.getType() != SocketType::WebRTC) { + qDebug() << "Inconsistent WebRTC socket types!"; + } - // WEBRTC TODO: Set the public Internet address obtained from the WebSocket used in WebRTC signaling. - - newHeader.publicSockAddr.setPort(senderSockAddr.getPort()); // We don't know whether it's a public or local connection - newHeader.localSockAddr.setPort(senderSockAddr.getPort()); // so set both ports. + // We don't know whether it's a public or local connection so set both the same. + auto address = senderSockAddr.getAddress(); + auto port = senderSockAddr.getPort(); + newHeader.publicSockAddr.setAddress(address); + newHeader.publicSockAddr.setPort(port); + newHeader.localSockAddr.setAddress(address); + newHeader.localSockAddr.setPort(port); } newHeader.senderSockAddr = senderSockAddr; diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index c25dd61f68..285549734c 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -942,7 +942,7 @@ void AudioClient::Gate::flush() { void AudioClient::handleNoisyMutePacket(QSharedPointer message) { - if (!_muted) { + if (!_isMuted) { setMuted(true); // have the audio scripting interface emit a signal to say we were muted by the mixer @@ -989,7 +989,7 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { _selectedCodecName = selectedCodecName; - qCDebug(audioclient) << "Selected Codec:" << _selectedCodecName << "isStereoInput:" << _isStereoInput; + qCDebug(audioclient) << "Selected codec:" << _selectedCodecName << "; Is stereo input:" << _isStereoInput; // release any old codec encoder/decoder first... if (_codec && _encoder) { @@ -1005,7 +1005,7 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { _codec = plugin; _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, _isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO); - qCDebug(audioclient) << "Selected Codec Plugin:" << _codec.get(); + qCDebug(audioclient) << "Selected codec plugin:" << _codec.get(); break; } } @@ -1269,7 +1269,7 @@ void AudioClient::processWebrtcNearEnd(int16_t* samples, int numFrames, int numC void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { // If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here. bool hasReverb = _reverb || _receivedAudioStream.hasReverb(); - if ((_muted && !_shouldEchoLocally) || !_audioOutput || (!_shouldEchoLocally && !hasReverb) || !_audioGateOpen) { + if ((_isMuted && !_shouldEchoLocally) || !_audioOutput || (!_shouldEchoLocally && !hasReverb) || !_audioGateOpen) { return; } @@ -1357,7 +1357,7 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) { bool audioGateOpen = false; - if (!_muted) { + if (!_isMuted) { int16_t* samples = reinterpret_cast(audioBuffer.data()); int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE; int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO); @@ -1378,7 +1378,7 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) { } // loudness after mute/gate - _lastInputLoudness = (_muted || !audioGateOpen) ? 0.0f : _lastRawInputLoudness; + _lastInputLoudness = (_isMuted || !audioGateOpen) ? 0.0f : _lastRawInputLoudness; // detect gate opening and closing bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened @@ -1482,7 +1482,7 @@ void AudioClient::handleMicAudioInput() { emit inputLoudnessChanged(_lastSmoothedRawInputLoudness, isClipping); - if (!_muted) { + if (!_isMuted) { possibleResampling(_inputToNetworkResampler, inputAudioSamples.get(), networkAudioSamples, inputSamplesRequired, numNetworkSamples, @@ -1748,10 +1748,10 @@ void AudioClient::sendMuteEnvironmentPacket() { } void AudioClient::setMuted(bool muted, bool emitSignal) { - if (_muted != muted) { - _muted = muted; + if (_isMuted != muted) { + _isMuted = muted; if (emitSignal) { - emit muteToggled(_muted); + emit muteToggled(_isMuted); } } } @@ -1896,7 +1896,6 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice if (_dummyAudioInput) { _dummyAudioInput->stop(); - _dummyAudioInput->deleteLater(); _dummyAudioInput = NULL; } diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index c414d74b6a..51e0ecd2ee 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -217,7 +217,7 @@ public slots: void audioMixerKilled(); void setMuted(bool muted, bool emitSignal = true); - bool isMuted() { return _muted; } + bool isMuted() { return _isMuted; } virtual bool setIsStereoInput(bool stereo) override; virtual bool isStereoInput() override { return _isStereoInput; } @@ -410,7 +410,7 @@ private: float _timeSinceLastClip{ -1.0f }; int _totalInputAudioSamples; - bool _muted{ false }; + bool _isMuted{ false }; bool _shouldEchoLocally{ false }; bool _shouldEchoToServer{ false }; bool _isNoiseGateEnabled{ true }; diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 7a81b8a67a..e946c6afb7 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -167,7 +167,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { bool packetPCM = codecInPacket == "pcm" || codecInPacket == ""; if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) { auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead()); - parseAudioData(message.getType(), afterProperties); + parseAudioData(afterProperties); _mismatchedAudioCodecCount = 0; } else { @@ -267,7 +267,7 @@ int InboundAudioStream::lostAudioData(int numPackets) { return 0; } -int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) { +int InboundAudioStream::parseAudioData(const QByteArray& packetAfterStreamProperties) { QByteArray decodedBuffer; // may block on the real-time thread, which is acceptible as diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index c10a86cb69..b42609d576 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -132,7 +132,7 @@ protected: /// parses the audio data in the network packet. /// default implementation assumes packet contains raw audio samples after stream properties - virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties); + virtual int parseAudioData(const QByteArray& packetAfterStreamProperties); /// produces audio data for lost network packets. virtual int lostAudioData(int numPackets); diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp index 6510f0bfc9..d1312edb95 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.cpp +++ b/libraries/audio/src/MixedProcessedAudioStream.cpp @@ -61,7 +61,7 @@ int MixedProcessedAudioStream::lostAudioData(int numPackets) { return 0; } -int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) { +int MixedProcessedAudioStream::parseAudioData(const QByteArray& packetAfterStreamProperties) { QByteArray decodedBuffer; // may block on the real-time thread, which is acceptible as diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h index 14da1d45af..5732f32e90 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.h +++ b/libraries/audio/src/MixedProcessedAudioStream.h @@ -34,7 +34,7 @@ public: protected: int writeDroppableSilentFrames(int silentFrames) override; - int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) override; + int parseAudioData(const QByteArray& packetAfterStreamProperties) override; int lostAudioData(int numPackets) override; private: diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index a90da4a929..de9fb6bddf 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -196,7 +196,9 @@ bool Node::isIgnoringNodeWithID(const QUuid& nodeID) const { QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._type; out << node._uuid; + out << node._publicSocket.getType(); out << node._publicSocket; + out << node._localSocket.getType(); out << node._localSocket; out << node._permissions; out << node._isReplicated; @@ -205,10 +207,15 @@ QDataStream& operator<<(QDataStream& out, const Node& node) { } QDataStream& operator>>(QDataStream& in, Node& node) { + SocketType publicSocketType, localSocketType; in >> node._type; in >> node._uuid; + in >> publicSocketType; in >> node._publicSocket; + node._publicSocket.setType(publicSocketType); + in >> localSocketType; in >> node._localSocket; + node._localSocket.setType(localSocketType); in >> node._permissions; in >> node._isReplicated; in >> node._localID; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 1957b09e82..58d161a797 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -470,10 +470,12 @@ void NodeList::sendDomainServerCheckIn() { QByteArray compressedSystemInfo = qCompress(systemInfo); if (compressedSystemInfo.size() > MAX_SYSTEM_INFO_SIZE) { + // FIXME // Highly unlikely, as not even unreasonable machines will // overflow the max size, but prevent MTU overflow anyway. // We could do something sophisticated like clearing specific // values if they're too big, but we'll save that for later. + // Alternative solution would be to write system info at the end of the packet, only if there is space. compressedSystemInfo.clear(); } @@ -494,7 +496,8 @@ void NodeList::sendDomainServerCheckIn() { // pack our data to send to the domain-server including // the hostname information (so the domain-server can see which place name we came in on) - packetStream << _ownerType.load() << publicSockAddr << localSockAddr << _nodeTypesOfInterest.toList(); + packetStream << _ownerType.load() << publicSockAddr.getType() << publicSockAddr << localSockAddr.getType() + << localSockAddr << _nodeTypesOfInterest.toList(); packetStream << DependencyManager::get()->getPlaceName(); if (!domainIsConnected) { @@ -879,14 +882,19 @@ void NodeList::processDomainServerRemovedNode(QSharedPointer me void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { NewNodeInfo info; + SocketType publicSocketType, localSocketType; packetStream >> info.type >> info.uuid + >> publicSocketType >> info.publicSocket + >> localSocketType >> info.localSocket >> info.permissions >> info.isReplicated >> info.sessionLocalID >> info.connectionSecretUUID; + info.publicSocket.setType(publicSocketType); + info.localSocket.setType(localSocketType); // if the public socket address is 0 then it's reachable at the same IP // as the domain server @@ -894,10 +902,6 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { info.publicSocket.setAddress(_domainHandler.getIP()); } - // WEBRTC TODO: Handle WebRTC-connected nodes. Probably need to include SocketType in SockAddr << and >> - info.publicSocket.setSocketType(SocketType::UDP); - info.localSocket.setSocketType(SocketType::UDP); - addNewNode(info); } diff --git a/libraries/networking/src/SockAddr.cpp b/libraries/networking/src/SockAddr.cpp index 58dc9714bd..e8eb6c4b86 100644 --- a/libraries/networking/src/SockAddr.cpp +++ b/libraries/networking/src/SockAddr.cpp @@ -116,6 +116,10 @@ QString SockAddr::toString() const { return socketTypeToString(_socketType) + " " + _address.toString() + ":" + QString::number(_port); } +QString SockAddr::toShortString() const { + return _address.toString() + ":" + QString::number(_port); +} + bool SockAddr::hasPrivateAddress() const { // an address is private if it is loopback or falls in any of the RFC1918 address spaces const QPair TWENTY_FOUR_BIT_BLOCK = { QHostAddress("10.0.0.0"), 8 }; @@ -129,27 +133,22 @@ bool SockAddr::hasPrivateAddress() const { } QDebug operator<<(QDebug debug, const SockAddr& sockAddr) { - debug.nospace() << socketTypeToString(sockAddr._socketType).toLocal8Bit().constData() << " " + debug.nospace() + << (sockAddr._socketType != SocketType::Unknown + ? (socketTypeToString(sockAddr._socketType) + " ").toLocal8Bit().constData() : "") << sockAddr._address.toString().toLocal8Bit().constData() << ":" << sockAddr._port; return debug.space(); } QDataStream& operator<<(QDataStream& dataStream, const SockAddr& sockAddr) { - // Don't include socketType because it can be implied from the type of connection used. - // WEBRTC TODO: Reconsider this. + // Don't include socket type because ICE packets must not have it. dataStream << sockAddr._address << sockAddr._port; return dataStream; } QDataStream& operator>>(QDataStream& dataStream, SockAddr& sockAddr) { - // Don't include socketType because it can be implied from the type of connection used. - // WEBRTC TODO: Reconsider this. + // Don't include socket type because ICE packets must not have it. dataStream >> sockAddr._address >> sockAddr._port; - - // Set default for non-WebRTC code. - // WEBRTC TODO: Reconsider this. - sockAddr.setSocketType(SocketType::UDP); - return dataStream; } diff --git a/libraries/networking/src/SockAddr.h b/libraries/networking/src/SockAddr.h index ab70325ed4..877bae4ee4 100644 --- a/libraries/networking/src/SockAddr.h +++ b/libraries/networking/src/SockAddr.h @@ -40,9 +40,9 @@ public: bool operator==(const SockAddr& rhsSockAddr) const; bool operator!=(const SockAddr& rhsSockAddr) const { return !(*this == rhsSockAddr); } - SocketType getSocketType() const { return _socketType; } + SocketType getType() const { return _socketType; } SocketType* getSocketTypePointer() { return &_socketType; } - void setSocketType(const SocketType socketType) { _socketType = socketType; } + void setType(const SocketType socketType) { _socketType = socketType; } const QHostAddress& getAddress() const { return _address; } QHostAddress* getAddressPointer() { return &_address; } @@ -56,6 +56,7 @@ public: static int unpackSockAddr(const unsigned char* packetData, SockAddr& unpackDestSockAddr); QString toString() const; + QString toShortString() const; bool hasPrivateAddress() const; // checks if the address behind this sock addr is private per RFC 1918 diff --git a/libraries/networking/src/SocketType.h b/libraries/networking/src/SocketType.h index a798fb59c6..d9b613a7e1 100644 --- a/libraries/networking/src/SocketType.h +++ b/libraries/networking/src/SocketType.h @@ -19,8 +19,8 @@ /// @brief The types of network socket. -enum class SocketType { - Unknown, ///< Unknown socket type. +enum class SocketType : uint8_t { + Unknown, ///< Socket type unknown or not set. UDP, ///< UDP socket. WebRTC ///< WebRTC socket. A WebRTC data channel presented as a UDP-style socket. }; diff --git a/libraries/networking/src/udt/NetworkSocket.cpp b/libraries/networking/src/udt/NetworkSocket.cpp index fd646fe317..cc28cbfc73 100644 --- a/libraries/networking/src/udt/NetworkSocket.cpp +++ b/libraries/networking/src/udt/NetworkSocket.cpp @@ -126,14 +126,14 @@ qintptr NetworkSocket::socketDescriptor(SocketType socketType) const { qint64 NetworkSocket::writeDatagram(const QByteArray& datagram, const SockAddr& sockAddr) { - switch (sockAddr.getSocketType()) { + switch (sockAddr.getType()) { case SocketType::UDP: // WEBRTC TODO: The Qt documentation says that the following call shouldn't be used if the UDP socket is connected!!! // https://doc.qt.io/qt-5/qudpsocket.html#writeDatagram return _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); #if defined(WEBRTC_DATA_CHANNELS) case SocketType::WebRTC: - return _webrtcSocket.writeDatagram(datagram, sockAddr.getPort()); + return _webrtcSocket.writeDatagram(datagram, sockAddr); #endif default: qCCritical(networking) << "Socket type not specified in writeDatagram() address"; @@ -141,13 +141,13 @@ qint64 NetworkSocket::writeDatagram(const QByteArray& datagram, const SockAddr& } } -qint64 NetworkSocket::bytesToWrite(SocketType socketType, quint16 port) const { +qint64 NetworkSocket::bytesToWrite(SocketType socketType, const SockAddr& address) const { switch (socketType) { case SocketType::UDP: return _udpSocket.bytesToWrite(); #if defined(WEBRTC_DATA_CHANNELS) case SocketType::WebRTC: - return _webrtcSocket.bytesToWrite(port); + return _webrtcSocket.bytesToWrite(address); #endif default: qCCritical(networking) << "Socket type not specified in bytesToWrite()"; @@ -197,7 +197,7 @@ qint64 NetworkSocket::readDatagram(char* data, qint64 maxSize, SockAddr* sockAdd _lastSocketTypeRead = SocketType::UDP; _pendingDatagramSizeSocketType = SocketType::Unknown; if (sockAddr) { - sockAddr->setSocketType(SocketType::UDP); + sockAddr->setType(SocketType::UDP); return _udpSocket.readDatagram(data, maxSize, sockAddr->getAddressPointer(), sockAddr->getPortPointer()); } else { return _udpSocket.readDatagram(data, maxSize); @@ -206,7 +206,7 @@ qint64 NetworkSocket::readDatagram(char* data, qint64 maxSize, SockAddr* sockAdd _lastSocketTypeRead = SocketType::WebRTC; _pendingDatagramSizeSocketType = SocketType::Unknown; if (sockAddr) { - sockAddr->setSocketType(SocketType::WebRTC); + sockAddr->setType(SocketType::WebRTC); return _webrtcSocket.readDatagram(data, maxSize, sockAddr->getAddressPointer(), sockAddr->getPortPointer()); } else { return _webrtcSocket.readDatagram(data, maxSize); @@ -214,7 +214,7 @@ qint64 NetworkSocket::readDatagram(char* data, qint64 maxSize, SockAddr* sockAdd } #else if (sockAddr) { - sockAddr->setSocketType(SocketType::UDP); + sockAddr->setType(SocketType::UDP); return _udpSocket.readDatagram(data, maxSize, sockAddr->getAddressPointer(), sockAddr->getPortPointer()); } else { return _udpSocket.readDatagram(data, maxSize); diff --git a/libraries/networking/src/udt/NetworkSocket.h b/libraries/networking/src/udt/NetworkSocket.h index 887e73b32b..030f27e119 100644 --- a/libraries/networking/src/udt/NetworkSocket.h +++ b/libraries/networking/src/udt/NetworkSocket.h @@ -80,9 +80,10 @@ public: /// @brief Gets the number of bytes waiting to be written. /// @details For UDP, there's a single buffer used for all destinations. For WebRTC, each destination has its own buffer. /// @param socketType The type of socket for which to get the number of bytes waiting to be written. - /// @param port If a WebRTC socket, the data channel for which to get the number of bytes waiting. + /// @param address If a WebRTCSocket, the destination address for which to get the number of bytes waiting. + /// @param port If a WebRTC socket, the destination port for which to get the number of bytes waiting. /// @return The number of bytes waiting to be written. - qint64 bytesToWrite(SocketType socketType, quint16 port = 0) const; + qint64 bytesToWrite(SocketType socketType, const SockAddr& address = SockAddr()) const; /// @brief Gets whether there is a pending datagram waiting to be read. diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index f7c1192886..e561bfe21e 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -27,7 +27,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::DomainConnectRequestPending: // keeping the old version to maintain the protocol hash return 17; case PacketType::DomainList: - return static_cast(DomainListVersion::HasConnectReason); + return static_cast(DomainListVersion::SocketTypes); case PacketType::EntityAdd: case PacketType::EntityClone: case PacketType::EntityEdit: @@ -72,10 +72,12 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(DomainConnectionDeniedVersion::IncludesExtraInfo); case PacketType::DomainConnectRequest: - return static_cast(DomainConnectRequestVersion::HasCompressedSystemInfo); + return static_cast(DomainConnectRequestVersion::SocketTypes); + case PacketType::DomainListRequest: + return static_cast(DomainListRequestVersion::SocketTypes); case PacketType::DomainServerAddedNode: - return static_cast(DomainServerAddedNodeVersion::PermissionsGrid); + return static_cast(DomainServerAddedNodeVersion::SocketTypes); case PacketType::EntityScriptCallMethod: return static_cast(EntityScriptCallMethodVersion::ClientCallable); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 6fc1b6c157..64b2e481c5 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -368,7 +368,13 @@ enum class DomainConnectRequestVersion : PacketVersion { HasTimestamp, HasReason, HasSystemInfo, - HasCompressedSystemInfo + HasCompressedSystemInfo, + SocketTypes +}; + +enum class DomainListRequestVersion : PacketVersion { + PreSocketTypes = 22, + SocketTypes }; enum class DomainConnectionDeniedVersion : PacketVersion { @@ -379,7 +385,8 @@ enum class DomainConnectionDeniedVersion : PacketVersion { enum class DomainServerAddedNodeVersion : PacketVersion { PrePermissionsGrid = 17, - PermissionsGrid + PermissionsGrid, + SocketTypes }; enum class DomainListVersion : PacketVersion { @@ -389,7 +396,8 @@ enum class DomainListVersion : PacketVersion { GetMachineFingerprintFromUUIDSupport, AuthenticationOptional, HasTimestamp, - HasConnectReason + HasConnectReason, + SocketTypes }; enum class AudioVersion : PacketVersion { diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8313a87bbf..721eafd7e7 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -245,7 +245,7 @@ qint64 Socket::writeDatagram(const char* data, qint64 size, const SockAddr& sock } qint64 Socket::writeDatagram(const QByteArray& datagram, const SockAddr& sockAddr) { - auto socketType = sockAddr.getSocketType(); + auto socketType = sockAddr.getType(); // don't attempt to write the datagram if we're unbound. Just drop it. // _networkSocket.writeDatagram will return an error anyway, but there are @@ -256,7 +256,7 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const SockAddr& sockAdd } qint64 bytesWritten = _networkSocket.writeDatagram(datagram, sockAddr); - int pending = _networkSocket.bytesToWrite(socketType, sockAddr.getPort()); + int pending = _networkSocket.bytesToWrite(socketType, sockAddr); if (bytesWritten < 0 || pending) { int wsaError = 0; static std::atomic previousWsaError (0); diff --git a/libraries/networking/src/webrtc/WebRTCDataChannels.cpp b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp index 3f7b84086d..cbc5a8ff6e 100644 --- a/libraries/networking/src/webrtc/WebRTCDataChannels.cpp +++ b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp @@ -131,12 +131,12 @@ void WDCDataChannelObserver::OnMessage(const DataBuffer& buffer) { } -WDCConnection::WDCConnection(WebRTCDataChannels* parent, quint16 webSocketID) : +WDCConnection::WDCConnection(WebRTCDataChannels* parent, const QString& dataChannelID) : _parent(parent), - _webSocketID(webSocketID) + _dataChannelID(dataChannelID) { #ifdef WEBRTC_DEBUG - qCDebug(networking_webrtc) << "WDCConnection::WDCConnection() :" << webSocketID; + qCDebug(networking_webrtc) << "WDCConnection::WDCConnection() :" << dataChannelID; #endif // Create observers. @@ -196,7 +196,7 @@ void WDCConnection::sendAnswer(SessionDescriptionInterface* description) { QJsonObject jsonObject; jsonObject.insert("from", QString(_parent->getNodeType())); - jsonObject.insert("to", _webSocketID); + jsonObject.insert("to", _dataChannelID); jsonObject.insert("data", jsonWebRTCPayload); _parent->sendSignalingMessage(jsonObject); @@ -250,7 +250,7 @@ void WDCConnection::sendIceCandidate(const IceCandidateInterface* candidate) { QJsonObject jsonObject; jsonObject.insert("from", QString(_parent->getNodeType())); - jsonObject.insert("to", _webSocketID); + jsonObject.insert("to", _dataChannelID); jsonObject.insert("data", jsonWebRTCData); QJsonDocument jsonDocument = QJsonDocument(jsonObject); @@ -288,7 +288,6 @@ void WDCConnection::onDataChannelOpened(rtc::scoped_refptr #endif _dataChannel = dataChannel; - _dataChannelID = _parent->getNewDataChannelID(); // Not dataChannel->id() because it's only unique per peer connection. _dataChannel->RegisterObserver(_dataChannelObserver.get()); #ifdef WEBRTC_DEBUG @@ -328,7 +327,13 @@ void WDCConnection::onDataChannelMessageReceived(const DataBuffer& buffer) { #ifdef WEBRTC_DEBUG qCDebug(networking_webrtc) << "Echo message back"; #endif - _parent->sendDataMessage(_dataChannelID, byteArray); // Use parent method to exercise the code stack. + auto addressParts = _dataChannelID.split(":"); + if (addressParts.length() != 2) { + qCWarning(networking_webrtc) << "Invalid dataChannelID:" << _dataChannelID; + return; + } + auto address = SockAddr(SocketType::WebRTC, QHostAddress(addressParts[0]), addressParts[1].toInt()); + _parent->sendDataMessage(address, byteArray); // Use parent method to exercise the code stack. return; } @@ -420,26 +425,19 @@ WebRTCDataChannels::~WebRTCDataChannels() { } void WebRTCDataChannels::reset() { - QHashIterator i(_connectionsByDataChannel); + QHashIterator i(_connectionsByID); while (i.hasNext()) { i.next(); delete i.value(); } - _connectionsByWebSocket.clear(); - _connectionsByDataChannel.clear(); + _connectionsByID.clear(); } -quint16 WebRTCDataChannels::getNewDataChannelID() { - static const int QUINT16_LIMIT = std::numeric_limits::max() + 1; - _lastDataChannelID = std::max((_lastDataChannelID + 1) % QUINT16_LIMIT, 1); - return _lastDataChannelID; -} - -void WebRTCDataChannels::onDataChannelOpened(WDCConnection* connection, quint16 dataChannelID) { +void WebRTCDataChannels::onDataChannelOpened(WDCConnection* connection, const QString& dataChannelID) { #ifdef WEBRTC_DEBUG qCDebug(networking_webrtc) << "WebRTCDataChannels::onDataChannelOpened() :" << dataChannelID; #endif - _connectionsByDataChannel.insert(dataChannelID, connection); + _connectionsByID.insert(dataChannelID, connection); } void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) { @@ -449,13 +447,13 @@ void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) { // Validate message. const int MAX_DEBUG_DETAIL_LENGTH = 64; + const QRegularExpression DATA_CHANNEL_ID_REGEX{ "^[1-9]\\d*\\.\\d+\\.\\d+\\.\\d+:\\d+$" }; auto data = message.value("data").isObject() ? message.value("data").toObject() : QJsonObject(); - int from = message.value("from").isDouble() ? (quint16)(message.value("from").toInt()) : 0; + auto from = message.value("from").toString(); auto to = NodeType::fromChar(message.value("to").toString().at(0)); - - if (from <= 0 || from > MAXUINT16 || to == NodeType::Unassigned + if (!DATA_CHANNEL_ID_REGEX.match(from).hasMatch() || to == NodeType::Unassigned || !data.contains("description") && !data.contains("candidate")) { - qCWarning(networking_webrtc) << "Unexpected signaling message:" + qCWarning(networking_webrtc) << "Invalid or unexpected signaling message:" << QJsonDocument(message).toJson(QJsonDocument::Compact).left(MAX_DEBUG_DETAIL_LENGTH); return; } @@ -465,11 +463,11 @@ void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) { // Find or create a connection. WDCConnection* connection; - if (_connectionsByWebSocket.contains(from)) { - connection = _connectionsByWebSocket.value(from); + if (_connectionsByID.contains(from)) { + connection = _connectionsByID.value(from); } else { connection = new WDCConnection(this, from); - _connectionsByWebSocket.insert(from, connection); + _connectionsByID.insert(from, connection); } // Set the remote description and reply with an answer. @@ -498,35 +496,45 @@ void WebRTCDataChannels::sendSignalingMessage(const QJsonObject& message) { emit signalingMessage(message); } -void WebRTCDataChannels::emitDataMessage(int dataChannelID, const QByteArray& byteArray) { +void WebRTCDataChannels::emitDataMessage(const QString& dataChannelID, const QByteArray& byteArray) { #ifdef WEBRTC_DEBUG qCDebug(networking_webrtc) << "WebRTCDataChannels::emitDataMessage() :" << dataChannelID << byteArray.toHex() << byteArray.length(); #endif - emit dataMessage(dataChannelID, byteArray); + auto addressParts = dataChannelID.split(":"); + if (addressParts.length() != 2) { + qCWarning(networking_webrtc) << "Invalid dataChannelID:" << dataChannelID; + return; + } + auto address = SockAddr(SocketType::WebRTC, QHostAddress(addressParts[0]), addressParts[1].toInt()); + emit dataMessage(address, byteArray); } -bool WebRTCDataChannels::sendDataMessage(int dataChannelID, const QByteArray& byteArray) { +bool WebRTCDataChannels::sendDataMessage(const SockAddr& destination, const QByteArray& byteArray) { + auto dataChannelID = destination.toShortString(); #ifdef WEBRTC_DEBUG qCDebug(networking_webrtc) << "WebRTCDataChannels::sendDataMessage() :" << dataChannelID; #endif - // Find connection. - if (!_connectionsByDataChannel.contains(dataChannelID)) { - qCWarning(networking_webrtc) << "Could not find data channel to send message on!"; + if (!_connectionsByID.contains(dataChannelID)) { + qCWarning(networking_webrtc) << "Could not find WebRTC data channel to send message on!"; return false; } - auto connection = _connectionsByDataChannel.value(dataChannelID); + auto connection = _connectionsByID.value(dataChannelID); DataBuffer buffer(byteArray.toStdString(), true); return connection->sendDataMessage(buffer); } -/// @brief Gets the number of bytes waiting to be written on a data channel. -/// @param port The data channel ID. -/// @return The number of bytes waiting to be written on the data channel. -qint64 WebRTCDataChannels::getBufferedAmount(int dataChannelID) const { - auto connection = _connectionsByDataChannel.value(dataChannelID); +qint64 WebRTCDataChannels::getBufferedAmount(const SockAddr& address) const { + auto dataChannelID = address.toShortString(); + if (!_connectionsByID.contains(dataChannelID)) { +#ifdef WEBRTC_DEBUG + qCDebug(networking_webrtc) << "WebRTCDataChannels::getBufferedAmount() : Channel doesn't exist:" << dataChannelID; +#endif + return 0; + } + auto connection = _connectionsByID.value(dataChannelID); return connection->getBufferedAmount(); } @@ -573,10 +581,9 @@ void WebRTCDataChannels::closePeerConnectionNow(WDCConnection* connection) { // Delete the WDCConnection. #ifdef WEBRTC_DEBUG - qCDebug(networking_webrtc) << "Dispose of connection for channel ID:" << connection->getDataChannelID(); + qCDebug(networking_webrtc) << "Dispose of connection for channel:" << connection->getDataChannelID(); #endif - _connectionsByWebSocket.remove(connection->getWebSocketID()); - _connectionsByDataChannel.remove(connection->getDataChannelID()); + _connectionsByID.remove(connection->getDataChannelID()); delete connection; #ifdef WEBRTC_DEBUG qCDebug(networking_webrtc) << "Disposed of connection"; diff --git a/libraries/networking/src/webrtc/WebRTCDataChannels.h b/libraries/networking/src/webrtc/WebRTCDataChannels.h index b1751093d5..fe8af77078 100644 --- a/libraries/networking/src/webrtc/WebRTCDataChannels.h +++ b/libraries/networking/src/webrtc/WebRTCDataChannels.h @@ -22,6 +22,7 @@ #define emit #include "../NodeType.h" +#include "../SockAddr.h" class WebRTCDataChannels; class WDCConnection; @@ -128,16 +129,12 @@ public: /// @brief Constructs a new WDCConnection and opens a WebRTC data connection. /// @param parent The parent WebRTCDataChannels object. - /// @param webSocketID The signaling channel that initiated the opening of the WebRTC data channel. - WDCConnection(WebRTCDataChannels* parent, quint16 webSocketID); + /// @param dataChannelID The data channel ID. + WDCConnection(WebRTCDataChannels* parent, const QString& dataChannelID); - /// @brief Gets the WebSocket ID. - /// @return The ID of the WebSocket. - quint16 getWebSocketID() const { return _webSocketID; } - - /// @brief Gets the WebRTC data channel ID. - /// @return The WebRTC data channel ID. `-1` if not open yet. - int getDataChannelID() const { return _dataChannelID; } + /// @brief Gets the data channel ID. + /// @return The data channel ID. + QString getDataChannelID() const { return _dataChannelID; } /// @brief Sets the remote session description received from the remote client via the signaling channel. @@ -159,7 +156,7 @@ public: /// @param data The ICE candidate. void addIceCandidate(QJsonObject& data); - /// @brief Sends an ICE candidate to the remote vlient via the signaling channel. + /// @brief Sends an ICE candidate to the remote client via the signaling channel. /// @param candidate The ICE candidate. void sendIceCandidate(const webrtc::IceCandidateInterface* candidate); @@ -194,8 +191,7 @@ public: private: WebRTCDataChannels* _parent; - quint16 _webSocketID { 0 }; - int _dataChannelID { -1 }; + QString _dataChannelID; rtc::scoped_refptr _setSessionDescriptionObserver { nullptr }; rtc::scoped_refptr _createSessionDescriptionObserver { nullptr }; @@ -220,6 +216,9 @@ private: /// Additionally, for debugging purposes, instead of containing a Vircadia protocol payload, a WebRTC message may be an echo /// request. This is bounced back to the client. /// +/// A WebRTC data channel is identified by the IP address and port of the client WebSocket that was used when opening the data +/// channel - this is considered to be the WebRTC data channel's address. The IP address and port of the actual WebRTC +/// connection is not used. class WebRTCDataChannels : public QObject { Q_OBJECT @@ -241,36 +240,30 @@ public: /// @brief Immediately closes all connections and resets the socket. void reset(); - /// @brief Get a new data channel ID to uniquely identify a WDCConnection. - /// @details This ID is assigned by WebRTCDataChannels; it is not the WebRTC data channel ID because that is only - /// unique within a peer connection. - /// @return A new data channel ID. - quint16 getNewDataChannelID(); - /// @brief Handles a WebRTC data channel opening. /// @param connection The WebRTC data channel connection. - /// @param dataChannelID The WebRTC data channel ID. - void onDataChannelOpened(WDCConnection* connection, quint16 dataChannelID); + /// @param dataChannelID The IP address and port of the signaling WebSocket that the client used to connect, `"n.n.n.n:n"`. + void onDataChannelOpened(WDCConnection* connection, const QString& dataChannelID); /// @brief Emits a signalingMessage to be sent to the Interface client. /// @param message The WebRTC signaling message to send. void sendSignalingMessage(const QJsonObject& message); /// @brief Emits a dataMessage received from the Interface client. - /// @param dataChannelID The WebRTC data channel the message was received on. + /// @param dataChannelID The IP address and port of the signaling WebSocket that the client used to connect, `"n.n.n.n:n"`. /// @param byteArray The data message received. - void emitDataMessage(int dataChannelID, const QByteArray& byteArray); + void emitDataMessage(const QString& dataChannelID, const QByteArray& byteArray); /// @brief Sends a data message to an Interface client. - /// @param dataChannelID The WebRTC channel ID of the Interface client. + /// @param dataChannelID The IP address and port of the signaling WebSocket that the client used to connect, `"n.n.n.n:n"`. /// @param message The data message to send. /// @return `true` if the data message was sent, otherwise `false`. - bool sendDataMessage(int dataChannelID, const QByteArray& message); + bool sendDataMessage(const SockAddr& destination, const QByteArray& message); /// @brief Gets the number of bytes waiting to be sent on a data channel. - /// @param dataChannelID The data channel ID. + /// @param address The address of the signaling WebSocket that the client used to connect. /// @return The number of bytes waiting to be sent on the data channel. - qint64 getBufferedAmount(int dataChannelID) const; + qint64 getBufferedAmount(const SockAddr& address) const; /// @brief Creates a new WebRTC peer connection for connecting to an Interface client. /// @param peerConnectionObserver An observer to monitor the WebRTC peer connection. @@ -305,9 +298,9 @@ signals: /// @brief A WebRTC data message received from the Interface client. /// @details This message is for handling at a higher level in the Vircadia protocol. - /// @param dataChannelID The WebRTC data channel ID. + /// @param address The address of the signaling WebSocket that the client used to connect. /// @param byteArray The Vircadia protocol message. - void dataMessage(int dataChannelID, const QByteArray& byteArray); + void dataMessage(const SockAddr& address, const QByteArray& byteArray); /// @brief Signals that the peer connection for a WebRTC data channel should be closed. /// @details Used by {@link WebRTCDataChannels.closePeerConnection}. @@ -326,10 +319,9 @@ private: rtc::scoped_refptr _peerConnectionFactory { nullptr }; - quint16 _lastDataChannelID { 0 }; // First data channel ID is 1. - - QHash _connectionsByWebSocket; - QHash _connectionsByDataChannel; + QHash _connectionsByID; // + // The client's WebSocket IP and port is used as the data channel ID to uniquely identify each. + // The WebSocket IP address and port is formatted as "n.n.n.n:n", the same as used in WebRTCSignalingServer. }; diff --git a/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp b/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp index a11d09ea41..b35cd5158b 100644 --- a/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp +++ b/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp @@ -62,7 +62,8 @@ void WebRTCSignalingServer::webSocketTextMessageReceived(const QString& message) source->sendTextMessage(echo); } else { // WebRTC message or assignment client echo request. (Send both to target.) - json.insert("from", source->peerPort()); + auto from = source->peerAddress().toString() + ":" + QString::number(source->peerPort()); + json.insert("from", from); emit messageReceived(json); } } else { @@ -71,9 +72,9 @@ void WebRTCSignalingServer::webSocketTextMessageReceived(const QString& message) } void WebRTCSignalingServer::sendMessage(const QJsonObject& message) { - quint16 destinationPort = message.value("to").toInt(); - if (_webSockets.contains(destinationPort)) { - _webSockets.value(destinationPort)->sendTextMessage(QString(QJsonDocument(message).toJson())); + auto destinationAddress = message.value("to").toString(); + if (_webSockets.contains(destinationAddress)) { + _webSockets.value(destinationAddress)->sendTextMessage(QString(QJsonDocument(message).toJson())); } else { qCWarning(networking_webrtc) << "Failed to find WebSocket for outgoing WebRTC signaling message."; } @@ -82,7 +83,9 @@ void WebRTCSignalingServer::sendMessage(const QJsonObject& message) { void WebRTCSignalingServer::webSocketDisconnected() { auto source = qobject_cast(sender()); if (source) { - _webSockets.remove(source->peerPort()); + auto address = source->peerAddress().toString() + ":" + QString::number(source->peerPort()); + delete _webSockets.value(address); + _webSockets.remove(address); } } @@ -90,7 +93,8 @@ void WebRTCSignalingServer::newWebSocketConnection() { auto webSocket = _webSocketServer->nextPendingConnection(); connect(webSocket, &QWebSocket::textMessageReceived, this, &WebRTCSignalingServer::webSocketTextMessageReceived); connect(webSocket, &QWebSocket::disconnected, this, &WebRTCSignalingServer::webSocketDisconnected); - _webSockets.insert(webSocket->peerPort(), webSocket); + auto webSocketAddress = webSocket->peerAddress().toString() + ":" + QString::number(webSocket->peerPort()); + _webSockets.insert(webSocketAddress, webSocket); } #endif // WEBRTC_DATA_CHANNELS diff --git a/libraries/networking/src/webrtc/WebRTCSignalingServer.h b/libraries/networking/src/webrtc/WebRTCSignalingServer.h index 418becd8eb..fb695cc6fc 100644 --- a/libraries/networking/src/webrtc/WebRTCSignalingServer.h +++ b/libraries/networking/src/webrtc/WebRTCSignalingServer.h @@ -39,19 +39,20 @@ /// signaling `data` payload or an `echo` request: /// /// | Interface -> Server || -/// | -------- | -----------------------| -/// | `to` | NodeType | -/// | `from` | WebSocket port number* | -/// | [`data`] | WebRTC payload | -/// | [`echo`] | Echo request | -/// * The `from` field is filled in by the WebRTCSignalingServer. +/// | -------- | ---------------------------------------- | +/// | `to` | NodeType | +/// | `from` | WebSocket IP address & port, "n.n.n.n:n" | +/// | [`data`] | WebRTC signaling payload | +/// | [`echo`] | Echo request | +/// +/// `*` The `from` field is filled in upon receipt by the WebRTCSignalingServer. /// /// | Server -> Interface || -/// | -------- | --------------------- | -/// | `to` | WebSocket port number | -/// | `from` | NodeType | -/// | [`data`] | WebRTC payload | -/// | [`echo`] | Echo response | +/// | -------- | ---------------------------------------- | +/// | `to` | WebSocket IP address & port, "n.n.n.n:n" | +/// | `from` | NodeType | +/// | [`data`] | WebRTC signaling payload | +/// | [`echo`] | Echo response | /// class WebRTCSignalingServer : public QObject { Q_OBJECT @@ -97,7 +98,9 @@ private: QHostAddress _address; quint16 _port { 0 }; - QHash _webSockets; // client WebSocket port, client WebSocket object + QHash _webSockets; // + // The WebSocket IP address and port is formatted as "n.n.n.n:n". + // A QString is used rather than a SockAddr, to make signaling easier. QTimer* _isWebSocketServerListeningTimer; }; diff --git a/libraries/networking/src/webrtc/WebRTCSocket.cpp b/libraries/networking/src/webrtc/WebRTCSocket.cpp index 69b97ebf94..e34dc5d5a2 100644 --- a/libraries/networking/src/webrtc/WebRTCSocket.cpp +++ b/libraries/networking/src/webrtc/WebRTCSocket.cpp @@ -78,17 +78,17 @@ void WebRTCSocket::abort() { } -qint64 WebRTCSocket::writeDatagram(const QByteArray& datagram, quint16 port) { +qint64 WebRTCSocket::writeDatagram(const QByteArray& datagram, const SockAddr& destination) { clearError(); - if (_dataChannels.sendDataMessage(port, datagram)) { + if (_dataChannels.sendDataMessage(destination, datagram)) { return datagram.length(); } setError(QAbstractSocket::SocketError::UnknownSocketError, "Failed to write datagram"); return -1; } -qint64 WebRTCSocket::bytesToWrite(quint16 port) const { - return _dataChannels.getBufferedAmount(port); +qint64 WebRTCSocket::bytesToWrite(const SockAddr& destination) const { + return _dataChannels.getBufferedAmount(destination); } @@ -114,12 +114,11 @@ qint64 WebRTCSocket::readDatagram(char* data, qint64 maxSize, QHostAddress* addr } if (address) { - // WEBRTC TODO: Use signaling channel's remote WebSocket address? Or remote data channel address? - *address = QHostAddress::AnyIPv4; + *address = datagram.first.getAddress(); } if (port) { - *port = datagram.first; + *port = datagram.first.getPort(); } return length; @@ -148,8 +147,8 @@ void WebRTCSocket::clearError() { } -void WebRTCSocket::onDataChannelReceivedMessage(int dataChannelID, const QByteArray& message) { - _receivedQueue.enqueue(QPair(dataChannelID, message)); +void WebRTCSocket::onDataChannelReceivedMessage(const SockAddr& source, const QByteArray& message) { + _receivedQueue.enqueue(QPair(source, message)); emit readyRead(); } diff --git a/libraries/networking/src/webrtc/WebRTCSocket.h b/libraries/networking/src/webrtc/WebRTCSocket.h index 8e429673e1..04856f50f1 100644 --- a/libraries/networking/src/webrtc/WebRTCSocket.h +++ b/libraries/networking/src/webrtc/WebRTCSocket.h @@ -24,6 +24,10 @@ /// @brief Provides a QUdpSocket-style interface for using WebRTCDataChannels. +/// +/// @details A WebRTC data channel is identified by the IP address and port of the client WebSocket that was used when opening +/// the data channel - this is considered to be the WebRTC data channel's address. The IP address and port of the actual WebRTC +/// connection is not used. class WebRTCSocket : public QObject { Q_OBJECT @@ -71,28 +75,26 @@ public: void abort(); /// @brief Nominally gets the host port number. - /// @details /// Included for compatibility with the QUdpSocket interface. /// @return 0 quint16 localPort() const { return 0; } /// @brief Nominally gets the socket descriptor. - /// @details /// Included for compatibility with the QUdpSocket interface. /// @return -1 qintptr socketDescriptor() const { return -1; } - /// @brief Sends a datagram to the host on a data channel. + /// @brief Sends a datagram. /// @param datagram The datagram to send. - /// @param port The data channel ID. + /// @param destination The destination WebRTC data channel address. /// @return The number of bytes if successfully sent, otherwise -1. - qint64 writeDatagram(const QByteArray& datagram, quint16 port); + qint64 writeDatagram(const QByteArray& datagram, const SockAddr& destination); /// @brief Gets the number of bytes waiting to be written. - /// @param port The data channel ID. + /// @param destination The destination WebRTC data channel address. /// @return The number of bytes waiting to be written. - qint64 bytesToWrite(quint16 port) const; + qint64 bytesToWrite(const SockAddr& destination) const; /// @brief Gets whether there's a datagram waiting to be read. /// @return true if there's a datagram waiting to be read, false if there isn't. @@ -106,8 +108,8 @@ public: /// @details Any remaining data in the datagram is lost. /// @param data The destination to read the datagram into. /// @param maxSize The maximum number of bytes to read. - /// @param address The destination to put the IP address that the datagram was read from. (Not currently set.) - /// @param port The destination to put the data channel ID that the datagram was read from. + /// @param address The destination to put the WebRTC data channel's IP address. + /// @param port The destination to put the WebRTC data channel's port. /// @return The number of bytes read on success; -1 if reading unsuccessful. qint64 readDatagram(char* data, qint64 maxSize, QHostAddress* address = nullptr, quint16* port = nullptr); @@ -124,9 +126,9 @@ public slots: /// @brief Handles the WebRTC data channel receiving a message. /// @details Queues the message to be read via readDatagram. - /// @param dataChannelID The data channel that the message was received on. + /// @param source The WebRTC data channel that the message was received on. /// @param message The message that was received. - void onDataChannelReceivedMessage(int dataChannelID, const QByteArray& message); + void onDataChannelReceivedMessage(const SockAddr& source, const QByteArray& message); signals: @@ -155,7 +157,7 @@ private: bool _isBound { false }; - QQueue> _receivedQueue; // Messages received are queued for reading from the "socket". + QQueue> _receivedQueue; // Messages received are queued for reading from the "socket". QAbstractSocket::SocketError _lastErrorType { QAbstractSocket::UnknownSocketError }; QString _lastErrorString;