Skip to content

Commit

Permalink
Allow to set multiple STUN servers
Browse files Browse the repository at this point in the history
This way we can for example add a server for IPv4 and one IPv6.
  • Loading branch information
olesalscheider authored and lnjX committed Mar 16, 2020
1 parent 133c94d commit bb47e1b
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 26 deletions.
55 changes: 38 additions & 17 deletions src/base/QXmppStun.cpp
Expand Up @@ -1703,19 +1703,25 @@ class QXmppIcePrivate
QString localPassword;
QString remoteUser;
QString remotePassword;
QHostAddress stunHost;
quint16 stunPort;
QList<QPair<QHostAddress, quint16>> stunServers;
QByteArray tieBreaker;
};

QXmppIcePrivate::QXmppIcePrivate()
: iceControlling(false), stunPort(0)
: iceControlling(false)
{
localUser = QXmppUtils::generateStanzaHash(4);
localPassword = QXmppUtils::generateStanzaHash(22);
tieBreaker = QXmppUtils::generateRandomBytes(8);
}

struct QXmppIceTransportDetails
{
QXmppIceTransport *transport;
QHostAddress stunHost;
quint16 stunPort;
};

class QXmppIceComponentPrivate
{
public:
Expand Down Expand Up @@ -1746,7 +1752,7 @@ class QXmppIceComponentPrivate
QTimer *timer;

// STUN server
QMap<QXmppStunTransaction *, QXmppIceTransport *> stunTransactions;
QMap<QXmppStunTransaction *, QXmppIceTransportDetails> stunTransactions;

// TURN server
QXmppTurnAllocation *turnAllocation;
Expand Down Expand Up @@ -1850,19 +1856,19 @@ void QXmppIceComponentPrivate::setSockets(QList<QUdpSocket *> sockets)
}

// start STUN checks
if (!config->stunHost.isNull() && config->stunPort) {
stunTransactions.clear();

stunTransactions.clear();
for (auto &stunServer : config->stunServers) {
QXmppStunMessage request;
request.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request);
for (auto *transport : transports) {
const QXmppJingleCandidate local = transport->localCandidate(component);
if (!isCompatibleAddress(local.host(), config->stunHost))
if (!isCompatibleAddress(local.host(), stunServer.first)) {
continue;
}

request.setId(QXmppUtils::generateRandomBytes(STUN_ID_SIZE));
auto *transaction = new QXmppStunTransaction(request, q);
stunTransactions.insert(transaction, transport);
stunTransactions.insert(transaction, {transport, stunServer.first, stunServer.second});
}
}

