10#include <QHostAddress>
11#include <QNetworkInterface>
14#include <sys/socket.h>
17#include "kstars_debug.h"
21const quint16 MDNS_PORT = 5353;
28const quint16 kQR_Query = 0x0000;
29const quint16 kQR_Response = 0x8000;
30const quint16 kRecordA = 0x0001;
31const quint16 kRecordAAAA = 0x001C;
32const quint16 kNsecType = 0x002F;
33const quint16 kFQDN_Separator = 0x0000;
34const quint16 kFQDN_Length = 0xC00C;
35const quint16 kIN_BitFlush = 0x8001;
36const quint16 kIN_Normal = 0x0001;
41const quint16 kQuery_QDCOUNT = 0x02;
42const quint16 kQuery_ANCOUNT = 0x00;
43const quint16 kQuery_NSCOUNT = 0x00;
44const quint16 kQuery_ARCOUNT = 0x00;
49const quint16 kResponse_QDCOUNT = 0x00;
50const quint16 kResponse_ANCOUNT = 0x01;
51const quint16 kResponse_NSCOUNT = 0x00;
52const quint16 kResponse_ARCOUNT = 0x02;
55const int MIN_LENGTH = 13;
56const int IPI_LENGTH = 10;
57const int IP4_LENGTH = IPI_LENGTH + 4;
58const int IP6_LENGTH = IPI_LENGTH + 16;
66 data.
append ((number & 0xff00) >> 8);
67 data.
append ((number & 0xff));
77 data.
append ((number & 0xff000000UL) >> 24);
78 data.
append ((number & 0x00ff0000UL) >> 16);
79 data.
append ((number & 0x0000ff00UL) >> 8);
80 data.
append ((number & 0x000000ffUL));
87quint16 DECODE_16_BIT (quint8 upper, quint8 lower)
89 return (quint16) ((upper << 8) | lower);
103 int domain = PF_UNSPEC;
114 &reuse, sizeof (reuse));
117 return socket->
bind (address, port,
153 static qMDNS instance;
172 if (!
string.endsWith (
".local") && !
string.contains (
"."))
173 address =
string +
".local";
175 if (
string.endsWith (
"."))
200 qCWarning(KSTARS) << Q_FUNC_INFO <<
"Empty host name specified";
204 qCInfo(KSTARS) <<
"Starting lookup for service" << name;
206 m_serviceName = name;
226 QString host = address.split (
".").first();
227 QString domain = address.split (
".").last();
232 qWarning() << Q_FUNC_INFO << host <<
"is too long!";
237 data.
append (ENCODE_16_BIT (0));
238 data.
append (ENCODE_16_BIT (kQR_Query));
239 data.
append (ENCODE_16_BIT (kQuery_QDCOUNT));
240 data.
append (ENCODE_16_BIT (kQuery_ANCOUNT));
241 data.
append (ENCODE_16_BIT (kQuery_NSCOUNT));
242 data.
append (ENCODE_16_BIT (kQuery_ARCOUNT));
253 data.
append ((
char) kFQDN_Separator);
256 data.
append (ENCODE_16_BIT (kRecordA));
257 data.
append (ENCODE_16_BIT (kIN_Normal));
260 data.
append (ENCODE_16_BIT (kFQDN_Length));
263 data.
append (ENCODE_16_BIT (kRecordAAAA));
264 data.
append (ENCODE_16_BIT (kIN_Normal));
278 qWarning() <<
"Invalid domain name";
288void qMDNS::onReadyRead()
304 if (data.
length() > MIN_LENGTH)
306 quint16 flag = DECODE_16_BIT (data.
at (2), data.
at (3));
308 if (flag == kQR_Query)
311 else if (flag >= kQR_Response)
323 if (data.
length() < MIN_LENGTH)
328 int hostLength = data.
at (n);
329 int domainLength = data.
at (n + hostLength + 1);
334 while (data.
at (h) != (
char) domainLength)
342 int d = n + hostLength + 2;
343 while (data.
at (d) != kFQDN_Separator)
354 sendResponse (DECODE_16_BIT (data.
at (0), data.
at (1)));
360void qMDNS::sendPacket (
const QByteArray &data)
375void qMDNS::readResponse (
const QByteArray &data)
377 if (data.
length() < MIN_LENGTH)
380 qCDebug(KSTARS) << data;
386 QString host = getHostNameFromResponse (data);
392 info.setHostName (host);
393 info.setAddresses (addresses);
396 qCInfo(KSTARS) <<
"Found service on" << host;
398 emit hostFound (info);
408void qMDNS::sendResponse (
const quint16 query_id)
426 ipv4 = (ipv4 == 0 ?
address.toIPv4Address() : ipv4);
436 qCWarning(KSTARS) << Q_FUNC_INFO << host <<
"is too long!";
441 data.
append (ENCODE_16_BIT (query_id));
442 data.
append (ENCODE_16_BIT (kQR_Response));
443 data.
append (ENCODE_16_BIT (kResponse_QDCOUNT));
444 data.
append (ENCODE_16_BIT (kResponse_ANCOUNT));
445 data.
append (ENCODE_16_BIT (kResponse_NSCOUNT));
446 data.
append (ENCODE_16_BIT (kResponse_ARCOUNT));
455 data.
append ((
char) kFQDN_Separator);
458 data.
append (ENCODE_16_BIT (kRecordA));
459 data.
append (ENCODE_16_BIT (kIN_BitFlush));
460 data.
append (ENCODE_32_BIT (m_ttl));
461 data.
append (ENCODE_16_BIT (
sizeof (ipv4)));
464 data.
append (ENCODE_32_BIT (ipv4));
467 data.
append (ENCODE_16_BIT (kFQDN_Length));
470 foreach (QIPv6Address ip, ipv6)
472 data.
append (ENCODE_16_BIT (kRecordAAAA));
473 data.
append (ENCODE_16_BIT (kIN_BitFlush));
474 data.
append (ENCODE_32_BIT (m_ttl));
475 data.
append (ENCODE_16_BIT (
sizeof (ip.c)));
478 for (
unsigned long i = 0; i <
sizeof (ip.c); ++i)
482 data.
append (ENCODE_16_BIT (kFQDN_Length));
489 data.
append (ENCODE_16_BIT (kNsecType));
490 data.
append (ENCODE_16_BIT (kIN_BitFlush));
491 data.
append (ENCODE_32_BIT (m_ttl));
492 data.
append (ENCODE_16_BIT (nsec_length));
529 while (data.
at (n) != kFQDN_Separator)
540 if (character == (
char)
address.length())
580 int n = MIN_LENGTH + host.
length();
583 if (data.
length() < n + IP4_LENGTH)
587 quint16 typeCode = DECODE_16_BIT (data.
at (n + 1), data.
at (n + 2));
588 quint16 classCode = DECODE_16_BIT (data.
at (n + 3), data.
at (n + 4));
591 if (typeCode != kRecordA || classCode != kIN_BitFlush)
595 quint8 length = data.
at (n + IPI_LENGTH);
598 for (
int i = 1; i < length + 1; ++i)
601 ip += (i < length) ?
"." :
"";
638 int n = MIN_LENGTH + IP4_LENGTH + host.
length();
648 if (data.
length() < n + IP6_LENGTH)
652 quint16 typeCode = DECODE_16_BIT (data.
at (n + 1), data.
at (n + 2));
653 quint16 classCode = DECODE_16_BIT (data.
at (n + 3), data.
at (n + 4));
654 isIPv6 = (typeCode == kRecordAAAA && classCode == kIN_BitFlush);
660 quint8 length = data.
at (n + IPI_LENGTH);
664 for (
int i = 1; i < length + 1; ++i)
668 byte.
setNum ((quint8) data.
at (n + i + IPI_LENGTH), 16);
674 if ((i & 1) == 0 && (i < length))
701 if (!IPv4Address.
isNull())
705 foreach (
QString ip, getIPv6FromResponse (data, host))
Implements a simple mDNS responder using Qt.
void lookup(const QString &name)
Performs a mDNS lookup to find the given host name.
void setTTL(const quint32 ttl)
Changes the TTL send to other computers in the mDNS network.
void setHostName(const QString &name)
Changes the host name of the client computer.
static qMDNS * getInstance()
Returns the only running instance of this class.
QString hostName() const
Returns the mDNS name assigned to the client computer.
QString getAddress(const QString &string)
Ensures that the given string is a valid mDNS/DNS address.
PostalAddress address(const QVariant &location)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardAction id)
bool bind(QHostAddress::SpecialAddress addr, quint16 port, BindMode mode)
virtual bool setSocketDescriptor(qintptr socketDescriptor, SocketState socketState, OpenMode openMode)
virtual qintptr socketDescriptor() const const
QByteArray & append(QByteArrayView data)
char at(qsizetype i) const const
bool contains(QByteArrayView bv) const const
bool isEmpty() const const
qsizetype length() const const
void resize(qsizetype newSize, char c)
qsizetype size() const const
bool isNull() const const
int lookupHost(const QString &name, Functor &&functor)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype count() const const
bool isEmpty() const const
QList< QHostAddress > allAddresses()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QObject * sender() const const
QString & append(QChar ch)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString & setNum(double n, char format, int precision)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
QString toLower() const const
QByteArray toUtf8() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
bool hasPendingDatagrams() const const
bool joinMulticastGroup(const QHostAddress &groupAddress)
qint64 pendingDatagramSize() const const
qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port)
qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)