diff --git a/src/libs/zeroconf/avahiLib.cpp b/src/libs/zeroconf/avahiLib.cpp index bec4e3e595b..1a850950bee 100644 --- a/src/libs/zeroconf/avahiLib.cpp +++ b/src/libs/zeroconf/avahiLib.cpp @@ -204,7 +204,7 @@ public: return kDNSServiceErr_Unknown; AvahiServiceResolver *resolver = m_serviceResolverNew(connection->client, interfaceIndex, AVAHI_PROTO_INET, name, regtype, domain, AVAHI_PROTO_INET, AvahiLookupFlags(0), &cAvahiResolveReply, gatherer); - // *sdRef = reinterpret_cast(resolver); // as we delete in the callback we don't need it... + //*sdRef = reinterpret_cast(resolver); // add for restart? if (!resolver) return kDNSServiceErr_Unknown; // avahi_strerror(avahi_client_errno(connection->client)); return kDNSServiceErr_NoError; @@ -325,9 +325,11 @@ ZConfLib::Ptr ZConfLib::createAvahiLib(const QString &libName, ZConfLib::Ptr fal return ZConfLib::Ptr(new AvahiZConfLib(libName, fallback)); } -extern "C" void cAvahiResolveReply( AvahiServiceResolver * r, AvahiIfIndex interface, AvahiProtocol /*protocol*/, - AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *hostName, - const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags /*flags*/, void* context) +extern "C" void cAvahiResolveReply( + AvahiServiceResolver * r, AvahiIfIndex interface, AvahiProtocol /*protocol*/, + AvahiResolverEvent event, const char * /*name*/, const char * /*type*/, + const char * /*domain*/, const char *hostName, const AvahiAddress *address, uint16_t port, + AvahiStringList *txt, AvahiLookupResultFlags /*flags*/, void* context) { enum { defaultTtl = 0 }; ServiceGatherer *sg = reinterpret_cast(context); @@ -335,24 +337,18 @@ extern "C" void cAvahiResolveReply( AvahiServiceResolver * r, AvahiIfIndex inter qDebug() << "context was null in cAvahiResolveReply"; return; } - const unsigned char * txtPtr = 0; - unsigned short txtLen = 0; AvahiStringList *txtAtt=0; + const unsigned char emptyTxt[1]=""; switch (event) { case AVAHI_RESOLVER_FAILURE: sg->serviceResolveReply(0, kDNSServiceErr_Timeout, interface, 0, QString(), 0, 0); break; case AVAHI_RESOLVER_FOUND: - if (txt) { - txtPtr = txt->text; - txtLen = static_cast(txt->size); - qDebug() << "Error: txt was null in cAvahiResolveReply for service:" << name << " type:" << type << " domain:" << domain; - } - txtAtt=(txt?txt->next:0); sg->serviceResolveReply(kDNSServiceFlagsAdd|((txtAtt || address)?kDNSServiceFlagsMoreComing:0), interface, kDNSServiceErr_NoError, - hostName, QString::number(port), txtLen, txtPtr); + hostName, QString::number(port), 0, emptyTxt); + txtAtt=txt; while (txtAtt) { - sg->txtRecordReply(kDNSServiceFlagsAdd|((txtAtt->next || address)?kDNSServiceFlagsMoreComing:0),kDNSServiceErr_NoError, + sg->txtFieldReply(kDNSServiceFlagsAdd|((txtAtt->next || address)?kDNSServiceFlagsMoreComing:0),kDNSServiceErr_NoError, static_cast(txtAtt->size),txtAtt->text,-1); txtAtt = txtAtt->next; } @@ -366,11 +362,13 @@ extern "C" void cAvahiResolveReply( AvahiServiceResolver * r, AvahiIfIndex inter ipv4.sin_family = AF_INET; memcpy(&(ipv4.sin_addr),&(address->data.ipv4.address),sizeof(ipv4.sin_addr)); sg->addrReply(kDNSServiceFlagsAdd, kDNSServiceErr_NoError, hostName, reinterpret_cast(&ipv4), defaultTtl); + break; case (AVAHI_PROTO_INET6): memset(&ipv6,0,sizeof(ipv6)); ipv6.sin6_family = AF_INET6; memcpy(&(ipv6.sin6_addr), &(address->data.ipv6.address), sizeof(ipv6.sin6_addr)); sg->addrReply(kDNSServiceFlagsAdd, kDNSServiceErr_NoError, hostName, reinterpret_cast(&ipv6), defaultTtl); + break; default: if (DEBUG_ZEROCONF) qDebug() << "Warning: ignoring address with protocol " << address->proto << " for service " << sg->fullName(); diff --git a/src/libs/zeroconf/servicebrowser.cpp b/src/libs/zeroconf/servicebrowser.cpp index 35b785b835f..6889259fd18 100644 --- a/src/libs/zeroconf/servicebrowser.cpp +++ b/src/libs/zeroconf/servicebrowser.cpp @@ -204,13 +204,14 @@ QDebug operator<<(QDebug dbg, const Service &service) << " fullName:" << service.fullName() << ", port:" << service.port() << ", txtRecord:{"; bool first=true; - const ServiceTxtRecord &txtRecord = service.txtRecord(); - foreach (const QString &k, txtRecord){ + QHashIterator i(service.txtRecord()); + while (i.hasNext()){ + i.next(); if (first) first = false; else dbg << ", "; - dbg << k << ":" << txtRecord.value(k); + dbg << i.key() << ":" << i.value(); } dbg << "}, "; if (const QHostInfo *host = service.host()){ @@ -734,7 +735,6 @@ void ServiceGatherer::serviceResolveReply(DNSServiceFlags fl } if (publishedService) publishedService->invalidate(); // delay this to enactServiceChange? serviceBrowser->updateFlowStatusForFlags(flags); - uint16_t nKeys = txtRecordGetCount(txtLen, rawTxtRecord); for (uint16_t i = 0; i < nKeys; ++i){ enum { maxTxtLen= 256 }; @@ -749,11 +749,7 @@ void ServiceGatherer::serviceResolveReply(DNSServiceFlags fl break; } keyBuf[maxTxtLen-1] = 0; // just to be sure - if (flags & kDNSServiceFlagsAdd) { - txtRecord[QString::fromUtf8(keyBuf)] = QString::fromUtf8(valueCStr, valLen); - } else { - txtRecord.remove(QString::fromUtf8(keyBuf)); // check value??? - } + currentService->m_txtRecord.insert(QString::fromUtf8(keyBuf),QString::fromUtf8(valueCStr, valLen)); } currentService->m_interfaceNr = interfaceIndex; currentService->m_port = port; @@ -809,23 +805,65 @@ void ServiceGatherer::txtRecordReply(DNSServiceFlags flags, qDebug() << "ServiceBrowser " << serviceBrowser->serviceType << " error " << txtErr << " decoding txt record of service " << currentService->fullName(); if ((flags & kDNSServiceFlagsAdd) == 0) - txtRecord.clear(); + currentService->m_txtRecord.clear(); break; } keyBuf[255] = 0; // just to be sure if (flags & kDNSServiceFlagsAdd) { - txtRecord[QString::fromUtf8(keyBuf)] = QString::fromUtf8(valueCStr, valLen); + currentService->m_txtRecord.insert(QString::fromUtf8(keyBuf), QString::fromUtf8(valueCStr, valLen)); } else { - txtRecord.remove(QString::fromUtf8(keyBuf)); // check value??? + currentService->m_txtRecord.remove(QString::fromUtf8(keyBuf)); // check value??? } } if ((flags & kDNSServiceFlagsAdd) != 0) { status |= TxtConnectionSuccess; } - if (txtRecord.count() != 0 && currentServiceCanBePublished()) + if (currentService->m_txtRecord.count() != 0 && currentServiceCanBePublished()) serviceBrowser->pendingGathererAdd(gatherer()); } +void ServiceGatherer::txtFieldReply(DNSServiceFlags flags, + DNSServiceErrorType errorCode, + uint16_t txtLen, + const void *rawTxtRecord, + uint32_t /*ttl*/){ + if (errorCode != kDNSServiceErr_NoError){ + if (errorCode == kDNSServiceErr_Timeout){ + if ((status & TxtConnectionSuccess) == 0){ + qDebug() << "ServiceBrowser " << serviceBrowser->serviceType << " failed txt gathering for service " + << currentService->fullName() << " as it did timeout"; + status |= TxtConnectionFailed; + } + } else { + qDebug() << "ServiceBrowser " << serviceBrowser->serviceType << " failed txt gathering for service " + << currentService->fullName() << " with error " << errorCode; + status |= TxtConnectionFailed; + } + if (status & TxtConnectionActive) { + status &= ~TxtConnectionActive; + lib()->refDeallocate(txtConnection); + serviceBrowser->updateFlowStatusForCancel(); + } + return; + } + serviceBrowser->updateFlowStatusForFlags(flags); + uint16_t keyLen=0; + const char *txt=reinterpret_cast(rawTxtRecord); + while (keyLen < txtLen) { + if (txt[keyLen]=='=') + break; + ++keyLen; + } + if (flags & kDNSServiceFlagsAdd) { + currentService->m_txtRecord.insert(QString::fromUtf8(txt, keyLen), + QString::fromUtf8(txt + keyLen + 1, + ((txtLen>keyLen)?txtLen - keyLen - 1:0))); + } else { + currentService->m_txtRecord.remove(QString::fromUtf8(txt, keyLen)); // check value??? + } + +} + void ServiceGatherer::addrReply(DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *hostname, diff --git a/src/libs/zeroconf/servicebrowser_p.h b/src/libs/zeroconf/servicebrowser_p.h index b6cc8a21b9b..c2e027dad7a 100644 --- a/src/libs/zeroconf/servicebrowser_p.h +++ b/src/libs/zeroconf/servicebrowser_p.h @@ -112,7 +112,6 @@ protected: /// class that gathers all needed info on a service, all its methods (creation included) are supposed to be called by the listener/reaction thread class ServiceGatherer { public: - QHash txtRecord; QString hostName; ServiceBrowserPrivate *serviceBrowser; QHostInfo *host; @@ -158,6 +157,8 @@ public: void txtRecordReply(DNSServiceFlags flags, DNSServiceErrorType errorCode, uint16_t txtLen, const void *rawTxtRecord, uint32_t ttl); + void txtFieldReply(DNSServiceFlags flags, DNSServiceErrorType errorCode, + uint16_t txtLen, const void *rawTxtRecord, uint32_t ttl); void addrReply(DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl);