Skip to content

Commit

Permalink
Add QXmppIceConnection::gatheringState property
Browse files Browse the repository at this point in the history
  • Loading branch information
jlaine committed Sep 3, 2015
1 parent eea8f85 commit 1d82820
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
QXmpp 0.9.3 (UNRELEASED)

- Add QXmppIceConnection::gatheringState property.

QXmpp 0.9.2 (Sep 2, 2015)
-------------------------

Expand Down
77 changes: 76 additions & 1 deletion src/base/QXmppStun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ static const quint16 STUN_HEADER = 20;
static const quint8 STUN_IPV4 = 0x01;
static const quint8 STUN_IPV6 = 0x02;

static const char* gathering_states[] = {
"new",
"gathering",
"complete"
};

static const char* pair_states[] = {
"frozen",
"waiting",
Expand Down Expand Up @@ -1761,6 +1767,8 @@ class QXmppIceComponentPrivate
const QXmppIcePrivate* const config;
CandidatePair *fallbackPair;

QXmppIceConnection::GatheringState gatheringState;

QList<QXmppJingleCandidate> localCandidates;

quint32 peerReflexivePriority;
Expand All @@ -1786,6 +1794,7 @@ QXmppIceComponentPrivate::QXmppIceComponentPrivate(int component_, QXmppIcePriva
, component(component_)
, config(config_)
, fallbackPair(0)
, gatheringState(QXmppIceConnection::NewGatheringState)
, peerReflexivePriority(0)
, timer(0)
, turnAllocation(0)
Expand Down Expand Up @@ -1909,6 +1918,8 @@ void QXmppIceComponentPrivate::setSockets(QList<QUdpSocket*> sockets)
transports << turnAllocation;
turnAllocation->connectToHost();
}

q->updateGatheringState();
}

void QXmppIceComponentPrivate::setTurnServer(const QHostAddress &host, quint16 port)
Expand Down Expand Up @@ -1965,6 +1976,9 @@ QXmppIceComponent::QXmppIceComponent(int component, QXmppIcePrivate *config, QOb
check = connect(d->turnAllocation, SIGNAL(datagramReceived(QByteArray,QHostAddress,quint16)),
this, SLOT(handleDatagram(QByteArray,QHostAddress,quint16)));
Q_ASSERT(check);
check = connect(d->turnAllocation, SIGNAL(disconnected()),
this, SLOT(updateGatheringState()));
Q_ASSERT(check);

// calculate peer-reflexive candidate priority
// see RFC 5245 - 7.1.2.1. PRIORITY and USE-CANDIDATE
Expand Down Expand Up @@ -2313,6 +2327,7 @@ void QXmppIceComponent::transactionFinished()
transaction->response().errorPhrase));
}
d->stunTransactions.remove(transaction);
updateGatheringState();
return;
}
}
Expand All @@ -2328,6 +2343,7 @@ void QXmppIceComponent::turnConnected()
d->localCandidates << candidate;

emit localCandidatesChanged();
updateGatheringState();
}

static QList<QUdpSocket*> reservePort(const QList<QHostAddress> &addresses, quint16 port, QObject *parent)
Expand Down Expand Up @@ -2443,6 +2459,23 @@ qint64 QXmppIceComponent::sendDatagram(const QByteArray &datagram)
return pair->transport->writeDatagram(datagram, pair->remote.host(), pair->remote.port());
}

void QXmppIceComponent::updateGatheringState()
{
QXmppIceConnection::GatheringState newGatheringState;
if (d->transports.isEmpty())
newGatheringState = QXmppIceConnection::NewGatheringState;
else if (!d->stunTransactions.isEmpty()
|| d->turnAllocation->state() == QXmppTurnAllocation::ConnectingState)
newGatheringState = QXmppIceConnection::BusyGatheringState;
else
newGatheringState = QXmppIceConnection::CompleteGatheringState;

if (newGatheringState != d->gatheringState) {
d->gatheringState = newGatheringState;
emit gatheringStateChanged();
}
}

void QXmppIceComponent::writeStun(const QXmppStunMessage &message)
{
QXmppStunTransaction *transaction = qobject_cast<QXmppStunTransaction*>(sender());
Expand Down Expand Up @@ -2476,14 +2509,17 @@ class QXmppIceConnectionPrivate : public QXmppIcePrivate
QMap<int, QXmppIceComponent*> components;
QTimer *connectTimer;

QXmppIceConnection::GatheringState gatheringState;

QHostAddress turnHost;
quint16 turnPort;
QString turnUser;
QString turnPassword;
};

QXmppIceConnectionPrivate::QXmppIceConnectionPrivate()
: turnPort(0)
: gatheringState(QXmppIceConnection::NewGatheringState)
, turnPort(0)
{
}

Expand Down Expand Up @@ -2549,6 +2585,10 @@ void QXmppIceConnection::addComponent(int component)
this, SLOT(slotConnected()));
Q_ASSERT(check);

check = connect(socket, SIGNAL(gatheringStateChanged()),
this, SLOT(slotGatheringStateChanged()));
Q_ASSERT(check);

d->components[component] = socket;
}

