mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-05 21:22:07 +02:00
Multiplex UDP and WebRTC sockets in a QUdpSocket-style NetworkSocket
This commit is contained in:
parent
d65ecead9f
commit
5a5cb6488c
18 changed files with 633 additions and 106 deletions
|
@ -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;
|
||||
|
|
|
@ -69,7 +69,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
// create a NodeList so we can receive stats from children
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<LimitedNodeList>(listenPort);
|
||||
auto nodeList = DependencyManager::set<LimitedNodeList>(NodeType::Unassigned, listenPort);
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AssignmentClientStatus,
|
||||
|
|
|
@ -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<LimitedNodeList>(domainServerPort, domainServerDTLSPort);
|
||||
auto nodeList = DependencyManager::set<LimitedNodeList>(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
|
||||
|
|
|
@ -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<udt::Packet> packet) { processPacket(std::move(packet)); });
|
||||
|
|
|
@ -551,7 +551,7 @@ void setupPreferences() {
|
|||
auto getter = [nodeListWeak] {
|
||||
auto nodeList = nodeListWeak.lock();
|
||||
if (nodeList) {
|
||||
return static_cast<int>(nodeList->getSocketLocalPort());
|
||||
return static_cast<int>(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<quint16>(preset));
|
||||
nodeList->setSocketLocalPort(SocketType::UDP, static_cast<quint16>(preset));
|
||||
}
|
||||
};
|
||||
auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter);
|
||||
|
|
|
@ -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<NodeList>();
|
||||
|
|
|
@ -27,21 +27,22 @@
|
|||
int hifiSockAddrMetaTypeId = qRegisterMetaType<HifiSockAddr>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,16 @@ struct sockaddr;
|
|||
|
||||
#include <QtNetwork/QHostInfo>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
|
|
@ -49,18 +49,18 @@ static Setting::Handle<quint16> 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>("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<udt::BasePacket> 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
39
libraries/networking/src/SocketType.h
Normal file
39
libraries/networking/src/SocketType.h
Normal file
|
@ -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
|
281
libraries/networking/src/udt/NetworkSocket.cpp
Normal file
281
libraries/networking/src/udt/NetworkSocket.cpp
Normal file
|
@ -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);
|
||||
}
|
163
libraries/networking/src/udt/NetworkSocket.h
Normal file
163
libraries/networking/src/udt/NetworkSocket.h
Normal file
|
@ -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 <QObject>
|
||||
#include <QUdpSocket>
|
||||
|
||||
#include <shared/WebRTC.h>
|
||||
|
||||
#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 <code>0</code>.
|
||||
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 <code>-1</code>.
|
||||
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 <code>-1</code>.
|
||||
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 <code>true</code> if there is a datagram waiting to be read, <code>false</code> 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 <code>-1</code>.
|
||||
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
|
|
@ -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<int> 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<char[]>(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<HifiSockAddr> Socket::getConnectionSockAddrs() {
|
|||
return addr;
|
||||
}
|
||||
|
||||
void Socket::handleSocketError(QAbstractSocket::SocketError socketError) {
|
||||
void Socket::handleSocketError(SocketType socketType, QAbstractSocket::SocketError socketError) {
|
||||
int wsaError = 0;
|
||||
static std::atomic<int> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtNetwork/QUdpSocket>
|
||||
|
||||
#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<std::pair<HifiSockAddr, ConnectionStats::Stats>>;
|
||||
|
||||
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;
|
||||
|
|
|
@ -62,7 +62,7 @@ ICEClientApp::ICEClientApp(int argc, char* argv[]) :
|
|||
const_cast<QLoggingCategory*>(&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<udt::Packet> packet) { processPacket(std::move(packet)); });
|
||||
_socket->addUnfilteredHandler(_stunSockAddr,
|
||||
[this](std::unique_ptr<udt::BasePacket> 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<udt::BasePacket> 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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue