From 62f54e12354e208c8931e069fce235c4ca14d205 Mon Sep 17 00:00:00 2001 From: dknn Date: Sat, 7 Jul 2012 12:08:42 +0200 Subject: Add raw UDP transport payload: element, serializer, parser and tests diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index e6f3f60..167f5c1 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -69,6 +69,7 @@ #include #include #include +#include using namespace boost; @@ -132,6 +133,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(boost::make_shared()); factories_.push_back(boost::make_shared(this)); factories_.push_back(boost::make_shared >("payload-type")); + factories_.push_back(boost::make_shared >("transport", "urn:xmpp:jingle:transports:raw-udp:1")); foreach(shared_ptr factory, factories_) { addFactory(factory.get()); diff --git a/Swiften/Parser/PayloadParsers/JingleRawUDPTransportPayloadParser.cpp b/Swiften/Parser/PayloadParsers/JingleRawUDPTransportPayloadParser.cpp new file mode 100644 index 0000000..aa6aaf7 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleRawUDPTransportPayloadParser.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012 Yoann Blein + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include +#include + +namespace Swift { + +JingleRawUDPTransportPayloadParser::JingleRawUDPTransportPayloadParser() : level(0) { + +} + +void JingleRawUDPTransportPayloadParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + if (level == 1 && element == "candidate") { + JingleRawUDPTransportPayload::Candidate candidate; + + // component + try { + candidate.component = boost::numeric_cast(boost::lexical_cast(attributes.getAttributeValue("component").get_value_or("0"))); + } catch(boost::bad_lexical_cast &) { } + // generation + try { + candidate.generation = boost::numeric_cast(boost::lexical_cast(attributes.getAttributeValue("generation").get_value_or("0"))); + } catch(boost::bad_lexical_cast &) { } + // id + candidate.cid = attributes.getAttributeValue("id").get_value_or(""); + // ip/port + int port = -1; + try { + port = boost::lexical_cast(attributes.getAttributeValue("port").get_value_or("0")); + } catch(boost::bad_lexical_cast &) { } + candidate.hostAddressPort = HostAddressPort(HostAddress(attributes.getAttributeValue("ip").get_value_or("")), port); + // type + candidate.type = stringToType(attributes.getAttributeValue("type").get_value_or("")); + + getPayloadInternal()->addCandidate(candidate); + } + + ++level; +} + +void JingleRawUDPTransportPayloadParser::handleEndElement(const std::string&, const std::string&) { + --level; +} + +void JingleRawUDPTransportPayloadParser::handleCharacterData(const std::string&) { + +} + +JingleRawUDPTransportPayload::Candidate::Type JingleRawUDPTransportPayloadParser::stringToType(const std::string &str) const { + if (str == "host") { + return JingleRawUDPTransportPayload::Candidate::Host; + } else if (str == "prflx") { + return JingleRawUDPTransportPayload::Candidate::PeerReflected; + } else if (str == "relay") { + return JingleRawUDPTransportPayload::Candidate::Relayed; + } else if (str == "srflx") { + return JingleRawUDPTransportPayload::Candidate::ServerReflected; + } else { + return JingleRawUDPTransportPayload::Candidate::Unknown; + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/JingleRawUDPTransportPayloadParser.h b/Swiften/Parser/PayloadParsers/JingleRawUDPTransportPayloadParser.h new file mode 100644 index 0000000..859fe88 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleRawUDPTransportPayloadParser.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Yoann Blein + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + +class JingleRawUDPTransportPayloadParser : public GenericPayloadParser { + public: + JingleRawUDPTransportPayloadParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + JingleRawUDPTransportPayload::Candidate::Type stringToType(const std::string &str) const; + + private: + int level; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp index 18f38b2..2dd301f 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp @@ -15,8 +15,8 @@ #include #include #include -//#include #include +#include #include #include @@ -47,6 +47,8 @@ class JingleParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse_Xep0167_Example1); CPPUNIT_TEST(testParse_Xep0167_Example48); + CPPUNIT_TEST(testParse_Xep0177_Example3); + CPPUNIT_TEST_SUITE_END(); public: @@ -819,6 +821,77 @@ class JingleParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("AS"), type); CPPUNIT_ASSERT_EQUAL(std::string("128"), value); } + + // http://xmpp.org/extensions/xep-0177.html#example-3 + void testParse_Xep0177_Example3() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + )); + + JinglePayload::ref jingle = parser.getPayload(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionAccept, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), jingle->getResponder()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + JingleContentPayload::ref content = jingle->getPayload(); + CPPUNIT_ASSERT(content); + CPPUNIT_ASSERT_EQUAL(std::string("voice"), content->getName()); + + JingleRTPDescription::ref desc = content->getDescription(); + CPPUNIT_ASSERT(desc); + CPPUNIT_ASSERT_EQUAL(JingleRTPDescription::Audio, desc->getMedia()); + + CPPUNIT_ASSERT_EQUAL(static_cast(1), desc->getPayloadTypes().size()); + + const RTPPayloadType& payloadType = desc->getPayloadTypes()[0]; + CPPUNIT_ASSERT_EQUAL(static_cast(18), payloadType.getID()); + CPPUNIT_ASSERT_EQUAL(std::string("G729"), payloadType.getName()); + + JingleRawUDPTransportPayload::ref transport = content->getTransport(); + CPPUNIT_ASSERT(transport); + + CPPUNIT_ASSERT_EQUAL(static_cast(2), transport->getCandidates().size()); + + const JingleRawUDPTransportPayload::Candidate& candidate1 = transport->getCandidates()[0]; + boost::uint8_t expected = 1; + boost::uint8_t actual = candidate1.component; + + CPPUNIT_ASSERT_EQUAL(expected, actual); + CPPUNIT_ASSERT_EQUAL(static_cast(0), candidate1.generation); + CPPUNIT_ASSERT_EQUAL(std::string("z7sdjb01hf"), candidate1.cid); + CPPUNIT_ASSERT(HostAddressPort(HostAddress("208.68.163.214"), 9876) == candidate1.hostAddressPort); + + const JingleRawUDPTransportPayload::Candidate& candidate2 = transport->getCandidates()[1]; + CPPUNIT_ASSERT_EQUAL(static_cast(2), candidate2.component); + CPPUNIT_ASSERT_EQUAL(static_cast(0), candidate2.generation); + CPPUNIT_ASSERT_EQUAL(std::string("hg92lsn10b"), candidate2.cid); + CPPUNIT_ASSERT(HostAddressPort(HostAddress("208.68.163.214"), 9877) == candidate2.hostAddressPort); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(JingleParserTest); diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 1ce84b9..43d50f0 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -75,6 +75,7 @@ sources = [ "PayloadParsers/WhiteboardParser.cpp", "PayloadParsers/RTPPayloadTypeParser.cpp", "PayloadParsers/JingleRTPDescriptionParser.cpp", + "PayloadParsers/JingleRawUDPTransportPayloadParser.cpp", "PlatformXMLParserFactory.cpp", "PresenceParser.cpp", "SerializingParser.cpp", diff --git a/Swiften/SConscript b/Swiften/SConscript index a08cb6e..78c20e5 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -1,4 +1,4 @@ -import os, re, Version, os.path, time +import os, re, Version, os.path Import("env") @@ -6,7 +6,7 @@ Import("env") # Flags ################################################################################ -swiften_dep_modules = ["BOOST", "GCONF", "ICU", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI", "LIBMINIUPNPC", "LIBNATPMP", "SQLITE", "SQLITE_ASYNC"] +swiften_dep_modules = ["BOOST", "GCONF", "ICU", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI", "LIBMINIUPNPC", "LIBNATPMP", "SQLITE", "SQLITE_ASYNC", "JRTPLIB"] external_swiften_dep_modules = ["BOOST"] if env["SCONS_STAGE"] == "flags" : @@ -206,6 +206,7 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/WhiteboardSerializer.cpp", "Serializer/PayloadSerializers/RTPPayloadTypeSerializer.cpp", "Serializer/PayloadSerializers/JingleRTPDescriptionSerializer.cpp", + "Serializer/PayloadSerializers/JingleRawUDPTransportPayloadSerializer.cpp", "Serializer/PresenceSerializer.cpp", "Serializer/StanzaSerializer.cpp", "Serializer/StreamErrorSerializer.cpp", diff --git a/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp index c36d574..f2ba1a7 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "Swiften/FileTransfer/JingleTransport.h" @@ -58,11 +59,17 @@ std::string JingleContentPayloadSerializer::serializePayload(boost::shared_ptrgetTransports()) { if ((ibb = boost::dynamic_pointer_cast(transport))) { payloadXML.addNode(boost::make_shared(ibbSerializer.serializePayload(ibb))); } else if ((s5b = boost::dynamic_pointer_cast(transport))) { payloadXML.addNode(boost::make_shared(s5bSerializer.serializePayload(s5b))); + } else if ((rawUDP = boost::dynamic_pointer_cast(transport))) { + payloadXML.addNode(boost::make_shared(rawUdpSerializer.serializePayload(rawUDP))); } } } diff --git a/Swiften/Serializer/PayloadSerializers/JingleRawUDPTransportPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleRawUDPTransportPayloadSerializer.cpp new file mode 100644 index 0000000..af13003 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleRawUDPTransportPayloadSerializer.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012 Yoann Blein + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include +#include + +#include +#include + +namespace Swift { + +JingleRawUDPTransportPayloadSerializer::JingleRawUDPTransportPayloadSerializer() { +} + +std::string JingleRawUDPTransportPayloadSerializer::serializePayload(boost::shared_ptr payload) const { + XMLElement payloadXML("transport", "urn:xmpp:jingle:transports:raw-udp:1"); + + foreach (JingleRawUDPTransportPayload::Candidate candidate, payload->getCandidates()) { + boost::shared_ptr candidateXML = boost::make_shared("candidate"); + candidateXML->setAttribute("component", boost::lexical_cast(static_cast(candidate.component))); + candidateXML->setAttribute("generation", boost::lexical_cast(static_cast(candidate.generation))); + candidateXML->setAttribute("id", candidate.cid); + candidateXML->setAttribute("ip", candidate.hostAddressPort.getAddress().toString()); + candidateXML->setAttribute("port", boost::lexical_cast(candidate.hostAddressPort.getPort())); + if (candidate.type != JingleRawUDPTransportPayload::Candidate::Unknown) + candidateXML->setAttribute("type", typeToString(candidate.type)); + payloadXML.addNode(candidateXML); + } + + return payloadXML.serialize(); +} + +std::string JingleRawUDPTransportPayloadSerializer::typeToString(JingleRawUDPTransportPayload::Candidate::Type type) const { + switch (type) { + case JingleRawUDPTransportPayload::Candidate::Unknown: + return ""; + case JingleRawUDPTransportPayload::Candidate::Host: + return "host"; + case JingleRawUDPTransportPayload::Candidate::PeerReflected: + return "prflx"; + case JingleRawUDPTransportPayload::Candidate::Relayed: + return "relay"; + case JingleRawUDPTransportPayload::Candidate::ServerReflected: + return "srflx"; + } + assert(false); + return ""; +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleRawUDPTransportPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleRawUDPTransportPayloadSerializer.h new file mode 100644 index 0000000..5479d1d --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleRawUDPTransportPayloadSerializer.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2012 Yoann Blein + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + class JingleRawUDPTransportPayloadSerializer : public GenericPayloadSerializer { + public: + JingleRawUDPTransportPayloadSerializer(); + + virtual std::string serializePayload(boost::shared_ptr) const; + + private: + std::string typeToString(JingleRawUDPTransportPayload::Candidate::Type) const; + + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp index a89c91c..4a74a24 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include using namespace Swift; @@ -56,6 +58,10 @@ class JingleSerializersTest : public CppUnit::TestFixture { CPPUNIT_TEST(testSerialize_Xep0167_Example1); CPPUNIT_TEST(testSerialize_Xep0167_Example48); + CPPUNIT_TEST(testSerialize_RawUDPTransportPayload); + + CPPUNIT_TEST(testSerialize_Xep0177_Example3); + CPPUNIT_TEST_SUITE_END(); boost::shared_ptr createTestling() { @@ -660,6 +666,95 @@ class JingleSerializersTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); } + void testSerialize_RawUDPTransportPayload() { + std::string expected = + "" + "" + ""; + + JingleRawUDPTransportPayload::ref transport = boost::make_shared(); + + JingleRawUDPTransportPayload::Candidate candidate; + candidate.component = 1; + candidate.generation = 0; + candidate.cid = "a9j3mnbtu1"; + candidate.hostAddressPort = HostAddressPort(HostAddress("10.1.1.104"), 13540); + candidate.type = JingleRawUDPTransportPayload::Candidate::ServerReflected; + transport->addCandidate(candidate); + + boost::shared_ptr serializer = boost::make_shared(); + CPPUNIT_ASSERT_EQUAL(expected, serializer->serialize(transport)); + } + + // http://xmpp.org/extensions/xep-0177.html#example-3 + void testSerialize_Xep0177_Example3() { + std::string expected = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + JinglePayload::ref payload = boost::make_shared(); + payload->setAction(JinglePayload::SessionAccept); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setResponder(JID("juliet@capulet.lit/balcony")); + payload->setSessionID("a73sjjvkla37jfea"); + + JingleRTPDescription::ref desc = boost::make_shared(JingleRTPDescription::Audio); + RTPPayloadType payloadType(18, "G729"); + desc->addPayloadType(payloadType); + + JingleRawUDPTransportPayload::ref transport = boost::make_shared(); + + JingleRawUDPTransportPayload::Candidate candidate1; + candidate1.component = 1; + candidate1.generation = 0; + candidate1.cid = "z7sdjb01hf"; + candidate1.hostAddressPort = HostAddressPort(HostAddress("208.68.163.214"), 9876); + transport->addCandidate(candidate1); + + JingleRawUDPTransportPayload::Candidate candidate2; + candidate2.component = 2; + candidate2.generation = 0; + candidate2.cid = "hg92lsn10b"; + candidate2.hostAddressPort = HostAddressPort(HostAddress("208.68.163.214"), 9877); + transport->addCandidate(candidate2); + + JingleContentPayload::ref content = boost::make_shared(); + content->setCreator(JingleContentPayload::InitiatorCreator); + content->setName("voice"); + content->addDescription(desc); + content->addTransport(transport); + + payload->addPayload(content); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + private: FullPayloadSerializerCollection collection; }; -- cgit v0.10.2-6-g49f6