📄 qsocks5socketengine.cpp
字号:
bool QSocks5SocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol){ Q_D(QSocks5SocketEngine); d->socketDescriptor = descriptorCounter.fetchAndAdd(1); d->socketType = type; d->socketProtocol = protocol; return true;}bool QSocks5SocketEngine::initialize(int socketDescriptor, QAbstractSocket::SocketState socketState){ Q_D(QSocks5SocketEngine); QSOCKS5_Q_DEBUG << "initialize" << socketDescriptor; // this is only valid for the other side of a bind, nothing else is supported if (socketState != QAbstractSocket::ConnectedState) { //### must be connected state ??? return false; } QSocks5BindData *bindData = socks5BindStore()->retrieve(socketDescriptor); if (bindData) { d->socketState = socketState; d->socketType = QAbstractSocket::TcpSocket; d->connectData = new QSocks5ConnectData; d->data = d->connectData; d->mode = QSocks5SocketEnginePrivate::ConnectMode; d->data->controlSocket = bindData->controlSocket; bindData->controlSocket = 0; d->data->controlSocket->setParent(this); d->socketProtocol = d->data->controlSocket->localAddress().protocol(); d->data->authenticator = bindData->authenticator; bindData->authenticator = 0; d->localPort = bindData->localPort; d->localAddress = bindData->localAddress; d->peerPort = bindData->peerPort; d->peerAddress = bindData->peerAddress; delete bindData; QObject::connect(d->data->controlSocket, SIGNAL(connected()), this, SLOT(_q_controlSocketConnected())); QObject::connect(d->data->controlSocket, SIGNAL(readyRead()), this, SLOT(_q_controlSocketReadNotification())); QObject::connect(d->data->controlSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_controlSocketBytesWritten())); QObject::connect(d->data->controlSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(_q_controlSocketError(QAbstractSocket::SocketError))); QObject::connect(d->data->controlSocket, SIGNAL(disconnected()), this, SLOT(_q_controlSocketDisconnected())); QObject::connect(d->data->controlSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(_q_controlSocketStateChanged(QAbstractSocket::SocketState))); d->socks5State = QSocks5SocketEnginePrivate::Connected; if (d->data->controlSocket->bytesAvailable() != 0) d->_q_controlSocketReadNotification(); return true; } return false;}void QSocks5SocketEngine::setProxy(const QNetworkProxy &networkProxy){ Q_D(QSocks5SocketEngine); d->proxyInfo = networkProxy;}int QSocks5SocketEngine::socketDescriptor() const{ Q_D(const QSocks5SocketEngine); return d->socketDescriptor;}bool QSocks5SocketEngine::isValid() const{ Q_D(const QSocks5SocketEngine); return d->socketType != QAbstractSocket::UnknownSocketType && d->socketProtocol != QAbstractSocket::UnknownNetworkLayerProtocol && d->socks5State != QSocks5SocketEnginePrivate::SocksError && (d->socketError == QAbstractSocket::UnknownSocketError || d->socketError == QAbstractSocket::SocketTimeoutError);}bool QSocks5SocketEngine::connectToHost(const QHostAddress &address, quint16 port){ Q_D(QSocks5SocketEngine); QSOCKS5_DEBUG << "connectToHost" << address << ":" << port; if (!d->data) { if (socketType() == QAbstractSocket::TcpSocket) { d->initialize(QSocks5SocketEnginePrivate::ConnectMode);#ifndef QT_NO_UDPSOCKET } else if (socketType() == QAbstractSocket::UdpSocket) { d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode); // all udp needs to be bound if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0)) return false; d->peerAddress = address; d->peerPort = port; setState(QAbstractSocket::ConnectedState); return true;#endif } else { //### something invalied return false; } } if (d->socks5State == QSocks5SocketEnginePrivate::unInitialized && d->socketState != QAbstractSocket::ConnectingState) { setPeerAddress(address); setPeerPort(port); setState(QAbstractSocket::ConnectingState); d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port()); return false; } else if (d->socks5State == QSocks5SocketEnginePrivate::RequestSuccess) { setState(QAbstractSocket::ConnectedState); d->socks5State = QSocks5SocketEnginePrivate::Connected; // check for pending data if (d->data->controlSocket->bytesAvailable()) d->_q_controlSocketReadNotification(); return true; } else if (d->socks5State == QSocks5SocketEnginePrivate::RequestError) { setError(s5RAsSocketError(d->socks5Error), makeErrorString(d->socks5ErrorString)); setState(QAbstractSocket::UnconnectedState); return false; } else if (d->socks5State == QSocks5SocketEnginePrivate::ConnectError) { setError(d->data->controlSocket->error(), d->data->controlSocket->errorString()); setState(QAbstractSocket::UnconnectedState); return false; } else if (d->socks5State == QSocks5SocketEnginePrivate::AuthenticatingError) { setState(QAbstractSocket::UnconnectedState); return false; } else if (d->socketState == QAbstractSocket::ConnectingState && d->socks5State != QSocks5SocketEnginePrivate::RequestSuccess) { QSOCKS5_DEBUG << "not yet connected"; return false; } else { // qDebug() << "unexpected call to contectToHost"; } return false;}void QSocks5SocketEnginePrivate::_q_controlSocketConnected(){ QSOCKS5_DEBUG << "_q_controlSocketConnected"; QByteArray buf(3, 0); buf[0] = S5_VERSION_5; buf[1] = 0x01; buf[2] = data->authenticator->methodId(); data->controlSocket->write(buf); socks5State = AuthenticationMethodsSent;}void QSocks5SocketEnginePrivate::_q_controlSocketReadNotification(){ QSOCKS5_D_DEBUG << "_q_controlSocketReadNotification socks5state" << s5StateToString(socks5State) << "bytes available" << data->controlSocket->bytesAvailable(); if (data->controlSocket->bytesAvailable() == 0) { QSOCKS5_D_DEBUG << "########## bogus read why do we get these ... on windows only"; return; } switch (socks5State) { case AuthenticationMethodsSent: parseAuthenticationMethodReply(); break; case Authenticating: parseAuthenticatingReply(); break; case RequestMethodSent: parseRequestMethodReply(); break; case RequestSuccess: if (mode == BindMode) { // only get here if command is bind parseNewConnection(); } // else in conect mode but wating for second call to connectToHost break; case Connected: { QByteArray buf; if (!data->authenticator->unSeal(data->controlSocket, &buf)) { // qDebug() << "unseal error maybe need to wait for more data"; } if (buf.size()) { QSOCKS5_DEBUG << dump(buf); connectData->readBuffer += buf; emitReadNotification(); } break; } default: QSOCKS5_DEBUG << "why a _q_controlSocketReadNotification ????"; break; };}void QSocks5SocketEnginePrivate::_q_controlSocketBytesWritten(){ QSOCKS5_DEBUG << "_q_controlSocketBytesWritten"; if (socks5State != Connected || (mode == ConnectMode && data->controlSocket->bytesToWrite())) return; emitWriteNotification(); writeNotificationActivated = false;}void QSocks5SocketEnginePrivate::_q_controlSocketError(QAbstractSocket::SocketError error){ QSOCKS5_D_DEBUG << "controlSocketError" << error << data->controlSocket->errorString(); if (error == QAbstractSocket::RemoteHostClosedError) { // clear the read buffer in connect mode so that bytes available returns 0 // if there already is a read notification pending then this will be porcessed first if (mode == ConnectMode) { socks5State = ControlSocketError; if (!readNotificationPending) connectData->readBuffer.clear(); emitReadNotification(); } } else if (error == QAbstractSocket::ConnectionRefusedError || error == QAbstractSocket::HostNotFoundError) { socks5State = ConnectError; emitWriteNotification(); }}void QSocks5SocketEnginePrivate::_q_controlSocketDisconnected(){ QSOCKS5_D_DEBUG << "_q_controlSocketDisconnected";}void QSocks5SocketEnginePrivate::_q_controlSocketStateChanged(QAbstractSocket::SocketState state){ QSOCKS5_D_DEBUG << "_q_controlSocketStateChanged" << state;}#ifndef QT_NO_UDPSOCKETvoid QSocks5SocketEnginePrivate::checkForDatagrams() const{ // udp should be unbuffered so we need to do some polling at certain points if (udpData->udpSocket->hasPendingDatagrams()) const_cast<QSocks5SocketEnginePrivate *>(this)->_q_udpSocketReadNotification();}void QSocks5SocketEnginePrivate::_q_udpSocketReadNotification(){ QSOCKS5_D_DEBUG << "_q_udpSocketReadNotification()"; // check some state stuff if (!udpData->udpSocket->hasPendingDatagrams()) { QSOCKS5_D_DEBUG << "false read ??"; return; } while (udpData->udpSocket->hasPendingDatagrams()) { QByteArray sealedBuf(udpData->udpSocket->pendingDatagramSize(), 0); QSOCKS5_D_DEBUG << "new datagram"; udpData->udpSocket->readDatagram(sealedBuf.data(), sealedBuf.size()); QByteArray inBuf; if (!data->authenticator->unSeal(sealedBuf, &inBuf)) { QSOCKS5_D_DEBUG << "failed unsealing datagram discarding"; return; } QSOCKS5_DEBUG << dump(inBuf); int pos = 0; const char *buf = inBuf.constData(); if (inBuf.size() < 4) { QSOCKS5_D_DEBUG << "bugus udp data, discarding"; return; } QSocks5RevivedDatagram datagram; if (buf[pos++] != 0 || buf[pos++] != 0) { QSOCKS5_D_DEBUG << "invalid datagram discarding"; return; } if (buf[pos++] != 0) { //### add fragmentation reading support QSOCKS5_D_DEBUG << "don't support fragmentation yet disgarding"; return; } if (!qt_socks5_get_host_address_and_port(inBuf, &datagram.address, &datagram.port, &pos)) { QSOCKS5_D_DEBUG << "failed to get address from datagram disgarding"; return; } datagram.data = QByteArray(&buf[pos], inBuf.size() - pos); udpData->pendingDatagrams.enqueue(datagram); } emitReadNotification();}#endif // QT_NO_UDPSOCKETbool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port){ Q_D(QSocks5SocketEngine); // when bind wee will block until the bind is finished as the info from the proxy server is needed if (!d->data) { if (socketType() == QAbstractSocket::TcpSocket) { d->initialize(QSocks5SocketEnginePrivate::BindMode);#ifndef QT_NO_UDPSOCKET } else if (socketType() == QAbstractSocket::UdpSocket) { d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);#endif } else { //### something invalid return false; } }#ifndef QT_NO_UDPSOCKET if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) { if (!d->udpData->udpSocket->bind(address, port)) { QSOCKS5_Q_DEBUG << "local udp bind failed"; setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString()); return false; } d->localAddress = d->udpData->udpSocket->localAddress(); d->localPort = d->udpData->udpSocket->localPort(); } else#endif if (d->mode == QSocks5SocketEnginePrivate::BindMode) { d->localAddress = address; d->localPort = port; } else { //### something invalid return false; } int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT; QTime stopWatch; stopWatch.start(); d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port()); if (!d->data->controlSocket->waitForConnected(qt_timeout_value(msecs, stopWatch.elapsed()))) { if (d->data->controlSocket->error() != QAbstractSocket::SocketTimeoutError) { setError(d->data->controlSocket->error(), d->data->controlSocket->errorString()); } else { setError(QAbstractSocket::SocketTimeoutError, tr("Socks5 timeout error connecting to socks server")); } QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString(); return false; } while (d->data->controlSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) { // check error if (d->socks5State == QSocks5SocketEnginePrivate::RequestSuccess) { setState(QAbstractSocket::BoundState);#ifndef QT_NO_UDPSOCKET if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) { d->udpData->associateAddress = d->localAddress; d->localAddress = QHostAddress(); d->udpData->associatePort = d->localPort; d->localPort = 0; QUdpSocket dummy; QNetworkProxy proxy; proxy.setType(QNetworkProxy::NoProxy); dummy.setProxy(proxy); if (!dummy.bind() || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0 || !dummy.waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed())) || dummy.readDatagram(0,0, &d->localAddress, &d->localPort) != 0) { QSOCKS5_DEBUG << "udp actual address and port lookup failed"; //### reset and error return false; } QSOCKS5_DEBUG << "udp actual address and port" << d->localAddress << ":" << d->localPort; }#endif // QT_NO_UDPSOCKET return true; } QSOCKS5_DEBUG << "looping"; } // set error string = socks 5 timeout///### delete d->udpSocket;///### d->udpSocket = 0; return false;}bool QSocks5SocketEngine::listen(){ Q_D(QSocks5SocketEngine); QSOCKS5_Q_DEBUG << "listen()"; // check that we are in bound and then go to listening. if (d->socketState == QAbstractSocket::BoundState) { d->socketState = QAbstractSocket::ListeningState; // check if we already have a connection if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) d->emitReadNotification(); return true; } return false;}int QSocks5SocketEngine::accept(){ Q_D(QSocks5SocketEngine); // check we are listing --- QSOCKS5_Q_DEBUG << "accept()"; if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) { QSOCKS5_Q_DEBUG << "BindSuccess adding" << d->socketDescriptor << "to the bind store"; d->data->controlSocket->disconnect(); d->data->controlSocket->setParent(0); d->bindData->localAddress = d->localAddress; d->bindData->localPort = d->localPort; int sd = d->socketDescriptor; socks5BindStore()->add(sd, d->bindData); d->data = 0; d->bindData = 0; d->socketDescriptor = 0; //### do something about this socket layer ... set it closed and an error about why ... // reset state and local port/address d->socks5State = QSocks5SocketEnginePrivate::unInitialized; // ..?? d->socketState = QAbstractSocket::UnconnectedState; return sd; } else if (d->socks5State == QSocks5SocketEnginePrivate::BindError) { // what now } else if (d->socks5State == QSocks5SocketEnginePrivate::RequestSuccess) { // accept was called to early ... } return -1;}void QSocks5SocketEngine::close(){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -