summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/Base/String.cpp17
-rw-r--r--Swiften/Base/String.h2
-rw-r--r--Swiften/Base/UnitTest/StringTest.cpp10
-rw-r--r--Swiften/EventLoop/DummyEventLoop.h20
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h2
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h2
-rw-r--r--Swiften/LinkLocal/DNSSD/DNSSDQuerier.h3
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp25
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h8
-rw-r--r--Swiften/LinkLocal/DNSSD/Makefile.inc3
-rw-r--r--Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp25
-rw-r--r--Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h12
-rw-r--r--Swiften/LinkLocal/LinkLocalConnector.cpp34
-rw-r--r--Swiften/LinkLocal/LinkLocalConnector.h19
-rw-r--r--Swiften/LinkLocal/LinkLocalService.cpp4
-rw-r--r--Swiften/LinkLocal/LinkLocalService.h3
-rw-r--r--Swiften/LinkLocal/LinkLocalServiceBrowser.h5
-rw-r--r--Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp135
-rw-r--r--Swiften/LinkLocal/UnitTest/Makefile.inc3
-rw-r--r--Swiften/Network/BoostConnectionServer.cpp48
-rw-r--r--Swiften/Network/BoostConnectionServer.h13
-rw-r--r--Swiften/Network/FakeConnection.h88
-rw-r--r--Swiften/Network/HostAddress.cpp12
-rw-r--r--Swiften/Network/HostAddress.h8
-rw-r--r--Swiften/Network/UnitTest/HostAddressTest.cpp11
-rw-r--r--Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp72
-rw-r--r--Swiften/QA/NetworkTest/Makefile.inc1
27 files changed, 534 insertions, 51 deletions
diff --git a/Swiften/Base/String.cpp b/Swiften/Base/String.cpp
index 3495d9a..cc989f6 100644
--- a/Swiften/Base/String.cpp
+++ b/Swiften/Base/String.cpp
@@ -96,4 +96,21 @@ String String::getLowerCase() const {
return String(lower);
}
+std::vector<String> String::split(char c) const {
+ assert((c & 0x80) == 0);
+ std::vector<String> result;
+ String accumulator;
+ for (size_t i = 0; i < data_.size(); ++i) {
+ if (data_[i] == c) {
+ result.push_back(accumulator);
+ accumulator = "";
+ }
+ else {
+ accumulator += data_[i];
+ }
+ }
+ result.push_back(accumulator);
+ return result;
+}
+
}
diff --git a/Swiften/Base/String.h b/Swiften/Base/String.h
index 247a8a3..336a663 100644
--- a/Swiften/Base/String.h
+++ b/Swiften/Base/String.h
@@ -37,6 +37,8 @@ namespace Swift {
*/
std::pair<String,String> getSplittedAtFirst(char c) const;
+ std::vector<String> split(char c) const;
+
size_t getLength() const;
String getLowerCase() const;
diff --git a/Swiften/Base/UnitTest/StringTest.cpp b/Swiften/Base/UnitTest/StringTest.cpp
index 2fa9f54..1dd44fb 100644
--- a/Swiften/Base/UnitTest/StringTest.cpp
+++ b/Swiften/Base/UnitTest/StringTest.cpp
@@ -24,6 +24,7 @@ class StringTest : public CppUnit::TestFixture
CPPUNIT_TEST(testReplaceAll_ConsecutiveChars);
CPPUNIT_TEST(testReplaceAll_MatchingReplace);
CPPUNIT_TEST(testGetLowerCase);
+ CPPUNIT_TEST(testSplit);
CPPUNIT_TEST_SUITE_END();
public:
@@ -148,6 +149,15 @@ class StringTest : public CppUnit::TestFixture
CPPUNIT_ASSERT_EQUAL(String("abcd e"), testling.getLowerCase());
}
+
+ void testSplit() {
+ std::vector<String> result = String("abc def ghi").split(' ');
+
+ CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(result.size()));
+ CPPUNIT_ASSERT_EQUAL(String("abc"), result[0]);
+ CPPUNIT_ASSERT_EQUAL(String("def"), result[1]);
+ CPPUNIT_ASSERT_EQUAL(String("ghi"), result[2]);
+ }
};
CPPUNIT_TEST_SUITE_REGISTRATION(StringTest);
diff --git a/Swiften/EventLoop/DummyEventLoop.h b/Swiften/EventLoop/DummyEventLoop.h
index 234ecfa..7766bd4 100644
--- a/Swiften/EventLoop/DummyEventLoop.h
+++ b/Swiften/EventLoop/DummyEventLoop.h
@@ -1,7 +1,7 @@
-#ifndef SWIFTEN_DummyEventLoop_H
-#define SWIFTEN_DummyEventLoop_H
+#pragma once
#include <deque>
+#include <iostream>
#include <boost/function.hpp>
#include "Swiften/EventLoop/EventLoop.h"
@@ -13,6 +13,13 @@ namespace Swift {
DummyEventLoop() {
}
+ ~DummyEventLoop() {
+ if (!events_.empty()) {
+ std::cerr << "DummyEventLoop: Unhandled events at destruction time" << std::endl;
+ }
+ events_.clear();
+ }
+
void processEvents() {
while (!events_.empty()) {
handleEvent(events_[0]);
@@ -20,9 +27,9 @@ namespace Swift {
}
}
- bool hasEvents() {
- return events_.size() > 0;
- }
+ bool hasEvents() {
+ return events_.size() > 0;
+ }
virtual void post(const Event& event) {
events_.push_back(event);
@@ -32,6 +39,3 @@ namespace Swift {
std::deque<Event> events_;
};
}
-
-#endif
-
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h
index c605175..2dec2fb 100644
--- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h
@@ -41,7 +41,7 @@ namespace Swift {
MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this());
}
else {
- std::cout << "Discovered service: name:" << name << " domain:" << domain << " type: " << type << std::endl;
+ //std::cout << "Discovered service: name:" << name << " domain:" << domain << " type: " << type << std::endl;
DNSSDServiceID service(name, domain, type, interfaceIndex);
if (flags & kDNSServiceFlagsAdd) {
MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this());
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h
index 886b87b..1c38179 100644
--- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h
@@ -45,7 +45,7 @@ namespace Swift {
MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
}
else {
- std::cout << "Service resolved: name:" << fullName << " host:" << host << " port:" << port << std::endl;
+ //std::cout << "Service resolved: name:" << fullName << " host:" << host << " port:" << port << std::endl;
MainEventLoop::postEvent(
boost::bind(
boost::ref(onServiceResolved),
diff --git a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h
index 799bc0c..efcc140 100644
--- a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h
+++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h
@@ -15,6 +15,9 @@ namespace Swift {
public:
virtual ~DNSSDQuerier();
+ virtual void start() = 0;
+ virtual void stop() = 0;
+
virtual boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery() = 0;
virtual boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery(
const String& name, int port, const ByteArray& info) = 0;
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
index 5079192..c26f8ee 100644
--- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
@@ -13,6 +13,12 @@ namespace Swift {
FakeDNSSDQuerier::FakeDNSSDQuerier(const String& domain) : domain(domain) {
}
+FakeDNSSDQuerier::~FakeDNSSDQuerier() {
+ if (!runningQueries.empty()) {
+ std::cerr << "FakeDNSSDQuerier: Running queries not empty at destruction time" << std::endl;
+ }
+}
+
boost::shared_ptr<DNSSDBrowseQuery> FakeDNSSDQuerier::createBrowseQuery() {
return boost::shared_ptr<DNSSDBrowseQuery>(new FakeDNSSDBrowseQuery(shared_from_this()));
}
@@ -47,6 +53,15 @@ void FakeDNSSDQuerier::addRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query)
DNSSDServiceID service(registerQuery->name, domain);
MainEventLoop::postEvent(boost::bind(boost::ref(registerQuery->onRegisterFinished), service), shared_from_this());
}
+ else if (boost::shared_ptr<FakeDNSSDResolveHostnameQuery> resolveHostnameQuery = boost::dynamic_pointer_cast<FakeDNSSDResolveHostnameQuery>(query)) {
+ std::map<String,boost::optional<HostAddress> >::const_iterator i = addresses.find(resolveHostnameQuery->hostname);
+ if (i != addresses.end()) {
+ MainEventLoop::postEvent(
+ boost::bind(
+ boost::ref(resolveHostnameQuery->onHostnameResolved), i->second),
+ shared_from_this());
+ }
+ }
}
void FakeDNSSDQuerier::removeRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query) {
@@ -102,4 +117,14 @@ void FakeDNSSDQuerier::setRegisterError() {
}
}
+void FakeDNSSDQuerier::setAddress(const String& hostname, boost::optional<HostAddress> address) {
+ addresses[hostname] = address;
+ foreach(const boost::shared_ptr<FakeDNSSDResolveHostnameQuery>& query, getQueries<FakeDNSSDResolveHostnameQuery>()) {
+ if (query->hostname == hostname) {
+ MainEventLoop::postEvent(boost::bind(
+ boost::ref(query->onHostnameResolved), address), shared_from_this());
+ }
+ }
+}
+
}
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
index f2ec17b..22bca0c 100644
--- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
@@ -6,9 +6,11 @@
#include <set>
#include "Swiften/Base/foreach.h"
+#include "Swiften/Base/String.h"
#include "Swiften/EventLoop/EventOwner.h"
#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
+#include "Swiften/Network/HostAddress.h"
namespace Swift {
class ByteArray;
@@ -21,6 +23,10 @@ namespace Swift {
public boost::enable_shared_from_this<FakeDNSSDQuerier> {
public:
FakeDNSSDQuerier(const String& domain);
+ ~FakeDNSSDQuerier();
+
+ void start() {}
+ void stop() {}
boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery();
boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery(
@@ -37,6 +43,7 @@ namespace Swift {
void removeService(const DNSSDServiceID& id);
void setServiceInfo(const DNSSDServiceID& id, const DNSSDResolveServiceQuery::Result& info);
bool isServiceRegistered(const String& name, int port, const ByteArray& info);
+ void setAddress(const String& hostname, boost::optional<HostAddress> address);
void setBrowseError();
void setRegisterError();
@@ -59,5 +66,6 @@ namespace Swift {
std::set<DNSSDServiceID> services;
typedef std::map<DNSSDServiceID,DNSSDResolveServiceQuery::Result> ServiceInfoMap;
ServiceInfoMap serviceInfo;
+ std::map<String, boost::optional<HostAddress> > addresses;
};
}
diff --git a/Swiften/LinkLocal/DNSSD/Makefile.inc b/Swiften/LinkLocal/DNSSD/Makefile.inc
index f6997ef..4b014f3 100644
--- a/Swiften/LinkLocal/DNSSD/Makefile.inc
+++ b/Swiften/LinkLocal/DNSSD/Makefile.inc
@@ -4,7 +4,8 @@ SWIFTEN_SOURCES += \
Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp \
Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp \
Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp \
- Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp
+ Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp \
+ Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp
ifeq ($(HAVE_BONJOUR),yes)
include Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc
diff --git a/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp
new file mode 100644
index 0000000..e704b72
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp
@@ -0,0 +1,25 @@
+#include "Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h"
+
+#ifdef HAVE_SWIFTEN_CONFIG_H
+#include "Swiften/config.h"
+#endif
+#if defined(HAVE_BONJOUR)
+#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h"
+#elif defined(HAVE_AVAHI)
+#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h"
+#endif
+
+
+namespace Swift {
+
+boost::shared_ptr<DNSSDQuerier> PlatformDNSSDQuerierFactory::createQuerier() {
+#if defined(HAVE_BONJOUR)
+ return boost::shared_ptr<DNSSDQuerier>(new BonjourQuerier());
+#elif defined(HAVE_AVAHI)
+ return boost::shared_ptr<DNSSDQuerier>(new AvahiQuerier());
+#else
+ return boost::shared_ptr<DNSSDQuerier>();
+#endif
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h
new file mode 100644
index 0000000..b52814b
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+ class DNSSDQuerier;
+
+ class PlatformDNSSDQuerierFactory {
+ public:
+ boost::shared_ptr<DNSSDQuerier> createQuerier();
+ };
+}
diff --git a/Swiften/LinkLocal/LinkLocalConnector.cpp b/Swiften/LinkLocal/LinkLocalConnector.cpp
index 18b5d6a..fba4a4e 100644
--- a/Swiften/LinkLocal/LinkLocalConnector.cpp
+++ b/Swiften/LinkLocal/LinkLocalConnector.cpp
@@ -12,22 +12,22 @@
namespace Swift {
LinkLocalConnector::LinkLocalConnector(
- const JID& remoteJID,
- const String& hostname,
- int interfaceIndex,
- int port,
+ const LinkLocalService& service,
boost::shared_ptr<DNSSDQuerier> querier,
boost::shared_ptr<Connection> connection) :
- remoteJID(remoteJID),
- hostname(hostname),
- interfaceIndex(interfaceIndex),
- port(port),
+ service(service),
querier(querier),
connection(connection) {
}
+LinkLocalConnector::~LinkLocalConnector() {
+ assert(!resolveQuery);
+}
+
void LinkLocalConnector::connect() {
- resolveQuery = querier->createResolveHostnameQuery(hostname, interfaceIndex);
+ resolveQuery = querier->createResolveHostnameQuery(
+ service.getHostname(),
+ service.getID().getNetworkInterfaceID());
resolveQuery->onHostnameResolved.connect(boost::bind(
&LinkLocalConnector::handleHostnameResolved,
boost::dynamic_pointer_cast<LinkLocalConnector>(shared_from_this()),
@@ -35,16 +35,24 @@ void LinkLocalConnector::connect() {
resolveQuery->run();
}
+void LinkLocalConnector::cancel() {
+ if (resolveQuery) {
+ resolveQuery->finish();
+ }
+ resolveQuery.reset();
+ connection->disconnect();
+}
+
void LinkLocalConnector::handleHostnameResolved(const boost::optional<HostAddress>& address) {
+ resolveQuery->finish();
+ resolveQuery.reset();
if (address) {
- resolveQuery->finish();
- resolveQuery.reset();
connection->onConnectFinished.connect(
boost::bind(boost::ref(onConnectFinished), _1));
- connection->connect(HostAddressPort(*address, port));
+ connection->connect(HostAddressPort(*address, service.getPort()));
}
else {
- onConnectFinished(false);
+ onConnectFinished(true);
}
}
diff --git a/Swiften/LinkLocal/LinkLocalConnector.h b/Swiften/LinkLocal/LinkLocalConnector.h
index 134656c..0b6baef 100644
--- a/Swiften/LinkLocal/LinkLocalConnector.h
+++ b/Swiften/LinkLocal/LinkLocalConnector.h
@@ -5,13 +5,12 @@
#include <boost/enable_shared_from_this.hpp>
#include <vector>
-#include "Swiften/JID/JID.h"
#include "Swiften/Network/Connection.h"
+#include "Swiften/LinkLocal/LinkLocalService.h"
namespace Swift {
class ConnectionFactory;
class HostAddress;
- class String;
class Element;
class PayloadParserFactoryCollection;
class PayloadSerializerCollection;
@@ -21,18 +20,17 @@ namespace Swift {
class LinkLocalConnector : public boost::enable_shared_from_this<LinkLocalConnector> {
public:
LinkLocalConnector(
- const JID& remoteJID,
- const String& hostname,
- int interfaceIndex,
- int port,
+ const LinkLocalService& service,
boost::shared_ptr<DNSSDQuerier> querier,
boost::shared_ptr<Connection> connection);
+ ~LinkLocalConnector();
- const JID& getRemoteJID() const {
- return remoteJID;
+ const LinkLocalService& getService() const {
+ return service;
}
void connect();
+ void cancel();
void queueElement(boost::shared_ptr<Element> element);
const std::vector<boost::shared_ptr<Element> >& getQueuedElements() const {
@@ -50,10 +48,7 @@ namespace Swift {
void handleConnected(bool error);
private:
- JID remoteJID;
- String hostname;
- int interfaceIndex;
- int port;
+ LinkLocalService service;
boost::shared_ptr<DNSSDQuerier> querier;
boost::shared_ptr<DNSSDResolveHostnameQuery> resolveQuery;
boost::shared_ptr<Connection> connection;
diff --git a/Swiften/LinkLocal/LinkLocalService.cpp b/Swiften/LinkLocal/LinkLocalService.cpp
index f567a63..f1114ed 100644
--- a/Swiften/LinkLocal/LinkLocalService.cpp
+++ b/Swiften/LinkLocal/LinkLocalService.cpp
@@ -20,4 +20,8 @@ String LinkLocalService::getDescription() const {
return getName();
}
+JID LinkLocalService::getJID() const {
+ return JID(getName());
+}
+
}
diff --git a/Swiften/LinkLocal/LinkLocalService.h b/Swiften/LinkLocal/LinkLocalService.h
index f7e9e3c..8ae593c 100644
--- a/Swiften/LinkLocal/LinkLocalService.h
+++ b/Swiften/LinkLocal/LinkLocalService.h
@@ -1,6 +1,7 @@
#pragma once
#include "Swiften/Base/String.h"
+#include "Swiften/JID/JID.h"
#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
@@ -36,6 +37,8 @@ namespace Swift {
String getDescription() const;
+ JID getJID() const;
+
private:
DNSSDServiceID id;
DNSSDResolveServiceQuery::Result info;
diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.h b/Swiften/LinkLocal/LinkLocalServiceBrowser.h
index 7ef661c..66973d5 100644
--- a/Swiften/LinkLocal/LinkLocalServiceBrowser.h
+++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.h
@@ -36,6 +36,11 @@ namespace Swift {
std::vector<LinkLocalService> getServices() const;
+ // FIXME: Ugly that we need this
+ boost::shared_ptr<DNSSDQuerier> getQuerier() const {
+ return querier;
+ }
+
boost::signal<void (const LinkLocalService&)> onServiceAdded;
boost::signal<void (const LinkLocalService&)> onServiceChanged;
boost::signal<void (const LinkLocalService&)> onServiceRemoved;
diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp
new file mode 100644
index 0000000..ee5e414
--- /dev/null
+++ b/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp
@@ -0,0 +1,135 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swiften/LinkLocal/LinkLocalConnector.h"
+#include "Swiften/LinkLocal/LinkLocalService.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h"
+#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h"
+#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h"
+#include "Swiften/EventLoop/DummyEventLoop.h"
+#include "Swiften/Network/FakeConnection.h"
+
+using namespace Swift;
+
+class LinkLocalConnectorTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(LinkLocalConnectorTest);
+ CPPUNIT_TEST(testConnect);
+ CPPUNIT_TEST(testConnect_UnableToResolve);
+ CPPUNIT_TEST(testConnect_UnableToConnect);
+ CPPUNIT_TEST(testCancel_DuringResolve);
+ CPPUNIT_TEST(testCancel_DuringConnect);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ eventLoop = new DummyEventLoop();
+ querier = boost::shared_ptr<FakeDNSSDQuerier>(
+ new FakeDNSSDQuerier("rabbithole.local"));
+ connection = boost::shared_ptr<FakeConnection>(new FakeConnection());
+ connectFinished = false;
+ }
+
+ void tearDown() {
+ delete eventLoop;
+ }
+
+ void testConnect() {
+ boost::shared_ptr<LinkLocalConnector>
+ testling(createConnector("rabbithole.local", 1234));
+ querier->setAddress("rabbithole.local", HostAddress("192.168.1.1"));
+
+ testling->connect();
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(connectFinished);
+ CPPUNIT_ASSERT(!connectError);
+ CPPUNIT_ASSERT(connection->connectedTo);
+ CPPUNIT_ASSERT_EQUAL(String(connection->connectedTo->getAddress().toString()), String("192.168.1.1"));
+ CPPUNIT_ASSERT_EQUAL(connection->connectedTo->getPort(), 1234);
+ }
+
+ void testConnect_UnableToResolve() {
+ boost::shared_ptr<LinkLocalConnector>
+ testling(createConnector("rabbithole.local", 1234));
+ querier->setAddress("rabbithole.local", boost::optional<HostAddress>());
+
+ testling->connect();
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(connectFinished);
+ CPPUNIT_ASSERT(connectError);
+ CPPUNIT_ASSERT(!connection->connectedTo);
+ }
+
+ void testConnect_UnableToConnect() {
+ boost::shared_ptr<LinkLocalConnector>
+ testling(createConnector("rabbithole.local", 1234));
+ querier->setAddress("rabbithole.local", HostAddress("192.168.1.1"));
+ connection->setError(Connection::ReadError);
+
+ testling->connect();
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(connectFinished);
+ CPPUNIT_ASSERT(connectError);
+ CPPUNIT_ASSERT(!connection->connectedTo);
+ }
+
+ void testCancel_DuringResolve() {
+ boost::shared_ptr<LinkLocalConnector>
+ testling(createConnector("rabbithole.local", 1234));
+ testling->connect();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT(!connectFinished);
+
+ testling->cancel();
+ eventLoop->processEvents();
+ querier->setAddress("rabbithole.local", HostAddress("192.168.1.1"));
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(FakeConnection::Disconnected == connection->state);
+ }
+
+ void testCancel_DuringConnect() {
+ boost::shared_ptr<LinkLocalConnector>
+ testling(createConnector("rabbithole.local", 1234));
+ querier->setAddress("rabbithole.local", HostAddress("192.168.1.1"));
+ connection->setDelayConnect();
+ testling->connect();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT(FakeConnection::Connecting == connection->state);
+
+ testling->cancel();
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(FakeConnection::Disconnected == connection->state);
+ }
+
+ private:
+ boost::shared_ptr<LinkLocalConnector> createConnector(const String& hostname, int port) {
+ LinkLocalService service(
+ DNSSDServiceID("myname", "local."),
+ DNSSDResolveServiceQuery::Result(
+ "myname._presence._tcp.local", hostname, port,
+ LinkLocalServiceInfo().toTXTRecord()));
+ boost::shared_ptr<LinkLocalConnector> result(
+ new LinkLocalConnector(service, querier, connection));
+ result->onConnectFinished.connect(
+ boost::bind(&LinkLocalConnectorTest::handleConnected, this, _1));
+ return result;
+ }
+
+ void handleConnected(bool e) {
+ connectFinished = true;
+ connectError = e;
+ }
+
+ private:
+ DummyEventLoop* eventLoop;
+ boost::shared_ptr<FakeDNSSDQuerier> querier;
+ boost::shared_ptr<FakeConnection> connection;
+ bool connectFinished;
+ bool connectError;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalConnectorTest);
diff --git a/Swiften/LinkLocal/UnitTest/Makefile.inc b/Swiften/LinkLocal/UnitTest/Makefile.inc
index e5f1bf0..330808a 100644
--- a/Swiften/LinkLocal/UnitTest/Makefile.inc
+++ b/Swiften/LinkLocal/UnitTest/Makefile.inc
@@ -1,4 +1,5 @@
UNITTEST_SOURCES += \
Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp \
Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp \
- Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp
+ Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp \
+ Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp
diff --git a/Swiften/Network/BoostConnectionServer.cpp b/Swiften/Network/BoostConnectionServer.cpp
index 18a3ca4..4e83ad5 100644
--- a/Swiften/Network/BoostConnectionServer.cpp
+++ b/Swiften/Network/BoostConnectionServer.cpp
@@ -1,28 +1,64 @@
#include "Swiften/Network/BoostConnectionServer.h"
#include <boost/bind.hpp>
+#include <boost/system/system_error.hpp>
#include "Swiften/EventLoop/MainEventLoop.h"
namespace Swift {
-BoostConnectionServer::BoostConnectionServer(int port, boost::asio::io_service* ioService) : acceptor_(*ioService, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)) {
+BoostConnectionServer::BoostConnectionServer(int port, boost::asio::io_service* ioService) : port_(port), ioService_(ioService), acceptor_(NULL) {
}
void BoostConnectionServer::start() {
- acceptNextConnection();
+ try {
+ assert(!acceptor_);
+ acceptor_ = new boost::asio::ip::tcp::acceptor(
+ *ioService_,
+ boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port_));
+ acceptNextConnection();
+ }
+ catch (const boost::system::system_error& e) {
+ if (e.code() == boost::asio::error::address_in_use) {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onStopped), Conflict), shared_from_this());
+ }
+ else {
+ MainEventLoop::postEvent(boost::bind(boost::ref(onStopped), UnknownError), shared_from_this());
+ }
+ }
+}
+
+
+void BoostConnectionServer::stop() {
+ stop(boost::optional<Error>());
+}
+
+void BoostConnectionServer::stop(boost::optional<Error> e) {
+ if (acceptor_) {
+ acceptor_->close();
+ acceptor_ = NULL;
+ }
+ MainEventLoop::postEvent(boost::bind(boost::ref(onStopped), e), shared_from_this());
}
void BoostConnectionServer::acceptNextConnection() {
- boost::shared_ptr<BoostConnection> newConnection(new BoostConnection(&acceptor_.io_service()));
- acceptor_.async_accept(newConnection->getSocket(),
+ boost::shared_ptr<BoostConnection> newConnection(new BoostConnection(&acceptor_->io_service()));
+ acceptor_->async_accept(newConnection->getSocket(),
boost::bind(&BoostConnectionServer::handleAccept, shared_from_this(), newConnection, boost::asio::placeholders::error));
}
void BoostConnectionServer::handleAccept(boost::shared_ptr<BoostConnection> newConnection, const boost::system::error_code& error) {
- if (!error) {
- MainEventLoop::postEvent(boost::bind(boost::ref(onNewConnection), newConnection), shared_from_this());
+ if (error) {
+ MainEventLoop::postEvent(
+ boost::bind(
+ &BoostConnectionServer::stop, shared_from_this(), UnknownError),
+ shared_from_this());
+ }
+ else {
+ MainEventLoop::postEvent(
+ boost::bind(boost::ref(onNewConnection), newConnection),
+ shared_from_this());
newConnection->listen();
acceptNextConnection();
}
diff --git a/Swiften/Network/BoostConnectionServer.h b/Swiften/Network/BoostConnectionServer.h
index c92318e..d8e5eb4 100644
--- a/Swiften/Network/BoostConnectionServer.h
+++ b/Swiften/Network/BoostConnectionServer.h
@@ -3,6 +3,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
+#include <boost/signal.hpp>
#include "Swiften/Network/BoostConnection.h"
#include "Swiften/Network/ConnectionServer.h"
@@ -11,15 +12,25 @@
namespace Swift {
class BoostConnectionServer : public ConnectionServer, public EventOwner, public boost::enable_shared_from_this<BoostConnectionServer> {
public:
+ enum Error {
+ Conflict,
+ UnknownError
+ };
BoostConnectionServer(int port, boost::asio::io_service* ioService);
void start();
+ void stop();
+
+ boost::signal<void (boost::optional<Error>)> onStopped;
private:
+ void stop(boost::optional<Error> e);
void acceptNextConnection();
void handleAccept(boost::shared_ptr<BoostConnection> newConnection, const boost::system::error_code& error);
private:
- boost::asio::ip::tcp::acceptor acceptor_;
+ int port_;
+ boost::asio::io_service* ioService_;
+ boost::asio::ip::tcp::acceptor* acceptor_;
};
}
diff --git a/Swiften/Network/FakeConnection.h b/Swiften/Network/FakeConnection.h
new file mode 100644
index 0000000..92a03c3
--- /dev/null
+++ b/Swiften/Network/FakeConnection.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include <boost/optional.hpp>
+#include <boost/bind.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <vector>
+
+#include "Swiften/Network/Connection.h"
+#include "Swiften/Network/HostAddressPort.h"
+#include "Swiften/EventLoop/EventOwner.h"
+#include "Swiften/EventLoop/MainEventLoop.h"
+
+namespace Swift {
+ class FakeConnection :
+ public Connection,
+ public EventOwner,
+ public boost::enable_shared_from_this<FakeConnection> {
+ public:
+ enum State {
+ Initial,
+ Connecting,
+ Connected,
+ Disconnected,
+ DisconnectedWithError
+ };
+
+ FakeConnection() : state(Initial), delayConnect(false) {}
+
+ virtual void listen() {
+ assert(false);
+ }
+
+ void setError(const Error& e) {
+ error = boost::optional<Error>(e);
+ state = DisconnectedWithError;
+ if (connectedTo) {
+ MainEventLoop::postEvent(
+ boost::bind(boost::ref(onDisconnected), error),
+ shared_from_this());
+ }
+ }
+
+ virtual void connect(const HostAddressPort& address) {
+ if (delayConnect) {
+ state = Connecting;
+ }
+ else {
+ if (!error) {
+ connectedTo = address;
+ state = Connected;
+ }
+ else {
+ state = DisconnectedWithError;
+ }
+ MainEventLoop::postEvent(
+ boost::bind(boost::ref(onConnectFinished), error),
+ shared_from_this());
+ }
+ }
+
+ virtual void disconnect() {
+ if (!error) {
+ state = Disconnected;
+ }
+ else {
+ state = DisconnectedWithError;
+ }
+ connectedTo.reset();
+ MainEventLoop::postEvent(
+ boost::bind(boost::ref(onDisconnected), error),
+ shared_from_this());
+ }
+
+ virtual void write(const ByteArray& data) {
+ dataWritten.push_back(data);
+ }
+
+ void setDelayConnect() {
+ delayConnect = true;
+ }
+
+ boost::optional<HostAddressPort> connectedTo;
+ std::vector<ByteArray> dataWritten;
+ boost::optional<Error> error;
+ State state;
+ bool delayConnect;
+ };
+}
diff --git a/Swiften/Network/HostAddress.cpp b/Swiften/Network/HostAddress.cpp
index 84a0012..ea324cb 100644
--- a/Swiften/Network/HostAddress.cpp
+++ b/Swiften/Network/HostAddress.cpp
@@ -1,10 +1,14 @@
#include "Swiften/Network/HostAddress.h"
#include <boost/numeric/conversion/cast.hpp>
+#include <boost/lexical_cast.hpp>
#include <cassert>
#include <sstream>
#include <iomanip>
+#include "Swiften/Base/foreach.h"
+#include "Swiften/Base/String.h"
+
namespace Swift {
HostAddress::HostAddress() {
@@ -13,6 +17,14 @@ HostAddress::HostAddress() {
}
}
+HostAddress::HostAddress(const String& address) {
+ std::vector<String> components = address.split('.');
+ assert(components.size() == 4);
+ foreach(const String& component, components) {
+ address_.push_back(boost::lexical_cast<int>(component.getUTF8String()));
+ }
+}
+
HostAddress::HostAddress(const unsigned char* address, int length) {
assert(length == 4 || length == 16);
address_.reserve(length);
diff --git a/Swiften/Network/HostAddress.h b/Swiften/Network/HostAddress.h
index 2c9760d..fa34df4 100644
--- a/Swiften/Network/HostAddress.h
+++ b/Swiften/Network/HostAddress.h
@@ -1,13 +1,15 @@
-#ifndef SWIFTEN_HOSTADDRESS
-#define SWIFTEN_HOSTADDRESS
+#pragma once
#include <string>
#include <vector>
namespace Swift {
+ class String;
+
class HostAddress {
public:
HostAddress();
+ HostAddress(const String&);
HostAddress(const unsigned char* address, int length);
const std::vector<unsigned char>& getRawAddress() const {
@@ -20,5 +22,3 @@ namespace Swift {
std::vector<unsigned char> address_;
};
}
-
-#endif
diff --git a/Swiften/Network/UnitTest/HostAddressTest.cpp b/Swiften/Network/UnitTest/HostAddressTest.cpp
index b805647..50e9198 100644
--- a/Swiften/Network/UnitTest/HostAddressTest.cpp
+++ b/Swiften/Network/UnitTest/HostAddressTest.cpp
@@ -2,18 +2,23 @@
#include <cppunit/extensions/TestFactoryRegistry.h>
#include "Swiften/Network/HostAddress.h"
+#include "Swiften/Base/String.h"
using namespace Swift;
-class HostAddressTest : public CppUnit::TestFixture
-{
+class HostAddressTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(HostAddressTest);
+ CPPUNIT_TEST(testConstructor);
CPPUNIT_TEST(testToString);
CPPUNIT_TEST(testToString_IPv6);
CPPUNIT_TEST_SUITE_END();
public:
- HostAddressTest() {}
+ void testConstructor() {
+ HostAddress testling("192.168.1.254");
+
+ CPPUNIT_ASSERT_EQUAL(std::string("192.168.1.254"), testling.toString());
+ }
void testToString() {
unsigned char address[4] = {10, 0, 1, 253};
diff --git a/Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp b/Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp
new file mode 100644
index 0000000..a5c51aa
--- /dev/null
+++ b/Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp
@@ -0,0 +1,72 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/Network/BoostConnectionServer.h"
+#include "Swiften/Network/BoostIOServiceThread.h"
+#include "Swiften/EventLoop/DummyEventLoop.h"
+
+using namespace Swift;
+
+class BoostConnectionServerTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(BoostConnectionServerTest);
+ CPPUNIT_TEST(testConstructor_TwoServersOnSamePort);
+ CPPUNIT_TEST(testStart_Conflict);
+ CPPUNIT_TEST(testStop);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ boostIOServiceThread_ = new BoostIOServiceThread();
+ eventLoop_ = new DummyEventLoop();
+ stopped = false;
+ stoppedError.reset();
+ }
+
+ void tearDown() {
+ delete eventLoop_;
+ delete boostIOServiceThread_;
+ }
+
+ void testConstructor_TwoServersOnSamePort() {
+ boost::shared_ptr<BoostConnectionServer> testling(new BoostConnectionServer(9999, &boostIOServiceThread_->getIOService()));
+ boost::shared_ptr<BoostConnectionServer> testling2(new BoostConnectionServer(9999, &boostIOServiceThread_->getIOService()));
+ }
+
+ void testStart_Conflict() {
+ boost::shared_ptr<BoostConnectionServer> testling(new BoostConnectionServer(9999, &boostIOServiceThread_->getIOService()));
+ testling->start();
+
+ boost::shared_ptr<BoostConnectionServer> testling2(new BoostConnectionServer(9999, &boostIOServiceThread_->getIOService()));
+ testling2->onStopped.connect(
+ boost::bind(&BoostConnectionServerTest::handleStopped, this, _1));
+
+ testling->stop();
+ }
+
+ void testStop() {
+ boost::shared_ptr<BoostConnectionServer> testling(new BoostConnectionServer(9999, &boostIOServiceThread_->getIOService()));
+ testling->start();
+
+ testling->stop();
+
+ boost::shared_ptr<BoostConnectionServer> testling2(new BoostConnectionServer(9999, &boostIOServiceThread_->getIOService()));
+ testling2->start();
+
+ testling2->stop();
+ }
+
+ void handleStopped(boost::optional<BoostConnectionServer::Error> e) {
+ stopped = true;
+ stoppedError = e;
+ }
+
+ private:
+ BoostIOServiceThread* boostIOServiceThread_;
+ DummyEventLoop* eventLoop_;
+ bool stopped;
+ boost::optional<BoostConnectionServer::Error> stoppedError;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(BoostConnectionServerTest);
diff --git a/Swiften/QA/NetworkTest/Makefile.inc b/Swiften/QA/NetworkTest/Makefile.inc
index b263cdb..57c97a1 100644
--- a/Swiften/QA/NetworkTest/Makefile.inc
+++ b/Swiften/QA/NetworkTest/Makefile.inc
@@ -2,6 +2,7 @@ NETWORKTEST_TARGET += Swiften/QA/NetworkTest/checker
NETWORKTEST_SOURCES += \
Swiften/QA/NetworkTest/DomainNameResolverTest.cpp \
Swiften/QA/NetworkTest/BoostConnectionTest.cpp \
+ Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp \
QA/UnitTest/checker.cpp
NETWORKTEST_OBJECTS = \
$(NETWORKTEST_SOURCES:.cpp=.o)