summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShane Kearns <ext-shane.2.kearns@nokia.com>2012-03-15 17:58:22 +0000
committerQt by Nokia <qt-info@nokia.com>2012-03-22 18:59:45 +0100
commitcae5299f48d950ab924e8b78452d25535bd8b811 (patch)
treebba1f53b34cbd2b1ffbb8ef9368b7a1f2ed6f9aa
parentfa8e18c3860d8c43795152da1d4c38dc1471f320 (diff)
Allow autobound UDP sockets to send to IPv4 and IPv6
When writeDatagram is called without first binding the UDP socket, then bind it as QHostAddress::Any. This allows the same socket to be used to sent to both IPv4 and IPv6 destination addresses. Allowing the OS to autobind the socket inside sendTo() may result in a single protocol socket. Task-number: QTBUG-5275 Change-Id: I2b76507e8a8a38369c6eafb61ce4191d1d6cc930 Reviewed-by: Richard J. Moore <rich@kde.org> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Martin Petersson <Martin.Petersson@nokia.com>
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp3
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp3
-rw-r--r--src/network/socket/qudpsocket.cpp4
-rw-r--r--tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp79
4 files changed, 86 insertions, 3 deletions
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index b7c149c18d..295d3961a8 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -854,7 +854,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
struct sockaddr_in6 sockAddrIPv6;
if (host.protocol() == QAbstractSocket::IPv6Protocol
- || socketProtocol == QAbstractSocket::IPv6Protocol) {
+ || socketProtocol == QAbstractSocket::IPv6Protocol
+ || socketProtocol == QAbstractSocket::AnyIPProtocol) {
memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
sockAddrIPv6.sin6_family = AF_INET6;
sockAddrIPv6.sin6_port = htons(port);
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 93a470c77f..4bf2a6c6e3 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -202,7 +202,8 @@ void QNativeSocketEnginePrivate::setPortAndAddress(sockaddr_in * sockAddrIPv4, q
if (address.protocol() == QAbstractSocket::IPv6Protocol
|| address.protocol() == QAbstractSocket::AnyIPProtocol
- || socketProtocol == QAbstractSocket::IPv6Protocol) {
+ || socketProtocol == QAbstractSocket::IPv6Protocol
+ || socketProtocol == QAbstractSocket::AnyIPProtocol) {
memset(sockAddrIPv6, 0, sizeof(qt_sockaddr_in6));
sockAddrIPv6->sin6_family = AF_INET6;
sockAddrIPv6->sin6_scope_id = address.scopeId().toInt();
diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp
index a31b16e97d..ec751c289e 100644
--- a/src/network/socket/qudpsocket.cpp
+++ b/src/network/socket/qudpsocket.cpp
@@ -332,8 +332,10 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre
qDebug("QUdpSocket::writeDatagram(%p, %llu, \"%s\", %i)", data, size,
address.toString().toLatin1().constData(), port);
#endif
- if (!d->ensureInitialized(address))
+ if (!d->doEnsureInitialized(QHostAddress::Any, 0, address))
return -1;
+ if (state() == UnconnectedState)
+ bind();
qint64 sent = d->socketEngine->writeDatagram(data, size, address, port);
d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
index 3dabe6741a..c53450eec6 100644
--- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
+++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
@@ -92,6 +92,8 @@ private slots:
void ipv6Loop_data();
void ipv6Loop();
void dualStack();
+ void dualStackAutoBinding();
+ void dualStackNoIPv4onV6only();
void readLine();
void pendingDatagramSize();
void writeDatagram();
@@ -490,6 +492,83 @@ void tst_QUdpSocket::dualStack()
}
+void tst_QUdpSocket::dualStackAutoBinding()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ QSKIP("test server SOCKS proxy doesn't support IPv6");
+ QUdpSocket v4Sock;
+ QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
+
+ QUdpSocket v6Sock;
+ QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0));
+
+ QByteArray dualData("dual");
+ QHostAddress from;
+ quint16 port;
+ QByteArray buffer;
+ int size;
+
+ {
+ //test an autobound socket can send to both v4 and v6 addresses (v4 first)
+ QUdpSocket dualSock;
+
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
+ QVERIFY(v4Sock.waitForReadyRead(5000));
+ buffer.reserve(100);
+ size = v4Sock.readDatagram(buffer.data(), 100, &from, &port);
+ QCOMPARE((int)size, dualData.length());
+ buffer.resize(size);
+ QCOMPARE(buffer, dualData);
+
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
+ QVERIFY(v6Sock.waitForReadyRead(5000));
+ buffer.reserve(100);
+ size = v6Sock.readDatagram(buffer.data(), 100, &from, &port);
+ QCOMPARE((int)size, dualData.length());
+ buffer.resize(size);
+ QCOMPARE(buffer, dualData);
+ }
+
+ {
+ //test an autobound socket can send to both v4 and v6 addresses (v6 first)
+ QUdpSocket dualSock;
+
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
+ QVERIFY(v6Sock.waitForReadyRead(5000));
+ buffer.reserve(100);
+ size = v6Sock.readDatagram(buffer.data(), 100, &from, &port);
+ QCOMPARE((int)size, dualData.length());
+ buffer.resize(size);
+ QCOMPARE(buffer, dualData);
+
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
+ QVERIFY(v4Sock.waitForReadyRead(5000));
+ buffer.reserve(100);
+ size = v4Sock.readDatagram(buffer.data(), 100, &from, &port);
+ QCOMPARE((int)size, dualData.length());
+ buffer.resize(size);
+ QCOMPARE(buffer, dualData);
+ }
+}
+
+void tst_QUdpSocket::dualStackNoIPv4onV6only()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ QSKIP("test server SOCKS proxy doesn't support IPv6");
+ QUdpSocket v4Sock;
+ QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
+ QByteArray v4Data("v4");
+
+ QUdpSocket v6Sock;
+ QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0));
+
+ //test v4 -> v6 (should not be received as this is a v6 only socket)
+ QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), v6Sock.localPort()), v4Data.length());
+ QVERIFY(!v6Sock.waitForReadyRead(1000));
+}
+
void tst_QUdpSocket::empty_readyReadSlot()
{
QTestEventLoop::instance().exitLoop();