diff options
| author | Remko Tronçon <git@el-tramo.be> | 2010-02-08 16:48:54 (GMT) | 
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2010-02-08 16:48:54 (GMT) | 
| commit | 936f7ff9b80aca95040301a4b3cfcd2a248e3334 (patch) | |
| tree | 3abf0d398fd4211b99b6593c92006fef3dcb2951 | |
| parent | c7e907730e98176be0fdd4e484f2a903b4228348 (diff) | |
| download | swift-936f7ff9b80aca95040301a4b3cfcd2a248e3334.zip swift-936f7ff9b80aca95040301a4b3cfcd2a248e3334.tar.bz2 | |
Added beginnings of Avahi support.
| -rw-r--r-- | Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h | 64 | ||||
| -rw-r--r-- | Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp | 19 | ||||
| -rw-r--r-- | Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h | 8 | ||||
| -rw-r--r-- | Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp | 13 | ||||
| -rw-r--r-- | Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h | 22 | ||||
| -rw-r--r-- | Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h | 123 | ||||
| -rw-r--r-- | Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h | 31 | ||||
| -rw-r--r-- | Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h | 73 | ||||
| -rw-r--r-- | Swiften/LinkLocal/SConscript | 5 | 
9 files changed, 348 insertions, 10 deletions
| 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 <boost/bind.hpp> + +#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<AvahiQuerier> 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<AvahiBrowseQuery*>(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 <iostream> -//#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<DNSSDBrowseQuery> AvahiQuerier::createBrowseQuery() { -	//return boost::shared_ptr<DNSSDBrowseQuery>(new AvahiBrowseQuery(shared_from_this())); +	return boost::shared_ptr<DNSSDBrowseQuery>(new AvahiBrowseQuery(shared_from_this()));  }  boost::shared_ptr<DNSSDRegisterQuery> AvahiQuerier::createRegisterQuery(const String& name, int port, const ByteArray& info) { -	//return boost::shared_ptr<DNSSDRegisterQuery>(new AvahiRegisterQuery(name, port, info, shared_from_this())); +	return boost::shared_ptr<DNSSDRegisterQuery>(new AvahiRegisterQuery(name, port, info, shared_from_this()));  }  boost::shared_ptr<DNSSDResolveServiceQuery> AvahiQuerier::createResolveServiceQuery(const DNSSDServiceID& service) { -	//return boost::shared_ptr<DNSSDResolveServiceQuery>(new AvahiResolveServiceQuery(service, shared_from_this())); +	return boost::shared_ptr<DNSSDResolveServiceQuery>(new AvahiResolveServiceQuery(service, shared_from_this()));  }  boost::shared_ptr<DNSSDResolveHostnameQuery> AvahiQuerier::createResolveHostnameQuery(const String& hostname, int interfaceIndex) { -	//return boost::shared_ptr<DNSSDResolveHostnameQuery>(new AvahiResolveHostnameQuery(hostname, interfaceIndex, shared_from_this())); +	return boost::shared_ptr<DNSSDResolveHostnameQuery>(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<AvahiQuerier> 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 <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> + +#include "Swiften/EventLoop/EventOwner.h" + +namespace Swift { +	class AvahiQuerier; + +	class AvahiQuery :  +			public EventOwner, +			public boost::enable_shared_from_this<AvahiQuery> { +		public: +			AvahiQuery(boost::shared_ptr<AvahiQuerier>); +			virtual ~AvahiQuery(); +			 +		protected: +			boost::shared_ptr<AvahiQuerier> 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 <avahi-client/publish.h> + +#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<AvahiQuerier> 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<DNSSDServiceID>()), 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<DNSSDServiceID>()), 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<AvahiRegisterQuery*>(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>(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<DNSSDServiceID>()), shared_from_this()); +			} +		} + +/* +			static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { +				static_cast<AvahiRegisterQuery*>(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<DNSSDServiceID>()), 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 <netinet/in.h> + +namespace Swift { +	class AvahiQuerier; + +	class AvahiResolveHostnameQuery : public DNSSDResolveHostnameQuery, public AvahiQuery { +		public:  +			AvahiResolveHostnameQuery(const String& hostname, int, boost::shared_ptr<AvahiQuerier> querier) : AvahiQuery(querier), hostname(hostname) { +				std::cout << "Resolving hostname " << hostname << std::endl; +			} + +			void run() { +					MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>(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<AvahiQuerier> 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<Result>()), 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<AvahiResolveServiceQuery*>(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<Result>()), 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]) | 
 Swift
 Swift