diff options
Diffstat (limited to 'Swiften')
306 files changed, 5010 insertions, 1583 deletions
diff --git a/Swiften/Avatars/CombinedAvatarProvider.cpp b/Swiften/Avatars/CombinedAvatarProvider.cpp index 465512f..ba6e6be 100644 --- a/Swiften/Avatars/CombinedAvatarProvider.cpp +++ b/Swiften/Avatars/CombinedAvatarProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -39,17 +39,17 @@ void CombinedAvatarProvider::handleAvatarChanged(const JID& jid) { } boost::optional<std::string> newHash = getCombinedAvatarAndCache(jid); if (newHash != oldHash) { - SWIFT_LOG(debug) << "Avatar changed: " << jid << ": " << oldHash << " -> " << (newHash ? newHash.get() : "NULL") << std::endl; + SWIFT_LOG(debug) << "Avatar changed: " << jid << ": " << oldHash << " -> " << (newHash ? newHash.get() : "NULL"); onAvatarChanged(jid); } } boost::optional<std::string> CombinedAvatarProvider::getCombinedAvatarAndCache(const JID& jid) const { - SWIFT_LOG(debug) << "JID: " << jid << std::endl; + SWIFT_LOG(debug) << "JID: " << jid; boost::optional<std::string> hash; for (size_t i = 0; i < providers.size() && !hash; ++i) { hash = providers[i]->getAvatarHash(jid); - SWIFT_LOG(debug) << "Provider " << providers[i] << ": " << (hash ? hash.get() : "NULL") << std::endl; + SWIFT_LOG(debug) << "Provider " << providers[i] << ": " << (hash ? hash.get() : "NULL"); } if (hash) { avatars[jid] = *hash; diff --git a/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp b/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp index 241f375..5a35410 100644 --- a/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp +++ b/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 Isode Limited. + * Copyright (c) 2014-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -91,6 +91,7 @@ class AvatarManagerImplTest : public CppUnit::TestFixture { /* send new presence to notify of blank avatar */ vcardUpdate = std::make_shared<VCardUpdate>(); + vcardUpdate->setPhotoHash("da39a3ee5e6b4b0d3255bfef95601890afd80709"); presence = std::make_shared<Presence>(); presence->setTo(ownerJID); presence->setFrom(personJID); diff --git a/Swiften/Avatars/VCardUpdateAvatarManager.cpp b/Swiften/Avatars/VCardUpdateAvatarManager.cpp index 3e8d87b..d04c13c 100644 --- a/Swiften/Avatars/VCardUpdateAvatarManager.cpp +++ b/Swiften/Avatars/VCardUpdateAvatarManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -32,10 +32,14 @@ void VCardUpdateAvatarManager::handlePresenceReceived(std::shared_ptr<Presence> return; } JID from = getAvatarJID(presence->getFrom()); + if (update->getPhotoHash().size() != 40) { + SWIFT_LOG(debug) << "Invalid vCard avatar photo hash length. Must be hex-encoded SHA-1, i.e. 40 characters."; + return; + } if (getAvatarHash(from) == update->getPhotoHash()) { return; } - SWIFT_LOG(debug) << "Updated hash: " << from << " -> " << update->getPhotoHash() << std::endl; + SWIFT_LOG(debug) << "Updated hash: " << from << " -> " << update->getPhotoHash(); if (avatarStorage_->hasAvatar(update->getPhotoHash())) { setAvatarHash(from, update->getPhotoHash()); } @@ -46,7 +50,7 @@ void VCardUpdateAvatarManager::handlePresenceReceived(std::shared_ptr<Presence> void VCardUpdateAvatarManager::handleVCardChanged(const JID& from, VCard::ref vCard) { if (!vCard) { - SWIFT_LOG(debug) << "Missing element: " << from << ": null vcard payload" << std::endl; + SWIFT_LOG(debug) << "Missing element: " << from << ": null vcard payload"; return; } @@ -63,7 +67,7 @@ void VCardUpdateAvatarManager::handleVCardChanged(const JID& from, VCard::ref vC } void VCardUpdateAvatarManager::setAvatarHash(const JID& from, const std::string& hash) { - SWIFT_LOG(debug) << "Updating hash: " << from << " -> " << hash << std::endl; + SWIFT_LOG(debug) << "Updating hash: " << from << " -> " << hash; avatarHashes_[from] = hash; onAvatarChanged(from); } diff --git a/Swiften/Base/Algorithm.h b/Swiften/Base/Algorithm.h index 108dbe3..ee761b7 100644 --- a/Swiften/Base/Algorithm.h +++ b/Swiften/Base/Algorithm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -160,4 +160,28 @@ namespace Swift { return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred); } + + /** + * Ranges + */ + template <typename T> + class range_t { + public: + range_t(T b, T e) : b_(b), e_(e) {} + + T begin() { + return b_; + } + T end() { + return e_; + } + private: + T b_; + T e_; + }; + + template <typename T> + range_t<T> range(T b, T e) { + return range_t<T>(b, e); + } } diff --git a/Swiften/Base/DateTime.cpp b/Swiften/Base/DateTime.cpp index 4443566..23b3b84 100644 --- a/Swiften/Base/DateTime.cpp +++ b/Swiften/Base/DateTime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -40,7 +40,7 @@ std::string dateTimeToLocalString(const boost::posix_time::ptime& time) { localString = boost::posix_time::to_simple_string(boost::date_time::c_local_adjustor<boost::posix_time::ptime>::utc_to_local(time)); } catch(std::out_of_range& exception) { - SWIFT_LOG(debug) << exception.what() << std::endl; + SWIFT_LOG(debug) << exception.what(); } return localString; } diff --git a/Swiften/Base/Log.cpp b/Swiften/Base/Log.cpp index 0efac7e..b6f1851 100644 --- a/Swiften/Base/Log.cpp +++ b/Swiften/Base/Log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,6 +16,8 @@ namespace Swift { static Log::Severity logLevel = Log::warning; +std::unique_ptr<FILE, Log::LogFileClose> Log::logfile; +Log::Callback Log::logCallback; Log::Log() { } @@ -25,18 +27,38 @@ Log::~Log() { __android_log_print(ANDROID_LOG_VERBOSE, "Swift", stream.str().c_str(), 1); #else // Using stdio for thread safety (POSIX file i/o calls are guaranteed to be atomic) - fprintf(stderr, "%s", stream.str().c_str()); - fflush(stderr); + if (logCallback) { + logCallback(severity_, std::move(file_), line_, std::move(function_), stream.str()); + } + else { + stream << std::endl; + if (logfile) { + fwrite(stream.str().c_str(), sizeof(char), stream.str().size(), logfile.get()); + fflush(logfile.get()); + } + else { + fwrite(stream.str().c_str(), sizeof(char), stream.str().size(), stderr); + fflush(stderr); + } + } #endif } std::ostringstream& Log::getStream( - Severity /*severity*/, - const std::string& severityString, - const std::string& file, + Severity severity, + std::string severityString, + std::string file, int line, - const std::string& function) { - stream << "[" << severityString << "] " << file << ":" << line << " " << function << ": "; + std::string function) { + if (logCallback) { + severity_ = severity; + file_ = std::move(file); + line_ = line; + function_ = std::move(function); + } + else { + stream << "[" << severityString << "] " << file << ":" << line << " " << function << ": "; + } return stream; } @@ -48,4 +70,14 @@ void Log::setLogLevel(Severity level) { logLevel = level; } +void Log::setLogFile(const std::string& fileName) { + if (!fileName.empty()) { + logfile = std::unique_ptr<FILE, Log::LogFileClose>(fopen(fileName.c_str(), "a")); + } +} + +void Log::setLogCallback(Callback callback) { + Log::logCallback = callback; +} + } diff --git a/Swiften/Base/Log.h b/Swiften/Base/Log.h index 33c969d..255e478 100644 --- a/Swiften/Base/Log.h +++ b/Swiften/Base/Log.h @@ -6,6 +6,9 @@ #pragma once +#include <cstdio> +#include <functional> +#include <memory> #include <sstream> #include <Swiften/Base/API.h> @@ -16,22 +19,38 @@ namespace Swift { enum Severity { error, warning, info, debug }; + using Callback = std::function<void(Severity severity, std::string file, int line, std::string function, std::string message)>; Log(); ~Log(); std::ostringstream& getStream( Severity severity, - const std::string& severityString, - const std::string& file, + std::string severityString, + std::string file, int line, - const std::string& function); + std::string function); static Severity getLogLevel(); static void setLogLevel(Severity level); + static void setLogFile(const std::string& fileName); + static void setLogCallback(Callback callback); private: + struct LogFileClose { + void operator()(FILE* p) { + if (p) { + fclose(p); + } + } + }; std::ostringstream stream; + static std::unique_ptr<FILE, LogFileClose> logfile; + static Callback logCallback; + Severity severity_; + std::string file_; + int line_; + std::string function_; }; } diff --git a/Swiften/Base/Platform.h b/Swiften/Base/Platform.h index 4deba2b..22dff30 100644 --- a/Swiften/Base/Platform.h +++ b/Swiften/Base/Platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -43,9 +43,9 @@ #endif // Endianness -#include <boost/detail/endian.hpp> -#if defined(BOOST_LITTLE_ENDIAN) +#include <boost/predef/other/endian.h> +#if defined(BOOST_ENDIAN_LITTLE_BYTE) #define SWIFTEN_LITTLE_ENDIAN -#elif defined(BOOST_BIG_ENDIAN) +#elif defined(BOOST_ENDIAN_BIG_BYTE) #define SWIFTEN_BIG_ENDIAN #endif diff --git a/Swiften/Base/URL.cpp b/Swiften/Base/URL.cpp index 4a47a11..5c0f0d7 100644 --- a/Swiften/Base/URL.cpp +++ b/Swiften/Base/URL.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,7 +11,7 @@ namespace Swift { -int URL::getPortOrDefaultPort(const URL& url) { +unsigned short URL::getPortOrDefaultPort(const URL& url) { if (url.getPort()) { return *url.getPort(); } @@ -62,7 +62,7 @@ URL URL::fromString(const std::string& urlString) { } std::string host; - boost::optional<int> port; + boost::optional<unsigned short> port; if (hostAndPort[0] == '[') { // handle IPv6 address literals size_t addressEndIndex = hostAndPort.find(']'); @@ -71,9 +71,9 @@ URL URL::fromString(const std::string& urlString) { colonIndex = hostAndPort.find(':', addressEndIndex); if (colonIndex != std::string::npos) { try { - port = boost::lexical_cast<int>(hostAndPort.substr(colonIndex + 1)); + port = boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(hostAndPort.substr(colonIndex + 1))); } - catch (const boost::bad_lexical_cast&) { + catch (...) { return URL(); } } @@ -87,7 +87,7 @@ URL URL::fromString(const std::string& urlString) { if (colonIndex != std::string::npos) { host = unescape(hostAndPort.substr(0, colonIndex)); try { - port = boost::lexical_cast<int>(hostAndPort.substr(colonIndex + 1)); + port = boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(hostAndPort.substr(colonIndex + 1))); } catch (const boost::bad_lexical_cast&) { return URL(); @@ -132,7 +132,7 @@ std::string URL::toString() const { } if (port) { result += ":"; - result += boost::lexical_cast<std::string>(*port); + result += std::to_string(*port); } result += path; return result; diff --git a/Swiften/Base/URL.h b/Swiften/Base/URL.h index 1a03efe..8fdb018 100644 --- a/Swiften/Base/URL.h +++ b/Swiften/Base/URL.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -21,7 +21,7 @@ class SWIFTEN_API URL { URL() : scheme(""), user(""), password(""), host(""), path(""), empty(true) { } - URL(const std::string& scheme, const std::string& host, int port, const std::string& path) : scheme(scheme), user(), password(), host(host), port(port), path(path), empty(false) { + URL(const std::string& scheme, const std::string& host, unsigned short port, const std::string& path) : scheme(scheme), user(), password(), host(host), port(port), path(path), empty(false) { } URL(const std::string& scheme, const std::string& host, const std::string& path) : scheme(scheme), user(), password(), host(host), path(path), empty(false) { @@ -51,7 +51,7 @@ class SWIFTEN_API URL { /** * Port number */ - boost::optional<int> getPort() const { + boost::optional<unsigned short> getPort() const { return port; } @@ -64,7 +64,7 @@ class SWIFTEN_API URL { std::string toString() const; - static int getPortOrDefaultPort(const URL& url); + static unsigned short getPortOrDefaultPort(const URL& url); static URL fromString(const std::string&); static std::string unescape(const std::string&); @@ -74,7 +74,7 @@ class SWIFTEN_API URL { std::string user; std::string password; std::string host; - boost::optional<int> port; + boost::optional<unsigned short> port; std::string path; bool empty; }; diff --git a/Swiften/Base/UnitTest/LogTest.cpp b/Swiften/Base/UnitTest/LogTest.cpp new file mode 100644 index 0000000..5d710db --- /dev/null +++ b/Swiften/Base/UnitTest/LogTest.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <vector> + +#include <boost/algorithm/string/predicate.hpp> + +#include <gtest/gtest.h> + +#include <Swiften/Base/Log.h> + +using namespace Swift; + +struct LogEntry { + LogEntry(Log::Severity severity, std::string file, int line, std::string function, std::string message) : severity(severity), file(std::move(file)), line(line), function(std::move(function)), message(std::move(message)) {} + + Log::Severity severity; + std::string file; + int line; + std::string function; + std::string message; +}; + +// Helper class to set the logging callback. Using this class to set it will ensure the +// logCallback is reset to empty (its default state) after each test. +class LogCallbackSetter { +public: + LogCallbackSetter(Log::Callback callback) { + Log::setLogCallback(callback); + } + ~LogCallbackSetter() { + Log::setLogCallback({}); + } +}; + +TEST(LogTest, testCallback) { + std::vector<LogEntry> logEntries; + LogCallbackSetter callbackSetter = {[&](Log::Severity severity, const std::string& file, int line, const std::string& function, const std::string& message) { + logEntries.emplace_back(severity, file, line, function, message); + }}; + + SWIFT_LOG(error) << "An error"; + ASSERT_EQ(1, logEntries.size()); + ASSERT_EQ(Log::error, logEntries[0].severity); + ASSERT_EQ("An error", logEntries[0].message); +} diff --git a/Swiften/Base/UnitTest/URLTest.cpp b/Swiften/Base/UnitTest/URLTest.cpp index c38398a..da9f15c 100644 --- a/Swiften/Base/UnitTest/URLTest.cpp +++ b/Swiften/Base/UnitTest/URLTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -66,7 +66,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(1234, *url.getPort()); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(1234), *url.getPort()); CPPUNIT_ASSERT_EQUAL(std::string("/baz/bam"), url.getPath()); } @@ -75,7 +75,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(11440, *url.getPort()); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(11440), *url.getPort()); CPPUNIT_ASSERT_EQUAL(std::string("/http-bind/"), url.getPath()); } @@ -84,7 +84,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(1234, *url.getPort()); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(1234), *url.getPort()); CPPUNIT_ASSERT_EQUAL(std::string(""), url.getPath()); } @@ -121,7 +121,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("127.0.0.1"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(12345, url.getPort().get_value_or(0)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(12345), url.getPort().get_value_or(0)); CPPUNIT_ASSERT_EQUAL(std::string("/foobar"), url.getPath()); } @@ -137,7 +137,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("fdf8:f53b:82e4::53"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(12435, url.getPort().get_value_or(0)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(12435), url.getPort().get_value_or(0)); } void test_FromString_ToString_IPv6RFC2732() { @@ -147,7 +147,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(80, url.getPort().get_value_or(2)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(80), url.getPort().get_value_or(2)); CPPUNIT_ASSERT_EQUAL(std::string("/index.html"), url.getPath()); CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString()); @@ -159,7 +159,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("1080:0:0:0:8:800:200C:417A"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(2), url.getPort().get_value_or(2)); CPPUNIT_ASSERT_EQUAL(std::string("/index.html"), url.getPath()); CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString()); @@ -171,7 +171,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("3ffe:2a00:100:7031::1"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(2), url.getPort().get_value_or(2)); CPPUNIT_ASSERT_EQUAL(std::string(""), url.getPath()); CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString()); @@ -183,7 +183,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("1080::8:800:200C:417A"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(2), url.getPort().get_value_or(2)); CPPUNIT_ASSERT_EQUAL(std::string("/foo"), url.getPath()); CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString()); @@ -195,7 +195,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("::192.9.5.5"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(2), url.getPort().get_value_or(2)); CPPUNIT_ASSERT_EQUAL(std::string("/ipng"), url.getPath()); CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString()); @@ -207,7 +207,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("::FFFF:129.144.52.38"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(80, url.getPort().get_value_or(2)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(80), url.getPort().get_value_or(2)); CPPUNIT_ASSERT_EQUAL(std::string("/index.html"), url.getPath()); CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString()); @@ -219,7 +219,7 @@ class URLTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); CPPUNIT_ASSERT_EQUAL(std::string("2010:836B:4179::836B:4179"), url.getHost()); - CPPUNIT_ASSERT_EQUAL(2, url.getPort().get_value_or(2)); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(2), url.getPort().get_value_or(2)); CPPUNIT_ASSERT_EQUAL(std::string(), url.getPath()); CPPUNIT_ASSERT_EQUAL(std::string(testVector), url.toString()); diff --git a/Swiften/ChangeLog.md b/Swiften/ChangeLog.md index d823954..60355b4 100644 --- a/Swiften/ChangeLog.md +++ b/Swiften/ChangeLog.md @@ -1,3 +1,28 @@ +5-in-progress +------------- +- Update build system from scons 2.4.0 to 3.0.1 + +4.0.1 (2018-03-28) +------------------ +- Fix handling errors when fetching own vCard + +4.0 (2018-03-20) +---------------- +- Moved code-base to C++11 + - Use C++11 threading instead of Boost.Thread library + - Use C++11 smart pointers instead of Boost's +- Migrated from Boost.Signals to Boost.Signals2 +- Build without warnings on our CI platforms +- General cleanup like remove of superflous files and #include statements. This means header files that previously were included implictly need to be explicitly included now +- Support IPv6 addresses in URLs +- Handle sessions being closed by the server +- Verify certificates when using HTTPS in BOSH connections +- In memory caching of latest entity capabilites lookups +- Changed source code style to use soft tabs (4 spaces wide) instead of hard tabs. Custom patches for Swiften will need to be reformatted accordingly +- Require a TLS backend for building +- Update 3rdParty/lcov to version 1.12 +- Fix several possible race conditions, smaller leaks, and other small bugs + 4.0-rc1 ( 2017-05-17 ) ---------------------- - Handle sessions being closed by the server diff --git a/Swiften/Chat/ChatStateTracker.cpp b/Swiften/Chat/ChatStateTracker.cpp index 25ecd1c..839f47d 100644 --- a/Swiften/Chat/ChatStateTracker.cpp +++ b/Swiften/Chat/ChatStateTracker.cpp @@ -17,7 +17,7 @@ void ChatStateTracker::handleMessageReceived(std::shared_ptr<Message> message) { } std::shared_ptr<ChatState> statePayload = message->getPayload<ChatState>(); if (statePayload) { - changeState(statePayload->getChatState());; + changeState(statePayload->getChatState()); } } diff --git a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp index efd37d9..b6c909a 100644 --- a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp +++ b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -13,6 +13,9 @@ #include <Swiften/Disco/DummyEntityCapsProvider.h> #include <Swiften/Network/DummyTimerFactory.h> +// Clang wrongly things that tests for 0 are using 0 as null. +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" + using namespace Swift; class ChatStateNotifierTest : public ::testing::Test { diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index 661a832..1114336 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -88,7 +88,7 @@ ClientSession::ClientSession( authenticationPort(-1) { #ifdef SWIFTEN_PLATFORM_WIN32 if (WindowsRegistry::isFIPSEnabled()) { - SWIFT_LOG(info) << "Windows is running in FIPS-140 mode. Some authentication methods will be unavailable." << std::endl; + SWIFT_LOG(info) << "Windows is running in FIPS-140 mode. Some authentication methods will be unavailable."; } #endif } @@ -122,7 +122,7 @@ void ClientSession::sendStanza(std::shared_ptr<Stanza> stanza) { } void ClientSession::handleStreamStart(const ProtocolHeader&) { - CHECK_STATE_OR_RETURN(State::WaitingForStreamStart); + CHECK_STATE_OR_RETURN(State::WaitingForStreamStart) state = State::Negotiating; } @@ -214,7 +214,7 @@ void ClientSession::handleElement(std::shared_ptr<ToplevelElement> element) { } } else if (StreamFeatures* streamFeatures = dynamic_cast<StreamFeatures*>(element.get())) { - CHECK_STATE_OR_RETURN(State::Negotiating); + CHECK_STATE_OR_RETURN(State::Negotiating) if (streamFeatures->hasStartTLS() && stream->supportsTLSEncryption() && useTLS != NeverUseTLS) { state = State::WaitingForEncrypt; @@ -231,13 +231,13 @@ void ClientSession::handleElement(std::shared_ptr<ToplevelElement> element) { #ifdef SWIFTEN_PLATFORM_WIN32 if (singleSignOn) { const boost::optional<std::string> authenticationHostname = streamFeatures->getAuthenticationHostname(); - bool gssapiSupported = streamFeatures->hasAuthenticationMechanism("GSSAPI") && authenticationHostname && !authenticationHostname->empty(); + bool gssapiSupported = streamFeatures->hasAuthenticationMechanism("GSSAPI"); if (!gssapiSupported) { finishSession(Error::NoSupportedAuthMechanismsError); } else { - WindowsGSSAPIClientAuthenticator* gssapiAuthenticator = new WindowsGSSAPIClientAuthenticator(*authenticationHostname, localJID.getDomain(), authenticationPort); + WindowsGSSAPIClientAuthenticator* gssapiAuthenticator = new WindowsGSSAPIClientAuthenticator(authenticationHostname.value_or(""), localJID.getDomain(), authenticationPort); std::shared_ptr<Error> error = std::make_shared<Error>(Error::AuthenticationFailedError); authenticator = gssapiAuthenticator; @@ -320,7 +320,7 @@ void ClientSession::handleElement(std::shared_ptr<ToplevelElement> element) { } } else if (std::dynamic_pointer_cast<Compressed>(element)) { - CHECK_STATE_OR_RETURN(State::Compressing); + CHECK_STATE_OR_RETURN(State::Compressing) state = State::WaitingForStreamStart; stream->addZLibCompression(); stream->resetXMPPParser(); @@ -343,7 +343,7 @@ void ClientSession::handleElement(std::shared_ptr<ToplevelElement> element) { continueSessionInitialization(); } else if (AuthChallenge* challenge = dynamic_cast<AuthChallenge*>(element.get())) { - CHECK_STATE_OR_RETURN(State::Authenticating); + CHECK_STATE_OR_RETURN(State::Authenticating) assert(authenticator); if (authenticator->setChallenge(challenge->getValue())) { stream->writeElement(std::make_shared<AuthResponse>(authenticator->getResponse())); @@ -361,7 +361,7 @@ void ClientSession::handleElement(std::shared_ptr<ToplevelElement> element) { } } else if (AuthSuccess* authSuccess = dynamic_cast<AuthSuccess*>(element.get())) { - CHECK_STATE_OR_RETURN(State::Authenticating); + CHECK_STATE_OR_RETURN(State::Authenticating) assert(authenticator); if (!authenticator->setChallenge(authSuccess->getValue())) { finishSession(Error::ServerVerificationFailedError); @@ -378,7 +378,7 @@ void ClientSession::handleElement(std::shared_ptr<ToplevelElement> element) { finishSession(Error::AuthenticationFailedError); } else if (dynamic_cast<TLSProceed*>(element.get())) { - CHECK_STATE_OR_RETURN(State::WaitingForEncrypt); + CHECK_STATE_OR_RETURN(State::WaitingForEncrypt) state = State::Encrypting; stream->addTLSEncryption(); } @@ -433,7 +433,7 @@ void ClientSession::sendCredentials(const SafeByteArray& password) { void ClientSession::handleTLSEncrypted() { if (!std::dynamic_pointer_cast<BOSHSessionStream>(stream)) { - CHECK_STATE_OR_RETURN(State::Encrypting); + CHECK_STATE_OR_RETURN(State::Encrypting) } std::vector<Certificate::ref> certificateChain = stream->getPeerCertificateChain(); @@ -531,7 +531,7 @@ void ClientSession::finish() { finishSession(std::shared_ptr<Error>()); } else { - SWIFT_LOG(warning) << "Session already finished or finishing." << std::endl; + SWIFT_LOG(warning) << "Session already finished or finishing."; } } @@ -544,7 +544,7 @@ void ClientSession::finishSession(std::shared_ptr<Swift::Error> error) { error_ = error; } else { - SWIFT_LOG(warning) << "Session finished twice" << std::endl; + SWIFT_LOG(warning) << "Session finished twice"; } assert(stream->isOpen()); if (stanzaAckResponder_) { diff --git a/Swiften/Client/ClientSessionStanzaChannel.cpp b/Swiften/Client/ClientSessionStanzaChannel.cpp index f48b306..6a5d07d 100644 --- a/Swiften/Client/ClientSessionStanzaChannel.cpp +++ b/Swiften/Client/ClientSessionStanzaChannel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -49,7 +49,7 @@ std::string ClientSessionStanzaChannel::getNewIQID() { void ClientSessionStanzaChannel::send(std::shared_ptr<Stanza> stanza) { if (!isAvailable()) { - SWIFT_LOG(warning) << "Client: Trying to send a stanza while disconnected." << std::endl; + SWIFT_LOG(warning) << "Client: Trying to send a stanza while disconnected."; return; } session->sendStanza(stanza); diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index 1de1d61..7579bca 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -69,33 +69,53 @@ void CoreClient::connect(const ClientOptions& o) { HostAddressPort systemHTTPConnectProxy = networkFactories->getProxyProvider()->getHTTPConnectProxy(); switch (o.proxyType) { case ClientOptions::NoProxy: - SWIFT_LOG(debug) << " without a proxy" << std::endl; + SWIFT_LOG(debug) << " without a proxy"; break; case ClientOptions::SystemConfiguredProxy: - SWIFT_LOG(debug) << " with a system configured proxy" << std::endl; + SWIFT_LOG(debug) << " with a system configured proxy"; if (systemSOCKS5Proxy.isValid()) { - SWIFT_LOG(debug) << "Found SOCK5 Proxy: " << systemSOCKS5Proxy.getAddress().toString() << ":" << systemSOCKS5Proxy.getPort() << std::endl; + SWIFT_LOG(debug) << "Found SOCK5 Proxy: " << systemSOCKS5Proxy.getAddress().toString() << ":" << systemSOCKS5Proxy.getPort(); proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), systemSOCKS5Proxy.getAddress().toString(), systemSOCKS5Proxy.getPort())); } if (systemHTTPConnectProxy.isValid()) { - SWIFT_LOG(debug) << "Found HTTPConnect Proxy: " << systemHTTPConnectProxy.getAddress().toString() << ":" << systemHTTPConnectProxy.getPort() << std::endl; + SWIFT_LOG(debug) << "Found HTTPConnect Proxy: " << systemHTTPConnectProxy.getAddress().toString() << ":" << systemHTTPConnectProxy.getPort(); proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), systemHTTPConnectProxy.getAddress().toString(), systemHTTPConnectProxy.getPort())); } break; case ClientOptions::SOCKS5Proxy: { - SWIFT_LOG(debug) << " with manual configured SOCKS5 proxy" << std::endl; + SWIFT_LOG(debug) << " with manual configured SOCKS5 proxy"; std::string proxyHostname = o.manualProxyHostname.empty() ? systemSOCKS5Proxy.getAddress().toString() : o.manualProxyHostname; - int proxyPort = o.manualProxyPort == -1 ? systemSOCKS5Proxy.getPort() : o.manualProxyPort; - SWIFT_LOG(debug) << "Proxy: " << proxyHostname << ":" << proxyPort << std::endl; + auto proxyPort = systemSOCKS5Proxy.getPort(); + if (o.manualProxyPort != -1) { + try { + proxyPort = boost::numeric_cast<unsigned short>(o.manualProxyPort); + } + catch (const boost::numeric::bad_numeric_cast& e) { + SWIFT_LOG(warning) << "Manual proxy port " << o.manualProxyPort << " is invalid: " << e.what(); + onDisconnected(boost::optional<ClientError>(ClientError::ConnectionError)); + return; + } + } + SWIFT_LOG(debug) << "Proxy: " << proxyHostname << ":" << proxyPort; proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), proxyHostname, proxyPort)); useDirectConnection = false; break; } case ClientOptions::HTTPConnectProxy: { - SWIFT_LOG(debug) << " with manual configured HTTPConnect proxy" << std::endl; + SWIFT_LOG(debug) << " with manual configured HTTPConnect proxy"; std::string proxyHostname = o.manualProxyHostname.empty() ? systemHTTPConnectProxy.getAddress().toString() : o.manualProxyHostname; - int proxyPort = o.manualProxyPort == -1 ? systemHTTPConnectProxy.getPort() : o.manualProxyPort; - SWIFT_LOG(debug) << "Proxy: " << proxyHostname << ":" << proxyPort << std::endl; + unsigned short proxyPort = systemHTTPConnectProxy.getPort(); + if (o.manualProxyPort != -1) { + try { + proxyPort = boost::numeric_cast<unsigned short>(o.manualProxyPort); + } + catch (const boost::numeric::bad_numeric_cast& e) { + SWIFT_LOG(warning) << "Manual proxy port " << o.manualProxyPort << " is invalid: " << e.what(); + onDisconnected(boost::optional<ClientError>(ClientError::ConnectionError)); + return; + } + } + SWIFT_LOG(debug) << "Proxy: " << proxyHostname << ":" << proxyPort; proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), proxyHostname, proxyPort, o.httpTrafficFilter)); useDirectConnection = false; break; @@ -108,7 +128,17 @@ void CoreClient::connect(const ClientOptions& o) { // Create connector std::string host = o.manualHostname.empty() ? jid_.getDomain() : o.manualHostname; - int port = o.manualPort; + unsigned short port = 0; + if (o.manualPort != -1) { + try { + port = boost::numeric_cast<unsigned short>(o.manualPort); + } + catch (const boost::numeric::bad_numeric_cast& e) { + SWIFT_LOG(warning) << "Invalid manual port " << o.manualPort << ": " << e.what(); + onDisconnected(boost::optional<ClientError>(ClientError::ConnectionError)); + return; + } + } boost::optional<std::string> serviceLookupPrefix; if (o.manualHostname.empty()) { serviceLookupPrefix = "_xmpp-client._tcp."; @@ -144,7 +174,7 @@ void CoreClient::connect(const ClientOptions& o) { sessionStream_->onDataRead.connect(boost::bind(&CoreClient::handleDataRead, this, _1)); sessionStream_->onDataWritten.connect(boost::bind(&CoreClient::handleDataWritten, this, _1)); if (certificate_ && !certificate_->isNull()) { - SWIFT_LOG(debug) << "set certificate" << std::endl; + SWIFT_LOG(debug) << "set certificate"; sessionStream_->setTLSCertificate(certificate_); } boshSessionStream_->open(); @@ -286,6 +316,8 @@ void CoreClient::handleSessionFinished(std::shared_ptr<Error> error) { clientError = ClientError(ClientError::CertificateCardRemoved); break; case TLSError::UnknownError: + case TLSError::AcceptFailed: + case TLSError::ConnectFailed: clientError = ClientError(ClientError::TLSError); break; } @@ -391,7 +423,7 @@ void CoreClient::sendPresence(std::shared_ptr<Presence> presence) { void CoreClient::sendData(const std::string& data) { if (!sessionStream_) { - SWIFT_LOG(warning) << "Client: Trying to send data while disconnected." << std::endl; + SWIFT_LOG(warning) << "Client: Trying to send data while disconnected."; return; } sessionStream_->writeData(data); @@ -475,11 +507,11 @@ void CoreClient::resetSession() { void CoreClient::forceReset() { if (connector_) { - SWIFT_LOG(warning) << "Client not disconnected properly: Connector still active" << std::endl; + SWIFT_LOG(warning) << "Client not disconnected properly: Connector still active"; resetConnector(); } if (sessionStream_ || connection_) { - SWIFT_LOG(warning) << "Client not disconnected properly: Session still active" << std::endl; + SWIFT_LOG(warning) << "Client not disconnected properly: Session still active"; resetSession(); } } diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h index 4cc0f7e..1ba70ad 100644 --- a/Swiften/Client/DummyStanzaChannel.h +++ b/Swiften/Client/DummyStanzaChannel.h @@ -48,8 +48,12 @@ namespace Swift { return available_; } + virtual void setStreamManagementEnabled(bool enable) { + streamManagement_ = enable; + } + virtual bool getStreamManagementEnabled() const { - return false; + return streamManagement_; } template<typename T> bool isRequestAtIndex(size_t index, const JID& jid, IQ::Type type) { @@ -101,5 +105,6 @@ namespace Swift { bool available_ = true; bool uniqueIDs_ = false; unsigned int idCounter_ = 0; + bool streamManagement_ = false; }; } diff --git a/Swiften/Client/UnitTest/XMLBeautifierTest.cpp b/Swiften/Client/UnitTest/XMLBeautifierTest.cpp index 2eac086..2a639ea 100644 --- a/Swiften/Client/UnitTest/XMLBeautifierTest.cpp +++ b/Swiften/Client/UnitTest/XMLBeautifierTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,6 +8,9 @@ #include <Swiften/Client/XMLBeautifier.h> #include <iostream> +// Clang wrongly things that tests for 0 are using 0 as null. +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" + using namespace Swift; namespace { diff --git a/Swiften/Component/ComponentConnector.cpp b/Swiften/Component/ComponentConnector.cpp index a7375a7..7789c4c 100644 --- a/Swiften/Component/ComponentConnector.cpp +++ b/Swiften/Component/ComponentConnector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -15,7 +15,7 @@ namespace Swift { -ComponentConnector::ComponentConnector(const std::string& hostname, int port, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), port(port), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0) { +ComponentConnector::ComponentConnector(const std::string& hostname, unsigned short port, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), port(port), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0) { } void ComponentConnector::setTimeoutMilliseconds(int milliseconds) { diff --git a/Swiften/Component/ComponentConnector.h b/Swiften/Component/ComponentConnector.h index ab36901..cfd49fe 100644 --- a/Swiften/Component/ComponentConnector.h +++ b/Swiften/Component/ComponentConnector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -28,7 +28,7 @@ namespace Swift { public: typedef std::shared_ptr<ComponentConnector> ref; - static ComponentConnector::ref create(const std::string& hostname, int port, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { + static ComponentConnector::ref create(const std::string& hostname, unsigned short port, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { return ref(new ComponentConnector(hostname, port, resolver, connectionFactory, timerFactory)); } @@ -40,7 +40,7 @@ namespace Swift { boost::signals2::signal<void (std::shared_ptr<Connection>)> onConnectFinished; private: - ComponentConnector(const std::string& hostname, int port, DomainNameResolver*, ConnectionFactory*, TimerFactory*); + ComponentConnector(const std::string& hostname, unsigned short port, DomainNameResolver*, ConnectionFactory*, TimerFactory*); void handleAddressQueryResult(const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> error); void tryNextAddress(); @@ -53,7 +53,7 @@ namespace Swift { private: std::string hostname; - int port; + unsigned short port; DomainNameResolver* resolver; ConnectionFactory* connectionFactory; TimerFactory* timerFactory; diff --git a/Swiften/Component/ComponentSessionStanzaChannel.cpp b/Swiften/Component/ComponentSessionStanzaChannel.cpp index e4bf231..deac8b2 100644 --- a/Swiften/Component/ComponentSessionStanzaChannel.cpp +++ b/Swiften/Component/ComponentSessionStanzaChannel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -47,7 +47,7 @@ std::string ComponentSessionStanzaChannel::getNewIQID() { void ComponentSessionStanzaChannel::send(std::shared_ptr<Stanza> stanza) { if (!isAvailable()) { - SWIFT_LOG(warning) << "Component: Trying to send a stanza while disconnected." << std::endl; + SWIFT_LOG(warning) << "Component: Trying to send a stanza while disconnected."; return; } session->sendStanza(stanza); diff --git a/Swiften/Component/CoreComponent.cpp b/Swiften/Component/CoreComponent.cpp index 3896bdd..ef7d3a4 100644 --- a/Swiften/Component/CoreComponent.cpp +++ b/Swiften/Component/CoreComponent.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -33,7 +33,7 @@ CoreComponent::CoreComponent(const JID& jid, const std::string& secret, NetworkF CoreComponent::~CoreComponent() { if (session_ || connection_) { - SWIFT_LOG(warning) << "Component not disconnected properly" << std::endl; + SWIFT_LOG(warning) << "Component not disconnected properly"; } delete iqRouter_; @@ -43,7 +43,7 @@ CoreComponent::~CoreComponent() { delete stanzaChannel_; } -void CoreComponent::connect(const std::string& host, int port) { +void CoreComponent::connect(const std::string& host, unsigned short port) { assert(!connector_); connector_ = ComponentConnector::create(host, port, networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory()); connector_->onConnectFinished.connect(boost::bind(&CoreComponent::handleConnectorFinished, this, _1)); @@ -166,4 +166,12 @@ void CoreComponent::sendData(const std::string& data) { sessionStream_->writeData(data); } +bool CoreComponent::isActive() const { + return session_ || connector_; +} + +bool CoreComponent::isAvailable() const { + return stanzaChannel_->isAvailable(); +} + } diff --git a/Swiften/Component/CoreComponent.h b/Swiften/Component/CoreComponent.h index f673643..7565d00 100644 --- a/Swiften/Component/CoreComponent.h +++ b/Swiften/Component/CoreComponent.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -46,7 +46,7 @@ namespace Swift { CoreComponent(const JID& jid, const std::string& secret, NetworkFactories* networkFactories); virtual ~CoreComponent(); - void connect(const std::string& host, int port); + void connect(const std::string& host, unsigned short port); void disconnect(); void sendMessage(std::shared_ptr<Message>); @@ -61,9 +61,18 @@ namespace Swift { return stanzaChannel_; } - bool isAvailable() const { - return stanzaChannel_->isAvailable(); - } + /** + * Checks whether the component is connected to the server, + * and stanzas can be sent. + */ + bool isAvailable() const; + + /** + * Checks whether the component is active. + * + * A component is active when it is connected or connecting to the server. + */ + bool isActive() const; /** * Returns the JID of the component diff --git a/Swiften/Component/UnitTest/ComponentConnectorTest.cpp b/Swiften/Component/UnitTest/ComponentConnectorTest.cpp index 3b4fa83..bd26989 100644 --- a/Swiften/Component/UnitTest/ComponentConnectorTest.cpp +++ b/Swiften/Component/UnitTest/ComponentConnectorTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -146,7 +146,7 @@ class ComponentConnectorTest : public CppUnit::TestFixture { } private: - ComponentConnector::ref createConnector(const std::string& hostname, int port) { + ComponentConnector::ref createConnector(const std::string& hostname, unsigned short port) { ComponentConnector::ref connector = ComponentConnector::create(hostname, port, resolver, connectionFactory, timerFactory); connector->onConnectFinished.connect(boost::bind(&ComponentConnectorTest::handleConnectorFinished, this, _1)); return connector; diff --git a/Swiften/Config/SConscript b/Swiften/Config/SConscript index dd06d61..ae0d37a 100644 --- a/Swiften/Config/SConscript +++ b/Swiften/Config/SConscript @@ -10,7 +10,7 @@ def cStringVariable(env, cVar, sconsVar) : # FIXME: Probably not very robust for var in sconsVar.split(" ") : result += "\t\"" + env.subst(var).replace("\\", "\\\\") + "\",\n" - result += "\t0\n" + result += "\tnullptr\n" result += "};\n" return result @@ -22,15 +22,15 @@ swiften_env.UseFlags(swiften_env["SWIFTEN_DEP_FLAGS"]) cppflags = replaceSwiftenPath(" ".join([ swiften_env.subst("$CPPFLAGS").replace("-isystem ","-I"), - swiften_env.subst("$_CPPDEFFLAGS"), + swiften_env.subst("$_CPPDEFFLAGS"), swiften_env.subst("$_CPPINCFLAGS")])) config_flags += cStringVariable(swiften_env, "CPPFLAGS", cppflags) libflags = replaceSwiftenPath(" ".join([ - swiften_env.subst("$_LIBDIRFLAGS"), - swiften_env.subst("$_LIBFLAGS"), - swiften_env.subst("$_FRAMEWORKPATH"), - swiften_env.subst("$_FRAMEWORKS"), + swiften_env.subst("$_LIBDIRFLAGS"), + swiften_env.subst("$_LIBFLAGS"), + swiften_env.subst("$_FRAMEWORKPATH"), + swiften_env.subst("$_FRAMEWORKS"), swiften_env.subst("$_FRAMEWORKSFLAGS") ])) config_flags += cStringVariable(swiften_env, "LIBFLAGS", libflags) diff --git a/Swiften/Crypto/CommonCryptoCryptoProvider.cpp b/Swiften/Crypto/CommonCryptoCryptoProvider.cpp index d4257e0..3cc69b0 100644 --- a/Swiften/Crypto/CommonCryptoCryptoProvider.cpp +++ b/Swiften/Crypto/CommonCryptoCryptoProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 Isode Limited. + * Copyright (c) 2013-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -49,7 +49,12 @@ namespace { template<typename ContainerType> Hash& updateInternal(const ContainerType& data) { assert(!finalized); - if (!CC_SHA1_Update(&context, vecptr(data), boost::numeric_cast<CC_LONG>(data.size()))) { + try { + if (!CC_SHA1_Update(&context, vecptr(data), boost::numeric_cast<CC_LONG>(data.size()))) { + assert(false); + } + } + catch (const boost::numeric::bad_numeric_cast&) { assert(false); } return *this; @@ -90,7 +95,12 @@ namespace { template<typename ContainerType> Hash& updateInternal(const ContainerType& data) { assert(!finalized); - if (!CC_MD5_Update(&context, vecptr(data), boost::numeric_cast<CC_LONG>(data.size()))) { + try { + if (!CC_MD5_Update(&context, vecptr(data), boost::numeric_cast<CC_LONG>(data.size()))) { + assert(false); + } + } + catch (const boost::numeric::bad_numeric_cast&) { assert(false); } return *this; @@ -104,7 +114,12 @@ namespace { template<typename T> ByteArray getHMACSHA1Internal(const T& key, const ByteArray& data) { std::vector<unsigned char> result(CC_SHA1_DIGEST_LENGTH); - CCHmac(kCCHmacAlgSHA1, vecptr(key), key.size(), vecptr(data), boost::numeric_cast<CC_LONG>(data.size()), vecptr(result)); + try { + CCHmac(kCCHmacAlgSHA1, vecptr(key), key.size(), vecptr(data), boost::numeric_cast<CC_LONG>(data.size()), vecptr(result)); + } + catch (const boost::numeric::bad_numeric_cast&) { + assert(false); + } return result; } } diff --git a/Swiften/Crypto/OpenSSLCryptoProvider.cpp b/Swiften/Crypto/OpenSSLCryptoProvider.cpp index b46cb2a..5245bd8 100644 --- a/Swiften/Crypto/OpenSSLCryptoProvider.cpp +++ b/Swiften/Crypto/OpenSSLCryptoProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 Isode Limited. + * Copyright (c) 2013-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -28,7 +28,7 @@ namespace { } } - ~SHA1Hash() { + ~SHA1Hash() override { } virtual Hash& update(const ByteArray& data) override { @@ -69,7 +69,7 @@ namespace { } } - ~MD5Hash() { + ~MD5Hash() override { } virtual Hash& update(const ByteArray& data) override { @@ -107,7 +107,12 @@ namespace { ByteArray getHMACSHA1Internal(const T& key, const ByteArray& data) { unsigned int len = SHA_DIGEST_LENGTH; std::vector<unsigned char> result(len); - HMAC(EVP_sha1(), vecptr(key), boost::numeric_cast<int>(key.size()), vecptr(data), data.size(), vecptr(result), &len); + try { + HMAC(EVP_sha1(), vecptr(key), boost::numeric_cast<int>(key.size()), vecptr(data), data.size(), vecptr(result), &len); + } + catch (const boost::numeric::bad_numeric_cast&) { + assert(false); + } return result; } } diff --git a/Swiften/Disco/CapsManager.cpp b/Swiften/Disco/CapsManager.cpp index 794cf74..2b8fb7d 100644 --- a/Swiften/Disco/CapsManager.cpp +++ b/Swiften/Disco/CapsManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -53,7 +53,7 @@ void CapsManager::handleDiscoInfoReceived(const JID& from, const std::string& ha requestedDiscoInfos.erase(hash); if (error || !discoInfo || CapsInfoGenerator("", crypto).generateCapsInfo(*discoInfo.get()).getVersion() != hash) { if (warnOnInvalidHash && !error && discoInfo) { - SWIFT_LOG(warning) << "Caps from " << from.toString() << " do not verify" << std::endl; + SWIFT_LOG(warning) << "Caps from " << from.toString() << " do not verify"; } failingCaps.insert(std::make_pair(from, hash)); std::map<std::string, std::set< std::pair<JID, std::string> > >::iterator i = fallbacks.find(hash); diff --git a/Swiften/Disco/DiscoServiceWalker.cpp b/Swiften/Disco/DiscoServiceWalker.cpp index a3f95d2..7332e63 100644 --- a/Swiften/Disco/DiscoServiceWalker.cpp +++ b/Swiften/Disco/DiscoServiceWalker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -17,7 +17,7 @@ DiscoServiceWalker::DiscoServiceWalker(const JID& service, IQRouter* iqRouter, s } void DiscoServiceWalker::beginWalk() { - SWIFT_LOG(debug) << "Starting walk to " << service_ << std::endl; + SWIFT_LOG(debug) << "Starting walk to " << service_; assert(!active_); assert(servicesBeingSearched_.empty()); active_ = true; @@ -26,7 +26,7 @@ void DiscoServiceWalker::beginWalk() { void DiscoServiceWalker::endWalk() { if (active_) { - SWIFT_LOG(debug) << "Ending walk to " << service_ << std::endl; + SWIFT_LOG(debug) << "Ending walk to " << service_; for (auto&& request : pendingDiscoInfoRequests_) { request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, request)); } @@ -39,7 +39,7 @@ void DiscoServiceWalker::endWalk() { } void DiscoServiceWalker::walkNode(const JID& jid) { - SWIFT_LOG(debug) << "Walking node " << jid << std::endl; + SWIFT_LOG(debug) << "Walking node " << jid; servicesBeingSearched_.insert(jid); searchedServices_.insert(jid); GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(jid, iqRouter_); @@ -54,7 +54,7 @@ void DiscoServiceWalker::handleDiscoInfoResponse(std::shared_ptr<DiscoInfo> info return; } - SWIFT_LOG(debug) << "Disco info response from " << request->getReceiver() << std::endl; + SWIFT_LOG(debug) << "Disco info response from " << request->getReceiver(); request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, request)); pendingDiscoInfoRequests_.erase(request); @@ -90,7 +90,7 @@ void DiscoServiceWalker::handleDiscoItemsResponse(std::shared_ptr<DiscoItems> it return; } - SWIFT_LOG(debug) << "Received disco items from " << request->getReceiver() << std::endl; + SWIFT_LOG(debug) << "Received disco items from " << request->getReceiver(); request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoItemsResponse, this, _1, _2, request)); pendingDiscoItemsRequests_.erase(request); if (error) { @@ -103,7 +103,7 @@ void DiscoServiceWalker::handleDiscoItemsResponse(std::shared_ptr<DiscoItems> it * but I've never seen one in the wild, and it's an easy fix for not looping. */ if (std::find(searchedServices_.begin(), searchedServices_.end(), item.getJID()) == searchedServices_.end()) { /* Don't recurse infinitely */ - SWIFT_LOG(debug) << "Received disco item " << item.getJID() << std::endl; + SWIFT_LOG(debug) << "Received disco item " << item.getJID(); walkNode(item.getJID()); } } @@ -112,12 +112,12 @@ void DiscoServiceWalker::handleDiscoItemsResponse(std::shared_ptr<DiscoItems> it } void DiscoServiceWalker::handleDiscoError(const JID& jid, ErrorPayload::ref /*error*/) { - SWIFT_LOG(debug) << "Disco error from " << jid << std::endl; + SWIFT_LOG(debug) << "Disco error from " << jid; markNodeCompleted(jid); } void DiscoServiceWalker::markNodeCompleted(const JID& jid) { - SWIFT_LOG(debug) << "Node completed " << jid << std::endl; + SWIFT_LOG(debug) << "Node completed " << jid; servicesBeingSearched_.erase(jid); /* All results are in */ if (servicesBeingSearched_.empty()) { diff --git a/Swiften/Elements/Bytestreams.h b/Swiften/Elements/Bytestreams.h index ca30922..599ed46 100644 --- a/Swiften/Elements/Bytestreams.h +++ b/Swiften/Elements/Bytestreams.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -22,11 +22,11 @@ namespace Swift { typedef std::shared_ptr<Bytestreams> ref; struct StreamHost { - StreamHost(const std::string& host = "", const JID& jid = JID(), int port = -1) : host(host), jid(jid), port(port) {} + StreamHost(const std::string& host = "", const JID& jid = JID(), unsigned short port = 0) : host(host), jid(jid), port(port) {} std::string host; JID jid; - int port; + unsigned short port; }; Bytestreams() {} diff --git a/Swiften/Elements/DiscoInfo.cpp b/Swiften/Elements/DiscoInfo.cpp index 11f0623..701ed40 100644 --- a/Swiften/Elements/DiscoInfo.cpp +++ b/Swiften/Elements/DiscoInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -26,6 +26,7 @@ const std::string DiscoInfo::MessageDeliveryReceiptsFeature = std::string("urn:x const std::string DiscoInfo::WhiteboardFeature = std::string("http://swift.im/whiteboard"); const std::string DiscoInfo::BlockingCommandFeature = std::string("urn:xmpp:blocking"); const std::string DiscoInfo::MessageCarbonsFeature = std::string("urn:xmpp:carbons:2"); +const std::string DiscoInfo::ReferencesFeature = std::string("urn:xmpp:references:0"); bool DiscoInfo::Identity::operator<(const Identity& other) const { if (category_ == other.category_) { diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h index c8009ee..713eaba 100644 --- a/Swiften/Elements/DiscoInfo.h +++ b/Swiften/Elements/DiscoInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -37,6 +37,7 @@ namespace Swift { static const std::string WhiteboardFeature; static const std::string BlockingCommandFeature; static const std::string MessageCarbonsFeature; + static const std::string ReferencesFeature; class Identity { public: diff --git a/Swiften/Elements/Form.h b/Swiften/Elements/Form.h index 899fb93..827e497 100644 --- a/Swiften/Elements/Form.h +++ b/Swiften/Elements/Form.h @@ -89,6 +89,9 @@ namespace Swift { return instructions_; } + /** Returns the Form::Type enum (ie. ResultType, CancelType etc.). + * NOT to be confused with Form::getFormType(). + */ Type getType() const { return type_; } @@ -97,6 +100,9 @@ namespace Swift { type_ = type; } + /** Returns the value of the field FORM_TYPE + * NOT to be confused with Form::getType(). + */ std::string getFormType() const; FormField::ref getField(const std::string& name) const; void addItem(const FormItem& item); diff --git a/Swiften/Elements/IBB.h b/Swiften/Elements/IBB.h index bd0b661..6ebe66e 100644 --- a/Swiften/Elements/IBB.h +++ b/Swiften/Elements/IBB.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -28,10 +28,10 @@ namespace Swift { MessageStanza }; - IBB(Action action = Open, const std::string& streamID = "") : action(action), streamID(streamID), stanzaType(IQStanza), blockSize(-1), sequenceNumber(-1) { + IBB(Action action = Open, const std::string& streamID = "") : action(action), streamID(streamID), stanzaType(IQStanza), blockSize(0), sequenceNumber(-1) { } - static IBB::ref createIBBOpen(const std::string& streamID, int blockSize) { + static IBB::ref createIBBOpen(const std::string& streamID, unsigned int blockSize) { IBB::ref result = std::make_shared<IBB>(Open, streamID); result->setBlockSize(blockSize); return result; @@ -80,11 +80,11 @@ namespace Swift { this->data = data; } - int getBlockSize() const { + unsigned int getBlockSize() const { return blockSize; } - void setBlockSize(int blockSize) { + void setBlockSize(unsigned int blockSize) { this->blockSize = blockSize; } @@ -101,7 +101,7 @@ namespace Swift { std::string streamID; std::vector<unsigned char> data; StanzaType stanzaType; - int blockSize; + unsigned int blockSize; int sequenceNumber; }; } diff --git a/Swiften/Elements/JingleFileTransferFileInfo.h b/Swiften/Elements/JingleFileTransferFileInfo.h index 9fd8756..0e8ccd4 100644 --- a/Swiften/Elements/JingleFileTransferFileInfo.h +++ b/Swiften/Elements/JingleFileTransferFileInfo.h @@ -36,7 +36,7 @@ namespace Swift { public: void setName(const std::string& name) { - name_ = name;; + name_ = name; } const std::string& getName() const { diff --git a/Swiften/Elements/PubSubItem.cpp b/Swiften/Elements/PubSubItem.cpp index 4dc0907..b5f17cc 100644 --- a/Swiften/Elements/PubSubItem.cpp +++ b/Swiften/Elements/PubSubItem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,5 +11,8 @@ using namespace Swift; PubSubItem::PubSubItem() { } +PubSubItem::PubSubItem(const std::string& id) : id_(id) { +} + PubSubItem::~PubSubItem() { } diff --git a/Swiften/Elements/PubSubItem.h b/Swiften/Elements/PubSubItem.h index ba13150..161b733 100644 --- a/Swiften/Elements/PubSubItem.h +++ b/Swiften/Elements/PubSubItem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 Isode Limited. + * Copyright (c) 2013-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -18,32 +18,32 @@ namespace Swift { public: PubSubItem(); + PubSubItem(const std::string& id); virtual ~PubSubItem(); const std::vector< std::shared_ptr<Payload> >& getData() const { - return data; + return data_; } void setData(const std::vector< std::shared_ptr<Payload> >& value) { - this->data = value ; + this->data_ = value ; } void addData(std::shared_ptr<Payload> value) { - this->data.push_back(value); + this->data_.push_back(value); } const std::string& getID() const { - return id; + return id_; } void setID(const std::string& value) { - this->id = value ; + this->id_ = value ; } - private: - std::vector< std::shared_ptr<Payload> > data; - std::string id; + std::vector< std::shared_ptr<Payload> > data_; + std::string id_; }; } diff --git a/Swiften/Elements/PubSubItems.h b/Swiften/Elements/PubSubItems.h index c60adca..c8b7f53 100644 --- a/Swiften/Elements/PubSubItems.h +++ b/Swiften/Elements/PubSubItems.h @@ -61,7 +61,6 @@ namespace Swift { this->subscriptionID = value ; } - private: std::string node; std::vector< std::shared_ptr<PubSubItem> > items; diff --git a/Swiften/Elements/ReferencePayload.cpp b/Swiften/Elements/ReferencePayload.cpp new file mode 100644 index 0000000..288f28f --- /dev/null +++ b/Swiften/Elements/ReferencePayload.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/ReferencePayload.h> + +namespace Swift { + +ReferencePayload::ReferencePayload() + : type_(Type::Data) { +} + +const ReferencePayload::Type& ReferencePayload::getType() const { + return type_; +} + +void ReferencePayload::setType(const ReferencePayload::Type& type) { + type_ = type; +} + +const boost::optional<std::string>& ReferencePayload::getUri() const { + return uri_; +} + +void ReferencePayload::setUri(const boost::optional<std::string>& uri) { + uri_ = uri; +} + +const boost::optional<std::string>& ReferencePayload::getBegin() const { + return begin_; +} + +void ReferencePayload::setBegin(const boost::optional<std::string>& begin) { + begin_ = begin; +} + +const boost::optional<std::string>& ReferencePayload::getEnd() const { + return end_; +} + +void ReferencePayload::setEnd(const boost::optional<std::string>& end) { + end_ = end; +} + +const boost::optional<std::string>& ReferencePayload::getAnchor() const { + return anchor_; +} + +void ReferencePayload::setAnchor(const boost::optional<std::string>& anchor) { + anchor_ = anchor; +} + +const std::vector<std::shared_ptr<Payload>>& ReferencePayload::getPayloads() const { + return payloads_; +} + +void ReferencePayload::addPayload(const std::shared_ptr<Payload>& payload) { + payloads_.push_back(payload); +} + +} diff --git a/Swiften/Elements/ReferencePayload.h b/Swiften/Elements/ReferencePayload.h new file mode 100644 index 0000000..b9a394e --- /dev/null +++ b/Swiften/Elements/ReferencePayload.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <string> +#include <vector> + +#include <boost/optional.hpp> + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + /** + * reference from XEP-0372 + */ + class SWIFTEN_API ReferencePayload : public Payload { + + public: + + typedef std::shared_ptr<ReferencePayload> ref; + + enum class Type { + Data, + Mention, + PubSub, + Unknown + }; + + ReferencePayload(); + + const Type& getType() const; + const boost::optional<std::string>& getUri() const; + const boost::optional<std::string>& getBegin() const; + const boost::optional<std::string>& getEnd() const; + const boost::optional<std::string>& getAnchor() const; + + const std::vector<std::shared_ptr<Payload>>& getPayloads() const; + + void setType(const Type& type); + void setUri(const boost::optional<std::string>& uri); + void setBegin(const boost::optional<std::string>& begin); + void setEnd(const boost::optional<std::string>& end); + void setAnchor(const boost::optional<std::string>& anchor); + + void addPayload(const std::shared_ptr<Payload>& payload); + + private: + + Type type_; + boost::optional<std::string> uri_; + boost::optional<std::string> begin_; + boost::optional<std::string> end_; + boost::optional<std::string> anchor_; + + std::vector<std::shared_ptr<Payload>> payloads_; + }; +} diff --git a/Swiften/Elements/S5BProxyRequest.h b/Swiften/Elements/S5BProxyRequest.h index e3f5206..2fecae4 100644 --- a/Swiften/Elements/S5BProxyRequest.h +++ b/Swiften/Elements/S5BProxyRequest.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -30,7 +30,7 @@ public: public: struct StreamHost { std::string host; - int port; + unsigned short port; JID jid; }; diff --git a/Swiften/Elements/SecurityLabel.h b/Swiften/Elements/SecurityLabel.h index 0f0311e..fcaa610 100644 --- a/Swiften/Elements/SecurityLabel.h +++ b/Swiften/Elements/SecurityLabel.h @@ -15,6 +15,7 @@ namespace Swift { class SWIFTEN_API SecurityLabel : public Payload { public: + using ref = std::shared_ptr<SecurityLabel>; SecurityLabel(); diff --git a/Swiften/Elements/StanzaAck.cpp b/Swiften/Elements/StanzaAck.cpp index bd0b78d..dda97f5 100644 --- a/Swiften/Elements/StanzaAck.cpp +++ b/Swiften/Elements/StanzaAck.cpp @@ -1,19 +1,17 @@ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/Elements/StanzaAck.h> -#include <boost/numeric/conversion/cast.hpp> - using namespace Swift; StanzaAck::~StanzaAck() { } -void StanzaAck::setHandledStanzasCount(int i) { - handledStanzasCount = boost::numeric_cast<unsigned int>(i); +void StanzaAck::setHandledStanzasCount(unsigned int i) { + handledStanzasCount = i; valid = true; } diff --git a/Swiften/Elements/StanzaAck.h b/Swiften/Elements/StanzaAck.h index 68f0a2f..f664aca 100644 --- a/Swiften/Elements/StanzaAck.h +++ b/Swiften/Elements/StanzaAck.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -24,7 +24,7 @@ namespace Swift { return handledStanzasCount; } - void setHandledStanzasCount(int i); + void setHandledStanzasCount(unsigned int i); bool isValid() const { return valid; diff --git a/Swiften/Elements/StreamError.h b/Swiften/Elements/StreamError.h index aa294fd..6dda15c 100644 --- a/Swiften/Elements/StreamError.h +++ b/Swiften/Elements/StreamError.h @@ -27,7 +27,6 @@ namespace Swift { ImproperAddressing, InternalServerError, InvalidFrom, - InvalidID, InvalidNamespace, InvalidXML, NotAuthorized, @@ -41,6 +40,7 @@ namespace Swift { SystemShutdown, UndefinedCondition, UnsupportedEncoding, + UnsupportedFeature, UnsupportedStanzaType, UnsupportedVersion }; diff --git a/Swiften/Elements/StreamInitiationFileInfo.h b/Swiften/Elements/StreamInitiationFileInfo.h index f2dc5b9..773814f 100644 --- a/Swiften/Elements/StreamInitiationFileInfo.h +++ b/Swiften/Elements/StreamInitiationFileInfo.h @@ -26,7 +26,7 @@ public: name(name), description(description), size(size), hash(hash), date(date), algo(algo), supportsRangeRequests(false), rangeOffset(0) {} void setName(const std::string& name) { - this->name = name;; + this->name = name; } const std::string& getName() const { diff --git a/Swiften/Entity/PayloadPersister.cpp b/Swiften/Entity/PayloadPersister.cpp index 3fd246c..fe51d86 100644 --- a/Swiften/Entity/PayloadPersister.cpp +++ b/Swiften/Entity/PayloadPersister.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -34,7 +34,7 @@ void PayloadPersister::savePayload(std::shared_ptr<Payload> payload, const boost file.close(); } catch (const boost::filesystem::filesystem_error& e) { - SWIFT_LOG(error) << e.what() << std::endl; + SWIFT_LOG(error) << e.what(); } } @@ -50,7 +50,7 @@ std::shared_ptr<Payload> PayloadPersister::loadPayload(const boost::filesystem:: } } catch (const boost::filesystem::filesystem_error& e) { - SWIFT_LOG(error) << e.what() << std::endl; + SWIFT_LOG(error) << e.what(); } return std::shared_ptr<Payload>(); } diff --git a/Swiften/EventLoop/BoostASIOEventLoop.cpp b/Swiften/EventLoop/BoostASIOEventLoop.cpp index 30143b9..45dd4a2 100644 --- a/Swiften/EventLoop/BoostASIOEventLoop.cpp +++ b/Swiften/EventLoop/BoostASIOEventLoop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,7 +23,7 @@ void BoostASIOEventLoop::handleASIOEvent() { std::unique_lock<std::recursive_mutex> lock(isEventInASIOEventLoopMutex_); isEventInASIOEventLoop_ = false; } - handleNextEvents(); + handleNextEvent(); } void BoostASIOEventLoop::eventPosted() { diff --git a/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm b/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm index b8ab621..39dc7ec 100644 --- a/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm +++ b/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,7 +23,7 @@ void CocoaEventLoop::handleNextCocoaEvent() { std::unique_lock<std::recursive_mutex> lock(isEventInCocoaEventLoopMutex_); isEventInCocoaEventLoop_ = false; } - handleNextEvents(); + handleNextEvent(); } void CocoaEventLoop::eventPosted() { diff --git a/Swiften/EventLoop/DummyEventLoop.cpp b/Swiften/EventLoop/DummyEventLoop.cpp index 4dfbac3..234ba7a 100644 --- a/Swiften/EventLoop/DummyEventLoop.cpp +++ b/Swiften/EventLoop/DummyEventLoop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -15,14 +15,14 @@ DummyEventLoop::DummyEventLoop() { DummyEventLoop::~DummyEventLoop() { if (hasEvents()) { - SWIFT_LOG(warning) << "DummyEventLoop: Unhandled events at destruction time" << std::endl; + SWIFT_LOG(warning) << "DummyEventLoop: Unhandled events at destruction time"; } } void DummyEventLoop::processEvents() { while(hasEvents()) { hasEvents_ = false; - handleNextEvents(); + handleNextEvent(); } } diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp index 186616f..1852f3f 100644 --- a/Swiften/EventLoop/EventLoop.cpp +++ b/Swiften/EventLoop/EventLoop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -10,15 +10,10 @@ #include <cassert> #include <vector> -#include <boost/bind.hpp> -#include <boost/lambda/bind.hpp> -#include <boost/lambda/lambda.hpp> #include <boost/optional.hpp> #include <Swiften/Base/Log.h> -namespace lambda = boost::lambda; - namespace Swift { inline void invokeCallback(const Event& event) { @@ -27,10 +22,10 @@ inline void invokeCallback(const Event& event) { event.callback(); } catch (const std::exception& e) { - SWIFT_LOG(error) << "Uncaught exception in event loop: " << e.what() << std::endl; + SWIFT_LOG(error) << "Uncaught exception in event loop: " << e.what(); } catch (...) { - SWIFT_LOG(error) << "Uncaught non-exception in event loop" << std::endl; + SWIFT_LOG(error) << "Uncaught non-exception in event loop"; } } @@ -40,9 +35,8 @@ EventLoop::EventLoop() : nextEventID_(0), handlingEvents_(false) { EventLoop::~EventLoop() { } -void EventLoop::handleNextEvents() { - const int eventsBatched = 100; - // If handleNextEvents is already in progress, e.g. in case of a recursive call due to +void EventLoop::handleNextEvent() { + // If handleNextEvent is already in progress, e.g. in case of a recursive call due to // the event loop implementation, then do no handle further events. Instead call // eventPosted() to continue event handling later. bool callEventPosted = handlingEvents_; @@ -50,19 +44,17 @@ void EventLoop::handleNextEvents() { handlingEvents_ = true; std::unique_lock<std::recursive_mutex> lock(removeEventsMutex_); { - std::vector<Event> nextEvents; + boost::optional<Event> nextEvent; { - std::unique_lock<std::recursive_mutex> lock(eventsMutex_); - for (int n = 0; ((n < eventsBatched) && !events_.empty()); n++) { - nextEvents.push_back(events_.front()); + std::unique_lock<std::recursive_mutex> eventsLock(eventsMutex_); + if (!events_.empty()) { + nextEvent = events_.front(); events_.pop_front(); } callEventPosted = !events_.empty(); } - if (!nextEvents.empty()) { - for (const auto& event : nextEvents) { - invokeCallback(event); - } + if (nextEvent) { + invokeCallback(*nextEvent); } } handlingEvents_ = false; @@ -96,7 +88,9 @@ void EventLoop::removeEventsFromOwner(std::shared_ptr<EventOwner> owner) { std::lock(removeLock, eventsLock); - events_.remove_if(lambda::bind(&Event::owner, lambda::_1) == owner); + events_.remove_if([&](const Event& event) { + return event.owner == owner; + }); } } diff --git a/Swiften/EventLoop/EventLoop.h b/Swiften/EventLoop/EventLoop.h index 06b9fbb..f61b9bc 100644 --- a/Swiften/EventLoop/EventLoop.h +++ b/Swiften/EventLoop/EventLoop.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -43,21 +43,20 @@ namespace Swift { protected: /** - * The \ref handleNextEvents method is called by an implementation of the abstract \ref EventLoop class + * The \ref handleNextEvent method is called by an implementation of the abstract \ref EventLoop class * at any point after the virtual \ref eventPosted method has been called. * This method does not block, except for short-time synchronization. - * It can process multiple events before it reutrns. * If called recursively, the event queue is not further processed. Instead, \ref eventPosted * is called to notify the implementing event loop of the non-empty event queue. - * It is recommended to not call \ref handleNextEvents inside an event posted to the event loop + * It is recommended to not call \ref handleNextEvent inside an event posted to the event loop * as this can lead to an infinite loop. */ - void handleNextEvents(); + void handleNextEvent(); /** * The \ref eventPosted virtual method serves as notification for when events are still available in the queue. * It is called after the first event is posted to an empty queue or after an event has been handled in - * \ref handleNextEvents and there are still remaining events in the queue. + * \ref handleNextEvent and there are still remaining events in the queue. */ virtual void eventPosted() = 0; diff --git a/Swiften/EventLoop/Qt/QtEventLoop.h b/Swiften/EventLoop/Qt/QtEventLoop.h index b1644c2..cf374ab 100644 --- a/Swiften/EventLoop/Qt/QtEventLoop.h +++ b/Swiften/EventLoop/Qt/QtEventLoop.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -38,7 +38,7 @@ namespace Swift { std::unique_lock<std::recursive_mutex> lock(isEventInQtEventLoopMutex_); isEventInQtEventLoop_ = false; } - handleNextEvents(); + handleNextEvent(); //event->deleteLater(); FIXME: Leak? return true; } diff --git a/Swiften/EventLoop/SimpleEventLoop.cpp b/Swiften/EventLoop/SimpleEventLoop.cpp index cac04e4..745fadb 100644 --- a/Swiften/EventLoop/SimpleEventLoop.cpp +++ b/Swiften/EventLoop/SimpleEventLoop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -34,7 +34,7 @@ void SimpleEventLoop::doRun(bool breakAfterEvents) { } void SimpleEventLoop::runOnce() { - handleNextEvents(); + handleNextEvent(); } void SimpleEventLoop::stop() { diff --git a/Swiften/EventLoop/SingleThreadedEventLoop.cpp b/Swiften/EventLoop/SingleThreadedEventLoop.cpp index 0542f37..89b4460 100644 --- a/Swiften/EventLoop/SingleThreadedEventLoop.cpp +++ b/Swiften/EventLoop/SingleThreadedEventLoop.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2016 Isode Limited. + * Copyright (c) 2016-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -43,7 +43,7 @@ void SingleThreadedEventLoop::handleEvents() { std::lock_guard<std::mutex> lock(eventAvailableMutex_); eventAvailable_ = false; } - handleNextEvents(); + handleNextEvent(); } void SingleThreadedEventLoop::stop() { diff --git a/Swiften/EventLoop/UnitTest/EventLoopTest.cpp b/Swiften/EventLoop/UnitTest/EventLoopTest.cpp index 00a4376..26c56d3 100644 --- a/Swiften/EventLoop/UnitTest/EventLoopTest.cpp +++ b/Swiften/EventLoop/UnitTest/EventLoopTest.cpp @@ -23,6 +23,7 @@ class EventLoopTest : public CppUnit::TestFixture { CPPUNIT_TEST(testPost); CPPUNIT_TEST(testRemove); CPPUNIT_TEST(testHandleEvent_Recursive); + CPPUNIT_TEST(testHandleEvent_FirstEventRemovesSecondEvent); CPPUNIT_TEST_SUITE_END(); public: @@ -74,6 +75,18 @@ class EventLoopTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, events_[1]); } + void testHandleEvent_FirstEventRemovesSecondEvent() { + DummyEventLoop testling; + auto eventOwner = std::make_shared<MyEventOwner>(); + auto secondEventFired = false; + + testling.postEvent([&](){ testling.removeEventsFromOwner(eventOwner); }, eventOwner); + testling.postEvent([&](){ secondEventFired = true; }, eventOwner); + testling.processEvents(); + + CPPUNIT_ASSERT_EQUAL(false, secondEventFired); + } + private: struct MyEventOwner : public EventOwner {}; void logEvent(int i) { diff --git a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp index 607038f..cc783c6 100644 --- a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp +++ b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp @@ -77,7 +77,7 @@ int main(int argc, char* argv[]) { ClientXMLTracer* tracer = new ClientXMLTracer(client); client->onConnected.connect(&handleConnected); errorConnection = client->onDisconnected.connect(&handleDisconnected); - std::cout << "Connecting to JID " << jid << " with timeout " << timeout << "ms on host: "; ; + std::cout << "Connecting to JID " << jid << " with timeout " << timeout << "ms on host: "; if (!connectHost.empty()) { std::cout << connectHost << std::endl; ClientOptions options; diff --git a/Swiften/Examples/SendFile/ReceiveFile.cpp b/Swiften/Examples/SendFile/ReceiveFile.cpp index 193c1b7..d641662 100644 --- a/Swiften/Examples/SendFile/ReceiveFile.cpp +++ b/Swiften/Examples/SendFile/ReceiveFile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -80,7 +80,7 @@ class FileReceiver { } void handleIncomingFileTransfer(IncomingFileTransfer::ref transfer) { - SWIFT_LOG(debug) << "foo" << std::endl; + SWIFT_LOG(debug) << "foo"; incomingFileTransfers.push_back(transfer); std::shared_ptr<FileWriteBytestream> out = std::make_shared<FileWriteBytestream>("out"); transfer->onFinished.connect(boost::bind(&FileReceiver::handleFileTransferFinished, this, _1, out)); diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.cpp b/Swiften/FileTransfer/ByteArrayReadBytestream.cpp index cd9fa4a..3fdff27 100644 --- a/Swiften/FileTransfer/ByteArrayReadBytestream.cpp +++ b/Swiften/FileTransfer/ByteArrayReadBytestream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -19,13 +19,19 @@ std::shared_ptr<ByteArray> ByteArrayReadBytestream::read(size_t size) { if (position + readSize > data.size()) { readSize = data.size() - position; } - std::shared_ptr<ByteArray> result = std::make_shared<ByteArray>( - data.begin() + boost::numeric_cast<long long>(position), - data.begin() + boost::numeric_cast<long long>(position) + boost::numeric_cast<long long>(readSize)); - - onRead(*result); - position += readSize; - return result; + try { + std::shared_ptr<ByteArray> result = std::make_shared<ByteArray>( + data.begin() + boost::numeric_cast<long long>(position), + data.begin() + boost::numeric_cast<long long>(position) + boost::numeric_cast<long long>(readSize)); + onRead(*result); + position += readSize; + return result; + } + catch (const boost::numeric::bad_numeric_cast&) { + // If we cannot cast to long long, we probably ran out of memory long ago + assert(false); + return {}; + } } void ByteArrayReadBytestream::addData(const std::vector<unsigned char>& moreData) { diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp index c6987c0..ae3d7e0 100644 --- a/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp +++ b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -133,7 +133,7 @@ void DefaultFileTransferTransporter::handleActivateProxySessionResult(const std: void DefaultFileTransferTransporter::startActivatingProxy(const JID& proxyServiceJID) { // activate proxy - SWIFT_LOG(debug) << "Start activating proxy " << proxyServiceJID.toString() << " with sid = " << s5bSessionID << "." << std::endl; + SWIFT_LOG(debug) << "Start activating proxy " << proxyServiceJID.toString() << " with sid = " << s5bSessionID << "."; S5BProxyRequest::ref proxyRequest = std::make_shared<S5BProxyRequest>(); proxyRequest->setSID(s5bSessionID); proxyRequest->setActivate(role == Initiator ? responder : initiator); @@ -207,7 +207,7 @@ std::shared_ptr<TransportSession> DefaultFileTransferTransporter::createLocalCan transportSession = std::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >(proxySession, stream); } else { - SWIFT_LOG(error) << "Failed obtaining proxy session with candidate JID " << candidate.jid << " and dstAddr " << getLocalCandidateSOCKS5DstAddr() << "." << std::endl; + SWIFT_LOG(error) << "Failed obtaining proxy session with candidate JID " << candidate.jid << " and dstAddr " << getLocalCandidateSOCKS5DstAddr() << "."; } } @@ -234,7 +234,7 @@ std::shared_ptr<TransportSession> DefaultFileTransferTransporter::createLocalCan transportSession = std::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >(proxySession, stream); } else { - SWIFT_LOG(error) << "Failed obtaining proxy session with candidate JID " << candidate.jid << " and dstAddr " << getLocalCandidateSOCKS5DstAddr() << "." << std::endl; + SWIFT_LOG(error) << "Failed obtaining proxy session with candidate JID " << candidate.jid << " and dstAddr " << getLocalCandidateSOCKS5DstAddr() << "."; } } @@ -255,11 +255,11 @@ std::string DefaultFileTransferTransporter::getSOCKS5DstAddr() const { std::string result; if (role == Initiator) { result = getInitiatorCandidateSOCKS5DstAddr(); - SWIFT_LOG(debug) << "Initiator S5B DST.ADDR = " << s5bSessionID << " + " << initiator.toString() << " + " << responder.toString() << " : " << result << std::endl; + SWIFT_LOG(debug) << "Initiator S5B DST.ADDR = " << s5bSessionID << " + " << initiator.toString() << " + " << responder.toString() << " : " << result; } else { result = getResponderCandidateSOCKS5DstAddr(); - SWIFT_LOG(debug) << "Responder S5B DST.ADDR = " << s5bSessionID << " + " << responder.toString() << " + " << initiator.toString() << " : " << result << std::endl; + SWIFT_LOG(debug) << "Responder S5B DST.ADDR = " << s5bSessionID << " + " << responder.toString() << " + " << initiator.toString() << " : " << result; } return result; } diff --git a/Swiften/FileTransfer/FailingTransportSession.cpp b/Swiften/FileTransfer/FailingTransportSession.cpp index d1eb6a6..b9c79a0 100644 --- a/Swiften/FileTransfer/FailingTransportSession.cpp +++ b/Swiften/FileTransfer/FailingTransportSession.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Isode Limited. + * Copyright (c) 2016-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -14,7 +14,7 @@ FailingTransportSession::~FailingTransportSession() { } void FailingTransportSession::start() { - SWIFT_LOG(error) << "Trying to start failing transport." << std::endl; + SWIFT_LOG(error) << "Trying to start failing transport."; onFinished(FileTransferError(FileTransferError::PeerError)); } diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp index 05dd3bb..98eb50e 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.cpp +++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -156,7 +156,7 @@ OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer( } } else { - SWIFT_LOG(warning) << "No entity capabilities information for " << receipient.toString() << std::endl; + SWIFT_LOG(warning) << "No entity capabilities information for " << receipient.toString(); } return outgoingFTManager->createOutgoingFileTransfer(iqRouter->getJID(), receipient, bytestream, fileInfo, options); diff --git a/Swiften/FileTransfer/IBBSendSession.cpp b/Swiften/FileTransfer/IBBSendSession.cpp index e51c91c..258412b 100644 --- a/Swiften/FileTransfer/IBBSendSession.cpp +++ b/Swiften/FileTransfer/IBBSendSession.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -40,7 +40,7 @@ IBBSendSession::~IBBSendSession() { void IBBSendSession::start() { IBBRequest::ref request = IBBRequest::create( - from, to, IBB::createIBBOpen(id, boost::numeric_cast<int>(blockSize)), router); + from, to, IBB::createIBBOpen(id, blockSize), router); request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); active = true; request->send(); diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp index d5de5e4..7c46c60 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -67,8 +67,8 @@ IncomingJingleFileTransfer::~IncomingJingleFileTransfer() { void IncomingJingleFileTransfer::accept( std::shared_ptr<WriteBytestream> stream, const FileTransferOptions& options) { - SWIFT_LOG(debug) << std::endl; - if (state != Initial) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + SWIFT_LOG(debug); + if (state != Initial) { SWIFT_LOG(warning) << "Incorrect state"; return; } assert(!this->stream); this->stream = stream; @@ -85,7 +85,7 @@ void IncomingJingleFileTransfer::accept( JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>(); JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>(); if (s5bTransport) { - SWIFT_LOG(debug) << "Got S5B transport as initial payload." << std::endl; + SWIFT_LOG(debug) << "Got S5B transport as initial payload."; setTransporter(transporterFactory->createResponderTransporter( getInitiator(), getResponder(), s5bTransport->getSessionID(), options)); transporter->addRemoteCandidates(s5bTransport->getCandidates(), s5bTransport->getDstAddr()); @@ -93,7 +93,7 @@ void IncomingJingleFileTransfer::accept( transporter->startGeneratingLocalCandidates(); } else if (ibbTransport && options.isInBandAllowed()) { - SWIFT_LOG(debug) << "Got IBB transport as initial payload." << std::endl; + SWIFT_LOG(debug) << "Got IBB transport as initial payload."; setTransporter(transporterFactory->createResponderTransporter( getInitiator(), getResponder(), ibbTransport->getSessionID(), options)); @@ -112,7 +112,7 @@ void IncomingJingleFileTransfer::accept( } void IncomingJingleFileTransfer::cancel() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); terminate(state == Initial ? JinglePayload::Reason::Decline : JinglePayload::Reason::Cancel); } @@ -120,8 +120,8 @@ void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated( const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>& candidates, const std::string& dstAddr) { - SWIFT_LOG(debug) << std::endl; - if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + SWIFT_LOG(debug); + if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state"; return; } fillCandidateMap(localCandidates, candidates); @@ -140,11 +140,11 @@ void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated( void IncomingJingleFileTransfer::handleSessionInfoReceived(JinglePayload::ref jinglePayload) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); JingleFileTransferHash::ref transferHash = jinglePayload->getPayload<JingleFileTransferHash>(); if (transferHash) { - SWIFT_LOG(debug) << "Received hash information." << std::endl; + SWIFT_LOG(debug) << "Received hash information."; waitOnHashTimer->stop(); if (transferHash->getFileInfo().getHashes().find("sha-1") != transferHash->getFileInfo().getHashes().end()) { hashes["sha-1"] = transferHash->getFileInfo().getHash("sha-1").get(); @@ -157,16 +157,16 @@ void IncomingJingleFileTransfer::handleSessionInfoReceived(JinglePayload::ref ji } } else { - SWIFT_LOG(debug) << "Ignoring unknown session info" << std::endl; + SWIFT_LOG(debug) << "Ignoring unknown session info"; } } void IncomingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) { - SWIFT_LOG(debug) << std::endl; - if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + SWIFT_LOG(debug); + if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state"; return; } if (state == Finished) { - SWIFT_LOG(debug) << "Already terminated" << std::endl; + SWIFT_LOG(debug) << "Already terminated"; return; } @@ -187,21 +187,21 @@ void IncomingJingleFileTransfer::checkHashAndTerminate() { terminate(JinglePayload::Reason::Success); } else { - SWIFT_LOG(warning) << "Hash verification failed" << std::endl; + SWIFT_LOG(warning) << "Hash verification failed"; terminate(JinglePayload::Reason::MediaError); } } void IncomingJingleFileTransfer::checkIfAllDataReceived() { if (receivedBytes == getFileSizeInBytes()) { - SWIFT_LOG(debug) << "All data received." << std::endl; + SWIFT_LOG(debug) << "All data received."; bool hashInfoAvailable = false; for (const auto& hashElement : hashes) { hashInfoAvailable |= !hashElement.second.empty(); } if (!hashInfoAvailable) { - SWIFT_LOG(debug) << "No hash information yet. Waiting a while on hash info." << std::endl; + SWIFT_LOG(debug) << "No hash information yet. Waiting a while on hash info."; setState(WaitingForHash); waitOnHashTimer->start(); } @@ -210,7 +210,7 @@ void IncomingJingleFileTransfer::checkIfAllDataReceived() { } } else if (receivedBytes > getFileSizeInBytes()) { - SWIFT_LOG(debug) << "We got more than we could handle!" << std::endl; + SWIFT_LOG(debug) << "We got more than we could handle!"; terminate(JinglePayload::Reason::MediaError); } } @@ -225,15 +225,15 @@ void IncomingJingleFileTransfer::handleWriteStreamDataReceived( void IncomingJingleFileTransfer::handleTransportReplaceReceived( const JingleContentID& content, JingleTransportPayload::ref transport) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (state != WaitingForFallbackOrTerminate) { - SWIFT_LOG(warning) << "Incorrect state" << std::endl; + SWIFT_LOG(warning) << "Incorrect state"; return; } JingleIBBTransportPayload::ref ibbTransport; if (options.isInBandAllowed() && (ibbTransport = std::dynamic_pointer_cast<JingleIBBTransportPayload>(transport))) { - SWIFT_LOG(debug) << "transport replaced with IBB" << std::endl; + SWIFT_LOG(debug) << "transport replaced with IBB"; startTransferring(transporter->createIBBReceiveSession( ibbTransport->getSessionID(), @@ -242,7 +242,7 @@ void IncomingJingleFileTransfer::handleTransportReplaceReceived( session->sendTransportAccept(content, ibbTransport); } else { - SWIFT_LOG(debug) << "Unknown replace transport" << std::endl; + SWIFT_LOG(debug) << "Unknown replace transport"; session->sendTransportReject(content, transport); } } @@ -253,25 +253,25 @@ JingleContentID IncomingJingleFileTransfer::getContentID() const { bool IncomingJingleFileTransfer::verifyData() { if (hashes.empty()) { - SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl; + SWIFT_LOG(debug) << "no verification possible, skipping"; return true; } if (hashes.find("sha-1") != hashes.end()) { - SWIFT_LOG(debug) << "Verify SHA-1 hash: " << (hashes["sha-1"] == hashCalculator->getSHA1Hash()) << std::endl; + SWIFT_LOG(debug) << "Verify SHA-1 hash: " << (hashes["sha-1"] == hashCalculator->getSHA1Hash()); return hashes["sha-1"] == hashCalculator->getSHA1Hash(); } else if (hashes.find("md5") != hashes.end()) { - SWIFT_LOG(debug) << "Verify MD5 hash: " << (hashes["md5"] == hashCalculator->getMD5Hash()) << std::endl; + SWIFT_LOG(debug) << "Verify MD5 hash: " << (hashes["md5"] == hashCalculator->getMD5Hash()); return hashes["md5"] == hashCalculator->getMD5Hash(); } else { - SWIFT_LOG(debug) << "Unknown hash, skipping" << std::endl; + SWIFT_LOG(debug) << "Unknown hash, skipping"; return true; } } void IncomingJingleFileTransfer::handleWaitOnHashTimerTicked() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); waitOnHashTimer->stop(); terminate(JinglePayload::Reason::Success); } @@ -285,14 +285,14 @@ const JID& IncomingJingleFileTransfer::getRecipient() const { } void IncomingJingleFileTransfer::setState(State state) { - SWIFT_LOG(debug) << state << std::endl; + SWIFT_LOG(debug) << state; this->state = state; onStateChanged(FileTransfer::State(getExternalState(state))); } void IncomingJingleFileTransfer::setFinishedState( FileTransfer::State::Type type, const boost::optional<FileTransferError>& error) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); this->state = Finished; onStateChanged(type); onFinished(error); @@ -340,7 +340,7 @@ void IncomingJingleFileTransfer::stopAll() { transportSession->stop(); transportSession.reset(); break; - case Finished: SWIFT_LOG(warning) << "Already finished" << std::endl; break; + case Finished: SWIFT_LOG(warning) << "Already finished"; break; } if (state != Initial) { removeTransporter(); @@ -356,7 +356,7 @@ void IncomingJingleFileTransfer::fallback() { } void IncomingJingleFileTransfer::startTransferViaRemoteCandidate() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (ourCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { setState(WaitingForPeerProxyActivate); @@ -367,7 +367,7 @@ void IncomingJingleFileTransfer::startTransferViaRemoteCandidate() { } void IncomingJingleFileTransfer::startTransferViaLocalCandidate() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (theirCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { setState(WaitingForLocalProxyActivate); @@ -379,7 +379,7 @@ void IncomingJingleFileTransfer::startTransferViaLocalCandidate() { } void IncomingJingleFileTransfer::startTransferring(std::shared_ptr<TransportSession> transportSession) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); this->transportSession = transportSession; transferFinishedConnection = transportSession->onFinished.connect( @@ -409,7 +409,7 @@ std::shared_ptr<TransportSession> IncomingJingleFileTransfer::createRemoteCandid } void IncomingJingleFileTransfer::terminate(JinglePayload::Reason::Type reason) { - SWIFT_LOG(debug) << reason << std::endl; + SWIFT_LOG(debug) << reason; if (state != Finished) { session->sendTerminate(reason); diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp index f177304..faddcb9 100644 --- a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp @@ -64,12 +64,12 @@ ByteArray IncrementalBytestreamHashCalculator::getMD5Hash() { std::string IncrementalBytestreamHashCalculator::getSHA1String() { assert(sha1Hasher); - return Hexify::hexify(getSHA1Hash());; + return Hexify::hexify(getSHA1Hash()); } std::string IncrementalBytestreamHashCalculator::getMD5String() { assert(md5Hasher); - return Hexify::hexify(getMD5Hash());; + return Hexify::hexify(getMD5Hash()); } } diff --git a/Swiften/FileTransfer/JingleFileTransfer.cpp b/Swiften/FileTransfer/JingleFileTransfer.cpp index 62c3a53..3d05db9 100644 --- a/Swiften/FileTransfer/JingleFileTransfer.cpp +++ b/Swiften/FileTransfer/JingleFileTransfer.cpp @@ -1,13 +1,11 @@ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/FileTransfer/JingleFileTransfer.h> -#include <boost/typeof/typeof.hpp> - #include <Swiften/Base/Log.h> #include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/FileTransfer/FileTransferTransporter.h> @@ -29,7 +27,6 @@ JingleFileTransfer::JingleFileTransfer( theirCandidateSelectFinished(false) { session->addListener(this); - } JingleFileTransfer::~JingleFileTransfer() { @@ -81,7 +78,7 @@ boost::optional<FileTransferError> JingleFileTransfer::getFileTransferError(Jing void JingleFileTransfer::handleRemoteTransportCandidateSelectFinished( const std::string& s5bSessionID, const boost::optional<JingleS5BTransportPayload::Candidate>& candidate) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); ourCandidateChoice = candidate; ourCandidateSelectFinished = true; @@ -101,42 +98,42 @@ void JingleFileTransfer::handleRemoteTransportCandidateSelectFinished( // decide on candidates according to http://xmpp.org/extensions/xep-0260.html#complete void JingleFileTransfer::decideOnCandidates() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (!ourCandidateSelectFinished || !theirCandidateSelectFinished) { - SWIFT_LOG(debug) << "Can't make a decision yet!" << std::endl; + SWIFT_LOG(debug) << "Can't make a decision yet!"; return; } if (!ourCandidateChoice && !theirCandidateChoice) { - SWIFT_LOG(debug) << "No candidates succeeded." << std::endl; + SWIFT_LOG(debug) << "No candidates succeeded."; fallback(); } else if (ourCandidateChoice && !theirCandidateChoice) { - SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid << "." << std::endl; + SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid << "."; startTransferViaRemoteCandidate(); } else if (theirCandidateChoice && !ourCandidateChoice) { - SWIFT_LOG(debug) << "Start transfer using local candidate: " << theirCandidateChoice.get().cid << "." << std::endl; + SWIFT_LOG(debug) << "Start transfer using local candidate: " << theirCandidateChoice.get().cid << "."; startTransferViaLocalCandidate(); } else { SWIFT_LOG(debug) << "Choosing between candidates " << ourCandidateChoice->cid << "(" << ourCandidateChoice->priority << ")" << " and " - << theirCandidateChoice->cid << "(" << theirCandidateChoice->priority << ")" << std::endl; + << theirCandidateChoice->cid << "(" << theirCandidateChoice->priority << ")"; if (ourCandidateChoice->priority > theirCandidateChoice->priority) { - SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid << "." << std::endl; + SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid << "."; startTransferViaRemoteCandidate(); } else if (ourCandidateChoice->priority < theirCandidateChoice->priority) { - SWIFT_LOG(debug) << "Start transfer using local candidate:" << theirCandidateChoice.get().cid << "." << std::endl; + SWIFT_LOG(debug) << "Start transfer using local candidate:" << theirCandidateChoice.get().cid << "."; startTransferViaLocalCandidate(); } else { if (hasPriorityOnCandidateTie()) { - SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid << std::endl; + SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid; startTransferViaRemoteCandidate(); } else { - SWIFT_LOG(debug) << "Start transfer using local candidate: " << theirCandidateChoice.get().cid << std::endl; + SWIFT_LOG(debug) << "Start transfer using local candidate: " << theirCandidateChoice.get().cid; startTransferViaLocalCandidate(); } } @@ -145,11 +142,11 @@ void JingleFileTransfer::decideOnCandidates() { void JingleFileTransfer::handleProxyActivateFinished( const std::string& s5bSessionID, ErrorPayload::ref error) { - SWIFT_LOG(debug) << std::endl; - if (!isWaitingForLocalProxyActivate()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + SWIFT_LOG(debug); + if (!isWaitingForLocalProxyActivate()) { SWIFT_LOG(warning) << "Incorrect state"; return; } if (error) { - SWIFT_LOG(debug) << "Error activating proxy" << std::endl; + SWIFT_LOG(debug) << "Error activating proxy"; JingleS5BTransportPayload::ref proxyError = std::make_shared<JingleS5BTransportPayload>(); proxyError->setSessionID(s5bSessionID); proxyError->setProxyError(true); @@ -167,18 +164,18 @@ void JingleFileTransfer::handleProxyActivateFinished( void JingleFileTransfer::handleTransportInfoReceived( const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (JingleS5BTransportPayload::ref s5bPayload = std::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { if (s5bPayload->hasCandidateError() || !s5bPayload->getCandidateUsed().empty()) { - SWIFT_LOG(debug) << "Received candidate decision from peer" << std::endl; - if (!isTryingCandidates()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + SWIFT_LOG(debug) << "Received candidate decision from peer"; + if (!isTryingCandidates()) { SWIFT_LOG(warning) << "Incorrect state"; return; } theirCandidateSelectFinished = true; if (!s5bPayload->hasCandidateError()) { - BOOST_AUTO(theirCandidate, localCandidates.find(s5bPayload->getCandidateUsed())); + auto theirCandidate = localCandidates.find(s5bPayload->getCandidateUsed()); if (theirCandidate == localCandidates.end()) { - SWIFT_LOG(warning) << "Got invalid candidate" << std::endl; + SWIFT_LOG(warning) << "Got invalid candidate"; terminate(JinglePayload::Reason::GeneralError); return; } @@ -187,27 +184,27 @@ void JingleFileTransfer::handleTransportInfoReceived( decideOnCandidates(); } else if (!s5bPayload->getActivated().empty()) { - SWIFT_LOG(debug) << "Received peer activate from peer" << std::endl; - if (!isWaitingForPeerProxyActivate()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + SWIFT_LOG(debug) << "Received peer activate from peer"; + if (!isWaitingForPeerProxyActivate()) { SWIFT_LOG(warning) << "Incorrect state"; return; } if (ourCandidateChoice->cid == s5bPayload->getActivated()) { startTransferring(createRemoteCandidateSession()); } else { - SWIFT_LOG(warning) << "ourCandidateChoice doesn't match activated proxy candidate!" << std::endl; + SWIFT_LOG(warning) << "ourCandidateChoice doesn't match activated proxy candidate!"; terminate(JinglePayload::Reason::GeneralError); } } else if (s5bPayload->hasProxyError()) { - SWIFT_LOG(debug) << "Received proxy error. Trying to fall back to IBB." << std::endl; + SWIFT_LOG(debug) << "Received proxy error. Trying to fall back to IBB."; fallback(); } else { - SWIFT_LOG(debug) << "Ignoring unknown info" << std::endl; + SWIFT_LOG(debug) << "Ignoring unknown info"; } } else { - SWIFT_LOG(debug) << "Ignoring unknown info" << std::endl; + SWIFT_LOG(debug) << "Ignoring unknown info"; } } @@ -231,4 +228,3 @@ void JingleFileTransfer::removeTransporter() { transporter = nullptr; } } - diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp index 834a401..7cb4cbb 100644 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -45,7 +45,7 @@ LocalJingleTransportCandidateGenerator::LocalJingleTransportCandidateGenerator( } LocalJingleTransportCandidateGenerator::~LocalJingleTransportCandidateGenerator() { - SWIFT_LOG_ASSERT(!s5bServerInitializeRequest, warning) << std::endl; + SWIFT_LOG_ASSERT(!s5bServerInitializeRequest, warning); } void LocalJingleTransportCandidateGenerator::start() { @@ -98,7 +98,7 @@ void LocalJingleTransportCandidateGenerator::handleS5BServerInitialized(bool suc } } else { - SWIFT_LOG(warning) << "Unable to start SOCKS5 server" << std::endl; + SWIFT_LOG(warning) << "Unable to start SOCKS5 server"; if (s5bServerResourceUser_) { s5bServerResourceUser_->onSuccessfulInitialized.disconnect(boost::bind(&LocalJingleTransportCandidateGenerator::handleS5BServerInitialized, this, _1)); } diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp index 367fc97..57a18a8 100644 --- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -87,9 +87,9 @@ OutgoingJingleFileTransfer::~OutgoingJingleFileTransfer() { } void OutgoingJingleFileTransfer::start() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (state != Initial) { - SWIFT_LOG(warning) << "Incorrect state" << std::endl; + SWIFT_LOG(warning) << "Incorrect state"; return; } @@ -109,7 +109,7 @@ void OutgoingJingleFileTransfer::cancel() { } void OutgoingJingleFileTransfer::terminate(JinglePayload::Reason::Type reason) { - SWIFT_LOG(debug) << reason << std::endl; + SWIFT_LOG(debug) << reason; if (state != Initial && state != GeneratingInitialLocalCandidates && state != Finished) { session->sendTerminate(reason); @@ -122,8 +122,8 @@ void OutgoingJingleFileTransfer::handleSessionAcceptReceived( const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref transportPayload) { - SWIFT_LOG(debug) << std::endl; - if (state != WaitingForAccept) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + SWIFT_LOG(debug); + if (state != WaitingForAccept) { SWIFT_LOG(warning) << "Incorrect state"; return; } if (JingleS5BTransportPayload::ref s5bPayload = std::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload)) { transporter->addRemoteCandidates(s5bPayload->getCandidates(), s5bPayload->getDstAddr()); @@ -134,14 +134,14 @@ void OutgoingJingleFileTransfer::handleSessionAcceptReceived( startTransferring(transporter->createIBBSendSession(ibbPayload->getSessionID(), ibbPayload->getBlockSize().get_value_or(DEFAULT_BLOCK_SIZE), stream)); } else { - SWIFT_LOG(debug) << "Unknown transport payload. Falling back." << std::endl; + SWIFT_LOG(debug) << "Unknown transport payload. Falling back."; fallback(); } } void OutgoingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) { - SWIFT_LOG(debug) << std::endl; - if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state: " << state << std::endl; return; } + SWIFT_LOG(debug); + if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state: " << state; return; } stopAll(); if (state == WaitForTermination) { @@ -162,26 +162,26 @@ void OutgoingJingleFileTransfer::handleSessionTerminateReceived(boost::optional< } void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleContentID&, JingleTransportPayload::ref transport) { - SWIFT_LOG(debug) << std::endl; - if (state != FallbackRequested) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + SWIFT_LOG(debug); + if (state != FallbackRequested) { SWIFT_LOG(warning) << "Incorrect state"; return; } if (JingleIBBTransportPayload::ref ibbPayload = std::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { startTransferring(transporter->createIBBSendSession(ibbPayload->getSessionID(), ibbPayload->getBlockSize().get_value_or(DEFAULT_BLOCK_SIZE), stream)); } else { - SWIFT_LOG(debug) << "Unknown transport replacement" << std::endl; + SWIFT_LOG(debug) << "Unknown transport replacement"; terminate(JinglePayload::Reason::FailedTransport); } } void OutgoingJingleFileTransfer::handleTransportRejectReceived(const JingleContentID &, std::shared_ptr<JingleTransportPayload>) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); terminate(JinglePayload::Reason::UnsupportedTransports); } void OutgoingJingleFileTransfer::sendSessionInfoHash() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); JingleFileTransferHash::ref hashElement = std::make_shared<JingleFileTransferHash>(); hashElement->getFileInfo().addHash(HashElement("sha-1", hashCalculator->getSHA1Hash())); @@ -191,8 +191,8 @@ void OutgoingJingleFileTransfer::sendSessionInfoHash() { void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated( const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>& candidates, const std::string& dstAddr) { - SWIFT_LOG(debug) << std::endl; - if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state: " << state << std::endl; return; } + SWIFT_LOG(debug); + if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state: " << state; return; } fillCandidateMap(localCandidates, candidates); @@ -203,7 +203,7 @@ void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated( JingleTransportPayload::ref transport; if (candidates.empty()) { - SWIFT_LOG(debug) << "no S5B candidates generated. Send IBB transport candidate." << std::endl; + SWIFT_LOG(debug) << "no S5B candidates generated. Send IBB transport candidate."; JingleIBBTransportPayload::ref ibbTransport = std::make_shared<JingleIBBTransportPayload>(); ibbTransport->setBlockSize(DEFAULT_BLOCK_SIZE); ibbTransport->setSessionID(idGenerator->generateID()); @@ -216,7 +216,7 @@ void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated( s5bTransport->setDstAddr(dstAddr); for (auto&& candidate : candidates) { s5bTransport->addCandidate(candidate); - SWIFT_LOG(debug) << "\t" << "S5B candidate: " << candidate.hostPort.toString() << std::endl; + SWIFT_LOG(debug) << "\t" << "S5B candidate: " << candidate.hostPort.toString(); } transport = s5bTransport; } @@ -226,7 +226,7 @@ void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated( void OutgoingJingleFileTransfer::fallback() { if (options.isInBandAllowed()) { - SWIFT_LOG(debug) << "Trying to fallback to IBB transport." << std::endl; + SWIFT_LOG(debug) << "Trying to fallback to IBB transport."; JingleIBBTransportPayload::ref ibbTransport = std::make_shared<JingleIBBTransportPayload>(); ibbTransport->setBlockSize(DEFAULT_BLOCK_SIZE); ibbTransport->setSessionID(idGenerator->generateID()); @@ -234,14 +234,14 @@ void OutgoingJingleFileTransfer::fallback() { session->sendTransportReplace(contentID, ibbTransport); } else { - SWIFT_LOG(debug) << "Fallback to IBB transport not allowed." << std::endl; + SWIFT_LOG(debug) << "Fallback to IBB transport not allowed."; terminate(JinglePayload::Reason::ConnectivityError); } } void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { - SWIFT_LOG(debug) << std::endl; - if (state != Transferring) { SWIFT_LOG(warning) << "Incorrect state: " << state << std::endl; return; } + SWIFT_LOG(debug); + if (state != Transferring) { SWIFT_LOG(warning) << "Incorrect state: " << state; return; } if (error) { terminate(JinglePayload::Reason::ConnectivityError); @@ -256,7 +256,7 @@ void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTran } void OutgoingJingleFileTransfer::startTransferring(std::shared_ptr<TransportSession> transportSession) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); this->transportSession = transportSession; processedBytesConnection = transportSession->onBytesSent.connect( @@ -269,14 +269,14 @@ void OutgoingJingleFileTransfer::startTransferring(std::shared_ptr<TransportSess void OutgoingJingleFileTransfer::setInternalState(State state) { - SWIFT_LOG(debug) << state << std::endl; + SWIFT_LOG(debug) << state; this->state = state; setState(FileTransfer::State(getExternalState(state))); } void OutgoingJingleFileTransfer::setFinishedState( FileTransfer::State::Type type, const boost::optional<FileTransferError>& error) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); this->state = Finished; onStateChanged(type); onFinished(error); @@ -301,9 +301,9 @@ FileTransfer::State::Type OutgoingJingleFileTransfer::getExternalState(State sta } void OutgoingJingleFileTransfer::stopAll() { - SWIFT_LOG(debug) << state << std::endl; + SWIFT_LOG(debug) << state; switch (state) { - case Initial: SWIFT_LOG(warning) << "Not yet started" << std::endl; break; + case Initial: SWIFT_LOG(warning) << "Not yet started"; break; case GeneratingInitialLocalCandidates: transporter->stopGeneratingLocalCandidates(); break; case WaitingForAccept: break; case TryingCandidates: transporter->stopTryingRemoteCandidates(); break; @@ -320,7 +320,7 @@ void OutgoingJingleFileTransfer::stopAll() { break; case WaitForTermination: break; - case Finished: SWIFT_LOG(warning) << "Already finished" << std::endl; break; + case Finished: SWIFT_LOG(warning) << "Already finished"; break; } if (state != Initial) { removeTransporter(); @@ -328,7 +328,7 @@ void OutgoingJingleFileTransfer::stopAll() { } void OutgoingJingleFileTransfer::startTransferViaRemoteCandidate() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (ourCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { setInternalState(WaitingForPeerProxyActivate); @@ -340,7 +340,7 @@ void OutgoingJingleFileTransfer::startTransferViaRemoteCandidate() { } void OutgoingJingleFileTransfer::startTransferViaLocalCandidate() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (theirCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { setInternalState(WaitingForLocalProxyActivate); @@ -400,7 +400,7 @@ std::shared_ptr<TransportSession> OutgoingJingleFileTransfer::createRemoteCandid void OutgoingJingleFileTransfer::handleWaitForRemoteTerminationTimeout() { assert(state == WaitForTermination); - SWIFT_LOG(warning) << "Other party did not terminate session. Terminate it now." << std::endl; + SWIFT_LOG(warning) << "Other party did not terminate session. Terminate it now."; waitForRemoteTermination->stop(); terminate(JinglePayload::Reason::MediaError); } diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp index 56013ca..4023be3 100644 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -56,14 +56,14 @@ void RemoteJingleTransportCandidateSelector::stopSelectingCandidate() { void RemoteJingleTransportCandidateSelector::tryNextCandidate() { if (candidates.empty()) { - SWIFT_LOG(debug) << "No more candidates" << std::endl; + SWIFT_LOG(debug) << "No more candidates"; onCandidateSelectFinished( boost::optional<JingleS5BTransportPayload::Candidate>(), std::shared_ptr<SOCKS5BytestreamClientSession>()); } else { lastCandidate = candidates.top(); candidates.pop(); - SWIFT_LOG(debug) << "Trying candidate " << lastCandidate.cid << std::endl; + SWIFT_LOG(debug) << "Trying candidate " << lastCandidate.cid; if ((lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType && options.isDirectAllowed()) || (lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType && options.isAssistedAllowed()) || (lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType && options.isProxiedAllowed())) { @@ -75,7 +75,7 @@ void RemoteJingleTransportCandidateSelector::tryNextCandidate() { s5bSession->start(); } else { - SWIFT_LOG(debug) << "Can't handle this type of candidate" << std::endl; + SWIFT_LOG(debug) << "Can't handle this type of candidate"; tryNextCandidate(); } } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp index 5ddd32b..a3f0dab 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -49,7 +49,7 @@ SOCKS5BytestreamClientSession::~SOCKS5BytestreamClientSession() { void SOCKS5BytestreamClientSession::start() { assert(state == Initial); - SWIFT_LOG(debug) << "Trying to connect via TCP to " << addressPort.toString() << "." << std::endl; + SWIFT_LOG(debug) << "Trying to connect via TCP to " << addressPort.toString() << "."; weFailedTimeout->start(); connectFinishedConnection = connection->onConnectFinished.connect( boost::bind(&SOCKS5BytestreamClientSession::handleConnectFinished, this, _1)); @@ -57,7 +57,7 @@ void SOCKS5BytestreamClientSession::start() { } void SOCKS5BytestreamClientSession::stop() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (state < Ready) { weFailedTimeout->stop(); } @@ -70,7 +70,7 @@ void SOCKS5BytestreamClientSession::stop() { } void SOCKS5BytestreamClientSession::process() { - SWIFT_LOG(debug) << "unprocessedData.size(): " << unprocessedData.size() << std::endl; + SWIFT_LOG(debug) << "unprocessedData.size(): " << unprocessedData.size(); ByteArray bndAddress; switch(state) { case Initial: @@ -124,19 +124,19 @@ void SOCKS5BytestreamClientSession::process() { } unprocessedData.clear(); state = Ready; - SWIFT_LOG(debug) << "session ready" << std::endl; + SWIFT_LOG(debug) << "session ready"; // issue ready signal so the bytestream can be used for reading or writing weFailedTimeout->stop(); onSessionReady(false); break; case Ready: - SWIFT_LOG(debug) << "Received further data in Ready state." << std::endl; + SWIFT_LOG(debug) << "Received further data in Ready state."; break; case Reading: case Writing: case Finished: - SWIFT_LOG(debug) << "Unexpected receive of data. Current state: " << state << std::endl; - SWIFT_LOG(debug) << "Data: " << Hexify::hexify(unprocessedData) << std::endl; + SWIFT_LOG(debug) << "Unexpected receive of data. Current state: " << state; + SWIFT_LOG(debug) << "Data: " << Hexify::hexify(unprocessedData); unprocessedData.clear(); //assert(false); } @@ -150,7 +150,7 @@ void SOCKS5BytestreamClientSession::hello() { } void SOCKS5BytestreamClientSession::authenticate() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); SafeByteArray header = createSafeByteArray("\x05\x01\x00\x03", 4); SafeByteArray message = header; append(message, createSafeByteArray(boost::numeric_cast<char>(destination.size()))); @@ -168,7 +168,7 @@ void SOCKS5BytestreamClientSession::startReceiving(std::shared_ptr<WriteBytestre writeBytestream->write(unprocessedData); unprocessedData.clear(); } else { - SWIFT_LOG(debug) << "Session isn't ready for transfer yet!" << std::endl; + SWIFT_LOG(debug) << "Session isn't ready for transfer yet!"; } } @@ -180,7 +180,7 @@ void SOCKS5BytestreamClientSession::startSending(std::shared_ptr<ReadBytestream> boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); sendData(); } else { - SWIFT_LOG(debug) << "Session isn't ready for transfer yet!" << std::endl; + SWIFT_LOG(debug) << "Session isn't ready for transfer yet!"; } } @@ -205,7 +205,7 @@ void SOCKS5BytestreamClientSession::sendData() { } void SOCKS5BytestreamClientSession::finish(bool error) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); if (state < Ready) { weFailedTimeout->stop(); } @@ -227,10 +227,10 @@ void SOCKS5BytestreamClientSession::finish(bool error) { void SOCKS5BytestreamClientSession::handleConnectFinished(bool error) { connectFinishedConnection.disconnect(); if (error) { - SWIFT_LOG(debug) << "Failed to connect via TCP to " << addressPort.toString() << "." << std::endl; + SWIFT_LOG(debug) << "Failed to connect via TCP to " << addressPort.toString() << "."; finish(true); } else { - SWIFT_LOG(debug) << "Successfully connected via TCP" << addressPort.toString() << "." << std::endl; + SWIFT_LOG(debug) << "Successfully connected via TCP" << addressPort.toString() << "."; disconnectedConnection = connection->onDisconnected.connect( boost::bind(&SOCKS5BytestreamClientSession::handleDisconnected, this, _1)); dataReadConnection = connection->onDataRead.connect( @@ -242,7 +242,7 @@ void SOCKS5BytestreamClientSession::handleConnectFinished(bool error) { } void SOCKS5BytestreamClientSession::handleDataRead(std::shared_ptr<SafeByteArray> data) { - SWIFT_LOG(debug) << "state: " << state << " data.size() = " << data->size() << std::endl; + SWIFT_LOG(debug) << "state: " << state << " data.size() = " << data->size(); if (state != Reading) { append(unprocessedData, *data); process(); @@ -254,14 +254,14 @@ void SOCKS5BytestreamClientSession::handleDataRead(std::shared_ptr<SafeByteArray } void SOCKS5BytestreamClientSession::handleDisconnected(const boost::optional<Connection::Error>& error) { - SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error") << std::endl; + SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error"); if (error) { finish(true); } } void SOCKS5BytestreamClientSession::handleWeFailedTimeout() { - SWIFT_LOG(debug) << "Failed due to timeout!" << std::endl; + SWIFT_LOG(debug) << "Failed due to timeout!"; finish(true); } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp index cd4cfaa..72c4d41 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -46,7 +46,7 @@ SOCKS5BytestreamProxiesManager::~SOCKS5BytestreamProxiesManager() { void SOCKS5BytestreamProxiesManager::addS5BProxy(S5BProxyRequest::ref proxy) { if (proxy) { - SWIFT_LOG_ASSERT(HostAddress::fromString(proxy->getStreamHost().get().host), warning) << std::endl; + SWIFT_LOG_ASSERT(HostAddress::fromString(proxy->getStreamHost().get().host), warning); if (!localS5BProxies_) { localS5BProxies_ = std::vector<S5BProxyRequest::ref>(); } @@ -62,7 +62,7 @@ const boost::optional<std::vector<S5BProxyRequest::ref> >& SOCKS5BytestreamProxi } void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& sessionID) { - SWIFT_LOG(debug) << "session ID: " << sessionID << std::endl; + SWIFT_LOG(debug) << "session ID: " << sessionID; ProxyJIDClientSessionVector clientSessions; if (localS5BProxies_) { @@ -71,7 +71,7 @@ void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& session if (proxyHostAddress) { std::shared_ptr<Connection> conn = connectionFactory_->createConnection(); HostAddressPort addressPort = HostAddressPort(proxyHostAddress.get(), proxy->getStreamHost().get().port); - SWIFT_LOG_ASSERT(addressPort.isValid(), warning) << std::endl; + SWIFT_LOG_ASSERT(addressPort.isValid(), warning); std::shared_ptr<SOCKS5BytestreamClientSession> session = std::make_shared<SOCKS5BytestreamClientSession>(conn, addressPort, sessionID, timerFactory_); JID proxyJid = proxy->getStreamHost().get().jid; clientSessions.push_back(std::pair<JID, std::shared_ptr<SOCKS5BytestreamClientSession> >(proxyJid, session)); @@ -103,7 +103,7 @@ std::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::g i->second->stop(); } } - SWIFT_LOG_ASSERT(activeSession, warning) << "No active session with matching ID found." << std::endl; + SWIFT_LOG_ASSERT(activeSession, warning) << "No active session with matching ID found."; proxySessions_.erase(sessionID); @@ -144,7 +144,7 @@ void SOCKS5BytestreamProxiesManager::handleNameLookupResult(const std::vector<Ho } else { if (addresses.empty()) { - SWIFT_LOG(warning) << "S5B proxy hostname does not resolve." << std::endl; + SWIFT_LOG(warning) << "S5B proxy hostname does not resolve."; } else { // generate proxy per returned address diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp index 90c42dd..1efc54a 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -71,10 +71,10 @@ void SOCKS5BytestreamProxyFinder::handleProxyResponse(std::shared_ptr<GenericReq requester->onResponse.disconnect(boost::bind(&SOCKS5BytestreamProxyFinder::handleProxyResponse, this, requester, _1, _2)); pendingRequests.erase(requester); if (error) { - SWIFT_LOG(debug) << "ERROR" << std::endl; + SWIFT_LOG(debug) << "ERROR"; } else { if (request) { - SWIFT_LOG(debug) << "add request" << std::endl; + SWIFT_LOG(debug) << "add request"; proxyHosts.push_back(request); } } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp index f749735..7fc1388 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -48,12 +48,12 @@ SOCKS5BytestreamServerManager::SOCKS5BytestreamServerManager( } SOCKS5BytestreamServerManager::~SOCKS5BytestreamServerManager() { - SWIFT_LOG_ASSERT(!connectionServer, warning) << std::endl; - SWIFT_LOG_ASSERT(!getPublicIPRequest, warning) << std::endl; - SWIFT_LOG_ASSERT(!forwardPortRequest, warning) << std::endl; - SWIFT_LOG_ASSERT(state == Start, warning) << std::endl; + SWIFT_LOG_ASSERT(!connectionServer, warning); + SWIFT_LOG_ASSERT(!getPublicIPRequest, warning); + SWIFT_LOG_ASSERT(!forwardPortRequest, warning); + SWIFT_LOG_ASSERT(state == Start, warning); if (portMapping && !unforwardPortRequest) { - SWIFT_LOG(warning) << "Port forwarding still alive. Trying to remove it now." << std::endl; + SWIFT_LOG(warning) << "Port forwarding still alive. Trying to remove it now."; unforwardPortRequest = natTraverser->createRemovePortForwardingRequest(portMapping.get().getLocalPort(), portMapping.get().getPublicPort()); unforwardPortRequest->start(); } @@ -114,27 +114,27 @@ void SOCKS5BytestreamServerManager::initialize() { // Find a port to listen on assert(!connectionServer); - int port; + unsigned short port; for (port = LISTEN_PORTS_BEGIN; port < LISTEN_PORTS_END; ++port) { - SWIFT_LOG(debug) << "Trying to start server on port " << port << std::endl; + SWIFT_LOG(debug) << "Trying to start server on port " << port; connectionServer = connectionServerFactory->createConnectionServer(HostAddress::fromString("::").get(), port); boost::optional<ConnectionServer::Error> error = connectionServer->tryStart(); if (!error) { break; } else if (*error != ConnectionServer::Conflict) { - SWIFT_LOG(debug) << "Error starting server" << std::endl; + SWIFT_LOG(debug) << "Error starting server"; onInitialized(false); return; } connectionServer.reset(); } if (!connectionServer) { - SWIFT_LOG(debug) << "Unable to find an open port" << std::endl; + SWIFT_LOG(debug) << "Unable to find an open port"; onInitialized(false); return; } - SWIFT_LOG(debug) << "Server started succesfully" << std::endl; + SWIFT_LOG(debug) << "Server started succesfully"; connectionServerPort = port; // Start bytestream server. Should actually happen before the connectionserver is started @@ -164,7 +164,7 @@ void SOCKS5BytestreamServerManager::setupPortForwarding() { } // Forward ports - int port = server->getAddressPort().getPort(); + auto port = server->getAddressPort().getPort(); assert(!forwardPortRequest); portMapping = boost::optional<NATPortMapping>(); if ((forwardPortRequest = natTraverser->createForwardPortRequest(port, port))) { @@ -211,10 +211,10 @@ void SOCKS5BytestreamServerManager::stop() { void SOCKS5BytestreamServerManager::handleGetPublicIPResult(boost::optional<HostAddress> address) { if (address) { - SWIFT_LOG(debug) << "Public IP discovered as " << address.get().toString() << "." << std::endl; + SWIFT_LOG(debug) << "Public IP discovered as " << address.get().toString() << "."; } else { - SWIFT_LOG(debug) << "No public IP discoverable." << std::endl; + SWIFT_LOG(debug) << "No public IP discoverable."; } publicAddress = address; @@ -225,10 +225,10 @@ void SOCKS5BytestreamServerManager::handleGetPublicIPResult(boost::optional<Host void SOCKS5BytestreamServerManager::handleForwardPortResult(boost::optional<NATPortMapping> mapping) { if (mapping) { - SWIFT_LOG(debug) << "Mapping port was successful." << std::endl; + SWIFT_LOG(debug) << "Mapping port was successful."; } else { - SWIFT_LOG(debug) << "Mapping port has failed." << std::endl; + SWIFT_LOG(debug) << "Mapping port has failed."; } portMapping = mapping; @@ -243,7 +243,7 @@ void SOCKS5BytestreamServerManager::handleUnforwardPortResult(boost::optional<bo portMapping.reset(); } else { - SWIFT_LOG(warning) << "Failed to remove port forwarding." << std::endl; + SWIFT_LOG(warning) << "Failed to remove port forwarding."; } attemptedPortMapping_ = false; unforwardPortRequest.reset(); diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h index 3c06513..74578cc 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -78,7 +78,7 @@ namespace Swift { enum { Start, Initializing, Initialized } state; SOCKS5BytestreamServer* server; std::shared_ptr<ConnectionServer> connectionServer; - int connectionServerPort = -1; + unsigned short connectionServerPort = 0; std::shared_ptr<NATTraversalGetPublicIPRequest> getPublicIPRequest; std::shared_ptr<NATTraversalForwardPortRequest> forwardPortRequest; diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp index bc4e8e4..a4ab751 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -33,13 +33,13 @@ SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession( SOCKS5BytestreamServerSession::~SOCKS5BytestreamServerSession() { if (state != Finished && state != Initial) { - SWIFT_LOG(warning) << "SOCKS5BytestreamServerSession unfinished" << std::endl; + SWIFT_LOG(warning) << "SOCKS5BytestreamServerSession unfinished"; finish(); } } void SOCKS5BytestreamServerSession::start() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); dataReadConnection = connection->onDataRead.connect( boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); state = WaitingForAuthentication; @@ -50,7 +50,7 @@ void SOCKS5BytestreamServerSession::stop() { } void SOCKS5BytestreamServerSession::startSending(std::shared_ptr<ReadBytestream> stream) { - if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; return; } + if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!"; return; } readBytestream = stream; state = WritingData; @@ -62,7 +62,7 @@ void SOCKS5BytestreamServerSession::startSending(std::shared_ptr<ReadBytestream> } void SOCKS5BytestreamServerSession::startReceiving(std::shared_ptr<WriteBytestream> stream) { - if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; return; } + if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!"; return; } writeBytestream = stream; state = ReadingData; @@ -93,7 +93,7 @@ void SOCKS5BytestreamServerSession::handleDataAvailable() { } void SOCKS5BytestreamServerSession::handleDisconnected(const boost::optional<Connection::Error>& error) { - SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error") << std::endl; + SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error"); finish(error ? boost::optional<FileTransferError>(FileTransferError::PeerError) : boost::optional<FileTransferError>()); } @@ -109,7 +109,7 @@ void SOCKS5BytestreamServerSession::process() { if (i == 2 + authCount) { // Authentication message is complete if (i != unprocessedData.size()) { - SWIFT_LOG(debug) << "Junk after authentication mechanism" << std::endl; + SWIFT_LOG(debug) << "Junk after authentication mechanism"; } unprocessedData.clear(); connection->write(createSafeByteArray("\x05\x00", 2)); @@ -130,7 +130,7 @@ void SOCKS5BytestreamServerSession::process() { i += 2; if (i <= unprocessedData.size()) { if (i != unprocessedData.size()) { - SWIFT_LOG(debug) << "Junk after authentication mechanism" << std::endl; + SWIFT_LOG(debug) << "Junk after authentication mechanism"; } unprocessedData.clear(); streamID = byteArrayToString(requestID); @@ -138,15 +138,22 @@ void SOCKS5BytestreamServerSession::process() { SafeByteArray result = createSafeByteArray("\x05", 1); result.push_back(hasBytestream ? 0x0 : 0x4); append(result, createByteArray("\x00\x03", 2)); - result.push_back(boost::numeric_cast<unsigned char>(requestID.size())); + try { + result.push_back(boost::numeric_cast<unsigned char>(requestID.size())); + } + catch (const boost::numeric::bad_numeric_cast& e) { + SWIFT_LOG(warning) << "SOCKS5 request ID is too long (" << requestID.size() << "): " << e.what(); + finish(); + return; + } append(result, concat(requestID, createByteArray("\x00\x00", 2))); if (!hasBytestream) { - SWIFT_LOG(debug) << "Readstream or Wrtiestream with ID " << streamID << " not found!" << std::endl; + SWIFT_LOG(debug) << "Readstream or Wrtiestream with ID " << streamID << " not found!"; connection->write(result); finish(boost::optional<FileTransferError>(FileTransferError::PeerError)); } else { - SWIFT_LOG(debug) << "Found stream. Sent OK." << std::endl; + SWIFT_LOG(debug) << "Found stream. Sent OK."; connection->write(result); state = ReadyForTransfer; } @@ -178,7 +185,7 @@ void SOCKS5BytestreamServerSession::sendData() { } void SOCKS5BytestreamServerSession::finish(const boost::optional<FileTransferError>& error) { - SWIFT_LOG(debug) << "state: " << state << std::endl; + SWIFT_LOG(debug) << "state: " << state; if (state == Finished) { return; } diff --git a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp index f9057f8..2399cbe 100644 --- a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -58,7 +58,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(0, JID("foo@bar.com/baz"), IQ::Set)); IBB::ref ibb = stanzaChannel->sentStanzas[0]->getPayload<IBB>(); CPPUNIT_ASSERT_EQUAL(IBB::Open, ibb->getAction()); - CPPUNIT_ASSERT_EQUAL(1234, ibb->getBlockSize()); + CPPUNIT_ASSERT_EQUAL(1234u, ibb->getBlockSize()); CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID()); } diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp index 80667b6..fad02da 100644 --- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -238,7 +238,7 @@ private: std::shared_ptr<SafeByteArray> dataToSend; //ByteArray failingData = Hexify::unhexify("8417947d1d305c72c11520ea7d2c6e787396705e72c312c6ccc3f66613d7cae1b91b7ab48e8b59a17d559c15fb51"); //append(dataToSend, failingData); - //SWIFT_LOG(debug) << "hexed: " << Hexify::hexify(failingData) << std::endl; + //SWIFT_LOG(debug) << "hexed: " << Hexify::hexify(failingData); do { ByteArray rndArray = generateRandomByteArray(correctData->size()); dataToSend = createSafeByteArrayRef(vecptr(rndArray), rndArray.size()); @@ -255,7 +255,7 @@ private: void handleConnectionDataWritten(const SafeByteArray& data) { append(unprocessedInput, data); - //SWIFT_LOG(debug) << "unprocessedInput (" << unprocessedInput.size() << "): " << Hexify::hexify(unprocessedInput) << std::endl; + //SWIFT_LOG(debug) << "unprocessedInput (" << unprocessedInput.size() << "): " << Hexify::hexify(unprocessedInput); } void handleSessionReady(bool error) { diff --git a/Swiften/IDN/ICUConverter.cpp b/Swiften/IDN/ICUConverter.cpp index d6b0827..37ce708 100644 --- a/Swiften/IDN/ICUConverter.cpp +++ b/Swiften/IDN/ICUConverter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -19,6 +19,8 @@ using namespace Swift; using boost::numeric_cast; namespace { + static constexpr auto maxStringPrepLength = 1023; + typedef std::vector<UChar, SafeAllocator<UChar> > ICUString; const char* toConstCharArray(const std::string& input) { @@ -93,15 +95,8 @@ namespace { ICUString icuInput = convertToICUString(s); ICUString icuResult; UParseError parseError; - icuResult.resize(icuInput.size()); + icuResult.resize(maxStringPrepLength); int32_t icuResultLength = usprep_prepare(icuProfile.get(), vecptr(icuInput), numeric_cast<int32_t>(icuInput.size()), vecptr(icuResult), numeric_cast<int32_t>(icuResult.size()), USPREP_ALLOW_UNASSIGNED, &parseError, &status); - icuResult.resize(numeric_cast<size_t>(icuResultLength)); - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - icuResult.resize(numeric_cast<size_t>(icuResultLength)); - icuResultLength = usprep_prepare(icuProfile.get(), vecptr(icuInput), numeric_cast<int32_t>(icuInput.size()), vecptr(icuResult), numeric_cast<int32_t>(icuResult.size()), USPREP_ALLOW_UNASSIGNED, &parseError, &status); - icuResult.resize(numeric_cast<size_t>(icuResultLength)); - } if (U_FAILURE(status)) { return std::vector<char, SafeAllocator<char> >(); } diff --git a/Swiften/IDN/LibIDNConverter.cpp b/Swiften/IDN/LibIDNConverter.cpp index 0c01352..e2a87be 100644 --- a/Swiften/IDN/LibIDNConverter.cpp +++ b/Swiften/IDN/LibIDNConverter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -24,7 +24,7 @@ extern "C" { using namespace Swift; namespace { - static const int MAX_STRINGPREP_SIZE = 1024; + static const size_t MAX_STRINGPREP_SIZE = 1024; const Stringprep_profile* getLibIDNProfile(IDNConverter::StringPrepProfile profile) { switch(profile) { @@ -44,7 +44,8 @@ namespace { return ContainerType(); } - input.resize(MAX_STRINGPREP_SIZE); + // Ensure we have enough space for stringprepping, and that input is always NUL terminated + input.resize(std::max(MAX_STRINGPREP_SIZE, input.size() + 1)); if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast<Stringprep_profile_flags>(0), getLibIDNProfile(profile)) == 0) { return input; } @@ -77,6 +78,9 @@ boost::optional<std::string> LibIDNConverter::getIDNAEncoded(const std::string& if (idna_to_ascii_8z(domain.c_str(), &output, IDNA_USE_STD3_ASCII_RULES) == IDNA_SUCCESS) { std::string result(output); free(output); + if (result.size() > 255) { + return boost::optional<std::string>(); + } return result; } else { diff --git a/Swiften/IDN/PlatformIDNConverter.cpp b/Swiften/IDN/PlatformIDNConverter.cpp index c85d3b6..3564bb9 100644 --- a/Swiften/IDN/PlatformIDNConverter.cpp +++ b/Swiften/IDN/PlatformIDNConverter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -13,16 +13,17 @@ namespace Swift { -IDNConverter* PlatformIDNConverter::create() { +std::unique_ptr<IDNConverter> PlatformIDNConverter::create() { #if defined(HAVE_LIBIDN) - return new LibIDNConverter(); + return std::make_unique<LibIDNConverter>(); #elif defined(HAVE_ICU) - return new ICUConverter(); + return std::make_unique<ICUConverter>(); #else #if defined(NEED_IDN) #error "No IDN implementation" +#else + return {}; #endif - return nullptr; #endif } diff --git a/Swiften/IDN/PlatformIDNConverter.h b/Swiften/IDN/PlatformIDNConverter.h index 704f7a7..3b9a275 100644 --- a/Swiften/IDN/PlatformIDNConverter.h +++ b/Swiften/IDN/PlatformIDNConverter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Isode Limited. + * Copyright (c) 2012-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,10 +8,12 @@ #include <Swiften/Base/API.h> +#include <memory> + namespace Swift { class IDNConverter; namespace PlatformIDNConverter { - SWIFTEN_API IDNConverter* create(); + SWIFTEN_API std::unique_ptr<IDNConverter> create(); } } diff --git a/Swiften/IDN/SConscript b/Swiften/IDN/SConscript index 28596f7..0afad0e 100644 --- a/Swiften/IDN/SConscript +++ b/Swiften/IDN/SConscript @@ -23,6 +23,7 @@ swiften_env.Append(SWIFTEN_OBJECTS = [objects]) if env["TEST"] : test_env = myenv.Clone() test_env.UseFlags(swiften_env["CPPUNIT_FLAGS"]) + test_env.UseFlags(myenv.get("GOOGLETEST_FLAGS", "")) env.Append(UNITTEST_OBJECTS = test_env.SwiftenObject([ File("UnitTest/IDNConverterTest.cpp"), File("UnitTest/UTF8ValidatorTest.cpp") diff --git a/Swiften/IDN/UnitTest/IDNConverterTest.cpp b/Swiften/IDN/UnitTest/IDNConverterTest.cpp index 508a28c..77a1ece 100644 --- a/Swiften/IDN/UnitTest/IDNConverterTest.cpp +++ b/Swiften/IDN/UnitTest/IDNConverterTest.cpp @@ -1,64 +1,98 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <memory> -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/extensions/TestFactoryRegistry.h> +#include <gtest/gtest.h> #include <Swiften/IDN/IDNConverter.h> #include <Swiften/IDN/PlatformIDNConverter.h> using namespace Swift; -class IDNConverterTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(IDNConverterTest); - CPPUNIT_TEST(testStringPrep); - CPPUNIT_TEST(testStringPrep_Empty); - CPPUNIT_TEST(testGetEncoded); - CPPUNIT_TEST(testGetEncoded_International); - CPPUNIT_TEST(testGetEncoded_Invalid); - CPPUNIT_TEST_SUITE_END(); - - public: - void setUp() { - testling = std::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); - } - - void testStringPrep() { - std::string result = testling->getStringPrepared("tron\xc3\x87on", IDNConverter::NamePrep); - - CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), result); - } - - void testStringPrep_Empty() { - CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::NamePrep)); - CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::XMPPNodePrep)); - CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::XMPPResourcePrep)); - } - - void testGetEncoded() { - boost::optional<std::string> result = testling->getIDNAEncoded("www.swift.im"); - CPPUNIT_ASSERT(!!result); - CPPUNIT_ASSERT_EQUAL(std::string("www.swift.im"), *result); - } - - void testGetEncoded_International() { - boost::optional<std::string> result = testling->getIDNAEncoded("www.tron\xc3\x87on.com"); - CPPUNIT_ASSERT(!!result); - CPPUNIT_ASSERT_EQUAL(std::string("www.xn--tronon-zua.com"), *result); - } - - void testGetEncoded_Invalid() { - boost::optional<std::string> result = testling->getIDNAEncoded("www.foo,bar.com"); - CPPUNIT_ASSERT(!result); - } - - private: - std::shared_ptr<IDNConverter> testling; +class IDNConverterTest : public ::testing::Test { + +protected: + virtual void SetUp() { + testling_ = std::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); + } + + std::shared_ptr<IDNConverter> testling_; }; -CPPUNIT_TEST_SUITE_REGISTRATION(IDNConverterTest); +TEST_F(IDNConverterTest, testStringPrep) { + std::string result = testling_->getStringPrepared("tron\xc3\x87on", IDNConverter::NamePrep); + + ASSERT_EQ(std::string("tron\xc3\xa7on"), result); +} + +TEST_F(IDNConverterTest, testStringPrep_Empty) { + ASSERT_EQ(std::string(""), testling_->getStringPrepared("", IDNConverter::NamePrep)); + ASSERT_EQ(std::string(""), testling_->getStringPrepared("", IDNConverter::XMPPNodePrep)); + ASSERT_EQ(std::string(""), testling_->getStringPrepared("", IDNConverter::XMPPResourcePrep)); +} + +TEST_F(IDNConverterTest, testStringPrep_MaximumOutputSize) { + const std::string input(1023, 'x'); + ASSERT_EQ(input, testling_->getStringPrepared(input, IDNConverter::NamePrep)); + ASSERT_EQ(input, testling_->getStringPrepared(input, IDNConverter::XMPPNodePrep)); + ASSERT_EQ(input, testling_->getStringPrepared(input, IDNConverter::XMPPResourcePrep)); +} + +TEST_F(IDNConverterTest, testStringPrep_TooLong) { + const std::string input(1024, 'x'); + ASSERT_THROW(testling_->getStringPrepared(input, IDNConverter::NamePrep), std::exception); + ASSERT_THROW(testling_->getStringPrepared(input, IDNConverter::XMPPNodePrep), std::exception); + ASSERT_THROW(testling_->getStringPrepared(input, IDNConverter::XMPPResourcePrep), std::exception); +} + +TEST_F(IDNConverterTest, testStringPrep_ShrinkingBelow1023) { + std::string input; + std::string expected; + // The four byte \u03b1\u0313 UTF-8 string will shrink to the three byte \u1f00 + for (auto i = 0; i < 300; ++i) { + input +="\xce\xb1\xcc\x93"; // UTF-8 repesentation of U+03B1 U+0313 + expected += "\xe1\xbc\x80"; // UTF-8 representation of U+1F00 + } + ASSERT_EQ(expected, testling_->getStringPrepared(input, IDNConverter::NamePrep)); + ASSERT_EQ(expected, testling_->getStringPrepared(input, IDNConverter::XMPPNodePrep)); + ASSERT_EQ(expected, testling_->getStringPrepared(input, IDNConverter::XMPPResourcePrep)); +} + +TEST_F(IDNConverterTest, testGetEncoded) { + boost::optional<std::string> result = testling_->getIDNAEncoded("www.swift.im"); + ASSERT_TRUE(!!result); + ASSERT_EQ(std::string("www.swift.im"), *result); +} + +TEST_F(IDNConverterTest, testGetEncoded_International) { + boost::optional<std::string> result = testling_->getIDNAEncoded("www.tron\xc3\x87on.com"); + ASSERT_TRUE(result); + ASSERT_EQ(std::string("www.xn--tronon-zua.com"), *result); +} + +TEST_F(IDNConverterTest, testGetEncoded_Invalid) { + boost::optional<std::string> result = testling_->getIDNAEncoded("www.foo,bar.com"); + ASSERT_FALSE(result); +} + +TEST_F(IDNConverterTest, testRFC1035LengthRestrictions) { + // label size check, 63 octets or less + ASSERT_TRUE(testling_->getIDNAEncoded(std::string(63, 'a') + ".example")); + ASSERT_TRUE(testling_->getIDNAEncoded(std::string(63, 'a') + "." + std::string(63, 'a') + ".example")); + ASSERT_FALSE(testling_->getIDNAEncoded(std::string(64, 'a') + "." + std::string(63, 'a') + ".example")); + ASSERT_FALSE(testling_->getIDNAEncoded(std::string(63, 'a') + "." + std::string(64, 'a') + ".example")); + ASSERT_FALSE(testling_->getIDNAEncoded(std::string(0, 'a') + "." + std::string(63, 'a') + ".example")); + ASSERT_FALSE(testling_->getIDNAEncoded(std::string(63, 'a') + "." + std::string(0, 'a') + ".example")); + + // domain name 255 octets or less + ASSERT_TRUE(testling_->getIDNAEncoded(std::string(63, 'a') + ".example")); + ASSERT_TRUE(testling_->getIDNAEncoded(std::string(63, 'a') + "." + std::string(63, 'a') + ".example")); + ASSERT_TRUE(testling_->getIDNAEncoded(std::string(63, 'a') + "." + std::string(63, 'a') + "." + std::string(63, 'a') + ".example")); + ASSERT_TRUE(testling_->getIDNAEncoded(std::string(63, 'a') + "." + std::string(63, 'a') + "." + std::string(63, 'a') + "." + std::string(55, 'a') + ".example")); + ASSERT_FALSE(testling_->getIDNAEncoded(std::string(63, 'a') + "." + std::string(63, 'a') + "." + std::string(63, 'a') + "." + std::string(56, 'a') + ".example")); + ASSERT_FALSE(testling_->getIDNAEncoded(std::string(63, 'a') + "." + std::string(56, 'a') + "." + std::string(63, 'a') + "." + std::string(63, 'a') + ".example")); +} diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index c82674d..eb72014 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp @@ -1,25 +1,19 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ -#define SWIFTEN_CACHE_JID_PREP - #include <sstream> #include <string> #include <vector> -#ifdef SWIFTEN_CACHE_JID_PREP -#include <mutex> -#include <unordered_map> -#endif - #include <boost/optional.hpp> #include <Swiften/Base/String.h> #include <Swiften/IDN/IDNConverter.h> #include <Swiften/JID/JID.h> +#include <Swiften/Network/HostAddress.h> #ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER #include <memory> @@ -28,15 +22,6 @@ using namespace Swift; -#ifdef SWIFTEN_CACHE_JID_PREP -typedef std::unordered_map<std::string, std::string> PrepCache; - -static std::mutex namePrepCacheMutex; -static PrepCache nodePrepCache; -static PrepCache domainPrepCache; -static PrepCache resourcePrepCache; -#endif - static const std::vector<char> escapedChars = {' ', '"', '&', '\'', '/', '<', '>', '@', ':'}; static IDNConverter* idnConverter = nullptr; @@ -87,6 +72,33 @@ JID::JID(const std::string& node, const std::string& domain, const std::string& nameprepAndSetComponents(node, domain, resource); } +JID::JID(const JID& other) { + this->operator=(other); +} + +JID::JID(JID&& other) { + this->operator=(std::move(other)); +} + +JID& JID::operator=(const JID& other) { + valid_ = other.valid_; + node_ = other.node_; + domain_ = other.domain_; + hasResource_ = other.hasResource_; + resource_ = other.resource_; + return *this; +} + +JID& JID::operator=(JID&& other) { + valid_ = other.valid_; + other.valid_ = false; + node_ = std::move(other.node_); + domain_ = std::move(other.domain_); + hasResource_ = other.hasResource_; + resource_ = std::move(other.resource_); + return *this; +} + void JID::initializeFromString(const std::string& jid) { if (String::beginsWith(jid, '@')) { valid_ = false; @@ -104,74 +116,76 @@ void JID::initializeFromString(const std::string& jid) { hasResource_ = false; bare = jid; } - std::pair<std::string,std::string> nodeAndDomain = String::getSplittedAtFirst(bare, '@'); - if (nodeAndDomain.second.empty()) { - nameprepAndSetComponents("", nodeAndDomain.first, resource); + auto firstMatch = bare.find('@'); + if (firstMatch != bare.npos) { + nameprepAndSetComponents(bare.substr(0, firstMatch), bare.substr(firstMatch + 1), resource); } else { - nameprepAndSetComponents(nodeAndDomain.first, nodeAndDomain.second, resource); + nameprepAndSetComponents("", bare, resource); } } - -void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { - if (domain.empty() || !idnConverter->getIDNAEncoded(domain)) { +void JID::setComponents(const std::string& node, const std::string& domain, const std::string& resource) { + domain_ = domain; + try { + node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); + resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); + } + catch (...) { valid_ = false; return; } +} - if (hasResource_ && resource.empty()) { +void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { + if (domain.empty() || (hasResource_ && resource.empty())) { valid_ = false; return; } -#ifndef SWIFTEN_CACHE_JID_PREP - node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); - domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); - resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); -#else - std::unique_lock<std::mutex> lock(namePrepCacheMutex); - - std::pair<PrepCache::iterator, bool> r; - - r = nodePrepCache.insert(std::make_pair(node, std::string())); - if (r.second) { - try { - r.first->second = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); - } - catch (...) { - nodePrepCache.erase(r.first); - valid_ = false; + + // Handling IPv6 addresses according to RFC 3986 rules + // saying that they are enclosed in square brackets + // which we have to remove when passing to HostAddress + if (domain.size() > 2 && domain.front() == '[' && domain.back() == ']') { + auto inner = std::string(domain.begin() + 1, domain.end() - 1); + auto hostAddress = HostAddress::fromString(inner); + if (hostAddress && hostAddress->isValid()) { + setComponents(node, domain, resource); return; } } - node_ = r.first->second; - r = domainPrepCache.insert(std::make_pair(domain, std::string())); - if (r.second) { - try { - r.first->second = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); - } - catch (...) { - domainPrepCache.erase(r.first); - valid_ = false; + const auto isAnyOfNonNumericAndNotDot = std::any_of(std::begin(domain), std::end(domain), [](char c) {return !::isdigit(c) && c != '.'; }); + const auto isDomainAllNumeric = std::all_of(std::begin(domain), std::end(domain), [](char c) {return ::isdigit(c) ; }); + + //Prevent Windows validating non-dotted integers as OK if it can unpack them + if (!isAnyOfNonNumericAndNotDot && !isDomainAllNumeric) { + auto hostAddress = HostAddress::fromString(domain); + if (hostAddress && hostAddress->isValid()) { + setComponents(node, domain, resource); return; } } - domain_ = r.first->second; - r = resourcePrepCache.insert(std::make_pair(resource, std::string())); - if (r.second) { - try { - r.first->second = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); + if (!isAnyOfNonNumericAndNotDot || !idnConverter->getIDNAEncoded(domain)) { + valid_ = false; + return; + } + + try { + node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); + if (domain.back() == '.') { + domain_ = idnConverter->getStringPrepared(domain.substr(0, domain.size() - 1), IDNConverter::NamePrep); } - catch (...) { - resourcePrepCache.erase(r.first); - valid_ = false; - return; + else { + domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); } + resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); + } + catch (...) { + valid_ = false; + return; } - resource_ = r.first->second; -#endif if (domain_.empty()) { valid_ = false; diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h index dc92f53..aecc7cb 100644 --- a/Swiften/JID/JID.h +++ b/Swiften/JID/JID.h @@ -75,6 +75,11 @@ namespace Swift { */ JID(const std::string& node, const std::string& domain, const std::string& resource); + JID(const JID& other); + JID(JID&& other); + JID& operator=(const JID& other); + JID& operator=(JID&& other); + /** * @return Is a correctly-formatted JID. */ @@ -184,6 +189,7 @@ namespace Swift { private: void nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource); + void setComponents(const std::string& node, const std::string& domain, const std::string& resource); void initializeFromString(const std::string&); private: diff --git a/Swiften/JID/UnitTest/JIDTest.cpp b/Swiften/JID/UnitTest/JIDTest.cpp index ca3e5ae..fc7583f 100644 --- a/Swiften/JID/UnitTest/JIDTest.cpp +++ b/Swiften/JID/UnitTest/JIDTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,11 +20,20 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_TEST(testConstructorWithString_NoNode); CPPUNIT_TEST(testConstructorWithString_EmptyResource); CPPUNIT_TEST(testConstructorWithString_OnlyDomain); + CPPUNIT_TEST(testConstructorWithString_OnlyDomainWithDot); + CPPUNIT_TEST(testConstructorWithString_OnlyDomainDotStrippedOff); + CPPUNIT_TEST(testConstructorWithString_InvalidOnlyDomainSingleDot); CPPUNIT_TEST(testConstructorWithString_InvalidDomain); + CPPUNIT_TEST(testConstructorWithString_InvalidDomainOnlyDigits); + CPPUNIT_TEST(testConstructorWithString_InvalidDomainEmptyLabel); CPPUNIT_TEST(testConstructorWithString_UpperCaseNode); CPPUNIT_TEST(testConstructorWithString_UpperCaseDomain); CPPUNIT_TEST(testConstructorWithString_UpperCaseResource); CPPUNIT_TEST(testConstructorWithString_EmptyNode); + CPPUNIT_TEST(testConstructorWithString_EmptyDomain); + CPPUNIT_TEST(testConstructorWithString_EmptyDomainWithResource); + CPPUNIT_TEST(testConstructorWithString_DotDomain); + CPPUNIT_TEST(testConstructorWithString_DotDomainWithResource); CPPUNIT_TEST(testConstructorWithString_IllegalResource); CPPUNIT_TEST(testConstructorWithString_SpacesInNode); CPPUNIT_TEST(testConstructorWithStrings); @@ -62,6 +71,13 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_TEST(testGetEscapedNode_BackslashAtEnd); CPPUNIT_TEST(testGetUnescapedNode); CPPUNIT_TEST(testGetUnescapedNode_XEP106Examples); + CPPUNIT_TEST(testStringPrepFailures); + CPPUNIT_TEST(testConstructorWithString_DomainIPv4); + CPPUNIT_TEST(testConstructorWithString_DomainNOTIPv4); + CPPUNIT_TEST(testConstructorWithString_ValidDomainNOTIPv4); + CPPUNIT_TEST(testConstructorWithString_DomainIPv6); + CPPUNIT_TEST(testConstructorWithString_DomainInvalidIPv6); + CPPUNIT_TEST(testConstructorWithString_DomainIPv6NoBrackets); CPPUNIT_TEST_SUITE_END(); public: @@ -119,10 +135,42 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_ASSERT(testling.isValid()); } + void testConstructorWithString_OnlyDomainWithDot() { + JID testling("bar."); + + CPPUNIT_ASSERT_EQUAL(std::string(""), testling.getNode()); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), testling.getDomain()); + CPPUNIT_ASSERT_EQUAL(std::string(""), testling.getResource()); + CPPUNIT_ASSERT(testling.isBare()); + CPPUNIT_ASSERT(testling.isValid()); + } + + void testConstructorWithString_OnlyDomainDotStrippedOff() { + JID testling("foo.@bar./resource."); + + CPPUNIT_ASSERT_EQUAL(std::string("foo."), testling.getNode()); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), testling.getDomain()); + CPPUNIT_ASSERT_EQUAL(std::string("resource."), testling.getResource()); + CPPUNIT_ASSERT(!testling.isBare()); + CPPUNIT_ASSERT(testling.isValid()); + } + + void testConstructorWithString_InvalidOnlyDomainSingleDot() { + CPPUNIT_ASSERT(!JID(".").isValid()); + } + void testConstructorWithString_InvalidDomain() { CPPUNIT_ASSERT(!JID("foo@bar,baz").isValid()); } + void testConstructorWithString_InvalidDomainOnlyDigits() { + CPPUNIT_ASSERT(!JID("1234").isValid()); + } + + void testConstructorWithString_InvalidDomainEmptyLabel() { + CPPUNIT_ASSERT(!JID("foo@bar..").isValid()); + } + void testConstructorWithString_UpperCaseNode() { JID testling("Fo\xCE\xA9@bar"); @@ -151,6 +199,36 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_ASSERT(!testling.isValid()); } + void testConstructorWithString_EmptyDomain() { + JID testling("bar@"); + + CPPUNIT_ASSERT(!testling.isValid()); + } + + void testStringPrepFailures() { + CPPUNIT_ASSERT_EQUAL(false, JID("foo@bar", "example.com").isValid()); + CPPUNIT_ASSERT_EQUAL(false, JID("foo^", "example*com").isValid()); + CPPUNIT_ASSERT_EQUAL(false, JID("foobar", "example^com").isValid()); + } + + void testConstructorWithString_EmptyDomainWithResource() { + JID testling("bar@/resource"); + + CPPUNIT_ASSERT(!testling.isValid()); + } + + void testConstructorWithString_DotDomain() { + JID testling("bar@."); + + CPPUNIT_ASSERT(!testling.isValid()); + } + + void testConstructorWithString_DotDomainWithResource() { + JID testling("bar@./resource"); + + CPPUNIT_ASSERT(!testling.isValid()); + } + void testConstructorWithString_IllegalResource() { JID testling("foo@bar.com/\xd8\xb1\xd9\x85\xd9\x82\xd9\x87\x20\xd8\xaa\xd8\xb1\xd9\x86\xd8\xb3\x20"); @@ -425,6 +503,46 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(std::string("c:\\cool stuff"), JID("c\\3a\\cool\\20stuff@example.com").getUnescapedNode()); CPPUNIT_ASSERT_EQUAL(std::string("c:\\5commas"), JID("c\\3a\\5c5commas@example.com").getUnescapedNode()); } + + void testConstructorWithString_DomainIPv4() { + JID testling("foo@192.34.12.1/resource"); + + CPPUNIT_ASSERT_EQUAL(std::string("foo"), testling.getNode()); + CPPUNIT_ASSERT_EQUAL(std::string("192.34.12.1"), testling.getDomain()); + CPPUNIT_ASSERT_EQUAL(std::string("resource"), testling.getResource()); + CPPUNIT_ASSERT(!testling.isBare()); + CPPUNIT_ASSERT(testling.isValid()); + } + + void testConstructorWithString_DomainNOTIPv4() { + JID testling("foo@500.34.12.1/resource"); + CPPUNIT_ASSERT(!testling.isValid()); + } + + void testConstructorWithString_ValidDomainNOTIPv4() { + JID testling("foo@500.34.12.1a/resource"); + CPPUNIT_ASSERT(testling.isValid()); + } + + void testConstructorWithString_DomainIPv6() { + JID testling("foo@[fe80::a857:33ff:febd:3580]/resource"); + + CPPUNIT_ASSERT_EQUAL(std::string("foo"), testling.getNode()); + CPPUNIT_ASSERT_EQUAL(std::string("[fe80::a857:33ff:febd:3580]"), testling.getDomain()); + CPPUNIT_ASSERT_EQUAL(std::string("resource"), testling.getResource()); + CPPUNIT_ASSERT(!testling.isBare()); + CPPUNIT_ASSERT(testling.isValid()); + } + + void testConstructorWithString_DomainInvalidIPv6() { + JID testling("foo@[1111::a1111:1111:111!:!!!!]/resource"); + CPPUNIT_ASSERT(!testling.isValid()); + } + + void testConstructorWithString_DomainIPv6NoBrackets() { + JID testling("foo@fe80::a857:33ff:febd:3580/resource"); + CPPUNIT_ASSERT(!testling.isValid()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(JIDTest); diff --git a/Swiften/Jingle/AbstractJingleSessionListener.cpp b/Swiften/Jingle/AbstractJingleSessionListener.cpp index 20edf15..56d2e92 100644 --- a/Swiften/Jingle/AbstractJingleSessionListener.cpp +++ b/Swiften/Jingle/AbstractJingleSessionListener.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,31 +11,31 @@ using namespace Swift; void AbstractJingleSessionListener::handleSessionAcceptReceived(const JingleContentID&, std::shared_ptr<JingleDescription>, std::shared_ptr<JingleTransportPayload>) { - SWIFT_LOG(warning) << "Unimplemented" << std::endl; + SWIFT_LOG(warning) << "Unimplemented"; } void AbstractJingleSessionListener::handleSessionInfoReceived(std::shared_ptr<JinglePayload>) { - SWIFT_LOG(warning) << "Unimplemented" << std::endl; + SWIFT_LOG(warning) << "Unimplemented"; } void AbstractJingleSessionListener::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason>) { - SWIFT_LOG(warning) << "Unimplemented" << std::endl; + SWIFT_LOG(warning) << "Unimplemented"; } void AbstractJingleSessionListener::handleTransportAcceptReceived(const JingleContentID&, std::shared_ptr<JingleTransportPayload>) { - SWIFT_LOG(warning) << "Unimplemented" << std::endl; + SWIFT_LOG(warning) << "Unimplemented"; } void AbstractJingleSessionListener::handleTransportInfoReceived(const JingleContentID&, std::shared_ptr<JingleTransportPayload>) { - SWIFT_LOG(warning) << "Unimplemented" << std::endl; + SWIFT_LOG(warning) << "Unimplemented"; } void AbstractJingleSessionListener::handleTransportRejectReceived(const JingleContentID&, std::shared_ptr<JingleTransportPayload>) { - SWIFT_LOG(warning) << "Unimplemented" << std::endl; + SWIFT_LOG(warning) << "Unimplemented"; } void AbstractJingleSessionListener::handleTransportReplaceReceived(const JingleContentID&, std::shared_ptr<JingleTransportPayload>) { - SWIFT_LOG(warning) << "Unimplemented" << std::endl; + SWIFT_LOG(warning) << "Unimplemented"; } void AbstractJingleSessionListener::handleTransportInfoAcknowledged(const std::string&) { diff --git a/Swiften/Jingle/JingleResponder.cpp b/Swiften/Jingle/JingleResponder.cpp index 09bb234..af9808e 100644 --- a/Swiften/Jingle/JingleResponder.cpp +++ b/Swiften/Jingle/JingleResponder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -32,17 +32,17 @@ bool JingleResponder::handleSetRequest(const JID& from, const JID& to, const std JingleSessionImpl::ref session = std::make_shared<JingleSessionImpl>(payload->getInitiator(), from, payload->getSessionID(), router); sessionManager->handleIncomingSession(from, to, session, payload->getContents()); } else { - SWIFT_LOG(debug) << "Unable to create Jingle session due to initiator not being a full JID." << std::endl; + SWIFT_LOG(debug) << "Unable to create Jingle session due to initiator not being a full JID."; } } } else { JingleSessionImpl::ref session; if (payload->getInitiator().isValid()) { - SWIFT_LOG(debug) << "Lookup session by initiator." << std::endl; + SWIFT_LOG(debug) << "Lookup session by initiator."; session = sessionManager->getSession(payload->getInitiator(), payload->getSessionID()); } else { - SWIFT_LOG(debug) << "Lookup session by from attribute." << std::endl; + SWIFT_LOG(debug) << "Lookup session by from attribute."; session = sessionManager->getSession(from, payload->getSessionID()); } if (session) { diff --git a/Swiften/Jingle/JingleSessionImpl.cpp b/Swiften/Jingle/JingleSessionImpl.cpp index 06aa039..b4c5d03 100644 --- a/Swiften/Jingle/JingleSessionImpl.cpp +++ b/Swiften/Jingle/JingleSessionImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,7 +23,7 @@ namespace Swift { JingleSessionImpl::JingleSessionImpl(const JID& initiator, const JID& peerJID, const std::string& id, IQRouter* router) : JingleSession(initiator, id), iqRouter(router), peerJID(peerJID) { - SWIFT_LOG(debug) << "initiator: " << initiator << ", peerJID: " << peerJID << std::endl; + SWIFT_LOG(debug) << "initiator: " << initiator << ", peerJID: " << peerJID; } void JingleSessionImpl::handleIncomingAction(JinglePayload::ref action) { @@ -38,7 +38,7 @@ void JingleSessionImpl::handleIncomingAction(JinglePayload::ref action) { JingleContentPayload::ref content = action->getPayload<JingleContentPayload>(); if (!content) { - SWIFT_LOG(debug) << "no content payload!" << std::endl; + SWIFT_LOG(debug) << "no content payload!"; return; } JingleContentID contentID(content->getName(), content->getCreator()); diff --git a/Swiften/Jingle/JingleSessionManager.cpp b/Swiften/Jingle/JingleSessionManager.cpp index f7ed58e..083554a 100644 --- a/Swiften/Jingle/JingleSessionManager.cpp +++ b/Swiften/Jingle/JingleSessionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -38,7 +38,7 @@ void JingleSessionManager::removeIncomingSessionHandler(IncomingJingleSessionHan void JingleSessionManager::registerOutgoingSession(const JID& initiator, JingleSessionImpl::ref session) { sessions.insert(std::make_pair(JIDSession(initiator, session->getID()), session)); - SWIFT_LOG(debug) << "Added session " << session->getID() << " for initiator " << initiator.toString() << std::endl; + SWIFT_LOG(debug) << "Added session " << session->getID() << " for initiator " << initiator.toString(); } void JingleSessionManager::handleIncomingSession(const JID& initiator, const JID& recipient, JingleSessionImpl::ref session, const std::vector<JingleContentPayload::ref>& contents) { diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp index 1b79946..66b4ae8 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -25,7 +25,7 @@ std::shared_ptr<DNSSDBrowseQuery> AvahiQuerier::createBrowseQuery() { return std::make_shared<AvahiBrowseQuery>(shared_from_this(), eventLoop); } -std::shared_ptr<DNSSDRegisterQuery> AvahiQuerier::createRegisterQuery(const std::string& name, int port, const ByteArray& info) { +std::shared_ptr<DNSSDRegisterQuery> AvahiQuerier::createRegisterQuery(const std::string& name, unsigned short port, const ByteArray& info) { return std::make_shared<AvahiRegisterQuery>(name, port, info, shared_from_this(), eventLoop); } diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h index 5dce19d..73dd11d 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -30,7 +30,7 @@ namespace Swift { std::shared_ptr<DNSSDBrowseQuery> createBrowseQuery(); std::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( - const std::string& name, int port, const ByteArray& info); + const std::string& name, unsigned short port, const ByteArray& info); std::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery( const DNSSDServiceID&); std::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery( diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h index 68281d0..b780043 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -18,7 +18,7 @@ namespace Swift { class AvahiRegisterQuery : public DNSSDRegisterQuery, public AvahiQuery { public: - AvahiRegisterQuery(const std::string& name, int port, const ByteArray& txtRecord, std::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), name(name), port(port), txtRecord(txtRecord), group(0) { + AvahiRegisterQuery(const std::string& name, unsigned short port, const ByteArray& txtRecord, std::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), name(name), port(port), txtRecord(txtRecord), group(0) { } void registerService(); @@ -50,7 +50,7 @@ namespace Swift { private: std::string name; - int port; + unsigned short port; ByteArray txtRecord; AvahiEntryGroup* group; }; diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp index 08de722..262add3 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -15,7 +15,7 @@ namespace Swift { AvahiResolveHostnameQuery::AvahiResolveHostnameQuery(const std::string& hostname, int, std::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), hostname(hostname) { - SWIFT_LOG(debug) << "Resolving hostname " << hostname << std::endl; + SWIFT_LOG(debug) << "Resolving hostname " << hostname; } void AvahiResolveHostnameQuery::run() { diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h index c049ed2..63f34db 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -50,12 +50,17 @@ namespace Swift { } else { //std::cout << "Discovered service: name:" << name << " domain:" << domain << " type: " << type << std::endl; - DNSSDServiceID service(name, domain, type, boost::numeric_cast<int>(interfaceIndex)); - if (flags & kDNSServiceFlagsAdd) { - eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); + try { + DNSSDServiceID service(name, domain, type, boost::numeric_cast<int>(interfaceIndex)); + if (flags & kDNSServiceFlagsAdd) { + eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); + } + else { + eventLoop->postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); + } } - else { - eventLoop->postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); + catch (...) { + eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); } } } diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp index 0906ffc..551421e 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,6 +11,7 @@ #include <unistd.h> #include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/Log.h> #include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h> #include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h> #include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h> @@ -36,7 +37,7 @@ std::shared_ptr<DNSSDBrowseQuery> BonjourQuerier::createBrowseQuery() { return std::make_shared<BonjourBrowseQuery>(shared_from_this(), eventLoop); } -std::shared_ptr<DNSSDRegisterQuery> BonjourQuerier::createRegisterQuery(const std::string& name, int port, const ByteArray& info) { +std::shared_ptr<DNSSDRegisterQuery> BonjourQuerier::createRegisterQuery(const std::string& name, unsigned short port, const ByteArray& info) { return std::make_shared<BonjourRegisterQuery>(name, port, info, shared_from_this(), eventLoop); } diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h index 77326bc..6af1c1f 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -25,7 +25,7 @@ namespace Swift { std::shared_ptr<DNSSDBrowseQuery> createBrowseQuery(); std::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( - const std::string& name, int port, const ByteArray& info); + const std::string& name, unsigned short port, const ByteArray& info); std::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery( const DNSSDServiceID&); std::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery( diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h index 8b2e955..cc95d64 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,12 +20,21 @@ namespace Swift { class BonjourRegisterQuery : public DNSSDRegisterQuery, public BonjourQuery { public: - BonjourRegisterQuery(const std::string& name, int port, const ByteArray& txtRecord, std::shared_ptr<BonjourQuerier> querier, EventLoop* eventLoop) : BonjourQuery(querier, eventLoop) { + BonjourRegisterQuery(const std::string& name, unsigned short port, const ByteArray& txtRecord, std::shared_ptr<BonjourQuerier> querier, EventLoop* eventLoop) : BonjourQuery(querier, eventLoop) { + unsigned short recordSize = 0; + try { + recordSize = boost::numeric_cast<unsigned short>(txtRecord.size()); + } + catch (const boost::numeric::bad_numeric_cast&) { + SWIFT_LOG(warning) << "Bonjour TXT record is too long (" << txtRecord.size() << " bytes), not registring service"; + return; + } DNSServiceErrorType result = DNSServiceRegister( - &sdRef, 0, 0, name.c_str(), "_presence._tcp", nullptr, nullptr, boost::numeric_cast<unsigned short>(port), - boost::numeric_cast<unsigned short>(txtRecord.size()), vecptr(txtRecord), + &sdRef, 0, 0, name.c_str(), "_presence._tcp", nullptr, nullptr, port, + recordSize, vecptr(txtRecord), &BonjourRegisterQuery::handleServiceRegisteredStatic, this); if (result != kDNSServiceErr_NoError) { + SWIFT_LOG(warning) << "Failed to register Bonjour service"; sdRef = nullptr; } } @@ -45,7 +54,12 @@ namespace Swift { void updateServiceInfo(const ByteArray& txtRecord) { std::lock_guard<std::mutex> lock(sdRefMutex); - DNSServiceUpdateRecord(sdRef, nullptr, 0, boost::numeric_cast<unsigned short>(txtRecord.size()), vecptr(txtRecord), 0); + try { + DNSServiceUpdateRecord(sdRef, nullptr, 0, boost::numeric_cast<unsigned short>(txtRecord.size()), vecptr(txtRecord), 0); + } + catch (const boost::numeric::bad_numeric_cast&) { + SWIFT_LOG(warning) << "Bonjour TXT record is too long (" << txtRecord.size() << " bytes), not updating service record"; + } } private: diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h index dbf3f0e..61f000e 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,11 +23,16 @@ namespace Swift { class BonjourResolveHostnameQuery : public DNSSDResolveHostnameQuery, public BonjourQuery { public: BonjourResolveHostnameQuery(const std::string& hostname, int interfaceIndex, std::shared_ptr<BonjourQuerier> querier, EventLoop* eventLoop) : BonjourQuery(querier, eventLoop) { - DNSServiceErrorType result = DNSServiceGetAddrInfo( - &sdRef, 0, boost::numeric_cast<unsigned int>(interfaceIndex), kDNSServiceProtocol_IPv4, - hostname.c_str(), - &BonjourResolveHostnameQuery::handleHostnameResolvedStatic, this); - if (result != kDNSServiceErr_NoError) { + try { + DNSServiceErrorType result = DNSServiceGetAddrInfo( + &sdRef, 0, boost::numeric_cast<unsigned int>(interfaceIndex), kDNSServiceProtocol_IPv4, + hostname.c_str(), + &BonjourResolveHostnameQuery::handleHostnameResolvedStatic, this); + if (result != kDNSServiceErr_NoError) { + sdRef = nullptr; + } + } + catch (...) { sdRef = nullptr; } } diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h index 7a5555e..4baf87b 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,12 +20,17 @@ namespace Swift { class BonjourResolveServiceQuery : public DNSSDResolveServiceQuery, public BonjourQuery { public: BonjourResolveServiceQuery(const DNSSDServiceID& service, std::shared_ptr<BonjourQuerier> querier, EventLoop* eventLoop) : BonjourQuery(querier, eventLoop) { - DNSServiceErrorType result = DNSServiceResolve( - &sdRef, 0, boost::numeric_cast<unsigned int>(service.getNetworkInterfaceID()), - service.getName().c_str(), service.getType().c_str(), - service.getDomain().c_str(), - &BonjourResolveServiceQuery::handleServiceResolvedStatic, this); - if (result != kDNSServiceErr_NoError) { + try { + DNSServiceErrorType result = DNSServiceResolve( + &sdRef, 0, boost::numeric_cast<unsigned int>(service.getNetworkInterfaceID()), + service.getName().c_str(), service.getType().c_str(), + service.getDomain().c_str(), + &BonjourResolveServiceQuery::handleServiceResolvedStatic, this); + if (result != kDNSServiceErr_NoError) { + sdRef = nullptr; + } + } + catch (...) { sdRef = nullptr; } } diff --git a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h index 8f3c3ec..3924c05 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -26,7 +26,7 @@ namespace Swift { virtual std::shared_ptr<DNSSDBrowseQuery> createBrowseQuery() = 0; virtual std::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( - const std::string& name, int port, const ByteArray& info) = 0; + const std::string& name, unsigned short port, const ByteArray& info) = 0; virtual std::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery( const DNSSDServiceID&) = 0; virtual std::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery( diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h index b55447a..6416d69 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,11 +16,11 @@ namespace Swift { class DNSSDResolveServiceQuery { public: struct Result { - Result(const std::string& fullName, const std::string& host, int port, const ByteArray& info) : + Result(const std::string& fullName, const std::string& host, unsigned short port, const ByteArray& info) : fullName(fullName), host(host), port(port), info(info) {} std::string fullName; std::string host; - int port; + unsigned short port; ByteArray info; }; diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp index c17f8b2..3381a26 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -32,7 +32,7 @@ std::shared_ptr<DNSSDBrowseQuery> FakeDNSSDQuerier::createBrowseQuery() { return std::make_shared<FakeDNSSDBrowseQuery>(shared_from_this()); } -std::shared_ptr<DNSSDRegisterQuery> FakeDNSSDQuerier::createRegisterQuery(const std::string& name, int port, const ByteArray& info) { +std::shared_ptr<DNSSDRegisterQuery> FakeDNSSDQuerier::createRegisterQuery(const std::string& name, unsigned short port, const ByteArray& info) { return std::make_shared<FakeDNSSDRegisterQuery>(name, port, info, shared_from_this()); } @@ -105,7 +105,7 @@ void FakeDNSSDQuerier::setServiceInfo(const DNSSDServiceID& id, const DNSSDResol } } -bool FakeDNSSDQuerier::isServiceRegistered(const std::string& name, int port, const ByteArray& info) { +bool FakeDNSSDQuerier::isServiceRegistered(const std::string& name, unsigned short port, const ByteArray& info) { for (const auto& query : getQueries<FakeDNSSDRegisterQuery>()) { if (query->name == name && query->port == port && query->info == info) { return true; diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h index 5d4fefd..07cb75c 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -39,7 +39,7 @@ namespace Swift { std::shared_ptr<DNSSDBrowseQuery> createBrowseQuery(); std::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( - const std::string& name, int port, const ByteArray& info); + const std::string& name, unsigned short port, const ByteArray& info); std::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery( const DNSSDServiceID&); std::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery( @@ -51,7 +51,7 @@ namespace Swift { void addService(const DNSSDServiceID& id); void removeService(const DNSSDServiceID& id); void setServiceInfo(const DNSSDServiceID& id, const DNSSDResolveServiceQuery::Result& info); - bool isServiceRegistered(const std::string& name, int port, const ByteArray& info); + bool isServiceRegistered(const std::string& name, unsigned short port, const ByteArray& info); void setAddress(const std::string& hostname, boost::optional<HostAddress> address); void setBrowseError(); diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h index 7478841..ee6bb92 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -17,7 +17,7 @@ namespace Swift { class FakeDNSSDRegisterQuery : public DNSSDRegisterQuery, public FakeDNSSDQuery { public: - FakeDNSSDRegisterQuery(const std::string& name, int port, const ByteArray& info, std::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), name(name), port(port), info(info) { + FakeDNSSDRegisterQuery(const std::string& name, unsigned short port, const ByteArray& info, std::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), name(name), port(port), info(info) { } void registerService() { @@ -33,7 +33,7 @@ namespace Swift { } std::string name; - int port; + unsigned short port; ByteArray info; }; } diff --git a/Swiften/LinkLocal/LinkLocalService.h b/Swiften/LinkLocal/LinkLocalService.h index 9b0e2ab..c51f890 100644 --- a/Swiften/LinkLocal/LinkLocalService.h +++ b/Swiften/LinkLocal/LinkLocalService.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -31,7 +31,7 @@ namespace Swift { return id.getName(); } - int getPort() const { + unsigned short getPort() const { return info.port; } diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp index b79f184..0498384 100644 --- a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -65,17 +65,29 @@ bool LinkLocalServiceBrowser::isRegistered() const { return !!registerQuery; } -void LinkLocalServiceBrowser::registerService(const std::string& name, int port, const LinkLocalServiceInfo& info) { +void LinkLocalServiceBrowser::registerService(const std::string& name, unsigned short port, const LinkLocalServiceInfo& info) { assert(!registerQuery); - registerQuery = querier->createRegisterQuery(name, port, info.toTXTRecord()); - registerQuery->onRegisterFinished.connect( - boost::bind(&LinkLocalServiceBrowser::handleRegisterFinished, this, _1)); - registerQuery->registerService(); + if (auto txtRecord = info.toTXTRecord()) { + registerQuery = querier->createRegisterQuery(name, port, *txtRecord); + registerQuery->onRegisterFinished.connect( + boost::bind(&LinkLocalServiceBrowser::handleRegisterFinished, this, _1)); + registerQuery->registerService(); + } + else { + haveError = true; + stop(); + } } void LinkLocalServiceBrowser::updateService(const LinkLocalServiceInfo& info) { assert(registerQuery); - registerQuery->updateServiceInfo(info.toTXTRecord()); + if (auto txtRecord = info.toTXTRecord()) { + registerQuery->updateServiceInfo(*txtRecord); + } + else { + haveError = true; + stop(); + } } void LinkLocalServiceBrowser::unregisterService() { diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.h b/Swiften/LinkLocal/LinkLocalServiceBrowser.h index c59a4d0..bfcfc07 100644 --- a/Swiften/LinkLocal/LinkLocalServiceBrowser.h +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -35,7 +35,7 @@ namespace Swift { void registerService( const std::string& name, - int port, + unsigned short port, const LinkLocalServiceInfo& info = LinkLocalServiceInfo()); void updateService( const LinkLocalServiceInfo& info = LinkLocalServiceInfo()); diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp index 7a7ed3b..5e529fd 100644 --- a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp +++ b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,40 +11,47 @@ #include <Swiften/Base/Algorithm.h> #include <Swiften/Base/Concat.h> +#include <Swiften/Base/Log.h> namespace Swift { -ByteArray LinkLocalServiceInfo::toTXTRecord() const { - ByteArray result(getEncoded("txtvers=1")); - if (!firstName.empty()) { - append(result, getEncoded("1st=" + firstName)); - } - if (!lastName.empty()) { - append(result, getEncoded("last=" + lastName)); - } - if (!email.empty()) { - append(result, getEncoded("email=" + email)); - } - if (jid.isValid()) { - append(result, getEncoded("jid=" + jid.toString())); - } - if (!message.empty()) { - append(result, getEncoded("msg=" + message)); - } - if (!nick.empty()) { - append(result, getEncoded("nick=" + nick)); - } - if (port) { - append(result, getEncoded("port.p2pj=" + std::string(boost::lexical_cast<std::string>(*port)))); - } +boost::optional<ByteArray> LinkLocalServiceInfo::toTXTRecord() const { + try { + ByteArray result(getEncoded("txtvers=1")); + if (!firstName.empty()) { + append(result, getEncoded("1st=" + firstName)); + } + if (!lastName.empty()) { + append(result, getEncoded("last=" + lastName)); + } + if (!email.empty()) { + append(result, getEncoded("email=" + email)); + } + if (jid.isValid()) { + append(result, getEncoded("jid=" + jid.toString())); + } + if (!message.empty()) { + append(result, getEncoded("msg=" + message)); + } + if (!nick.empty()) { + append(result, getEncoded("nick=" + nick)); + } + if (port) { + append(result, getEncoded("port.p2pj=" + std::string(std::to_string(*port)))); + } - switch (status) { - case Available: append(result, getEncoded("status=avail")); break; - case Away: append(result, getEncoded("status=away")); break; - case DND: append(result, getEncoded("status=dnd")); break; - } + switch (status) { + case Available: append(result, getEncoded("status=avail")); break; + case Away: append(result, getEncoded("status=away")); break; + case DND: append(result, getEncoded("status=dnd")); break; + } - return result; + return result; + } + catch (const std::exception& e) { + SWIFT_LOG(warning) << "Failed to create TXT record for link local service info: " << e.what(); + return boost::none; + } } ByteArray LinkLocalServiceInfo::getEncoded(const std::string& s) { @@ -82,7 +89,13 @@ LinkLocalServiceInfo LinkLocalServiceInfo::createFromTXTRecord(const ByteArray& info.setNick(entry.second); } else if (entry.first == "port.p2pj") { - info.setPort(boost::lexical_cast<int>(entry.second)); + try { + info.setPort(boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(entry.second))); + } + catch (const boost::bad_lexical_cast&) { + } + catch (const boost::numeric::bad_numeric_cast&) { + } } else if (entry.first == "status") { if (entry.second == "away") { diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.h b/Swiften/LinkLocal/LinkLocalServiceInfo.h index 9f15c6e..adfd062 100644 --- a/Swiften/LinkLocal/LinkLocalServiceInfo.h +++ b/Swiften/LinkLocal/LinkLocalServiceInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -43,10 +43,10 @@ namespace Swift { Status getStatus() const { return status; } void setStatus(Status s) { status = s; } - boost::optional<int> getPort() const { return port; } - void setPort(int p) { port = p; } + boost::optional<unsigned short> getPort() const { return port; } + void setPort(unsigned short p) { port = p; } - ByteArray toTXTRecord() const; + boost::optional<ByteArray> toTXTRecord() const; static LinkLocalServiceInfo createFromTXTRecord(const ByteArray& record); @@ -62,6 +62,6 @@ namespace Swift { std::string message; std::string nick; Status status; - boost::optional<int> port; + boost::optional<unsigned short> port; }; } diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp index 85ae537..59cf996 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -53,7 +53,7 @@ class LinkLocalConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!connectError); CPPUNIT_ASSERT(connection->connectedTo); CPPUNIT_ASSERT_EQUAL(std::string(connection->connectedTo->getAddress().toString()), std::string("192.168.1.1")); - CPPUNIT_ASSERT_EQUAL(connection->connectedTo->getPort(), 1234); + CPPUNIT_ASSERT_EQUAL(connection->connectedTo->getPort(), static_cast<unsigned short>(1234)); } void testConnect_UnableToResolve() { @@ -114,12 +114,14 @@ class LinkLocalConnectorTest : public CppUnit::TestFixture { } private: - std::shared_ptr<LinkLocalConnector> createConnector(const std::string& hostname, int port) { + std::shared_ptr<LinkLocalConnector> createConnector(const std::string& hostname, unsigned short port) { + auto txtRecord = LinkLocalServiceInfo().toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); LinkLocalService service( DNSSDServiceID("myname", "local."), DNSSDResolveServiceQuery::Result( "myname._presence._tcp.local", hostname, port, - LinkLocalServiceInfo().toTXTRecord())); + *txtRecord)); std::shared_ptr<LinkLocalConnector> result( new LinkLocalConnector(service, querier, connection)); result->onConnectFinished.connect( diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp index a80d748..3491634 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -47,10 +47,12 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { eventLoop = new DummyEventLoop(); querier = std::make_shared<FakeDNSSDQuerier>("wonderland.lit", eventLoop); aliceServiceID = new DNSSDServiceID("alice", "wonderland.lit"); - aliceServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.wonderland.lit", "xmpp.wonderland.lit", 1234, LinkLocalServiceInfo().toTXTRecord()); + auto txtRecord = LinkLocalServiceInfo().toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); + aliceServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.wonderland.lit", "xmpp.wonderland.lit", 1234, *txtRecord); testServiceID = new DNSSDServiceID("foo", "bar.local"); - testServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.bar.local", "xmpp.bar.local", 1234, LinkLocalServiceInfo().toTXTRecord()); - testServiceInfo2 = new DNSSDResolveServiceQuery::Result("_presence.tcp.bar.local", "xmpp.foo.local", 2345, LinkLocalServiceInfo().toTXTRecord()); + testServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.bar.local", "xmpp.bar.local", 1234, *txtRecord); + testServiceInfo2 = new DNSSDResolveServiceQuery::Result("_presence.tcp.bar.local", "xmpp.foo.local", 2345, *txtRecord); errorStopReceived = false; normalStopReceived = false; } @@ -292,7 +294,9 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { testling->registerService("foo@bar", 1234, info); eventLoop->processEvents(); - CPPUNIT_ASSERT(querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord())); + auto txtRecord = info.toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); + CPPUNIT_ASSERT(querier->isServiceRegistered("foo@bar", 1234, *txtRecord)); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(registeredServices.size())); CPPUNIT_ASSERT(registeredServices[0] == DNSSDServiceID("foo@bar", "wonderland.lit")); testling->stop(); @@ -311,7 +315,9 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!testling->isRunning()); CPPUNIT_ASSERT(testling->hasError()); CPPUNIT_ASSERT(errorStopReceived); - CPPUNIT_ASSERT(!querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord())); + auto txtRecord = info.toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); + CPPUNIT_ASSERT(!querier->isServiceRegistered("foo@bar", 1234, *txtRecord)); } void testRegisterService_Reregister() { @@ -329,7 +335,9 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { testling->registerService("bar@baz", 3456, info); eventLoop->processEvents(); - CPPUNIT_ASSERT(querier->isServiceRegistered("bar@baz", 3456, info.toTXTRecord())); + auto txtRecord = info.toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); + CPPUNIT_ASSERT(querier->isServiceRegistered("bar@baz", 3456, *txtRecord)); testling->stop(); } @@ -346,7 +354,9 @@ class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { info.setFirstName("Bar"); testling->updateService(info); - CPPUNIT_ASSERT(querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord())); + auto txtRecord = info.toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); + CPPUNIT_ASSERT(querier->isServiceRegistered("foo@bar", 1234, *txtRecord)); testling->stop(); } diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp index 0a94a98..35cb1b4 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -29,7 +29,9 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture { info.setLastName("Tron\xc3\xe7on"); info.setStatus(LinkLocalServiceInfo::Away); - CPPUNIT_ASSERT_EQUAL(createByteArray("\x09txtvers=1\x09" + std::string("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away")), info.toTXTRecord()); + auto txtRecord = info.toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x09txtvers=1\x09" + std::string("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away")), *txtRecord); } void testCreateFromTXTRecord() { @@ -57,7 +59,9 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture { info.setStatus(LinkLocalServiceInfo::DND); info.setPort(1234); - LinkLocalServiceInfo info2 = LinkLocalServiceInfo::createFromTXTRecord(info.toTXTRecord()); + auto txtRecord = info.toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); + LinkLocalServiceInfo info2 = LinkLocalServiceInfo::createFromTXTRecord(*txtRecord); CPPUNIT_ASSERT_EQUAL(info.getFirstName(), info2.getFirstName()); CPPUNIT_ASSERT_EQUAL(info.getLastName(), info2.getLastName()); CPPUNIT_ASSERT_EQUAL(info.getEMail(), info2.getEMail()); @@ -67,6 +71,13 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(info.getStatus() == info2.getStatus()); CPPUNIT_ASSERT(info.getPort() == info2.getPort()); } + + void testToTXTRecordWithInvalidParameter() { + LinkLocalServiceInfo info; + info.setFirstName(std::string(256, 'x')); + auto txtRecord = info.toTXTRecord(); + CPPUNIT_ASSERT(!txtRecord); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceInfoTest); diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp index 206d824..cb5f40a 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -58,10 +58,12 @@ class LinkLocalServiceTest : public CppUnit::TestFixture { info.setFirstName(firstName); info.setLastName(lastName); info.setNick(nickName); + auto txtRecord = info.toTXTRecord(); + CPPUNIT_ASSERT(txtRecord); return LinkLocalService(service, DNSSDResolveServiceQuery::Result( name + "._presence._tcp.local", "rabbithole.local", 1234, - info.toTXTRecord())); + *txtRecord)); } }; diff --git a/Swiften/MIX/MIXImpl.h b/Swiften/MIX/MIXImpl.h index 58b33f4..4da7a62 100644 --- a/Swiften/MIX/MIXImpl.h +++ b/Swiften/MIX/MIXImpl.h @@ -1,4 +1,10 @@ /* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + + /* * Copyright (c) 2017 Tarun Gupta * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. @@ -18,7 +24,7 @@ namespace Swift { public: MIXImpl(const JID& ownJID, const JID& channelJID, IQRouter* iqRouter); - virtual ~MIXImpl(); + virtual ~MIXImpl() override; /** * Returns the (bare) JID of the user. diff --git a/Swiften/MUC/MUCBookmarkManager.cpp b/Swiften/MUC/MUCBookmarkManager.cpp index 9f8ae77..e0922ae 100644 --- a/Swiften/MUC/MUCBookmarkManager.cpp +++ b/Swiften/MUC/MUCBookmarkManager.cpp @@ -1,11 +1,12 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/MUC/MUCBookmarkManager.h> +#include <algorithm> #include <memory> #include <boost/bind.hpp> @@ -25,14 +26,15 @@ MUCBookmarkManager::MUCBookmarkManager(IQRouter* iqRouter) { } void MUCBookmarkManager::handleBookmarksReceived(std::shared_ptr<Storage> payload, ErrorPayload::ref error) { - if (error) { + if (error || !payload) { return; } ready_ = true; + handlingReceivedBookmarks_ = true; onBookmarksReady(); - storage = payload; + storage_ = payload; std::vector<MUCBookmark> receivedBookmarks; for (const auto& room : payload->getRooms()) { @@ -47,18 +49,25 @@ void MUCBookmarkManager::handleBookmarksReceived(std::shared_ptr<Storage> payloa onBookmarkRemoved(oldBookmark); } } - + std::vector<MUCBookmark> newAddedBookmarksToBeSignaled; for (const auto& newBookmark : receivedBookmarks) { if (!containsEquivalent(bookmarks_, newBookmark)) { newBookmarks.push_back(newBookmark); - onBookmarkAdded(newBookmark); + //If the bookmark does not exist in bookmark manager, after emmiting the signal, chatsmanager will try to join the room, if the bookmark has autojoin to true. + //The bookmark is not yet available in bookmark manager, therefore a new bookmark will be created which will be lost when newBookmarks replace bookmarks. + newAddedBookmarksToBeSignaled.push_back(newBookmark); } } bookmarks_ = newBookmarks; + for (auto bookmark : newAddedBookmarksToBeSignaled) { + onBookmarkAdded(bookmark); + } + + handlingReceivedBookmarks_ = false; } bool MUCBookmarkManager::containsEquivalent(const std::vector<MUCBookmark>& list, const MUCBookmark& bookmark) { - return std::find(list.begin(), list.end(), bookmark) != list.end(); + return std::find_if(list.begin(), list.end(), [&](const MUCBookmark& val) { return bookmark.getRoom() == val.getRoom(); }) != list.end(); } void MUCBookmarkManager::replaceBookmark(const MUCBookmark& oldBookmark, const MUCBookmark& newBookmark) { @@ -76,8 +85,15 @@ void MUCBookmarkManager::replaceBookmark(const MUCBookmark& oldBookmark, const M void MUCBookmarkManager::addBookmark(const MUCBookmark& bookmark) { if (!ready_) return; - bookmarks_.push_back(bookmark); - onBookmarkAdded(bookmark); + if (auto found = lookupBookmark(bookmark.getRoom())) { + if (found != bookmark) { + replaceBookmark(found.get(), bookmark); + } + } + else { + bookmarks_.push_back(bookmark); + onBookmarkAdded(bookmark); + } flush(); } @@ -96,17 +112,20 @@ void MUCBookmarkManager::removeBookmark(const MUCBookmark& bookmark) { } void MUCBookmarkManager::flush() { - if (!storage) { - storage = std::make_shared<Storage>(); + if (handlingReceivedBookmarks_) { + return; + } + if (!storage_) { + storage_ = std::make_shared<Storage>(); } // Update the storage element - storage->clearRooms(); + storage_->clearRooms(); for (const auto& bookmark : bookmarks_) { - storage->addRoom(bookmark.toStorage()); + storage_->addRoom(bookmark.toStorage()); } // Send an iq to save the storage element - SetPrivateStorageRequest<Storage>::ref request = SetPrivateStorageRequest<Storage>::create(storage, iqRouter_); + SetPrivateStorageRequest<Storage>::ref request = SetPrivateStorageRequest<Storage>::create(storage_, iqRouter_); // FIXME: We should care about the result //request->onResponse.connect(boost::bind(&MUCBookmarkManager::handleBookmarksSet, this, _1, _2)); request->send(); @@ -116,4 +135,12 @@ const std::vector<MUCBookmark>& MUCBookmarkManager::getBookmarks() const { return bookmarks_; } +boost::optional<MUCBookmark> MUCBookmarkManager::lookupBookmark(const JID& bookmarkJID) const { + auto bookmarkIterator = std::find_if(bookmarks_.begin(), bookmarks_.end(), [&](const MUCBookmark& val) { return bookmarkJID == val.getRoom(); }); + if (bookmarkIterator != bookmarks_.end()) { + return *bookmarkIterator; + } + return boost::none; +} + } diff --git a/Swiften/MUC/MUCBookmarkManager.h b/Swiften/MUC/MUCBookmarkManager.h index 78fbbb0..1ef227d 100644 --- a/Swiften/MUC/MUCBookmarkManager.h +++ b/Swiften/MUC/MUCBookmarkManager.h @@ -27,8 +27,8 @@ namespace Swift { void addBookmark(const MUCBookmark& bookmark); void removeBookmark(const MUCBookmark& bookmark); void replaceBookmark(const MUCBookmark& oldBookmark, const MUCBookmark& newBookmark); - const std::vector<MUCBookmark>& getBookmarks() const; + boost::optional<MUCBookmark> lookupBookmark(const JID& bookmarkJID) const; public: boost::signals2::signal<void (const MUCBookmark&)> onBookmarkAdded; @@ -45,8 +45,9 @@ namespace Swift { private: bool ready_; + bool handlingReceivedBookmarks_; std::vector<MUCBookmark> bookmarks_; IQRouter* iqRouter_; - std::shared_ptr<Storage> storage; + std::shared_ptr<Storage> storage_; }; } diff --git a/Swiften/MUC/MUCImpl.cpp b/Swiften/MUC/MUCImpl.cpp index 029bb4b..d2b33f3 100644 --- a/Swiften/MUC/MUCImpl.cpp +++ b/Swiften/MUC/MUCImpl.cpp @@ -371,7 +371,7 @@ void MUCImpl::changeAffiliation(const JID& jid, MUCOccupant::Affiliation affilia MUCAdminPayload::ref mucPayload = std::make_shared<MUCAdminPayload>(); MUCItem item; item.affiliation = affiliation; - item.realJID = jid.toBare(); + item.realJID = jid; mucPayload->addItem(item); std::shared_ptr<GenericRequest<MUCAdminPayload> > request = std::make_shared<GenericRequest<MUCAdminPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); request->onResponse.connect(boost::bind(&MUCImpl::handleAffiliationChangeResponse, this, _1, _2, jid, affiliation)); diff --git a/Swiften/Network/BOSHConnection.cpp b/Swiften/Network/BOSHConnection.cpp index b4ffa7d..1312a3e 100644 --- a/Swiften/Network/BOSHConnection.cpp +++ b/Swiften/Network/BOSHConnection.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2011-2017 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -27,6 +27,7 @@ #include <Swiften/StreamStack/DummyStreamLayer.h> #include <Swiften/StreamStack/TLSLayer.h> #include <Swiften/TLS/TLSContext.h> +#include <Swiften/TLS/TLSContextFactory.h> #include <Swiften/TLS/TLSOptions.h> namespace Swift { @@ -42,7 +43,8 @@ BOSHConnection::BOSHConnection(const URL& boshURL, Connector::ref connector, XML connectionReady_(false) { if (boshURL_.getScheme() == "https") { - tlsLayer_ = std::make_shared<TLSLayer>(tlsContextFactory, tlsOptions); + auto tlsContext = tlsContextFactory->createTLSContext(tlsOptions); + tlsLayer_ = std::make_shared<TLSLayer>(std::move(tlsContext)); // The following dummyLayer_ is needed as the TLSLayer will pass the decrypted data to its parent layer. // The dummyLayer_ will serve as the parent layer. dummyLayer_ = std::make_shared<DummyStreamLayer>(tlsLayer_.get()); @@ -72,27 +74,27 @@ void BOSHConnection::cancelConnector() { } void BOSHConnection::handleTLSConnected() { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); onConnectFinished(false); } void BOSHConnection::handleTLSApplicationDataRead(const SafeByteArray& data) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); handleDataRead(std::make_shared<SafeByteArray>(data)); } void BOSHConnection::handleTLSNetowrkDataWriteRequest(const SafeByteArray& data) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); connection_->write(data); } void BOSHConnection::handleRawDataRead(std::shared_ptr<SafeByteArray> data) { - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); tlsLayer_->handleDataRead(*data.get()); } -void BOSHConnection::handleTLSError(std::shared_ptr<TLSError> /* error */) { - +void BOSHConnection::handleTLSError(std::shared_ptr<TLSError> error) { + SWIFT_LOG(debug) << (error ? error->getMessage() : "Unknown TLS error"); } void BOSHConnection::writeData(const SafeByteArray& data) { @@ -121,7 +123,7 @@ void BOSHConnection::restartStream() { bool BOSHConnection::setClientCertificate(CertificateWithKey::ref cert) { if (tlsLayer_) { - SWIFT_LOG(debug) << "set client certificate" << std::endl; + SWIFT_LOG(debug) << "set client certificate"; return tlsLayer_->setClientCertificate(cert); } else { @@ -209,7 +211,7 @@ void BOSHConnection::write(const SafeByteArray& data, bool streamRestart, bool t writeData(safeHeader); pending_ = true; - SWIFT_LOG(debug) << "write data: " << safeByteArrayToString(safeHeader) << std::endl; + SWIFT_LOG(debug) << "write data: " << safeByteArrayToString(safeHeader); } void BOSHConnection::handleConnectFinished(Connection::ref connection) { @@ -273,7 +275,7 @@ void BOSHConnection::startStream(const std::string& to, unsigned long long rid) SafeByteArray safeHeader = createSafeByteArray(header.str()); onBOSHDataWritten(safeHeader); writeData(safeHeader); - SWIFT_LOG(debug) << "write stream header: " << safeByteArrayToString(safeHeader) << std::endl; + SWIFT_LOG(debug) << "write stream header: " << safeByteArrayToString(safeHeader); } void BOSHConnection::handleDataRead(std::shared_ptr<SafeByteArray> data) { diff --git a/Swiften/Network/BOSHConnection.h b/Swiften/Network/BOSHConnection.h index c492ac4..f0a946a 100644 --- a/Swiften/Network/BOSHConnection.h +++ b/Swiften/Network/BOSHConnection.h @@ -31,7 +31,7 @@ namespace Swift { class XMLParserFactory; class TLSContextFactory; class TLSLayer; - struct TLSOptions; + class TLSOptions; class HighLayer; class SWIFTEN_API BOSHError : public SessionStream::SessionStreamError { diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp index 8a75e81..3a79a16 100644 --- a/Swiften/Network/BOSHConnectionPool.cpp +++ b/Swiften/Network/BOSHConnectionPool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -266,7 +266,7 @@ std::shared_ptr<BOSHConnection> BOSHConnectionPool::createConnection() { if (boshURL.getScheme() == "https") { bool success = connection->setClientCertificate(clientCertificate); - SWIFT_LOG(debug) << "setClientCertificate, success: " << success << std::endl; + SWIFT_LOG(debug) << "setClientCertificate, success: " << success; } connection->connect(); diff --git a/Swiften/Network/BoostConnection.cpp b/Swiften/Network/BoostConnection.cpp index 0de7b25..6ae6bf6 100644 --- a/Swiften/Network/BoostConnection.cpp +++ b/Swiften/Network/BoostConnection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -14,7 +14,6 @@ #include <boost/asio/placeholders.hpp> #include <boost/asio/write.hpp> #include <boost/bind.hpp> -#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Base/ByteArray.h> @@ -64,7 +63,7 @@ void BoostConnection::listen() { void BoostConnection::connect(const HostAddressPort& addressPort) { boost::asio::ip::tcp::endpoint endpoint( - boost::asio::ip::address::from_string(addressPort.getAddress().toString()), boost::numeric_cast<unsigned short>(addressPort.getPort())); + boost::asio::ip::address::from_string(addressPort.getAddress().toString()), addressPort.getPort()); socket_.async_connect( endpoint, boost::bind(&BoostConnection::handleConnectFinished, shared_from_this(), boost::asio::placeholders::error)); @@ -108,7 +107,7 @@ void BoostConnection::doWrite(const SafeByteArray& data) { } void BoostConnection::handleConnectFinished(const boost::system::error_code& error) { - SWIFT_LOG(debug) << "Connect finished: " << error << std::endl; + SWIFT_LOG(debug) << "Connect finished: " << error; if (!error) { eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), false), shared_from_this()); doRead(); @@ -127,7 +126,7 @@ void BoostConnection::doRead() { } void BoostConnection::handleSocketRead(const boost::system::error_code& error, size_t bytesTransferred) { - SWIFT_LOG(debug) << "Socket read " << error << std::endl; + SWIFT_LOG(debug) << "Socket read " << error; if (!error) { readBuffer_->resize(bytesTransferred); eventLoop->postEvent(boost::bind(boost::ref(onDataRead), readBuffer_), shared_from_this()); @@ -142,7 +141,7 @@ void BoostConnection::handleSocketRead(const boost::system::error_code& error, s } void BoostConnection::handleDataWritten(const boost::system::error_code& error) { - SWIFT_LOG(debug) << "Data written " << error << std::endl; + SWIFT_LOG(debug) << "Data written " << error; if (!error) { eventLoop->postEvent(boost::ref(onDataWritten), shared_from_this()); } diff --git a/Swiften/Network/BoostConnectionServer.cpp b/Swiften/Network/BoostConnectionServer.cpp index 34b5799..dc05172 100644 --- a/Swiften/Network/BoostConnectionServer.cpp +++ b/Swiften/Network/BoostConnectionServer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -19,10 +19,10 @@ namespace Swift { -BoostConnectionServer::BoostConnectionServer(int port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : port_(port), ioService_(ioService), eventLoop(eventLoop), acceptor_(nullptr) { +BoostConnectionServer::BoostConnectionServer(unsigned short port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : port_(port), ioService_(ioService), eventLoop(eventLoop), acceptor_(nullptr) { } -BoostConnectionServer::BoostConnectionServer(const HostAddress &address, int port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : address_(address), port_(port), ioService_(ioService), eventLoop(eventLoop), acceptor_(nullptr) { +BoostConnectionServer::BoostConnectionServer(const HostAddress &address, unsigned short port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : address_(address), port_(port), ioService_(ioService), eventLoop(eventLoop), acceptor_(nullptr) { } void BoostConnectionServer::start() { @@ -37,16 +37,16 @@ boost::optional<BoostConnectionServer::Error> BoostConnectionServer::tryStart() assert(!acceptor_); boost::asio::ip::tcp::endpoint endpoint; if (address_.isValid()) { - endpoint = boost::asio::ip::tcp::endpoint(address_.getRawAddress(), boost::numeric_cast<unsigned short>(port_)); + endpoint = boost::asio::ip::tcp::endpoint(address_.getRawAddress(), port_); } else { - endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), boost::numeric_cast<unsigned short>(port_)); + endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), port_); } acceptor_ = new boost::asio::ip::tcp::acceptor(*ioService_, endpoint); if (endpoint.protocol() == boost::asio::ip::tcp::v6()) { boost::system::error_code ec; acceptor_->set_option(boost::asio::ip::v6_only(false), ec); - SWIFT_LOG_ASSERT(ec, warning) << "IPv4/IPv6 dual-stack support is not supported on this platform." << std::endl; + SWIFT_LOG_ASSERT(ec, warning) << "IPv4/IPv6 dual-stack support is not supported on this platform."; } acceptNextConnection(); } @@ -58,6 +58,9 @@ boost::optional<BoostConnectionServer::Error> BoostConnectionServer::tryStart() return UnknownError; } } + catch (const boost::numeric::bad_numeric_cast&) { + return UnknownError; + } return boost::optional<Error>(); } diff --git a/Swiften/Network/BoostConnectionServer.h b/Swiften/Network/BoostConnectionServer.h index 3dd9830..917d638 100644 --- a/Swiften/Network/BoostConnectionServer.h +++ b/Swiften/Network/BoostConnectionServer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,11 +23,11 @@ namespace Swift { public: typedef std::shared_ptr<BoostConnectionServer> ref; - static ref create(int port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) { + static ref create(unsigned short port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) { return ref(new BoostConnectionServer(port, ioService, eventLoop)); } - static ref create(const HostAddress &address, int port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) { + static ref create(const HostAddress &address, unsigned short port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) { return ref(new BoostConnectionServer(address, port, ioService, eventLoop)); } @@ -40,8 +40,8 @@ namespace Swift { boost::signals2::signal<void (boost::optional<Error>)> onStopped; private: - BoostConnectionServer(int port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop); - BoostConnectionServer(const HostAddress &address, int port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop); + BoostConnectionServer(unsigned short port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop); + BoostConnectionServer(const HostAddress &address, unsigned short port, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop); void stop(boost::optional<Error> e); void acceptNextConnection(); @@ -49,7 +49,7 @@ namespace Swift { private: HostAddress address_; - int port_; + unsigned short port_; std::shared_ptr<boost::asio::io_service> ioService_; EventLoop* eventLoop; boost::asio::ip::tcp::acceptor* acceptor_; diff --git a/Swiften/Network/BoostConnectionServerFactory.cpp b/Swiften/Network/BoostConnectionServerFactory.cpp index 8b3fd2f..6936453 100644 --- a/Swiften/Network/BoostConnectionServerFactory.cpp +++ b/Swiften/Network/BoostConnectionServerFactory.cpp @@ -19,11 +19,11 @@ namespace Swift { BoostConnectionServerFactory::BoostConnectionServerFactory(std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : ioService(ioService), eventLoop(eventLoop) { } -std::shared_ptr<ConnectionServer> BoostConnectionServerFactory::createConnectionServer(int port) { +std::shared_ptr<ConnectionServer> BoostConnectionServerFactory::createConnectionServer(unsigned short port) { return BoostConnectionServer::create(port, ioService, eventLoop); } -std::shared_ptr<ConnectionServer> BoostConnectionServerFactory::createConnectionServer(const Swift::HostAddress &hostAddress, int port) { +std::shared_ptr<ConnectionServer> BoostConnectionServerFactory::createConnectionServer(const Swift::HostAddress &hostAddress, unsigned short port) { return BoostConnectionServer::create(hostAddress, port, ioService, eventLoop); } diff --git a/Swiften/Network/BoostConnectionServerFactory.h b/Swiften/Network/BoostConnectionServerFactory.h index 033e63d..956132b 100644 --- a/Swiften/Network/BoostConnectionServerFactory.h +++ b/Swiften/Network/BoostConnectionServerFactory.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -25,9 +25,9 @@ namespace Swift { public: BoostConnectionServerFactory(std::shared_ptr<boost::asio::io_service>, EventLoop* eventLoop); - virtual std::shared_ptr<ConnectionServer> createConnectionServer(int port); + virtual std::shared_ptr<ConnectionServer> createConnectionServer(unsigned short port); - virtual std::shared_ptr<ConnectionServer> createConnectionServer(const Swift::HostAddress &hostAddress, int port); + virtual std::shared_ptr<ConnectionServer> createConnectionServer(const Swift::HostAddress &hostAddress, unsigned short port); private: std::shared_ptr<boost::asio::io_service> ioService; diff --git a/Swiften/Network/BoostNetworkFactories.cpp b/Swiften/Network/BoostNetworkFactories.cpp index 9fef73c..13a7960 100644 --- a/Swiften/Network/BoostNetworkFactories.cpp +++ b/Swiften/Network/BoostNetworkFactories.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -44,9 +44,9 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop, std::shared_p idnConverter = PlatformIDNConverter::create(); #ifdef USE_UNBOUND // TODO: What to do about idnConverter. - domainNameResolver = new UnboundDomainNameResolver(idnConverter, ioServiceThread.getIOService(), eventLoop); + domainNameResolver = new UnboundDomainNameResolver(idnConverter.get(), ioServiceThread.getIOService(), eventLoop); #else - domainNameResolver = new PlatformDomainNameResolver(idnConverter, eventLoop); + domainNameResolver = new PlatformDomainNameResolver(idnConverter.get(), eventLoop); #endif cryptoProvider = PlatformCryptoProvider::create(); } @@ -54,7 +54,6 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop, std::shared_p BoostNetworkFactories::~BoostNetworkFactories() { delete cryptoProvider; delete domainNameResolver; - delete idnConverter; delete proxyProvider; delete tlsFactories; delete xmlParserFactory; diff --git a/Swiften/Network/BoostNetworkFactories.h b/Swiften/Network/BoostNetworkFactories.h index 2bf8d33..33a3584 100644 --- a/Swiften/Network/BoostNetworkFactories.h +++ b/Swiften/Network/BoostNetworkFactories.h @@ -1,11 +1,13 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once +#include <memory> + #include <Swiften/Base/API.h> #include <Swiften/Network/BoostIOServiceThread.h> #include <Swiften/Network/NetworkFactories.h> @@ -68,7 +70,7 @@ namespace Swift { } virtual IDNConverter* getIDNConverter() const override { - return idnConverter; + return idnConverter.get(); } virtual CryptoProvider* getCryptoProvider() const override { @@ -87,7 +89,7 @@ namespace Swift { PlatformTLSFactories* tlsFactories; ProxyProvider* proxyProvider; EventLoop* eventLoop; - IDNConverter* idnConverter; + std::unique_ptr<IDNConverter> idnConverter; CryptoProvider* cryptoProvider; }; } diff --git a/Swiften/Network/ChainedConnector.cpp b/Swiften/Network/ChainedConnector.cpp index ea55db3..a9210ba 100644 --- a/Swiften/Network/ChainedConnector.cpp +++ b/Swiften/Network/ChainedConnector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -18,7 +18,7 @@ using namespace Swift; ChainedConnector::ChainedConnector( const std::string& hostname, - int port, + unsigned short port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, const std::vector<ConnectionFactory*>& connectionFactories, @@ -45,7 +45,7 @@ void ChainedConnector::setTimeoutMilliseconds(int milliseconds) { } void ChainedConnector::start() { - SWIFT_LOG(debug) << "Starting queued connector for " << hostname << std::endl; + SWIFT_LOG(debug) << "Starting queued connector for " << hostname; connectionFactoryQueue = std::deque<ConnectionFactory*>(connectionFactories.begin(), connectionFactories.end()); tryNextConnectionFactory(); @@ -63,12 +63,12 @@ void ChainedConnector::stop() { void ChainedConnector::tryNextConnectionFactory() { assert(!currentConnector); if (connectionFactoryQueue.empty()) { - SWIFT_LOG(debug) << "No more connection factories" << std::endl; + SWIFT_LOG(debug) << "No more connection factories"; finish(std::shared_ptr<Connection>(), lastError); } else { ConnectionFactory* connectionFactory = connectionFactoryQueue.front(); - SWIFT_LOG(debug) << "Trying next connection factory: " << typeid(*connectionFactory).name() << std::endl; + SWIFT_LOG(debug) << "Trying next connection factory: " << typeid(*connectionFactory).name(); connectionFactoryQueue.pop_front(); currentConnector = Connector::create(hostname, port, serviceLookupPrefix, resolver, connectionFactory, timerFactory); currentConnector->setTimeoutMilliseconds(timeoutMilliseconds); @@ -78,7 +78,7 @@ void ChainedConnector::tryNextConnectionFactory() { } void ChainedConnector::handleConnectorFinished(std::shared_ptr<Connection> connection, std::shared_ptr<Error> error) { - SWIFT_LOG(debug) << "Connector finished" << std::endl; + SWIFT_LOG(debug) << "Connector finished"; currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); lastError = error; currentConnector.reset(); diff --git a/Swiften/Network/ChainedConnector.h b/Swiften/Network/ChainedConnector.h index a00d7e5..9620293 100644 --- a/Swiften/Network/ChainedConnector.h +++ b/Swiften/Network/ChainedConnector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -26,7 +26,7 @@ namespace Swift { class SWIFTEN_API ChainedConnector { public: - ChainedConnector(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); + ChainedConnector(const std::string& hostname, unsigned short port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); ~ChainedConnector(); void setTimeoutMilliseconds(int milliseconds); @@ -42,7 +42,7 @@ namespace Swift { private: std::string hostname; - int port; + unsigned short port; boost::optional<std::string> serviceLookupPrefix; DomainNameResolver* resolver; std::vector<ConnectionFactory*> connectionFactories; diff --git a/Swiften/Network/ConnectionServerFactory.h b/Swiften/Network/ConnectionServerFactory.h index 413131e..2ebccc1 100644 --- a/Swiften/Network/ConnectionServerFactory.h +++ b/Swiften/Network/ConnectionServerFactory.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -24,8 +24,8 @@ namespace Swift { public: virtual ~ConnectionServerFactory(); - virtual std::shared_ptr<ConnectionServer> createConnectionServer(int port) = 0; + virtual std::shared_ptr<ConnectionServer> createConnectionServer(unsigned short port) = 0; - virtual std::shared_ptr<ConnectionServer> createConnectionServer(const Swift::HostAddress& hostAddress, int port) = 0; + virtual std::shared_ptr<ConnectionServer> createConnectionServer(const Swift::HostAddress& hostAddress, unsigned short port) = 0; }; } diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp index 457d8a9..e27b95d 100644 --- a/Swiften/Network/Connector.cpp +++ b/Swiften/Network/Connector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -17,7 +17,7 @@ namespace Swift { -Connector::Connector(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), port(port), serviceLookupPrefix(serviceLookupPrefix), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0), queriedAllServices(true), foundSomeDNS(false) { +Connector::Connector(const std::string& hostname, unsigned short port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), port(port), serviceLookupPrefix(serviceLookupPrefix), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0), queriedAllServices(true), foundSomeDNS(false) { } void Connector::setTimeoutMilliseconds(int milliseconds) { @@ -25,17 +25,17 @@ void Connector::setTimeoutMilliseconds(int milliseconds) { } void Connector::start() { - SWIFT_LOG(debug) << "Starting connector for " << hostname << std::endl; + SWIFT_LOG(debug) << "Starting connector for " << hostname; assert(!currentConnection); assert(!serviceQuery); assert(!timer); - queriedAllServices = false; auto hostAddress = HostAddress::fromString(hostname); if (timeoutMilliseconds > 0) { timer = timerFactory->createTimer(timeoutMilliseconds); timer->onTick.connect(boost::bind(&Connector::handleTimeout, shared_from_this())); } if (serviceLookupPrefix) { + queriedAllServices = false; serviceQuery = resolver->createServiceQuery(*serviceLookupPrefix, hostname); serviceQuery->onResult.connect(boost::bind(&Connector::handleServiceQueryResult, shared_from_this(), _1)); serviceQuery->run(); @@ -66,7 +66,7 @@ void Connector::queryAddress(const std::string& hostname) { } void Connector::handleServiceQueryResult(const std::vector<DomainNameServiceQuery::Result>& result) { - SWIFT_LOG(debug) << result.size() << " SRV result(s)" << std::endl; + SWIFT_LOG(debug) << result.size() << " SRV result(s)"; serviceQueryResults = std::deque<DomainNameServiceQuery::Result>(result.begin(), result.end()); serviceQuery.reset(); if (!serviceQueryResults.empty()) { @@ -77,23 +77,23 @@ void Connector::handleServiceQueryResult(const std::vector<DomainNameServiceQuer void Connector::tryNextServiceOrFallback() { if (queriedAllServices) { - SWIFT_LOG(debug) << "Queried all services" << std::endl; + SWIFT_LOG(debug) << "Queried all services"; finish(std::shared_ptr<Connection>()); } else if (serviceQueryResults.empty()) { - SWIFT_LOG(debug) << "Falling back on A resolution" << std::endl; + SWIFT_LOG(debug) << "Falling back on A resolution"; // Fall back on simple address resolving queriedAllServices = true; queryAddress(hostname); } else { - SWIFT_LOG(debug) << "Querying next address" << std::endl; + SWIFT_LOG(debug) << "Querying next address"; queryAddress(serviceQueryResults.front().hostname); } } void Connector::handleAddressQueryResult(const std::vector<HostAddress>& addresses, boost::optional<DomainNameResolveError> error) { - SWIFT_LOG(debug) << addresses.size() << " addresses" << std::endl; + SWIFT_LOG(debug) << addresses.size() << " addresses"; addressQuery.reset(); if (error || addresses.empty()) { if (!serviceQueryResults.empty()) { @@ -110,7 +110,7 @@ void Connector::handleAddressQueryResult(const std::vector<HostAddress>& address void Connector::tryNextAddress() { if (addressQueryResults.empty()) { - SWIFT_LOG(debug) << "Done trying addresses. Moving on." << std::endl; + SWIFT_LOG(debug) << "Done trying addresses. Moving on."; // Done trying all addresses. Move on to the next host. if (!serviceQueryResults.empty()) { serviceQueryResults.pop_front(); @@ -118,11 +118,11 @@ void Connector::tryNextAddress() { tryNextServiceOrFallback(); } else { - SWIFT_LOG(debug) << "Trying next address" << std::endl; + SWIFT_LOG(debug) << "Trying next address"; HostAddress address = addressQueryResults.front(); addressQueryResults.pop_front(); - int connectPort = (port == -1 ? 5222 : port); + unsigned short connectPort = (port == 0 ? 5222 : port); if (!serviceQueryResults.empty()) { connectPort = serviceQueryResults.front().port; } @@ -133,7 +133,7 @@ void Connector::tryNextAddress() { void Connector::tryConnect(const HostAddressPort& target) { assert(!currentConnection); - SWIFT_LOG(debug) << "Trying to connect to " << target.getAddress().toString() << ":" << target.getPort() << std::endl; + SWIFT_LOG(debug) << "Trying to connect to " << target.getAddress().toString() << ":" << target.getPort(); currentConnection = connectionFactory->createConnection(); currentConnection->onConnectFinished.connect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); currentConnection->connect(target); @@ -143,11 +143,18 @@ void Connector::tryConnect(const HostAddressPort& target) { } void Connector::handleConnectionConnectFinished(bool error) { - SWIFT_LOG(debug) << "ConnectFinished: " << (error ? "error" : "success") << std::endl; + SWIFT_LOG(debug) << "ConnectFinished: " << (error ? "error" : "success"); if (timer) { timer->stop(); timer.reset(); } + if (!currentConnection) { + // We've hit a race condition where multiple finisheds were on the eventloop queue at once. + // This is particularly likely on macOS where the hourly momentary wakeup while asleep + // can cause both a timeout and an onConnectFinished to be queued sequentially (SWIFT-232). + // Let the first one process as normal, but ignore the second. + return; + } currentConnection->onConnectFinished.disconnect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); if (error) { currentConnection.reset(); @@ -188,7 +195,8 @@ void Connector::finish(std::shared_ptr<Connection> connection) { } void Connector::handleTimeout() { - SWIFT_LOG(debug) << "Timeout" << std::endl; + SWIFT_LOG(debug) << "Timeout"; + SWIFT_LOG_ASSERT(currentConnection, error) << "Connection not valid but triggered a timeout"; handleConnectionConnectFinished(true); } diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h index d8a1b88..c76a4af 100644 --- a/Swiften/Network/Connector.h +++ b/Swiften/Network/Connector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -30,7 +30,7 @@ namespace Swift { public: typedef std::shared_ptr<Connector> ref; - static Connector::ref create(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { + static Connector::ref create(const std::string& hostname, unsigned short port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { return ref(new Connector(hostname, port, serviceLookupPrefix, resolver, connectionFactory, timerFactory)); } @@ -46,7 +46,7 @@ namespace Swift { boost::signals2::signal<void (std::shared_ptr<Connection>, std::shared_ptr<Error>)> onConnectFinished; private: - Connector(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver*, ConnectionFactory*, TimerFactory*); + Connector(const std::string& hostname, unsigned short port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver*, ConnectionFactory*, TimerFactory*); void handleServiceQueryResult(const std::vector<DomainNameServiceQuery::Result>& result); void handleAddressQueryResult(const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> error); @@ -63,7 +63,7 @@ namespace Swift { private: std::string hostname; - int port; + unsigned short port; boost::optional<std::string> serviceLookupPrefix; DomainNameResolver* resolver; ConnectionFactory* connectionFactory; diff --git a/Swiften/Network/DomainNameServiceQuery.cpp b/Swiften/Network/DomainNameServiceQuery.cpp index 708bbce..5784dd7 100644 --- a/Swiften/Network/DomainNameServiceQuery.cpp +++ b/Swiften/Network/DomainNameServiceQuery.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,15 +11,11 @@ #include <iterator> #include <numeric> -#include <boost/lambda/bind.hpp> -#include <boost/lambda/lambda.hpp> #include <boost/numeric/conversion/cast.hpp> -#include <boost/typeof/typeof.hpp> #include <Swiften/Base/RandomGenerator.h> using namespace Swift; -namespace lambda = boost::lambda; namespace { struct ResultPriorityComparator { @@ -43,19 +39,25 @@ void DomainNameServiceQuery::sortResults(std::vector<DomainNameServiceQuery::Res std::vector<DomainNameServiceQuery::Result>::iterator next = std::upper_bound(i, queries.end(), *i, comparator); if (std::distance(i, next) > 1) { std::vector<int> weights; - std::transform(i, next, std::back_inserter(weights), - /* easy hack to account for '0' weights getting at least some weight */ - lambda::bind(&Result::weight, lambda::_1) + 1); - for (int j = 0; j < boost::numeric_cast<int>(weights.size() - 1); ++j) { - std::vector<int> cumulativeWeights; - std::partial_sum( - weights.begin() + j, - weights.end(), - std::back_inserter(cumulativeWeights)); - int randomNumber = generator.generateRandomInteger(cumulativeWeights.back()); - BOOST_AUTO(selectedIndex, std::lower_bound(cumulativeWeights.begin(), cumulativeWeights.end(), randomNumber) - cumulativeWeights.begin()); - std::swap(i[j], i[j + selectedIndex]); - std::swap(weights.begin()[j], weights.begin()[j + selectedIndex]); + std::transform(i, next, std::back_inserter(weights), [](const DomainNameServiceQuery::Result& result) { + /* easy hack to account for '0' weights getting at least some weight */ + return result.weight + 1; + }); + try { + for (int j = 0; j < boost::numeric_cast<int>(weights.size()) - 1; ++j) { + std::vector<int> cumulativeWeights; + std::partial_sum( + weights.begin() + j, + weights.end(), + std::back_inserter(cumulativeWeights)); + int randomNumber = generator.generateRandomInteger(cumulativeWeights.back()); + auto selectedIndex = std::lower_bound(cumulativeWeights.begin(), cumulativeWeights.end(), randomNumber) - cumulativeWeights.begin(); + std::swap(i[j], i[j + selectedIndex]); + std::swap(weights.begin()[j], weights.begin()[j + selectedIndex]); + } + } + catch (const boost::numeric::bad_numeric_cast&) { + // In the unlikely event of weights.size() being too large, use the list as-is. } } i = next; diff --git a/Swiften/Network/DomainNameServiceQuery.h b/Swiften/Network/DomainNameServiceQuery.h index b27f32e..1631b99 100644 --- a/Swiften/Network/DomainNameServiceQuery.h +++ b/Swiften/Network/DomainNameServiceQuery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -24,9 +24,9 @@ namespace Swift { typedef std::shared_ptr<DomainNameServiceQuery> ref; struct Result { - Result(const std::string& hostname = "", int port = -1, int priority = -1, int weight = -1) : hostname(hostname), port(port), priority(priority), weight(weight) {} + Result(const std::string& hostname = "", unsigned short port = 0, int priority = -1, int weight = -1) : hostname(hostname), port(port), priority(priority), weight(weight) {} std::string hostname; - int port; + unsigned short port; int priority; int weight; }; diff --git a/Swiften/Network/DummyConnectionServer.h b/Swiften/Network/DummyConnectionServer.h index 970cbb7..a4fd07f 100644 --- a/Swiften/Network/DummyConnectionServer.h +++ b/Swiften/Network/DummyConnectionServer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -17,8 +17,8 @@ namespace Swift { class SWIFTEN_API DummyConnectionServer : public ConnectionServer, public EventOwner, public std::enable_shared_from_this<DummyConnectionServer> { public: - DummyConnectionServer(EventLoop* /*eventLoop*/, int port) : localAddressPort(HostAddress(), port) {} - DummyConnectionServer(EventLoop* /*eventLoop*/, const Swift::HostAddress& hostAddress, int port) : localAddressPort(hostAddress, port) {} + DummyConnectionServer(EventLoop* /*eventLoop*/, unsigned short port) : localAddressPort(HostAddress(), port) {} + DummyConnectionServer(EventLoop* /*eventLoop*/, const Swift::HostAddress& hostAddress, unsigned short port) : localAddressPort(hostAddress, port) {} virtual ~DummyConnectionServer() {} virtual HostAddressPort getAddressPort() const { diff --git a/Swiften/Network/DummyConnectionServerFactory.h b/Swiften/Network/DummyConnectionServerFactory.h index 822f95f..4b25118 100644 --- a/Swiften/Network/DummyConnectionServerFactory.h +++ b/Swiften/Network/DummyConnectionServerFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 Isode Limited. + * Copyright (c) 2014-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,11 +20,11 @@ public: DummyConnectionServerFactory(EventLoop* eventLoop) : eventLoop(eventLoop) {} virtual ~DummyConnectionServerFactory() {} - virtual std::shared_ptr<ConnectionServer> createConnectionServer(int port) { + virtual std::shared_ptr<ConnectionServer> createConnectionServer(unsigned short port) { return std::make_shared<DummyConnectionServer>(eventLoop, port); } - virtual std::shared_ptr<ConnectionServer> createConnectionServer(const Swift::HostAddress& hostAddress, int port) { + virtual std::shared_ptr<ConnectionServer> createConnectionServer(const Swift::HostAddress& hostAddress, unsigned short port) { return std::make_shared<DummyConnectionServer>(eventLoop, hostAddress, port); } diff --git a/Swiften/Network/EnvironmentProxyProvider.cpp b/Swiften/Network/EnvironmentProxyProvider.cpp index 8edb136..6fbf373 100644 --- a/Swiften/Network/EnvironmentProxyProvider.cpp +++ b/Swiften/Network/EnvironmentProxyProvider.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2016 Isode Limited. + * Copyright (c) 2016-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -17,6 +17,8 @@ #include <iostream> +#include <boost/numeric/conversion/cast.hpp> + #include <Swiften/Base/Log.h> namespace Swift { @@ -24,7 +26,7 @@ namespace Swift { EnvironmentProxyProvider::EnvironmentProxyProvider() { socksProxy = getFromEnv("all_proxy", "socks"); httpProxy = getFromEnv("http_proxy", "http"); - SWIFT_LOG(debug) << "Environment: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString() << std::endl; + SWIFT_LOG(debug) << "Environment: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString(); } HostAddressPort EnvironmentProxyProvider::getHTTPConnectProxy() const { @@ -38,7 +40,7 @@ HostAddressPort EnvironmentProxyProvider::getSOCKS5Proxy() const { HostAddressPort EnvironmentProxyProvider::getFromEnv(const char* envVarName, std::string proxyProtocol) { char* envVar = nullptr; std::string address; - int port = 0; + unsigned short port = 0; envVar = getenv(envVarName); @@ -46,7 +48,11 @@ HostAddressPort EnvironmentProxyProvider::getFromEnv(const char* envVarName, std address = envVar != nullptr ? envVar : "0.0.0.0"; if(envVar != nullptr && address.compare(0, proxyProtocol.length(), proxyProtocol) == 0) { address = address.substr(proxyProtocol.length(), address.length()); - port = atoi(address.substr(address.find(':') + 1, address.length()).c_str()); + try { + port = boost::numeric_cast<unsigned short>(atoi(address.substr(address.find(':') + 1, address.length()).c_str())); + } + catch (boost::numeric::bad_numeric_cast&) { + } address = address.substr(0, address.find(':')); } diff --git a/Swiften/Network/GConfProxyProvider.cpp b/Swiften/Network/GConfProxyProvider.cpp index eade450..a2f8adc 100644 --- a/Swiften/Network/GConfProxyProvider.cpp +++ b/Swiften/Network/GConfProxyProvider.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2016-2017 Isode Limited. + * Copyright (c) 2016-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -21,6 +21,8 @@ extern "C" { #include <gconf/gconf-client.h> } +#include <boost/numeric/conversion/cast.hpp> + #include <Swiften/Base/Log.h> namespace Swift { @@ -37,7 +39,7 @@ GConfProxyProvider::GConfProxyProvider() { socksProxy = getFromGConf("/system/proxy/socks_host", "/system/proxy/socks_port"); httpProxy = getFromGConf("/system/http_proxy/host", "/system/http_proxy/port"); - SWIFT_LOG(debug) << "GConf: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString() << std::endl; + SWIFT_LOG(debug) << "GConf: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString(); } HostAddressPort GConfProxyProvider::getHTTPConnectProxy() const { @@ -50,13 +52,17 @@ HostAddressPort GConfProxyProvider::getSOCKS5Proxy() const { HostAddressPort GConfProxyProvider::getFromGConf(const char* gcHost, const char* gcPort) { std::string address; - int port = 0; + unsigned short port = 0; gchar* str; GConfClient* client = gconf_client_get_default(); str = gconf_client_get_string(client, gcHost, NULL); - port = static_cast<int> (gconf_client_get_int(client, gcPort, NULL)); + try { + port = boost::numeric_cast<unsigned short>(gconf_client_get_int(client, gcPort, NULL)); + } + catch (const boost::numeric::bad_numeric_cast&) { + } if(str) { address = static_cast<char*> (str); diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp index b5e521b..e63b8e2 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -36,7 +36,7 @@ HTTPConnectProxiedConnection::HTTPConnectProxiedConnection( ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, - int proxyPort, + unsigned short proxyPort, const SafeString& authID, const SafeString& authPassword) : ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort), @@ -77,7 +77,7 @@ void HTTPConnectProxiedConnection::initializeProxy() { nextHTTPRequestHeaders_.clear(); } append(data, createSafeByteArray("\r\n")); - SWIFT_LOG(debug) << "HTTP Proxy send headers: " << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl; + SWIFT_LOG(debug) << "HTTP Proxy send headers: " << byteArrayToString(ByteArray(data.begin(), data.end())); write(data); } @@ -111,7 +111,7 @@ void HTTPConnectProxiedConnection::sendHTTPRequest(const std::string& statusLine void HTTPConnectProxiedConnection::handleProxyInitializeData(std::shared_ptr<SafeByteArray> data) { std::string dataString = byteArrayToString(ByteArray(data->begin(), data->end())); - SWIFT_LOG(debug) << data << std::endl; + SWIFT_LOG(debug) << data; httpResponseBuffer_.append(dataString); std::string statusLine; @@ -141,17 +141,17 @@ void HTTPConnectProxiedConnection::handleProxyInitializeData(std::shared_ptr<Saf if (tmp.size() > 1) { try { int status = boost::lexical_cast<int>(tmp[1]); - SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl; + SWIFT_LOG(debug) << "Proxy Status: " << status; if (status / 100 == 2) { // all 2XX states are OK setProxyInitializeFinished(true); } else { - SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << httpResponseBuffer_ << std::endl; + SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << httpResponseBuffer_; setProxyInitializeFinished(false); } } catch (boost::bad_lexical_cast&) { - SWIFT_LOG(warning) << "Unexpected response: " << tmp[1] << std::endl; + SWIFT_LOG(warning) << "Unexpected response: " << tmp[1]; setProxyInitializeFinished(false); } } diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h index 6592839..a83d47c 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.h +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2011-2017 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -30,14 +30,14 @@ namespace Swift { virtual ~HTTPConnectProxiedConnection(); - static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) { + static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort, const SafeString& authID, const SafeString& authPassword) { return ref(new HTTPConnectProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, authID, authPassword)); } void setHTTPTrafficFilter(std::shared_ptr<HTTPTrafficFilter> trafficFilter); private: - HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); + HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort, const SafeString& authID, const SafeString& authPassword); virtual void initializeProxy(); virtual void handleProxyInitializeData(std::shared_ptr<SafeByteArray> data); diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp index 91ace3d..54b998a 100644 --- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,11 +16,11 @@ namespace Swift { -HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(""), authPassword_(""), httpTrafficFilter_(httpTrafficFilter) { +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort, std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(""), authPassword_(""), httpTrafficFilter_(httpTrafficFilter) { } -HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword, std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(authID), authPassword_(authPassword), httpTrafficFilter_(httpTrafficFilter) { +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort, const SafeString& authID, const SafeString& authPassword, std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(authID), authPassword_(authPassword), httpTrafficFilter_(httpTrafficFilter) { } std::shared_ptr<Connection> HTTPConnectProxiedConnectionFactory::createConnection() { diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h index 395f64f..7a5f527 100644 --- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -24,8 +24,8 @@ namespace Swift { class SWIFTEN_API HTTPConnectProxiedConnectionFactory : public ConnectionFactory { public: - HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter = std::shared_ptr<HTTPTrafficFilter>()); - HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword, std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter = std::shared_ptr<HTTPTrafficFilter>()); + HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort, std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter = std::shared_ptr<HTTPTrafficFilter>()); + HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort, const SafeString& authID, const SafeString& authPassword, std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter = std::shared_ptr<HTTPTrafficFilter>()); virtual std::shared_ptr<Connection> createConnection(); @@ -34,7 +34,7 @@ namespace Swift { ConnectionFactory* connectionFactory_; TimerFactory* timerFactory_; std::string proxyHost_; - int proxyPort_; + unsigned short proxyPort_; SafeString authID_; SafeString authPassword_; std::shared_ptr<HTTPTrafficFilter> httpTrafficFilter_; diff --git a/Swiften/Network/HostAddress.cpp b/Swiften/Network/HostAddress.cpp index 6eca80b..e82f433 100644 --- a/Swiften/Network/HostAddress.cpp +++ b/Swiften/Network/HostAddress.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -43,7 +43,7 @@ std::string HostAddress::toString() const { addressString = address_.to_string(errorCode); if (errorCode) { - SWIFT_LOG(debug) << "error: " << errorCode.message() << std::endl; + SWIFT_LOG(debug) << "error: " << errorCode.message(); } return addressString; diff --git a/Swiften/Network/HostAddress.h b/Swiften/Network/HostAddress.h index e4ddffb..7a22cf4 100644 --- a/Swiften/Network/HostAddress.h +++ b/Swiften/Network/HostAddress.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -27,6 +27,10 @@ namespace Swift { return address_ == o.address_; } + bool operator<(const HostAddress& o) const { + return address_ < o.address_; + } + bool isValid() const; bool isLocalhost() const; diff --git a/Swiften/Network/HostAddressPort.cpp b/Swiften/Network/HostAddressPort.cpp index 76c276e..248be2d 100644 --- a/Swiften/Network/HostAddressPort.cpp +++ b/Swiften/Network/HostAddressPort.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -10,7 +10,7 @@ using namespace Swift; -HostAddressPort::HostAddressPort(const HostAddress& address, int port) : address_(address), port_(port) { +HostAddressPort::HostAddressPort(const HostAddress& address, unsigned short port) : address_(address), port_(port) { } HostAddressPort::HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint) { @@ -21,7 +21,7 @@ HostAddressPort::HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint) std::string HostAddressPort::toString() const { std::string portAsString; try { - portAsString = boost::lexical_cast<std::string>(getPort()); + portAsString = std::to_string(getPort()); } catch (boost::bad_lexical_cast&) { } return getAddress().toString() + ":" + portAsString; diff --git a/Swiften/Network/HostAddressPort.h b/Swiften/Network/HostAddressPort.h index e42e1d1..759af01 100644 --- a/Swiften/Network/HostAddressPort.h +++ b/Swiften/Network/HostAddressPort.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -14,14 +14,14 @@ namespace Swift { class SWIFTEN_API HostAddressPort { public: - HostAddressPort(const HostAddress& address = HostAddress(), int port = -1); + HostAddressPort(const HostAddress& address = HostAddress(), unsigned short port = 0); HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint); const HostAddress& getAddress() const { return address_; } - int getPort() const { + unsigned short getPort() const { return port_; } @@ -29,6 +29,13 @@ namespace Swift { return address_ == o.address_ && port_ == o.port_; } + bool operator<(const HostAddressPort& o) const { + if (address_ < o.address_) { + return true; + } + return address_ == o.address_ && port_ < o.port_; + } + bool isValid() const { return address_.isValid() && port_ > 0; } @@ -37,6 +44,6 @@ namespace Swift { private: HostAddress address_; - int port_; + unsigned short port_; }; } diff --git a/Swiften/Network/MacOSXProxyProvider.cpp b/Swiften/Network/MacOSXProxyProvider.cpp index 232fc60..d3b10dd 100644 --- a/Swiften/Network/MacOSXProxyProvider.cpp +++ b/Swiften/Network/MacOSXProxyProvider.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013-2016 Isode Limited. + * Copyright (c) 2013-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -40,13 +40,15 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl CFRelease(zero); if(result != kCFCompareEqualTo) { - int port = 0; + unsigned short port = 0; std::string host = ""; try { CFNumberRef numberValue = reinterpret_cast<CFNumberRef> (CFDictionaryGetValue(dict, portKey)); if(numberValue != nullptr) { - CFNumberGetValue(numberValue, kCFNumberIntType, &port); + int intPort = 0; + CFNumberGetValue(numberValue, kCFNumberIntType, &intPort); + port = boost::numeric_cast<unsigned short>(intPort); } CFStringRef stringValue = reinterpret_cast<CFStringRef> (CFDictionaryGetValue(dict, hostKey)); diff --git a/Swiften/Network/MiniUPnPInterface.cpp b/Swiften/Network/MiniUPnPInterface.cpp index dbe8bcd..8425c77 100644 --- a/Swiften/Network/MiniUPnPInterface.cpp +++ b/Swiften/Network/MiniUPnPInterface.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -14,8 +14,6 @@ #include <memory> -#include <boost/lexical_cast.hpp> - #include <miniupnpc.h> #include <upnpcommands.h> #include <upnperrors.h> @@ -73,16 +71,16 @@ boost::optional<HostAddress> MiniUPnPInterface::getPublicIP() { } } -boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(int actualLocalPort, int actualPublicPort) { +boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(unsigned short actualLocalPort, unsigned short actualPublicPort) { if (!p->isValid) { return boost::optional<NATPortMapping>(); } NATPortMapping mapping(actualLocalPort, actualPublicPort, NATPortMapping::TCP); - std::string publicPort = boost::lexical_cast<std::string>(mapping.getPublicPort()); - std::string localPort = boost::lexical_cast<std::string>(mapping.getLocalPort()); - std::string leaseSeconds = boost::lexical_cast<std::string>(mapping.getLeaseInSeconds()); + std::string publicPort = std::to_string(mapping.getPublicPort()); + std::string localPort = std::to_string(mapping.getLocalPort()); + std::string leaseSeconds = std::to_string(mapping.getLeaseInSeconds()); int ret = UPNP_AddPortMapping( p->urls.controlURL, @@ -107,9 +105,9 @@ bool MiniUPnPInterface::removePortForward(const NATPortMapping& mapping) { return false; } - std::string publicPort = boost::lexical_cast<std::string>(mapping.getPublicPort()); - std::string localPort = boost::lexical_cast<std::string>(mapping.getLocalPort()); - std::string leaseSeconds = boost::lexical_cast<std::string>(mapping.getLeaseInSeconds()); + std::string publicPort = std::to_string(mapping.getPublicPort()); + std::string localPort = std::to_string(mapping.getLocalPort()); + std::string leaseSeconds = std::to_string(mapping.getLeaseInSeconds()); int ret = UPNP_DeletePortMapping(p->urls.controlURL, p->data.first.servicetype, publicPort.c_str(), mapping.getProtocol() == NATPortMapping::TCP ? "TCP" : "UDP", nullptr); return ret == UPNPCOMMAND_SUCCESS; diff --git a/Swiften/Network/MiniUPnPInterface.h b/Swiften/Network/MiniUPnPInterface.h index 89457b8..8c68268 100644 --- a/Swiften/Network/MiniUPnPInterface.h +++ b/Swiften/Network/MiniUPnPInterface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ @@ -23,7 +23,7 @@ namespace Swift { virtual bool isAvailable(); boost::optional<HostAddress> getPublicIP(); - boost::optional<NATPortMapping> addPortForward(int localPort, int publicPort); + boost::optional<NATPortMapping> addPortForward(unsigned short localPort, unsigned short publicPort); bool removePortForward(const NATPortMapping&); private: diff --git a/Swiften/Network/NATPMPInterface.cpp b/Swiften/Network/NATPMPInterface.cpp index 5e0b3b3..e20fecd 100644 --- a/Swiften/Network/NATPMPInterface.cpp +++ b/Swiften/Network/NATPMPInterface.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2014-2016 Isode Limited. + * Copyright (c) 2014-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -14,8 +14,6 @@ #include <memory> -#include <boost/numeric/conversion/cast.hpp> - #include <Swiften/Base/Log.h> // This has to be included after the previous headers, because of WIN32 macro @@ -44,7 +42,7 @@ bool NATPMPInterface::isAvailable() { boost::optional<HostAddress> NATPMPInterface::getPublicIP() { if (sendpublicaddressrequest(&p->natpmp) < 0) { - SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!" << std::endl; + SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!"; return boost::optional<HostAddress>(); } @@ -69,20 +67,20 @@ boost::optional<HostAddress> NATPMPInterface::getPublicIP() { return boost::optional<HostAddress>(HostAddress(reinterpret_cast<const unsigned char*>(&(response.pnu.publicaddress.addr)), 4)); } else { - SWIFT_LOG(debug) << "Inavlid NAT-PMP response." << std::endl; + SWIFT_LOG(debug) << "Inavlid NAT-PMP response."; return boost::optional<HostAddress>(); } } -boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, int publicPort) { +boost::optional<NATPortMapping> NATPMPInterface::addPortForward(unsigned short localPort, unsigned short publicPort) { NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); if (sendnewportmappingrequest( &p->natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, - boost::numeric_cast<uint16_t>(mapping.getLocalPort()), - boost::numeric_cast<uint16_t>(mapping.getPublicPort()), - boost::numeric_cast<uint32_t>(mapping.getLeaseInSeconds())) < 0) { - SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!" << std::endl; + mapping.getLocalPort(), + mapping.getPublicPort(), + mapping.getLeaseInSeconds()) < 0) { + SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!"; return boost::optional<NATPortMapping>(); } @@ -104,18 +102,18 @@ boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, i } while(false /*r == NATPMP_TRYAGAIN*/); if (r == 0) { - NATPortMapping result(response.pnu.newportmapping.privateport, response.pnu.newportmapping.mappedpublicport, NATPortMapping::TCP, boost::numeric_cast<int>(response.pnu.newportmapping.lifetime)); + NATPortMapping result(response.pnu.newportmapping.privateport, response.pnu.newportmapping.mappedpublicport, NATPortMapping::TCP, response.pnu.newportmapping.lifetime); return result; } else { - SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl; + SWIFT_LOG(debug) << "Invalid NAT-PMP response."; return boost::optional<NATPortMapping>(); } } bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { - if (sendnewportmappingrequest(&p->natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, boost::numeric_cast<uint32_t>(mapping.getLocalPort())) < 0) { - SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!" << std::endl; + if (sendnewportmappingrequest(&p->natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, mapping.getLocalPort(), 0, 0) < 0) { + SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!"; return false; } @@ -135,7 +133,7 @@ bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { return true; } else { - SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl; + SWIFT_LOG(debug) << "Invalid NAT-PMP response."; return false; } } diff --git a/Swiften/Network/NATPMPInterface.h b/Swiften/Network/NATPMPInterface.h index e1666c8..58d62b6 100644 --- a/Swiften/Network/NATPMPInterface.h +++ b/Swiften/Network/NATPMPInterface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ @@ -23,7 +23,7 @@ namespace Swift { virtual bool isAvailable(); virtual boost::optional<HostAddress> getPublicIP(); - virtual boost::optional<NATPortMapping> addPortForward(int localPort, int publicPort); + virtual boost::optional<NATPortMapping> addPortForward(unsigned short localPort, unsigned short publicPort); virtual bool removePortForward(const NATPortMapping&); private: diff --git a/Swiften/Network/NATPortMapping.h b/Swiften/Network/NATPortMapping.h index ff8fde3..bf0fb1c 100644 --- a/Swiften/Network/NATPortMapping.h +++ b/Swiften/Network/NATPortMapping.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,16 +23,16 @@ namespace Swift { UDP }; - NATPortMapping(int localPort, int publicPort, Protocol protocol = TCP, int leaseInSeconds = 60 * 60 * 24) : + NATPortMapping(unsigned short localPort, unsigned short publicPort, Protocol protocol = TCP, uint32_t leaseInSeconds = 60 * 60 * 24) : publicPort(publicPort), localPort(localPort), protocol(protocol), leaseInSeconds(leaseInSeconds) { } - int getPublicPort() const { + unsigned short getPublicPort() const { return publicPort; } - int getLocalPort() const { + unsigned short getLocalPort() const { return localPort; } @@ -40,14 +40,14 @@ namespace Swift { return protocol; } - int getLeaseInSeconds() const { + uint32_t getLeaseInSeconds() const { return leaseInSeconds; } private: - int publicPort; - int localPort; + unsigned short publicPort; + unsigned short localPort; Protocol protocol; - int leaseInSeconds; + uint32_t leaseInSeconds; }; } diff --git a/Swiften/Network/NATTraversalInterface.h b/Swiften/Network/NATTraversalInterface.h index ea9ed6a..1655eb6 100644 --- a/Swiften/Network/NATTraversalInterface.h +++ b/Swiften/Network/NATTraversalInterface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ @@ -19,7 +19,7 @@ namespace Swift { virtual bool isAvailable() = 0; virtual boost::optional<HostAddress> getPublicIP() = 0; - virtual boost::optional<NATPortMapping> addPortForward(int localPort, int publicPort) = 0; + virtual boost::optional<NATPortMapping> addPortForward(unsigned short localPort, unsigned short publicPort) = 0; virtual bool removePortForward(const NATPortMapping&) = 0; }; } diff --git a/Swiften/Network/NATTraversalRemovePortForwardingRequest.h b/Swiften/Network/NATTraversalRemovePortForwardingRequest.h index 3db9ee1..83235f9 100644 --- a/Swiften/Network/NATTraversalRemovePortForwardingRequest.h +++ b/Swiften/Network/NATTraversalRemovePortForwardingRequest.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -26,8 +26,8 @@ namespace Swift { UDP }; - unsigned int publicPort; - unsigned int localPort; + unsigned short publicPort; + unsigned short localPort; Protocol protocol; unsigned long leaseInSeconds; }; diff --git a/Swiften/Network/NATTraverser.h b/Swiften/Network/NATTraverser.h index 716bfcb..7f03c03 100644 --- a/Swiften/Network/NATTraverser.h +++ b/Swiften/Network/NATTraverser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,7 +20,7 @@ namespace Swift { virtual ~NATTraverser(); virtual std::shared_ptr<NATTraversalGetPublicIPRequest> createGetPublicIPRequest() = 0; - virtual std::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(int localPort, int publicPort) = 0; - virtual std::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(int localPort, int publicPort) = 0; + virtual std::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(unsigned short localPort, unsigned short publicPort) = 0; + virtual std::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(unsigned short localPort, unsigned short publicPort) = 0; }; } diff --git a/Swiften/Network/NullNATTraversalInterface.h b/Swiften/Network/NullNATTraversalInterface.h index ecbf110..eabc197 100644 --- a/Swiften/Network/NullNATTraversalInterface.h +++ b/Swiften/Network/NullNATTraversalInterface.h @@ -21,7 +21,7 @@ namespace Swift { return boost::optional<HostAddress>(); } - virtual boost::optional<NATPortMapping> addPortForward(int, int) { + virtual boost::optional<NATPortMapping> addPortForward(unsigned short, unsigned short) { return boost::optional<NATPortMapping>(); } diff --git a/Swiften/Network/NullNATTraverser.cpp b/Swiften/Network/NullNATTraverser.cpp index cc8bae0..0b9464e 100644 --- a/Swiften/Network/NullNATTraverser.cpp +++ b/Swiften/Network/NullNATTraverser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -72,11 +72,11 @@ std::shared_ptr<NATTraversalGetPublicIPRequest> NullNATTraverser::createGetPubli return std::make_shared<NullNATTraversalGetPublicIPRequest>(eventLoop); } -std::shared_ptr<NATTraversalForwardPortRequest> NullNATTraverser::createForwardPortRequest(int, int) { +std::shared_ptr<NATTraversalForwardPortRequest> NullNATTraverser::createForwardPortRequest(unsigned short, unsigned short) { return std::make_shared<NullNATTraversalForwardPortRequest>(eventLoop); } -std::shared_ptr<NATTraversalRemovePortForwardingRequest> NullNATTraverser::createRemovePortForwardingRequest(int, int) { +std::shared_ptr<NATTraversalRemovePortForwardingRequest> NullNATTraverser::createRemovePortForwardingRequest(unsigned short, unsigned short) { return std::make_shared<NullNATTraversalRemovePortForwardingRequest>(eventLoop); } diff --git a/Swiften/Network/NullNATTraverser.h b/Swiften/Network/NullNATTraverser.h index d3a6640..2f975bf 100644 --- a/Swiften/Network/NullNATTraverser.h +++ b/Swiften/Network/NullNATTraverser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,8 +16,8 @@ namespace Swift { NullNATTraverser(EventLoop* eventLoop); std::shared_ptr<NATTraversalGetPublicIPRequest> createGetPublicIPRequest(); - std::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(int localPort, int publicPort); - std::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(int localPort, int publicPort); + std::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(unsigned short localPort, unsigned short publicPort); + std::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(unsigned short localPort, unsigned short publicPort); private: EventLoop* eventLoop; diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.cpp b/Swiften/Network/PlatformDomainNameServiceQuery.cpp index a5d180b..2ff14e1 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.cpp +++ b/Swiften/Network/PlatformDomainNameServiceQuery.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -58,7 +58,7 @@ void PlatformDomainNameServiceQuery::runBlocking() { return; } - SWIFT_LOG(debug) << "Querying " << service << std::endl; + SWIFT_LOG(debug) << "Querying " << service; std::vector<DomainNameServiceQuery::Result> records; @@ -97,7 +97,7 @@ void PlatformDomainNameServiceQuery::runBlocking() { response.resize(NS_PACKETSZ); int responseLength = res_query(const_cast<char*>(service.c_str()), ns_c_in, ns_t_srv, reinterpret_cast<u_char*>(vecptr(response)), response.size()); if (responseLength == -1) { - SWIFT_LOG(debug) << "Error" << std::endl; + SWIFT_LOG(debug) << "Error"; emitError(); return; } @@ -129,35 +129,42 @@ void PlatformDomainNameServiceQuery::runBlocking() { currentEntry += entryLength; currentEntry += NS_RRFIXEDSZ; - // Priority - if (currentEntry + 2 >= messageEnd) { - emitError(); - return; - } - record.priority = boost::numeric_cast<int>(ns_get16(currentEntry)); - currentEntry += 2; - - // Weight - if (currentEntry + 2 >= messageEnd) { - emitError(); - return; + try { + // Priority + if (currentEntry + 2 >= messageEnd) { + emitError(); + return; + } + record.priority = boost::numeric_cast<int>(ns_get16(currentEntry)); + currentEntry += 2; + + // Weight + if (currentEntry + 2 >= messageEnd) { + emitError(); + return; + } + record.weight = boost::numeric_cast<int>(ns_get16(currentEntry)); + currentEntry += 2; + + // Port + if (currentEntry + 2 >= messageEnd) { + emitError(); + return; + } + record.port = boost::numeric_cast<unsigned short>(ns_get16(currentEntry)); + currentEntry += 2; + + // Hostname + if (currentEntry >= messageEnd) { + emitError(); + return; + } } - record.weight = boost::numeric_cast<int>(ns_get16(currentEntry)); - currentEntry += 2; - - // Port - if (currentEntry + 2 >= messageEnd) { + catch (const boost::numeric::bad_numeric_cast&) { emitError(); return; } - record.port = boost::numeric_cast<int>(ns_get16(currentEntry)); - currentEntry += 2; - // Hostname - if (currentEntry >= messageEnd) { - emitError(); - return; - } ByteArray entry; entry.resize(NS_MAXDNAME); entryLength = dn_expand(messageStart, messageEnd, currentEntry, reinterpret_cast<char*>(vecptr(entry)), entry.size()); diff --git a/Swiften/Network/PlatformNATTraversalWorker.cpp b/Swiften/Network/PlatformNATTraversalWorker.cpp index f56de0b..5431379 100644 --- a/Swiften/Network/PlatformNATTraversalWorker.cpp +++ b/Swiften/Network/PlatformNATTraversalWorker.cpp @@ -84,7 +84,7 @@ class PlatformNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPReq class PlatformNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest, public PlatformNATTraversalRequest { public: - PlatformNATTraversalForwardPortRequest(PlatformNATTraversalWorker* worker, unsigned int localIP, unsigned int publicIP) : PlatformNATTraversalRequest(worker), localIP(localIP), publicIP(publicIP) { + PlatformNATTraversalForwardPortRequest(PlatformNATTraversalWorker* worker, unsigned short localPort, unsigned short publicPort) : PlatformNATTraversalRequest(worker), localPort(localPort), publicPort(publicPort) { } virtual ~PlatformNATTraversalForwardPortRequest() { @@ -99,12 +99,12 @@ class PlatformNATTraversalForwardPortRequest : public NATTraversalForwardPortReq } virtual void runBlocking() { - getEventLoop()->postEvent(boost::bind(boost::ref(onResult), getNATTraversalInterface()->addPortForward(boost::numeric_cast<int>(localIP), boost::numeric_cast<int>(publicIP))), shared_from_this()); + getEventLoop()->postEvent(boost::bind(boost::ref(onResult), getNATTraversalInterface()->addPortForward(localPort, publicPort)), shared_from_this()); } private: - unsigned int localIP; - unsigned int publicIP; + unsigned short localPort; + unsigned short publicPort; }; class PlatformNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePortForwardingRequest, public PlatformNATTraversalRequest { @@ -157,7 +157,7 @@ NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() co miniUPnPInterface = new MiniUPnPInterface(); miniUPnPSupported = miniUPnPInterface->isAvailable(); } - SWIFT_LOG(debug) << "UPnP NAT traversal supported: " << miniUPnPSupported << std::endl; + SWIFT_LOG(debug) << "UPnP NAT traversal supported: " << static_cast<bool>(miniUPnPSupported); if (miniUPnPSupported) { return miniUPnPInterface; } @@ -168,7 +168,7 @@ NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() co natPMPInterface = new NATPMPInterface(); natPMPSupported = natPMPInterface->isAvailable(); } - SWIFT_LOG(debug) << "NAT-PMP NAT traversal supported: " << natPMPSupported << std::endl; + SWIFT_LOG(debug) << "NAT-PMP NAT traversal supported: " << static_cast<bool>(natPMPSupported); if (natPMPSupported) { return natPMPInterface; } @@ -181,11 +181,11 @@ std::shared_ptr<NATTraversalGetPublicIPRequest> PlatformNATTraversalWorker::crea return std::make_shared<PlatformNATTraversalGetPublicIPRequest>(this); } -std::shared_ptr<NATTraversalForwardPortRequest> PlatformNATTraversalWorker::createForwardPortRequest(int localPort, int publicPort) { +std::shared_ptr<NATTraversalForwardPortRequest> PlatformNATTraversalWorker::createForwardPortRequest(unsigned short localPort, unsigned short publicPort) { return std::make_shared<PlatformNATTraversalForwardPortRequest>(this, localPort, publicPort); } -std::shared_ptr<NATTraversalRemovePortForwardingRequest> PlatformNATTraversalWorker::createRemovePortForwardingRequest(int localPort, int publicPort) { +std::shared_ptr<NATTraversalRemovePortForwardingRequest> PlatformNATTraversalWorker::createRemovePortForwardingRequest(unsigned short localPort, unsigned short publicPort) { NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); // FIXME return std::make_shared<PlatformNATTraversalRemovePortForwardingRequest>(this, mapping); } diff --git a/Swiften/Network/PlatformNATTraversalWorker.h b/Swiften/Network/PlatformNATTraversalWorker.h index aee1052..368798e 100644 --- a/Swiften/Network/PlatformNATTraversalWorker.h +++ b/Swiften/Network/PlatformNATTraversalWorker.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2016-2017 Isode Limited. + * Copyright (c) 2016-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -44,8 +44,8 @@ namespace Swift { virtual ~PlatformNATTraversalWorker(); std::shared_ptr<NATTraversalGetPublicIPRequest> createGetPublicIPRequest(); - std::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(int localPort, int publicPort); - std::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(int localPort, int publicPort); + std::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(unsigned short localPort, unsigned short publicPort); + std::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(unsigned short localPort, unsigned short publicPort); private: NATTraversalInterface* getNATTraversalInterface() const; diff --git a/Swiften/Network/ProxiedConnection.cpp b/Swiften/Network/ProxiedConnection.cpp index aa6c4d2..0c5cda6 100644 --- a/Swiften/Network/ProxiedConnection.cpp +++ b/Swiften/Network/ProxiedConnection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,7 +20,7 @@ ProxiedConnection::ProxiedConnection( ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, - int proxyPort) : + unsigned short proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), @@ -37,7 +37,7 @@ ProxiedConnection::~ProxiedConnection() { connection_->onDisconnected.disconnect(boost::bind(&ProxiedConnection::handleDisconnected, shared_from_this(), _1)); } if (connected_) { - SWIFT_LOG(warning) << "Connection was still established." << std::endl; + SWIFT_LOG(warning) << "Connection was still established."; } } diff --git a/Swiften/Network/ProxiedConnection.h b/Swiften/Network/ProxiedConnection.h index 440fb86..f79845a 100644 --- a/Swiften/Network/ProxiedConnection.h +++ b/Swiften/Network/ProxiedConnection.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 Isode Limited. + * Copyright (c) 2012-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,7 +20,7 @@ namespace Swift { class SWIFTEN_API ProxiedConnection : public Connection, public std::enable_shared_from_this<ProxiedConnection> { public: - ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); + ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort); virtual ~ProxiedConnection(); virtual void listen(); @@ -55,7 +55,7 @@ namespace Swift { ConnectionFactory* connectionFactory_; TimerFactory* timerFactory_; std::string proxyHost_; - int proxyPort_; + unsigned short proxyPort_; HostAddressPort server_; Connector::ref connector_; std::shared_ptr<Connection> connection_; diff --git a/Swiften/Network/SOCKS5ProxiedConnection.cpp b/Swiften/Network/SOCKS5ProxiedConnection.cpp index 2492827..c76b6e6 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.cpp +++ b/Swiften/Network/SOCKS5ProxiedConnection.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2014-2016 Isode Limited. + * Copyright (c) 2014-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -27,7 +27,7 @@ SOCKS5ProxiedConnection::SOCKS5ProxiedConnection( ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, - int proxyPort) : + unsigned short proxyPort) : ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort), proxyState_(Initial) { } @@ -50,7 +50,7 @@ void SOCKS5ProxiedConnection::handleProxyInitializeData(std::shared_ptr<SafeByte assert(rawAddress.is_v4() || rawAddress.is_v6()); if (proxyState_ == ProxyAuthenticating) { - SWIFT_LOG(debug) << "ProxyAuthenticating response received, reply with the connect BYTEs" << std::endl; + SWIFT_LOG(debug) << "ProxyAuthenticating response received, reply with the connect BYTEs"; unsigned char choosenMethod = static_cast<unsigned char> ((*data)[1]); if ((*data)[0] == 0x05 && choosenMethod != 0xFF) { switch(choosenMethod) { // use the correct Method @@ -79,7 +79,7 @@ void SOCKS5ProxiedConnection::handleProxyInitializeData(std::shared_ptr<SafeByte return; } catch(...) { - SWIFT_LOG(error) << "exception caught" << std::endl; + SWIFT_LOG(error) << "exception caught"; } write(socksConnect); break; @@ -92,8 +92,8 @@ void SOCKS5ProxiedConnection::handleProxyInitializeData(std::shared_ptr<SafeByte setProxyInitializeFinished(false); } else if (proxyState_ == ProxyConnecting) { - SWIFT_LOG(debug) << "Connect response received, check if successfully." << std::endl; - SWIFT_LOG(debug) << "Errorbyte: 0x" << std::hex << static_cast<int> ((*data)[1]) << std::dec << std::endl; + SWIFT_LOG(debug) << "Connect response received, check if successfully."; + SWIFT_LOG(debug) << "Errorbyte: 0x" << std::hex << static_cast<int> ((*data)[1]) << std::dec; /* data.at(1) can be one of the following: @@ -109,11 +109,11 @@ void SOCKS5ProxiedConnection::handleProxyInitializeData(std::shared_ptr<SafeByte 0x09 bis 0xFF unassigned */ if ((*data)[0] == 0x05 && (*data)[1] == 0x0) { - SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl; + SWIFT_LOG(debug) << "Successfully connected the server via the proxy."; setProxyInitializeFinished(true); } else { - SWIFT_LOG(error) << "SOCKS Proxy returned an error: " << std::hex << (*data)[1] << std::endl; + SWIFT_LOG(error) << "SOCKS Proxy returned an error: " << std::hex << (*data)[1]; setProxyInitializeFinished(false); } } diff --git a/Swiften/Network/SOCKS5ProxiedConnection.h b/Swiften/Network/SOCKS5ProxiedConnection.h index c8faae9..515c5b7 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.h +++ b/Swiften/Network/SOCKS5ProxiedConnection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -24,12 +24,12 @@ namespace Swift { public: typedef std::shared_ptr<SOCKS5ProxiedConnection> ref; - static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) { + static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort) { return ref(new SOCKS5ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort)); } private: - SOCKS5ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); + SOCKS5ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort); virtual void initializeProxy(); virtual void handleProxyInitializeData(std::shared_ptr<SafeByteArray> data); diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp index 01ce8ac..abd7718 100644 --- a/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp @@ -16,7 +16,7 @@ namespace Swift { -SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort) { +SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort) { } std::shared_ptr<Connection> SOCKS5ProxiedConnectionFactory::createConnection() { diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h index 8631239..47ae9a3 100644 --- a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,7 +23,7 @@ namespace Swift { class SWIFTEN_API SOCKS5ProxiedConnectionFactory : public ConnectionFactory { public: - SOCKS5ProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); + SOCKS5ProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, unsigned short proxyPort); virtual std::shared_ptr<Connection> createConnection(); @@ -32,6 +32,6 @@ namespace Swift { ConnectionFactory* connectionFactory_; TimerFactory* timerFactory_; std::string proxyHost_; - int proxyPort_; + unsigned short proxyPort_; }; } diff --git a/Swiften/Network/StaticDomainNameResolver.cpp b/Swiften/Network/StaticDomainNameResolver.cpp index 95b3dd9..eca6687 100644 --- a/Swiften/Network/StaticDomainNameResolver.cpp +++ b/Swiften/Network/StaticDomainNameResolver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -50,6 +50,10 @@ namespace { if (!resolver->getIsResponsive()) { return; } + if (auto address = HostAddress::fromString(host)) { + // IP Literals should resolve to themselves + resolver->addAddress(host, *address); + } StaticDomainNameResolver::AddressesMap::const_iterator i = resolver->getAddresses().find(host); if (i != resolver->getAddresses().end()) { eventLoop->postEvent( @@ -98,14 +102,14 @@ void StaticDomainNameResolver::addService(const std::string& service, const Doma void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, const HostAddressPort& address) { static int hostid = 0; - std::string hostname(std::string("host-") + boost::lexical_cast<std::string>(hostid)); + std::string hostname(std::string("host-") + std::to_string(hostid)); hostid++; addService("_xmpp-client._tcp." + domain, ServiceQuery::Result(hostname, address.getPort(), 0, 0)); addAddress(hostname, address.getAddress()); } -void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, const std::string& hostname, int port) { +void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, const std::string& hostname, unsigned short port) { addService("_xmpp-client._tcp." + domain, ServiceQuery::Result(hostname, port, 0, 0)); } diff --git a/Swiften/Network/StaticDomainNameResolver.h b/Swiften/Network/StaticDomainNameResolver.h index 76394d0..2064046 100644 --- a/Swiften/Network/StaticDomainNameResolver.h +++ b/Swiften/Network/StaticDomainNameResolver.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -31,7 +31,7 @@ namespace Swift { void addAddress(const std::string& domain, const HostAddress& address); void addService(const std::string& service, const DomainNameServiceQuery::Result& result); void addXMPPClientService(const std::string& domain, const HostAddressPort&); - void addXMPPClientService(const std::string& domain, const std::string& host, int port); + void addXMPPClientService(const std::string& domain, const std::string& host, unsigned short port); const AddressesMap& getAddresses() const { return addresses; diff --git a/Swiften/Network/TLSConnection.cpp b/Swiften/Network/TLSConnection.cpp index 7c293d1..82bf114 100644 --- a/Swiften/Network/TLSConnection.cpp +++ b/Swiften/Network/TLSConnection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -32,7 +32,6 @@ TLSConnection::~TLSConnection() { connection->onDataRead.disconnect(boost::bind(&TLSConnection::handleRawDataRead, this, _1)); connection->onDataWritten.disconnect(boost::bind(&TLSConnection::handleRawDataWritten, this)); connection->onDisconnected.disconnect(boost::bind(&TLSConnection::handleRawDisconnected, this, _1)); - delete context; } void TLSConnection::handleTLSConnectFinished(bool error) { @@ -71,7 +70,7 @@ HostAddressPort TLSConnection::getRemoteAddress() const { } TLSContext* TLSConnection::getTLSContext() const { - return context; + return context.get(); } void TLSConnection::handleRawConnectFinished(bool error) { diff --git a/Swiften/Network/TLSConnection.h b/Swiften/Network/TLSConnection.h index 0c395d1..1ab1ec6 100644 --- a/Swiften/Network/TLSConnection.h +++ b/Swiften/Network/TLSConnection.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -46,7 +46,7 @@ namespace Swift { void handleTLSDataForApplication(const SafeByteArray& data); private: - TLSContext* context; + std::unique_ptr<TLSContext> context; Connection::ref connection; }; } diff --git a/Swiften/Network/UnboundDomainNameResolver.cpp b/Swiften/Network/UnboundDomainNameResolver.cpp index 1df6b8f..21bc697 100644 --- a/Swiften/Network/UnboundDomainNameResolver.cpp +++ b/Swiften/Network/UnboundDomainNameResolver.cpp @@ -64,7 +64,7 @@ class UnboundDomainNameServiceQuery : public DomainNameServiceQuery, public Unbo 1 /* CLASS IN (internet) */, helper, UnboundDomainNameResolver::unbound_callback_wrapper, NULL); if(retval != 0) { - SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval); delete helper; } } @@ -73,7 +73,7 @@ class UnboundDomainNameServiceQuery : public DomainNameServiceQuery, public Unbo std::vector<DomainNameServiceQuery::Result> serviceRecords; if(err != 0) { - SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err); } else { if(result->havedata) { ldns_pkt* replyPacket = 0; @@ -105,7 +105,7 @@ class UnboundDomainNameServiceQuery : public DomainNameServiceQuery, public Unbo serviceRecord.hostname = std::string(reinterpret_cast<char*>(ldns_buffer_at(buffer, 0))); serviceRecords.push_back(serviceRecord); - SWIFT_LOG(debug) << "hostname " << serviceRecord.hostname << " added" << std::endl; + SWIFT_LOG(debug) << "hostname " << serviceRecord.hostname << " added"; } } if (replyPacket) ldns_pkt_free(replyPacket); @@ -137,7 +137,7 @@ class UnboundDomainNameAddressQuery : public DomainNameAddressQuery, public Unbo 1 /* CLASS IN (internet) */, helper, UnboundDomainNameResolver::unbound_callback_wrapper, NULL); if(retval != 0) { - SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval); delete helper; } } @@ -145,10 +145,10 @@ class UnboundDomainNameAddressQuery : public DomainNameAddressQuery, public Unbo void handleResult(int err, struct ub_result* result) { std::vector<HostAddress> addresses; boost::optional<DomainNameResolveError> error; - SWIFT_LOG(debug) << "Result for: " << name << std::endl; + SWIFT_LOG(debug) << "Result for: " << name; if(err != 0) { - SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err); error = DomainNameResolveError(); } else { if(result->havedata) { @@ -156,13 +156,13 @@ class UnboundDomainNameAddressQuery : public DomainNameAddressQuery, public Unbo char address[100]; const char* addressStr = 0; if ((addressStr = inet_ntop(AF_INET, result->data[i], address, 100))) { - SWIFT_LOG(debug) << "IPv4 address: " << addressStr << std::endl; + SWIFT_LOG(debug) << "IPv4 address: " << addressStr; addresses.push_back(HostAddress(std::string(addressStr))); } else if ((addressStr = inet_ntop(AF_INET6, result->data[i], address, 100))) { - SWIFT_LOG(debug) << "IPv6 address: " << addressStr << std::endl; + SWIFT_LOG(debug) << "IPv6 address: " << addressStr; addresses.push_back(HostAddress(std::string(addressStr))); } else { - SWIFT_LOG(debug) << "inet_ntop() failed" << std::endl; + SWIFT_LOG(debug) << "inet_ntop() failed"; error = DomainNameResolveError(); } } @@ -182,7 +182,7 @@ class UnboundDomainNameAddressQuery : public DomainNameAddressQuery, public Unbo UnboundDomainNameResolver::UnboundDomainNameResolver(IDNConverter* idnConverter, std::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : idnConverter(idnConverter), ioService(ioService), ubDescriptior(*ioService), eventLoop(eventLoop) { ubContext = ub_ctx_create(); if(!ubContext) { - SWIFT_LOG(debug) << "could not create unbound context" << std::endl; + SWIFT_LOG(debug) << "could not create unbound context"; } eventOwner = std::make_shared<EventOwner>(); @@ -192,11 +192,11 @@ UnboundDomainNameResolver::UnboundDomainNameResolver(IDNConverter* idnConverter, /* read /etc/resolv.conf for DNS proxy settings (from DHCP) */ if( (ret=ub_ctx_resolvconf(ubContext, const_cast<char*>("/etc/resolv.conf"))) != 0) { - SWIFT_LOG(error) << "error reading resolv.conf: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + SWIFT_LOG(error) << "error reading resolv.conf: " << ub_strerror(ret) << ". errno says: " << strerror(errno); } /* read /etc/hosts for locally supplied host addresses */ if( (ret=ub_ctx_hosts(ubContext, const_cast<char*>("/etc/hosts"))) != 0) { - SWIFT_LOG(error) << "error reading hosts: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + SWIFT_LOG(error) << "error reading hosts: " << ub_strerror(ret) << ". errno says: " << strerror(errno); } ubDescriptior.assign(ub_fd(ubContext)); @@ -231,7 +231,7 @@ void UnboundDomainNameResolver::processData() { if (ub_poll(ubContext)) { int ret = ub_process(ubContext); if(ret != 0) { - SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret); } } } diff --git a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp index 5d6fedd..4aeaf24 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp @@ -194,7 +194,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); /* 0 was waiting for response, open and send on 1 */ CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* data */ c1 = connectionFactory->connections[1]; - std::string fullBody = "<body rid='" + boost::lexical_cast<std::string>(rid) + "' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'><blah/></body>"; /* check empty write */ + std::string fullBody = "<body rid='" + std::to_string(rid) + "' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'><blah/></body>"; /* check empty write */ CPPUNIT_ASSERT_EQUAL(fullBody, lastBody()); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT(c1->pending); @@ -310,7 +310,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { readResponse("<body></body>", c0); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); - std::string fullBody = "<body rid='" + boost::lexical_cast<std::string>(initialRID + 2) + "' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'></body>"; + std::string fullBody = "<body rid='" + std::to_string(initialRID + 2) + "' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'></body>"; std::string response = boshDataWritten[2]; size_t bodyPosition = response.find("\r\n\r\n"); CPPUNIT_ASSERT_EQUAL(fullBody, response.substr(bodyPosition+4)); @@ -427,7 +427,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { "Access-Control-Allow-Headers: Content-Type\r\n" "Content-Length: ")); connection->onDataRead(data1); - std::shared_ptr<SafeByteArray> data2 = std::make_shared<SafeByteArray>(createSafeByteArray(boost::lexical_cast<std::string>(response.size()))); + std::shared_ptr<SafeByteArray> data2 = std::make_shared<SafeByteArray>(createSafeByteArray(std::to_string(response.size()))); connection->onDataRead(data2); std::shared_ptr<SafeByteArray> data3 = std::make_shared<SafeByteArray>(createSafeByteArray("\r\n\r\n")); connection->onDataRead(data3); @@ -440,7 +440,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { std::string result = "POST /" + path + " HTTP/1.1\r\n" + "Host: " + to + ":" + port + "\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" - + "Content-Length: " + boost::lexical_cast<std::string>(body.size()) + "\r\n\r\n" + + "Content-Length: " + std::to_string(body.size()) + "\r\n\r\n" + body; return result; } diff --git a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp index e34cb96..17d8333 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp @@ -318,7 +318,7 @@ class BOSHConnectionTest : public CppUnit::TestFixture { "Access-Control-Allow-Headers: Content-Type\r\n" "Content-Length: ")); connection->onDataRead(data1); - std::shared_ptr<SafeByteArray> data2 = std::make_shared<SafeByteArray>(createSafeByteArray(boost::lexical_cast<std::string>(response.size()))); + std::shared_ptr<SafeByteArray> data2 = std::make_shared<SafeByteArray>(createSafeByteArray(std::to_string(response.size()))); connection->onDataRead(data2); std::shared_ptr<SafeByteArray> data3 = std::make_shared<SafeByteArray>(createSafeByteArray("\r\n\r\n")); connection->onDataRead(data3); diff --git a/Swiften/Network/UnitTest/ConnectorTest.cpp b/Swiften/Network/UnitTest/ConnectorTest.cpp index 8524439..065911d 100644 --- a/Swiften/Network/UnitTest/ConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ConnectorTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -26,6 +26,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST(testConnect); CPPUNIT_TEST(testConnect_NoServiceLookups); CPPUNIT_TEST(testConnect_NoServiceLookups_DefaultPort); + CPPUNIT_TEST(testConnect_OnlyLiteral); CPPUNIT_TEST(testConnect_FirstAddressHostFails); CPPUNIT_TEST(testConnect_NoSRVHost); CPPUNIT_TEST(testConnect_NoHosts); @@ -91,7 +92,7 @@ class ConnectorTest : public CppUnit::TestFixture { } void testConnect_NoServiceLookups_DefaultPort() { - Connector::ref testling(createConnector(-1, boost::optional<std::string>())); + Connector::ref testling(createConnector(0, boost::optional<std::string>())); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); resolver->addAddress("foo.com", host3.getAddress()); @@ -102,7 +103,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3.getAddress() == (*(connections[0]->hostAddressPort)).getAddress()); - CPPUNIT_ASSERT_EQUAL(5222, (*(connections[0]->hostAddressPort)).getPort()); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(5222), (*(connections[0]->hostAddressPort)).getPort()); CPPUNIT_ASSERT(!std::dynamic_pointer_cast<DomainNameResolveError>(error)); } @@ -119,6 +120,21 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!std::dynamic_pointer_cast<DomainNameResolveError>(error)); } + void testConnect_OnlyLiteral() { + auto testling = Connector::create("1.1.1.1", 1234, boost::none, resolver, connectionFactory, timerFactory); + testling->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1, _2)); + + auto address1 = HostAddress::fromString("1.1.1.1").get(); + connectionFactory->failingPorts.push_back(HostAddressPort(address1, 1234)); + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connectionFactory->createdConnections.size())); + } + void testConnect_FirstAddressHostFails() { Connector::ref testling(createConnector()); @@ -312,7 +328,7 @@ class ConnectorTest : public CppUnit::TestFixture { private: - Connector::ref createConnector(int port = -1, boost::optional<std::string> serviceLookupPrefix = boost::optional<std::string>("_xmpp-client._tcp.")) { + Connector::ref createConnector(unsigned short port = 0, boost::optional<std::string> serviceLookupPrefix = boost::optional<std::string>("_xmpp-client._tcp.")) { Connector::ref connector = Connector::create("foo.com", port, serviceLookupPrefix, resolver, connectionFactory, timerFactory); connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; @@ -356,12 +372,15 @@ class ConnectorTest : public CppUnit::TestFixture { } std::shared_ptr<Connection> createConnection() { - return std::make_shared<MockConnection>(failingPorts, isResponsive, eventLoop); + auto connection = std::make_shared<MockConnection>(failingPorts, isResponsive, eventLoop); + createdConnections.push_back(connection); + return connection; } EventLoop* eventLoop; bool isResponsive; std::vector<HostAddressPort> failingPorts; + std::vector<std::shared_ptr<MockConnection>> createdConnections; }; private: diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp index 1a160b7..e9268b0 100644 --- a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp +++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -37,7 +37,7 @@ namespace { virtual std::vector<std::pair<std::string, std::string> > filterHTTPResponseHeader(const std::string& /* statusLine */, const std::vector<std::pair<std::string, std::string> >& response) { filterResponses.push_back(response); - SWIFT_LOG(debug) << std::endl; + SWIFT_LOG(debug); return filterResponseReturn; } @@ -409,7 +409,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { std::shared_ptr<Connection> createConnection() { std::shared_ptr<MockConnection> connection = std::make_shared<MockConnection>(failingPorts, eventLoop); connections.push_back(connection); - SWIFT_LOG(debug) << "new connection created" << std::endl; + SWIFT_LOG(debug) << "new connection created"; return connection; } @@ -421,7 +421,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { private: std::string proxyHost; HostAddressPort proxyHostAddress; - int proxyPort; + unsigned short proxyPort; HostAddressPort host; DummyEventLoop* eventLoop; StaticDomainNameResolver* resolver; diff --git a/Swiften/Network/UnitTest/HostAddressTest.cpp b/Swiften/Network/UnitTest/HostAddressTest.cpp index 226346b..bd345a7 100644 --- a/Swiften/Network/UnitTest/HostAddressTest.cpp +++ b/Swiften/Network/UnitTest/HostAddressTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -10,6 +10,7 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/HostAddressPort.h> using namespace Swift; @@ -21,6 +22,7 @@ class HostAddressTest : public CppUnit::TestFixture { CPPUNIT_TEST(testToString); CPPUNIT_TEST(testToString_IPv6); CPPUNIT_TEST(testToString_Invalid); + CPPUNIT_TEST(testComparison); CPPUNIT_TEST_SUITE_END(); public: @@ -62,6 +64,32 @@ class HostAddressTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("0.0.0.0"), testling.toString()); } + + void testComparison() { + auto ha127_0_0_1 = *HostAddress::fromString("127.0.0.1"); + auto ha127_0_0_2 = *HostAddress::fromString("127.0.0.2"); + auto ha127_0_1_0 = *HostAddress::fromString("127.0.1.0"); + + CPPUNIT_ASSERT(ha127_0_0_1 < ha127_0_0_2); + CPPUNIT_ASSERT(ha127_0_0_2 < ha127_0_1_0); + CPPUNIT_ASSERT(!(ha127_0_0_1 < ha127_0_0_1)); + CPPUNIT_ASSERT(!(ha127_0_0_2 < ha127_0_0_1)); + CPPUNIT_ASSERT(!(ha127_0_0_2 == ha127_0_0_1)); + CPPUNIT_ASSERT(ha127_0_0_1 == ha127_0_0_1); + + auto hap_127_0_0_1__1 = HostAddressPort(ha127_0_0_1, 1); + auto hap_127_0_0_1__2 = HostAddressPort(ha127_0_0_1, 2); + auto hap_127_0_0_2__1 = HostAddressPort(ha127_0_0_2, 1); + auto hap_127_0_0_2__2 = HostAddressPort(ha127_0_0_2, 2); + + CPPUNIT_ASSERT(hap_127_0_0_1__1 < hap_127_0_0_1__2); + CPPUNIT_ASSERT(!(hap_127_0_0_1__1 < hap_127_0_0_1__1)); + CPPUNIT_ASSERT(!(hap_127_0_0_1__1 == hap_127_0_0_1__2)); + CPPUNIT_ASSERT(hap_127_0_0_1__1 == hap_127_0_0_1__1); + CPPUNIT_ASSERT(!(hap_127_0_0_1__2 == hap_127_0_0_1__1)); + CPPUNIT_ASSERT(hap_127_0_0_1__2 < hap_127_0_0_2__1); + CPPUNIT_ASSERT(hap_127_0_0_2__1 < hap_127_0_0_2__2); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(HostAddressTest); diff --git a/Swiften/Network/WindowsProxyProvider.cpp b/Swiften/Network/WindowsProxyProvider.cpp index 78bd72f..13fdb25 100644 --- a/Swiften/Network/WindowsProxyProvider.cpp +++ b/Swiften/Network/WindowsProxyProvider.cpp @@ -17,6 +17,7 @@ #include <stdlib.h> #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <windows.h> @@ -51,7 +52,7 @@ WindowsProxyProvider::WindowsProxyProvider() for(auto&& proxy : proxies) { if(proxy.find('=') != std::string::npos) { protocolAndProxy = String::getSplittedAtFirst(proxy, '='); - SWIFT_LOG(debug) << "Found proxy: " << protocolAndProxy.first << " => " << protocolAndProxy.second << std::endl; + SWIFT_LOG(debug) << "Found proxy: " << protocolAndProxy.first << " => " << protocolAndProxy.second; if(protocolAndProxy.first.compare("socks") == 0) { socksProxy = getAsHostAddressPort(protocolAndProxy.second); } @@ -77,15 +78,15 @@ HostAddressPort WindowsProxyProvider::getAsHostAddressPort(std::string proxy) { try { std::pair<std::string, std::string> tmp; - int port = 0; + unsigned short port = 0; tmp = String::getSplittedAtFirst(proxy, ':'); // .c_str() is needed as tmp.second can include a \0 char which will end in an exception of the lexical cast. // with .c_str() the \0 will not be part of the string which is to be casted - port = boost::lexical_cast<int> (tmp.second.c_str()); + port = boost::numeric_cast<unsigned short>(boost::lexical_cast<int> (tmp.second.c_str())); ret = HostAddressPort(HostAddress::fromString(tmp.first).get(), port); } catch(...) { - SWIFT_LOG(error) << "Exception occured while parsing windows proxy \"getHostAddressPort\"." << std::endl; + SWIFT_LOG(error) << "Exception occured while parsing windows proxy \"getHostAddressPort\"."; } return ret; diff --git a/Swiften/Parser/Attribute.h b/Swiften/Parser/Attribute.h index f54317e..07e63b4 100644 --- a/Swiften/Parser/Attribute.h +++ b/Swiften/Parser/Attribute.h @@ -14,6 +14,9 @@ namespace Swift { Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) { } + Attribute(const std::string& name, const std::string& ns, const std::string& prefix) : name(name), ns(ns), prefix(prefix) { + } + const std::string& getName() const { return name; } @@ -22,6 +25,10 @@ namespace Swift { return ns; } + const std::string& getPrefix() const { + return prefix; + } + bool operator==(const Attribute& o) const { return o.name == name && o.ns == ns; } @@ -29,5 +36,6 @@ namespace Swift { private: std::string name; std::string ns; + std::string prefix; }; } diff --git a/Swiften/Parser/AttributeMap.cpp b/Swiften/Parser/AttributeMap.cpp index c112d52..7814a64 100644 --- a/Swiften/Parser/AttributeMap.cpp +++ b/Swiften/Parser/AttributeMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,19 +8,17 @@ #include <algorithm> -#include <boost/lambda/bind.hpp> -#include <boost/lambda/lambda.hpp> #include <boost/optional.hpp> using namespace Swift; -namespace lambda = boost::lambda; AttributeMap::AttributeMap() { } std::string AttributeMap::getAttribute(const std::string& attribute, const std::string& ns) const { - AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), - lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, ns)); + const auto i = std::find_if(attributes.begin(), attributes.end(), [&](const Entry& entry) { + return entry.getAttribute() == Attribute(attribute, ns); + }); if (i == attributes.end()) { return ""; } @@ -30,8 +28,9 @@ std::string AttributeMap::getAttribute(const std::string& attribute, const std:: } bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultValue) const { - AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), - lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, "")); + const auto i = std::find_if(attributes.begin(), attributes.end(), [&](const Entry& entry) { + return entry.getAttribute() == Attribute(attribute, ""); + }); if (i == attributes.end()) { return defaultValue; } @@ -41,8 +40,9 @@ bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultVa } boost::optional<std::string> AttributeMap::getAttributeValue(const std::string& attribute) const { - AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), - lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, "")); + const auto i = std::find_if(attributes.begin(), attributes.end(), [&](const Entry& entry) { + return entry.getAttribute() == Attribute(attribute, ""); + }); if (i == attributes.end()) { return boost::optional<std::string>(); } @@ -54,3 +54,7 @@ boost::optional<std::string> AttributeMap::getAttributeValue(const std::string& void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) { attributes.push_back(Entry(Attribute(name, ns), value)); } + +void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& prefix, const std::string& value) { + attributes.push_back(Entry(Attribute(name, ns, prefix), value)); +} diff --git a/Swiften/Parser/AttributeMap.h b/Swiften/Parser/AttributeMap.h index 804d6aa..26d5826 100644 --- a/Swiften/Parser/AttributeMap.h +++ b/Swiften/Parser/AttributeMap.h @@ -43,6 +43,7 @@ namespace Swift { boost::optional<std::string> getAttributeValue(const std::string&) const; void addAttribute(const std::string& name, const std::string& ns, const std::string& value); + void addAttribute(const std::string& name, const std::string& ns, const std::string& prefix, const std::string& value); const std::vector<Entry>& getEntries() const { return attributes; diff --git a/Swiften/Parser/BOSHBodyExtractor.cpp b/Swiften/Parser/BOSHBodyExtractor.cpp index c45d338..ff56792 100644 --- a/Swiften/Parser/BOSHBodyExtractor.cpp +++ b/Swiften/Parser/BOSHBodyExtractor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,8 +8,6 @@ #include <memory> -#include <boost/numeric/conversion/cast.hpp> - #include <Swiften/Parser/XMLParser.h> #include <Swiften/Parser/XMLParserClient.h> #include <Swiften/Parser/XMLParserFactory.h> @@ -119,17 +117,19 @@ BOSHBodyExtractor::BOSHBodyExtractor(XMLParserFactory* parserFactory, const Byte body = BOSHBody(); if (!endElementSeen) { + assert(i <= j.base()); body->content = std::string( reinterpret_cast<const char*>(vecptr(data) + std::distance(data.begin(), i)), - boost::numeric_cast<size_t>(std::distance(i, j.base()))); + static_cast<size_t>(std::distance(i, j.base()))); } // Parse the body element BOSHBodyParserClient parserClient(this); std::shared_ptr<XMLParser> parser(parserFactory->createXMLParser(&parserClient)); + assert(data.begin() <= i); if (!parser->parse(std::string( reinterpret_cast<const char*>(vecptr(data)), - boost::numeric_cast<size_t>(std::distance(data.begin(), i))))) { + static_cast<size_t>(std::distance(data.begin(), i))))) { /* TODO: This needs to be only validating the BOSH <body> element, so that XMPP parsing errors are caught at the correct higher layer */ body = boost::optional<BOSHBody>(); diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index 77d959c..32d4f53 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -7,18 +7,46 @@ #include <Swiften/Parser/ExpatParser.h> #include <cassert> +#include <limits> #include <memory> #include <string> -#include <expat.h> +#include <boost/algorithm/string.hpp> -#include <boost/numeric/conversion/cast.hpp> +#include <expat.h> #include <Swiften/Base/String.h> #include <Swiften/Parser/XMLParserClient.h> #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +namespace { +struct XmlInfo { + std::string prefix; + std::string uri; + std::string name; +}; + +XmlInfo splitExpatInfo(const std::string& s, char sep) { + // name + // uri|name + // uri|name|prefix + std::vector<std::string> v; + boost::split(v, s, [sep](char c) {return c == sep; }); + switch (v.size()) { + case 1: + return{ "", "", std::move(v[0]) }; + case 2: + return{ "", std::move(v[0]), std::move(v[1]) }; + case 3: + return{ std::move(v[2]), std::move(v[0]), std::move(v[1]) }; + default: + return{ "", "", "" }; + } +} +} + + namespace Swift { static const char NAMESPACE_SEPARATOR = '\x01'; @@ -28,33 +56,24 @@ struct ExpatParser::Private { }; static void handleStartElement(void* parser, const XML_Char* name, const XML_Char** attributes) { - std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); - if (nsTagPair.second == "") { - nsTagPair.second = nsTagPair.first; - nsTagPair.first = ""; - } + auto elemInfo = splitExpatInfo(name, NAMESPACE_SEPARATOR); + AttributeMap attributeValues; const XML_Char** currentAttribute = attributes; while (*currentAttribute) { - std::pair<std::string,std::string> nsAttributePair = String::getSplittedAtFirst(*currentAttribute, NAMESPACE_SEPARATOR); - if (nsAttributePair.second == "") { - nsAttributePair.second = nsAttributePair.first; - nsAttributePair.first = ""; - } - attributeValues.addAttribute(nsAttributePair.second, nsAttributePair.first, std::string(*(currentAttribute+1))); + auto attribInfo = splitExpatInfo(*currentAttribute, NAMESPACE_SEPARATOR); + attributeValues.addAttribute(attribInfo.name, attribInfo.uri, attribInfo.prefix, std::string(*(currentAttribute+1))); currentAttribute += 2; } - static_cast<XMLParser*>(parser)->getClient()->handleStartElement(nsTagPair.second, nsTagPair.first, attributeValues); + auto* client = static_cast<XMLParser*>(parser)->getClient(); + client->handleStartElementPrefix(elemInfo.prefix, elemInfo.uri, elemInfo.name, attributeValues); + client->handleStartElement(elemInfo.name, elemInfo.uri, attributeValues); } static void handleEndElement(void* parser, const XML_Char* name) { - std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); - if (nsTagPair.second == "") { - nsTagPair.second = nsTagPair.first; - nsTagPair.first = ""; - } - static_cast<XMLParser*>(parser)->getClient()->handleEndElement(nsTagPair.second, nsTagPair.first); + auto elemInfo = splitExpatInfo(name, NAMESPACE_SEPARATOR); + static_cast<XMLParser*>(parser)->getClient()->handleEndElement(elemInfo.name, elemInfo.uri); } static void handleCharacterData(void* parser, const XML_Char* data, int len) { @@ -65,26 +84,51 @@ static void handleCharacterData(void* parser, const XML_Char* data, int len) { static void handleXMLDeclaration(void*, const XML_Char*, const XML_Char*, int) { } +static void handleNamespaceDeclaration(void* parser, const XML_Char* prefix, const XML_Char* uri) { + static_cast<XMLParser*>(parser)->getClient()->handleNamespaceDeclaration(std::string(prefix ? prefix : ""), std::string(uri ? uri : "")); +} + static void handleEntityDeclaration(void* parser, const XML_Char*, int, const XML_Char*, int, const XML_Char*, const XML_Char*, const XML_Char*, const XML_Char*) { static_cast<ExpatParser*>(parser)->stopParser(); } +static void handleComment(void* parser, const XML_Char* /*data*/) { + if (!static_cast<ExpatParser*>(parser)->allowsComments()) { + static_cast<ExpatParser*>(parser)->stopParser(); + } +} -ExpatParser::ExpatParser(XMLParserClient* client) : XMLParser(client), p(new Private()) { +static void handleProcessingInstruction(void* parser, const XML_Char* /*target*/, const XML_Char* /*data*/) { + static_cast<ExpatParser*>(parser)->stopParser(); +} + +static void handleDoctypeDeclaration(void* parser, const XML_Char* /*doctypeName*/, const XML_Char* /*sysid*/, const XML_Char* /*pubid*/, int /*has_internal_subset*/) { + static_cast<ExpatParser*>(parser)->stopParser(); +} + +ExpatParser::ExpatParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) { p->parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR); + XML_SetReturnNSTriplet(p->parser_, true); XML_SetUserData(p->parser_, this); XML_SetElementHandler(p->parser_, handleStartElement, handleEndElement); XML_SetCharacterDataHandler(p->parser_, handleCharacterData); XML_SetXmlDeclHandler(p->parser_, handleXMLDeclaration); XML_SetEntityDeclHandler(p->parser_, handleEntityDeclaration); + XML_SetNamespaceDeclHandler(p->parser_, handleNamespaceDeclaration, nullptr); + XML_SetCommentHandler(p->parser_, handleComment); + XML_SetProcessingInstructionHandler(p->parser_, handleProcessingInstruction); + XML_SetDoctypeDeclHandler(p->parser_, handleDoctypeDeclaration, nullptr); } ExpatParser::~ExpatParser() { XML_ParserFree(p->parser_); } -bool ExpatParser::parse(const std::string& data) { - bool success = XML_Parse(p->parser_, data.c_str(), boost::numeric_cast<int>(data.size()), false) == XML_STATUS_OK; +bool ExpatParser::parse(const std::string& data, bool finalData) { + if (data.size() > std::numeric_limits<int>::max()) { + return false; + } + bool success = XML_Parse(p->parser_, data.c_str(), static_cast<int>(data.size()), finalData) == XML_STATUS_OK; /*if (!success) { std::cout << "ERROR: " << XML_ErrorString(XML_GetErrorCode(p->parser_)) << " while parsing " << data << std::endl; }*/ diff --git a/Swiften/Parser/ExpatParser.h b/Swiften/Parser/ExpatParser.h index 12df463..34d790d 100644 --- a/Swiften/Parser/ExpatParser.h +++ b/Swiften/Parser/ExpatParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,10 +16,10 @@ namespace Swift { class SWIFTEN_API ExpatParser : public XMLParser, public boost::noncopyable { public: - ExpatParser(XMLParserClient* client); + ExpatParser(XMLParserClient* client, bool allowComments = false); ~ExpatParser(); - bool parse(const std::string& data); + bool parse(const std::string& data, bool finalData = false); void stopParser(); diff --git a/Swiften/Parser/IQParser.cpp b/Swiften/Parser/IQParser.cpp index 5cfae34..363f7ec 100644 --- a/Swiften/Parser/IQParser.cpp +++ b/Swiften/Parser/IQParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -32,7 +32,7 @@ void IQParser::handleStanzaAttributes(const AttributeMap& attributes) { getStanzaGeneric()->setType(IQ::Error); } else { - SWIFT_LOG(warning) << "Unknown IQ type: " << *type << std::endl; + SWIFT_LOG(warning) << "Unknown IQ type: " << *type; getStanzaGeneric()->setType(IQ::Get); } } diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index be0a92d..32b91a1 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,16 +8,21 @@ #include <cassert> #include <cstring> +#include <limits> #include <memory> #include <string> -#include <boost/numeric/conversion/cast.hpp> - #include <libxml/parser.h> #include <Swiften/Base/Log.h> #include <Swiften/Parser/XMLParserClient.h> +namespace { +std::string asString(const unsigned char* s) { + return s ? std::string(reinterpret_cast<const char*>(s)) : std::string(); +} +} + namespace Swift { struct LibXMLParser::Private { @@ -25,32 +30,62 @@ struct LibXMLParser::Private { xmlParserCtxtPtr context_; }; -static void handleStartElement(void* parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { +static void handleStartElement(void* parser, const xmlChar* name, const xmlChar* prefix, const xmlChar* xmlns, int nbNamespaces, const xmlChar** namespaces, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { AttributeMap attributeValues; if (nbDefaulted != 0) { // Just because i don't understand what this means yet :-) - SWIFT_LOG(error) << "Unexpected nbDefaulted on XML element" << std::endl; + SWIFT_LOG(error) << "Unexpected nbDefaulted on XML element"; } for (int i = 0; i < nbAttributes*5; i += 5) { - std::string attributeNS = ""; - if (attributes[i+2]) { - attributeNS = std::string(reinterpret_cast<const char*>(attributes[i+2])); - } + std::string attributeName = asString(attributes[i]); + std::string attributePrefix = asString(attributes[i+1]); + std::string attributeNS = asString(attributes[i+2]); + assert(attributes[i+4] >= attributes[i+3]); attributeValues.addAttribute( - std::string(reinterpret_cast<const char*>(attributes[i])), + attributeName, attributeNS, + attributePrefix, std::string(reinterpret_cast<const char*>(attributes[i+3]), - boost::numeric_cast<size_t>(attributes[i+4]-attributes[i+3]))); + static_cast<size_t>(attributes[i+4]-attributes[i+3]))); + } + auto* client = static_cast<XMLParser*>(parser)->getClient(); + for (auto i = 0; i < nbNamespaces * 2; i += 2) { + const auto prefix = asString(namespaces[i]); + const auto uri = asString(namespaces[i + 1]); + client->handleNamespaceDeclaration(prefix, uri); } - static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); + auto nameStr = asString(name); + auto xmlsnsStr = asString(xmlns); + auto prefixStr = asString(prefix); + client->handleStartElementPrefix(prefixStr, xmlsnsStr, nameStr, attributeValues); + client->handleStartElement(nameStr, xmlsnsStr, attributeValues); } static void handleEndElement(void *parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns) { - static_cast<XMLParser*>(parser)->getClient()->handleEndElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string())); + static_cast<XMLParser*>(parser)->getClient()->handleEndElement(asString(name), asString(xmlns)); } static void handleCharacterData(void* parser, const xmlChar* data, int len) { - static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(reinterpret_cast<const char*>(data), boost::numeric_cast<size_t>(len))); + assert(len >= 0); + static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(reinterpret_cast<const char*>(data), static_cast<size_t>(len))); +} + +static void handleComment(void* parser, const xmlChar* /*data*/) { + if (!static_cast<LibXMLParser*>(parser)->allowsComments()) { + static_cast<LibXMLParser*>(parser)->stopParser(); + } +} + +static void handleEntityDeclaration(void * parser, const xmlChar* /*name*/, int /*type*/, const xmlChar* /*publicId*/, const xmlChar* /*systemId*/, xmlChar* /*content*/) { + static_cast<LibXMLParser*>(parser)->stopParser(); +} + +static void handleProcessingInstruction(void* parser, const xmlChar* /*target*/, const xmlChar* /*data*/) { + static_cast<LibXMLParser*>(parser)->stopParser(); +} + +static void handleExternalSubset(void* parser, const xmlChar * /*name*/, const xmlChar * /*ExternalID*/, const xmlChar * /*SystemID*/) { + static_cast<LibXMLParser*>(parser)->stopParser(); } static void handleError(void*, const char* /*m*/, ... ) { @@ -65,12 +100,20 @@ static void handleError(void*, const char* /*m*/, ... ) { static void handleWarning(void*, const char*, ... ) { } +static void handleGenericError(void*, const char*, ... ) { +} + +static void handleStructuredError(void*, xmlErrorPtr) { +} + bool LibXMLParser::initialized = false; -LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client), p(new Private()) { +LibXMLParser::LibXMLParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) { // Initialize libXML for multithreaded applications if (!initialized) { xmlInitParser(); + xmlSetGenericErrorFunc(nullptr, handleGenericError); + xmlSetStructuredErrorFunc(nullptr, handleStructuredError); initialized = true; } @@ -81,6 +124,10 @@ LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client), p(new P p->handler_.characters = &handleCharacterData; p->handler_.warning = &handleWarning; p->handler_.error = &handleError; + p->handler_.comment = &handleComment; + p->handler_.entityDecl = &handleEntityDeclaration; + p->handler_.processingInstruction = &handleProcessingInstruction; + p->handler_.externalSubset = &handleExternalSubset; p->context_ = xmlCreatePushParserCtxt(&p->handler_, this, nullptr, 0, nullptr); xmlCtxtUseOptions(p->context_, XML_PARSE_NOENT); @@ -93,12 +140,16 @@ LibXMLParser::~LibXMLParser() { } } -bool LibXMLParser::parse(const std::string& data) { - if (xmlParseChunk(p->context_, data.c_str(), boost::numeric_cast<int>(data.size()), false) == XML_ERR_OK) { +bool LibXMLParser::parse(const std::string& data, bool finalData) { + if (data.size() > std::numeric_limits<int>::max()) { + return false; + } + auto error = xmlParseChunk(p->context_, data.c_str(), static_cast<int>(data.size()), finalData); + if (error == XML_ERR_OK) { return true; } - xmlError* error = xmlCtxtGetLastError(p->context_); - if (error->code == XML_WAR_NS_URI || error->code == XML_WAR_NS_URI_RELATIVE) { + if (stopped_) return false; + if (error == XML_WAR_NS_URI || error == XML_WAR_NS_URI_RELATIVE) { xmlCtxtResetLastError(p->context_); p->context_->errNo = XML_ERR_OK; return true; @@ -106,4 +157,9 @@ bool LibXMLParser::parse(const std::string& data) { return false; } +void LibXMLParser::stopParser() { + stopped_ = true; + xmlStopParser(p->context_); +} + } diff --git a/Swiften/Parser/LibXMLParser.h b/Swiften/Parser/LibXMLParser.h index 9f752ce..e21770d 100644 --- a/Swiften/Parser/LibXMLParser.h +++ b/Swiften/Parser/LibXMLParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -19,13 +19,16 @@ namespace Swift { */ class LibXMLParser : public XMLParser, public boost::noncopyable { public: - LibXMLParser(XMLParserClient* client); + LibXMLParser(XMLParserClient* client, bool allowComments = false); virtual ~LibXMLParser(); - bool parse(const std::string& data); + bool parse(const std::string& data, bool finalData = false); + + void stopParser(); private: static bool initialized; + bool stopped_ = false; struct Private; const std::unique_ptr<Private> p; diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp index 405c593..71bce54 100644 --- a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -7,6 +7,7 @@ #include <Swiften/Parser/PayloadParsers/BytestreamsParser.h> #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp> namespace Swift { @@ -23,7 +24,9 @@ void BytestreamsParser::handleStartElement(const std::string& element, const std else if (level == PayloadLevel) { if (element == "streamhost") { try { - getPayloadInternal()->addStreamHost(Bytestreams::StreamHost(attributes.getAttribute("host"), JID(attributes.getAttribute("jid")), boost::lexical_cast<int>(attributes.getAttribute("port")))); + getPayloadInternal()->addStreamHost(Bytestreams::StreamHost(attributes.getAttribute("host"), JID(attributes.getAttribute("jid")), boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(attributes.getAttribute("port"))))); + } + catch (boost::numeric::bad_numeric_cast&) { } catch (boost::bad_lexical_cast&) { } diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index 43c4ebb..9e56b63 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -75,6 +75,7 @@ #include <Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h> #include <Swiften/Parser/PayloadParsers/PubSubParser.h> #include <Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h> #include <Swiften/Parser/PayloadParsers/ReplaceParser.h> #include <Swiften/Parser/PayloadParsers/ResourceBindParser.h> #include <Swiften/Parser/PayloadParsers/ResultSetParser.h> @@ -187,6 +188,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(std::make_shared<GenericPayloadParserFactory2<CarbonsSentParser> >("sent", "urn:xmpp:carbons:2", this)); factories_.push_back(std::make_shared<GenericPayloadParserFactory<CarbonsPrivateParser> >("private", "urn:xmpp:carbons:2")); factories_.push_back(std::make_shared<MIXJoinParserFactory>()); + factories_.push_back(std::make_shared<GenericPayloadParserFactory2<ReferencePayloadParser> >("reference", "urn:xmpp:reference:0", this)); for (auto& factory : factories_) { addFactory(factory.get()); diff --git a/Swiften/Parser/PayloadParsers/IBBParser.cpp b/Swiften/Parser/PayloadParsers/IBBParser.cpp index 9b6babc..1ba44e1 100644 --- a/Swiften/Parser/PayloadParsers/IBBParser.cpp +++ b/Swiften/Parser/PayloadParsers/IBBParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -39,7 +39,7 @@ void IBBParser::handleStartElement(const std::string& element, const std::string getPayloadInternal()->setStanzaType(IBB::IQStanza); } try { - getPayloadInternal()->setBlockSize(boost::lexical_cast<int>(attributes.getAttribute("block-size"))); + getPayloadInternal()->setBlockSize(boost::lexical_cast<unsigned int>(attributes.getAttribute("block-size"))); } catch (boost::bad_lexical_cast&) { } diff --git a/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp index e639e20..a405e0e 100644 --- a/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2014-2016 Isode Limited. + * Copyright (c) 2014-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -13,6 +13,7 @@ #include <Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.h> #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <boost/optional.hpp> #include <Swiften/Base/Log.h> @@ -40,10 +41,10 @@ namespace Swift { JingleS5BTransportPayload::Candidate candidate; candidate.cid = attributes.getAttributeValue("cid").get_value_or(""); - int port = -1; + unsigned short port = 0; try { - port = boost::lexical_cast<int>(attributes.getAttributeValue("port").get_value_or("-1")); - } catch(boost::bad_lexical_cast &) { } + port = boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(attributes.getAttributeValue("port").get_value_or("0"))); + } catch(...) { } candidate.hostPort = HostAddressPort(HostAddress::fromString(attributes.getAttributeValue("host").get_value_or("")).get_value_or(HostAddress()), port); candidate.jid = JID(attributes.getAttributeValue("jid").get_value_or("")); int priority = -1; diff --git a/Swiften/Parser/PayloadParsers/MIXUpdateSubscriptionParser.h b/Swiften/Parser/PayloadParsers/MIXUpdateSubscriptionParser.h index 9975411..47966ff 100644 --- a/Swiften/Parser/PayloadParsers/MIXUpdateSubscriptionParser.h +++ b/Swiften/Parser/PayloadParsers/MIXUpdateSubscriptionParser.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2017 Isode Limited. + * Copyright (c) 2017-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -24,7 +24,7 @@ namespace Swift { class SWIFTEN_API MIXUpdateSubscriptionParser : public GenericPayloadParser<MIXUpdateSubscription> { public: MIXUpdateSubscriptionParser(); - virtual ~MIXUpdateSubscriptionParser(); + virtual ~MIXUpdateSubscriptionParser() override; virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) override; virtual void handleEndElement(const std::string& element, const std::string&) override; diff --git a/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp new file mode 100644 index 0000000..a337a29 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h> + +#include <cassert> +#include <iostream> + +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> + +namespace Swift { + +ReferencePayloadParser::ReferencePayloadParser(PayloadParserFactoryCollection* factories) : factories_(factories) { +} + +ReferencePayload::Type ReferencePayloadParser::getTypeFromString(const std::string& typeString) const { + if (typeString == "data") { + return ReferencePayload::Type::Data; + } + else if (typeString == "mention") { + return ReferencePayload::Type::Mention; + } + else if (typeString == "pubsub") { + return ReferencePayload::Type::PubSub; + } + else { + return ReferencePayload::Type::Unknown; + } +} + +void ReferencePayloadParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level_ == topLevel_) { + if (element == "reference") { + getPayloadInternal()->setType(getTypeFromString(attributes.getAttribute("type"))); + getPayloadInternal()->setUri(attributes.getAttributeValue("uri")); + getPayloadInternal()->setBegin(attributes.getAttributeValue("begin")); + getPayloadInternal()->setEnd(attributes.getAttributeValue("end")); + getPayloadInternal()->setAnchor(attributes.getAttributeValue("anchor")); + } + } + else if (level_ == payloadLevel_) { + PayloadParserFactory* payloadParserFactory = factories_->getPayloadParserFactory(element, ns, attributes); + if (payloadParserFactory) { + currentPayloadParser_.reset(payloadParserFactory->createPayloadParser()); + } + } + + if (level_ >= payloadLevel_ && currentPayloadParser_) { + currentPayloadParser_->handleStartElement(element, ns, attributes); + } + + ++level_; +} + +void ReferencePayloadParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + if (currentPayloadParser_) { + if (level_ >= payloadLevel_) { + currentPayloadParser_->handleEndElement(element, ns); + } + + if (level_ == payloadLevel_) { + getPayloadInternal()->addPayload(currentPayloadParser_->getPayload()); + currentPayloadParser_.reset(); + } + } +} + +void ReferencePayloadParser::handleCharacterData(const std::string& data) { + if (level_ > payloadLevel_ && currentPayloadParser_) { + currentPayloadParser_->handleCharacterData(data); + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h new file mode 100644 index 0000000..3afd181 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ReferencePayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + + class PayloadParserFactoryCollection; + + class SWIFTEN_API ReferencePayloadParser : public GenericPayloadParser<ReferencePayload> { + public: + + ReferencePayloadParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string& ns); + virtual void handleCharacterData(const std::string& data); + + private: + + ReferencePayload::Type getTypeFromString(const std::string& typeString) const; + int level_ = 0; + const int topLevel_ = 0; + const int payloadLevel_ = 1; + PayloadParserFactoryCollection* factories_; + std::shared_ptr<PayloadParser> currentPayloadParser_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp index 502f400..7a5a1fd 100644 --- a/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp +++ b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -13,6 +13,7 @@ #include <Swiften/Parser/PayloadParsers/S5BProxyRequestParser.h> #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <boost/optional.hpp> namespace Swift { @@ -27,15 +28,14 @@ void S5BProxyRequestParser::handleStartElement(const std::string& element, const if (element == "streamhost") { if (attributes.getAttributeValue("host") && attributes.getAttributeValue("jid") && attributes.getAttributeValue("port")) { std::string host = attributes.getAttributeValue("host").get_value_or(""); - int port = -1; + unsigned short port = 0; JID jid = attributes.getAttributeValue("jid").get_value_or(""); try { - port = boost::lexical_cast<int>(attributes.getAttributeValue("port").get()); - } catch (boost::bad_lexical_cast &) { - port = -1; + port = boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(attributes.getAttributeValue("port").get())); + } catch (...) { } - if (!host.empty() && port != -1 && jid.isValid()) { + if (!host.empty() && port != 0 && jid.isValid()) { S5BProxyRequest::StreamHost streamHost; streamHost.host = host; streamHost.port = port; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h index dcdbffa..8f9e0e1 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h +++ b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h @@ -19,7 +19,7 @@ namespace Swift { class PayloadsParserTester : public XMLParserClient { public: PayloadsParserTester() : level(0) { - xmlParser = PlatformXMLParserFactory().createXMLParser(this); + xmlParser = PlatformXMLParserFactory().createXMLParser(this, false); } bool parse(const std::string& data) { diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp new file mode 100644 index 0000000..ca7b280 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <gtest/gtest.h> + +#include <Swiften/Elements/Body.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +TEST(ReferencePayloadParserTest, testParse) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + "<reference xmlns='urn:xmpp:reference:0' " + "type='data' " + "uri='https://www.example.com/mindBlowingImage.jpeg' " + "begin='11' " + "end='22' " + "anchor='xmpp:data@localhost.example.test'>" + "</reference>")); + + auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); + ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(payload->getType())); + ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *payload->getUri()); + ASSERT_EQ(std::string("11"), *payload->getBegin()); + ASSERT_EQ(std::string("22"), *payload->getEnd()); + ASSERT_EQ(std::string("xmpp:data@localhost.example.test"), *payload->getAnchor()); +} + +TEST(ReferencePayloadParserTest, testParseNoType) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + "<reference xmlns='urn:xmpp:reference:0' " + "uri='https://www.example.com/mindBlowingImage.jpeg' " + "begin='11' " + "end='22' " + "anchor='xmpp:data@localhost.example.test'>" + "</reference>")); + + auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); + ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Unknown), static_cast<int>(payload->getType())); + ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *payload->getUri()); + ASSERT_EQ(std::string("11"), *payload->getBegin()); + ASSERT_EQ(std::string("22"), *payload->getEnd()); + ASSERT_EQ(std::string("xmpp:data@localhost.example.test"), *payload->getAnchor()); +} + +TEST(ReferencePayloadParserTest, testParseEmbeddedPayloads) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + "<reference xmlns='urn:xmpp:reference:0' type='data'> " + "<error type=\"modify\">" + "<bad-request xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>" + "<delay xmlns='urn:xmpp:delay' from='juliet@capulet.com/balcony' stamp='2002-09-10T23:41:07Z'/>" + "<text xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">boo</text>" + "</error>" + "</reference>")); + + auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); + ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(payload->getType())); + ASSERT_FALSE(payload->getUri()); + ASSERT_FALSE(payload->getBegin()); + ASSERT_FALSE(payload->getEnd()); + ASSERT_FALSE(payload->getAnchor()); + auto childPayloadList = payload->getPayloads(); + auto errorPayload = std::dynamic_pointer_cast<ErrorPayload>(childPayloadList[0]); + ASSERT_TRUE(errorPayload); + ASSERT_EQ("boo", errorPayload->getText()); + auto delayPayload = std::dynamic_pointer_cast<Delay>(errorPayload->getPayload()); + ASSERT_TRUE(delayPayload); +} + +TEST(ReferencePayloadParserTest, testParseEmbeddedPayloadWithText) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + "<reference xmlns='urn:xmpp:reference:0' type='data'> " + "<body>Example Text</body>" + "</reference>")); + + auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); + auto childPayloadList = payload->getPayloads(); + auto bodyPayload = std::dynamic_pointer_cast<Body>(childPayloadList[0]); + ASSERT_EQ("Example Text", bodyPayload->getText()); +} + +TEST(ReferencePayloadParserTest, testParseRecursive) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + "<reference xmlns='urn:xmpp:reference:0' type='data'> " + "<reference xmlns='urn:xmpp:reference:0' type='data' uri='https://download.montague.lit/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/summit.jpg' /> " + "<reference xmlns='urn:xmpp:reference:0' type='data' uri='xmpp:romeo@montague.lit/resource?jingle;id=9559976B-3FBF-4E7E-B457-2DAA225972BB' /> " + "<reference xmlns='urn:xmpp:reference:0' type='data'> " + "<reference xmlns='urn:xmpp:reference:0' type='data' uri='https://www.example.com/mindBlowingImage.jpeg' /> " + "</reference>" + "</reference>")); + + auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); + ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(payload->getType())); + auto childPayloadList = payload->getPayloads(); + auto childPayloadA = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[0]); + auto childPayloadB = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[1]); + auto childPayloadC = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[2]); + ASSERT_TRUE(childPayloadA); + ASSERT_TRUE(childPayloadB); + ASSERT_TRUE(childPayloadC); + ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(childPayloadA->getType())); + ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(childPayloadB->getType())); + ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(childPayloadC->getType())); + ASSERT_EQ(std::string("https://download.montague.lit/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/summit.jpg"), *childPayloadA->getUri()); + ASSERT_EQ(std::string("xmpp:romeo@montague.lit/resource?jingle;id=9559976B-3FBF-4E7E-B457-2DAA225972BB"), *childPayloadB->getUri()); + ASSERT_FALSE(childPayloadC->getUri()); + ASSERT_FALSE(childPayloadC->getBegin()); + ASSERT_FALSE(childPayloadC->getEnd()); + ASSERT_FALSE(childPayloadC->getAnchor()); + auto grandChildPayloadList = childPayloadC->getPayloads(); + auto grandChildPayload = std::dynamic_pointer_cast<ReferencePayload>(grandChildPayloadList[0]); + ASSERT_TRUE(grandChildPayload); + ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(grandChildPayload->getType())); + ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *grandChildPayload->getUri()); + ASSERT_FALSE(grandChildPayload->getBegin()); + ASSERT_FALSE(grandChildPayload->getEnd()); + ASSERT_FALSE(grandChildPayload->getAnchor()); +} diff --git a/Swiften/Parser/PlatformXMLParserFactory.cpp b/Swiften/Parser/PlatformXMLParserFactory.cpp index bf66734..a424aca 100644 --- a/Swiften/Parser/PlatformXMLParserFactory.cpp +++ b/Swiften/Parser/PlatformXMLParserFactory.cpp @@ -20,11 +20,11 @@ namespace Swift { PlatformXMLParserFactory::PlatformXMLParserFactory() { } -std::unique_ptr<XMLParser> PlatformXMLParserFactory::createXMLParser(XMLParserClient* client) { +std::unique_ptr<XMLParser> PlatformXMLParserFactory::createXMLParser(XMLParserClient* client, bool allowComments) { #ifdef HAVE_LIBXML - return std::make_unique<LibXMLParser>(client); + return std::make_unique<LibXMLParser>(client, allowComments); #else - return std::make_unique<ExpatParser>(client); + return std::make_unique<ExpatParser>(client, allowComments); #endif } diff --git a/Swiften/Parser/PlatformXMLParserFactory.h b/Swiften/Parser/PlatformXMLParserFactory.h index fa3ca19..d72a513 100644 --- a/Swiften/Parser/PlatformXMLParserFactory.h +++ b/Swiften/Parser/PlatformXMLParserFactory.h @@ -14,6 +14,6 @@ namespace Swift { public: PlatformXMLParserFactory(); - virtual std::unique_ptr<XMLParser> createXMLParser(XMLParserClient*); + virtual std::unique_ptr<XMLParser> createXMLParser(XMLParserClient*, bool allowComments = false); }; } diff --git a/Swiften/Parser/PresenceParser.cpp b/Swiften/Parser/PresenceParser.cpp index 0235a12..f73e9d8 100644 --- a/Swiften/Parser/PresenceParser.cpp +++ b/Swiften/Parser/PresenceParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -41,7 +41,7 @@ void PresenceParser::handleStanzaAttributes(const AttributeMap& attributes) { getStanzaGeneric()->setType(Presence::Error); } else { - SWIFT_LOG(error) << "Unknown Presence type: " << *type << std::endl; + SWIFT_LOG(error) << "Unknown Presence type: " << *type; getStanzaGeneric()->setType(Presence::Available); } } diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 30c61a7..4ac5aa4 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -53,6 +53,7 @@ sources = [ "PayloadParsers/PriorityParser.cpp", "PayloadParsers/PrivateStorageParser.cpp", "PayloadParsers/RawXMLPayloadParser.cpp", + "PayloadParsers/ReferencePayloadParser.cpp", "PayloadParsers/ResourceBindParser.cpp", "PayloadParsers/RosterItemExchangeParser.cpp", "PayloadParsers/RosterParser.cpp", diff --git a/Swiften/Parser/StanzaAckParser.cpp b/Swiften/Parser/StanzaAckParser.cpp index de0287e..42ab181 100644 --- a/Swiften/Parser/StanzaAckParser.cpp +++ b/Swiften/Parser/StanzaAckParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -17,7 +17,7 @@ void StanzaAckParser::handleStartElement(const std::string&, const std::string&, if (depth == 0) { std::string handledStanzasString = attributes.getAttribute("h"); try { - getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<int>(handledStanzasString)); + getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<unsigned int>(handledStanzasString)); } catch (const boost::bad_lexical_cast &) { } diff --git a/Swiften/Parser/StreamErrorParser.cpp b/Swiften/Parser/StreamErrorParser.cpp index 64e0681..e89af58 100644 --- a/Swiften/Parser/StreamErrorParser.cpp +++ b/Swiften/Parser/StreamErrorParser.cpp @@ -48,9 +48,6 @@ void StreamErrorParser::handleEndElement(const std::string& element, const std:: else if(element == "invalid-from") { getElementGeneric()->setType(StreamError::InvalidFrom); } - else if(element == "invalid-id") { - getElementGeneric()->setType(StreamError::InvalidID); - } else if(element == "invalid-namespace") { getElementGeneric()->setType(StreamError::InvalidNamespace); } @@ -90,6 +87,9 @@ void StreamErrorParser::handleEndElement(const std::string& element, const std:: else if(element == "unsupported-encoding") { getElementGeneric()->setType(StreamError::UnsupportedEncoding); } + else if(element == "unsupported-feature") { + getElementGeneric()->setType(StreamError::UnsupportedFeature); + } else if(element == "unsupported-stanza-type") { getElementGeneric()->setType(StreamError::UnsupportedStanzaType); } diff --git a/Swiften/Parser/Tree/ParserElement.cpp b/Swiften/Parser/Tree/ParserElement.cpp index 5415945..988bc13 100644 --- a/Swiften/Parser/Tree/ParserElement.cpp +++ b/Swiften/Parser/Tree/ParserElement.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -7,13 +7,8 @@ #include <Swiften/Parser/Tree/ParserElement.h> -#include <boost/lambda/bind.hpp> -#include <boost/lambda/lambda.hpp> - #include <Swiften/Parser/Tree/NullParserElement.h> -namespace lambda = boost::lambda; - namespace Swift { ParserElement::ParserElement(const std::string& name, const std::string& xmlns, const AttributeMap& attributes) : name_(name), xmlns_(xmlns), attributes_(attributes) { @@ -34,8 +29,9 @@ void ParserElement::appendCharacterData(const std::string& data) { std::vector<ParserElement::ref> ParserElement::getChildren(const std::string& name, const std::string& xmlns) const { std::vector<ParserElement::ref> result; - std::remove_copy_if(children_.begin(), children_.end(), std::back_inserter(result), - lambda::bind(&ParserElement::getName, *lambda::_1) != name || lambda::bind(&ParserElement::getNamespace, *lambda::_1) != xmlns); + std::remove_copy_if(children_.begin(), children_.end(), std::back_inserter(result), [&](const ParserElement::ref& element) { + return (element->getName() != name) || (element->getNamespace() != xmlns); + }); return result; } diff --git a/Swiften/Parser/UnitTest/AttributeMapTest.cpp b/Swiften/Parser/UnitTest/AttributeMapTest.cpp index 4529eac..d9335c1 100644 --- a/Swiften/Parser/UnitTest/AttributeMapTest.cpp +++ b/Swiften/Parser/UnitTest/AttributeMapTest.cpp @@ -15,6 +15,7 @@ class AttributeMapTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(AttributeMapTest); CPPUNIT_TEST(testGetAttribute_Namespaced); + CPPUNIT_TEST(testGetAttribute_Namespaced_Prefix); CPPUNIT_TEST(testGetBoolAttribute_True); CPPUNIT_TEST(testGetBoolAttribute_1); CPPUNIT_TEST(testGetBoolAttribute_False); @@ -34,6 +35,22 @@ class AttributeMapTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); } + void testGetAttribute_Namespaced_Prefix() { + AttributeMap testling; + testling.addAttribute("lang", "", "prefix", "nl"); + testling.addAttribute("lang", "http://www.w3.org/XML/1998/namespace", "prefix", "en"); + testling.addAttribute("lang", "", "prefix", "fr"); + + CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); + const auto& entries = testling.getEntries(); + auto it = std::find_if(entries.begin(), entries.end(), [](const AttributeMap::Entry& e) { + return e.getValue() == "en"; + }); + const bool found = it != entries.end(); + CPPUNIT_ASSERT_EQUAL(true, found); + CPPUNIT_ASSERT_EQUAL(std::string("prefix"), it->getAttribute().getPrefix()); + } + void testGetBoolAttribute_True() { AttributeMap testling; testling.addAttribute("foo", "", "true"); diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index b593aa7..89229c9 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -6,6 +6,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <unordered_map> #include <vector> #include <string> @@ -34,10 +35,17 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse_WhitespaceInAttribute); CPPUNIT_TEST(testParse_AttributeWithoutNamespace); CPPUNIT_TEST(testParse_AttributeWithNamespace); + CPPUNIT_TEST(testParse_AttributeWithNamespaceNoPrefix); CPPUNIT_TEST(testParse_BillionLaughs); CPPUNIT_TEST(testParse_InternalEntity); //CPPUNIT_TEST(testParse_UndefinedPrefix); //CPPUNIT_TEST(testParse_UndefinedAttributePrefix); + CPPUNIT_TEST(testParse_AllowCommentsInXML); + CPPUNIT_TEST(testParse_DisallowCommentsInXML); + CPPUNIT_TEST(testParse_Doctype); + CPPUNIT_TEST(testParse_ProcessingInstructions); + CPPUNIT_TEST(testParse_ProcessingPrefixedElement); + CPPUNIT_TEST(testParse_InvalidlyEncodedInput); CPPUNIT_TEST_SUITE_END(); public: @@ -61,6 +69,9 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].namespaces.count("")); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].namespaces[""]); CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[2].data); @@ -85,10 +96,13 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].namespaces[""]); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); CPPUNIT_ASSERT_EQUAL(std::string("name"), client_.events[1].data); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].namespaces.size()); CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type); CPPUNIT_ASSERT_EQUAL(std::string("Swift"), client_.events[2].data); @@ -161,6 +175,8 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[0].data); CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].namespaces["p"]); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); CPPUNIT_ASSERT_EQUAL(std::string("y"), client_.events[1].data); @@ -176,7 +192,7 @@ class XMLParserTest : public CppUnit::TestFixture { } void testParse_UnhandledXML() { - ParserType testling(&client_); + ParserType testling(&client_, true); CPPUNIT_ASSERT(testling.parse("<iq><!-- Testing --></iq>")); @@ -217,6 +233,15 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[1].data); } + void testParse_CompleteDocument() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<iq", true)); + CPPUNIT_ASSERT(!testling.parse("<iq>", true)); + CPPUNIT_ASSERT(!testling.parse("<iq><child>foo</child>", true)); + CPPUNIT_ASSERT(testling.parse("<iq><child>foo</child></iq>", true)); + } + void testParse_WhitespaceInAttribute() { ParserType testling(&client_); @@ -242,6 +267,7 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); } void testParse_AttributeWithNamespace() { @@ -253,6 +279,25 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + CPPUNIT_ASSERT_EQUAL(std::string("f"), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); + } + + void testParse_AttributeWithNamespaceNoPrefix() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' attr='3'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); } void testParse_BillionLaughs() { @@ -292,6 +337,7 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[0].data); CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].namespaces.size()); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data); @@ -309,48 +355,136 @@ class XMLParserTest : public CppUnit::TestFixture { void testParse_UndefinedAttributePrefix() { ParserType testling(&client_); - CPPUNIT_ASSERT(testling.parse( - "<foo bar:baz='bla'/>")); + CPPUNIT_ASSERT(testling.parse("<foo bar:baz='bla'/>")); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("bar:baz"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); } + void testParse_AllowCommentsInXML() { + ParserType testling(&client_, true); + + CPPUNIT_ASSERT(testling.parse("<message><!-- Some More Comments Testing --></message>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); + + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data); + } + + void testParse_DisallowCommentsInXML() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<message><!-- Some More Comments Testing --></message>")); + } + + void testParse_Doctype() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<!DOCTYPE greeting SYSTEM \"hello.dtd\">")); + } + + void testParse_ProcessingInstructions() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<?xml-stylesheet type=\"text/xsl\" href=\"Sample.xsl\"?>")); + } + + void testParse_ProcessingPrefixedElement() { + client_.testingStartElementPrefix = true; + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse("<prefix:message xmlns='uri' xmlns:prefix='uriPrefix'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); + + CPPUNIT_ASSERT_EQUAL(Client::StartElementPrefix, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data); + CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(std::string("prefix"), client_.events[0].prefix); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data); + CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[1].ns); + } + + void testParse_InvalidlyEncodedInput() { + ParserType testling(&client_); + + // The following input was generated by a fuzzer, and triggered a crash in the LibXML2 parser because + // some types of error (buffer I/O errors, for instance) will not update the error in the parser context, + // and the code used to rely on that error always being set if parsing failed. + // This particular input will trick the parser into believing the encoding is UTF-16LE, which eventually will lead + // to two invalid encodings, followed by an I/O error. The latter will end parsing without updating the + // error in the parsing context, which used to trigger a crash. + testling.parse(std::string("<\0?\0\x80q type='get' id='aab9a'<<query xmlns='jabber:iq:roster'/>\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9br:i><quq:private'><storage xml s='s'\x00\x10</query></iq>", 271)); + testling.parse("<iq type='get'\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e to='ad5d8d2b25' ext='ca cs min@wonderland.t' id='aabda'><vCard xmlnr='vcard-temp'/>O/iq>"); + testling.parse("<\xff\xff\xff\x7fype:'get' to='won\x84" "erland.lit' id='aabea'><tuery xmlns='\xd8Vtp://jabber.org/p\x88ot\x8b" "col/disco#info'/>abber.org/protocol/disco#Nnfo'/></iq>"); + } + private: class Client : public XMLParserClient { public: - enum Type { StartElement, EndElement, CharacterData }; + using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>; + enum Type { StartElement, StartElementPrefix, EndElement, CharacterData, NamespaceDefined }; struct Event { Event( Type type, const std::string& data, const std::string& ns, - const AttributeMap& attributes) - : type(type), data(data), ns(ns), attributes(attributes) {} + const std::string& prefix, + const AttributeMap& attributes, + NamespaceMap namespaces) + : type(type), data(data), ns(ns), prefix(prefix), attributes(attributes), namespaces(std::move(namespaces)) {} + Event( + Type type, + const std::string& data, + const std::string& ns, + const AttributeMap& attributes, + NamespaceMap namespaces = {}) + : Event(type, data, ns, {}, attributes, std::move(namespaces)) {} Event(Type type, const std::string& data, const std::string& ns = std::string()) - : type(type), data(data), ns(ns) {} + : Event(type, data, ns, "", AttributeMap(), NamespaceMap()) {} Type type; std::string data; std::string ns; + std::string prefix; AttributeMap attributes; + NamespaceMap namespaces; }; Client() {} - virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { - events.push_back(Event(StartElement, element, ns, attributes)); + void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) override { + if (testingStartElementPrefix) return; + events.push_back(Event(StartElement, element, ns, attributes, std::move(namespaces_))); } - virtual void handleEndElement(const std::string& element, const std::string& ns) { + void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& name, const AttributeMap&) override { + if (!testingStartElementPrefix) return; + events.push_back(Event(StartElementPrefix, name, uri, prefix, AttributeMap(), NamespaceMap())); + } + + void handleEndElement(const std::string& element, const std::string& ns) override { events.push_back(Event(EndElement, element, ns)); } - virtual void handleCharacterData(const std::string& data) { + void handleCharacterData(const std::string& data) override { events.push_back(Event(CharacterData, data)); } + void handleNamespaceDeclaration(const std::string& prefix, const std::string& uri) override { + namespaces_[prefix] = uri; + } + std::vector<Event> events; + bool testingStartElementPrefix = false; + private: + NamespaceMap namespaces_; } client_; }; diff --git a/Swiften/Parser/XMLParser.cpp b/Swiften/Parser/XMLParser.cpp index 8e92fe4..8a0799f 100644 --- a/Swiften/Parser/XMLParser.cpp +++ b/Swiften/Parser/XMLParser.cpp @@ -8,7 +8,7 @@ namespace Swift { -XMLParser::XMLParser(XMLParserClient* client) : client_(client) { +XMLParser::XMLParser(XMLParserClient* client, bool allowComments) : client_(client), allowComments_(allowComments){ } XMLParser::~XMLParser() { diff --git a/Swiften/Parser/XMLParser.h b/Swiften/Parser/XMLParser.h index 8a73c3f..3b09d22 100644 --- a/Swiften/Parser/XMLParser.h +++ b/Swiften/Parser/XMLParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -15,16 +15,21 @@ namespace Swift { class SWIFTEN_API XMLParser { public: - XMLParser(XMLParserClient* client); + XMLParser(XMLParserClient* client, bool allowComments = false); virtual ~XMLParser(); - virtual bool parse(const std::string& data) = 0; + virtual bool parse(const std::string& data, bool finalData = false) = 0; XMLParserClient* getClient() const { return client_; } + bool allowsComments() const { + return allowComments_; + } + private: XMLParserClient* client_; + const bool allowComments_ = false; }; } diff --git a/Swiften/Parser/XMLParserClient.cpp b/Swiften/Parser/XMLParserClient.cpp index 6dc6db6..6698900 100644 --- a/Swiften/Parser/XMLParserClient.cpp +++ b/Swiften/Parser/XMLParserClient.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,5 +11,14 @@ namespace Swift { XMLParserClient::~XMLParserClient() { } +void XMLParserClient::handleStartElement(const std::string&, const std::string&, const AttributeMap&) { +} + +void XMLParserClient::handleStartElementPrefix(const std::string&, const std::string&, const std::string&, const AttributeMap&) { +} + +void XMLParserClient::handleNamespaceDeclaration(const std::string&, const std::string&) { +} + } diff --git a/Swiften/Parser/XMLParserClient.h b/Swiften/Parser/XMLParserClient.h index e4346f6..2f0bc9e 100644 --- a/Swiften/Parser/XMLParserClient.h +++ b/Swiften/Parser/XMLParserClient.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -14,8 +14,22 @@ namespace Swift { public: virtual ~XMLParserClient(); - virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) = 0; + /** + * Client will have to implement only one of the following methods depending on whether + * he is interested in processing the element prefix or not. + */ + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); + virtual void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& element, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string& ns) = 0; virtual void handleCharacterData(const std::string& data) = 0; + + /** + * Signal that a namespace prefix has been declared + * This callback might be called multiple times for a single element, + * and will trigger before the corresponding \ref handleStartElement + * is called. + */ + virtual void handleNamespaceDeclaration(const std::string& prefix, const std::string& uri); }; } diff --git a/Swiften/Parser/XMLParserFactory.h b/Swiften/Parser/XMLParserFactory.h index 595512b..ae3c90e 100644 --- a/Swiften/Parser/XMLParserFactory.h +++ b/Swiften/Parser/XMLParserFactory.h @@ -18,6 +18,6 @@ namespace Swift { public: virtual ~XMLParserFactory(); - virtual std::unique_ptr<XMLParser> createXMLParser(XMLParserClient*) = 0; + virtual std::unique_ptr<XMLParser> createXMLParser(XMLParserClient*, bool allowComments = false) = 0; }; } diff --git a/Swiften/QA/ClientTest/ClientTest.cpp b/Swiften/QA/ClientTest/ClientTest.cpp index 5cb1765..c5117fa 100644 --- a/Swiften/QA/ClientTest/ClientTest.cpp +++ b/Swiften/QA/ClientTest/ClientTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,6 +8,7 @@ #include <thread> #include <boost/bind.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Client/Client.h> #include <Swiften/Client/ClientXMLTracer.h> @@ -74,7 +75,17 @@ int main(int, char**) { if (boshHost && boshPort && boshPath) { std::cout << "Using BOSH with URL: http://" << boshHost << ":" << boshPort << boshPath << std::endl; - options.boshURL = URL("http", boshHost, atoi(boshPort), boshPath); + try { + options.boshURL = URL("http", boshHost, boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(boshPort)), boshPath); + } + catch (const boost::numeric::bad_numeric_cast& e) { + std::cerr << "SWIFT_CLIENTTEST_BOSH_PORT doesn't hold a valid port number: " << e.what() << std::endl; + return -1; + } + catch (const boost::bad_lexical_cast& e) { + std::cerr << "SWIFT_CLIENTTEST_BOSH_PORT doesn't hold a valid port number: " << e.what() << std::endl; + return -1; + } } client = new Swift::Client(JID(jid), std::string(pass), &networkFactories); diff --git a/Swiften/QA/DNSSDTest/DNSSDTest.cpp b/Swiften/QA/DNSSDTest/DNSSDTest.cpp index ae2fafd..5a78d2f 100644 --- a/Swiften/QA/DNSSDTest/DNSSDTest.cpp +++ b/Swiften/QA/DNSSDTest/DNSSDTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -35,7 +35,7 @@ class DNSSDTest : public CppUnit::TestFixture { public: void setUp() { eventLoop = new DummyEventLoop(); - querier = std::make_shared<DNSSDQuerier>(); + querier = std::make_shared<DNSSDQuerierType>(eventLoop); querier->start(); } @@ -55,7 +55,7 @@ class DNSSDTest : public CppUnit::TestFixture { // Publish the service LinkLocalServiceInfo info; - std::shared_ptr<DNSSDRegisterQuery> registerQuery = querier->createRegisterQuery("DNSSDTest", 1234, info.toTXTRecord()); + std::shared_ptr<DNSSDRegisterQuery> registerQuery = querier->createRegisterQuery("DNSSDTest", 1234, *info.toTXTRecord()); registerQuery->onRegisterFinished.connect(boost::bind(&DNSSDTest::handleRegisterFinished, this, _1)); registerQuery->registerService(); @@ -137,7 +137,7 @@ class DNSSDTest : public CppUnit::TestFixture { private: DummyEventLoop* eventLoop; - std::shared_ptr<DNSSDQuerier> querier; + std::shared_ptr<DNSSDQuerierType> querier; std::vector<DNSSDServiceID> added; std::vector<DNSSDServiceID> registered; std::vector<DNSSDServiceID> toRemove; diff --git a/Swiften/QA/DNSSDTest/SConscript b/Swiften/QA/DNSSDTest/SConscript index 275a314..d9c9b04 100644 --- a/Swiften/QA/DNSSDTest/SConscript +++ b/Swiften/QA/DNSSDTest/SConscript @@ -7,6 +7,7 @@ if env["TEST"] : myenv.MergeFlags(myenv["CHECKER_FLAGS"]) myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) myenv.MergeFlags(myenv["CPPUNIT_FLAGS"]) + myenv.MergeFlags(myenv["GOOGLETEST_FLAGS"]) myenv.MergeFlags(myenv["BOOST_FLAGS"]) myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) if myenv.get("HAVE_BONJOUR", 0) : @@ -14,6 +15,7 @@ if env["TEST"] : elif myenv.get("HAVE_AVAHI", 0) : myenv.Append(CPPDEFINES = ["HAVE_AVAHI"]) myenv.MergeFlags(myenv["AVAHI_FLAGS"]) + myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) tester = myenv.Program("DNSSDTest", [ "DNSSDTest.cpp", diff --git a/Swiften/QA/FileTransferTest/FileTransferTest.cpp b/Swiften/QA/FileTransferTest/FileTransferTest.cpp index ebdb36a..7d69277 100644 --- a/Swiften/QA/FileTransferTest/FileTransferTest.cpp +++ b/Swiften/QA/FileTransferTest/FileTransferTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 Isode Limited. + * Copyright (c) 2014-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,7 +8,6 @@ #include <boost/algorithm/string.hpp> #include <boost/filesystem.hpp> -#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Debug.h> @@ -78,14 +77,14 @@ class FileTransferTest { sendFilePath_ = boost::filesystem::unique_path("ft_send_%%%%%%%%%%%%%%%%.bin"); receiveFilePath_ = boost::filesystem::unique_path("ft_receive_%%%%%%%%%%%%%%%%.bin"); - size_t size = 1024 + boost::numeric_cast<size_t>(randGen.generateRandomInteger(1024 * 10)); + size_t size = 1024 + static_cast<size_t>(randGen.generateRandomInteger(1024 * 10)); sendData_.resize(size); for (unsigned char& n : sendData_) { - n = boost::numeric_cast<unsigned char>(randGen.generateRandomInteger(255)); + n = static_cast<unsigned char>(randGen.generateRandomInteger(255)); } std::ofstream outfile(sendFilePath_.native().c_str(), std::ios::out | std::ios::binary); - outfile.write(reinterpret_cast<char *>(&sendData_[0]), boost::numeric_cast<ptrdiff_t>(sendData_.size())); + outfile.write(reinterpret_cast<char *>(&sendData_[0]), static_cast<ptrdiff_t>(sendData_.size())); outfile.close(); } diff --git a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp index 95ebb6d..69e6fe8 100644 --- a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp +++ b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -179,19 +179,19 @@ class DomainNameResolverTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(4, static_cast<int>(serviceQueryResult.size())); CPPUNIT_ASSERT_EQUAL(std::string("xmpp1.test.swift.im"), serviceQueryResult[0].hostname); - CPPUNIT_ASSERT_EQUAL(5000, serviceQueryResult[0].port); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(5000), serviceQueryResult[0].port); CPPUNIT_ASSERT_EQUAL(0, serviceQueryResult[0].priority); CPPUNIT_ASSERT_EQUAL(1, serviceQueryResult[0].weight); CPPUNIT_ASSERT_EQUAL(std::string("xmpp-invalid.test.swift.im"), serviceQueryResult[1].hostname); - CPPUNIT_ASSERT_EQUAL(5000, serviceQueryResult[1].port); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(5000), serviceQueryResult[1].port); CPPUNIT_ASSERT_EQUAL(1, serviceQueryResult[1].priority); CPPUNIT_ASSERT_EQUAL(100, serviceQueryResult[1].weight); CPPUNIT_ASSERT_EQUAL(std::string("xmpp3.test.swift.im"), serviceQueryResult[2].hostname); - CPPUNIT_ASSERT_EQUAL(5000, serviceQueryResult[2].port); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(5000), serviceQueryResult[2].port); CPPUNIT_ASSERT_EQUAL(3, serviceQueryResult[2].priority); CPPUNIT_ASSERT_EQUAL(100, serviceQueryResult[2].weight); CPPUNIT_ASSERT_EQUAL(std::string("xmpp2.test.swift.im"), serviceQueryResult[3].hostname); - CPPUNIT_ASSERT_EQUAL(5000, serviceQueryResult[3].port); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(5000), serviceQueryResult[3].port); CPPUNIT_ASSERT_EQUAL(5, serviceQueryResult[3].priority); CPPUNIT_ASSERT_EQUAL(100, serviceQueryResult[3].weight); } diff --git a/Swiften/QA/StorageTest/SConscript b/Swiften/QA/StorageTest/SConscript index b8360ec..46107a0 100644 --- a/Swiften/QA/StorageTest/SConscript +++ b/Swiften/QA/StorageTest/SConscript @@ -10,7 +10,8 @@ if env["TEST"] : myenv.MergeFlags(myenv["CPPUNIT_FLAGS"]) myenv.MergeFlags(myenv["GOOGLETEST_FLAGS"]) myenv.MergeFlags(myenv["BOOST_FLAGS"]) - myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) + myenv.MergeFlags(myenv.get("LIBIDN_FLAGS", {})) + myenv.MergeFlags(myenv.get("ICU_FLAGS", {})) myenv.MergeFlags(myenv.get("EXPAT_FLAGS", {})) myenv.MergeFlags(myenv.get("LIBXML_FLAGS", {})) myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) diff --git a/Swiften/QA/TLSTest/CertificateTest.cpp b/Swiften/QA/TLSTest/CertificateTest.cpp index 02ec0f8..463ef9e 100644 --- a/Swiften/QA/TLSTest/CertificateTest.cpp +++ b/Swiften/QA/TLSTest/CertificateTest.cpp @@ -15,6 +15,9 @@ #include <Swiften/Base/ByteArray.h> #include <Swiften/TLS/CertificateFactory.h> +#include <Swiften/TLS/TLSContext.h> +#include <Swiften/TLS/PlatformTLSFactories.h> +#include <Swiften/TLS/TLSContextFactory.h> #include <SwifTools/Application/PlatformApplicationPathProvider.h> @@ -30,13 +33,21 @@ class CertificateTest : public CppUnit::TestFixture { CPPUNIT_TEST(testGetSRVNames); CPPUNIT_TEST(testGetDNSNames); CPPUNIT_TEST(testGetXMPPAddresses); + CPPUNIT_TEST(testCreateCertificateChain); + CPPUNIT_TEST(testCreateTlsContext); + CPPUNIT_TEST(testCreateTlsContextDisableSystemTAs); CPPUNIT_TEST_SUITE_END(); public: void setUp() { pathProvider = std::make_unique<PlatformApplicationPathProvider>("FileReadBytestreamTest"); readByteArrayFromFile(certificateData, (pathProvider->getExecutableDir() / "jabber_org.crt")); + readByteArrayFromFile(chainData, (pathProvider->getExecutableDir() / "certificateChain.pem")); + readByteArrayFromFile(keyData, (pathProvider->getExecutableDir() / "privateKey.pem")); certificateFactory = std::unique_ptr<CertificateFactory>(new CERTIFICATE_FACTORY()); + + PlatformTLSFactories* tlsFactories_ = new PlatformTLSFactories(); + tlsContextFactory_ = tlsFactories_->getTLSContextFactory(); } void testConstructFromDER() { @@ -88,10 +99,68 @@ class CertificateTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getXMPPAddresses()[0]); } + void testCreateCertificateChain() { + // The input chain contains a 2-certificate chain: + // the first certificate has: + // a subject of "O=messaging,CN=Mixer Messaging Configuration,CN=badger.isode.net" + // an issuer of "O=messaging, CN=New Messaging CA" + // the second certificate has: + // a subject of "O=messaging, CN=New Messaging CA" + // an issuer of "O=messaging, CN=New Messaging CA" + // i.e. it is a self-signed certificate + std::vector<std::shared_ptr<Certificate>> chain = certificateFactory->createCertificateChain(chainData); + CPPUNIT_ASSERT_EQUAL(2,static_cast<int>(chain.size())); + CPPUNIT_ASSERT_EQUAL(std::string("Mixer Messaging Configuration"), chain[0]->getCommonNames()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("badger.isode.net"), chain[0]->getCommonNames()[1]); + CPPUNIT_ASSERT_EQUAL(std::string("New Messaging CA"), chain[1]->getCommonNames()[0]); + } + + void testCreateTlsContext() { + // Create 2-certificate chain as in previous test + std::vector<std::shared_ptr<Certificate>> chain = certificateFactory->createCertificateChain(chainData); + CPPUNIT_ASSERT_EQUAL(2,static_cast<int>(chain.size())); + + // Load private key from string + PrivateKey::ref key = certificateFactory->createPrivateKey(Swift::createSafeByteArray(keyData)); + CPPUNIT_ASSERT(key); + + const TLSOptions options; + auto context = tlsContextFactory_->createTLSContext(options, TLSContext::Mode::Server); + CPPUNIT_ASSERT(context); + + context->setCertificateChain(chain); + context->setPrivateKey(key); + } + + /** + * This test does not actually verify that use of system TAs has been disabled, it just provides + * a convenient mechanism for testing via a debugger. + **/ + void testCreateTlsContextDisableSystemTAs() { + // Create 2-certificate chain as in previous test + std::vector<std::shared_ptr<Certificate>> chain = certificateFactory->createCertificateChain(chainData); + CPPUNIT_ASSERT_EQUAL(2,static_cast<int>(chain.size())); + + // Load private key from string + PrivateKey::ref key = certificateFactory->createPrivateKey(Swift::createSafeByteArray(keyData)); + CPPUNIT_ASSERT(key); + + // Turn off use of system TAs + TLSOptions options; + options.ignoreSystemTrustAnchors = true; + auto context = tlsContextFactory_->createTLSContext(options, TLSContext::Mode::Server); + CPPUNIT_ASSERT(context); + + context->setCertificateChain(chain); + context->setPrivateKey(key); + } private: std::unique_ptr<PlatformApplicationPathProvider> pathProvider; ByteArray certificateData; + ByteArray chainData; + ByteArray keyData; std::unique_ptr<CertificateFactory> certificateFactory; + TLSContextFactory* tlsContextFactory_; }; #ifdef HAVE_OPENSSL diff --git a/Swiften/QA/TLSTest/SConscript b/Swiften/QA/TLSTest/SConscript index 7811b50..81e2471 100644 --- a/Swiften/QA/TLSTest/SConscript +++ b/Swiften/QA/TLSTest/SConscript @@ -24,4 +24,4 @@ if env["TEST"] : # Reenable if either http://www.tls-o-matic.com/ is fixed or we have setup a replacement. #"CertificateErrorTest.cpp" ]) - myenv.Test(tester, "system")
\ No newline at end of file + myenv.Test(tester, "system") diff --git a/Swiften/QA/TLSTest/certificateChain.pem b/Swiften/QA/TLSTest/certificateChain.pem new file mode 100644 index 0000000..cb3c0fb --- /dev/null +++ b/Swiften/QA/TLSTest/certificateChain.pem @@ -0,0 +1,49 @@ +-----BEGIN CERTIFICATE----- +MIIFFTCCA/2gAwIBAgIKXmMION+1bnZpIzANBgkqhkiG9w0BAQsFADAvMRIwEAYD +VQQKEwltZXNzYWdpbmcxGTAXBgNVBAMTEE5ldyBNZXNzYWdpbmcgQ0EwHhcNMTkw +NzI5MTAxMjMxWhcNMjAwNzI5MTAxMjMxWjBXMRIwEAYDVQQKEwltZXNzYWdpbmcx +JjAkBgNVBAMTHU1peGVyIE1lc3NhZ2luZyBDb25maWd1cmF0aW9uMRkwFwYDVQQD +ExBiYWRnZXIuaXNvZGUubmV0MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC +AYEAt42TMYe9oO4K6XmvST4kiy4cG+nmVDCtZRfAfF/A+1GQXTZ8OfLbPF5noLIF +f1Jj6fBDA2HiKoLQWfNnIklNEzgPbOREuAuCe660sW1JzJFr5O5qYyf6bHKkYmRr +CGHJ3G5kkXZOW3MhczPNHrTIUSL7lYLMZAcyWStkhgBy7lBuYtgDEXbdRH8OGgly +XC39AAU93y7ynw6W3SorU6h9cwvS0Ho8KVemCXoE38WLeSrIw1ks+Kf1YQopg9O3 +2SkXp6Z9elG5Wk5Rh0L0H2XHnAvmodr9TW6rtrPkJZfLL+NfcnGtI6QKnvL8EhYG +d+XiPOV8jyGAFRC1Be72wlF29Rw20zdoD3kAdeqBLWfL8H9mnQpebEIDj8Lmahub ++W4uuUqCG8NuY43lGJzJni9CFWvhD7ss1yVGz84zqRHu5iXNDncWH2luJT1gXvFW +6mxcfe+AwSiZ8PrhDQZBfTyx7ob4Ozdc1d59XTPyckj2msnCo2ayg+jKaViDd4vz +nNwhAgMBAAGjggGJMIIBhTAbBgNVHREEFDASghBiYWRnZXIuaXNvZGUubmV0MA4G +A1UdDwEB/wQEAwIF4DAMBgNVHRMBAf8EAjAAMHQGA1UdHwRtMGswaaBnoGWGY2xk +YXA6Ly9kaWFib2xvLmlzb2RlLm5ldDoxOTM4OS9jbj1OZXclMjBNZXNzYWdpbmcl +MjBDQSxvPW1lc3NhZ2luZz9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0O2JpbmFy +eTCBkQYIKwYBBQUHAQEEgYQwgYEwfwYIKwYBBQUHMAKGc2xkYXA6Ly9kaWFib2xv +Lmlzb2RlLm5ldDoxOTM4OS9jbj1OZXclMjBNZXNzYWdpbmclMjBDQSxvPW1lc3Nh +Z2luZz9jQUNlcnRpZmljYXRlO2JpbmFyeSxjcm9zc0NlcnRpZmljYXRlUGFpcjti +aW5hcnkwHQYDVR0OBBYEFFjf69BczlDoKiSBSvxCr9sy0OJ2MB8GA1UdIwQYMBaA +FJvoU0Lwg8vVCEmEMoKy29zFo/Y7MA0GCSqGSIb3DQEBCwUAA4IBAQCS4zLVH98S +Cl4gsmTkxM+lBsdzQ18ymA6p9ZRXGmJ405C9rN7um9XnbWwOHO6ach7zie2GxWLp +KOYKjX/5Pjt7mPwG8eKepPAxDenzKw5TocjscR9VxBsym0oEkWHPQG+xSqySQGUw +/5QoGy6v06yE8CZ7BKHPh91Jy7IjIDBxWaEtTAPyuH4i4DnsmA0/xSrJ7ez6g399 +YgqDnBInC63bYv5IDD1CmEr/0boBWpsOf50OC6JVhaPLAldwTAxLSOMBJ4q4onXC +ZqDHY3EMRtwYEffNg9ZorXJwLmU3Lq/R3B9lC22XNPDFj/bZ5RpwVFtuN5HfeZzO +aPbNoa0Nf+QB +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDJDCCAgygAwIBAgIKSm7KkUZOigMk9zANBgkqhkiG9w0BAQsFADAvMRIwEAYD +VQQKEwltZXNzYWdpbmcxGTAXBgNVBAMTEE5ldyBNZXNzYWdpbmcgQ0EwHhcNMTYw +MTI2MTU1MTU2WhcNMjYwMTI2MTU1MTU2WjAvMRIwEAYDVQQKEwltZXNzYWdpbmcx +GTAXBgNVBAMTEE5ldyBNZXNzYWdpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDgcuX1s8EvO8GDHx7vSW9oeDnLUBx5E48Vb2qcJVc34ik1j6ZV +d8/+tzmyy/BskFbaOJ0KD5XYOoI8TJtu28lASWZj1vAEZkfrDdBbKeb1BQhShMt2 +ICgzp7l4ubwd6rqCGHpD/f12RVhSlU3y6TniaK62a9RwJOpL/wvnCcJLPjaTw8om +EY62EyUP+FymUbo3Rb3aWLM7avHl1/32pyzUgRzvZR63hlMHnlE5Sgc84j9KMwJH +k+mCyXIGPc+yhL33ljR63Eoiqynyk0HPU6pWai1WKuSv6zMDPwnNaJA3VpLNUHsd +eVe1GyOmPFePnhRPZYfC+Dk8lxDUmZfNFKZlAgMBAAGjQjBAMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSb6FNC8IPL1QhJhDKCstvc +xaP2OzANBgkqhkiG9w0BAQsFAAOCAQEApgA5oupwTS2Ylt9mhS/TDX9wzR0DqnC5 +t9skgU9B/1MnzgqEMKGmuhRBiqDyr0jsPegBFI/CpTdIpakpSUrIvBTZADzkrkI+ +3k2jnpEv0vodaFIHQonDysq5h4bXsCSdSprdhiUa1GKFtnJ92Ro/2Uaw5UcqFPCg +7kj7RmRVlAIynUAT81cefQww0HBFPN9SdBEpp6YP4P1u1x8GV0Bfq93r4G5jkiHN +dA6xejk7RZK4mTH+K2aFpWoHCqMr7RAzV5UiXis4cFAmtv+5K/G7eazNx0Y+ODo4 +fweh+xW+dOXuP1lzW4DzwhEf/8tgFgI0jIvscPgdgHY7t9SQRJPYQQ== +-----END CERTIFICATE----- diff --git a/Swiften/QA/TLSTest/privateKey.pem b/Swiften/QA/TLSTest/privateKey.pem new file mode 100644 index 0000000..5769000 --- /dev/null +++ b/Swiften/QA/TLSTest/privateKey.pem @@ -0,0 +1,40 @@ +-----BEGIN PRIVATE KEY----- +MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDu1QdEBrcWj+D/ +rkmh++QSu2f0qlJ6Re8dEBtbqpxLiyYZ5IeaLts9szXabfSTchdJr/d0IyHfHQFS +MGXDphKRaNnV5r//XuojUtorPyGe0DnZR2mp8S9adD7WxNjQLSQabr8PPPW8jrTx +eJyIvYToLs9lx1IIDcr/3ZTuhBe2FK3Q173M5GF36Jb4yKWLPIfJ6auZjO5G9LZF +3o2vVWxfc7ESnXvf3sAcWQPR08/ud0vLa3W3A8dC0XGk4BbE32cxvSuzWPHZd257 +HiHIW5pKLZXSMTu7fVNzBzDlo8BYQ5kad1ic+hhyIHBwTUO0Hz3EYP+9FG3TNG84 +65K9EeN3/Qw2P9468GHWAXqlzKFiIGikxYHGwvGd0CdegHtZ/TwIgVvpIDp6XB6U +ez/TYPEiMCqX8TCIQi8FU3obEouMoPMHKM8vzQdSItZtPn6gD16M4xKdMm6fbvCD +1okdcrWQnZo72pp8cfpS87KhP5z1ec9B/Wqysh4nrO35v8LXH60CAwEAAQKCAYEA +jPDUJ9XaqAriWaBtvZTbpB5KG72DjLrGgB0oN/E36PDF3FPbniZ2pTOj3TI0OesD +SS351uSAsZz5UZpUA6B2pq78llllBnvpqkzTiN/ppEH3UXzuIya8riGZj758wGVT +P/II+CIeVlbU+wcVQTCuRSKSq9pzU2NoX5RQtmznXUFYzbzzOf2wc0WkCk7GOqPO +8l3eMXBUkTUKd7L9Y/ICUVYBsh2To6pdLp1tPp9DvtNRvEq/HfCx34GgEg9YAHhg +1rcPhh71M+TLYHznl5r/Jm1kIVrP3zyr1Bm5DDgZLE3GTN/oFumgXQyFCPyslup1 +gdZzS6W+fbeKxoPzjPOhzHVUxVZ/yqJH1xa1gs4ECQ4QXxdnr7yY1H5k5S8dabO5 +bEvXP+tH95HcAtAbvoRt+NC+xIJ39d6X7X2c4TPLoMIxDxmbEOCi9sg+4Ws+7E2s +a/01fTZFT+lzuGBdp9Zz/tltDrwfYD0V+Q7qO0o/nJPINI+alAWlqQia00ZyZr4V +AoHBAPxwCls99/LUzY7IJc0TV3ukk3sFi3rt58u8BE4+RaCtmgPMDj1l+EnaY9RW +IOj91ECZ8+a23elNPZOkXKuYuJmJIpjOogOMM8r+Q4WF87xoRcdcjPh+PBat66HZ ++8mbm0VQ98cjxs0/kTRRayzz7UG9Onf1PhFfnw55sbMGItVssRDi9lRZJdSRU+CC +qyAt8TUEH0lo+8AKbRn7xW4VHiD0hmLKDi4F713QLCPgmNlPQ/C60FTIRYS18gzK +ARhuzwKBwQDyM9YiiFFQ3irGKtbj9W3bDHNmMl9YOHMYVXJAvh83Zcp80qRsShtw +n3mV3vcVI+KNeZtKFUrJIYNTspNBP/w8U4lGGW+7tAt0dd0WY9m3ygnZg0GOHoaC +uUusGicZR7FgbYlJzCiRhFhWcFyh0VOrm/k7OjznAvwfWbRKrlLvQdrWrLj7dyN3 +8n9lArq9ZxXJLpBXDUJ1R+F+hPIIIRKeYF2ULUFNE0U9Pj7SVTT7L7jPMWKnrVJh +U4/hVAEHyMMCgcB4hCTtmpAdZmscl4E0ft9tMA0Y1nTYo2veYEzN7fzf0QGOfoTt +2xjGaXTvko7zrPsAPH+szfDzyOR08Cst4SOAaXAS89N1TiIL74fc3y6V7FIj85N5 +rwqQ6UdtZdxHS/q9BQLGF9Z5drej+proQywqDmUzj+mp8bTF/GNRzMQkkFeYcEKZ +0lW1PgyFStzX6BcX8HffXDeUX2Xm2cRP4dUYdqUR1NUgM8UrTI9GMZvHY4hUDVwY +neRSj2qXoHkVaRECgcEArilkM9S+VF5Nd85aU/WqFzeuy7AxK2j8KmVXEQMlw1oo +7vUxUsU/Ug77CTAZkFQLlxv49J629kZo/wiMJwFxyZdwQL4NwHXJPud6IZ2Pcz+P +MZ/WxfFhXCMOLSVpNB5/iA18CVsLWQhH1XBay+mQNvijkVlhbeSRk6GXqZQNAwrh +6Divk/Opx5jSzrnVulikK9SV6mMYhOk5VxcWS44sq0I0SFb6fAf9Y/qchfbLcExy +olqqzFQvxtilv6v+SbCtAoHBAOXPUQ7VVuQZo4HA+CaQRYgQjGMxo4jeGiqrUAaX +b+MpUjU7VxiSrfH3wFxCuMfW7dfQJKp7BAG8PCNzP1eW3+LhPkRSPAT0nwk/bQ5E +N/n6NBqwsJFoTqueS0qDVdPichwKGvnIrraHSVeMeHZNv+TQdMjmTJ5AfBNCal9b +7EPTFQO0Tj4GAB77fVRzewyVB+qXccoD2Gts9aWbY9FVGyhkvRenL7CcbgrzLZvt +php/1crfbWtZ/3Nwz6L8LEdZHA== +-----END PRIVATE KEY----- diff --git a/Swiften/Roster/XMPPRosterController.cpp b/Swiften/Roster/XMPPRosterController.cpp index 8ee9755..2b98b53 100644 --- a/Swiften/Roster/XMPPRosterController.cpp +++ b/Swiften/Roster/XMPPRosterController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -66,7 +66,7 @@ void XMPPRosterController::handleRosterReceived(std::shared_ptr<RosterPayload> r xmppRoster_->addContact(item.getJID(), item.getName(), item.getGroups(), item.getSubscription()); } else { - SWIFT_LOG(error) << "Stored invalid roster item" << std::endl; + SWIFT_LOG(error) << "Stored invalid roster item"; } } } diff --git a/Swiften/SASL/UnitTest/WindowsServicePrincipalNameTest.cpp b/Swiften/SASL/UnitTest/WindowsServicePrincipalNameTest.cpp index fa07052..ef3a9b3 100644 --- a/Swiften/SASL/UnitTest/WindowsServicePrincipalNameTest.cpp +++ b/Swiften/SASL/UnitTest/WindowsServicePrincipalNameTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -97,16 +97,16 @@ class WindowsServicePrincipalNameTest : public CppUnit::TestFixture { WindowsServicePrincipalName spn("adlon.isode.net"); spn.setInstanceName("mlink.adlon.isode.net"); - spn.setInstancePort(6222); - CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/mlink.adlon.isode.net:6222/adlon.isode.net")); + spn.setInstancePort(55222); + CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/mlink.adlon.isode.net:55222/adlon.isode.net")); spn.setInstancePort(0); CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/mlink.adlon.isode.net/adlon.isode.net")); WindowsServicePrincipalName spn2("mlink.adlon.isode.net"); - spn2.setInstancePort(6222); - CPPUNIT_ASSERT_EQUAL(spn2.toString(), std::string("xmpp/mlink.adlon.isode.net:6222")); + spn2.setInstancePort(55222); + CPPUNIT_ASSERT_EQUAL(spn2.toString(), std::string("xmpp/mlink.adlon.isode.net:55222")); spn2.setInstancePort(0); CPPUNIT_ASSERT_EQUAL(spn2.toString(), std::string("xmpp/mlink.adlon.isode.net")); diff --git a/Swiften/SASL/WindowsAuthentication.cpp b/Swiften/SASL/WindowsAuthentication.cpp index b86381b..f951fac 100644 --- a/Swiften/SASL/WindowsAuthentication.cpp +++ b/Swiften/SASL/WindowsAuthentication.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,14 +16,14 @@ #define ASSIGN_ERROR(status, errorCode) \ { \ errorCode = std::make_shared<boost::system::error_code>(status, boost::system::system_category()); \ - SWIFT_LOG(debug) << std::hex << "status: 0x" << status << ": " << errorCode->message() << std::endl; \ + SWIFT_LOG(debug) << std::hex << "status: 0x" << status << ": " << errorCode->message(); \ } #define ASSIGN_SEC_ERROR(status, errorCode) \ { \ if (status == SEC_E_OK) \ { \ - SWIFT_LOG(debug) << "success" << std::endl; \ + SWIFT_LOG(debug) << "success"; \ } \ else { \ ASSIGN_ERROR(status, errorCode); \ @@ -46,14 +46,14 @@ std::shared_ptr<boost::system::error_code> getUserNameEx(std::string& userName, std::size_t position; userName = convertWStringToString(std::wstring(vecptr(value), length)); - SWIFT_LOG(debug) << "User Name: " << userName << std::endl; + SWIFT_LOG(debug) << "User Name: " << userName; position = userName.find("\\"); clientName = userName.substr(position + 1); - SWIFT_LOG(debug) << "Client name: " << clientName << std::endl; + SWIFT_LOG(debug) << "Client name: " << clientName; serverName = userName.substr(0, position); - SWIFT_LOG(debug) << "Server name: " << serverName << std::endl; + SWIFT_LOG(debug) << "Server name: " << serverName; break; } @@ -161,7 +161,7 @@ std::shared_ptr<boost::system::error_code> initializeSecurityContext(const boost } if ((status == SEC_E_OK) || (status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_I_CONTINUE_NEEDED)) { outputToken = createSafeByteArray (static_cast<unsigned char *>(outputTokenBuffer.pvBuffer), outputTokenBuffer.cbBuffer); - SWIFT_LOG(debug) << "outputToken.size(): " << outputToken.size() << std::endl; + SWIFT_LOG(debug) << "outputToken.size(): " << outputToken.size(); freeContextBuffer(outputTokenBuffer.pvBuffer); return std::shared_ptr<boost::system::error_code>(); /* success */ @@ -229,7 +229,7 @@ std::shared_ptr<boost::system::error_code> decryptMessage(const PCtxtHandle cont messageBuffer[1].cbBuffer = 0; messageBuffer[1].pvBuffer = NULL; - SWIFT_LOG(debug) << "inputMessage.size(): " << inputMessage.size() << std::endl; + SWIFT_LOG(debug) << "inputMessage.size(): " << inputMessage.size(); status = DecryptMessage( contextHandle, @@ -239,13 +239,13 @@ std::shared_ptr<boost::system::error_code> decryptMessage(const PCtxtHandle cont ASSIGN_SEC_ERROR(status, errorCode); if (status == SEC_E_OK) { if (qualityOfProtection == SECQOP_WRAP_NO_ENCRYPT) { - SWIFT_LOG(debug) << "Message was signed only" << std::endl; + SWIFT_LOG(debug) << "Message was signed only"; } else { - SWIFT_LOG(debug) << "Message was encrypted" << std::endl; + SWIFT_LOG(debug) << "Message was encrypted"; } - SWIFT_LOG(debug) << "messageBuffer[1].cbBuffer: " << messageBuffer[1].cbBuffer << std::endl; + SWIFT_LOG(debug) << "messageBuffer[1].cbBuffer: " << messageBuffer[1].cbBuffer; decrypted = createSafeByteArray (static_cast<unsigned char *>(messageBuffer[1].pvBuffer), messageBuffer[1].cbBuffer); } @@ -281,9 +281,9 @@ std::shared_ptr<boost::system::error_code> encryptMessage(const PCtxtHandle cont messageBuffer[2].cbBuffer = sizes.cbBlockSize; messageBuffer[2].pvBuffer = vecptr(blockSize); - SWIFT_LOG(debug) << "sizes.cbSecurityTrailer: " << sizes.cbSecurityTrailer << std::endl; - SWIFT_LOG(debug) << "inputMessage.size(): " << inputMessage.size() << std::endl; - SWIFT_LOG(debug) << "sizes.cbBlockSize: " << sizes.cbBlockSize << std::endl; + SWIFT_LOG(debug) << "sizes.cbSecurityTrailer: " << sizes.cbSecurityTrailer; + SWIFT_LOG(debug) << "inputMessage.size(): " << inputMessage.size(); + SWIFT_LOG(debug) << "sizes.cbBlockSize: " << sizes.cbBlockSize; status = EncryptMessage( contextHandle, @@ -294,9 +294,9 @@ std::shared_ptr<boost::system::error_code> encryptMessage(const PCtxtHandle cont if (status == SEC_E_OK) { unsigned char* pointer; - SWIFT_LOG(debug) << "messageBuffer[0].cbBuffer: " << messageBuffer[0].cbBuffer << std::endl; - SWIFT_LOG(debug) << "messageBuffer[1].cbBuffer: " << messageBuffer[1].cbBuffer << std::endl; - SWIFT_LOG(debug) << "messageBuffer[2].cbBuffer: " << messageBuffer[2].cbBuffer << std::endl; + SWIFT_LOG(debug) << "messageBuffer[0].cbBuffer: " << messageBuffer[0].cbBuffer; + SWIFT_LOG(debug) << "messageBuffer[1].cbBuffer: " << messageBuffer[1].cbBuffer; + SWIFT_LOG(debug) << "messageBuffer[2].cbBuffer: " << messageBuffer[2].cbBuffer; output.resize(messageBuffer[0].cbBuffer + messageBuffer[1].cbBuffer + messageBuffer[2].cbBuffer); pointer = vecptr(output); diff --git a/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp index aae437f..10e8c89 100644 --- a/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp +++ b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -44,7 +44,7 @@ WindowsGSSAPIClientAuthenticator::~WindowsGSSAPIClientAuthenticator() { } boost::optional<SafeByteArray> WindowsGSSAPIClientAuthenticator::getResponse() const { - SWIFT_LOG(debug) << "response_.size(): " << response_.size() << std::endl; + SWIFT_LOG(debug) << "response_.size(): " << response_.size(); return response_; } @@ -56,7 +56,7 @@ bool WindowsGSSAPIClientAuthenticator::setChallenge(const boost::optional<ByteAr } else if (step_ == SecurityLayerNegotiation) { if (!challengeData) { - SWIFT_LOG(debug) << "Empty message received from the server" << std::endl; + SWIFT_LOG(debug) << "Empty message received from the server"; error_ = true; return false; } @@ -68,7 +68,7 @@ bool WindowsGSSAPIClientAuthenticator::setChallenge(const boost::optional<ByteAr } if (challenge.size() != 4) { - SWIFT_LOG(debug) << "Token received from the server of incorrect length: " << challenge.size() << std::endl; + SWIFT_LOG(debug) << "Token received from the server of incorrect length: " << challenge.size(); error_ = true; return false; } @@ -77,14 +77,14 @@ bool WindowsGSSAPIClientAuthenticator::setChallenge(const boost::optional<ByteAr unsigned char serverSecurityLayer = challengePointer[0]; if (serverSecurityLayer == 0) { - SWIFT_LOG(debug) << "Server supports unknown security layer, assuming no security layer" << std::endl; + SWIFT_LOG(debug) << "Server supports unknown security layer, assuming no security layer"; serverSecurityLayer = SECURITY_LAYER_NONE; } else if (serverSecurityLayer == SECURITY_LAYER_NONE) { - SWIFT_LOG(debug) << "Server supports no security layer" << std::endl; + SWIFT_LOG(debug) << "Server supports no security layer"; } else { - SWIFT_LOG(debug) << "Server supports security layer" << std::endl; + SWIFT_LOG(debug) << "Server supports security layer"; } unsigned int serverMaximumBuffer = (challengePointer[1] << 16) | @@ -92,7 +92,7 @@ bool WindowsGSSAPIClientAuthenticator::setChallenge(const boost::optional<ByteAr (challengePointer[3] << 0); if ((serverSecurityLayer == SECURITY_LAYER_NONE) && (serverMaximumBuffer != 0)) { - SWIFT_LOG(debug) << "Server supports no security layer but has maximum buffer size" << serverMaximumBuffer << std::endl; + SWIFT_LOG(debug) << "Server supports no security layer but has maximum buffer size" << serverMaximumBuffer; error_ = true; return false; } @@ -158,7 +158,7 @@ void WindowsGSSAPIClientAuthenticator::buildSecurityContext(const boost::optiona } if (contextSupported & ISC_REQ_MUTUAL_AUTH == 0) { - SWIFT_LOG(debug) << "Mutual authentication not supported" << std::endl; + SWIFT_LOG(debug) << "Mutual authentication not supported"; error_ = true; return; } @@ -181,14 +181,14 @@ void WindowsGSSAPIClientAuthenticator::buildSecurityContext(const boost::optiona } userName_ = names.sUserName; - SWIFT_LOG(debug) << "User name: " << userName_ << std::endl; + SWIFT_LOG(debug) << "User name: " << userName_; std::size_t position = userName_.find("\\"); clientName_ = userName_.substr(position + 1); - SWIFT_LOG(debug) << "Client name: " << clientName_ << std::endl; + SWIFT_LOG(debug) << "Client name: " << clientName_; serverName_ = userName_.substr(0, position); - SWIFT_LOG(debug) << "Server name: " << serverName_ << std::endl; + SWIFT_LOG(debug) << "Server name: " << serverName_; freeContextBuffer(names.sUserName); step_ = SecurityLayerNegotiation; diff --git a/Swiften/SASL/WindowsServicePrincipalName.cpp b/Swiften/SASL/WindowsServicePrincipalName.cpp index 419395c..6c87925 100644 --- a/Swiften/SASL/WindowsServicePrincipalName.cpp +++ b/Swiften/SASL/WindowsServicePrincipalName.cpp @@ -64,7 +64,7 @@ std::string WindowsServicePrincipalName::toString() { firstCall = false; } - SWIFT_LOG(debug) << "SPN: " << str << std::endl; + SWIFT_LOG(debug) << "SPN: " << str; return str; } @@ -72,17 +72,17 @@ DWORD WindowsServicePrincipalName::dsMakeSpn(DWORD* length, wchar_t* value) { DWORD status; #ifdef UNICODE - SWIFT_LOG(debug) << "UNICODE is defined" << std::endl; + SWIFT_LOG(debug) << "UNICODE is defined"; #else - SWIFT_LOG(debug) << "UNICODE is not defined" << std::endl; + SWIFT_LOG(debug) << "UNICODE is not defined"; #endif - SWIFT_LOG(debug) << "serviceClass_: " << convertWStringToString(serviceClass_.c_str()) << std::endl; - SWIFT_LOG(debug) << "serviceName_: " << convertWStringToString(serviceName_.c_str()) << std::endl; - SWIFT_LOG(debug) << "instanceName_: " << convertWStringToString(instanceName_.c_str()) << std::endl; - SWIFT_LOG(debug) << "referrer_: " << convertWStringToString(referrer_.c_str()) << std::endl; - SWIFT_LOG(debug) << "instancePort_: " << instancePort_ << std::endl; - SWIFT_LOG(debug) << "length: " << *length << std::endl; + SWIFT_LOG(debug) << "serviceClass_: " << convertWStringToString(serviceClass_.c_str()); + SWIFT_LOG(debug) << "serviceName_: " << convertWStringToString(serviceName_.c_str()); + SWIFT_LOG(debug) << "instanceName_: " << convertWStringToString(instanceName_.c_str()); + SWIFT_LOG(debug) << "referrer_: " << convertWStringToString(referrer_.c_str()); + SWIFT_LOG(debug) << "instancePort_: " << instancePort_; + SWIFT_LOG(debug) << "length: " << *length; /* Call the Unicode function because that is recommended: https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407%28v=vs.85%29.aspx */ @@ -97,7 +97,7 @@ https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407%28v=vs.85%29.a if (status != ERROR_SUCCESS) { boost::system::error_code errorCode(status, boost::system::system_category()); - SWIFT_LOG(debug) << std::hex << "status: 0x" << status << ": " << errorCode.message() << std::endl; + SWIFT_LOG(debug) << std::hex << "status: 0x" << status << ": " << errorCode.message(); } return status; diff --git a/Swiften/SASL/WindowsServicePrincipalName.h b/Swiften/SASL/WindowsServicePrincipalName.h index 4c9f557..2e4e5c4 100644 --- a/Swiften/SASL/WindowsServicePrincipalName.h +++ b/Swiften/SASL/WindowsServicePrincipalName.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -49,7 +49,7 @@ namespace Swift { * it remain 0 to indicate that the default port is * used. */ - void setInstancePort(short int instancePort) { instancePort_ = instancePort; } + void setInstancePort(unsigned short instancePort) { instancePort_ = instancePort; } /* * This follows the rules of SPN creation on Windows and diff --git a/Swiften/SConscript b/Swiften/SConscript index d028a0c..7ea7355 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -12,7 +12,7 @@ external_swiften_dep_modules = ["BOOST"] if env["SCONS_STAGE"] == "flags" : env["SWIFTEN_DLL"] = env["swiften_dll"] env["SWIFTEN_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift") - version_match = re.match("(\d+)\.(\d+).*", env["SWIFTEN_VERSION"]) + version_match = re.match(r"(\d+)\.(\d+).*", env["SWIFTEN_VERSION"]) if version_match : env["SWIFTEN_VERSION_MAJOR"] = int(version_match.group(1)) env["SWIFTEN_VERSION_MINOR"] = int(version_match.group(2)) @@ -142,6 +142,7 @@ if env["SCONS_STAGE"] == "build" : "Elements/PubSubPayload.cpp", "Elements/PubSubOwnerPayload.cpp", "Elements/PubSubEventPayload.cpp", + "Elements/ReferencePayload.cpp", "Elements/RosterItemExchangePayload.cpp", "Elements/RosterPayload.cpp", "Elements/SecurityLabel.cpp", @@ -225,6 +226,7 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp", "Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.cpp", "Serializer/PayloadSerializers/MUCInvitationPayloadSerializer.cpp", + "Serializer/PayloadSerializers/ReferencePayloadSerializer.cpp", "Serializer/PayloadSerializers/ResourceBindSerializer.cpp", "Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp", "Serializer/PayloadSerializers/RosterSerializer.cpp", @@ -381,6 +383,7 @@ if env["SCONS_STAGE"] == "build" : File("Avatars/UnitTest/CombinedAvatarProviderTest.cpp"), File("Avatars/UnitTest/AvatarManagerImplTest.cpp"), File("Base/UnitTest/IDGeneratorTest.cpp"), + File("Base/UnitTest/LogTest.cpp"), File("Base/UnitTest/LRUCacheTest.cpp"), File("Base/UnitTest/SimpleIDGeneratorTest.cpp"), File("Base/UnitTest/StringTest.cpp"), @@ -437,6 +440,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/CommandParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RosterParserTest.cpp"), @@ -514,6 +518,7 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/IBBSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/ReferencePayloadSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp"), @@ -575,6 +580,10 @@ if env["SCONS_STAGE"] == "build" : File("Whiteboard/UnitTest/WhiteboardServerTest.cpp"), File("Whiteboard/UnitTest/WhiteboardClientTest.cpp"), ]) + if env.get("HAVE_OPENSSL", 0) : + env.Append(UNITTEST_SOURCES = [ + File("TLS/UnitTest/ClientServerTest.cpp"), + ]) # Generate the Swiften header def relpath(path, start) : @@ -585,6 +594,8 @@ if env["SCONS_STAGE"] == "build" : swiften_public_includes = [] top_path = env.Dir("..").abspath for root, dirs, files in os.walk(env.Dir(".").abspath) : + dirs.sort() + files.sort() if root.endswith("UnitTest") : continue for file in files : @@ -635,8 +646,9 @@ if env["SCONS_STAGE"] == "build" : # Install swiften if swiften_env.get("SWIFTEN_INSTALLDIR", "") : - swiften_env.Install(os.path.join(swiften_env["SWIFTEN_INSTALLDIR"], "lib"), swiften_lib) + swiften_libdir = swiften_env.get("SWIFTEN_LIBDIR", "lib") + swiften_env.Install(os.path.join(swiften_env["SWIFTEN_INSTALLDIR"], swiften_libdir), swiften_lib) for alias in myenv["SWIFTEN_LIBRARY_ALIASES"] : - myenv.Command(myenv.File(os.path.join(swiften_env["SWIFTEN_INSTALLDIR"], "lib", alias)), [env.Value(swiften_lib[0].name), swiften_lib[0]], symlink) + myenv.Command(myenv.File(os.path.join(swiften_env["SWIFTEN_INSTALLDIR"], swiften_libdir, alias)), [env.Value(swiften_lib[0].name), swiften_lib[0]], symlink) for include in swiften_includes : swiften_env.Install(os.path.join(swiften_env["SWIFTEN_INSTALLDIR"], "include", os.path.dirname(include)), "#/" + include) diff --git a/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.cpp index 78bb0eb..37a9c03 100644 --- a/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.cpp @@ -25,7 +25,7 @@ std::string BytestreamsSerializer::serializePayload(std::shared_ptr<Bytestreams> std::shared_ptr<XMLElement> streamHostElement(new XMLElement("streamhost")); streamHostElement->setAttribute("host", streamHost.host); streamHostElement->setAttribute("jid", streamHost.jid.toString()); - streamHostElement->setAttribute("port", boost::lexical_cast<std::string>(streamHost.port)); + streamHostElement->setAttribute("port", std::to_string(streamHost.port)); queryElement.addNode(streamHostElement); } diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index 428ce76..31294f1 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -69,6 +69,7 @@ #include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h> #include <Swiften/Serializer/PayloadSerializers/PubSubSerializer.h> #include <Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h> #include <Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h> #include <Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h> #include <Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h> @@ -186,6 +187,8 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new IsodeIQDelegationSerializer(this)); + serializers_.push_back(new ReferencePayloadSerializer(this)); + for (auto serializer : serializers_) { addSerializer(serializer); } diff --git a/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp b/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp index e41ff8c..74a8e7b 100644 --- a/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp @@ -26,7 +26,7 @@ std::string IBBSerializer::serializePayload(std::shared_ptr<IBB> ibb) const { XMLElement ibbElement("data", "http://jabber.org/protocol/ibb"); ibbElement.setAttribute("sid", ibb->getStreamID()); if (ibb->getSequenceNumber() >= 0) { - ibbElement.setAttribute("seq", boost::lexical_cast<std::string>(ibb->getSequenceNumber())); + ibbElement.setAttribute("seq", std::to_string(ibb->getSequenceNumber())); } ibbElement.addNode(std::make_shared<XMLTextNode>(Base64::encode(ibb->getData()))); return ibbElement.serialize(); @@ -39,7 +39,7 @@ std::string IBBSerializer::serializePayload(std::shared_ptr<IBB> ibb) const { case IBB::MessageStanza: ibbElement.setAttribute("stanza", "message"); break; } assert(ibb->getBlockSize() > 0); - ibbElement.setAttribute("block-size", boost::lexical_cast<std::string>(ibb->getBlockSize())); + ibbElement.setAttribute("block-size", std::to_string(ibb->getBlockSize())); return ibbElement.serialize(); } case IBB::Close: { diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.cpp index 35a0a6e..95996c7 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.cpp @@ -44,13 +44,13 @@ std::string JingleFileTransferFileInfoSerializer::serializePayload(std::shared_p if (fileInfo->getSupportsRangeRequests()) { std::shared_ptr<XMLElement> range = std::make_shared<XMLElement>("range"); if (fileInfo->getRangeOffset() != 0) { - range->setAttribute("offset", boost::lexical_cast<std::string>(fileInfo->getRangeOffset())); + range->setAttribute("offset", std::to_string(fileInfo->getRangeOffset())); } fileElement.addNode(range); } if (fileInfo->getSize() > 0) { - fileElement.addNode(std::make_shared<XMLElement>("size", "", boost::lexical_cast<std::string>(fileInfo->getSize()))); + fileElement.addNode(std::make_shared<XMLElement>("size", "", std::to_string(fileInfo->getSize()))); } for (const auto& hashElement : fileInfo->getHashes()) { diff --git a/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp index 9930e44..c5c45e1 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp @@ -28,7 +28,7 @@ JingleIBBTransportPayloadSerializer::JingleIBBTransportPayloadSerializer() { std::string JingleIBBTransportPayloadSerializer::serializePayload(std::shared_ptr<JingleIBBTransportPayload> payload) const { XMLElement payloadXML("transport", "urn:xmpp:jingle:transports:ibb:1"); if (payload->getBlockSize()) { - payloadXML.setAttribute("block-size", boost::lexical_cast<std::string>(*payload->getBlockSize())); + payloadXML.setAttribute("block-size", std::to_string(*payload->getBlockSize())); } payloadXML.setAttribute("sid", payload->getSessionID()); diff --git a/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp index aaac757..566d556 100644 --- a/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -93,7 +93,7 @@ std::string JinglePayloadSerializer::actionToString(JinglePayload::Action action case JinglePayload::TransportReplace: return "transport-replace"; case JinglePayload::UnknownAction: - SWIFT_LOG(warning) << "Serializing unknown action value." << std::endl; + SWIFT_LOG(warning) << "Serializing unknown action value."; return ""; } assert(false); @@ -103,7 +103,7 @@ std::string JinglePayloadSerializer::actionToString(JinglePayload::Action action std::string JinglePayloadSerializer::reasonTypeToString(JinglePayload::Reason::Type type) const { switch(type) { case JinglePayload::Reason::UnknownType: - SWIFT_LOG(warning) << "Unknown jingle reason type!" << std::endl; + SWIFT_LOG(warning) << "Unknown jingle reason type!"; return ""; case JinglePayload::Reason::AlternativeSession: return "alternative-session"; diff --git a/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.cpp index 5e74d8e..f9a1832 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.cpp @@ -39,8 +39,8 @@ std::string JingleS5BTransportPayloadSerializer::serializePayload(std::shared_pt candidateXML->setAttribute("cid", candidate.cid); candidateXML->setAttribute("host", candidate.hostPort.getAddress().toString()); candidateXML->setAttribute("jid", candidate.jid.toString()); - candidateXML->setAttribute("port", boost::lexical_cast<std::string>(candidate.hostPort.getPort())); - candidateXML->setAttribute("priority", boost::lexical_cast<std::string>(candidate.priority)); + candidateXML->setAttribute("port", std::to_string(candidate.hostPort.getPort())); + candidateXML->setAttribute("priority", std::to_string(candidate.priority)); candidateXML->setAttribute("type", typeToString(candidate.type)); payloadXML.addNode(candidateXML); } diff --git a/Swiften/Serializer/PayloadSerializers/LastSerializer.h b/Swiften/Serializer/PayloadSerializers/LastSerializer.h index 1710bc0..719eff5 100644 --- a/Swiften/Serializer/PayloadSerializers/LastSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/LastSerializer.h @@ -18,7 +18,7 @@ namespace Swift { LastSerializer() : GenericPayloadSerializer<Last>() {} virtual std::string serializePayload(std::shared_ptr<Last> last) const { - return "<query xmlns='jabber:iq:last' seconds='" + boost::lexical_cast<std::string>(last->getSeconds()) + "'/>"; + return "<query xmlns='jabber:iq:last' seconds='" + std::to_string(last->getSeconds()) + "'/>"; } }; } diff --git a/Swiften/Serializer/PayloadSerializers/MIXUpdateSubscriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/MIXUpdateSubscriptionSerializer.h index ee59bf7..4ba9584 100644 --- a/Swiften/Serializer/PayloadSerializers/MIXUpdateSubscriptionSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/MIXUpdateSubscriptionSerializer.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2017 Isode Limited. + * Copyright (c) 2017-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,7 +23,7 @@ namespace Swift { class SWIFTEN_API MIXUpdateSubscriptionSerializer : public GenericPayloadSerializer<MIXUpdateSubscription> { public: MIXUpdateSubscriptionSerializer(); - virtual ~MIXUpdateSubscriptionSerializer(); + virtual ~MIXUpdateSubscriptionSerializer() override; virtual std::string serializePayload(std::shared_ptr<MIXUpdateSubscription>) const override; }; diff --git a/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp index 4f0f637..cde129e 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp @@ -25,15 +25,15 @@ std::string MUCPayloadSerializer::serializePayload(std::shared_ptr<MUCPayload> m std::shared_ptr<XMLElement> historyElement(new XMLElement("history")); bool history = false; if (muc->getMaxChars() >= 0) { - historyElement->setAttribute("maxchars", boost::lexical_cast<std::string>(muc->getMaxChars())); + historyElement->setAttribute("maxchars", std::to_string(muc->getMaxChars())); history = true; } if (muc->getMaxStanzas() >= 0) { - historyElement->setAttribute("maxstanzas", boost::lexical_cast<std::string>(muc->getMaxStanzas())); + historyElement->setAttribute("maxstanzas", std::to_string(muc->getMaxStanzas())); history = true; } if (muc->getSeconds() >= 0) { - historyElement->setAttribute("seconds", boost::lexical_cast<std::string>(muc->getSeconds())); + historyElement->setAttribute("seconds", std::to_string(muc->getSeconds())); history = true; } if (muc->getSince() != boost::posix_time::not_a_date_time) { diff --git a/Swiften/Serializer/PayloadSerializers/PrioritySerializer.h b/Swiften/Serializer/PayloadSerializers/PrioritySerializer.h index 687d07f..fa2cef0 100644 --- a/Swiften/Serializer/PayloadSerializers/PrioritySerializer.h +++ b/Swiften/Serializer/PayloadSerializers/PrioritySerializer.h @@ -18,7 +18,7 @@ namespace Swift { PrioritySerializer() : GenericPayloadSerializer<Priority>() {} virtual std::string serializePayload(std::shared_ptr<Priority> priority) const { - return "<priority>" + boost::lexical_cast<std::string>(priority->getPriority()) + "</priority>"; + return "<priority>" + std::to_string(priority->getPriority()) + "</priority>"; } }; } diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp index 9786f51..b2c7326 100644 --- a/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp @@ -37,7 +37,7 @@ std::string PubSubItemsSerializer::serializePayload(std::shared_ptr<PubSubItems> element.addNode(std::make_shared<XMLRawTextNode>(PubSubItemSerializer(serializers).serialize(item))); } if (payload->getMaximumItems()) { - element.setAttribute("max_items", boost::lexical_cast<std::string>(*payload->getMaximumItems())); + element.setAttribute("max_items", std::to_string(*payload->getMaximumItems())); } if (payload->getSubscriptionID()) { element.setAttribute("subid", *payload->getSubscriptionID()); diff --git a/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.cpp new file mode 100644 index 0000000..128aac7 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018-2019 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h> + +#include <memory> + +#include <Swiften/Base/Log.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> + +namespace Swift { + +ReferencePayloadSerializer::ReferencePayloadSerializer(PayloadSerializerCollection* payloadSerializers) : GenericPayloadSerializer<ReferencePayload>(), payloadSerializers_(payloadSerializers) { +} + +std::string ReferencePayloadSerializer::serializePayload(ReferencePayload::ref reference) const { + XMLElement element("reference", "urn:xmpp:reference:0"); + + auto type = reference->getType(); + if (type != ReferencePayload::Type::Unknown) { + element.setAttribute("type", getTypeString(type)); + + if (auto uri = reference->getUri()) { + element.setAttribute("uri", *uri); + } + if (auto begin = reference->getBegin()) { + element.setAttribute("begin", *begin); + } + if (auto end = reference->getEnd()) { + element.setAttribute("end", *end); + } + if (auto anchor = reference->getAnchor()) { + element.setAttribute("anchor", *anchor); + } + + std::string serializedPayloads; + for (const auto& payload : reference->getPayloads()) { + if (auto serializer = payloadSerializers_->getPayloadSerializer(payload)) { + element.addNode(std::make_shared<XMLRawTextNode>(serializer->serialize(payload))); + } + else { + SWIFT_LOG(warning) << "Could not find serializer for " << typeid(*(payload.get())).name(); + } + } + } + return element.serialize(); +} + +const std::string ReferencePayloadSerializer::getTypeString(const ReferencePayload::Type type) const { + switch(type) { + case ReferencePayload::Type::Data: return "data"; + case ReferencePayload::Type::Mention: return "mention"; + case ReferencePayload::Type::PubSub: return "pubsub"; + case ReferencePayload::Type::Unknown: return "unknown"; + } + return ""; +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h new file mode 100644 index 0000000..2af6045 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ReferencePayload.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API ReferencePayloadSerializer : public GenericPayloadSerializer<ReferencePayload> { + public: + ReferencePayloadSerializer(PayloadSerializerCollection* payloadSerializers); + virtual std::string serializePayload(ReferencePayload::ref reference) const; + + private: + const std::string getTypeString(const ReferencePayload::Type type) const; + + PayloadSerializerCollection* payloadSerializers_; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp index 3302863..3d13ce3 100644 --- a/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp @@ -29,21 +29,21 @@ std::string ResultSetSerializer::serializePayload(std::shared_ptr<ResultSet> pay XMLElement element("set", "http://jabber.org/protocol/rsm"); if (payload->getMaxItems()) { - element.addNode(std::make_shared<XMLElement>("max", "", boost::lexical_cast<std::string>(*payload->getMaxItems()))); + element.addNode(std::make_shared<XMLElement>("max", "", std::to_string(*payload->getMaxItems()))); } if (payload->getCount()) { - element.addNode(std::make_shared<XMLElement>("count", "", boost::lexical_cast<std::string>(*payload->getCount()))); + element.addNode(std::make_shared<XMLElement>("count", "", std::to_string(*payload->getCount()))); } if (payload->getIndex()) { - element.addNode(std::make_shared<XMLElement>("index", "", boost::lexical_cast<std::string>(*payload->getIndex()))); + element.addNode(std::make_shared<XMLElement>("index", "", std::to_string(*payload->getIndex()))); } if (payload->getFirstID()) { std::shared_ptr<XMLElement> firstElement = std::make_shared<XMLElement>("first", "", *payload->getFirstID()); if (payload->getFirstIDIndex()) { - firstElement->setAttribute("index", boost::lexical_cast<std::string>(*payload->getFirstIDIndex())); + firstElement->setAttribute("index", std::to_string(*payload->getFirstIDIndex())); } element.addNode(firstElement); } diff --git a/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h b/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h index 14cbd14..e992f72 100644 --- a/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h @@ -29,7 +29,7 @@ namespace Swift { if (s5bProxyRequest && s5bProxyRequest->getStreamHost()) { std::shared_ptr<XMLElement> streamHost = std::make_shared<XMLElement>("streamhost"); streamHost->setAttribute("host", s5bProxyRequest->getStreamHost().get().host); - streamHost->setAttribute("port", boost::lexical_cast<std::string>(s5bProxyRequest->getStreamHost().get().port)); + streamHost->setAttribute("port", std::to_string(s5bProxyRequest->getStreamHost().get().port)); streamHost->setAttribute("jid", s5bProxyRequest->getStreamHost().get().jid.toString()); queryElement.addNode(streamHost); } else if (s5bProxyRequest && s5bProxyRequest->getActivate()) { diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp b/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp index ba296f9..718e550 100644 --- a/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp @@ -40,7 +40,7 @@ std::string StreamInitiationFileInfoSerializer::serializePayload(std::shared_ptr fileElement.setAttribute("name", fileInfo->getName()); } if (fileInfo->getSize() != 0) { - fileElement.setAttribute("size", boost::lexical_cast<std::string>(fileInfo->getSize())); + fileElement.setAttribute("size", std::to_string(fileInfo->getSize())); } if (!fileInfo->getDescription().empty()) { std::shared_ptr<XMLElement> desc = std::make_shared<XMLElement>("desc", "", fileInfo->getDescription()); @@ -49,7 +49,7 @@ std::string StreamInitiationFileInfoSerializer::serializePayload(std::shared_ptr if (fileInfo->getSupportsRangeRequests()) { std::shared_ptr<XMLElement> range = std::make_shared<XMLElement>("range"); if (fileInfo->getRangeOffset() != 0) { - range->setAttribute("offset", boost::lexical_cast<std::string>(fileInfo->getRangeOffset())); + range->setAttribute("offset", std::to_string(fileInfo->getRangeOffset())); } fileElement.addNode(range); } diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp index 3faa5b7..813edb4 100644 --- a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp @@ -38,7 +38,7 @@ std::string StreamInitiationSerializer::serializePayload(std::shared_ptr<StreamI std::shared_ptr<XMLElement> fileElement(new XMLElement("file", "http://jabber.org/protocol/si/profile/file-transfer")); fileElement->setAttribute("name", file.getName()); if (file.getSize() != 0) { - fileElement->setAttribute("size", boost::lexical_cast<std::string>(file.getSize())); + fileElement->setAttribute("size", std::to_string(file.getSize())); } if (!file.getDescription().empty()) { std::shared_ptr<XMLElement> descElement(new XMLElement("desc")); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ReferencePayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ReferencePayloadSerializerTest.cpp new file mode 100644 index 0000000..82465d7 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ReferencePayloadSerializerTest.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <gtest/gtest.h> + +#include <Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h> + +#include <Swiften/Elements/Body.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +static FullPayloadSerializerCollection serializers; + +TEST(ReferencePayloadSerializerTest, testSerialize) { + ReferencePayloadSerializer testling(&serializers); + auto reference = std::make_shared<ReferencePayload>(); + reference->setType(ReferencePayload::Type::Data); + reference->setUri(boost::optional<std::string>("https://www.example.com/mindBlowingImage.jpeg")); + reference->setBegin(boost::optional<std::string>("11")); + reference->setEnd(boost::optional<std::string>("22")); + reference->setAnchor(boost::optional<std::string>("xmpp:data@localhost.example.test")); + + std::string expectedResult = + "<reference " + "anchor=\"xmpp:data@localhost.example.test\" " + "begin=\"11\" " + "end=\"22\" " + "type=\"data\" " + "uri=\"https://www.example.com/mindBlowingImage.jpeg\" " + "xmlns=\"urn:xmpp:reference:0\"/>"; + + ASSERT_EQ(expectedResult, testling.serialize(reference)); +} + +TEST(ReferencePayloadSerializerTest, testSerializeNoType) { + ReferencePayloadSerializer testling(&serializers); + auto reference = std::make_shared<ReferencePayload>(); + reference->setUri(boost::optional<std::string>("https://www.example.com/mindBlowingImage.jpeg")); + reference->setBegin(boost::optional<std::string>("11")); + reference->setEnd(boost::optional<std::string>("22")); + reference->setAnchor(boost::optional<std::string>("xmpp:data@localhost.example.test")); + + std::string expectedResult = + "<reference " + "anchor=\"xmpp:data@localhost.example.test\" " + "begin=\"11\" " + "end=\"22\" " + "type=\"data\" " + "uri=\"https://www.example.com/mindBlowingImage.jpeg\" " + "xmlns=\"urn:xmpp:reference:0\"/>"; + + ASSERT_EQ(expectedResult, testling.serialize(reference)); +} + +TEST(ReferencePayloadSerializerTest, testSerializeWithEmbeddedPayload) { + ReferencePayloadSerializer testling(&serializers); + auto reference = std::make_shared<ReferencePayload>(); + reference->setUri(boost::optional<std::string>("https://www.example.com/mindBlowingImage.jpeg")); + reference->setBegin(boost::optional<std::string>("11")); + reference->setEnd(boost::optional<std::string>("22")); + reference->setAnchor(boost::optional<std::string>("xmpp:data@localhost.example.test")); + auto payload = std::make_shared<Body>(std::string("Look, I'm in a reference")); + reference->addPayload(payload); + + std::string expectedResult = + "<reference " + "anchor=\"xmpp:data@localhost.example.test\" " + "begin=\"11\" " + "end=\"22\" " + "type=\"data\" " + "uri=\"https://www.example.com/mindBlowingImage.jpeg\" " + "xmlns=\"urn:xmpp:reference:0\">" + "<body>Look, I'm in a reference</body>" + "</reference>"; + + ASSERT_EQ(expectedResult, testling.serialize(reference)); +} diff --git a/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp index 687b566..8bb3a4b 100644 --- a/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp @@ -26,7 +26,7 @@ std::string UserTuneSerializer::serializePayload(std::shared_ptr<UserTune> paylo } XMLElement element("tune", "http://jabber.org/protocol/tune"); if (payload->getRating()) { - element.addNode(std::make_shared<XMLElement>("rating", "", boost::lexical_cast<std::string>(*payload->getRating()))); + element.addNode(std::make_shared<XMLElement>("rating", "", std::to_string(*payload->getRating()))); } if (payload->getTitle()) { element.addNode(std::make_shared<XMLElement>("title", "", *payload->getTitle())); @@ -44,7 +44,7 @@ std::string UserTuneSerializer::serializePayload(std::shared_ptr<UserTune> paylo element.addNode(std::make_shared<XMLElement>("source", "", *payload->getSource())); } if (payload->getLength()) { - element.addNode(std::make_shared<XMLElement>("length", "", boost::lexical_cast<std::string>(*payload->getLength()))); + element.addNode(std::make_shared<XMLElement>("length", "", std::to_string(*payload->getLength()))); } return element.serialize(); } diff --git a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp index 34fd149..f38f5b7 100644 --- a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2016 Isode Limited. + * Copyright (c) 2016-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -26,13 +26,13 @@ namespace Swift { void WhiteboardElementSerializingVisitor::visit(WhiteboardLineElement& line) { element = std::make_shared<XMLElement>("line"); try { - element->setAttribute("x1", boost::lexical_cast<std::string>(line.x1())); - element->setAttribute("y1", boost::lexical_cast<std::string>(line.y1())); - element->setAttribute("x2", boost::lexical_cast<std::string>(line.x2())); - element->setAttribute("y2", boost::lexical_cast<std::string>(line.y2())); + element->setAttribute("x1", std::to_string(line.x1())); + element->setAttribute("y1", std::to_string(line.y1())); + element->setAttribute("x2", std::to_string(line.x2())); + element->setAttribute("y2", std::to_string(line.y2())); element->setAttribute("id", line.getID()); element->setAttribute("stroke", line.getColor().toHex()); - element->setAttribute("stroke-width", boost::lexical_cast<std::string>(line.getPenWidth())); + element->setAttribute("stroke-width", std::to_string(line.getPenWidth())); element->setAttribute("opacity", alphaToOpacity(line.getColor().getAlpha())); } catch (boost::bad_lexical_cast&) { } @@ -43,14 +43,14 @@ namespace Swift { element->setAttribute("id", path.getID()); element->setAttribute("stroke", path.getColor().toHex()); try { - element->setAttribute("stroke-width", boost::lexical_cast<std::string>(path.getPenWidth())); + element->setAttribute("stroke-width", std::to_string(path.getPenWidth())); element->setAttribute("opacity", alphaToOpacity(path.getColor().getAlpha())); std::string pathData; if (path.getPoints().size() != 0) { std::vector<std::pair<int, int> >::const_iterator it = path.getPoints().begin(); - pathData = "M"+boost::lexical_cast<std::string>(it->first)+" "+boost::lexical_cast<std::string>(it->second)+"L"; + pathData = "M"+std::to_string(it->first)+" "+std::to_string(it->second)+"L"; for (; it != path.getPoints().end(); ++it) { - pathData += boost::lexical_cast<std::string>(it->first)+" "+boost::lexical_cast<std::string>(it->second)+" "; + pathData += std::to_string(it->first)+" "+std::to_string(it->second)+" "; } } element->setAttribute("d", pathData); @@ -61,14 +61,14 @@ namespace Swift { void WhiteboardElementSerializingVisitor::visit(WhiteboardRectElement& rect) { element = std::make_shared<XMLElement>("rect"); try { - element->setAttribute("x", boost::lexical_cast<std::string>(rect.getX())); - element->setAttribute("y", boost::lexical_cast<std::string>(rect.getY())); - element->setAttribute("width", boost::lexical_cast<std::string>(rect.getWidth())); - element->setAttribute("height", boost::lexical_cast<std::string>(rect.getHeight())); + element->setAttribute("x", std::to_string(rect.getX())); + element->setAttribute("y", std::to_string(rect.getY())); + element->setAttribute("width", std::to_string(rect.getWidth())); + element->setAttribute("height", std::to_string(rect.getHeight())); element->setAttribute("id", rect.getID()); element->setAttribute("stroke", rect.getPenColor().toHex()); - element->setAttribute("fill", rect.getBrushColor().toHex());; - element->setAttribute("stroke-width", boost::lexical_cast<std::string>(rect.getPenWidth())); + element->setAttribute("fill", rect.getBrushColor().toHex()); + element->setAttribute("stroke-width", std::to_string(rect.getPenWidth())); element->setAttribute("opacity", alphaToOpacity(rect.getPenColor().getAlpha())); element->setAttribute("fill-opacity", alphaToOpacity(rect.getBrushColor().getAlpha())); } catch (boost::bad_lexical_cast&) { @@ -80,14 +80,14 @@ namespace Swift { try { element->setAttribute("id", polygon.getID()); element->setAttribute("stroke", polygon.getPenColor().toHex()); - element->setAttribute("fill", polygon.getBrushColor().toHex());; - element->setAttribute("stroke-width", boost::lexical_cast<std::string>(polygon.getPenWidth())); + element->setAttribute("fill", polygon.getBrushColor().toHex()); + element->setAttribute("stroke-width", std::to_string(polygon.getPenWidth())); element->setAttribute("opacity", alphaToOpacity(polygon.getPenColor().getAlpha())); element->setAttribute("fill-opacity", alphaToOpacity(polygon.getBrushColor().getAlpha())); std::string points; std::vector<std::pair<int, int> >::const_iterator it = polygon.getPoints().begin(); for (; it != polygon.getPoints().end(); ++it) { - points += boost::lexical_cast<std::string>(it->first)+","+boost::lexical_cast<std::string>(it->second)+" "; + points += std::to_string(it->first)+","+std::to_string(it->second)+" "; } element->setAttribute("points", points); } catch (boost::bad_lexical_cast&) { @@ -97,9 +97,9 @@ namespace Swift { void WhiteboardElementSerializingVisitor::visit(WhiteboardTextElement& text) { element = std::make_shared<XMLElement>("text"); try { - element->setAttribute("x", boost::lexical_cast<std::string>(text.getX())); - element->setAttribute("y", boost::lexical_cast<std::string>(text.getY())); - element->setAttribute("font-size", boost::lexical_cast<std::string>(text.getSize())); + element->setAttribute("x", std::to_string(text.getX())); + element->setAttribute("y", std::to_string(text.getY())); + element->setAttribute("font-size", std::to_string(text.getSize())); element->setAttribute("id", text.getID()); element->setAttribute("fill", text.getColor().toHex()); element->setAttribute("opacity", alphaToOpacity(text.getColor().getAlpha())); @@ -111,14 +111,14 @@ namespace Swift { void WhiteboardElementSerializingVisitor::visit(WhiteboardEllipseElement& ellipse) { element = std::make_shared<XMLElement>("ellipse"); try { - element->setAttribute("cx", boost::lexical_cast<std::string>(ellipse.getCX())); - element->setAttribute("cy", boost::lexical_cast<std::string>(ellipse.getCY())); - element->setAttribute("rx", boost::lexical_cast<std::string>(ellipse.getRX())); - element->setAttribute("ry", boost::lexical_cast<std::string>(ellipse.getRY())); + element->setAttribute("cx", std::to_string(ellipse.getCX())); + element->setAttribute("cy", std::to_string(ellipse.getCY())); + element->setAttribute("rx", std::to_string(ellipse.getRX())); + element->setAttribute("ry", std::to_string(ellipse.getRY())); element->setAttribute("id", ellipse.getID()); element->setAttribute("stroke", ellipse.getPenColor().toHex()); - element->setAttribute("fill", ellipse.getBrushColor().toHex());; - element->setAttribute("stroke-width", boost::lexical_cast<std::string>(ellipse.getPenWidth())); + element->setAttribute("fill", ellipse.getBrushColor().toHex()); + element->setAttribute("stroke-width", std::to_string(ellipse.getPenWidth())); element->setAttribute("opacity", alphaToOpacity(ellipse.getPenColor().getAlpha())); element->setAttribute("fill-opacity", alphaToOpacity(ellipse.getBrushColor().getAlpha())); } catch (boost::bad_lexical_cast&) { @@ -134,7 +134,7 @@ namespace Swift { if (opacity == 100) { return "1"; } else { - return "."+boost::lexical_cast<std::string>(opacity); + return "."+std::to_string(opacity); } } @@ -148,7 +148,7 @@ namespace Swift { if (insertOp) { try { operationNode->setAttribute("type", "insert"); - operationNode->setAttribute("pos", boost::lexical_cast<std::string>(insertOp->getPos())); + operationNode->setAttribute("pos", std::to_string(insertOp->getPos())); operationNode->setAttribute("id", insertOp->getID()); operationNode->setAttribute("parentid", insertOp->getParentID()); } catch (boost::bad_lexical_cast&) { @@ -160,10 +160,10 @@ namespace Swift { if (updateOp) { try { operationNode->setAttribute("type", "update"); - operationNode->setAttribute("pos", boost::lexical_cast<std::string>(updateOp->getPos())); + operationNode->setAttribute("pos", std::to_string(updateOp->getPos())); operationNode->setAttribute("id", updateOp->getID()); operationNode->setAttribute("parentid", updateOp->getParentID()); - operationNode->setAttribute("newpos", boost::lexical_cast<std::string>(updateOp->getNewPos())); + operationNode->setAttribute("newpos", std::to_string(updateOp->getNewPos())); } catch (boost::bad_lexical_cast&) { } updateOp->getElement()->accept(visitor); @@ -175,7 +175,7 @@ namespace Swift { if (deleteOp) { try { operationNode->setAttribute("type", "delete"); - operationNode->setAttribute("pos", boost::lexical_cast<std::string>(deleteOp->getPos())); + operationNode->setAttribute("pos", std::to_string(deleteOp->getPos())); operationNode->setAttribute("id", deleteOp->getID()); operationNode->setAttribute("parentid", deleteOp->getParentID()); operationNode->setAttribute("elementid", deleteOp->getElementID()); @@ -199,7 +199,7 @@ namespace Swift { case WhiteboardPayload::SessionTerminate: return "session-terminate"; case WhiteboardPayload::UnknownType: - SWIFT_LOG(warning) << "Serializing unknown action value." << std::endl; + SWIFT_LOG(warning) << "Serializing unknown action value."; return ""; } assert(false); diff --git a/Swiften/Serializer/StanzaAckSerializer.h b/Swiften/Serializer/StanzaAckSerializer.h index f5a27dc..228d67b 100644 --- a/Swiften/Serializer/StanzaAckSerializer.h +++ b/Swiften/Serializer/StanzaAckSerializer.h @@ -25,7 +25,7 @@ namespace Swift { StanzaAck::ref stanzaAck(std::dynamic_pointer_cast<StanzaAck>(element)); assert(stanzaAck->isValid()); XMLElement result("a", "urn:xmpp:sm:2"); - result.setAttribute("h", std::string(boost::lexical_cast<std::string>(stanzaAck->getHandledStanzasCount()))); + result.setAttribute("h", std::string(std::to_string(stanzaAck->getHandledStanzasCount()))); return createSafeByteArray(result.serialize()); } }; diff --git a/Swiften/Serializer/StanzaSerializer.cpp b/Swiften/Serializer/StanzaSerializer.cpp index 3de706d..d4231c5 100644 --- a/Swiften/Serializer/StanzaSerializer.cpp +++ b/Swiften/Serializer/StanzaSerializer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -53,7 +53,7 @@ SafeByteArray StanzaSerializer::serialize(std::shared_ptr<ToplevelElement> eleme serializedPayloads += serializer->serialize(payload); } else { - SWIFT_LOG(warning) << "Could not find serializer for " << typeid(*(payload.get())).name() << std::endl; + SWIFT_LOG(warning) << "Could not find serializer for " << typeid(*(payload.get())).name(); } } serializedPayloads = String::sanitizeXMPPString(serializedPayloads); diff --git a/Swiften/Serializer/StreamErrorSerializer.cpp b/Swiften/Serializer/StreamErrorSerializer.cpp index 66a71ca..684e8fe 100644 --- a/Swiften/Serializer/StreamErrorSerializer.cpp +++ b/Swiften/Serializer/StreamErrorSerializer.cpp @@ -30,7 +30,6 @@ SafeByteArray StreamErrorSerializer::serialize(std::shared_ptr<ToplevelElement> case StreamError::ImproperAddressing: typeTag = "improper-addressing"; break; case StreamError::InternalServerError: typeTag = "internal-server-error"; break; case StreamError::InvalidFrom: typeTag = "invalid-from"; break; - case StreamError::InvalidID: typeTag = "invalid-id"; break; case StreamError::InvalidNamespace: typeTag = "invalid-namespace"; break; case StreamError::InvalidXML: typeTag = "invalid-xml"; break; case StreamError::NotAuthorized: typeTag = "not-authorized"; break; @@ -44,6 +43,7 @@ SafeByteArray StreamErrorSerializer::serialize(std::shared_ptr<ToplevelElement> case StreamError::SystemShutdown: typeTag = "system-shutdown"; break; case StreamError::UndefinedCondition: typeTag = "undefined-condition"; break; case StreamError::UnsupportedEncoding: typeTag = "unsupported-encoding"; break; + case StreamError::UnsupportedFeature: typeTag = "unsupported-feature"; break; case StreamError::UnsupportedStanzaType: typeTag = "unsupported-stanza-type"; break; case StreamError::UnsupportedVersion: typeTag = "unsupported-version"; break; } diff --git a/Swiften/Serializer/StreamResumeSerializer.cpp b/Swiften/Serializer/StreamResumeSerializer.cpp index 619ac9c..e4a40c9 100644 --- a/Swiften/Serializer/StreamResumeSerializer.cpp +++ b/Swiften/Serializer/StreamResumeSerializer.cpp @@ -23,7 +23,7 @@ SafeByteArray StreamResumeSerializer::serialize(std::shared_ptr<ToplevelElement> XMLElement element("resume", "urn:xmpp:sm:2"); element.setAttribute("previd", e->getResumeID()); if (e->getHandledStanzasCount()) { - element.setAttribute("h", boost::lexical_cast<std::string>(e->getHandledStanzasCount().get())); + element.setAttribute("h", std::to_string(e->getHandledStanzasCount().get())); } return createSafeByteArray(element.serialize()); } diff --git a/Swiften/Serializer/StreamResumedSerializer.cpp b/Swiften/Serializer/StreamResumedSerializer.cpp index 5b88ded..2398335 100644 --- a/Swiften/Serializer/StreamResumedSerializer.cpp +++ b/Swiften/Serializer/StreamResumedSerializer.cpp @@ -23,7 +23,7 @@ SafeByteArray StreamResumedSerializer::serialize(std::shared_ptr<ToplevelElement XMLElement element("resumed", "urn:xmpp:sm:2"); element.setAttribute("previd", e->getResumeID()); if (e->getHandledStanzasCount()) { - element.setAttribute("h", boost::lexical_cast<std::string>(e->getHandledStanzasCount().get())); + element.setAttribute("h", std::to_string(e->getHandledStanzasCount().get())); } return createSafeByteArray(element.serialize()); } diff --git a/Swiften/Serializer/XML/UnitTest/XMLElementTest.cpp b/Swiften/Serializer/XML/UnitTest/XMLElementTest.cpp index ed3f8ab..ce6d7fa 100644 --- a/Swiften/Serializer/XML/UnitTest/XMLElementTest.cpp +++ b/Swiften/Serializer/XML/UnitTest/XMLElementTest.cpp @@ -65,6 +65,13 @@ class XMLElementTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(std::string("<foo myatt=\"\"/>"), testling.serialize()); } + + void testEscape_SpecialAttributeCharacters() { + auto testling = XMLElement::escapeAttributeValue(R"(<"'&>not escaped.)"); + + CPPUNIT_ASSERT_EQUAL(std::string("<"'&>not escaped."), testling); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(XMLElementTest); diff --git a/Swiften/Serializer/XML/XMLElement.cpp b/Swiften/Serializer/XML/XMLElement.cpp index f2397ca..7515061 100644 --- a/Swiften/Serializer/XML/XMLElement.cpp +++ b/Swiften/Serializer/XML/XMLElement.cpp @@ -39,14 +39,17 @@ std::string XMLElement::serialize() { return result; } +std::string XMLElement::escapeAttributeValue(std::string value) { + String::replaceAll(value, '&', "&"); + String::replaceAll(value, '<', "<"); + String::replaceAll(value, '>', ">"); + String::replaceAll(value, '\'', "'"); + String::replaceAll(value, '"', """); + return value; +} + void XMLElement::setAttribute(const std::string& attribute, const std::string& value) { - std::string escapedValue(value); - String::replaceAll(escapedValue, '&', "&"); - String::replaceAll(escapedValue, '<', "<"); - String::replaceAll(escapedValue, '>', ">"); - String::replaceAll(escapedValue, '\'', "'"); - String::replaceAll(escapedValue, '"', """); - attributes_[attribute] = escapedValue; + attributes_[attribute] = escapeAttributeValue(value); } void XMLElement::addNode(std::shared_ptr<XMLNode> node) { diff --git a/Swiften/Serializer/XML/XMLElement.h b/Swiften/Serializer/XML/XMLElement.h index 54de041..db74626 100644 --- a/Swiften/Serializer/XML/XMLElement.h +++ b/Swiften/Serializer/XML/XMLElement.h @@ -21,6 +21,7 @@ namespace Swift { XMLElement(const std::string& tag, const std::string& xmlns = "", const std::string& text = ""); + static std::string escapeAttributeValue(std::string value); void setAttribute(const std::string& attribute, const std::string& value); void addNode(std::shared_ptr<XMLNode> node); diff --git a/Swiften/Serializer/XMPPSerializer.cpp b/Swiften/Serializer/XMPPSerializer.cpp index 9cde777..7a003fb 100644 --- a/Swiften/Serializer/XMPPSerializer.cpp +++ b/Swiften/Serializer/XMPPSerializer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -89,7 +89,7 @@ SafeByteArray XMPPSerializer::serializeElement(std::shared_ptr<ToplevelElement> return (*i)->serialize(element); } else { - SWIFT_LOG(warning) << "Could not find serializer for " << typeid(*(element.get())).name() << std::endl; + SWIFT_LOG(warning) << "Could not find serializer for " << typeid(*(element.get())).name(); return createSafeByteArray(""); } } diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp index 10c6ad0..c44961d 100644 --- a/Swiften/Session/BasicSessionStream.cpp +++ b/Swiften/Session/BasicSessionStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -34,11 +34,8 @@ BasicSessionStream::BasicSessionStream( connection(connection), tlsContextFactory(tlsContextFactory), timerFactory(timerFactory), - compressionLayer(nullptr), - tlsLayer(nullptr), - whitespacePingLayer(nullptr), tlsOptions_(tlsOptions) { - xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, streamType); + auto xmppLayer = std::make_unique<XMPPLayer>(payloadParserFactories, payloadSerializers, xmlParserFactory, streamType); xmppLayer->onStreamStart.connect(boost::bind(&BasicSessionStream::handleStreamStartReceived, this, _1)); xmppLayer->onStreamEnd.connect(boost::bind(&BasicSessionStream::handleStreamEndReceived, this)); xmppLayer->onElement.connect(boost::bind(&BasicSessionStream::handleElementReceived, this, _1)); @@ -47,53 +44,50 @@ BasicSessionStream::BasicSessionStream( xmppLayer->onWriteData.connect(boost::bind(&BasicSessionStream::handleDataWritten, this, _1)); connection->onDisconnected.connect(boost::bind(&BasicSessionStream::handleConnectionFinished, this, _1)); - connectionLayer = new ConnectionLayer(connection); - - streamStack = new StreamStack(xmppLayer, connectionLayer); + streamStack = std::make_unique<StreamStack>(std::move(xmppLayer), std::unique_ptr<ConnectionLayer>(new ConnectionLayer(connection))); available = true; } BasicSessionStream::~BasicSessionStream() { - delete compressionLayer; - if (tlsLayer) { + if (auto tlsLayer = streamStack->getLayer<TLSLayer>()) { tlsLayer->onError.disconnect(boost::bind(&BasicSessionStream::handleTLSError, this, _1)); tlsLayer->onConnected.disconnect(boost::bind(&BasicSessionStream::handleTLSConnected, this)); - delete tlsLayer; } - delete whitespacePingLayer; - delete streamStack; connection->onDisconnected.disconnect(boost::bind(&BasicSessionStream::handleConnectionFinished, this, _1)); - delete connectionLayer; + auto xmppLayer = streamStack->getLayer<XMPPLayer>(); xmppLayer->onStreamStart.disconnect(boost::bind(&BasicSessionStream::handleStreamStartReceived, this, _1)); xmppLayer->onStreamEnd.disconnect(boost::bind(&BasicSessionStream::handleStreamEndReceived, this)); xmppLayer->onElement.disconnect(boost::bind(&BasicSessionStream::handleElementReceived, this, _1)); xmppLayer->onError.disconnect(boost::bind(&BasicSessionStream::handleXMPPError, this)); xmppLayer->onDataRead.disconnect(boost::bind(&BasicSessionStream::handleDataRead, this, _1)); xmppLayer->onWriteData.disconnect(boost::bind(&BasicSessionStream::handleDataWritten, this, _1)); - delete xmppLayer; } void BasicSessionStream::writeHeader(const ProtocolHeader& header) { assert(available); + auto* xmppLayer = streamStack->getLayer<XMPPLayer>(); xmppLayer->writeHeader(header); } void BasicSessionStream::writeElement(std::shared_ptr<ToplevelElement> element) { assert(available); + auto* xmppLayer = streamStack->getLayer<XMPPLayer>(); xmppLayer->writeElement(element); } void BasicSessionStream::writeFooter() { assert(available); + auto* xmppLayer = streamStack->getLayer<XMPPLayer>(); xmppLayer->writeFooter(); } void BasicSessionStream::writeData(const std::string& data) { assert(available); + auto* xmppLayer = streamStack->getLayer<XMPPLayer>(); xmppLayer->writeData(data); } @@ -111,12 +105,14 @@ bool BasicSessionStream::supportsTLSEncryption() { void BasicSessionStream::addTLSEncryption() { assert(available); - tlsLayer = new TLSLayer(tlsContextFactory, tlsOptions_); + auto tlsContext = tlsContextFactory->createTLSContext(tlsOptions_); + auto tlsLayer = std::make_unique<TLSLayer>(std::move(tlsContext)); if (hasTLSCertificate() && !tlsLayer->setClientCertificate(getTLSCertificate())) { onClosed(std::make_shared<SessionStreamError>(SessionStreamError::InvalidTLSCertificateError)); } else { - streamStack->addLayer(tlsLayer); + streamStack->addLayer(std::move(tlsLayer)); + auto tlsLayer = streamStack->getLayer<TLSLayer>(); tlsLayer->onError.connect(boost::bind(&BasicSessionStream::handleTLSError, this, _1)); tlsLayer->onConnected.connect(boost::bind(&BasicSessionStream::handleTLSConnected, this)); tlsLayer->connect(); @@ -124,23 +120,23 @@ void BasicSessionStream::addTLSEncryption() { } bool BasicSessionStream::isTLSEncrypted() { - return tlsLayer; + return streamStack->getLayer<TLSLayer>(); } Certificate::ref BasicSessionStream::getPeerCertificate() const { - return tlsLayer->getPeerCertificate(); + return streamStack->getLayer<TLSLayer>()->getPeerCertificate(); } std::vector<Certificate::ref> BasicSessionStream::getPeerCertificateChain() const { - return tlsLayer->getPeerCertificateChain(); + return streamStack->getLayer<TLSLayer>()->getPeerCertificateChain(); } std::shared_ptr<CertificateVerificationError> BasicSessionStream::getPeerCertificateVerificationError() const { - return tlsLayer->getPeerCertificateVerificationError(); + return streamStack->getLayer<TLSLayer>()->getPeerCertificateVerificationError(); } ByteArray BasicSessionStream::getTLSFinishMessage() const { - return tlsLayer->getContext()->getFinishMessage(); + return streamStack->getLayer<TLSLayer>()->getContext()->getFinishMessage(); } bool BasicSessionStream::supportsZLibCompression() { @@ -148,15 +144,15 @@ bool BasicSessionStream::supportsZLibCompression() { } void BasicSessionStream::addZLibCompression() { - compressionLayer = new CompressionLayer(); - streamStack->addLayer(compressionLayer); + streamStack->addLayer(std::make_unique<CompressionLayer>()); } void BasicSessionStream::setWhitespacePingEnabled(bool enabled) { + auto whitespacePingLayer = streamStack->getLayer<WhitespacePingLayer>(); if (enabled) { if (!whitespacePingLayer) { - whitespacePingLayer = new WhitespacePingLayer(timerFactory); - streamStack->addLayer(whitespacePingLayer); + streamStack->addLayer(std::make_unique<WhitespacePingLayer>(timerFactory)); + whitespacePingLayer = streamStack->getLayer<WhitespacePingLayer>(); } whitespacePingLayer->setActive(); } @@ -166,6 +162,7 @@ void BasicSessionStream::setWhitespacePingEnabled(bool enabled) { } void BasicSessionStream::resetXMPPParser() { + auto* xmppLayer = streamStack->getLayer<XMPPLayer>(); xmppLayer->resetParser(); } diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h index 48b3d63..30a7e3b 100644 --- a/Swiften/Session/BasicSessionStream.h +++ b/Swiften/Session/BasicSessionStream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -83,12 +83,7 @@ namespace Swift { std::shared_ptr<Connection> connection; TLSContextFactory* tlsContextFactory; TimerFactory* timerFactory; - XMPPLayer* xmppLayer; - ConnectionLayer* connectionLayer; - CompressionLayer* compressionLayer; - TLSLayer* tlsLayer; - WhitespacePingLayer* whitespacePingLayer; - StreamStack* streamStack; + std::unique_ptr<StreamStack> streamStack; TLSOptions tlsOptions_; }; diff --git a/Swiften/Session/Session.cpp b/Swiften/Session/Session.cpp index ebdb5d1..b1525b8 100644 --- a/Swiften/Session/Session.cpp +++ b/Swiften/Session/Session.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -22,16 +22,10 @@ Session::Session( payloadParserFactories(payloadParserFactories), payloadSerializers(payloadSerializers), xmlParserFactory(xmlParserFactory), - xmppLayer(nullptr), - connectionLayer(nullptr), - streamStack(nullptr), finishing(false) { } Session::~Session() { - delete streamStack; - delete connectionLayer; - delete xmppLayer; } void Session::startSession() { @@ -44,7 +38,7 @@ void Session::finishSession() { return; } finishing = true; - if (xmppLayer) { + if (auto xmppLayer = getXMPPLayer()) { xmppLayer->writeFooter(); } connection->disconnect(); @@ -55,14 +49,14 @@ void Session::finishSession(const SessionError& /*error*/) { return; } finishing = true; - if (xmppLayer) { + if (auto xmppLayer = getXMPPLayer()) { xmppLayer->writeFooter(); } connection->disconnect(); } void Session::initializeStreamStack() { - xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, ClientStreamType); + auto xmppLayer = std::unique_ptr<XMPPLayer>(new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, ClientStreamType)); xmppLayer->onStreamStart.connect( boost::bind(&Session::handleStreamStart, this, _1)); xmppLayer->onElement.connect(boost::bind(&Session::handleElement, this, _1)); @@ -72,12 +66,20 @@ void Session::initializeStreamStack() { xmppLayer->onWriteData.connect(boost::bind(boost::ref(onDataWritten), _1)); connection->onDisconnected.connect( boost::bind(&Session::handleDisconnected, this, _1)); - connectionLayer = new ConnectionLayer(connection); - streamStack = new StreamStack(xmppLayer, connectionLayer); + streamStack = std::unique_ptr<StreamStack>(new StreamStack(std::move(xmppLayer), std::unique_ptr<ConnectionLayer>(new ConnectionLayer(connection)))); } +XMPPLayer* Session::getXMPPLayer() const { + return dynamic_cast<XMPPLayer*>(streamStack->getTopLayer()); +} + +StreamStack* Session::getStreamStack() const { + return streamStack.get(); +} + + void Session::sendElement(std::shared_ptr<ToplevelElement> stanza) { - xmppLayer->writeElement(stanza); + getXMPPLayer()->writeElement(stanza); } void Session::handleDisconnected(const boost::optional<Connection::Error>& connectionError) { diff --git a/Swiften/Session/Session.h b/Swiften/Session/Session.h index 04153ec..e6a0d53 100644 --- a/Swiften/Session/Session.h +++ b/Swiften/Session/Session.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -85,13 +85,8 @@ namespace Swift { void initializeStreamStack(); - XMPPLayer* getXMPPLayer() const { - return xmppLayer; - } - - StreamStack* getStreamStack() const { - return streamStack; - } + XMPPLayer* getXMPPLayer() const; + StreamStack* getStreamStack() const; void setFinished(); @@ -105,9 +100,8 @@ namespace Swift { PayloadParserFactoryCollection* payloadParserFactories; PayloadSerializerCollection* payloadSerializers; XMLParserFactory* xmlParserFactory; - XMPPLayer* xmppLayer; - ConnectionLayer* connectionLayer; - StreamStack* streamStack; + + std::unique_ptr<StreamStack> streamStack; bool finishing; }; } diff --git a/Swiften/StreamManagement/StanzaAckRequester.cpp b/Swiften/StreamManagement/StanzaAckRequester.cpp index 8941f4a..c71803a 100644 --- a/Swiften/StreamManagement/StanzaAckRequester.cpp +++ b/Swiften/StreamManagement/StanzaAckRequester.cpp @@ -1,19 +1,17 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/StreamManagement/StanzaAckRequester.h> -#include <boost/numeric/conversion/cast.hpp> - #include <Swiften/Base/Log.h> #include <Swiften/Elements/Message.h> namespace Swift { -static const unsigned int MAX_HANDLED_STANZA_COUNT = boost::numeric_cast<unsigned int>((1ULL<<32) - 1); +static const unsigned int MAX_HANDLED_STANZA_COUNT = static_cast<unsigned int>((1ULL<<32) - 1); StanzaAckRequester::StanzaAckRequester() : lastHandledStanzasCount(0) { @@ -30,7 +28,7 @@ void StanzaAckRequester::handleAckReceived(unsigned int handledStanzasCount) { unsigned int i = lastHandledStanzasCount; while (i != handledStanzasCount) { if (unackedStanzas.empty()) { - SWIFT_LOG(warning) << "Server acked more stanzas than we sent" << std::endl; + SWIFT_LOG(warning) << "Server acked more stanzas than we sent"; break; } std::shared_ptr<Stanza> ackedStanza = unackedStanzas.front(); diff --git a/Swiften/StreamManagement/StanzaAckResponder.cpp b/Swiften/StreamManagement/StanzaAckResponder.cpp index b6171d0..bfe6f4d 100644 --- a/Swiften/StreamManagement/StanzaAckResponder.cpp +++ b/Swiften/StreamManagement/StanzaAckResponder.cpp @@ -1,16 +1,14 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/StreamManagement/StanzaAckResponder.h> -#include <boost/numeric/conversion/cast.hpp> - namespace Swift { -static const unsigned int MAX_HANDLED_STANZA_COUNT = boost::numeric_cast<unsigned int>((1ULL<<32) - 1); +static const unsigned int MAX_HANDLED_STANZA_COUNT = static_cast<unsigned int>((1ULL << 32) - 1); StanzaAckResponder::StanzaAckResponder() : handledStanzasCount(0) { } diff --git a/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp b/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp index ce16e1f..e0ebefd 100644 --- a/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp +++ b/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp @@ -1,11 +1,12 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ +#include <cstdint> + #include <boost/bind.hpp> -#include <boost/numeric/conversion/cast.hpp> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -111,7 +112,7 @@ class StanzaAckRequesterTest : public CppUnit::TestFixture { // Handle stanza ack count wrapping, as per the XEP void testHandleAckReceived_WrapAround() { std::shared_ptr<StanzaAckRequester> testling(createRequester()); - testling->lastHandledStanzasCount = boost::numeric_cast<unsigned int>((1ULL<<32) - 1); + testling->lastHandledStanzasCount = UINT32_MAX; testling->handleStanzaSent(createMessage("m1")); testling->handleStanzaSent(createMessage("m2")); diff --git a/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp b/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp index ffdabe9..ee4b913 100644 --- a/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp +++ b/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp @@ -1,11 +1,12 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ +#include <cstdint> + #include <boost/bind.hpp> -#include <boost/numeric/conversion/cast.hpp> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -63,7 +64,7 @@ class StanzaAckResponderTest : public CppUnit::TestFixture { // Handle stanza ack count wrapping, as per the XEP void testHandleAckRequestReceived_WrapAround() { std::shared_ptr<StanzaAckResponder> testling(createResponder()); - testling->handledStanzasCount = boost::numeric_cast<unsigned int>((1ULL<<32) - 1); + testling->handledStanzasCount = UINT32_MAX; testling->handleStanzaReceived(); testling->handleStanzaReceived(); diff --git a/Swiften/StreamStack/StreamStack.cpp b/Swiften/StreamStack/StreamStack.cpp index 44a018d..cf80fb1 100644 --- a/Swiften/StreamStack/StreamStack.cpp +++ b/Swiften/StreamStack/StreamStack.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,30 +8,30 @@ #include <boost/bind.hpp> +#include <Swiften/StreamStack/HighLayer.h> #include <Swiften/StreamStack/LowLayer.h> #include <Swiften/StreamStack/StreamLayer.h> -#include <Swiften/StreamStack/XMPPLayer.h> namespace Swift { -StreamStack::StreamStack(XMPPLayer* xmppLayer, LowLayer* physicalLayer) : xmppLayer_(xmppLayer), physicalLayer_(physicalLayer) { - physicalLayer_->setParentLayer(xmppLayer_); - xmppLayer_->setChildLayer(physicalLayer_); +StreamStack::StreamStack(std::unique_ptr<HighLayer> topLayer, std::unique_ptr<LowLayer> bottomLayer) : topLayer_(std::move(topLayer)), bottomLayer_(std::move(bottomLayer)) { + bottomLayer_->setParentLayer(topLayer_.get()); + topLayer_->setChildLayer(bottomLayer_.get()); } StreamStack::~StreamStack() { } -void StreamStack::addLayer(StreamLayer* newLayer) { - LowLayer* lowLayer = layers_.empty() ? physicalLayer_ : *layers_.rbegin(); +void StreamStack::addLayer(std::unique_ptr<StreamLayer> streamLayer) { + auto* lowLayer = layers_.empty() ? bottomLayer_.get() : layers_.rbegin()->get(); - xmppLayer_->setChildLayer(newLayer); - newLayer->setParentLayer(xmppLayer_); + topLayer_->setChildLayer(streamLayer.get()); + streamLayer->setParentLayer(topLayer_.get()); - lowLayer->setParentLayer(newLayer); - newLayer->setChildLayer(lowLayer); + lowLayer->setParentLayer(streamLayer.get()); + streamLayer->setChildLayer(lowLayer); - layers_.push_back(newLayer); + layers_.emplace_back(std::move(streamLayer)); } } diff --git a/Swiften/StreamStack/StreamStack.h b/Swiften/StreamStack/StreamStack.h index b12a69f..263b1f5 100644 --- a/Swiften/StreamStack/StreamStack.h +++ b/Swiften/StreamStack/StreamStack.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -15,34 +15,40 @@ #include <Swiften/Elements/Stanza.h> namespace Swift { - class XMPPLayer; + class HighLayer; class LowLayer; class StreamLayer; class SWIFTEN_API StreamStack { public: - StreamStack(XMPPLayer* xmppLayer, LowLayer* physicalLayer); + StreamStack(std::unique_ptr<HighLayer> topLayer, std::unique_ptr<LowLayer> bottomLayer); ~StreamStack(); - void addLayer(StreamLayer*); + void addLayer(std::unique_ptr<StreamLayer> /* streamLayer */); - XMPPLayer* getXMPPLayer() const { - return xmppLayer_; + HighLayer* getTopLayer() const { + return topLayer_.get(); } - template<typename T> T* getLayer() { - for (auto& i : layers_) { - T* layer = dynamic_cast<T*>(i); + template<typename T> T* getLayer() const { + for (const auto& i : layers_) { + T* layer = dynamic_cast<T*>(i.get()); if (layer) { return layer; } } + if (T* layer = dynamic_cast<T*>(topLayer_.get())) { + return layer; + } + if (T* layer = dynamic_cast<T*>(bottomLayer_.get())) { + return layer; + } return nullptr; } private: - XMPPLayer* xmppLayer_; - LowLayer* physicalLayer_; - std::vector<StreamLayer*> layers_; + std::unique_ptr<HighLayer> topLayer_; + std::unique_ptr<LowLayer> bottomLayer_; + std::vector<std::unique_ptr<StreamLayer>> layers_; }; } diff --git a/Swiften/StreamStack/TLSLayer.cpp b/Swiften/StreamStack/TLSLayer.cpp index ced879e..9f84889 100644 --- a/Swiften/StreamStack/TLSLayer.cpp +++ b/Swiften/StreamStack/TLSLayer.cpp @@ -1,11 +1,13 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/StreamStack/TLSLayer.h> +#include <memory> + #include <boost/bind.hpp> #include <Swiften/TLS/TLSContext.h> @@ -13,44 +15,42 @@ namespace Swift { -TLSLayer::TLSLayer(TLSContextFactory* factory, const TLSOptions& tlsOptions) { - context = factory->createTLSContext(tlsOptions); - context->onDataForNetwork.connect(boost::bind(&TLSLayer::writeDataToChildLayer, this, _1)); - context->onDataForApplication.connect(boost::bind(&TLSLayer::writeDataToParentLayer, this, _1)); - context->onConnected.connect(onConnected); - context->onError.connect(onError); +TLSLayer::TLSLayer(std::unique_ptr<TLSContext> tlsContext) : context_(std::move(tlsContext)) { + context_->onDataForNetwork.connect(boost::bind(&TLSLayer::writeDataToChildLayer, this, _1)); + context_->onDataForApplication.connect(boost::bind(&TLSLayer::writeDataToParentLayer, this, _1)); + context_->onConnected.connect(onConnected); + context_->onError.connect(onError); } TLSLayer::~TLSLayer() { - delete context; } void TLSLayer::connect() { - context->connect(); + context_->connect(); } void TLSLayer::writeData(const SafeByteArray& data) { - context->handleDataFromApplication(data); + context_->handleDataFromApplication(data); } void TLSLayer::handleDataRead(const SafeByteArray& data) { - context->handleDataFromNetwork(data); + context_->handleDataFromNetwork(data); } bool TLSLayer::setClientCertificate(CertificateWithKey::ref certificate) { - return context->setClientCertificate(certificate); + return context_->setClientCertificate(certificate); } Certificate::ref TLSLayer::getPeerCertificate() const { - return context->getPeerCertificate(); + return context_->getPeerCertificate(); } std::vector<Certificate::ref> TLSLayer::getPeerCertificateChain() const { - return context->getPeerCertificateChain(); + return context_->getPeerCertificateChain(); } std::shared_ptr<CertificateVerificationError> TLSLayer::getPeerCertificateVerificationError() const { - return context->getPeerCertificateVerificationError(); + return context_->getPeerCertificateVerificationError(); } } diff --git a/Swiften/StreamStack/TLSLayer.h b/Swiften/StreamStack/TLSLayer.h index 415a3f0..89588e3 100644 --- a/Swiften/StreamStack/TLSLayer.h +++ b/Swiften/StreamStack/TLSLayer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,7 +23,7 @@ namespace Swift { class SWIFTEN_API TLSLayer : public StreamLayer { public: - TLSLayer(TLSContextFactory*, const TLSOptions&); + TLSLayer(std::unique_ptr<TLSContext> tlsContext); virtual ~TLSLayer(); void connect(); @@ -37,7 +37,7 @@ namespace Swift { void handleDataRead(const SafeByteArray& data); TLSContext* getContext() const { - return context; + return context_.get(); } public: @@ -45,6 +45,6 @@ namespace Swift { boost::signals2::signal<void ()> onConnected; private: - TLSContext* context; + std::unique_ptr<TLSContext> context_; }; } diff --git a/Swiften/StreamStack/UnitTest/StreamStackTest.cpp b/Swiften/StreamStack/UnitTest/StreamStackTest.cpp index f0f82c9..b074736 100644 --- a/Swiften/StreamStack/UnitTest/StreamStackTest.cpp +++ b/Swiften/StreamStack/UnitTest/StreamStackTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -39,19 +39,17 @@ class StreamStackTest : public CppUnit::TestFixture { public: void setUp() { - physicalStream_ = new TestLowLayer(); - xmppStream_ = new XMPPLayer(&parserFactories_, &serializers_, &xmlParserFactory_, ClientStreamType); + testling_ = std::make_unique<StreamStack>(std::make_unique<XMPPLayer>(&parserFactories_, &serializers_, &xmlParserFactory_, ClientStreamType), std::make_unique<TestLowLayer>()); + physicalStream_ = testling_->getLayer<TestLowLayer>(); + xmppStream_ = testling_->getLayer<XMPPLayer>(); elementsReceived_ = 0; dataWriteReceived_ = 0; } void tearDown() { - delete physicalStream_; - delete xmppStream_; } void testWriteData_NoIntermediateStreamStack() { - StreamStack testling(xmppStream_, physicalStream_); xmppStream_->writeData("foo"); @@ -60,9 +58,8 @@ class StreamStackTest : public CppUnit::TestFixture { } void testWriteData_OneIntermediateStream() { - StreamStack testling(xmppStream_, physicalStream_); - std::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); - testling.addLayer(xStream.get()); + std::unique_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); + testling_->addLayer(std::move(xStream)); xmppStream_->writeData("foo"); @@ -71,11 +68,10 @@ class StreamStackTest : public CppUnit::TestFixture { } void testWriteData_TwoIntermediateStreamStack() { - StreamStack testling(xmppStream_, physicalStream_); - std::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); - std::shared_ptr<MyStreamLayer> yStream(new MyStreamLayer("Y")); - testling.addLayer(xStream.get()); - testling.addLayer(yStream.get()); + std::unique_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); + std::unique_ptr<MyStreamLayer> yStream(new MyStreamLayer("Y")); + testling_->addLayer(std::move(xStream)); + testling_->addLayer(std::move(yStream)); xmppStream_->writeData("foo"); @@ -84,7 +80,6 @@ class StreamStackTest : public CppUnit::TestFixture { } void testReadData_NoIntermediateStreamStack() { - StreamStack testling(xmppStream_, physicalStream_); xmppStream_->onElement.connect(boost::bind(&StreamStackTest::handleElement, this, _1)); physicalStream_->onDataRead(createSafeByteArray("<stream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); @@ -93,10 +88,9 @@ class StreamStackTest : public CppUnit::TestFixture { } void testReadData_OneIntermediateStream() { - StreamStack testling(xmppStream_, physicalStream_); xmppStream_->onElement.connect(boost::bind(&StreamStackTest::handleElement, this, _1)); - std::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("<")); - testling.addLayer(xStream.get()); + std::unique_ptr<MyStreamLayer> xStream(new MyStreamLayer("<")); + testling_->addLayer(std::move(xStream)); physicalStream_->onDataRead(createSafeByteArray("stream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); @@ -104,12 +98,11 @@ class StreamStackTest : public CppUnit::TestFixture { } void testReadData_TwoIntermediateStreamStack() { - StreamStack testling(xmppStream_, physicalStream_); xmppStream_->onElement.connect(boost::bind(&StreamStackTest::handleElement, this, _1)); - std::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("s")); - std::shared_ptr<MyStreamLayer> yStream(new MyStreamLayer("<")); - testling.addLayer(xStream.get()); - testling.addLayer(yStream.get()); + std::unique_ptr<MyStreamLayer> xStream(new MyStreamLayer("s")); + std::unique_ptr<MyStreamLayer> yStream(new MyStreamLayer("<")); + testling_->addLayer(std::move(xStream)); + testling_->addLayer(std::move(yStream)); physicalStream_->onDataRead(createSafeByteArray("tream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); @@ -117,10 +110,9 @@ class StreamStackTest : public CppUnit::TestFixture { } void testAddLayer_ExistingOnWriteDataSlot() { - StreamStack testling(xmppStream_, physicalStream_); xmppStream_->onWriteData.connect(boost::bind(&StreamStackTest::handleWriteData, this, _1)); - std::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); - testling.addLayer(xStream.get()); + std::unique_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); + testling_->addLayer(std::move(xStream)); xmppStream_->writeData("foo"); @@ -176,6 +168,7 @@ class StreamStackTest : public CppUnit::TestFixture { TestLowLayer* physicalStream_; PlatformXMLParserFactory xmlParserFactory_; XMPPLayer* xmppStream_; + std::unique_ptr<StreamStack> testling_; int elementsReceived_; int dataWriteReceived_; }; diff --git a/Swiften/StreamStack/WhitespacePingLayer.cpp b/Swiften/StreamStack/WhitespacePingLayer.cpp index 9a473f3..7c8301e 100644 --- a/Swiften/StreamStack/WhitespacePingLayer.cpp +++ b/Swiften/StreamStack/WhitespacePingLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -22,7 +22,7 @@ WhitespacePingLayer::WhitespacePingLayer(TimerFactory* timerFactory) : isActive( } WhitespacePingLayer::~WhitespacePingLayer() { - SWIFT_LOG_ASSERT(!isActive, debug) << "WhitespacePingLayer still active at destruction." << std::endl; + SWIFT_LOG_ASSERT(!isActive, debug) << "WhitespacePingLayer still active at destruction."; if (isActive) { timer->stop(); } diff --git a/Swiften/TLS/CAPICertificate.cpp b/Swiften/TLS/CAPICertificate.cpp index a46b9f6..526b535 100644 --- a/Swiften/TLS/CAPICertificate.cpp +++ b/Swiften/TLS/CAPICertificate.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -14,6 +14,7 @@ #include <Swiften/Base/Log.h> #include <Swiften/Network/TimerFactory.h> #include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/TLS/Schannel/SchannelUtil.h> // Size of the SHA1 hash #define SHA1_HASH_LEN 20 @@ -21,7 +22,7 @@ #define DEBUG_SCARD_STATUS(function, status) \ { \ std::shared_ptr<boost::system::error_code> errorCode = std::make_shared<boost::system::error_code>(status, boost::system::system_category()); \ - SWIFT_LOG(debug) << std::hex << function << ": status: 0x" << status << ": " << errorCode->message() << std::endl; \ + SWIFT_LOG(debug) << std::hex << function << ": status: 0x" << status << ": " << errorCode->message(); \ } namespace Swift { @@ -43,6 +44,7 @@ CAPICertificate::CAPICertificate(const std::string& capiUri, TimerFactory* timer } CAPICertificate::~CAPICertificate() { + SWIFT_LOG(debug) << "Destroying the CAPICertificate"; if (smartCardTimer_) { smartCardTimer_->stop(); smartCardTimer_->onTick.disconnect(boost::bind(&CAPICertificate::handleSmartCardTimerTick, this)); @@ -50,7 +52,9 @@ CAPICertificate::~CAPICertificate() { } if (certStoreHandle_) { - CertCloseStore(certStoreHandle_, 0); + if (CertCloseStore(certStoreHandle_, 0) == FALSE) { + SWIFT_LOG(debug) << "Failed to close the certificate store handle"; + } } if (cardHandle_) { @@ -80,7 +84,7 @@ const std::string& CAPICertificate::getSmartCardReaderName() const { return smartCardReaderName_; } -PCCERT_CONTEXT findCertificateInStore (HCERTSTORE certStoreHandle, const std::string &certName) { +PCCERT_CONTEXT findCertificateInStore(HCERTSTORE certStoreHandle, const std::string &certName) { if (!boost::iequals(certName.substr(0, 5), "sha1:")) { // Find client certificate. Note that this sample just searches for a @@ -105,8 +109,7 @@ PCCERT_CONTEXT findCertificateInStore (HCERTSTORE certStoreHandle, const std::st } - -void CAPICertificate::setUri (const std::string& capiUri) { +void CAPICertificate::setUri(const std::string& capiUri) { valid_ = false; /* Syntax: "certstore:" <cert_store> ":" <hash> ":" <hash_of_cert> */ @@ -118,7 +121,7 @@ void CAPICertificate::setUri (const std::string& capiUri) { /* Substring of subject: uses "storename" */ std::string capiIdentity = capiUri.substr(10); std::string newCertStoreName; - size_t pos = capiIdentity.find_first_of (':'); + size_t pos = capiIdentity.find_first_of(':'); if (pos == std::string::npos) { /* Using the default certificate store */ @@ -146,49 +149,38 @@ void CAPICertificate::setUri (const std::string& capiUri) { certStore_ = newCertStoreName; - PCCERT_CONTEXT certContext = findCertificateInStore (certStoreHandle_, certName_); - + ScopedCertContext certContext(findCertificateInStore(certStoreHandle_, certName_)); if (!certContext) { return; } - /* Now verify that we can have access to the corresponding private key */ DWORD len; - CRYPT_KEY_PROV_INFO *pinfo; - HCRYPTPROV hprov; - HCRYPTKEY key; - if (!CertGetCertificateContextProperty(certContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len)) { - CertFreeCertificateContext(certContext); + SWIFT_LOG(error) << "Error while retrieving context properties"; return; } - pinfo = static_cast<CRYPT_KEY_PROV_INFO *>(malloc(len)); + std::shared_ptr<CRYPT_KEY_PROV_INFO> pinfo(static_cast<CRYPT_KEY_PROV_INFO *>(malloc(len)), free); if (!pinfo) { - CertFreeCertificateContext(certContext); return; } - if (!CertGetCertificateContextProperty(certContext, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) { - CertFreeCertificateContext(certContext); - free(pinfo); + if (!CertGetCertificateContextProperty(certContext, CERT_KEY_PROV_INFO_PROP_ID, pinfo.get(), &len)) { return; } + certContext.FreeContext(); - CertFreeCertificateContext(certContext); - + HCRYPTPROV hprov; // Now verify if we have access to the private key if (!CryptAcquireContextW(&hprov, pinfo->pwszContainerName, pinfo->pwszProvName, pinfo->dwProvType, 0)) { - free(pinfo); return; } - char smartCardReader[1024]; DWORD bufferLength = sizeof(smartCardReader); if (!CryptGetProvParam(hprov, PP_SMARTCARD_READER, (BYTE *)&smartCardReader, &bufferLength, 0)) { @@ -205,19 +197,19 @@ void CAPICertificate::setUri (const std::string& capiUri) { smartCardTimer_ = timerFactory_->createTimer(SMARTCARD_EJECTION_CHECK_FREQUENCY_MILLISECONDS); } else { - ///Need to handle an error here + CryptReleaseContext(hprov, 0); + return; } } + HCRYPTKEY key; if (!CryptGetUserKey(hprov, pinfo->dwKeySpec, &key)) { CryptReleaseContext(hprov, 0); - free(pinfo); return; } CryptDestroyKey(key); CryptReleaseContext(hprov, 0); - free(pinfo); if (smartCardTimer_) { smartCardTimer_->onTick.connect(boost::bind(&CAPICertificate::handleSmartCardTimerTick, this)); @@ -227,7 +219,7 @@ void CAPICertificate::setUri (const std::string& capiUri) { valid_ = true; } -static void smartcard_check_status (SCARDCONTEXT hContext, +static void smartcard_check_status(SCARDCONTEXT hContext, const char* pReader, SCARDHANDLE hCardHandle, /* Can be 0 on the first call */ SCARDHANDLE* newCardHandle, /* The handle returned */ @@ -288,37 +280,35 @@ static void smartcard_check_status (SCARDCONTEXT hContext, } } -bool CAPICertificate::checkIfSmartCardPresent () { +bool CAPICertificate::checkIfSmartCardPresent() { if (!smartCardReaderName_.empty()) { DWORD dwState; smartcard_check_status(scardContext_, smartCardReaderName_.c_str(), cardHandle_, &cardHandle_, &dwState); switch (dwState) { case SCARD_ABSENT: - SWIFT_LOG(debug) << "Card absent." << std::endl; + SWIFT_LOG(debug) << "Card absent."; break; case SCARD_PRESENT: - SWIFT_LOG(debug) << "Card present." << std::endl; + SWIFT_LOG(debug) << "Card present."; break; case SCARD_SWALLOWED: - SWIFT_LOG(debug) << "Card swallowed." << std::endl; + SWIFT_LOG(debug) << "Card swallowed."; break; case SCARD_POWERED: - SWIFT_LOG(debug) << "Card has power." << std::endl; + SWIFT_LOG(debug) << "Card has power."; break; case SCARD_NEGOTIABLE: - SWIFT_LOG(debug) << "Card reset and waiting PTS negotiation." << std::endl; + SWIFT_LOG(debug) << "Card reset and waiting PTS negotiation."; break; case SCARD_SPECIFIC: - SWIFT_LOG(debug) << "Card has specific communication protocols set." << std::endl; + SWIFT_LOG(debug) << "Card has specific communication protocols set."; break; default: - SWIFT_LOG(debug) << "Unknown or unexpected card state." << std::endl; + SWIFT_LOG(debug) << "Unknown or unexpected card state."; break; } - - switch (dwState) { case SCARD_ABSENT: return false; @@ -342,6 +332,7 @@ bool CAPICertificate::checkIfSmartCardPresent () { void CAPICertificate::handleSmartCardTimerTick() { bool poll = checkIfSmartCardPresent(); if (lastPollingResult_ && !poll) { + SWIFT_LOG(debug) << "CAPI Certificate detected that the certificate card was removed"; onCertificateCardRemoved(); } lastPollingResult_ = poll; diff --git a/Swiften/TLS/CertificateFactory.cpp b/Swiften/TLS/CertificateFactory.cpp index 303bcf7..d4db3f4 100644 --- a/Swiften/TLS/CertificateFactory.cpp +++ b/Swiften/TLS/CertificateFactory.cpp @@ -23,9 +23,9 @@ namespace Swift { CertificateFactory::~CertificateFactory() { } -std::vector<Certificate::ref> CertificateFactory::createCertificateChain(const ByteArray& /* data */) { +std::vector<std::shared_ptr<Certificate>> CertificateFactory::createCertificateChain(const ByteArray& /* data */) { assert(false); - return std::vector<Certificate::ref>(); + return std::vector<std::shared_ptr<Certificate>>(); } PrivateKey::ref CertificateFactory::createPrivateKey(const SafeByteArray& data, boost::optional<SafeByteArray> password) { diff --git a/Swiften/TLS/CertificateFactory.h b/Swiften/TLS/CertificateFactory.h index cb7fb6e..873c36b 100644 --- a/Swiften/TLS/CertificateFactory.h +++ b/Swiften/TLS/CertificateFactory.h @@ -19,7 +19,7 @@ namespace Swift { virtual ~CertificateFactory(); virtual Certificate* createCertificateFromDER(const ByteArray& der) = 0; - virtual std::vector<Certificate::ref> createCertificateChain(const ByteArray& data); + virtual std::vector<std::shared_ptr<Certificate>> createCertificateChain(const ByteArray& data); PrivateKey::ref createPrivateKey(const SafeByteArray& data, boost::optional<SafeByteArray> password = boost::optional<SafeByteArray>()); }; } diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp index 8d2d965..66b650d 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -32,11 +32,19 @@ OpenSSLCertificate::OpenSSLCertificate(const ByteArray& der) { #endif cert = std::shared_ptr<X509>(d2i_X509(nullptr, &p, der.size()), X509_free); if (!cert) { - SWIFT_LOG(warning) << "Error creating certificate from DER data" << std::endl; +// SWIFT_LOG(warning) << "Error creating certificate from DER data"; } parse(); } +void OpenSSLCertificate::incrementReferenceCount() const { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + X509_up_ref(cert.get()); +#else + CRYPTO_add(&(cert.get()->references), 1, CRYPTO_LOCK_EVP_PKEY); +#endif +} + ByteArray OpenSSLCertificate::toDER() const { ByteArray result; if (!cert) { diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.h b/Swiften/TLS/OpenSSL/OpenSSLCertificate.h index 186caea..64da82a 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificate.h +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.h @@ -45,6 +45,8 @@ namespace Swift { return cert; } + void incrementReferenceCount() const; + private: void parse(); diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp index c94702c..73058a5 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp @@ -7,6 +7,7 @@ #include <Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h> #include <openssl/pem.h> +#include <openssl/err.h> namespace Swift { @@ -20,8 +21,8 @@ Certificate* OpenSSLCertificateFactory::createCertificateFromDER(const ByteArray return new OpenSSLCertificate(der); } -std::vector<Certificate::ref> OpenSSLCertificateFactory::createCertificateChain(const ByteArray& data) { - std::vector<Certificate::ref> certificateChain; +std::vector<std::shared_ptr<Certificate>> OpenSSLCertificateFactory::createCertificateChain(const ByteArray& data) { + std::vector<std::shared_ptr<Certificate>> certificateChain; if (data.size() > std::numeric_limits<int>::max()) { return certificateChain; @@ -35,15 +36,20 @@ std::vector<Certificate::ref> OpenSSLCertificateFactory::createCertificateChain( auto x509certFromPEM = PEM_read_bio_X509(bio.get(), &openSSLCert, nullptr, nullptr); if (x509certFromPEM && openSSLCert) { std::shared_ptr<X509> x509Cert(openSSLCert, X509_free); - certificateChain.push_back(std::make_shared<OpenSSLCertificate>(x509Cert)); + certificateChain.emplace_back(std::make_shared<OpenSSLCertificate>(x509Cert)); openSSLCert = nullptr; while ((x509certFromPEM = PEM_read_bio_X509(bio.get(), &openSSLCert, nullptr, nullptr)) != nullptr) { std::shared_ptr<X509> x509Cert(openSSLCert, X509_free); - certificateChain.push_back(std::make_shared<OpenSSLCertificate>(x509Cert)); + certificateChain.emplace_back(std::make_shared<OpenSSLCertificate>(x509Cert)); openSSLCert = nullptr; } } + // Clear any (expected) errors which resulted from PEM parsing + // If we don't do this, any existing TLS context will detect these + // spurious errors and fail to work + ERR_clear_error(); + return certificateChain; } diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h index af45a33..a6974c8 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h @@ -16,6 +16,6 @@ namespace Swift { virtual ~OpenSSLCertificateFactory() override final; virtual Certificate* createCertificateFromDER(const ByteArray& der) override final; - virtual std::vector<Certificate::ref> createCertificateChain(const ByteArray& data) override final; + virtual std::vector<std::shared_ptr<Certificate>> createCertificateChain(const ByteArray& data) override final; }; } diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp index 6f15edf..86b0504 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp @@ -1,8 +1,9 @@ /* - * Copyright (c) 2010-2018 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ + #include <Swiften/Base/Platform.h> #ifdef SWIFTEN_PLATFORM_WINDOWS @@ -14,6 +15,8 @@ #include <memory> #include <vector> + +#include <openssl/bio.h> #include <openssl/err.h> #include <openssl/pkcs12.h> @@ -21,6 +24,8 @@ #include <Security/Security.h> #endif +#include <Swiften/Base/Log.h> +#include <Swiften/Base/Algorithm.h> #include <Swiften/TLS/OpenSSL/OpenSSLContext.h> #include <Swiften/TLS/OpenSSL/OpenSSLCertificate.h> #include <Swiften/TLS/CertificateWithKey.h> @@ -37,6 +42,14 @@ namespace Swift { static const int MAX_FINISHED_SIZE = 4096; static const int SSL_READ_BUFFERSIZE = 8192; +#define SSL_DEFAULT_VERIFY_DEPTH 5 + +// Callback function declarations for certificate verification +extern "C" { + static int certVerifyCallback(X509_STORE_CTX *store_ctx, void*); + static int verifyCallback(int preverify_ok, X509_STORE_CTX *ctx); +} + static void freeX509Stack(STACK_OF(X509)* stack) { sk_X509_free(stack); } @@ -61,65 +74,105 @@ namespace { OpenSSLInitializerFinalizer(const OpenSSLInitializerFinalizer &) = delete; }; -} -OpenSSLContext::OpenSSLContext() : state_(State::Start) { + std::unique_ptr<SSL_CTX> createSSL_CTX(OpenSSLContext::Mode mode) { + std::unique_ptr<SSL_CTX> sslCtx; + switch (mode) { + case OpenSSLContext::Mode::Client: + sslCtx = std::unique_ptr<SSL_CTX>(SSL_CTX_new(SSLv23_client_method())); + break; + case OpenSSLContext::Mode::Server: + sslCtx = std::unique_ptr<SSL_CTX>(SSL_CTX_new(SSLv23_server_method())); + break; + } + return sslCtx; + } + + std::string openSSLInternalErrorToString() { + auto bio = std::shared_ptr<BIO>(BIO_new(BIO_s_mem()), BIO_free); + ERR_print_errors(bio.get()); + std::string errorString; + errorString.resize(BIO_pending(bio.get())); + BIO_read(bio.get(), (void*)errorString.data(), errorString.size()); + return errorString; + } + } + +OpenSSLContext::OpenSSLContext(const TLSOptions& options, Mode mode) : mode_(mode), state_(State::Start) { ensureLibraryInitialized(); - context_ = std::unique_ptr<SSL_CTX>(SSL_CTX_new(SSLv23_client_method())); + context_ = createSSL_CTX(mode_); SSL_CTX_set_options(context_.get(), SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + if (mode_ == Mode::Server) { +#if OPENSSL_VERSION_NUMBER < 0x1010 + // Automatically select highest preference curve used for ECDH temporary keys used during + // key exchange if possible. + // Since version 1.1.0, this option is always enabled. + SSL_CTX_set_ecdh_auto(context_.get(), 1); +#endif + + SSL_CTX_set_tlsext_servername_arg(context_.get(), this); + SSL_CTX_set_tlsext_servername_callback(context_.get(), OpenSSLContext::handleServerNameCallback); + } + // TODO: implement CRL checking // TODO: download CRL (HTTP transport) // TODO: cache CRL downloads for configurable time period // TODO: implement OCSP support // TODO: handle OCSP stapling see https://www.rfc-editor.org/rfc/rfc4366.txt - // Load system certs + + // Default for ignoreSystemTrustAnchors is false, i.e. load System TAs by default, + // to preserve previous behaviour + if (!options.ignoreSystemTrustAnchors) { + // Load system certs #if defined(SWIFTEN_PLATFORM_WINDOWS) - X509_STORE* store = SSL_CTX_get_cert_store(context_.get()); - HCERTSTORE systemStore = CertOpenSystemStore(0, "ROOT"); - if (systemStore) { - PCCERT_CONTEXT certContext = NULL; - while (true) { - certContext = CertFindCertificateInStore(systemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, certContext); - if (!certContext) { - break; - } - OpenSSLCertificate cert(createByteArray(certContext->pbCertEncoded, certContext->cbCertEncoded)); - if (store && cert.getInternalX509()) { - X509_STORE_add_cert(store, cert.getInternalX509().get()); + X509_STORE* store = SSL_CTX_get_cert_store(context_.get()); + HCERTSTORE systemStore = CertOpenSystemStore(0, "ROOT"); + if (systemStore) { + PCCERT_CONTEXT certContext = nullptr; + while (true) { + certContext = CertFindCertificateInStore(systemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, certContext); + if (!certContext) { + break; + } + OpenSSLCertificate cert(createByteArray(certContext->pbCertEncoded, certContext->cbCertEncoded)); + if (store && cert.getInternalX509()) { + X509_STORE_add_cert(store, cert.getInternalX509().get()); + } } } - } #elif !defined(SWIFTEN_PLATFORM_MACOSX) - SSL_CTX_set_default_verify_paths(context_.get()); + SSL_CTX_set_default_verify_paths(context_.get()); #elif defined(SWIFTEN_PLATFORM_MACOSX) && !defined(SWIFTEN_PLATFORM_IPHONE) - // On Mac OS X 10.5 (OpenSSL < 0.9.8), OpenSSL does not automatically look in the system store. - // On Mac OS X 10.6 (OpenSSL >= 0.9.8), OpenSSL *does* look in the system store to determine trust. - // However, if there is a certificate error, it will always emit the "Invalid CA" error if we didn't add - // the certificates first. See - // http://opensource.apple.com/source/OpenSSL098/OpenSSL098-27/src/crypto/x509/x509_vfy_apple.c - // to understand why. We therefore add all certs from the system store ourselves. - X509_STORE* store = SSL_CTX_get_cert_store(context_.get()); - CFArrayRef anchorCertificates; - if (SecTrustCopyAnchorCertificates(&anchorCertificates) == 0) { - for (int i = 0; i < CFArrayGetCount(anchorCertificates); ++i) { - SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(const_cast<void*>(CFArrayGetValueAtIndex(anchorCertificates, i))); - CSSM_DATA certCSSMData; - if (SecCertificateGetData(cert, &certCSSMData) != 0 || certCSSMData.Length == 0) { - continue; - } - std::vector<unsigned char> certData; - certData.resize(certCSSMData.Length); - memcpy(&certData[0], certCSSMData.Data, certCSSMData.Length); - OpenSSLCertificate certificate(certData); - if (store && certificate.getInternalX509()) { - X509_STORE_add_cert(store, certificate.getInternalX509().get()); + // On Mac OS X 10.5 (OpenSSL < 0.9.8), OpenSSL does not automatically look in the system store. + // On Mac OS X 10.6 (OpenSSL >= 0.9.8), OpenSSL *does* look in the system store to determine trust. + // However, if there is a certificate error, it will always emit the "Invalid CA" error if we didn't add + // the certificates first. See + // http://opensource.apple.com/source/OpenSSL098/OpenSSL098-27/src/crypto/x509/x509_vfy_apple.c + // to understand why. We therefore add all certs from the system store ourselves. + X509_STORE* store = SSL_CTX_get_cert_store(context_.get()); + CFArrayRef anchorCertificates; + if (SecTrustCopyAnchorCertificates(&anchorCertificates) == 0) { + for (int i = 0; i < CFArrayGetCount(anchorCertificates); ++i) { + SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(const_cast<void*>(CFArrayGetValueAtIndex(anchorCertificates, i))); + CSSM_DATA certCSSMData; + if (SecCertificateGetData(cert, &certCSSMData) != 0 || certCSSMData.Length == 0) { + continue; + } + std::vector<unsigned char> certData; + certData.resize(certCSSMData.Length); + memcpy(&certData[0], certCSSMData.Data, certCSSMData.Length); + OpenSSLCertificate certificate(certData); + if (store && certificate.getInternalX509()) { + X509_STORE_add_cert(store, certificate.getInternalX509().get()); + } } + CFRelease(anchorCertificates); } - CFRelease(anchorCertificates); - } #endif + } + configure(options); } OpenSSLContext::~OpenSSLContext() { @@ -129,23 +182,318 @@ void OpenSSLContext::ensureLibraryInitialized() { static OpenSSLInitializerFinalizer openSSLInit; } +void OpenSSLContext::initAndSetBIOs() { + // Ownership of BIOs is transferred + readBIO_ = BIO_new(BIO_s_mem()); + writeBIO_ = BIO_new(BIO_s_mem()); + SSL_set_bio(handle_.get(), readBIO_, writeBIO_); +} + +// This callback is called by OpenSSL when a client certificate needs to be verified. +// In turn, this calls the verification callback which the user +// of this OpenSSLContext has configured (if any). +static int certVerifyCallback(X509_STORE_CTX* store_ctx, void* arg) +{ + OpenSSLContext* context = static_cast<OpenSSLContext *>(arg); + + // Need to stash store_ctx pointer for use within verification + context->setX509StoreContext(store_ctx); + + int ret; + + // This callback shouldn't have been set up if the context doesn't + // have a verifyCertCallback set, but it doesn't hurt to double check + std::function<int (const TLSContext *)> cb = context->getVerifyCertCallback(); + if (cb != nullptr) { + ret = cb(static_cast<const OpenSSLContext*>(context)); + } else { + SWIFT_LOG(debug) << "certVerifyCallback called but context.verifyCertCallback is unset"; + ret = 0; + } + + context->setX509StoreContext(nullptr); + return ret; +} + +// Convenience function to generate a text representation +// of an X509 Name. This information is only used for logging. +static std::string X509_NAME_to_text(X509_NAME* name) +{ + std::string nameString; + + if (!name) { + return nameString; + } + + std::unique_ptr<BIO, decltype(&BIO_free)> io(BIO_new(BIO_s_mem()), &BIO_free); + int r = X509_NAME_print_ex(io.get(), name, 0, XN_FLAG_RFC2253); + BIO_write(io.get(), "\0", 1); + + if (r > 0) { + BUF_MEM* ptr = nullptr; + BIO_get_mem_ptr(io.get(), &ptr); + nameString = ptr->data; + } + + return nameString; +} + +// Check depth of certificate chain +static int verifyCallback(int preverifyOk, X509_STORE_CTX* ctx) +{ + // Retrieve the pointer to the SSL of the connection currently treated + // and the application specific data stored into the SSL object. + + int err = X509_STORE_CTX_get_error(ctx); + int depth = X509_STORE_CTX_get_error_depth(ctx); + + SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); + SSL_CTX* sslctx = ssl ? SSL_get_SSL_CTX(ssl) : nullptr; + if (!sslctx) { + SWIFT_LOG(debug) << "verifyCallback: internal error"; + return preverifyOk; + } + + if (SSL_CTX_get_verify_mode(sslctx) == SSL_VERIFY_NONE) { + SWIFT_LOG(debug) << "verifyCallback: no verification required"; + // No verification requested + return 1; + } + + X509* errCert = X509_STORE_CTX_get_current_cert(ctx); + std::string subjectString; + if (errCert) { + X509_NAME* subjectName = X509_get_subject_name(errCert); + subjectString = X509_NAME_to_text(subjectName); + } + + // Catch a too long certificate chain. The depth limit set using + // SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so + // that whenever the "depth>verify_depth" condition is met, we + // have violated the limit and want to log this error condition. + // We must do it here, because the CHAIN_TOO_LONG error would not + // be found explicitly; only errors introduced by cutting off the + // additional certificates would be logged. + if (depth >= SSL_CTX_get_verify_depth(sslctx)) { + preverifyOk = 0; + err = X509_V_ERR_CERT_CHAIN_TOO_LONG; + X509_STORE_CTX_set_error(ctx, err); + } + + if (!preverifyOk) { + std::string issuerString; + if (errCert) { + X509_NAME* issuerName = X509_get_issuer_name(errCert); + issuerString = X509_NAME_to_text(issuerName); + } + SWIFT_LOG(debug) << "verifyCallback: verification error " << + X509_verify_cert_error_string(err) << " depth: " << + depth << " issuer: " << ((issuerString.length() > 0) ? issuerString : "<unknown>"); + } else { + SWIFT_LOG(debug) << "verifyCallback: SSL depth: " << depth << " Subject: " << + ((subjectString.length() > 0) ? subjectString : "<>"); + } + // Always return "OK", as check on verification status + // will be performed once TLS handshake has completed, + // by calling OpenSSLContext::getVerificationErrorTypeForResult() to + // get the value set via X509_STORE_CTX_set_error() above. + return 1; +} + +bool OpenSSLContext::configure(const TLSOptions &options) +{ + if (options.cipherSuites) { + std::string cipherSuites = *(options.cipherSuites); + if (SSL_CTX_set_cipher_list(context_.get(), cipherSuites.c_str()) != 1 ) { + SWIFT_LOG(debug) << "Failed to set cipher-suites"; + return false; + } + } + + if (options.context) { + const auto& contextId = *options.context; + + if (SSL_CTX_set_session_id_context(context_.get(), + reinterpret_cast<const unsigned char *>(contextId.c_str()), + contextId.length()) != 1) { + SWIFT_LOG(debug) << "Failed to set context-id"; + return false; + } + } + + if (options.sessionCacheTimeout) { + int scto = *options.sessionCacheTimeout; + if (scto <= 0) { + SWIFT_LOG(debug) << "Invalid value for session-cache-timeout"; + return false; + } + (void)SSL_CTX_set_timeout(context_.get(), scto); + if (SSL_CTX_get_timeout(context_.get()) != scto) { + SWIFT_LOG(debug) << "Failed to set session-cache-timeout"; + return false; + } + } + + if (options.verifyCertificateCallback) { + verifyCertCallback = *options.verifyCertificateCallback; + } else { + verifyCertCallback = nullptr; + } + + if (options.verifyMode) { + TLSOptions::VerifyMode verify_mode = *options.verifyMode; + int mode; + switch (verify_mode) { + case TLSOptions::VerifyMode::None: + mode = SSL_VERIFY_NONE; + break; + case TLSOptions::VerifyMode::Required: + mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE; + break; + case TLSOptions::VerifyMode::Optional: + mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; + break; + } + + // Set up default certificate chain verification depth - may be overridden below + SSL_CTX_set_verify_depth(context_.get(), SSL_DEFAULT_VERIFY_DEPTH + 1); + + // Set callbacks up + SSL_CTX_set_verify(context_.get(), mode, verifyCallback); + + // Only set up certificate verification callback if a user callback has + // been configured via the TLSOptions + if (verifyCertCallback != nullptr) { + SSL_CTX_set_cert_verify_callback(context_.get(), certVerifyCallback, this); + } + } + + if (options.verifyDepth) { + int depth = *options.verifyDepth; + if (depth <= 0) { + SWIFT_LOG(debug) << "Invalid value for verify-depth"; + return false; + } + + // Increase depth limit by one, so that verifyCallback() will log it + SSL_CTX_set_verify_depth(context_.get(), depth + 1); + } + + auto updateOptionIfPresent = [this](boost::optional<bool> option, int flag) { + if (option) { + if (*option) { + SSL_CTX_set_options(context_.get(), flag); + } + else { + SSL_CTX_clear_options(context_.get(), flag); + } + } + }; + updateOptionIfPresent(options.workaroundMicrosoftSessID, SSL_OP_MICROSOFT_SESS_ID_BUG); + updateOptionIfPresent(options.workaroundNetscapeChallenge, SSL_OP_NETSCAPE_CHALLENGE_BUG); + updateOptionIfPresent(options.workaroundNetscapeReuseCipherChange, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); + updateOptionIfPresent(options.workaroundSSLRef2ReuseCertType, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG); + updateOptionIfPresent(options.workaroundMicrosoftBigSSLv3Buffer, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); + updateOptionIfPresent(options.workaroundSSLeay080ClientDH, SSL_OP_SSLEAY_080_CLIENT_DH_BUG); + updateOptionIfPresent(options.workaroundTLSD5, SSL_OP_TLS_D5_BUG); + updateOptionIfPresent(options.workaroundTLSBlockPadding, SSL_OP_TLS_BLOCK_PADDING_BUG); + updateOptionIfPresent(options.workaroundDontInsertEmptyFragments, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + updateOptionIfPresent(options.workaroundAll, SSL_OP_ALL); + updateOptionIfPresent(options.suppressSSLv2, SSL_OP_NO_SSLv2); + updateOptionIfPresent(options.suppressSSLv3, SSL_OP_NO_SSLv3); + updateOptionIfPresent(options.suppressTLSv1, SSL_OP_NO_TLSv1); + updateOptionIfPresent(options.disableTLSRollBackBug, SSL_OP_TLS_ROLLBACK_BUG); + updateOptionIfPresent(options.singleDHUse, SSL_OP_SINGLE_DH_USE); + + if (options.trustAnchors) { + // Add any additional Trust Anchors which are present in the TLSOptions + X509_STORE* store = SSL_CTX_get_cert_store(context_.get()); + + if (store) { + for (auto& certificate : *options.trustAnchors) { + auto openSSLCert = dynamic_cast<OpenSSLCertificate*>(certificate.get()); + if (openSSLCert && openSSLCert->getInternalX509()) { + X509_STORE_add_cert(store, openSSLCert->getInternalX509().get()); + // Don't need to increment reference count as X509_STORE_add_cert does thiS + } + } + } + } + + return true; +} + + +void OpenSSLContext::accept() { + assert(mode_ == Mode::Server); + handle_ = std::unique_ptr<SSL>(SSL_new(context_.get())); + if (!handle_) { + state_ = State::Error; + onError(std::make_shared<TLSError>(TLSError::AcceptFailed, openSSLInternalErrorToString())); + return; + } + + initAndSetBIOs(); + + state_ = State::Accepting; + doAccept(); +} + void OpenSSLContext::connect() { + connect(std::string()); +} + +void OpenSSLContext::connect(const std::string& requestedServerName) { + assert(mode_ == Mode::Client); handle_ = std::unique_ptr<SSL>(SSL_new(context_.get())); if (!handle_) { state_ = State::Error; - onError(std::make_shared<TLSError>()); + onError(std::make_shared<TLSError>(TLSError::ConnectFailed, openSSLInternalErrorToString())); return; } - // Ownership of BIOs is transferred - readBIO_ = BIO_new(BIO_s_mem()); - writeBIO_ = BIO_new(BIO_s_mem()); - SSL_set_bio(handle_.get(), readBIO_, writeBIO_); + if (!requestedServerName.empty()) { + if (SSL_set_tlsext_host_name(handle_.get(), const_cast<char*>(requestedServerName.c_str())) != 1) { + onError(std::make_shared<TLSError>(TLSError::ConnectFailed, "Failed to set Server Name Indication: " + openSSLInternalErrorToString()));\ + return; + } + } + + // Ownership of BIOs is transferred to the SSL_CTX instance in handle_. + initAndSetBIOs(); state_ = State::Connecting; doConnect(); } +void OpenSSLContext::doAccept() { + auto acceptResult = SSL_accept(handle_.get()); + auto error = SSL_get_error(handle_.get(), acceptResult); + switch (error) { + case SSL_ERROR_NONE: { + state_ = State::Connected; + //std::cout << x->name << std::endl; + //const char* comp = SSL_get_current_compression(handle_.get()); + //std::cout << "Compression: " << SSL_COMP_get_name(comp) << std::endl; + onConnected(); + // The following call is important so the client knowns the handshake is finished. + sendPendingDataToNetwork(); + sendPendingDataToApplication(); + break; + } + case SSL_ERROR_WANT_READ: + sendPendingDataToNetwork(); + break; + case SSL_ERROR_WANT_WRITE: + sendPendingDataToNetwork(); + break; + default: + state_ = State::Error; + onError(std::make_shared<TLSError>(TLSError::AcceptFailed, openSSLInternalErrorToString())); + sendPendingDataToNetwork(); + } +} + void OpenSSLContext::doConnect() { int connectResult = SSL_connect(handle_.get()); int error = SSL_get_error(handle_.get(), connectResult); @@ -156,6 +504,9 @@ void OpenSSLContext::doConnect() { //const char* comp = SSL_get_current_compression(handle_.get()); //std::cout << "Compression: " << SSL_COMP_get_name(comp) << std::endl; onConnected(); + // The following is needed since OpenSSL 1.1.1 for the server to be able to calculate the + // TLS finish message. + sendPendingDataToNetwork(); break; } case SSL_ERROR_WANT_READ: @@ -164,9 +515,28 @@ void OpenSSLContext::doConnect() { default: state_ = State::Error; onError(std::make_shared<TLSError>()); + onError(std::make_shared<TLSError>(TLSError::ConnectFailed, openSSLInternalErrorToString())); } } +int OpenSSLContext::handleServerNameCallback(SSL* ssl, int*, void* arg) { + if (ssl == nullptr) + return SSL_TLSEXT_ERR_NOACK; + + const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + if (servername) { + auto serverNameString = std::string(servername); + auto context = reinterpret_cast<OpenSSLContext*>(arg); + context->onServerNameRequested(serverNameString); + + if (context->abortTLSHandshake_) { + context->abortTLSHandshake_ = false; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + return SSL_TLSEXT_ERR_OK; +} + void OpenSSLContext::sendPendingDataToNetwork() { int size = BIO_pending(writeBIO_); if (size > 0) { @@ -180,6 +550,9 @@ void OpenSSLContext::sendPendingDataToNetwork() { void OpenSSLContext::handleDataFromNetwork(const SafeByteArray& data) { BIO_write(readBIO_, vecptr(data), data.size()); switch (state_) { + case State::Accepting: + doAccept(); + break; case State::Connecting: doConnect(); break; @@ -192,12 +565,13 @@ void OpenSSLContext::handleDataFromNetwork(const SafeByteArray& data) { } void OpenSSLContext::handleDataFromApplication(const SafeByteArray& data) { - if (SSL_write(handle_.get(), vecptr(data), data.size()) >= 0) { - sendPendingDataToNetwork(); + auto ret = SSL_write(handle_.get(), vecptr(data), data.size()); + if (ret > 0 || SSL_get_error(handle_.get(), ret) == SSL_ERROR_WANT_READ) { + sendPendingDataToNetwork(); } else { state_ = State::Error; - onError(std::make_shared<TLSError>()); + onError(std::make_shared<TLSError>(TLSError::UnknownError, openSSLInternalErrorToString())); } } @@ -213,10 +587,111 @@ void OpenSSLContext::sendPendingDataToApplication() { } if (ret < 0 && SSL_get_error(handle_.get(), ret) != SSL_ERROR_WANT_READ) { state_ = State::Error; - onError(std::make_shared<TLSError>()); + onError(std::make_shared<TLSError>(TLSError::UnknownError, openSSLInternalErrorToString())); } } +bool OpenSSLContext::setCertificateChain(const std::vector<std::shared_ptr<Certificate>>& certificateChain) { + if (certificateChain.size() == 0) { + SWIFT_LOG(debug) << "Trying to load empty certificate chain."; + return false; + } + + // load endpoint certificate + auto openSSLCert = dynamic_cast<OpenSSLCertificate*>(certificateChain[0].get()); + if (!openSSLCert) { + return false; + } + + // This increments the reference count on the X509 certificate automatically + if (SSL_CTX_use_certificate(context_.get(), openSSLCert->getInternalX509().get()) != 1) { + return false; + } + + if (certificateChain.size() > 1) { + for (auto certificate = certificateChain.begin() + 1; certificate != certificateChain.end(); ++certificate) { + auto openSSLCert = dynamic_cast<OpenSSLCertificate*>(certificate->get()); + if (!openSSLCert) { + return false; + } + + if (SSL_CTX_add_extra_chain_cert(context_.get(), openSSLCert->getInternalX509().get()) != 1) { + SWIFT_LOG(debug) << "Trying to load empty certificate chain."; + return false; + } + // Have to manually increment reference count as SSL_CTX_add_extra_chain_cert does not do so + openSSLCert->incrementReferenceCount(); + } + } + + if (handle_) { + // This workaround is needed as OpenSSL has a shortcut to not do anything + // if you set the SSL_CTX to the existing SSL_CTX and not reloading the + // certificates from the SSL_CTX. + auto dummyContext = createSSL_CTX(mode_); + SSL_set_SSL_CTX(handle_.get(), dummyContext.get()); + SSL_set_SSL_CTX(handle_.get(), context_.get()); + } + + return true; +} + +int empty_or_preset_password_cb(char* buf, int max_len, int flag, void* password); + +int empty_or_preset_password_cb(char* buf, int max_len, int /* flag */, void* password) { + char* charPassword = (char*)password; + if (charPassword == nullptr) { + return 0; + } + int len = strlen(charPassword); + if(len > max_len) { + return 0; + } + memcpy(buf, charPassword, len); + return len; +} + +bool OpenSSLContext::setPrivateKey(const PrivateKey::ref& privateKey) { + if (privateKey->getData().size() > std::numeric_limits<int>::max()) { + return false; + } + + auto bio = std::shared_ptr<BIO>(BIO_new(BIO_s_mem()), BIO_free); + BIO_write(bio.get(), vecptr(privateKey->getData()), int(privateKey->getData().size())); + + SafeByteArray safePassword; + void* password = nullptr; + if (privateKey->getPassword()) { + safePassword = privateKey->getPassword().get(); + safePassword.push_back(0); + password = safePassword.data(); + } + // Make sure resultKey is tidied up by wrapping it in a shared_ptr + auto resultKey = std::shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(bio.get(), nullptr, empty_or_preset_password_cb, password), EVP_PKEY_free); + if (resultKey) { + if (handle_) { + auto result = SSL_use_PrivateKey(handle_.get(), resultKey.get()); + if (result != 1) { + return false; + } + } + else { + auto result = SSL_CTX_use_PrivateKey(context_.get(), resultKey.get()); + if (result != 1) { + return false; + } + } + } + else { + return false; + } + return true; +} + +void OpenSSLContext::setAbortTLSHandshake(bool abort) { + abortTLSHandshake_ = abort; +} + bool OpenSSLContext::setClientCertificate(CertificateWithKey::ref certificate) { std::shared_ptr<PKCS12Certificate> pkcs12Certificate = std::dynamic_pointer_cast<PKCS12Certificate>(certificate); if (!pkcs12Certificate || pkcs12Certificate->isNull()) { @@ -259,15 +734,54 @@ bool OpenSSLContext::setClientCertificate(CertificateWithKey::ref certificate) { return true; } +bool OpenSSLContext::setDiffieHellmanParameters(const ByteArray& parametersInOpenSslDer) { + auto bio = std::unique_ptr<BIO, decltype(&BIO_free)>(BIO_new(BIO_s_mem()), BIO_free); + if (bio) { + BIO_write(bio.get(), vecptr(parametersInOpenSslDer), parametersInOpenSslDer.size()); + auto result = 0L; + if (auto dhparams = d2i_DHparams_bio(bio.get(), nullptr)) { + if (handle_) { + result = SSL_set_tmp_dh(handle_.get(), dhparams); + } + else { + result = SSL_CTX_set_tmp_dh(context_.get(), dhparams); + } + DH_free(dhparams); + } + return result == 1; + } + return false; +} + std::vector<Certificate::ref> OpenSSLContext::getPeerCertificateChain() const { std::vector<Certificate::ref> result; + + // When this context is a server, the peer (client) certificate + // is obtained via SSL_get_peer_certificate, and any other + // certificates set by the peer are available via SSL_get_peer_cert_chain. + // When this context is a client, all of the server's certificates are + // obtained using SSL_get_peer_cert_chain + if (mode_ == Mode::Server) { + auto cert = SSL_get_peer_certificate(handle_.get()); + if (cert) { + // Do not need to copy the returned cert as SSL_get_peer_certificate + // increments the reference count on the certificate + std::shared_ptr<X509> x509Cert(cert, X509_free); + Certificate::ref cert = std::make_shared<OpenSSLCertificate>(x509Cert); + result.push_back(cert); + } + } + STACK_OF(X509)* chain = SSL_get_peer_cert_chain(handle_.get()); for (int i = 0; i < sk_X509_num(chain); ++i) { + // Here we do need to copy the returned cert, since SSL_get_peer_cert_chain + // does not increment the reference count on each certificate std::shared_ptr<X509> x509Cert(X509_dup(sk_X509_value(chain, i)), X509_free); Certificate::ref cert = std::make_shared<OpenSSLCertificate>(x509Cert); result.push_back(cert); } + return result; } @@ -284,11 +798,19 @@ std::shared_ptr<CertificateVerificationError> OpenSSLContext::getPeerCertificate ByteArray OpenSSLContext::getFinishMessage() const { ByteArray data; data.resize(MAX_FINISHED_SIZE); - size_t size = SSL_get_finished(handle_.get(), vecptr(data), data.size()); + auto size = SSL_get_finished(handle_.get(), vecptr(data), data.size()); data.resize(size); return data; } +ByteArray OpenSSLContext::getPeerFinishMessage() const { + ByteArray data; + data.resize(MAX_FINISHED_SIZE); + auto size = SSL_get_peer_finished(handle_.get(), vecptr(data), data.size()); + data.resize(size); + return data; + } + CertificateVerificationError::Type OpenSSLContext::getVerificationErrorTypeForResult(int result) { assert(result != 0); switch (result) { diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.h b/Swiften/TLS/OpenSSL/OpenSSLContext.h index 49ada51..8eb5758 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContext.h +++ b/Swiften/TLS/OpenSSL/OpenSSLContext.h @@ -16,6 +16,7 @@ #include <Swiften/Base/ByteArray.h> #include <Swiften/TLS/CertificateWithKey.h> #include <Swiften/TLS/TLSContext.h> +#include <Swiften/TLS/TLSOptions.h> namespace std { template<> @@ -38,11 +39,18 @@ namespace std { namespace Swift { class OpenSSLContext : public TLSContext, boost::noncopyable { public: - OpenSSLContext(); + OpenSSLContext(const TLSOptions& options, Mode mode); virtual ~OpenSSLContext() override final; + void accept() override final; void connect() override final; + void connect(const std::string& requestHostname) override final; + + bool setCertificateChain(const std::vector<std::shared_ptr<Certificate>>& certificateChain) override final; + bool setPrivateKey(const PrivateKey::ref& privateKey) override final; bool setClientCertificate(CertificateWithKey::ref cert) override final; + void setAbortTLSHandshake(bool abort) override final; + bool setDiffieHellmanParameters(const ByteArray& parametersInOpenSslDer) override final; void handleDataFromNetwork(const SafeByteArray&) override final; void handleDataFromApplication(const SafeByteArray&) override final; @@ -51,23 +59,34 @@ namespace Swift { std::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const override final; virtual ByteArray getFinishMessage() const override final; + virtual ByteArray getPeerFinishMessage() const override final; + + void setX509StoreContext(X509_STORE_CTX *ptr) { x509_store_ctx = ptr; } + std::function<int (const TLSContext *)> getVerifyCertCallback() { return verifyCertCallback; } private: + bool configure(const TLSOptions& options); static void ensureLibraryInitialized(); - + static int handleServerNameCallback(SSL *ssl, int *ad, void *arg); static CertificateVerificationError::Type getVerificationErrorTypeForResult(int); + void initAndSetBIOs(); + void doAccept(); void doConnect(); void sendPendingDataToNetwork(); void sendPendingDataToApplication(); private: - enum class State { Start, Connecting, Connected, Error }; + enum class State { Start, Accepting, Connecting, Connected, Error }; + const Mode mode_; State state_; std::unique_ptr<SSL_CTX> context_; std::unique_ptr<SSL> handle_; BIO* readBIO_ = nullptr; BIO* writeBIO_ = nullptr; - }; + bool abortTLSHandshake_ = false; + X509_STORE_CTX *x509_store_ctx = nullptr; + std::function<int (const TLSContext *)> verifyCertCallback = nullptr; + }; } diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp index 9f7b2aa..e332ca8 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp @@ -1,34 +1,60 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/TLS/OpenSSL/OpenSSLContextFactory.h> +#include <openssl/bio.h> +#include <openssl/dh.h> +#include <openssl/pem.h> + #include <Swiften/Base/Log.h> #include <Swiften/TLS/OpenSSL/OpenSSLContext.h> +#pragma clang diagnostic ignored "-Wshorten-64-to-32" + namespace Swift { bool OpenSSLContextFactory::canCreate() const { return true; } -TLSContext* OpenSSLContextFactory::createTLSContext(const TLSOptions&) { - return new OpenSSLContext(); +std::unique_ptr<TLSContext> OpenSSLContextFactory::createTLSContext(const TLSOptions& options, TLSContext::Mode mode) { + return std::make_unique<OpenSSLContext>(options, mode); +} + +ByteArray OpenSSLContextFactory::convertDHParametersFromPEMToDER(const std::string& dhParametersInPEM) { + ByteArray dhParametersInDER; + + auto bio = std::unique_ptr<BIO, decltype(&BIO_free)>(BIO_new(BIO_s_mem()), BIO_free); + if (bio) { + BIO_write(bio.get(), dhParametersInPEM.data(), dhParametersInPEM.size()); + if (auto params = PEM_read_bio_DHparams(bio.get(), nullptr, nullptr, nullptr)) { + unsigned char* buffer = nullptr; + auto len = i2d_DHparams(params, &buffer); + if (len > 0) { + dhParametersInDER = createByteArray(buffer, static_cast<size_t>(len)); + free(buffer); + } + DH_free(params); + + } + } + return dhParametersInDER; } void OpenSSLContextFactory::setCheckCertificateRevocation(bool check) { if (check) { - SWIFT_LOG(warning) << "CRL Checking not supported for OpenSSL" << std::endl; + SWIFT_LOG(warning) << "CRL Checking not supported for OpenSSL"; assert(false); } } void OpenSSLContextFactory::setDisconnectOnCardRemoval(bool check) { if (check) { - SWIFT_LOG(warning) << "Smart cards not supported for OpenSSL" << std::endl; + SWIFT_LOG(warning) << "Smart cards not supported for OpenSSL"; } } diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h index e121a1a..834e479 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h +++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h @@ -1,23 +1,25 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once -#include <cassert> +#include <memory> #include <Swiften/TLS/TLSContextFactory.h> namespace Swift { class OpenSSLContextFactory : public TLSContextFactory { public: - bool canCreate() const; - virtual TLSContext* createTLSContext(const TLSOptions& tlsOptions); + bool canCreate() const override final; + virtual std::unique_ptr<TLSContext> createTLSContext(const TLSOptions& tlsOptions, TLSContext::Mode mode) override final; + + virtual ByteArray convertDHParametersFromPEMToDER(const std::string& dhParametersInPEM) override final; // Not supported - virtual void setCheckCertificateRevocation(bool b); - virtual void setDisconnectOnCardRemoval(bool b); + virtual void setCheckCertificateRevocation(bool b) override final; + virtual void setDisconnectOnCardRemoval(bool b) override final; }; } diff --git a/Swiften/TLS/SConscript b/Swiften/TLS/SConscript index ec9edd5..a79e6a1 100644 --- a/Swiften/TLS/SConscript +++ b/Swiften/TLS/SConscript @@ -20,6 +20,8 @@ if myenv.get("HAVE_OPENSSL", 0) : "OpenSSL/OpenSSLCertificateFactory.cpp", ]) myenv.Append(CPPDEFINES = "HAVE_OPENSSL") + if myenv["PLATFORM"] == "win32" : + myenv.Append(CPPDEFINES = "NOMINMAX") elif myenv.get("HAVE_SCHANNEL", 0) : swiften_env.Append(LIBS = ["Winscard"]) objects += myenv.SwiftenObject([ diff --git a/Swiften/TLS/Schannel/SchannelContext.cpp b/Swiften/TLS/Schannel/SchannelContext.cpp index 5799157..722fb4a 100644 --- a/Swiften/TLS/Schannel/SchannelContext.cpp +++ b/Swiften/TLS/Schannel/SchannelContext.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,6 +16,7 @@ #include <WinHTTP.h> /* For SECURITY_FLAG_IGNORE_CERT_CN_INVALID */ +#include <Swiften/Base/Log.h> #include <Swiften/TLS/CAPICertificate.h> #include <Swiften/TLS/Schannel/SchannelCertificate.h> @@ -39,13 +40,20 @@ SchannelContext::SchannelContext(bool tls1_0Workaround) : state_(Start), secCont //------------------------------------------------------------------------ SchannelContext::~SchannelContext() { - if (myCertStore_) CertCloseStore(myCertStore_, 0); + SWIFT_LOG(debug) << "Destroying SchannelContext"; + if (myCertStore_) { + if (CertCloseStore(myCertStore_, 0) == FALSE) { + SWIFT_LOG(debug) << "Failed to close the certificate store"; + } + } } //------------------------------------------------------------------------ void SchannelContext::determineStreamSizes() { - QueryContextAttributes(contextHandle_, SECPKG_ATTR_STREAM_SIZES, &streamSizes_); + if (QueryContextAttributes(contextHandle_, SECPKG_ATTR_STREAM_SIZES, &streamSizes_) != SEC_E_OK) { + SWIFT_LOG(debug) << "QueryContextAttributes failed to determinate the stream size"; + } } //------------------------------------------------------------------------ @@ -267,8 +275,8 @@ void SchannelContext::continueHandshake(const SafeByteArray& data) { SecBuffer inBuffers[2]; // Provide Schannel with the remote host's handshake data - inBuffers[0].pvBuffer = (char*)(&receivedData_[0]); - inBuffers[0].cbBuffer = (unsigned long)receivedData_.size(); + inBuffers[0].pvBuffer = static_cast<char*>(&receivedData_[0]); + inBuffers[0].cbBuffer = static_cast<unsigned long>(receivedData_.size()); inBuffers[0].BufferType = SECBUFFER_TOKEN; inBuffers[1].pvBuffer = NULL; @@ -483,8 +491,8 @@ void SchannelContext::decryptAndProcessData(const SafeByteArray& data) { // contexts. Additionally, a second SECBUFFER_TOKEN type buffer that contains a security token // must also be supplied. // - inBuffers[0].pvBuffer = (char*)(&receivedData_[0]); - inBuffers[0].cbBuffer = (unsigned long)receivedData_.size(); + inBuffers[0].pvBuffer = static_cast<char*>(&receivedData_[0]); + inBuffers[0].cbBuffer = static_cast<unsigned long>(receivedData_.size()); inBuffers[0].BufferType = SECBUFFER_DATA; inBuffers[1].BufferType = SECBUFFER_EMPTY; @@ -578,7 +586,7 @@ void SchannelContext::encryptAndSendData(const SafeByteArray& data) { outBuffers[0].BufferType = SECBUFFER_STREAM_HEADER; outBuffers[1].pvBuffer = &sendBuffer[0] + streamSizes_.cbHeader; - outBuffers[1].cbBuffer = (unsigned long)bytesToSend; + outBuffers[1].cbBuffer = static_cast<unsigned long>(bytesToSend); outBuffers[1].BufferType = SECBUFFER_DATA; outBuffers[2].pvBuffer = &sendBuffer[0] + streamSizes_.cbHeader + bytesToSend; @@ -645,6 +653,7 @@ std::vector<Certificate::ref> SchannelContext::getPeerCertificateChain() const { SECURITY_STATUS status = QueryContextAttributes(contextHandle_, SECPKG_ATTR_REMOTE_CERT_CONTEXT, pServerCert.Reset()); if (status != SEC_E_OK) { + SWIFT_LOG(debug) << "Error while Querying the Certificate Chain"; return certificateChain; } certificateChain.push_back(std::make_shared<SchannelCertificate>(pServerCert)); @@ -678,6 +687,10 @@ ByteArray SchannelContext::getFinishMessage() const { if (ret == SEC_E_OK) { return createByteArray(((unsigned char*) bindings.Bindings) + bindings.Bindings->dwApplicationDataOffset + 11 /* tls-unique:*/, bindings.Bindings->cbApplicationDataLength - 11); } + else { + SWIFT_LOG(debug) << "Error while retrieving Finish Message"; + } + return ByteArray(); } diff --git a/Swiften/TLS/Schannel/SchannelContextFactory.cpp b/Swiften/TLS/Schannel/SchannelContextFactory.cpp index f78d386..d029730 100644 --- a/Swiften/TLS/Schannel/SchannelContextFactory.cpp +++ b/Swiften/TLS/Schannel/SchannelContextFactory.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,11 +23,13 @@ bool SchannelContextFactory::canCreate() const { return true; } -TLSContext* SchannelContextFactory::createTLSContext(const TLSOptions& tlsOptions) { +std::unique_ptr<TLSContext> SchannelContextFactory::createTLSContext(const TLSOptions& tlsOptions, TLSContext::Mode mode) { + // TLS server mode is not supported for the SecureTransport backend yet. + assert(mode == TLSContext::Mode::Client); SchannelContext* context = new SchannelContext(tlsOptions.schannelTLS1_0Workaround); context->setCheckCertificateRevocation(checkCertificateRevocation); context->setDisconnectOnCardRemoval(disconnectOnCardRemoval); - return context; + return std::unique_ptr<TLSContext>(context); } void SchannelContextFactory::setCheckCertificateRevocation(bool b) { diff --git a/Swiften/TLS/Schannel/SchannelContextFactory.h b/Swiften/TLS/Schannel/SchannelContextFactory.h index 142f193..76ff365 100644 --- a/Swiften/TLS/Schannel/SchannelContextFactory.h +++ b/Swiften/TLS/Schannel/SchannelContextFactory.h @@ -5,13 +5,15 @@ */ /* - * Copyright (c) 2015 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once +#include <memory> + #include <Swiften/TLS/TLSContextFactory.h> namespace Swift { @@ -20,8 +22,7 @@ namespace Swift { SchannelContextFactory(); bool canCreate() const; - virtual TLSContext* createTLSContext(const TLSOptions& tlsOptions); - + virtual std::unique_ptr<TLSContext> createTLSContext(const TLSOptions& tlsOptions, TLSContext::Mode mode = TLSContext::Mode::Client); virtual void setCheckCertificateRevocation(bool b); virtual void setDisconnectOnCardRemoval(bool b); diff --git a/Swiften/TLS/SecureTransport/SecureTransportContext.mm b/Swiften/TLS/SecureTransport/SecureTransportContext.mm index 1ed636b..b4f7842 100644 --- a/Swiften/TLS/SecureTransport/SecureTransportContext.mm +++ b/Swiften/TLS/SecureTransport/SecureTransportContext.mm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -72,14 +72,14 @@ CFArrayRef CreateClientCertificateChainAsCFArrayRef(CertificateWithKey::ref key) break; case errSecAuthFailed: // Password did not work for decoding the certificate. - SWIFT_LOG(warning) << "Invalid password." << std::endl; + SWIFT_LOG(warning) << "Invalid password."; break; case errSecDecode: // Other decoding error. - SWIFT_LOG(warning) << "PKCS12 decoding error." << std::endl; + SWIFT_LOG(warning) << "PKCS12 decoding error."; break; default: - SWIFT_LOG(warning) << "Unknown error." << std::endl; + SWIFT_LOG(warning) << "Unknown error."; } if (securityError != errSecSuccess) { @@ -110,20 +110,20 @@ SecureTransportContext::SecureTransportContext(bool checkCertificateRevocation) // set IO callbacks error = SSLSetIOFuncs(sslContext_.get(), &SecureTransportContext::SSLSocketReadCallback, &SecureTransportContext::SSLSocketWriteCallback); if (error != noErr) { - SWIFT_LOG(error) << "Unable to set IO functions to SSL context." << std::endl; + SWIFT_LOG(error) << "Unable to set IO functions to SSL context."; sslContext_.reset(); } error = SSLSetConnection(sslContext_.get(), this); if (error != noErr) { - SWIFT_LOG(error) << "Unable to set connection to SSL context." << std::endl; + SWIFT_LOG(error) << "Unable to set connection to SSL context."; sslContext_.reset(); } error = SSLSetSessionOption(sslContext_.get(), kSSLSessionOptionBreakOnServerAuth, true); if (error != noErr) { - SWIFT_LOG(error) << "Unable to set kSSLSessionOptionBreakOnServerAuth on session." << std::endl; + SWIFT_LOG(error) << "Unable to set kSSLSessionOptionBreakOnServerAuth on session."; sslContext_.reset(); } } @@ -154,19 +154,19 @@ std::string SecureTransportContext::stateToString(State state) { } void SecureTransportContext::setState(State newState) { - SWIFT_LOG(debug) << "Switch state from " << stateToString(state_) << " to " << stateToString(newState) << "." << std::endl; + SWIFT_LOG(debug) << "Switch state from " << stateToString(state_) << " to " << stateToString(newState) << "."; state_ = newState; } void SecureTransportContext::connect() { - SWIFT_LOG_ASSERT(state_ == None, error) << "current state '" << stateToString(state_) << " invalid." << std::endl; + SWIFT_LOG_ASSERT(state_ == None, error) << "current state '" << stateToString(state_) << " invalid."; if (clientCertificate_) { CFArrayRef certs = CreateClientCertificateChainAsCFArrayRef(clientCertificate_); if (certs) { std::shared_ptr<CFArray> certRefs(certs, CFRelease); OSStatus result = SSLSetCertificate(sslContext_.get(), certRefs.get()); if (result != noErr) { - SWIFT_LOG(error) << "SSLSetCertificate failed with error " << result << "." << std::endl; + SWIFT_LOG(error) << "SSLSetCertificate failed with error " << result << "."; } } } @@ -174,23 +174,23 @@ void SecureTransportContext::connect() { } void SecureTransportContext::processHandshake() { - SWIFT_LOG_ASSERT(state_ == None || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid." << std::endl; + SWIFT_LOG_ASSERT(state_ == None || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid."; OSStatus error = SSLHandshake(sslContext_.get()); if (error == errSSLWouldBlock) { setState(Handshake); } else if (error == noErr) { - SWIFT_LOG(debug) << "TLS handshake successful." << std::endl; + SWIFT_LOG(debug) << "TLS handshake successful."; setState(HandshakeDone); onConnected(); } else if (error == errSSLPeerAuthCompleted) { - SWIFT_LOG(debug) << "Received server certificate. Start verification." << std::endl; + SWIFT_LOG(debug) << "Received server certificate. Start verification."; setState(Handshake); verifyServerCertificate(); } else { - SWIFT_LOG(debug) << "Error returned from SSLHandshake call is " << error << "." << std::endl; + SWIFT_LOG(debug) << "Error returned from SSLHandshake call is " << error << "."; fatalError(nativeToTLSError(error), std::make_shared<CertificateVerificationError>()); } } @@ -226,13 +226,13 @@ void SecureTransportContext::verifyServerCertificate() { OSStatus cssmResult = 0; switch(trustResult) { case kSecTrustResultUnspecified: - SWIFT_LOG(warning) << "Successful implicit validation. Result unspecified." << std::endl; + SWIFT_LOG(warning) << "Successful implicit validation. Result unspecified."; break; case kSecTrustResultProceed: - SWIFT_LOG(warning) << "Validation resulted in explicitly trusted." << std::endl; + SWIFT_LOG(warning) << "Validation resulted in explicitly trusted."; break; case kSecTrustResultRecoverableTrustFailure: - SWIFT_LOG(warning) << "recoverable trust failure" << std::endl; + SWIFT_LOG(warning) << "recoverable trust failure"; error = SecTrustGetCssmResultCode(trust, &cssmResult); if (error == errSecSuccess) { verificationError_ = CSSMErrorToVerificationError(cssmResult); @@ -304,8 +304,8 @@ bool SecureTransportContext::setClientCertificate(CertificateWithKey::ref cert) } void SecureTransportContext::handleDataFromNetwork(const SafeByteArray& data) { - SWIFT_LOG(debug) << std::endl; - SWIFT_LOG_ASSERT(state_ == HandshakeDone || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid." << std::endl; + SWIFT_LOG(debug); + SWIFT_LOG_ASSERT(state_ == HandshakeDone || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid."; append(readingBuffer_, data); @@ -332,7 +332,7 @@ void SecureTransportContext::handleDataFromNetwork(const SafeByteArray& data) { break; } else { - SWIFT_LOG(error) << "SSLRead failed with error " << error << ", read bytes: " << bytesRead << "." << std::endl; + SWIFT_LOG(error) << "SSLRead failed with error " << error << ", read bytes: " << bytesRead << "."; fatalError(std::make_shared<TLSError>(), std::make_shared<CertificateVerificationError>()); return; } @@ -347,7 +347,7 @@ void SecureTransportContext::handleDataFromNetwork(const SafeByteArray& data) { } break; case Error: - SWIFT_LOG(debug) << "Igoring received data in error state." << std::endl; + SWIFT_LOG(debug) << "Igoring received data in error state."; break; } } @@ -358,13 +358,13 @@ void SecureTransportContext::handleDataFromApplication(const SafeByteArray& data OSStatus error = SSLWrite(sslContext_.get(), data.data(), data.size(), &processedBytes); switch(error) { case errSSLWouldBlock: - SWIFT_LOG(warning) << "Unexpected because the write callback does not block." << std::endl; + SWIFT_LOG(warning) << "Unexpected because the write callback does not block."; return; case errSSLClosedGraceful: case noErr: return; default: - SWIFT_LOG(warning) << "SSLWrite returned error code: " << error << ", processed bytes: " << processedBytes << std::endl; + SWIFT_LOG(warning) << "SSLWrite returned error code: " << error << ", processed bytes: " << processedBytes; fatalError(std::make_shared<TLSError>(), std::shared_ptr<CertificateVerificationError>()); } } @@ -376,7 +376,7 @@ std::vector<Certificate::ref> SecureTransportContext::getPeerCertificateChain() typedef boost::remove_pointer<SecTrustRef>::type SecTrust; std::shared_ptr<SecTrust> securityTrust; - SecTrustRef secTrust = nullptr;; + SecTrustRef secTrust = nullptr; OSStatus error = SSLCopyPeerTrust(sslContext_.get(), &secTrust); if (error == noErr) { securityTrust = std::shared_ptr<SecTrust>(secTrust, CFRelease); @@ -390,7 +390,7 @@ std::vector<Certificate::ref> SecureTransportContext::getPeerCertificateChain() } } else { - SWIFT_LOG(warning) << "Failed to obtain peer trust structure; error = " << error << "." << std::endl; + SWIFT_LOG(warning) << "Failed to obtain peer trust structure; error = " << error << "."; } } @@ -402,7 +402,7 @@ CertificateVerificationError::ref SecureTransportContext::getPeerCertificateVeri } ByteArray SecureTransportContext::getFinishMessage() const { - SWIFT_LOG(warning) << "Access to TLS handshake finish message is not part of OS X Secure Transport APIs." << std::endl; + SWIFT_LOG(warning) << "Access to TLS handshake finish message is not part of OS X Secure Transport APIs."; return ByteArray(); } @@ -453,42 +453,42 @@ std::shared_ptr<CertificateVerificationError> SecureTransportContext::CSSMErrorT std::shared_ptr<CertificateVerificationError> error; switch(resultCode) { case CSSMERR_TP_NOT_TRUSTED: - SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_NOT_TRUSTED" << std::endl; + SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_NOT_TRUSTED"; error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::Untrusted); break; case CSSMERR_TP_CERT_NOT_VALID_YET: - SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_NOT_VALID_YET" << std::endl; + SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_NOT_VALID_YET"; error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::NotYetValid); break; case CSSMERR_TP_CERT_EXPIRED: - SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_EXPIRED" << std::endl; + SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_EXPIRED"; error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::Expired); break; case CSSMERR_TP_CERT_REVOKED: - SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_REVOKED" << std::endl; + SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_REVOKED"; error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::Revoked); break; case CSSMERR_TP_VERIFY_ACTION_FAILED: - SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_VERIFY_ACTION_FAILED" << std::endl; + SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_VERIFY_ACTION_FAILED"; break; case CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK: - SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK" << std::endl; + SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK"; if (checkCertificateRevocation_) { error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::RevocationCheckFailed); } break; case CSSMERR_APPLETP_OCSP_UNAVAILABLE: - SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_OCSP_UNAVAILABLE" << std::endl; + SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_OCSP_UNAVAILABLE"; if (checkCertificateRevocation_) { error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::RevocationCheckFailed); } break; case CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE: - SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE" << std::endl; + SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE"; error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::InvalidPurpose); break; default: - SWIFT_LOG(warning) << "unhandled CSSM error: " << resultCode << ", CSSM_TP_BASE_TP_ERROR: " << CSSM_TP_BASE_TP_ERROR << std::endl; + SWIFT_LOG(warning) << "unhandled CSSM error: " << resultCode << ", CSSM_TP_BASE_TP_ERROR: " << CSSM_TP_BASE_TP_ERROR; error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::UnknownError); break; } diff --git a/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp index 1fac1fb..ac399e1 100644 --- a/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp +++ b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -26,8 +26,10 @@ bool SecureTransportContextFactory::canCreate() const { return true; } -TLSContext* SecureTransportContextFactory::createTLSContext(const TLSOptions& /* tlsOptions */) { - return new SecureTransportContext(checkCertificateRevocation_); +std::unique_ptr<TLSContext> SecureTransportContextFactory::createTLSContext(const TLSOptions& /* tlsOptions */, TLSContext::Mode mode) { + // TLS server mode is not supported for the SecureTransport backend yet. + assert(mode == TLSContext::Mode::Client); + return std::unique_ptr<TLSContext>(new SecureTransportContext(checkCertificateRevocation_)); } void SecureTransportContextFactory::setCheckCertificateRevocation(bool b) { @@ -37,7 +39,7 @@ void SecureTransportContextFactory::setCheckCertificateRevocation(bool b) { void SecureTransportContextFactory::setDisconnectOnCardRemoval(bool b) { disconnectOnCardRemoval_ = b; if (disconnectOnCardRemoval_) { - SWIFT_LOG(warning) << "Smart cards have not been tested yet" << std::endl; + SWIFT_LOG(warning) << "Smart cards have not been tested yet"; } } diff --git a/Swiften/TLS/SecureTransport/SecureTransportContextFactory.h b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.h index 74c598f..b86639a 100644 --- a/Swiften/TLS/SecureTransport/SecureTransportContextFactory.h +++ b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.h @@ -1,11 +1,13 @@ /* - * Copyright (c) 2015 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once +#include <memory> + #include <Swiften/TLS/TLSContextFactory.h> namespace Swift { @@ -17,7 +19,7 @@ class SecureTransportContextFactory : public TLSContextFactory { virtual bool canCreate() const; - virtual TLSContext* createTLSContext(const TLSOptions& tlsOptions); + virtual std::unique_ptr<TLSContext> createTLSContext(const TLSOptions& tlsOptions, TLSContext::Mode mode = TLSContext::Mode::Client); virtual void setCheckCertificateRevocation(bool b); virtual void setDisconnectOnCardRemoval(bool b); diff --git a/Swiften/TLS/ServerIdentityVerifier.cpp b/Swiften/TLS/ServerIdentityVerifier.cpp index 226e94b..18ea2aa 100644 --- a/Swiften/TLS/ServerIdentityVerifier.cpp +++ b/Swiften/TLS/ServerIdentityVerifier.cpp @@ -12,7 +12,7 @@ namespace Swift { -ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter) : domainValid(false) { +ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter, bool checkServer) : domainValid(false), checkServer_(checkServer) { domain = jid.getDomain(); boost::optional<std::string> domainResult = idnConverter->getIDNAEncoded(domain); if (!!domainResult) { @@ -36,12 +36,14 @@ bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) { } hasSAN |= !dnsNames.empty(); + std::string prefix = (checkServer_) ? "_xmpp-server." : "_xmpp-client."; + // SRV names std::vector<std::string> srvNames = certificate->getSRVNames(); for (const auto& srvName : srvNames) { // Only match SRV names that begin with the service; this isn't required per // spec, but we're being purist about this. - if (boost::starts_with(srvName, "_xmpp-client.") && matchesDomain(srvName.substr(std::string("_xmpp-client.").size(), srvName.npos))) { + if (boost::starts_with(srvName, prefix) && matchesDomain(srvName.substr(prefix.size(), srvName.npos))) { return true; } } @@ -80,15 +82,15 @@ bool ServerIdentityVerifier::matchesDomain(const std::string& s) const { if (dotIndex != matchDomain.npos) { matchDomain = matchDomain.substr(dotIndex + 1, matchDomain.npos); } - return matchString == matchDomain; + return boost::iequals(matchString, matchDomain); } else { - return s == encodedDomain; + return boost::iequals(s, encodedDomain); } } bool ServerIdentityVerifier::matchesAddress(const std::string& s) const { - return s == domain; + return boost::iequals(s, domain); } } diff --git a/Swiften/TLS/ServerIdentityVerifier.h b/Swiften/TLS/ServerIdentityVerifier.h index f40c683..f2cf46f 100644 --- a/Swiften/TLS/ServerIdentityVerifier.h +++ b/Swiften/TLS/ServerIdentityVerifier.h @@ -18,7 +18,7 @@ namespace Swift { class SWIFTEN_API ServerIdentityVerifier { public: - ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter); + ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter, bool checkServer=false); bool certificateVerifies(Certificate::ref); @@ -30,5 +30,6 @@ namespace Swift { std::string domain; std::string encodedDomain; bool domainValid; + bool checkServer_; }; } diff --git a/Swiften/TLS/TLSContext.cpp b/Swiften/TLS/TLSContext.cpp index 2763547..fd31c2d 100644 --- a/Swiften/TLS/TLSContext.cpp +++ b/Swiften/TLS/TLSContext.cpp @@ -1,19 +1,53 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/TLS/TLSContext.h> +#include <cassert> + namespace Swift { TLSContext::~TLSContext() { } +void TLSContext::accept() { + assert(false); +} + +void TLSContext::connect(const std::string& /* serverName */) { + assert(false); +} + +bool TLSContext::setCertificateChain(const std::vector<std::shared_ptr<Certificate>>& /* certificateChain */) { + assert(false); + return false; +} + +bool TLSContext::setPrivateKey(const PrivateKey::ref& /* privateKey */) { + assert(false); + return false; +} + +bool TLSContext::setDiffieHellmanParameters(const ByteArray& /*parametersInOpenSslDer*/) { + assert(false); + return false; +} + +void TLSContext::setAbortTLSHandshake(bool /* abort */) { + assert(false); +} + Certificate::ref TLSContext::getPeerCertificate() const { std::vector<Certificate::ref> chain = getPeerCertificateChain(); return chain.empty() ? Certificate::ref() : chain[0]; } +ByteArray TLSContext::getPeerFinishMessage() const { + assert(false); + return ByteArray(); +} + } diff --git a/Swiften/TLS/TLSContext.h b/Swiften/TLS/TLSContext.h index 79e3485..f2dbdce 100644 --- a/Swiften/TLS/TLSContext.h +++ b/Swiften/TLS/TLSContext.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -15,6 +15,7 @@ #include <Swiften/TLS/Certificate.h> #include <Swiften/TLS/CertificateVerificationError.h> #include <Swiften/TLS/CertificateWithKey.h> +#include <Swiften/TLS/PrivateKey.h> #include <Swiften/TLS/TLSError.h> namespace Swift { @@ -23,9 +24,21 @@ namespace Swift { public: virtual ~TLSContext(); + virtual void accept(); virtual void connect() = 0; + virtual void connect(const std::string& serverName); + + virtual bool setCertificateChain(const std::vector<std::shared_ptr<Certificate>>& /* certificateChain */); + virtual bool setPrivateKey(const PrivateKey::ref& /* privateKey */); virtual bool setClientCertificate(CertificateWithKey::ref cert) = 0; + virtual bool setDiffieHellmanParameters(const ByteArray& parametersInOpenSslDer); + + /** + * This method can be used during the \ref onServerNameRequested signal, + * to report an error about an unknown host back to the requesting client. + */ + virtual void setAbortTLSHandshake(bool /* abort */); virtual void handleDataFromNetwork(const SafeByteArray&) = 0; virtual void handleDataFromApplication(const SafeByteArray&) = 0; @@ -35,11 +48,19 @@ namespace Swift { virtual CertificateVerificationError::ref getPeerCertificateVerificationError() const = 0; virtual ByteArray getFinishMessage() const = 0; + virtual ByteArray getPeerFinishMessage() const; + + public: + enum class Mode { + Client, + Server + }; public: boost::signals2::signal<void (const SafeByteArray&)> onDataForNetwork; boost::signals2::signal<void (const SafeByteArray&)> onDataForApplication; boost::signals2::signal<void (std::shared_ptr<TLSError>)> onError; boost::signals2::signal<void ()> onConnected; + boost::signals2::signal<void (const std::string&)> onServerNameRequested; }; } diff --git a/Swiften/TLS/TLSContextFactory.cpp b/Swiften/TLS/TLSContextFactory.cpp index d196e15..91e60d6 100644 --- a/Swiften/TLS/TLSContextFactory.cpp +++ b/Swiften/TLS/TLSContextFactory.cpp @@ -6,9 +6,16 @@ #include <Swiften/TLS/TLSContextFactory.h> +#include <cassert> + namespace Swift { TLSContextFactory::~TLSContextFactory() { } +ByteArray TLSContextFactory::convertDHParametersFromPEMToDER(const std::string& /* pem */) { + assert(false); + return ByteArray(); +} + } diff --git a/Swiften/TLS/TLSContextFactory.h b/Swiften/TLS/TLSContextFactory.h index d2ffe15..5f70541 100644 --- a/Swiften/TLS/TLSContextFactory.h +++ b/Swiften/TLS/TLSContextFactory.h @@ -1,25 +1,29 @@ /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once +#include <memory> + #include <Swiften/Base/API.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/TLS/TLSContext.h> #include <Swiften/TLS/TLSOptions.h> namespace Swift { - class TLSContext; - class SWIFTEN_API TLSContextFactory { public: virtual ~TLSContextFactory(); virtual bool canCreate() const = 0; - virtual TLSContext* createTLSContext(const TLSOptions& tlsOptions) = 0; + virtual std::unique_ptr<TLSContext> createTLSContext(const TLSOptions& tlsOptions, TLSContext::Mode = TLSContext::Mode::Client) = 0; virtual void setCheckCertificateRevocation(bool b) = 0; virtual void setDisconnectOnCardRemoval(bool b) = 0; + + virtual ByteArray convertDHParametersFromPEMToDER(const std::string& pem); }; } diff --git a/Swiften/TLS/TLSError.h b/Swiften/TLS/TLSError.h index ae775e6..9e4af2f 100644 --- a/Swiften/TLS/TLSError.h +++ b/Swiften/TLS/TLSError.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Isode Limited. + * Copyright (c) 2012-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -7,6 +7,7 @@ #pragma once #include <memory> +#include <string> #include <Swiften/Base/API.h> #include <Swiften/Base/Error.h> @@ -18,16 +19,23 @@ namespace Swift { enum Type { UnknownError, - CertificateCardRemoved + CertificateCardRemoved, + AcceptFailed, + ConnectFailed }; - TLSError(Type type = UnknownError) : type(type) {} + TLSError(Type type = UnknownError, std::string message = "") : type_(type), message_(std::move(message)) {} Type getType() const { - return type; + return type_; + } + + const std::string& getMessage() const { + return message_; } private: - Type type; + Type type_; + std::string message_; }; } diff --git a/Swiften/TLS/TLSOptions.h b/Swiften/TLS/TLSOptions.h index dd7e920..e3faaf9 100644 --- a/Swiften/TLS/TLSOptions.h +++ b/Swiften/TLS/TLSOptions.h @@ -7,8 +7,11 @@ #pragma once namespace Swift { + class TLSContext; + class Certificate; - struct TLSOptions { + class TLSOptions { + public: TLSOptions() : schannelTLS1_0Workaround(false) { } @@ -21,5 +24,54 @@ namespace Swift { */ bool schannelTLS1_0Workaround; + /** + * OpenSSL configuration flags + */ + boost::optional<bool> workaroundMicrosoftSessID; + boost::optional<bool> workaroundNetscapeChallenge; + boost::optional<bool> workaroundNetscapeReuseCipherChange; + boost::optional<bool> workaroundSSLRef2ReuseCertType; + boost::optional<bool> workaroundMicrosoftBigSSLv3Buffer; + boost::optional<bool> workaroundSSLeay080ClientDH; + boost::optional<bool> workaroundTLSD5; + boost::optional<bool> workaroundTLSBlockPadding; + boost::optional<bool> workaroundDontInsertEmptyFragments; + boost::optional<bool> workaroundAll; + boost::optional<bool> suppressSSLv2; + boost::optional<bool> suppressSSLv3; + boost::optional<bool> suppressTLSv1; + boost::optional<bool> disableTLSRollBackBug; + boost::optional<bool> singleDHUse; + + /** + * Other OpenSSL configuration items + */ + boost::optional<std::string> cipherSuites; + boost::optional<std::string> context; + boost::optional<int> sessionCacheTimeout; + boost::optional<int> verifyDepth; + + enum class VerifyMode { + None, + Required, + Optional + }; + boost::optional<VerifyMode> verifyMode; + + /** + * Callback for certificate verification + */ + + boost::optional<std::function<int(const TLSContext *)>> verifyCertificateCallback; + + /** + * Allows specification of application-specific Trust Anchors + */ + boost::optional<std::vector<std::shared_ptr<Certificate>>> trustAnchors; + + /** + * Turns off automatic loading of system Trust Anchors + */ + bool ignoreSystemTrustAnchors = false; }; } diff --git a/Swiften/TLS/UnitTest/CertificateTest.cpp b/Swiften/TLS/UnitTest/CertificateTest.cpp index aac2cfb..d5bf210 100644 --- a/Swiften/TLS/UnitTest/CertificateTest.cpp +++ b/Swiften/TLS/UnitTest/CertificateTest.cpp @@ -73,7 +73,7 @@ zqCzpwGL auto certificateChain = tlsFactories.getCertificateFactory()->createCertificateChain(createByteArray(PEMCertificate)); CPPUNIT_ASSERT_EQUAL(size_t(1), certificateChain.size()); - auto certificate = certificateChain[0]; + auto certificate = certificateChain[0].get(); CPPUNIT_ASSERT_EQUAL(std::string("/CN=montague.example"), certificate->getSubjectName()); } diff --git a/Swiften/TLS/UnitTest/ClientServerTest.cpp b/Swiften/TLS/UnitTest/ClientServerTest.cpp new file mode 100644 index 0000000..a356dcf --- /dev/null +++ b/Swiften/TLS/UnitTest/ClientServerTest.cpp @@ -0,0 +1,883 @@ +/* + * Copyright (c) 2010-2019 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <map> +#include <memory> +#include <utility> +#include <vector> + +#include <boost/variant.hpp> + +#include <gtest/gtest.h> + +#include <Swiften/Base/Log.h> +#include <Swiften/TLS/CertificateFactory.h> +#include <Swiften/TLS/PlatformTLSFactories.h> +#include <Swiften/TLS/TLSContext.h> +#include <Swiften/TLS/TLSContextFactory.h> +#include <Swiften/TLS/TLSOptions.h> + +using namespace Swift; +namespace { + + +std::map<std::string, std::string> certificatePEM = { + {"montague.example", +R"(-----BEGIN CERTIFICATE----- +MIIEsjCCApoCCQCbkjlQfUqPtTANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDDBBt +b250YWd1ZS5leGFtcGxlMB4XDTE4MDExODE2NTMxMloXDTQ1MDYwNDE2NTMxMlow +GzEZMBcGA1UEAwwQbW9udGFndWUuZXhhbXBsZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBALAx5xuEYOjDJ9QHMvwRuDzxbHl1zR97SJFPAkmD8xH0sC61 +DNRyUvRq6UXb4znhqeqrNuZ9PV47GyK2Dpy/c/MY5NE3m/c+Z1tUnrcqyCkxITIn +jdSI/elc9yhtMXX6lRi68BdPJnj/9+6trW0cWHlKEgnaSTAgCVB+4Dg9mjTIroCa +HLoAKhr2zS7Ihs28aWb0cSvZ+qFgQhr7FGP2kfssTTQYyRPn9uHhtyWH6RqSv5x9 +BBGZWN5GtjkJvupcYWLt8ftuQyFpwEeEz5cgtiyKgsfz9CYvS9/OcwdLQr4z5Zq6 +eKxsog9GdwIi1Us4KR0X6tKu9ze42iEWF+foEWFP9/bjrVK/tt5lTSKnenk0nA8I +amkG0btNAGihDti3lv60bGpd3B2/uh4gzzT2buXdf0EaybCt52MIr8xkwMU0Tkri +RAYchdS8U8sekWG5Lg9m3L2BDa8/TKS/WflJhGcZeInGQslgIx7fCgO1M7Zr50pO +wSURPXpvqUkXNEBy639UQEUsnBhntEQwZWx/6x6Ma/U5a5dL6qbtEJjlwIvS+nl9 +3w26g3DvWydNMCtZIVhgdrl+dZs+Uw5eA3QkHkDTSfYvQk7X5SYL0J5ZxwBvU9r1 +ED054+TAEuX2euiRA37xLhxonj8BaKkPQGlAHCLZaZPmNJWkNxElJhMoCfqBAgMB +AAEwDQYJKoZIhvcNAQELBQADggIBAF+FNyW3nVeQeugBMksIhj7EMJl1AEKi0+78 +ZPsYX3CDbc/8GRZoTg/EWSiwPCBYc9VsxuKtODEYABCZgk7LnSBYoEauJDKWqkgM +UOKPJI2hu7mIK7FJpjvEZe2MnRRA63oI/NVDJm8T2clrv/vPkY+ppsVl0toC0SpH +/3dF5c65vYI19rTJraRU6kIrrgxFBzxzpn07LGh2rrOCQfy2umTSRMwz3ORAFfmi ++Kek1Dt7c+JVJ0ivCwhhc8MKza3JS2MuDfVWGnXtDLb81Ai0t4tQfLKvZEcgW+lh +Drz9gv22buwncWL/IxtuhzyILtDSDKAYFbhfG6IAQut9BjMgpMnKrBCDlOLJl08K +tgj2h7vUKyNSt3ndcSAtXjr6FD7+xPExJuyn/MgLONGGAZoZHFB4QO90wQaXxMPh +7rnjUtzfLR8qkDmX8ZB4f4VOWpDWo4hBpgjTk0gYfzEkrh+zTqE9reh7CZ1WzwXO +KnIBU2dZOE+XsJe49lW106DLqGzKRuQMUAwFMb7C7Nlg9GKTnvi41o+g6YE+MgxR +uPKu891pCBtnDxZiWPT+7Fa/9UXxdIOTVIHW6utSWiWYbeNwXSmIm2ShfmNfWj9m +x1JgJrFB6daWGR9aDBeDVRhgL6Z35lH7xI62pLJ4o2d2Y/9dUWAJfz5O8opeCyrF +zqCzpwGL +-----END CERTIFICATE----- +)"}, + {"capulet.example", +R"(-----BEGIN CERTIFICATE----- +MIIEsDCCApgCCQDUGdmqHfGngTANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9j +YXB1bGV0LmV4YW1wbGUwHhcNMTgwMTE4MTY1NjEyWhcNNDUwNjA0MTY1NjEyWjAa +MRgwFgYDVQQDDA9jYXB1bGV0LmV4YW1wbGUwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCgA/CpV7UGqUdjhEVoMjFIZ6Ca/C7utrVPAqBvE14eiurIhQrQ +AmYeC9zA4/uXCdqkGq/a/RbF3OOCKLRUejCcynb0EnxiHxHa48ZsvLbKCK6guoXE +pWnaZsmRpvJrBB2z6ohmxRuaDuc5CJT+Oq8AFPp3StTAFDo3Cju3fsGZPkNpCGbj +ELwk4ok9INtEuTrMEmHZTD+VfjpXauUfN4ygKaPXJanCuxuifyin403BWgd8igkD +oSCWxoDFMy3HGbh/NU+nJPJ23FxVC39RdDG3elvjNFpSZnALbiMnyor7YjF5TN93 +1ZWwn3VTnl7DnFquEbKbYyVFUzRII8Cd1TzKOL48rVLrCAqMXwm6YFtST6qPb9TZ +0SX8qZGCwBfHV5OeS0ZgiBMMlmUPYcw9MlyvZnYyDPCOoPWmhEqd2gQzn//7hzb5 +mriCEyfcMzAqohylBNHXUVZTx5KcazJz6oOYdWEs1jfSXNKefgSWlgeoG2fgTXPN +1OkQVS+FOiI0VCAIwR+vxhG3hVTz3kzXWvEt7M51faaHWWlnSzOrbSuj3f0ibS5J +cj6ClyzOQRQDwzofyZ7oPWh6No/XkepVIn3HTTlnj1/8e6VsH+EBKSzoX2XvWPkO +GAZEGHKiKh944u6d6mW37BPD2oKyusP3uPL5j2Fdm+m0HkP3/7yw+5EFVQIDAQAB +MA0GCSqGSIb3DQEBCwUAA4ICAQCfCGK4iDo8H0i12wBC0+6GB9NBmgn8P09AUN0l +tQjZPaqZCtLtBBqOrAaZQBQMfI0QAm5/h/VkhMvz5HQjqmQhI2drSDOmarYzOGgY +yVItkEwtLEVhiGoeJ+L3Smosoqq6QFjcDzH7UzPTrJNspnY+09+m53pJggh41zzt +1TOU+QasaB5oGopFaFUUlwjHAc7FpZgEd+tV6j0cpdT3GabVkkoLg01Z+0mqkpLD +OjRBKJX8XvZ38VESsy3gWpcXnDq03n+8OgZo4R9SEcyyxjWbyb+qg2dzbQvRB2Va +QNoXp5EzemXvFSulhR+TfDk2K1h45BurikRQxDi8LpBTUsCMwiqXdem68HOlTwLi +/kMWbnVBcdurYcWVSwlJU4EJcTEdk51JStO1V0nAA0nCwn/iEhY8I6BitnrcCJ5e +4CGVWr+zAm8DBjaFMTzy46Q5NcT0hwnHGN6T6l4aMcRggIK9anRbXCn6dSzma1pd +R5N/Do00FTpyZGcUlVPnSlIfZVl7y/9XEO1n6xDJURrefL1JrM7UMyB17jA8HMq3 +S05kF7XRpludRB4QkAJt5BNNv6BPP7HPIKyR/rq94ONvzVPAo7uASyFE2sMBsfwP +pXAI1LVolPCoUC13jEkKdmc8kMSxU+XtsvFryNhkfQtZfSg+nBRFYptFE7GrZ9WY +GMSL4g== +-----END CERTIFICATE----- +)"}, + {"casigned.example.com", +R"(-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIJAPEpYlUWlJW8MA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV +BAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMQ4wDAYDVQQKDAVJc29kZTEPMA0GA1UE +AwwGVGVzdENBMB4XDTE4MDExODAwMDAwMFoXDTQ5MDExODAwMDAwMFowTjELMAkG +A1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQxDjAMBgNVBAoMBUlzb2RlMR0wGwYD +VQQDDBRjYXNpZ25lZC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKw4iCscGIDCc55mwxgJsn/v2GEorpE9zHYsMfl6px2aRLGgB8ki +xYyNiEPA/b/ilShRp7pp22LPb5O3aOVVWzAs5FTvPdFY2vS8YIxR6XSKXO3u4Q8/ +w8CR0AbKpeCtL0TwSl1u76nq6ORMep6QGsTjDLQ7wUwdShL4qV4nIGxJWon/5GI0 +nl4Xr/wzmysbMjAMSiWOR90DNZMvqQBBhQcJdqdirc+whR8gOhIMvJBn5jlMuFEB +zL/bR+kG/zFuD0EMsMTy6TETefYuxeWmhuzQENyAV5+1v48G/1a9zzN9Y0xQ6T0N +ppbLzq+/zhxT1eBN8/O0bAGUzzk1VSFvouECAwEAAaNQME4wHQYDVR0OBBYEFCnR +umlxjdaUvcpf77zahrDmPnt1MB8GA1UdIwQYMBaAFAbbhPAKtD5YzxQqGH2Um4/f +OmdFMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEPrTTKS+7A4dJJh +gSAS44ZYyR8/kt9Y3V4qxJM2xrOrW6rM8N15n2i/osSy0AYHiPuvgDG+D7hLt5Ct +7jZKrp3JRsBaU8//9k6+euwVyWS+EKo/eb7qtSNibZOk7GwrXekJMbRXz1cHTKnW +0R8UG+EMkOqKQh5dhWuEBXff9SYLTALf0/i+/Ixl3b9rQ6zpY/7UwBdlWLaliM1i +odIgVu1XRE6Su+bGMa1L5ArniN0LMFq9Mxag2H0V7Kru7vIvbBkL7U6tbi7u26hv +q4kUFROW2U2C02FTmJeSEBvWoDyMoVjKkmaTL0+vDSQRPGtCsvCgaCXgOwU2Po9s +8jjHQxg= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIJAPEpYlUWlJW7MA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV +BAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMQ4wDAYDVQQKDAVJc29kZTEPMA0GA1UE +AwwGVGVzdENBMB4XDTE4MDExODAwMDAwMFoXDTQ5MDExODAwMDAwMFowQDELMAkG +A1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQxDjAMBgNVBAoMBUlzb2RlMQ8wDQYD +VQQDDAZUZXN0Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCiCA+9 +bdSHFNPOgbsnhrKbLJP+1lxWTe06+ExwJA3QgCKsR13MsAK8rhmuNB0k8ZIFJL+c +yUOUgw0370eP940QAtK+HinJpvaGEZKEwaB8VUCjzFTb7zUBio1Y7B45aawEV3qT +Lzcnil3f7vPIxnAoaptzPriySdggIsimj+y6AWum5FUPyfZzF7EnYfF/VH8V/ZNX +fku7PPbaeDHvu4EF/0s8P+/l6jddz8dqbDMjH3GDM8sjryWPQPNDjKZ1x80BIdyq +s9m/kXqIIySNwdIa/X+nYTMchUa5y46n2N4n0RA4F+rf+Ni1Cxk9Ejmmz5hinV+t +Yzh6jsbB7yZiqEnzAgMBAAGjUDBOMB0GA1UdDgQWBBQG24TwCrQ+WM8UKhh9lJuP +3zpnRTAfBgNVHSMEGDAWgBQG24TwCrQ+WM8UKhh9lJuP3zpnRTAMBgNVHRMEBTAD +AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBMHQ3WMEhkEc0VoOEw3mbsngt1eyJz+nFM +FeGdRb7JSwpJfe/yBxyGodGyHsQJPVole6sUdq8S1QGT547PkgDHc6Btoq96Mahq +brgfx1JL9a1F8qaqcENebHc7ltW8kps4xtdlithfo4nKaciYZ5mKbug+AFv569mb +LU3F282dyW1dLa7+L8dGbb8Ntpnp0BB0Cotm4GX3Xi6Y+fikouqcmXj7vX+uMhG4 +pQpXqb2ML1Gev4w6XUsnls+OJok97x99NsOcqtwqsLJS/sg0cpwrgZ9+50hQKlHO +8H6hhNjGBkvpIiNsWb9UOc+Id86J+drs9Ed93Eyyvwnq2XcqPGF3 +-----END CERTIFICATE-----)"}}; +std::map<std::string, std::string> privateKeyPEM = { + {"montague.example", +R"(-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCwMecbhGDowyfU +BzL8Ebg88Wx5dc0fe0iRTwJJg/MR9LAutQzUclL0aulF2+M54anqqzbmfT1eOxsi +tg6cv3PzGOTRN5v3PmdbVJ63KsgpMSEyJ43UiP3pXPcobTF1+pUYuvAXTyZ4//fu +ra1tHFh5ShIJ2kkwIAlQfuA4PZo0yK6Amhy6ACoa9s0uyIbNvGlm9HEr2fqhYEIa ++xRj9pH7LE00GMkT5/bh4bclh+kakr+cfQQRmVjeRrY5Cb7qXGFi7fH7bkMhacBH +hM+XILYsioLH8/QmL0vfznMHS0K+M+WaunisbKIPRncCItVLOCkdF+rSrvc3uNoh +Fhfn6BFhT/f2461Sv7beZU0ip3p5NJwPCGppBtG7TQBooQ7Yt5b+tGxqXdwdv7oe +IM809m7l3X9BGsmwredjCK/MZMDFNE5K4kQGHIXUvFPLHpFhuS4PZty9gQ2vP0yk +v1n5SYRnGXiJxkLJYCMe3woDtTO2a+dKTsElET16b6lJFzRAcut/VEBFLJwYZ7RE +MGVsf+sejGv1OWuXS+qm7RCY5cCL0vp5fd8NuoNw71snTTArWSFYYHa5fnWbPlMO +XgN0JB5A00n2L0JO1+UmC9CeWccAb1Pa9RA9OePkwBLl9nrokQN+8S4caJ4/AWip +D0BpQBwi2WmT5jSVpDcRJSYTKAn6gQIDAQABAoICABqc/wZ2AVlHGP36tGXEm2qB +INxbwcbujTB9mZ/XEWD176KucCiquAL5HxERPIointK2V82Kvzk7fkbI7v4YIQBo +Ey/S0XkP8Panmm2aRa+LHzN/K/odUxTrmN1/WMg0OE8K9Xbf2rTOHPntO9POQ0LW +wFDCqulc/WsuLtnv3Bn68fi0zn/9xF5cRvO5EDuFKPqHE40HGMdFTdbbc+IBfV1N +/L9QuxaJpA3MVSiTFc+QuOZ/L50k53pzfdSxtyeZGpCh1jofFn62hXeIBP8TztB9 +f3GKVKdr328HtPI2GPe3yQeNAOsyYWwjPZiSAFujOPqPAUYfbXH6NuBmgOfjcrRb +AhOv9F1VNi+G56NJ6jo/NPygD+LYQdIKs5rv3E4ehyQzbu+SoGyVCnF3qm0cvz+v +tB5/gNiWiyRhNF94DZHlceDMQSdyB/pfTZsKZ44Yv44Bzl54YbzR8yr/ZKzAj6gt +5lwAqCIcdRj4i5DmIa7psj3iYWe9hYV7f+zwdosPKibRvO9FpvDCbb7biIPkMozw +cYH6QlSsZ+XsK/Z3WPFPq0wHOgoWW9Tr8LYyQxGjLO+xD8ziQ7Rp0KApEunuO29s +CPXj+l1HqNmAK2LkdNI3c/yStlaAcOzYD6pauciHWlTnIGZG8aHV6elIjK0C/h7B +3GndVc0TbewbP0bL56QBAoIBAQDU/yl4nlELhpoI1WW8v/FcDnc3V5dBilJ3LQtp +a3SKBcNWXE850TviOAklMrYmS1wuWdBTjEay9Ka6dImqMFGupmJjLmUw0KXrtPin +xIz5DZ42nmTKnYevuBQoQrrq7toxf5hYow2ZjeH2vSX+igY1gxDZbLW4Wb9GPYMo +Au5+z8XpA8R0key52nvnKastm5YxNstAlBOodAPKlbIr2bzmrHSjXAGjUzb+z6NZ +5Lx+zvQCy9kaIYvfOJm3eLSbMXzeP2S59qbwL+dC4ZJ5m3hjRmMaactV6LSchVNt +eLEYJpm92IdjQhG6oqM0IaU3aSjWMSrOAytylmqoEt4wA+WhAoIBAQDTxJ9VLb+J +OD0x/9cm17KpK1nGQBQ0T0oZQUH5M/tXTPCCoIpoL9UhKQ34vlPaZXkBQrXPw+PN +Y0J26uR6w4CowWAMn8LR6cYsWcOKuURcDYs/SPflD3rraevJwugQhkXtub2nV7dP +88Z/jGvhXthJmjUmNoKq3OC2MuSfHSkm8ipvaAblwb+lt5zBJGQ6iGXbi5TI6b+D +lnAidQpG/V464Zc9gb788P0K2vUeoZRLI7CurYqpDV0mBtPhFv5L1M0S8+psG7Pa +NIEKcW/b76vU9odTrtGBT0gCVYU7f8QnTN4g6c7dEhcZa2Zvg0YSmb4XuU9RQGC5 +As47nEUnPCjhAoIBAQDTXKnAogn2kAmGvoyIs0hFe61d47ObPDH9RVvPruwkkvd2 +WX/c9f6gy853dU0/zwSYklOitM7rgs94s3BwzCYiU8XKeh28RTCBKEKf6PGjq5nW +xXNrhMtC2j5WfXGS9JbdC6sYOiWivSMAgE6Vuk3TCE7OE4x4dcbTYvMl31Lf0Dqq +sixfKPdqrp7Jk5XkWkK+b4teeBLR1N52R/pYfWdw2K2d9g1CD6/BSDbnW46Zn7CQ +nczAm417Y2VWpZdDceZhfTLtPxAFxOOOgN2jg14B1bU+XsGCbLvdnohdV6kVOCjU +NWyUWNnTBNVDRCf5RodZlczORmL1AMKyKpcFurhBAoIBABSxbfBg3AqImFI+ccO1 +6BtnxQn+UPsblF4LZmr3jWPmfMoG7f9oTSdEX70ivAbnS3+4CRQYTDZRsLj2EwV7 +/SKAYuZY5iyk71x+GQGBQRDNsgGpG7AiZxyB6Sx6Azs6I7MrJ0Em7R6+73KfQhtv +rSrkCrWFNheEJeEn7/csXk0T9NmWDLZ+zD9hRcwJxlGB6pIdfZh0XuZ42NRFI4/0 +SjTuvlygRQ1qbw+UfcdUeq0s+6LWCmqih6ujlyizmn3GeZOUih+uRVDZOJLQquGO +9feFb4vZ1VcRbDPuL2q0/XHprPsCXdh0YBV3zTawWTSQGWcwEHQcGld50rU4e/lt +g4ECggEBAKwoqsqIHheL+uS2CHXmwFIr+rvOlLYlfB8XrwV/da3p7QChaDLbNIVM +uOAozCMkJY+dufPGI+3cKsR3kLAGejmfbH5OTzTbwCLOJFCWaoMuvOTY2Govte61 +gU1BWnjUgVJgVA/YTwn2yo02d0nG5/rSZ9xIt3hfO6ac5FhHBTA1DAZ1wDiLeow+ +qngZ2sA4ePtwhGFtvLVwTcGAfkWvQFi2YPBpesFIAmQ/ACGC7Ye75Ja4k36/8YwE +NiXR2Yy1hxwwi7CTWWzI0X+mvE/Oqpd8PUqPJCJcpz892Gq4EGCxM7Bz7NxCcvvw +5IMXuORWuoq0gXiCdEyko+saXsyWlqw= +-----END PRIVATE KEY----- +)"},{"capulet.example", +R"(-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCgA/CpV7UGqUdj +hEVoMjFIZ6Ca/C7utrVPAqBvE14eiurIhQrQAmYeC9zA4/uXCdqkGq/a/RbF3OOC +KLRUejCcynb0EnxiHxHa48ZsvLbKCK6guoXEpWnaZsmRpvJrBB2z6ohmxRuaDuc5 +CJT+Oq8AFPp3StTAFDo3Cju3fsGZPkNpCGbjELwk4ok9INtEuTrMEmHZTD+VfjpX +auUfN4ygKaPXJanCuxuifyin403BWgd8igkDoSCWxoDFMy3HGbh/NU+nJPJ23FxV +C39RdDG3elvjNFpSZnALbiMnyor7YjF5TN931ZWwn3VTnl7DnFquEbKbYyVFUzRI +I8Cd1TzKOL48rVLrCAqMXwm6YFtST6qPb9TZ0SX8qZGCwBfHV5OeS0ZgiBMMlmUP +Ycw9MlyvZnYyDPCOoPWmhEqd2gQzn//7hzb5mriCEyfcMzAqohylBNHXUVZTx5Kc +azJz6oOYdWEs1jfSXNKefgSWlgeoG2fgTXPN1OkQVS+FOiI0VCAIwR+vxhG3hVTz +3kzXWvEt7M51faaHWWlnSzOrbSuj3f0ibS5Jcj6ClyzOQRQDwzofyZ7oPWh6No/X +kepVIn3HTTlnj1/8e6VsH+EBKSzoX2XvWPkOGAZEGHKiKh944u6d6mW37BPD2oKy +usP3uPL5j2Fdm+m0HkP3/7yw+5EFVQIDAQABAoICAQCBom+IYdvwp5eEUhaA0ZkH +lZyRsxi6oB7HAdPD6SbpC5YmGVKnLipY0TdotcqPlJYjONObUErwxYEzY5KkldFo +VMaF+av3OkCW2s1YLpLPnrUK1dGlfHUDUR6f92aRuGXv6mPTDoDMEKLWm9NJG3XH +VTeNCXzOmBSJnqq+f9yML9sg7oOcFWS3ZSfV9BZv2Lh/t6y6BIHGtNrDE4DIB5LP +9qwbkxGzBy7eOLJRQV8u86b5CENBQ3pJbEvKdynxES9dL212dgJQtTnAVG4zKTVV +9bUXnsRF2WOQfwvQItDx051NLjAkv05kJutAcR9IzhTQzNmr9Wiufzft8bkMpUJ3 +Mf8cJk5VNm9mgKvWnqKrPSyfNcicykcVHXr0yDICLgttWy5d9bj9/DcfrIOzEwhd +MOhTixYtR1dv/7p9kqw2mRgMV3GtB6f+AoQ29NrCt9bD6T2Rth9lXSo90sLW47J9 +QIan8jb/T4N7nuga37wLlpL5KhA7nyzlaF37PyvhbErzOxRfq287iQKCyF+nh3n5 +9HzWDWz+8zYcjsxlYc1x7XHWWAYKS1h+ZWPjWCLH8hlh3ZRdPm4CUfwuZmA2EjNT +8dRblRQ8QB9cvsKoLjKt8vB8mIoH6Sjk5I3vqNVXl6Su0JrvLg5A/3tfyPfxsm5c +rTunLQllzpgo2/q6ssz9yQKCAQEAzgDf0ozoyH9+k4ND7LCy5G1vGr8LqMhyjgSC +4AhBIM/Hz56YSrU0hIFpgu/VGWLkGN/0AiwhHBKpt+6KkvLBjxnv71dmI2hBIbb4 +Hzy4EXtPTtFqn4gffYjOen6co8RUl1vTOmRDUdfS6su0v9TD3335TIIfF+5DAGvR +V6OIHkQWWrHazUZx0tbwRyty3Q4NtYgXLFrcWFYfMFd26GhFrM7uHFrbOg5U3gpZ +/YdaaJzfdaJKHNPNQJUPD40n36n8RyjlWSWkUfEV3ITm0IMiCJ19WDjyddLUXuzC +KSoeiTCISXzZ8lhmvnBB4pW9V1O1o8cDJFRT1ouUfOKqK86lxwKCAQEAxtnMzmEp +Z+W3Jlz9istkJHerNATtQzj3KSNHbrM8gB+O0igq0BWbj+lvNtbuZVprLrOpbDk8 +Ksk+PdbgSbsQjALcs1FpoIsPWt6sKTwrZQuMCocHzGfrp0MA613YCRw9sNBM08C6 +TNbjSTiVlBb3xyjsI3hLZ9sj8N9rV6yomlwM6MnpdIDUxfiv5tlqZcqCYdibJ9zu +tWi44O2tim3uCVrajop/NsHXbROjd7MeV4gaj3SsJ4cLyvfcBkfwrhUse5D6qy6y +08ZsbrMUqY50ZG0WUcKzJxJcF/mOANZ+Dgqe9jwKlxV8E1Lj7PaQWWzQ5bWVgnLe +TuKoZurGEaJMAwKCAQEAgWHJMYswlOSGUg2KdrjP0mns8wZ0QzCJyiqJLD3i8cGu +Q/bevWUrs+E3rHYHCCe1DO5zaX3f2arbD1txizOOX9sxd8gTrT9IUO2CztOq48fn +mqAqcEHlTUnELOkiZjTj0CBq/OyF33xGyxLf1e/CibasAeJjtvr89+G/nGRoFGI9 +C/9SZcTNrlcyl/Bw9udhstbjfwceBxkoA4ubcgIzaIKayBJESCVCJiaoOHRvUu7b +5hzkoVBhRCOaTvEfzvkLKoJD8YaTuqdJTLPn56PEl1aap/M0TM36dhgLJiF/BjkG +D+mrVOsytH760l2ripJXraJLleCku0X1H66YpGTodwKCAQA34vCntDEB7VLrKklr +37v2b9ejGBtiwDjey/aAi0lerP/j2rwlnV0KNk42eHOp8p6bEo10SCW71LF0idah +gjylTQygLSpln4+iN2Dlee6sSHGEZ+zuKurVKISyob5c2R4ReomNHeZ+QArDAm8v +nsDmrX6ofV+cAb/5K6Gsk28TavmJ122Qe8DRHxK467P2hdLdExaQPoysWZFUThhv +BnRXFrzEQPJ9/j7Afjt8IdBOQ4dLeDwGI/NRiRXCgieHlZXZ6KY6xDYoROUmu5f8 +C3h03R/fvLvDKGrPpiid3aqx4ZRJmhhT3AryF2LNr4JkT6vqU32Amy4Vt6givKsM +O7PnAoIBAAggpMq7PMugGP4B9PgNb00oGmWfXSa+M83O0GGN7jSirxqkaK+/eDOY +kSnVFWmORNBlSz+bLoA3Bw2mFXI8HfSbHM9E/Qt0scf0hV+SwpTuO3pDWF5ev20G +mL1QEBUNDmvOn2SYERKI1iRevjBBXSzwTpAXnfaWvvTn1XSKzSJK3TjMhFTZHtbj +mgPPV65cznhofUsg2QenT8zKisvYPYN3p3p9Jo6IqHyT/CCymwIB4OMZITiwXxQs +PMAxlZGkX3Uri5A8Ln3QQ46elanI2TlC+ZDa84gu/Gw691JWCfsaSaQDTJKnGqos +dwiNVl130YWaJLjiA9Poc2llKtypfQ8= +-----END PRIVATE KEY----- +)"}, + {"casigned.example.com", +R"(-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCsOIgrHBiAwnOe +ZsMYCbJ/79hhKK6RPcx2LDH5eqcdmkSxoAfJIsWMjYhDwP2/4pUoUae6adtiz2+T +t2jlVVswLORU7z3RWNr0vGCMUel0ilzt7uEPP8PAkdAGyqXgrS9E8Epdbu+p6ujk +THqekBrE4wy0O8FMHUoS+KleJyBsSVqJ/+RiNJ5eF6/8M5srGzIwDEoljkfdAzWT +L6kAQYUHCXanYq3PsIUfIDoSDLyQZ+Y5TLhRAcy/20fpBv8xbg9BDLDE8ukxE3n2 +LsXlpobs0BDcgFeftb+PBv9Wvc8zfWNMUOk9DaaWy86vv84cU9XgTfPztGwBlM85 +NVUhb6LhAgMBAAECggEAP5KesUstwFoHU/GbEsSBn7hpp3Pc/MBTOUwXJoCgL81C +jk8EkLrFMZ0NL/WNtcduR/PcdnOdCFyKU3zgu8dGYgIwRyoJJ74lFTJ0cVfLVbm9 +lBcZ/QcMu4kXwWoM0WMcj9YjnVnWHmMYlS2mFeIb/5HQnrdwIyisr1QbMSZAUbgn +HOLSjkd0KUcXxwP9HfE/8zUFbUsv/wPHE9T5eWqZz7lKZRvgUyk3jYElpewxqPvR +HPOq9BN87ft7rPzmmZ4JCU2tM5MEQONo3jT5pljTU/iz4pfs1HArHS+/zZbGcoiu +AhODErhLucodwZ07MZsE9KAdGPGUeob4SgMwmkIiAQKBgQDYZ33DHOgYd5Fa7Tqv +TC77Nbpjmnk5lyoInNf+7pxBTgqIuKbpS6Ctq76nHI0qerNfd44LqojQEJ9S5rbL +3s+HR+pypx3DyysE92uLaVsF4rfwZeEpJyQ1Q9NGbsKVb2nNrdGs3LZhG5PL+JQT +8lS9h/sMIbh5Gd/Dkt8a2HlTawKBgQDLu3YdXWeWUOcq63YrLFDO+RUGsCe1cf+2 +3wTmMRgxfzpAPDZKymUPwrJNd1ddCQiRVKg91pLhlDl8B89Q4iWdOpYnE6vrnw3w +6iEdEyA6IauvEvD3JPXHGtVHKBS/wz06wQVGzsgMvVun1w32SDzTGZ/somvkN1UE +BTMRVqXB4wKBgCgkgnq4GQG45FjGmtU7v5dP7yRc2lHpjZ2NYq/imU+v51pXTncG +VWcB7drX/AO+QRnbdpkJaFmYS8W4EH6e9UY1+/KKt4XDYVaJgwSYZY8g8FgCvhLB +NQFAdKejEitgQHMr5DI5uwcmc3MpyGYu1LNXzyT/+FVWjGCeFQ7IyzDDAoGAXK9I ++ez/bkQaFs2OMe/0R2TL6wIC3qohMpndSbf2ELaX0pdR/856EaR6p4FujlXIvw0r +iQ5wPg3H5SRMbbikchYwL1DkusnedsadD/QeijO9PmW4mEcJRW5wrvGOFvuEhJFB +jEgQfLM82muc33lXqpYSyn3N5cJCfBS9edrYiA8CgYEA0Tsa4KvwzmBXzy2jexUT +PPYtV9S7hS0D7Owf5SBI1wtWczOu3Y6DsCG4mbDi/tvo1dxC9d5Ns8RXHH9mtdyn +8VUuSu24lk7VZ0OP5/byiAGqC2urDFGe0iBqePdb+3uS1g132LzAJm4RqBYw4Xjd +P6n9b0V3iodcFLMTy1ShJ+I= +-----END PRIVATE KEY----- +)"}}; + +auto montagueEncryptedPEM = R"(-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,6B0A69362920334824667C1B6207279B + +vlDCCnUf9aDbCD4+PUuo5LGvzTFlT03ZRMnHDcBzE2mp1OMBjxeEu4j4cqUJE2qV +NXCRbsedMsydoHlg76LssYM7J/AI9dp5cek0HgYMqdeB+hoNn22AmjRb7WhY4VeW +RqKAzkXT1lsxEF8hykQcalbsrbdmKkPosiNJF4Pb9EEefl01e+Ny3nb7GRs22tzX +lJNBk+lrM0Jlg1Y6c3F5/5CkKHTXP4924Pzjzf6Bw5hG80izrYeBUC5lZJtqDM7B +lmFXAng4RIDKk1TsqeJ11Fa1nMqFkvRvlU8RdrcZ5rtngWxIAvTXAjbDk5mvS6Iw +WdjmH46TrVMQLXC2Qh++grldyx4GDm7rShLm23J9lUAdPLjIvurYT+LfbCRqfgIw +hkPtm6BWkkf95KfpMKZ0giOhikqnF2YsozgqI5SphDFIAGN7bXa7Z8g/xFI9Uqie +2+rWqVvBOQ8PBepTd2H2uahV+pP1wHmgqN/bp/paXt6+Qf7ptH6MNTwgnTanDfnk +wzyhVlw5tTsG8okjD1cT2R7RbuDQRkArpzbnATPEU9Itrx0Sh/ZPKPDDVS+aSBHA +3JytZX5yzd/yilNjE3NfN1G923lcWXRX3KsdZUQjbcPugML7xbC+orqwxeYLipMN +jfNEGK0IrTNmRN5HqFU6JBNbas67BlFU4Zt4Tt73sUHrMpSSRINd8itRZaKtqZuM +8upj7ZUD/j6j/JmSxN2w+TcmHXfNWZirTFWUvtF/l1WCHilsuO49VW/CqGFW2Bad +32YzPkENljj/xuijGOHr1qVFozfG4/noXdVtJm0oflt1ImdjvOO91LneaAhVE8lO +K5SwOnsrlr6UM0tb/HnunT5Se49YQSGnXOiXO68bPO9S0JZ33MeAP5kSbMSZ6VXr +luw7dga0jfJLqnWU2arxOqruc9bSwkfU0RUoWXZqrKwUiXdyl/vVeU1Y67yuYqXH +7eUrdL+BdSDbeOC/5xmWAkeheC4OBBYCcwbVv1Aw67sUaQIcyWMkx8Kq9tn8vpRa +ETcagVjUXqAjrYtRpmCXU6KdmeGKoQZq14EVREytk0KnTUQTFtv8LJhsau16v4pS +in7Yt658hdf9CSA5snfUcvLeETNeQHQWvmN+0uD/UB9vRPbHp3kPSvitoS799QB1 +ydrD8zXdUSpcW+V2P75c7u0XkcUTbyGIBuwLAtr5fweyyiKs/v//rPaBlzEG1WUr +OFSH9KZ+m9UwqmauXesySXoVsmjCQKUVVj4/QI/aWftmMY58CDNJw+q77dAzSYrj +yFbhUt5ZKqAvb+rt3dJswkZ1sxAbmTw290NAV4NPP8cjXUjLwmU+KNZ2VFkxt77p +1LxG+Ia+TV1JystBvFeiJ6sWEC3lQ7+0b8oDfE5aovQpGk+Cb7hyt0EvDh0/AkvT +B/KCQc8wUjyn+yejBicfMzHVaOphwlajrt+vSNF4G7J+Wo5luTEXpWQrKq22xnah +sal7IusjSgPdFpLCuyAy6atb/4aQoeXlE/r8tXbmrl48SnadwAndoZVt3gzIv1/Z +oDc5koTBQk6aIoWHb6qslRt9tmrnF22aP+/a10oahgIliWAL3jUwLqZYzdbMKkMv +NEbobf7kO5LTzv+w09K0A8miF+8js351FBw05gsaUHgufF3OCGAdQfXDN7d6Lxho +HbhiuzxlHOnth3TWNfqhvNkwFP3gfAIaqlU1Z28AP6pZtUw93QYNABUez8QFZj5c +sdUpopUO8krnwUPNup6yTB/m72Vx2aSqXgu4upxUNVJlgDFmnCBhOe0KKjzduIvy +bRHxL93UZxDnpn8DBB1bgmdSzgInc2gfq91j1AyL+nbZv+kob/jG3OxMWNjenVDj ++TeyP3OypAUK/8jP98ExS75mE661mN28kKrUfTRxZGt8CJY4AFL4lAzIf2p4JMch +aPE30/DmXmKng+VP+3ik5FEomMLIc6QkrEzzcMYQkDsNdjd202CAXRSAqnT+VFtR +MlopkSVvEpn83HdCqcANl8rNo+ANnFMyyPL7sFd470KhSVTcQVSb+wR8DOiZr8Vt +uR0G3+KgdEDAvZStkWTCr5eMYhm95QVclnHhsLq0AaLrOm32PqBi2C4mGyW04Mud +m7lUuRkf/mLKWZZfKleefp12waahMqSXAo3shqyTNVPKOFSVA/UF0mFGon1Npo/x +6z4hd5sbG1kiPlrt9EeTgtwFhQ0lxM755QTvAB6GXcLxkGkdNdqhJzFtTRAE9P01 +CiI1JYEvTHBdGcsBbw9zJikOEXCA19fAMkHqSfo5aU/qbuvDsY2QLZkgfiMnpoOx +ghQzeJ95jiYE3V5WNtB/7CRthfC54moWW7w6ZgdIuCEN6JvK0zmsahv2o16kkzWA +YTw1lqaNMHIhlidRwy2Q+ke0mmNTIHHtNqLGVfOE4TwSN3VIIhXNZ5E65LuBw7tQ +SyFK07dfMQXixqaeo+ytXBNTFEq1MEza/PxwUojn7njbCKhO5qGavkiyNs5nk3ZE +htkhtreIUj6kHzWAvylxLbRy9+4AJA3/UCnudMRtX/McjtN2jNwZKPaXWCQF85ff +koOclVf4j/eYQnWT03zXjAx1DKazIk0laEfB4soXfQfgXdFyj3YKXKKD8WzCW/ag +cloY4yZVa+SWnj0P23oPdptL9vOM1NK1lXAp2tvvZHPp0UmLtXVU4eNaabC79dXC +3KU9bVruCdpQki4kGk3MvsoB9OyNEZE1jxLZ+7FI0D1XKJ4qHZcwOyGqD07+Xect +w2xs4stXxvogUZdQ3G6GBANFXEjDzEu5vZn9z668mCe0cQG/iNWOR5ZGmdjlmW5O +6O9ibFmk7pc975V9SVHH9rS/GZGz/PW6CJ8O0GALw5y9fczXxjvCz7dPHK5MO40m +fDWCwIqK1D2LOEewMFqOOleBhHMpVfQX+Uu34UlWHGFnOm1fK+dIdT7tss5o8Gkz +gCBFpmjyi8H+VtXOy5JTTIi/80pnLO8nsv27FNPVU3UZJCZjfR9LCeqZwgF1MFIe +X137HnkpmtJGF+bcMRwY5u9fSQQZtBNLCadRsvHnz6J+1uodFDnre0+Q4dokmFfv +0UveWc1CDRa3qXpzW5U6NpFjYWQmiS3KA5VY5/KHE7UJxnEI1R1gEaQ6/Ogp2cmI +-----END RSA PRIVATE KEY----- +)"; + +auto dhParamsOpenSslDer1024 = R"(-----BEGIN DH PARAMETERS----- +MIGHAoGBANjw4f5+gu8b8X8O6ALyJA1tH9TQTWZEI3YjUKQ1m0dVBMJ6XDC7FLJn +gqE4hIGcm1FAWwIiuo0uMufqyVwFT2c+G8j4JHWK5z1tEP+GaqiO34N0cUo86qHp +THSkJN7LuHbYRqI9fHWDZocW/5yAsDq5RPUCjFZAoh1BWdfDFfrjAgEC +-----END DH PARAMETERS----- +)"; +auto dhParamsOpenSslDer2048 = R"(-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA0Q6vD5qtrh3XEkVkbN29ord/k3sgo2Q3PiFmyFt89qqVbebEzYmt +t8DwaFGMcGlyKs4Lb1s7vocm9y3M9C0FZm85Muvv8WCbLZVZ+wfEtMibOjgRoDqt +p7Qqe7/iPgMVrSjWegVkg3V8K8dnPpohPClM0yOe4NpBjSVNgBVJRpEtH8gFiCor +H7hw63HpN/MgFdkjZNeCN+erv8p673xH8LrN98gQpkdQ9vCqYt1dHxF2XZcxBp8x +XganwPeGgQosofkA6nVB70hyjwjEyxnHJZIMlx6DPXWC7X6ed0SazgH0sQNdACvG +uU1zHCVIv6/f0adKrJg0s1jrM3qWZ6HmUwIBAg== +-----END DH PARAMETERS----- +)"; + +auto createTLSContext = [](TLSContext::Mode mode) { + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + auto tlsContextFactory = tlsFactories->getTLSContextFactory(); + + auto tlsContext = std::unique_ptr<TLSContext>(tlsContextFactory->createTLSContext({}, mode)); + return tlsContext; +}; + +// This connects a TLSContext to another TLSContext +class ClientServerConnector { + public: + ClientServerConnector(TLSContext* client, TLSContext* server) : clientContext_(client), serverContext_(server) { + connections_.push_back(clientContext_->onDataForNetwork.connect([&](const SafeByteArray& data) { + serverContext_->handleDataFromNetwork(data); + })); + connections_.push_back(serverContext_->onDataForNetwork.connect([&](const SafeByteArray& data) { + clientContext_->handleDataFromNetwork(data); + })); + } + + private: + TLSContext* clientContext_; + TLSContext* serverContext_; + std::vector<boost::signals2::connection> connections_; +}; + +struct TLSDataForNetwork { + SafeByteArray data; +}; + +struct TLSDataForApplication { + SafeByteArray data; +}; + +struct TLSFault { + std::shared_ptr<Swift::TLSError> error; +}; + +struct TLSConnected { + std::vector<Certificate::ref> chain; +}; + +struct TLSServerNameRequested { + std::string name; +}; + +using TLSEvent = boost::variant<TLSDataForNetwork, TLSDataForApplication, TLSFault, TLSConnected, TLSServerNameRequested>; + +class TLSEventToSafeByteArrayVisitor : public boost::static_visitor<SafeByteArray> { + public: + SafeByteArray operator()(const TLSDataForNetwork& tlsData) const { + return tlsData.data; + } + + SafeByteArray operator()(const TLSDataForApplication& tlsData) const { + return tlsData.data; + } + + SafeByteArray operator()(const TLSFault&) const { + return createSafeByteArray(""); + } + + SafeByteArray operator()(const TLSConnected&) const { + return createSafeByteArray(""); + } + + SafeByteArray operator()(const TLSServerNameRequested&) const { + return createSafeByteArray(""); + } +}; + +class TLSEventToStringVisitor : public boost::static_visitor<std::string> { + public: + std::string operator()(const TLSDataForNetwork& event) const { + return std::string("TLSDataForNetwork(") + "size: " + std::to_string(event.data.size()) + ")"; + } + + std::string operator()(const TLSDataForApplication& event) const { + return std::string("TLSDataForApplication(") + "size: " + std::to_string(event.data.size()) + ")"; + } + + std::string operator()(const TLSFault&) const { + return "TLSFault()"; + } + + std::string operator()(const TLSConnected& event) const { + std::string certificates; + for (auto cert : event.chain) { + certificates += "\t" + cert->getSubjectName() + "\n"; + } + return std::string("TLSConnected()") + "\n" + certificates; + } + + std::string operator()(const TLSServerNameRequested& event) const { + return std::string("TLSServerNameRequested(") + "name: " + event.name + ")"; + } +}; + +class TLSClientServerEventHistory { + public: + TLSClientServerEventHistory(TLSContext* client, TLSContext* server) { + connectContext(std::string("client"), client); + connectContext(std::string("server"), server); + } + + __attribute__((unused)) + void print() { + auto count = 0; + std::cout << "\n"; + for (auto event : events) { + if (event.first == "server") { + std::cout << std::string(80, ' '); + } + std::cout << count << ". "; + std::cout << event.first << " : " << boost::apply_visitor(TLSEventToStringVisitor(), event.second) << std::endl; + count++; + } + } + + template<class TLSEventType> + boost::optional<TLSEventType> getEvent(const std::string& peer, size_t number = 0) { + for (const auto& pair : events) { + if (pair.first == peer) { + if (pair.second.type() == typeid(TLSEventType)) { + if (number == 0) { + return boost::optional<TLSEventType>(boost::get<TLSEventType>(pair.second)); + } + else { + number--; + } + } + } + } + return {}; + } + + private: + void connectContext(const std::string& name, TLSContext* context) { + connections_.push_back(context->onDataForNetwork.connect([=](const SafeByteArray& data) { + events.push_back(std::pair<std::string, TLSEvent>(name, TLSDataForNetwork{data})); + })); + connections_.push_back(context->onDataForApplication.connect([=](const SafeByteArray& data) { + events.push_back(std::pair<std::string, TLSEvent>(name, TLSDataForApplication{data})); + })); + connections_.push_back(context->onError.connect([=](std::shared_ptr<Swift::TLSError> error) { + events.push_back(std::pair<std::string, TLSEvent>(name, TLSFault{error})); + })); + connections_.push_back(context->onConnected.connect([=](){ + events.push_back(std::pair<std::string, TLSEvent>(name, TLSConnected{context->getPeerCertificateChain()})); + })); + } + + public: + std::vector<std::pair<std::string, TLSEvent>> events; + + private: + std::vector<boost::signals2::connection> connections_; +}; + +} + +TEST(ClientServerTest, testInitAndFreeContext) { + auto tlsClientContext = createTLSContext(TLSContext::Mode::Client); + auto tlsServerContext = createTLSContext(TLSContext::Mode::Server); +} + +TEST(ClientServerTest, testServerSetPrivateKey) { + auto tlsServerContext = createTLSContext(TLSContext::Mode::Server); +} + +TEST(ClientServerTest, testServerSetCertificateChain) { + auto tlsServerContext = createTLSContext(TLSContext::Mode::Server); +} + +TEST(ClientServerTest, testClientServerBasicCommunicationWithCertificateMissing) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["capulet.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + serverContext->accept(); + clientContext->connect(); + + ASSERT_EQ("server", events.events[1].first); + ASSERT_EQ("TLSFault()", boost::apply_visitor(TLSEventToStringVisitor(), events.events[1].second)); +} + +TEST(ClientServerTest, testClientServerBasicCommunicationWithPrivateKeyMissing) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + serverContext->accept(); + clientContext->connect(); + + ASSERT_EQ("server", events.events[1].first); + ASSERT_EQ("TLSFault()", boost::apply_visitor(TLSEventToStringVisitor(), events.events[1].second)); +} + +TEST(ClientServerTest, testWrongPrivateKeyAfterCertificate) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["montague.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(false, serverContext->setPrivateKey(privateKey)); + + serverContext->accept(); + clientContext->connect(); +} + +TEST(ClientServerTest, testWrongCertificateAfterPrivateKey) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["montague.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + serverContext->accept(); + clientContext->connect(); + + ASSERT_EQ("server", events.events[1].first); + ASSERT_EQ("TLSFault()", boost::apply_visitor(TLSEventToStringVisitor(), events.events[1].second)); +} + +TEST(ClientServerTest, testClientServerBasicCommunication) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["capulet.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + serverContext->accept(); + clientContext->connect(); + + clientContext->handleDataFromApplication(createSafeByteArray("This is a test message from the client.")); + serverContext->handleDataFromApplication(createSafeByteArray("This is a test message from the server.")); + + auto firstMessageFromClient = events.getEvent<TLSDataForApplication>("server"); + ASSERT_EQ(true, firstMessageFromClient.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the client.")), safeByteArrayToString(firstMessageFromClient->data)); + auto firstMessageFromServer = events.getEvent<TLSDataForApplication>("client"); + ASSERT_EQ(true, firstMessageFromServer.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the server.")), safeByteArrayToString(firstMessageFromServer->data)); +} + +TEST(ClientServerTest, testClientServerBasicCommunicationEncryptedPrivateKeyRightPassword) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["montague.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(montagueEncryptedPEM), createSafeByteArray("test")); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + serverContext->accept(); + clientContext->connect(); + + clientContext->handleDataFromApplication(createSafeByteArray("This is a test message from the client.")); + serverContext->handleDataFromApplication(createSafeByteArray("This is a test message from the server.")); + + auto firstMessageFromClient = events.getEvent<TLSDataForApplication>("server"); + ASSERT_EQ(true, firstMessageFromClient.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the client.")), safeByteArrayToString(firstMessageFromClient->data)); + auto firstMessageFromServer = events.getEvent<TLSDataForApplication>("client"); + ASSERT_EQ(true, firstMessageFromServer.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the server.")), safeByteArrayToString(firstMessageFromServer->data)); +} + +TEST(ClientServerTest, testClientServerBasicCommunicationWithChainedCert) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_TRUE(serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["casigned.example.com"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["casigned.example.com"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_TRUE(serverContext->setPrivateKey(privateKey)); + + serverContext->accept(); + clientContext->connect(); + + clientContext->handleDataFromApplication(createSafeByteArray("This is a test message from the client.")); + serverContext->handleDataFromApplication(createSafeByteArray("This is a test message from the server.")); + + auto serverEvent = std::find_if(events.events.begin(), events.events.end(), [](std::pair<std::string, TLSEvent>& event){ + return event.first == "server" && (event.second.type() == typeid(TLSDataForApplication)); + }); + ASSERT_NE(events.events.end(), serverEvent); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the client.")), safeByteArrayToString(boost::apply_visitor(TLSEventToSafeByteArrayVisitor(), serverEvent->second))); + auto clientEvent = std::find_if(events.events.begin(), events.events.end(), [](std::pair<std::string, TLSEvent>& event){ + return event.first == "client" && (event.second.type() == typeid(TLSDataForApplication)); + }); + ASSERT_NE(events.events.end(), clientEvent); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the server.")), safeByteArrayToString(boost::apply_visitor(TLSEventToSafeByteArrayVisitor(), clientEvent->second))); +} + +TEST(ClientServerTest, testSettingPrivateKeyWithWrongPassword) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["montague.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(montagueEncryptedPEM), createSafeByteArray("foo")); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(false, serverContext->setPrivateKey(privateKey)); +} + +TEST(ClientServerTest, testSettingPrivateKeyWithoutRequiredPassword) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["montague.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(montagueEncryptedPEM)); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(false, serverContext->setPrivateKey(privateKey)); +} + +TEST(ClientServerTest, testClientServerSNIRequestedHostAvailable) { + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + serverContext->onServerNameRequested.connect([&](const std::string& requestedName) { + if (certificatePEM.find(requestedName) != certificatePEM.end() && privateKeyPEM.find(requestedName) != privateKeyPEM.end()) { + auto certChain = tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM[requestedName])); + ASSERT_EQ(true, serverContext->setCertificateChain(std::move(certChain))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM[requestedName])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + } + }); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["capulet.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + serverContext->accept(); + clientContext->connect("montague.example"); + + clientContext->handleDataFromApplication(createSafeByteArray("This is a test message from the client.")); + serverContext->handleDataFromApplication(createSafeByteArray("This is a test message from the server.")); + + auto firstMessageFromClient = events.getEvent<TLSDataForApplication>("server"); + ASSERT_EQ(true, firstMessageFromClient.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the client.")), safeByteArrayToString(firstMessageFromClient->data)); + auto firstMessageFromServer = events.getEvent<TLSDataForApplication>("client"); + ASSERT_EQ(true, firstMessageFromServer.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the server.")), safeByteArrayToString(firstMessageFromServer->data)); + + ASSERT_EQ("/CN=montague.example", events.getEvent<TLSConnected>("client")->chain[0]->getSubjectName()); +} + +TEST(ClientServerTest, testClientServerSNIRequestedHostUnavailable) { + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + serverContext->onServerNameRequested.connect([&](const std::string&) { + serverContext->setAbortTLSHandshake(true); + }); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["capulet.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + serverContext->accept(); + clientContext->connect("montague.example"); + + ASSERT_EQ("server", events.events[1].first); + ASSERT_EQ("TLSFault()", boost::apply_visitor(TLSEventToStringVisitor(), events.events[1].second)); + + ASSERT_EQ("client", events.events[3].first); + ASSERT_EQ("TLSFault()", boost::apply_visitor(TLSEventToStringVisitor(), events.events[3].second)); +} + +TEST(ClientServerTest, testClientServerEqualFinishedMessage) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["capulet.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + serverContext->accept(); + clientContext->connect(); + + ASSERT_EQ(serverContext->getPeerFinishMessage(), clientContext->getFinishMessage()); + ASSERT_EQ(clientContext->getPeerFinishMessage(), serverContext->getFinishMessage()); +} + +TEST(ClientServerTest, testClientServerBasicCommunicationWith2048BitDHParams) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["capulet.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + ASSERT_EQ(true, serverContext->setDiffieHellmanParameters(tlsFactories->getTLSContextFactory()->convertDHParametersFromPEMToDER(dhParamsOpenSslDer2048))); + + serverContext->accept(); + clientContext->connect(); + + clientContext->handleDataFromApplication(createSafeByteArray("This is a test message from the client.")); + serverContext->handleDataFromApplication(createSafeByteArray("This is a test message from the server.")); + + auto firstMessageFromClient = events.getEvent<TLSDataForApplication>("server"); + ASSERT_EQ(true, firstMessageFromClient.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the client.")), safeByteArrayToString(firstMessageFromClient->data)); + auto firstMessageFromServer = events.getEvent<TLSDataForApplication>("client"); + ASSERT_EQ(true, firstMessageFromServer.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the server.")), safeByteArrayToString(firstMessageFromServer->data)); +} + +TEST(ClientServerTest, testClientServerBasicCommunicationWith1024BitDHParams) { + auto clientContext = createTLSContext(TLSContext::Mode::Client); + auto serverContext = createTLSContext(TLSContext::Mode::Server); + + TLSClientServerEventHistory events(clientContext.get(), serverContext.get()); + + ClientServerConnector connector(clientContext.get(), serverContext.get()); + + auto tlsFactories = std::make_shared<PlatformTLSFactories>(); + + ASSERT_EQ(true, serverContext->setCertificateChain(tlsFactories->getCertificateFactory()->createCertificateChain(createByteArray(certificatePEM["capulet.example"])))); + + auto privateKey = tlsFactories->getCertificateFactory()->createPrivateKey(createSafeByteArray(privateKeyPEM["capulet.example"])); + ASSERT_NE(nullptr, privateKey.get()); + ASSERT_EQ(true, serverContext->setPrivateKey(privateKey)); + + ASSERT_EQ(true, serverContext->setDiffieHellmanParameters(tlsFactories->getTLSContextFactory()->convertDHParametersFromPEMToDER(dhParamsOpenSslDer1024))); + + serverContext->accept(); + clientContext->connect(); + + clientContext->handleDataFromApplication(createSafeByteArray("This is a test message from the client.")); + serverContext->handleDataFromApplication(createSafeByteArray("This is a test message from the server.")); + + auto firstMessageFromClient = events.getEvent<TLSDataForApplication>("server"); + ASSERT_EQ(true, firstMessageFromClient.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the client.")), safeByteArrayToString(firstMessageFromClient->data)); + auto firstMessageFromServer = events.getEvent<TLSDataForApplication>("client"); + ASSERT_EQ(true, firstMessageFromServer.is_initialized()); + ASSERT_EQ(safeByteArrayToString(createSafeByteArray("This is a test message from the server.")), safeByteArrayToString(firstMessageFromServer->data)); +} diff --git a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp index 30fe423..47f3db2 100644 --- a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp +++ b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp @@ -35,6 +35,8 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { CPPUNIT_TEST(testCertificateVerifies_WithMatchingInternationalXmppAddr); CPPUNIT_TEST(testCertificateVerifies_WithMatchingCNWithoutSAN); CPPUNIT_TEST(testCertificateVerifies_WithMatchingCNWithSAN); + CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithServerExpected); + CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithClientUnexpected); CPPUNIT_TEST_SUITE_END(); public: @@ -58,6 +60,14 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); } + void testCertificateVerifies_WithMatchingDNSNameMixedCase() { + ServerIdentityVerifier testling(JID("foo@baR.com/baz"), idnConverter.get()); + SimpleCertificate::ref certificate(new SimpleCertificate()); + certificate->addDNSName("Bar.com"); + + CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); + } + void testCertificateVerifies_WithSecondMatchingDNSName() { ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); @@ -131,6 +141,24 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); } + void testCertificateVerifies_WithMatchingSRVNameWithServerExpected() { + // Server-mode test which gets cert with "xmpp-server" SRV name + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get(), true); + SimpleCertificate::ref certificate(new SimpleCertificate()); + certificate->addSRVName("_xmpp-server.bar.com"); + + CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); + } + + void testCertificateVerifies_WithMatchingSRVNameWithClientUnexpected() { + // Server-mode test which gets cert with "xmpp-client" SRV name + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get(), true); + SimpleCertificate::ref certificate(new SimpleCertificate()); + certificate->addSRVName("_xmpp-client.bar.com"); + + CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); + } + void testCertificateVerifies_WithMatchingXmppAddr() { ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); @@ -139,6 +167,14 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); } + void testCertificateVerifies_WithMatchingXmppAddrMixedCase() { + ServerIdentityVerifier testling(JID("foo@baR.com/baz"), idnConverter.get()); + SimpleCertificate::ref certificate(new SimpleCertificate()); + certificate->addXMPPAddress("bAr.com"); + + CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); + } + void testCertificateVerifies_WithMatchingXmppAddrWithWildcard() { ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); @@ -147,6 +183,14 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); } + void testCertificateVerifies_WithMatchingXmppAddrWithWildcardMixedCase() { + ServerIdentityVerifier testling(JID("foo@im.bAr.com/baz"), idnConverter.get()); + SimpleCertificate::ref certificate(new SimpleCertificate()); + certificate->addXMPPAddress("*.baR.com"); + + CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); + } + void testCertificateVerifies_WithMatchingInternationalXmppAddr() { ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); @@ -155,6 +199,14 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); } + void testCertificateVerifies_WithMatchingInternationalXmppAddrMixedCase() { + ServerIdentityVerifier testling(JID("foo@tRon\xc3\xa7.com/baz"), idnConverter.get()); + SimpleCertificate::ref certificate(new SimpleCertificate()); + certificate->addXMPPAddress("trOn\xc3\xa7.com"); + + CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); + } + void testCertificateVerifies_WithMatchingCNWithoutSAN() { ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); diff --git a/Swiften/VCards/UnitTest/VCardManagerTest.cpp b/Swiften/VCards/UnitTest/VCardManagerTest.cpp index 3d5338d..669c3ff 100644 --- a/Swiften/VCards/UnitTest/VCardManagerTest.cpp +++ b/Swiften/VCards/UnitTest/VCardManagerTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -31,7 +31,17 @@ class VCardManagerTest : public CppUnit::TestFixture { CPPUNIT_TEST(testRequest_Error); CPPUNIT_TEST(testRequest_VCardAlreadyRequested); CPPUNIT_TEST(testRequest_AfterPreviousRequest); - CPPUNIT_TEST(testRequestOwnVCard); + + CPPUNIT_TEST(testRequestVCard_ReturnFullVCard); + CPPUNIT_TEST(testRequestVCard_ReturnEmptyVCard); + CPPUNIT_TEST(testRequestVCard_ReturnItemNotFoundError); + CPPUNIT_TEST(testRequestVCard_ReturnFeatureNotImplementedError); + + CPPUNIT_TEST(testRequestOwnVCard_ReturnFullVCard); + CPPUNIT_TEST(testRequestOwnVCard_ReturnEmptyVCard); + CPPUNIT_TEST(testRequestOwnVCard_ReturnItemNotFoundError); + CPPUNIT_TEST(testRequestOwnVCard_ReturnFeatureNotImplementedError); + CPPUNIT_TEST(testCreateSetVCardRequest); CPPUNIT_TEST(testCreateSetVCardRequest_Error); CPPUNIT_TEST_SUITE_END(); @@ -54,7 +64,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testGet_NewVCardRequestsVCard() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); VCard::ref result = testling->getVCardAndRequestWhenNeeded(JID("foo@bar.com/baz")); CPPUNIT_ASSERT(!result); @@ -63,7 +73,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testGet_ExistingVCard() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); VCard::ref vcard(new VCard()); vcard->setFullName("Foo Bar"); vcardStorage->setVCard(JID("foo@bar.com/baz"), vcard); @@ -75,7 +85,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_RequestsVCard() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); @@ -83,7 +93,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_ReceiveEmitsNotification() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); stanzaChannel->onIQReceived(createVCardResult()); @@ -96,7 +106,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_Error() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); @@ -105,7 +115,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_VCardAlreadyRequested() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); VCard::ref result = testling->getVCardAndRequestWhenNeeded(JID("foo@bar.com/baz")); @@ -114,7 +124,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_AfterPreviousRequest() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); stanzaChannel->onIQReceived(createVCardResult()); testling->requestVCard(JID("foo@bar.com/baz")); @@ -123,8 +133,60 @@ class VCardManagerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(1, JID("foo@bar.com/baz"), IQ::Get)); } - void testRequestOwnVCard() { - std::shared_ptr<VCardManager> testling = createManager(); + void testRequestVCard_ReturnFullVCard() { + auto testling = createManager(); + testling->requestVCard(JID("foo@bar.com/baz")); + stanzaChannel->onIQReceived(createVCardResult()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID("foo@bar.com/baz"), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/baz"), changes[0].first); + CPPUNIT_ASSERT_EQUAL(std::string("Foo Bar"), changes[0].second->getFullName()); + CPPUNIT_ASSERT_EQUAL(false, changes[0].second->isEmpty()); + } + + void testRequestVCard_ReturnEmptyVCard() { + auto testling = createManager(); + testling->requestVCard(JID("foo@bar.com/baz")); + stanzaChannel->onIQReceived([&](){ + auto vcard = std::make_shared<VCard>(); + return IQ::createResult(JID("foo@bar.com/baz"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), vcard); + }()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID("foo@bar.com/baz"), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); + CPPUNIT_ASSERT_EQUAL(true, changes[0].second->isEmpty()); + } + + void testRequestVCard_ReturnItemNotFoundError() { + auto testling = createManager(); + testling->requestVCard(JID("foo@bar.com/baz")); + stanzaChannel->onIQReceived([&](){ + return IQ::createError(JID("foo@bar.com/baz"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), ErrorPayload::ItemNotFound); + }()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID("foo@bar.com/baz"), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); + CPPUNIT_ASSERT_EQUAL(true, changes[0].second->isEmpty()); + } + + void testRequestVCard_ReturnFeatureNotImplementedError() { + auto testling = createManager(); + testling->requestVCard(JID("foo@bar.com/baz")); + stanzaChannel->onIQReceived([&](){ + return IQ::createError(JID("foo@bar.com/baz"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), ErrorPayload::FeatureNotImplemented); + }()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID("foo@bar.com/baz"), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size())); + } + + void testRequestOwnVCard_ReturnFullVCard() { + auto testling = createManager(); testling->requestVCard(ownJID); stanzaChannel->onIQReceived(createOwnVCardResult()); @@ -139,8 +201,47 @@ class VCardManagerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Myself"), ownChanges[0]->getFullName()); } + void testRequestOwnVCard_ReturnEmptyVCard() { + auto testling = createManager(); + testling->requestVCard(ownJID); + stanzaChannel->onIQReceived([&](){ + auto vcard = std::make_shared<VCard>(); + return IQ::createResult(JID(), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), vcard); + }()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID(), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); + CPPUNIT_ASSERT_EQUAL(true, changes[0].second->isEmpty()); + } + + void testRequestOwnVCard_ReturnItemNotFoundError() { + auto testling = createManager(); + testling->requestVCard(ownJID); + stanzaChannel->onIQReceived([&](){ + return IQ::createError(JID(), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), ErrorPayload::ItemNotFound); + }()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID(), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); + CPPUNIT_ASSERT_EQUAL(true, changes[0].second->isEmpty()); + } + + void testRequestOwnVCard_ReturnFeatureNotImplementedError() { + auto testling = createManager(); + testling->requestVCard(ownJID); + stanzaChannel->onIQReceived([&](){ + return IQ::createError(JID(), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), ErrorPayload::FeatureNotImplemented); + }()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID(), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size())); + } + void testCreateSetVCardRequest() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); VCard::ref vcard = std::make_shared<VCard>(); vcard->setFullName("New Name"); SetVCardRequest::ref request = testling->createSetVCardRequest(vcard); @@ -154,7 +255,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testCreateSetVCardRequest_Error() { - std::shared_ptr<VCardManager> testling = createManager(); + auto testling = createManager(); VCard::ref vcard = std::make_shared<VCard>(); vcard->setFullName("New Name"); SetVCardRequest::ref request = testling->createSetVCardRequest(vcard); diff --git a/Swiften/VCards/VCardManager.cpp b/Swiften/VCards/VCardManager.cpp index 95b96fa..9423702 100644 --- a/Swiften/VCards/VCardManager.cpp +++ b/Swiften/VCards/VCardManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -50,10 +50,9 @@ void VCardManager::requestOwnVCard() { requestVCard(JID()); } - void VCardManager::handleVCardReceived(const JID& actualJID, VCard::ref vcard, ErrorPayload::ref error) { requestedVCards.erase(actualJID); - if (!error) { + if (!error || (error && error->getCondition() == ErrorPayload::ItemNotFound)) { if (!vcard) { vcard = VCard::ref(new VCard()); } |