void write(const QByteArray &buf, const QHostAddress &addr, int port) { QByteArray packet = allocate->encode(buf, addr, port); if(debugLevel >= TurnClient::DL_Packet) { StunMessage msg = StunMessage::fromBinary(packet); if(!msg.isNull()) { emit q->debugLine("STUN SEND"); emit q->debugLine(StunTypes::print_packet_str(msg)); } else emit q->debugLine("Sending ChannelData-based data packet"); } writeItems += WriteItem(packet.size(), addr, port); ++outPendingWrite; if(udp) { emit q->outgoingDatagram(packet); } else { if(tls) tls->write(packet); else bs->write(packet); } }
QByteArray processNonPoolPacket(const QByteArray &buf, bool notStun, QHostAddress *addr, int *port) { if(notStun) { // not stun? maybe it is a data packet QByteArray data = allocate->decode(buf, addr, port); if(!data.isNull()) { if(debugLevel >= TurnClient::DL_Packet) emit q->debugLine("Received ChannelData-based data packet"); return data; } } else { // packet might be stun not owned by pool. // let's see StunMessage message = StunMessage::fromBinary(buf); if(!message.isNull()) { QByteArray data = allocate->decode(message, addr, port); if(!data.isNull()) { if(debugLevel >= TurnClient::DL_Packet) emit q->debugLine("Received STUN-based data packet"); return data; } else { if(debugLevel >= TurnClient::DL_Packet) emit q->debugLine("Warning: server responded with an unexpected STUN packet, skipping."); } return QByteArray(); } } if(debugLevel >= TurnClient::DL_Packet) emit q->debugLine("Warning: server responded with what doesn't seem to be a STUN or data packet, skipping."); return QByteArray(); }
void tryRequest() { emit q->createMessage(pool->d->generateId()); if(origMessage.isNull()) { // since a transaction is not cancelable nor reusable, // there's no DOR-SR issue here QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection, Q_ARG(XMPP::StunTransaction::Error, StunTransaction::ErrorGeneric)); return; } StunMessage out = origMessage; out.setClass(StunMessage::Request); id = QByteArray((const char *)out.id(), 12); if(!stuser.isEmpty()) { QList<StunMessage::Attribute> list = out.attributes(); StunMessage::Attribute attr; attr.type = StunTypes::USERNAME; attr.value = StunTypes::createUsername(QString::fromUtf8(StunUtil::saslPrep(stuser.toUtf8()).toByteArray())); list += attr; out.setAttributes(list); key = StunUtil::saslPrep(stpass.toUtf8()).toByteArray(); } else if(!pool->d->nonce.isEmpty()) { QList<StunMessage::Attribute> list = out.attributes(); { StunMessage::Attribute attr; attr.type = StunTypes::USERNAME; attr.value = StunTypes::createUsername(QString::fromUtf8(StunUtil::saslPrep(pool->d->user.toUtf8()).toByteArray())); list += attr; } { StunMessage::Attribute attr; attr.type = StunTypes::REALM; attr.value = StunTypes::createRealm(pool->d->realm); list += attr; } { StunMessage::Attribute attr; attr.type = StunTypes::NONCE; attr.value = StunTypes::createNonce(pool->d->nonce); list += attr; } out.setAttributes(list); QCA::SecureArray buf; buf += StunUtil::saslPrep(pool->d->user.toUtf8()); buf += QByteArray(1, ':'); buf += StunUtil::saslPrep(pool->d->realm.toUtf8()); buf += QByteArray(1, ':'); buf += StunUtil::saslPrep(pool->d->pass); key = QCA::Hash("md5").process(buf).toByteArray(); } if(!key.isEmpty()) packet = out.toBinary(StunMessage::MessageIntegrity | StunMessage::Fingerprint, key); else packet = out.toBinary(StunMessage::Fingerprint); if(packet.isEmpty()) { // since a transaction is not cancelable nor reusable, // there's no DOR-SR issue here QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection, Q_ARG(XMPP::StunTransaction::Error, StunTransaction::ErrorGeneric)); return; } active = true; tries = 1; // we transmit immediately here, so count it if(mode == StunTransaction::Udp) { last_interval = rm * rto; t->start(rto); rto *= 2; } else if(mode == StunTransaction::Tcp) { t->start(ti); } else Q_ASSERT(0); #ifdef STUNTRANSACTION_DEBUG time.start(); #endif pool->d->insert(q); transmit(); }
void StunMessageTestSuite::testFullEncodeParse() { StunMessage msg ; StunMessage check ; bool bRC ; char szString[1024] ; uint16_t usValue ; bool bValue ; uint16_t values[16] ; size_t size ; // Valid empty state CPPUNIT_ASSERT(!msg.getMappedAddress(szString, usValue)) ; CPPUNIT_ASSERT(!msg.getResponseAddress(szString, usValue)) ; CPPUNIT_ASSERT(!msg.getChangePort()) ; CPPUNIT_ASSERT(!msg.getChangeIp()) ; CPPUNIT_ASSERT(!msg.getSourceAddress(szString, usValue)) ; CPPUNIT_ASSERT(!msg.getChangedAddress(szString, usValue)) ; CPPUNIT_ASSERT(!msg.getUsername(szString)) ; CPPUNIT_ASSERT(!msg.getPassword(szString)) ; CPPUNIT_ASSERT(!msg.getError(usValue, szString)) ; CPPUNIT_ASSERT(!msg.getUnknownAttributes(values, 16, size)) ; CPPUNIT_ASSERT(!msg.getReflectedFrom(szString, usValue)) ; CPPUNIT_ASSERT(!msg.getServer(szString)) ; // Set Values msg.setType(MSG_STUN_BIND_REQUEST) ; msg.allocTransactionId() ; msg.setMappedAddress("10.1.1.1", 1) ; msg.setResponseAddress("10.1.1.2", 2) ; msg.setChangePort(true) ; msg.setChangeIp(true) ; msg.setSourceAddress("10.1.1.3", 3) ; msg.setChangedAddress("10.1.1.4", 4) ; msg.setUsername("Username") ; msg.setPassword("Password") ; msg.setError(302, "Reason") ; msg.addUnknownAttribute(0x1234) ; msg.setReflectedFrom("10.1.1.5", 5) ; msg.setServer("Server") ; // Verify Values CPPUNIT_ASSERT(msg.getType() == MSG_STUN_BIND_REQUEST) ; bRC = msg.getMappedAddress(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.1") == 0) ; CPPUNIT_ASSERT(usValue == 1) ; bRC = msg.getResponseAddress(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.2") == 0) ; CPPUNIT_ASSERT(usValue == 2) ; bValue = msg.getChangePort() ; CPPUNIT_ASSERT(bValue == true) ; bValue = msg.getChangeIp() ; CPPUNIT_ASSERT(bValue == true) ; bRC = msg.getSourceAddress(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.3") == 0) ; CPPUNIT_ASSERT(usValue == 3) ; bRC = msg.getChangedAddress(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.4") == 0) ; CPPUNIT_ASSERT(usValue == 4) ; bRC = msg.getUsername(szString) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "Username") == 0) ; bRC = msg.getPassword(szString) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "Password") == 0) ; bRC = msg.getError(usValue, szString) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(usValue == 302) ; CPPUNIT_ASSERT(strcmp(szString, "Reason") == 0) ; bRC = msg.getUnknownAttributes(values, 16, size) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(size == 1) ; CPPUNIT_ASSERT(values[0] == 0x1234) ; bRC = msg.getReflectedFrom(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.5") == 0) ; CPPUNIT_ASSERT(usValue == 5) ; bRC = msg.getServer(szString) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "Server") == 0) ; msg.setRequestXorOnly() ; char encoded[4096] ; size_t nLength ; if (msg.encode(encoded, 4096, nLength)) { if (check.parse(encoded, nLength)) { // Verify Values (again -- copy from above) CPPUNIT_ASSERT(msg.getType() == MSG_STUN_BIND_REQUEST) ; bRC = msg.getMappedAddress(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.1") == 0) ; CPPUNIT_ASSERT(usValue == 1) ; bRC = msg.getResponseAddress(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.2") == 0) ; CPPUNIT_ASSERT(usValue == 2) ; bValue = msg.getChangePort() ; CPPUNIT_ASSERT(bValue == true) ; bValue = msg.getChangeIp() ; CPPUNIT_ASSERT(bValue == true) ; bRC = msg.getSourceAddress(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.3") == 0) ; CPPUNIT_ASSERT(usValue == 3) ; bRC = msg.getChangedAddress(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.4") == 0) ; CPPUNIT_ASSERT(usValue == 4) ; bRC = msg.getUsername(szString) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "Username") == 0) ; bRC = msg.getPassword(szString) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "Password") == 0) ; bRC = msg.getError(usValue, szString) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(usValue == 302) ; CPPUNIT_ASSERT(strcmp(szString, "Reason") == 0) ; bRC = msg.getUnknownAttributes(values, 16, size) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(size == 1) ; CPPUNIT_ASSERT(values[0] == 0x1234) ; bRC = msg.getReflectedFrom(szString, usValue) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "10.1.1.5") == 0) ; CPPUNIT_ASSERT(usValue == 5) ; bRC = msg.getServer(szString) ; CPPUNIT_ASSERT(bRC) ; CPPUNIT_ASSERT(strcmp(szString, "Server") == 0) ; } else { CPPUNIT_ASSERT(false) ; } } else { CPPUNIT_ASSERT(false) ; } }
bool StunUtils::sendStunNatTest(OsDatagramSocket* pSocket, const char* szServerIp, const int port, bool bChangePort, bool bChangeIP, char* szMappedIp, unsigned short* piMappedPort, char* szChangedIp, unsigned short* piChangedPort) { StunMessage msgSend ; char cMsgSend[2048] ; StunMessage msgReceive ; char cMsgReceive[2048] ; size_t nLength ; bool bSuccess = false ; msgSend.setType(MSG_STUN_BIND_REQUEST) ; msgSend.allocTransactionId() ; msgSend.setRequestXorOnly() ; if (bChangePort) { msgSend.setChangePort(true) ; } if (bChangeIP) { msgSend.setChangeIp(true) ; } if (msgSend.encode(cMsgSend, sizeof(cMsgSend), nLength)) { for (int i=0; (i<3) && (bSuccess == false); i++) { if (pSocket->write(cMsgSend, (int) nLength, szServerIp, port) > 0) { if (pSocket->isReadyToRead(500)) { int length = pSocket->read(cMsgReceive, sizeof(cMsgReceive)) ; if ((length > 0) && msgReceive.parse(cMsgReceive, length)) { if (msgReceive.getType() == MSG_STUN_BIND_RESPONSE) { bSuccess = true ; // Get optional mapped address if (szMappedIp && piMappedPort) { msgReceive.getMappedAddress(szMappedIp, *piMappedPort) ; } // Get optional changed address if (szChangedIp && piChangedPort) { msgReceive.getChangedAddress(szChangedIp, *piChangedPort) ; } } else { // Abort on error response break ; } } } } else { break ; } } } else { assert(false) ; } return bSuccess ; }