summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp1
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp112
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h1
-rw-r--r--src/network/access/qhttpnetworkreply.cpp2
-rw-r--r--src/network/access/qhttpprotocolhandler.cpp8
-rw-r--r--src/network/bearer/qnetworkconfigmanager_p.cpp24
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp3
-rw-r--r--src/network/kernel/kernel.pri5
-rw-r--r--src/network/kernel/qhostaddress.cpp136
-rw-r--r--src/network/kernel/qhostaddress.h2
-rw-r--r--src/network/kernel/qhostinfo.cpp16
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp9
-rw-r--r--src/network/kernel/qhostinfo_win.cpp19
-rw-r--r--src/network/kernel/qhostinfo_winrt.cpp39
-rw-r--r--src/network/kernel/qnetworkinterface.cpp14
-rw-r--r--src/network/kernel/qnetworkinterface.h3
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp52
-rw-r--r--src/network/kernel/qnetworkinterface_win.cpp140
-rw-r--r--src/network/kernel/qnetworkinterface_win_p.h262
-rw-r--r--src/network/kernel/qnetworkproxy_mac.cpp1
-rw-r--r--src/network/socket/qabstractsocket.cpp116
-rw-r--r--src/network/socket/qabstractsocket_p.h3
-rw-r--r--src/network/socket/qabstractsocketengine_p.h48
-rw-r--r--src/network/socket/qhttpsocketengine.cpp6
-rw-r--r--src/network/socket/qhttpsocketengine_p.h7
-rw-r--r--src/network/socket/qnativesocketengine.cpp74
-rw-r--r--src/network/socket/qnativesocketengine_p.h126
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp317
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp329
-rw-r--r--src/network/socket/qnativesocketengine_winrt.cpp25
-rw-r--r--src/network/socket/qnativesocketengine_winrt_p.h9
-rw-r--r--src/network/socket/qnet_unix_p.h27
-rw-r--r--src/network/socket/qsocks5socketengine.cpp18
-rw-r--r--src/network/socket/qsocks5socketengine_p.h7
-rw-r--r--src/network/socket/qtcpserver.cpp4
-rw-r--r--src/network/socket/qudpsocket.cpp28
-rw-r--r--src/network/ssl/qsslsocket.cpp29
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp74
-rw-r--r--src/network/ssl/qsslsocket_mac_p.h7
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp76
-rw-r--r--src/network/ssl/qsslsocket_winrt.cpp30
41 files changed, 1077 insertions, 1132 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 16ed67fbc0..c2d986ef3d 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -971,7 +971,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
for (int i = 0; i < channelCount; ++i) {
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
channels[i].resendCurrent = false;
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
// if this is not possible, error will be emitted and connection terminated
if (!channels[i].resetUploadData())
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 98247b7df0..8980ed7a41 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE
// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
+// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
+// connection times out)
+// We use 3 because we can get a _q_error 3 times depending on the timing:
+static const int reconnectAttemptsDefault = 3;
+
QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
: socket(0)
, ssl(false)
@@ -69,7 +74,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
, resendCurrent(false)
, lastStatus(0)
, pendingEncrypt(false)
- , reconnectAttempts(2)
+ , reconnectAttempts(reconnectAttemptsDefault)
, authMethod(QAuthenticatorPrivate::None)
, proxyAuthMethod(QAuthenticatorPrivate::None)
, authenticationCredentialsSent(false)
@@ -106,19 +111,18 @@ void QHttpNetworkConnectionChannel::init()
socket->setProxy(QNetworkProxy::NoProxy);
#endif
- // We want all signals (except the interactive ones) be connected as QueuedConnection
- // because else we're falling into cases where we recurse back into the socket code
- // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
- // is safer.
+ // After some back and forth in all the last years, this is now a DirectConnection because otherwise
+ // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
+ // which behave slightly differently on Windows vs Linux
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(connected()),
this, SLOT(_q_connected()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(readyRead()),
this, SLOT(_q_readyRead()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
// The disconnected() and error() signals may already come
// while calling connectToHost().
@@ -129,10 +133,10 @@ void QHttpNetworkConnectionChannel::init()
qRegisterMetaType<QAbstractSocket::SocketError>();
QObject::connect(socket, SIGNAL(disconnected()),
this, SLOT(_q_disconnected()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(_q_error(QAbstractSocket::SocketError)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
#ifndef QT_NO_NETWORKPROXY
@@ -147,7 +151,7 @@ void QHttpNetworkConnectionChannel::init()
// won't be a sslSocket if encrypt is false
QObject::connect(sslSocket, SIGNAL(encrypted()),
this, SLOT(_q_encrypted()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(_q_sslErrors(QList<QSslError>)),
Qt::DirectConnection);
@@ -156,7 +160,7 @@ void QHttpNetworkConnectionChannel::init()
Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
this, SLOT(_q_encryptedBytesWritten(qint64)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();
@@ -400,7 +404,7 @@ void QHttpNetworkConnectionChannel::allDone()
// reset the reconnection attempts after we receive a complete reply.
// in case of failures, each channel will attempt two reconnects before emitting error.
- reconnectAttempts = 2;
+ reconnectAttempts = reconnectAttemptsDefault;
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
if (state != QHttpNetworkConnectionChannel::ClosingState)
@@ -668,6 +672,15 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
+void QHttpNetworkConnectionChannel::resendCurrentRequest()
+{
+ requeueCurrentlyPipelinedRequests();
+ if (reply)
+ resendCurrent = true;
+ if (qobject_cast<QHttpNetworkConnection*>(connection))
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+}
+
bool QHttpNetworkConnectionChannel::isSocketBusy() const
{
return (state & QHttpNetworkConnectionChannel::BusyState);
@@ -711,8 +724,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
return;
}
- // read the available data before closing
- if (isSocketWaiting() || isSocketReading()) {
+ // read the available data before closing (also done in _q_error for other codepaths)
+ if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) {
if (reply) {
state = QHttpNetworkConnectionChannel::ReadingState;
_q_receiveReply();
@@ -724,7 +737,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
state = QHttpNetworkConnectionChannel::IdleState;
requeueCurrentlyPipelinedRequests();
- close();
+
+ pendingEncrypt = false;
}
@@ -806,11 +820,19 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
errorCode = QNetworkReply::ConnectionRefusedError;
break;
case QAbstractSocket::RemoteHostClosedError:
- // try to reconnect/resend before sending an error.
- // while "Reading" the _q_disconnected() will handle this.
- if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
+ // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
+ // Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket).
+ // The reconnectAttempts handling catches the cases where we can re-send the request.
+ if (!reply && state == QHttpNetworkConnectionChannel::IdleState) {
+ // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request
+ // is sent on them. No need to error the other replies below. Just bail out here.
+ // The _q_disconnected will handle the possibly pipelined replies
+ return;
+ } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
+ // Try to reconnect/resend before sending an error.
+ // While "Reading" the _q_disconnected() will handle this.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
} else {
errorCode = QNetworkReply::RemoteHostClosedError;
@@ -821,11 +843,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
if (!reply->d_func()->expectContent()) {
// No content expected, this is a valid way to have the connection closed by the server
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
return;
}
if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
// There was no content-length header and it's not chunked encoding,
// so this is a valid way to have the connection closed by the server
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
return;
}
// ok, we got a disconnect even though we did not expect it
@@ -835,24 +861,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// we can ignore the readbuffersize as the data is already
// in memory and we will not receive more data on the socket.
reply->setReadBufferSize(0);
+ reply->setDownstreamLimited(false);
_q_receiveReply();
-#ifndef QT_NO_SSL
- if (ssl) {
- // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket.
- // So we need to check this if the socket is a QSslSocket. When the socket is flushed
- // it will force a decrypt of the encrypted data in the plainsocket.
- QSslSocket *sslSocket = static_cast<QSslSocket*>(socket);
- qint64 beforeFlush = sslSocket->encryptedBytesAvailable();
- while (sslSocket->encryptedBytesAvailable()) {
- sslSocket->flush();
- _q_receiveReply();
- qint64 afterFlush = sslSocket->encryptedBytesAvailable();
- if (afterFlush == beforeFlush)
- break;
- beforeFlush = afterFlush;
- }
+ if (!reply) {
+ // No more reply assigned after the previous call? Then it had been finished successfully.
+ requeueCurrentlyPipelinedRequests();
+ state = QHttpNetworkConnectionChannel::IdleState;
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ return;
}
-#endif
}
errorCode = QNetworkReply::RemoteHostClosedError;
@@ -863,7 +880,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::SocketTimeoutError:
// try to reconnect/resend before sending an error.
if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::TimeoutError;
@@ -877,7 +894,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::ProxyConnectionClosedError:
// try to reconnect/resend before sending an error.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::ProxyConnectionClosedError;
@@ -885,7 +902,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::ProxyConnectionTimeoutError:
// try to reconnect/resend before sending an error.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::ProxyTimeoutError;
@@ -933,8 +950,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
- if (that) //signal emission triggered event loop
- close();
+ if (that) {
+ //signal emission triggered event loop
+ if (!socket)
+ state = QHttpNetworkConnectionChannel::IdleState;
+ else if (socket->state() == QAbstractSocket::UnconnectedState)
+ state = QHttpNetworkConnectionChannel::IdleState;
+ else
+ state = QHttpNetworkConnectionChannel::ClosingState;
+
+ // pendingEncrypt must only be true in between connected and encrypted states
+ pendingEncrypt = false;
+ }
}
#ifndef QT_NO_NETWORKPROXY
@@ -958,7 +985,8 @@ void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetwor
void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
{
- sendRequest();
+ if (reply)
+ sendRequest();
}
#ifndef QT_NO_SSL
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 16d6c3b40f..37ad6c9b0a 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -169,6 +169,7 @@ public:
void handleUnexpectedEOF();
void closeAndResendCurrentRequest();
+ void resendCurrentRequest();
bool isSocketBusy() const;
bool isSocketWriting() const;
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 172d4dab5b..dd108ad5c7 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -208,7 +208,7 @@ QByteArray QHttpNetworkReply::readAny()
return QByteArray();
// we'll take the last buffer, so schedule another read from http
- if (d->downstreamLimited && d->responseData.bufferCount() == 1)
+ if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
d->connection->d_func()->readMoreLater(this);
return d->responseData.read();
}
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
index 55187755bf..a2083158f1 100644
--- a/src/network/access/qhttpprotocolhandler.cpp
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -237,7 +237,12 @@ void QHttpProtocolHandler::_q_readyRead()
}
if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) {
- m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
+ if (m_socket->bytesAvailable()) {
+ // We might get a spurious call from readMoreLater()
+ // call of the QHttpNetworkConnection even while the socket is disconnecting.
+ // Therefore check if there is actually bytes available before changing the channel state.
+ m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
+ }
if (m_reply)
_q_receiveReply();
}
@@ -250,7 +255,6 @@ bool QHttpProtocolHandler::sendRequest()
if (!m_reply) {
// heh, how should that happen!
qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply";
- m_channel->state = QHttpNetworkConnectionChannel::IdleState;
return false;
}
diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp
index 78d4970ca1..71e435b771 100644
--- a/src/network/bearer/qnetworkconfigmanager_p.cpp
+++ b/src/network/bearer/qnetworkconfigmanager_p.cpp
@@ -43,6 +43,10 @@
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/private/qthread_p.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+
+
#ifndef QT_NO_BEARERMANAGEMENT
QT_BEGIN_NAMESPACE
@@ -375,6 +379,8 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations()
updating = false;
#ifndef QT_NO_LIBRARY
+ bool envOK = false;
+ const int skipGeneric = qgetenv("QT_EXCLUDE_GENERIC_BEARER").toInt(&envOK);
QBearerEngine *generic = 0;
QFactoryLoader *l = loader();
const PluginKeyMap keyMap = l->keyMap();
@@ -409,8 +415,10 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations()
}
}
- if (generic)
- sessionEngines.append(generic);
+ if (generic) {
+ if (!envOK || skipGeneric <= 0)
+ sessionEngines.append(generic);
+ }
#endif // QT_NO_LIBRARY
}
@@ -466,15 +474,18 @@ QList<QBearerEngine *> QNetworkConfigurationManagerPrivate::engines() const
void QNetworkConfigurationManagerPrivate::startPolling()
{
QMutexLocker locker(&mutex);
-
- if(!pollTimer) {
+ if (!pollTimer) {
pollTimer = new QTimer(this);
- pollTimer->setInterval(10000);
+ bool ok;
+ int interval = qgetenv("QT_BEARER_POLL_TIMEOUT").toInt(&ok);
+ if (!ok)
+ interval = 10000;//default 10 seconds
+ pollTimer->setInterval(interval);
pollTimer->setSingleShot(true);
connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollEngines()));
}
- if(pollTimer->isActive())
+ if (pollTimer->isActive())
return;
foreach (QBearerEngine *engine, sessionEngines) {
@@ -483,6 +494,7 @@ void QNetworkConfigurationManagerPrivate::startPolling()
break;
}
}
+ performAsyncConfigurationUpdate();
}
void QNetworkConfigurationManagerPrivate::pollEngines()
diff --git a/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp b/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
index a7ab8c0977..3bd57f1d44 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
@@ -51,7 +51,8 @@ void SslServer::incomingConnection(qintptr socketDescriptor)
{
QSslSocket *serverSocket = new QSslSocket;
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
- connect(serverSocket, SIGNAL(encrypted()), this, SLOT(ready()));
+ addPendingConnection(serverSocket);
+ connect(serverSocket, &QSslSocket::encrypted, this, &SslServer::ready);
serverSocket->startServerEncryption();
} else {
delete serverSocket;
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index e539388b81..435bfd6c27 100644
--- a/src/network/kernel/kernel.pri
+++ b/src/network/kernel/kernel.pri
@@ -34,11 +34,12 @@ android {
win32: {
!winrt {
- HEADERS += kernel/qnetworkinterface_win_p.h
SOURCES += kernel/qdnslookup_win.cpp \
kernel/qhostinfo_win.cpp \
kernel/qnetworkinterface_win.cpp
- LIBS_PRIVATE += -ldnsapi
+ LIBS_PRIVATE += -ldnsapi -liphlpapi
+ DEFINES += WINVER=0x0600 _WIN32_WINNT=0x0600
+
} else {
SOURCES += kernel/qdnslookup_winrt.cpp \
kernel/qhostinfo_winrt.cpp \
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
index 58c0de1f3b..935af04e31 100644
--- a/src/network/kernel/qhostaddress.cpp
+++ b/src/network/kernel/qhostaddress.cpp
@@ -46,6 +46,9 @@
#ifndef QT_NO_DATASTREAM
#include <qdatastream.h>
#endif
+#ifdef __SSE2__
+# include <private/qsimd_p.h>
+#endif
#ifdef QT_LINUXBASE
# include <arpa/inet.h>
@@ -106,7 +109,11 @@ public:
QString scopeId;
quint32 a; // IPv4 address
- Q_IPV6ADDR a6; // IPv6 address
+ union {
+ Q_IPV6ADDR a6; // IPv6 address
+ struct { quint64 c[2]; } a6_64;
+ struct { quint32 c[4]; } a6_32;
+ };
QAbstractSocket::NetworkLayerProtocol protocol;
bool isParsed;
@@ -123,24 +130,17 @@ QHostAddressPrivate::QHostAddressPrivate()
void QHostAddressPrivate::setAddress(quint32 a_)
{
a = a_;
+ protocol = QAbstractSocket::IPv4Protocol;
+ isParsed = true;
+
//create mapped address, except for a_ == 0 (any)
- memset(&a6, 0, sizeof(a6));
+ a6_64.c[0] = 0;
if (a) {
- a6[11] = 0xFF;
- a6[10] = 0xFF;
+ a6_32.c[2] = qToBigEndian(0xffff);
+ a6_32.c[3] = qToBigEndian(a);
} else {
- a6[11] = 0;
- a6[10] = 0;
+ a6_64.c[1] = 0;
}
-
- int i;
- for (i=15; a_ != 0; i--) {
- a6[i] = a_ & 0xFF;
- a_ >>=8;
- }
- Q_ASSERT(i >= 11);
- protocol = QAbstractSocket::IPv4Protocol;
- isParsed = true;
}
/// parses v4-mapped addresses or the AnyIPv6 address and stores in \a a;
@@ -163,21 +163,16 @@ static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6)
void QHostAddressPrivate::setAddress(const quint8 *a_)
{
- for (int i = 0; i < 16; i++)
- a6[i] = a_[i];
- a = 0;
- convertToIpv4(a, a6);
protocol = QAbstractSocket::IPv6Protocol;
isParsed = true;
+ memcpy(a6.c, a_, sizeof(a6));
+ a = 0;
+ convertToIpv4(a, a6);
}
void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_)
{
- a6 = a_;
- a = 0;
- convertToIpv4(a, a6);
- protocol = QAbstractSocket::IPv6Protocol;
- isParsed = true;
+ setAddress(a_.c);
}
static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, QString *scopeId)
@@ -193,7 +188,7 @@ static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr,
return QIPAddressUtils::parseIp6(addr, tmp.constBegin(), tmp.constEnd()) == 0;
}
-bool QHostAddressPrivate::parse()
+Q_NEVER_INLINE bool QHostAddressPrivate::parse()
{
isParsed = true;
protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
@@ -486,31 +481,35 @@ QHostAddress::QHostAddress(SpecialAddress address)
{
Q_IPV6ADDR ip6;
memset(&ip6, 0, sizeof ip6);
+ quint32 ip4 = INADDR_ANY;
switch (address) {
case Null:
- break;
+ return;
+
case Broadcast:
- d->setAddress(quint32(-1));
+ ip4 = INADDR_BROADCAST;
break;
case LocalHost:
- d->setAddress(0x7f000001);
- break;
- case LocalHostIPv6:
- ip6[15] = 1;
- d->setAddress(ip6);
+ ip4 = INADDR_LOOPBACK;
break;
case AnyIPv4:
- setAddress(0u);
break;
+
+ case LocalHostIPv6:
+ ip6[15] = 1;
+ // fall through
case AnyIPv6:
d->setAddress(ip6);
- break;
+ return;
+
case Any:
- d->clear();
d->protocol = QAbstractSocket::AnyIPProtocol;
- break;
+ return;
}
+
+ // common IPv4 part
+ d->setAddress(ip4);
}
/*!
@@ -775,11 +774,6 @@ QString QHostAddress::toString() const
on your host. Link-local addresses ("fe80...") are generated from the MAC
address of the local network adaptor, and are not guaranteed to be unique.
- \li Site-local: Addresses that are local to the site / private network
- (e.g., the company intranet). Site-local addresses ("fec0...") are
- usually distributed by the site router, and are not guaranteed to be
- unique outside of the local site.
-
\li Global: For globally routable addresses, such as public servers on the
Internet.
@@ -790,7 +784,7 @@ QString QHostAddress::toString() const
usually the same as the interface name (e.g., "eth0", "en1") or number
(e.g., "1", "2").
- \sa setScopeId()
+ \sa setScopeId(), QNetworkInterface, QNetworkInterface::interfaceFromName
*/
QString QHostAddress::scopeId() const
{
@@ -801,8 +795,14 @@ QString QHostAddress::scopeId() const
/*!
\since 4.1
- Sets the IPv6 scope ID of the address to \a id. If the address
- protocol is not IPv6, this function does nothing.
+ Sets the IPv6 scope ID of the address to \a id. If the address protocol is
+ not IPv6, this function does nothing. The scope ID may be set as an
+ interface name (such as "eth0" or "en1") or as an integer representing the
+ interface index. If \a id is an interface name, QtNetwork will convert to
+ an interface index using QNetworkInterface::interfaceIndexFromName() before
+ calling the operating system networking functions.
+
+ \sa scopeId(), QNetworkInterface, QNetworkInterface::interfaceFromName
*/
void QHostAddress::setScopeId(const QString &id)
{
@@ -836,34 +836,36 @@ bool QHostAddress::operator==(const QHostAddress &other) const
bool QHostAddress::operator ==(SpecialAddress other) const
{
QT_ENSURE_PARSED(this);
+ quint32 ip4 = INADDR_ANY;
switch (other) {
case Null:
return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol;
case Broadcast:
- return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_BROADCAST;
+ ip4 = INADDR_BROADCAST;
+ break;
case LocalHost:
- return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_LOOPBACK;
+ ip4 = INADDR_LOOPBACK;
+ break;
case Any:
return d->protocol == QAbstractSocket::AnyIPProtocol;
case AnyIPv4:
- return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_ANY;
+ break;
case LocalHostIPv6:
case AnyIPv6:
if (d->protocol == QAbstractSocket::IPv6Protocol) {
- Q_IPV6ADDR ip6 = { { 0 } };
- ip6[15] = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any
- return memcmp(&d->a6, &ip6, sizeof ip6) == 0;
+ quint64 second = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any
+ return d->a6_64.c[0] == 0 && d->a6_64.c[1] == qToBigEndian(second);
}
return false;
}
- Q_UNREACHABLE();
- return false;
+ // common IPv4 part
+ return d->protocol == QAbstractSocket::IPv4Protocol && d->a == ip4;
}
/*!
@@ -1085,16 +1087,36 @@ bool QHostAddress::isLoopback() const
if ((d->a & 0xFF000000) == 0x7F000000)
return true; // v4 range (including IPv6 wrapped IPv4 addresses)
if (d->protocol == QAbstractSocket::IPv6Protocol) {
- if (d->a6.c[15] != 1)
+#ifdef __SSE2__
+ const __m128i loopback = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+ __m128i ipv6 = _mm_loadu_si128((const __m128i *)d->a6.c);
+ __m128i cmp = _mm_cmpeq_epi8(ipv6, loopback);
+ return _mm_movemask_epi8(cmp) == 0xffff;
+#else
+ if (d->a6_64.c[0] != 0 || qFromBigEndian(d->a6_64.c[1]) != 1)
return false;
- for (int i = 0; i < 15; i++)
- if (d->a6[i] != 0)
- return false;
+#endif
return true;
}
return false;
}
+/*!
+ \since 5.6
+
+ Returns \c true if the address is an IPv4 or IPv6 multicast address, \c
+ false otherwise.
+*/
+bool QHostAddress::isMulticast() const
+{
+ QT_ENSURE_PARSED(this);
+ if ((d->a & 0xF0000000) == 0xE0000000)
+ return true; // 224.0.0.0-239.255.255.255 (including v4-mapped IPv6 addresses)
+ if (d->protocol == QAbstractSocket::IPv6Protocol)
+ return d->a6.c[0] == 0xff;
+ return false;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const QHostAddress &address)
{
@@ -1112,7 +1134,7 @@ uint qHash(const QHostAddress &key, uint seed)
{
// both lines might throw
QT_ENSURE_PARSED(&key);
- return qHash(QByteArray::fromRawData(reinterpret_cast<const char *>(key.d->a6.c), 16), seed);
+ return qHashBits(key.d->a6.c, 16, seed);
}
#ifndef QT_NO_DATASTREAM
diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h
index 8478240d28..9e3ee43d04 100644
--- a/src/network/kernel/qhostaddress.h
+++ b/src/network/kernel/qhostaddress.h
@@ -124,6 +124,7 @@ public:
bool isInSubnet(const QPair<QHostAddress, int> &subnet) const;
bool isLoopback() const;
+ bool isMulticast() const;
static QPair<QHostAddress, int> parseSubnet(const QString &subnet);
@@ -131,6 +132,7 @@ public:
protected:
QScopedPointer<QHostAddressPrivate> d;
};
+Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QHostAddress)
inline bool operator ==(QHostAddress::SpecialAddress address1, const QHostAddress &address2)
{ return address2 == address1; }
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index a2ac9065fd..c6c09542e7 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -415,10 +415,22 @@ void QHostInfo::setErrorString(const QString &str)
/*!
\fn QString QHostInfo::localHostName()
- Returns the host name of this machine.
+ Returns this machine's host name, if one is configured. Note that hostnames
+ are not guaranteed to be globally unique, especially if they were
+ configured automatically.
- \sa hostName()
+ This function does not guarantee the returned host name is a Fully
+ Qualified Domain Name (FQDN). For that, use fromName() to resolve the
+ returned name to an FQDN.
+
+ This function returns the same as QSysInfo::machineHostName().
+
+ \sa hostName(), localDomainName()
*/
+QString QHostInfo::localHostName()
+{
+ return QSysInfo::machineHostName();
+}
/*!
\fn QString QHostInfo::localDomainName()
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
index 90a6f763f7..266a67771c 100644
--- a/src/network/kernel/qhostinfo_unix.cpp
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -315,15 +315,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}
-QString QHostInfo::localHostName()
-{
- char hostName[512];
- if (gethostname(hostName, sizeof(hostName)) == -1)
- return QString();
- hostName[sizeof(hostName) - 1] = '\0';
- return QString::fromLocal8Bit(hostName);
-}
-
QString QHostInfo::localDomainName()
{
#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID)
diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp
index e044728198..da28cd48c1 100644
--- a/src/network/kernel/qhostinfo_win.cpp
+++ b/src/network/kernel/qhostinfo_win.cpp
@@ -111,7 +111,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
QMutexLocker locker(&qPrivCEMutex);
#endif
- QWindowsSockInit winSock;
+ QSysInfo::machineHostName(); // this initializes ws2_32.dll
// Load res_init on demand.
static QBasicAtomicInt triedResolve = Q_BASIC_ATOMIC_INITIALIZER(false);
@@ -136,7 +136,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
// Reverse lookup
if (local_getnameinfo) {
sockaddr_in sa4;
- qt_sockaddr_in6 sa6;
+ sockaddr_in6 sa6;
sockaddr *sa;
QT_SOCKLEN_T saSize;
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
@@ -150,7 +150,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
saSize = sizeof(sa6);
memset(&sa6, 0, sizeof(sa6));
sa6.sin6_family = AF_INET6;
- memcpy(sa6.sin6_addr.qt_s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.qt_s6_addr));
+ memcpy(&sa6.sin6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr));
}
char hbuf[NI_MAXHOST];
@@ -197,7 +197,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
break;
case AF_INET6: {
QHostAddress addr;
- addr.setAddress(((qt_sockaddr_in6 *) p->ai_addr)->sin6_addr.qt_s6_addr);
+ addr.setAddress(((sockaddr_in6 *) p->ai_addr)->sin6_addr.s6_addr);
if (!addresses.contains(addr))
addresses.append(addr);
}
@@ -256,17 +256,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}
-QString QHostInfo::localHostName()
-{
- QWindowsSockInit winSock;
-
- char hostName[512];
- if (gethostname(hostName, sizeof(hostName)) == -1)
- return QString();
- hostName[sizeof(hostName) - 1] = '\0';
- return QString::fromLocal8Bit(hostName);
-}
-
// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo_winrt.cpp b/src/network/kernel/qhostinfo_winrt.cpp
index 1a97fe0e40..3d2344726b 100644
--- a/src/network/kernel/qhostinfo_winrt.cpp
+++ b/src/network/kernel/qhostinfo_winrt.cpp
@@ -130,45 +130,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results;
}
-QString QHostInfo::localHostName()
-{
- ComPtr<INetworkInformationStatics> statics;
- GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &statics);
-
- ComPtr<IVectorView<HostName *>> hostNames;
- statics->GetHostNames(&hostNames);
- if (!hostNames)
- return QString();
-
- unsigned int size;
- hostNames->get_Size(&size);
- if (size == 0)
- return QString();
-
- for (unsigned int i = 0; i < size; ++i) {
- ComPtr<IHostName> hostName;
- hostNames->GetAt(i, &hostName);
- HostNameType type;
- hostName->get_Type(&type);
- if (type != HostNameType_DomainName)
- continue;
-
- HString name;
- hostName->get_CanonicalName(name.GetAddressOf());
- UINT32 length;
- PCWSTR rawString = name.GetRawBuffer(&length);
- return QString::fromWCharArray(rawString, length);
- }
- ComPtr<IHostName> firstHost;
- hostNames->GetAt(0, &firstHost);
-
- HString name;
- firstHost->get_CanonicalName(name.GetAddressOf());
- UINT32 length;
- PCWSTR rawString = name.GetRawBuffer(&length);
- return QString::fromWCharArray(rawString, length);
-}
-
// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp
index 2fbbf56e0f..4a527052d1 100644
--- a/src/network/kernel/qnetworkinterface.cpp
+++ b/src/network/kernel/qnetworkinterface.cpp
@@ -86,9 +86,16 @@ QSharedDataPointer<QNetworkInterfacePrivate> QNetworkInterfaceManager::interface
{
QList<QSharedDataPointer<QNetworkInterfacePrivate> > interfaceList = allInterfaces();
QList<QSharedDataPointer<QNetworkInterfacePrivate> >::ConstIterator it = interfaceList.constBegin();
- for ( ; it != interfaceList.constEnd(); ++it)
- if ((*it)->name == name)
+
+ bool ok;
+ uint index = name.toUInt(&ok);
+
+ for ( ; it != interfaceList.constEnd(); ++it) {
+ if (ok && (*it)->index == int(index))
return *it;
+ else if ((*it)->name == name)
+ return *it;
+ }
return empty;
}
@@ -516,6 +523,9 @@ QList<QNetworkAddressEntry> QNetworkInterface::addressEntries() const
name. If no such interface exists, this function returns an
invalid QNetworkInterface object.
+ The string \a name may be either an actual interface name (such as "eth0"
+ or "en1") or an interface index in string form ("1", "2", etc.).
+
\sa name(), isValid()
*/
QNetworkInterface QNetworkInterface::interfaceFromName(const QString &name)
diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h
index 31d3b7b128..b3daa3d4a0 100644
--- a/src/network/kernel/qnetworkinterface.h
+++ b/src/network/kernel/qnetworkinterface.h
@@ -133,6 +133,9 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkInterface &networ
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QNetworkAddressEntry)
+Q_DECLARE_METATYPE(QNetworkInterface)
+
#endif // QT_NO_NETWORKINTERFACE
#endif
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp
index 9c5ba4e799..cc53087024 100644
--- a/src/network/kernel/qnetworkinterface_unix.cpp
+++ b/src/network/kernel/qnetworkinterface_unix.cpp
@@ -127,14 +127,13 @@ static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags)
#ifdef QT_NO_GETIFADDRS
// getifaddrs not available
-static const int STORAGEBUFFER_GROWTH = 256;
-
static QSet<QByteArray> interfaceNames(int socket)
{
QSet<QByteArray> result;
#ifdef QT_NO_IPV6IFNAME
QByteArray storageBuffer;
struct ifconf interfaceList;
+ static const int STORAGEBUFFER_GROWTH = 256;
forever {
// grow the storage buffer
@@ -186,9 +185,14 @@ static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfa
QNetworkInterfacePrivate *iface = 0;
int ifindex = 0;
-#ifndef QT_NO_IPV6IFNAME
+#if !defined(QT_NO_IPV6IFNAME) || defined(SIOCGIFINDEX)
// Get the interface index
+# ifdef SIOCGIFINDEX
+ if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
+ ifindex = req.ifr_ifindex;
+# else
ifindex = if_nametoindex(req.ifr_name);
+# endif
// find the interface data
QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
@@ -214,6 +218,27 @@ static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfa
iface = new QNetworkInterfacePrivate;
iface->index = ifindex;
interfaces << iface;
+ }
+
+ return iface;
+}
+
+static QList<QNetworkInterfacePrivate *> interfaceListing()
+{
+ QList<QNetworkInterfacePrivate *> interfaces;
+
+ int socket;
+ if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
+ return interfaces; // error
+
+ QSet<QByteArray> names = interfaceNames(socket);
+ QSet<QByteArray>::ConstIterator it = names.constBegin();
+ for ( ; it != names.constEnd(); ++it) {
+ ifreq req;
+ memset(&req, 0, sizeof(ifreq));
+ memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1));
+
+ QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
#ifdef SIOCGIFNAME
// Get the canonical name
@@ -242,27 +267,6 @@ static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfa
iface->hardwareAddress = iface->makeHwAddress(6, addr);
}
#endif
- }
-
- return iface;
-}
-
-static QList<QNetworkInterfacePrivate *> interfaceListing()
-{
- QList<QNetworkInterfacePrivate *> interfaces;
-
- int socket;
- if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
- return interfaces; // error
-
- QSet<QByteArray> names = interfaceNames(socket);
- QSet<QByteArray>::ConstIterator it = names.constBegin();
- for ( ; it != names.constEnd(); ++it) {
- ifreq req;
- memset(&req, 0, sizeof(ifreq));
- memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1));
-
- QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
// Get the interface broadcast address
QNetworkAddressEntry entry;
diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp
index ddeb6c111f..907638f73e 100644
--- a/src/network/kernel/qnetworkinterface_win.cpp
+++ b/src/network/kernel/qnetworkinterface_win.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Intel Corporation.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -31,7 +32,7 @@
**
****************************************************************************/
-#include "qnetworkinterface_win_p.h"
+#define WIN32_LEAN_AND_MEAN 1
#include "qnetworkinterface.h"
#include "qnetworkinterface_p.h"
@@ -41,16 +42,23 @@
#include <qhostinfo.h>
#include <qhash.h>
#include <qurl.h>
-#include <private/qsystemlibrary_p.h>
+
+// Since we need to include winsock2.h, we need to define WIN32_LEAN_AND_MEAN
+// (above) so windows.h won't include winsock.h.
+// In addition, we need to include winsock2.h before iphlpapi.h and we need
+// to include ws2ipdef.h to work around an MinGW-w64 bug
+// (http://sourceforge.net/p/mingw-w64/mailman/message/32935366/)
+#include <winsock2.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+#include <ws2tcpip.h>
+
+#include <qt_windows.h>
QT_BEGIN_NAMESPACE
-typedef DWORD (WINAPI *PtrGetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG);
-static PtrGetAdaptersInfo ptrGetAdaptersInfo = 0;
-typedef ULONG (WINAPI *PtrGetAdaptersAddresses)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
-static PtrGetAdaptersAddresses ptrGetAdaptersAddresses = 0;
-typedef DWORD (WINAPI *PtrGetNetworkParams)(PFIXED_INFO, PULONG);
-static PtrGetNetworkParams ptrGetNetworkParams = 0;
+typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceLuidToName)(const NET_LUID *, PWSTR, SIZE_T);
+static PtrConvertInterfaceLuidToName ptrConvertInterfaceLuidToName = 0;
static void resolveLibs()
{
@@ -58,21 +66,17 @@ static void resolveLibs()
static bool done = false;
if (!done) {
- done = true;
-
- HINSTANCE iphlpapiHnd = QSystemLibrary::load(L"iphlpapi");
- if (iphlpapiHnd == NULL)
- return;
+ HINSTANCE iphlpapiHnd = GetModuleHandle(L"iphlpapi");
+ Q_ASSERT(iphlpapiHnd);
#if defined(Q_OS_WINCE)
- ptrGetAdaptersInfo = (PtrGetAdaptersInfo)GetProcAddress(iphlpapiHnd, L"GetAdaptersInfo");
- ptrGetAdaptersAddresses = (PtrGetAdaptersAddresses)GetProcAddress(iphlpapiHnd, L"GetAdaptersAddresses");
- ptrGetNetworkParams = (PtrGetNetworkParams)GetProcAddress(iphlpapiHnd, L"GetNetworkParams");
+ // since Windows Embedded Compact 7
+ ptrConvertInterfaceLuidToName = (PtrConvertInterfaceLuidToName)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceLuidToNameW");
#else
- ptrGetAdaptersInfo = (PtrGetAdaptersInfo)GetProcAddress(iphlpapiHnd, "GetAdaptersInfo");
- ptrGetAdaptersAddresses = (PtrGetAdaptersAddresses)GetProcAddress(iphlpapiHnd, "GetAdaptersAddresses");
- ptrGetNetworkParams = (PtrGetNetworkParams)GetProcAddress(iphlpapiHnd, "GetNetworkParams");
+ // since Windows Vista
+ ptrConvertInterfaceLuidToName = (PtrConvertInterfaceLuidToName)GetProcAddress(iphlpapiHnd, "ConvertInterfaceLuidToNameW");
#endif
+ done = true;
}
}
@@ -85,8 +89,8 @@ static QHostAddress addressFromSockaddr(sockaddr *sa)
if (sa->sa_family == AF_INET)
address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
else if (sa->sa_family == AF_INET6) {
- address.setAddress(((qt_sockaddr_in6 *)sa)->sin6_addr.qt_s6_addr);
- int scope = ((qt_sockaddr_in6 *)sa)->sin6_scope_id;
+ address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr);
+ int scope = ((sockaddr_in6 *)sa)->sin6_scope_id;
if (scope)
address.setScopeId(QString::number(scope));
} else
@@ -103,14 +107,14 @@ static QHash<QHostAddress, QHostAddress> ipv4Netmasks()
ULONG bufSize = sizeof staticBuf;
QHash<QHostAddress, QHostAddress> ipv4netmasks;
- DWORD retval = ptrGetAdaptersInfo(pAdapter, &bufSize);
+ DWORD retval = GetAdaptersInfo(pAdapter, &bufSize);
if (retval == ERROR_BUFFER_OVERFLOW) {
// need more memory
pAdapter = (IP_ADAPTER_INFO *)malloc(bufSize);
if (!pAdapter)
return ipv4netmasks;
// try again
- if (ptrGetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
+ if (GetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
free(pAdapter);
return ipv4netmasks;
}
@@ -145,14 +149,14 @@ static QList<QNetworkInterfacePrivate *> interfaceListingWinXP()
ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_MULTICAST;
- ULONG retval = ptrGetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize);
+ ULONG retval = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize);
if (retval == ERROR_BUFFER_OVERFLOW) {
// need more memory
pAdapter = (IP_ADAPTER_ADDRESSES *)malloc(bufSize);
if (!pAdapter)
return interfaces;
// try again
- if (ptrGetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize) != ERROR_SUCCESS) {
+ if (GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize) != ERROR_SUCCESS) {
free(pAdapter);
return interfaces;
}
@@ -180,7 +184,16 @@ static QList<QNetworkInterfacePrivate *> interfaceListingWinXP()
if (ptr->IfType == IF_TYPE_PPP)
iface->flags |= QNetworkInterface::IsPointToPoint;
- iface->name = QString::fromLocal8Bit(ptr->AdapterName);
+ if (ptrConvertInterfaceLuidToName && ptr->Length >= offsetof(IP_ADAPTER_ADDRESSES, Luid)) {
+ // use ConvertInterfaceLuidToName because that returns a friendlier name, though not
+ // as friendly as FriendlyName below
+ WCHAR buf[IF_MAX_STRING_SIZE + 1];
+ if (ptrConvertInterfaceLuidToName(&ptr->Luid, buf, sizeof(buf)/sizeof(buf[0])) == NO_ERROR)
+ iface->name = QString::fromWCharArray(buf);
+ }
+ if (iface->name.isEmpty())
+ iface->name = QString::fromLocal8Bit(ptr->AdapterName);
+
iface->friendlyName = QString::fromWCharArray(ptr->FriendlyName);
if (ptr->PhysicalAddressLength)
iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength,
@@ -221,92 +234,25 @@ static QList<QNetworkInterfacePrivate *> interfaceListingWinXP()
return interfaces;
}
-static QList<QNetworkInterfacePrivate *> interfaceListingWin2k()
-{
- QList<QNetworkInterfacePrivate *> interfaces;
- IP_ADAPTER_INFO staticBuf[2]; // 2 is arbitrary
- PIP_ADAPTER_INFO pAdapter = staticBuf;
- ULONG bufSize = sizeof staticBuf;
-
- DWORD retval = ptrGetAdaptersInfo(pAdapter, &bufSize);
- if (retval == ERROR_BUFFER_OVERFLOW) {
- // need more memory
- pAdapter = (IP_ADAPTER_INFO *)malloc(bufSize);
- if (!pAdapter)
- return interfaces;
- // try again
- if (ptrGetAdaptersInfo(pAdapter, &bufSize) != ERROR_SUCCESS) {
- free(pAdapter);
- return interfaces;
- }
- } else if (retval != ERROR_SUCCESS) {
- // error
- return interfaces;
- }
-
- // iterate over the list and add the entries to our listing
- for (PIP_ADAPTER_INFO ptr = pAdapter; ptr; ptr = ptr->Next) {
- QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
- interfaces << iface;
-
- iface->index = ptr->Index;
- iface->flags = QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
- if (ptr->Type == MIB_IF_TYPE_PPP)
- iface->flags |= QNetworkInterface::IsPointToPoint;
- else
- iface->flags |= QNetworkInterface::CanBroadcast;
- iface->name = QString::fromLocal8Bit(ptr->AdapterName);
- iface->hardwareAddress = QNetworkInterfacePrivate::makeHwAddress(ptr->AddressLength,
- ptr->Address);
-
- for (PIP_ADDR_STRING addr = &ptr->IpAddressList; addr; addr = addr->Next) {
- QNetworkAddressEntry entry;
- entry.setIp(QHostAddress(QLatin1String(addr->IpAddress.String)));
- entry.setNetmask(QHostAddress(QLatin1String(addr->IpMask.String)));
- // broadcast address is set on postProcess()
-
- iface->addressEntries << entry;
- }
- }
-
- if (pAdapter != staticBuf)
- free(pAdapter);
-
- return interfaces;
-}
-
-static QList<QNetworkInterfacePrivate *> interfaceListing()
-{
- resolveLibs();
- if (ptrGetAdaptersAddresses != NULL)
- return interfaceListingWinXP();
- else if (ptrGetAdaptersInfo != NULL)
- return interfaceListingWin2k();
-
- // failed
- return QList<QNetworkInterfacePrivate *>();
-}
-
QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
{
- return interfaceListing();
+ resolveLibs();
+ return interfaceListingWinXP();
}
QString QHostInfo::localDomainName()
{
resolveLibs();
- if (ptrGetNetworkParams == NULL)
- return QString(); // couldn't resolve
FIXED_INFO info, *pinfo;
ULONG bufSize = sizeof info;
pinfo = &info;
- if (ptrGetNetworkParams(pinfo, &bufSize) == ERROR_BUFFER_OVERFLOW) {
+ if (GetNetworkParams(pinfo, &bufSize) == ERROR_BUFFER_OVERFLOW) {
pinfo = (FIXED_INFO *)malloc(bufSize);
if (!pinfo)
return QString();
// try again
- if (ptrGetNetworkParams(pinfo, &bufSize) != ERROR_SUCCESS) {
+ if (GetNetworkParams(pinfo, &bufSize) != ERROR_SUCCESS) {
free(pinfo);
return QString(); // error
}
diff --git a/src/network/kernel/qnetworkinterface_win_p.h b/src/network/kernel/qnetworkinterface_win_p.h
deleted file mode 100644
index 88c1945fe6..0000000000
--- a/src/network/kernel/qnetworkinterface_win_p.h
+++ /dev/null
@@ -1,262 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL21$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QNETWORKINTERFACE_WIN_P_H
-#define QNETWORKINTERFACE_WIN_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the QLibrary class. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-#include <winsock2.h>
-#include <qt_windows.h>
-#include <time.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef GAA_FLAG_INCLUDE_ALL_INTERFACES
-# define GAA_FLAG_INCLUDE_ALL_INTERFACES 0x0100
-#endif
-#ifndef MAX_ADAPTER_ADDRESS_LENGTH
-// definitions from iptypes.h
-# define MAX_ADAPTER_DESCRIPTION_LENGTH 128 // arb.
-# define MAX_ADAPTER_NAME_LENGTH 256 // arb.
-# define MAX_ADAPTER_ADDRESS_LENGTH 8 // arb.
-# define DEFAULT_MINIMUM_ENTITIES 32 // arb.
-# define MAX_HOSTNAME_LEN 128 // arb.
-# define MAX_DOMAIN_NAME_LEN 128 // arb.
-# define MAX_SCOPE_ID_LEN 256 // arb.
-
-# define GAA_FLAG_SKIP_UNICAST 0x0001
-# define GAA_FLAG_SKIP_ANYCAST 0x0002
-# define GAA_FLAG_SKIP_MULTICAST 0x0004
-# define GAA_FLAG_SKIP_DNS_SERVER 0x0008
-# define GAA_FLAG_INCLUDE_PREFIX 0x0010
-# define GAA_FLAG_SKIP_FRIENDLY_NAME 0x0020
-
-# define IP_ADAPTER_DDNS_ENABLED 0x01
-# define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX 0x02
-# define IP_ADAPTER_DHCP_ENABLED 0x04
-# define IP_ADAPTER_RECEIVE_ONLY 0x08
-# define IP_ADAPTER_NO_MULTICAST 0x10
-# define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20
-
-# define MIB_IF_TYPE_OTHER 1
-# define MIB_IF_TYPE_ETHERNET 6
-# define MIB_IF_TYPE_TOKENRING 9
-# define MIB_IF_TYPE_FDDI 15
-# define MIB_IF_TYPE_PPP 23
-# define MIB_IF_TYPE_LOOPBACK 24
-# define MIB_IF_TYPE_SLIP 28
-
-// definitions from Ipifcons.h
-#define IF_TYPE_PPP 23
-
-#endif
-// copied from qnativesocketengine_win.cpp
-struct qt_in6_addr {
- u_char qt_s6_addr[16];
-};
-typedef struct {
- short sin6_family; /* AF_INET6 */
- u_short sin6_port; /* Transport level port number */
- u_long sin6_flowinfo; /* IPv6 flow information */
- struct qt_in6_addr sin6_addr; /* IPv6 address */
- u_long sin6_scope_id; /* set of interfaces for a scope */
-} qt_sockaddr_in6;
-
-// copied from MSDN online help
-typedef enum {
- IpPrefixOriginOther = 0,
- IpPrefixOriginManual,
- IpPrefixOriginWellKnown,
- IpPrefixOriginDhcp,
- IpPrefixOriginRouterAdvertisement
-} IP_PREFIX_ORIGIN;
-
-typedef enum {
- IpSuffixOriginOther = 0,
- IpSuffixOriginManual,
- IpSuffixOriginWellKnown,
- IpSuffixOriginDhcp,
- IpSuffixOriginLinkLayerAddress,
- IpSuffixOriginRandom
-} IP_SUFFIX_ORIGIN;
-
-typedef enum {
- IpDadStateInvalid = 0,
- IpDadStateTentative,
- IpDadStateDuplicate,
- IpDadStateDeprecated,
- IpDadStatePreferred,
-} IP_DAD_STATE;
-
-typedef enum {
- IfOperStatusUp = 1,
- IfOperStatusDown,
- IfOperStatusTesting,
- IfOperStatusUnknown,
- IfOperStatusDormant,
- IfOperStatusNotPresent,
- IfOperStatusLowerLayerDown
-} IF_OPER_STATUS;
-
-typedef struct _IP_ADAPTER_UNICAST_ADDRESS {
- union {
- ULONGLONG Alignment;
- struct {
- ULONG Length;
- DWORD Flags;
- };
- };
- struct _IP_ADAPTER_UNICAST_ADDRESS* Next;
- SOCKET_ADDRESS Address;
- IP_PREFIX_ORIGIN PrefixOrigin;
- IP_SUFFIX_ORIGIN SuffixOrigin;
- IP_DAD_STATE DadState;
- ULONG ValidLifetime;
- ULONG PreferredLifetime;
- ULONG LeaseLifetime;
-} IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS;
-
-typedef struct _IP_ADAPTER_ANYCAST_ADDRESS
- IP_ADAPTER_ANYCAST_ADDRESS, *PIP_ADAPTER_ANYCAST_ADDRESS;
-
-typedef struct _IP_ADAPTER_MULTICAST_ADDRESS
- IP_ADAPTER_MULTICAST_ADDRESS,
- *PIP_ADAPTER_MULTICAST_ADDRESS;
-
-typedef struct _IP_ADAPTER_DNS_SERVER_ADDRESS
- IP_ADAPTER_DNS_SERVER_ADDRESS,
- *PIP_ADAPTER_DNS_SERVER_ADDRESS;
-
-typedef struct _IP_ADAPTER_PREFIX {
- union {
- ULONGLONG Alignment;
- struct {
- ULONG Length;
- DWORD Flags;
- };
- };
- struct _IP_ADAPTER_PREFIX* Next;
- SOCKET_ADDRESS Address;
- ULONG PrefixLength;
-} IP_ADAPTER_PREFIX,
- *PIP_ADAPTER_PREFIX;
-
-typedef struct _IP_ADAPTER_ADDRESSES {
- union {
- ULONGLONG Alignment;
- struct {
- ULONG Length;
- DWORD IfIndex;
- };
- };
- struct _IP_ADAPTER_ADDRESSES* Next;
- PCHAR AdapterName;
- PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress;
- PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress;
- PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress;
- PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress;
- PWCHAR DnsSuffix;
- PWCHAR Description;
- PWCHAR FriendlyName;
- BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
- DWORD PhysicalAddressLength;
- DWORD Flags;
- DWORD Mtu;
- DWORD IfType;
- IF_OPER_STATUS OperStatus;
- DWORD Ipv6IfIndex;
- DWORD ZoneIndices[16];
- PIP_ADAPTER_PREFIX FirstPrefix;
-} IP_ADAPTER_ADDRESSES,
- *PIP_ADAPTER_ADDRESSES;
-
-typedef struct {
- char String[4 * 4];
-} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
-
-typedef struct _IP_ADDR_STRING {
- struct _IP_ADDR_STRING* Next;
- IP_ADDRESS_STRING IpAddress;
- IP_MASK_STRING IpMask;
- DWORD Context;
-} IP_ADDR_STRING,
- *PIP_ADDR_STRING;
-
-typedef struct _IP_ADAPTER_INFO {
- struct _IP_ADAPTER_INFO* Next;
- DWORD ComboIndex;
- char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
- char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
- UINT AddressLength;
- BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
- DWORD Index;
- UINT Type;
- UINT DhcpEnabled;
- PIP_ADDR_STRING CurrentIpAddress;
- IP_ADDR_STRING IpAddressList;
- IP_ADDR_STRING GatewayList;
- IP_ADDR_STRING DhcpServer;
- BOOL HaveWins;
- IP_ADDR_STRING PrimaryWinsServer;
- IP_ADDR_STRING SecondaryWinsServer;
- time_t LeaseObtained;
- time_t LeaseExpires;
-} IP_ADAPTER_INFO,
- *PIP_ADAPTER_INFO;
-
-typedef struct {
- char HostName[MAX_HOSTNAME_LEN + 4];
- char DomainName[MAX_DOMAIN_NAME_LEN + 4];
- PIP_ADDR_STRING CurrentDnsServer;
- IP_ADDR_STRING DnsServerList;
- UINT NodeType;
- char ScopeId[MAX_SCOPE_ID_LEN + 4];
- UINT EnableRouting;
- UINT EnableProxy;
- UINT EnableDns;
-} FIXED_INFO, *PFIXED_INFO;
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
index 51400f55bb..05d4c6955a 100644
--- a/src/network/kernel/qnetworkproxy_mac.cpp
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
@@ -35,6 +35,7 @@
#ifndef QT_NO_NETWORKPROXY
+#include <CFNetwork/CFNetwork.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 785ea17389..b2426f5c00 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -630,8 +630,8 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
resetSocketLayer();
socketEngine = QAbstractSocketEngine::createSocketEngine(q->socketType(), proxyInUse, q);
if (!socketEngine) {
- socketError = QAbstractSocket::UnsupportedSocketOperationError;
- q->setErrorString(QAbstractSocket::tr("Operation on socket is not supported"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QAbstractSocket::tr("Operation on socket is not supported"));
return false;
}
#ifndef QT_NO_BEARERMANAGEMENT
@@ -644,8 +644,7 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(),
socketEngine->errorString().toLatin1().constData());
#endif
- socketError = socketEngine->error();
- q->setErrorString(socketEngine->errorString());
+ setError(socketEngine->error(), socketEngine->errorString());
return false;
}
@@ -771,6 +770,7 @@ bool QAbstractSocketPrivate::canReadNotification()
void QAbstractSocketPrivate::canCloseNotification()
{
Q_Q(QAbstractSocket);
+ // Note that this method is only called on Windows. Other platforms close in the canReadNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canCloseNotification()");
@@ -780,7 +780,11 @@ void QAbstractSocketPrivate::canCloseNotification()
if (isBuffered) {
// Try to read to the buffer, if the read fail we can close the socket.
newBytes = buffer.size();
- if (!readFromSocket()) {
+ qint64 oldReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // temporarily disable max read buffer, we want to empty the OS buffer
+ bool hadReadFromSocket = readFromSocket();
+ readBufferMaxSize = oldReadBufferMaxSize;
+ if (!hadReadFromSocket) {
q->disconnectFromHost();
return;
}
@@ -880,13 +884,11 @@ bool QAbstractSocketPrivate::writeToSocket()
// Attempt to write it all in one chunk.
qint64 written = socketEngine->write(ptr, nextSize);
if (written < 0) {
- socketError = socketEngine->error();
- q->setErrorString(socketEngine->errorString());
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug() << "QAbstractSocketPrivate::writeToSocket() write error, aborting."
<< socketEngine->errorString();
#endif
- emit q->error(socketError);
+ setErrorAndEmit(socketEngine->error(), socketEngine->errorString());
// an unexpected error so close the socket.
q->abort();
return false;
@@ -1004,8 +1006,7 @@ void QAbstractSocketPrivate::startConnectingByName(const QString &host)
}
// failed to connect
- socketError = socketEngine->error();
- q->setErrorString(socketEngine->errorString());
+ setError(socketEngine->error(), socketEngine->errorString());
}
state = QAbstractSocket::UnconnectedState;
@@ -1064,8 +1065,7 @@ void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo)
qDebug("QAbstractSocketPrivate::_q_startConnecting(), host not found");
#endif
state = QAbstractSocket::UnconnectedState;
- socketError = QAbstractSocket::HostNotFoundError;
- q->setErrorString(QAbstractSocket::tr("Host not found"));
+ setError(QAbstractSocket::HostNotFoundError, QAbstractSocket::tr("Host not found"));
emit q->stateChanged(state);
emit q->error(QAbstractSocket::HostNotFoundError);
return;
@@ -1114,11 +1114,10 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
|| socketEngine->error() == QAbstractSocket::UnsupportedSocketOperationError
#endif
) && socketEngine->state() == QAbstractSocket::ConnectingState) {
- socketError = QAbstractSocket::ConnectionRefusedError;
- q->setErrorString(QAbstractSocket::tr("Connection refused"));
+ setError(QAbstractSocket::ConnectionRefusedError,
+ QAbstractSocket::tr("Connection refused"));
} else {
- socketError = socketEngine->error();
- q->setErrorString(socketEngine->errorString());
+ setError(socketEngine->error(), socketEngine->errorString());
}
} else {
// socketError = QAbstractSocket::ConnectionRefusedError;
@@ -1242,8 +1241,8 @@ void QAbstractSocketPrivate::_q_abortConnectionAttempt()
if (addresses.isEmpty()) {
state = QAbstractSocket::UnconnectedState;
- socketError = QAbstractSocket::SocketTimeoutError;
- q->setErrorString(QAbstractSocket::tr("Connection timed out"));
+ setError(QAbstractSocket::SocketTimeoutError,
+ QAbstractSocket::tr("Connection timed out"));
emit q->stateChanged(state);
emit q->error(socketError);
} else {
@@ -1303,9 +1302,7 @@ bool QAbstractSocketPrivate::readFromSocket()
#endif
if (!socketEngine->isValid()) {
- socketError = socketEngine->error();
- q->setErrorString(socketEngine->errorString());
- emit q->error(socketError);
+ setErrorAndEmit(socketEngine->error(), socketEngine->errorString());
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::readFromSocket() read failed: %s",
q->errorString().toLatin1().constData());
@@ -1390,6 +1387,31 @@ QAbstractSocketEngine* QAbstractSocketPrivate::getSocketEngine(QAbstractSocket *
return socket->d_func()->socketEngine;
}
+/*!
+ \internal
+
+ Sets the socket error state to \c errorCode and \a errorString.
+*/
+void QAbstractSocketPrivate::setError(QAbstractSocket::SocketError errorCode,
+ const QString &errStr)
+{
+ socketError = errorCode;
+ errorString = errStr;
+}
+
+/*!
+ \internal
+
+ Sets the socket error state to \c errorCode and \a errorString,
+ and emits the QAbstractSocket::error() signal.
+*/
+void QAbstractSocketPrivate::setErrorAndEmit(QAbstractSocket::SocketError errorCode,
+ const QString &errorString)
+{
+ Q_Q(QAbstractSocket);
+ setError(errorCode, errorString);
+ emit q->error(errorCode);
+}
/*! \internal
@@ -1554,9 +1576,7 @@ bool QAbstractSocketPrivate::bind(const QHostAddress &address, quint16 port, QAb
cachedSocketDescriptor = socketEngine->socketDescriptor();
if (!result) {
- socketError = socketEngine->error();
- q->setErrorString(socketEngine->errorString());
- emit q->error(socketError);
+ setErrorAndEmit(socketEngine->error(), socketEngine->errorString());
return false;
}
@@ -1633,9 +1653,7 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
if (d->state == ConnectedState || d->state == ConnectingState
|| d->state == ClosingState || d->state == HostLookupState) {
qWarning("QAbstractSocket::connectToHost() called when already looking up or connecting/connected to \"%s\"", qPrintable(hostName));
- d->socketError = QAbstractSocket::OperationError;
- setErrorString(QAbstractSocket::tr("Trying to connect while connection is in progress"));
- emit error(d->socketError);
+ d->setErrorAndEmit(OperationError, tr("Trying to connect while connection is in progress"));
return;
}
@@ -1664,9 +1682,8 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
d->resolveProxy(hostName, port);
if (d->proxyInUse.type() == QNetworkProxy::DefaultProxy) {
// failed to setup the proxy
- d->socketError = QAbstractSocket::UnsupportedSocketOperationError;
- setErrorString(QAbstractSocket::tr("Operation on socket is not supported"));
- emit error(d->socketError);
+ d->setErrorAndEmit(UnsupportedSocketOperationError,
+ tr("Operation on socket is not supported"));
return;
}
#endif
@@ -1886,8 +1903,7 @@ bool QAbstractSocket::setSocketDescriptor(qintptr socketDescriptor, SocketState
d->buffer.clear();
d->socketEngine = QAbstractSocketEngine::createSocketEngine(socketDescriptor, this);
if (!d->socketEngine) {
- d->socketError = UnsupportedSocketOperationError;
- setErrorString(tr("Operation on socket is not supported"));
+ d->setError(UnsupportedSocketOperationError, tr("Operation on socket is not supported"));
return false;
}
#ifndef QT_NO_BEARERMANAGEMENT
@@ -1896,8 +1912,7 @@ bool QAbstractSocket::setSocketDescriptor(qintptr socketDescriptor, SocketState
#endif
bool result = d->socketEngine->initialize(socketDescriptor, socketState);
if (!result) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
+ d->setError(d->socketEngine->error(), d->socketEngine->errorString());
return false;
}
@@ -2107,11 +2122,10 @@ bool QAbstractSocket::waitForConnected(int msecs)
}
if ((timedOut && state() != ConnectedState) || state() == ConnectingState) {
- d->socketError = SocketTimeoutError;
+ d->setError(SocketTimeoutError, tr("Socket operation timed out"));
d->state = UnconnectedState;
emit stateChanged(d->state);
d->resetSocketLayer();
- setErrorString(tr("Socket operation timed out"));
}
#if defined (QABSTRACTSOCKET_DEBUG)
@@ -2170,13 +2184,11 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
- msecs, d->socketError, errorString().toLatin1().constData());
+ msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
#endif
- emit error(d->socketError);
+ d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
if (d->socketError != SocketTimeoutError)
close();
return false;
@@ -2242,13 +2254,11 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)",
- msecs, d->socketError, errorString().toLatin1().constData());
+ msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
#endif
- emit error(d->socketError);
+ d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
if (d->socketError != SocketTimeoutError)
close();
return false;
@@ -2324,13 +2334,11 @@ bool QAbstractSocket::waitForDisconnected(int msecs)
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, state() == ConnectedState,
!d->writeBuffer.isEmpty(),
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
- msecs, d->socketError, errorString().toLatin1().constData());
+ msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
#endif
- emit error(d->socketError);
+ d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
if (d->socketError != SocketTimeoutError)
close();
return false;
@@ -2461,8 +2469,7 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
// -2 from the engine means no bytes available (EAGAIN) so read more later
return 0;
} else if (readBytes < 0) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
+ d->setError(d->socketEngine->error(), d->socketEngine->errorString());
d->resetSocketLayer();
d->state = QAbstractSocket::UnconnectedState;
} else if (!d->socketEngine->isReadNotificationEnabled()) {
@@ -2492,8 +2499,7 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
{
Q_D(QAbstractSocket);
if (d->state == QAbstractSocket::UnconnectedState) {
- d->socketError = QAbstractSocket::UnknownSocketError;
- setErrorString(tr("Socket is not connected"));
+ d->setError(UnknownSocketError, tr("Socket is not connected"));
return -1;
}
@@ -2501,8 +2507,7 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
// This code is for the new Unbuffered QTcpSocket use case
qint64 written = d->socketEngine->write(data, size);
if (written < 0) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
+ d->setError(d->socketEngine->error(), d->socketEngine->errorString());
return written;
} else if (written < size) {
// Buffer what was not written yet
@@ -2516,8 +2521,7 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
// This is for a QUdpSocket that was connect()ed
qint64 written = d->socketEngine->write(data, size);
if (written < 0) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
+ d->setError(d->socketEngine->error(), d->socketEngine->errorString());
} else if (!d->writeBuffer.isEmpty()) {
d->socketEngine->setWriteNotificationEnabled(true);
}
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
index c0662f01b4..ba129b48df 100644
--- a/src/network/socket/qabstractsocket_p.h
+++ b/src/network/socket/qabstractsocket_p.h
@@ -138,6 +138,9 @@ public:
bool writeToSocket();
void emitReadyRead();
+ void setError(QAbstractSocket::SocketError errorCode, const QString &errorString);
+ void setErrorAndEmit(QAbstractSocket::SocketError errorCode, const QString &errorString);
+
qint64 readBufferMaxSize;
QRingBuffer writeBuffer;
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
index f2a3149678..d2b5882d18 100644
--- a/src/network/socket/qabstractsocketengine_p.h
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Intel Corporation.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -58,6 +59,30 @@ class QNetworkInterface;
#endif
class QNetworkProxy;
+class QIpPacketHeader
+{
+public:
+ QIpPacketHeader(const QHostAddress &dstAddr = QHostAddress(), quint16 port = 0)
+ : destinationAddress(dstAddr), ifindex(0), hopLimit(-1), destinationPort(port)
+ {}
+
+ void clear()
+ {
+ senderAddress.clear();
+ destinationAddress.clear();
+ ifindex = 0;
+ hopLimit = -1;
+ }
+
+ QHostAddress senderAddress;
+ QHostAddress destinationAddress;
+
+ uint ifindex;
+ qint16 hopLimit;
+ quint16 senderPort;
+ quint16 destinationPort;
+};
+
class QAbstractSocketEngineReceiver {
public:
virtual ~QAbstractSocketEngineReceiver(){}
@@ -93,9 +118,21 @@ public:
KeepAliveOption,
MulticastTtlOption,
MulticastLoopbackOption,
- TypeOfServiceOption
+ TypeOfServiceOption,
+ ReceivePacketInformation,
+ ReceiveHopLimit
};
+ enum PacketHeaderOption {
+ WantNone = 0,
+ WantDatagramSender,
+ WantDatagramDestination,
+ WantDatagramHopLimit,
+
+ WantAll = 0xff
+ };
+ Q_DECLARE_FLAGS(PacketHeaderOptions, PacketHeaderOption)
+
virtual bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) = 0;
virtual bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) = 0;
@@ -126,10 +163,9 @@ public:
virtual bool setMulticastInterface(const QNetworkInterface &iface) = 0;
#endif // QT_NO_NETWORKINTERFACE
- virtual qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0) = 0;
- virtual qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port) = 0;
+ virtual qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header = 0,
+ PacketHeaderOptions = WantNone) = 0;
+ virtual qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header) = 0;
virtual bool hasPendingDatagrams() const = 0;
virtual qint64 pendingDatagramSize() const = 0;
#endif // QT_NO_UDPSOCKET
@@ -225,6 +261,8 @@ private:
friend class QAbstractSocketEngine;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractSocketEngine::PacketHeaderOptions)
+
QT_END_NAMESPACE
#endif // QABSTRACTSOCKETENGINE_P_H
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index 23347ce08b..1a90abd22c 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -271,14 +271,12 @@ bool QHttpSocketEngine::setMulticastInterface(const QNetworkInterface &)
}
#endif // QT_NO_NETWORKINTERFACE
-qint64 QHttpSocketEngine::readDatagram(char *, qint64, QHostAddress *,
- quint16 *)
+qint64 QHttpSocketEngine::readDatagram(char *, qint64, QIpPacketHeader *, PacketHeaderOptions)
{
return 0;
}
-qint64 QHttpSocketEngine::writeDatagram(const char *, qint64, const QHostAddress &,
- quint16)
+qint64 QHttpSocketEngine::writeDatagram(const char *, qint64, const QIpPacketHeader &)
{
return 0;
}
diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h
index 4d90487679..41c63fe11e 100644
--- a/src/network/socket/qhttpsocketengine_p.h
+++ b/src/network/socket/qhttpsocketengine_p.h
@@ -105,10 +105,9 @@ public:
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
#endif // QT_NO_NETWORKINTERFACE
- qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0) Q_DECL_OVERRIDE;
- qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port) Q_DECL_OVERRIDE;
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *,
+ PacketHeaderOptions) Q_DECL_OVERRIDE;
+ qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
#endif // QT_NO_UDPSOCKET
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index 33bf3af0b5..c11b889220 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -88,6 +88,25 @@
errorString() can be called to determine the cause of the error.
*/
+/*!
+ \enum QAbstractSocketEngine::PacketHeaderOption
+
+ Specifies which fields in the IP packet header are desired in the call to
+ readDatagram().
+
+ \value WantNone caller isn't interested in the packet metadata
+ \value WantDatagramSender caller wants the sender address and port number
+ \value WantDatagramDestination caller wants the packet's destination address and port number
+ (this option is useful to distinguish multicast packets from unicast)
+ \value WantDatagramHopLimit caller wants the packet's remaining hop limit or time to live
+ (this option is useful in IPv4 multicasting, where the TTL is used
+ to indicate the realm)
+ \value WantAll this is a catch-all value to indicate the caller is
+ interested in all the available information
+
+ \sa readDatagram(), QUdpDatagram
+*/
+
#include "qnativesocketengine_p.h"
#include <qabstracteventdispatcher.h>
@@ -152,10 +171,6 @@ QT_BEGIN_NAMESPACE
/*! \internal
Constructs the private class and initializes all data members.
-
- On Windows, WSAStartup is called "recursively" for every
- concurrent QNativeSocketEngine. This is safe, because WSAStartup and
- WSACleanup are reference counted.
*/
QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() :
socketDescriptor(-1),
@@ -163,6 +178,9 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() :
writeNotifier(0),
exceptNotifier(0)
{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ QSysInfo::machineHostName(); // this initializes ws2_32.dll
+#endif
}
/*! \internal
@@ -395,13 +413,18 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb
return false;
}
- // Set the broadcasting flag if it's a UDP socket.
- if (socketType == QAbstractSocket::UdpSocket
- && !setOption(BroadcastSocketOption, 1)) {
- d->setError(QAbstractSocket::UnsupportedSocketOperationError,
- QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString);
- close();
- return false;
+ if (socketType == QAbstractSocket::UdpSocket) {
+ // Set the broadcasting flag if it's a UDP socket.
+ if (!setOption(BroadcastSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Set some extra flags that are interesting to us, but accept failure
+ setOption(ReceivePacketInformation, 1);
+ setOption(ReceiveHopLimit, 1);
}
@@ -760,9 +783,8 @@ qint64 QNativeSocketEngine::pendingDatagramSize() const
/*!
Reads up to \a maxSize bytes of a datagram from the socket,
stores it in \a data and returns the number of bytes read. The
- address and port of the sender are stored in \a address and \a
- port. If either of these pointers is 0, the corresponding value is
- discarded.
+ address, port, and other IP header fields are stored in \a header
+ according to the request in \a options.
To avoid unnecessarily loss of data, call pendingDatagramSize() to
determine the size of the pending message before reading it. If \a
@@ -772,20 +794,23 @@ qint64 QNativeSocketEngine::pendingDatagramSize() const
\sa hasPendingDatagrams()
*/
-qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QHostAddress *address,
- quint16 *port)
+qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QIpPacketHeader *header,
+ PacketHeaderOptions options)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::readDatagram(), -1);
Q_CHECK_TYPE(QNativeSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, -1);
- return d->nativeReceiveDatagram(data, maxSize, address, port);
+ return d->nativeReceiveDatagram(data, maxSize, header, options);
}
/*!
Writes a UDP datagram of size \a size bytes to the socket from
- \a data to the address \a host on port \a port, and returns the
- number of bytes written, or -1 if an error occurred.
+ \a data to the destination contained in \a header, and returns the
+ number of bytes written, or -1 if an error occurred. If \a header
+ contains other settings like hop limit or source address, this function
+ will try to pass them to the operating system too, but will not
+ indicate an error if it could not pass them.
Only one datagram is sent, and if there is too much data to fit
into a single datagram, the operation will fail and error()
@@ -795,18 +820,19 @@ qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QHostAddres
disadvised, as even if they are sent successfully, they are likely
to be fragmented before arriving at their destination.
- Experience has shown that it is in general safe to send datagrams
- no larger than 512 bytes.
+ Experience has shown that it is in general safe to send IPv4 datagrams
+ no larger than 512 bytes or IPv6 datagrams no larger than 1280 (the
+ minimum MTU).
\sa readDatagram()
*/
-qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size,
- const QHostAddress &host, quint16 port)
+qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size, const QIpPacketHeader &header)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1);
Q_CHECK_TYPE(QNativeSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1);
- return d->nativeSendDatagram(data, size, d->adjustAddressProtocol(host), port);
+
+ return d->nativeSendDatagram(data, size, header);
}
/*!
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index 24909bf310..0fa1d8f96e 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -51,46 +51,51 @@
# include <netinet/in.h>
#else
# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <mswsock.h>
#endif
QT_BEGIN_NAMESPACE
-// Use our own defines and structs which we know are correct
-# define QT_SS_MAXSIZE 128
-# define QT_SS_ALIGNSIZE (sizeof(qint64))
-# define QT_SS_PAD1SIZE (QT_SS_ALIGNSIZE - sizeof (short))
-# define QT_SS_PAD2SIZE (QT_SS_MAXSIZE - (sizeof (short) + QT_SS_PAD1SIZE + QT_SS_ALIGNSIZE))
-struct qt_sockaddr_storage {
- short ss_family;
- char __ss_pad1[QT_SS_PAD1SIZE];
- qint64 __ss_align;
- char __ss_pad2[QT_SS_PAD2SIZE];
-};
-
#ifdef Q_OS_WIN
#define QT_SOCKLEN_T int
#define QT_SOCKOPTLEN_T int
-#endif
-// sockaddr_in6 size changed between old and new SDK
-// Only the new version is the correct one, so always
-// use this structure.
-struct qt_in6_addr {
- quint8 qt_s6_addr[16];
-};
-struct qt_sockaddr_in6 {
- short sin6_family; /* AF_INET6 */
- quint16 sin6_port; /* Transport level port number */
- quint32 sin6_flowinfo; /* IPv6 flow information */
- struct qt_in6_addr sin6_addr; /* IPv6 address */
- quint32 sin6_scope_id; /* set of interfaces for a scope */
-};
+// 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 Q_OS_WINCE
+# 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
+# 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
+#endif
+#endif
union qt_sockaddr {
sockaddr a;
sockaddr_in a4;
- qt_sockaddr_in6 a6;
- qt_sockaddr_storage storage;
+ sockaddr_in6 a6;
};
class QNativeSocketEnginePrivate;
@@ -133,10 +138,9 @@ public:
qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE;
- qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0) Q_DECL_OVERRIDE;
- qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port) Q_DECL_OVERRIDE;
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
+ PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE;
+ qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
@@ -173,16 +177,6 @@ private:
Q_DISABLE_COPY(QNativeSocketEngine)
};
-#ifdef Q_OS_WIN
-class QWindowsSockInit
-{
-public:
- QWindowsSockInit();
- ~QWindowsSockInit();
- int version;
-};
-#endif
-
class QSocketNotifier;
class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate
@@ -196,10 +190,10 @@ public:
QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier;
-#ifdef Q_OS_WIN
- QWindowsSockInit winSock;
-#endif
-
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ LPFN_WSASENDMSG sendmsg;
+ LPFN_WSARECVMSG recvmsg;
+# endif
enum ErrorString {
NonBlockingInitFailedErrorString,
BroadcastingInitFailedErrorString,
@@ -256,24 +250,48 @@ public:
bool nativeHasPendingDatagrams() const;
qint64 nativePendingDatagramSize() const;
- qint64 nativeReceiveDatagram(char *data, qint64 maxLength,
- QHostAddress *address, quint16 *port);
- qint64 nativeSendDatagram(const char *data, qint64 length,
- const QHostAddress &host, quint16 port);
+ 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;
-#ifdef Q_OS_WIN
- void setPortAndAddress(sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6,
- quint16 port, const QHostAddress & address, sockaddr ** sockAddrPtr, QT_SOCKLEN_T *sockAddrSize);
-#endif
void nativeClose();
bool checkProxy(const QHostAddress &address);
bool fetchConnectionParameters();
+
+ static uint scopeIdFromString(const QString &scopeid);
+
+ /*! \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;
+ aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId());
+ aa->a6.sin6_port = htons(port);
+ Q_IPV6ADDR tmp = address.toIPv6Address();
+ memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp));
+ *sockAddrSize = 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);
+ }
+ }
+
};
QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 5c4e4e885b..0e14c175c5 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -49,6 +49,9 @@
#ifdef QT_LINUXBASE
#include <arpa/inet.h>
#endif
+#ifdef Q_OS_BSD4
+#include <net/if_dl.h>
+#endif
#if defined QNATIVESOCKETENGINE_DEBUG
#include <qstring.h>
@@ -128,9 +131,9 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po
}
}
-static inline uint makeScopeId(const QHostAddress &addr)
+// inline on purpose
+inline uint QNativeSocketEnginePrivate::scopeIdFromString(const QString &scopeid)
{
- QString scopeid = addr.scopeId();
if (scopeid.isEmpty())
return 0;
@@ -202,6 +205,32 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
n = IP_TOS;
}
break;
+ case QNativeSocketEngine::ReceivePacketInformation:
+ if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_RECVPKTINFO;
+ } else if (socketProtocol == QAbstractSocket::IPv4Protocol) {
+ level = IPPROTO_IP;
+#ifdef IP_PKTINFO
+ n = IP_PKTINFO;
+#elif defined(IP_RECVDSTADDR)
+ // variant found in QNX and FreeBSD; it will get us only the
+ // destination address, not the interface; we need IP_RECVIF for that.
+ n = IP_RECVDSTADDR;
+#endif
+ }
+ break;
+ case QNativeSocketEngine::ReceiveHopLimit:
+ if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_RECVHOPLIMIT;
+ } else if (socketProtocol == QAbstractSocket::IPv4Protocol) {
+#ifdef IP_RECVTTL // IP_RECVTTL is a non-standard extension supported on some OS
+ level = IPPROTO_IP;
+ n = IP_RECVTTL;
+#endif
+ }
+ break;
}
}
@@ -285,7 +314,7 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
QT_SOCKOPTLEN_T len = sizeof(v);
convertToLevelAndOption(opt, socketProtocol, level, n);
- if (::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
+ if (n != -1 && ::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
return v;
return -1;
@@ -360,37 +389,11 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
qDebug() << "QNativeSocketEnginePrivate::nativeConnect() " << socketDescriptor;
#endif
- struct sockaddr_in sockAddrIPv4;
- struct sockaddr *sockAddrPtr = 0;
- QT_SOCKLEN_T sockAddrSize = 0;
-
- struct sockaddr_in6 sockAddrIPv6;
-
- if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
- memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
- sockAddrIPv6.sin6_family = AF_INET6;
- sockAddrIPv6.sin6_port = htons(port);
- sockAddrIPv6.sin6_scope_id = makeScopeId(addr);
-
- Q_IPV6ADDR ip6 = addr.toIPv6Address();
- memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &ip6, sizeof(ip6));
-
- sockAddrSize = sizeof(sockAddrIPv6);
- sockAddrPtr = (struct sockaddr *) &sockAddrIPv6;
- } else
- if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
- memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
- sockAddrIPv4.sin_family = AF_INET;
- sockAddrIPv4.sin_port = htons(port);
- sockAddrIPv4.sin_addr.s_addr = htonl(addr.toIPv4Address());
-
- sockAddrSize = sizeof(sockAddrIPv4);
- sockAddrPtr = (struct sockaddr *) &sockAddrIPv4;
- } else {
- // unreachable
- }
+ qt_sockaddr aa;
+ QT_SOCKLEN_T sockAddrSize;
+ setPortAndAddress(port, addr, &aa, &sockAddrSize);
- int connectResult = qt_safe_connect(socketDescriptor, sockAddrPtr, sockAddrSize);
+ int connectResult = qt_safe_connect(socketDescriptor, &aa.a, sockAddrSize);
#if defined (QNATIVESOCKETENGINE_DEBUG)
int ecopy = errno;
#endif
@@ -462,51 +465,28 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port)
{
- struct sockaddr_in sockAddrIPv4;
- struct sockaddr *sockAddrPtr = 0;
- QT_SOCKLEN_T sockAddrSize = 0;
-
-
- struct sockaddr_in6 sockAddrIPv6;
+ qt_sockaddr aa;
+ QT_SOCKLEN_T sockAddrSize;
+ setPortAndAddress(port, address, &aa, &sockAddrSize);
- if (address.protocol() == QAbstractSocket::IPv6Protocol || address.protocol() == QAbstractSocket::AnyIPProtocol) {
#ifdef IPV6_V6ONLY
+ if (aa.a.sa_family == AF_INET6) {
int ipv6only = 0;
if (address.protocol() == QAbstractSocket::IPv6Protocol)
ipv6only = 1;
//default value of this socket option varies depending on unix variant (or system configuration on BSD), so always set it explicitly
::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
+ }
#endif
- memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
- sockAddrIPv6.sin6_family = AF_INET6;
- sockAddrIPv6.sin6_port = htons(port);
- sockAddrIPv6.sin6_scope_id = makeScopeId(address);
-
- Q_IPV6ADDR tmp = address.toIPv6Address();
- memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
- sockAddrSize = sizeof(sockAddrIPv6);
- sockAddrPtr = (struct sockaddr *) &sockAddrIPv6;
- } else
- if (address.protocol() == QAbstractSocket::IPv4Protocol) {
- memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
- sockAddrIPv4.sin_family = AF_INET;
- sockAddrIPv4.sin_port = htons(port);
- sockAddrIPv4.sin_addr.s_addr = htonl(address.toIPv4Address());
- sockAddrSize = sizeof(sockAddrIPv4);
- sockAddrPtr = (struct sockaddr *) &sockAddrIPv4;
- } else {
- // unreachable
- }
- int bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize);
+ int bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
if (bindResult < 0 && errno == EAFNOSUPPORT && address.protocol() == QAbstractSocket::AnyIPProtocol) {
- memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
- sockAddrIPv4.sin_family = AF_INET;
- sockAddrIPv4.sin_port = htons(port);
- sockAddrIPv4.sin_addr.s_addr = htonl(address.toIPv4Address());
- sockAddrSize = sizeof(sockAddrIPv4);
- sockAddrPtr = (struct sockaddr *) &sockAddrIPv4;
- bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize);
+ // retry with v4
+ aa.a4.sin_family = AF_INET;
+ aa.a4.sin_port = htons(port);
+ aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address());
+ sockAddrSize = sizeof(aa.a4);
+ bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
}
if (bindResult < 0) {
@@ -844,68 +824,183 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
return qint64(recvResult);
}
-qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize,
- QHostAddress *address, quint16 *port)
+qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QIpPacketHeader *header,
+ QAbstractSocketEngine::PacketHeaderOptions options)
{
+ // we use quintptr to force the alignment
+ quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) + sizeof(quintptr) - 1) / sizeof(quintptr)];
+
+ struct msghdr msg;
+ struct iovec vec;
qt_sockaddr aa;
+ char c;
+ memset(&msg, 0, sizeof(msg));
memset(&aa, 0, sizeof(aa));
- QT_SOCKLEN_T sz;
- sz = sizeof(aa);
- ssize_t recvFromResult = 0;
+ // we need to receive at least one byte, even if our user isn't interested in it
+ vec.iov_base = maxSize ? data : &c;
+ vec.iov_len = maxSize ? maxSize : 1;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ if (options & QAbstractSocketEngine::WantDatagramSender) {
+ msg.msg_name = &aa;
+ msg.msg_namelen = sizeof(aa);
+ }
+ if (options & (QAbstractSocketEngine::WantDatagramHopLimit | QAbstractSocketEngine::WantDatagramDestination)) {
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
+ }
+
+ ssize_t recvResult = 0;
do {
- char c;
- recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1,
- 0, &aa.a, &sz);
- } while (recvFromResult == -1 && errno == EINTR);
+ recvResult = ::recvmsg(socketDescriptor, &msg, 0);
+ } while (recvResult == -1 && errno == EINTR);
- if (recvFromResult == -1) {
+ if (recvResult == -1) {
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
- } else if (port || address) {
- qt_socket_getPortAndAddress(&aa, port, address);
+ if (header)
+ header->clear();
+ } else if (options != QAbstractSocketEngine::WantNone) {
+ Q_ASSERT(header);
+ qt_socket_getPortAndAddress(&aa, &header->senderPort, &header->senderAddress);
+ header->destinationPort = localPort;
+
+ // parse the ancillary data
+ struct cmsghdr *cmsgptr;
+ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+ cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
+ if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO
+ && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in6_pktinfo))) {
+ in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
+
+ header->destinationAddress.setAddress(reinterpret_cast<quint8 *>(&info->ipi6_addr));
+ header->ifindex = info->ipi6_ifindex;
+ if (header->ifindex)
+ header->destinationAddress.setScopeId(QString::number(info->ipi6_ifindex));
+ }
+
+#ifdef IP_PKTINFO
+ if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO
+ && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_pktinfo))) {
+ in_pktinfo *info = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsgptr));
+
+ header->destinationAddress.setAddress(ntohl(info->ipi_addr.s_addr));
+ header->ifindex = info->ipi_ifindex;
+ }
+#else
+# ifdef IP_RECVDSTADDR
+ if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVDSTADDR
+ && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_addr))) {
+ in_addr *addr = reinterpret_cast<in_addr *>(CMSG_DATA(cmsgptr));
+
+ header->destinationAddress.setAddress(ntohl(addr->s_addr));
+ }
+# endif
+# if defined(IP_RECVIF) && defined(Q_OS_BSD4)
+ if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVIF
+ && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sockaddr_dl))) {
+ sockaddr_dl *sdl = reinterpret_cast<sockaddr_dl *>(CMSG_DATA(cmsgptr));
+
+ header->ifindex = LLINDEX(sdl);
+ }
+# endif
+#endif
+
+ if (cmsgptr->cmsg_len == CMSG_LEN(sizeof(int))
+ && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT)
+ || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
+ header->hopLimit = *reinterpret_cast<int *>(CMSG_DATA(cmsgptr));
+ }
+ }
}
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
- data, qt_prettyDebug(data, qMin(recvFromResult, ssize_t(16)), recvFromResult).data(), maxSize,
+ data, qt_prettyDebug(data, qMin(recvResult, ssize_t(16)), recvResult).data(), maxSize,
address ? address->toString().toLatin1().constData() : "(nil)",
- port ? *port : 0, (qint64) recvFromResult);
+ port ? *port : 0, (qint64) recvResult);
#endif
- return qint64(maxSize ? recvFromResult : recvFromResult == -1 ? -1 : 0);
+ return qint64(maxSize ? recvResult : recvResult == -1 ? -1 : 0);
}
-qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
- const QHostAddress &host, quint16 port)
+qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
{
- struct sockaddr_in sockAddrIPv4;
- struct sockaddr *sockAddrPtr = 0;
- QT_SOCKLEN_T sockAddrSize = 0;
-
- struct sockaddr_in6 sockAddrIPv6;
- if (host.protocol() == QAbstractSocket::IPv6Protocol
- || socketProtocol == QAbstractSocket::IPv6Protocol
- || socketProtocol == QAbstractSocket::AnyIPProtocol) {
- memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
- sockAddrIPv6.sin6_family = AF_INET6;
- sockAddrIPv6.sin6_port = htons(port);
- sockAddrIPv6.sin6_scope_id = makeScopeId(host);
-
- Q_IPV6ADDR tmp = host.toIPv6Address();
- memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
- sockAddrSize = sizeof(sockAddrIPv6);
- sockAddrPtr = (struct sockaddr *)&sockAddrIPv6;
- } else if (host.protocol() == QAbstractSocket::IPv4Protocol) {
- memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
- sockAddrIPv4.sin_family = AF_INET;
- sockAddrIPv4.sin_port = htons(port);
- sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address());
- sockAddrSize = sizeof(sockAddrIPv4);
- sockAddrPtr = (struct sockaddr *)&sockAddrIPv4;
+ // we use quintptr to force the alignment
+ quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) + sizeof(quintptr) - 1) / sizeof(quintptr)];
+
+ struct cmsghdr *cmsgptr = reinterpret_cast<struct cmsghdr *>(cbuf);
+ struct msghdr msg;
+ struct iovec vec;
+ qt_sockaddr aa;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&aa, 0, sizeof(aa));
+ vec.iov_base = const_cast<char *>(data);
+ vec.iov_len = len;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_name = &aa.a;
+ msg.msg_control = &cbuf;
+
+ setPortAndAddress(header.destinationPort, header.destinationAddress, &aa, &msg.msg_namelen);
+
+ if (msg.msg_namelen == sizeof(aa.a6)) {
+ if (header.hopLimit != -1) {
+ msg.msg_controllen += CMSG_SPACE(sizeof(int));
+ cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsgptr->cmsg_level = IPPROTO_IPV6;
+ cmsgptr->cmsg_type = IPV6_HOPLIMIT;
+ memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
+ cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(int)));
+ }
+ if (header.ifindex != 0 || !header.senderAddress.isNull()) {
+ struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
+ memset(data, 0, sizeof(*data));
+ msg.msg_controllen += CMSG_SPACE(sizeof(*data));
+ cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data));
+ cmsgptr->cmsg_level = IPPROTO_IPV6;
+ cmsgptr->cmsg_type = IPV6_PKTINFO;
+ data->ipi6_ifindex = header.ifindex;
+
+ QIPv6Address tmp = header.senderAddress.toIPv6Address();
+ memcpy(&data->ipi6_addr, &tmp, sizeof(tmp));
+ cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
+ }
+ } else {
+ if (header.hopLimit != -1) {
+ msg.msg_controllen += CMSG_SPACE(sizeof(int));
+ cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsgptr->cmsg_level = IPPROTO_IP;
+ cmsgptr->cmsg_type = IP_TTL;
+ memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
+ cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(int)));
+ }
+
+#if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
+ if (header.ifindex != 0 || !header.senderAddress.isNull()) {
+# ifdef IP_PKTINFO
+ struct in_pktinfo *data = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsgptr));
+ memset(data, 0, sizeof(*data));
+ cmsgptr->cmsg_type = IP_PKTINFO;
+ data->ipi_ifindex = header.ifindex;
+ data->ipi_addr.s_addr = htonl(header.senderAddress.toIPv4Address());
+# elif defined(IP_SENDSRCADDR)
+ struct in_addr *data = reinterpret_cast<in_addr *>(CMSG_DATA(cmsgptr));
+ cmsgptr->cmsg_type = IP_SENDSRCADDR;
+ addr->s_addr = htonl(header.senderAddress.toIPv4Address());
+# endif
+ cmsgptr->cmsg_level = IPPROTO_IP;
+ msg.msg_controllen += CMSG_SPACE(sizeof(*data));
+ cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data));
+ cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
+ }
+#endif
}
- ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len,
- 0, sockAddrPtr, sockAddrSize);
+ if (msg.msg_controllen == 0)
+ msg.msg_control = 0;
+ ssize_t sentBytes = qt_safe_sendmsg(socketDescriptor, &msg, 0);
if (sentBytes < 0) {
switch (errno) {
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 7856db0487..2e905ad610 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -59,6 +59,9 @@ QT_BEGIN_NAMESPACE
#ifndef IPV6_V6ONLY
#define IPV6_V6ONLY 27
#endif
+#ifndef IP_HOPLIMIT
+#define IP_HOPLIMIT 21 // Receive packet hop limit.
+#endif
#if defined(QNATIVESOCKETENGINE_DEBUG)
@@ -168,10 +171,10 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxLength)
static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt_sockaddr *sa, quint16 *port, QHostAddress *address)
{
if (sa->a.sa_family == AF_INET6) {
- const qt_sockaddr_in6 *sa6 = &sa->a6;
+ const sockaddr_in6 *sa6 = &sa->a6;
Q_IPV6ADDR tmp;
for (int i = 0; i < 16; ++i)
- tmp.c[i] = sa6->sin6_addr.qt_s6_addr[i];
+ tmp.c[i] = sa6->sin6_addr.s6_addr[i];
if (address) {
QHostAddress a;
a.setAddress(tmp);
@@ -252,40 +255,24 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
n = IP_MULTICAST_LOOP;
}
break;
- }
-}
-
-/*! \internal
-
- Sets the port and address to a sockaddr. Requires that sa point to the IPv6 struct if the address is IPv6.
-*/
-void QNativeSocketEnginePrivate::setPortAndAddress(sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6,
- quint16 port, const QHostAddress & address, sockaddr ** sockAddrPtr, QT_SOCKLEN_T *sockAddrSize)
-{
- if (address.protocol() == QAbstractSocket::IPv6Protocol
- || address.protocol() == QAbstractSocket::AnyIPProtocol
- || socketProtocol == QAbstractSocket::IPv6Protocol
- || socketProtocol == QAbstractSocket::AnyIPProtocol) {
- memset(sockAddrIPv6, 0, sizeof(qt_sockaddr_in6));
- sockAddrIPv6->sin6_family = AF_INET6;
- sockAddrIPv6->sin6_scope_id = address.scopeId().toUInt();
- WSAHtons(socketDescriptor, port, &(sockAddrIPv6->sin6_port));
- Q_IPV6ADDR tmp = address.toIPv6Address();
- memcpy(&(sockAddrIPv6->sin6_addr.qt_s6_addr), &tmp, sizeof(tmp));
- *sockAddrSize = sizeof(qt_sockaddr_in6);
- *sockAddrPtr = (struct sockaddr *) sockAddrIPv6;
- } else
-
- if (address.protocol() == QAbstractSocket::IPv4Protocol
- || address.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) {
- memset(sockAddrIPv4, 0, sizeof(sockaddr_in));
- sockAddrIPv4->sin_family = AF_INET;
- WSAHtons(socketDescriptor, port, &(sockAddrIPv4->sin_port));
- WSAHtonl(socketDescriptor, address.toIPv4Address(), &(sockAddrIPv4->sin_addr.s_addr));
- *sockAddrSize = sizeof(sockaddr_in);
- *sockAddrPtr = (struct sockaddr *) sockAddrIPv4;
- } else {
- // unreachable
+ case QNativeSocketEngine::ReceivePacketInformation:
+ if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_PKTINFO;
+ } else if (socketProtocol == QAbstractSocket::IPv4Protocol) {
+ level = IPPROTO_IP;
+ n = IP_PKTINFO;
+ }
+ break;
+ case QNativeSocketEngine::ReceiveHopLimit:
+ if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_HOPLIMIT;
+ } else if (socketProtocol == QAbstractSocket::IPv4Protocol) {
+ level = IPPROTO_IP;
+ n = IP_HOPLIMIT;
+ }
+ break;
}
}
@@ -320,25 +307,6 @@ static inline int qt_socket_getMaxMsgSize(qintptr socketDescriptor)
return value;
}
-QWindowsSockInit::QWindowsSockInit()
-: version(0)
-{
- //### should we try for 2.2 on all platforms ??
- WSAData wsadata;
-
- // IPv6 requires Winsock v2.0 or better.
- if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) {
- qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
- } else {
- version = 0x20;
- }
-}
-
-QWindowsSockInit::~QWindowsSockInit()
-{
- WSACleanup();
-}
-
// MS Transport Provider IOCTL to control
// reporting PORT_UNREACHABLE messages
// on UDP sockets via recv/WSARecv/etc.
@@ -354,6 +322,12 @@ QWindowsSockInit::~QWindowsSockInit()
# define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
+// inline on purpose
+inline uint QNativeSocketEnginePrivate::scopeIdFromString(const QString &scopeid)
+{
+ return scopeid.toUInt();
+}
+
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol)
{
@@ -439,6 +413,20 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
WS_ERROR_DEBUG(err);
}
}
+
+ // get the pointer to sendmsg and recvmsg
+ DWORD bytesReturned;
+ GUID recvmsgguid = WSAID_WSARECVMSG;
+ if (WSAIoctl(socketDescriptor, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &recvmsgguid, sizeof(recvmsgguid),
+ &recvmsg, sizeof(recvmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR)
+ recvmsg = 0;
+
+ GUID sendmsgguid = WSAID_WSASENDMSG;
+ if (WSAIoctl(socketDescriptor, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &sendmsgguid, sizeof(sendmsgguid),
+ &sendmsg, sizeof(sendmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR)
+ sendmsg = 0;
#endif
socketDescriptor = socket;
@@ -630,12 +618,10 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
qDebug("QNativeSocketEnginePrivate::nativeConnect() to %s :: %i", address.toString().toLatin1().constData(), port);
#endif
- struct sockaddr_in sockAddrIPv4;
- qt_sockaddr_in6 sockAddrIPv6;
- struct sockaddr *sockAddrPtr = 0;
+ qt_sockaddr aa;
QT_SOCKLEN_T sockAddrSize = 0;
- setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
+ setPortAndAddress(port, address, &aa, &sockAddrSize);
if ((socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) && address.toIPv4Address()) {
//IPV6_V6ONLY option must be cleared to connect to a V4 mapped address
@@ -646,7 +632,7 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
}
forever {
- int connectResult = ::WSAConnect(socketDescriptor, sockAddrPtr, sockAddrSize, 0,0,0,0);
+ int connectResult = ::WSAConnect(socketDescriptor, &aa.a, sockAddrSize, 0,0,0,0);
if (connectResult == SOCKET_ERROR) {
int err = WSAGetLastError();
WS_ERROR_DEBUG(err);
@@ -769,46 +755,36 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &a, quint16 port)
{
QHostAddress address = a;
- DWORD ipv6only = 0;
- switch (address.protocol()) {
- case QAbstractSocket::IPv6Protocol:
- if (address.toIPv6Address()[0] == 0xff) {
- // binding to a multicast address
- address = QHostAddress(QHostAddress::AnyIPv6);
- }
- //This is default in current windows versions, it may change in future so set it explicitly
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) {
- ipv6only = 1;
- ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
- }
- break;
- case QAbstractSocket::IPv4Protocol:
+ if (address.protocol() == QAbstractSocket::IPv4Protocol) {
if ((address.toIPv4Address() & 0xffff0000) == 0xefff0000) {
// binding to a multicast address
address = QHostAddress(QHostAddress::AnyIPv4);
}
- break;
- case QAbstractSocket::AnyIPProtocol:
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) {
- ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
- } else {
- address = QHostAddress(QHostAddress::AnyIPv4); //xp/WS2003 and earlier don't support dual stack, so bind to IPv4
- socketProtocol = QAbstractSocket::IPv4Protocol;
- }
- break;
- default:
- break;
}
- struct sockaddr_in sockAddrIPv4;
- qt_sockaddr_in6 sockAddrIPv6;
- struct sockaddr *sockAddrPtr = 0;
+ qt_sockaddr aa;
QT_SOCKLEN_T sockAddrSize = 0;
+ setPortAndAddress(port, address, &aa, &sockAddrSize);
- setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
+ if (aa.a.sa_family == AF_INET6) {
+ // The default may change in future, so set it explicitly
+ int ipv6only = 0;
+ if (address.protocol() == QAbstractSocket::IPv6Protocol)
+ ipv6only = 1;
+ ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
+ }
- int bindResult = ::bind(socketDescriptor, sockAddrPtr, sockAddrSize);
+ int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
+ if (bindResult == SOCKET_ERROR && WSAGetLastError() == WSAEAFNOSUPPORT
+ && address.protocol() == QAbstractSocket::AnyIPProtocol) {
+ // retry with v4
+ aa.a4.sin_family = AF_INET;
+ aa.a4.sin_port = htons(port);
+ aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address());
+ sockAddrSize = sizeof(aa.a4);
+ bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
+ }
if (bindResult == SOCKET_ERROR) {
int err = WSAGetLastError();
WS_ERROR_DEBUG(err);
@@ -1215,33 +1191,47 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
return ret;
}
+#ifdef Q_OS_WINCE
+// Windows CE has no support for sendmsg or recvmsg. We set it to null here to simplify the code below.
+static int (*const recvmsg)(...) = 0;
+static int (*const sendmsg)(...) = 0;
+#endif
-qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxLength,
- QHostAddress *address, quint16 *port)
+qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header,
+ QAbstractSocketEngine::PacketHeaderOptions options)
{
- qint64 ret = 0;
-
+ union {
+ char cbuf[WSA_CMSG_SPACE(sizeof(struct in6_pktinfo)) + WSA_CMSG_SPACE(sizeof(int))];
+ WSACMSGHDR align; // only to ensure alignment
+ };
+ WSAMSG msg;
+ WSABUF buf;
qt_sockaddr aa;
+ char c;
+ memset(&msg, 0, sizeof(msg));
memset(&aa, 0, sizeof(aa));
- QT_SOCKLEN_T sz;
- sz = sizeof(aa);
- WSABUF buf;
- buf.buf = data;
- buf.len = maxLength;
-#if !defined(Q_OS_WINCE)
- buf.buf = data;
- buf.len = maxLength;
-#else
- char tmpChar;
- buf.buf = data ? data : &tmpChar;
- buf.len = maxLength;
-#endif
+ // we need to receive at least one byte, even if our user isn't interested in it
+ buf.buf = maxLength ? data : &c;
+ buf.len = maxLength ? maxLength : 1;
+ msg.lpBuffers = &buf;
+ msg.dwBufferCount = 1;
+ msg.name = reinterpret_cast<LPSOCKADDR>(&aa);
+ msg.namelen = sizeof(aa);
+ if (options & (QAbstractSocketEngine::WantDatagramHopLimit | QAbstractSocketEngine::WantDatagramDestination)) {
+ msg.Control.buf = cbuf;
+ msg.Control.len = sizeof(cbuf);
+ }
DWORD flags = 0;
DWORD bytesRead = 0;
- int wsaRet = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, &aa.a, &sz,0,0);
- if (wsaRet == SOCKET_ERROR) {
+ qint64 ret;
+
+ if (recvmsg)
+ ret = recvmsg(socketDescriptor, &msg, &bytesRead, 0,0);
+ else
+ ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, msg.name, &msg.namelen,0,0);
+ if (ret == SOCKET_ERROR) {
int err = WSAGetLastError();
if (err == WSAEMSGSIZE) {
// it is ok the buffer was to small if bytesRead is larger than
@@ -1251,12 +1241,44 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
WS_ERROR_DEBUG(err);
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
ret = -1;
+ if (header)
+ header->clear();
}
} else {
ret = qint64(bytesRead);
+ if (options & QNativeSocketEngine::WantDatagramSender)
+ qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress);
}
- qt_socket_getPortAndAddress(socketDescriptor, &aa, port, address);
+ if (ret != -1 && recvmsg) {
+ // get the ancillary data
+ WSACMSGHDR *cmsgptr;
+ for (cmsgptr = WSA_CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+ cmsgptr = WSA_CMSG_NXTHDR(&msg, cmsgptr)) {
+ if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO
+ && cmsgptr->cmsg_len >= WSA_CMSG_LEN(sizeof(in6_pktinfo))) {
+ in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
+ QHostAddress target(reinterpret_cast<quint8 *>(&info->ipi6_addr));
+ if (info->ipi6_ifindex)
+ target.setScopeId(QString::number(info->ipi6_ifindex));
+ }
+ if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO
+ && cmsgptr->cmsg_len >= WSA_CMSG_LEN(sizeof(in_pktinfo))) {
+ in_pktinfo *info = reinterpret_cast<in_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
+ u_long addr;
+ WSANtohl(socketDescriptor, info->ipi_addr.s_addr, &addr);
+ QHostAddress target(addr);
+ if (info->ipi_ifindex)
+ target.setScopeId(QString::number(info->ipi_ifindex));
+ }
+
+ if (cmsgptr->cmsg_len == WSA_CMSG_LEN(sizeof(int))
+ && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT)
+ || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
+ header->hopLimit = *reinterpret_cast<int *>(WSA_CMSG_DATA(cmsgptr));
+ }
+ }
+ }
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %li, %s, %i) == %li",
@@ -1270,27 +1292,94 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
- const QHostAddress &address, quint16 port)
+ const QIpPacketHeader &header)
{
- qint64 ret = -1;
- struct sockaddr_in sockAddrIPv4;
- qt_sockaddr_in6 sockAddrIPv6;
- struct sockaddr *sockAddrPtr = 0;
- QT_SOCKLEN_T sockAddrSize = 0;
-
- setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
-
+ union {
+ char cbuf[WSA_CMSG_SPACE(sizeof(struct in6_pktinfo)) + WSA_CMSG_SPACE(sizeof(int))];
+ WSACMSGHDR align; // ensures alignment
+ };
+ WSACMSGHDR *cmsgptr = &align;
+ WSAMSG msg;
WSABUF buf;
+ qt_sockaddr aa;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&aa, 0, sizeof(aa));
#if !defined(Q_OS_WINCE)
buf.buf = len ? (char*)data : 0;
#else
char tmp;
buf.buf = len ? (char*)data : &tmp;
#endif
+ msg.lpBuffers = &buf;
+ msg.dwBufferCount = 1;
+ msg.name = &aa.a;
buf.len = len;
+
+ setPortAndAddress(header.destinationPort, header.destinationAddress, &aa, &msg.namelen);
+
+ if (msg.namelen == sizeof(aa.a6)) {
+ // sending IPv6
+ if (header.hopLimit != -1) {
+ msg.Control.len += WSA_CMSG_SPACE(sizeof(int));
+ cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(int));
+ cmsgptr->cmsg_level = IPPROTO_IPV6;
+ cmsgptr->cmsg_type = IPV6_HOPLIMIT;
+ memcpy(WSA_CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
+ cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
+ + WSA_CMSG_SPACE(sizeof(int)));
+ }
+ if (header.ifindex != 0 || !header.senderAddress.isNull()) {
+ struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
+ memset(data, 0, sizeof(*data));
+ msg.Control.len += WSA_CMSG_SPACE(sizeof(*data));
+ cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(*data));
+ cmsgptr->cmsg_level = IPPROTO_IPV6;
+ cmsgptr->cmsg_type = IPV6_PKTINFO;
+ data->ipi6_ifindex = header.ifindex;
+
+ Q_IPV6ADDR tmp = header.senderAddress.toIPv6Address();
+ memcpy(&data->ipi6_addr, &tmp, sizeof(tmp));
+ cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
+ + WSA_CMSG_SPACE(sizeof(*data)));
+ }
+ } else {
+ // sending IPv4
+ if (header.hopLimit != -1) {
+ msg.Control.len += WSA_CMSG_SPACE(sizeof(int));
+ cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(int));
+ cmsgptr->cmsg_level = IPPROTO_IP;
+ cmsgptr->cmsg_type = IP_TTL;
+ memcpy(WSA_CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
+ cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
+ + WSA_CMSG_SPACE(sizeof(int)));
+ }
+ if (header.ifindex != 0 || !header.senderAddress.isNull()) {
+ struct in_pktinfo *data = reinterpret_cast<in_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
+ memset(data, 0, sizeof(*data));
+ msg.Control.len += WSA_CMSG_SPACE(sizeof(*data));
+ cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(*data));
+ cmsgptr->cmsg_level = IPPROTO_IP;
+ cmsgptr->cmsg_type = IP_PKTINFO;
+ data->ipi_ifindex = header.ifindex;
+ WSAHtonl(socketDescriptor, header.senderAddress.toIPv4Address(), &data->ipi_addr.s_addr);
+ cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
+ + WSA_CMSG_SPACE(sizeof(*data)));
+ }
+ }
+
+ if (msg.Control.len != 0)
+ msg.Control.buf = cbuf;
+
DWORD flags = 0;
DWORD bytesSent = 0;
- if (::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, sockAddrPtr, sockAddrSize, 0,0) == SOCKET_ERROR) {
+ qint64 ret = -1;
+ if (sendmsg) {
+ ret = sendmsg(socketDescriptor, &msg, flags, &bytesSent, 0,0);
+ } else {
+ ret = ::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, msg.name, msg.namelen, 0,0);
+ }
+ if (ret == SOCKET_ERROR) {
int err = WSAGetLastError();
WS_ERROR_DEBUG(err);
switch (err) {
diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp
index 2d04946601..025e3e5017 100644
--- a/src/network/socket/qnativesocketengine_winrt.cpp
+++ b/src/network/socket/qnativesocketengine_winrt.cpp
@@ -538,18 +538,19 @@ qint64 QNativeSocketEngine::write(const char *data, qint64 len)
return bytesWritten;
}
-qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr, quint16 *port)
+qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header,
+ PacketHeaderOptions)
{
Q_D(QNativeSocketEngine);
- if (d->socketType != QAbstractSocket::UdpSocket || d->pendingDatagrams.isEmpty())
+ if (d->socketType != QAbstractSocket::UdpSocket || d->pendingDatagrams.isEmpty()) {
+ if (header)
+ header->clear();
return -1;
+ }
WinRtDatagram datagram = d->pendingDatagrams.takeFirst();
- if (addr)
- *addr = datagram.address;
-
- if (port)
- *port = datagram.port;
+ if (header)
+ *header = datagram.header;
QByteArray readOrigin;
// Do not read the whole datagram. Put the rest of it back into the "queue"
@@ -564,7 +565,7 @@ qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress
return readOrigin.length();
}
-qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &addr, quint16 port)
+qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
{
Q_D(QNativeSocketEngine);
if (d->socketType != QAbstractSocket::UdpSocket)
@@ -576,13 +577,13 @@ qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QH
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
&hostNameFactory);
RETURN_IF_FAILED("Could not obtain hostname factory", return -1);
- const QString addressString = addr.toString();
+ const QString addressString = header.destinationAddress.toString();
HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
ComPtr<IAsyncOperation<IOutputStream *>> streamOperation;
ComPtr<IOutputStream> stream;
- const QString portString = QString::number(port);
+ const QString portString = QString::number(header.destinationPort);
HStringReference portRef(reinterpret_cast<LPCWSTR>(portString.utf16()));
hr = d->udpSocket()->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation);
RETURN_IF_FAILED("Failed to get output stream to socket", return -1);
@@ -1230,11 +1231,11 @@ HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, I
remoteHost->get_CanonicalName(remoteHostString.GetAddressOf());
RETURN_OK_IF_FAILED("Could not obtain remote host's canonical name");
returnAddress.setAddress(qt_QStringFromHString(remoteHostString));
- datagram.address = returnAddress;
+ datagram.header.senderAddress = returnAddress;
HString remotePort;
hr = args->get_RemotePort(remotePort.GetAddressOf());
RETURN_OK_IF_FAILED("Could not obtain remote port");
- datagram.port = qt_QStringFromHString(remotePort).toInt();
+ datagram.header.senderPort = qt_QStringFromHString(remotePort).toInt();
ComPtr<IDataReader> reader;
hr = args->GetDataReader(&reader);
diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h
index eb032bc977..4286ff6373 100644
--- a/src/network/socket/qnativesocketengine_winrt_p.h
+++ b/src/network/socket/qnativesocketengine_winrt_p.h
@@ -58,8 +58,7 @@ class QNativeSocketEnginePrivate;
struct WinRtDatagram {
QByteArray data;
- int port;
- QHostAddress address;
+ QIpPacketHeader header;
};
class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine
@@ -97,10 +96,8 @@ public:
qint64 read(char *data, qint64 maxlen);
qint64 write(const char *data, qint64 len);
- qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0);
- qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port);
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *, PacketHeaderOptions);
+ qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header);
bool hasPendingDatagrams() const;
qint64 pendingDatagramSize() const;
diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h
index a5a87fc7c1..9626c53711 100644
--- a/src/network/socket/qnet_unix_p.h
+++ b/src/network/socket/qnet_unix_p.h
@@ -173,8 +173,7 @@ static inline in_addr_t qt_safe_inet_addr(const char *cp)
#endif
}
-// VxWorks' headers do not specify any const modifiers
-static inline int qt_safe_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *to, QT_SOCKLEN_T tolen)
+static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
@@ -183,11 +182,7 @@ static inline int qt_safe_sendto(int sockfd, const void *buf, size_t len, int fl
#endif
int ret;
-#ifdef Q_OS_VXWORKS
- EINTR_LOOP(ret, ::sendto(sockfd, (char *) buf, len, flags, (struct sockaddr *) to, tolen));
-#else
- EINTR_LOOP(ret, ::sendto(sockfd, buf, len, flags, to, tolen));
-#endif
+ EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags));
return ret;
}
@@ -199,24 +194,6 @@ static inline int qt_safe_recvmsg(int sockfd, struct msghdr *msg, int flags)
return ret;
}
-// VxWorks' headers do not specify any const modifiers
-static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags)
-{
-#ifdef MSG_NOSIGNAL
- flags |= MSG_NOSIGNAL;
-#else
- qt_ignore_sigpipe();
-#endif
-
- int ret;
-#ifdef Q_OS_VXWORKS
- EINTR_LOOP(ret, ::sendmsg(sockfd, (struct msghdr *) msg, flags);
-#else
- EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags));
-#endif
- return ret;
-}
-
QT_END_NAMESPACE
#endif // QNET_UNIX_P_H
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index a6eafd2601..26543883cc 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -1383,7 +1383,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
#endif
dummy.setProxy(QNetworkProxy::NoProxy);
if (!dummy.bind()
- || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0
+ || writeDatagram(0,0, QIpPacketHeader(d->data->controlSocket->localAddress(), dummy.localPort())) != 0
|| !dummy.waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))
|| dummy.readDatagram(0,0, &d->localAddress, &d->localPort) != 0) {
QSOCKS5_DEBUG << "udp actual address and port lookup failed";
@@ -1555,7 +1555,7 @@ qint64 QSocks5SocketEngine::write(const char *data, qint64 len)
#ifndef QT_NO_UDPSOCKET
} else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
// send to connected address
- return writeDatagram(data, len, d->peerAddress, d->peerPort);
+ return writeDatagram(data, len, QIpPacketHeader(d->peerAddress, d->peerPort));
#endif
}
//### set an error ???
@@ -1594,8 +1594,7 @@ bool QSocks5SocketEngine::setMulticastInterface(const QNetworkInterface &)
}
#endif // QT_NO_NETWORKINTERFACE
-qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr,
- quint16 *port)
+qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header, PacketHeaderOptions)
{
Q_D(QSocks5SocketEngine);
@@ -1607,15 +1606,12 @@ qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress
QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
int copyLen = qMin<int>(maxlen, datagram.data.size());
memcpy(data, datagram.data.constData(), copyLen);
- if (addr)
- *addr = datagram.address;
- if (port)
- *port = datagram.port;
+ header->senderAddress = datagram.address;
+ header->senderPort = datagram.port;
return copyLen;
}
-qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &address,
- quint16 port)
+qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
{
Q_D(QSocks5SocketEngine);
@@ -1634,7 +1630,7 @@ qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QH
outBuf[0] = 0x00;
outBuf[1] = 0x00;
outBuf[2] = 0x00;
- if (!qt_socks5_set_host_address_and_port(address, port, &outBuf)) {
+ if (!qt_socks5_set_host_address_and_port(header.destinationAddress, header.destinationPort, &outBuf)) {
}
outBuf += QByteArray(data, len);
QSOCKS5_DEBUG << "sending" << dump(outBuf);
diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h
index c97b0e89ce..de20e0ef0e 100644
--- a/src/network/socket/qsocks5socketengine_p.h
+++ b/src/network/socket/qsocks5socketengine_p.h
@@ -93,10 +93,9 @@ public:
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
#endif // QT_NO_NETWORKINTERFACE
- qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0) Q_DECL_OVERRIDE;
- qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port) Q_DECL_OVERRIDE;
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
+ PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE;
+ qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
#endif // QT_NO_UDPSOCKET
diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp
index 914c14877e..bf75666548 100644
--- a/src/network/socket/qtcpserver.cpp
+++ b/src/network/socket/qtcpserver.cpp
@@ -559,6 +559,10 @@ QTcpSocket *QTcpServer::nextPendingConnection()
may not be usable with native socket functions, and should only be
used with QTcpSocket::setSocketDescriptor().
+ \note If another socket is created in the reimplementation
+ of this method, it needs to be added to the Pending Connections mechanism
+ by calling addPendingConnection().
+
\note If you want to handle an incoming connection as a new QTcpSocket
object in another thread you have to pass the socketDescriptor
to the other thread and create the QTcpSocket object there and
diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp
index 87686f94e1..a46e6ade04 100644
--- a/src/network/socket/qudpsocket.cpp
+++ b/src/network/socket/qudpsocket.cpp
@@ -333,15 +333,13 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre
if (state() == UnconnectedState)
bind();
- qint64 sent = d->socketEngine->writeDatagram(data, size, address, port);
+ qint64 sent = d->socketEngine->writeDatagram(data, size, QIpPacketHeader(address, port));
d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
if (sent >= 0) {
emit bytesWritten(sent);
} else {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
- emit error(d->socketError);
+ d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
}
return sent;
}
@@ -379,13 +377,23 @@ qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *addres
qDebug("QUdpSocket::readDatagram(%p, %llu, %p, %p)", data, maxSize, address, port);
#endif
QT_CHECK_BOUND("QUdpSocket::readDatagram()", -1);
- qint64 readBytes = d->socketEngine->readDatagram(data, maxSize, address, port);
- d_func()->socketEngine->setReadNotificationEnabled(true);
- if (readBytes < 0) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
- emit error(d->socketError);
+
+ qint64 readBytes;
+ if (address || port) {
+ QIpPacketHeader header;
+ readBytes = d->socketEngine->readDatagram(data, maxSize, &header,
+ QAbstractSocketEngine::WantDatagramSender);
+ if (address)
+ *address = header.senderAddress;
+ if (port)
+ *port = header.senderPort;
+ } else {
+ readBytes = d->socketEngine->readDatagram(data, maxSize);
}
+
+ d_func()->socketEngine->setReadNotificationEnabled(true);
+ if (readBytes < 0)
+ d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
return readBytes;
}
#endif // QT_NO_UDPSOCKET
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index c15045b180..b62cfd2fde 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -499,8 +499,7 @@ bool QSslSocket::setSocketDescriptor(qintptr socketDescriptor, SocketState state
d->createPlainSocket(openMode);
bool retVal = d->plainSocket->setSocketDescriptor(socketDescriptor, state, openMode);
d->cachedSocketDescriptor = d->plainSocket->socketDescriptor();
- setSocketError(d->plainSocket->error());
- setErrorString(d->plainSocket->errorString());
+ d->setError(d->plainSocket->error(), d->plainSocket->errorString());
setSocketState(state);
setOpenMode(openMode);
setLocalPort(d->plainSocket->localPort());
@@ -1532,8 +1531,7 @@ bool QSslSocket::waitForConnected(int msecs)
bool retVal = d->plainSocket->waitForConnected(msecs);
if (!retVal) {
setSocketState(d->plainSocket->state());
- setSocketError(d->plainSocket->error());
- setErrorString(d->plainSocket->errorString());
+ d->setError(d->plainSocket->error(), d->plainSocket->errorString());
}
return retVal;
}
@@ -1688,8 +1686,7 @@ bool QSslSocket::waitForDisconnected(int msecs)
bool retVal = d->plainSocket->waitForDisconnected(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
if (!retVal) {
setSocketState(d->plainSocket->state());
- setSocketError(d->plainSocket->error());
- setErrorString(d->plainSocket->errorString());
+ d->setError(d->plainSocket->error(), d->plainSocket->errorString());
}
return retVal;
}
@@ -2402,15 +2399,22 @@ void QSslSocketPrivate::_q_stateChangedSlot(QAbstractSocket::SocketState state)
*/
void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
{
- Q_Q(QSslSocket);
+ Q_UNUSED(error)
#ifdef QSSLSOCKET_DEBUG
+ Q_Q(QSslSocket);
qCDebug(lcSsl) << "QSslSocket::_q_errorSlot(" << error << ')';
qCDebug(lcSsl) << "\tstate =" << q->state();
qCDebug(lcSsl) << "\terrorString =" << q->errorString();
#endif
- q->setSocketError(plainSocket->error());
- q->setErrorString(plainSocket->errorString());
- emit q->error(error);
+ // this moves encrypted bytes from plain socket into our buffer
+ if (plainSocket->bytesAvailable()) {
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
+ transmit();
+ readBufferMaxSize = tmpReadBufferMaxSize;
+ }
+
+ setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
}
/*!
@@ -2475,7 +2479,6 @@ void QSslSocketPrivate::_q_flushReadBuffer()
*/
void QSslSocketPrivate::_q_resumeImplementation()
{
- Q_Q(QSslSocket);
if (plainSocket)
plainSocket->resume();
paused = false;
@@ -2483,9 +2486,7 @@ void QSslSocketPrivate::_q_resumeImplementation()
if (verifyErrorsHaveBeenIgnored()) {
continueHandshake();
} else {
- q->setErrorString(sslErrors.first().errorString());
- q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
- emit q->error(QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.first().errorString());
plainSocket->disconnectFromHost();
return;
}
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index b83e56c29e..06c707f271 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -51,6 +51,10 @@
#include <algorithm>
#include <cstddef>
+#ifdef Q_OS_OSX
+#include <CoreServices/CoreServices.h>
+#endif
+
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_securetransport_mutex, (QMutex::Recursive))
@@ -318,7 +322,7 @@ void QSslSocketBackendPrivate::startClientEncryption()
// Error description/code were set, 'error' emitted
// by initSslContext, but OpenSSL socket also sets error
// emits a signal twice, so ...
- setError("Unable to init SSL Context", QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError, "Unable to init SSL Context");
return;
}
@@ -331,7 +335,7 @@ void QSslSocketBackendPrivate::startServerEncryption()
// Error description/code were set, 'error' emitted
// by initSslContext, but OpenSSL socket also sets error
// emits a signal twice, so ...
- setError("Unable to init SSL Context", QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError, "Unable to init SSL Context");
return;
}
@@ -360,8 +364,8 @@ void QSslSocketBackendPrivate::transmit()
qCDebug(lcSsl) << plainSocket << "SSLWrite returned" << err;
#endif
if (err != noErr && err != errSSLWouldBlock) {
- setError(QStringLiteral("SSLWrite failed: %1").arg(err),
- QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QStringLiteral("SSLWrite failed: %1").arg(err));
break;
}
@@ -395,12 +399,12 @@ void QSslSocketBackendPrivate::transmit()
#endif
if (err == errSSLClosedGraceful) {
shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
- setError(QSslSocket::tr("The TLS/SSL connection has been closed"),
- QAbstractSocket::RemoteHostClosedError);
+ setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
+ QSslSocket::tr("The TLS/SSL connection has been closed"));
break;
} else if (err != noErr && err != errSSLWouldBlock) {
- setError(QStringLiteral("SSLRead failed: %1").arg(err),
- QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QStringLiteral("SSLRead failed: %1").arg(err));
break;
}
@@ -658,7 +662,7 @@ bool QSslSocketBackendPrivate::initSslContext()
context = SSLCreateContext(Q_NULLPTR, side, kSSLStreamType);
if (!context) {
- setError("SSLCreateContext failed", QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError, "SSLCreateContext failed");
return false;
}
@@ -666,8 +670,8 @@ bool QSslSocketBackendPrivate::initSslContext()
reinterpret_cast<SSLWriteFunc>(&_q_SSLWrite));
if (err != noErr) {
destroySslContext();
- setError(QStringLiteral("SSLSetIOFuncs failed: %1").arg(err),
- QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QStringLiteral("SSLSetIOFuncs failed: %1").arg(err));
return false;
}
@@ -679,14 +683,14 @@ bool QSslSocketBackendPrivate::initSslContext()
QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
if (!setSessionCertificate(errorDescription, errorCode)) {
destroySslContext();
- setError(errorDescription, errorCode);
+ setErrorAndEmit(errorCode, errorDescription);
return false;
}
}
if (!setSessionProtocol()) {
destroySslContext();
- setError("Failed to set protocol version", QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError, "Failed to set protocol version");
return false;
}
@@ -698,8 +702,8 @@ bool QSslSocketBackendPrivate::initSslContext()
const OSStatus err = SSLSetEnableCertVerify(context, false);
if (err != noErr) {
destroySslContext();
- setError(QStringLiteral("SSLSetEnableCertVerify failed: %1").arg(err),
- QSslSocket::SslInternalError);
+ setErrorAndEmit(QSslSocket::SslInternalError,
+ QStringLiteral("SSLSetEnableCertVerify failed: %1").arg(err));
return false;
}
}
@@ -720,8 +724,8 @@ bool QSslSocketBackendPrivate::initSslContext()
if (err != noErr) {
destroySslContext();
- setError(QStringLiteral("SSLSetSessionOption failed: %1").arg(err),
- QSslSocket::SslInternalError);
+ setErrorAndEmit(QSslSocket::SslInternalError,
+ QStringLiteral("SSLSetSessionOption failed: %1").arg(err));
return false;
}
//
@@ -737,8 +741,8 @@ bool QSslSocketBackendPrivate::initSslContext()
if (err != noErr) {
destroySslContext();
- setError(QStringLiteral("failed to set SSL context option in server mode: %1").arg(err),
- QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QStringLiteral("failed to set SSL context option in server mode: %1").arg(err));
return false;
}
}
@@ -981,8 +985,8 @@ bool QSslSocketBackendPrivate::verifyPeerTrust()
// !trust - SSLCopyPeerTrust can return noErr but null trust.
if (err != noErr || !trust) {
if (!canIgnoreVerify) {
- setError(QStringLiteral("Failed to obtain peer trust: %1").arg(err),
- QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
+ QStringLiteral("Failed to obtain peer trust: %1").arg(err));
plainSocket->disconnectFromHost();
return false;
} else {
@@ -1005,8 +1009,8 @@ bool QSslSocketBackendPrivate::verifyPeerTrust()
if (err != noErr) {
// We can not ignore this, it's not even about trust verification
// probably ...
- setError(QStringLiteral("SecTrustEvaluate failed: %1").arg(err),
- QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
+ QStringLiteral("SecTrustEvaluate failed: %1").arg(err));
plainSocket->disconnectFromHost();
return false;
}
@@ -1124,8 +1128,8 @@ bool QSslSocketBackendPrivate::checkSslErrors()
pauseSocketNotifiers(q);
paused = true;
} else {
- setError(sslErrors.first().errorString(),
- QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
+ sslErrors.first().errorString());
plainSocket->disconnectFromHost();
}
return false;
@@ -1162,7 +1166,7 @@ bool QSslSocketBackendPrivate::startHandshake()
// setSessionCertificate does not fail if we have no certificate.
// Failure means a real error (invalid certificate, no private key, etc).
if (!setSessionCertificate(errorDescription, errorCode)) {
- setError(errorDescription, errorCode);
+ setErrorAndEmit(errorCode, errorDescription);
return false;
} else {
// We try to resume a handshake, even if have no
@@ -1177,8 +1181,8 @@ bool QSslSocketBackendPrivate::startHandshake()
return startHandshake();
}
- setError(QStringLiteral("SSLHandshake failed: %1").arg(err),
- QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
+ QStringLiteral("SSLHandshake failed: %1").arg(err));
plainSocket->disconnectFromHost();
return false;
}
@@ -1192,8 +1196,8 @@ bool QSslSocketBackendPrivate::startHandshake()
// check protocol version ourselves, as Secure Transport does not enforce
// the requested min / max versions.
if (!verifySessionProtocol()) {
- setError("Protocol version mismatch",
- QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
+ "Protocol version mismatch");
plainSocket->disconnectFromHost();
return false;
}
@@ -1206,16 +1210,6 @@ bool QSslSocketBackendPrivate::startHandshake()
}
}
-void QSslSocketBackendPrivate::setError(const QString &errorString,
- QAbstractSocket::SocketError errorCode)
-{
- Q_Q(QSslSocket);
-
- q->setErrorString(errorString);
- q->setSocketError(errorCode);
- emit q->error(errorCode);
-}
-
/*
PKCS12 helpers.
*/
diff --git a/src/network/ssl/qsslsocket_mac_p.h b/src/network/ssl/qsslsocket_mac_p.h
index 868b816957..414c155882 100644
--- a/src/network/ssl/qsslsocket_mac_p.h
+++ b/src/network/ssl/qsslsocket_mac_p.h
@@ -101,13 +101,6 @@ private:
bool checkSslErrors();
bool startHandshake();
- // Aux. function, sets:
- //1) socket error code,
- //2) error string (description)
- //3) emits a signal.
- void setError(const QString &errorString,
- QAbstractSocket::SocketError errorCode);
-
mutable QCFType<SSLContextRef> context;
Q_DISABLE_COPY(QSslSocketBackendPrivate);
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 1634d65eb6..0a4c68d7c0 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -364,9 +364,7 @@ bool QSslSocketBackendPrivate::initSslContext()
}
if (sslContextPointer->error() != QSslError::NoError) {
- q->setErrorString(sslContextPointer->errorString());
- q->setSocketError(QAbstractSocket::SslInvalidUserDataError);
- emit q->error(QAbstractSocket::SslInvalidUserDataError);
+ setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
sslContextPointer.clear(); // deletes the QSslContext
return false;
}
@@ -374,9 +372,8 @@ bool QSslSocketBackendPrivate::initSslContext()
// Create and initialize SSL session
if (!(ssl = sslContextPointer->createSsl())) {
// ### Bad error code
- q->setErrorString(QSslSocket::tr("Error creating SSL session, %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error creating SSL session, %1").arg(getErrorsFromOpenSsl()));
return false;
}
@@ -405,9 +402,8 @@ bool QSslSocketBackendPrivate::initSslContext()
readBio = q_BIO_new(q_BIO_s_mem());
writeBio = q_BIO_new(q_BIO_s_mem());
if (!readBio || !writeBio) {
- q->setErrorString(QSslSocket::tr("Error creating SSL session: %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error creating SSL session: %1").arg(getErrorsFromOpenSsl()));
return false;
}
@@ -808,11 +804,9 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
void QSslSocketBackendPrivate::startClientEncryption()
{
- Q_Q(QSslSocket);
if (!initSslContext()) {
- q->setErrorString(QSslSocket::tr("Unable to init SSL Context: %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Unable to init SSL Context: %1").arg(getErrorsFromOpenSsl()));
return;
}
@@ -824,11 +818,9 @@ void QSslSocketBackendPrivate::startClientEncryption()
void QSslSocketBackendPrivate::startServerEncryption()
{
- Q_Q(QSslSocket);
if (!initSslContext()) {
- q->setErrorString(QSslSocket::tr("Unable to init SSL Context: %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Unable to init SSL Context: %1").arg(getErrorsFromOpenSsl()));
return;
}
@@ -874,9 +866,9 @@ void QSslSocketBackendPrivate::transmit()
break;
} else {
// ### Better error handling.
- q->setErrorString(QSslSocket::tr("Unable to write data: %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Unable to write data: %1").arg(
+ getErrorsFromOpenSsl()));
return;
}
}
@@ -918,9 +910,7 @@ void QSslSocketBackendPrivate::transmit()
#endif
if (actualWritten < 0) {
//plain socket write fails if it was in the pending close state.
- q->setErrorString(plainSocket->errorString());
- q->setSocketError(plainSocket->error());
- emit q->error(plainSocket->error());
+ setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
return;
}
transmitting = true;
@@ -946,9 +936,9 @@ void QSslSocketBackendPrivate::transmit()
plainSocket->read(data.data(), writtenToBio);
} else {
// ### Better error handling.
- q->setErrorString(QSslSocket::tr("Unable to decrypt data: %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Unable to decrypt data: %1").arg(
+ getErrorsFromOpenSsl()));
return;
}
@@ -1022,17 +1012,15 @@ void QSslSocketBackendPrivate::transmit()
qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: remote disconnect";
#endif
shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
- q->setErrorString(QSslSocket::tr("The TLS/SSL connection has been closed"));
- q->setSocketError(QAbstractSocket::RemoteHostClosedError);
- emit q->error(QAbstractSocket::RemoteHostClosedError);
+ setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
+ QSslSocket::tr("The TLS/SSL connection has been closed"));
return;
case SSL_ERROR_SYSCALL: // some IO error
case SSL_ERROR_SSL: // error in the SSL library
// we do not know exactly what the error is, nor whether we can recover from it,
// so just return to prevent an endless loop in the outer "while" statement
- q->setErrorString(QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
return;
default:
// SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: can only happen with a
@@ -1040,9 +1028,8 @@ void QSslSocketBackendPrivate::transmit()
// SSL_ERROR_WANT_X509_LOOKUP: can only happen with a
// SSL_CTX_set_client_cert_cb(), which we do not call.
// So this default case should never be triggered.
- q->setErrorString(QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
break;
}
} while (ssl && readBytes > 0);
@@ -1134,12 +1121,12 @@ bool QSslSocketBackendPrivate::startHandshake()
// The handshake is not yet complete.
break;
default:
- q->setErrorString(QSslSocket::tr("Error during SSL handshake: %1").arg(getErrorsFromOpenSsl()));
- q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
+ QString errorString
+ = QSslSocket::tr("Error during SSL handshake: %1").arg(getErrorsFromOpenSsl());
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::startHandshake: error!" << q->errorString();
+ qCDebug(lcSsl) << "QSslSocketBackendPrivate::startHandshake: error!" << errorString;
#endif
- emit q->error(QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, errorString);
q->abort();
}
return false;
@@ -1290,9 +1277,7 @@ bool QSslSocketBackendPrivate::checkSslErrors()
pauseSocketNotifiers(q);
paused = true;
} else {
- q->setErrorString(sslErrors.first().errorString());
- q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
- emit q->error(QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.first().errorString());
plainSocket->disconnectFromHost();
}
return false;
@@ -1513,6 +1498,13 @@ void QSslSocketBackendPrivate::disconnected()
{
if (plainSocket->bytesAvailable() <= 0)
destroySslContext();
+ else {
+ // Move all bytes into the plain buffer
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
+ transmit();
+ readBufferMaxSize = tmpReadBufferMaxSize;
+ }
//if there is still buffered data in the plain socket, don't destroy the ssl context yet.
//it will be destroyed when the socket is deleted.
}
diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp
index aba3ea8170..b03f234d49 100644
--- a/src/network/ssl/qsslsocket_winrt.cpp
+++ b/src/network/ssl/qsslsocket_winrt.cpp
@@ -251,9 +251,8 @@ void QSslSocketBackendPrivate::startClientEncryption()
case QSsl::TlsV1_2OrLater:
// TlsV1_0OrLater, TlsV1_1OrLater and TlsV1_2OrLater are disabled on WinRT
// because there is no good way to map them to the native API.
- q->setErrorString(QStringLiteral("unsupported protocol"));
- q->setSocketError(QAbstractSocket::SslInvalidUserDataError);
- emit q->error(QAbstractSocket::SslInvalidUserDataError);
+ setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
+ QStringLiteral("unsupported protocol"));
return;
default:
protectionLevel = SocketProtectionLevel_Tls12; // default to highest
@@ -347,13 +346,10 @@ QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
void QSslSocketBackendPrivate::continueHandshake()
{
- Q_Q(QSslSocket);
-
IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
if (qintptr(socket) == -1) {
- q->setErrorString(QStringLiteral("At attempt was made to continue the handshake on an invalid socket."));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QStringLiteral("At attempt was made to continue the handshake on an invalid socket."));
return;
}
@@ -372,9 +368,7 @@ void QSslSocketBackendPrivate::continueHandshake()
Q_ASSERT_SUCCEEDED(hr);
}
if (FAILED(hr)) {
- q->setErrorString(qt_error_string(hr));
- q->setSocketError(QAbstractSocket::SslInvalidUserDataError);
- emit q->error(QAbstractSocket::SslInvalidUserDataError);
+ setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, qt_error_string(hr));
return;
}
@@ -440,10 +434,8 @@ void QSslSocketBackendPrivate::continueHandshake()
ComPtr<IAsyncAction> op;
hr = socket->UpgradeToSslAsync(protectionLevel, hostName.Get(), &op);
if (FAILED(hr)) {
- q->setErrorString(QSslSocket::tr("Error creating SSL session: %1")
- .arg(qt_error_string(hr)));
- q->setSocketError(QAbstractSocket::SslInternalError);
- emit q->error(QAbstractSocket::SslInternalError);
+ setErrorAndEmit(QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error creating SSL session: %1").arg(qt_error_string(hr)));
return;
}
@@ -467,9 +459,7 @@ HRESULT QSslSocketBackendPrivate::onSslUpgrade(IAsyncAction *action, AsyncStatus
QSet<QSslError> errors;
switch (hr) {
case SEC_E_INVALID_TOKEN: // Occurs when the server doesn't support the requested protocol
- q->setErrorString(qt_error_string(hr));
- q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
- emit q->error(QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, qt_error_string(hr));
q->disconnectFromHost();
return S_OK;
default:
@@ -628,9 +618,7 @@ HRESULT QSslSocketBackendPrivate::onSslUpgrade(IAsyncAction *action, AsyncStatus
if (!sslErrors.isEmpty()) {
emit q->sslErrors(sslErrors);
- q->setErrorString(sslErrors.first().errorString());
- q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
- emit q->error(QAbstractSocket::SslHandshakeFailedError);
+ setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.first().errorString());
// Disconnect if there are any non-ignorable errors
foreach (const QSslError &error, sslErrors) {