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