diff options
Diffstat (limited to 'src/network/socket')
28 files changed, 545 insertions, 401 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 87607ef413..e456d00713 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -173,8 +173,9 @@ parameter describes the type of error that occurred. When this signal is emitted, the socket may not be ready for a reconnect - attempt. In that case, attempts to reconnect should be done from the event - loop. For example, use a QTimer::singleShot() with 0 as the timeout. + attempt. In that case, attempts to reconnect should be done from the + event loop. For example, use QChronoTimer::singleShot() with 0ns as + the timeout. QAbstractSocket::SocketError is not a registered metatype, so for queued connections, you will have to register it with Q_DECLARE_METATYPE() and @@ -439,7 +440,7 @@ #include <qmetaobject.h> #include <qpointer.h> #include <qtimer.h> -#include <qelapsedtimer.h> +#include <qdeadlinetimer.h> #include <qscopedvaluerollback.h> #include <qvarlengtharray.h> @@ -465,11 +466,12 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +using namespace std::chrono_literals; QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketState, QAbstractSocket__SocketState) QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketError, QAbstractSocket__SocketError) -static const int DefaultConnectTimeout = 30000; +static constexpr auto DefaultConnectTimeout = 30s; static bool isProxyError(QAbstractSocket::SocketError error) { @@ -636,11 +638,19 @@ bool QAbstractSocketPrivate::canReadNotification() return !q->isReadable(); } } else { - if (hasPendingData) { + const bool isUdpSocket = (socketType == QAbstractSocket::UdpSocket); + if (hasPendingData && (!isUdpSocket || hasPendingDatagram)) { socketEngine->setReadNotificationEnabled(false); return true; } - hasPendingData = true; + if (!isUdpSocket +#if QT_CONFIG(udpsocket) + || socketEngine->hasPendingDatagrams() +#endif + ) { + hasPendingData = true; + hasPendingDatagram = isUdpSocket; + } } emitReadyRead(); @@ -836,7 +846,7 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port) } // return the first that we can use - for (const QNetworkProxy &p : qAsConst(proxies)) { + for (const QNetworkProxy &p : std::as_const(proxies)) { if (socketType == QAbstractSocket::UdpSocket && (p.capabilities() & QNetworkProxy::UdpTunnelingCapability) == 0) continue; @@ -1057,8 +1067,7 @@ void QAbstractSocketPrivate::_q_connectToNextAddress() q, SLOT(_q_abortConnectionAttempt()), Qt::DirectConnection); } - int connectTimeout = DefaultConnectTimeout; - connectTimer->start(connectTimeout); + connectTimer->start(DefaultConnectTimeout); } // Wait for a write notification that will eventually call @@ -2052,8 +2061,7 @@ bool QAbstractSocket::waitForConnected(int msecs) bool wasPendingClose = d->pendingClose; d->pendingClose = false; - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline{msecs}; if (d->state == HostLookupState) { #if defined (QABSTRACTSOCKET_DEBUG) @@ -2073,22 +2081,21 @@ bool QAbstractSocket::waitForConnected(int msecs) if (state() == UnconnectedState) return false; // connect not im progress anymore! - int connectTimeout = DefaultConnectTimeout; bool timedOut = true; #if defined (QABSTRACTSOCKET_DEBUG) int attempt = 1; #endif - while (state() == ConnectingState && (msecs == -1 || stopWatch.elapsed() < msecs)) { - int timeout = qt_subtract_from_timeout(msecs, stopWatch.elapsed()); - if (msecs != -1 && timeout > connectTimeout) - timeout = connectTimeout; + while (state() == ConnectingState && !deadline.hasExpired()) { + QDeadlineTimer timer = deadline; + if (!deadline.isForever() && deadline.remainingTimeAsDuration() > DefaultConnectTimeout) + timer = QDeadlineTimer(DefaultConnectTimeout); #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::waitForConnected(%i) waiting %.2f secs for connection attempt #%i", - msecs, timeout / 1000.0, attempt++); + msecs, timer.remainingTime() / 1000.0, attempt++); #endif timedOut = false; - if (d->socketEngine && d->socketEngine->waitForWrite(timeout, &timedOut) && !timedOut) { + if (d->socketEngine && d->socketEngine->waitForWrite(timer, &timedOut) && !timedOut) { d->_q_testConnection(); } else { d->_q_connectToNextAddress(); @@ -2143,8 +2150,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs) return false; } - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline{msecs}; // handle a socket in connecting state if (state() == HostLookupState || state() == ConnectingState) { @@ -2160,7 +2166,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs) bool readyToRead = false; bool readyToWrite = false; if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(), - qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + deadline)) { #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)", msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData()); @@ -2178,7 +2184,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs) if (readyToWrite) d->canWriteNotification(); - } while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0); + } while (!deadline.hasExpired()); return false; } @@ -2214,8 +2220,7 @@ bool QAbstractSocket::waitForBytesWritten(int msecs) if (d->writeBuffer.isEmpty()) return false; - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline{msecs}; // handle a socket in connecting state if (state() == HostLookupState || state() == ConnectingState) { @@ -2223,13 +2228,13 @@ bool QAbstractSocket::waitForBytesWritten(int msecs) return false; } - forever { + for (;;) { bool readyToRead = false; bool readyToWrite = false; if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, !d->readBufferMaxSize || d->buffer.size() < d->readBufferMaxSize, !d->writeBuffer.isEmpty(), - qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + deadline)) { #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)", msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData()); @@ -2293,8 +2298,7 @@ bool QAbstractSocket::waitForDisconnected(int msecs) return false; } - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline{msecs}; // handle a socket in connecting state if (state() == HostLookupState || state() == ConnectingState) { @@ -2304,12 +2308,12 @@ bool QAbstractSocket::waitForDisconnected(int msecs) return true; } - forever { + for (;;) { bool readyToRead = false; bool readyToWrite = false; if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, state() == ConnectedState, !d->writeBuffer.isEmpty(), - qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + deadline)) { #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)", msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData()); diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index f421955e7e..1d5d45096a 100644 --- a/src/network/socket/qabstractsocket.h +++ b/src/network/socket/qabstractsocket.h @@ -8,7 +8,7 @@ #if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) #include <QtNetwork/qabstractsocket.h> #endif -#ifdef Q_CLANG_QDOC +#ifdef Q_QDOC #include <QtNetwork/qhostaddress.h> #endif #include <QtCore/qiodevice.h> @@ -129,7 +129,7 @@ public: virtual bool bind(const QHostAddress &address, quint16 port = 0, BindMode mode = DefaultForPlatform); -#if QT_VERSION >= QT_VERSION_CHECK(7,0,0) || defined(Q_CLANG_QDOC) +#if QT_VERSION >= QT_VERSION_CHECK(7,0,0) || defined(Q_QDOC) bool bind(QHostAddress::SpecialAddress addr, quint16 port = 0, BindMode mode = DefaultForPlatform) { return bind(QHostAddress(addr), port, mode); } bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform) diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 98d74dcfd4..cc5f53179c 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -110,6 +110,7 @@ public: qint64 readBufferMaxSize = 0; bool isBuffered = false; bool hasPendingData = false; + bool hasPendingDatagram = false; QTimer *connectTimer = nullptr; diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h index 4209a32ca7..9ee79cebc1 100644 --- a/src/network/socket/qabstractsocketengine_p.h +++ b/src/network/socket/qabstractsocketengine_p.h @@ -19,8 +19,9 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> #include "QtNetwork/qhostaddress.h" #include "QtNetwork/qabstractsocket.h" -#include "private/qobject_p.h" +#include <QtCore/qdeadlinetimer.h> #include "private/qnetworkdatagram_p.h" +#include "private/qobject_p.h" QT_BEGIN_NAMESPACE @@ -44,6 +45,8 @@ public: #endif }; +static constexpr std::chrono::seconds DefaultTimeout{30}; + class Q_AUTOTEST_EXPORT QAbstractSocketEngine : public QObject { Q_OBJECT @@ -98,7 +101,7 @@ public: virtual bool connectToHostByName(const QString &name, quint16 port) = 0; virtual bool bind(const QHostAddress &address, quint16 port) = 0; virtual bool listen(int backlog) = 0; - virtual int accept() = 0; + virtual qintptr accept() = 0; virtual void close() = 0; virtual qint64 bytesAvailable() const = 0; @@ -128,11 +131,14 @@ public: virtual int option(SocketOption option) const = 0; virtual bool setOption(SocketOption option, int value) = 0; - virtual bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) = 0; - virtual bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) = 0; + virtual bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) = 0; + virtual bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) = 0; virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = nullptr) = 0; + QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) = 0; QAbstractSocket::SocketError error() const; QString errorString() const; diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 260484aaf3..a700023bd5 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -7,7 +7,7 @@ #include "qurl.h" #include "private/qhttpnetworkreply_p.h" #include "private/qiodevice_p.h" -#include "qelapsedtimer.h" +#include "qdeadlinetimer.h" #include "qnetworkinterface.h" #if !defined(QT_NO_NETWORKPROXY) @@ -164,7 +164,7 @@ bool QHttpSocketEngine::listen(int backlog) return false; } -int QHttpSocketEngine::accept() +qintptr QHttpSocketEngine::accept() { qWarning("Operation is not supported"); setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1); @@ -310,19 +310,16 @@ bool QHttpSocketEngine::setOption(SocketOption option, int value) return false; } -bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut) +bool QHttpSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut) { Q_D(const QHttpSocketEngine); if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState) return false; - QElapsedTimer stopWatch; - stopWatch.start(); - // Wait for more data if nothing is available. if (!d->socket->bytesAvailable()) { - if (!d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + if (!d->socket->waitForReadyRead(deadline.remainingTime())) { if (d->socket->state() == QAbstractSocket::UnconnectedState) return true; setError(d->socket->error(), d->socket->errorString()); @@ -332,11 +329,7 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut) } } - // If we're not connected yet, wait until we are, or until an error - // occurs. - while (d->state != Connected && d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { - // Loop while the protocol handshake is taking place. - } + waitForProtocolHandshake(deadline); // Report any error that may occur. if (d->state != Connected) { @@ -348,14 +341,14 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut) return true; } -bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut) +bool QHttpSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut) { Q_D(const QHttpSocketEngine); // If we're connected, just forward the call. if (d->state == Connected) { if (d->socket->bytesToWrite()) { - if (!d->socket->waitForBytesWritten(msecs)) { + if (!d->socket->waitForBytesWritten(deadline.remainingTime())) { if (d->socket->error() == QAbstractSocket::SocketTimeoutError && timedOut) *timedOut = true; return false; @@ -364,15 +357,7 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut) return true; } - QElapsedTimer stopWatch; - stopWatch.start(); - - // If we're not connected yet, wait until we are, and until bytes have - // been received (i.e., the socket has connected, we have sent the - // greeting, and then received the response). - while (d->state != Connected && d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { - // Loop while the protocol handshake is taking place. - } + waitForProtocolHandshake(deadline); // Report any error that may occur. if (d->state != Connected) { @@ -386,25 +371,37 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut) bool QHttpSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs, bool *timedOut) + QDeadlineTimer deadline, bool *timedOut) { Q_UNUSED(checkRead); if (!checkWrite) { // Not interested in writing? Then we wait for read notifications. - bool canRead = waitForRead(msecs, timedOut); + bool canRead = waitForRead(deadline, timedOut); if (readyToRead) *readyToRead = canRead; return canRead; } // Interested in writing? Then we wait for write notifications. - bool canWrite = waitForWrite(msecs, timedOut); + bool canWrite = waitForWrite(deadline, timedOut); if (readyToWrite) *readyToWrite = canWrite; return canWrite; } +void QHttpSocketEngine::waitForProtocolHandshake(QDeadlineTimer deadline) const +{ + Q_D(const QHttpSocketEngine); + + // If we're not connected yet, wait until we are (and until bytes have + // been received, i.e. the socket has connected, we have sent the + // greeting, and then received the response), or until an error occurs. + while (d->state != Connected && d->socket->waitForReadyRead(deadline.remainingTime())) { + // Loop while the protocol handshake is taking place. + } +} + bool QHttpSocketEngine::isReadNotificationEnabled() const { Q_D(const QHttpSocketEngine); @@ -556,16 +553,8 @@ void QHttpSocketEngine::slotSocketReadNotification() d->authenticator.detach(); priv = QAuthenticatorPrivate::getPrivate(d->authenticator); - if (d->credentialsSent && priv->phase != QAuthenticatorPrivate::Phase2) { - // Remember that (e.g.) NTLM is two-phase, so only reset when the authentication is not currently in progress. - //407 response again means the provided username/password were invalid. - d->authenticator = QAuthenticator(); //this is needed otherwise parseHttpResponse won't set the state, and then signal isn't emitted. - d->authenticator.detach(); - priv = QAuthenticatorPrivate::getPrivate(d->authenticator); - priv->hasFailed = true; - } - - priv->parseHttpResponse(d->reply->header(), true, d->proxy.hostName()); + const auto headers = d->reply->header(); + priv->parseHttpResponse(headers, true, d->proxy.hostName()); if (priv->phase == QAuthenticatorPrivate::Invalid) { // problem parsing the reply @@ -576,6 +565,29 @@ void QHttpSocketEngine::slotSocketReadNotification() return; } + if (priv->phase == QAuthenticatorPrivate::Done + || (priv->phase == QAuthenticatorPrivate::Start + && (priv->method == QAuthenticatorPrivate::Ntlm + || priv->method == QAuthenticatorPrivate::Negotiate))) { + if (priv->phase == QAuthenticatorPrivate::Start) + priv->phase = QAuthenticatorPrivate::Phase1; + bool credentialsWasSent = d->credentialsSent; + if (d->credentialsSent) { + // Remember that (e.g.) NTLM is two-phase, so only reset when the authentication is + // not currently in progress. 407 response again means the provided + // username/password were invalid. + d->authenticator.detach(); + priv = QAuthenticatorPrivate::getPrivate(d->authenticator); + priv->hasFailed = true; + d->credentialsSent = false; + priv->phase = QAuthenticatorPrivate::Done; + } + if ((priv->method != QAuthenticatorPrivate::Ntlm + && priv->method != QAuthenticatorPrivate::Negotiate) + || credentialsWasSent) + proxyAuthenticationRequired(d->proxy, &d->authenticator); + } + bool willClose; QByteArray proxyConnectionHeader = d->reply->headerField("Proxy-Connection"); // Although most proxies use the unofficial Proxy-Connection header, the Connection header @@ -603,10 +615,8 @@ void QHttpSocketEngine::slotSocketReadNotification() d->reply = new QHttpNetworkReply(QUrl(), this); } - if (priv->phase == QAuthenticatorPrivate::Done) - proxyAuthenticationRequired(d->proxy, &d->authenticator); - // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above. if (priv->phase == QAuthenticatorPrivate::Done) { + d->authenticator = QAuthenticator(); setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required")); d->socket->disconnectFromHost(); } else { diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h index 77e3167ede..7926abf513 100644 --- a/src/network/socket/qhttpsocketengine_p.h +++ b/src/network/socket/qhttpsocketengine_p.h @@ -16,10 +16,12 @@ // #include <QtNetwork/private/qtnetworkglobal_p.h> -#include "private/qabstractsocketengine_p.h" + +#include <QtNetwork/qnetworkproxy.h> + #include "qabstractsocket.h" -#include "qnetworkproxy.h" #include "private/qauthenticator_p.h" +#include "private/qabstractsocketengine_p.h" QT_REQUIRE_CONFIG(http); @@ -60,7 +62,7 @@ public: bool connectToHostByName(const QString &name, quint16 port) override; bool bind(const QHostAddress &address, quint16 port) override; bool listen(int backlog) override; - int accept() override; + qintptr accept() override; void close() override; qint64 bytesAvailable() const override; @@ -90,11 +92,16 @@ public: int option(SocketOption option) const override; bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override; - bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override; + bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; + bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = nullptr) override; + QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; + + void waitForProtocolHandshake(QDeadlineTimer deadline) const; bool isReadNotificationEnabled() const override; void setReadNotificationEnabled(bool enable) override; diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index d96f540148..5ef2db6b94 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -265,9 +265,27 @@ bool QLocalServer::hasPendingConnections() const */ void QLocalServer::incomingConnection(quintptr socketDescriptor) { - Q_D(QLocalServer); QLocalSocket *socket = new QLocalSocket(this); socket->setSocketDescriptor(socketDescriptor); + addPendingConnection(socket); +} + +/*! + This function is called by QLocalServer::incomingConnection() + to add the \a socket to the list of pending incoming connections. + + \note Don't forget to call this member from reimplemented + incomingConnection() if you do not want to break the + Pending Connections mechanism. This function emits the + pendingConnectionAvailable() signal after the socket has been + added. + + \sa incomingConnection(), pendingConnectionAvailable() + \since 6.8 +*/ +void QLocalServer::addPendingConnection(QLocalSocket *socket) +{ + Q_D(QLocalServer); d->pendingConnections.enqueue(socket); emit newConnection(); } diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h index 81073450e2..685253e8be 100644 --- a/src/network/socket/qlocalserver.h +++ b/src/network/socket/qlocalserver.h @@ -68,6 +68,7 @@ public: protected: virtual void incomingConnection(quintptr socketDescriptor); + void addPendingConnection(QLocalSocket *socket); private: Q_DISABLE_COPY(QLocalServer) diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index dcd001a263..9aa9a5b86f 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -279,8 +279,7 @@ void QLocalServerPrivate::_q_onNewConnection() void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut) { pollfd pfd = qt_make_pollfd(listenSocket, POLLIN); - - switch (qt_poll_msecs(&pfd, 1, msec)) { + switch (qt_safe_poll(&pfd, 1, QDeadlineTimer(msec))) { case 0: if (timedOut) *timedOut = true; diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp index 0c447e90a4..af0dc988af 100644 --- a/src/network/socket/qlocalsocket_unix.cpp +++ b/src/network/socket/qlocalsocket_unix.cpp @@ -13,16 +13,17 @@ #include <errno.h> #include <qdir.h> +#include <qdeadlinetimer.h> #include <qdebug.h> -#include <qelapsedtimer.h> #include <qstringconverter.h> #ifdef Q_OS_VXWORKS # include <selectLib.h> #endif -#define QT_CONNECT_TIMEOUT 30000 +using namespace std::chrono_literals; +#define QT_CONNECT_TIMEOUT 30000 QT_BEGIN_NAMESPACE @@ -401,8 +402,8 @@ bool QLocalSocketPrivate::parseSockaddr(const struct ::sockaddr_un &addr, if (!name.isEmpty() && !toUtf16.hasError()) { //conversion encodes the trailing zeros. So, in case of non-abstract namespace we //chop them off as \0 character is not allowed in filenames - if (!abstractNamespace && (name.at(name.length() - 1) == QChar::fromLatin1('\0'))) { - int truncPos = name.length() - 1; + if (!abstractNamespace && (name.at(name.size() - 1) == QChar::fromLatin1('\0'))) { + int truncPos = name.size() - 1; while (truncPos > 0 && name.at(truncPos - 1) == QChar::fromLatin1('\0')) truncPos--; name.truncate(truncPos); @@ -585,21 +586,20 @@ bool QLocalSocket::waitForConnected(int msec) if (state() != ConnectingState) return (state() == ConnectedState); - QElapsedTimer timer; - timer.start(); - pollfd pfd = qt_make_pollfd(d->connectingSocket, POLLIN); - do { - const int timeout = (msec > 0) ? qMax(msec - timer.elapsed(), Q_INT64_C(0)) : msec; - const int result = qt_poll_msecs(&pfd, 1, timeout); + QDeadlineTimer deadline{msec}; + auto remainingTime = deadline.remainingTimeAsDuration(); + do { + const int result = qt_safe_poll(&pfd, 1, deadline); if (result == -1) d->setErrorAndEmit(QLocalSocket::UnknownSocketError, "QLocalSocket::waitForConnected"_L1); else if (result > 0) d->_q_connectToSocket(); - } while (state() == ConnectingState && !timer.hasExpired(msec)); + } while (state() == ConnectingState + && (remainingTime = deadline.remainingTimeAsDuration()) > 0ns); return (state() == ConnectedState); } diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index 8e7f3d539b..4c8b3ebf3f 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -78,7 +78,7 @@ \sa readDatagram(), QNetworkDatagram */ -#include "qnativesocketengine_p.h" +#include "qnativesocketengine_p_p.h" #include <qabstracteventdispatcher.h> #include <qsocketnotifier.h> @@ -679,7 +679,7 @@ bool QNativeSocketEngine::listen(int backlog) \sa bind(), listen() */ -int QNativeSocketEngine::accept() +qintptr QNativeSocketEngine::accept() { Q_D(QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1); @@ -948,23 +948,23 @@ void QNativeSocketEngine::close() d->peerAddress.clear(); d->inboundStreamCount = d->outboundStreamCount = 0; if (d->readNotifier) { - qDeleteInEventHandler(d->readNotifier); + delete d->readNotifier; d->readNotifier = nullptr; } if (d->writeNotifier) { - qDeleteInEventHandler(d->writeNotifier); + delete d->writeNotifier; d->writeNotifier = nullptr; } if (d->exceptNotifier) { - qDeleteInEventHandler(d->exceptNotifier); + delete d->exceptNotifier; d->exceptNotifier = nullptr; } } /*! - Waits for \a msecs milliseconds or until the socket is ready for - reading. If \a timedOut is not \nullptr and \a msecs milliseconds - have passed, the value of \a timedOut is set to true. + Waits until \a deadline has expired or until the socket is ready for + reading. If \a timedOut is not \nullptr and \a deadline has expired, + the value of \a timedOut is set to true. Returns \c true if data is available for reading; otherwise returns false. @@ -976,7 +976,7 @@ void QNativeSocketEngine::close() is to create a QSocketNotifier, passing the socket descriptor returned by socketDescriptor() to its constructor. */ -bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) +bool QNativeSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut) { Q_D(const QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false); @@ -986,7 +986,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) if (timedOut) *timedOut = false; - int ret = d->nativeSelect(msecs, true); + int ret = d->nativeSelect(deadline, true); if (ret == 0) { if (timedOut) *timedOut = true; @@ -1002,9 +1002,9 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) } /*! - Waits for \a msecs milliseconds or until the socket is ready for - writing. If \a timedOut is not \nullptr and \a msecs milliseconds - have passed, the value of \a timedOut is set to true. + Waits until \a deadline has expired or until the socket is ready for + writing. If \a timedOut is not \nullptr and \a deadline has expired, + the value of \a timedOut is set to true. Returns \c true if data is available for writing; otherwise returns false. @@ -1016,7 +1016,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) is to create a QSocketNotifier, passing the socket descriptor returned by socketDescriptor() to its constructor. */ -bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) +bool QNativeSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut) { Q_D(QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false); @@ -1026,7 +1026,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) if (timedOut) *timedOut = false; - int ret = d->nativeSelect(msecs, false); + int ret = d->nativeSelect(deadline, false); // On Windows, the socket is in connected state if a call to // select(writable) is successful. In this case we should not // issue a second call to WSAConnect() @@ -1074,14 +1074,14 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs, bool *timedOut) + QDeadlineTimer deadline, bool *timedOut) { Q_D(QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForReadOrWrite(), false); Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(), QAbstractSocket::UnconnectedState, false); - int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite); + int ret = d->nativeSelect(deadline, checkRead, checkWrite, readyToRead, readyToWrite); // On Windows, the socket is in connected state if a call to // select(writable) is successful. In this case we should not // issue a second call to WSAConnect() @@ -1255,7 +1255,7 @@ bool QReadNotifier::event(QEvent *e) class QWriteNotifier : public QSocketNotifier { public: - QWriteNotifier(int fd, QNativeSocketEngine *parent) + QWriteNotifier(qintptr fd, QNativeSocketEngine *parent) : QSocketNotifier(fd, QSocketNotifier::Write, parent) { engine = parent; } protected: @@ -1279,7 +1279,7 @@ bool QWriteNotifier::event(QEvent *e) class QExceptionNotifier : public QSocketNotifier { public: - QExceptionNotifier(int fd, QNativeSocketEngine *parent) + QExceptionNotifier(qintptr fd, QNativeSocketEngine *parent) : QSocketNotifier(fd, QSocketNotifier::Exception, parent) { engine = parent; } protected: diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index a9c6da1977..4c185b7a4a 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -20,8 +20,9 @@ #include "QtNetwork/qhostaddress.h" #include "QtNetwork/qnetworkinterface.h" #include "private/qabstractsocketengine_p.h" +#include "qplatformdefs.h" + #ifndef Q_OS_WIN -# include "qplatformdefs.h" # include <netinet/in.h> #else # include <winsock2.h> @@ -34,51 +35,63 @@ QT_BEGIN_NAMESPACE #ifdef Q_OS_WIN # define QT_SOCKLEN_T int # define QT_SOCKOPTLEN_T int - -// The following definitions are copied from the MinGW header mswsock.h which -// was placed in the public domain. The WSASendMsg and WSARecvMsg functions -// were introduced with Windows Vista, so some Win32 headers are lacking them. -// There are no known versions of Windows CE or Embedded that contain them. -# ifndef WSAID_WSARECVMSG -typedef INT (WINAPI *LPFN_WSARECVMSG)(SOCKET s, LPWSAMSG lpMsg, - LPDWORD lpdwNumberOfBytesRecvd, - LPWSAOVERLAPPED lpOverlapped, - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); -# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} -# endif // !WSAID_WSARECVMSG -# ifndef WSAID_WSASENDMSG -typedef struct { - LPWSAMSG lpMsg; - DWORD dwFlags; - LPDWORD lpNumberOfBytesSent; - LPWSAOVERLAPPED lpOverlapped; - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine; -} WSASENDMSG, *LPWSASENDMSG; - -typedef INT (WSAAPI *LPFN_WSASENDMSG)(SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags, - LPDWORD lpNumberOfBytesSent, - LPWSAOVERLAPPED lpOverlapped, - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - -# define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}} -# endif // !WSAID_WSASENDMSG -#endif // Q_OS_WIN - -union qt_sockaddr { - sockaddr a; - sockaddr_in a4; - sockaddr_in6 a6; -}; +#endif namespace { namespace SetSALen { template <typename T> void set(T *sa, typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len) { sa->sa_len = len; } + template <typename T> void set(T *sa, typename std::enable_if<(&T::sin_len, true), QT_SOCKLEN_T>::type len) + { sa->sin_len = len; } template <typename T> void set(T *sin6, typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len) { sin6->sin6_len = len; } template <typename T> void set(T *, ...) {} } + +inline QT_SOCKLEN_T setSockaddr(sockaddr_in *sin, const QHostAddress &addr, quint16 port = 0) +{ + *sin = {}; + SetSALen::set(sin, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + sin->sin_addr.s_addr = htonl(addr.toIPv4Address()); + return sizeof(*sin); +} + +inline QT_SOCKLEN_T setSockaddr(sockaddr_in6 *sin6, const QHostAddress &addr, quint16 port = 0) +{ + *sin6 = {}; + SetSALen::set(sin6, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(port); + memcpy(sin6->sin6_addr.s6_addr, addr.toIPv6Address().c, sizeof(sin6->sin6_addr)); +#if QT_CONFIG(networkinterface) + sin6->sin6_scope_id = QNetworkInterface::interfaceIndexFromName(addr.scopeId()); +#else + // it had better be a number then, if it is not empty + sin6->sin6_scope_id = addr.scopeId().toUInt(); +#endif + return sizeof(*sin6); +} + +inline QT_SOCKLEN_T setSockaddr(sockaddr *sa, const QHostAddress &addr, quint16 port = 0) +{ + switch (addr.protocol()) { + case QHostAddress::IPv4Protocol: + return setSockaddr(reinterpret_cast<sockaddr_in *>(sa), addr, port); + + case QHostAddress::IPv6Protocol: + case QHostAddress::AnyIPProtocol: + return setSockaddr(reinterpret_cast<sockaddr_in6 *>(sa), addr, port); + + case QHostAddress::UnknownNetworkLayerProtocol: + break; + } + *sa = {}; + sa->sa_family = AF_UNSPEC; + return 0; } +} // unnamed namespace class QNativeSocketEnginePrivate; #ifndef QT_NO_NETWORKINTERFACE @@ -103,7 +116,7 @@ public: bool connectToHostByName(const QString &name, quint16 port) override; bool bind(const QHostAddress &address, quint16 port) override; bool listen(int backlog) override; - int accept() override; + qintptr accept() override; void close() override; qint64 bytesAvailable() const override; @@ -141,11 +154,14 @@ public: int option(SocketOption option) const override; bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override; - bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override; + bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; + bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = nullptr) override; + QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool isReadNotificationEnabled() const override; void setReadNotificationEnabled(bool enable) override; @@ -163,132 +179,6 @@ private: Q_DISABLE_COPY_MOVE(QNativeSocketEngine) }; -class QSocketNotifier; - -class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate -{ - Q_DECLARE_PUBLIC(QNativeSocketEngine) -public: - QNativeSocketEnginePrivate(); - ~QNativeSocketEnginePrivate(); - - qintptr socketDescriptor; - - QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; - -#if defined(Q_OS_WIN) - LPFN_WSASENDMSG sendmsg; - LPFN_WSARECVMSG recvmsg; -# endif - enum ErrorString { - NonBlockingInitFailedErrorString, - BroadcastingInitFailedErrorString, - NoIpV6ErrorString, - RemoteHostClosedErrorString, - TimeOutErrorString, - ResourceErrorString, - OperationUnsupportedErrorString, - ProtocolUnsupportedErrorString, - InvalidSocketErrorString, - HostUnreachableErrorString, - NetworkUnreachableErrorString, - AccessErrorString, - ConnectionTimeOutErrorString, - ConnectionRefusedErrorString, - AddressInuseErrorString, - AddressNotAvailableErrorString, - AddressProtectedErrorString, - DatagramTooLargeErrorString, - SendDatagramErrorString, - ReceiveDatagramErrorString, - WriteErrorString, - ReadErrorString, - PortInuseErrorString, - NotSocketErrorString, - InvalidProxyTypeString, - TemporaryErrorString, - NetworkDroppedConnectionErrorString, - ConnectionResetErrorString, - - UnknownSocketErrorString = -1 - }; - - void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; - QHostAddress adjustAddressProtocol(const QHostAddress &address) const; - - // native functions - int option(QNativeSocketEngine::SocketOption option) const; - bool setOption(QNativeSocketEngine::SocketOption option, int value); - - bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol &protocol); - - bool nativeConnect(const QHostAddress &address, quint16 port); - bool nativeBind(const QHostAddress &address, quint16 port); - bool nativeListen(int backlog); - int nativeAccept(); -#ifndef QT_NO_NETWORKINTERFACE - bool nativeJoinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface); - bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface); - QNetworkInterface nativeMulticastInterface() const; - bool nativeSetMulticastInterface(const QNetworkInterface &iface); -#endif - qint64 nativeBytesAvailable() const; - - bool nativeHasPendingDatagrams() const; - qint64 nativePendingDatagramSize() const; - qint64 nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header, - QAbstractSocketEngine::PacketHeaderOptions options); - qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header); - qint64 nativeRead(char *data, qint64 maxLength); - qint64 nativeWrite(const char *data, qint64 length); - int nativeSelect(int timeout, bool selectForRead) const; - int nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const; - - void nativeClose(); - - bool checkProxy(const QHostAddress &address); - bool fetchConnectionParameters(); - -#if QT_CONFIG(networkinterface) - static uint scopeIdFromString(const QString &scopeid) - { return QNetworkInterface::interfaceIndexFromName(scopeid); } -#endif - - /*! \internal - Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize. - The address \a is converted to IPv6 if the current socket protocol is also IPv6. - */ - void setPortAndAddress(quint16 port, const QHostAddress &address, qt_sockaddr *aa, QT_SOCKLEN_T *sockAddrSize) - { - if (address.protocol() == QAbstractSocket::IPv6Protocol - || address.protocol() == QAbstractSocket::AnyIPProtocol - || socketProtocol == QAbstractSocket::IPv6Protocol - || socketProtocol == QAbstractSocket::AnyIPProtocol) { - memset(&aa->a6, 0, sizeof(sockaddr_in6)); - aa->a6.sin6_family = AF_INET6; -#if QT_CONFIG(networkinterface) - aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId()); -#endif - aa->a6.sin6_port = htons(port); - Q_IPV6ADDR tmp = address.toIPv6Address(); - memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp)); - *sockAddrSize = sizeof(sockaddr_in6); - SetSALen::set(&aa->a, sizeof(sockaddr_in6)); - } else { - memset(&aa->a, 0, sizeof(sockaddr_in)); - aa->a4.sin_family = AF_INET; - aa->a4.sin_port = htons(port); - aa->a4.sin_addr.s_addr = htonl(address.toIPv4Address()); - *sockAddrSize = sizeof(sockaddr_in); - SetSALen::set(&aa->a, sizeof(sockaddr_in)); - } - } - -}; - QT_END_NAMESPACE #endif // QNATIVESOCKETENGINE_P_H diff --git a/src/network/socket/qnativesocketengine_p_p.h b/src/network/socket/qnativesocketengine_p_p.h new file mode 100644 index 0000000000..189a4327fd --- /dev/null +++ b/src/network/socket/qnativesocketengine_p_p.h @@ -0,0 +1,189 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QNATIVESOCKETENGINE_P_P_H +#define QNATIVESOCKETENGINE_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qabstractsocketengine_p.h" +#include "private/qnativesocketengine_p.h" + +#ifndef Q_OS_WIN +# include <netinet/in.h> +#else +# include <winsock2.h> +# include <ws2tcpip.h> +# include <mswsock.h> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN + +// The following definitions are copied from the MinGW header mswsock.h which +// was placed in the public domain. The WSASendMsg and WSARecvMsg functions +// were introduced with Windows Vista, so some Win32 headers are lacking them. +// There are no known versions of Windows CE or Embedded that contain them. +# ifndef WSAID_WSARECVMSG +typedef INT (WINAPI *LPFN_WSARECVMSG)(SOCKET s, LPWSAMSG lpMsg, + LPDWORD lpdwNumberOfBytesRecvd, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); +# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} +# endif // !WSAID_WSARECVMSG +# ifndef WSAID_WSASENDMSG +typedef struct { + LPWSAMSG lpMsg; + DWORD dwFlags; + LPDWORD lpNumberOfBytesSent; + LPWSAOVERLAPPED lpOverlapped; + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine; +} WSASENDMSG, *LPWSASENDMSG; + +typedef INT (WSAAPI *LPFN_WSASENDMSG)(SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags, + LPDWORD lpNumberOfBytesSent, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + +# define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}} +# endif // !WSAID_WSASENDMSG +#endif // Q_OS_WIN + +union qt_sockaddr { + sockaddr a; + sockaddr_in a4; + sockaddr_in6 a6; +}; + +class QSocketNotifier; + +class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate +{ + Q_DECLARE_PUBLIC(QNativeSocketEngine) +public: + QNativeSocketEnginePrivate(); + ~QNativeSocketEnginePrivate(); + + qintptr socketDescriptor; + + QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; + +#if defined(Q_OS_WIN) + LPFN_WSASENDMSG sendmsg; + LPFN_WSARECVMSG recvmsg; +# endif + enum ErrorString { + NonBlockingInitFailedErrorString, + BroadcastingInitFailedErrorString, + NoIpV6ErrorString, + RemoteHostClosedErrorString, + TimeOutErrorString, + ResourceErrorString, + OperationUnsupportedErrorString, + ProtocolUnsupportedErrorString, + InvalidSocketErrorString, + HostUnreachableErrorString, + NetworkUnreachableErrorString, + AccessErrorString, + ConnectionTimeOutErrorString, + ConnectionRefusedErrorString, + AddressInuseErrorString, + AddressNotAvailableErrorString, + AddressProtectedErrorString, + DatagramTooLargeErrorString, + SendDatagramErrorString, + ReceiveDatagramErrorString, + WriteErrorString, + ReadErrorString, + PortInuseErrorString, + NotSocketErrorString, + InvalidProxyTypeString, + TemporaryErrorString, + NetworkDroppedConnectionErrorString, + ConnectionResetErrorString, + + UnknownSocketErrorString = -1 + }; + + void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; + QHostAddress adjustAddressProtocol(const QHostAddress &address) const; + + // native functions + int option(QNativeSocketEngine::SocketOption option) const; + bool setOption(QNativeSocketEngine::SocketOption option, int value); + + bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol &protocol); + + bool nativeConnect(const QHostAddress &address, quint16 port); + bool nativeBind(const QHostAddress &address, quint16 port); + bool nativeListen(int backlog); + qintptr nativeAccept(); +#ifndef QT_NO_NETWORKINTERFACE + bool nativeJoinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface); + bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface); + QNetworkInterface nativeMulticastInterface() const; + bool nativeSetMulticastInterface(const QNetworkInterface &iface); +#endif + qint64 nativeBytesAvailable() const; + + bool nativeHasPendingDatagrams() const; + qint64 nativePendingDatagramSize() const; + qint64 nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header, + QAbstractSocketEngine::PacketHeaderOptions options); + qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header); + qint64 nativeRead(char *data, qint64 maxLength); + qint64 nativeWrite(const char *data, qint64 length); + int nativeSelect(QDeadlineTimer deadline, bool selectForRead) const; + int nativeSelect(QDeadlineTimer deadline, bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) const; + + void nativeClose(); + + bool checkProxy(const QHostAddress &address); + bool fetchConnectionParameters(); + + /*! \internal + Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize. + The address \a is converted to IPv6 if the current socket protocol is also IPv6. + */ + void setPortAndAddress(quint16 port, const QHostAddress &address, qt_sockaddr *aa, QT_SOCKLEN_T *sockAddrSize) + { + switch (socketProtocol) { + case QHostAddress::IPv6Protocol: + case QHostAddress::AnyIPProtocol: + // force to IPv6 + setSockaddr(&aa->a6, address, port); + *sockAddrSize = sizeof(sockaddr_in6); + return; + + case QHostAddress::IPv4Protocol: + // force to IPv4 + setSockaddr(&aa->a4, address, port); + *sockAddrSize = sizeof(sockaddr_in); + return; + + case QHostAddress::UnknownNetworkLayerProtocol: + // don't force + break; + } + *sockAddrSize = setSockaddr(&aa->a, address, port); + } + +}; + +QT_END_NAMESPACE + +#endif // QNATIVESOCKETENGINE_P_P_H diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 2c2ea706e5..b6df412253 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -3,11 +3,11 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only //#define QNATIVESOCKETENGINE_DEBUG -#include "qnativesocketengine_p.h" +#include "qnativesocketengine_p_p.h" #include "private/qnet_unix_p.h" +#include "qdeadlinetimer.h" #include "qiodevice.h" #include "qhostaddress.h" -#include "qelapsedtimer.h" #include "qvarlengtharray.h" #include "qnetworkinterface.h" #include "qendian.h" @@ -17,15 +17,6 @@ #include <time.h> #include <errno.h> #include <fcntl.h> -#ifndef QT_NO_IPV6IFNAME -#include <net/if.h> -#endif -#ifdef QT_LINUXBASE -#include <arpa/inet.h> -#endif -#ifdef Q_OS_BSD4 -#include <net/if_dl.h> -#endif #ifdef Q_OS_INTEGRITY #include <sys/uio.h> #endif @@ -40,6 +31,9 @@ #include <sys/socket.h> #include <netinet/sctp.h> #endif +#ifdef Q_OS_BSD4 +# include <net/if_dl.h> +#endif QT_BEGIN_NAMESPACE @@ -442,6 +436,7 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 case EFAULT: case ENOTSOCK: socketState = QAbstractSocket::UnconnectedState; + break; default: break; } @@ -559,7 +554,7 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog) return true; } -int QNativeSocketEnginePrivate::nativeAccept() +qintptr QNativeSocketEnginePrivate::nativeAccept() { int acceptedDescriptor = qt_safe_accept(socketDescriptor, nullptr, nullptr); if (acceptedDescriptor == -1) { @@ -605,7 +600,7 @@ int QNativeSocketEnginePrivate::nativeAccept() } } - return acceptedDescriptor; + return qintptr(acceptedDescriptor); } #ifndef QT_NO_NETWORKINTERFACE @@ -729,10 +724,10 @@ QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const if (v.s_addr != 0 && sizeofv >= QT_SOCKOPTLEN_T(sizeof(v))) { QHostAddress ipv4(ntohl(v.s_addr)); QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces(); - for (int i = 0; i < ifaces.count(); ++i) { + for (int i = 0; i < ifaces.size(); ++i) { const QNetworkInterface &iface = ifaces.at(i); QList<QNetworkAddressEntry> entries = iface.addressEntries(); - for (int j = 0; j < entries.count(); ++j) { + for (int j = 0; j < entries.size(); ++j) { const QNetworkAddressEntry &entry = entries.at(j); if (entry.ip() == ipv4) return iface; @@ -752,7 +747,7 @@ bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInter struct in_addr v; if (iface.isValid()) { QList<QNetworkAddressEntry> entries = iface.addressEntries(); - for (int i = 0; i < entries.count(); ++i) { + for (int i = 0; i < entries.size(); ++i) { const QNetworkAddressEntry &entry = entries.at(i); const QHostAddress &ip = entry.ip(); if (ip.protocol() == QAbstractSocket::IPv4Protocol) { @@ -799,7 +794,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const // Peek 1 bytes into the next message. ssize_t readBytes; char c; - EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK)); + QT_EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK)); // If there's no error, or if our buffer was too small, there must be a // pending datagram. @@ -818,7 +813,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const #ifdef Q_OS_LINUX // Linux can return the actual datagram size if we use MSG_TRUNC char c; - EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC)); + QT_EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC)); #elif defined(SO_NREAD) // macOS can return the actual datagram size if we use SO_NREAD int value; @@ -1281,6 +1276,9 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); q->close(); break; +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif case EAGAIN: writtenBytes = 0; break; @@ -1350,16 +1348,17 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) return qint64(r); } -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const { bool dummy; - return nativeSelect(timeout, selectForRead, !selectForRead, &dummy, &dummy); + return nativeSelect(deadline, selectForRead, !selectForRead, &dummy, &dummy); } #ifndef Q_OS_WASM -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead, + bool checkWrite, bool *selectForRead, + bool *selectForWrite) const { pollfd pfd = qt_make_pollfd(socketDescriptor, 0); @@ -1369,7 +1368,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c if (checkWrite) pfd.events |= POLLOUT; - const int ret = qt_poll_msecs(&pfd, 1, timeout); + const int ret = qt_safe_poll(&pfd, 1, deadline); if (ret <= 0) return ret; @@ -1390,13 +1389,16 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c #else -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead, + bool checkWrite, bool *selectForRead, + bool *selectForWrite) const { *selectForRead = checkRead; *selectForWrite = checkWrite; bool socketDisconnect = false; - QEventDispatcherWasm::socketSelect(timeout, socketDescriptor, checkRead, checkWrite,selectForRead, selectForWrite, &socketDisconnect); + QEventDispatcherWasm::socketSelect(deadline.remainingTime(), socketDescriptor, checkRead, + checkWrite, selectForRead, selectForWrite, + &socketDisconnect); // The disconnect/close handling code in QAbstractsScket::canReadNotification() // does not detect remote disconnect properly; do that here as a workardound. diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 13fe03afa2..6525f46e30 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -2,13 +2,10 @@ // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -// Prevent windows system header files from defining min/max as macros. -#define NOMINMAX 1 - #include <winsock2.h> #include <ws2tcpip.h> -#include "qnativesocketengine_p.h" +#include "qnativesocketengine_p_p.h" #include <qabstracteventdispatcher.h> #include <qsocketnotifier.h> @@ -19,6 +16,7 @@ #include <qvarlengtharray.h> #include <algorithm> +#include <chrono> //#define QNATIVESOCKETENGINE_DEBUG #if defined(QNATIVESOCKETENGINE_DEBUG) @@ -773,10 +771,10 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog) return true; } -int QNativeSocketEnginePrivate::nativeAccept() +qintptr QNativeSocketEnginePrivate::nativeAccept() { - int acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0); - if (acceptedDescriptor == -1) { + SOCKET acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0); + if (acceptedDescriptor == INVALID_SOCKET) { int err = WSAGetLastError(); switch (err) { case WSAEACCES: @@ -810,7 +808,7 @@ int QNativeSocketEnginePrivate::nativeAccept() setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString); break; } - } else if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) { + } else if (acceptedDescriptor != INVALID_SOCKET && QAbstractEventDispatcher::instance()) { // Because of WSAAsyncSelect() WSAAccept returns a non blocking socket // with the same attributes as the listening socket including the current // WSAAsyncSelect(). To be able to change the socket to blocking mode the @@ -820,9 +818,9 @@ int QNativeSocketEnginePrivate::nativeAccept() n.setEnabled(false); } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor); + qDebug("QNativeSocketEnginePrivate::nativeAccept() == %lld", qint64(acceptedDescriptor)); #endif - return acceptedDescriptor; + return qintptr(acceptedDescriptor); } static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, @@ -1431,7 +1429,18 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength) return ret; } -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +inline timeval durationToTimeval(std::chrono::nanoseconds dur) noexcept +{ + using namespace std::chrono; + const auto secs = duration_cast<seconds>(dur); + const auto frac = duration_cast<microseconds>(dur - secs); + struct timeval tval; + tval.tv_sec = secs.count(); + tval.tv_usec = frac.count(); + return tval; +} + +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const { bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled(); if (readEnabled) @@ -1445,12 +1454,10 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co fds.fd_count = 1; fds.fd_array[0] = (SOCKET)socketDescriptor; - struct timeval tv; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; + struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration()); if (selectForRead) { - ret = select(0, &fds, 0, 0, timeout < 0 ? 0 : &tv); + ret = select(0, &fds, 0, 0, &tv); } else { // select for write @@ -1459,7 +1466,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co FD_ZERO(&fdexception); FD_SET((SOCKET)socketDescriptor, &fdexception); - ret = select(0, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv); + ret = select(0, 0, &fds, &fdexception, &tv); // ... but if it is actually set, pretend it did not happen if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception)) @@ -1472,7 +1479,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co return ret; } -int QNativeSocketEnginePrivate::nativeSelect(int timeout, +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const { @@ -1501,11 +1508,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, FD_SET((SOCKET)socketDescriptor, &fdexception); } - struct timeval tv; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; + struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration()); - ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); + ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, &tv); //... but if it is actually set, pretend it did not happen if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception)) diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h index c72e5745b0..a172a14a10 100644 --- a/src/network/socket/qnet_unix_p.h +++ b/src/network/socket/qnet_unix_p.h @@ -108,7 +108,7 @@ static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SO { int ret; // Solaris e.g. expects a non-const 2nd parameter - EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen)); + QT_EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen)); return ret; } #undef QT_SOCKET_CONNECT @@ -124,15 +124,10 @@ static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SO # undef listen #endif -// VxWorks' headers specify 'int' instead of '...' for the 3rd ioctl() parameter. template <typename T> static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg) { -#ifdef Q_OS_VXWORKS - return ::ioctl(sockfd, request, (int) arg); -#else return ::ioctl(sockfd, request, arg); -#endif } static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags) @@ -144,7 +139,7 @@ static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flag #endif int ret; - EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags)); + QT_EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags)); return ret; } @@ -152,7 +147,7 @@ static inline int qt_safe_recvmsg(int sockfd, struct msghdr *msg, int flags) { int ret; - EINTR_LOOP(ret, ::recvmsg(sockfd, msg, flags)); + QT_EINTR_LOOP(ret, ::recvmsg(sockfd, msg, flags)); return ret; } diff --git a/src/network/socket/qsctpserver.cpp b/src/network/socket/qsctpserver.cpp index 4e61a6c6bd..cd060d93e8 100644 --- a/src/network/socket/qsctpserver.cpp +++ b/src/network/socket/qsctpserver.cpp @@ -46,7 +46,7 @@ between endpoints. Call nextPendingDatagramConnection() to accept the pending datagram-mode connection as a connected QSctpSocket. - \note This feature is not supported on the Windows platform. + \note This class is not supported on the Windows platform. \sa QTcpServer, QSctpSocket, QAbstractSocket */ diff --git a/src/network/socket/qsctpserver.h b/src/network/socket/qsctpserver.h index 23ffdc770d..f82ae71f16 100644 --- a/src/network/socket/qsctpserver.h +++ b/src/network/socket/qsctpserver.h @@ -9,7 +9,7 @@ QT_BEGIN_NAMESPACE -#if !defined(QT_NO_SCTP) || defined(Q_CLANG_QDOC) +#if !defined(QT_NO_SCTP) || defined(Q_QDOC) class QSctpServerPrivate; class QSctpSocket; diff --git a/src/network/socket/qsctpsocket.cpp b/src/network/socket/qsctpsocket.cpp index 546c2d18bf..868c9e3785 100644 --- a/src/network/socket/qsctpsocket.cpp +++ b/src/network/socket/qsctpsocket.cpp @@ -74,7 +74,7 @@ etc. is allowed in datagram mode with the same limitations as in continuous byte stream mode. - \note This feature is not supported on the Windows platform. + \note This class is not supported on the Windows platform. \sa QSctpServer, QTcpSocket, QAbstractSocket */ @@ -83,7 +83,6 @@ #include "qsctpsocket_p.h" #include "qabstractsocketengine_p.h" -#include "private/qbytearray_p.h" #ifdef QSCTPSOCKET_DEBUG #include <qdebug.h> @@ -133,7 +132,7 @@ bool QSctpSocketPrivate::canReadNotification() bytesToRead = 4096; } - Q_ASSERT((datagramSize + qsizetype(bytesToRead)) < MaxByteArraySize); + Q_ASSERT((datagramSize + qsizetype(bytesToRead)) < QByteArray::max_size()); incomingDatagram.resize(datagramSize + int(bytesToRead)); #if defined (QSCTPSOCKET_DEBUG) diff --git a/src/network/socket/qsctpsocket.h b/src/network/socket/qsctpsocket.h index 13279ddb4a..8f0578ac26 100644 --- a/src/network/socket/qsctpsocket.h +++ b/src/network/socket/qsctpsocket.h @@ -9,7 +9,7 @@ QT_BEGIN_NAMESPACE -#if !defined(QT_NO_SCTP) || defined(Q_CLANG_QDOC) +#if !defined(QT_NO_SCTP) || defined(Q_QDOC) class QSctpSocketPrivate; diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index 8e1f9a5e34..0564ad7a33 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -9,6 +9,7 @@ #include "qdebug.h" #include "qhash.h" #include "qqueue.h" +#include "qdeadlinetimer.h" #include "qelapsedtimer.h" #include "qmutex.h" #include "qthread.h" @@ -20,18 +21,21 @@ #include <qendian.h> #include <qnetworkinterface.h> +#include <QtCore/qpointer.h> + #include <memory> QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +using namespace std::chrono_literals; static const int MaxWriteBufferSize = 128*1024; //#define QSOCKS5SOCKETLAYER_DEBUG #define MAX_DATA_DUMP 256 -#define SOCKS5_BLOCKING_BIND_TIMEOUT 5000 +static constexpr auto Socks5BlockingBindTimeout = 5s; #define Q_INIT_CHECK(returnValue) do { \ if (!d->data) { \ @@ -154,11 +158,11 @@ static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 po QByteArray encodedHostName = QUrl::toAce(hostname); QByteArray &buf = *pBuf; - if (encodedHostName.length() > 255) + if (encodedHostName.size() > 255) return false; buf.append(S5_DOMAINNAME); - buf.append(uchar(encodedHostName.length())); + buf.append(uchar(encodedHostName.size())); buf.append(encodedHostName); // add port @@ -317,9 +321,10 @@ void QSocks5BindStore::add(qintptr socketDescriptor, QSocks5BindData *bindData) } bindData->timeStamp.start(); store.insert(socketDescriptor, bindData); + // start sweep timer if not started if (sweepTimerId == -1) - sweepTimerId = startTimer(60000); + sweepTimerId = startTimer(1min); } bool QSocks5BindStore::contains(qintptr socketDescriptor) @@ -1325,11 +1330,8 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port) return false; } - int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT; - QElapsedTimer stopWatch; - stopWatch.start(); d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port()); - if (!d->waitForConnected(msecs, nullptr) || + if (!d->waitForConnected(QDeadlineTimer{Socks5BlockingBindTimeout}, nullptr) || d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) { // waitForConnected sets the error state and closes the socket QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString(); @@ -1379,7 +1381,7 @@ bool QSocks5SocketEngine::listen(int backlog) return false; } -int QSocks5SocketEngine::accept() +qintptr QSocks5SocketEngine::accept() { Q_D(QSocks5SocketEngine); // check we are listing --- @@ -1420,11 +1422,9 @@ void QSocks5SocketEngine::close() Q_D(QSocks5SocketEngine); if (d->data && d->data->controlSocket) { if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) { - int msecs = 100; - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline(100ms); while (!d->data->controlSocket->bytesToWrite()) { - if (!d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) + if (!d->data->controlSocket->waitForBytesWritten(deadline.remainingTime())) break; } } @@ -1445,7 +1445,7 @@ qint64 QSocks5SocketEngine::bytesAvailable() const #ifndef QT_NO_UDPSOCKET else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode && !d->udpData->pendingDatagrams.isEmpty()) - return d->udpData->pendingDatagrams.first().data.size(); + return d->udpData->pendingDatagrams.constFirst().data.size(); #endif return 0; } @@ -1677,7 +1677,7 @@ bool QSocks5SocketEngine::setOption(SocketOption option, int value) return false; } -bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut) +bool QSocks5SocketEnginePrivate::waitForConnected(QDeadlineTimer deadline, bool *timedOut) { if (data->controlSocket->state() == QAbstractSocket::UnconnectedState) return false; @@ -1687,11 +1687,8 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut) mode == BindMode ? BindSuccess : UdpAssociateSuccess; - QElapsedTimer stopWatch; - stopWatch.start(); - while (socks5State != wantedState) { - if (!data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + if (!data->controlSocket->waitForReadyRead(deadline.remainingTime())) { if (data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; @@ -1705,18 +1702,15 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut) return true; } -bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) +bool QSocks5SocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut) { Q_D(QSocks5SocketEngine); - QSOCKS5_DEBUG << "waitForRead" << msecs; + QSOCKS5_DEBUG << "waitForRead" << deadline.remainingTimeAsDuration(); d->readNotificationActivated = false; - QElapsedTimer stopWatch; - stopWatch.start(); - // are we connected yet? - if (!d->waitForConnected(msecs, timedOut)) + if (!d->waitForConnected(deadline, timedOut)) return false; if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; @@ -1730,7 +1724,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) if (d->mode == QSocks5SocketEnginePrivate::ConnectMode || d->mode == QSocks5SocketEnginePrivate::BindMode) { while (!d->readNotificationActivated) { - if (!d->data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + if (!d->data->controlSocket->waitForReadyRead(deadline.remainingTime())) { if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; @@ -1743,7 +1737,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) #ifndef QT_NO_UDPSOCKET } else { while (!d->readNotificationActivated) { - if (!d->udpData->udpSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + if (!d->udpData->udpSocket->waitForReadyRead(deadline.remainingTime())) { setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString()); if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError) *timedOut = true; @@ -1762,16 +1756,13 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) } -bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut) +bool QSocks5SocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut) { Q_D(QSocks5SocketEngine); - QSOCKS5_DEBUG << "waitForWrite" << msecs; - - QElapsedTimer stopWatch; - stopWatch.start(); + QSOCKS5_DEBUG << "waitForWrite" << deadline.remainingTimeAsDuration(); // are we connected yet? - if (!d->waitForConnected(msecs, timedOut)) + if (!d->waitForConnected(deadline, timedOut)) return false; if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; @@ -1780,27 +1771,32 @@ bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut) // flush any bytes we may still have buffered in the time that we have left if (d->data->controlSocket->bytesToWrite()) - d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed())); - while ((msecs == -1 || stopWatch.elapsed() < msecs) - && d->data->controlSocket->state() == QAbstractSocket::ConnectedState - && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize) - d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed())); + d->data->controlSocket->waitForBytesWritten(deadline.remainingTime()); + + auto shouldWriteBytes = [&]() { + return d->data->controlSocket->state() == QAbstractSocket::ConnectedState + && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize; + }; + + qint64 remainingTime = deadline.remainingTime(); + for (; remainingTime > 0 && shouldWriteBytes(); remainingTime = deadline.remainingTime()) + d->data->controlSocket->waitForBytesWritten(remainingTime); return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize; } bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs, bool *timedOut) + QDeadlineTimer deadline, bool *timedOut) { Q_UNUSED(checkRead); if (!checkWrite) { - bool canRead = waitForRead(msecs, timedOut); + bool canRead = waitForRead(deadline, timedOut); if (readyToRead) *readyToRead = canRead; return canRead; } - bool canWrite = waitForWrite(msecs, timedOut); + bool canWrite = waitForWrite(deadline, timedOut); if (readyToWrite) *readyToWrite = canWrite; return canWrite; diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h index 3d9ccf0ba1..3a169812df 100644 --- a/src/network/socket/qsocks5socketengine_p.h +++ b/src/network/socket/qsocks5socketengine_p.h @@ -16,8 +16,10 @@ // #include <QtNetwork/private/qtnetworkglobal_p.h> + +#include <QtNetwork/qnetworkproxy.h> + #include "qabstractsocketengine_p.h" -#include "qnetworkproxy.h" QT_REQUIRE_CONFIG(socks5); @@ -46,7 +48,7 @@ public: bool connectToHostByName(const QString &name, quint16 port) override; bool bind(const QHostAddress &address, quint16 port) override; bool listen(int backlog) override; - int accept() override; + qintptr accept() override; void close() override; qint64 bytesAvailable() const override; @@ -76,11 +78,14 @@ public: int option(SocketOption option) const override; bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override; - bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override; + bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; + bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = nullptr) override; + QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool isReadNotificationEnabled() const override; void setReadNotificationEnabled(bool enable) override; @@ -206,7 +211,7 @@ public: void parseRequestMethodReply(); void parseNewConnection(); - bool waitForConnected(int msecs, bool *timedOut); + bool waitForConnected(QDeadlineTimer deadline, bool *timedOut); void _q_controlSocketConnected(); void _q_controlSocketReadNotification(); diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp index 95d1877a5d..a0c0f00aaa 100644 --- a/src/network/socket/qtcpserver.cpp +++ b/src/network/socket/qtcpserver.cpp @@ -43,8 +43,8 @@ use waitForNewConnection(), which blocks until either a connection is available or a timeout expires. - \sa QTcpSocket, {Fortune Server Example}, {Threaded Fortune Server Example}, - {Loopback Example}, {Torrent Example} + \sa QTcpSocket, {Fortune Server}, {Threaded Fortune Server}, + {Torrent Example} */ /*! \fn void QTcpServer::newConnection() @@ -133,7 +133,7 @@ QNetworkProxy QTcpServerPrivate::resolveProxy(const QHostAddress &address, quint } // return the first that we can use - for (const QNetworkProxy &p : qAsConst(proxies)) { + for (const QNetworkProxy &p : std::as_const(proxies)) { if (socketType == QAbstractSocket::TcpSocket && (p.capabilities() & QNetworkProxy::ListeningCapability) != 0) return p; @@ -172,7 +172,7 @@ void QTcpServerPrivate::readNotification() { Q_Q(QTcpServer); for (;;) { - if (pendingConnections.count() >= maxConnections) { + if (totalPendingConnections() >= maxConnections) { #if defined (QTCPSERVER_DEBUG) qDebug("QTcpServerPrivate::_q_processIncomingConnection() too many connections"); #endif @@ -181,7 +181,7 @@ void QTcpServerPrivate::readNotification() return; } - int descriptor = socketEngine->accept(); + qintptr descriptor = socketEngine->accept(); if (descriptor == -1) { if (socketEngine->error() != QAbstractSocket::TemporaryError) { q->pauseAccepting(); @@ -206,6 +206,20 @@ void QTcpServerPrivate::readNotification() } /*! + \internal + Return the amount of sockets currently in queue for the server. + This is to make maxPendingConnections work properly with servers that don't + necessarily have 'ready-to-go' sockets as soon as they connect, + e.g. QSslServer. + By default we just return pendingConnections.size(), which is equivalent to + what it did before. +*/ +int QTcpServerPrivate::totalPendingConnections() const +{ + return int(pendingConnections.size()); +} + +/*! Constructs a QTcpServer object. \a parent is passed to the QObject constructor. @@ -484,7 +498,7 @@ bool QTcpServer::waitForNewConnection(int msec, bool *timedOut) if (d->state != QAbstractSocket::ListeningState) return false; - if (!d->socketEngine->waitForRead(msec, timedOut)) { + if (!d->socketEngine->waitForRead(QDeadlineTimer(msec), timedOut)) { d->serverSocketError = d->socketEngine->error(); d->serverSocketErrorString = d->socketEngine->errorString(); return false; diff --git a/src/network/socket/qtcpserver_p.h b/src/network/socket/qtcpserver_p.h index a526549538..853a4aaf96 100644 --- a/src/network/socket/qtcpserver_p.h +++ b/src/network/socket/qtcpserver_p.h @@ -56,6 +56,7 @@ public: #endif virtual void configureCreatedSocket(); + virtual int totalPendingConnections() const; // from QAbstractSocketEngineReceiver void readNotification() override; diff --git a/src/network/socket/qtcpsocket.cpp b/src/network/socket/qtcpsocket.cpp index 3d06197b1e..979382f26c 100644 --- a/src/network/socket/qtcpsocket.cpp +++ b/src/network/socket/qtcpsocket.cpp @@ -23,9 +23,9 @@ \note TCP sockets cannot be opened in QIODevice::Unbuffered mode. \sa QTcpServer, QUdpSocket, QNetworkAccessManager, - {Fortune Server Example}, {Fortune Client Example}, - {Threaded Fortune Server Example}, {Blocking Fortune Client Example}, - {Loopback Example}, {Torrent Example} + {Fortune Server}, {Fortune Client}, + {Threaded Fortune Server}, {Blocking Fortune Client}, + {Torrent Example} */ #include "qtcpsocket.h" diff --git a/src/network/socket/qtcpsocket.h b/src/network/socket/qtcpsocket.h index aeac92c678..a1c610b69b 100644 --- a/src/network/socket/qtcpsocket.h +++ b/src/network/socket/qtcpsocket.h @@ -21,7 +21,7 @@ public: explicit QTcpSocket(QObject *parent = nullptr); virtual ~QTcpSocket(); -#if QT_VERSION < QT_VERSION_CHECK(7,0,0) && !defined(Q_CLANG_QDOC) +#if QT_VERSION < QT_VERSION_CHECK(7,0,0) && !defined(Q_QDOC) // ### Qt7: move into QAbstractSocket using QAbstractSocket::bind; bool bind(QHostAddress::SpecialAddress addr, quint16 port = 0, BindMode mode = DefaultForPlatform) diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index 2a7982057e..bfeea307b2 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -382,7 +382,7 @@ qint64 QUdpSocket::writeDatagram(const QNetworkDatagram &datagram) if (state() == UnconnectedState) bind(); - qint64 sent = d->socketEngine->writeDatagram(datagram.d->data, + qint64 sent = d->socketEngine->writeDatagram(datagram.d->data.constData(), datagram.d->data.size(), datagram.d->header); d->cachedSocketDescriptor = d->socketEngine->socketDescriptor(); @@ -430,6 +430,7 @@ QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize) qint64 readBytes = d->socketEngine->readDatagram(result.d->data.data(), maxSize, &result.d->header, QAbstractSocketEngine::WantAll); d->hasPendingData = false; + d->hasPendingDatagram = false; d->socketEngine->setReadNotificationEnabled(true); if (readBytes < 0) { d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString()); @@ -479,6 +480,7 @@ qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *addres } d->hasPendingData = false; + d->hasPendingDatagram = false; d->socketEngine->setReadNotificationEnabled(true); if (readBytes < 0) { if (readBytes == -2) { diff --git a/src/network/socket/qudpsocket.h b/src/network/socket/qudpsocket.h index 34657fffa5..3fd1d3710a 100644 --- a/src/network/socket/qudpsocket.h +++ b/src/network/socket/qudpsocket.h @@ -24,7 +24,7 @@ public: explicit QUdpSocket(QObject *parent = nullptr); virtual ~QUdpSocket(); -#if QT_VERSION < QT_VERSION_CHECK(7,0,0) && !defined(Q_CLANG_QDOC) +#if QT_VERSION < QT_VERSION_CHECK(7,0,0) && !defined(Q_QDOC) // ### Qt7: move into QAbstractSocket using QAbstractSocket::bind; bool bind(QHostAddress::SpecialAddress addr, quint16 port = 0, BindMode mode = DefaultForPlatform) |