-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzeroconfservicepublisherdnssd.cpp
146 lines (126 loc) · 6.09 KB
/
zeroconfservicepublisherdnssd.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* [email protected] or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "zeroconfservicepublisherdnssd.h"
#include <loggingcategories.h>
#include <QNetworkInterface>
#include <QtEndian>
ZeroConfServicePublisherDnssd::ZeroConfServicePublisherDnssd(QObject *parent) : ZeroConfServicePublisher(parent)
{
}
bool ZeroConfServicePublisherDnssd::registerService(const QString &name, const QHostAddress &hostAddress, const quint16 &port, const QString &serviceType, const QHash<QString, QString> &txtRecords)
{
if (m_services.contains(name)) {
qCDebug(dcPlatformZeroConf) << "Service" << name << "already registered. Cannot reregister.";
return false;
}
Context *ctx = new Context();
ctx->self = this;
ctx->name = name;
return registerServiceInternal(ctx, hostAddress, port, serviceType, txtRecords);
}
bool ZeroConfServicePublisherDnssd::registerServiceInternal(ZeroConfServicePublisherDnssd::Context *ctx, const QHostAddress &hostAddress, const quint16 &port, const QString &serviceType, const QHash<QString, QString> &txtRecords)
{
uint32_t ifIndex = 0;
if (hostAddress != QHostAddress("0.0.0.0")) {
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
foreach (const QNetworkAddressEntry &addressEntry, interface.addressEntries()) {
QPair<QHostAddress, int> subnet = QHostAddress::parseSubnet(addressEntry.ip().toString() + "/" + addressEntry.netmask().toString());
if (hostAddress.isInSubnet(subnet.first, subnet.second)) {
ifIndex = static_cast<uint32_t>(interface.index());
break;
}
}
}
}
QByteArray txt;
foreach (const QString &key, txtRecords.keys()) {
QString record = key;
record.append("=");
record.append(txtRecords.value(key));
txt.append(static_cast<quint8>(record.size()));
txt.append(record.toUtf8());
}
ctx->effectiveName = ctx->name + ((ctx->collisionIndex > 0) ? " #" + QString::number(ctx->collisionIndex) : "");
DNSServiceErrorType err = DNSServiceRegister(&ctx->ref, 0, ifIndex, ctx->effectiveName.toUtf8().data(), serviceType.toUtf8().data(), 0, 0, qFromBigEndian<quint16>(port), txt.length(), txt, (DNSServiceRegisterReply) registerCallback, ctx);
if (err != kDNSServiceErr_NoError) {
qCWarning(dcPlatformZeroConf) << "Failed to register ZeroConf service" << ctx->name << "with dns_sd. Error:" << err;
if (err == kDNSServiceErr_NameConflict) {
qCDebug(dcPlatformZeroConf()) << "Handling service collision";
ctx->collisionIndex++;
return registerServiceInternal(ctx, hostAddress, port, serviceType, txtRecords);
}
delete ctx;
return false;
}
int sockFd = DNSServiceRefSockFD(ctx->ref);
if (sockFd == -1) {
qCWarning(dcPlatformZeroConf) << "Error obtaining ZeroConf socket descriptor.";
DNSServiceRefDeallocate(ctx->ref);
delete ctx;
return false;
}
ctx->socketNotifier = new QSocketNotifier(sockFd, QSocketNotifier::Read, this);
connect(ctx->socketNotifier, &QSocketNotifier::activated, this, [this, ctx]{
DNSServiceErrorType err = DNSServiceProcessResult(ctx->ref);
if (err != kDNSServiceErr_NoError) {
qCWarning(dcPlatformZeroConf) << "Error processing ZeroConf Socket data.";
DNSServiceRefDeallocate(ctx->ref);
m_services.remove(ctx->name);
ctx->socketNotifier->deleteLater();
delete ctx;
}
});
m_services.insert(ctx->name, ctx);
qCDebug(dcPlatformZeroConf) << "ZeroConf service" << ctx->name << serviceType << port << "registerd at dns_sd as" << ctx->effectiveName;
return true;
}
void ZeroConfServicePublisherDnssd::unregisterService(const QString &name)
{
if (!m_services.contains(name)) {
qCDebug(dcPlatformZeroConf) << "Service" << name << "unknown. Cannot unregister.";
return;
}
qCDebug(dcPlatformZeroConf) << "ZeroConf service" << name << "unregistered";
Context *ctx = m_services.take(name);
ctx->socketNotifier->deleteLater();
DNSServiceRefDeallocate(ctx->ref);
delete ctx;
}
void DNSSD_API ZeroConfServicePublisherDnssd::registerCallback(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *, const char *, const char *, void *userdata)
{
if (errorCode != kDNSServiceErr_NoError) {
Context *ctx = static_cast<Context*>(userdata);
qCWarning(dcPlatformZeroConf) << "Zeroconf registration failed with error code" << errorCode << ctx->name;
DNSServiceRefDeallocate(ctx->ref);
ctx->self->m_services.remove(ctx->name);
ctx->socketNotifier->deleteLater();
delete ctx;
}
}