File indexing completed on 2024-04-28 15:22:06
0001 /* 0002 This file is part of the KDE project 0003 0004 SPDX-FileCopyrightText: 2004 Jakub Stachowski <qbast@go2.pl> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "domainbrowser.h" 0010 #include "mdnsd-responder.h" 0011 #include "mdnsd-sdevent.h" 0012 #include "mdnsd-servicebrowser_p.h" 0013 #include "remoteservice.h" 0014 #include "servicebrowser.h" 0015 #include <QCoreApplication> 0016 #include <QHash> 0017 #include <QHostInfo> 0018 #include <QStringList> 0019 #include <QTimer> 0020 #include <dns_sd.h> 0021 0022 #define TIMEOUT_WAN 2000 0023 #define TIMEOUT_LAN 200 0024 0025 namespace KDNSSD 0026 { 0027 void query_callback(DNSServiceRef, 0028 DNSServiceFlags flags, 0029 uint32_t, 0030 DNSServiceErrorType errorCode, 0031 const char *serviceName, 0032 const char *regtype, 0033 const char *replyDomain, 0034 void *context); 0035 0036 ServiceBrowser::ServiceBrowser(const QString &type, bool autoResolve, const QString &domain, const QString &subtype) 0037 : d(new ServiceBrowserPrivate(this)) 0038 { 0039 Q_D(ServiceBrowser); 0040 d->m_type = type; 0041 d->m_autoResolve = autoResolve; 0042 d->m_domain = domain; 0043 d->m_subtype = subtype; 0044 d->timeout.setSingleShot(true); 0045 connect(&d->timeout, SIGNAL(timeout()), d, SLOT(onTimeout())); 0046 } 0047 0048 ServiceBrowser::State ServiceBrowser::isAvailable() 0049 { 0050 // DNSServiceRef ref; 0051 // bool ok (DNSServiceCreateConnection(&ref)==kDNSServiceErr_NoError); 0052 // if (ok) DNSServiceRefDeallocate(ref); 0053 // return (ok) ? Working : Stopped; 0054 return Working; 0055 } 0056 0057 ServiceBrowser::~ServiceBrowser() = default; 0058 0059 bool ServiceBrowser::isAutoResolving() const 0060 { 0061 Q_D(const ServiceBrowser); 0062 return d->m_autoResolve; 0063 } 0064 0065 void ServiceBrowserPrivate::serviceResolved(bool success) 0066 { 0067 QObject *sender_obj = const_cast<QObject *>(sender()); 0068 RemoteService *svr = static_cast<RemoteService *>(sender_obj); 0069 disconnect(svr, SIGNAL(resolved(bool)), this, SLOT(serviceResolved(bool))); 0070 QList<RemoteService::Ptr>::Iterator it = m_duringResolve.begin(); 0071 QList<RemoteService::Ptr>::Iterator itEnd = m_duringResolve.end(); 0072 while (it != itEnd && svr != (*it).data()) { 0073 ++it; 0074 } 0075 if (it != itEnd) { 0076 if (success) { 0077 m_services += (*it); 0078 Q_EMIT m_parent->serviceAdded(RemoteService::Ptr(svr)); 0079 } 0080 m_duringResolve.erase(it); 0081 queryFinished(); 0082 } 0083 } 0084 0085 void ServiceBrowser::startBrowse() 0086 { 0087 Q_D(ServiceBrowser); 0088 if (d->isRunning()) { 0089 return; 0090 } 0091 d->m_finished = false; 0092 DNSServiceRef ref; 0093 QString fullType = d->m_type; 0094 if (!d->m_subtype.isEmpty()) { 0095 fullType = d->m_subtype + "._sub." + d->m_type; 0096 } 0097 if (DNSServiceBrowse(&ref, 0, 0, fullType.toLatin1().constData(), domainToDNS(d->m_domain).constData(), query_callback, reinterpret_cast<void *>(d)) 0098 == kDNSServiceErr_NoError) { 0099 d->setRef(ref); 0100 } 0101 if (!d->isRunning()) { 0102 Q_EMIT finished(); 0103 } else { 0104 d->timeout.start(domainIsLocal(d->m_domain) ? TIMEOUT_LAN : TIMEOUT_WAN); 0105 } 0106 } 0107 0108 void ServiceBrowserPrivate::queryFinished() 0109 { 0110 if (!m_duringResolve.count() && m_finished) { 0111 Q_EMIT m_parent->finished(); 0112 } 0113 } 0114 0115 QList<RemoteService::Ptr> ServiceBrowser::services() const 0116 { 0117 Q_D(const ServiceBrowser); 0118 return d->m_services; 0119 } 0120 0121 void ServiceBrowser::virtual_hook(int, void *) 0122 { 0123 } 0124 0125 RemoteService::Ptr ServiceBrowserPrivate::find(RemoteService::Ptr s, const QList<RemoteService::Ptr> &where) const 0126 { 0127 for (const RemoteService::Ptr &i : where) 0128 if (*s == *i) { 0129 return i; 0130 } 0131 return RemoteService::Ptr(); 0132 } 0133 0134 void ServiceBrowserPrivate::customEvent(QEvent *event) 0135 { 0136 if (event->type() == QEvent::User + SD_ERROR) { 0137 stop(); 0138 m_finished = false; 0139 queryFinished(); 0140 } 0141 if (event->type() == QEvent::User + SD_ADDREMOVE) { 0142 AddRemoveEvent *aev = static_cast<AddRemoveEvent *>(event); 0143 // m_type has useless trailing dot 0144 RemoteService::Ptr svr(new RemoteService(aev->m_name, aev->m_type.left(aev->m_type.length() - 1), aev->m_domain)); 0145 if (aev->m_op == AddRemoveEvent::Add) { 0146 if (m_autoResolve) { 0147 connect(svr.data(), SIGNAL(resolved(bool)), this, SLOT(serviceResolved(bool))); 0148 m_duringResolve += svr; 0149 svr->resolveAsync(); 0150 } else { 0151 m_services += svr; 0152 Q_EMIT m_parent->serviceAdded(svr); 0153 } 0154 } else { 0155 RemoteService::Ptr found = find(svr, m_duringResolve); 0156 if (found) { 0157 m_duringResolve.removeAll(found); 0158 } else { 0159 found = find(svr, m_services); 0160 if (found) { 0161 Q_EMIT m_parent->serviceRemoved(found); 0162 m_services.removeAll(found); 0163 } 0164 } 0165 } 0166 m_finished = aev->m_last; 0167 if (m_finished) { 0168 queryFinished(); 0169 } 0170 } 0171 } 0172 0173 void ServiceBrowserPrivate::onTimeout() 0174 { 0175 m_finished = true; 0176 queryFinished(); 0177 } 0178 0179 void query_callback(DNSServiceRef, 0180 DNSServiceFlags flags, 0181 uint32_t, 0182 DNSServiceErrorType errorCode, 0183 const char *serviceName, 0184 const char *regtype, 0185 const char *replyDomain, 0186 void *context) 0187 { 0188 QObject *obj = reinterpret_cast<QObject *>(context); 0189 if (errorCode != kDNSServiceErr_NoError) { 0190 ErrorEvent err; 0191 QCoreApplication::sendEvent(obj, &err); 0192 } else { 0193 AddRemoveEvent arev((flags & kDNSServiceFlagsAdd) ? AddRemoveEvent::Add : AddRemoveEvent::Remove, 0194 QString::fromUtf8(serviceName), 0195 regtype, 0196 DNSToDomain(replyDomain), 0197 !(flags & kDNSServiceFlagsMoreComing)); 0198 QCoreApplication::sendEvent(obj, &arev); 0199 } 0200 } 0201 0202 // TODO: Please Implement Me - Using a KResolver (if not natively) 0203 QHostAddress ServiceBrowser::resolveHostName(const QString &hostname) 0204 { 0205 return QHostAddress(); 0206 } 0207 0208 QString ServiceBrowser::getLocalHostName() 0209 { 0210 return QHostInfo::localHostName(); 0211 } 0212 0213 } 0214 0215 #include "moc_mdnsd-servicebrowser_p.cpp" 0216 #include "moc_servicebrowser.cpp"