From 40c39853816cfab113d79682c34bc76a2c79c357 Mon Sep 17 00:00:00 2001 From: Jeremy Lainé Date: Wed, 11 Aug 2010 07:31:23 +0000 Subject: rename "source" directory to "src" --- source/QXmppStun.cpp | 979 --------------------------------------------------- 1 file changed, 979 deletions(-) delete mode 100644 source/QXmppStun.cpp (limited to 'source/QXmppStun.cpp') diff --git a/source/QXmppStun.cpp b/source/QXmppStun.cpp deleted file mode 100644 index 5bd3fd54..00000000 --- a/source/QXmppStun.cpp +++ /dev/null @@ -1,979 +0,0 @@ -/* - * Copyright (C) 2008-2010 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - */ - -#define QXMPP_DEBUG_STUN - -#include -#include -#include -#include -#include - -#include "QXmppStun.h" -#include "QXmppUtils.h" - -#define ID_SIZE 12 - -static const quint32 STUN_MAGIC = 0x2112A442; -static const quint16 STUN_HEADER = 20; -static const quint8 STUN_IPV4 = 0x01; -static const quint8 STUN_IPV6 = 0x02; - -enum MessageType { - BindingRequest = 0x0001, - BindingIndication = 0x0011, - BindingResponse = 0x0101, - BindingError = 0x0111, - SharedSecretRequest = 0x0002, - SharedSecretResponse = 0x0102, - SharedSecretError = 0x0112, -}; - -enum AttributeType { - MappedAddress = 0x0001, - Username = 0x0006, - MessageIntegrity = 0x0008, - ErrorCode = 0x0009, - XorMappedAddress = 0x0020, - Priority = 0x0024, - UseCandidate = 0x0025, - Software = 0x8022, - Fingerprint = 0x8028, - IceControlled = 0x8029, - IceControlling = 0x802a, - OtherAddress = 0x802c, -}; - -static bool decodeAddress(QDataStream &stream, quint16 a_length, QHostAddress &address, quint16 &port) -{ - if (a_length < 4) - return false; - quint8 reserved, protocol; - stream >> reserved; - stream >> protocol; - stream >> port; - if (protocol == STUN_IPV4) - { - if (a_length != 8) - return false; - quint32 addr; - stream >> addr; - address = QHostAddress(addr); - } else if (protocol == STUN_IPV6) { - if (a_length != 20) - return false; - Q_IPV6ADDR addr; - stream.readRawData((char*)&addr, sizeof(addr)); - address = QHostAddress(addr); - } else { - return false; - } - return true; -} - -static void encodeAddress(QDataStream &stream, const QHostAddress &address, quint16 port) -{ - stream << quint16(8); - stream << quint8(0); - if (address.protocol() == QAbstractSocket::IPv4Protocol) - { - stream << quint8(STUN_IPV4); - stream << port; - stream << address.toIPv4Address(); - } else if (address.protocol() == QAbstractSocket::IPv6Protocol) { - stream << quint8(STUN_IPV6); - stream << port; - Q_IPV6ADDR addr = address.toIPv6Address(); - stream.writeRawData((char*)&addr, sizeof(addr)); - } -} - -static void encodeString(QDataStream &stream, const QString &string) -{ - const QByteArray utf8string = string.toUtf8(); - stream << quint16(utf8string.size()); - stream.writeRawData(utf8string.data(), utf8string.size()); - if (utf8string.size() % 4) - { - const QByteArray padding(4 - (utf8string.size() % 4), 0); - stream.writeRawData(padding.data(), padding.size()); - } -} - -static QByteArray randomByteArray(int length) -{ - QByteArray result(length, 0); - for (int i = 0; i < length; ++i) - result[i] = quint8(qrand() % 255); - return result; -} - -/// Constructs a new QXmppStunMessage. - -QXmppStunMessage::QXmppStunMessage() - : errorCode(0), - priority(0), - mappedPort(0), - otherPort(0), - xorMappedPort(0), - useCandidate(false) -{ - m_id = QByteArray(ID_SIZE, 0); -} - -QByteArray QXmppStunMessage::id() const -{ - return m_id; -} - -void QXmppStunMessage::setId(const QByteArray &id) -{ - Q_ASSERT(id.size() == ID_SIZE); - m_id = id; -} - -quint16 QXmppStunMessage::type() const -{ - return m_type; -} - -void QXmppStunMessage::setType(quint16 type) -{ - m_type = type; -} - -/// Decodes a QXmppStunMessage and checks its integrity using the given -/// password. -/// -/// \param buffer -/// \param password - -bool QXmppStunMessage::decode(const QByteArray &buffer, const QString &password, QStringList *errors) -{ - QStringList silent; - if (!errors) - errors = &silent; - - if (buffer.size() < STUN_HEADER) - { - *errors << QLatin1String("Received a truncated STUN packet"); - return false; - } - - // parse STUN header - QDataStream stream(buffer); - quint16 length; - quint32 cookie; - stream >> m_type; - stream >> length; - stream >> cookie; - stream.readRawData(m_id.data(), m_id.size()); - - if (cookie != STUN_MAGIC || length != buffer.size() - STUN_HEADER) - { - *errors << QLatin1String("Received an invalid STUN packet"); - return false; - } - - // parse STUN attributes - int done = 0; - bool after_integrity = false; - while (done < length) - { - quint16 a_type, a_length; - stream >> a_type; - stream >> a_length; - const int pad_length = 4 * ((a_length + 3) / 4) - a_length; - - // only FINGERPRINT is allowed after MESSAGE-INTEGRITY - if (after_integrity && a_type != Fingerprint) - { - *errors << QString("Skipping attribute %1 after MESSAGE-INTEGRITY").arg(QString::number(a_type)); - stream.skipRawData(a_length + pad_length); - done += 4 + a_length + pad_length; - continue; - } - - if (a_type == Priority) - { - // PRIORITY - if (a_length != sizeof(priority)) - return false; - stream >> priority; - - } else if (a_type == ErrorCode) { - - // ERROR-CODE - if (a_length < 4) - return false; - quint16 reserved; - quint8 errorCodeHigh, errorCodeLow; - stream >> reserved; - stream >> errorCodeHigh; - stream >> errorCodeLow; - errorCode = errorCodeHigh * 100 + errorCodeLow; - QByteArray phrase(a_length - 4, 0); - stream.readRawData(phrase.data(), phrase.size()); - errorPhrase = QString::fromUtf8(phrase); - - } else if (a_type == UseCandidate) { - - // USE-CANDIDATE - if (a_length != 0) - return false; - useCandidate = true; - - } else if (a_type == Software) { - - // SOFTWARE - QByteArray utf8Software(a_length, 0); - stream.readRawData(utf8Software.data(), utf8Software.size()); - software = QString::fromUtf8(utf8Software); - - } else if (a_type == MappedAddress) { - - // MAPPED-ADDRESS - if (!decodeAddress(stream, a_length, mappedHost, mappedPort)) - { - *errors << QLatin1String("Bad MAPPED-ADDRESS"); - return false; - } - - } else if (a_type == OtherAddress) { - - // OTHER-ADDRESS - if (!decodeAddress(stream, a_length, otherHost, otherPort)) - { - *errors << QLatin1String("Bad OTHER-ADDRESS"); - return false; - } - - } else if (a_type == XorMappedAddress) { - - // XOR-MAPPED-ADDRESS - if (a_length < 4) - return false; - quint8 reserved, protocol; - quint16 xport; - stream >> reserved; - stream >> protocol; - stream >> xport; - xorMappedPort = xport ^ (STUN_MAGIC >> 16); - if (protocol == STUN_IPV4) - { - if (a_length != 8) - return false; - quint32 xaddr; - stream >> xaddr; - xorMappedHost = QHostAddress(xaddr ^ STUN_MAGIC); - } else if (protocol == STUN_IPV6) { - if (a_length != 20) - return false; - QByteArray xaddr(16, 0); - stream.readRawData(xaddr.data(), xaddr.size()); - QByteArray xpad; - QDataStream(&xpad, QIODevice::WriteOnly) << STUN_MAGIC; - xpad += m_id; - Q_IPV6ADDR addr; - for (int i = 0; i < 16; i++) - addr[i] = xaddr[i] ^ xpad[i]; - xorMappedHost = QHostAddress(addr); - } else { - *errors << QString("Bad protocol %1").arg(QString::number(protocol)); - return false; - } - - } else if (a_type == MessageIntegrity) { - - // MESSAGE-INTEGRITY - if (a_length != 20) - return false; - QByteArray integrity(20, 0); - stream.readRawData(integrity.data(), integrity.size()); - - // check HMAC-SHA1 - if (!password.isEmpty()) - { - const QByteArray key = password.toUtf8(); - QByteArray copy = buffer.left(STUN_HEADER + done); - setBodyLength(copy, done + 24); - if (integrity != generateHmacSha1(key, copy)) - { - *errors << QLatin1String("Bad message integrity"); - return false; - } - } - - // from here onwards, only FINGERPRINT is allowed - after_integrity = true; - - } else if (a_type == Fingerprint) { - - // FINGERPRINT - if (a_length != 4) - return false; - quint32 fingerprint; - stream >> fingerprint; - - // check CRC32 - QByteArray copy = buffer.left(STUN_HEADER + done); - setBodyLength(copy, done + 8); - const quint32 expected = generateCrc32(copy) ^ 0x5354554eL; - if (fingerprint != expected) - { - *errors << QLatin1String("Bad fingerprint"); - return false; - } - - // stop parsing, no more attributes are allowed - return true; - - } else if (a_type == IceControlling) { - - /// ICE-CONTROLLING - if (a_length != 8) - return false; - iceControlling.resize(8); - stream.readRawData(iceControlling.data(), iceControlling.size()); - - } else if (a_type == IceControlled) { - - /// ICE-CONTROLLED - if (a_length != 8) - return false; - iceControlled.resize(8); - stream.readRawData(iceControlled.data(), iceControlled.size()); - - } else if (a_type == Username) { - - // USERNAME - QByteArray utf8Username(a_length, 0); - stream.readRawData(utf8Username.data(), utf8Username.size()); - username = QString::fromUtf8(utf8Username); - - } else { - - // Unknown attribute - stream.skipRawData(a_length); - *errors << QString("Skipping unknown attribute %1").arg(QString::number(a_type)); - - } - stream.skipRawData(pad_length); - done += 4 + a_length + pad_length; - } - return true; -} - -/// Encodes the current QXmppStunMessage, optionally calculating the -/// message integrity attribute using the given password. -/// -/// \param password - -QByteArray QXmppStunMessage::encode(const QString &password) const -{ - QByteArray buffer; - QDataStream stream(&buffer, QIODevice::WriteOnly); - - // encode STUN header - quint16 length = 0; - stream << m_type; - stream << length; - stream << STUN_MAGIC; - stream.writeRawData(m_id.data(), m_id.size()); - - // MAPPED-ADDRESS - if (mappedPort && !mappedHost.isNull() && - (mappedHost.protocol() == QAbstractSocket::IPv4Protocol || - mappedHost.protocol() == QAbstractSocket::IPv6Protocol)) - { - stream << quint16(MappedAddress); - encodeAddress(stream, mappedHost, mappedPort); - } - - // OTHER-ADDRESS - if (otherPort && !otherHost.isNull() && - (otherHost.protocol() == QAbstractSocket::IPv4Protocol || - otherHost.protocol() == QAbstractSocket::IPv6Protocol)) - { - stream << quint16(OtherAddress); - encodeAddress(stream, otherHost, otherPort); - } - - // XOR-MAPPED-ADDRESS - if (xorMappedPort && !xorMappedHost.isNull() && - (xorMappedHost.protocol() == QAbstractSocket::IPv4Protocol || - xorMappedHost.protocol() == QAbstractSocket::IPv6Protocol)) - { - stream << quint16(XorMappedAddress); - stream << quint16(8); - stream << quint8(0); - if (xorMappedHost.protocol() == QAbstractSocket::IPv4Protocol) - { - stream << quint8(STUN_IPV4); - stream << quint16(xorMappedPort ^ (STUN_MAGIC >> 16)); - stream << quint32(xorMappedHost.toIPv4Address() ^ STUN_MAGIC); - } else { - stream << quint8(STUN_IPV6); - stream << quint16(xorMappedPort ^ (STUN_MAGIC >> 16)); - Q_IPV6ADDR addr = xorMappedHost.toIPv6Address(); - QByteArray xaddr; - QDataStream(&xaddr, QIODevice::WriteOnly) << STUN_MAGIC; - xaddr += m_id; - for (int i = 0; i < 16; i++) - xaddr[i] = xaddr[i] ^ addr[i]; - stream.writeRawData(xaddr.data(), xaddr.size()); - } - } - - // ERROR-CODE - if (errorCode) - { - const quint16 reserved = 0; - const quint8 errorCodeHigh = errorCode / 100; - const quint8 errorCodeLow = errorCode % 100; - const QByteArray phrase = errorPhrase.toUtf8(); - stream << quint16(ErrorCode); - stream << quint16(phrase.size() + 4); - stream << reserved; - stream << errorCodeHigh; - stream << errorCodeLow; - stream.writeRawData(phrase.data(), phrase.size()); - if (phrase.size() % 4) - { - const QByteArray padding(4 - (phrase.size() % 4), 0); - stream.writeRawData(padding.data(), padding.size()); - } - } - - // PRIORITY - if (priority) - { - stream << quint16(Priority); - stream << quint16(sizeof(priority)); - stream << priority; - } - - // USE-CANDIDATE - if (useCandidate) - { - stream << quint16(UseCandidate); - stream << quint16(0); - } - - // SOFTWARE - if (!software.isEmpty()) - { - stream << quint16(Software); - encodeString(stream, software); - } - - // ICE-CONTROLLING or ICE-CONTROLLED - if (!iceControlling.isEmpty()) - { - stream << quint16(IceControlling); - stream << quint16(iceControlling.size()); - stream.writeRawData(iceControlling.data(), iceControlling.size()); - } else if (!iceControlled.isEmpty()) { - stream << quint16(IceControlled); - stream << quint16(iceControlled.size()); - stream.writeRawData(iceControlled.data(), iceControlled.size()); - } - - // USERNAME - if (!username.isEmpty()) - { - stream << quint16(Username); - encodeString(stream, username); - } - - // set body length - setBodyLength(buffer, buffer.size() - STUN_HEADER); - - // MESSAGE-INTEGRITY - if (!password.isEmpty()) - { - const QByteArray key = password.toUtf8(); - setBodyLength(buffer, buffer.size() - STUN_HEADER + 24); - QByteArray integrity = generateHmacSha1(key, buffer); - stream << quint16(MessageIntegrity); - stream << quint16(integrity.size()); - stream.writeRawData(integrity.data(), integrity.size()); - } - - // FINGERPRINT - setBodyLength(buffer, buffer.size() - STUN_HEADER + 8); - quint32 fingerprint = generateCrc32(buffer) ^ 0x5354554eL; - stream << quint16(Fingerprint); - stream << quint16(sizeof(fingerprint)); - stream << fingerprint; - - return buffer; -} - -/// If the given packet looks like a STUN message, returns the message -/// type, otherwise returns 0. -/// -/// \param buffer - -quint16 QXmppStunMessage::peekType(const QByteArray &buffer) -{ - if (buffer.size() < STUN_HEADER) - return 0; - - // parse STUN header - QDataStream stream(buffer); - quint16 type; - quint16 length; - quint32 cookie; - stream >> type; - stream >> length; - stream >> cookie; - - if (cookie != STUN_MAGIC || length != buffer.size() - STUN_HEADER) - return 0; - - return type; -} - -void QXmppStunMessage::setBodyLength(QByteArray &buffer, qint16 length) const -{ - QDataStream stream(&buffer, QIODevice::WriteOnly); - stream.device()->seek(2); - stream << length; -} - -QString QXmppStunMessage::toString() const -{ - QStringList dumpLines; - QString typeName; - switch (m_type & 0x000f) - { - case 1: typeName = "Binding"; break; - case 2: typeName = "Shared Secret"; break; - default: typeName = "Unknown"; break; - } - switch (m_type & 0x0ff0) - { - case 0x000: typeName += " Request"; break; - case 0x010: typeName += " Indication"; break; - case 0x100: typeName += " Response"; break; - case 0x110: typeName += " Error"; break; - default: break; - } - dumpLines << QString(" type %1 (%2)") - .arg(typeName) - .arg(QString::number(m_type)); - dumpLines << QString(" id %1").arg(QString::fromAscii(m_id.toHex())); - - // attributes - if (!username.isEmpty()) - dumpLines << QString(" * USERNAME %1").arg(username); - if (errorCode) - dumpLines << QString(" * ERROR-CODE %1 %2") - .arg(QString::number(errorCode)) - .arg(errorPhrase); - if (!software.isEmpty()) - dumpLines << QString(" * SOFTWARE %1").arg(software); - if (mappedPort) - dumpLines << QString(" * MAPPED-ADDRESS %1 %2") - .arg(mappedHost.toString()) - .arg(QString::number(mappedPort)); - if (otherPort) - dumpLines << QString(" * OTHER-ADDRESS %1 %2") - .arg(otherHost.toString()) - .arg(QString::number(otherPort)); - if (xorMappedPort) - dumpLines << QString(" * XOR-MAPPED-ADDRESS %1 %2") - .arg(xorMappedHost.toString()) - .arg(QString::number(xorMappedPort)); - if (!iceControlling.isEmpty()) - dumpLines << QString(" * ICE-CONTROLLING %1") - .arg(QString::fromAscii(iceControlling.toHex())); - if (!iceControlled.isEmpty()) - dumpLines << QString(" * ICE-CONTROLLED %1") - .arg(QString::fromAscii(iceControlled.toHex())); - - return dumpLines.join("\n"); -} - -QXmppStunSocket::Pair::Pair() - : checked(QIODevice::NotOpen) -{ - // FIXME : calculate priority - priority = 1862270975; - transaction = randomByteArray(ID_SIZE); -} - -QString QXmppStunSocket::Pair::toString() const -{ - QString str = QString("%1 %2").arg(remote.host().toString(), QString::number(remote.port())); - if (!reflexive.host().isNull() && reflexive.port()) - str += QString(" (reflexive %1 %2)").arg(reflexive.host().toString(), QString::number(reflexive.port())); - return str; -} - -/// Constructs a new QXmppStunSocket. -/// - -QXmppStunSocket::QXmppStunSocket(bool iceControlling, QObject *parent) - : QObject(parent), - m_activePair(0), - m_iceControlling(iceControlling) -{ - m_localUser = generateStanzaHash(4); - m_localPassword = generateStanzaHash(22); - - m_socket = new QUdpSocket(this); - connect(m_socket, SIGNAL(readyRead()), this, SLOT(readyRead())); - if (!m_socket->bind()) - qWarning("QXmppStunSocket could not start listening"); - - m_timer = new QTimer(this); - m_timer->setInterval(500); - connect(m_timer, SIGNAL(timeout()), this, SLOT(checkCandidates())); -} - -QXmppStunSocket::~QXmppStunSocket() -{ - foreach (Pair *pair, m_pairs) - delete pair; -} - -/// Returns the component id for the current socket, e.g. 1 for RTP -/// and 2 for RTCP. - -int QXmppStunSocket::component() const -{ - return m_component; -} - -/// Sets the component id for the current socket, e.g. 1 for RTP -/// and 2 for RTCP. -/// -/// \param component - -void QXmppStunSocket::setComponent(int component) -{ - m_component = component; -} - -void QXmppStunSocket::checkCandidates() -{ - debug("Checking remote candidates"); - foreach (Pair *pair, m_pairs) - { - // send a binding request - QXmppStunMessage message; - message.setId(pair->transaction); - message.setType(BindingRequest); - message.priority = pair->priority; - message.username = QString("%1:%2").arg(m_remoteUser, m_localUser); - if (m_iceControlling) - { - message.iceControlling = QByteArray(8, 0); - message.useCandidate = true; - } else { - message.iceControlled = QByteArray(8, 0); - } - writeStun(message, pair); - } -} - -/// Closes the socket. - -void QXmppStunSocket::close() -{ - m_socket->close(); - m_timer->stop(); -} - -/// Start ICE connectivity checks. - -void QXmppStunSocket::connectToHost() -{ - checkCandidates(); - m_timer->start(); -} - -/// Returns true if ICE negotiation completed, false otherwise. - -bool QXmppStunSocket::isConnected() const -{ - return m_activePair != 0; -} - -void QXmppStunSocket::debug(const QString &message, QXmppLogger::MessageType type) -{ - emit logMessage(type, QString("STUN(%1) %2").arg(QString::number(m_component)).arg(message)); -} - -/// Returns the list of local HOST CANDIDATES candidates by iterating -/// over the available network interfaces. - -QList QXmppStunSocket::localCandidates() const -{ - QList candidates; - foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) - { - if (!(interface.flags() & QNetworkInterface::IsRunning) || - interface.flags() & QNetworkInterface::IsLoopBack) - continue; - - foreach (const QNetworkAddressEntry &entry, interface.addressEntries()) - { - if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol || - entry.netmask().isNull() || - entry.netmask() == QHostAddress::Broadcast) - continue; - - QXmppJingleCandidate candidate; - candidate.setComponent(m_component); - candidate.setHost(entry.ip()); - candidate.setId(generateStanzaHash(10)); - candidate.setNetwork(interface.index()); - candidate.setPort(m_socket->localPort()); - candidate.setPriority(2130706432 - m_component); - candidate.setProtocol("udp"); - candidate.setType("host"); - candidates << candidate; - } - } - return candidates; -} - -QString QXmppStunSocket::localUser() const -{ - return m_localUser; -} - -void QXmppStunSocket::setLocalUser(const QString &user) -{ - m_localUser = user; -} - -QString QXmppStunSocket::localPassword() const -{ - return m_localPassword; -} - -void QXmppStunSocket::setLocalPassword(const QString &password) -{ - m_localPassword = password; -} - -/// Adds a remote STUN candidate. - -bool QXmppStunSocket::addRemoteCandidate(const QXmppJingleCandidate &candidate) -{ - if (candidate.component() != m_component || - candidate.type() != "host" || - candidate.protocol() != "udp") - return false; - - foreach (Pair *pair, m_pairs) - if (pair->remote.host() == candidate.host() && - pair->remote.port() == candidate.port()) - return false; - - Pair *pair = new Pair; - pair->remote = candidate; - m_pairs << pair; - return true; -} - -/// Adds a discovered STUN candidate. - -QXmppStunSocket::Pair *QXmppStunSocket::addRemoteCandidate(const QHostAddress &host, quint16 port) -{ - foreach (Pair *pair, m_pairs) - if (pair->remote.host() == host && - pair->remote.port() == port) - return pair; - - QXmppJingleCandidate candidate; - candidate.setHost(host); - candidate.setPort(port); - candidate.setProtocol("udp"); - candidate.setComponent(m_component); - - Pair *pair = new Pair; - pair->remote = candidate; - m_pairs << pair; - - debug(QString("Added candidate %1").arg(pair->toString())); - return pair; -} - -void QXmppStunSocket::setRemoteUser(const QString &user) -{ - m_remoteUser = user; -} - -void QXmppStunSocket::setRemotePassword(const QString &password) -{ - m_remotePassword = password; -} - -void QXmppStunSocket::readyRead() -{ - const qint64 size = m_socket->pendingDatagramSize(); - QHostAddress remoteHost; - quint16 remotePort; - QByteArray buffer(size, 0); - m_socket->readDatagram(buffer.data(), buffer.size(), &remoteHost, &remotePort); - - // if this is not a STUN message, emit it - quint16 messageType = QXmppStunMessage::peekType(buffer); - if (!messageType) - { - emit datagramReceived(buffer); - return; - } - - // parse STUN message - const QString messagePassword = (messageType & 0xFF00) ? m_remotePassword : m_localPassword; - if (messagePassword.isEmpty()) - return; - QXmppStunMessage message; - QStringList errors; - if (!message.decode(buffer, messagePassword, &errors)) - { - foreach (const QString &error, errors) - debug(error, QXmppLogger::WarningMessage); - return; - } -#ifdef QXMPP_DEBUG_STUN - debug(QString("Received from %1 port %2\n%3") - .arg(remoteHost.toString()) - .arg(QString::number(remotePort)) - .arg(message.toString()), - QXmppLogger::ReceivedMessage); -#endif - - if (m_activePair) - return; - - // process message - Pair *pair = 0; - if (message.type() == BindingRequest) - { - // add remote candidate - pair = addRemoteCandidate(remoteHost, remotePort); - - // send a binding response - QXmppStunMessage response; - response.setId(message.id()); - response.setType(BindingResponse); - response.username = message.username; - response.xorMappedHost = pair->remote.host(); - response.xorMappedPort = pair->remote.port(); - writeStun(response, pair); - - // update state - if (m_iceControlling || message.useCandidate) - { - debug(QString("ICE reverse check %1").arg(pair->toString())); - pair->checked |= QIODevice::ReadOnly; - } - - if (!m_iceControlling) - { - // send a triggered connectivity test - QXmppStunMessage message; - message.setId(pair->transaction); - message.setType(BindingRequest); - message.priority = pair->priority; - message.username = QString("%1:%2").arg(m_remoteUser, m_localUser); - message.iceControlled = QByteArray(8, 0); - writeStun(message, pair); - } - - } else if (message.type() == BindingResponse) { - - // find the pair for this transaction - foreach (Pair *ptr, m_pairs) - { - if (ptr->transaction == message.id()) - { - pair = ptr; - break; - } - } - if (!pair) - { - debug(QString("Unknown transaction %1").arg(QString::fromAscii(message.id().toHex()))); - return; - } - // store reflexive address - pair->reflexive.setHost(message.xorMappedHost); - pair->reflexive.setPort(message.xorMappedPort); - - // add the new remote candidate - addRemoteCandidate(remoteHost, remotePort); - -#if 0 - // send a binding indication - QXmppStunMessage indication; - indication.setId(randomByteArray(ID_SIZE)); - indication.setType(BindingIndication); - m_socket->writeStun(indication, pair); -#endif - // outgoing media can flow - debug(QString("ICE forward check %1").arg(pair->toString())); - pair->checked |= QIODevice::WriteOnly; - } - - // signal completion - if (pair && pair->checked == QIODevice::ReadWrite) - { - debug(QString("ICE completed %1").arg(pair->toString())); - m_activePair = pair; - m_timer->stop(); - emit connected(); - } -} - -/// Sends a data packet to the remote party. -/// -/// \param datagram - -qint64 QXmppStunSocket::writeDatagram(const QByteArray &datagram) -{ - if (!m_activePair) - return -1; - return m_socket->writeDatagram(datagram, m_activePair->remote.host(), m_activePair->remote.port()); -} - -/// Sends a STUN packet to the remote party. - -qint64 QXmppStunSocket::writeStun(const QXmppStunMessage &message, QXmppStunSocket::Pair *pair) -{ - const QString messagePassword = (message.type() & 0xFF00) ? m_localPassword : m_remotePassword; -#ifdef QXMPP_DEBUG_STUN - debug( - QString("Sent to %1\n%2").arg(pair->toString(), message.toString()), - QXmppLogger::SentMessage); -#endif - return m_socket->writeDatagram(message.encode(messagePassword), pair->remote.host(), pair->remote.port()); -} - -- cgit v1.2.3