mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 22:56:54 +02:00
Merge pull request #1259 from ctrlaltdavid/dev/webrtc-packet
First exchange of Vircadia protocol packets with the Vircadia Web SDK
This commit is contained in:
commit
dfd71ab18b
30 changed files with 1070 additions and 222 deletions
|
@ -82,7 +82,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
|
||||||
_assignmentServerHostname = assignmentServerHostname;
|
_assignmentServerHostname = assignmentServerHostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
_assignmentServerSocket = HifiSockAddr(SocketType::UDP, _assignmentServerHostname, assignmentServerPort, true);
|
||||||
if (_assignmentServerSocket.isNull()) {
|
if (_assignmentServerSocket.isNull()) {
|
||||||
qCCritical(assignment_client) << "PAGE: Couldn't resolve domain server address" << _assignmentServerHostname;
|
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?
|
// did we get an assignment-client monitor port?
|
||||||
if (assignmentMonitorPort > 0) {
|
if (assignmentMonitorPort > 0) {
|
||||||
_assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, assignmentMonitorPort);
|
_assignmentClientMonitorSocket = HifiSockAddr(SocketType::UDP, DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME,
|
||||||
|
assignmentMonitorPort);
|
||||||
_assignmentClientMonitorSocket.setObjectName("AssignmentClientMonitor");
|
_assignmentClientMonitorSocket.setObjectName("AssignmentClientMonitor");
|
||||||
|
|
||||||
qCDebug(assignment_client) << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket;
|
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
|
// create a NodeList so we can receive stats from children
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
auto addressManager = DependencyManager::set<AddressManager>();
|
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();
|
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||||
packetReceiver.registerListener(PacketType::AssignmentClientStatus,
|
packetReceiver.registerListener(PacketType::AssignmentClientStatus,
|
||||||
|
|
|
@ -165,10 +165,6 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||||
DomainServer::DomainServer(int argc, char* argv[]) :
|
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
QCoreApplication(argc, argv),
|
QCoreApplication(argc, argv),
|
||||||
_gatekeeper(this),
|
_gatekeeper(this),
|
||||||
#ifdef WEBRTC_DATA_CHANNELS
|
|
||||||
_webrtcSignalingServer(QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT, this),
|
|
||||||
_webrtcDataChannels(NodeType::DomainServer, this),
|
|
||||||
#endif
|
|
||||||
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT,
|
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT,
|
||||||
QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this)
|
QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this)
|
||||||
{
|
{
|
||||||
|
@ -252,8 +248,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
updateDownstreamNodes();
|
updateDownstreamNodes();
|
||||||
updateUpstreamNodes();
|
updateUpstreamNodes();
|
||||||
|
|
||||||
setUpWebRTC();
|
|
||||||
|
|
||||||
if (_type != NonMetaverse) {
|
if (_type != NonMetaverse) {
|
||||||
// if we have a metaverse domain, we'll use an access token for API calls
|
// if we have a metaverse domain, we'll use an access token for API calls
|
||||||
resetAccountManagerAccessToken();
|
resetAccountManagerAccessToken();
|
||||||
|
@ -737,10 +731,11 @@ void DomainServer::setupNodeListAndAssignments() {
|
||||||
// check for scripts the user wants to persist from their domain-server config
|
// check for scripts the user wants to persist from their domain-server config
|
||||||
populateStaticScriptedAssignmentsFromSettings();
|
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
|
// 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
|
// store our local http ports in shared memory
|
||||||
quint16 localHttpPort = DOMAIN_SERVER_HTTP_PORT;
|
quint16 localHttpPort = DOMAIN_SERVER_HTTP_PORT;
|
||||||
|
@ -3047,6 +3042,7 @@ ReplicationServerInfo serverInformationFromSettings(QVariantMap serverMap, Repli
|
||||||
|
|
||||||
// read the address and port and construct a HifiSockAddr from them
|
// read the address and port and construct a HifiSockAddr from them
|
||||||
serverInfo.sockAddr = {
|
serverInfo.sockAddr = {
|
||||||
|
SocketType::UDP,
|
||||||
serverMap[REPLICATION_SERVER_ADDRESS].toString(),
|
serverMap[REPLICATION_SERVER_ADDRESS].toString(),
|
||||||
(quint16) serverMap[REPLICATION_SERVER_PORT].toString().toInt()
|
(quint16) serverMap[REPLICATION_SERVER_PORT].toString().toInt()
|
||||||
};
|
};
|
||||||
|
@ -3139,20 +3135,6 @@ void DomainServer::updateUpstreamNodes() {
|
||||||
updateReplicationNodes(Upstream);
|
updateReplicationNodes(Upstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::setUpWebRTC() {
|
|
||||||
#ifdef WEBRTC_DATA_CHANNELS
|
|
||||||
|
|
||||||
// Inbound WebRTC signaling messages received from a client.
|
|
||||||
connect(&_webrtcSignalingServer, &WebRTCSignalingServer::messageReceived,
|
|
||||||
&_webrtcDataChannels, &WebRTCDataChannels::onSignalingMessage);
|
|
||||||
|
|
||||||
// Outbound WebRTC signaling messages being sent to a client.
|
|
||||||
connect(&_webrtcDataChannels, &WebRTCDataChannels::signalingMessage,
|
|
||||||
&_webrtcSignalingServer, &WebRTCSignalingServer::sendMessage);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void DomainServer::initializeExporter() {
|
void DomainServer::initializeExporter() {
|
||||||
static const QString ENABLE_EXPORTER = "monitoring.enable_prometheus_exporter";
|
static const QString ENABLE_EXPORTER = "monitoring.enable_prometheus_exporter";
|
||||||
static const QString EXPORTER_PORT = "monitoring.prometheus_exporter_port";
|
static const QString EXPORTER_PORT = "monitoring.prometheus_exporter_port";
|
||||||
|
@ -3641,7 +3623,7 @@ void DomainServer::randomizeICEServerAddress(bool shouldTriggerHostLookup) {
|
||||||
indexToTry = distribution(generator);
|
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;
|
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
|
// clear our number of hearbeat denials, this should be re-set on ice-server change
|
||||||
|
|
|
@ -27,11 +27,6 @@
|
||||||
#include <Assignment.h>
|
#include <Assignment.h>
|
||||||
#include <HTTPSConnection.h>
|
#include <HTTPSConnection.h>
|
||||||
#include <LimitedNodeList.h>
|
#include <LimitedNodeList.h>
|
||||||
#include <shared/WebRTC.h>
|
|
||||||
#if defined(WEBRTC_DATA_CHANNELS)
|
|
||||||
#include <webrtc/WebRTCDataChannels.h>
|
|
||||||
#include <webrtc/WebRTCSignalingServer.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "AssetsBackupHandler.h"
|
#include "AssetsBackupHandler.h"
|
||||||
#include "DomainGatekeeper.h"
|
#include "DomainGatekeeper.h"
|
||||||
|
@ -147,8 +142,6 @@ private slots:
|
||||||
void updateDownstreamNodes();
|
void updateDownstreamNodes();
|
||||||
void updateUpstreamNodes();
|
void updateUpstreamNodes();
|
||||||
|
|
||||||
void setUpWebRTC();
|
|
||||||
|
|
||||||
void initializeExporter();
|
void initializeExporter();
|
||||||
void initializeMetadataExporter();
|
void initializeMetadataExporter();
|
||||||
|
|
||||||
|
@ -319,11 +312,6 @@ private:
|
||||||
std::unordered_map<int, std::unique_ptr<QTemporaryFile>> _pendingContentFiles;
|
std::unordered_map<int, std::unique_ptr<QTemporaryFile>> _pendingContentFiles;
|
||||||
|
|
||||||
QThread _assetClientThread;
|
QThread _assetClientThread;
|
||||||
|
|
||||||
#ifdef WEBRTC_DATA_CHANNELS
|
|
||||||
WebRTCSignalingServer _webrtcSignalingServer;
|
|
||||||
WebRTCDataChannels _webrtcDataChannels;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ IceServer::IceServer(int argc, char* argv[]) :
|
||||||
{
|
{
|
||||||
// start the ice-server socket
|
// start the ice-server socket
|
||||||
qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT;
|
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
|
// set processPacket as the verified packet callback for the udt::Socket
|
||||||
_serverSocket.setPacketHandler([this](std::unique_ptr<udt::Packet> packet) { processPacket(std::move(packet)); });
|
_serverSocket.setPacketHandler([this](std::unique_ptr<udt::Packet> packet) { processPacket(std::move(packet)); });
|
||||||
|
|
|
@ -551,7 +551,7 @@ void setupPreferences() {
|
||||||
auto getter = [nodeListWeak] {
|
auto getter = [nodeListWeak] {
|
||||||
auto nodeList = nodeListWeak.lock();
|
auto nodeList = nodeListWeak.lock();
|
||||||
if (nodeList) {
|
if (nodeList) {
|
||||||
return static_cast<int>(nodeList->getSocketLocalPort());
|
return static_cast<int>(nodeList->getSocketLocalPort(SocketType::UDP));
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -559,7 +559,7 @@ void setupPreferences() {
|
||||||
auto setter = [nodeListWeak](int preset) {
|
auto setter = [nodeListWeak](int preset) {
|
||||||
auto nodeList = nodeListWeak.lock();
|
auto nodeList = nodeListWeak.lock();
|
||||||
if (nodeList) {
|
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);
|
auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter);
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
DomainHandler::DomainHandler(QObject* parent) :
|
DomainHandler::DomainHandler(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
_sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
|
_sockAddr(HifiSockAddr(SocketType::UDP, QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
|
||||||
_icePeer(this),
|
_icePeer(this),
|
||||||
_settingsTimer(this),
|
_settingsTimer(this),
|
||||||
_apiRefreshTimer(this)
|
_apiRefreshTimer(this)
|
||||||
|
@ -282,7 +282,8 @@ void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname,
|
||||||
|
|
||||||
HifiSockAddr* replaceableSockAddr = &_iceServerSockAddr;
|
HifiSockAddr* replaceableSockAddr = &_iceServerSockAddr;
|
||||||
replaceableSockAddr->~HifiSockAddr();
|
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");
|
_iceServerSockAddr.setObjectName("IceServer");
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
@ -367,7 +368,7 @@ void DomainHandler::setIsConnected(bool isConnected) {
|
||||||
emit connectedToDomain(_domainURL);
|
emit connectedToDomain(_domainURL);
|
||||||
|
|
||||||
// FIXME: Reinstate the requestDomainSettings() call here in version 2021.2.0 instead of having it in
|
// FIXME: Reinstate the requestDomainSettings() call here in version 2021.2.0 instead of having it in
|
||||||
// NodeList::processDomainServerList().
|
// NodeList::processDomainList().
|
||||||
/*
|
/*
|
||||||
if (_domainURL.scheme() == URL_SCHEME_HIFI && !_domainURL.host().isEmpty()) {
|
if (_domainURL.scheme() == URL_SCHEME_HIFI && !_domainURL.host().isEmpty()) {
|
||||||
// we've connected to new domain - time to ask it for global settings
|
// we've connected to new domain - time to ask it for global settings
|
||||||
|
|
|
@ -27,21 +27,22 @@
|
||||||
int hifiSockAddrMetaTypeId = qRegisterMetaType<HifiSockAddr>();
|
int hifiSockAddrMetaTypeId = qRegisterMetaType<HifiSockAddr>();
|
||||||
|
|
||||||
HifiSockAddr::HifiSockAddr() :
|
HifiSockAddr::HifiSockAddr() :
|
||||||
|
_socketType(SocketType::Unknown),
|
||||||
_address(),
|
_address(),
|
||||||
_port(0)
|
_port(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiSockAddr::HifiSockAddr(const QHostAddress& address, quint16 port) :
|
HifiSockAddr::HifiSockAddr(SocketType socketType, const QHostAddress& address, quint16 port) :
|
||||||
|
_socketType(socketType),
|
||||||
_address(address),
|
_address(address),
|
||||||
_port(port)
|
_port(port)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) :
|
HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) :
|
||||||
QObject(),
|
QObject(),
|
||||||
|
_socketType(otherSockAddr._socketType),
|
||||||
_address(otherSockAddr._address),
|
_address(otherSockAddr._address),
|
||||||
_port(otherSockAddr._port)
|
_port(otherSockAddr._port)
|
||||||
{
|
{
|
||||||
|
@ -50,12 +51,14 @@ HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) :
|
||||||
|
|
||||||
HifiSockAddr& HifiSockAddr::operator=(const HifiSockAddr& rhsSockAddr) {
|
HifiSockAddr& HifiSockAddr::operator=(const HifiSockAddr& rhsSockAddr) {
|
||||||
setObjectName(rhsSockAddr.objectName());
|
setObjectName(rhsSockAddr.objectName());
|
||||||
|
_socketType = rhsSockAddr._socketType;
|
||||||
_address = rhsSockAddr._address;
|
_address = rhsSockAddr._address;
|
||||||
_port = rhsSockAddr._port;
|
_port = rhsSockAddr._port;
|
||||||
return *this;
|
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),
|
_address(hostname),
|
||||||
_port(hostOrderPort)
|
_port(hostOrderPort)
|
||||||
{
|
{
|
||||||
|
@ -73,19 +76,10 @@ HifiSockAddr::HifiSockAddr(const QString& hostname, quint16 hostOrderPort, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiSockAddr::HifiSockAddr(const sockaddr* sockaddr) {
|
|
||||||
_address = QHostAddress(sockaddr);
|
|
||||||
|
|
||||||
if (sockaddr->sa_family == AF_INET) {
|
|
||||||
_port = ntohs(reinterpret_cast<const sockaddr_in*>(sockaddr)->sin_port);
|
|
||||||
} else {
|
|
||||||
_port = ntohs(reinterpret_cast<const sockaddr_in6*>(sockaddr)->sin6_port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HifiSockAddr::swap(HifiSockAddr& otherSockAddr) {
|
void HifiSockAddr::swap(HifiSockAddr& otherSockAddr) {
|
||||||
using std::swap;
|
using std::swap;
|
||||||
|
|
||||||
|
swap(_socketType, otherSockAddr._socketType);
|
||||||
swap(_address, otherSockAddr._address);
|
swap(_address, otherSockAddr._address);
|
||||||
swap(_port, otherSockAddr._port);
|
swap(_port, otherSockAddr._port);
|
||||||
|
|
||||||
|
@ -96,7 +90,7 @@ void HifiSockAddr::swap(HifiSockAddr& otherSockAddr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HifiSockAddr::operator==(const HifiSockAddr& rhsSockAddr) const {
|
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) {
|
void HifiSockAddr::handleLookupResult(const QHostInfo& hostInfo) {
|
||||||
|
@ -118,7 +112,7 @@ void HifiSockAddr::handleLookupResult(const QHostInfo& hostInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString HifiSockAddr::toString() const {
|
QString HifiSockAddr::toString() const {
|
||||||
return _address.toString() + ":" + QString::number(_port);
|
return socketTypeToString(_socketType) + " " + _address.toString() + ":" + QString::number(_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HifiSockAddr::hasPrivateAddress() const {
|
bool HifiSockAddr::hasPrivateAddress() const {
|
||||||
|
@ -134,17 +128,27 @@ bool HifiSockAddr::hasPrivateAddress() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr) {
|
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();
|
return debug.space();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr) {
|
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;
|
dataStream << sockAddr._address << sockAddr._port;
|
||||||
return dataStream;
|
return dataStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) {
|
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;
|
dataStream >> sockAddr._address >> sockAddr._port;
|
||||||
|
|
||||||
|
// Set default for non-WebRTC code.
|
||||||
|
// WEBRTC TODO: Reconsider this.
|
||||||
|
sockAddr.setSocketType(SocketType::UDP);
|
||||||
|
|
||||||
return dataStream;
|
return dataStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,16 @@ struct sockaddr;
|
||||||
|
|
||||||
#include <QtNetwork/QHostInfo>
|
#include <QtNetwork/QHostInfo>
|
||||||
|
|
||||||
|
#include "SocketType.h"
|
||||||
|
|
||||||
|
|
||||||
class HifiSockAddr : public QObject {
|
class HifiSockAddr : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
HifiSockAddr();
|
HifiSockAddr();
|
||||||
HifiSockAddr(const QHostAddress& address, quint16 port);
|
HifiSockAddr(SocketType socketType, const QHostAddress& address, quint16 port);
|
||||||
HifiSockAddr(const HifiSockAddr& otherSockAddr);
|
HifiSockAddr(const HifiSockAddr& otherSockAddr);
|
||||||
HifiSockAddr(const QString& hostname, quint16 hostOrderPort, bool shouldBlockForLookup = false);
|
HifiSockAddr(SocketType socketType, const QString& hostname, quint16 hostOrderPort, bool shouldBlockForLookup = false);
|
||||||
HifiSockAddr(const sockaddr* sockaddr);
|
|
||||||
|
|
||||||
bool isNull() const { return _address.isNull() && _port == 0; }
|
bool isNull() const { return _address.isNull() && _port == 0; }
|
||||||
void clear() { _address.clear(); _port = 0;}
|
void clear() { _address.clear(); _port = 0;}
|
||||||
|
@ -37,6 +39,10 @@ public:
|
||||||
bool operator==(const HifiSockAddr& rhsSockAddr) const;
|
bool operator==(const HifiSockAddr& rhsSockAddr) const;
|
||||||
bool operator!=(const HifiSockAddr& rhsSockAddr) const { return !(*this == rhsSockAddr); }
|
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; }
|
const QHostAddress& getAddress() const { return _address; }
|
||||||
QHostAddress* getAddressPointer() { return &_address; }
|
QHostAddress* getAddressPointer() { return &_address; }
|
||||||
void setAddress(const QHostAddress& address) { _address = address; }
|
void setAddress(const QHostAddress& address) { _address = address; }
|
||||||
|
@ -53,6 +59,7 @@ public:
|
||||||
bool hasPrivateAddress() const; // checks if the address behind this sock addr is private per RFC 1918
|
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 QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr);
|
||||||
|
|
||||||
friend QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr);
|
friend QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr);
|
||||||
friend QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr);
|
friend QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr);
|
||||||
|
|
||||||
|
@ -62,6 +69,7 @@ signals:
|
||||||
void lookupCompleted();
|
void lookupCompleted();
|
||||||
void lookupFailed();
|
void lookupFailed();
|
||||||
private:
|
private:
|
||||||
|
SocketType _socketType { SocketType::Unknown };
|
||||||
QHostAddress _address;
|
QHostAddress _address;
|
||||||
quint16 _port;
|
quint16 _port;
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,18 +49,18 @@ static Setting::Handle<quint16> LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.Loc
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
static const std::chrono::milliseconds CONNECTION_RATE_INTERVAL_MS = 1s;
|
static const std::chrono::milliseconds CONNECTION_RATE_INTERVAL_MS = 1s;
|
||||||
|
|
||||||
LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) :
|
LimitedNodeList::LimitedNodeList(char ownerType, int socketListenPort, int dtlsListenPort) :
|
||||||
_nodeSocket(this),
|
_nodeSocket(this, true, ownerType),
|
||||||
_packetReceiver(new PacketReceiver(this))
|
_packetReceiver(new PacketReceiver(this))
|
||||||
{
|
{
|
||||||
qRegisterMetaType<ConnectionStep>("ConnectionStep");
|
qRegisterMetaType<ConnectionStep>("ConnectionStep");
|
||||||
auto port = (socketListenPort != INVALID_PORT) ? socketListenPort : LIMITED_NODELIST_LOCAL_PORT.get();
|
auto port = (socketListenPort != INVALID_PORT) ? socketListenPort : LIMITED_NODELIST_LOCAL_PORT.get();
|
||||||
_nodeSocket.bind(QHostAddress::AnyIPv4, port);
|
_nodeSocket.bind(SocketType::UDP, QHostAddress::AnyIPv4, port);
|
||||||
quint16 assignedPort = _nodeSocket.localPort();
|
quint16 assignedPort = _nodeSocket.localPort(SocketType::UDP);
|
||||||
if (socketListenPort != INVALID_PORT && socketListenPort != 0 && socketListenPort != assignedPort) {
|
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) {
|
if (dtlsListenPort != INVALID_PORT) {
|
||||||
// only create the DTLS socket during constructor if a custom port is passed
|
// 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();
|
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
|
// check for local socket updates every so often
|
||||||
const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000;
|
const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000;
|
||||||
QTimer* localSocketUpdate = new QTimer(this);
|
QTimer* localSocketUpdate = new QTimer(this);
|
||||||
|
@ -204,15 +206,20 @@ void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::setSocketLocalPort(quint16 socketLocalPort) {
|
void LimitedNodeList::setSocketLocalPort(SocketType socketType, quint16 socketLocalPort) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "setSocketLocalPort", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(this, "setSocketLocalPort", Qt::QueuedConnection,
|
||||||
Q_ARG(quint16, socketLocalPort));
|
Q_ARG(quint16, socketLocalPort));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_nodeSocket.localPort() != socketLocalPort) {
|
if (_nodeSocket.localPort(socketType) != socketLocalPort) {
|
||||||
_nodeSocket.rebind(socketLocalPort);
|
_nodeSocket.rebind(socketType, socketLocalPort);
|
||||||
LIMITED_NODELIST_LOCAL_PORT.set(socketLocalPort);
|
if (socketType == SocketType::UDP) {
|
||||||
|
LIMITED_NODELIST_LOCAL_PORT.set(socketLocalPort);
|
||||||
|
} else {
|
||||||
|
// WEBRTC TODO: Add WebRTC equivalent?
|
||||||
|
qCWarning(networking_webrtc) << "LIMITED_NODELIST_LOCAL_PORT not set for WebRTC socket";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1105,7 +1112,7 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr<udt::BasePacket> packe
|
||||||
_publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
|
_publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
|
||||||
_publicSockAddr.getPort());
|
_publicSockAddr.getPort());
|
||||||
|
|
||||||
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
|
_publicSockAddr = HifiSockAddr(SocketType::UDP, newPublicAddress, newPublicPort);
|
||||||
|
|
||||||
if (!_hasCompletedInitialSTUN) {
|
if (!_hasCompletedInitialSTUN) {
|
||||||
// if we're here we have definitely completed our initial STUN sequence
|
// if we're here we have definitely completed our initial STUN sequence
|
||||||
|
@ -1186,7 +1193,7 @@ void LimitedNodeList::stopInitialSTUNUpdate(bool success) {
|
||||||
qCDebug(networking) << "LimitedNodeList public socket will be set with local port and null QHostAddress.";
|
qCDebug(networking) << "LimitedNodeList public socket will be set with local port and null QHostAddress.";
|
||||||
|
|
||||||
// reset the public address and port to a null address
|
// 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
|
// we have changed the publicSockAddr, so emit our signal
|
||||||
emit publicSockAddrChanged(_publicSockAddr);
|
emit publicSockAddrChanged(_publicSockAddr);
|
||||||
|
@ -1213,7 +1220,7 @@ void LimitedNodeList::stopInitialSTUNUpdate(bool success) {
|
||||||
void LimitedNodeList::updateLocalSocket() {
|
void LimitedNodeList::updateLocalSocket() {
|
||||||
// when update is called, if the local socket is empty then start with the guessed local socket
|
// when update is called, if the local socket is empty then start with the guessed local socket
|
||||||
if (_localSockAddr.isNull()) {
|
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
|
// attempt to use Google's DNS to confirm that local IP
|
||||||
|
@ -1237,7 +1244,7 @@ void LimitedNodeList::connectedForLocalSocketTest() {
|
||||||
auto localHostAddress = localIPTestSocket->localAddress();
|
auto localHostAddress = localIPTestSocket->localAddress();
|
||||||
|
|
||||||
if (localHostAddress.protocol() == QAbstractSocket::IPv4Protocol) {
|
if (localHostAddress.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
setLocalSocket(HifiSockAddr { localHostAddress, _nodeSocket.localPort() });
|
setLocalSocket(HifiSockAddr { SocketType::UDP, localHostAddress, _nodeSocket.localPort(SocketType::UDP) });
|
||||||
_hasTCPCheckedLocalSocket = true;
|
_hasTCPCheckedLocalSocket = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,7 +1260,7 @@ void LimitedNodeList::errorTestingLocalSocket() {
|
||||||
// error connecting to the test socket - if we've never set our local socket using this test socket
|
// 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
|
// then use our possibly updated guessed local address as fallback
|
||||||
if (!_hasTCPCheckedLocalSocket) {
|
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"
|
qCCritical(networking) << "PAGE: Can't connect to Google DNS service via TCP, falling back to guessed local address"
|
||||||
<< getLocalSockAddr();
|
<< getLocalSockAddr();
|
||||||
}
|
}
|
||||||
|
@ -1273,8 +1280,8 @@ void LimitedNodeList::setLocalSocket(const HifiSockAddr& sockAddr) {
|
||||||
_localSockAddr = sockAddr;
|
_localSockAddr = sockAddr;
|
||||||
if (_hasTCPCheckedLocalSocket) { // Force a port change for NAT:
|
if (_hasTCPCheckedLocalSocket) { // Force a port change for NAT:
|
||||||
reset("local socket change");
|
reset("local socket change");
|
||||||
_nodeSocket.rebind(0);
|
_nodeSocket.rebind(SocketType::UDP, 0);
|
||||||
_localSockAddr.setPort(_nodeSocket.localPort());
|
_localSockAddr.setPort(_nodeSocket.localPort(SocketType::UDP));
|
||||||
qCInfo(networking) << "Local port changed to" << _localSockAddr.getPort();
|
qCInfo(networking) << "Local port changed to" << _localSockAddr.getPort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,8 +135,8 @@ public:
|
||||||
bool getThisNodeCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); }
|
bool getThisNodeCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); }
|
||||||
bool getThisNodeCanRezAvatarEntities() const { return _permissions.can(NodePermissions::Permission::canRezAvatarEntities); }
|
bool getThisNodeCanRezAvatarEntities() const { return _permissions.can(NodePermissions::Permission::canRezAvatarEntities); }
|
||||||
|
|
||||||
quint16 getSocketLocalPort() const { return _nodeSocket.localPort(); }
|
quint16 getSocketLocalPort(SocketType socketType) const { return _nodeSocket.localPort(socketType); }
|
||||||
Q_INVOKABLE void setSocketLocalPort(quint16 socketLocalPort);
|
Q_INVOKABLE void setSocketLocalPort(SocketType socketType, quint16 socketLocalPort);
|
||||||
|
|
||||||
QUdpSocket& getDTLSSocket();
|
QUdpSocket& getDTLSSocket();
|
||||||
|
|
||||||
|
@ -413,7 +413,8 @@ protected:
|
||||||
QUuid connectionSecretUUID;
|
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
|
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
|
void operator=(LimitedNodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
|
||||||
|
|
||||||
|
@ -446,7 +447,7 @@ protected:
|
||||||
QUdpSocket* _dtlsSocket { nullptr };
|
QUdpSocket* _dtlsSocket { nullptr };
|
||||||
HifiSockAddr _localSockAddr;
|
HifiSockAddr _localSockAddr;
|
||||||
HifiSockAddr _publicSockAddr;
|
HifiSockAddr _publicSockAddr;
|
||||||
HifiSockAddr _stunSockAddr { STUN_SERVER_HOSTNAME, STUN_SERVER_PORT };
|
HifiSockAddr _stunSockAddr { SocketType::UDP, STUN_SERVER_HOSTNAME, STUN_SERVER_PORT };
|
||||||
bool _hasTCPCheckedLocalSocket { false };
|
bool _hasTCPCheckedLocalSocket { false };
|
||||||
bool _useAuthentication { true };
|
bool _useAuthentication { true };
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ const int KEEPALIVE_PING_INTERVAL_MS = 1000;
|
||||||
const int MAX_SYSTEM_INFO_SIZE = 1000;
|
const int MAX_SYSTEM_INFO_SIZE = 1000;
|
||||||
|
|
||||||
NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) :
|
NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) :
|
||||||
LimitedNodeList(socketListenPort, dtlsListenPort),
|
LimitedNodeList(newOwnerType, socketListenPort, dtlsListenPort),
|
||||||
_ownerType(newOwnerType),
|
_ownerType(newOwnerType),
|
||||||
_nodeTypesOfInterest(),
|
_nodeTypesOfInterest(),
|
||||||
_domainHandler(this),
|
_domainHandler(this),
|
||||||
|
@ -147,7 +147,7 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
|
||||||
|
|
||||||
auto& packetReceiver = getPacketReceiver();
|
auto& packetReceiver = getPacketReceiver();
|
||||||
packetReceiver.registerListener(PacketType::DomainList,
|
packetReceiver.registerListener(PacketType::DomainList,
|
||||||
PacketReceiver::makeUnsourcedListenerReference<NodeList>(this, &NodeList::processDomainServerList));
|
PacketReceiver::makeUnsourcedListenerReference<NodeList>(this, &NodeList::processDomainList));
|
||||||
packetReceiver.registerListener(PacketType::Ping,
|
packetReceiver.registerListener(PacketType::Ping,
|
||||||
PacketReceiver::makeSourcedListenerReference<NodeList>(this, &NodeList::processPingPacket));
|
PacketReceiver::makeSourcedListenerReference<NodeList>(this, &NodeList::processPingPacket));
|
||||||
packetReceiver.registerListener(PacketType::PingReply,
|
packetReceiver.registerListener(PacketType::PingReply,
|
||||||
|
@ -357,7 +357,7 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
|
|
||||||
if (publicSockAddr.isNull()) {
|
if (publicSockAddr.isNull()) {
|
||||||
// we don't know our public socket and we need to send it to the domain server
|
// we don't know our public socket and we need to send it to the domain server
|
||||||
qCDebug(networking_ice) << "Waiting for inital public socket from STUN. Will not send domain-server check in.";
|
qCDebug(networking_ice) << "Waiting for initial public socket from STUN. Will not send domain-server check in.";
|
||||||
} else if (domainHandlerIp.isNull() && _domainHandler.requiresICE()) {
|
} else if (domainHandlerIp.isNull() && _domainHandler.requiresICE()) {
|
||||||
qCDebug(networking_ice) << "Waiting for ICE discovered domain-server socket. Will not send domain-server check in.";
|
qCDebug(networking_ice) << "Waiting for ICE discovered domain-server socket. Will not send domain-server check in.";
|
||||||
handleICEConnectionToDomainServer();
|
handleICEConnectionToDomainServer();
|
||||||
|
@ -401,6 +401,8 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WEBRTC TODO: Move code into packet library. And update reference in DomainConnectRequest.js.
|
||||||
|
|
||||||
auto domainPacket = NLPacket::create(domainPacketType);
|
auto domainPacket = NLPacket::create(domainPacketType);
|
||||||
|
|
||||||
QDataStream packetStream(domainPacket.get());
|
QDataStream packetStream(domainPacket.get());
|
||||||
|
@ -452,7 +454,6 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
packetStream << hardwareAddress;
|
packetStream << hardwareAddress;
|
||||||
|
|
||||||
// now add the machine fingerprint
|
// now add the machine fingerprint
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
|
||||||
packetStream << FingerprintUtils::getMachineFingerprint();
|
packetStream << FingerprintUtils::getMachineFingerprint();
|
||||||
|
|
||||||
platform::json all = platform::getAll();
|
platform::json all = platform::getAll();
|
||||||
|
@ -710,7 +711,9 @@ void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer<ReceivedM
|
||||||
sendDomainServerCheckIn();
|
sendDomainServerCheckIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message) {
|
void NodeList::processDomainList(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
|
||||||
|
// WEBRTC TODO: Move code into packet library. And update reference in DomainServerList.js.
|
||||||
|
|
||||||
// parse header information
|
// parse header information
|
||||||
QDataStream packetStream(message->getMessage());
|
QDataStream packetStream(message->getMessage());
|
||||||
|
@ -891,6 +894,10 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) {
|
||||||
info.publicSocket.setAddress(_domainHandler.getIP());
|
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);
|
addNewNode(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ public slots:
|
||||||
void sendDomainServerCheckIn();
|
void sendDomainServerCheckIn();
|
||||||
void handleDSPathQuery(const QString& newPath);
|
void handleDSPathQuery(const QString& newPath);
|
||||||
|
|
||||||
void processDomainServerList(QSharedPointer<ReceivedMessage> message);
|
void processDomainList(QSharedPointer<ReceivedMessage> message);
|
||||||
void processDomainServerAddedNode(QSharedPointer<ReceivedMessage> message);
|
void processDomainServerAddedNode(QSharedPointer<ReceivedMessage> message);
|
||||||
void processDomainServerRemovedNode(QSharedPointer<ReceivedMessage> message);
|
void processDomainServerRemovedNode(QSharedPointer<ReceivedMessage> message);
|
||||||
void processDomainServerPathResponse(QSharedPointer<ReceivedMessage> message);
|
void processDomainServerPathResponse(QSharedPointer<ReceivedMessage> message);
|
||||||
|
@ -153,7 +153,9 @@ private slots:
|
||||||
void maybeSendIgnoreSetToNode(SharedNodePointer node);
|
void maybeSendIgnoreSetToNode(SharedNodePointer node);
|
||||||
|
|
||||||
private:
|
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(char ownerType, int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT);
|
||||||
NodeList(NodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
|
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
|
void operator=(NodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
|
||||||
|
|
|
@ -139,9 +139,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr<udt::Packet> packet) {
|
||||||
if (_shouldDropPackets) {
|
if (_shouldDropPackets) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
|
||||||
|
|
||||||
// setup an NLPacket from the packet we were passed
|
// setup an NLPacket from the packet we were passed
|
||||||
auto nlPacket = NLPacket::fromBase(std::move(packet));
|
auto nlPacket = NLPacket::fromBase(std::move(packet));
|
||||||
auto receivedMessage = QSharedPointer<ReceivedMessage>::create(*nlPacket);
|
auto receivedMessage = QSharedPointer<ReceivedMessage>::create(*nlPacket);
|
||||||
|
|
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 types of network socket.
|
||||||
|
enum class SocketType {
|
||||||
|
Unknown, ///< Unknown socket type.
|
||||||
|
UDP, ///< UDP socket.
|
||||||
|
WebRTC ///< WebRTC socket. A WebRTC data channel presented as a UDP-style socket.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Returns the name of a SocketType value, e.g., <code>"WebRTC"</code>.
|
||||||
|
/// @param socketType The SocketType value.
|
||||||
|
/// @return The name of the SocketType value.
|
||||||
|
static QString socketTypeToString(SocketType socketType) {
|
||||||
|
static QStringList SOCKET_TYPE_STRINGS { "Unknown", "UDP", "WebRTC" };
|
||||||
|
return SOCKET_TYPE_STRINGS[(int)socketType];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
#endif // vircadia_SocketType_h
|
|
@ -57,7 +57,7 @@ BasePacket::BasePacket(qint64 size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
Q_ASSERT(size >= 0 || size < maxPayload);
|
Q_ASSERT(size >= 0 && size <= maxPayload);
|
||||||
|
|
||||||
_packetSize = size;
|
_packetSize = size;
|
||||||
_packet.reset(new char[_packetSize]());
|
_packet.reset(new char[_packetSize]());
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace udt {
|
||||||
static const int CONNECTION_SEND_BUFFER_SIZE_PACKETS = 8192;
|
static const int CONNECTION_SEND_BUFFER_SIZE_PACKETS = 8192;
|
||||||
static const int UDP_SEND_BUFFER_SIZE_BYTES = 1048576;
|
static const int UDP_SEND_BUFFER_SIZE_BYTES = 1048576;
|
||||||
static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576;
|
static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576;
|
||||||
|
static const int WEBRTC_SEND_BUFFER_SIZE_BYTES = 1048576;
|
||||||
|
static const int WEBRTC_RECEIVE_BUFFER_SIZE_BYTES = 1048576;
|
||||||
static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000;
|
static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000;
|
||||||
|
|
||||||
|
|
||||||
|
|
284
libraries/networking/src/udt/NetworkSocket.cpp
Normal file
284
libraries/networking/src/udt/NetworkSocket.cpp
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
//
|
||||||
|
// 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);
|
||||||
|
// Use old SIGNAL/SLOT mechanism for Android builds.
|
||||||
|
connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||||
|
this, SLOT(onUDPSocketError(QAbstractSocket::SocketError)));
|
||||||
|
|
||||||
|
#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.
|
||||||
|
/// @details For UDP, there's a single buffer used for all destinations. For WebRTC, each destination has its own buffer.
|
||||||
|
/// @param socketType The type of socket for which to get the number of bytes waiting to be written.
|
||||||
|
/// @param port If a WebRTC socket, the data channel for which to get the number of bytes waiting.
|
||||||
|
/// @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
|
|
@ -10,6 +10,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// WEBRTC TODO: Rename / split up into files with better names.
|
||||||
|
|
||||||
#ifndef hifi_PacketHeaders_h
|
#ifndef hifi_PacketHeaders_h
|
||||||
#define hifi_PacketHeaders_h
|
#define hifi_PacketHeaders_h
|
||||||
|
|
||||||
|
|
|
@ -39,18 +39,17 @@ using namespace udt;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Socket::Socket(QObject* parent, bool shouldChangeSocketOptions) :
|
Socket::Socket(QObject* parent, bool shouldChangeSocketOptions, NodeType_t nodeType) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
_udpSocket(parent),
|
_networkSocket(parent, nodeType),
|
||||||
_readyReadBackupTimer(new QTimer(this)),
|
_readyReadBackupTimer(new QTimer(this)),
|
||||||
_shouldChangeSocketOptions(shouldChangeSocketOptions)
|
_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
|
// make sure we hear about errors and state changes from the underlying socket
|
||||||
connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
|
connect(&_networkSocket, &NetworkSocket::socketError, this, &Socket::handleSocketError);
|
||||||
this, SLOT(handleSocketError(QAbstractSocket::SocketError)));
|
connect(&_networkSocket, &NetworkSocket::stateChanged, this, &Socket::handleStateChanged);
|
||||||
connect(&_udpSocket, &QAbstractSocket::stateChanged, this, &Socket::handleStateChanged);
|
|
||||||
|
|
||||||
// in order to help track down the zombie server bug, add a timer to check if we missed a readyRead
|
// 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;
|
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);
|
_readyReadBackupTimer->start(READY_READ_BACKUP_CHECK_MSECS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::bind(const QHostAddress& address, quint16 port) {
|
void Socket::bind(SocketType socketType, const QHostAddress& address, quint16 port) {
|
||||||
|
_networkSocket.bind(socketType, address, port);
|
||||||
_udpSocket.bind(address, port);
|
|
||||||
|
|
||||||
if (_shouldChangeSocketOptions) {
|
if (_shouldChangeSocketOptions) {
|
||||||
setSystemBufferSizes();
|
setSystemBufferSizes(socketType);
|
||||||
|
if (socketType == SocketType::WebRTC) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX)
|
#if defined(Q_OS_LINUX)
|
||||||
auto sd = _udpSocket.socketDescriptor();
|
auto sd = _networkSocket.socketDescriptor(socketType);
|
||||||
int val = IP_PMTUDISC_DONT;
|
int val = IP_PMTUDISC_DONT;
|
||||||
setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val));
|
setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val));
|
||||||
#elif defined(Q_OS_WIN)
|
#elif defined(Q_OS_WIN)
|
||||||
auto sd = _udpSocket.socketDescriptor();
|
auto sd = _networkSocket.socketDescriptor(socketType);
|
||||||
int val = 0; // false
|
int val = 0; // false
|
||||||
if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAGMENT, (const char *)&val, sizeof(val))) {
|
if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAGMENT, (const char *)&val, sizeof(val))) {
|
||||||
auto wsaErr = WSAGetLastError();
|
auto wsaErr = WSAGetLastError();
|
||||||
|
@ -80,16 +81,16 @@ void Socket::bind(const QHostAddress& address, quint16 port) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::rebind() {
|
void Socket::rebind(SocketType socketType) {
|
||||||
rebind(_udpSocket.localPort());
|
rebind(socketType, _networkSocket.localPort(socketType));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::rebind(quint16 localPort) {
|
void Socket::rebind(SocketType socketType, quint16 localPort) {
|
||||||
_udpSocket.abort();
|
_networkSocket.abort(socketType);
|
||||||
bind(QHostAddress::AnyIPv4, localPort);
|
bind(socketType, QHostAddress::AnyIPv4, localPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::setSystemBufferSizes() {
|
void Socket::setSystemBufferSizes(SocketType socketType) {
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
QAbstractSocket::SocketOption bufferOpt;
|
QAbstractSocket::SocketOption bufferOpt;
|
||||||
QString bufferTypeString;
|
QString bufferTypeString;
|
||||||
|
@ -98,20 +99,22 @@ void Socket::setSystemBufferSizes() {
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
bufferOpt = QAbstractSocket::SendBufferSizeSocketOption;
|
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";
|
bufferTypeString = "send";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption;
|
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";
|
bufferTypeString = "receive";
|
||||||
}
|
}
|
||||||
|
|
||||||
int oldBufferSize = _udpSocket.socketOption(bufferOpt).toInt();
|
int oldBufferSize = _networkSocket.socketOption(socketType, bufferOpt).toInt();
|
||||||
|
|
||||||
if (oldBufferSize < numBytes) {
|
if (oldBufferSize < numBytes) {
|
||||||
_udpSocket.setSocketOption(bufferOpt, QVariant(numBytes));
|
_networkSocket.setSocketOption(socketType, bufferOpt, QVariant(numBytes));
|
||||||
int newBufferSize = _udpSocket.socketOption(bufferOpt).toInt();
|
int newBufferSize = _networkSocket.socketOption(socketType, bufferOpt).toInt();
|
||||||
|
|
||||||
qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to"
|
qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to"
|
||||||
<< newBufferSize << "bytes";
|
<< 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) {
|
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.
|
// 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.
|
// 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;
|
qCDebug(networking) << "Attempt to writeDatagram when in unbound state to" << sockAddr;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort());
|
qint64 bytesWritten = _networkSocket.writeDatagram(datagram, sockAddr);
|
||||||
int pending = _udpSocket.bytesToWrite();
|
|
||||||
|
int pending = _networkSocket.bytesToWrite(socketType, sockAddr.getPort());
|
||||||
if (bytesWritten < 0 || pending) {
|
if (bytesWritten < 0 || pending) {
|
||||||
int wsaError = 0;
|
int wsaError = 0;
|
||||||
static std::atomic<int> previousWsaError (0);
|
static std::atomic<int> previousWsaError (0);
|
||||||
|
@ -252,8 +257,8 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc
|
||||||
wsaError = WSAGetLastError();
|
wsaError = WSAGetLastError();
|
||||||
#endif
|
#endif
|
||||||
QString errorString;
|
QString errorString;
|
||||||
QDebug(&errorString) << "udt::writeDatagram (" << _udpSocket.state() << sockAddr << ") error - "
|
QDebug(&errorString) << "udt::writeDatagram (" << _networkSocket.state(socketType) << sockAddr << ") error - "
|
||||||
<< wsaError << _udpSocket.error() << "(" << _udpSocket.errorString() << ")"
|
<< wsaError << _networkSocket.error(socketType) << "(" << _networkSocket.errorString(socketType) << ")"
|
||||||
<< (pending ? "pending bytes:" : "pending:") << pending;
|
<< (pending ? "pending bytes:" : "pending:") << pending;
|
||||||
|
|
||||||
if (previousWsaError.exchange(wsaError) != wsaError) {
|
if (previousWsaError.exchange(wsaError) != wsaError) {
|
||||||
|
@ -343,7 +348,7 @@ void Socket::messageFailed(Connection* connection, Packet::MessageNumber message
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::checkForReadyReadBackup() {
|
void Socket::checkForReadyReadBackup() {
|
||||||
if (_udpSocket.hasPendingDatagrams()) {
|
if (_networkSocket.hasPendingDatagrams()) {
|
||||||
qCDebug(networking) << "Socket::checkForReadyReadBackup() detected blocked readyRead signal. Flushing pending datagrams.";
|
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
|
// 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
|
// drop all of the pending datagrams on the floor
|
||||||
int droppedCount = 0;
|
int droppedCount = 0;
|
||||||
while (_udpSocket.hasPendingDatagrams()) {
|
while (_networkSocket.hasPendingDatagrams()) {
|
||||||
_udpSocket.readDatagram(nullptr, 0);
|
_networkSocket.readDatagram(nullptr, 0);
|
||||||
++droppedCount;
|
++droppedCount;
|
||||||
}
|
}
|
||||||
qCDebug(networking) << "Flushed" << droppedCount << "Packets";
|
qCDebug(networking) << "Flushed" << droppedCount << "Packets";
|
||||||
|
@ -371,8 +376,8 @@ void Socket::readPendingDatagrams() {
|
||||||
const auto abortTime = system_clock::now() + MAX_PROCESS_TIME;
|
const auto abortTime = system_clock::now() + MAX_PROCESS_TIME;
|
||||||
int packetSizeWithHeader = -1;
|
int packetSizeWithHeader = -1;
|
||||||
|
|
||||||
while (_udpSocket.hasPendingDatagrams() &&
|
while (_networkSocket.hasPendingDatagrams() &&
|
||||||
(packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) {
|
(packetSizeWithHeader = _networkSocket.pendingDatagramSize()) != -1) {
|
||||||
if (system_clock::now() > abortTime) {
|
if (system_clock::now() > abortTime) {
|
||||||
// We've been running for too long, stop processing packets for now
|
// 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
|
// 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]);
|
auto buffer = std::unique_ptr<char[]>(new char[packetSizeWithHeader]);
|
||||||
|
|
||||||
// pull the datagram
|
// pull the datagram
|
||||||
auto sizeRead = _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader,
|
auto sizeRead = _networkSocket.readDatagram(buffer.get(), packetSizeWithHeader, &senderSockAddr);
|
||||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
|
||||||
|
|
||||||
// save information for this packet, in case it is the one that sticks readyRead
|
// save information for this packet, in case it is the one that sticks readyRead
|
||||||
_lastPacketSizeRead = sizeRead;
|
_lastPacketSizeRead = sizeRead;
|
||||||
|
@ -540,17 +544,17 @@ std::vector<HifiSockAddr> Socket::getConnectionSockAddrs() {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Socket::handleSocketError(QAbstractSocket::SocketError socketError) {
|
void Socket::handleSocketError(SocketType socketType, QAbstractSocket::SocketError socketError) {
|
||||||
int wsaError = 0;
|
int wsaError = 0;
|
||||||
static std::atomic<int> previousWsaError(0);
|
static std::atomic<int> previousWsaError(0);
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
wsaError = WSAGetLastError();
|
wsaError = WSAGetLastError();
|
||||||
#endif
|
#endif
|
||||||
int pending = _udpSocket.bytesToWrite();
|
int pending = _networkSocket.bytesToWrite(socketType);
|
||||||
QString errorString;
|
QString errorString;
|
||||||
QDebug(&errorString) << "udt::Socket (" << _udpSocket.state() << ") error - " << wsaError << socketError <<
|
QDebug(&errorString) << "udt::Socket (" << socketTypeToString(socketType) << _networkSocket.state(socketType)
|
||||||
"(" << _udpSocket.errorString() << ")" << (pending ? "pending bytes:" : "pending:")
|
<< ") error - " << wsaError << socketError << "(" << _networkSocket.errorString(socketType) << ")"
|
||||||
<< pending;
|
<< (pending ? "pending bytes:" : "pending:") << pending;
|
||||||
|
|
||||||
if (previousWsaError.exchange(wsaError) != wsaError) {
|
if (previousWsaError.exchange(wsaError) != wsaError) {
|
||||||
qCDebug(networking).noquote() << errorString;
|
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) {
|
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/QObject>
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QtNetwork/QUdpSocket>
|
|
||||||
|
|
||||||
#include "../HifiSockAddr.h"
|
#include "../HifiSockAddr.h"
|
||||||
#include "TCPVegasCC.h"
|
#include "TCPVegasCC.h"
|
||||||
#include "Connection.h"
|
#include "Connection.h"
|
||||||
|
#include "NetworkSocket.h"
|
||||||
|
|
||||||
//#define UDT_CONNECTION_DEBUG
|
//#define UDT_CONNECTION_DEBUG
|
||||||
|
|
||||||
|
@ -55,9 +55,9 @@ class Socket : public QObject {
|
||||||
public:
|
public:
|
||||||
using StatsVector = std::vector<std::pair<HifiSockAddr, ConnectionStats::Stats>>;
|
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
|
// Simple functions writing to the socket with no processing
|
||||||
qint64 writeBasePacket(const BasePacket& packet, const HifiSockAddr& sockAddr);
|
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 char* data, qint64 size, const HifiSockAddr& sockAddr);
|
||||||
qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr);
|
qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr);
|
||||||
|
|
||||||
void bind(const QHostAddress& address, quint16 port = 0);
|
void bind(SocketType socketType, const QHostAddress& address, quint16 port = 0);
|
||||||
void rebind(quint16 port);
|
void rebind(SocketType socketType, quint16 port);
|
||||||
void rebind();
|
void rebind(SocketType socketType);
|
||||||
|
|
||||||
void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; }
|
void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; }
|
||||||
void setPacketHandler(PacketHandler handler) { _packetHandler = handler; }
|
void setPacketHandler(PacketHandler handler) { _packetHandler = handler; }
|
||||||
|
@ -105,11 +105,11 @@ private slots:
|
||||||
void readPendingDatagrams();
|
void readPendingDatagrams();
|
||||||
void checkForReadyReadBackup();
|
void checkForReadyReadBackup();
|
||||||
|
|
||||||
void handleSocketError(QAbstractSocket::SocketError socketError);
|
void handleSocketError(SocketType socketType, QAbstractSocket::SocketError socketError);
|
||||||
void handleStateChanged(QAbstractSocket::SocketState socketState);
|
void handleStateChanged(SocketType socketType, QAbstractSocket::SocketState socketState);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setSystemBufferSizes();
|
void setSystemBufferSizes(SocketType socketType);
|
||||||
Connection* findOrCreateConnection(const HifiSockAddr& sockAddr, bool filterCreation = false);
|
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
|
// 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 writeReliablePacket(Packet* packet, const HifiSockAddr& sockAddr);
|
||||||
Q_INVOKABLE void writeReliablePacketList(PacketList* packetList, const HifiSockAddr& sockAddr);
|
Q_INVOKABLE void writeReliablePacketList(PacketList* packetList, const HifiSockAddr& sockAddr);
|
||||||
|
|
||||||
QUdpSocket _udpSocket { this };
|
NetworkSocket _networkSocket;
|
||||||
PacketFilterOperator _packetFilterOperator;
|
PacketFilterOperator _packetFilterOperator;
|
||||||
PacketHandler _packetHandler;
|
PacketHandler _packetHandler;
|
||||||
MessageHandler _messageHandler;
|
MessageHandler _messageHandler;
|
||||||
|
|
|
@ -25,6 +25,8 @@ const int MAX_WEBRTC_BUFFER_SIZE = 16777216; // 16MB
|
||||||
|
|
||||||
// #define WEBRTC_DEBUG
|
// #define WEBRTC_DEBUG
|
||||||
|
|
||||||
|
using namespace webrtc;
|
||||||
|
|
||||||
|
|
||||||
void WDCSetSessionDescriptionObserver::OnSuccess() {
|
void WDCSetSessionDescriptionObserver::OnSuccess() {
|
||||||
#ifdef WEBRTC_DEBUG
|
#ifdef WEBRTC_DEBUG
|
||||||
|
@ -330,6 +332,13 @@ void WDCConnection::onDataChannelMessageReceived(const DataBuffer& buffer) {
|
||||||
_parent->emitDataMessage(_dataChannelID, byteArray);
|
_parent->emitDataMessage(_dataChannelID, byteArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qint64 WDCConnection::getBufferedAmount() const {
|
||||||
|
#ifdef WEBRTC_DEBUG
|
||||||
|
qCDebug(networking_webrtc) << "WDCConnection::getBufferedAmount()";
|
||||||
|
#endif
|
||||||
|
return _dataChannel->buffered_amount();
|
||||||
|
}
|
||||||
|
|
||||||
bool WDCConnection::sendDataMessage(const DataBuffer& buffer) {
|
bool WDCConnection::sendDataMessage(const DataBuffer& buffer) {
|
||||||
#ifdef WEBRTC_DEBUG
|
#ifdef WEBRTC_DEBUG
|
||||||
qCDebug(networking_webrtc) << "WDCConnection::sendDataMessage()";
|
qCDebug(networking_webrtc) << "WDCConnection::sendDataMessage()";
|
||||||
|
@ -356,12 +365,13 @@ void WDCConnection::closePeerConnection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WebRTCDataChannels::WebRTCDataChannels(NodeType_t nodeType, QObject* parent) :
|
WebRTCDataChannels::WebRTCDataChannels(QObject* parent, NodeType_t nodeType) :
|
||||||
_nodeType(nodeType),
|
QObject(parent),
|
||||||
_parent(parent)
|
_parent(parent),
|
||||||
|
_nodeType(nodeType)
|
||||||
{
|
{
|
||||||
#ifdef WEBRTC_DEBUG
|
#ifdef WEBRTC_DEBUG
|
||||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::WebRTCDataChannels()";
|
qCDebug(networking_webrtc) << "WebRTCDataChannels::WebRTCDataChannels()" << nodeType << NodeType::getNodeTypeName(nodeType);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create a peer connection factory.
|
// Create a peer connection factory.
|
||||||
|
@ -392,14 +402,7 @@ WebRTCDataChannels::~WebRTCDataChannels() {
|
||||||
#ifdef WEBRTC_DEBUG
|
#ifdef WEBRTC_DEBUG
|
||||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::~WebRTCDataChannels()";
|
qCDebug(networking_webrtc) << "WebRTCDataChannels::~WebRTCDataChannels()";
|
||||||
#endif
|
#endif
|
||||||
QHashIterator<quint16, WDCConnection*> i(_connectionsByDataChannel);
|
reset();
|
||||||
while (i.hasNext()) {
|
|
||||||
i.next();
|
|
||||||
delete i.value();
|
|
||||||
}
|
|
||||||
_connectionsByWebSocket.clear();
|
|
||||||
_connectionsByDataChannel.clear();
|
|
||||||
|
|
||||||
_peerConnectionFactory = nullptr;
|
_peerConnectionFactory = nullptr;
|
||||||
_rtcSignalingThread->Stop();
|
_rtcSignalingThread->Stop();
|
||||||
_rtcSignalingThread = nullptr;
|
_rtcSignalingThread = nullptr;
|
||||||
|
@ -409,6 +412,16 @@ WebRTCDataChannels::~WebRTCDataChannels() {
|
||||||
_rtcNetworkThread = nullptr;
|
_rtcNetworkThread = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebRTCDataChannels::reset() {
|
||||||
|
QHashIterator<quint16, WDCConnection*> i(_connectionsByDataChannel);
|
||||||
|
while (i.hasNext()) {
|
||||||
|
i.next();
|
||||||
|
delete i.value();
|
||||||
|
}
|
||||||
|
_connectionsByWebSocket.clear();
|
||||||
|
_connectionsByDataChannel.clear();
|
||||||
|
}
|
||||||
|
|
||||||
quint16 WebRTCDataChannels::getNewDataChannelID() {
|
quint16 WebRTCDataChannels::getNewDataChannelID() {
|
||||||
static const int QUINT16_LIMIT = std::numeric_limits<uint16_t>::max() + 1;
|
static const int QUINT16_LIMIT = std::numeric_limits<uint16_t>::max() + 1;
|
||||||
_lastDataChannelID = std::max((_lastDataChannelID + 1) % QUINT16_LIMIT, 1);
|
_lastDataChannelID = std::max((_lastDataChannelID + 1) % QUINT16_LIMIT, 1);
|
||||||
|
@ -474,7 +487,7 @@ void WebRTCDataChannels::sendSignalingMessage(const QJsonObject& message) {
|
||||||
|
|
||||||
void WebRTCDataChannels::emitDataMessage(int dataChannelID, const QByteArray& byteArray) {
|
void WebRTCDataChannels::emitDataMessage(int dataChannelID, const QByteArray& byteArray) {
|
||||||
#ifdef WEBRTC_DEBUG
|
#ifdef WEBRTC_DEBUG
|
||||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::emitDataMessage() :" << dataChannelID;
|
qCDebug(networking_webrtc) << "WebRTCDataChannels::emitDataMessage() :" << dataChannelID << byteArray;
|
||||||
#endif
|
#endif
|
||||||
emit dataMessage(dataChannelID, byteArray);
|
emit dataMessage(dataChannelID, byteArray);
|
||||||
}
|
}
|
||||||
|
@ -495,6 +508,14 @@ bool WebRTCDataChannels::sendDataMessage(int dataChannelID, const QByteArray& by
|
||||||
return connection->sendDataMessage(buffer);
|
return connection->sendDataMessage(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Gets the number of bytes waiting to be written on a data channel.
|
||||||
|
/// @param port The data channel ID.
|
||||||
|
/// @return The number of bytes waiting to be written on the data channel.
|
||||||
|
qint64 WebRTCDataChannels::getBufferedAmount(int dataChannelID) const {
|
||||||
|
auto connection = _connectionsByDataChannel.value(dataChannelID);
|
||||||
|
return connection->getBufferedAmount();
|
||||||
|
}
|
||||||
|
|
||||||
rtc::scoped_refptr<PeerConnectionInterface> WebRTCDataChannels::createPeerConnection(
|
rtc::scoped_refptr<PeerConnectionInterface> WebRTCDataChannels::createPeerConnection(
|
||||||
const std::shared_ptr<WDCPeerConnectionObserver> peerConnectionObserver) {
|
const std::shared_ptr<WDCPeerConnectionObserver> peerConnectionObserver) {
|
||||||
#ifdef WEBRTC_DEBUG
|
#ifdef WEBRTC_DEBUG
|
||||||
|
|
|
@ -23,8 +23,6 @@
|
||||||
|
|
||||||
#include "../NodeType.h"
|
#include "../NodeType.h"
|
||||||
|
|
||||||
using namespace webrtc;
|
|
||||||
|
|
||||||
class WebRTCDataChannels;
|
class WebRTCDataChannels;
|
||||||
class WDCConnection;
|
class WDCConnection;
|
||||||
|
|
||||||
|
@ -33,7 +31,7 @@ class WDCConnection;
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// @brief A WebRTC session description observer.
|
/// @brief A WebRTC session description observer.
|
||||||
class WDCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
|
class WDCSetSessionDescriptionObserver : public webrtc::SetSessionDescriptionObserver {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @brief The call to SetLocalDescription or SetRemoteDescription succeeded.
|
/// @brief The call to SetLocalDescription or SetRemoteDescription succeeded.
|
||||||
|
@ -41,12 +39,12 @@ public:
|
||||||
|
|
||||||
/// @brief The call to SetLocalDescription or SetRemoteDescription failed.
|
/// @brief The call to SetLocalDescription or SetRemoteDescription failed.
|
||||||
/// @param error Error information.
|
/// @param error Error information.
|
||||||
void OnFailure(RTCError error) override;
|
void OnFailure(webrtc::RTCError error) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// @brief A WebRTC create session description observer.
|
/// @brief A WebRTC create session description observer.
|
||||||
class WDCCreateSessionDescriptionObserver : public CreateSessionDescriptionObserver {
|
class WDCCreateSessionDescriptionObserver : public webrtc::CreateSessionDescriptionObserver {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @brief Constructs a session description observer.
|
/// @brief Constructs a session description observer.
|
||||||
|
@ -55,11 +53,11 @@ public:
|
||||||
|
|
||||||
/// @brief The call to CreateAnswer succeeded.
|
/// @brief The call to CreateAnswer succeeded.
|
||||||
/// @param The session description.
|
/// @param The session description.
|
||||||
void OnSuccess(SessionDescriptionInterface* desc) override;
|
void OnSuccess(webrtc::SessionDescriptionInterface* desc) override;
|
||||||
|
|
||||||
//@ @brief The call to CreateAnswer failed.
|
//@ @brief The call to CreateAnswer failed.
|
||||||
/// @param error Error information.
|
/// @param error Error information.
|
||||||
void OnFailure(RTCError error) override;
|
void OnFailure(webrtc::RTCError error) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WDCConnection* _parent;
|
WDCConnection* _parent;
|
||||||
|
@ -67,7 +65,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
/// @brief A WebRTC peer connection observer.
|
/// @brief A WebRTC peer connection observer.
|
||||||
class WDCPeerConnectionObserver : public PeerConnectionObserver {
|
class WDCPeerConnectionObserver : public webrtc::PeerConnectionObserver {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @brief Constructs a peer connection observer.
|
/// @brief Constructs a peer connection observer.
|
||||||
|
@ -76,26 +74,26 @@ public:
|
||||||
|
|
||||||
/// @brief Called when the SignalingState changes.
|
/// @brief Called when the SignalingState changes.
|
||||||
/// @param newState The new signaling state.
|
/// @param newState The new signaling state.
|
||||||
void OnSignalingChange(PeerConnectionInterface::SignalingState newState) override;
|
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState newState) override;
|
||||||
|
|
||||||
/// @brief Called when renegotiation is needed. For example, an ICE restart has begun.
|
/// @brief Called when renegotiation is needed. For example, an ICE restart has begun.
|
||||||
void OnRenegotiationNeeded() override;
|
void OnRenegotiationNeeded() override;
|
||||||
|
|
||||||
/// @brief Called when the ICE gather state changes.
|
/// @brief Called when the ICE gather state changes.
|
||||||
/// @param newState The new ICE gathering state.
|
/// @param newState The new ICE gathering state.
|
||||||
void OnIceGatheringChange(PeerConnectionInterface::IceGatheringState newState) override;
|
void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState newState) override;
|
||||||
|
|
||||||
/// @brief Called when a new ICE candidate has been gathered.
|
/// @brief Called when a new ICE candidate has been gathered.
|
||||||
/// @param candidate The new ICE candidate.
|
/// @param candidate The new ICE candidate.
|
||||||
void OnIceCandidate(const IceCandidateInterface* candidate) override;
|
void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override;
|
||||||
|
|
||||||
/// @brief Called when a remote peer opens a data channel.
|
/// @brief Called when a remote peer opens a data channel.
|
||||||
/// @param dataChannel The data channel.
|
/// @param dataChannel The data channel.
|
||||||
void OnDataChannel(rtc::scoped_refptr<DataChannelInterface> dataChannel) override;
|
void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel) override;
|
||||||
|
|
||||||
/// @brief Called when the peer connection state changes.
|
/// @brief Called when the peer connection state changes.
|
||||||
/// @param newState The new peer connection state.
|
/// @param newState The new peer connection state.
|
||||||
void OnConnectionChange(PeerConnectionInterface::PeerConnectionState newState) override;
|
void OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState newState) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WDCConnection* _parent;
|
WDCConnection* _parent;
|
||||||
|
@ -103,7 +101,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
/// @brief A WebRTC data channel observer.
|
/// @brief A WebRTC data channel observer.
|
||||||
class WDCDataChannelObserver : public DataChannelObserver {
|
class WDCDataChannelObserver : public webrtc::DataChannelObserver {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @brief Constructs a data channel observer.
|
/// @brief Constructs a data channel observer.
|
||||||
|
@ -115,7 +113,7 @@ public:
|
||||||
|
|
||||||
/// @brief A data channel message was received.
|
/// @brief A data channel message was received.
|
||||||
/// @param The message received.
|
/// @param The message received.
|
||||||
void OnMessage(const DataBuffer& buffer) override;
|
void OnMessage(const webrtc::DataBuffer& buffer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WDCConnection* _parent;
|
WDCConnection* _parent;
|
||||||
|
@ -135,11 +133,11 @@ public:
|
||||||
|
|
||||||
/// @brief Gets the WebSocket ID.
|
/// @brief Gets the WebSocket ID.
|
||||||
/// @return The ID of the WebSocket.
|
/// @return The ID of the WebSocket.
|
||||||
quint16 getWebSocketID() { return _webSocketID; }
|
quint16 getWebSocketID() const { return _webSocketID; }
|
||||||
|
|
||||||
/// @brief Gets the WebRTC data channel ID.
|
/// @brief Gets the WebRTC data channel ID.
|
||||||
/// @return The WebRTC data channel ID. `-1` if not open yet.
|
/// @return The WebRTC data channel ID. `-1` if not open yet.
|
||||||
int getDataChannelID() { return _dataChannelID; }
|
int getDataChannelID() const { return _dataChannelID; }
|
||||||
|
|
||||||
|
|
||||||
/// @brief Sets the remote session description received from the remote client via the signaling channel.
|
/// @brief Sets the remote session description received from the remote client via the signaling channel.
|
||||||
|
@ -151,11 +149,11 @@ public:
|
||||||
|
|
||||||
/// @brief Sends an answer to the remote client via the signaling channel.
|
/// @brief Sends an answer to the remote client via the signaling channel.
|
||||||
/// @param description The answer.
|
/// @param description The answer.
|
||||||
void sendAnswer(SessionDescriptionInterface* description);
|
void sendAnswer(webrtc::SessionDescriptionInterface* description);
|
||||||
|
|
||||||
/// @brief Sets the local session description on the WebRTC data channel being connected.
|
/// @brief Sets the local session description on the WebRTC data channel being connected.
|
||||||
/// @param description The local session description.
|
/// @param description The local session description.
|
||||||
void setLocalDescription(SessionDescriptionInterface* description);
|
void setLocalDescription(webrtc::SessionDescriptionInterface* description);
|
||||||
|
|
||||||
/// @brief Adds an ICE candidate received from the remote client via the signaling channel.
|
/// @brief Adds an ICE candidate received from the remote client via the signaling channel.
|
||||||
/// @param data The ICE candidate.
|
/// @param data The ICE candidate.
|
||||||
|
@ -163,15 +161,15 @@ public:
|
||||||
|
|
||||||
/// @brief Sends an ICE candidate to the remote vlient via the signaling channel.
|
/// @brief Sends an ICE candidate to the remote vlient via the signaling channel.
|
||||||
/// @param candidate The ICE candidate.
|
/// @param candidate The ICE candidate.
|
||||||
void sendIceCandidate(const IceCandidateInterface* candidate);
|
void sendIceCandidate(const webrtc::IceCandidateInterface* candidate);
|
||||||
|
|
||||||
/// @brief Monitors the peer connection state.
|
/// @brief Monitors the peer connection state.
|
||||||
/// @param state The new peer connection state.
|
/// @param state The new peer connection state.
|
||||||
void onPeerConnectionStateChanged(PeerConnectionInterface::PeerConnectionState state);
|
void onPeerConnectionStateChanged(webrtc::PeerConnectionInterface::PeerConnectionState state);
|
||||||
|
|
||||||
/// @brief Handles the WebRTC data channel being opened.
|
/// @brief Handles the WebRTC data channel being opened.
|
||||||
/// @param dataChannel The WebRTC data channel.
|
/// @param dataChannel The WebRTC data channel.
|
||||||
void onDataChannelOpened(rtc::scoped_refptr<DataChannelInterface> dataChannel);
|
void onDataChannelOpened(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel);
|
||||||
|
|
||||||
/// @brief Handles a change in the state of the WebRTC data channel.
|
/// @brief Handles a change in the state of the WebRTC data channel.
|
||||||
void onDataChannelStateChanged();
|
void onDataChannelStateChanged();
|
||||||
|
@ -179,12 +177,17 @@ public:
|
||||||
|
|
||||||
/// @brief Handles a message being received on the WebRTC data channel.
|
/// @brief Handles a message being received on the WebRTC data channel.
|
||||||
/// @param buffer The message received.
|
/// @param buffer The message received.
|
||||||
void onDataChannelMessageReceived(const DataBuffer& buffer);
|
void onDataChannelMessageReceived(const webrtc::DataBuffer& buffer);
|
||||||
|
|
||||||
|
/// @brief Gets the number of bytes waiting to be sent on the WebRTC data channel.
|
||||||
|
/// @return The number of bytes waiting to be sent on the WebRTC data channel.
|
||||||
|
qint64 getBufferedAmount() const;
|
||||||
|
|
||||||
|
|
||||||
/// @brief Sends a message on the WebRTC data channel.
|
/// @brief Sends a message on the WebRTC data channel.
|
||||||
/// @param buffer The message to send.
|
/// @param buffer The message to send.
|
||||||
/// @return `true` if the message was sent, otherwise `false`.
|
/// @return `true` if the message was sent, otherwise `false`.
|
||||||
bool sendDataMessage(const DataBuffer& buffer);
|
bool sendDataMessage(const webrtc::DataBuffer& buffer);
|
||||||
|
|
||||||
/// @brief Closes the WebRTC peer connection.
|
/// @brief Closes the WebRTC peer connection.
|
||||||
void closePeerConnection();
|
void closePeerConnection();
|
||||||
|
@ -198,10 +201,10 @@ private:
|
||||||
rtc::scoped_refptr<WDCCreateSessionDescriptionObserver> _createSessionDescriptionObserver { nullptr };
|
rtc::scoped_refptr<WDCCreateSessionDescriptionObserver> _createSessionDescriptionObserver { nullptr };
|
||||||
|
|
||||||
std::shared_ptr<WDCDataChannelObserver> _dataChannelObserver { nullptr };
|
std::shared_ptr<WDCDataChannelObserver> _dataChannelObserver { nullptr };
|
||||||
rtc::scoped_refptr<DataChannelInterface> _dataChannel { nullptr };
|
rtc::scoped_refptr<webrtc::DataChannelInterface> _dataChannel { nullptr };
|
||||||
|
|
||||||
std::shared_ptr<WDCPeerConnectionObserver> _peerConnectionObserver { nullptr };
|
std::shared_ptr<WDCPeerConnectionObserver> _peerConnectionObserver { nullptr };
|
||||||
rtc::scoped_refptr<PeerConnectionInterface> _peerConnection { nullptr };
|
rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -223,20 +226,25 @@ class WebRTCDataChannels : public QObject {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @brief Constructs a new WebRTCDataChannels object.
|
/// @brief Constructs a new WebRTCDataChannels object.
|
||||||
/// @param nodeType The type of node that the WebRTCDataChannels object is being used in.
|
|
||||||
/// @param parent The parent Qt object.
|
/// @param parent The parent Qt object.
|
||||||
WebRTCDataChannels(NodeType_t nodeType, QObject* parent);
|
/// @param nodeType The type of node that the WebRTCDataChannels object is being used in.
|
||||||
|
WebRTCDataChannels(QObject* parent, NodeType_t nodeType);
|
||||||
|
|
||||||
/// @brief Destroys a WebRTCDataChannels object.
|
/// @brief Destroys a WebRTCDataChannels object.
|
||||||
~WebRTCDataChannels();
|
~WebRTCDataChannels();
|
||||||
|
|
||||||
/// @brief Returns the type of node that the WebRTCDataChannels object is being used in.
|
/// @brief Gets the type of node that the WebRTCDataChannels object is being used in.
|
||||||
/// @return The type of node.
|
/// @return The type of node.
|
||||||
NodeType_t getNodeType() {
|
NodeType_t getNodeType() {
|
||||||
return _nodeType;
|
return _nodeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Immediately closes all connections and resets the socket.
|
||||||
|
void reset();
|
||||||
|
|
||||||
/// @brief Get a new data channel ID to uniquely identify a WDCConnection.
|
/// @brief Get a new data channel ID to uniquely identify a WDCConnection.
|
||||||
|
/// @details This ID is assigned by WebRTCDataChannels; it is <em>not</em> the WebRTC data channel ID because that is only
|
||||||
|
/// unique within a peer connection.
|
||||||
/// @return A new data channel ID.
|
/// @return A new data channel ID.
|
||||||
quint16 getNewDataChannelID();
|
quint16 getNewDataChannelID();
|
||||||
|
|
||||||
|
@ -260,10 +268,15 @@ public:
|
||||||
/// @return `true` if the data message was sent, otherwise `false`.
|
/// @return `true` if the data message was sent, otherwise `false`.
|
||||||
bool sendDataMessage(int dataChannelID, const QByteArray& message);
|
bool sendDataMessage(int dataChannelID, const QByteArray& message);
|
||||||
|
|
||||||
|
/// @brief Gets the number of bytes waiting to be sent on a data channel.
|
||||||
|
/// @param dataChannelID The data channel ID.
|
||||||
|
/// @return The number of bytes waiting to be sent on the data channel.
|
||||||
|
qint64 getBufferedAmount(int dataChannelID) const;
|
||||||
|
|
||||||
/// @brief Creates a new WebRTC peer connection for connecting to an Interface client.
|
/// @brief Creates a new WebRTC peer connection for connecting to an Interface client.
|
||||||
/// @param peerConnectionObserver An observer to monitor the WebRTC peer connection.
|
/// @param peerConnectionObserver An observer to monitor the WebRTC peer connection.
|
||||||
/// @return The new WebRTC peer connection.
|
/// @return The new WebRTC peer connection.
|
||||||
rtc::scoped_refptr<PeerConnectionInterface> createPeerConnection(
|
rtc::scoped_refptr<webrtc::PeerConnectionInterface> createPeerConnection(
|
||||||
const std::shared_ptr<WDCPeerConnectionObserver> peerConnectionObserver);
|
const std::shared_ptr<WDCPeerConnectionObserver> peerConnectionObserver);
|
||||||
|
|
||||||
/// @brief Initiates closing the peer connection for a WebRTC data channel.
|
/// @brief Initiates closing the peer connection for a WebRTC data channel.
|
||||||
|
@ -312,9 +325,9 @@ private:
|
||||||
std::unique_ptr<rtc::Thread> _rtcWorkerThread { nullptr };
|
std::unique_ptr<rtc::Thread> _rtcWorkerThread { nullptr };
|
||||||
std::unique_ptr<rtc::Thread> _rtcSignalingThread { nullptr };
|
std::unique_ptr<rtc::Thread> _rtcSignalingThread { nullptr };
|
||||||
|
|
||||||
rtc::scoped_refptr<PeerConnectionFactoryInterface> _peerConnectionFactory { nullptr };
|
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> _peerConnectionFactory { nullptr };
|
||||||
|
|
||||||
quint16 _lastDataChannelID { 0 };
|
quint16 _lastDataChannelID { 0 }; // First data channel ID is 1.
|
||||||
|
|
||||||
QHash<quint16, WDCConnection*> _connectionsByWebSocket;
|
QHash<quint16, WDCConnection*> _connectionsByWebSocket;
|
||||||
QHash<quint16, WDCConnection*> _connectionsByDataChannel;
|
QHash<quint16, WDCConnection*> _connectionsByDataChannel;
|
||||||
|
|
|
@ -19,33 +19,33 @@
|
||||||
|
|
||||||
const int WEBRTC_SOCKET_CHECK_INTERVAL_IN_MS = 30000;
|
const int WEBRTC_SOCKET_CHECK_INTERVAL_IN_MS = 30000;
|
||||||
|
|
||||||
WebRTCSignalingServer::WebRTCSignalingServer(const QHostAddress& address, quint16 port, QObject* parent) :
|
WebRTCSignalingServer::WebRTCSignalingServer(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
_address(address),
|
|
||||||
_port(port),
|
|
||||||
_webSocketServer(new QWebSocketServer(QStringLiteral("WebRTC Signaling Server"), QWebSocketServer::NonSecureMode, this))
|
_webSocketServer(new QWebSocketServer(QStringLiteral("WebRTC Signaling Server"), QWebSocketServer::NonSecureMode, this))
|
||||||
{
|
{
|
||||||
connect(_webSocketServer, &QWebSocketServer::newConnection, this, &WebRTCSignalingServer::newWebSocketConnection);
|
connect(_webSocketServer, &QWebSocketServer::newConnection, this, &WebRTCSignalingServer::newWebSocketConnection);
|
||||||
|
|
||||||
bindSocket();
|
|
||||||
|
|
||||||
// Automatically recover from network interruptions.
|
// Automatically recover from network interruptions.
|
||||||
_isWebSocketServerListeningTimer = new QTimer(this);
|
_isWebSocketServerListeningTimer = new QTimer(this);
|
||||||
connect(_isWebSocketServerListeningTimer, &QTimer::timeout, this, &WebRTCSignalingServer::checkWebSocketServerIsListening);
|
connect(_isWebSocketServerListeningTimer, &QTimer::timeout, this, &WebRTCSignalingServer::checkWebSocketServerIsListening);
|
||||||
_isWebSocketServerListeningTimer->start(WEBRTC_SOCKET_CHECK_INTERVAL_IN_MS);
|
_isWebSocketServerListeningTimer->start(WEBRTC_SOCKET_CHECK_INTERVAL_IN_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebRTCSignalingServer::bind(const QHostAddress& address, quint16 port) {
|
||||||
|
_address = address;
|
||||||
|
_port = port;
|
||||||
|
auto success = _webSocketServer->listen(_address, _port);
|
||||||
|
if (!success) {
|
||||||
|
qCWarning(networking_webrtc) << "Failed to open WebSocket for WebRTC signaling.";
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
void WebRTCSignalingServer::checkWebSocketServerIsListening() {
|
void WebRTCSignalingServer::checkWebSocketServerIsListening() {
|
||||||
if (!_webSocketServer->isListening()) {
|
if (!_webSocketServer->isListening()) {
|
||||||
qCWarning(networking_webrtc) << "WebSocket on port " << QString::number(_port) << " is no longer listening";
|
qCWarning(networking_webrtc) << "WebSocket on port " << QString::number(_port) << " is no longer listening";
|
||||||
_webSockets.clear();
|
_webSockets.clear();
|
||||||
bindSocket();
|
_webSocketServer->listen(_address, _port);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebRTCSignalingServer::bindSocket() {
|
|
||||||
if (!_webSocketServer->listen(_address, _port)) {
|
|
||||||
qCWarning(networking_webrtc) << "Failed to open WebSocket for WebRTC signaling.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,14 @@ class WebRTCSignalingServer : public QObject {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @brief Constructs a new WebRTCSignalingServer object.
|
/// @brief Constructs a new WebRTCSignalingServer object.
|
||||||
/// @param address The IP address to use for the WebSocket.
|
|
||||||
/// @param port The port to use for the WebSocket.
|
|
||||||
/// @param parent Qt parent object.
|
/// @param parent Qt parent object.
|
||||||
WebRTCSignalingServer(const QHostAddress& address, quint16 port, QObject* parent = nullptr);
|
WebRTCSignalingServer(QObject* parent);
|
||||||
|
|
||||||
|
/// @brief Binds the WebRTC signaling server's WebSocket to an address and port.
|
||||||
|
/// @param address The address to use for the WebSocket.
|
||||||
|
/// @param port The port to use for the WebSocket.
|
||||||
|
/// @return <code>true</code> if the WebSocket was successfully bound, <code>false</code> if it wasn't.
|
||||||
|
bool bind(const QHostAddress& address, quint16 port);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
|
@ -88,11 +92,10 @@ private slots:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void checkWebSocketServerIsListening();
|
void checkWebSocketServerIsListening();
|
||||||
void bindSocket();
|
|
||||||
|
|
||||||
QWebSocketServer* _webSocketServer;
|
QWebSocketServer* _webSocketServer;
|
||||||
QHostAddress _address;
|
QHostAddress _address;
|
||||||
const quint16 _port;
|
quint16 _port { 0 };
|
||||||
|
|
||||||
QHash<quint16, QWebSocket*> _webSockets; // client WebSocket port, client WebSocket object
|
QHash<quint16, QWebSocket*> _webSockets; // client WebSocket port, client WebSocket object
|
||||||
|
|
||||||
|
|
157
libraries/networking/src/webrtc/WebRTCSocket.cpp
Normal file
157
libraries/networking/src/webrtc/WebRTCSocket.cpp
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
//
|
||||||
|
// WebRTCSocket.cpp
|
||||||
|
// libraries/networking/src/webrtc
|
||||||
|
//
|
||||||
|
// Created by David Rowe on 21 Jun 2021.
|
||||||
|
// Copyright 2021 Vircadia contributors.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "WebRTCSocket.h"
|
||||||
|
|
||||||
|
#if defined(WEBRTC_DATA_CHANNELS)
|
||||||
|
|
||||||
|
#include "../NetworkLogging.h"
|
||||||
|
#include "../udt/Constants.h"
|
||||||
|
|
||||||
|
|
||||||
|
WebRTCSocket::WebRTCSocket(QObject* parent, NodeType_t nodeType) :
|
||||||
|
QObject(parent),
|
||||||
|
_signalingServer(this /*, QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT*/),
|
||||||
|
_dataChannels(this, nodeType)
|
||||||
|
{
|
||||||
|
// Connect WebRTC signaling server and data channels.
|
||||||
|
connect(&_signalingServer, &WebRTCSignalingServer::messageReceived,
|
||||||
|
&_dataChannels, &WebRTCDataChannels::onSignalingMessage);
|
||||||
|
connect(&_dataChannels, &WebRTCDataChannels::signalingMessage,
|
||||||
|
&_signalingServer, &WebRTCSignalingServer::sendMessage);
|
||||||
|
|
||||||
|
// Route received data channel messages.
|
||||||
|
connect(&_dataChannels, &WebRTCDataChannels::dataMessage, this, &WebRTCSocket::onDataChannelReceivedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRTCSocket::setSocketOption(QAbstractSocket::SocketOption option, const QVariant& value) {
|
||||||
|
clearError();
|
||||||
|
switch (option) {
|
||||||
|
case QAbstractSocket::SocketOption::ReceiveBufferSizeSocketOption:
|
||||||
|
case QAbstractSocket::SocketOption::SendBufferSizeSocketOption:
|
||||||
|
// WebRTC doesn't provide access to setting these buffer sizes.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setError(QAbstractSocket::SocketError::UnsupportedSocketOperationError, "Failed to set socket option");
|
||||||
|
qCCritical(networking_webrtc) << "WebRTCSocket::setSocketOption() not implemented for option:" << option;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant WebRTCSocket::socketOption(QAbstractSocket::SocketOption option) {
|
||||||
|
clearError();
|
||||||
|
switch (option) {
|
||||||
|
case QAbstractSocket::SocketOption::ReceiveBufferSizeSocketOption:
|
||||||
|
// WebRTC doesn't provide access to the receive buffer size. Just use the default buffer size.
|
||||||
|
return udt::WEBRTC_RECEIVE_BUFFER_SIZE_BYTES;
|
||||||
|
case QAbstractSocket::SocketOption::SendBufferSizeSocketOption:
|
||||||
|
// WebRTC doesn't provide access to the send buffer size though it's probably 16MB. Just use the default buffer size.
|
||||||
|
return udt::WEBRTC_SEND_BUFFER_SIZE_BYTES;
|
||||||
|
default:
|
||||||
|
setError(QAbstractSocket::SocketError::UnsupportedSocketOperationError, "Failed to get socket option");
|
||||||
|
qCCritical(networking_webrtc) << "WebRTCSocket::getSocketOption() not implemented for option:" << option;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebRTCSocket::bind(const QHostAddress& address, quint16 port, QAbstractSocket::BindMode mode) {
|
||||||
|
// WebRTC data channels aren't bound to ports so just treat this as a successful operation.
|
||||||
|
auto wasBound = _isBound;
|
||||||
|
_isBound = _signalingServer.bind(address, port);
|
||||||
|
if (_isBound != wasBound) {
|
||||||
|
emit stateChanged(_isBound ? QAbstractSocket::BoundState : QAbstractSocket::UnconnectedState);
|
||||||
|
}
|
||||||
|
return _isBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractSocket::SocketState WebRTCSocket::state() const {
|
||||||
|
return _isBound ? QAbstractSocket::BoundState : QAbstractSocket::UnconnectedState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRTCSocket::abort() {
|
||||||
|
_dataChannels.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qint64 WebRTCSocket::writeDatagram(const QByteArray& datagram, quint16 port) {
|
||||||
|
clearError();
|
||||||
|
if (_dataChannels.sendDataMessage(port, datagram)) {
|
||||||
|
return datagram.length();
|
||||||
|
}
|
||||||
|
setError(QAbstractSocket::SocketError::UnknownSocketError, "Failed to write datagram");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 WebRTCSocket::bytesToWrite(quint16 port) const {
|
||||||
|
return _dataChannels.getBufferedAmount(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WebRTCSocket::hasPendingDatagrams() const {
|
||||||
|
return _receivedQueue.length() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 WebRTCSocket::pendingDatagramSize() const {
|
||||||
|
if (_receivedQueue.length() > 0) {
|
||||||
|
return _receivedQueue.head().second.length();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 WebRTCSocket::readDatagram(char* data, qint64 maxSize, QHostAddress* address, quint16* port) {
|
||||||
|
clearError();
|
||||||
|
if (_receivedQueue.length() > 0) {
|
||||||
|
auto datagram = _receivedQueue.dequeue();
|
||||||
|
auto length = std::min((qint64)datagram.second.length(), maxSize);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
memcpy(data, datagram.second.constData(), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address) {
|
||||||
|
// WEBRTC TODO: Use signaling channel's remote WebSocket address? Or remote data channel address?
|
||||||
|
*address = QHostAddress::AnyIPv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port) {
|
||||||
|
*port = datagram.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
setError(QAbstractSocket::SocketError::UnknownSocketError, "Failed to read datagram");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QAbstractSocket::SocketError WebRTCSocket::error() const {
|
||||||
|
return _lastErrorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WebRTCSocket::errorString() const {
|
||||||
|
return _lastErrorString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WebRTCSocket::setError(QAbstractSocket::SocketError errorType, QString errorString) {
|
||||||
|
_lastErrorType = errorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRTCSocket::clearError() {
|
||||||
|
_lastErrorType = QAbstractSocket::SocketError();
|
||||||
|
_lastErrorString = QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WebRTCSocket::onDataChannelReceivedMessage(int dataChannelID, const QByteArray& message) {
|
||||||
|
_receivedQueue.enqueue(QPair<int, QByteArray>(dataChannelID, message));
|
||||||
|
emit readyRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WEBRTC_DATA_CHANNELS
|
161
libraries/networking/src/webrtc/WebRTCSocket.h
Normal file
161
libraries/networking/src/webrtc/WebRTCSocket.h
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
//
|
||||||
|
// WebRTCSocket.h
|
||||||
|
// libraries/networking/src/webrtc
|
||||||
|
//
|
||||||
|
// Created by David Rowe on 21 Jun 2021.
|
||||||
|
// Copyright 2021 Vircadia contributors.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef vircadia_WebRTCSocket_h
|
||||||
|
#define vircadia_WebRTCSocket_h
|
||||||
|
|
||||||
|
#include <shared/WebRTC.h>
|
||||||
|
|
||||||
|
#if defined(WEBRTC_DATA_CHANNELS)
|
||||||
|
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
#include "WebRTCDataChannels.h"
|
||||||
|
#include "WebRTCSignalingServer.h"
|
||||||
|
|
||||||
|
/// @addtogroup Networking
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Provides a QUdpSocket-style interface for using WebRTCDataChannels.
|
||||||
|
class WebRTCSocket : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// @brief Constructs a new WebRTCSocket object.
|
||||||
|
/// @param parent Qt parent object.
|
||||||
|
/// @param nodeType The type of node that the WebRTCsocket object is being used in.
|
||||||
|
WebRTCSocket(QObject* parent, NodeType_t nodeType);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Nominally sets the value of a socket option.
|
||||||
|
/// @details Only <code>SendBufferSizeSocketOption</code> and <code>ReceiveBufferSizeSocketOption</code> options are handled
|
||||||
|
/// and for these no action is taken because these buffer sizes are not configurable in WebRTC.
|
||||||
|
/// Included for compatibility with the QUdpSocket interface.
|
||||||
|
/// @param option The socket option.
|
||||||
|
/// @param value The value of the socket option.
|
||||||
|
void setSocketOption(QAbstractSocket::SocketOption option, const QVariant& value);
|
||||||
|
|
||||||
|
/// @brief Nominally gets the value of a socket option.
|
||||||
|
/// @details Only <code>SendBufferSizeSocketOption</code> and <code>ReceiveBufferSizeSocketOption</code> options are handled
|
||||||
|
/// and for these only default values are returned because these buffer sizes are not configurable in WebRTC.
|
||||||
|
/// Included for compatibility with the QUdpSocket interface.
|
||||||
|
/// @param option The socket option.
|
||||||
|
/// @return The value of the socket option.
|
||||||
|
QVariant socketOption(QAbstractSocket::SocketOption option);
|
||||||
|
|
||||||
|
/// @brief Binds the WebRTC socket's signaling server to an address and port.
|
||||||
|
/// @details Note: WebRTC data connections aren't bound to an address or port. Their ports are negotiated as part of the
|
||||||
|
/// WebRTC peer connection process.
|
||||||
|
/// @param address The address to use for the signaling server.
|
||||||
|
/// @param port The port to use for the signaling server.
|
||||||
|
/// @param mode The bind mode. (Not used: included for compatibility with the QUdpSocket interface.)
|
||||||
|
/// @return <code>true</code> if the signaling server was successfully bound, <code>false</code> if it wasn't.
|
||||||
|
bool bind(const QHostAddress& address, quint16 port = 0, QAbstractSocket::BindMode mode
|
||||||
|
= QAbstractSocket::DefaultForPlatform);
|
||||||
|
|
||||||
|
/// @brief Gets the state of the socket.
|
||||||
|
/// @details In particular, QAbstractSocket::BoundState is returned if the socket is bound,
|
||||||
|
/// QAbstractSocket::UnconnectedState if it isn't.
|
||||||
|
/// @return The state of the socket.
|
||||||
|
QAbstractSocket::SocketState state() const;
|
||||||
|
|
||||||
|
/// @brief Immediately closes all connections and resets the socket.
|
||||||
|
void abort();
|
||||||
|
|
||||||
|
/// @brief Nominally gets the host port number.
|
||||||
|
/// @details
|
||||||
|
/// Included for compatibility with the QUdpSocket interface.
|
||||||
|
/// @return <code>0</code>
|
||||||
|
quint16 localPort() const { return 0; }
|
||||||
|
|
||||||
|
/// @brief Nominally gets the socket descriptor.
|
||||||
|
/// @details
|
||||||
|
/// Included for compatibility with the QUdpSocket interface.
|
||||||
|
/// @return <code>-1</code>
|
||||||
|
qintptr socketDescriptor() const { return -1; }
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Sends a datagram to the host on a data channel.
|
||||||
|
/// @param datagram The datagram to send.
|
||||||
|
/// @param port The data channel ID.
|
||||||
|
/// @return The number of bytes if successfully sent, otherwise <code>-1</code>.
|
||||||
|
qint64 writeDatagram(const QByteArray& datagram, quint16 port);
|
||||||
|
|
||||||
|
/// @brief Gets the number of bytes waiting to be written.
|
||||||
|
/// @param port The data channel ID.
|
||||||
|
/// @return The number of bytes waiting to be written.
|
||||||
|
qint64 bytesToWrite(quint16 port) const;
|
||||||
|
|
||||||
|
/// @brief Gets whether there's a datagram waiting to be read.
|
||||||
|
/// @return <code>true</code> if there's a datagram waiting to be read, <code>false</code> if there isn't.
|
||||||
|
bool hasPendingDatagrams() const;
|
||||||
|
|
||||||
|
/// @brief Gets the size of the first pending datagram.
|
||||||
|
/// @return the size of the first pending datagram; <code>-1</code> if there is no pending datagram.
|
||||||
|
qint64 pendingDatagramSize() const;
|
||||||
|
|
||||||
|
/// @brief Reads the next datagram, up to a maximum number of bytes.
|
||||||
|
/// @details Any remaining data in the datagram is lost.
|
||||||
|
/// @param data The destination to read the datagram into.
|
||||||
|
/// @param maxSize The maximum number of bytes to read.
|
||||||
|
/// @param address The destination to put the IP address that the datagram was read from. (Not currently set.)
|
||||||
|
/// @param port The destination to put the data channel ID that the datagram was read from.
|
||||||
|
/// @return The number of bytes read on success; <code>-1</code> if reading unsuccessful.
|
||||||
|
qint64 readDatagram(char* data, qint64 maxSize, QHostAddress* address = nullptr, quint16* port = nullptr);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Gets the type of error that last occurred.
|
||||||
|
/// @return The type of error that last occurred.
|
||||||
|
QAbstractSocket::SocketError error() const;
|
||||||
|
|
||||||
|
/// @brief Gets the description of the error that last occurred.
|
||||||
|
/// @return The description of the error that last occurred.
|
||||||
|
QString errorString() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
/// @brief Handles the WebRTC data channel receiving a message.
|
||||||
|
/// @details Queues the message to be read via readDatagram.
|
||||||
|
/// @param dataChannelID The data channel that the message was received on.
|
||||||
|
/// @param message The message that was received.
|
||||||
|
void onDataChannelReceivedMessage(int dataChannelID, const QByteArray& message);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
/// @brief Emitted when the state of the socket changes.
|
||||||
|
void stateChanged(QAbstractSocket::SocketState socketState);
|
||||||
|
|
||||||
|
/// @brief Emitted each time new data becomes available for reading.
|
||||||
|
void readyRead();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void setError(QAbstractSocket::SocketError errorType, QString errorString);
|
||||||
|
void clearError();
|
||||||
|
|
||||||
|
WebRTCSignalingServer _signalingServer;
|
||||||
|
WebRTCDataChannels _dataChannels;
|
||||||
|
|
||||||
|
bool _isBound { false };
|
||||||
|
|
||||||
|
QQueue<QPair<int, QByteArray>> _receivedQueue; // Messages received are queued for reading from the "socket".
|
||||||
|
|
||||||
|
QAbstractSocket::SocketError _lastErrorType { QAbstractSocket::UnknownSocketError };
|
||||||
|
QString _lastErrorString;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
#endif // WEBRTC_DATA_CHANNELS
|
||||||
|
|
||||||
|
#endif // vircadia_WebRTCSocket_h
|
|
@ -62,7 +62,7 @@ ICEClientApp::ICEClientApp(int argc, char* argv[]) :
|
||||||
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtWarningMsg, false);
|
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);
|
_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)) {
|
if (parser.isSet(iceServerAddressOption)) {
|
||||||
// parse the IP and port combination for this target
|
// parse the IP and port combination for this target
|
||||||
QString hostnamePortString = parser.value(iceServerAddressOption);
|
QString hostnamePortString = parser.value(iceServerAddressOption);
|
||||||
|
@ -96,7 +96,7 @@ ICEClientApp::ICEClientApp(int argc, char* argv[]) :
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
|
||||||
} else {
|
} else {
|
||||||
_iceServerAddr = HifiSockAddr(address, port);
|
_iceServerAddr = HifiSockAddr(SocketType::UDP, address, port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ void ICEClientApp::openSocket() {
|
||||||
|
|
||||||
_socket = new udt::Socket();
|
_socket = new udt::Socket();
|
||||||
unsigned int localPort = 0;
|
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->setPacketHandler([this](std::unique_ptr<udt::Packet> packet) { processPacket(std::move(packet)); });
|
||||||
_socket->addUnfilteredHandler(_stunSockAddr,
|
_socket->addUnfilteredHandler(_stunSockAddr,
|
||||||
[this](std::unique_ptr<udt::BasePacket> packet) {
|
[this](std::unique_ptr<udt::BasePacket> packet) {
|
||||||
|
@ -140,10 +140,10 @@ void ICEClientApp::openSocket() {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (_verbose) {
|
if (_verbose) {
|
||||||
qDebug() << "local port is" << _socket->localPort();
|
qDebug() << "local port is" << _socket->localPort(SocketType::UDP);
|
||||||
}
|
}
|
||||||
_localSockAddr = HifiSockAddr("127.0.0.1", _socket->localPort());
|
_localSockAddr = HifiSockAddr(SocketType::UDP, "127.0.0.1", _socket->localPort(SocketType::UDP));
|
||||||
_publicSockAddr = HifiSockAddr("127.0.0.1", _socket->localPort());
|
_publicSockAddr = HifiSockAddr(SocketType::UDP, "127.0.0.1", _socket->localPort(SocketType::UDP));
|
||||||
_domainPingCount = 0;
|
_domainPingCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ void ICEClientApp::doSomething() {
|
||||||
if (_verbose) {
|
if (_verbose) {
|
||||||
qDebug() << "using cached STUN response";
|
qDebug() << "using cached STUN response";
|
||||||
}
|
}
|
||||||
_publicSockAddr.setPort(_socket->localPort());
|
_publicSockAddr.setPort(_socket->localPort(SocketType::UDP));
|
||||||
setState(talkToIceServer);
|
setState(talkToIceServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ void ICEClientApp::processSTUNResponse(std::unique_ptr<udt::BasePacket> packet)
|
||||||
uint16_t newPublicPort;
|
uint16_t newPublicPort;
|
||||||
QHostAddress newPublicAddress;
|
QHostAddress newPublicAddress;
|
||||||
if (LimitedNodeList::parseSTUNResponse(packet.get(), newPublicAddress, newPublicPort)) {
|
if (LimitedNodeList::parseSTUNResponse(packet.get(), newPublicAddress, newPublicPort)) {
|
||||||
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
|
_publicSockAddr = HifiSockAddr(SocketType::UDP, newPublicAddress, newPublicPort);
|
||||||
if (_verbose) {
|
if (_verbose) {
|
||||||
qDebug() << "My public address is" << _publicSockAddr;
|
qDebug() << "My public address is" << _publicSockAddr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit ab6c8b1a54aec359b1894f70722f69cfec7f04f1
|
Subproject commit 0afaa769d46683d461c9288aa31468f64cba0233
|
Loading…
Reference in a new issue