Expand Down Expand Up @@ -2027,7 +2033,7 @@ void QXmppIceComponent::handleDatagram(const QByteArray &buffer, const QHostAddr
QXmppStunTransaction *stunTransaction = nullptr;
for (auto *t : d->stunTransactions.keys()) {
if (t->request().id() == messageId &&
d->stunTransactions.value(t) == transport) {
d->stunTransactions.value(t).transport == transport) {
stunTransaction = t;
break;
}
Expand Down Expand Up @@ -2208,7 +2214,7 @@ void QXmppIceComponent::transactionFinished()
}

// STUN checks
QXmppIceTransport *transport = d->stunTransactions.value(transaction);
QXmppIceTransport *transport = d->stunTransactions.value(transaction).transport;
if (transport) {
const QXmppStunMessage response = transaction->response();
if (response.messageClass() == QXmppStunMessage::Response) {
Expand Down Expand Up @@ -2411,11 +2417,12 @@ void QXmppIceComponent::writeStun(const QXmppStunMessage &message)
}

// STUN checks
QXmppIceTransport *transport = d->stunTransactions.value(transaction);
QXmppIceTransportDetails transportDetails = d->stunTransactions.value(transaction);
QXmppIceTransport *transport = transportDetails.transport;
if (transport) {
transport->writeDatagram(message.encode(), d->config->stunHost, d->config->stunPort);
transport->writeDatagram(message.encode(), transportDetails.stunHost, transportDetails.stunPort);
#ifdef QXMPP_DEBUG_STUN
logSent(QString("STUN packet to %1 port %2\n%3").arg(d->config->stunHost.toString(), QString::number(d->config->stunPort), message.toString()));
logSent(QString("STUN packet to %1 port %2\n%3").arg(transportDetails.stunHost.toString(), QString::number(transportDetails.stunPort), message.toString()));
#endif
return;
}
Expand Down Expand Up @@ -2628,7 +2635,21 @@ void QXmppIceConnection::setRemotePassword(const QString &password)
d->remotePassword = password;
}

/// Sets the STUN server to use to determine server-reflexive addresses
/// Sets multiple STUN servers to use to determine server-reflexive addresses
/// and ports.
///
/// \note This may only be called prior to calling bind().
///
/// \param servers List of the STUN servers.
///
/// \since QXmpp 1.3

void QXmppIceConnection::setStunServers(const QList<QPair<QHostAddress, quint16>> &servers)
{
d->stunServers = servers;
}

/// Sets a single STUN server to use to determine server-reflexive addresses
/// and ports.
///
/// \note This may only be called prior to calling bind().
Expand All @@ -2638,8 +2659,8 @@ void QXmppIceConnection::setRemotePassword(const QString &password)

void QXmppIceConnection::setStunServer(const QHostAddress &host, quint16 port)
{
d->stunHost = host;
d->stunPort = port;
d->stunServers.clear();
d->stunServers.push_back(QPair<QHostAddress, quint16>(host, port));
}

/// Sets the TURN server to use to relay packets in double-NAT configurations.
Expand Down
1 change: 1 addition & 0 deletions src/base/QXmppStun.h
Expand Up @@ -267,6 +267,7 @@ class QXMPP_EXPORT QXmppIceConnection : public QXmppLoggable
void setRemoteUser(const QString &user);
void setRemotePassword(const QString &password);

void setStunServers(const QList<QPair<QHostAddress, quint16>> &servers);
void setStunServer(const QHostAddress &host, quint16 port = 3478);
void setTurnServer(const QHostAddress &host, quint16 port = 3478);
void setTurnUser(const QString &user);
Expand Down
2 changes: 1 addition & 1 deletion src/client/QXmppCall.cpp
Expand Up @@ -450,7 +450,7 @@ QXmppCallStream *QXmppCallPrivate::createStream(const QString &media, const QStr

// ICE connection
stream->d->connection->setIceControlling(direction == QXmppCall::OutgoingDirection);
stream->d->connection->setStunServer(manager->d->stunHost, manager->d->stunPort);
stream->d->connection->setStunServers(manager->d->stunServers);
stream->d->connection->setTurnServer(manager->d->turnHost, manager->d->turnPort);
stream->d->connection->setTurnUser(manager->d->turnUser);
stream->d->connection->setTurnPassword(manager->d->turnPassword);
Expand Down
25 changes: 20 additions & 5 deletions src/client/QXmppCallManager.cpp
Expand Up @@ -38,8 +38,7 @@
#include <QTimer>

QXmppCallManagerPrivate::QXmppCallManagerPrivate(QXmppCallManager *qq)
: stunPort(0),
turnPort(0),
: turnPort(0),
q(qq)
{
// Initialize GStreamer
Expand Down Expand Up @@ -153,16 +152,32 @@ QXmppCall *QXmppCallManager::call(const QString &jid)
return call;
}

/// Sets the STUN server to use to determine server-reflexive addresses
/// Sets multiple STUN servers to use to determine server-reflexive addresses
/// and ports.
///
/// \note This may only be called prior to calling bind().
///
/// \param servers List of the STUN servers.
///
/// \since QXmpp 1.3

void QXmppCallManager::setStunServers(const QList<QPair<QHostAddress, quint16>> &servers)
{
d->stunServers = servers;
}

/// Sets a single STUN server to use to determine server-reflexive addresses
/// and ports.
///
/// \note This may only be called prior to calling bind().
///
/// \param host The address of the STUN server.
/// \param port The port of the STUN server.

void QXmppCallManager::setStunServer(const QHostAddress &host, quint16 port)
{
d->stunHost = host;
d->stunPort = port;
d->stunServers.clear();
d->stunServers.push_back(QPair<QHostAddress, quint16>(host, port));
}

/// Sets the TURN server to use to relay packets in double-NAT configurations.
Expand Down
1 change: 1 addition & 0 deletions src/client/QXmppCallManager.h
Expand Up @@ -68,6 +68,7 @@ class QXMPP_EXPORT QXmppCallManager : public QXmppClientExtension
public:
QXmppCallManager();
~QXmppCallManager() override;
void setStunServers(const QList<QPair<QHostAddress, quint16>> &servers);
void setStunServer(const QHostAddress &host, quint16 port = 3478);
void setTurnServer(const QHostAddress &host, quint16 port = 3478);
void setTurnUser(const QString &user);
Expand Down
3 changes: 1 addition & 2 deletions src/client/QXmppCallManager_p.h
Expand Up @@ -49,8 +49,7 @@ class QXmppCallManagerPrivate
QXmppCall *findCall(const QString &sid, QXmppCall::Direction direction) const;

QList<QXmppCall *> calls;
QHostAddress stunHost;
quint16 stunPort;
QList<QPair<QHostAddress, quint16>> stunServers;
QHostAddress turnHost;
quint16 turnPort;
QString turnUser;
Expand Down
6 changes: 5 additions & 1 deletion tests/qxmppiceconnection/tst_qxmppiceconnection.cpp
Expand Up @@ -78,7 +78,11 @@ void tst_QXmppIceConnection::testBindStun()
connect(&client, &QXmppLoggable::logMessage,
&logger, &QXmppLogger::log);
client.setIceControlling(true);
client.setStunServer(stunInfo.addresses().first(), 19302);
QList<QPair<QHostAddress, quint16>> stunServers;
for (auto &address : stunInfo.addresses()) {
stunServers.push_back({address, 19302});
}
client.setStunServers(stunServers);
client.addComponent(componentId);

QXmppIceComponent *component = client.component(componentId);
Expand Down

0 comments on commit bb47e1b

Please sign in to comment.