1 /*
2 * Copyright (C) 2017 Sergey Ilinykh
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 *
19 */
20
21 #include "irisnetplugin.h"
22
23 #include <QNetworkInterface>
24
25 namespace XMPP {
26
27 class IrisQtName : public NameProvider
28 {
29 Q_OBJECT
30 Q_INTERFACES(XMPP::NameProvider)
31
32 int currentId;
33 QHash<int,QDnsLookup*> lookups;
34
35 public:
IrisQtName(QObject * parent=0)36 IrisQtName(QObject *parent = 0) :
37 NameProvider(parent),
38 currentId(0)
39 {
40
41 }
42
~IrisQtName()43 ~IrisQtName()
44 {
45 qDeleteAll(lookups);
46 }
47
supportsSingle() const48 bool supportsSingle() const
49 {
50 return true;
51 }
52
supportsRecordType(int type) const53 bool supportsRecordType(int type) const
54 {
55 // yes the types matched to ones from jdns, so it's fine.
56 static QVector<int> types = {
57 QDnsLookup::A, QDnsLookup::AAAA, QDnsLookup::ANY,
58 QDnsLookup::CNAME, QDnsLookup::MX, QDnsLookup::NS,
59 QDnsLookup::PTR, QDnsLookup::SRV, QDnsLookup::TXT};
60 return types.contains(type);
61 }
62
resolve_start(const QByteArray & name,int qType,bool longLived)63 int resolve_start(const QByteArray &name, int qType, bool longLived)
64 {
65 Q_UNUSED(longLived); // FIXME handle local like in jdns name provider
66 int id = currentId++;
67
68 // check if it's A/AAAA. QDnsLookup fails to handle this in some cases.
69 QHostAddress addr(QString::fromLatin1(name));
70 if (!addr.isNull()) {
71 QList<XMPP::NameRecord> results;
72 XMPP::NameRecord r;
73 r.setAddress(addr);
74 results.append(r);
75 QMetaObject::invokeMethod(this, "resolve_resultsReady", Qt::QueuedConnection,
76 Q_ARG(int, id), Q_ARG(QList<XMPP::NameRecord>, results));
77 } else {
78 QDnsLookup *lookup = new QDnsLookup((QDnsLookup::Type)qType, QString::fromLatin1(name), this);
79 connect(lookup, SIGNAL(finished()), this, SLOT(handleLookup()));
80 lookup->setProperty("iid", id);
81 lookups.insert(id, lookup);
82 QMetaObject::invokeMethod(lookup, "lookup", Qt::QueuedConnection);
83 }
84 return id;
85 }
86
resolve_stop(int id)87 void resolve_stop(int id)
88 {
89 QDnsLookup *lookup = lookups.value(id);
90 if (lookup) {
91 lookup->abort(); // handleLookup will catch it and delete
92 }
93 }
94
95 private slots:
handleLookup()96 void handleLookup()
97 {
98 QDnsLookup *lookup = static_cast<QDnsLookup *>(sender());
99 int id = lookup->property("iid").toInt();
100 lookups.remove(id);
101 if (lookup->error() != QDnsLookup::NoError) {
102 XMPP::NameResolver::Error e;
103 switch (lookup->error()) {
104 case QDnsLookup::InvalidReplyError:
105 e = XMPP::NameResolver::ErrorTimeout;
106 break;
107 case QDnsLookup::NotFoundError:
108 e = XMPP::NameResolver::ErrorNoName;
109 break;
110 case QDnsLookup::ResolverError:
111 case QDnsLookup::OperationCancelledError:
112 case QDnsLookup::InvalidRequestError:
113 case QDnsLookup::ServerFailureError:
114 case QDnsLookup::ServerRefusedError:
115 default:
116 e = XMPP::NameResolver::ErrorGeneric;
117 break;
118 }
119 if (lookup->error() != QDnsLookup::OperationCancelledError) { // don't report after resolve_stop()
120 emit resolve_error(id, e);
121 }
122 lookup->deleteLater();
123 return;
124 }
125
126 QList<XMPP::NameRecord> results;
127 for (auto &qtr: lookup->hostAddressRecords()) {
128 XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
129 ir.setAddress(qtr.value());
130 results += ir;
131 }
132 for (auto &qtr: lookup->mailExchangeRecords()) {
133 XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
134 ir.setMx(qtr.exchange().toLatin1(), qtr.preference());
135 results += ir;
136 }
137 for (auto &qtr: lookup->nameServerRecords()) {
138 XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
139 ir.setNs(qtr.value().toLatin1());
140 results += ir;
141 }
142 for (auto &qtr: lookup->pointerRecords()) {
143 XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
144 ir.setPtr(qtr.value().toLatin1());
145 results += ir;
146 }
147 for (auto &qtr: lookup->canonicalNameRecords()) {
148 XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
149 ir.setCname(qtr.value().toLatin1());
150 results += ir;
151 }
152 for (auto &qtr: lookup->serviceRecords()) {
153 XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
154 ir.setSrv(qtr.target().toLatin1(),qtr.port(),qtr.priority(),qtr.weight());
155 results += ir;
156 }
157 for (auto &qtr: lookup->textRecords()) {
158 XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
159 ir.setTxt(qtr.values());
160 results += ir;
161 }
162 lookup->deleteLater();
163 emit resolve_resultsReady(id, results);
164 }
165 };
166
167 class IrisQtNameProvider : public IrisNetProvider
168 {
169 Q_OBJECT
170 Q_INTERFACES(XMPP::IrisNetProvider)
171 public:
172
createNameProviderInternet()173 NameProvider *createNameProviderInternet()
174 {
175 return new IrisQtName;
176 }
177 };
178
irisnet_createQtNameProvider()179 IrisNetProvider *irisnet_createQtNameProvider()
180 {
181 return new IrisQtNameProvider;
182 }
183
184 }
185
186 #include "netinterface_qtname.moc"
187