Fix QTcpServer::serverAddress() for dual stack sockets
authorShane Kearns <shane.kearns@accenture.com>
Wed, 30 Nov 2011 17:21:51 +0000 (17:21 +0000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 1 Dec 2011 14:58:57 +0000 (15:58 +0100)
When listening on QHostAddress::Any, serverAddress() should return
QHostAddress::Any too, assuming that setting the socket options
was successful.

Task-number: QTBUG-22899
Change-Id: I50a9ff1b4ad0c1c1905e2952c595d7068df2627d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
src/network/socket/qnativesocketengine_unix.cpp
src/network/socket/qnativesocketengine_win.cpp
tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp

index ae7e239..09aed25 100644 (file)
@@ -922,6 +922,21 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
         return false;
     }
 
+#if defined (IPV6_V6ONLY)
+    // determine if local address is dual mode
+    int ipv6only = 0;
+    socklen_t optlen = sizeof(ipv6only);
+    if (localAddress == QHostAddress::AnyIPv6
+        && !getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, &optlen )) {
+            if (optlen != sizeof(ipv6only))
+                qWarning("unexpected size of IPV6_V6ONLY socket option");
+            if (!ipv6only) {
+                socketProtocol = QAbstractSocket::AnyIPProtocol;
+                localAddress = QHostAddress::Any;
+            }
+    }
+#endif
+
     // Determine the remote address
     if (!::getpeername(socketDescriptor, &sa.a, &sockAddrSize))
         qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress);
index 4be930b..247de01 100644 (file)
@@ -554,6 +554,22 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
         }
     }
 
+#if defined (IPV6_V6ONLY)
+    // determine if local address is dual mode
+    DWORD ipv6only = 0;
+    int optlen = sizeof(ipv6only);
+    if (localAddress == QHostAddress::AnyIPv6
+        && QSysInfo::windowsVersion() >= QSysInfo::WV_6_0
+        && !getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, &optlen )) {
+            if (optlen != sizeof(ipv6only))
+                qWarning("unexpected size of IPV6_V6ONLY socket option");
+            if (!ipv6only) {
+                socketProtocol = QAbstractSocket::AnyIPProtocol;
+                localAddress = QHostAddress::Any;
+            }
+    }
+#endif
+
     memset(&sa, 0, sizeof(sa));
     if (::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
         qt_socket_getPortAndAddress(socketDescriptor, &sa, &peerPort, &peerAddress);
index 0cdd3a7..769544e 100644 (file)
@@ -116,6 +116,8 @@ private slots:
 
     void qtbug14268_peek();
 
+    void serverAddress_data();
+    void serverAddress();
 private:
 #ifndef QT_NO_BEARERMANAGEMENT
     QNetworkSession *networkSession;
@@ -789,5 +791,39 @@ void tst_QTcpServer::qtbug14268_peek()
     QVERIFY(helper.lastDataPeeked == QByteArray("6162630a6465660a6768690a"));
 }
 
+void tst_QTcpServer::serverAddress_data()
+{
+    QTest::addColumn<QHostAddress>("listenAddress");
+    QTest::addColumn<QHostAddress>("serverAddress");
+#ifdef Q_OS_WIN
+    if (QSysInfo::windowsVersion() < QSysInfo::WV_6_0)
+        QTest::newRow("Any") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv4); //windows XP doesn't support dual stack sockets
+    else
+#endif
+    QTest::newRow("Any") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::Any);
+    QTest::newRow("AnyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress(QHostAddress::AnyIPv4);
+    QTest::newRow("AnyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv6);
+    foreach (const QHostAddress& addr, QNetworkInterface::allAddresses()) {
+        if (addr.isInSubnet(QHostAddress::parseSubnet("fe80::/10"))
+            || addr.isInSubnet(QHostAddress::parseSubnet("169.254/16")))
+            continue; //cannot bind on link local addresses
+        QTest::newRow(qPrintable(addr.toString())) << addr << addr;
+    }
+}
+
+void tst_QTcpServer::serverAddress()
+{
+    QFETCH_GLOBAL(bool, setProxy);
+    if (setProxy)
+        return;
+
+    QFETCH(QHostAddress, listenAddress);
+    QFETCH(QHostAddress, serverAddress);
+    QTcpServer server;
+    if (!server.listen(listenAddress))
+        QSKIP(qPrintable(server.errorString()));
+    QCOMPARE(server.serverAddress(), serverAddress);
+}
+
 QTEST_MAIN(tst_QTcpServer)
 #include "tst_qtcpserver.moc"
index 9c87ac0..00a9ed2 100644 (file)
@@ -1542,7 +1542,9 @@ void tst_QTcpSocket::dontCloseOnTimeout()
     QVERIFY(server.listen());
 
     QHostAddress serverAddress = QHostAddress::LocalHost;
-    if (!(server.serverAddress() == QHostAddress::AnyIPv4) && !(server.serverAddress() == QHostAddress::AnyIPv6))
+    if (!(server.serverAddress() == QHostAddress::AnyIPv4)
+        && !(server.serverAddress() == QHostAddress::AnyIPv6)
+        && !(server.serverAddress() == QHostAddress::Any))
         serverAddress = server.serverAddress();
 
     QTcpSocket *socket = newSocket();