src/network/socket/qsocks5socketengine.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtNetwork module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 
       
    60 QT_BEGIN_NAMESPACE
       
    61 
       
    62 #ifdef Q_OS_SYMBIAN
       
    63 static const int MaxWriteBufferSize = 4*1024;
       
    64 #else
       
    65 static 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]"
       
   109 static 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 
       
   130 static 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 
       
   150 static inline QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State) { return QString(); }
       
   151 static 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 */
       
   158 static 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 */
       
   191 static 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 */
       
   221 static 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 */
       
   285 static 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 
       
   294 struct QSocks5Data
       
   295 {
       
   296     QTcpSocket *controlSocket;
       
   297     QSocks5Authenticator *authenticator;
       
   298 };
       
   299 
       
   300 struct QSocks5ConnectData : public QSocks5Data
       
   301 {
       
   302     QByteArray readBuffer;
       
   303 };
       
   304 
       
   305 struct QSocks5BindData : public QSocks5Data
       
   306 {
       
   307     QHostAddress localAddress;
       
   308     quint16 localPort;
       
   309     QHostAddress peerAddress;
       
   310     quint16 peerPort;
       
   311     QDateTime timeStamp;
       
   312 };
       
   313 
       
   314 struct QSocks5RevivedDatagram
       
   315 {
       
   316     QByteArray data;
       
   317     QHostAddress address;
       
   318     quint16 port;
       
   319 };
       
   320 
       
   321 #ifndef QT_NO_UDPSOCKET
       
   322 struct 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
       
   332 class QSocks5BindStore : public QObject
       
   333 {
       
   334 public:
       
   335     QSocks5BindStore();
       
   336     ~QSocks5BindStore();
       
   337 
       
   338     void add(int socketDescriptor, QSocks5BindData *bindData);
       
   339     bool contains(int socketDescriptor);
       
   340     QSocks5BindData *retrieve(int socketDescriptor);
       
   341 
       
   342 protected:
       
   343     void timerEvent(QTimerEvent * event);
       
   344 
       
   345     QMutex mutex;
       
   346     int sweepTimerId;
       
   347     //socket descriptor, data, timestamp
       
   348     QHash<int, QSocks5BindData *> store;
       
   349 };
       
   350 
       
   351 Q_GLOBAL_STATIC(QSocks5BindStore, socks5BindStore)
       
   352 
       
   353 QSocks5BindStore::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 
       
   362 QSocks5BindStore::~QSocks5BindStore()
       
   363 {
       
   364 }
       
   365 
       
   366 void QSocks5BindStore::add(int socketDescriptor, QSocks5BindData *bindData)
       
   367 {
       
   368     QMutexLocker lock(&mutex);
       
   369     if (store.contains(socketDescriptor)) {
       
   370         // qDebug() << "delete it";
       
   371     }
       
   372     bindData->timeStamp = QDateTime::currentDateTime();
       
   373     store.insert(socketDescriptor, bindData);
       
   374     // start sweep timer if not started
       
   375     if (sweepTimerId == -1)
       
   376         sweepTimerId = startTimer(60000);
       
   377 }
       
   378 
       
   379 bool QSocks5BindStore::contains(int socketDescriptor)
       
   380 {
       
   381     QMutexLocker lock(&mutex);
       
   382     return store.contains(socketDescriptor);
       
   383 }
       
   384 
       
   385 QSocks5BindData *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 
       
   407 void 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.secsTo(QDateTime::currentDateTime()) > 350) {
       
   416                 QSOCKS5_DEBUG << "QSocks5BindStore removing JJJJ";
       
   417                 it.remove();
       
   418             }
       
   419         }
       
   420     }
       
   421 }
       
   422 
       
   423 QSocks5Authenticator::QSocks5Authenticator()
       
   424 {
       
   425 }
       
   426 
       
   427 QSocks5Authenticator::~QSocks5Authenticator()
       
   428 {
       
   429 }
       
   430 
       
   431 char QSocks5Authenticator::methodId()
       
   432 {
       
   433     return 0x00;
       
   434 }
       
   435 
       
   436 bool QSocks5Authenticator::beginAuthenticate(QTcpSocket *socket, bool *completed)
       
   437 {
       
   438     Q_UNUSED(socket);
       
   439     *completed = true;
       
   440     return true;
       
   441 }
       
   442 
       
   443 bool QSocks5Authenticator::continueAuthenticate(QTcpSocket *socket, bool *completed)
       
   444 {
       
   445     Q_UNUSED(socket);
       
   446     *completed = true;
       
   447     return true;
       
   448 }
       
   449 
       
   450 bool QSocks5Authenticator::seal(const QByteArray buf, QByteArray *sealedBuf)
       
   451 {
       
   452     *sealedBuf = buf;
       
   453     return true;
       
   454 }
       
   455 
       
   456 bool QSocks5Authenticator::unSeal(const QByteArray sealedBuf, QByteArray *buf)
       
   457 {
       
   458     *buf = sealedBuf;
       
   459     return true;
       
   460 }
       
   461 
       
   462 bool QSocks5Authenticator::unSeal(QTcpSocket *sealedSocket, QByteArray *buf)
       
   463 {
       
   464     return unSeal(sealedSocket->readAll(), buf);
       
   465 }
       
   466 
       
   467 QSocks5PasswordAuthenticator::QSocks5PasswordAuthenticator(const QString &userName, const QString &password)
       
   468 {
       
   469     this->userName = userName;
       
   470     this->password = password;
       
   471 }
       
   472 
       
   473 char QSocks5PasswordAuthenticator::methodId()
       
   474 {
       
   475     return 0x02;
       
   476 }
       
   477 
       
   478 bool 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 
       
   495 bool 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 
       
   513 QString QSocks5PasswordAuthenticator::errorString()
       
   514 {
       
   515     return QLatin1String("Socks5 user name or password incorrect");
       
   516 }
       
   517 
       
   518 
       
   519 
       
   520 QSocks5SocketEnginePrivate::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 
       
   541 QSocks5SocketEnginePrivate::~QSocks5SocketEnginePrivate()
       
   542 {
       
   543 }
       
   544 
       
   545 void 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 
       
   594 void 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 
       
   669 void 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 
       
   715 void 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 
       
   746 void 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 
       
   781 void 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 
       
   792 void 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 
       
   837 void 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 
       
   912 void 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 
       
   931 void 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 
       
   942 void 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 
       
   952 void 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 
       
   963 void QSocks5SocketEnginePrivate::_q_emitPendingConnectionNotification()
       
   964 {
       
   965     connectionNotificationPending = false;
       
   966     Q_Q(QSocks5SocketEngine);
       
   967     QSOCKS5_D_DEBUG << "emitting connectionNotification";
       
   968     emit q->connectionNotification();
       
   969 }
       
   970 
       
   971 void 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 
       
   979 QSocks5SocketEngine::QSocks5SocketEngine(QObject *parent)
       
   980 :QAbstractSocketEngine(*new QSocks5SocketEnginePrivate(), parent)
       
   981 {
       
   982 }
       
   983 
       
   984 QSocks5SocketEngine::~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 
       
  1004 static QBasicAtomicInt descriptorCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
       
  1005 
       
  1006 bool 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 
       
  1018 bool 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 
       
  1074 void QSocks5SocketEngine::setProxy(const QNetworkProxy &networkProxy)
       
  1075 {
       
  1076     Q_D(QSocks5SocketEngine);
       
  1077     d->proxyInfo = networkProxy;
       
  1078 }
       
  1079 
       
  1080 int QSocks5SocketEngine::socketDescriptor() const
       
  1081 {
       
  1082     Q_D(const QSocks5SocketEngine);
       
  1083     return d->socketDescriptor;
       
  1084 }
       
  1085 
       
  1086 bool 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 
       
  1096 bool 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 
       
  1128 bool 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 
       
  1140 bool 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 
       
  1151 void 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 
       
  1162 void 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 
       
  1210 void 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 
       
  1224 void 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     } else if (socks5State == Uninitialized
       
  1239                || socks5State == AuthenticationMethodsSent
       
  1240                || socks5State == Authenticating
       
  1241                || socks5State == RequestMethodSent) {
       
  1242         setErrorState(socks5State == Uninitialized ? ConnectError : ControlSocketError);
       
  1243         data->controlSocket->close();
       
  1244         emitConnectionNotification();
       
  1245     } else {
       
  1246         q_func()->setError(data->controlSocket->error(), data->controlSocket->errorString());
       
  1247         emitReadNotification();
       
  1248     }
       
  1249 }
       
  1250 
       
  1251 void QSocks5SocketEnginePrivate::_q_controlSocketDisconnected()
       
  1252 {
       
  1253     QSOCKS5_D_DEBUG << "_q_controlSocketDisconnected";
       
  1254 }
       
  1255 
       
  1256 void QSocks5SocketEnginePrivate::_q_controlSocketStateChanged(QAbstractSocket::SocketState state)
       
  1257 {
       
  1258     QSOCKS5_D_DEBUG << "_q_controlSocketStateChanged" << state;
       
  1259 }
       
  1260 
       
  1261 #ifndef QT_NO_UDPSOCKET
       
  1262 void QSocks5SocketEnginePrivate::checkForDatagrams() const
       
  1263 {
       
  1264     // udp should be unbuffered so we need to do some polling at certain points
       
  1265     if (udpData->udpSocket->hasPendingDatagrams())
       
  1266         const_cast<QSocks5SocketEnginePrivate *>(this)->_q_udpSocketReadNotification();
       
  1267 }
       
  1268 
       
  1269 void QSocks5SocketEnginePrivate::_q_udpSocketReadNotification()
       
  1270 {
       
  1271     QSOCKS5_D_DEBUG << "_q_udpSocketReadNotification()";
       
  1272 
       
  1273     // check some state stuff
       
  1274     if (!udpData->udpSocket->hasPendingDatagrams()) {
       
  1275         QSOCKS5_D_DEBUG << "false read ??";
       
  1276         return;
       
  1277     }
       
  1278 
       
  1279     while (udpData->udpSocket->hasPendingDatagrams()) {
       
  1280         QByteArray sealedBuf(udpData->udpSocket->pendingDatagramSize(), 0);
       
  1281         QSOCKS5_D_DEBUG << "new datagram";
       
  1282         udpData->udpSocket->readDatagram(sealedBuf.data(), sealedBuf.size());
       
  1283         QByteArray inBuf;
       
  1284         if (!data->authenticator->unSeal(sealedBuf, &inBuf)) {
       
  1285             QSOCKS5_D_DEBUG << "failed unsealing datagram discarding";
       
  1286             return;
       
  1287         }
       
  1288         QSOCKS5_DEBUG << dump(inBuf);
       
  1289         int pos = 0;
       
  1290         const char *buf = inBuf.constData();
       
  1291         if (inBuf.size() < 4) {
       
  1292             QSOCKS5_D_DEBUG << "bugus udp data, discarding";
       
  1293             return;
       
  1294         }
       
  1295         QSocks5RevivedDatagram datagram;
       
  1296         if (buf[pos++] != 0 || buf[pos++] != 0) {
       
  1297             QSOCKS5_D_DEBUG << "invalid datagram discarding";
       
  1298             return;
       
  1299         }
       
  1300         if (buf[pos++] != 0) { //### add fragmentation reading support
       
  1301             QSOCKS5_D_DEBUG << "don't support fragmentation yet disgarding";
       
  1302             return;
       
  1303         }
       
  1304         if (!qt_socks5_get_host_address_and_port(inBuf, &datagram.address, &datagram.port, &pos)) {
       
  1305             QSOCKS5_D_DEBUG << "failed to get address from datagram disgarding";
       
  1306             return;
       
  1307         }
       
  1308         datagram.data = QByteArray(&buf[pos], inBuf.size() - pos);
       
  1309         udpData->pendingDatagrams.enqueue(datagram);
       
  1310     }
       
  1311     emitReadNotification();
       
  1312 }
       
  1313 #endif // QT_NO_UDPSOCKET
       
  1314 
       
  1315 bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port)
       
  1316 {
       
  1317     Q_D(QSocks5SocketEngine);
       
  1318 
       
  1319     // when bind wee will block until the bind is finished as the info from the proxy server is needed
       
  1320 
       
  1321     if (!d->data) {
       
  1322         if (socketType() == QAbstractSocket::TcpSocket) {
       
  1323             d->initialize(QSocks5SocketEnginePrivate::BindMode);
       
  1324 #ifndef QT_NO_UDPSOCKET
       
  1325         } else if (socketType() == QAbstractSocket::UdpSocket) {
       
  1326             d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
       
  1327 #endif
       
  1328         } else {
       
  1329             //### something invalid
       
  1330             return false;
       
  1331         }
       
  1332     }
       
  1333 
       
  1334 #ifndef QT_NO_UDPSOCKET
       
  1335     if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
       
  1336         if (!d->udpData->udpSocket->bind(address, port)) {
       
  1337             QSOCKS5_Q_DEBUG << "local udp bind failed";
       
  1338             setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
       
  1339             return false;
       
  1340         }
       
  1341         d->localAddress = d->udpData->udpSocket->localAddress();
       
  1342         d->localPort = d->udpData->udpSocket->localPort();
       
  1343     } else
       
  1344 #endif
       
  1345     if (d->mode == QSocks5SocketEnginePrivate::BindMode) {
       
  1346         d->localAddress = address;
       
  1347         d->localPort = port;
       
  1348     } else {
       
  1349         //### something invalid
       
  1350         return false;
       
  1351     }
       
  1352 
       
  1353     int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT;
       
  1354     QTime stopWatch;
       
  1355     stopWatch.start();
       
  1356     d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
       
  1357     if (!d->waitForConnected(msecs, 0) ||
       
  1358         d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
       
  1359         // waitForConnected sets the error state and closes the socket
       
  1360         QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString();
       
  1361         return false;
       
  1362     }
       
  1363     if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
       
  1364         setState(QAbstractSocket::BoundState);
       
  1365         return true;
       
  1366 #ifndef QT_NO_UDPSOCKET
       
  1367     } else if (d->socks5State == QSocks5SocketEnginePrivate::UdpAssociateSuccess) {
       
  1368         setState(QAbstractSocket::BoundState);
       
  1369         d->udpData->associateAddress = d->localAddress;
       
  1370         d->localAddress = QHostAddress();
       
  1371         d->udpData->associatePort = d->localPort;
       
  1372         d->localPort = 0;
       
  1373         QUdpSocket dummy;
       
  1374         dummy.setProxy(QNetworkProxy::NoProxy);
       
  1375         if (!dummy.bind()
       
  1376             || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0
       
  1377             || !dummy.waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))
       
  1378             || dummy.readDatagram(0,0, &d->localAddress, &d->localPort) != 0) {
       
  1379             QSOCKS5_DEBUG << "udp actual address and port lookup failed";
       
  1380             setState(QAbstractSocket::UnconnectedState);
       
  1381             setError(dummy.error(), dummy.errorString());
       
  1382             d->data->controlSocket->close();
       
  1383             //### reset and error
       
  1384             return false;
       
  1385         }
       
  1386         QSOCKS5_DEBUG << "udp actual address and port" << d->localAddress << ':' << d->localPort;
       
  1387         return true;
       
  1388 #endif // QT_NO_UDPSOCKET
       
  1389     }
       
  1390 
       
  1391     // binding timed out
       
  1392     setError(QAbstractSocket::SocketTimeoutError,
       
  1393              QLatin1String(QT_TRANSLATE_NOOP("QSocks5SocketEngine", "Network operation timed out")));
       
  1394 
       
  1395 ///###    delete d->udpSocket;
       
  1396 ///###    d->udpSocket = 0;
       
  1397     return false;
       
  1398 }
       
  1399 
       
  1400 
       
  1401 bool QSocks5SocketEngine::listen()
       
  1402 {
       
  1403     Q_D(QSocks5SocketEngine);
       
  1404 
       
  1405     QSOCKS5_Q_DEBUG << "listen()";
       
  1406 
       
  1407     // check that we are in bound and then go to listening.
       
  1408     if (d->socketState == QAbstractSocket::BoundState) {
       
  1409         d->socketState = QAbstractSocket::ListeningState;
       
  1410 
       
  1411         // check if we already have a connection
       
  1412         if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
       
  1413             d->emitReadNotification();
       
  1414 
       
  1415         return true;
       
  1416     }
       
  1417     return false;
       
  1418 }
       
  1419 
       
  1420 int QSocks5SocketEngine::accept()
       
  1421 {
       
  1422     Q_D(QSocks5SocketEngine);
       
  1423     // check we are listing ---
       
  1424 
       
  1425     QSOCKS5_Q_DEBUG << "accept()";
       
  1426 
       
  1427     if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
       
  1428         QSOCKS5_Q_DEBUG << "BindSuccess adding" << d->socketDescriptor << "to the bind store";
       
  1429         d->data->controlSocket->disconnect();
       
  1430         d->data->controlSocket->setParent(0);
       
  1431         d->bindData->localAddress = d->localAddress;
       
  1432         d->bindData->localPort = d->localPort;
       
  1433         int sd = d->socketDescriptor;
       
  1434         socks5BindStore()->add(sd, d->bindData);
       
  1435         d->data = 0;
       
  1436         d->bindData = 0;
       
  1437         d->socketDescriptor = 0;
       
  1438         //### do something about this socket layer ... set it closed and an error about why ...
       
  1439         // reset state and local port/address
       
  1440         d->socks5State = QSocks5SocketEnginePrivate::Uninitialized; // ..??
       
  1441         d->socketState = QAbstractSocket::UnconnectedState;
       
  1442         return sd;
       
  1443     }
       
  1444     return -1;
       
  1445 }
       
  1446 
       
  1447 void QSocks5SocketEngine::close()
       
  1448 {
       
  1449     QSOCKS5_Q_DEBUG << "close()";
       
  1450     Q_D(QSocks5SocketEngine);
       
  1451     if (d->data && d->data->controlSocket) {
       
  1452         if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
       
  1453             int msecs = 100;
       
  1454             QTime stopWatch;
       
  1455             stopWatch.start();
       
  1456             while (!d->data->controlSocket->bytesToWrite()) {
       
  1457                if (!d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed())))
       
  1458                    break;
       
  1459             }
       
  1460         }
       
  1461         d->data->controlSocket->close();
       
  1462     }
       
  1463 #ifndef QT_NO_UDPSOCKET
       
  1464     if (d->udpData && d->udpData->udpSocket)
       
  1465         d->udpData->udpSocket->close();
       
  1466 #endif
       
  1467 }
       
  1468 
       
  1469 qint64 QSocks5SocketEngine::bytesAvailable() const
       
  1470 {
       
  1471     Q_D(const QSocks5SocketEngine);
       
  1472     if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
       
  1473         return d->connectData->readBuffer.size();
       
  1474 #ifndef QT_NO_UDPSOCKET
       
  1475     else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
       
  1476              && !d->udpData->pendingDatagrams.isEmpty())
       
  1477         return d->udpData->pendingDatagrams.first().data.size();
       
  1478 #endif
       
  1479     return 0;
       
  1480 }
       
  1481 
       
  1482 qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
       
  1483 {
       
  1484     Q_D(QSocks5SocketEngine);
       
  1485     QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ')';
       
  1486     if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
       
  1487         if (d->connectData->readBuffer.size() == 0) {
       
  1488             if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
       
  1489                 //imitate remote closed
       
  1490                 close();
       
  1491                 setError(QAbstractSocket::RemoteHostClosedError,
       
  1492                          QLatin1String("Remote host closed connection###"));
       
  1493                 setState(QAbstractSocket::UnconnectedState);
       
  1494                 return -1;
       
  1495             } else {
       
  1496                 return 0;       // nothing to be read
       
  1497             }
       
  1498         }
       
  1499         qint64 copy = qMin<qint64>(d->connectData->readBuffer.size(), maxlen);
       
  1500         memcpy(data, d->connectData->readBuffer.constData(), copy);
       
  1501         d->connectData->readBuffer.remove(0, copy);
       
  1502         QSOCKS5_DEBUG << "read" << dump(QByteArray(data, copy));
       
  1503         return copy;
       
  1504 #ifndef QT_NO_UDPSOCKET
       
  1505     } else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
       
  1506         return readDatagram(data, maxlen);
       
  1507 #endif
       
  1508     }
       
  1509     return 0;
       
  1510 }
       
  1511 
       
  1512 qint64 QSocks5SocketEngine::write(const char *data, qint64 len)
       
  1513 {
       
  1514     Q_D(QSocks5SocketEngine);
       
  1515     QSOCKS5_Q_DEBUG << "write" << dump(QByteArray(data, len));
       
  1516 
       
  1517     if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
       
  1518         // clamp down the amount of bytes to transfer at once
       
  1519         len = qMin<qint64>(len, MaxWriteBufferSize) - d->data->controlSocket->bytesToWrite();
       
  1520         if (len <= 0)
       
  1521             return 0;
       
  1522 
       
  1523         QByteArray buf = QByteArray::fromRawData(data, len);
       
  1524         QByteArray sealedBuf;
       
  1525         if (!d->data->authenticator->seal(buf, &sealedBuf)) {
       
  1526             // ### Handle this error.
       
  1527         }
       
  1528 
       
  1529         d->data->controlSocket->write(sealedBuf);
       
  1530         d->data->controlSocket->waitForBytesWritten(0);
       
  1531         return len;
       
  1532 #ifndef QT_NO_UDPSOCKET
       
  1533     } else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
       
  1534         // send to connected address
       
  1535         return writeDatagram(data, len, d->peerAddress, d->peerPort);
       
  1536 #endif
       
  1537     }
       
  1538     //### set an error ???
       
  1539     return -1;
       
  1540 }
       
  1541 
       
  1542 #ifndef QT_NO_UDPSOCKET
       
  1543 qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr,
       
  1544                                         quint16 *port)
       
  1545 {
       
  1546     Q_D(QSocks5SocketEngine);
       
  1547 
       
  1548     d->checkForDatagrams();
       
  1549 
       
  1550     if (d->udpData->pendingDatagrams.isEmpty())
       
  1551         return 0;
       
  1552 
       
  1553     QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
       
  1554     int copyLen = qMin<int>(maxlen, datagram.data.size());
       
  1555     memcpy(data, datagram.data.constData(), copyLen);
       
  1556     if (addr)
       
  1557         *addr = datagram.address;
       
  1558     if (port)
       
  1559         *port = datagram.port;
       
  1560     return copyLen;
       
  1561 }
       
  1562 
       
  1563 qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &address,
       
  1564                                          quint16 port)
       
  1565 {
       
  1566     Q_D(QSocks5SocketEngine);
       
  1567 
       
  1568     // it is possible to send with out first binding with udp, but socks5 requires a bind.
       
  1569     if (!d->data) {
       
  1570         d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
       
  1571         // all udp needs to be bound
       
  1572         if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0)) {
       
  1573             //### set error
       
  1574             return -1;
       
  1575         }
       
  1576     }
       
  1577 
       
  1578     QByteArray outBuf;
       
  1579     outBuf.reserve(270 + len);
       
  1580     outBuf[0] = 0x00;
       
  1581     outBuf[1] = 0x00;
       
  1582     outBuf[2] = 0x00;
       
  1583     if (!qt_socks5_set_host_address_and_port(address, port, &outBuf)) {
       
  1584     }
       
  1585     outBuf += QByteArray(data, len);
       
  1586     QSOCKS5_DEBUG << "sending" << dump(outBuf);
       
  1587     QByteArray sealedBuf;
       
  1588     if (!d->data->authenticator->seal(outBuf, &sealedBuf)) {
       
  1589         QSOCKS5_DEBUG << "sealing data failed";
       
  1590         setError(QAbstractSocket::SocketAccessError, d->data->authenticator->errorString());
       
  1591         return -1;
       
  1592     }
       
  1593     if (d->udpData->udpSocket->writeDatagram(sealedBuf, d->udpData->associateAddress, d->udpData->associatePort) != sealedBuf.size()) {
       
  1594         //### try frgamenting
       
  1595         if (d->udpData->udpSocket->error() == QAbstractSocket::DatagramTooLargeError)
       
  1596             setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
       
  1597         //### else maybe more serious error
       
  1598         return -1;
       
  1599     }
       
  1600 
       
  1601     return len;
       
  1602 }
       
  1603 
       
  1604 bool QSocks5SocketEngine::hasPendingDatagrams() const
       
  1605 {
       
  1606     Q_D(const QSocks5SocketEngine);
       
  1607     Q_INIT_CHECK(false);
       
  1608 
       
  1609     d->checkForDatagrams();
       
  1610 
       
  1611     return !d->udpData->pendingDatagrams.isEmpty();
       
  1612 }
       
  1613 
       
  1614 qint64 QSocks5SocketEngine::pendingDatagramSize() const
       
  1615 {
       
  1616     Q_D(const QSocks5SocketEngine);
       
  1617 
       
  1618     d->checkForDatagrams();
       
  1619 
       
  1620     if (!d->udpData->pendingDatagrams.isEmpty())
       
  1621         return d->udpData->pendingDatagrams.head().data.size();
       
  1622     return 0;
       
  1623 }
       
  1624 #endif // QT_NO_UDPSOCKET
       
  1625 
       
  1626 int QSocks5SocketEngine::option(SocketOption option) const
       
  1627 {
       
  1628     Q_D(const QSocks5SocketEngine);
       
  1629     if (d->data && d->data->controlSocket) {
       
  1630         // convert the enum and call the real socket
       
  1631         if (option == QAbstractSocketEngine::LowDelayOption)
       
  1632             return d->data->controlSocket->socketOption(QAbstractSocket::LowDelayOption).toInt();
       
  1633         if (option == QAbstractSocketEngine::KeepAliveOption)
       
  1634             return d->data->controlSocket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
       
  1635     }
       
  1636     return -1;
       
  1637 }
       
  1638 
       
  1639 bool QSocks5SocketEngine::setOption(SocketOption option, int value)
       
  1640 {
       
  1641     Q_D(QSocks5SocketEngine);
       
  1642     if (d->data && d->data->controlSocket) {
       
  1643         // convert the enum and call the real socket
       
  1644         if (option == QAbstractSocketEngine::LowDelayOption)
       
  1645             d->data->controlSocket->setSocketOption(QAbstractSocket::LowDelayOption, value);
       
  1646         if (option == QAbstractSocketEngine::KeepAliveOption)
       
  1647             d->data->controlSocket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
       
  1648         return true;
       
  1649     }
       
  1650     return false;
       
  1651 }
       
  1652 
       
  1653 bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
       
  1654 {
       
  1655     if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
       
  1656         return false;
       
  1657 
       
  1658     const Socks5State wantedState =
       
  1659         mode == ConnectMode ? Connected :
       
  1660         mode == BindMode ? BindSuccess :
       
  1661         UdpAssociateSuccess;
       
  1662 
       
  1663     QTime stopWatch;
       
  1664     stopWatch.start();
       
  1665 
       
  1666     while (socks5State != wantedState) {
       
  1667         if (!data->controlSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
       
  1668             if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
       
  1669                 return true;
       
  1670 
       
  1671             setErrorState(QSocks5SocketEnginePrivate::ControlSocketError);
       
  1672             if (timedOut && data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
       
  1673                 *timedOut = true;
       
  1674             return false;
       
  1675         }
       
  1676     }
       
  1677 
       
  1678     return true;
       
  1679 }
       
  1680 
       
  1681 bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
       
  1682 {
       
  1683     Q_D(QSocks5SocketEngine);
       
  1684     QSOCKS5_DEBUG << "waitForRead" << msecs;
       
  1685 
       
  1686     d->readNotificationActivated = false;
       
  1687 
       
  1688     QTime stopWatch;
       
  1689     stopWatch.start();
       
  1690 
       
  1691     // are we connected yet?
       
  1692     if (!d->waitForConnected(msecs, timedOut))
       
  1693         return false;
       
  1694     if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
       
  1695         return true;
       
  1696 
       
  1697     // we're connected
       
  1698     if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
       
  1699         d->mode == QSocks5SocketEnginePrivate::BindMode) {
       
  1700         while (!d->readNotificationActivated) {
       
  1701             if (!d->data->controlSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
       
  1702                 if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
       
  1703                     return true;
       
  1704 
       
  1705                 setError(d->data->controlSocket->error(), d->data->controlSocket->errorString());
       
  1706                 if (timedOut && d->data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
       
  1707                     *timedOut = true;
       
  1708                 return false;
       
  1709             }
       
  1710         }
       
  1711 #ifndef QT_NO_UDPSOCKET
       
  1712     } else {
       
  1713         while (!d->readNotificationActivated) {
       
  1714             if (!d->udpData->udpSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
       
  1715                 setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
       
  1716                 if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
       
  1717                     *timedOut = true;
       
  1718                 return false;
       
  1719             }
       
  1720         }
       
  1721 #endif // QT_NO_UDPSOCKET
       
  1722     }
       
  1723 
       
  1724 
       
  1725     bool ret = d->readNotificationActivated;
       
  1726     d->readNotificationActivated = false;
       
  1727 
       
  1728     QSOCKS5_DEBUG << "waitForRead returned" << ret;
       
  1729     return ret;
       
  1730 }
       
  1731 
       
  1732 
       
  1733 bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
       
  1734 {
       
  1735     Q_D(QSocks5SocketEngine);
       
  1736     QSOCKS5_DEBUG << "waitForWrite" << msecs;
       
  1737 
       
  1738     QTime stopWatch;
       
  1739     stopWatch.start();
       
  1740 
       
  1741     // are we connected yet?
       
  1742     if (!d->waitForConnected(msecs, timedOut))
       
  1743         return false;
       
  1744     if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
       
  1745         return true;
       
  1746 
       
  1747     // we're connected
       
  1748 
       
  1749     // flush any bytes we may still have buffered in the time that we have left
       
  1750     if (d->data->controlSocket->bytesToWrite())
       
  1751         d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed()));
       
  1752     while ((msecs == -1 || stopWatch.elapsed() < msecs)
       
  1753            && d->data->controlSocket->state() == QAbstractSocket::ConnectedState
       
  1754            && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize)
       
  1755         d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed()));
       
  1756     return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
       
  1757 }
       
  1758 
       
  1759 bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
       
  1760                                             bool checkRead, bool checkWrite,
       
  1761                                             int msecs, bool *timedOut)
       
  1762 {
       
  1763     Q_UNUSED(checkRead);
       
  1764     if (!checkWrite) {
       
  1765         bool canRead = waitForRead(msecs, timedOut);
       
  1766         if (readyToRead)
       
  1767             *readyToRead = canRead;
       
  1768         return canRead;
       
  1769     }
       
  1770 
       
  1771     bool canWrite = waitForWrite(msecs, timedOut);
       
  1772     if (readyToWrite)
       
  1773         *readyToWrite = canWrite;
       
  1774     return canWrite;
       
  1775 }
       
  1776 
       
  1777 bool QSocks5SocketEngine::isReadNotificationEnabled() const
       
  1778 {
       
  1779     Q_D(const QSocks5SocketEngine);
       
  1780     return d->readNotificationEnabled;
       
  1781 }
       
  1782 
       
  1783 void QSocks5SocketEngine::setReadNotificationEnabled(bool enable)
       
  1784 {
       
  1785     Q_D(QSocks5SocketEngine);
       
  1786 
       
  1787     QSOCKS5_Q_DEBUG << "setReadNotificationEnabled(" << enable << ')';
       
  1788 
       
  1789     bool emitSignal = false;
       
  1790     if (!d->readNotificationEnabled
       
  1791         && enable) {
       
  1792         if (d->mode == QSocks5SocketEnginePrivate::ConnectMode)
       
  1793             emitSignal = !d->connectData->readBuffer.isEmpty();
       
  1794 #ifndef QT_NO_UDPSOCKET
       
  1795         else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode)
       
  1796             emitSignal = !d->udpData->pendingDatagrams.isEmpty();
       
  1797 #endif
       
  1798         else if (d->mode == QSocks5SocketEnginePrivate::BindMode
       
  1799             && d->socketState == QAbstractSocket::ListeningState
       
  1800             && d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
       
  1801             emitSignal = true;
       
  1802     }
       
  1803 
       
  1804     d->readNotificationEnabled = enable;
       
  1805 
       
  1806     if (emitSignal)
       
  1807         d->emitReadNotification();
       
  1808 }
       
  1809 
       
  1810 bool QSocks5SocketEngine::isWriteNotificationEnabled() const
       
  1811 {
       
  1812     Q_D(const QSocks5SocketEngine);
       
  1813     return d->writeNotificationEnabled;
       
  1814 }
       
  1815 
       
  1816 void QSocks5SocketEngine::setWriteNotificationEnabled(bool enable)
       
  1817 {
       
  1818     Q_D(QSocks5SocketEngine);
       
  1819     d->writeNotificationEnabled = enable;
       
  1820     if (enable && d->socketState == QAbstractSocket::ConnectedState) {
       
  1821         if (d->mode == QSocks5SocketEnginePrivate::ConnectMode && d->data->controlSocket->bytesToWrite())
       
  1822             return; // will be emitted as a result of bytes written
       
  1823        d->emitWriteNotification();
       
  1824        d->writeNotificationActivated = false;
       
  1825     }
       
  1826 }
       
  1827 
       
  1828 bool QSocks5SocketEngine::isExceptionNotificationEnabled() const
       
  1829 {
       
  1830     Q_D(const QSocks5SocketEngine);
       
  1831     return d->exceptNotificationEnabled;
       
  1832 }
       
  1833 
       
  1834 void QSocks5SocketEngine::setExceptionNotificationEnabled(bool enable)
       
  1835 {
       
  1836     Q_D(QSocks5SocketEngine);
       
  1837     d->exceptNotificationEnabled = enable;
       
  1838 }
       
  1839 
       
  1840 QAbstractSocketEngine *
       
  1841 QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socketType,
       
  1842                                                const QNetworkProxy &proxy, QObject *parent)
       
  1843 {
       
  1844     Q_UNUSED(socketType);
       
  1845 
       
  1846     // proxy type must have been resolved by now
       
  1847     if (proxy.type() != QNetworkProxy::Socks5Proxy) {
       
  1848         QSOCKS5_DEBUG << "not proxying";
       
  1849         return 0;
       
  1850     }
       
  1851     QScopedPointer<QSocks5SocketEngine> engine(new QSocks5SocketEngine(parent));
       
  1852     engine->setProxy(proxy);
       
  1853     return engine.take();
       
  1854 }
       
  1855 
       
  1856 QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(int socketDescriptor, QObject *parent)
       
  1857 {
       
  1858     QSOCKS5_DEBUG << "createSocketEngine" << socketDescriptor;
       
  1859     if (socks5BindStore()->contains(socketDescriptor)) {
       
  1860         QSOCKS5_DEBUG << "bind store contains" << socketDescriptor;
       
  1861         return new QSocks5SocketEngine(parent);
       
  1862     }
       
  1863     return 0;
       
  1864 }
       
  1865 
       
  1866 #endif // QT_NO_SOCKS5
       
  1867 
       
  1868 QT_END_NAMESPACE