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

Last change on this file since 123 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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