diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index adc7f5e3c5..196e9a20b7 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -82,7 +82,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri _assignmentServerHostname = assignmentServerHostname; } - _assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true); + _assignmentServerSocket = HifiSockAddr(SocketType::UDP, _assignmentServerHostname, assignmentServerPort, true); if (_assignmentServerSocket.isNull()) { qCCritical(assignment_client) << "PAGE: Couldn't resolve domain server address" << _assignmentServerHostname; } @@ -110,7 +110,8 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri // did we get an assignment-client monitor port? if (assignmentMonitorPort > 0) { - _assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, assignmentMonitorPort); + _assignmentClientMonitorSocket = HifiSockAddr(SocketType::UDP, DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, + assignmentMonitorPort); _assignmentClientMonitorSocket.setObjectName("AssignmentClientMonitor"); qCDebug(assignment_client) << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket; diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 68c0dfc9fd..a085d1d3f4 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -69,7 +69,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(listenPort); + auto nodeList = DependencyManager::set(NodeType::Unassigned, 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 1a31e0869c..dca17df340 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -731,10 +731,11 @@ void DomainServer::setupNodeListAndAssignments() { // check for scripts the user wants to persist from their domain-server config populateStaticScriptedAssignmentsFromSettings(); - auto nodeList = DependencyManager::set(domainServerPort, domainServerDTLSPort); + auto nodeList = DependencyManager::set(NodeType::DomainServer, 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, nodeList->getSocketLocalPort()); + nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this, + nodeList->getSocketLocalPort(SocketType::UDP)); // store our local http ports in shared memory quint16 localHttpPort = DOMAIN_SERVER_HTTP_PORT; @@ -3041,6 +3042,7 @@ ReplicationServerInfo serverInformationFromSettings(QVariantMap serverMap, Repli // read the address and port and construct a HifiSockAddr from them serverInfo.sockAddr = { + SocketType::UDP, serverMap[REPLICATION_SERVER_ADDRESS].toString(), (quint16) serverMap[REPLICATION_SERVER_PORT].toString().toInt() }; @@ -3621,7 +3623,7 @@ void DomainServer::randomizeICEServerAddress(bool shouldTriggerHostLookup) { indexToTry = distribution(generator); } - _iceServerSocket = HifiSockAddr { candidateICEAddresses[indexToTry], ICE_SERVER_DEFAULT_PORT }; + _iceServerSocket = HifiSockAddr { SocketType::UDP, candidateICEAddresses[indexToTry], ICE_SERVER_DEFAULT_PORT }; qCInfo(domain_server_ice) << "Set candidate ice-server socket to" << _iceServerSocket; // clear our number of hearbeat denials, this should be re-set on ice-server change diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index a8e50d31a9..373d33013d 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -37,7 +37,7 @@ IceServer::IceServer(int argc, char* argv[]) : { // start the ice-server socket qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; - _serverSocket.bind(QHostAddress::AnyIPv4, ICE_SERVER_DEFAULT_PORT); + _serverSocket.bind(SocketType::UDP, QHostAddress::AnyIPv4, ICE_SERVER_DEFAULT_PORT); // set processPacket as the verified packet callback for the udt::Socket _serverSocket.setPacketHandler([this](std::unique_ptr packet) { processPacket(std::move(packet)); }); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index c2f1abdd94..9c1c4fa784 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -551,7 +551,7 @@ void setupPreferences() { auto getter = [nodeListWeak] { auto nodeList = nodeListWeak.lock(); if (nodeList) { - return static_cast(nodeList->getSocketLocalPort()); + return static_cast(nodeList->getSocketLocalPort(SocketType::UDP)); } else { return -1; } @@ -559,7 +559,7 @@ void setupPreferences() { auto setter = [nodeListWeak](int preset) { auto nodeList = nodeListWeak.lock(); if (nodeList) { - nodeList->setSocketLocalPort(static_cast(preset)); + nodeList->setSocketLocalPort(SocketType::UDP, static_cast(preset)); } }; auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 5a1d8fb4a0..a77cde4ecc 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -37,7 +37,7 @@ DomainHandler::DomainHandler(QObject* parent) : QObject(parent), - _sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), + _sockAddr(HifiSockAddr(SocketType::UDP, QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _icePeer(this), _settingsTimer(this), _apiRefreshTimer(this) @@ -282,7 +282,8 @@ void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, HifiSockAddr* replaceableSockAddr = &_iceServerSockAddr; replaceableSockAddr->~HifiSockAddr(); - replaceableSockAddr = new (replaceableSockAddr) HifiSockAddr(iceServerHostname, ICE_SERVER_DEFAULT_PORT); + replaceableSockAddr = new (replaceableSockAddr) HifiSockAddr(SocketType::UDP, iceServerHostname, + ICE_SERVER_DEFAULT_PORT); _iceServerSockAddr.setObjectName("IceServer"); auto nodeList = DependencyManager::get(); diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index 434f8daa3d..091ccd6ed6 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -27,21 +27,22 @@ int hifiSockAddrMetaTypeId = qRegisterMetaType(); HifiSockAddr::HifiSockAddr() : + _socketType(SocketType::Unknown), _address(), _port(0) { - } -HifiSockAddr::HifiSockAddr(const QHostAddress& address, quint16 port) : +HifiSockAddr::HifiSockAddr(SocketType socketType, const QHostAddress& address, quint16 port) : + _socketType(socketType), _address(address), _port(port) { - } HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) : QObject(), + _socketType(otherSockAddr._socketType), _address(otherSockAddr._address), _port(otherSockAddr._port) { @@ -50,12 +51,14 @@ HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) : HifiSockAddr& HifiSockAddr::operator=(const HifiSockAddr& rhsSockAddr) { setObjectName(rhsSockAddr.objectName()); + _socketType = rhsSockAddr._socketType; _address = rhsSockAddr._address; _port = rhsSockAddr._port; return *this; } -HifiSockAddr::HifiSockAddr(const QString& hostname, quint16 hostOrderPort, bool shouldBlockForLookup) : +HifiSockAddr::HifiSockAddr(SocketType socketType, const QString& hostname, quint16 hostOrderPort, bool shouldBlockForLookup) : + _socketType(socketType), _address(hostname), _port(hostOrderPort) { @@ -75,7 +78,8 @@ HifiSockAddr::HifiSockAddr(const QString& hostname, quint16 hostOrderPort, bool void HifiSockAddr::swap(HifiSockAddr& otherSockAddr) { using std::swap; - + + swap(_socketType, otherSockAddr._socketType); swap(_address, otherSockAddr._address); swap(_port, otherSockAddr._port); @@ -86,7 +90,7 @@ void HifiSockAddr::swap(HifiSockAddr& otherSockAddr) { } bool HifiSockAddr::operator==(const HifiSockAddr& rhsSockAddr) const { - return _address == rhsSockAddr._address && _port == rhsSockAddr._port; + return _socketType == rhsSockAddr._socketType && _address == rhsSockAddr._address && _port == rhsSockAddr._port; } void HifiSockAddr::handleLookupResult(const QHostInfo& hostInfo) { @@ -108,7 +112,7 @@ void HifiSockAddr::handleLookupResult(const QHostInfo& hostInfo) { } QString HifiSockAddr::toString() const { - return _address.toString() + ":" + QString::number(_port); + return socketTypeToString(_socketType) + " " + _address.toString() + ":" + QString::number(_port); } bool HifiSockAddr::hasPrivateAddress() const { @@ -124,17 +128,27 @@ bool HifiSockAddr::hasPrivateAddress() const { } QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr) { - debug.nospace() << sockAddr._address.toString().toLocal8Bit().constData() << ":" << sockAddr._port; + debug.nospace() << socketTypeToString(sockAddr._socketType).toLocal8Bit().constData() << " " + << sockAddr._address.toString().toLocal8Bit().constData() << ":" << sockAddr._port; return debug.space(); } QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr) { + // Don't include socketType because it can be implied from the type of connection used. + // WEBRTC TODO: Reconsider this. dataStream << sockAddr._address << sockAddr._port; return dataStream; } QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) { + // Don't include socketType because it can be implied from the type of connection used. + // WEBRTC TODO: Reconsider this. 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/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index fc9fdd15a5..e4c5c0c6cd 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -19,13 +19,16 @@ struct sockaddr; #include +#include "SocketType.h" + + class HifiSockAddr : public QObject { Q_OBJECT public: HifiSockAddr(); - HifiSockAddr(const QHostAddress& address, quint16 port); + HifiSockAddr(SocketType socketType, const QHostAddress& address, quint16 port); HifiSockAddr(const HifiSockAddr& otherSockAddr); - HifiSockAddr(const QString& hostname, quint16 hostOrderPort, bool shouldBlockForLookup = false); + HifiSockAddr(SocketType socketType, const QString& hostname, quint16 hostOrderPort, bool shouldBlockForLookup = false); bool isNull() const { return _address.isNull() && _port == 0; } void clear() { _address.clear(); _port = 0;} @@ -36,6 +39,10 @@ public: bool operator==(const HifiSockAddr& rhsSockAddr) const; bool operator!=(const HifiSockAddr& rhsSockAddr) const { return !(*this == rhsSockAddr); } + SocketType getSocketType() const { return _socketType; } + SocketType* getSocketTypePointer() { return &_socketType; } + void setSocketType(const SocketType socketType) { _socketType = socketType; } + const QHostAddress& getAddress() const { return _address; } QHostAddress* getAddressPointer() { return &_address; } void setAddress(const QHostAddress& address) { _address = address; } @@ -52,6 +59,7 @@ public: bool hasPrivateAddress() const; // checks if the address behind this sock addr is private per RFC 1918 friend QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr); + friend QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr); friend QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr); @@ -61,6 +69,7 @@ signals: void lookupCompleted(); void lookupFailed(); private: + SocketType _socketType { SocketType::Unknown }; QHostAddress _address; quint16 _port; }; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 653611ae8c..275324b865 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -49,18 +49,18 @@ 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(int socketListenPort, int dtlsListenPort) : - _nodeSocket(this), +LimitedNodeList::LimitedNodeList(char ownerType, int socketListenPort, int dtlsListenPort) : + _nodeSocket(this, true, ownerType), _packetReceiver(new PacketReceiver(this)) { qRegisterMetaType("ConnectionStep"); auto port = (socketListenPort != INVALID_PORT) ? socketListenPort : LIMITED_NODELIST_LOCAL_PORT.get(); - _nodeSocket.bind(QHostAddress::AnyIPv4, port); - quint16 assignedPort = _nodeSocket.localPort(); + _nodeSocket.bind(SocketType::UDP, QHostAddress::AnyIPv4, port); + quint16 assignedPort = _nodeSocket.localPort(SocketType::UDP); if (socketListenPort != INVALID_PORT && socketListenPort != 0 && socketListenPort != assignedPort) { - qCCritical(networking) << "PAGE: NodeList is unable to assign requested port of" << socketListenPort; + qCCritical(networking) << "PAGE: NodeList is unable to assign requested UDP port of" << socketListenPort; } - qCDebug(networking) << "NodeList socket is listening on" << assignedPort; + qCDebug(networking) << "NodeList UDP socket is listening on" << assignedPort; if (dtlsListenPort != INVALID_PORT) { // only create the DTLS socket during constructor if a custom port is passed @@ -73,6 +73,8 @@ LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) : qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); } + _nodeSocket.bind(SocketType::WebRTC, QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT); + // check for local socket updates every so often const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000; QTimer* localSocketUpdate = new QTimer(this); @@ -204,15 +206,19 @@ void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) { } } -void LimitedNodeList::setSocketLocalPort(quint16 socketLocalPort) { +void LimitedNodeList::setSocketLocalPort(SocketType socketType, quint16 socketLocalPort) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setSocketLocalPort", Qt::QueuedConnection, Q_ARG(quint16, socketLocalPort)); return; } - if (_nodeSocket.localPort() != socketLocalPort) { - _nodeSocket.rebind(socketLocalPort); - LIMITED_NODELIST_LOCAL_PORT.set(socketLocalPort); + if (_nodeSocket.localPort(socketType) != socketLocalPort) { + _nodeSocket.rebind(socketType, socketLocalPort); + if (socketType == SocketType::UDP) { + LIMITED_NODELIST_LOCAL_PORT.set(socketLocalPort); + } else { + // WEBRTC TODO: Add WebRTC equivalent? + } } } @@ -1105,7 +1111,7 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr packe _publicSockAddr.getAddress().toString().toLocal8Bit().constData(), _publicSockAddr.getPort()); - _publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort); + _publicSockAddr = HifiSockAddr(SocketType::UDP, newPublicAddress, newPublicPort); if (!_hasCompletedInitialSTUN) { // if we're here we have definitely completed our initial STUN sequence @@ -1186,7 +1192,7 @@ void LimitedNodeList::stopInitialSTUNUpdate(bool success) { qCDebug(networking) << "LimitedNodeList public socket will be set with local port and null QHostAddress."; // reset the public address and port to a null address - _publicSockAddr = HifiSockAddr(QHostAddress(), _nodeSocket.localPort()); + _publicSockAddr = HifiSockAddr(SocketType::UDP, QHostAddress(), _nodeSocket.localPort(SocketType::UDP)); // we have changed the publicSockAddr, so emit our signal emit publicSockAddrChanged(_publicSockAddr); @@ -1213,7 +1219,7 @@ void LimitedNodeList::stopInitialSTUNUpdate(bool success) { void LimitedNodeList::updateLocalSocket() { // when update is called, if the local socket is empty then start with the guessed local socket if (_localSockAddr.isNull()) { - setLocalSocket(HifiSockAddr { getGuessedLocalAddress(), _nodeSocket.localPort() }); + setLocalSocket(HifiSockAddr { SocketType::UDP, getGuessedLocalAddress(), _nodeSocket.localPort(SocketType::UDP) }); } // attempt to use Google's DNS to confirm that local IP @@ -1237,7 +1243,7 @@ void LimitedNodeList::connectedForLocalSocketTest() { auto localHostAddress = localIPTestSocket->localAddress(); if (localHostAddress.protocol() == QAbstractSocket::IPv4Protocol) { - setLocalSocket(HifiSockAddr { localHostAddress, _nodeSocket.localPort() }); + setLocalSocket(HifiSockAddr { SocketType::UDP, localHostAddress, _nodeSocket.localPort(SocketType::UDP) }); _hasTCPCheckedLocalSocket = true; } @@ -1253,7 +1259,7 @@ void LimitedNodeList::errorTestingLocalSocket() { // error connecting to the test socket - if we've never set our local socket using this test socket // then use our possibly updated guessed local address as fallback if (!_hasTCPCheckedLocalSocket) { - setLocalSocket(HifiSockAddr { getGuessedLocalAddress(), _nodeSocket.localPort() }); + setLocalSocket(HifiSockAddr { SocketType::UDP, getGuessedLocalAddress(), _nodeSocket.localPort(SocketType::UDP) }); qCCritical(networking) << "PAGE: Can't connect to Google DNS service via TCP, falling back to guessed local address" << getLocalSockAddr(); } @@ -1273,8 +1279,8 @@ void LimitedNodeList::setLocalSocket(const HifiSockAddr& sockAddr) { _localSockAddr = sockAddr; if (_hasTCPCheckedLocalSocket) { // Force a port change for NAT: reset("local socket change"); - _nodeSocket.rebind(0); - _localSockAddr.setPort(_nodeSocket.localPort()); + _nodeSocket.rebind(SocketType::UDP, 0); + _localSockAddr.setPort(_nodeSocket.localPort(SocketType::UDP)); qCInfo(networking) << "Local port changed to" << _localSockAddr.getPort(); } } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 189f3e1b08..670d843dd3 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -135,8 +135,8 @@ public: bool getThisNodeCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); } bool getThisNodeCanRezAvatarEntities() const { return _permissions.can(NodePermissions::Permission::canRezAvatarEntities); } - quint16 getSocketLocalPort() const { return _nodeSocket.localPort(); } - Q_INVOKABLE void setSocketLocalPort(quint16 socketLocalPort); + quint16 getSocketLocalPort(SocketType socketType) const { return _nodeSocket.localPort(socketType); } + Q_INVOKABLE void setSocketLocalPort(SocketType socketType, quint16 socketLocalPort); QUdpSocket& getDTLSSocket(); @@ -413,7 +413,8 @@ protected: QUuid connectionSecretUUID; }; - LimitedNodeList(int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT); + LimitedNodeList(char ownerType = NodeType::DomainServer, 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 @@ -446,7 +447,7 @@ protected: QUdpSocket* _dtlsSocket { nullptr }; HifiSockAddr _localSockAddr; HifiSockAddr _publicSockAddr; - HifiSockAddr _stunSockAddr { STUN_SERVER_HOSTNAME, STUN_SERVER_PORT }; + HifiSockAddr _stunSockAddr { SocketType::UDP, STUN_SERVER_HOSTNAME, STUN_SERVER_PORT }; bool _hasTCPCheckedLocalSocket { false }; bool _useAuthentication { true }; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 9002746061..a660099199 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(socketListenPort, dtlsListenPort), + LimitedNodeList(newOwnerType, socketListenPort, dtlsListenPort), _ownerType(newOwnerType), _nodeTypesOfInterest(), _domainHandler(this), @@ -890,6 +890,10 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { info.publicSocket.setAddress(_domainHandler.getIP()); } + // WEBRTC TODO: Handle WebRTC-connected nodes. Probably need to include SocketType in HifiSockAddr << and >> + info.publicSocket.setSocketType(SocketType::UDP); + info.localSocket.setSocketType(SocketType::UDP); + addNewNode(info); } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 59b3815fba..2ffac59702 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -153,7 +153,9 @@ private slots: void maybeSendIgnoreSetToNode(SharedNodePointer node); private: - NodeList() : LimitedNodeList(INVALID_PORT, INVALID_PORT) { assert(false); } // Not implemented, needed for DependencyManager templates compile + NodeList() : LimitedNodeList(NodeType::Unassigned, INVALID_PORT, INVALID_PORT) { + assert(false); // Not implemented, needed for DependencyManager templates compile + } NodeList(char ownerType, int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT); NodeList(NodeList const&) = delete; // Don't implement, needed to avoid copies of singleton void operator=(NodeList const&) = delete; // Don't implement, needed to avoid copies of singleton diff --git a/libraries/networking/src/SocketType.h b/libraries/networking/src/SocketType.h new file mode 100644 index 0000000000..c63ee0cf34 --- /dev/null +++ b/libraries/networking/src/SocketType.h @@ -0,0 +1,39 @@ +// +// SocketType.h +// libraries/networking/src +// +// Created by David Rowe on 17 May 2021. +// Copyright 2021 Vircadia contributors. +// +// Handles UDP and WebRTC sockets in parallel. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef vircadia_SocketType_h +#define vircadia_SocketType_h + +/// @addtogroup Networking +/// @{ + + +/// @brief The network socket type. +enum class SocketType { + Unknown, ///< Unknown socket type. + UDP, ///< UDP socket. + WebRTC ///< WebRTC socket. +}; + +/// @brief Returns the name of a SocketType value as a string. +/// @param socketType The SocketType value. +/// @return The name of the SocketType value as a string. +static QString socketTypeToString(SocketType socketType) { + static QStringList SOCKET_TYPE_STRINGS { "Unknown", "UDP", "WebRTC" }; + return SOCKET_TYPE_STRINGS[(int)socketType]; +} + + +/// @} + +#endif // vircadia_SocketType_h diff --git a/libraries/networking/src/udt/NetworkSocket.cpp b/libraries/networking/src/udt/NetworkSocket.cpp new file mode 100644 index 0000000000..3fb039187e --- /dev/null +++ b/libraries/networking/src/udt/NetworkSocket.cpp @@ -0,0 +1,281 @@ +// +// NetworkSocket.cpp +// libraries/networking/src/udt +// +// Created by David Rowe on 21 Jun 2021. +// Copyright 2021 Vircadia contributors. +// + +#include "NetworkSocket.h" + +#include "../NetworkLogging.h" + + +NetworkSocket::NetworkSocket(QObject* parent, NodeType_t nodeType) : + QObject(parent), + _parent(parent), + _udpSocket(this) +#if defined(WEBRTC_DATA_CHANNELS) + , + _webrtcSocket(this, nodeType) +#endif +{ + connect(&_udpSocket, &QUdpSocket::readyRead, this, &NetworkSocket::readyRead); + connect(&_udpSocket, &QAbstractSocket::stateChanged, this, &NetworkSocket::onUDPStateChanged); + connect(&_udpSocket, &QAbstractSocket::errorOccurred, this, &NetworkSocket::onUDPSocketError); +#if defined(WEBRTC_DATA_CHANNELS) + connect(&_webrtcSocket, &WebRTCSocket::readyRead, this, &NetworkSocket::readyRead); + connect(&_webrtcSocket, &WebRTCSocket::stateChanged, this, &NetworkSocket::onWebRTCStateChanged); + // WEBRTC TODO: Add similar for errorOccurred +#endif +} + + +void NetworkSocket::setSocketOption(SocketType socketType, QAbstractSocket::SocketOption option, const QVariant& value) { + switch (socketType) { + case SocketType::UDP: + _udpSocket.setSocketOption(option, value); + break; +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + _webrtcSocket.setSocketOption(option, value); + break; +#endif + default: + qCCritical(networking) << "Socket type not specified in setSocketOption()"; + } +} + +QVariant NetworkSocket::socketOption(SocketType socketType, QAbstractSocket::SocketOption option) { + switch (socketType) { + case SocketType::UDP: + return _udpSocket.socketOption(option); +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + return _webrtcSocket.socketOption(option); +#endif + default: + qCCritical(networking) << "Socket type not specified in socketOption()"; + return ""; + } +} + + +void NetworkSocket::bind(SocketType socketType, const QHostAddress& address, quint16 port) { + switch (socketType) { + case SocketType::UDP: + _udpSocket.bind(address, port); + break; +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + _webrtcSocket.bind(address, port); + break; +#endif + default: + qCCritical(networking) << "Socket type not specified in bind()"; + } +} + +void NetworkSocket::abort(SocketType socketType) { + switch (socketType) { + case SocketType::UDP: + _udpSocket.abort(); + break; +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + _webrtcSocket.abort(); + break; +#endif + default: + qCCritical(networking) << "Socket type not specified in abort()"; + } +} + + +quint16 NetworkSocket::localPort(SocketType socketType) const { + switch (socketType) { + case SocketType::UDP: + return _udpSocket.localPort(); +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + return _webrtcSocket.localPort(); +#endif + default: + qCCritical(networking) << "Socket type not specified in localPort()"; + return 0; + } +} + +qintptr NetworkSocket::socketDescriptor(SocketType socketType) const { + switch (socketType) { + case SocketType::UDP: + return _udpSocket.socketDescriptor(); +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + return _webrtcSocket.socketDescriptor(); + return 0; +#endif + default: + qCCritical(networking) << "Socket type not specified in socketDescriptor()"; + return 0; + } +} + + +qint64 NetworkSocket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr) { + switch (sockAddr.getSocketType()) { + 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()); +#endif + default: + qCCritical(networking) << "Socket type not specified in writeDatagram() address"; + return 0; + } +} + +qint64 NetworkSocket::bytesToWrite(SocketType socketType, quint16 port) const { + switch (socketType) { + case SocketType::UDP: + return _udpSocket.bytesToWrite(); +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + return _webrtcSocket.bytesToWrite(port); +#endif + default: + qCCritical(networking) << "Socket type not specified in bytesToWrite()"; + return 0; + } +} + + +bool NetworkSocket::hasPendingDatagrams() const { + return +#if defined(WEBRTC_DATA_CHANNELS) + _webrtcSocket.hasPendingDatagrams() || +#endif + _udpSocket.hasPendingDatagrams(); +} + +qint64 NetworkSocket::pendingDatagramSize() { +#if defined(WEBRTC_DATA_CHANNELS) + // Alternate socket types, remembering the socket type used so that the same socket type is used next readDatagram(). + if (_lastSocketTypeRead == SocketType::UDP) { + if (_webrtcSocket.hasPendingDatagrams()) { + _pendingDatagramSizeSocketType = SocketType::WebRTC; + return _webrtcSocket.pendingDatagramSize(); + } else { + _pendingDatagramSizeSocketType = SocketType::UDP; + return _udpSocket.pendingDatagramSize(); + } + } else { + if (_udpSocket.hasPendingDatagrams()) { + _pendingDatagramSizeSocketType = SocketType::UDP; + return _udpSocket.pendingDatagramSize(); + } else { + _pendingDatagramSizeSocketType = SocketType::WebRTC; + return _webrtcSocket.pendingDatagramSize(); + } + } +#else + return _udpSocket.pendingDatagramSize(); +#endif +} + +qint64 NetworkSocket::readDatagram(char* data, qint64 maxSize, HifiSockAddr* sockAddr) { +#if defined(WEBRTC_DATA_CHANNELS) + // Read per preceding pendingDatagramSize() if any, otherwise alternate socket types. + if (_pendingDatagramSizeSocketType == SocketType::UDP + || _pendingDatagramSizeSocketType == SocketType::Unknown && _lastSocketTypeRead == SocketType::WebRTC) { + _lastSocketTypeRead = SocketType::UDP; + _pendingDatagramSizeSocketType = SocketType::Unknown; + if (sockAddr) { + sockAddr->setSocketType(SocketType::UDP); + return _udpSocket.readDatagram(data, maxSize, sockAddr->getAddressPointer(), sockAddr->getPortPointer()); + } else { + return _udpSocket.readDatagram(data, maxSize); + } + } else { + _lastSocketTypeRead = SocketType::WebRTC; + _pendingDatagramSizeSocketType = SocketType::Unknown; + if (sockAddr) { + sockAddr->setSocketType(SocketType::WebRTC); + return _webrtcSocket.readDatagram(data, maxSize, sockAddr->getAddressPointer(), sockAddr->getPortPointer()); + } else { + return _webrtcSocket.readDatagram(data, maxSize); + } + } +#else + if (sockAddr) { + sockAddr->setSocketType(SocketType::UDP); + return _udpSocket.readDatagram(data, maxSize, sockAddr->getAddressPointer(), sockAddr->getPortPointer()); + } else { + return _udpSocket.readDatagram(data, maxSize); + } +#endif +} + + +QAbstractSocket::SocketState NetworkSocket::state(SocketType socketType) const { + switch (socketType) { + case SocketType::UDP: + return _udpSocket.state(); +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + return _webrtcSocket.state(); +#endif + default: + qCCritical(networking) << "Socket type not specified in state()"; + return QAbstractSocket::SocketState::UnconnectedState; + } +} + + +QAbstractSocket::SocketError NetworkSocket::error(SocketType socketType) const { + switch (socketType) { + case SocketType::UDP: + return _udpSocket.error(); +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + return _webrtcSocket.error(); +#endif + default: + qCCritical(networking) << "Socket type not specified in error()"; + return QAbstractSocket::SocketError::UnknownSocketError; + } +} + +QString NetworkSocket::errorString(SocketType socketType) const { + switch (socketType) { + case SocketType::UDP: + return _udpSocket.errorString(); +#if defined(WEBRTC_DATA_CHANNELS) + case SocketType::WebRTC: + return _webrtcSocket.errorString(); +#endif + default: + qCCritical(networking) << "Socket type not specified in errorString()"; + return ""; + } +} + + +void NetworkSocket::onUDPStateChanged(QAbstractSocket::SocketState socketState) { + emit stateChanged(SocketType::UDP, socketState); +} + +void NetworkSocket::onWebRTCStateChanged(QAbstractSocket::SocketState socketState) { + emit stateChanged(SocketType::WebRTC, socketState); +} + +void NetworkSocket::onUDPSocketError(QAbstractSocket::SocketError socketError) { + emit NetworkSocket::socketError(SocketType::UDP, socketError); +} + +void NetworkSocket::onWebRTCSocketError(QAbstractSocket::SocketError socketError) { + emit NetworkSocket::socketError(SocketType::WebRTC, socketError); +} diff --git a/libraries/networking/src/udt/NetworkSocket.h b/libraries/networking/src/udt/NetworkSocket.h new file mode 100644 index 0000000000..b946ab0bd0 --- /dev/null +++ b/libraries/networking/src/udt/NetworkSocket.h @@ -0,0 +1,163 @@ +// +// NetworkSocket.h +// libraries/networking/src/udt +// +// Created by David Rowe on 21 Jun 2021. +// Copyright 2021 Vircadia contributors. +// + +#ifndef vircadia_NetworkSocket_h +#define vircadia_NetworkSocket_h + +#include +#include + +#include + +#include "../HifiSockAddr.h" +#include "../NodeType.h" +#include "../SocketType.h" +#if defined(WEBRTC_DATA_CHANNELS) +#include "../webrtc/WebRTCSocket.h" +#endif + +/// @addtogroup Networking +/// @{ + + +/// @brief Multiplexes a QUdpSocket and a WebRTCSocket so that they appear as a single QUdpSocket-style socket. +class NetworkSocket : public QObject { + Q_OBJECT + +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); + + + /// @brief Set the value of a UDP or WebRTC socket option. + /// @param socketType The type of socket for which to set the option value. + /// @param option The option to set the value of. + /// @param value The option value. + void setSocketOption(SocketType socketType, QAbstractSocket::SocketOption option, const QVariant& value); + + /// @brief Gets the value of a UDP or WebRTC socket option. + /// @param socketType The type of socket for which to get the option value. + /// @param option The option to get the value of. + /// @return The option value. + QVariant socketOption(SocketType socketType, QAbstractSocket::SocketOption option); + + + /// @brief Binds the UDP or WebRTC socket to an address and port. + /// @param socketType The type of socket to bind. + /// @param address The address to bind to. + /// @param port The port to bind to. + void bind(SocketType socketType, const QHostAddress& address, quint16 port = 0); + + /// @brief Immediately closes and resets the socket. + /// @param socketType The type of socket to close and reset. + void abort(SocketType socketType); + + + /// @brief Gets the UDP or WebRTC local port number. + /// @param socketType The type of socket for which to the get local port number. + /// @return The UDP or WebRTC local port number if available, otherwise 0. + quint16 localPort(SocketType socketType) const; + + /// @brief Returns the native socket descriptor of the UDP or WebRTC socket. + /// @param socketType The type of socket to get the socket descriptor for. + /// @return The native socket descriptor if available, otherwise -1. + qintptr socketDescriptor(SocketType socketType) const; + + + /// @brief Sends a datagram to a network address. + /// @param datagram The datagram to send. + /// @param sockAddr The address to send to. + /// @return The number of bytes if successfully sent, otherwise -1. + qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); + + /// @brief Gets the number of bytes waiting to be written. + /// @detail 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. + /// @return The number of bytes waiting to be written. + qint64 bytesToWrite(SocketType socketType, quint16 port = 0) const; + + + /// @brief Gets whether there is a pending datagram waiting to be read. + /// @return true if there is a datagram waiting to be read, false if there isn't. + 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. + qint64 pendingDatagramSize(); + + /// @brief Reads the next datagram per the most recent pendingDatagramSize call if made, otherwise alternating between + /// socket types if both have datagrams to read. + /// @param data The destination to write the data into. + /// @param maxSize The maximum number of bytes to read. + /// @param sockAddr The destination to write the source network address into. + /// @return The number of bytes if successfully read, otherwise -1. + qint64 readDatagram(char* data, qint64 maxSize, HifiSockAddr* sockAddr = nullptr); + + + /// @brief Gets the state of the UDP or WebRTC socket. + /// @param socketType The type of socket for which to get the state. + /// @return The socket state. + QAbstractSocket::SocketState state(SocketType socketType) const; + + + /// @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 + QAbstractSocket::SocketError error(SocketType socketType) const; + + /// @brief Gets the description of the error that last occurred. + /// @param socketType The type of socket for which to get the last error's description. + /// @return The description of the error that last occurred. + QString errorString(SocketType socketType) const; + +signals: + + /// @brief Emitted each time new data becomes available for reading. + void readyRead(); + + /// @brief Emitted when the state of the underlying UDP or WebRTC socket changes. + /// @param socketType The type of socket that changed state. + /// @param socketState The socket's new state. + void stateChanged(SocketType socketType, QAbstractSocket::SocketState socketState); + + /// @brief + /// @param socketType + /// @param socketError + void socketError(SocketType socketType, QAbstractSocket::SocketError socketError); + +private slots: + + void onUDPStateChanged(QAbstractSocket::SocketState socketState); + void onWebRTCStateChanged(QAbstractSocket::SocketState socketState); + + void onUDPSocketError(QAbstractSocket::SocketError socketError); + void onWebRTCSocketError(QAbstractSocket::SocketError socketError); + +private: + + QObject* _parent; + + QUdpSocket _udpSocket; +#if defined(WEBRTC_DATA_CHANNELS) + WebRTCSocket _webrtcSocket; +#endif + +#if defined(WEBRTC_DATA_CHANNELS) + SocketType _pendingDatagramSizeSocketType { SocketType::Unknown }; + SocketType _lastSocketTypeRead { SocketType::Unknown }; +#endif +}; + + +/// @} + +#endif // vircadia_NetworkSocket_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 017855d628..5365bc1e6c 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -39,18 +39,17 @@ using namespace udt; #endif -Socket::Socket(QObject* parent, bool shouldChangeSocketOptions) : +Socket::Socket(QObject* parent, bool shouldChangeSocketOptions, NodeType_t nodeType) : QObject(parent), - _udpSocket(parent), + _networkSocket(parent, nodeType), _readyReadBackupTimer(new QTimer(this)), _shouldChangeSocketOptions(shouldChangeSocketOptions) { - connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); + connect(&_networkSocket, &NetworkSocket::readyRead, this, &Socket::readPendingDatagrams); // make sure we hear about errors and state changes from the underlying socket - connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(handleSocketError(QAbstractSocket::SocketError))); - connect(&_udpSocket, &QAbstractSocket::stateChanged, this, &Socket::handleStateChanged); + connect(&_networkSocket, &NetworkSocket::socketError, this, &Socket::handleSocketError); + connect(&_networkSocket, &NetworkSocket::stateChanged, this, &Socket::handleStateChanged); // in order to help track down the zombie server bug, add a timer to check if we missed a readyRead const int READY_READ_BACKUP_CHECK_MSECS = 2 * 1000; @@ -58,19 +57,21 @@ Socket::Socket(QObject* parent, bool shouldChangeSocketOptions) : _readyReadBackupTimer->start(READY_READ_BACKUP_CHECK_MSECS); } -void Socket::bind(const QHostAddress& address, quint16 port) { - - _udpSocket.bind(address, port); +void Socket::bind(SocketType socketType, const QHostAddress& address, quint16 port) { + _networkSocket.bind(socketType, address, port); if (_shouldChangeSocketOptions) { - setSystemBufferSizes(); + setSystemBufferSizes(socketType); + if (socketType == SocketType::WebRTC) { + return; + } #if defined(Q_OS_LINUX) - auto sd = _udpSocket.socketDescriptor(); + auto sd = _networkSocket.socketDescriptor(socketType); int val = IP_PMTUDISC_DONT; setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); #elif defined(Q_OS_WIN) - auto sd = _udpSocket.socketDescriptor(); + auto sd = _networkSocket.socketDescriptor(socketType); int val = 0; // false if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAGMENT, (const char *)&val, sizeof(val))) { auto wsaErr = WSAGetLastError(); @@ -80,16 +81,16 @@ void Socket::bind(const QHostAddress& address, quint16 port) { } } -void Socket::rebind() { - rebind(_udpSocket.localPort()); +void Socket::rebind(SocketType socketType) { + rebind(socketType, _networkSocket.localPort(socketType)); } -void Socket::rebind(quint16 localPort) { - _udpSocket.abort(); - bind(QHostAddress::AnyIPv4, localPort); +void Socket::rebind(SocketType socketType, quint16 localPort) { + _networkSocket.abort(socketType); + bind(socketType, QHostAddress::AnyIPv4, localPort); } -void Socket::setSystemBufferSizes() { +void Socket::setSystemBufferSizes(SocketType socketType) { for (int i = 0; i < 2; i++) { QAbstractSocket::SocketOption bufferOpt; QString bufferTypeString; @@ -98,20 +99,22 @@ void Socket::setSystemBufferSizes() { if (i == 0) { bufferOpt = QAbstractSocket::SendBufferSizeSocketOption; - numBytes = udt::UDP_SEND_BUFFER_SIZE_BYTES; + numBytes = socketType == SocketType::UDP + ? udt::UDP_SEND_BUFFER_SIZE_BYTES : udt::WEBRTC_SEND_BUFFER_SIZE_BYTES; bufferTypeString = "send"; } else { bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption; - numBytes = udt::UDP_RECEIVE_BUFFER_SIZE_BYTES; + numBytes = socketType == SocketType::UDP + ? udt::UDP_RECEIVE_BUFFER_SIZE_BYTES : udt::WEBRTC_RECEIVE_BUFFER_SIZE_BYTES; bufferTypeString = "receive"; } - int oldBufferSize = _udpSocket.socketOption(bufferOpt).toInt(); + int oldBufferSize = _networkSocket.socketOption(socketType, bufferOpt).toInt(); if (oldBufferSize < numBytes) { - _udpSocket.setSocketOption(bufferOpt, QVariant(numBytes)); - int newBufferSize = _udpSocket.socketOption(bufferOpt).toInt(); + _networkSocket.setSocketOption(socketType, bufferOpt, QVariant(numBytes)); + int newBufferSize = _networkSocket.socketOption(socketType, bufferOpt).toInt(); qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" << newBufferSize << "bytes"; @@ -235,16 +238,18 @@ qint64 Socket::writeDatagram(const char* data, qint64 size, const HifiSockAddr& } qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr) { + auto socketType = sockAddr.getSocketType(); // don't attempt to write the datagram if we're unbound. Just drop it. - // _udpSocket.writeDatagram will return an error anyway, but there are + // _networkSocket.writeDatagram will return an error anyway, but there are // potential crashes in Qt when that happens. - if (_udpSocket.state() != QAbstractSocket::BoundState) { + if (_networkSocket.state(socketType) != QAbstractSocket::BoundState) { qCDebug(networking) << "Attempt to writeDatagram when in unbound state to" << sockAddr; return -1; } - qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); - int pending = _udpSocket.bytesToWrite(); + qint64 bytesWritten = _networkSocket.writeDatagram(datagram, sockAddr); + + int pending = _networkSocket.bytesToWrite(socketType, sockAddr.getPort()); if (bytesWritten < 0 || pending) { int wsaError = 0; static std::atomic previousWsaError (0); @@ -252,8 +257,8 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc wsaError = WSAGetLastError(); #endif QString errorString; - QDebug(&errorString) << "udt::writeDatagram (" << _udpSocket.state() << sockAddr << ") error - " - << wsaError << _udpSocket.error() << "(" << _udpSocket.errorString() << ")" + QDebug(&errorString) << "udt::writeDatagram (" << _networkSocket.state(socketType) << sockAddr << ") error - " + << wsaError << _networkSocket.error(socketType) << "(" << _networkSocket.errorString(socketType) << ")" << (pending ? "pending bytes:" : "pending:") << pending; if (previousWsaError.exchange(wsaError) != wsaError) { @@ -343,7 +348,7 @@ void Socket::messageFailed(Connection* connection, Packet::MessageNumber message } void Socket::checkForReadyReadBackup() { - if (_udpSocket.hasPendingDatagrams()) { + if (_networkSocket.hasPendingDatagrams()) { qCDebug(networking) << "Socket::checkForReadyReadBackup() detected blocked readyRead signal. Flushing pending datagrams."; // so that birarda can possibly figure out how the heck we get into this state in the first place @@ -357,8 +362,8 @@ void Socket::checkForReadyReadBackup() { // drop all of the pending datagrams on the floor int droppedCount = 0; - while (_udpSocket.hasPendingDatagrams()) { - _udpSocket.readDatagram(nullptr, 0); + while (_networkSocket.hasPendingDatagrams()) { + _networkSocket.readDatagram(nullptr, 0); ++droppedCount; } qCDebug(networking) << "Flushed" << droppedCount << "Packets"; @@ -371,8 +376,8 @@ void Socket::readPendingDatagrams() { const auto abortTime = system_clock::now() + MAX_PROCESS_TIME; int packetSizeWithHeader = -1; - while (_udpSocket.hasPendingDatagrams() && - (packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) { + while (_networkSocket.hasPendingDatagrams() && + (packetSizeWithHeader = _networkSocket.pendingDatagramSize()) != -1) { if (system_clock::now() > abortTime) { // We've been running for too long, stop processing packets for now // Once we've processed the event queue, we'll come back to packet processing @@ -397,8 +402,7 @@ void Socket::readPendingDatagrams() { auto buffer = std::unique_ptr(new char[packetSizeWithHeader]); // pull the datagram - auto sizeRead = _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, - senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); + auto sizeRead = _networkSocket.readDatagram(buffer.get(), packetSizeWithHeader, &senderSockAddr); // save information for this packet, in case it is the one that sticks readyRead _lastPacketSizeRead = sizeRead; @@ -540,17 +544,17 @@ std::vector Socket::getConnectionSockAddrs() { return addr; } -void Socket::handleSocketError(QAbstractSocket::SocketError socketError) { +void Socket::handleSocketError(SocketType socketType, QAbstractSocket::SocketError socketError) { int wsaError = 0; static std::atomic previousWsaError(0); #ifdef WIN32 wsaError = WSAGetLastError(); #endif - int pending = _udpSocket.bytesToWrite(); + int pending = _networkSocket.bytesToWrite(socketType); QString errorString; - QDebug(&errorString) << "udt::Socket (" << _udpSocket.state() << ") error - " << wsaError << socketError << - "(" << _udpSocket.errorString() << ")" << (pending ? "pending bytes:" : "pending:") - << pending; + QDebug(&errorString) << "udt::Socket (" << socketTypeToString(socketType) << _networkSocket.state(socketType) + << ") error - " << wsaError << socketError << "(" << _networkSocket.errorString(socketType) << ")" + << (pending ? "pending bytes:" : "pending:") << pending; if (previousWsaError.exchange(wsaError) != wsaError) { qCDebug(networking).noquote() << errorString; @@ -563,9 +567,9 @@ void Socket::handleSocketError(QAbstractSocket::SocketError socketError) { } } -void Socket::handleStateChanged(QAbstractSocket::SocketState socketState) { +void Socket::handleStateChanged(SocketType socketType, QAbstractSocket::SocketState socketState) { if (socketState != QAbstractSocket::BoundState) { - qCDebug(networking) << "udt::Socket state changed - state is now" << socketState; + qCDebug(networking) << socketTypeToString(socketType) << "socket state changed - state is now" << socketState; } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 6cd2d25659..1b697cdb77 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -21,11 +21,11 @@ #include #include -#include #include "../HifiSockAddr.h" #include "TCPVegasCC.h" #include "Connection.h" +#include "NetworkSocket.h" //#define UDT_CONNECTION_DEBUG @@ -55,9 +55,9 @@ class Socket : public QObject { public: using StatsVector = std::vector>; - Socket(QObject* object = 0, bool shouldChangeSocketOptions = true); + Socket(QObject* object = 0, bool shouldChangeSocketOptions = true, NodeType_t nodeType = NodeType::Unassigned); - quint16 localPort() const { return _udpSocket.localPort(); } + quint16 localPort(SocketType socketType) const { return _networkSocket.localPort(socketType); } // Simple functions writing to the socket with no processing qint64 writeBasePacket(const BasePacket& packet, const HifiSockAddr& sockAddr); @@ -67,9 +67,9 @@ public: qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr); qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); - void bind(const QHostAddress& address, quint16 port = 0); - void rebind(quint16 port); - void rebind(); + void bind(SocketType socketType, const QHostAddress& address, quint16 port = 0); + void rebind(SocketType socketType, quint16 port); + void rebind(SocketType socketType); void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; } void setPacketHandler(PacketHandler handler) { _packetHandler = handler; } @@ -105,11 +105,11 @@ private slots: void readPendingDatagrams(); void checkForReadyReadBackup(); - void handleSocketError(QAbstractSocket::SocketError socketError); - void handleStateChanged(QAbstractSocket::SocketState socketState); + void handleSocketError(SocketType socketType, QAbstractSocket::SocketError socketError); + void handleStateChanged(SocketType socketType, QAbstractSocket::SocketState socketState); private: - void setSystemBufferSizes(); + void setSystemBufferSizes(SocketType socketType); Connection* findOrCreateConnection(const HifiSockAddr& sockAddr, bool filterCreation = false); // privatized methods used by UDTTest - they are private since they must be called on the Socket thread @@ -121,7 +121,7 @@ private: Q_INVOKABLE void writeReliablePacket(Packet* packet, const HifiSockAddr& sockAddr); Q_INVOKABLE void writeReliablePacketList(PacketList* packetList, const HifiSockAddr& sockAddr); - QUdpSocket _udpSocket { this }; + NetworkSocket _networkSocket; PacketFilterOperator _packetFilterOperator; PacketHandler _packetHandler; MessageHandler _messageHandler; diff --git a/tools/ice-client/src/ICEClientApp.cpp b/tools/ice-client/src/ICEClientApp.cpp index 0301fad6f4..42e38bd748 100644 --- a/tools/ice-client/src/ICEClientApp.cpp +++ b/tools/ice-client/src/ICEClientApp.cpp @@ -62,7 +62,7 @@ ICEClientApp::ICEClientApp(int argc, char* argv[]) : const_cast(&networking())->setEnabled(QtWarningMsg, false); } - _stunSockAddr = HifiSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT, true); + _stunSockAddr = HifiSockAddr(SocketType::UDP, STUN_SERVER_HOSTNAME, STUN_SERVER_PORT, true); _cacheSTUNResult = parser.isSet(cacheSTUNOption); @@ -79,7 +79,7 @@ ICEClientApp::ICEClientApp(int argc, char* argv[]) : } } - _iceServerAddr = HifiSockAddr("127.0.0.1", ICE_SERVER_DEFAULT_PORT); + _iceServerAddr = HifiSockAddr(SocketType::UDP, "127.0.0.1", ICE_SERVER_DEFAULT_PORT); if (parser.isSet(iceServerAddressOption)) { // parse the IP and port combination for this target QString hostnamePortString = parser.value(iceServerAddressOption); @@ -96,7 +96,7 @@ ICEClientApp::ICEClientApp(int argc, char* argv[]) : QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); } else { - _iceServerAddr = HifiSockAddr(address, port); + _iceServerAddr = HifiSockAddr(SocketType::UDP, address, port); } } @@ -132,7 +132,7 @@ void ICEClientApp::openSocket() { _socket = new udt::Socket(); unsigned int localPort = 0; - _socket->bind(QHostAddress::AnyIPv4, localPort); + _socket->bind(SocketType::UDP, QHostAddress::AnyIPv4, localPort); _socket->setPacketHandler([this](std::unique_ptr packet) { processPacket(std::move(packet)); }); _socket->addUnfilteredHandler(_stunSockAddr, [this](std::unique_ptr packet) { @@ -140,10 +140,10 @@ void ICEClientApp::openSocket() { }); if (_verbose) { - qDebug() << "local port is" << _socket->localPort(); + qDebug() << "local port is" << _socket->localPort(SocketType::UDP); } - _localSockAddr = HifiSockAddr("127.0.0.1", _socket->localPort()); - _publicSockAddr = HifiSockAddr("127.0.0.1", _socket->localPort()); + _localSockAddr = HifiSockAddr(SocketType::UDP, "127.0.0.1", _socket->localPort(SocketType::UDP)); + _publicSockAddr = HifiSockAddr(SocketType::UDP, "127.0.0.1", _socket->localPort(SocketType::UDP)); _domainPingCount = 0; } @@ -188,7 +188,7 @@ void ICEClientApp::doSomething() { if (_verbose) { qDebug() << "using cached STUN response"; } - _publicSockAddr.setPort(_socket->localPort()); + _publicSockAddr.setPort(_socket->localPort(SocketType::UDP)); setState(talkToIceServer); } @@ -303,7 +303,7 @@ void ICEClientApp::processSTUNResponse(std::unique_ptr packet) uint16_t newPublicPort; QHostAddress newPublicAddress; if (LimitedNodeList::parseSTUNResponse(packet.get(), newPublicAddress, newPublicPort)) { - _publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort); + _publicSockAddr = HifiSockAddr(SocketType::UDP, newPublicAddress, newPublicPort); if (_verbose) { qDebug() << "My public address is" << _publicSockAddr; }