1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
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 General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QString> |
30 | #include <QtTest/QtTest> |
31 | #ifdef QT_NETWORK_LIB |
32 | #include <QtNetwork/QHostInfo> |
33 | #include <QtNetwork/QHostAddress> |
34 | #include <QtNetwork/QAbstractSocket> |
35 | #include <QtNetwork/QTcpSocket> |
36 | #endif |
37 | |
38 | #ifdef Q_OS_UNIX |
39 | #include <sys/types.h> |
40 | #include <sys/socket.h> |
41 | #include <netinet/in.h> |
42 | #include <unistd.h> |
43 | #endif |
44 | |
45 | class QtNetworkSettings |
46 | { |
47 | public: |
48 | |
49 | static QString serverLocalName() |
50 | { |
51 | return QString("qt-test-server" ); |
52 | } |
53 | static QString serverDomainName() |
54 | { |
55 | #ifdef QT_TEST_SERVER_DOMAIN |
56 | return QString(QT_TEST_SERVER_DOMAIN); // Defined in testserver feature |
57 | #else |
58 | return QString("qt-test-net" ); |
59 | #endif |
60 | } |
61 | static QString serverName() |
62 | { |
63 | return serverLocalName() + "." + serverDomainName(); |
64 | } |
65 | static QString winServerName() |
66 | { |
67 | return serverName(); |
68 | } |
69 | static QString wildcardServerName() |
70 | { |
71 | return "qt-test-server.wildcard.dev." + serverDomainName(); |
72 | } |
73 | |
74 | #ifdef QT_NETWORK_LIB |
75 | static QHostAddress getServerIpImpl(const QString &serverName) |
76 | { |
77 | const QHostInfo info = QHostInfo::fromName(name: serverName); |
78 | if (info.error()) { |
79 | QTest::qFail(qPrintable(info.errorString()), __FILE__, __LINE__); |
80 | return QHostAddress(); |
81 | } |
82 | return info.addresses().constFirst(); |
83 | } |
84 | |
85 | static QHostAddress serverIP() |
86 | { |
87 | return getServerIpImpl(serverName: serverName()); |
88 | } |
89 | #endif |
90 | |
91 | static bool compareReplyIMAP(QByteArray const& actual) |
92 | { |
93 | // Server greeting may contain capability, version and server name |
94 | // But spec only requires "* OK" and "\r\n" |
95 | // Match against a prefix and postfix that covers all Cyrus versions |
96 | if (actual.startsWith(c: "* OK " ) |
97 | && actual.endsWith(c: "server ready\r\n" )) { |
98 | return true; |
99 | } |
100 | |
101 | return false; |
102 | } |
103 | |
104 | static bool compareReplyIMAPSSL(QByteArray const& actual) |
105 | { |
106 | return compareReplyIMAP(actual); |
107 | } |
108 | |
109 | static bool compareReplyFtp(QByteArray const& actual) |
110 | { |
111 | // output would be e.g. "220 (vsFTPd 2.3.5)\r\n221 Goodbye.\r\n" |
112 | QRegularExpression ftpVersion(QRegularExpression::anchoredPattern(QStringLiteral("220 \\(vsFTPd \\d+\\.\\d+.\\d+\\)\\r\\n221 Goodbye.\\r\\n" ))); |
113 | return ftpVersion.match(subject: actual).hasMatch(); |
114 | } |
115 | |
116 | static bool hasIPv6() |
117 | { |
118 | #ifdef Q_OS_UNIX |
119 | int s = ::socket(AF_INET6, SOCK_DGRAM, protocol: 0); |
120 | if (s == -1) |
121 | return false; |
122 | else { |
123 | struct sockaddr_in6 addr; |
124 | memset(s: &addr, c: 0, n: sizeof(addr)); |
125 | addr.sin6_family = AF_INET6; |
126 | memcpy(dest: &addr.sin6_addr, src: &in6addr_loopback, n: sizeof(in6_addr)); |
127 | if (-1 == ::bind(fd: s, addr: (sockaddr*)&addr, len: sizeof(addr))) { |
128 | ::close(fd: s); |
129 | return false; |
130 | } |
131 | } |
132 | ::close(fd: s); |
133 | #endif |
134 | return true; |
135 | } |
136 | |
137 | static bool canBindToLowPorts() |
138 | { |
139 | #ifdef Q_OS_UNIX |
140 | if (geteuid() == 0) |
141 | return true; |
142 | if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) |
143 | return true; |
144 | // ### Which versions of iOS, watchOS and such does Apple's opening of |
145 | // all ports apply to? |
146 | return false; |
147 | #else |
148 | // Windows |
149 | return true; |
150 | #endif |
151 | } |
152 | |
153 | |
154 | #ifdef QT_NETWORK_LIB |
155 | static bool verifyTestNetworkSettings() |
156 | { |
157 | QHostInfo testServerResult = QHostInfo::fromName(name: QtNetworkSettings::serverName()); |
158 | if (testServerResult.error() != QHostInfo::NoError) { |
159 | qWarning() << "Could not lookup" << QtNetworkSettings::serverName(); |
160 | qWarning() << "Please configure the test environment!" ; |
161 | qWarning() << "See /etc/hosts or network-settings.h" ; |
162 | return false; |
163 | } |
164 | return true; |
165 | } |
166 | |
167 | static bool verifyConnection(QString serverName, quint16 port, quint32 retry = 60) |
168 | { |
169 | QTcpSocket socket; |
170 | for (quint32 i = 1; i < retry; i++) { |
171 | socket.connectToHost(hostName: serverName, port); |
172 | if (socket.waitForConnected(msecs: 1000)) |
173 | return true; |
174 | // Wait for service to start up |
175 | QTest::qWait(ms: 1000); |
176 | } |
177 | socket.connectToHost(hostName: serverName, port); |
178 | return socket.waitForConnected(msecs: 1000); |
179 | } |
180 | |
181 | // Helper function for usage with QVERIFY2 on sockets. |
182 | static QByteArray msgSocketError(const QAbstractSocket &s) |
183 | { |
184 | QString result; |
185 | QDebug debug(&result); |
186 | debug.nospace(); |
187 | debug.noquote(); |
188 | if (!s.localAddress().isNull()) |
189 | debug << "local=" << s.localAddress().toString() << ':' << s.localPort(); |
190 | if (!s.peerAddress().isNull()) |
191 | debug << ", peer=" << s.peerAddress().toString() << ':' << s.peerPort(); |
192 | debug << ", type=" << s.socketType() << ", state=" << s.state() |
193 | << ", error=" << s.error() << ": " << s.errorString(); |
194 | return result.toLocal8Bit(); |
195 | } |
196 | #endif // QT_NETWORK_LIB |
197 | |
198 | static QString ftpServerName() |
199 | { |
200 | #ifdef QT_TEST_SERVER_NAME |
201 | return QString("vsftpd." ) % serverDomainName(); |
202 | #else |
203 | return serverName(); |
204 | #endif |
205 | } |
206 | static QString ftpProxyServerName() |
207 | { |
208 | #ifdef QT_TEST_SERVER_NAME |
209 | return QString("ftp-proxy." ) % serverDomainName(); |
210 | #else |
211 | return serverName(); |
212 | #endif |
213 | } |
214 | static QString httpServerName() |
215 | { |
216 | #ifdef QT_TEST_SERVER_NAME |
217 | return QString("apache2." ) % serverDomainName(); |
218 | #else |
219 | return serverName(); |
220 | #endif |
221 | } |
222 | static QString httpProxyServerName() |
223 | { |
224 | #ifdef QT_TEST_SERVER_NAME |
225 | return QString("squid." ) % serverDomainName(); |
226 | #else |
227 | return serverName(); |
228 | #endif |
229 | } |
230 | static QString socksProxyServerName() |
231 | { |
232 | #ifdef QT_TEST_SERVER_NAME |
233 | return QString("danted." ) % serverDomainName(); |
234 | #else |
235 | return serverName(); |
236 | #endif |
237 | } |
238 | static QString imapServerName() |
239 | { |
240 | #ifdef QT_TEST_SERVER_NAME |
241 | return QString("cyrus." ) % serverDomainName(); |
242 | #else |
243 | return serverName(); |
244 | #endif |
245 | } |
246 | |
247 | static QString echoServerName() |
248 | { |
249 | #ifdef QT_TEST_SERVER_NAME |
250 | return QString("echo." ) % serverDomainName(); |
251 | #else |
252 | return serverName(); |
253 | #endif |
254 | } |
255 | |
256 | static QString firewallServerName() |
257 | { |
258 | #ifdef QT_TEST_SERVER_NAME |
259 | return QString("iptables." ) % serverDomainName(); |
260 | #else |
261 | return serverName(); |
262 | #endif |
263 | } |
264 | |
265 | static QString hostWithServiceOnPort(int port) |
266 | { |
267 | #if !defined(QT_TEST_SERVER) |
268 | Q_UNUSED(port); |
269 | return serverName(); |
270 | #else |
271 | switch (port) { |
272 | case 13: |
273 | case 22: |
274 | case 139: |
275 | return serverName(); // No such things in docker (yet?) |
276 | case 7: |
277 | return echoServerName(); |
278 | case 21: |
279 | return ftpServerName(); |
280 | case 80: |
281 | case 443: |
282 | return httpServerName(); |
283 | case 143: |
284 | return imapServerName(); |
285 | case 3128: |
286 | case 3129: |
287 | case 3130: |
288 | return httpProxyServerName(); |
289 | case 1080: |
290 | case 1081: |
291 | return socksProxyServerName(); |
292 | case 2121: |
293 | return ftpProxyServerName(); |
294 | default: |
295 | return serverName(); |
296 | } |
297 | #endif // QT_TEST_SERVER |
298 | } |
299 | |
300 | #ifdef QT_NETWORK_LIB |
301 | static QHostAddress imapServerIp() |
302 | { |
303 | return getServerIpImpl(serverName: imapServerName()); |
304 | } |
305 | |
306 | static QHostAddress httpServerIp() |
307 | { |
308 | return getServerIpImpl(serverName: httpServerName()); |
309 | } |
310 | |
311 | static QHostAddress httpProxyServerIp() |
312 | { |
313 | return getServerIpImpl(serverName: httpProxyServerName()); |
314 | } |
315 | |
316 | static QHostAddress socksProxyServerIp() |
317 | { |
318 | return getServerIpImpl(serverName: socksProxyServerName()); |
319 | } |
320 | |
321 | static QHostAddress ftpProxyServerIp() |
322 | { |
323 | return getServerIpImpl(serverName: ftpProxyServerName()); |
324 | } |
325 | |
326 | static QHostAddress ftpServerIp() |
327 | { |
328 | return getServerIpImpl(serverName: ftpServerName()); |
329 | } |
330 | |
331 | static QHostAddress firewallServerIp() |
332 | { |
333 | return getServerIpImpl(serverName: firewallServerName()); |
334 | } |
335 | |
336 | #endif // QT_NETWORK_LIB |
337 | }; |
338 | |