source: trunk/src/network/socket/qsocks5socketengine.cpp@ 1165

Last change on this file since 1165 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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