diff options
-rw-r--r-- | Nim/main.cpp | 5 | ||||
-rw-r--r-- | Swiften/LinkLocal/AppleDNSSDService.cpp | 73 | ||||
-rw-r--r-- | Swiften/LinkLocal/AppleDNSSDService.h | 6 | ||||
-rw-r--r-- | Swiften/LinkLocal/DNSSDService.h | 33 | ||||
-rw-r--r-- | Swiften/LinkLocal/LinkLocalRoster.cpp | 24 | ||||
-rw-r--r-- | Swiften/LinkLocal/LinkLocalRoster.h | 4 |
6 files changed, 132 insertions, 13 deletions
diff --git a/Nim/main.cpp b/Nim/main.cpp index 7c7105e..390bc6c 100644 --- a/Nim/main.cpp +++ b/Nim/main.cpp @@ -67,11 +67,11 @@ class Server { dnsSDService_->onServiceRegistered.connect(boost::bind(&Server::handleServiceRegistered, this, _1)); LinkLocalServiceInfo info; info.setFirstName("Remko"); - info.setLastName("Tron\xc3\xe7on"); + info.setLastName("Tron\xc3\xa7on"); info.setEMail("email@example.com"); info.setJID(JID("jid@example.com")); info.setMessage("I'm not Here"); - info.setNick("remko"); + info.setNick("Remko"); info.setStatus(LinkLocalServiceInfo::Away); info.setPort(linkLocalConnectionPort_); dnsSDService_->registerService(session->getJID().toBare().toString(), linkLocalConnectionPort_, info); @@ -85,6 +85,7 @@ class Server { void handleSessionFinished(boost::shared_ptr<ServerFromClientSession> session) { serverFromClientSessions_.erase(std::remove(serverFromClientSessions_.begin(), serverFromClientSessions_.end(), session), serverFromClientSessions_.end()); if (serverFromClientSessions_.empty()) { + std::cout << "Service unregistered" << std::endl; dnsSDServiceRegistered_ = false; dnsSDService_->unregisterService(); } diff --git a/Swiften/LinkLocal/AppleDNSSDService.cpp b/Swiften/LinkLocal/AppleDNSSDService.cpp index 4dd74eb..abf8548 100644 --- a/Swiften/LinkLocal/AppleDNSSDService.cpp +++ b/Swiften/LinkLocal/AppleDNSSDService.cpp @@ -12,17 +12,12 @@ namespace Swift { #if 0 namespace { - void handleServiceResolved( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context ) { - std::cerr << "Service resolved " << fullname << " " << hosttarget << " " << port << " " << txtLen << " " << /*std::string((const char*) txtRecord, txtLen) <<*/ std::endl; - } - 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 = DNSServiceResolve(&resolveSDRef, 0, 6, "Remko@Micro", "_presence._tcp.", "local.", handleServiceResolved , 0); result = DNSServiceGetAddrInfo(&addressSDRef, 0, 6, kDNSServiceProtocol_IPv4, "Micro.local.", handleAddressInfoReceived, 0); */ #endif @@ -51,19 +46,47 @@ void AppleDNSSDService::registerService(const String& name, int port, const Link assert(!registerSDRef); ByteArray txtRecord = info.toTXTRecord(); DNSServiceErrorType result = DNSServiceRegister(®isterSDRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, txtRecord.getSize(), txtRecord.getData(), &AppleDNSSDService::handleServiceRegisteredGlobal, this); - interruptSelect(); if (result != kDNSServiceErr_NoError) { onError(); } + + interruptSelect(); } void AppleDNSSDService::unregisterService() { boost::lock_guard<boost::mutex> lock(sdRefsMutex); assert(registerSDRef); - interruptSelect(); DNSServiceRefDeallocate(registerSDRef); registerSDRef = NULL; + + interruptSelect(); +} + +void AppleDNSSDService::startResolvingService(const Service& service) { + boost::lock_guard<boost::mutex> lock(sdRefsMutex); + + 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(); + } + + bool isNew = resolveSDRefs.insert(std::make_pair(service, resolveSDRef)).second; + assert(isNew); + + interruptSelect(); +} + +void AppleDNSSDService::stopResolvingService(const Service& service) { + boost::lock_guard<boost::mutex> lock(sdRefsMutex); + + ServiceSDRefMap::iterator i = resolveSDRefs.find(service); + assert(i != resolveSDRefs.end()); + DNSServiceRefDeallocate(i->second); + resolveSDRefs.erase(i); + + interruptSelect(); } void AppleDNSSDService::stop() { @@ -89,14 +112,15 @@ void AppleDNSSDService::doStart() { while (!stopRequested) { fd_set fdSet; FD_ZERO(&fdSet); - int maxSocket = 0; + int maxSocket = interruptSelectReadSocket; + FD_SET(interruptSelectReadSocket, &fdSet); { boost::lock_guard<boost::mutex> lock(sdRefsMutex); // Browsing int browseSocket = DNSServiceRefSockFD(browseSDRef); - maxSocket = browseSocket; + maxSocket = std::max(maxSocket, browseSocket); FD_SET(browseSocket, &fdSet); // Registration @@ -105,6 +129,13 @@ void AppleDNSSDService::doStart() { maxSocket = std::max(maxSocket, registerSocket); FD_SET(registerSocket, &fdSet); } + + // 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); + } } int selectResult = select(maxSocket+1, &fdSet, NULL, NULL, 0); @@ -125,6 +156,11 @@ void AppleDNSSDService::doStart() { if (registerSDRef && FD_ISSET(DNSServiceRefSockFD(registerSDRef), &fdSet)) { DNSServiceProcessResult(registerSDRef); } + for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) { + if (FD_ISSET(DNSServiceRefSockFD(i->second), &fdSet)) { + DNSServiceProcessResult(i->second); + } + } } } @@ -174,4 +210,23 @@ void AppleDNSSDService::handleServiceRegistered(DNSServiceRef, DNSServiceFlags, } } +void AppleDNSSDService::handleServiceResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context ) { + static_cast<AppleDNSSDService*>(context)->handleServiceResolved(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtLen, txtRecord); +} + +void AppleDNSSDService::handleServiceResolved(DNSServiceRef sdRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char *, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord) { + if (errorCode != kDNSServiceErr_NoError) { + std::cerr << "Resolve error " << hosttarget << std::endl; + return; + } + for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) { + if (i->second == sdRef) { + MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), i->first, ResolveResult(hosttarget, port, LinkLocalServiceInfo::createFromTXTRecord(ByteArray(reinterpret_cast<const char*>(txtRecord), txtLen)))), shared_from_this()); + return; + } + } + assert(false); +} + + } diff --git a/Swiften/LinkLocal/AppleDNSSDService.h b/Swiften/LinkLocal/AppleDNSSDService.h index 6299a96..bf6b4aa 100644 --- a/Swiften/LinkLocal/AppleDNSSDService.h +++ b/Swiften/LinkLocal/AppleDNSSDService.h @@ -15,6 +15,8 @@ namespace Swift { ~AppleDNSSDService(); virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&); + virtual void startResolvingService(const Service&); + virtual void stopResolvingService(const Service&); virtual void unregisterService(); virtual void start(); virtual void stop(); @@ -27,6 +29,8 @@ namespace Swift { void handleServiceDiscovered(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, const char *); static void handleServiceRegisteredGlobal(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType, const char *, const char *, const char *, void *); 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 *); private: boost::thread* thread; @@ -36,5 +40,7 @@ namespace Swift { boost::mutex sdRefsMutex; DNSServiceRef browseSDRef; DNSServiceRef registerSDRef; + typedef std::map<Service, DNSServiceRef> ServiceSDRefMap; + ServiceSDRefMap resolveSDRefs; }; } diff --git a/Swiften/LinkLocal/DNSSDService.h b/Swiften/LinkLocal/DNSSDService.h index 214cad4..6a9425f 100644 --- a/Swiften/LinkLocal/DNSSDService.h +++ b/Swiften/LinkLocal/DNSSDService.h @@ -4,6 +4,7 @@ #include <map> #include "Swiften/Base/String.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" namespace Swift { class LinkLocalServiceInfo; @@ -12,21 +13,53 @@ namespace Swift { public: struct Service { Service(const String& name, const String& type, const String& domain, int networkInterface) : name(name), type(type), domain(domain), networkInterface(networkInterface) {} + bool operator==(const Service& o) const { + return name == o.name && type == o.type && domain == o.domain && (networkInterface != 0 && o.networkInterface != 0 ? networkInterface == o.networkInterface : true); + } + bool operator<(const Service& o) const { + if (o.name == name) { + if (o.type == type) { + if (o.domain == domain) { + return networkInterface < o.networkInterface; + } + else { + return domain < o.domain; + } + } + else { + return type < o.type; + } + } + else { + return o.name < name; + } + } + String name; String type; String domain; int networkInterface; }; + struct ResolveResult { + ResolveResult(const String& host, int port, const LinkLocalServiceInfo& info) : host(host), port(port), info(info) {} + String host; + int port; + LinkLocalServiceInfo info; + }; + virtual ~DNSSDService(); virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&) = 0; + virtual void startResolvingService(const Service&) = 0; + virtual void stopResolvingService(const Service&) = 0; virtual void unregisterService() = 0; virtual void start() = 0; boost::signal<void (const Service&)> onServiceAdded; boost::signal<void (const Service&)> onServiceRemoved; boost::signal<void (const Service&)> onServiceRegistered; + boost::signal<void (const Service&, const ResolveResult&)> onServiceResolved; boost::signal<void ()> onError; }; } diff --git a/Swiften/LinkLocal/LinkLocalRoster.cpp b/Swiften/LinkLocal/LinkLocalRoster.cpp index 9f7e4ad..fde52a9 100644 --- a/Swiften/LinkLocal/LinkLocalRoster.cpp +++ b/Swiften/LinkLocal/LinkLocalRoster.cpp @@ -6,16 +6,36 @@ namespace Swift { LinkLocalRoster::LinkLocalRoster(boost::shared_ptr<DNSSDService> service) : dnsSDService(service) { - service->onServiceAdded.connect(boost::bind(&LinkLocalRoster::handleServiceAdded, this, _1)); - service->onServiceRemoved.connect(boost::bind(&LinkLocalRoster::handleServiceRemoved, 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)); } void LinkLocalRoster::handleServiceAdded(const DNSSDService::Service& service) { + if (selfService && *selfService == service) { + return; + } std::cout << "Service added " << service.name << " " << service.type << " " << service.domain << std::endl; + dnsSDService->startResolvingService(service); } void LinkLocalRoster::handleServiceRemoved(const DNSSDService::Service& service) { std::cout << "Service removed " << service.name << " " << service.type << " " << service.domain << std::endl; + dnsSDService->stopResolvingService(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; +} + +void LinkLocalRoster::handleServiceRegistered(const DNSSDService::Service& service) { + selfService = service; +} + +void LinkLocalRoster::handleDNSSDError() { + std::cout << "DNSSD Error" << std::endl; } } diff --git a/Swiften/LinkLocal/LinkLocalRoster.h b/Swiften/LinkLocal/LinkLocalRoster.h index 5b66b84..3cc8d55 100644 --- a/Swiften/LinkLocal/LinkLocalRoster.h +++ b/Swiften/LinkLocal/LinkLocalRoster.h @@ -12,8 +12,12 @@ namespace Swift { private: 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); private: boost::shared_ptr<DNSSDService> dnsSDService; + boost::optional<DNSSDService::Service> selfService; }; } |