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