Kstars

qMDNS.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Alex Spataru
3  SPDX-License-Identifier: MIT
4 */
5 
6 #include "qMDNS.h"
7 
8 #include <QHostInfo>
9 #include <QUdpSocket>
10 #include <QHostAddress>
11 #include <QNetworkInterface>
12 
13 #ifdef Q_OS_LINUX
14  #include <sys/socket.h>
15 #endif
16 
17 #include "kstars_debug.h"
18 /*
19  * DNS port and mutlicast addresses
20  */
21 const quint16 MDNS_PORT = 5353;
22 const QHostAddress IPV6_ADDRESS = QHostAddress ("FF02::FB");
23 const QHostAddress IPV4_ADDRESS = QHostAddress ("224.0.0.251");
24 
25 /*
26  * mDNS/DNS operation flags
27  */
28 const quint16 kQR_Query = 0x0000;
29 const quint16 kQR_Response = 0x8000;
30 const quint16 kRecordA = 0x0001;
31 const quint16 kRecordAAAA = 0x001C;
32 const quint16 kNsecType = 0x002F;
33 const quint16 kFQDN_Separator = 0x0000;
34 const quint16 kFQDN_Length = 0xC00C;
35 const quint16 kIN_BitFlush = 0x8001;
36 const quint16 kIN_Normal = 0x0001;
37 
38 /*
39  * DNS query properties
40  */
41 const quint16 kQuery_QDCOUNT = 0x02;
42 const quint16 kQuery_ANCOUNT = 0x00;
43 const quint16 kQuery_NSCOUNT = 0x00;
44 const quint16 kQuery_ARCOUNT = 0x00;
45 
46 /*
47  * DNS response properties
48  */
49 const quint16 kResponse_QDCOUNT = 0x00;
50 const quint16 kResponse_ANCOUNT = 0x01;
51 const quint16 kResponse_NSCOUNT = 0x00;
52 const quint16 kResponse_ARCOUNT = 0x02;
53 
54 /* Packet constants */
55 const int MIN_LENGTH = 13;
56 const int IPI_LENGTH = 10;
57 const int IP4_LENGTH = IPI_LENGTH + 4;
58 const int IP6_LENGTH = IPI_LENGTH + 16;
59 
60 /**
61  * Encodes the 16-bit \a number as two 8-bit numbers in a byte array
62  */
63 QByteArray ENCODE_16_BIT (quint16 number) {
64  QByteArray data;
65  data.append ((number & 0xff00) >> 8);
66  data.append ((number & 0xff));
67  return data;
68 }
69 
70 /**
71  * Encodes the 32-bit \a number as four 8-bit numbers
72  */
73 QByteArray ENCODE_32_BIT (quint32 number) {
74  QByteArray data;
75  data.append ((number & 0xff000000UL) >> 24);
76  data.append ((number & 0x00ff0000UL) >> 16);
77  data.append ((number & 0x0000ff00UL) >> 8);
78  data.append ((number & 0x000000ffUL));
79  return data;
80 }
81 
82 /**
83  * Obtains the 16-bit number stored in the \a upper and \a lower 8-bit numbers
84  */
85 quint16 DECODE_16_BIT (quint8 upper, quint8 lower) {
86  return (quint16) ((upper << 8) | lower);
87 }
88 
89 /**
90  * Binds the given \a socket to the given \a address and \a port.
91  * Under GNU/Linux, this function implements a workaround of QTBUG-33419.
92  */
93 bool BIND (QUdpSocket* socket, const QHostAddress& address, const int port) {
94  if (!socket)
95  return false;
96 
97 #ifdef Q_OS_LINUX
98  int reuse = 1;
99  int domain = PF_UNSPEC;
100 
101  if (address.protocol() == QAbstractSocket::IPv4Protocol)
102  domain = PF_INET;
103  else if (address.protocol() == QAbstractSocket::IPv6Protocol)
104  domain = PF_INET6;
105 
106  socket->setSocketDescriptor (::socket (domain, SOCK_DGRAM, 0),
108 
109  setsockopt (socket->socketDescriptor(), SOL_SOCKET, SO_REUSEADDR,
110  &reuse, sizeof (reuse));
111 #endif
112 
113  return socket->bind (address, port,
116 }
117 
118 qMDNS::qMDNS() {
119  /* Set default TTL to 4500 seconds */
120  m_ttl = 4500;
121 
122  /* Initialize sockets */
123  m_IPv4Socket = new QUdpSocket (this);
124  m_IPv6Socket = new QUdpSocket (this);
125 
126  /* Read and interpret data received from mDNS group */
127  connect (m_IPv4Socket, &QUdpSocket::readyRead, this, &qMDNS::onReadyRead);
128  connect (m_IPv6Socket, &QUdpSocket::readyRead, this, &qMDNS::onReadyRead);
129 
130  /* Bind the sockets to the mDNS multicast group */
131  if (BIND (m_IPv4Socket, QHostAddress::AnyIPv4, MDNS_PORT))
132  m_IPv4Socket->joinMulticastGroup (IPV4_ADDRESS);
133  if (BIND (m_IPv6Socket, QHostAddress::AnyIPv6, MDNS_PORT))
134  m_IPv6Socket->joinMulticastGroup (IPV6_ADDRESS);
135 }
136 
137 qMDNS::~qMDNS() {
138  delete m_IPv4Socket;
139  delete m_IPv6Socket;
140 }
141 
142 /**
143  * Returns the only running instance of this class
144  */
146  static qMDNS instance;
147  return &instance;
148 }
149 
150 /**
151  * Returns the mDNS name assigned to the client computer
152  */
154  return m_hostName;
155 }
156 
157 /**
158  * Ensures that the given \a string is a valid mDNS/DNS address.
159  */
161  QString address = string;
162 
163  if (!string.endsWith (".local") && !string.contains ("."))
164  address = string + ".local";
165 
166  if (string.endsWith ("."))
167  return "";
168 
169  return address;
170 }
171 
172 /**
173  * Changes the TTL send to other computers in the mDNS network
174  */
175 void qMDNS::setTTL (const quint32 ttl) {
176  m_ttl = ttl;
177 }
178 
179 /**
180  * Performs a mDNS lookup to find the given host \a name.
181  * If \a preferIPv6 is set to \c true, then this function will generate a
182  * packet that requests an AAAA-type Resource Record instead of an A-type
183  * Resource Record.
184  */
185 void qMDNS::lookup (const QString& name) {
186  /* The host name is empty, abort lookup */
187  if (name.isEmpty()) {
188  qCWarning(KSTARS) << Q_FUNC_INFO << "Empty host name specified";
189  return;
190  }
191 
192  qCInfo(KSTARS) << "Starting lookup for service" << name;
193 
194  m_serviceName = name;
195 
196  /* Ensure that we host name is a valid DNS address */
197  QString address = getAddress (name);
198  if (address.isEmpty())
199  return;
200 
201  /* Check if we are dealing with a normal DNS address */
202  if (!address.endsWith (".local", Qt::CaseInsensitive)) {
203  QHostInfo::lookupHost (address, this, SIGNAL (hostFound(QHostInfo)));
204  return;
205  }
206 
207  /* Perform a mDNS lookup */
208  else {
209  QByteArray data;
210 
211  /* Get the host name and domain */
212  QString host = address.split (".").first();
213  QString domain = address.split (".").last();
214 
215  /* Check that domain length is valid */
216  if (host.length() > 255) {
217  qWarning() << Q_FUNC_INFO << host << "is too long!";
218  return;
219  }
220 
221  /* Create header & flags */
222  data.append (ENCODE_16_BIT (0));
223  data.append (ENCODE_16_BIT (kQR_Query));
224  data.append (ENCODE_16_BIT (kQuery_QDCOUNT));
225  data.append (ENCODE_16_BIT (kQuery_ANCOUNT));
226  data.append (ENCODE_16_BIT (kQuery_NSCOUNT));
227  data.append (ENCODE_16_BIT (kQuery_ARCOUNT));
228 
229  /* Add name data */
230  data.append (host.length());
231  data.append (host.toUtf8());
232 
233  /* Add domain data */
234  data.append (domain.length());
235  data.append (domain.toUtf8());
236 
237  /* Add FQDN/TLD separator */
238  data.append ((char) kFQDN_Separator);
239 
240  /* Add IPv4 record type */
241  data.append (ENCODE_16_BIT (kRecordA));
242  data.append (ENCODE_16_BIT (kIN_Normal));
243 
244  /* Add FQDN length */
245  data.append (ENCODE_16_BIT (kFQDN_Length));
246 
247  /* Add IPv6 record type */
248  data.append (ENCODE_16_BIT (kRecordAAAA));
249  data.append (ENCODE_16_BIT (kIN_Normal));
250 
251  /* Send the datagram */
252  sendPacket (data);
253  }
254 }
255 
256 /**
257  * Changes the host name of the client computer
258  */
259 void qMDNS::setHostName (const QString& name) {
260  if (name.contains (".") && !name.endsWith (".local")) {
261  qWarning() << "Invalid domain name";
262  return;
263  }
264 
265  m_hostName = getAddress (name);
266 }
267 
268 /**
269  * Called when we receive data from a mDNS client on the network.
270  */
271 void qMDNS::onReadyRead() {
272  QByteArray data;
273  QUdpSocket* socket = qobject_cast<QUdpSocket*> (sender());
274 
275  /* Read data from the socket */
276  if (socket) {
277  while (socket->hasPendingDatagrams()) {
278  data.resize (socket->pendingDatagramSize());
279  socket->readDatagram (data.data(), data.size());
280  }
281  }
282 
283  /* Packet is a valid mDNS datagram */
284  if (data.length() > MIN_LENGTH) {
285  quint16 flag = DECODE_16_BIT (data.at (2), data.at (3));
286 
287  if (flag == kQR_Query)
288  readQuery (data);
289 
290  else if (flag >= kQR_Response)
291  readResponse (data);
292  }
293 }
294 
295 /**
296  * Reads the given query \a data and instructs the class to send a response
297  * packet if the query is looking for the host name assigned to this computer.
298  */
299 void qMDNS::readQuery (const QByteArray& data) {
300  /* Query packet is invalid */
301  if (data.length() < MIN_LENGTH)
302  return;
303 
304  /* Get the lengths of the host name and domain */
305  int n = 12;
306  int hostLength = data.at (n);
307  int domainLength = data.at (n + hostLength + 1);
308 
309  /* Read the host name until we stumble with the domain length character */
310  QString name;
311  int h = n + 1;
312  while (data.at (h) != (char) domainLength) {
313  name.append (data.at (h));
314  ++h;
315  }
316 
317  /* Read domain length until we stumble with the FQDN/TLD separator */
318  QString domain;
319  int d = n + hostLength + 2;
320  while (data.at (d) != kFQDN_Separator) {
321  domain.append (data.at (d));
322  ++d;
323  }
324 
325  /* Construct the full host name (name + domain) */
326  QString host = getAddress (name + "." + domain);
327 
328  /* The query packet wants to know more about us */
329  if (host.toLower() == hostName().toLower())
330  sendResponse (DECODE_16_BIT (data.at (0), data.at (1)));
331 }
332 
333 /**
334  * Sends the given \a data to both the IPv4 and IPv6 mDNS multicast groups
335  */
336 void qMDNS::sendPacket (const QByteArray& data) {
337  if (!data.isEmpty()) {
338  m_IPv4Socket->writeDatagram (data, IPV4_ADDRESS, MDNS_PORT);
339  m_IPv6Socket->writeDatagram (data, IPV6_ADDRESS, MDNS_PORT);
340  }
341 }
342 
343 /**
344  * Reads the given \a data of a response packet and obtains:
345  * - The remote host name
346  * - The remote IPv4
347  * - The remote IPv6
348  */
349 void qMDNS::readResponse (const QByteArray& data) {
350  if (data.length() < MIN_LENGTH)
351  return;
352 
353  qCDebug(KSTARS) << data;
354 
355  // data must contain service name
356  if (data.contains(m_serviceName.toLatin1()) == false)
357  return;
358 
359  QString host = getHostNameFromResponse (data);
360  QList<QHostAddress> addresses = getAddressesFromResponse (data, host);
361 
362  if (!host.isEmpty() && !addresses.isEmpty())
363  {
364  QHostInfo info;
365  info.setHostName (host);
366  info.setAddresses (addresses);
367  info.setError (QHostInfo::NoError);
368 
369  qCInfo(KSTARS) << "Found service on" << host;
370 
371  emit hostFound (info);
372  }
373 }
374 
375 /**
376  * Sends a response packet with:
377  * - Our mDNS host name
378  * - Our IPv4 address
379  * - Our IPv6 address
380  */
381 void qMDNS::sendResponse (const quint16 query_id) {
382  if (!hostName().isEmpty() && hostName().endsWith (".local")) {
383  QByteArray data;
384 
385  /* Get the host name and domain */
386  QString host = hostName().split (".").first();
387  QString domain = hostName().split (".").last();
388 
389  /* Get local IPs */
390  quint32 ipv4 = 0;
391  QList<QIPv6Address> ipv6;
392  foreach (QHostAddress address, QNetworkInterface::allAddresses()) {
393  if (!address.isLoopback()) {
394  if (address.protocol() == QAbstractSocket::IPv4Protocol)
395  ipv4 = (ipv4 == 0 ? address.toIPv4Address() : ipv4);
396 
397  if (address.protocol() == QAbstractSocket::IPv6Protocol)
398  ipv6.append (address.toIPv6Address());
399  }
400  }
401 
402  /* Check that domain length is valid */
403  if (host.length() > 255) {
404  qCWarning(KSTARS) << Q_FUNC_INFO << host << "is too long!";
405  return;
406  }
407 
408  /* Create header and flags */
409  data.append (ENCODE_16_BIT (query_id));
410  data.append (ENCODE_16_BIT (kQR_Response));
411  data.append (ENCODE_16_BIT (kResponse_QDCOUNT));
412  data.append (ENCODE_16_BIT (kResponse_ANCOUNT));
413  data.append (ENCODE_16_BIT (kResponse_NSCOUNT));
414  data.append (ENCODE_16_BIT (kResponse_ARCOUNT));
415 
416  /* Add name data */
417  data.append (host.length());
418  data.append (host.toUtf8());
419 
420  /* Add domain data and FQDN/TLD separator */
421  data.append (domain.length());
422  data.append (domain.toUtf8());
423  data.append ((char) kFQDN_Separator);
424 
425  /* Add IPv4 address header */
426  data.append (ENCODE_16_BIT (kRecordA));
427  data.append (ENCODE_16_BIT (kIN_BitFlush));
428  data.append (ENCODE_32_BIT (m_ttl));
429  data.append (ENCODE_16_BIT (sizeof (ipv4)));
430 
431  /* Add IPv4 bytes */
432  data.append (ENCODE_32_BIT (ipv4));
433 
434  /* Add FQDN offset */
435  data.append (ENCODE_16_BIT (kFQDN_Length));
436 
437  /* Add IPv6 addresses */
438  foreach (QIPv6Address ip, ipv6) {
439  data.append (ENCODE_16_BIT (kRecordAAAA));
440  data.append (ENCODE_16_BIT (kIN_BitFlush));
441  data.append (ENCODE_32_BIT (m_ttl));
442  data.append (ENCODE_16_BIT (sizeof (ip.c)));
443 
444  /* Add IPv6 bytes */
445  for (unsigned long i = 0; i < sizeof (ip.c); ++i)
446  data.append (ip.c [i]);
447 
448  /* Add FQDN offset */
449  data.append (ENCODE_16_BIT (kFQDN_Length));
450  }
451 
452  /* TODO: Generate NSEC code block */
453  int nsec_length = 0;
454 
455  /* Add NSEC data */
456  data.append (ENCODE_16_BIT (kNsecType));
457  data.append (ENCODE_16_BIT (kIN_BitFlush));
458  data.append (ENCODE_32_BIT (m_ttl));
459  data.append (ENCODE_16_BIT (nsec_length));
460 
461  /* Send the response */
462  sendPacket (data);
463  }
464 }
465 
466 /**
467  * Extracts the host name from the \a data received from the mDNS network.
468  * The host name begins at byte #12 (when the header and flags end) and ends
469  * with a mandatory NUL character after the domain.
470  *
471  * The host name is constructed in the following way (without spaces):
472  * \c NAME_LENGTH + \c NAME + \c DOMAIN_LENGTH + \c DOMAIN + \c NUL
473  *
474  * For example, appletv.local would be formatted as:
475  * \c 0x07 + \c appletv + \c 0x05 + \c local + \c 0x00
476  *
477  * Or, if you prefer hex data:
478  * \c { 07 61 70 70 6c 65 74 76 05 6c 6f 63 61 6c 00 }
479  * \c { 7 a p p l e t v 5 l o c a l 0 }
480  *
481  * In order to obtain the full host name (and its mDNS domain), we construct
482  * the string backwards. When the code notices that the current character is
483  * the same as the domain length, we know that the domain name has been
484  * extracted, and thus we can replace the domain length with a dot (.) and
485  * begin extracting the host name.
486  */
487 QString qMDNS::getHostNameFromResponse (const QByteArray& data) {
489  QString address = "";
490 
491  /* Begin reading host name at byte 13 (byte 12 is the host name length) */
492  int n = 13;
493 
494  /* Read the host name until we stumble with the FQDN/TLD separator */
495  while (data.at (n) != kFQDN_Separator) {
496  list.append (data.at (n));
497  ++n;
498  }
499 
500  /* Construct the string backwards (to replace domain length with a dot) */
501  for (int i = 0; i < list.count(); ++i) {
502  char character = list.at (list.count() - i - 1);
503 
504  if (character == (char) address.length())
505  address.prepend (".");
506  else
507  address.prepend (character);
508  }
509 
510  return address;
511 }
512 
513 /**
514  * Extracts the IPv4 from the \a data received from the mDNS network.
515  * The IPv4 data begins when the host name data ends.
516  *
517  * For the packet to contain IPv4 information, the DNS Record Type code must
518  * be "A" (IPv4) and the DNS Class code should correspond to "IN" (Internet).
519  *
520  * Here is the layout of the IPv4 section of the packet:
521  *
522  * - DNS Record Type
523  * - DNS Class Code
524  * - TTL
525  * - IP length
526  * - IP address bytes
527  *
528  * This is an example IPv4 section:
529  * \c {00 01 80 01 00 00 78 00 00 04 99 6d 07 5a}
530  *
531  * Data in example section:
532  * - \c {00 01} Type Codes
533  * - \c {80 01} Class Codes
534  * - \c {00 00 78 00} IP TTL
535  * - \c {00 04} Number of address bytes (length in layman's terms)
536  * - \c {99 6d 07 5a} IPv4 Address bytes (153, 109, 7, 90)
537  */
538 QString qMDNS::getIPv4FromResponse (const QByteArray& data,
539  const QString& host) {
540  QString ip = "";
541 
542  /* n stands for the byte index in which the host name data ends */
543  int n = MIN_LENGTH + host.length();
544 
545  /* Packet is too small */
546  if (data.length() < n + IP4_LENGTH)
547  return ip;
548 
549  /* Get the IP type and class codes */
550  quint16 typeCode = DECODE_16_BIT (data.at (n + 1), data.at (n + 2));
551  quint16 classCode = DECODE_16_BIT (data.at (n + 3), data.at (n + 4));
552 
553  /* Check if type and class codes are good */
554  if (typeCode != kRecordA || classCode != kIN_BitFlush)
555  return ip;
556 
557  /* Skip TTL indicator and obtain the number of address bytes */
558  quint8 length = data.at (n + IPI_LENGTH);
559 
560  /* Append each IPv4 address byte (and decimal dots) to the IP string */
561  for (int i = 1; i < length + 1; ++i) {
562  ip += QString::number ((quint8) data.at (n + IPI_LENGTH + i));
563  ip += (i < length) ? "." : "";
564  }
565 
566  return ip;
567 }
568 
569 /**
570  * Extracts the IPv6 from the \a data received from the mDNS network.
571  * The IPv6 data begins when the host name data ends.
572  *
573  * For the packet to contain IPv6 information, the DNS Record Type code must
574  * be "AAAA" (IPv6) and the DNS Class code should correspond to "IN" (Internet).
575  *
576  * Here is the layout of the IPv4 section of the packet:
577  *
578  * - DNS Record Type
579  * - DNS Class Code
580  * - TTL
581  * - IP length
582  * - IP address bytes
583  *
584  * This is an example IPv6 section:
585  * \c { 00 1c 80 01 00 00 78 00 00 10 fe 80 00 00 00 00 00 00 02 23 32 ff fe b1 21 52 }
586  *
587  * Data in example section:
588  * - \c {00 1c} Type Codes
589  * - \c {80 01} Class Codes
590  * - \c {00 00 78 00} IP TTL
591  * - \c {00 10} Number of address bytes (length in layman's terms)
592  * - \c {fe 80 00 00 ... 52} IPv6 Address bytes (there are 16 of them)
593  */
594 QStringList qMDNS::getIPv6FromResponse (const QByteArray& data,
595  const QString& host) {
597 
598  /* Skip the FQDN and IPv4 section */
599  int n = MIN_LENGTH + IP4_LENGTH + host.length();
600 
601  /* Get the IPv6 list */
602  bool isIPv6 = true;
603  while (isIPv6) {
604  /* Skip FQDN bytes */
605  n += 2;
606 
607  /* Packet is invalid */
608  if (data.length() < n + IP6_LENGTH)
609  break;
610 
611  /* Get the IP type and class codes */
612  quint16 typeCode = DECODE_16_BIT (data.at (n + 1), data.at (n + 2));
613  quint16 classCode = DECODE_16_BIT (data.at (n + 3), data.at (n + 4));
614  isIPv6 = (typeCode == kRecordAAAA && classCode == kIN_BitFlush);
615 
616  /* IP type and class codes are OK, extract IP */
617  if (isIPv6) {
618  /* Skip TTL indicator and obtain the number of address bytes */
619  quint8 length = data.at (n + IPI_LENGTH);
620 
621  /* Append each IPv6 address byte (encoded as hex) to the IP string */
622  QString ip = "";
623  for (int i = 1; i < length + 1; ++i) {
624  /* Get the hexadecimal representation of the byte */
625  QString byte;
626  byte.setNum ((quint8) data.at (n + i + IPI_LENGTH), 16);
627 
628  /* Add the obtained string */
629  ip += byte;
630 
631  /* Append colons after even indexes (except in the last byte) */
632  if ((i & 1) == 0 && (i < length))
633  ip += ":";
634  }
635 
636  /* Increase the counter to 'jump' to the next section */
637  n += 26;
638 
639  /* Append the obtained IP to the list */
640  if (!list.contains (ip))
641  list.append (ip);
642  }
643  }
644 
645  return list;
646 }
647 
648 /**
649  * Obtains the IPv4 and IPv6 addresses from the received data.
650  * \note This function will only generate a list with the valid IP addresses.
651  */
652 QList<QHostAddress> qMDNS::getAddressesFromResponse (const QByteArray& data,
653  const QString& host) {
655 
656  /* Add IPv4 address */
657  QHostAddress IPv4Address = QHostAddress (getIPv4FromResponse (data, host));
658  if (!IPv4Address.isNull())
659  list.append (IPv4Address);
660 
661  /* Add IPv6 addresses */
662  foreach (QString ip, getIPv6FromResponse (data, host)) {
664  if (!address.isNull())
665  list.append (address);
666  }
667 
668  return list;
669 }
void append(const T &value)
T & first()
qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port)
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool hasPendingDatagrams() const const
QString hostName() const
Returns the mDNS name assigned to the client computer.
Definition: qMDNS.cpp:153
QString number(int n, int base)
bool joinMulticastGroup(const QHostAddress &groupAddress)
static qMDNS * getInstance()
Returns the only running instance of this class.
Definition: qMDNS.cpp:145
CaseInsensitive
QByteArray & append(char ch)
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
int count(const T &value) const const
qint64 pendingDatagramSize() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QObject * sender() const const
QByteArray toLatin1() const const
QString getAddress(const QString &string)
Ensures that the given string is a valid mDNS/DNS address.
Definition: qMDNS.cpp:160
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
bool bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode)
Implements a simple mDNS responder using Qt.
Definition: qMDNS.h:29
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
char at(int i) const const
void lookup(const QString &name)
Performs a mDNS lookup to find the given host name.
Definition: qMDNS.cpp:185
void setHostName(const QString &name)
Changes the host name of the client computer.
Definition: qMDNS.cpp:259
QString & setNum(short n, int base)
bool isNull() const const
bool isEmpty() const const
QByteArray toUtf8() const const
int length() const const
const T & at(int i) const const
void readyRead()
bool isEmpty() const const
PostalAddress address(const QVariant &location)
int lookupHost(const QString &name, QObject *receiver, const char *member)
bool contains(char ch) const const
void setTTL(const quint32 ttl)
Changes the TTL send to other computers in the mDNS network.
Definition: qMDNS.cpp:175
T & last()
ScriptableExtension * host() const
bool isEmpty() const const
void resize(int size)
virtual bool setSocketDescriptor(qintptr socketDescriptor, QAbstractSocket::SocketState socketState, QIODevice::OpenMode openMode)
QString name(StandardShortcut id)
QList< QHostAddress > allAddresses()
int size() const const
int length() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString & append(QChar ch)
char * data()
virtual qintptr socketDescriptor() const const
qint64 writeDatagram(const QNetworkDatagram &datagram)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Aug 13 2022 04:01:58 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.