Expand Down Expand Up @@ -2622,6 +2662,14 @@ bool QXmppIceConnection::isConnected() const
return true;
}

/// Returns the ICE gathering state, that is the discovery of
/// local candidates.

QXmppIceConnection::GatheringState QXmppIceConnection::gatheringState() const
{
return d->gatheringState;
}

/// Sets whether the local party has the ICE controlling role.
///
/// \a note This must be called only once, immediately after creating
Expand Down Expand Up @@ -2740,6 +2788,33 @@ void QXmppIceConnection::slotConnected()
emit connected();
}

void QXmppIceConnection::slotGatheringStateChanged()
{
GatheringState newGatheringState;
bool allComplete = true;
bool allNew = true;
foreach (QXmppIceComponent *socket, d->components.values()) {
if (socket->d->gatheringState != CompleteGatheringState)
allComplete = false;
if (socket->d->gatheringState != NewGatheringState)
allNew = false;
}
if (allNew)
newGatheringState = NewGatheringState;
else if (allComplete)
newGatheringState = CompleteGatheringState;
else
newGatheringState = BusyGatheringState;

if (newGatheringState != d->gatheringState) {
info(QString("ICE gathering state changed from '%1' to '%2'").arg(
gathering_states[d->gatheringState],
gathering_states[newGatheringState]));
d->gatheringState = newGatheringState;
emit gatheringStateChanged();
}
}

void QXmppIceConnection::slotTimeout()
{
warning(QString("ICE negotiation timed out"));
Expand Down
19 changes: 19 additions & 0 deletions src/base/QXmppStun.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ private slots:
void handleDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port);
void turnConnected();
void transactionFinished();
void updateGatheringState();
void writeStun(const QXmppStunMessage &request);

signals:
Expand All @@ -195,6 +196,9 @@ private slots:
/// \brief This signal is emitted when a data packet is received.
void datagramReceived(const QByteArray &datagram);

/// \internal This signal is emitted when the gathering state of local candidates changes.
void gatheringStateChanged();

/// \brief This signal is emitted when the list of local candidates changes.
void localCandidatesChanged();

Expand Down Expand Up @@ -237,8 +241,17 @@ private slots:
class QXMPP_EXPORT QXmppIceConnection : public QXmppLoggable
{
Q_OBJECT
Q_ENUMS(GatheringState)
Q_PROPERTY(QXmppIceConnection::GatheringState gatheringState READ gatheringState NOTIFY gatheringStateChanged)

public:
enum GatheringState
{
NewGatheringState,
BusyGatheringState,
CompleteGatheringState
};

QXmppIceConnection(QObject *parent = 0);
~QXmppIceConnection();

Expand All @@ -262,13 +275,18 @@ class QXMPP_EXPORT QXmppIceConnection : public QXmppLoggable
bool bind(const QList<QHostAddress> &addresses);
bool isConnected() const;

GatheringState gatheringState() const;

signals:
/// \brief This signal is emitted once ICE negotiation succeeds.
void connected();

/// \brief This signal is emitted when ICE negotiation fails.
void disconnected();

/// \brief This signal is emitted when the gathering state of local candidates changes.
void gatheringStateChanged();

/// \brief This signal is emitted when the list of local candidates changes.
void localCandidatesChanged();

Expand All @@ -278,6 +296,7 @@ public slots:

private slots:
void slotConnected();
void slotGatheringStateChanged();
void slotTimeout();

private:
Expand Down
10 changes: 8 additions & 2 deletions tests/qxmppiceconnection/tst_qxmppiceconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ void tst_QXmppIceConnection::testBind()
QXmppIceComponent *component = client.component(componentId);
QVERIFY(component);

QCOMPARE(client.gatheringState(), QXmppIceConnection::NewGatheringState);
client.bind(QXmppIceComponent::discoverAddresses());
QCOMPARE(client.gatheringState(), QXmppIceConnection::CompleteGatheringState);
QCOMPARE(client.localCandidates().size(), component->localCandidates().size());
QVERIFY(!client.localCandidates().isEmpty());
foreach (const QXmppJingleCandidate &c, client.localCandidates()) {
Expand Down Expand Up @@ -80,13 +82,17 @@ void tst_QXmppIceConnection::testBindStun()
QXmppIceComponent *component = client.component(componentId);
QVERIFY(component);

QCOMPARE(client.gatheringState(), QXmppIceConnection::NewGatheringState);
client.bind(QXmppIceComponent::discoverAddresses());
QCOMPARE(client.gatheringState(), QXmppIceConnection::BusyGatheringState);

QEventLoop loop;
connect(&client, SIGNAL(localCandidatesChanged()),
connect(&client, SIGNAL(gatheringStateChanged()),
&loop, SLOT(quit()));
client.bind(QXmppIceComponent::discoverAddresses());
loop.exec();

bool foundReflexive = false;
QCOMPARE(client.gatheringState(), QXmppIceConnection::CompleteGatheringState);
QCOMPARE(client.localCandidates().size(), component->localCandidates().size());
QVERIFY(!client.localCandidates().isEmpty());
foreach (const QXmppJingleCandidate &c, client.localCandidates()) {
Expand Down

0 comments on commit 1d82820

Please sign in to comment.