1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QHOSTINFO_P_H
41 #define QHOSTINFO_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists for the convenience
48 // of the QHostInfo class.  This header file may change from
49 // version to version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtNetwork/private/qtnetworkglobal_p.h>
55 #include "QtCore/qcoreapplication.h"
56 #include "private/qcoreapplication_p.h"
57 #include "private/qmetaobject_p.h"
58 #include "QtNetwork/qhostinfo.h"
59 #include "QtCore/qmutex.h"
60 #include "QtCore/qwaitcondition.h"
61 #include "QtCore/qobject.h"
62 #include "QtCore/qpointer.h"
63 #include "QtCore/qthread.h"
64 #if QT_CONFIG(thread)
65 #include "QtCore/qthreadpool.h"
66 #endif
67 #include "QtCore/qrunnable.h"
68 #include "QtCore/qlist.h"
69 #include "QtCore/qqueue.h"
70 #include <QElapsedTimer>
71 #include <QCache>
72 
73 #include <QNetworkSession>
74 #include <QSharedPointer>
75 
76 #include <atomic>
77 
78 QT_BEGIN_NAMESPACE
79 
80 
81 class QHostInfoResult : public QObject
82 {
83     Q_OBJECT
84 public:
QHostInfoResult(const QObject * receiver,QtPrivate::QSlotObjectBase * slotObj)85     QHostInfoResult(const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
86         : receiver(receiver), slotObj(slotObj),
87           withContextObject(slotObj && receiver)
88     {
89         if (receiver)
90             moveToThread(receiver->thread());
91     }
92 
93     void postResultsReady(const QHostInfo &info);
94 
95 Q_SIGNALS:
96     void resultsReady(const QHostInfo &info);
97 
98 protected:
99     bool event(QEvent *event) override;
100 
101 private:
QHostInfoResult(const QHostInfoResult * other)102     QHostInfoResult(const QHostInfoResult *other)
103         : receiver(other->receiver), slotObj(other->slotObj),
104           withContextObject(other->withContextObject)
105     {
106         // cleanup if the application terminates before results are delivered
107         connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
108                 this, &QObject::deleteLater);
109         // maintain thread affinity
110         moveToThread(other->thread());
111     }
112 
113     QPointer<const QObject> receiver = nullptr;
114     QtPrivate::QSlotObjectBase *slotObj = nullptr;
115     const bool withContextObject = false;
116 };
117 
118 class QHostInfoAgent
119 {
120 public:
121     static QHostInfo fromName(const QString &hostName);
122 private:
123     static QHostInfo lookup(const QString &hostName);
124     static QHostInfo reverseLookup(const QHostAddress &address);
125 };
126 
127 class QHostInfoPrivate
128 {
129 public:
QHostInfoPrivate()130     inline QHostInfoPrivate()
131         : err(QHostInfo::NoError),
132           errorStr(QLatin1String(QT_TRANSLATE_NOOP("QHostInfo", "Unknown error"))),
133           lookupId(0)
134     {
135     }
136     static int lookupHostImpl(const QString &name,
137                               const QObject *receiver,
138                               QtPrivate::QSlotObjectBase *slotObj,
139                               const char *member);
140 
141     QHostInfo::HostInfoError err;
142     QString errorStr;
143     QList<QHostAddress> addrs;
144     QString hostName;
145     int lookupId;
146 };
147 
148 // These functions are outside of the QHostInfo class and strictly internal.
149 // Do NOT use them outside of QAbstractSocket.
150 QHostInfo Q_NETWORK_EXPORT qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id);
151 void Q_AUTOTEST_EXPORT qt_qhostinfo_clear_cache();
152 void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e);
153 void Q_AUTOTEST_EXPORT qt_qhostinfo_cache_inject(const QString &hostname, const QHostInfo &resolution);
154 
155 class QHostInfoCache
156 {
157 public:
158     QHostInfoCache();
159     const int max_age; // seconds
160 
161     QHostInfo get(const QString &name, bool *valid);
162     void put(const QString &name, const QHostInfo &info);
163     void clear();
164 
isEnabled()165     bool isEnabled() { return enabled.load(std::memory_order_relaxed); }
166     // this function is currently only used for the auto tests
167     // and not usable by public API
setEnabled(bool e)168     void setEnabled(bool e) { enabled.store(e, std::memory_order_relaxed); }
169 private:
170     std::atomic<bool> enabled;
171     struct QHostInfoCacheElement {
172         QHostInfo info;
173         QElapsedTimer age;
174     };
175     QCache<QString,QHostInfoCacheElement> cache;
176     QMutex mutex;
177 };
178 
179 // the following classes are used for the (normal) case: We use multiple threads to lookup DNS
180 
181 class QHostInfoRunnable : public QRunnable
182 {
183 public:
184     QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
185                       QtPrivate::QSlotObjectBase *slotObj);
186     void run() override;
187 
188     QString toBeLookedUp;
189     int id;
190     QHostInfoResult resultEmitter;
191 };
192 
193 
194 class QHostInfoLookupManager
195 {
196 public:
197     QHostInfoLookupManager();
198     ~QHostInfoLookupManager();
199 
200     void clear();
201 
202     // called from QHostInfo
203     void scheduleLookup(QHostInfoRunnable *r);
204     void abortLookup(int id);
205 
206     // called from QHostInfoRunnable
207     void lookupFinished(QHostInfoRunnable *r);
208     bool wasAborted(int id);
209 
210     QHostInfoCache cache;
211 
212     friend class QHostInfoRunnable;
213 protected:
214 #if QT_CONFIG(thread)
215     QList<QHostInfoRunnable*> currentLookups; // in progress
216     QList<QHostInfoRunnable*> postponedLookups; // postponed because in progress for same host
217 #endif
218     QQueue<QHostInfoRunnable*> scheduledLookups; // not yet started
219     QList<QHostInfoRunnable*> finishedLookups; // recently finished
220     QList<int> abortedLookups; // ids of aborted lookups
221 
222 #if QT_CONFIG(thread)
223     QThreadPool threadPool;
224 #endif
225     QMutex mutex;
226 
227     bool wasDeleted;
228 
229 private:
230     void rescheduleWithMutexHeld();
231 };
232 
233 QT_END_NAMESPACE
234 
235 #endif // QHOSTINFO_P_H
236