File indexing completed on 2024-04-28 03:54:04

0001 /*
0002     This file is part of the KDE project
0003 
0004     SPDX-FileCopyrightText: 2004, 2005 Jakub Stachowski <qbast@go2.pl>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "mdnsd-responder.h"
0010 #include "mdnsd-sdevent.h"
0011 #include "remoteservice.h"
0012 #include "servicebase_p.h"
0013 #include <QCoreApplication>
0014 #include <QDebug>
0015 #include <QEventLoop>
0016 
0017 #ifdef _WIN32
0018 #include <winsock2.h>
0019 #else
0020 #include <netinet/in.h>
0021 #endif
0022 
0023 namespace KDNSSD
0024 {
0025 void resolve_callback(DNSServiceRef,
0026                       DNSServiceFlags,
0027                       uint32_t,
0028                       DNSServiceErrorType errorCode,
0029                       const char *,
0030                       const char *hosttarget,
0031                       uint16_t port,
0032                       uint16_t txtLen,
0033                       const unsigned char *txtRecord,
0034                       void *context);
0035 
0036 #define KDNSSD_D RemoteServicePrivate *d = static_cast<RemoteServicePrivate *>(this->d.operator->())
0037 
0038 class RemoteServicePrivate : public Responder, public ServiceBasePrivate
0039 {
0040 public:
0041     RemoteServicePrivate(RemoteService *parent, const QString &name, const QString &type, const QString &domain)
0042         : Responder()
0043         , ServiceBasePrivate(name, type, domain, QString(), 0)
0044         , m_resolved(false)
0045         , m_parent(parent)
0046     {
0047     }
0048     bool m_resolved;
0049     RemoteService *m_parent;
0050     virtual void customEvent(QEvent *event);
0051 };
0052 
0053 RemoteService::RemoteService(const QString &name, const QString &type, const QString &domain)
0054     : ServiceBase(new RemoteServicePrivate(this, name, type, domain))
0055 {
0056 }
0057 
0058 RemoteService::~RemoteService()
0059 {
0060 }
0061 
0062 bool RemoteService::resolve()
0063 {
0064     KDNSSD_D;
0065     resolveAsync();
0066     while (d->isRunning() && !d->m_resolved) {
0067         d->process();
0068     }
0069     d->stop();
0070     return d->m_resolved;
0071 }
0072 
0073 void RemoteService::resolveAsync()
0074 {
0075     KDNSSD_D;
0076     if (d->isRunning()) {
0077         return;
0078     }
0079     d->m_resolved = false;
0080     // qDebug() << this << ":Starting resolve of : " << d->m_serviceName << " " << d->m_type << " " << d->m_domain << "\n";
0081     DNSServiceRef ref;
0082     if (DNSServiceResolve(&ref,
0083                           0,
0084                           0,
0085                           d->m_serviceName.toUtf8().constData(),
0086                           d->m_type.toLatin1().constData(),
0087                           domainToDNS(d->m_domain).constData(),
0088                           (DNSServiceResolveReply)resolve_callback,
0089                           reinterpret_cast<void *>(d))
0090         == kDNSServiceErr_NoError) {
0091         d->setRef(ref);
0092     }
0093     if (!d->isRunning()) {
0094         Q_EMIT resolved(false);
0095     }
0096 }
0097 
0098 bool RemoteService::isResolved() const
0099 {
0100     KDNSSD_D;
0101     return d->m_resolved;
0102 }
0103 
0104 void RemoteServicePrivate::customEvent(QEvent *event)
0105 {
0106     if (event->type() == QEvent::User + SD_ERROR) {
0107         stop();
0108         m_resolved = false;
0109         Q_EMIT m_parent->resolved(false);
0110     }
0111     if (event->type() == QEvent::User + SD_RESOLVE) {
0112         ResolveEvent *rev = static_cast<ResolveEvent *>(event);
0113         m_hostName = rev->m_hostname;
0114         m_port = rev->m_port;
0115         m_textData = rev->m_txtdata;
0116         m_resolved = true;
0117         Q_EMIT m_parent->resolved(true);
0118     }
0119 }
0120 
0121 void RemoteService::virtual_hook(int, void *)
0122 {
0123     // BASE::virtual_hook(int, void*);
0124 }
0125 
0126 void resolve_callback(DNSServiceRef,
0127                       DNSServiceFlags,
0128                       uint32_t,
0129                       DNSServiceErrorType errorCode,
0130                       const char *,
0131                       const char *hosttarget,
0132                       uint16_t port,
0133                       uint16_t txtLen,
0134                       const unsigned char *txtRecord,
0135                       void *context)
0136 {
0137     QObject *obj = reinterpret_cast<QObject *>(context);
0138     if (errorCode != kDNSServiceErr_NoError) {
0139         ErrorEvent err;
0140         QCoreApplication::sendEvent(obj, &err);
0141         return;
0142     }
0143     char key[256];
0144     int index = 0;
0145     unsigned char valueLen;
0146     // qDebug() << "Resolve callback\n";
0147     QMap<QString, QByteArray> map;
0148     const void *voidValue = 0;
0149     while (TXTRecordGetItemAtIndex(txtLen, txtRecord, index++, 256, key, &valueLen, &voidValue) == kDNSServiceErr_NoError) {
0150         if (voidValue) {
0151             map[QString::fromUtf8(key)] = QByteArray((const char *)voidValue, valueLen);
0152         } else {
0153             map[QString::fromUtf8(key)].clear();
0154         }
0155     }
0156     ResolveEvent rev(DNSToDomain(hosttarget), ntohs(port), map);
0157     QCoreApplication::sendEvent(obj, &rev);
0158 }
0159 
0160 }
0161 
0162 #include "moc_remoteservice.cpp"