From 936f7ff9b80aca95040301a4b3cfcd2a248e3334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Mon, 8 Feb 2010 17:48:54 +0100 Subject: Added beginnings of Avahi support. diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h new file mode 100644 index 0000000..229f97e --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h @@ -0,0 +1,64 @@ +#pragma once + +#include + +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" +#include "Swiften/EventLoop/MainEventLoop.h" + +namespace Swift { + class AvahiQuerier; + + class AvahiBrowseQuery : public DNSSDBrowseQuery, public AvahiQuery { + public: + AvahiBrowseQuery(boost::shared_ptr q) : AvahiQuery(q) { + } + + void startBrowsing() { + std::cout << "Start browsing" << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + std::cout << "Creating browser" << std::endl; + AvahiServiceBrowser* browser = avahi_service_browser_new(querier->getClient(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_presence._tcp", NULL, (AvahiLookupFlags) 0, &handleServiceDiscoveredStatic, this); + if (!browser) { + std::cout << "Error" << std::endl; + MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this()); + } + std::cout << "Unlocking" << std::endl; + avahi_threaded_poll_unlock(querier->getThreadedPoll()); + std::cout << "Browse started" << std::endl; + } + + void stopBrowsing() { + // TODO + } + + private: + static void handleServiceDiscoveredStatic(AvahiServiceBrowser *b, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* context) { + static_cast(context)->handleServiceDiscovered(b, interfaceIndex, protocol, event, name, type, domain, flags); + } + + void handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) { + switch (event) { + case AVAHI_BROWSER_FAILURE: + std::cout << "Service browse error" << std::endl; + MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this()); + break; + case AVAHI_BROWSER_NEW: { + DNSSDServiceID service(name, domain, type, interfaceIndex); + std::cout << "Service discovered " << name << " " << type << " " << domain << std::endl; + MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); + break; + } + case AVAHI_BROWSER_REMOVE: { + std::cout << "Service went away " << name << " " << type << " " << domain << std::endl; + DNSSDServiceID service(name, domain, type, interfaceIndex); + MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); + break; + } + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + break; + } + } + }; +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp index 55ccede..c4bfcb4 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp @@ -2,11 +2,10 @@ #include -//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h" -//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h" -//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h" -//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h" -//#include "Swiften/Base/foreach.h" +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h" +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h" +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h" +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h" namespace Swift { @@ -17,22 +16,23 @@ AvahiQuerier::~AvahiQuerier() { } boost::shared_ptr AvahiQuerier::createBrowseQuery() { - //return boost::shared_ptr(new AvahiBrowseQuery(shared_from_this())); + return boost::shared_ptr(new AvahiBrowseQuery(shared_from_this())); } boost::shared_ptr AvahiQuerier::createRegisterQuery(const String& name, int port, const ByteArray& info) { - //return boost::shared_ptr(new AvahiRegisterQuery(name, port, info, shared_from_this())); + return boost::shared_ptr(new AvahiRegisterQuery(name, port, info, shared_from_this())); } boost::shared_ptr AvahiQuerier::createResolveServiceQuery(const DNSSDServiceID& service) { - //return boost::shared_ptr(new AvahiResolveServiceQuery(service, shared_from_this())); + return boost::shared_ptr(new AvahiResolveServiceQuery(service, shared_from_this())); } boost::shared_ptr AvahiQuerier::createResolveHostnameQuery(const String& hostname, int interfaceIndex) { - //return boost::shared_ptr(new AvahiResolveHostnameQuery(hostname, interfaceIndex, shared_from_this())); + return boost::shared_ptr(new AvahiResolveHostnameQuery(hostname, interfaceIndex, shared_from_this())); } void AvahiQuerier::start() { + std::cout << "Starrting querier" << std::endl; assert(!threadedPoll); threadedPoll = avahi_threaded_poll_new(); int error; @@ -45,6 +45,7 @@ void AvahiQuerier::start() { std::cerr << "Avahi Error: " << avahi_strerror(error) << std::endl; return; } + std::cout << "Starrting event loop" << std::endl; avahi_threaded_poll_start(threadedPoll); } diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h index ca45384..ffb8441 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h @@ -31,6 +31,14 @@ namespace Swift { void start(); void stop(); + + AvahiThreadedPoll* getThreadedPoll() const { + return threadedPoll; + } + + AvahiClient* getClient() const { + return client; + } private: AvahiClient* client; diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp new file mode 100644 index 0000000..6b7c7f9 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp @@ -0,0 +1,13 @@ +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h" + +namespace Swift { + +AvahiQuery::AvahiQuery(boost::shared_ptr q) : querier(q) { +} + +AvahiQuery::~AvahiQuery() { +} + +} + diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h new file mode 100644 index 0000000..847f3f7 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#include "Swiften/EventLoop/EventOwner.h" + +namespace Swift { + class AvahiQuerier; + + class AvahiQuery : + public EventOwner, + public boost::enable_shared_from_this { + public: + AvahiQuery(boost::shared_ptr); + virtual ~AvahiQuery(); + + protected: + boost::shared_ptr querier; + }; +} + diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h new file mode 100644 index 0000000..102db1b --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h @@ -0,0 +1,123 @@ +#pragma once + +#include + +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/EventLoop/MainEventLoop.h" + +namespace Swift { + class AvahiQuerier; + + class AvahiRegisterQuery : public DNSSDRegisterQuery, public AvahiQuery { + public: + AvahiRegisterQuery(const String& name, int port, const ByteArray& txtRecord, boost::shared_ptr querier) : AvahiQuery(querier), name(name), port(port), txtRecord(txtRecord), group(0) { + } + + void registerService() { + std::cout << "Registering service " << name << ":" << port << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + if (!group) { + std::cout << "Creating entry group" << std::endl; + group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this); + if (!group) { + std::cout << "Error ceating entry group" << std::endl; + MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional()), shared_from_this()); + } + } + + doRegisterService(); + avahi_threaded_poll_unlock(querier->getThreadedPoll()); + } + + void unregisterService() { + } + + void updateServiceInfo(const ByteArray& txtRecord) { + this->txtRecord = txtRecord; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + assert(group); + avahi_entry_group_reset(group); + doRegisterService(); + avahi_threaded_poll_unlock(querier->getThreadedPoll()); + } + + private: + void doRegisterService() { + AvahiStringList* txtList; + avahi_string_list_parse(txtRecord.getData(), txtRecord.getSize(), &txtList); + + int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags) 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, txtList); + if (result < 0) { + std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; + MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional()), shared_from_this()); + } + result = avahi_entry_group_commit(group); + if (result < 0) { + std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; + } + } + + static void handleEntryGroupChange(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { + static_cast(userdata)->handleEntryGroupChange(g, state); + } + + void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) { + std::cout << "ENtry group callback: " << state << std::endl; + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED : + // Domain is a hack! + MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this()); + std::cout << "Entry group established" << std::endl; + break; + case AVAHI_ENTRY_GROUP_COLLISION : { + std::cout << "Entry group collision" << std::endl; + /*char *n; + n = avahi_alternative_service_name(name); + avahi_free(name); + name = n;*/ + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE : + std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl; + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; + + /* + DNSServiceErrorType result = DNSServiceRegister( + &sdRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, + txtRecord.getSize(), txtRecord.getData(), + &AvahiRegisterQuery::handleServiceRegisteredStatic, this); + if (result != kDNSServiceErr_NoError) { + sdRef = NULL; + }*/ + //MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional()), shared_from_this()); + } + } + +/* + static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { + static_cast(context)->handleServiceRegistered(errorCode, name, regtype, domain); + } + + void handleServiceRegistered(DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) { + if (errorCode != kDNSServiceErr_NoError) { + MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional()), shared_from_this()); + } + else { + } + } + */ + + private: + String name; + int port; + ByteArray txtRecord; + AvahiEntryGroup* group; + }; +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h new file mode 100644 index 0000000..ee0e837 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" +#include "Swiften/EventLoop/MainEventLoop.h" +#include "Swiften/Network/HostAddress.h" + +#include + +namespace Swift { + class AvahiQuerier; + + class AvahiResolveHostnameQuery : public DNSSDResolveHostnameQuery, public AvahiQuery { + public: + AvahiResolveHostnameQuery(const String& hostname, int, boost::shared_ptr querier) : AvahiQuery(querier), hostname(hostname) { + std::cout << "Resolving hostname " << hostname << std::endl; + } + + void run() { + MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional(HostAddress(hostname))), shared_from_this()); + } + + void finish() { + } + + private: + HostAddress hostAddress; + String hostname; + }; +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h new file mode 100644 index 0000000..8577837 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h @@ -0,0 +1,73 @@ +#pragma once + +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/EventLoop/MainEventLoop.h" + +namespace Swift { + class AvahiQuerier; + + class AvahiResolveServiceQuery : public DNSSDResolveServiceQuery, public AvahiQuery { + public: + AvahiResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr querier) : AvahiQuery(querier), service(service), resolver(NULL) { + } + + void start() { + std::cout << "Resolving " << service.getName() << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + assert(!resolver); + resolver = avahi_service_resolver_new(querier->getClient(), service.getNetworkInterfaceID(), AVAHI_PROTO_UNSPEC, service.getName().getUTF8Data(), service.getType().getUTF8Data(), service.getDomain().getUTF8Data(), AVAHI_PROTO_UNSPEC, (AvahiLookupFlags) 0, handleServiceResolvedStatic, this); + if (!resolver) { + std::cout << "Error starting resolver" << std::endl; + MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional()), shared_from_this()); + } + avahi_threaded_poll_unlock(querier->getThreadedPoll()); + } + + void stop() { + avahi_threaded_poll_lock(querier->getThreadedPoll()); + avahi_service_resolver_free(resolver); + resolver = NULL; + avahi_threaded_poll_unlock(querier->getThreadedPoll()); + } + + private: + static void handleServiceResolvedStatic(AvahiServiceResolver* resolver, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* context) { + static_cast(context)->handleServiceResolved(resolver, interfaceIndex, protocol, event, name, type, domain, host_name, address, port, txt, flags); + } + + void handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) { + std::cout << "Resolve finished" << std::endl; + switch(event) { + case AVAHI_RESOLVER_FAILURE: + std::cout << "Resolve error " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))) << std::endl; + MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional()), shared_from_this()); + break; + case AVAHI_RESOLVER_FOUND: { + char a[AVAHI_ADDRESS_STR_MAX]; + avahi_address_snprint(a, sizeof(a), address); + + ByteArray txtRecord; + txtRecord.resize(1024); + avahi_string_list_serialize(txt, txtRecord.getData(), txtRecord.getSize()); + + // FIXME: Probably not accurate + String fullname = String(name) + "." + String(type) + "." + String(domain) + "."; + std::cout << "Result: " << fullname << "->" << String(a) << ":" << port << std::endl; + MainEventLoop::postEvent( + boost::bind( + boost::ref(onServiceResolved), + Result(fullname, String(a), port, txtRecord)), + shared_from_this()); + break; + } + } + } + + private: + DNSSDServiceID service; + AvahiServiceResolver* resolver; + }; +} diff --git a/Swiften/LinkLocal/SConscript b/Swiften/LinkLocal/SConscript index f36d467..b929db1 100644 --- a/Swiften/LinkLocal/SConscript +++ b/Swiften/LinkLocal/SConscript @@ -28,7 +28,10 @@ if myenv.get("HAVE_BONJOUR", 0) : "DNSSD/Bonjour/BonjourQuery.cpp", ] elif myenv.get("HAVE_AVAHI", 0) : - sources += ["DNSSD/Avahi/AvahiQuerier.cpp"] + sources += [ + "DNSSD/Avahi/AvahiQuerier.cpp", + "DNSSD/Avahi/AvahiQuery.cpp" + ] objects = myenv.StaticObject(sources) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) -- cgit v0.10.2-6-g49f6