MythTV master
bonjourregister.cpp
Go to the documentation of this file.
1#include "bonjourregister.h"
2
3#include <cstdlib>
4#include <limits> // workaround QTBUG-90395
5
6#include <QtGlobal>
7#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
8#include <QtEnvironmentVariables>
9#endif
10#include <QSocketNotifier>
11#include <QtEndian>
12
13#include "mythrandom.h"
14#include "mythlogging.h"
15
16#define LOC QString("Bonjour: ")
17
19
21 : QObject(parent)
22{
23 qputenv("AVAHI_COMPAT_NOWARN", "1");
24}
25
27{
28 if (m_socket) {
29 m_socket->setEnabled(false);
30 m_socket->deleteLater();
31 m_socket = nullptr;
32 }
33
34 if (m_dnssref)
35 {
36 LOG(VB_GENERAL, LOG_INFO, LOC +
37 QString("De-registering service '%1' on '%2'")
38 .arg(m_type.data(), m_name.data()));
39 DNSServiceRefDeallocate(m_dnssref);
40 }
41 m_dnssref = nullptr;
42
43 delete m_lock;
44 m_lock = nullptr;
45}
46
47bool BonjourRegister::Register(uint16_t port, const QByteArray &type,
48 const QByteArray &name, const QByteArray &txt)
49{
50 if (m_dnssref)
51 {
52 LOG(VB_GENERAL, LOG_WARNING, LOC + "Service already registered.");
53 return true;
54 }
55
56 m_lock = new QMutexLocker(&g_lock);
57 m_data = txt;
58
59 uint16_t qport = qToBigEndian(port);
60 DNSServiceErrorType res =
61 DNSServiceRegister(&m_dnssref, 0, 0, name.data(), type.data(),
62 nullptr, nullptr, qport, txt.size(), (void*)txt.data(),
63 BonjourCallback, this);
64
65 if (kDNSServiceErr_NoError != res)
66 {
67 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error: %1").arg(res));
68 }
69 else
70 {
71 int fd = DNSServiceRefSockFD(m_dnssref);
72 if (fd != -1)
73 {
74 m_socket = new QSocketNotifier(fd, QSocketNotifier::Read, this);
75 m_socket->setEnabled(true);
76 connect(m_socket, &QSocketNotifier::activated,
78 delete m_lock; // would already have been deleted, but just in case
79 m_lock = nullptr;
80 return true;
81 }
82 }
83
84 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to register service.");
85 delete m_lock;
86 m_lock = nullptr;
87
88 return false;
89}
90
91
93{
94 DNSServiceErrorType res = DNSServiceProcessResult(m_dnssref);
95 if (kDNSServiceErr_NoError != res)
96 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Read Error: %1").arg(res));
97}
98
99
100void BonjourRegister::BonjourCallback([[maybe_unused]] DNSServiceRef ref,
101 [[maybe_unused]] DNSServiceFlags flags,
102 DNSServiceErrorType errorcode,
103 const char *name, const char *type,
104 const char *domain, void *object)
105{
106 auto *bonjour = static_cast<BonjourRegister *>(object);
107 if (bonjour)
108 {
109 delete bonjour->m_lock;
110 bonjour->m_lock = nullptr;
111 }
112
113 if (kDNSServiceErr_NoError != errorcode)
114 {
115 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Callback Error: %1")
116 .arg(errorcode));
117 }
118 else if (bonjour)
119 {
120 LOG(VB_GENERAL, LOG_INFO, LOC +
121 QString("Service registration complete: name '%1' type '%2' domain: '%3'")
122 .arg(QString::fromUtf8(name), QString::fromUtf8(type),
123 QString::fromUtf8(domain)));
124 bonjour->m_name = name;
125 bonjour->m_type = type;
126 }
127 else
128 {
129 LOG(VB_GENERAL, LOG_ERR, LOC +
130 QString("BonjourCallback for unknown object."));
131 }
132}
133
135{
136 QByteArray data = m_data;
137 QByteArray rnd;
138
139 data.append(7);
140 data.append("_rnd=");
141 rnd.append(MythRandom(33, 33 + 80 - 1));
142 data.append(rnd.toHex());
143
144 return data;
145}
146
148{
149 if (!m_dnssref)
150 {
151 // nothing to refresh
152 return false;
153 }
154
155 QByteArray data = RandomizeData();
156
157 DNSServiceErrorType res =
158 DNSServiceUpdateRecord(m_dnssref, /* DNSServiceRef sdRef */
159 nullptr, /* DNSRecordRef RecordRef */
160 0, /* DNSServiceFlags flags */
161 data.size(), /* uint16_t rdlen */
162 (void*)data.data(), /* const void *rdata */
163 0); /* uint32_t ttl */
164
165 if (kDNSServiceErr_NoError != res)
166 {
167 LOG(VB_GENERAL, LOG_ERR, LOC +
168 QString("Error ReAnnounceService(%1): %2")
169 .arg(m_name.data()).arg(res));
170 }
171 return kDNSServiceErr_NoError != res;
172}
173
174#include "moc_bonjourregister.cpp"
#define LOC
static QMutex g_lock
QByteArray m_data
QByteArray m_name
QMutexLocker< QMutex > * m_lock
QByteArray m_type
QByteArray RandomizeData(void)
QSocketNotifier * m_socket
BonjourRegister(QObject *parent=nullptr)
DNSServiceRef m_dnssref
static void DNSSD_API BonjourCallback(DNSServiceRef ref, DNSServiceFlags flags, DNSServiceErrorType errorcode, const char *name, const char *type, const char *domain, void *object)
~BonjourRegister() override
bool ReAnnounceService(void)
bool Register(uint16_t port, const QByteArray &type, const QByteArray &name, const QByteArray &txt)
unsigned short uint16_t
Definition: iso6937tables.h:3
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
Convenience inline random number generator functions.
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20