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