KDNSSD

mdnsd-publicservice.cpp
1/*
2 This file is part of the KDE project
3
4 SPDX-FileCopyrightText: 2004, 2005 Jakub Stachowski <qbast@go2.pl>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "mdnsd-responder.h"
10#include "mdnsd-sdevent.h"
11#include "publicservice.h"
12#include "servicebase_p.h"
13#include <QCoreApplication>
14#include <QStringList>
15
16#ifdef _WIN32
17#include <winsock2.h>
18#else
19#include <netinet/in.h>
20#endif
21
22#define KDNSSD_D PublicServicePrivate *d = static_cast<PublicServicePrivate *>(this->d.operator->())
23
24namespace KDNSSD
25{
26void publish_callback(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *, const char *, void *context);
27class PublicServicePrivate : public Responder, public ServiceBasePrivate
28{
29public:
30 PublicServicePrivate(PublicService *parent, const QString &name, const QString &type, unsigned int port, const QString &domain)
31 : Responder()
32 , ServiceBasePrivate(name, type, domain, QString(), port)
33 , m_published(false)
34 , m_parent(parent)
35 {
36 }
37 bool m_published;
38 PublicService *m_parent;
39 QStringList m_subtypes;
40 virtual void customEvent(QEvent *event);
41};
42
43PublicService::PublicService(const QString &name, const QString &type, unsigned int port, const QString &domain, const QStringList &subtypes)
44 : QObject()
45 , ServiceBase(new PublicServicePrivate(this, name, type, port, domain))
46{
47 KDNSSD_D;
48 if (domain.isNull()) {
49 d->m_domain = "local.";
50 }
51 d->m_subtypes = subtypes;
52}
53
54PublicService::~PublicService()
55{
56 stop();
57}
58
59void PublicService::setServiceName(const QString &serviceName)
60{
61 KDNSSD_D;
62 d->m_serviceName = serviceName;
63 if (d->isRunning()) {
64 stop();
65 publishAsync();
66 }
67}
68
69void PublicService::setDomain(const QString &domain)
70{
71 KDNSSD_D;
72 d->m_domain = domain;
73 if (d->isRunning()) {
74 stop();
75 publishAsync();
76 }
77}
78
79QStringList PublicService::subtypes() const
80{
81 KDNSSD_D;
82 return d->m_subtypes;
83}
84
85void PublicService::setType(const QString &type)
86{
87 KDNSSD_D;
88 d->m_type = type;
89 if (d->isRunning()) {
90 stop();
91 publishAsync();
92 }
93}
94
95void PublicService::setSubTypes(const QStringList &subtypes)
96{
97 KDNSSD_D;
98 d->m_subtypes = subtypes;
99 if (d->isRunning()) {
100 stop();
101 publishAsync();
102 }
103}
104
105void PublicService::setPort(unsigned short port)
106{
107 KDNSSD_D;
108 d->m_port = port;
109 if (d->isRunning()) {
110 stop();
111 publishAsync();
112 }
113}
114
115bool PublicService::isPublished() const
116{
117 KDNSSD_D;
118 return d->m_published;
119}
120
121void PublicService::setTextData(const QMap<QString, QByteArray> &textData)
122{
123 KDNSSD_D;
124 d->m_textData = textData;
125 if (d->isRunning()) {
126 stop();
127 publishAsync();
128 }
129}
130
131bool PublicService::publish()
132{
133 KDNSSD_D;
134 publishAsync();
135 while (d->isRunning() && !d->m_published) {
136 d->process();
137 }
138 return d->m_published;
139}
140
141void PublicService::stop()
142{
143 KDNSSD_D;
144 d->stop();
145 d->m_published = false;
146}
147
148void PublicService::publishAsync()
149{
150 KDNSSD_D;
151 if (d->isRunning()) {
152 stop();
153 }
154 TXTRecordRef txt;
155 TXTRecordCreate(&txt, 0, 0);
156 QMap<QString, QByteArray>::ConstIterator itEnd = d->m_textData.cend();
157 for (QMap<QString, QByteArray>::ConstIterator it = d->m_textData.cbegin(); it != itEnd; ++it) {
158 if (TXTRecordSetValue(&txt, it.key().toUtf8().constData(), it.value().length(), it.value().constData()) != kDNSServiceErr_NoError) {
159 TXTRecordDeallocate(&txt);
160 Q_EMIT published(false);
161 return;
162 }
163 }
164 DNSServiceRef ref;
165 QString fullType = d->m_type;
166 for (const QString &subtype : std::as_const(d->m_subtypes)) {
167 fullType += ',' + subtype;
168 }
169 if (DNSServiceRegister(&ref,
170 0,
171 0,
172 d->m_serviceName.toUtf8().constData(),
173 fullType.toLatin1().constData(),
174 domainToDNS(d->m_domain).constData(),
175 NULL,
176 htons(d->m_port),
177 TXTRecordGetLength(&txt),
178 TXTRecordGetBytesPtr(&txt),
179 publish_callback,
180 reinterpret_cast<void *>(d))
181 == kDNSServiceErr_NoError) {
182 d->setRef(ref);
183 }
184 TXTRecordDeallocate(&txt);
185 if (!d->isRunning()) {
186 Q_EMIT published(false);
187 }
188}
189
190void publish_callback(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *, const char *, void *context)
191{
192 QObject *obj = reinterpret_cast<QObject *>(context);
193 if (errorCode != kDNSServiceErr_NoError) {
194 ErrorEvent err;
196 } else {
197 PublishEvent pev(QString::fromUtf8(name));
199 }
200}
201
202void PublicServicePrivate::customEvent(QEvent *event)
203{
204 if (event->type() == QEvent::User + SD_ERROR) {
205 m_parent->stop();
206 Q_EMIT m_parent->published(false);
207 }
208 if (event->type() == QEvent::User + SD_PUBLISH) {
209 m_published = true;
210 Q_EMIT m_parent->published(true);
211 m_serviceName = static_cast<PublishEvent *>(event)->m_name;
212 }
213}
214
215void PublicService::virtual_hook(int, void *)
216{
217}
218
219}
220
221#include "moc_publicservice.cpp"
PublicService(const QString &name=QString(), const QString &type=QString(), unsigned int port=0, const QString &domain=QString(), const QStringList &subtypes=QStringList())
Creates a service description that can be published.
void stop(Ekos::AlignState mode)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
Type type(const QSqlDatabase &db)
QString name(StandardAction id)
const char * constData() const const
bool sendEvent(QObject *receiver, QEvent *event)
ConstIterator
virtual bool event(QEvent *e)
QObject * parent() const const
const QChar * constData() const const
QString fromUtf8(QByteArrayView str)
bool isNull() const const
QByteArray toLatin1() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:06:09 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.