Qt 4.8
qsocks5socketengine.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 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 
62 
63 #ifdef Q_OS_SYMBIAN
64 static const int MaxWriteBufferSize = 4*1024;
65 #else
66 static const int MaxWriteBufferSize = 128*1024;
67 #endif
68 
69 //#define QSOCKS5SOCKETLAYER_DEBUG
70 
71 #define MAX_DATA_DUMP 256
72 #if !defined(Q_OS_WINCE)
73 #define SOCKS5_BLOCKING_BIND_TIMEOUT 5000
74 #else
75 #define SOCKS5_BLOCKING_BIND_TIMEOUT 10000
76 #endif
77 
78 #define Q_INIT_CHECK(returnValue) do { \
79  if (!d->data) { \
80  return returnValue; \
81  } } while (0)
82 
83 #define S5_VERSION_5 0x05
84 #define S5_CONNECT 0x01
85 #define S5_BIND 0x02
86 #define S5_UDP_ASSOCIATE 0x03
87 #define S5_IP_V4 0x01
88 #define S5_DOMAINNAME 0x03
89 #define S5_IP_V6 0x04
90 #define S5_SUCCESS 0x00
91 #define S5_R_ERROR_SOCKS_FAILURE 0x01
92 #define S5_R_ERROR_CON_NOT_ALLOWED 0x02
93 #define S5_R_ERROR_NET_UNREACH 0x03
94 #define S5_R_ERROR_HOST_UNREACH 0x04
95 #define S5_R_ERROR_CONN_REFUSED 0x05
96 #define S5_R_ERROR_TTL 0x06
97 #define S5_R_ERROR_CMD_NOT_SUPPORTED 0x07
98 #define S5_R_ERROR_ADD_TYPE_NOT_SUPORTED 0x08
99 
100 #define S5_AUTHMETHOD_NONE 0x00
101 #define S5_AUTHMETHOD_PASSWORD 0x02
102 #define S5_AUTHMETHOD_NOTACCEPTABLE 0xFF
103 
104 #define S5_PASSWORDAUTH_VERSION 0x01
105 
106 #ifdef QSOCKS5SOCKETLAYER_DEBUG
107 # define QSOCKS5_Q_DEBUG qDebug() << this
108 # define QSOCKS5_D_DEBUG qDebug() << q_ptr
109 # define QSOCKS5_DEBUG qDebug() << "[QSocks5]"
111 {
112  switch (s) {
113  case QSocks5SocketEnginePrivate::Uninitialized: return QLatin1String("Uninitialized");
114  case QSocks5SocketEnginePrivate::ConnectError: return QLatin1String("ConnectError");
115  case QSocks5SocketEnginePrivate::AuthenticationMethodsSent: return QLatin1String("AuthenticationMethodsSent");
116  case QSocks5SocketEnginePrivate::Authenticating: return QLatin1String("Authenticating");
117  case QSocks5SocketEnginePrivate::AuthenticatingError: return QLatin1String("AuthenticatingError");
118  case QSocks5SocketEnginePrivate::RequestMethodSent: return QLatin1String("RequestMethodSent");
119  case QSocks5SocketEnginePrivate::RequestError: return QLatin1String("RequestError");
120  case QSocks5SocketEnginePrivate::Connected: return QLatin1String("Connected");
121  case QSocks5SocketEnginePrivate::UdpAssociateSuccess: return QLatin1String("UdpAssociateSuccess");
122  case QSocks5SocketEnginePrivate::BindSuccess: return QLatin1String("BindSuccess");
123  case QSocks5SocketEnginePrivate::ControlSocketError: return QLatin1String("ControlSocketError");
124  case QSocks5SocketEnginePrivate::SocksError: return QLatin1String("SocksError");
125  case QSocks5SocketEnginePrivate::HostNameLookupError: return QLatin1String("HostNameLookupError");
126  default: break;
127  }
128  return QLatin1String("unknown state");
129 }
130 
131 static QString dump(const QByteArray &buf)
132 {
133  QString data;
134  for (int i = 0; i < qMin<int>(MAX_DATA_DUMP, buf.size()); ++i) {
135  if (i) data += QLatin1Char(' ');
136  uint val = (unsigned char)buf.at(i);
137  // data += QString("0x%1").arg(val, 3, 16, QLatin1Char('0'));
138  data += QString::number(val);
139  }
140  if (buf.size() > MAX_DATA_DUMP)
141  data += QLatin1String(" ...");
142 
143  return QString::fromLatin1("size: %1 data: { %2 }").arg(buf.size()).arg(data);
144 }
145 
146 #else
147 # define QSOCKS5_DEBUG if (0) qDebug()
148 # define QSOCKS5_Q_DEBUG if (0) qDebug()
149 # define QSOCKS5_D_DEBUG if (0) qDebug()
150 
152 static inline QString dump(const QByteArray &) { return QString(); }
153 #endif
154 
155 /*
156  inserts the host address in buf at pos and updates pos.
157  if the func fails the data in buf and the vallue of pos is undefined
158 */
159 static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf)
160 {
161  QSOCKS5_DEBUG << "setting [" << address << ':' << port << ']';
162 
163  union {
164  quint16 port;
165  quint32 ipv4;
166  QIPv6Address ipv6;
167  char ptr;
168  } data;
169 
170  // add address
171  if (address.protocol() == QAbstractSocket::IPv4Protocol) {
172  data.ipv4 = qToBigEndian<quint32>(address.toIPv4Address());
173  pBuf->append(S5_IP_V4);
174  pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.ipv4));
175  } else if (address.protocol() == QAbstractSocket::IPv6Protocol) {
176  data.ipv6 = address.toIPv6Address();
177  pBuf->append(S5_IP_V6);
178  pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.ipv6));
179  } else {
180  return false;
181  }
182 
183  // add port
184  data.port = qToBigEndian<quint16>(port);
185  pBuf->append(QByteArray::fromRawData(&data.ptr, sizeof data.port));
186  return true;
187 }
188 
189 /*
190  like above, but for a hostname
191 */
192 static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 port, QByteArray *pBuf)
193 {
194  QSOCKS5_DEBUG << "setting [" << hostname << ':' << port << ']';
195 
196  QByteArray encodedHostName = QUrl::toAce(hostname);
197  QByteArray &buf = *pBuf;
198 
199  if (encodedHostName.length() > 255)
200  return false;
201 
202  buf.append(S5_DOMAINNAME);
203  buf.append(uchar(encodedHostName.length()));
204  buf.append(encodedHostName);
205 
206  // add port
207  union {
208  quint16 port;
209  char ptr;
210  } data;
211  data.port = qToBigEndian<quint16>(port);
212  buf.append(QByteArray::fromRawData(&data.ptr, sizeof data.port));
213 
214  return true;
215 }
216 
217 
218 /*
219  retrives the host address in buf at pos and updates pos.
220  if the func fails the value of the address and the pos is undefined
221 */
222 static bool qt_socks5_get_host_address_and_port(const QByteArray &buf, QHostAddress *pAddress, quint16 *pPort, int *pPos)
223 {
224  bool ret = false;
225  int pos = *pPos;
226  const unsigned char *pBuf = reinterpret_cast<const unsigned char*>(buf.constData());
227  QHostAddress address;
228  quint16 port = 0;
229 
230  if (buf.size() - pos < 1) {
231  QSOCKS5_DEBUG << "need more data address/port";
232  return false;
233  }
234  if (pBuf[pos] == S5_IP_V4) {
235  pos++;
236  if (buf.size() - pos < 4) {
237  QSOCKS5_DEBUG << "need more data for ip4 address";
238  return false;
239  }
240  address.setAddress(qFromBigEndian<quint32>(&pBuf[pos]));
241  pos += 4;
242  ret = true;
243  } else if (pBuf[pos] == S5_IP_V6) {
244  pos++;
245  if (buf.size() - pos < 16) {
246  QSOCKS5_DEBUG << "need more data for ip6 address";
247  return false;
248  }
250  for (int i = 0; i < 16; ++i)
251  add[i] = buf[pos++];
252  ret = true;
253  } else if (pBuf[pos] == S5_DOMAINNAME){
254  // just skip it
255  pos++;
256  qDebug() << "skipping hostname of len" << uint(pBuf[pos]);
257  pos += uchar(pBuf[pos]);
258  } else {
259  QSOCKS5_DEBUG << "invalid address type" << (int)pBuf[pos];
260  ret = false;
261  }
262 
263  if (ret) {
264  if (buf.size() - pos < 2) {
265  QSOCKS5_DEBUG << "need more data for port";
266  return false;
267  }
268  port = qFromBigEndian<quint16>(&pBuf[pos]);
269  pos += 2;
270  }
271 
272  if (ret) {
273  QSOCKS5_DEBUG << "got [" << address << ':' << port << ']';
274  *pAddress = address;
275  *pPort = port;
276  *pPos = pos;
277  }
278 
279  return ret;
280 }
281 
282 /*
283  Returns the difference between msecs and elapsed. If msecs is -1,
284  however, -1 is returned.
285 */
286 static int qt_timeout_value(int msecs, int elapsed)
287 {
288  if (msecs == -1)
289  return -1;
290 
291  int timeout = msecs - elapsed;
292  return timeout < 0 ? 0 : timeout;
293 }
294 
296 {
299 };
300 
302 {
304 };
305 
307 {
313 };
314 
316 {
320 };
321 
322 #ifndef QT_NO_UDPSOCKET
324 {
329 };
330 #endif
331 
332 // needs to be thread safe
333 class QSocks5BindStore : public QObject
334 {
335 public:
337  ~QSocks5BindStore();
338 
339  void add(int socketDescriptor, QSocks5BindData *bindData);
340  bool contains(int socketDescriptor);
341  QSocks5BindData *retrieve(int socketDescriptor);
342 
343 protected:
344  void timerEvent(QTimerEvent * event);
345 
348  //socket descriptor, data, timestamp
350 };
351 
352 Q_GLOBAL_STATIC(QSocks5BindStore, socks5BindStore)
353 
355  : mutex(QMutex::Recursive)
356  , sweepTimerId(-1)
357 {
359  if (app && app->thread() != thread())
360  moveToThread(app->thread());
361 }
362 
364 {
365 }
366 
367 void QSocks5BindStore::add(int socketDescriptor, QSocks5BindData *bindData)
368 {
369  QMutexLocker lock(&mutex);
370  if (store.contains(socketDescriptor)) {
371  // qDebug() << "delete it";
372  }
373  bindData->timeStamp.start();
374  store.insert(socketDescriptor, bindData);
375  // start sweep timer if not started
376  if (sweepTimerId == -1)
377  sweepTimerId = startTimer(60000);
378 }
379 
380 bool QSocks5BindStore::contains(int socketDescriptor)
381 {
382  QMutexLocker lock(&mutex);
383  return store.contains(socketDescriptor);
384 }
385 
387 {
388  QMutexLocker lock(&mutex);
389  if (!store.contains(socketDescriptor))
390  return 0;
391  QSocks5BindData *bindData = store.take(socketDescriptor);
392  if (bindData) {
393  if (bindData->controlSocket->thread() != QThread::currentThread()) {
394  qWarning("Can not access socks5 bind data from different thread");
395  return 0;
396  }
397  } else {
398  QSOCKS5_DEBUG << "__ERROR__ binddata == 0";
399  }
400  // stop the sweep timer if not needed
401  if (store.isEmpty()) {
402  killTimer(sweepTimerId);
403  sweepTimerId = -1;
404  }
405  return bindData;
406 }
407 
409 {
410  QMutexLocker lock(&mutex);
411  if (event->timerId() == sweepTimerId) {
412  QSOCKS5_DEBUG << "QSocks5BindStore performing sweep";
413  QMutableHashIterator<int, QSocks5BindData *> it(store);
414  while (it.hasNext()) {
415  it.next();
416  if (it.value()->timeStamp.hasExpired(350000)) {
417  QSOCKS5_DEBUG << "QSocks5BindStore removing JJJJ";
418  it.remove();
419  }
420  }
421  }
422 }
423 
425 {
426 }
427 
429 {
430 }
431 
433 {
434  return 0x00;
435 }
436 
438 {
439  Q_UNUSED(socket);
440  *completed = true;
441  return true;
442 }
443 
445 {
446  Q_UNUSED(socket);
447  *completed = true;
448  return true;
449 }
450 
452 {
453  *sealedBuf = buf;
454  return true;
455 }
456 
458 {
459  *buf = sealedBuf;
460  return true;
461 }
462 
464 {
465  return unSeal(sealedSocket->readAll(), buf);
466 }
467 
469 {
470  this->userName = userName;
471  this->password = password;
472 }
473 
475 {
476  return 0x02;
477 }
478 
480 {
481  *completed = false;
482  QByteArray uname = userName.toLatin1();
483  QByteArray passwd = password.toLatin1();
484  QByteArray dataBuf(3 + uname.size() + passwd.size(), 0);
485  char *buf = dataBuf.data();
486  int pos = 0;
487  buf[pos++] = S5_PASSWORDAUTH_VERSION;
488  buf[pos++] = uname.size();
489  memcpy(&buf[pos], uname.data(), uname.size());
490  pos += uname.size();
491  buf[pos++] = passwd.size();
492  memcpy(&buf[pos], passwd.data(), passwd.size());
493  return socket->write(dataBuf) == dataBuf.size();
494 }
495 
497 {
498  *completed = false;
499 
500  if (socket->bytesAvailable() < 2)
501  return true;
502 
503  QByteArray buf = socket->read(2);
504  if (buf.at(0) == S5_PASSWORDAUTH_VERSION && buf.at(1) == 0x00) {
505  *completed = true;
506  return true;
507  }
508 
509  // must disconnect
510  socket->close();
511  return false;
512 }
513 
515 {
516  return QLatin1String("Socks5 user name or password incorrect");
517 }
518 
519 
520 
522  : socks5State(Uninitialized)
523  , readNotificationEnabled(false)
524  , writeNotificationEnabled(false)
525  , exceptNotificationEnabled(false)
526  , socketDescriptor(-1)
527  , data(0)
528  , connectData(0)
529 #ifndef QT_NO_UDPSOCKET
530  , udpData(0)
531 #endif
532  , bindData(0)
533  , readNotificationActivated(false)
534  , writeNotificationActivated(false)
535  , readNotificationPending(false)
536  , writeNotificationPending(false)
537  , connectionNotificationPending(false)
538 {
539  mode = NoMode;
540 }
541 
543 {
544 }
545 
547 {
549 
550  mode = socks5Mode;
551  if (mode == ConnectMode) {
553  data = connectData;
554 #ifndef QT_NO_UDPSOCKET
555  } else if (mode == UdpAssociateMode) {
557  data = udpData;
558  udpData->udpSocket = new QUdpSocket(q);
559 #ifndef QT_NO_BEARERMANAGEMENT
560  udpData->udpSocket->setProperty("_q_networksession", q->property("_q_networksession"));
561 #endif
563  QObject::connect(udpData->udpSocket, SIGNAL(readyRead()),
566 #endif // QT_NO_UDPSOCKET
567  } else if (mode == BindMode) {
569  data = bindData;
570  }
571 
572  data->controlSocket = new QTcpSocket(q);
573 #ifndef QT_NO_BEARERMANAGEMENT
574  data->controlSocket->setProperty("_q_networksession", q->property("_q_networksession"));
575 #endif
591 
592  if (!proxyInfo.user().isEmpty() || !proxyInfo.password().isEmpty()) {
593  QSOCKS5_D_DEBUG << "using username/password authentication; user =" << proxyInfo.user();
595  } else {
596  QSOCKS5_D_DEBUG << "not using authentication";
598  }
599 }
600 
602 {
604 
605  switch (state) {
606  case Uninitialized:
607  case Authenticating:
609  case RequestMethodSent:
610  case Connected:
611  case UdpAssociateSuccess:
612  case BindSuccess:
613  // these aren't error states
614  return;
615 
616  case ConnectError:
617  case ControlSocketError: {
618  QAbstractSocket::SocketError controlSocketError = data->controlSocket->error();
619  if (socks5State != Connected) {
620  switch (controlSocketError) {
623  QSocks5SocketEngine::tr("Connection to proxy refused"));
624  break;
627  QSocks5SocketEngine::tr("Connection to proxy closed prematurely"));
628  break;
631  QSocks5SocketEngine::tr("Proxy host not found"));
632  break;
634  if (state == ConnectError) {
636  QSocks5SocketEngine::tr("Connection to proxy timed out"));
637  break;
638  }
639  /* fall through */
640  default:
641  q->setError(controlSocketError, data->controlSocket->errorString());
642  break;
643  }
644  } else {
645  q->setError(controlSocketError, data->controlSocket->errorString());
646  }
647  break;
648  }
649 
650  case AuthenticatingError:
652  extraMessage.isEmpty() ?
653  QSocks5SocketEngine::tr("Proxy authentication failed") :
654  QSocks5SocketEngine::tr("Proxy authentication failed: %1").arg(extraMessage));
655  break;
656 
657  case RequestError:
658  // error code set by caller (overload)
659  break;
660 
661  case SocksError:
663  QSocks5SocketEngine::tr("SOCKS version 5 protocol error"));
664  break;
665 
666  case HostNameLookupError:
668  QAbstractSocket::tr("Host not found"));
669  break;
670  }
671 
673  socks5State = state;
674 }
675 
677 {
679  switch (socks5error) {
680  case SocksFailure:
681  q->setError(QAbstractSocket::NetworkError,
682  QSocks5SocketEngine::tr("General SOCKSv5 server failure"));
683  break;
686  QSocks5SocketEngine::tr("Connection not allowed by SOCKSv5 server"));
687  break;
688  case NetworkUnreachable:
689  q->setError(QAbstractSocket::NetworkError,
690  QAbstractSocket::tr("Network unreachable"));
691  break;
692  case HostUnreachable:
694  QAbstractSocket::tr("Host not found"));
695  break;
696  case ConnectionRefused:
698  QAbstractSocket::tr("Connection refused"));
699  break;
700  case TTLExpired:
701  q->setError(QAbstractSocket::NetworkError,
702  QSocks5SocketEngine::tr("TTL expired"));
703  break;
704  case CommandNotSupported:
706  QSocks5SocketEngine::tr("SOCKSv5 command not supported"));
707  break;
710  QSocks5SocketEngine::tr("Address type not supported"));
711  break;
712 
713  default:
715  QSocks5SocketEngine::tr("Unknown SOCKSv5 proxy error code 0x%1").arg(int(socks5error), 16));
716  break;
717  }
718 
719  setErrorState(state, QString());
720 }
721 
723 {
725 
726  // we require authentication
727  QAuthenticator auth;
728  emit q->proxyAuthenticationRequired(proxyInfo, &auth);
729 
730  if (!auth.user().isEmpty() || !auth.password().isEmpty()) {
731  // we have new credentials, let's try again
732  QSOCKS5_DEBUG << "authentication failure: retrying connection";
734 
735  delete data->authenticator;
736  proxyInfo.setUser(auth.user());
739 
744  } else {
745  // authentication failure
746 
750  }
751 }
752 
754 {
755  // not enough data to begin
756  if (data->controlSocket->bytesAvailable() < 2)
757  return;
758 
759  QByteArray buf = data->controlSocket->read(2);
760  if (buf.at(0) != S5_VERSION_5) {
761  QSOCKS5_D_DEBUG << "Socks5 version incorrect";
765  return;
766  }
767 
768  bool authComplete = false;
769  if (uchar(buf.at(1)) == S5_AUTHMETHOD_NONE) {
770  authComplete = true;
771  } else if (uchar(buf.at(1)) == S5_AUTHMETHOD_NOTACCEPTABLE) {
772  reauthenticate();
773  return;
774  } else if (buf.at(1) != data->authenticator->methodId()
775  || !data->authenticator->beginAuthenticate(data->controlSocket, &authComplete)) {
776  setErrorState(AuthenticatingError, QLatin1String("Socks5 host did not support authentication method."));
777  socketError = QAbstractSocket::SocketAccessError; // change the socket error
779  return;
780  }
781 
782  if (authComplete)
784  else
786 }
787 
789 {
790  bool authComplete = false;
791  if (!data->authenticator->continueAuthenticate(data->controlSocket, &authComplete)) {
792  reauthenticate();
793  return;
794  }
795  if (authComplete)
797 }
798 
800 {
801  QHostAddress address;
802  quint16 port = 0;
803  char command = 0;
804  if (mode == ConnectMode) {
805  command = S5_CONNECT;
806  address = peerAddress;
807  port = peerPort;
808  } else if (mode == BindMode) {
809  command = S5_BIND;
810  address = localAddress;
811  port = localPort;
812  } else {
813 #ifndef QT_NO_UDPSOCKET
814  command = S5_UDP_ASSOCIATE;
815  address = localAddress; //data->controlSocket->localAddress();
816  port = localPort;
817 #endif
818  }
819 
820  QByteArray buf;
821  buf.reserve(270); // big enough for domain name;
822  buf[0] = S5_VERSION_5;
823  buf[1] = command;
824  buf[2] = 0x00;
825  if (peerName.isEmpty() && !qt_socks5_set_host_address_and_port(address, port, &buf)) {
826  QSOCKS5_DEBUG << "error setting address" << address << " : " << port;
827  //### set error code ....
828  return;
829  } else if (!peerName.isEmpty() && !qt_socks5_set_host_name_and_port(peerName, port, &buf)) {
830  QSOCKS5_DEBUG << "error setting address" << address << " : " << port;
831  //### set error code ....
832  return;
833  }
834  QSOCKS5_DEBUG << "sending" << dump(buf);
835  QByteArray sealedBuf;
836  if (!data->authenticator->seal(buf, &sealedBuf)) {
837  // ### Handle this error.
838  }
839  data->controlSocket->write(sealedBuf);
842 }
843 
845 {
847  QSOCKS5_DEBUG << "parseRequestMethodReply()";
848 
849  QByteArray inBuf;
850  if (!data->authenticator->unSeal(data->controlSocket, &inBuf)) {
851  // ### check error and not just not enough data
852  QSOCKS5_DEBUG << "unSeal failed, needs more data";
853  return;
854  }
855  QSOCKS5_DEBUG << dump(inBuf);
856  if (inBuf.size() < 2) {
857  QSOCKS5_DEBUG << "need more data for request reply header .. put this data somewhere";
858  return;
859  }
860 
861  QHostAddress address;
862  quint16 port = 0;
863 
864  if (inBuf.at(0) != S5_VERSION_5 || inBuf.length() < 3 || inBuf.at(2) != 0x00) {
865  QSOCKS5_DEBUG << "socks protocol error";
867  } else if (inBuf.at(1) != S5_SUCCESS) {
868  Socks5Error socks5Error = Socks5Error(inBuf.at(1));
869  QSOCKS5_DEBUG << "Request error :" << socks5Error;
870  if ((socks5Error == SocksFailure || socks5Error == ConnectionNotAllowed)
871  && !peerName.isEmpty()) {
872  // Dante seems to use this error code to indicate hostname resolution failure
874  } else {
875  setErrorState(RequestError, socks5Error);
876  }
877  } else {
878  // connection success, retrieve the remote addresses
879  int pos = 3;
880  if (!qt_socks5_get_host_address_and_port(inBuf, &address, &port, &pos)) {
881  QSOCKS5_DEBUG << "error getting address";
883  } else {
884  inBuf.remove(0, pos);
885  for (int i = inBuf.size() - 1; i >= 0 ; --i)
886  data->controlSocket->ungetChar(inBuf.at(i));
887  }
888  }
889 
891  // no error
892  localAddress = address;
893  localPort = port;
894 
895  if (mode == ConnectMode) {
897  // notify the upper layer that we're done
898  q->setState(QAbstractSocket::ConnectedState);
900  } else if (mode == BindMode) {
902  q->setState(QAbstractSocket::ListeningState);
903  } else {
905  }
906  } else if (socks5State == BindSuccess) {
907  // no error and we got a connection
908  bindData->peerAddress = address;
909  bindData->peerPort = port;
910 
912  } else {
913  // got an error
916  }
917 }
918 
920 {
922  readNotificationPending = false;
924  QSOCKS5_D_DEBUG << "emitting readNotification";
926  emit q->readNotification();
927  if (!qq)
928  return;
929  // check if there needs to be a new zero read notification
934  }
935  }
936 }
937 
939 {
943  QSOCKS5_D_DEBUG << "queueing readNotification";
945  QMetaObject::invokeMethod(q, "_q_emitPendingReadNotification", Qt::QueuedConnection);
946  }
947 }
948 
950 {
951  writeNotificationPending = false;
954  QSOCKS5_D_DEBUG << "emitting writeNotification";
955  emit q->writeNotification();
956  }
957 }
958 
960 {
964  QSOCKS5_D_DEBUG << "queueing writeNotification";
966  QMetaObject::invokeMethod(q, "_q_emitPendingWriteNotification", Qt::QueuedConnection);
967  }
968 }
969 
971 {
974  QSOCKS5_D_DEBUG << "emitting connectionNotification";
975  emit q->connectionNotification();
976 }
977 
979 {
981  QSOCKS5_D_DEBUG << "queueing connectionNotification";
983  QMetaObject::invokeMethod(q, "_q_emitPendingConnectionNotification", Qt::QueuedConnection);
984 }
985 
988 {
989 }
990 
992 {
994 
995  if (d->data) {
996  delete d->data->authenticator;
997  delete d->data->controlSocket;
998  }
999  if (d->connectData)
1000  delete d->connectData;
1001 #ifndef QT_NO_UDPSOCKET
1002  if (d->udpData) {
1003  delete d->udpData->udpSocket;
1004  delete d->udpData;
1005  }
1006 #endif
1007  if (d->bindData)
1008  delete d->bindData;
1009 }
1010 
1012 
1014 {
1016 
1017  d->socketDescriptor = descriptorCounter.fetchAndAddRelaxed(1);
1018 
1019  d->socketType = type;
1020  d->socketProtocol = protocol;
1021 
1022  return true;
1023 }
1024 
1026 {
1028 
1029  QSOCKS5_Q_DEBUG << "initialize" << socketDescriptor;
1030 
1031  // this is only valid for the other side of a bind, nothing else is supported
1032 
1033  if (socketState != QAbstractSocket::ConnectedState) {
1034  //### must be connected state ???
1035  return false;
1036  }
1037 
1038  QSocks5BindData *bindData = socks5BindStore()->retrieve(socketDescriptor);
1039  if (bindData) {
1040 
1041  d->socketState = QAbstractSocket::ConnectedState;
1042  d->socketType = QAbstractSocket::TcpSocket;
1043  d->connectData = new QSocks5ConnectData;
1044  d->data = d->connectData;
1046  d->data->controlSocket = bindData->controlSocket;
1047  bindData->controlSocket = 0;
1048  d->data->controlSocket->setParent(this);
1049  d->socketProtocol = d->data->controlSocket->localAddress().protocol();
1050  d->data->authenticator = bindData->authenticator;
1051  bindData->authenticator = 0;
1052  d->localPort = bindData->localPort;
1053  d->localAddress = bindData->localAddress;
1054  d->peerPort = bindData->peerPort;
1055  d->peerAddress = bindData->peerAddress;
1056  delete bindData;
1057 
1058  QObject::connect(d->data->controlSocket, SIGNAL(connected()), this, SLOT(_q_controlSocketConnected()),
1060  QObject::connect(d->data->controlSocket, SIGNAL(readyRead()), this, SLOT(_q_controlSocketReadNotification()),
1062  QObject::connect(d->data->controlSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_controlSocketBytesWritten()),
1064  QObject::connect(d->data->controlSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(_q_controlSocketError(QAbstractSocket::SocketError)),
1066  QObject::connect(d->data->controlSocket, SIGNAL(disconnected()), this, SLOT(_q_controlSocketDisconnected()),
1068  QObject::connect(d->data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
1069  this, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState)),
1071 
1073 
1074  if (d->data->controlSocket->bytesAvailable() != 0)
1075  d->_q_controlSocketReadNotification();
1076  return true;
1077  }
1078  return false;
1079 }
1080 
1082 {
1084  d->proxyInfo = networkProxy;
1085 }
1086 
1088 {
1089  Q_D(const QSocks5SocketEngine);
1090  return d->socketDescriptor;
1091 }
1092 
1094 {
1095  Q_D(const QSocks5SocketEngine);
1096  return d->socketType != QAbstractSocket::UnknownSocketType
1097  && d->socks5State != QSocks5SocketEnginePrivate::SocksError
1098  && (d->socketError == QAbstractSocket::UnknownSocketError
1099  || d->socketError == QAbstractSocket::SocketTimeoutError
1101 }
1102 
1104 {
1106 
1107  if (!d->data) {
1110 #ifndef QT_NO_UDPSOCKET
1111  } else if (socketType() == QAbstractSocket::UdpSocket) {
1113  // all udp needs to be bound
1114  if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0))
1115  return false;
1116 
1118  return true;
1119 #endif
1120  } else {
1121  qFatal("QSocks5SocketEngine::connectToHost: in QTcpServer mode");
1122  return false;
1123  }
1124  }
1125 
1126  if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized
1127  && d->socketState != QAbstractSocket::ConnectingState) {
1129  //limit buffer in internal socket, data is buffered in the external socket under application control
1130  d->data->controlSocket->setReadBufferSize(65536);
1131  d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1132  return false;
1133  }
1134  return false;
1135 }
1136 
1138 {
1140  QSOCKS5_DEBUG << "connectToHost" << address << ':' << port;
1141 
1142  setPeerAddress(address);
1143  setPeerPort(port);
1144  d->peerName.clear();
1145 
1146  return connectInternal();
1147 }
1148 
1150 {
1152 
1154  setPeerPort(port);
1155  d->peerName = hostname;
1156 
1157  return connectInternal();
1158 }
1159 
1161 {
1162  QSOCKS5_DEBUG << "_q_controlSocketConnected";
1163  QByteArray buf(3, 0);
1164  buf[0] = S5_VERSION_5;
1165  buf[1] = 0x01;
1166  buf[2] = data->authenticator->methodId();
1167  data->controlSocket->write(buf);
1168  socks5State = AuthenticationMethodsSent;
1169 }
1170 
1172 {
1173  QSOCKS5_D_DEBUG << "_q_controlSocketReadNotification socks5state" << s5StateToString(socks5State)
1174  << "bytes available" << data->controlSocket->bytesAvailable();
1175 
1176  if (data->controlSocket->bytesAvailable() == 0) {
1177  QSOCKS5_D_DEBUG << "########## bogus read why do we get these ... on windows only";
1178  return;
1179  }
1180 
1181  switch (socks5State) {
1182  case AuthenticationMethodsSent:
1183  parseAuthenticationMethodReply();
1184  break;
1185  case Authenticating:
1186  parseAuthenticatingReply();
1187  break;
1188  case RequestMethodSent:
1189  parseRequestMethodReply();
1190  break;
1191  case Connected: {
1192  QByteArray buf;
1193  if (!data->authenticator->unSeal(data->controlSocket, &buf)) {
1194  // qDebug() << "unseal error maybe need to wait for more data";
1195  }
1196  if (buf.size()) {
1197  QSOCKS5_DEBUG << dump(buf);
1198  connectData->readBuffer += buf;
1199  emitReadNotification();
1200  }
1201  break;
1202  }
1203  case BindSuccess:
1204  // only get here if command is bind
1205  if (mode == BindMode) {
1206  parseRequestMethodReply();
1207  break;
1208  }
1209 
1210  // fall through
1211  default:
1212  qWarning("QSocks5SocketEnginePrivate::_q_controlSocketReadNotification: "
1213  "Unexpectedly received data while in state=%d and mode=%d",
1214  socks5State, mode);
1215  break;
1216  };
1217 }
1218 
1220 {
1221  QSOCKS5_DEBUG << "_q_controlSocketBytesWritten";
1222 
1223  if (socks5State != Connected
1224  || (mode == ConnectMode
1225  && data->controlSocket->bytesToWrite()))
1226  return;
1227  if (data->controlSocket->bytesToWrite() < MaxWriteBufferSize) {
1228  emitWriteNotification();
1229  writeNotificationActivated = false;
1230  }
1231 }
1232 
1234 {
1235  QSOCKS5_D_DEBUG << "controlSocketError" << error << data->controlSocket->errorString();
1236 
1238  return; // ignore this error -- comes from the waitFor* functions
1239 
1241  && socks5State == Connected) {
1242  // clear the read buffer in connect mode so that bytes available returns 0
1243  // if there already is a read notification pending then this will be processed first
1244  if (!readNotificationPending)
1245  connectData->readBuffer.clear();
1246  emitReadNotification();
1247  data->controlSocket->close();
1248  // cause a disconnect in the outer socket
1249  emitWriteNotification();
1250  } else if (socks5State == Uninitialized
1251  || socks5State == AuthenticationMethodsSent
1252  || socks5State == Authenticating
1253  || socks5State == RequestMethodSent) {
1254  setErrorState(socks5State == Uninitialized ? ConnectError : ControlSocketError);
1255  data->controlSocket->close();
1256  emitConnectionNotification();
1257  } else {
1258  q_func()->setError(data->controlSocket->error(), data->controlSocket->errorString());
1259  emitReadNotification();
1260  emitWriteNotification();
1261  }
1262 }
1263 
1265 {
1266  QSOCKS5_D_DEBUG << "_q_controlSocketDisconnected";
1267 }
1268 
1270 {
1271  QSOCKS5_D_DEBUG << "_q_controlSocketStateChanged" << state;
1272 }
1273 
1274 #ifndef QT_NO_UDPSOCKET
1276 {
1277  // udp should be unbuffered so we need to do some polling at certain points
1278  if (udpData->udpSocket->hasPendingDatagrams())
1279  const_cast<QSocks5SocketEnginePrivate *>(this)->_q_udpSocketReadNotification();
1280 }
1281 
1283 {
1284  QSOCKS5_D_DEBUG << "_q_udpSocketReadNotification()";
1285 
1286  // check some state stuff
1287  if (!udpData->udpSocket->hasPendingDatagrams()) {
1288  QSOCKS5_D_DEBUG << "false read ??";
1289  return;
1290  }
1291 
1292  while (udpData->udpSocket->hasPendingDatagrams()) {
1293  QByteArray sealedBuf(udpData->udpSocket->pendingDatagramSize(), 0);
1294  QSOCKS5_D_DEBUG << "new datagram";
1295  udpData->udpSocket->readDatagram(sealedBuf.data(), sealedBuf.size());
1296  QByteArray inBuf;
1297  if (!data->authenticator->unSeal(sealedBuf, &inBuf)) {
1298  QSOCKS5_D_DEBUG << "failed unsealing datagram discarding";
1299  return;
1300  }
1301  QSOCKS5_DEBUG << dump(inBuf);
1302  int pos = 0;
1303  const char *buf = inBuf.constData();
1304  if (inBuf.size() < 4) {
1305  QSOCKS5_D_DEBUG << "bugus udp data, discarding";
1306  return;
1307  }
1308  QSocks5RevivedDatagram datagram;
1309  if (buf[pos++] != 0 || buf[pos++] != 0) {
1310  QSOCKS5_D_DEBUG << "invalid datagram discarding";
1311  return;
1312  }
1313  if (buf[pos++] != 0) { //### add fragmentation reading support
1314  QSOCKS5_D_DEBUG << "don't support fragmentation yet disgarding";
1315  return;
1316  }
1317  if (!qt_socks5_get_host_address_and_port(inBuf, &datagram.address, &datagram.port, &pos)) {
1318  QSOCKS5_D_DEBUG << "failed to get address from datagram disgarding";
1319  return;
1320  }
1321  datagram.data = QByteArray(&buf[pos], inBuf.size() - pos);
1322  udpData->pendingDatagrams.enqueue(datagram);
1323  }
1324  emitReadNotification();
1325 }
1326 #endif // QT_NO_UDPSOCKET
1327 
1329 {
1331 
1332  // when bind wee will block until the bind is finished as the info from the proxy server is needed
1333 
1334  if (!d->data) {
1337 #ifndef QT_NO_UDPSOCKET
1338  } else if (socketType() == QAbstractSocket::UdpSocket) {
1340 #endif
1341  } else {
1342  //### something invalid
1343  return false;
1344  }
1345  }
1346 
1347 #ifndef QT_NO_UDPSOCKET
1349  if (!d->udpData->udpSocket->bind(address, port)) {
1350  QSOCKS5_Q_DEBUG << "local udp bind failed";
1351  setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1352  return false;
1353  }
1354  d->localAddress = d->udpData->udpSocket->localAddress();
1355  d->localPort = d->udpData->udpSocket->localPort();
1356  } else
1357 #endif
1358  if (d->mode == QSocks5SocketEnginePrivate::BindMode) {
1359  d->localAddress = address;
1360  d->localPort = port;
1361  } else {
1362  //### something invalid
1363  return false;
1364  }
1365 
1366  int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT;
1367  QElapsedTimer stopWatch;
1368  stopWatch.start();
1369  d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
1370  if (!d->waitForConnected(msecs, 0) ||
1371  d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1372  // waitForConnected sets the error state and closes the socket
1373  QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString();
1374  return false;
1375  }
1376  if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
1378  return true;
1379 #ifndef QT_NO_UDPSOCKET
1380  } else if (d->socks5State == QSocks5SocketEnginePrivate::UdpAssociateSuccess) {
1382  d->udpData->associateAddress = d->localAddress;
1383  d->localAddress = QHostAddress();
1384  d->udpData->associatePort = d->localPort;
1385  d->localPort = 0;
1386  QUdpSocket dummy;
1387 #ifndef QT_NO_BEARERMANAGEMENT
1388  dummy.setProperty("_q_networksession", property("_q_networksession"));
1389 #endif
1391  if (!dummy.bind()
1392  || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0
1393  || !dummy.waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))
1394  || dummy.readDatagram(0,0, &d->localAddress, &d->localPort) != 0) {
1395  QSOCKS5_DEBUG << "udp actual address and port lookup failed";
1397  setError(dummy.error(), dummy.errorString());
1398  d->data->controlSocket->close();
1399  //### reset and error
1400  return false;
1401  }
1402  QSOCKS5_DEBUG << "udp actual address and port" << d->localAddress << ':' << d->localPort;
1403  return true;
1404 #endif // QT_NO_UDPSOCKET
1405  }
1406 
1407  // binding timed out
1409  QLatin1String(QT_TRANSLATE_NOOP("QSocks5SocketEngine", "Network operation timed out")));
1410 
1413  return false;
1414 }
1415 
1416 
1418 {
1420 
1421  QSOCKS5_Q_DEBUG << "listen()";
1422 
1423  // check that we are in bound and then go to listening.
1424  if (d->socketState == QAbstractSocket::BoundState) {
1425  d->socketState = QAbstractSocket::ListeningState;
1426 
1427  // check if we already have a connection
1428  if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1429  d->emitReadNotification();
1430 
1431  return true;
1432  }
1433  return false;
1434 }
1435 
1437 {
1439  // check we are listing ---
1440 
1441  QSOCKS5_Q_DEBUG << "accept()";
1442 
1443  if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
1444  QSOCKS5_Q_DEBUG << "BindSuccess adding" << d->socketDescriptor << "to the bind store";
1445  d->data->controlSocket->disconnect();
1446  d->data->controlSocket->setParent(0);
1447  d->bindData->localAddress = d->localAddress;
1448  d->bindData->localPort = d->localPort;
1449  int sd = d->socketDescriptor;
1450  socks5BindStore()->add(sd, d->bindData);
1451  d->data = 0;
1452  d->bindData = 0;
1453  d->socketDescriptor = 0;
1454  //### do something about this socket layer ... set it closed and an error about why ...
1455  // reset state and local port/address
1456  d->socks5State = QSocks5SocketEnginePrivate::Uninitialized; // ..??
1457  d->socketState = QAbstractSocket::UnconnectedState;
1458  return sd;
1459  }
1460  return -1;
1461 }
1462 
1464 {
1465  QSOCKS5_Q_DEBUG << "close()";
1467  if (d->data && d->data->controlSocket) {
1468  if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
1469  int msecs = 100;
1470  QElapsedTimer stopWatch;
1471  stopWatch.start();
1472  while (!d->data->controlSocket->bytesToWrite()) {
1473  if (!d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed())))
1474  break;
1475  }
1476  }
1477  d->data->controlSocket->close();
1478  }
1479 #ifndef QT_NO_UDPSOCKET
1480  if (d->udpData && d->udpData->udpSocket)
1481  d->udpData->udpSocket->close();
1482 #endif
1483 }
1484 
1486 {
1487  Q_D(const QSocks5SocketEngine);
1489  return d->connectData->readBuffer.size();
1490 #ifndef QT_NO_UDPSOCKET
1492  && !d->udpData->pendingDatagrams.isEmpty())
1493  return d->udpData->pendingDatagrams.first().data.size();
1494 #endif
1495  return 0;
1496 }
1497 
1499 {
1501  QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ')';
1503  if (d->connectData->readBuffer.size() == 0) {
1504  if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
1505  //imitate remote closed
1506  close();
1508  QLatin1String("Remote host closed connection###"));
1510  return -1;
1511  } else {
1512  return 0; // nothing to be read
1513  }
1514  }
1515  qint64 copy = qMin<qint64>(d->connectData->readBuffer.size(), maxlen);
1516  memcpy(data, d->connectData->readBuffer.constData(), copy);
1517  d->connectData->readBuffer.remove(0, copy);
1518  QSOCKS5_DEBUG << "read" << dump(QByteArray(data, copy));
1519  return copy;
1520 #ifndef QT_NO_UDPSOCKET
1521  } else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1522  return readDatagram(data, maxlen);
1523 #endif
1524  }
1525  return 0;
1526 }
1527 
1529 {
1531  QSOCKS5_Q_DEBUG << "write" << dump(QByteArray(data, len));
1532 
1534  // clamp down the amount of bytes to transfer at once
1535  len = qMin<qint64>(len, MaxWriteBufferSize) - d->data->controlSocket->bytesToWrite();
1536  if (len <= 0)
1537  return 0;
1538 
1539  QByteArray buf = QByteArray::fromRawData(data, len);
1540  QByteArray sealedBuf;
1541  if (!d->data->authenticator->seal(buf, &sealedBuf)) {
1542  // ### Handle this error.
1543  }
1544 
1545  qint64 written = d->data->controlSocket->write(sealedBuf);
1546  if (written <= 0) {
1547  QSOCKS5_Q_DEBUG << "native write returned" << written;
1548  return written;
1549  }
1550  d->data->controlSocket->waitForBytesWritten(0);
1551  //NB: returning len rather than written for the OK case, because the "sealing" may increase the length
1552  return len;
1553 #ifndef QT_NO_UDPSOCKET
1554  } else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
1555  // send to connected address
1556  return writeDatagram(data, len, d->peerAddress, d->peerPort);
1557 #endif
1558  }
1559  //### set an error ???
1560  return -1;
1561 }
1562 
1563 #ifndef QT_NO_UDPSOCKET
1564 #ifndef QT_NO_NETWORKINTERFACE
1566  const QNetworkInterface &)
1567 {
1569  QLatin1String("Operation on socket is not supported"));
1570  return false;
1571 }
1572 
1574  const QNetworkInterface &)
1575 {
1577  QLatin1String("Operation on socket is not supported"));
1578  return false;
1579 }
1580 
1581 
1583 {
1584  return QNetworkInterface();
1585 }
1586 
1588 {
1590  QLatin1String("Operation on socket is not supported"));
1591  return false;
1592 }
1593 #endif // QT_NO_NETWORKINTERFACE
1594 
1596  quint16 *port)
1597 {
1599 
1600  d->checkForDatagrams();
1601 
1602  if (d->udpData->pendingDatagrams.isEmpty())
1603  return 0;
1604 
1605  QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
1606  int copyLen = qMin<int>(maxlen, datagram.data.size());
1607  memcpy(data, datagram.data.constData(), copyLen);
1608  if (addr)
1609  *addr = datagram.address;
1610  if (port)
1611  *port = datagram.port;
1612  return copyLen;
1613 }
1614 
1616  quint16 port)
1617 {
1619 
1620  // it is possible to send with out first binding with udp, but socks5 requires a bind.
1621  if (!d->data) {
1623  // all udp needs to be bound
1624  if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0)) {
1625  //### set error
1626  return -1;
1627  }
1628  }
1629 
1630  QByteArray outBuf;
1631  outBuf.reserve(270 + len);
1632  outBuf[0] = 0x00;
1633  outBuf[1] = 0x00;
1634  outBuf[2] = 0x00;
1635  if (!qt_socks5_set_host_address_and_port(address, port, &outBuf)) {
1636  }
1637  outBuf += QByteArray(data, len);
1638  QSOCKS5_DEBUG << "sending" << dump(outBuf);
1639  QByteArray sealedBuf;
1640  if (!d->data->authenticator->seal(outBuf, &sealedBuf)) {
1641  QSOCKS5_DEBUG << "sealing data failed";
1642  setError(QAbstractSocket::SocketAccessError, d->data->authenticator->errorString());
1643  return -1;
1644  }
1645  if (d->udpData->udpSocket->writeDatagram(sealedBuf, d->udpData->associateAddress, d->udpData->associatePort) != sealedBuf.size()) {
1646  //### try frgamenting
1647  if (d->udpData->udpSocket->error() == QAbstractSocket::DatagramTooLargeError)
1648  setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1649  //### else maybe more serious error
1650  return -1;
1651  }
1652 
1653  return len;
1654 }
1655 
1657 {
1658  Q_D(const QSocks5SocketEngine);
1659  Q_INIT_CHECK(false);
1660 
1661  d->checkForDatagrams();
1662 
1663  return !d->udpData->pendingDatagrams.isEmpty();
1664 }
1665 
1667 {
1668  Q_D(const QSocks5SocketEngine);
1669 
1670  d->checkForDatagrams();
1671 
1672  if (!d->udpData->pendingDatagrams.isEmpty())
1673  return d->udpData->pendingDatagrams.head().data.size();
1674  return 0;
1675 }
1676 #endif // QT_NO_UDPSOCKET
1677 
1679 {
1680  Q_D(const QSocks5SocketEngine);
1681  if (d->data && d->data->controlSocket) {
1682  return d->data->controlSocket->bytesToWrite();
1683  } else {
1684  return 0;
1685  }
1686 }
1687 
1689 {
1690  Q_D(const QSocks5SocketEngine);
1691  if (d->data && d->data->controlSocket) {
1692  // convert the enum and call the real socket
1694  return d->data->controlSocket->socketOption(QAbstractSocket::LowDelayOption).toInt();
1696  return d->data->controlSocket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
1697  }
1698  return -1;
1699 }
1700 
1702 {
1704  if (d->data && d->data->controlSocket) {
1705  // convert the enum and call the real socket
1707  d->data->controlSocket->setSocketOption(QAbstractSocket::LowDelayOption, value);
1709  d->data->controlSocket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
1710  return true;
1711  }
1712  return false;
1713 }
1714 
1715 bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
1716 {
1717  if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1718  return false;
1719 
1720  const Socks5State wantedState =
1721  mode == ConnectMode ? Connected :
1722  mode == BindMode ? BindSuccess :
1723  UdpAssociateSuccess;
1724 
1725  QElapsedTimer stopWatch;
1726  stopWatch.start();
1727 
1728  while (socks5State != wantedState) {
1729  if (!data->controlSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
1730  if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1731  return true;
1732 
1734  if (timedOut && data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1735  *timedOut = true;
1736  return false;
1737  }
1738  }
1739 
1740  return true;
1741 }
1742 
1743 bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
1744 {
1746  QSOCKS5_DEBUG << "waitForRead" << msecs;
1747 
1748  d->readNotificationActivated = false;
1749 
1750  QElapsedTimer stopWatch;
1751  stopWatch.start();
1752 
1753  // are we connected yet?
1754  if (!d->waitForConnected(msecs, timedOut))
1755  return false;
1756  if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1757  return true;
1758 
1759  // we're connected
1762  while (!d->readNotificationActivated) {
1763  if (!d->data->controlSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
1764  if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1765  return true;
1766 
1767  setError(d->data->controlSocket->error(), d->data->controlSocket->errorString());
1768  if (timedOut && d->data->controlSocket->error() == QAbstractSocket::SocketTimeoutError)
1769  *timedOut = true;
1770  return false;
1771  }
1772  }
1773 #ifndef QT_NO_UDPSOCKET
1774  } else {
1775  while (!d->readNotificationActivated) {
1776  if (!d->udpData->udpSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
1777  setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
1778  if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
1779  *timedOut = true;
1780  return false;
1781  }
1782  }
1783 #endif // QT_NO_UDPSOCKET
1784  }
1785 
1786 
1787  bool ret = d->readNotificationActivated;
1788  d->readNotificationActivated = false;
1789 
1790  QSOCKS5_DEBUG << "waitForRead returned" << ret;
1791  return ret;
1792 }
1793 
1794 
1795 bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
1796 {
1798  QSOCKS5_DEBUG << "waitForWrite" << msecs;
1799 
1800  QElapsedTimer stopWatch;
1801  stopWatch.start();
1802 
1803  // are we connected yet?
1804  if (!d->waitForConnected(msecs, timedOut))
1805  return false;
1806  if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
1807  return true;
1808 
1809  // we're connected
1810 
1811  // flush any bytes we may still have buffered in the time that we have left
1812  if (d->data->controlSocket->bytesToWrite())
1813  d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed()));
1814  while ((msecs == -1 || stopWatch.elapsed() < msecs)
1815  && d->data->controlSocket->state() == QAbstractSocket::ConnectedState
1816  && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize)
1817  d->data->controlSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed()));
1818  return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
1819 }
1820 
1821 bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
1822  bool checkRead, bool checkWrite,
1823  int msecs, bool *timedOut)
1824 {
1825  Q_UNUSED(checkRead);
1826  if (!checkWrite) {
1827  bool canRead = waitForRead(msecs, timedOut);
1828  if (readyToRead)
1829  *readyToRead = canRead;
1830  return canRead;
1831  }
1832 
1833  bool canWrite = waitForWrite(msecs, timedOut);
1834  if (readyToWrite)
1835  *readyToWrite = canWrite;
1836  return canWrite;
1837 }
1838 
1840 {
1841  Q_D(const QSocks5SocketEngine);
1842  return d->readNotificationEnabled;
1843 }
1844 
1846 {
1848 
1849  QSOCKS5_Q_DEBUG << "setReadNotificationEnabled(" << enable << ')';
1850 
1851  bool emitSignal = false;
1852  if (!d->readNotificationEnabled
1853  && enable) {
1855  emitSignal = !d->connectData->readBuffer.isEmpty();
1856 #ifndef QT_NO_UDPSOCKET
1858  emitSignal = !d->udpData->pendingDatagrams.isEmpty();
1859 #endif
1860  else if (d->mode == QSocks5SocketEnginePrivate::BindMode
1861  && d->socketState == QAbstractSocket::ListeningState
1862  && d->socks5State == QSocks5SocketEnginePrivate::BindSuccess)
1863  emitSignal = true;
1864  }
1865 
1866  d->readNotificationEnabled = enable;
1867 
1868  if (emitSignal)
1869  d->emitReadNotification();
1870 }
1871 
1873 {
1874  Q_D(const QSocks5SocketEngine);
1875  return d->writeNotificationEnabled;
1876 }
1877 
1879 {
1881  d->writeNotificationEnabled = enable;
1882  if (enable && d->socketState == QAbstractSocket::ConnectedState) {
1883  if (d->mode == QSocks5SocketEnginePrivate::ConnectMode && d->data->controlSocket->bytesToWrite())
1884  return; // will be emitted as a result of bytes written
1885  d->emitWriteNotification();
1886  d->writeNotificationActivated = false;
1887  }
1888 }
1889 
1891 {
1892  Q_D(const QSocks5SocketEngine);
1893  return d->exceptNotificationEnabled;
1894 }
1895 
1897 {
1899  d->exceptNotificationEnabled = enable;
1900 }
1901 
1904  const QNetworkProxy &proxy, QObject *parent)
1905 {
1906  Q_UNUSED(socketType);
1907 
1908  // proxy type must have been resolved by now
1909  if (proxy.type() != QNetworkProxy::Socks5Proxy) {
1910  QSOCKS5_DEBUG << "not proxying";
1911  return 0;
1912  }
1914  engine->setProxy(proxy);
1915  return engine.take();
1916 }
1917 
1919 {
1920  QSOCKS5_DEBUG << "createSocketEngine" << socketDescriptor;
1921  if (socks5BindStore()->contains(socketDescriptor)) {
1922  QSOCKS5_DEBUG << "bind store contains" << socketDescriptor;
1923  return new QSocks5SocketEngine(parent);
1924  }
1925  return 0;
1926 }
1927 
1928 #endif // QT_NO_SOCKS5
1929 
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
QNetworkProxy::ProxyType type() const
Returns the proxy type for this instance.
void _q_controlSocketStateChanged(QAbstractSocket::SocketState)
double d
Definition: qnumeric_p.h:62
bool joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &interface)
QTcpSocket * controlSocket
bool connectToHost(const QHostAddress &address, quint16 port)
bool blockSignals(bool b)
If block is true, signals emitted by this object are blocked (i.e., emitting a signal will not invoke...
Definition: qobject.cpp:1406
bool setOption(SocketOption option, int value)
int type
Definition: qmetatype.cpp:239
The QUdpSocket class provides a UDP socket.
Definition: qudpsocket.h:59
Q_IPV6ADDR toIPv6Address() const
Returns the IPv6 address as a Q_IPV6ADDR structure.
static double elapsed(qint64 after, qint64 before)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
SocketType
This enum describes the transport layer protocol.
virtual bool continueAuthenticate(QTcpSocket *socket, bool *completed)
The QMutex class provides access serialization between threads.
Definition: qmutex.h:60
EventRef event
bool waitForReadyRead(int msecs=30000)
This function blocks until new data is available for reading and the QIODevice::readyRead() signal ha...
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
#define add(aName)
qint64 bytesAvailable() const
Returns the number of incoming bytes that are waiting to be read.
bool flush()
This function writes as much as possible from the internal write buffer to the underlying network soc...
bool setMulticastInterface(const QNetworkInterface &iface)
#define it(className, varName)
#define QSOCKS5_Q_DEBUG
QByteArray & append(char c)
Appends the character ch to this byte array.
#define S5_AUTHMETHOD_NOTACCEPTABLE
bool isExceptionNotificationEnabled() const
bool leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &interface)
#define error(msg)
void connectToHost(const QString &hostName, quint16 port, OpenMode mode=ReadWrite)
Attempts to make a connection to hostName on the given port.
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
#define SLOT(a)
Definition: qobjectdefs.h:226
T * take()
Returns the value of the pointer referenced by this object.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
Definition: qiodevice.cpp:1671
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object&#39;s name property to value.
Definition: qobject.cpp:3755
void setPeerAddress(const QHostAddress &address)
static const int MaxWriteBufferSize
QSocks5UdpAssociateData * udpData
#define S5_IP_V4
#define QT_TRANSLATE_NOOP(scope, x)
Marks the string literal sourceText for dynamic translation in the given context; i...
Definition: qglobal.h:2487
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
void setState(QAbstractSocket::SocketState state)
void setUser(const QString &userName)
Sets the user name for proxy authentication to be user.
bool contains(int socketDescriptor)
quint32 qFromBigEndian< quint32 >(const uchar *src)
Definition: qendian.h:239
quint32 toIPv4Address() const
Returns the IPv4 address as a number.
#define QT_NO_UDPSOCKET
NetworkLayerProtocol
This enum describes the network layer protocol values used in Qt.
bool bind(const QHostAddress &address, quint16 port)
void ungetChar(char c)
Puts the character c back into the device, and decrements the current position unless the position is...
Definition: qiodevice.cpp:1462
void abort()
Aborts the current connection and resets the socket.
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_BASIC_ATOMIC_INITIALIZER(a)
Definition: qbasicatomic.h:218
#define Q_D(Class)
Definition: qglobal.h:2482
bool isWriteNotificationEnabled() const
The QElapsedTimer class provides a fast way to calculate elapsed times.
Definition: qelapsedtimer.h:53
#define S5_DOMAINNAME
bool waitForRead(int msecs=30000, bool *timedOut=0)
qint64 elapsed() const
Returns the number of milliseconds since this QElapsedTimer was last started.
The QPointer class is a template class that provides guarded pointers to QObject. ...
Definition: qpointer.h:54
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon dest...
bool bind(const QHostAddress &address, quint16 port)
Binds this socket to the address address and the port port.
Definition: qudpsocket.cpp:255
#define Q_Q(Class)
Definition: qglobal.h:2483
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read...
Definition: qiodevice.cpp:791
SocketState
This enum describes the different states in which a socket can be.
void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object...
Q_CORE_EXPORT void qDebug(const char *,...)
#define SIGNAL(a)
Definition: qobjectdefs.h:227
unsigned char uchar
Definition: qglobal.h:994
The QNetworkProxy class provides a network layer proxy.
static QThread * currentThread()
Returns a pointer to a QThread which manages the currently executing thread.
Definition: qthread.cpp:419
static QByteArray toAce(const QString &)
Returns the ASCII Compatible Encoding of the given domain name domain.
Definition: qurl.cpp:6158
#define QSOCKS5_D_DEBUG
#define MAX_DATA_DUMP
void add(int socketDescriptor, QSocks5BindData *bindData)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QIntfbScreen * connected
void setError(QAbstractSocket::SocketError error, const QString &errorString) const
void setPeerPort(quint16 port)
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
bool waitForWrite(int msecs=30000, bool *timedOut=0)
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
#define S5_SUCCESS
QQueue< QSocks5RevivedDatagram > pendingDatagrams
qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr, quint16 port)
#define Q_GLOBAL_STATIC(TYPE, NAME)
Declares a global static variable with the given type and name.
Definition: qglobal.h:1968
virtual bool unSeal(const QByteArray sealedBuf, QByteArray *buf)
#define emit
Definition: qobjectdefs.h:76
static bool qt_socks5_get_host_address_and_port(const QByteArray &buf, QHostAddress *pAddress, quint16 *pPort, int *pPos)
SocketError
This enum describes the socket errors that can occur.
static QByteArray fromRawData(const char *, int size)
Constructs a QByteArray that uses the first size bytes of the data array.
unsigned short quint16
Definition: qglobal.h:936
Q_CORE_EXPORT void qWarning(const char *,...)
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition: qcoreevent.h:346
bool continueAuthenticate(QTcpSocket *socket, bool *completed)
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
QSocks5Authenticator * authenticator
QSocks5SocketEngine(QObject *parent=0)
bool connectToHostByName(const QString &name, quint16 port)
The QTcpSocket class provides a TCP socket.
Definition: qtcpsocket.h:56
void setProxy(const QNetworkProxy &networkProxy)
#define S5_VERSION_5
const T * ptr(const T &t)
QAbstractSocket::SocketError socketError
__int64 qint64
Definition: qglobal.h:942
void close()
Closes the I/O device for the socket, disconnects the socket&#39;s connection with the host...
The QAuthenticator class provides an authentication object.
void initialize(Socks5Mode socks5Mode)
quint16 qFromBigEndian< quint16 >(const uchar *src)
Definition: qendian.h:249
#define S5_IP_V6
int length() const
Same as size().
Definition: qbytearray.h:356
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
Q_CORE_EXPORT void qFatal(const char *,...)
The QCoreApplication class provides an event loop for console Qt applications.
void setWriteNotificationEnabled(bool enable)
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes...
Definition: qmutex.h:101
void setProxy(const QNetworkProxy &networkProxy)
Sets the explicit network proxy for this socket to networkProxy.
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
static int qt_timeout_value(int msecs, int elapsed)
static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf)
QAbstractSocket::NetworkLayerProtocol protocol() const
Returns the network layer protocol of the host address.
qint64 pendingDatagramSize() const
void setAddress(quint32 ip4Addr)
Set the IPv4 address specified by ip4Addr.
quint16 localPort() const
Returns the host port number (in native byte order) of the local socket if available; otherwise retur...
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:341
static QCoreApplication * instance()
Returns a pointer to the application&#39;s QCoreApplication (or QApplication) instance.
#define store(x)
virtual QAbstractSocketEngine * createSocketEngine(QAbstractSocket::SocketType socketType, const QNetworkProxy &, QObject *parent)
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
#define SOCKS5_BLOCKING_BIND_TIMEOUT
QAbstractSocket::SocketError error() const
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
QString user() const
returns the user used for authentication.
QHash< int, QSocks5BindData * > store
QAbstractSocket::NetworkLayerProtocol protocol() const
#define S5_BIND
unsigned int quint32
Definition: qglobal.h:938
quint16 port() const
Returns the port of the proxy host.
QSocks5BindData * retrieve(int socketDescriptor)
static QReadWriteLock lock
Definition: proxyconf.cpp:399
int fetchAndAddRelaxed(int valueToAdd)
static QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State)
QByteArray readAll()
Reads all available data from the device, and returns it as a QByteArray.
Definition: qiodevice.cpp:1025
QNetworkInterface multicastInterface() const
static QString dump(const QByteArray &)
#define Q_INIT_CHECK(returnValue)
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
#define S5_PASSWORDAUTH_VERSION
qint64 read(char *data, qint64 maxlen)
QVariant property(const char *name) const
Returns the value of the object&#39;s name property.
Definition: qobject.cpp:3807
QObject * parent
Definition: qobject.h:92
QString password() const
Returns the password used for authentication.
bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol=QAbstractSocket::IPv4Protocol)
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(0), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
Invokes the member (a signal or a slot name) on the object obj.
static QBasicAtomicInt descriptorCounter
qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr=0, quint16 *port=0)
void setReadNotificationEnabled(bool enable)
virtual bool beginAuthenticate(QTcpSocket *socket, bool *completed)
The QNetworkInterface class provides a listing of the host&#39;s IP addresses and network interfaces...
bool waitForConnected(int msecs, bool *timedOut)
QThread * thread() const
Returns the thread in which the object lives.
Definition: qobject.cpp:1419
The QHostAddress class provides an IP address.
Definition: qhostaddress.h:70
QAbstractSocket::SocketState state() const
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
QString password() const
returns the password used for authentication.
QSocks5ConnectData * connectData
#define S5_AUTHMETHOD_NONE
QString user() const
Returns the user name used for authentication.
char at(int i) const
Returns the character at index position i in the byte array.
Definition: qbytearray.h:413
SocketError error() const
Returns the type of error that last occurred.
void reserve(int size)
Attempts to allocate memory for at least size bytes.
Definition: qbytearray.h:449
#define S5_CONNECT
QAbstractSocket::SocketType socketType() const
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, int msecs=30000, bool *timedOut=0)
void setPassword(const QString &password)
Sets the password for proxy authentication to be password.
void _q_controlSocketError(QAbstractSocket::SocketError)
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 port, QByteArray *pBuf)
qint64 write(const char *data, qint64 len)
void start()
Starts this timer.
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *host=0, quint16 *port=0)
Receives a datagram no larger than maxSize bytes and stores it in data.
Definition: qudpsocket.cpp:583
#define QSOCKS5_DEBUG
QByteArray & remove(int index, int len)
Removes len bytes from the array, starting at index position pos, and returns a reference to the arra...
void clear()
Clears the contents of the byte array and makes it empty.
virtual bool seal(const QByteArray buf, QByteArray *sealedBuf)
int option(SocketOption option) const
SocketState state() const
Returns the state of the socket.
#define S5_UDP_ASSOCIATE
void setErrorState(Socks5State state, const QString &extraMessage=QString())
QSocks5PasswordAuthenticator(const QString &userName, const QString &password)
bool beginAuthenticate(QTcpSocket *socket, bool *completed)
void setExceptionNotificationEnabled(bool enable)
QString hostName() const
Returns the host name of the proxy host.
bool isReadNotificationEnabled() const