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#include "qsocks5socketengine_p.h"
41
42#include "qtcpsocket.h"
43#include "qudpsocket.h"
44#include "qtcpserver.h"
45#include "qdebug.h"
46#include "qhash.h"
47#include "qqueue.h"
48#include "qelapsedtimer.h"
49#include "qmutex.h"
50#include "qthread.h"
51#include "qcoreapplication.h"
52#include "qurl.h"
53#include "qauthenticator.h"
54#include "private/qiodevice_p.h"
55#include "private/qringbuffer_p.h"
56#include <qendian.h>
57#include <qnetworkinterface.h>
58
59QT_BEGIN_NAMESPACE
60
61static const int MaxWriteBufferSize = 128*1024;
62
63//#define QSOCKS5SOCKETLAYER_DEBUG
64
65#define MAX_DATA_DUMP 256
66#define SOCKS5_BLOCKING_BIND_TIMEOUT 5000
67
68#define Q_INIT_CHECK(returnValue) do { \
69 if (!d->data) { \
70 return returnValue; \
71 } } while (0)
72
73#define S5_VERSION_5 0x05
74#define S5_CONNECT 0x01
75#define S5_BIND 0x02
76#define S5_UDP_ASSOCIATE 0x03
77#define S5_IP_V4 0x01
78#define S5_DOMAINNAME 0x03
79#define S5_IP_V6 0x04
80#define S5_SUCCESS 0x00
81#define S5_R_ERROR_SOCKS_FAILURE 0x01
82#define S5_R_ERROR_CON_NOT_ALLOWED 0x02
83#define S5_R_ERROR_NET_UNREACH 0x03
84#define S5_R_ERROR_HOST_UNREACH 0x04
85#define S5_R_ERROR_CONN_REFUSED 0x05
86#define S5_R_ERROR_TTL 0x06
87#define S5_R_ERROR_CMD_NOT_SUPPORTED 0x07
88#define S5_R_ERROR_ADD_TYPE_NOT_SUPORTED 0x08
89
90#define S5_AUTHMETHOD_NONE 0x00
91#define S5_AUTHMETHOD_PASSWORD 0x02
92#define S5_AUTHMETHOD_NOTACCEPTABLE 0xFF
93
94#define S5_PASSWORDAUTH_VERSION 0x01
95
96#ifdef QSOCKS5SOCKETLAYER_DEBUG
97# define QSOCKS5_Q_DEBUG qDebug() << this
98# define QSOCKS5_D_DEBUG qDebug() << q_ptr
99# define QSOCKS5_DEBUG qDebug() << "[QSocks5]"
100static QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State s)
101{
102 switch (s) {
103 case QSocks5SocketEnginePrivate::Uninitialized: return QLatin1String("Uninitialized");
104 case QSocks5SocketEnginePrivate::ConnectError: return QLatin1String("ConnectError");
105 case QSocks5SocketEnginePrivate::AuthenticationMethodsSent: return QLatin1String("AuthenticationMethodsSent");
106 case QSocks5SocketEnginePrivate::Authenticating: return QLatin1String("Authenticating");
107 case QSocks5SocketEnginePrivate::AuthenticatingError: return QLatin1String("AuthenticatingError");
108 case QSocks5SocketEnginePrivate::RequestMethodSent: return QLatin1String("RequestMethodSent");
109 case QSocks5SocketEnginePrivate::RequestError: return QLatin1String("RequestError");
110 case QSocks5SocketEnginePrivate::Connected: return QLatin1String("Connected");
111 case QSocks5SocketEnginePrivate::UdpAssociateSuccess: return QLatin1String("UdpAssociateSuccess");
112 case QSocks5SocketEnginePrivate::BindSuccess: return QLatin1String("BindSuccess");
113 case QSocks5SocketEnginePrivate::ControlSocketError: return QLatin1String("ControlSocketError");
114 case QSocks5SocketEnginePrivate::SocksError: return QLatin1String("SocksError");
115 case QSocks5SocketEnginePrivate::HostNameLookupError: return QLatin1String("HostNameLookupError");
116 default: break;
117 }
118 return QLatin1String("unknown state");
119}
120
121static QString dump(const QByteArray &buf)
122{
123 QString data;
124 for (int i = 0; i < qMin<int>(MAX_DATA_DUMP, buf.size()); ++i) {
125 if (i) data += QLatin1Char(' ');
126 uint val = (unsigned char)buf.at(i);
127 // data += QString("0x%1").arg(val, 3, 16, QLatin1Char('0'));
128 data += QString::number(val);
129 }
130 if (buf.size() > MAX_DATA_DUMP)
131 data += QLatin1String(" ...");
132
133 return QString::fromLatin1("size: %1 data: { %2 }").arg(buf.size()).arg(data);
134}
135
136#else
137# define QSOCKS5_DEBUG if (0) qDebug()
138# define QSOCKS5_Q_DEBUG if (0) qDebug()
139# define QSOCKS5_D_DEBUG if (0) qDebug()
140
141static inline QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State) { return QString(); }
142static inline QString dump(const QByteArray &) { return QString(); }
143#endif
144
145/*
146 inserts the host address in buf at pos and updates pos.
147 if the func fails the data in buf and the vallue of pos is undefined
148*/
149static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf)
150{
151 QSOCKS5_DEBUG << "setting [" << address << ':' << port << ']';
152
153 union {
154 quint16 port;
155 quint32 ipv4;
156 QIPv6Address ipv6;
157 char ptr;
158 } data;
159
160 // add address
161 if (address.protocol() == QAbstractSocket::IPv4Protocol) {
162 data.ipv4 = qToBigEndian<quint32>(address.toIPv4Address());
163 pBuf->append(S5_IP_V4);
164 pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.ipv4));
165 } else if (address.protocol() == QAbstractSocket::IPv6Protocol) {
166 data.ipv6 = address.toIPv6Address();
167 pBuf->append(S5_IP_V6);
168 pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.ipv6));
169 } else {
170 return false;
171 }
172
173 // add port
174 data.port = qToBigEndian<quint16>(port);
175 pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.port));
176 return true;
177}
178
179/*
180 like above, but for a hostname
181*/
182static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 port, QByteArray *pBuf)
183{
184 QSOCKS5_DEBUG << "setting [" << hostname << ':' << port << ']';
185
186 QByteArray encodedHostName = QUrl::toAce(hostname);
187 QByteArray &buf = *pBuf;
188
189 if (encodedHostName.length() > 255)
190 return false;
191
192 buf.append(S5_DOMAINNAME);
193 buf.append(uchar(encodedHostName.length()));
194 buf.append(encodedHostName);
195
196 // add port
197 union {
198 quint16 port;
199 char ptr;
200 } data;
201 data.port = qToBigEndian<quint16>(port);
202 buf.append(QByteArray::fromRawData(&data.ptr, sizeof data.port));
203
204 return true;
205}
206
207
208/*
209 retrives the host address in buf at pos and updates pos.
210 return 1 if OK, 0 if need more data, -1 if error
211 if the func fails the value of the address and the pos is undefined
212*/
213static int qt_socks5_get_host_address_and_port(const QByteArray &buf, QHostAddress *pAddress, quint16 *pPort, int *pPos)
214{
215 int ret = -1;
216 int pos = *pPos;
217 const unsigned char *pBuf = reinterpret_cast<const unsigned char*>(buf.constData());
218 QHostAddress address;
219 quint16 port = 0;
220
221 if (buf.size() - pos < 1) {
222 QSOCKS5_DEBUG << "need more data address/port";
223 return 0;
224 }
225 if (pBuf[pos] == S5_IP_V4) {
226 pos++;
227 if (buf.size() - pos < 4) {
228 QSOCKS5_DEBUG << "need more data for ip4 address";
229 return 0;
230 }
231 address.setAddress(qFromBigEndian<quint32>(&pBuf[pos]));
232 pos += 4;
233 ret = 1;
234 } else if (pBuf[pos] == S5_IP_V6) {
235 pos++;
236 if (buf.size() - pos < 16) {
237 QSOCKS5_DEBUG << "need more data for ip6 address";
238 return 0;
239 }
240 QIPv6Address add;
241 for (int i = 0; i < 16; ++i)
242 add[i] = buf[pos++];
243 address.setAddress(add);
244 ret = 1;
245 } else if (pBuf[pos] == S5_DOMAINNAME){
246 // just skip it
247 pos++;
248 qDebug() << "skipping hostname of len" << uint(pBuf[pos]);
249 pos += uchar(pBuf[pos]);
250 } else {
251 QSOCKS5_DEBUG << "invalid address type" << (int)pBuf[pos];
252 ret = -1;
253 }
254
255 if (ret == 1) {
256 if (buf.size() - pos < 2) {
257 QSOCKS5_DEBUG << "need more data for port";
258 return 0;
259 }
260 port = qFromBigEndian<quint16>(&pBuf[pos]);
261 pos += 2;
262 }
263
264 if (ret == 1) {
265 QSOCKS5_DEBUG << "got [" << address << ':' << port << ']';
266 *pAddress = address;
267 *pPort = port;
268 *pPos = pos;
269 }
270
271 return ret;
272}
273
274struct QSocks5Data
275{
276 QTcpSocket *controlSocket;
277 QSocks5Authenticator *authenticator;
278};
279
280struct QSocks5ConnectData : public QSocks5Data
281{
282 QRingBuffer readBuffer;
283};
284
285struct QSocks5BindData : public QSocks5Data
286{
287 QHostAddress localAddress;
288 quint16 localPort;
289 QHostAddress peerAddress;
290 quint16 peerPort;
291 QElapsedTimer timeStamp;
292};
293
294struct QSocks5RevivedDatagram
295{
296 QByteArray data;
297 QHostAddress address;
298 quint16 port;
299};
300
301#ifndef QT_NO_UDPSOCKET
302struct QSocks5UdpAssociateData : public QSocks5Data
303{
304 QUdpSocket *udpSocket;
305 QHostAddress associateAddress;
306 quint16 associatePort;
307 QQueue<QSocks5RevivedDatagram> pendingDatagrams;
308};
309#endif
310
311// needs to be thread safe
312class QSocks5BindStore : public QObject
313{
314public:
315 QSocks5BindStore();
316 ~QSocks5BindStore();
317
318 void add(qintptr socketDescriptor, QSocks5BindData *bindData);
319 bool contains(qintptr socketDescriptor);
320 QSocks5BindData *retrieve(qintptr socketDescriptor);
321
322protected:
323 void timerEvent(QTimerEvent * event) override;
324
325 QRecursiveMutex mutex;
326 int sweepTimerId = -1;
327 //socket descriptor, data, timestamp
328 QHash<int, QSocks5BindData *> store;
329};
330
331Q_GLOBAL_STATIC(QSocks5BindStore, socks5BindStore)
332
333QSocks5BindStore::QSocks5BindStore()
334{
335 QCoreApplication *app = QCoreApplication::instance();
336 if (app && app->thread() != thread())
337 moveToThread(app->thread());
338}
339
340QSocks5BindStore::~QSocks5BindStore()
341{
342}
343
344void QSocks5BindStore::add(qintptr socketDescriptor, QSocks5BindData *bindData)
345{
346 QMutexLocker lock(&mutex);
347 if (store.contains(socketDescriptor)) {
348 // qDebug("delete it");
349 }
350 bindData->timeStamp.start();
351 store.insert(socketDescriptor, bindData);
352 // start sweep timer if not started
353 if (sweepTimerId == -1)
354 sweepTimerId = startTimer(60000);
355}
356
357bool QSocks5BindStore::contains(qintptr socketDescriptor)
358{
359 QMutexLocker lock(&mutex);
360 return store.contains(socketDescriptor);
361}
362
363QSocks5BindData *QSocks5BindStore::retrieve(qintptr socketDescriptor)
364{
365 QMutexLocker lock(&mutex);
366 const auto it = store.constFind(socketDescriptor);
367 if (it == store.cend())
368 return nullptr;
369 QSocks5BindData *bindData = it.value();
370 store.erase(it);
371 if (bindData) {
372 if (bindData->controlSocket->thread() != QThread::currentThread()) {
373 qWarning("Cannot access socks5 bind data from different thread");
374 return nullptr;
375 }
376 } else {
377 QSOCKS5_DEBUG << "__ERROR__ binddata == 0";
378 }
379 // stop the sweep timer if not needed
380 if (store.isEmpty()) {
381 killTimer(sweepTimerId);
382 sweepTimerId = -1;
383 }
384 return bindData;
385}
386
387void QSocks5BindStore::timerEvent(QTimerEvent * event)
388{
389 QMutexLocker lock(&mutex);
390 if (event->timerId() == sweepTimerId) {
391 QSOCKS5_DEBUG << "QSocks5BindStore performing sweep";
392 for (auto it = store.begin(), end = store.end(); it != end;) {
393 if (it.value()->timeStamp.hasExpired(350000)) {
394 QSOCKS5_DEBUG << "QSocks5BindStore removing JJJJ";
395 it = store.erase(it);
396 } else {
397 ++it;
398 }
399 }
400 }
401}
402
403QSocks5Authenticator::QSocks5Authenticator()
404{
405}
406
407QSocks5Authenticator::~QSocks5Authenticator()
408{
409}
410
411char QSocks5Authenticator::methodId()
412{
413 return 0x00;
414}
415
416bool QSocks5Authenticator::beginAuthenticate(QTcpSocket *socket, bool *completed)
417{
418 Q_UNUSED(socket);
419 *completed = true;
420 return true;
421}
422
423bool QSocks5Authenticator::continueAuthenticate(QTcpSocket *socket, bool *completed)
424{
425 Q_UNUSED(socket);
426 *completed = true;
427 return true;
428}
429
430bool QSocks5Authenticator::seal(const QByteArray &buf, QByteArray *sealedBuf)
431{
432 *sealedBuf = buf;
433 return true;
434}
435
436bool QSocks5Authenticator::unSeal(const QByteArray &sealedBuf, QByteArray *buf)
437{
438 *buf = sealedBuf;
439 return true;
440}
441
442bool QSocks5Authenticator::unSeal(QTcpSocket *sealedSocket, QByteArray *buf)
443{
444 return unSeal(sealedSocket->readAll(), buf);
445}
446
447QSocks5PasswordAuthenticator::QSocks5PasswordAuthenticator(const QString &userName, const QString &password)
448{
449 this->userName = userName;
450 this->password = password;
451}
452
453char QSocks5PasswordAuthenticator::methodId()
454{
455 return 0x02;
456}
457
458bool QSocks5PasswordAuthenticator::beginAuthenticate(QTcpSocket *socket, bool *completed)
459{
460 *completed = false;
461 QByteArray uname = userName.toLatin1();
462 QByteArray passwd = password.toLatin1();
463 QByteArray dataBuf(3 + uname.size() + passwd.size(), 0);
464 char *buf = dataBuf.data();
465 int pos = 0;
466 buf[pos++] = S5_PASSWORDAUTH_VERSION;
467 buf[pos++] = uname.size();
468 memcpy(&buf[pos], uname.data(), uname.size());
469 pos += uname.size();
470 buf[pos++] = passwd.size();
471 memcpy(&buf[pos], passwd.data(), passwd.size());
472 return socket->write(dataBuf) == dataBuf.size();
473}
474
475bool QSocks5PasswordAuthenticator::continueAuthenticate(QTcpSocket *socket, bool *completed)
476{
477 *completed = false;
478
479 if (socket->bytesAvailable() < 2)
480 return true;
481
482 QByteArray buf = socket->read(2);
483 if (buf.at(0) == S5_PASSWORDAUTH_VERSION && buf.at(1) == 0x00) {
484 *completed = true;
485 return true;
486 }
487
488 // must disconnect
489 socket->close();
490 return false;
491}
492
493QString QSocks5PasswordAuthenticator::errorString()
494{
495 return QLatin1String("Socks5 user name or password incorrect");
496}
497
498
499
500QSocks5SocketEnginePrivate::QSocks5SocketEnginePrivate()
501 : socks5State(Uninitialized)
502 , readNotificationEnabled(false)
503 , writeNotificationEnabled(false)
504 , exceptNotificationEnabled(false)
505 , socketDescriptor(-1)
506 , data(nullptr)
507 , connectData(nullptr)
508#ifndef QT_NO_UDPSOCKET
509 , udpData(nullptr)
510#endif
511 , bindData(nullptr)
512 , readNotificationActivated(false)
513 , writeNotificationActivated(false)
514 , readNotificationPending(false)
515 , writeNotificationPending(false)
516 , connectionNotificationPending(false)
517{
518 mode = NoMode;
519}
520
521QSocks5SocketEnginePrivate::~QSocks5SocketEnginePrivate()
522{
523}
524
525void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode)
526{
527 Q_Q(QSocks5SocketEngine);
528
529 mode = socks5Mode;
530 if (mode == ConnectMode) {
531 connectData = new QSocks5ConnectData;
532 data = connectData;
533#ifndef QT_NO_UDPSOCKET
534 } else if (mode == UdpAssociateMode) {
535 udpData = new QSocks5UdpAssociateData;
536 data = udpData;
537 udpData->udpSocket = new QUdpSocket(q);
538 udpData->udpSocket->setProxy(QNetworkProxy::NoProxy);
539 QObject::connect(udpData->udpSocket, SIGNAL(readyRead()),
540 q, SLOT(_q_udpSocketReadNotification()),
541 Qt::DirectConnection);
542#endif // QT_NO_UDPSOCKET
543 } else if (mode == BindMode) {
544 bindData = new QSocks5BindData;
545 data = bindData;
546 }
547
548 data->controlSocket = new QTcpSocket(q);
549 data->controlSocket->setProxy(QNetworkProxy::NoProxy);
550 QObject::connect(data->controlSocket, SIGNAL(connected()), q, SLOT(_q_controlSocketConnected()),
551 Qt::DirectConnection);
552 QObject::connect(data->controlSocket, SIGNAL(readyRead()), q, SLOT(_q_controlSocketReadNotification()),
553 Qt::DirectConnection);
554 QObject::connect(data->controlSocket, SIGNAL(bytesWritten(qint64)), q, SLOT(_q_controlSocketBytesWritten()),
555 Qt::DirectConnection);
556 QObject::connect(data->controlSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
557 q, SLOT(_q_controlSocketErrorOccurred(QAbstractSocket::SocketError)),
558 Qt::DirectConnection);
559 QObject::connect(data->controlSocket, SIGNAL(disconnected()), q, SLOT(_q_controlSocketDisconnected()),
560 Qt::DirectConnection);
561 QObject::connect(data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
562 q, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
563 Qt::DirectConnection);
564
565 if (!proxyInfo.user().isEmpty() || !proxyInfo.password().isEmpty()) {
566 QSOCKS5_D_DEBUG << "using username/password authentication; user =" << proxyInfo.user();
567 data->authenticator = new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
568 } else {
569 QSOCKS5_D_DEBUG << "not using authentication";
570 data->authenticator = new QSocks5Authenticator();
571 }
572}
573
574void QSocks5SocketEnginePrivate::setErrorState(Socks5State state, const QString &extraMessage)
575{
576 Q_Q(QSocks5SocketEngine);
577
578 switch (state) {
579 case Uninitialized:
580 case Authenticating:
581 case AuthenticationMethodsSent:
582 case RequestMethodSent:
583 case Connected:
584 case UdpAssociateSuccess:
585 case BindSuccess:
586 // these aren't error states
587 return;
588
589 case ConnectError:
590 case ControlSocketError: {
591 QAbstractSocket::SocketError controlSocketError = data->controlSocket->error();
592 if (socks5State != Connected) {
593 switch (controlSocketError) {
594 case QAbstractSocket::ConnectionRefusedError:
595 q->setError(QAbstractSocket::ProxyConnectionRefusedError,
596 QSocks5SocketEngine::tr("Connection to proxy refused"));
597 break;
598 case QAbstractSocket::RemoteHostClosedError:
599 q->setError(QAbstractSocket::ProxyConnectionClosedError,
600 QSocks5SocketEngine::tr("Connection to proxy closed prematurely"));
601 break;
602 case QAbstractSocket::HostNotFoundError:
603 q->setError(QAbstractSocket::ProxyNotFoundError,
604 QSocks5SocketEngine::tr("Proxy host not found"));
605 break;
606 case QAbstractSocket::SocketTimeoutError:
607 if (state == ConnectError) {
608 q->setError(QAbstractSocket::ProxyConnectionTimeoutError,
609 QSocks5SocketEngine::tr("Connection to proxy timed out"));
610 break;
611 }
612 Q_FALLTHROUGH();
613 default:
614 q->setError(controlSocketError, data->controlSocket->errorString());
615 break;
616 }
617 } else {
618 q->setError(controlSocketError, data->controlSocket->errorString());
619 }
620 break;
621 }
622
623 case AuthenticatingError:
624 q->setError(QAbstractSocket::ProxyAuthenticationRequiredError,
625 extraMessage.isEmpty() ?
626 QSocks5SocketEngine::tr("Proxy authentication failed") :
627 QSocks5SocketEngine::tr("Proxy authentication failed: %1").arg(extraMessage));
628 break;
629
630 case RequestError:
631 // error code set by caller (overload)
632 break;
633
634 case SocksError:
635 q->setError(QAbstractSocket::ProxyProtocolError,
636 QSocks5SocketEngine::tr("SOCKS version 5 protocol error"));
637 break;
638
639 case HostNameLookupError:
640 q->setError(QAbstractSocket::HostNotFoundError,
641 QAbstractSocket::tr("Host not found"));
642 break;
643 }
644
645 q->setState(QAbstractSocket::UnconnectedState);
646 socks5State = state;
647}
648
649void QSocks5SocketEnginePrivate::setErrorState(Socks5State state, Socks5Error socks5error)
650{
651 Q_Q(QSocks5SocketEngine);
652 switch (socks5error) {
653 case SocksFailure:
654 q->setError(QAbstractSocket::NetworkError,
655 QSocks5SocketEngine::tr("General SOCKSv5 server failure"));
656 break;
657 case ConnectionNotAllowed:
658 q->setError(QAbstractSocket::SocketAccessError,
659 QSocks5SocketEngine::tr("Connection not allowed by SOCKSv5 server"));
660 break;
661 case NetworkUnreachable:
662 q->setError(QAbstractSocket::NetworkError,
663 QAbstractSocket::tr("Network unreachable"));
664 break;
665 case HostUnreachable:
666 q->setError(QAbstractSocket::HostNotFoundError,
667 QAbstractSocket::tr("Host not found"));
668 break;
669 case ConnectionRefused:
670 q->setError(QAbstractSocket::ConnectionRefusedError,
671 QAbstractSocket::tr("Connection refused"));
672 break;
673 case TTLExpired:
674 q->setError(QAbstractSocket::NetworkError,
675 QSocks5SocketEngine::tr("TTL expired"));
676 break;
677 case CommandNotSupported:
678 q->setError(QAbstractSocket::UnsupportedSocketOperationError,
679 QSocks5SocketEngine::tr("SOCKSv5 command not supported"));
680 break;
681 case AddressTypeNotSupported:
682 q->setError(QAbstractSocket::UnsupportedSocketOperationError,
683 QSocks5SocketEngine::tr("Address type not supported"));
684 break;
685
686 default:
687 q->setError(QAbstractSocket::UnknownSocketError,
688 QSocks5SocketEngine::tr("Unknown SOCKSv5 proxy error code 0x%1").arg(int(socks5error), 16));
689 break;
690 }
691
692 setErrorState(state, QString());
693}
694
695void QSocks5SocketEnginePrivate::reauthenticate()
696{
697 Q_Q(QSocks5SocketEngine);
698
699 // we require authentication
700 QAuthenticator auth;
701 q->proxyAuthenticationRequired(proxyInfo, &auth);
702
703 if (!auth.user().isEmpty() || !auth.password().isEmpty()) {
704 // we have new credentials, let's try again
705 QSOCKS5_DEBUG << "authentication failure: retrying connection";
706 socks5State = QSocks5SocketEnginePrivate::Uninitialized;
707
708 delete data->authenticator;
709 proxyInfo.setUser(auth.user());
710 proxyInfo.setPassword(auth.password());
711 data->authenticator = new QSocks5PasswordAuthenticator(proxyInfo.user(), proxyInfo.password());
712
713 {
714 const QSignalBlocker blocker(data->controlSocket);
715 data->controlSocket->abort();
716 }
717 data->controlSocket->connectToHost(proxyInfo.hostName(), proxyInfo.port());
718 } else {
719 // authentication failure
720
721 setErrorState(AuthenticatingError);
722 data->controlSocket->close();
723 emitConnectionNotification();
724 }
725}
726
727void QSocks5SocketEnginePrivate::parseAuthenticationMethodReply()
728{
729 // not enough data to begin
730 if (data->controlSocket->bytesAvailable() < 2)
731 return;
732
733 QByteArray buf = data->controlSocket->read(2);
734 if (buf.at(0) != S5_VERSION_5) {
735 QSOCKS5_D_DEBUG << "Socks5 version incorrect";
736 setErrorState(SocksError);
737 data->controlSocket->close();
738 emitConnectionNotification();
739 return;
740 }
741
742 bool authComplete = false;
743 if (uchar(buf.at(1)) == S5_AUTHMETHOD_NONE) {
744 authComplete = true;
745 } else if (uchar(buf.at(1)) == S5_AUTHMETHOD_NOTACCEPTABLE) {
746 reauthenticate();
747 return;
748 } else if (buf.at(1) != data->authenticator->methodId()
749 || !data->authenticator->beginAuthenticate(data->controlSocket, &authComplete)) {
750 setErrorState(AuthenticatingError, QLatin1String("Socks5 host did not support authentication method."));
751 socketError = QAbstractSocket::SocketAccessError; // change the socket error
752 emitConnectionNotification();
753 return;
754 }
755
756 if (authComplete)
757 sendRequestMethod();
758 else
759 socks5State = Authenticating;
760}
761
762void QSocks5SocketEnginePrivate::parseAuthenticatingReply()
763{
764 bool authComplete = false;
765 if (!data->authenticator->continueAuthenticate(data->controlSocket, &authComplete)) {
766 reauthenticate();
767 return;
768 }
769 if (authComplete)
770 sendRequestMethod();
771}
772
773void QSocks5SocketEnginePrivate::sendRequestMethod()
774{
775 QHostAddress address;
776 quint16 port = 0;
777 char command = 0;
778 if (mode == ConnectMode) {
779 command = S5_CONNECT;
780 address = peerAddress;
781 port = peerPort;
782 } else if (mode == BindMode) {
783 command = S5_BIND;
784 address = localAddress;
785 port = localPort;
786 } else {
787#ifndef QT_NO_UDPSOCKET
788 command = S5_UDP_ASSOCIATE;
789 address = localAddress; //data->controlSocket->localAddress();
790 port = localPort;
791#endif
792 }
793
794 QByteArray buf;
795 buf.reserve(270); // big enough for domain name;
796 buf.append(char(S5_VERSION_5));
797 buf.append(command);
798 buf.append('\0');
799 if (peerName.isEmpty() && !qt_socks5_set_host_address_and_port(address, port, &buf)) {
800 QSOCKS5_DEBUG << "error setting address" << address << " : " << port;
801 //### set error code ....
802 return;
803 } else if (!peerName.isEmpty() && !qt_socks5_set_host_name_and_port(peerName, port, &buf)) {
804 QSOCKS5_DEBUG << "error setting peer name" << peerName << " : " << port;
805 //### set error code ....
806 return;
807 }
808 QSOCKS5_DEBUG << "sending" << dump(buf);
809 QByteArray sealedBuf;
810 if (!data->authenticator->seal(buf, &sealedBuf)) {
811 // ### Handle this error.
812 }
813 data->controlSocket->write(sealedBuf);
814 data->controlSocket->flush();
815 socks5State = RequestMethodSent;
816}
817
818void QSocks5SocketEnginePrivate::parseRequestMethodReply()
819{
820 Q_Q(QSocks5SocketEngine);
821 QSOCKS5_DEBUG << "parseRequestMethodReply()";
822
823 QByteArray inBuf;
824 if (!data->authenticator->unSeal(data->controlSocket, &inBuf)) {
825 // ### check error and not just not enough data
826 QSOCKS5_DEBUG << "unSeal failed, needs more data";
827 return;
828 }
829
830 inBuf.prepend(receivedHeaderFragment);
831 receivedHeaderFragment.clear();
832 QSOCKS5_DEBUG << dump(inBuf);
833 if (inBuf.size() < 3) {
834 QSOCKS5_DEBUG << "need more data for request reply header .. put this data somewhere";
835 receivedHeaderFragment = inBuf;
836 return;
837 }
838
839 QHostAddress address;
840 quint16 port = 0;
841
842 if (inBuf.at(0) != S5_VERSION_5 || inBuf.at(2) != 0x00) {
843 QSOCKS5_DEBUG << "socks protocol error";
844 setErrorState(SocksError);
845 } else if (inBuf.at(1) != S5_SUCCESS) {
846 Socks5Error socks5Error = Socks5Error(inBuf.at(1));
847 QSOCKS5_DEBUG << "Request error :" << socks5Error;
848 if ((socks5Error == SocksFailure || socks5Error == ConnectionNotAllowed)
849 && !peerName.isEmpty()) {
850 // Dante seems to use this error code to indicate hostname resolution failure
851 setErrorState(HostNameLookupError);
852 } else {
853 setErrorState(RequestError, socks5Error);
854 }
855 } else {
856 // connection success, retrieve the remote addresses
857 int pos = 3;
858 int err = qt_socks5_get_host_address_and_port(inBuf, &address, &port, &pos);
859 if (err == -1) {
860 QSOCKS5_DEBUG << "error getting address";
861 setErrorState(SocksError);
862 } else if (err == 0) {
863 //need more data
864 receivedHeaderFragment = inBuf;
865 return;
866 } else {
867 inBuf.remove(0, pos);
868 for (int i = inBuf.size() - 1; i >= 0 ; --i)
869 data->controlSocket->ungetChar(inBuf.at(i));
870 }
871 }
872
873 if (socks5State == RequestMethodSent) {
874 // no error
875 localAddress = address;
876 localPort = port;
877
878 if (mode == ConnectMode) {
879 inboundStreamCount = outboundStreamCount = 1;
880 socks5State = Connected;
881 // notify the upper layer that we're done
882 q->setState(QAbstractSocket::ConnectedState);
883 emitConnectionNotification();
884 } else if (mode == BindMode) {
885 socks5State = BindSuccess;
886 q->setState(QAbstractSocket::ListeningState);
887 } else {
888 socks5State = UdpAssociateSuccess;
889 }
890 } else if (socks5State == BindSuccess) {
891 // no error and we got a connection
892 bindData->peerAddress = address;
893 bindData->peerPort = port;
894
895 emitReadNotification();
896 } else {
897 // got an error
898 data->controlSocket->close();
899 emitConnectionNotification();
900 }
901}
902
903void QSocks5SocketEnginePrivate::_q_emitPendingReadNotification()
904{
905 Q_Q(QSocks5SocketEngine);
906 readNotificationPending = false;
907 if (readNotificationEnabled) {
908 QSOCKS5_D_DEBUG << "emitting readNotification";
909 QPointer<QSocks5SocketEngine> qq = q;
910 q->readNotification();
911 if (!qq)
912 return;
913 // check if there needs to be a new zero read notification
914 if (data && data->controlSocket->state() == QAbstractSocket::UnconnectedState
915 && data->controlSocket->error() == QAbstractSocket::RemoteHostClosedError) {
916 connectData->readBuffer.clear();
917 emitReadNotification();
918 }
919 }
920}
921
922void QSocks5SocketEnginePrivate::emitReadNotification()
923{
924 Q_Q(QSocks5SocketEngine);
925 readNotificationActivated = true;
926 if (readNotificationEnabled && !readNotificationPending) {
927 QSOCKS5_D_DEBUG << "queueing readNotification";
928 readNotificationPending = true;
929 QMetaObject::invokeMethod(q, "_q_emitPendingReadNotification", Qt::QueuedConnection);
930 }
931}
932
933void QSocks5SocketEnginePrivate::_q_emitPendingWriteNotification()
934{
935 writeNotificationPending = false;
936 Q_Q(QSocks5SocketEngine);
937 if (writeNotificationEnabled) {
938 QSOCKS5_D_DEBUG << "emitting writeNotification";
939 q->writeNotification();
940 }
941}
942
943void QSocks5SocketEnginePrivate::emitWriteNotification()
944{
945 Q_Q(QSocks5SocketEngine);
946 writeNotificationActivated = true;
947 if (writeNotificationEnabled && !writeNotificationPending) {
948 QSOCKS5_D_DEBUG << "queueing writeNotification";
949 writeNotificationPending = true;
950 QMetaObject::invokeMethod(q, "_q_emitPendingWriteNotification", Qt::QueuedConnection);
951 }
952}
953
954void QSocks5SocketEnginePrivate::_q_emitPendingConnectionNotification()
955{
956 connectionNotificationPending = false;
957 Q_Q(QSocks5SocketEngine);
958 QSOCKS5_D_DEBUG << "emitting connectionNotification";
959 q->connectionNotification();
960}
961
962void QSocks5SocketEnginePrivate::emitConnectionNotification()
963{
964 Q_Q(QSocks5SocketEngine);
965 QSOCKS5_D_DEBUG << "queueing connectionNotification";
966 connectionNotificationPending = true;
967 QMetaObject::invokeMethod(q, "_q_emitPendingConnectionNotification", Qt::QueuedConnection);
968}
969
970QSocks5SocketEngine::QSocks5SocketEngine(QObject *parent)
971:QAbstractSocketEngine(*new QSocks5SocketEnginePrivate(), parent)
972{
973}
974
975QSocks5SocketEngine::~QSocks5SocketEngine()
976{
977 Q_D(QSocks5SocketEngine);
978
979 if (d->data) {
980 delete d->data->authenticator;
981 delete d->data->controlSocket;
982 }
983 if (d->connectData)
984 delete d->connectData;
985#ifndef QT_NO_UDPSOCKET
986 if (d->udpData) {
987 delete d->udpData->udpSocket;
988 delete d->udpData;
989 }
990#endif
991 if (d->bindData)
992 delete d->bindData;
993}
994
995static int nextDescriptor()
996{
997 static QBasicAtomicInt counter;
998 return 1 + counter.fetchAndAddRelaxed(1);
999}
1000
1001bool QSocks5SocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
1002{
1003 Q_D(QSocks5SocketEngine);
1004
1005 d->socketDescriptor = nextDescriptor();
1006
1007 d->socketType = type;
1008 d->socketProtocol = protocol;
1009
1010 return true;
1011}
1012
1013bool QSocks5SocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState)
1014{
1015 Q_D(QSocks5SocketEngine);
1016
1017 QSOCKS5_Q_DEBUG << "initialize" << socketDescriptor;
1018
1019 // this is only valid for the other side of a bind, nothing else is supported
1020
1021 if (socketState != QAbstractSocket::ConnectedState) {
1022 //### must be connected state ???
1023 return false;
1024 }
1025
1026 QSocks5BindData *bindData = socks5BindStore()->retrieve(socketDescriptor);
1027 if (bindData) {
1028
1029 d->socketState = QAbstractSocket::ConnectedState;
1030 d->socketType = QAbstractSocket::TcpSocket;
1031 d->connectData = new QSocks5ConnectData;
1032 d->data = d->connectData;
1033 d->mode = QSocks5SocketEnginePrivate::ConnectMode;
1034 d->data->controlSocket = bindData->controlSocket;
1035 bindData->controlSocket = nullptr;
1036 d->data->controlSocket->setParent(this);
1037 d->socketProtocol = d->data->controlSocket->localAddress().protocol();
1038 d->data->authenticator = bindData->authenticator;
1039 bindData->authenticator = nullptr;
1040 d->localPort = bindData->localPort;
1041 d->localAddress = bindData->localAddress;
1042 d->peerPort = bindData->peerPort;
1043 d->peerAddress = bindData->peerAddress;
1044 d->inboundStreamCount = d->outboundStreamCount = 1;
1045 delete bindData;
1046
1047 QObject::connect(d->data->controlSocket, SIGNAL(connected()), this, SLOT(_q_controlSocketConnected()),
1048 Qt::DirectConnection);
1049 QObject::connect(d->data->controlSocket, SIGNAL(readyRead()), this, SLOT(_q_controlSocketReadNotification()),
1050 Qt::DirectConnection);
1051 QObject::connect(d->data->controlSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_controlSocketBytesWritten()),
1052 Qt::DirectConnection);
1053 QObject::connect(d->data->controlSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(_q_controlSocketErrorOccurred(QAbstractSocket::SocketError)),
1054 Qt::DirectConnection);
1055 QObject::connect(d->data->controlSocket, SIGNAL(disconnected()), this, SLOT(_q_controlSocketDisconnected()),
1056 Qt::DirectConnection);
1057 QObject::connect(d->data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
1058 this, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
1059 Qt::DirectConnection);
1060
1061 d->socks5State = QSocks5SocketEnginePrivate::Connected;
1062
1063 if (d->data->controlSocket->bytesAvailable() != 0)
1064 d->_q_controlSocketReadNotification();
1065 return true;
1066 }
1067 return false;
1068}
1069
1070void QSocks5SocketEngine::setProxy(const QNetworkProxy &networkProxy)
1071{
1072 Q_D(QSocks5SocketEngine);
1073 d->proxyInfo = networkProxy;
1074}
1075
1076qintptr QSocks5SocketEngine::socketDescriptor() const
1077{
1078 Q_D(const QSocks5SocketEngine);
1079 return d->socketDescriptor;
1080}
1081
1082bool QSocks5SocketEngine::isValid() const
1083{
1084 Q_D(const QSocks5SocketEngine);
1085 return d->socketType != QAbstractSocket::UnknownSocketType
1086 && d->socks5State != QSocks5SocketEnginePrivate::SocksError
1087 && (d->socketError == QAbstractSocket::UnknownSocketError
1088 || d->socketError == QAbstractSocket::SocketTimeoutError
1089 || d->socketError == QAbstractSocket::UnfinishedSocketOperationError);
1090}
1091
1092bool QSocks5SocketEngine::connectInternal()
1093{
1094 Q_D(QSocks5SocketEngine);
1095
1096 if (!d->data) {
1097 if (socketType() == QAbstractSocket::TcpSocket) {
1098 d->initialize(QSocks5SocketEnginePrivate::ConnectMode);
1099#ifndef QT_NO_UDPSOCKET
1100 } else if (socketType() == QAbstractSocket::UdpSocket) {
1101 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1102 // all udp needs to be bound
1103 if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0))
1104 return false;
1105
1106 setState(QAbstractSocket::ConnectedState);
1107 return true;
1108#endif
1109 } else {
1110 qFatal("QSocks5SocketEngine::connectToHost: in QTcpServer mode");
1111 return false;
1112 }
1113 }
1114
1115 if (d->socketState != QAbstractSocket::ConnectingState) {
1116 if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized
1117 // We may have new auth credentials since an earlier failure:
1118 || d->socks5State == QSocks5SocketEnginePrivate::AuthenticatingError) {
1119 setState(QAbstractSocket::ConnectingState);
1120 //limit buffer in internal socket, data is buffered in the external socket under application control
1121 d->data->controlSocket->setReadBufferSize(65536);
1122 }
1123
1124 d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1125 }
1126
1127 return false;
1128}
1129
1130bool QSocks5SocketEngine::connectToHost(const QHostAddress &address, quint16 port)
1131{
1132 Q_D(QSocks5SocketEngine);
1133 QSOCKS5_DEBUG << "connectToHost" << address << ':' << port;
1134
1135 setPeerAddress(address);
1136 setPeerPort(port);
1137 d->peerName.clear();
1138
1139 return connectInternal();
1140}
1141
1142bool QSocks5SocketEngine::connectToHostByName(const QString &hostname, quint16 port)
1143{
1144 Q_D(QSocks5SocketEngine);
1145
1146 setPeerAddress(QHostAddress());
1147 setPeerPort(port);
1148 d->peerName = hostname;
1149
1150 return connectInternal();
1151}
1152
1153void QSocks5SocketEnginePrivate::_q_controlSocketConnected()
1154{
1155 QSOCKS5_DEBUG << "_q_controlSocketConnected";
1156 QByteArray buf(3, 0);
1157 buf[0] = S5_VERSION_5;
1158 buf[1] = 0x01;
1159 buf[2] = data->authenticator->methodId();
1160 data->controlSocket->write(buf);
1161 socks5State = AuthenticationMethodsSent;
1162}
1163
1164void QSocks5SocketEnginePrivate::_q_controlSocketReadNotification()
1165{
1166 QSOCKS5_D_DEBUG << "_q_controlSocketReadNotification socks5state" << s5StateToString(socks5State)
1167 << "bytes available" << data->controlSocket->bytesAvailable();
1168
1169 if (data->controlSocket->bytesAvailable() == 0) {
1170 QSOCKS5_D_DEBUG << "########## bogus read why do we get these ... on windows only";
1171 return;
1172 }
1173
1174 switch (socks5State) {
1175 case AuthenticationMethodsSent:
1176 parseAuthenticationMethodReply();
1177 break;
1178 case Authenticating:
1179 parseAuthenticatingReply();
1180 break;
1181 case RequestMethodSent:
1182 parseRequestMethodReply();
1183 if (socks5State == Connected && data->controlSocket->bytesAvailable())
1184 _q_controlSocketReadNotification();
1185 break;
1186 case Connected: {
1187 QByteArray buf;
1188 if (!data->authenticator->unSeal(data->controlSocket, &buf)) {
1189 // qDebug("unseal error maybe need to wait for more data");
1190 }
1191 if (buf.size()) {
1192 QSOCKS5_DEBUG << dump(buf);
1193 connectData->readBuffer.append(buf);
1194 emitReadNotification();
1195 }
1196 break;
1197 }
1198 case BindSuccess:
1199 // only get here if command is bind
1200 if (mode == BindMode) {
1201 parseRequestMethodReply();
1202 break;
1203 }
1204
1205 Q_FALLTHROUGH();
1206 default:
1207 qWarning("QSocks5SocketEnginePrivate::_q_controlSocketReadNotification: "
1208 "Unexpectedly received data while in state=%d and mode=%d",
1209 socks5State, mode);
1210 break;
1211 };
1212}
1213
1214void QSocks5SocketEnginePrivate::_q_controlSocketBytesWritten()
1215{
1216 QSOCKS5_DEBUG << "_q_controlSocketBytesWritten";
1217
1218 if (socks5State != Connected
1219 || (mode == ConnectMode
1220 && data->controlSocket->bytesToWrite()))
1221 return;
1222 if (data->controlSocket->bytesToWrite() < MaxWriteBufferSize) {
1223 emitWriteNotification();
1224 writeNotificationActivated = false;
1225 }
1226}
1227
1228void QSocks5SocketEnginePrivate::_q_controlSocketErrorOccurred(QAbstractSocket::SocketError error)
1229{
1230 QSOCKS5_D_DEBUG << "controlSocketError" << error << data->controlSocket->errorString();
1231
1232 if (error == QAbstractSocket::SocketTimeoutError)
1233 return; // ignore this error -- comes from the waitFor* functions
1234
1235 if (error == QAbstractSocket::RemoteHostClosedError
1236 && socks5State == Connected) {
1237 // clear the read buffer in connect mode so that bytes available returns 0
1238 // if there already is a read notification pending then this will be processed first
1239 if (!readNotificationPending)
1240 connectData->readBuffer.clear();
1241 emitReadNotification();
1242 data->controlSocket->close();
1243 // cause a disconnect in the outer socket
1244 emitWriteNotification();
1245 } else if (socks5State == Uninitialized
1246 || socks5State == AuthenticationMethodsSent
1247 || socks5State == Authenticating
1248 || socks5State == RequestMethodSent) {
1249 setErrorState(socks5State == Uninitialized ? ConnectError : ControlSocketError);
1250 data->controlSocket->close();
1251 emitConnectionNotification();
1252 } else {
1253 q_func()->setError(data->controlSocket->error(), data->controlSocket->errorString());
1254 emitReadNotification();
1255 emitWriteNotification();
1256 }
1257}
1258
1259void QSocks5SocketEnginePrivate::_q_controlSocketDisconnected()
1260{
1261 QSOCKS5_D_DEBUG << "_q_controlSocketDisconnected";
1262}
1263
1264void QSocks5SocketEnginePrivate::_q_controlSocketStateChanged(QAbstractSocket::SocketState state)
1265{
1266 QSOCKS5_D_DEBUG << "_q_controlSocketStateChanged" << state;
1267}
1268
1269#ifndef QT_NO_UDPSOCKET
1270void QSocks5SocketEnginePrivate::_q_udpSocketReadNotification()
1271{
1272 QSOCKS5_D_DEBUG << "_q_udpSocketReadNotification()";
1273
1274 // check some state stuff
1275 if (!udpData->udpSocket->hasPendingDatagrams()) {
1276 QSOCKS5_D_DEBUG << "false read ??";
1277 return;
1278 }
1279
1280 while (udpData->udpSocket->hasPendingDatagrams()) {
1281 QByteArray sealedBuf(udpData->udpSocket->pendingDatagramSize(), 0);
1282 QSOCKS5_D_DEBUG << "new datagram";
1283 udpData->udpSocket->readDatagram(sealedBuf.data(), sealedBuf.size());
1284 QByteArray inBuf;
1285 if (!data->authenticator->unSeal(sealedBuf, &inBuf)) {
1286 QSOCKS5_D_DEBUG << "failed unsealing datagram discarding";
1287 return;
1288 }
1289 QSOCKS5_DEBUG << dump(inBuf);
1290 int pos = 0;
1291 const char *buf = inBuf.constData();
1292 if (inBuf.size() < 4) {
1293 QSOCKS5_D_DEBUG << "bugus udp data, discarding";
1294 return;
1295 }
1296 QSocks5RevivedDatagram datagram;
1297 if (buf[pos++] != 0 || buf[pos++] != 0) {
1298 QSOCKS5_D_DEBUG << "invalid datagram discarding";
1299 return;
1300 }
1301 if (buf[pos++] != 0) { //### add fragmentation reading support
1302 QSOCKS5_D_DEBUG << "don't support fragmentation yet disgarding";
1303 return;
1304 }
1305 if (qt_socks5_get_host_address_and_port(inBuf, &datagram.address, &datagram.port, &pos) != 1) {
1306 QSOCKS5_D_DEBUG << "failed to get address from datagram disgarding";
1307 return;
1308 }
1309 datagram.data = QByteArray(&buf[pos], inBuf.size() - pos);
1310 udpData->pendingDatagrams.enqueue(datagram);
1311 }
1312 emitReadNotification();
1313}
1314#endif // QT_NO_UDPSOCKET
1315
1316bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
1317{
1318 Q_D(QSocks5SocketEngine);
1319
1320 // when bind wee will block until the bind is finished as the info from the proxy server is needed
1321
1322 QHostAddress address;
1323 if (addr.protocol() == QAbstractSocket::AnyIPProtocol)
1324 address = QHostAddress::AnyIPv4; //SOCKS5 doesn't support dual stack, and there isn't any implementation of udp on ipv6 yet
1325 else
1326 address = addr;
1327
1328 if (!d->data) {
1329 if (socketType() == QAbstractSocket::TcpSocket) {
1330 d->initialize(QSocks5SocketEnginePrivate::BindMode);
1331#ifndef QT_NO_UDPSOCKET
1332 } else if (socketType() == QAbstractSocket::UdpSocket) {
1333 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1334#endif
1335 } else {
1336 //### something invalid
1337 return false;
1338 }
1339 }
1340
1341#ifndef QT_NO_UDPSOCKET
1342 if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1343 if (!d->udpData->udpSocket->bind(address, port)) {
1344 QSOCKS5_Q_DEBUG << "local udp bind failed";
1345 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1346 return false;
1347 }
1348 d->localAddress = d->udpData->udpSocket->localAddress();
1349 d->localPort = d->udpData->udpSocket->localPort();
1350 } else
1351#endif
1352 if (d->mode == QSocks5SocketEnginePrivate::BindMode) {
1353 d->localAddress = address;
1354 d->localPort = port;
1355 } else {
1356 //### something invalid
1357 return false;
1358 }
1359
1360 int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT;
1361 QElapsedTimer stopWatch;
1362 stopWatch.start();
1363 d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1364 if (!d->waitForConnected(msecs, nullptr) ||
1365 d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1366 // waitForConnected sets the error state and closes the socket
1367 QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString();
1368 return false;
1369 }
1370 if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
1371 setState(QAbstractSocket::BoundState);
1372 return true;
1373#ifndef QT_NO_UDPSOCKET
1374 } else if (d->socks5State == QSocks5SocketEnginePrivate::UdpAssociateSuccess) {
1375 setState(QAbstractSocket::BoundState);
1376 d->udpData->associateAddress = d->localAddress;
1377 d->localAddress = QHostAddress();
1378 d->udpData->associatePort = d->localPort;
1379 d->localPort = 0;
1380 return true;
1381#endif // QT_NO_UDPSOCKET
1382 }
1383
1384 // binding timed out
1385 setError(QAbstractSocket::SocketTimeoutError,
1386 QLatin1String(QT_TRANSLATE_NOOP("QSocks5SocketEngine", "Network operation timed out")));
1387
1388///### delete d->udpSocket;
1389///### d->udpSocket = 0;
1390 return false;
1391}
1392
1393
1394bool QSocks5SocketEngine::listen()
1395{
1396 Q_D(QSocks5SocketEngine);
1397
1398 QSOCKS5_Q_DEBUG << "listen()";
1399
1400 // check that we are in bound and then go to listening.
1401 if (d->socketState == QAbstractSocket::BoundState) {
1402 d->socketState = QAbstractSocket::ListeningState;
1403
1404 // check if we already have a connection
1405 if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1406 d->emitReadNotification();
1407
1408 return true;
1409 }
1410 return false;
1411}
1412
1413int QSocks5SocketEngine::accept()
1414{
1415 Q_D(QSocks5SocketEngine);
1416 // check we are listing ---
1417
1418 QSOCKS5_Q_DEBUG << "accept()";
1419
1420 qintptr sd = -1;
1421 switch (d->socks5State) {
1422 case QSocks5SocketEnginePrivate::BindSuccess:
1423 QSOCKS5_Q_DEBUG << "BindSuccess adding" << d->socketDescriptor << "to the bind store";
1424 d->data->controlSocket->disconnect();
1425 d->data->controlSocket->setParent(nullptr);
1426 d->bindData->localAddress = d->localAddress;
1427 d->bindData->localPort = d->localPort;
1428 sd = d->socketDescriptor;
1429 socks5BindStore()->add(sd, d->bindData);
1430 d->data = nullptr;
1431 d->bindData = nullptr;
1432 d->socketDescriptor = 0;
1433 //### do something about this socket layer ... set it closed and an error about why ...
1434 // reset state and local port/address
1435 d->socks5State = QSocks5SocketEnginePrivate::Uninitialized; // ..??
1436 d->socketState = QAbstractSocket::UnconnectedState;
1437 break;
1438 case QSocks5SocketEnginePrivate::ControlSocketError:
1439 setError(QAbstractSocket::ProxyProtocolError, QLatin1String("Control socket error"));
1440 break;
1441 default:
1442 setError(QAbstractSocket::ProxyProtocolError, QLatin1String("SOCKS5 proxy error"));
1443 break;
1444 }
1445 return sd;
1446}
1447
1448void QSocks5SocketEngine::close()
1449{
1450 QSOCKS5_Q_DEBUG << "close()";
1451 Q_D(QSocks5SocketEngine);
1452 if (d->data && d->data->controlSocket) {
1453 if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
1454 int msecs = 100;
1455 QElapsedTimer stopWatch;
1456 stopWatch.start();
1457 while (!d->data->controlSocket->bytesToWrite()) {
1458 if (!d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed())))
1459 break;
1460 }
1461 }
1462 d->data->controlSocket->close();
1463 }
1464 d->inboundStreamCount = d->outboundStreamCount = 0;
1465#ifndef QT_NO_UDPSOCKET
1466 if (d->udpData && d->udpData->udpSocket)
1467 d->udpData->udpSocket->close();
1468#endif
1469}
1470
1471qint64 QSocks5SocketEngine::bytesAvailable() const
1472{
1473 Q_D(const QSocks5SocketEngine);
1474 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
1475 return d->connectData->readBuffer.size();
1476#ifndef QT_NO_UDPSOCKET
1477 else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
1478 && !d->udpData->pendingDatagrams.isEmpty())
1479 return d->udpData->pendingDatagrams.first().data.size();
1480#endif
1481 return 0;
1482}
1483
1484qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
1485{
1486 Q_D(QSocks5SocketEngine);
1487 QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ')';
1488 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
1489 if (d->connectData->readBuffer.isEmpty()) {
1490 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1491 //imitate remote closed
1492 close();
1493 setError(QAbstractSocket::RemoteHostClosedError,
1494 QLatin1String("Remote host closed connection###"));
1495 setState(QAbstractSocket::UnconnectedState);
1496 return -1;
1497 } else {
1498 return 0; // nothing to be read
1499 }
1500 }
1501 const qint64 copy = d->connectData->readBuffer.read(data, maxlen);
1502 QSOCKS5_DEBUG << "read" << dump(QByteArray(data, copy));
1503 return copy;
1504#ifndef QT_NO_UDPSOCKET
1505 } else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1506 return readDatagram(data, maxlen);
1507#endif
1508 }
1509 return 0;
1510}
1511
1512qint64 QSocks5SocketEngine::write(const char *data, qint64 len)
1513{
1514 Q_D(QSocks5SocketEngine);
1515 QSOCKS5_Q_DEBUG << "write" << dump(QByteArray(data, len));
1516
1517 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
1518 // clamp down the amount of bytes to transfer at once
1519 len = qMin<qint64>(len, MaxWriteBufferSize) - d->data->controlSocket->bytesToWrite();
1520 if (len <= 0)
1521 return 0;
1522
1523 QByteArray buf = QByteArray::fromRawData(data, len);
1524 QByteArray sealedBuf;
1525 if (!d->data->authenticator->seal(buf, &sealedBuf)) {
1526 // ### Handle this error.
1527 }
1528
1529 qint64 written = d->data->controlSocket->write(sealedBuf);
1530 if (written <= 0) {
1531 QSOCKS5_Q_DEBUG << "native write returned" << written;
1532 return written;
1533 }
1534 d->data->controlSocket->waitForBytesWritten(0);
1535 //NB: returning len rather than written for the OK case, because the "sealing" may increase the length
1536 return len;
1537#ifndef QT_NO_UDPSOCKET
1538 } else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1539 // send to connected address
1540 return writeDatagram(data, len, QIpPacketHeader(d->peerAddress, d->peerPort));
1541#endif
1542 }
1543 //### set an error ???
1544 return -1;
1545}
1546
1547#ifndef QT_NO_UDPSOCKET
1548#ifndef QT_NO_NETWORKINTERFACE
1549bool QSocks5SocketEngine::joinMulticastGroup(const QHostAddress &,
1550 const QNetworkInterface &)
1551{
1552 setError(QAbstractSocket::UnsupportedSocketOperationError,
1553 QLatin1String("Operation on socket is not supported"));
1554 return false;
1555}
1556
1557bool QSocks5SocketEngine::leaveMulticastGroup(const QHostAddress &,
1558 const QNetworkInterface &)
1559{
1560 setError(QAbstractSocket::UnsupportedSocketOperationError,
1561 QLatin1String("Operation on socket is not supported"));
1562 return false;
1563}
1564
1565
1566QNetworkInterface QSocks5SocketEngine::multicastInterface() const
1567{
1568 return QNetworkInterface();
1569}
1570
1571bool QSocks5SocketEngine::setMulticastInterface(const QNetworkInterface &)
1572{
1573 setError(QAbstractSocket::UnsupportedSocketOperationError,
1574 QLatin1String("Operation on socket is not supported"));
1575 return false;
1576}
1577#endif // QT_NO_NETWORKINTERFACE
1578
1579bool QSocks5SocketEngine::hasPendingDatagrams() const
1580{
1581 Q_D(const QSocks5SocketEngine);
1582 Q_INIT_CHECK(false);
1583
1584 return !d->udpData->pendingDatagrams.isEmpty();
1585}
1586
1587qint64 QSocks5SocketEngine::pendingDatagramSize() const
1588{
1589 Q_D(const QSocks5SocketEngine);
1590
1591 if (!d->udpData->pendingDatagrams.isEmpty())
1592 return d->udpData->pendingDatagrams.head().data.size();
1593 return 0;
1594}
1595#endif // QT_NO_UDPSOCKET
1596
1597qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header, PacketHeaderOptions)
1598{
1599#ifndef QT_NO_UDPSOCKET
1600 Q_D(QSocks5SocketEngine);
1601
1602 if (d->udpData->pendingDatagrams.isEmpty())
1603 return 0;
1604
1605 QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
1606 int copyLen = qMin<int>(maxlen, datagram.data.size());
1607 memcpy(data, datagram.data.constData(), copyLen);
1608 if (header) {
1609 header->senderAddress = datagram.address;
1610 header->senderPort = datagram.port;
1611 }
1612 return copyLen;
1613#else
1614 Q_UNUSED(data);
1615 Q_UNUSED(maxlen);
1616 Q_UNUSED(header);
1617 return -1;
1618#endif // QT_NO_UDPSOCKET
1619}
1620
1621qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
1622{
1623#ifndef QT_NO_UDPSOCKET
1624 Q_D(QSocks5SocketEngine);
1625
1626 // it is possible to send with out first binding with udp, but socks5 requires a bind.
1627 if (!d->data) {
1628 d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
1629 // all udp needs to be bound
1630 if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0)) {
1631 //### set error
1632 return -1;
1633 }
1634 }
1635
1636 QByteArray outBuf;
1637 outBuf.reserve(270 + len);
1638 outBuf[0] = 0x00;
1639 outBuf[1] = 0x00;
1640 outBuf[2] = 0x00;
1641 if (!qt_socks5_set_host_address_and_port(header.destinationAddress, header.destinationPort, &outBuf)) {
1642 }
1643 outBuf += QByteArray(data, len);
1644 QSOCKS5_DEBUG << "sending" << dump(outBuf);
1645 QByteArray sealedBuf;
1646 if (!d->data->authenticator->seal(outBuf, &sealedBuf)) {
1647 QSOCKS5_DEBUG << "sealing data failed";
1648 setError(QAbstractSocket::SocketAccessError, d->data->authenticator->errorString());
1649 return -1;
1650 }
1651 if (d->udpData->udpSocket->writeDatagram(sealedBuf, d->udpData->associateAddress, d->udpData->associatePort) != sealedBuf.size()) {
1652 //### try frgamenting
1653 if (d->udpData->udpSocket->error() == QAbstractSocket::DatagramTooLargeError)
1654 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1655 //### else maybe more serious error
1656 return -1;
1657 }
1658
1659 return len;
1660#else
1661 Q_UNUSED(data);
1662 Q_UNUSED(len);
1663 Q_UNUSED(header);
1664 return -1;
1665#endif // QT_NO_UDPSOCKET
1666}
1667
1668qint64 QSocks5SocketEngine::bytesToWrite() const
1669{
1670 Q_D(const QSocks5SocketEngine);
1671 if (d->data && d->data->controlSocket) {
1672 return d->data->controlSocket->bytesToWrite();
1673 } else {
1674 return 0;
1675 }
1676}
1677
1678int QSocks5SocketEngine::option(SocketOption option) const
1679{
1680 Q_D(const QSocks5SocketEngine);
1681 if (d->data && d->data->controlSocket) {
1682 // convert the enum and call the real socket
1683 if (option == QAbstractSocketEngine::LowDelayOption)
1684 return d->data->controlSocket->socketOption(QAbstractSocket::LowDelayOption).toInt();
1685 if (option == QAbstractSocketEngine::KeepAliveOption)
1686 return d->data->controlSocket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
1687 }
1688 return -1;
1689}
1690
1691bool QSocks5SocketEngine::setOption(SocketOption option, int value)
1692{
1693 Q_D(QSocks5SocketEngine);
1694 if (d->data && d->data->controlSocket) {
1695 // convert the enum and call the real socket
1696 if (option == QAbstractSocketEngine::LowDelayOption)
1697 d->data->controlSocket->setSocketOption(QAbstractSocket::LowDelayOption, value);
1698 if (option == QAbstractSocketEngine::KeepAliveOption)
1699 d->data->controlSocket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
1700 return true;
1701 }
1702 return false;
1703}
1704
1705bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
1706{
1707 if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1708 return false;
1709
1710 const Socks5State wantedState =
1711 mode == ConnectMode ? Connected :
1712 mode == BindMode ? BindSuccess :
1713 UdpAssociateSuccess;
1714
1715 QElapsedTimer stopWatch;
1716 stopWatch.start();
1717
1718 while (socks5State != wantedState) {
1719 if (!data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
1720 if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1721 return true;
1722
1723 setErrorState(QSocks5SocketEnginePrivate::ControlSocketError);
1724 if (timedOut && data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1725 *timedOut = true;
1726 return false;
1727 }
1728 }
1729
1730 return true;
1731}
1732
1733bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
1734{
1735 Q_D(QSocks5SocketEngine);
1736 QSOCKS5_DEBUG << "waitForRead" << msecs;
1737
1738 d->readNotificationActivated = false;
1739
1740 QElapsedTimer stopWatch;
1741 stopWatch.start();
1742
1743 // are we connected yet?
1744 if (!d->waitForConnected(msecs, timedOut))
1745 return false;
1746 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1747 return true;
1748 if (bytesAvailable() && d->readNotificationPending) {
1749 // We've got some data incoming, but the queued call hasn't been performed yet.
1750 // The data is where we expect it to be already, so just return true.
1751 return true;
1752 }
1753
1754 // we're connected
1755 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
1756 d->mode == QSocks5SocketEnginePrivate::BindMode) {
1757 while (!d->readNotificationActivated) {
1758 if (!d->data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
1759 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1760 return true;
1761
1762 setError(d->data->controlSocket->error(), d->data->controlSocket->errorString());
1763 if (timedOut && d->data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1764 *timedOut = true;
1765 return false;
1766 }
1767 }
1768#ifndef QT_NO_UDPSOCKET
1769 } else {
1770 while (!d->readNotificationActivated) {
1771 if (!d->udpData->udpSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
1772 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1773 if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
1774 *timedOut = true;
1775 return false;
1776 }
1777 }
1778#endif // QT_NO_UDPSOCKET
1779 }
1780
1781
1782 bool ret = d->readNotificationActivated;
1783 d->readNotificationActivated = false;
1784
1785 QSOCKS5_DEBUG << "waitForRead returned" << ret;
1786 return ret;
1787}
1788
1789
1790bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
1791{
1792 Q_D(QSocks5SocketEngine);
1793 QSOCKS5_DEBUG << "waitForWrite" << msecs;
1794
1795 QElapsedTimer stopWatch;
1796 stopWatch.start();
1797
1798 // are we connected yet?
1799 if (!d->waitForConnected(msecs, timedOut))
1800 return false;
1801 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1802 return true;
1803
1804 // we're connected
1805
1806 // flush any bytes we may still have buffered in the time that we have left
1807 if (d->data->controlSocket->bytesToWrite())
1808 d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
1809 while ((msecs == -1 || stopWatch.elapsed() < msecs)
1810 && d->data->controlSocket->state() == QAbstractSocket::ConnectedState
1811 && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize)
1812 d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
1813 return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
1814}
1815
1816bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
1817 bool checkRead, bool checkWrite,
1818 int msecs, bool *timedOut)
1819{
1820 Q_UNUSED(checkRead);
1821 if (!checkWrite) {
1822 bool canRead = waitForRead(msecs, timedOut);
1823 if (readyToRead)
1824 *readyToRead = canRead;
1825 return canRead;
1826 }
1827
1828 bool canWrite = waitForWrite(msecs, timedOut);
1829 if (readyToWrite)
1830 *readyToWrite = canWrite;
1831 return canWrite;
1832}
1833
1834bool QSocks5SocketEngine::isReadNotificationEnabled() const
1835{
1836 Q_D(const QSocks5SocketEngine);
1837 return d->readNotificationEnabled;
1838}
1839
1840void QSocks5SocketEngine::setReadNotificationEnabled(bool enable)
1841{
1842 Q_D(QSocks5SocketEngine);
1843
1844 QSOCKS5_Q_DEBUG << "setReadNotificationEnabled(" << enable << ')';
1845
1846 bool emitSignal = false;
1847 if (!d->readNotificationEnabled
1848 && enable) {
1849 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
1850 emitSignal = !d->connectData->readBuffer.isEmpty();
1851#ifndef QT_NO_UDPSOCKET
1852 else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode)
1853 emitSignal = !d->udpData->pendingDatagrams.isEmpty();
1854#endif
1855 else if (d->mode == QSocks5SocketEnginePrivate::BindMode
1856 && d->socketState == QAbstractSocket::ListeningState
1857 && d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1858 emitSignal = true;
1859 }
1860
1861 d->readNotificationEnabled = enable;
1862
1863 if (emitSignal)
1864 d->emitReadNotification();
1865}
1866
1867bool QSocks5SocketEngine::isWriteNotificationEnabled() const
1868{
1869 Q_D(const QSocks5SocketEngine);
1870 return d->writeNotificationEnabled;
1871}
1872
1873void QSocks5SocketEngine::setWriteNotificationEnabled(bool enable)
1874{
1875 Q_D(QSocks5SocketEngine);
1876 d->writeNotificationEnabled = enable;
1877 if (enable && d->socketState == QAbstractSocket::ConnectedState) {
1878 if (d->mode == QSocks5SocketEnginePrivate::ConnectMode && d->data->controlSocket->bytesToWrite())
1879 return; // will be emitted as a result of bytes written
1880 d->emitWriteNotification();
1881 d->writeNotificationActivated = false;
1882 }
1883}
1884
1885bool QSocks5SocketEngine::isExceptionNotificationEnabled() const
1886{
1887 Q_D(const QSocks5SocketEngine);
1888 return d->exceptNotificationEnabled;
1889}
1890
1891void QSocks5SocketEngine::setExceptionNotificationEnabled(bool enable)
1892{
1893 Q_D(QSocks5SocketEngine);
1894 d->exceptNotificationEnabled = enable;
1895}
1896
1897QAbstractSocketEngine *
1898QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socketType,
1899 const QNetworkProxy &proxy, QObject *parent)
1900{
1901 Q_UNUSED(socketType);
1902
1903 // proxy type must have been resolved by now
1904 if (proxy.type() != QNetworkProxy::Socks5Proxy) {
1905 QSOCKS5_DEBUG << "not proxying";
1906 return nullptr;
1907 }
1908 QScopedPointer<QSocks5SocketEngine> engine(new QSocks5SocketEngine(parent));
1909 engine->setProxy(proxy);
1910 return engine.take();
1911}
1912
1913QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(qintptr socketDescriptor, QObject *parent)
1914{
1915 QSOCKS5_DEBUG << "createSocketEngine" << socketDescriptor;
1916 if (socks5BindStore()->contains(socketDescriptor)) {
1917 QSOCKS5_DEBUG << "bind store contains" << socketDescriptor;
1918 return new QSocks5SocketEngine(parent);
1919 }
1920 return nullptr;
1921}
1922
1923QT_END_NAMESPACE
1924
1925#include "moc_qsocks5socketengine_p.cpp"
1926