MythTV  master
bonjourregister.cpp
Go to the documentation of this file.
1 #include <cstdlib>
2 
3 #include <QSocketNotifier>
4 #include <QtEndian>
5 
6 #include "mythmiscutil.h"
7 #include "mythlogging.h"
8 #include "bonjourregister.h"
9 
10 #define LOC QString("Bonjour: ")
11 
13 
15  : QObject(parent)
16 {
17  setenv("AVAHI_COMPAT_NOWARN", "1", 1);
18 }
19 
21 {
22  if (m_socket) {
23  m_socket->setEnabled(false);
24  m_socket->deleteLater();
25  m_socket = nullptr;
26  }
27 
28  if (m_dnssref)
29  {
30  LOG(VB_GENERAL, LOG_INFO, LOC +
31  QString("De-registering service '%1' on '%2'")
32  .arg(m_type.data()).arg(m_name.data()));
33  DNSServiceRefDeallocate(m_dnssref);
34  }
35  m_dnssref = nullptr;
36 
37  delete m_lock;
38  m_lock = nullptr;
39 }
40 
41 bool BonjourRegister::Register(uint16_t port, const QByteArray &type,
42  const QByteArray &name, const QByteArray &txt)
43 {
44  if (m_dnssref)
45  {
46  LOG(VB_GENERAL, LOG_WARNING, LOC + "Service already registered.");
47  return true;
48  }
49 
50  m_lock = new QMutexLocker(&g_lock);
51  m_data = txt;
52 
53  uint16_t qport = qToBigEndian(port);
54  DNSServiceErrorType res =
55  DNSServiceRegister(&m_dnssref, 0, 0, name.data(), type.data(),
56  nullptr, nullptr, qport, txt.size(), (void*)txt.data(),
57  BonjourCallback, this);
58 
59  if (kDNSServiceErr_NoError != res)
60  {
61  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error: %1").arg(res));
62  }
63  else
64  {
65  int fd = DNSServiceRefSockFD(m_dnssref);
66  if (fd != -1)
67  {
68  m_socket = new QSocketNotifier(fd, QSocketNotifier::Read, this);
69  m_socket->setEnabled(true);
70  connect(m_socket, &QSocketNotifier::activated,
72  delete m_lock; // would already have been deleted, but just in case
73  m_lock = nullptr;
74  return true;
75  }
76  }
77 
78  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to register service.");
79  delete m_lock;
80  m_lock = nullptr;
81 
82  return false;
83 }
84 
85 
87 {
88  DNSServiceErrorType res = DNSServiceProcessResult(m_dnssref);
89  if (kDNSServiceErr_NoError != res)
90  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Read Error: %1").arg(res));
91 }
92 
93 
94 void BonjourRegister::BonjourCallback(DNSServiceRef ref, DNSServiceFlags flags,
95  DNSServiceErrorType errorcode,
96  const char *name, const char *type,
97  const char *domain, void *object)
98 {
99  (void)ref;
100  (void)flags;
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)).arg(QString::fromUtf8(type))
119  .arg(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() % 80) + 33);
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:20
LOC
#define LOC
Definition: bonjourregister.cpp:10
BonjourRegister::Register
bool Register(uint16_t port, const QByteArray &type, const QByteArray &name, const QByteArray &txt)
Definition: bonjourregister.cpp:41
setenv
#define setenv(x, y, z)
Definition: compat.h:158
arg
arg(title).arg(filename).arg(doDelete))
BonjourRegister::m_socket
QSocketNotifier * m_socket
Definition: bonjourregister.h:37
BonjourRegister::socketReadyRead
void socketReadyRead()
Definition: bonjourregister.cpp:86
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
BonjourRegister
Definition: bonjourregister.h:12
BonjourRegister::m_lock
QMutexLocker * m_lock
Definition: bonjourregister.h:38
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:94
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:39
MythRandom
MBASE_PUBLIC uint32_t MythRandom()
Definition: mythmiscutil.h:24
BonjourRegister::m_data
QByteArray m_data
Definition: bonjourregister.h:40
BonjourRegister::BonjourRegister
BonjourRegister(QObject *parent=nullptr)
Definition: bonjourregister.cpp:14
BonjourRegister::ReAnnounceService
bool ReAnnounceService(void)
Definition: bonjourregister.cpp:143
mythmiscutil.h
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
BonjourRegister::m_type
QByteArray m_type
Definition: bonjourregister.h:23