From 7388443bda19877980e368a0654b55097db0bda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Sat, 18 Jul 2009 12:17:45 +0200 Subject: Add DNS-SD hostname resolving. diff --git a/Swiften/LinkLocal/AppleDNSSDService.cpp b/Swiften/LinkLocal/AppleDNSSDService.cpp index abf8548..18cdcb0 100644 --- a/Swiften/LinkLocal/AppleDNSSDService.cpp +++ b/Swiften/LinkLocal/AppleDNSSDService.cpp @@ -4,30 +4,21 @@ #include #include #include +#include +#include #include "Swiften/EventLoop/MainEventLoop.h" #include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include "Swiften/Network/HostAddress.h" namespace Swift { -#if 0 -namespace { - void handleAddressInfoReceived ( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context ) { - //std::cerr << "Address received " << HostAddress((const unsigned char*) address->sa_data, 4).toString() << std::endl; - } -} - -/* - result = DNSServiceGetAddrInfo(&addressSDRef, 0, 6, kDNSServiceProtocol_IPv4, "Micro.local.", handleAddressInfoReceived, 0); - */ -#endif - - -AppleDNSSDService::AppleDNSSDService() : thread(0), stopRequested(false), browseSDRef(0), registerSDRef(0) { +AppleDNSSDService::AppleDNSSDService() : thread(0), stopRequested(false), haveError(false), browseSDRef(0), registerSDRef(0) { int fds[2]; int result = pipe(fds); assert(result == 0); interruptSelectReadSocket = fds[0]; + fcntl(interruptSelectReadSocket, F_SETFL, fcntl(interruptSelectReadSocket, F_GETFL)|O_NONBLOCK); interruptSelectWriteSocket = fds[1]; } @@ -36,10 +27,20 @@ AppleDNSSDService::~AppleDNSSDService() { } void AppleDNSSDService::start() { - assert(!thread); + stop(); thread = new boost::thread(boost::bind(&AppleDNSSDService::doStart, shared_from_this())); } +void AppleDNSSDService::stop() { + if (thread) { + stopRequested = true; + interruptSelect(); + thread->join(); + delete thread; + stopRequested = false; + } +} + void AppleDNSSDService::registerService(const String& name, int port, const LinkLocalServiceInfo& info) { boost::lock_guard lock(sdRefsMutex); @@ -47,7 +48,8 @@ void AppleDNSSDService::registerService(const String& name, int port, const Link ByteArray txtRecord = info.toTXTRecord(); DNSServiceErrorType result = DNSServiceRegister(®isterSDRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, txtRecord.getSize(), txtRecord.getData(), &AppleDNSSDService::handleServiceRegisteredGlobal, this); if (result != kDNSServiceErr_NoError) { - onError(); + std::cerr << "Error creating service registration" << std::endl; + haveError = true; } interruptSelect(); @@ -57,10 +59,8 @@ void AppleDNSSDService::unregisterService() { boost::lock_guard lock(sdRefsMutex); assert(registerSDRef); - DNSServiceRefDeallocate(registerSDRef); + DNSServiceRefDeallocate(registerSDRef); // Interrupts select() registerSDRef = NULL; - - interruptSelect(); } void AppleDNSSDService::startResolvingService(const Service& service) { @@ -69,11 +69,13 @@ void AppleDNSSDService::startResolvingService(const Service& service) { DNSServiceRef resolveSDRef; DNSServiceErrorType result = DNSServiceResolve(&resolveSDRef, 0, service.networkInterface, service.name.getUTF8Data(), service.type.getUTF8Data(), service.domain.getUTF8Data(), &AppleDNSSDService::handleServiceResolvedGlobal, this); if (result != kDNSServiceErr_NoError) { - onError(); + std::cerr << "Error creating service resolve query" << std::endl; + haveError = true; + } + else { + bool isNew = resolveSDRefs.insert(std::make_pair(service, resolveSDRef)).second; + assert(isNew); } - - bool isNew = resolveSDRefs.insert(std::make_pair(service, resolveSDRef)).second; - assert(isNew); interruptSelect(); } @@ -83,33 +85,40 @@ void AppleDNSSDService::stopResolvingService(const Service& service) { ServiceSDRefMap::iterator i = resolveSDRefs.find(service); assert(i != resolveSDRefs.end()); - DNSServiceRefDeallocate(i->second); + DNSServiceRefDeallocate(i->second); // Interrupts select() resolveSDRefs.erase(i); - - interruptSelect(); } -void AppleDNSSDService::stop() { - if (thread) { - stopRequested = true; - interruptSelect(); - thread->join(); - delete thread; - stopRequested = false; +void AppleDNSSDService::resolveHostname(const String& hostname, int interfaceIndex) { + boost::lock_guard lock(sdRefsMutex); + + DNSServiceRef hostnameResolveSDRef; + DNSServiceErrorType result = DNSServiceGetAddrInfo(&hostnameResolveSDRef, 0, interfaceIndex, kDNSServiceProtocol_IPv4, hostname.getUTF8Data(), &AppleDNSSDService::handleHostnameResolvedGlobal, this); + if (result != kDNSServiceErr_NoError) { + std::cerr << "Error creating hostname resolve query" << std::endl; + haveError = true; + } + else { + hostnameResolveSDRefs.push_back(hostnameResolveSDRef); } + + interruptSelect(); } void AppleDNSSDService::doStart() { + haveError = false; + onStarted(); + // Listen for new services assert(!browseSDRef); DNSServiceErrorType result = DNSServiceBrowse(&browseSDRef, 0, 0, "_presence._tcp", 0, &AppleDNSSDService::handleServiceDiscoveredGlobal , this); if (result != kDNSServiceErr_NoError) { - MainEventLoop::postEvent(boost::ref(onError), shared_from_this()); - return; + std::cerr << "Error creating browse query" << std::endl; + haveError = true; } // Run the main loop - while (!stopRequested) { + while (!haveError && !stopRequested) { fd_set fdSet; FD_ZERO(&fdSet); int maxSocket = interruptSelectReadSocket; @@ -130,24 +139,32 @@ void AppleDNSSDService::doStart() { FD_SET(registerSocket, &fdSet); } - // Resolving + // Service resolving for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) { int resolveSocket = DNSServiceRefSockFD(i->second); maxSocket = std::max(maxSocket, resolveSocket); FD_SET(resolveSocket, &fdSet); } + + // Hostname resolving + for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) { + int hostnameResolveSocket = DNSServiceRefSockFD(*i); + maxSocket = std::max(maxSocket, hostnameResolveSocket); + FD_SET(hostnameResolveSocket, &fdSet); + } } int selectResult = select(maxSocket+1, &fdSet, NULL, NULL, 0); + // Flush the interruptSelectReadSocket + if (FD_ISSET(interruptSelectReadSocket, &fdSet)) { + char dummy; + while (read(interruptSelectReadSocket, &dummy, 1) > 0) {} + } + { boost::lock_guard lock(sdRefsMutex); - - if (selectResult == -1) { - MainEventLoop::postEvent(boost::ref(onError), shared_from_this()); - return; - } - if (selectResult == 0) { + if (selectResult <= 0) { continue; } if (FD_ISSET(DNSServiceRefSockFD(browseSDRef), &fdSet)) { @@ -161,9 +178,27 @@ void AppleDNSSDService::doStart() { DNSServiceProcessResult(i->second); } } + for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) { + if (FD_ISSET(DNSServiceRefSockFD(*i), &fdSet)) { + DNSServiceProcessResult(*i); + hostnameResolveSDRefs.erase(std::remove(hostnameResolveSDRefs.begin(), hostnameResolveSDRefs.end(), *i), hostnameResolveSDRefs.end()); + DNSServiceRefDeallocate(*i); + break; // Stop the loop, because we removed an element + } + } } } + for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) { + DNSServiceRefDeallocate(i->second); + } + resolveSDRefs.clear(); + + for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) { + DNSServiceRefDeallocate(*i); + } + hostnameResolveSDRefs.clear(); + if (registerSDRef) { DNSServiceRefDeallocate(registerSDRef); registerSDRef = NULL; @@ -171,6 +206,8 @@ void AppleDNSSDService::doStart() { DNSServiceRefDeallocate(browseSDRef); browseSDRef = NULL; + + MainEventLoop::postEvent(boost::bind(boost::ref(onStopped), haveError), shared_from_this()); } void AppleDNSSDService::interruptSelect() { @@ -184,7 +221,7 @@ void AppleDNSSDService::handleServiceDiscoveredGlobal(DNSServiceRef sdRef, DNSSe void AppleDNSSDService::handleServiceDiscovered(DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain) { if (errorCode != kDNSServiceErr_NoError) { - MainEventLoop::postEvent(boost::ref(onError), shared_from_this()); + return; } else { Service service(serviceName, regtype, replyDomain, interfaceIndex); @@ -203,7 +240,8 @@ void AppleDNSSDService::handleServiceRegisteredGlobal(DNSServiceRef sdRef, DNSSe void AppleDNSSDService::handleServiceRegistered(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) { if (errorCode != kDNSServiceErr_NoError) { - MainEventLoop::postEvent(boost::ref(onError), shared_from_this()); + std::cerr << "Error registering service" << std::endl; + haveError = true; } else { MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRegistered), Service(name, regtype, domain, 0)), shared_from_this()); @@ -228,5 +266,21 @@ void AppleDNSSDService::handleServiceResolved(DNSServiceRef sdRef, DNSServiceFla assert(false); } +void AppleDNSSDService::handleHostnameResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context) { + static_cast(context)->handleHostnameResolved(sdRef, flags, interfaceIndex, errorCode, hostname, address, ttl); +} + +void AppleDNSSDService::handleHostnameResolved(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *rawAddress, uint32_t) { + if (errorCode) { + std::cerr << "Error resolving hostname" << std::endl; + MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), hostname, boost::optional()), shared_from_this()); + } + else { + assert(rawAddress->sa_family == AF_INET); + const sockaddr_in* sa = reinterpret_cast(rawAddress); + uint32_t address = ntohl(sa->sin_addr.s_addr); + MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), String(hostname), HostAddress(reinterpret_cast(&address), 4)), shared_from_this()); + } +} } diff --git a/Swiften/LinkLocal/AppleDNSSDService.h b/Swiften/LinkLocal/AppleDNSSDService.h index bf6b4aa..cdeafed 100644 --- a/Swiften/LinkLocal/AppleDNSSDService.h +++ b/Swiften/LinkLocal/AppleDNSSDService.h @@ -14,12 +14,16 @@ namespace Swift { AppleDNSSDService(); ~AppleDNSSDService(); + virtual void start(); + virtual void stop(); + virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&); + virtual void unregisterService(); + virtual void startResolvingService(const Service&); virtual void stopResolvingService(const Service&); - virtual void unregisterService(); - virtual void start(); - virtual void stop(); + + virtual void resolveHostname(const String& hostname, int interfaceIndex = 0); private: void doStart(); @@ -31,10 +35,13 @@ namespace Swift { void handleServiceRegistered(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType, const char *, const char *, const char *); static void handleServiceResolvedGlobal(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, uint16_t, uint16_t, const unsigned char *, void *); void handleServiceResolved(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, uint16_t, uint16_t, const unsigned char *); + static void handleHostnameResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context); + void handleHostnameResolved(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl); private: boost::thread* thread; bool stopRequested; + bool haveError; int interruptSelectReadSocket; int interruptSelectWriteSocket; boost::mutex sdRefsMutex; @@ -42,5 +49,7 @@ namespace Swift { DNSServiceRef registerSDRef; typedef std::map ServiceSDRefMap; ServiceSDRefMap resolveSDRefs; + typedef std::vector HostnameSDRefs; + HostnameSDRefs hostnameResolveSDRefs; }; } diff --git a/Swiften/LinkLocal/DNSSDService.h b/Swiften/LinkLocal/DNSSDService.h index 6a9425f..3dd8c7b 100644 --- a/Swiften/LinkLocal/DNSSDService.h +++ b/Swiften/LinkLocal/DNSSDService.h @@ -8,6 +8,7 @@ namespace Swift { class LinkLocalServiceInfo; + class HostAddress; class DNSSDService { public: @@ -50,16 +51,23 @@ namespace Swift { virtual ~DNSSDService(); + virtual void start() = 0; + virtual void stop() = 0; + virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&) = 0; + virtual void unregisterService() = 0; + virtual void startResolvingService(const Service&) = 0; virtual void stopResolvingService(const Service&) = 0; - virtual void unregisterService() = 0; - virtual void start() = 0; + + virtual void resolveHostname(const String& hostname, int interfaceIndex = 0) = 0; + boost::signal onStarted; + boost::signal onStopped; boost::signal onServiceAdded; boost::signal onServiceRemoved; boost::signal onServiceRegistered; boost::signal onServiceResolved; - boost::signal onError; + boost::signal&)> onHostnameResolved; }; } diff --git a/Swiften/LinkLocal/LinkLocalRoster.cpp b/Swiften/LinkLocal/LinkLocalRoster.cpp index fde52a9..feec7b7 100644 --- a/Swiften/LinkLocal/LinkLocalRoster.cpp +++ b/Swiften/LinkLocal/LinkLocalRoster.cpp @@ -2,15 +2,17 @@ #include #include "Swiften/LinkLocal/LinkLocalRoster.h" +#include "Swiften/Network/HostAddress.h" namespace Swift { LinkLocalRoster::LinkLocalRoster(boost::shared_ptr service) : dnsSDService(service) { + dnsSDService->onStopped.connect(boost::bind(&LinkLocalRoster::handleStopped, this, _1)); + dnsSDService->onServiceRegistered.connect(boost::bind(&LinkLocalRoster::handleServiceRegistered, this, _1)); dnsSDService->onServiceAdded.connect(boost::bind(&LinkLocalRoster::handleServiceAdded, this, _1)); dnsSDService->onServiceRemoved.connect(boost::bind(&LinkLocalRoster::handleServiceRemoved, this, _1)); dnsSDService->onServiceResolved.connect(boost::bind(&LinkLocalRoster::handleServiceResolved, this, _1, _2)); - dnsSDService->onError.connect(boost::bind(&LinkLocalRoster::handleDNSSDError, this)); - dnsSDService->onServiceRegistered.connect(boost::bind(&LinkLocalRoster::handleServiceRegistered, this, _1)); + dnsSDService->onHostnameResolved.connect(boost::bind(&LinkLocalRoster::handleHostnameResolved, this, _1, _2)); } void LinkLocalRoster::handleServiceAdded(const DNSSDService::Service& service) { @@ -28,14 +30,25 @@ void LinkLocalRoster::handleServiceRemoved(const DNSSDService::Service& service) void LinkLocalRoster::handleServiceResolved(const DNSSDService::Service& service, const DNSSDService::ResolveResult& result) { std::cout << "Service resolved: " << service.name << "->" << result.host << " " << result.port << " " << result.info.getLastName() << std::endl; + dnsSDService->resolveHostname(result.host); } +void LinkLocalRoster::handleHostnameResolved(const String& hostname, const boost::optional& address) { + if (address) { + std::cout << "Address resolved: " << hostname << " " << address->toString() << std::endl; + } + else { + std::cout << "Unable to resolve address for " << hostname << std::endl; + } +} + + void LinkLocalRoster::handleServiceRegistered(const DNSSDService::Service& service) { selfService = service; } -void LinkLocalRoster::handleDNSSDError() { - std::cout << "DNSSD Error" << std::endl; +void LinkLocalRoster::handleStopped(bool error) { + std::cout << "DNSSDService stopped: " << error << std::endl; } } diff --git a/Swiften/LinkLocal/LinkLocalRoster.h b/Swiften/LinkLocal/LinkLocalRoster.h index 3cc8d55..321bd96 100644 --- a/Swiften/LinkLocal/LinkLocalRoster.h +++ b/Swiften/LinkLocal/LinkLocalRoster.h @@ -1,20 +1,24 @@ #pragma once #include +#include #include "Swiften/LinkLocal/DNSSDService.h" namespace Swift { + class HostAddress; + class LinkLocalRoster { public: LinkLocalRoster(boost::shared_ptr service); private: + void handleStopped(bool); + void handleServiceRegistered(const DNSSDService::Service& service); void handleServiceAdded(const DNSSDService::Service&); void handleServiceRemoved(const DNSSDService::Service&); void handleServiceResolved(const DNSSDService::Service& service, const DNSSDService::ResolveResult& result); - void handleDNSSDError(); - void handleServiceRegistered(const DNSSDService::Service& service); + void handleHostnameResolved(const String& hostname, const boost::optional& address); private: boost::shared_ptr dnsSDService; -- cgit v0.10.2-6-g49f6