/**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef SERVICEBROWSER_P_H #define SERVICEBROWSER_P_H #include "dns_sd_types.h" #include "servicebrowser.h" #include #include #include #include #include #include #include #include #include namespace ZeroConf { class ServiceBrowser; namespace Internal { class ServiceGatherer; class ServiceBrowserPrivate; enum ZK_IP_Protocol { ZK_PROTO_IPv4_OR_IPv6, ZK_PROTO_IPv4, ZK_PROTO_IPv6 }; // represents a zero conf library exposing the dns-sd interface class ZConfLib { Q_DECLARE_TR_FUNCTIONS(ZeroConf::Internal::ZConfLib) public: typedef QSharedPointer Ptr; typedef void *ConnectionRef; typedef void *BrowserRef; enum RunLoopStatus { ProcessedIdle, ProcessedOk, ProcessedQuit, ProcessedError, ProcessedFailure }; enum { // Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this MAX_SEC_FOR_READ = 100000000 }; Ptr fallbackLib; ZConfLib(Ptr fallBack); virtual ~ZConfLib(); virtual QString name(); virtual bool tryStartDaemon(ErrorMessage::ErrorLogger *logger = 0); virtual void refDeallocate(DNSServiceRef sdRef) = 0; virtual void browserDeallocate(BrowserRef *sdRef) = 0; virtual DNSServiceErrorType resolve(ConnectionRef cRef, DNSServiceRef *sdRef, uint32_t interfaceIndex, ZK_IP_Protocol protocol, const char *name, const char *regtype, const char *domain, ServiceGatherer *gatherer) = 0; virtual DNSServiceErrorType queryRecord(ConnectionRef cRef, DNSServiceRef *sdRef, uint32_t interfaceIndex, const char *fullname, ServiceGatherer *gatherer) = 0; virtual DNSServiceErrorType getAddrInfo(ConnectionRef cRef, DNSServiceRef *sdRef, uint32_t interfaceIndex, DNSServiceProtocol protocol, const char *hostname, ServiceGatherer *gatherer) = 0; virtual DNSServiceErrorType reconfirmRecord(ConnectionRef cRef, uint32_t interfaceIndex, const char *name, const char *type, const char *domain, const char *fullname) = 0; virtual DNSServiceErrorType browse(ConnectionRef cRef, BrowserRef *sdRef, uint32_t interfaceIndex, const char *regtype, const char *domain, ServiceBrowserPrivate *browser) = 0; virtual DNSServiceErrorType getProperty(const char *property, void *result, uint32_t *size) = 0; virtual RunLoopStatus processOneEventBlock(ConnectionRef sdRef) = 0; virtual RunLoopStatus processOneEvent(MainConnection *mainConnection, ConnectionRef sdRef, qint64 maxMsBlock); virtual DNSServiceErrorType createConnection(MainConnection *mainConnection, ConnectionRef *sdRef) = 0; virtual void stopConnection(ConnectionRef cRef) = 0; virtual void destroyConnection(ConnectionRef *sdRef) = 0; virtual int refSockFD(ConnectionRef sdRef) = 0; bool isOk(); QString errorMsg(); void setError(bool failure, const QString &eMsg); int nFallbacks() const; int maxErrors() const; static Ptr createEmbeddedLib(const QString &daemonPath, const Ptr &fallback = Ptr(0)); static Ptr createDnsSdLib(const QString &libName, const Ptr &fallback = Ptr(0)); static Ptr createAvahiLib(const QString &libName, const QString &version, const Ptr &fallback = Ptr(0)); protected: bool m_isOk; QString m_errorMsg; int m_maxErrors; }; /// 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: QString hostName; ServiceBrowserPrivate *serviceBrowser; QHostInfo *host; Service::Ptr publishedService; Service *currentService; typedef QSharedPointer Ptr; enum Status { ResolveConnectionFailed = 1 << 0, ResolveConnectionActive = 1 << 1, ResolveConnectionSuccess = 1 << 2, ResolveConnectionV6Failed = 1 << 3, ResolveConnectionV6Active = 1 << 4, ResolveConnectionV6Success = 1 << 5, TxtConnectionFailed = 1 << 6, TxtConnectionActive = 1 << 7, TxtConnectionSuccess = 1 << 8, AddrConnectionFailed = 1 << 9, AddrConnectionActive = 1 << 10, AddrConnectionSuccess = 1 << 11 }; QString fullName(); bool enactServiceChange(); void retireService(); Ptr gatherer(); void stopResolve(ZK_IP_Protocol protocol = ZK_PROTO_IPv4_OR_IPv6); void stopTxt(); void stopHostResolution(); void restartResolve(ZK_IP_Protocol protocol = ZK_PROTO_IPv4_OR_IPv6); void restartTxt(); void restartHostResolution(); bool currentServiceCanBePublished(); ~ServiceGatherer(); static Ptr createGatherer(const QString &newService, const QString &newType, const QString &newDomain, const QString &fullName, uint32_t interfaceIndex, ZK_IP_Protocol protocol, ServiceBrowserPrivate *serviceBrowser); void serviceResolveReply(DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hosttarget, const QString &port, uint16_t txtLen, const unsigned char *rawTxtRecord); 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); void maybeRemove(); void stop(ZK_IP_Protocol protocol = ZK_PROTO_IPv4_OR_IPv6); void reload(qint32 interfaceIndex = 0, ZK_IP_Protocol protocol = ZK_PROTO_IPv4_OR_IPv6); void remove(); void reconfirm(); ZConfLib::Ptr lib(); private: ServiceGatherer(const QString &newService, const QString &newType, const QString &newDomain, const QString &fullName, uint32_t interfaceIndex, ZK_IP_Protocol protocol, ServiceBrowserPrivate *serviceBrowser); DNSServiceRef resolveConnection; DNSServiceRef resolveConnectionV6; DNSServiceRef txtConnection; DNSServiceRef addrConnection; uint32_t interfaceIndex; quint32 status; QWeakPointer self; }; //Q_DECLARE_METATYPE(Service::ConstPtr) class ConnectionThread; class MainConnection : private ErrorMessage::ErrorLogger { Q_DECLARE_TR_FUNCTIONS(ZeroConf) public: enum RequestFlowStatus { NormalRFS, MoreComingRFS, ForceUpdateRFS }; RequestFlowStatus flowStatus; /// WARNING order matters in this enum, and status should only be changed with increaseStatusTo enum Status { Starting, Started, Running, Stopping, Stopped }; ZConfLib::Ptr lib; MainConnection(ServiceBrowserPrivate *initialBrowser = 0); virtual ~MainConnection(); QMutex *lock(); QMutex *mainThreadLock(); void waitStartup(); void stop(bool wait = true); void addBrowser(ServiceBrowserPrivate *browser); void removeBrowser(ServiceBrowserPrivate *browser); void updateFlowStatusForCancel(); void updateFlowStatusForFlags(DNSServiceFlags flags); void maybeUpdateLists(); void gotoValidLib(); void abortLib(); void createConnection(); void destroyConnection(); ZConfLib::RunLoopStatus handleEvent(); bool increaseStatusTo(int s); void handleEvents(); ZConfLib::ConnectionRef mainRef(); Status status(); QList errors(); bool isOk(); void startupPhase(int progress, const QString &msg); private: void appendError(ErrorMessage::SeverityLevel severity, const QString &msg); mutable QMutex m_lock, m_mainThreadLock; QList m_browsers; ZConfLib::ConnectionRef m_mainRef; bool m_failed; ConnectionThread *m_thread; QAtomicInt m_status; int m_nErrs; QList m_errors; }; class ServiceBrowserPrivate { public: ServiceBrowser *q; QString serviceType; QString domain; MainConnectionPtr mainConnection; ZConfLib::BrowserRef serviceConnection; DNSServiceFlags flags; uint32_t interfaceIndex; QList knownServices; QMap gatherers; QList activeServices; QList nextActiveServices; QList pendingGatherers; qint64 delayDeletesUntil; bool failed; bool browsing; bool autoResolveAddresses; bool requireAddresses; bool shouldRefresh; ZConfLib::ConnectionRef mainRef(); void updateFlowStatusForCancel(); void updateFlowStatusForFlags(DNSServiceFlags flags); void pendingGathererAdd(ServiceGatherer::Ptr gatherer); ServiceBrowserPrivate(const QString &serviceType, const QString &domain, bool requireAddresses, MainConnectionPtr conn); ~ServiceBrowserPrivate(); void insertGatherer(const QString &fullName); void maybeUpdateLists(); void startBrowsing(quint32 interfaceIndex); bool internalStartBrowsing(); void stopBrowsing(); void triggerRefresh(); void refresh(); void reconfirmService(Service::ConstPtr s); void browseReply(DNSServiceFlags flags, uint32_t interfaceIndex, ZK_IP_Protocol proto, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain); void activateAutoRefresh(); void serviceChanged(const Service::ConstPtr &oldService, const Service::ConstPtr &newService, ServiceBrowser *browser); void serviceAdded(const Service::ConstPtr &service, ServiceBrowser *browser); void serviceRemoved(const Service::ConstPtr &service, ServiceBrowser *browser); void servicesUpdated(ServiceBrowser *browser); void startupPhase(int progress, const QString &description); void errorMessage(ErrorMessage::SeverityLevel severity, const QString &msg); void hadFailure(const QList &msgs); void startedBrowsing(); }; class ConnectionThread: public QThread { MainConnection &connection; void run(); public: ConnectionThread(MainConnection &mc, QObject *parent = 0); }; extern "C" void DNSSD_API cServiceResolveReply( 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); extern "C" void DNSSD_API cTxtRecordReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context); extern "C" void DNSSD_API cAddrReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context); extern "C" void DNSSD_API cBrowseReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context); } // namespace Internal } // namespace Zeroconf #endif // SERVICEBROWSER_P_H