Windows - fix getsockopt calls for narrower than int options
authorShane Kearns <ext-shane.2.kearns@nokia.com>
Mon, 20 Feb 2012 18:48:10 +0000 (18:48 +0000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 29 Feb 2012 23:09:57 +0000 (00:09 +0100)
Windows unhelpfully writes to only one byte of the output buffer
when getsockopt is called for a boolean option. Therefore we have
to zero initialise the int rather than initialising to -1 as was
done before.
This in general only works for little endian architecture, because
the word would look like 0x01000000 on big endian. So I have added
some compile time asserts in the assumption that windows is always
little endian. This is ok for comparisons with 0/false, but not
comparisons with true or nonzero values.
In the case of IPV6_V6ONLY, it is documented as DWORD (unsigned int)
but on some windows versions it is returned as a boolean triggering
the warning. I removed the warning, as the conversion to int works on
both LE and BE since it is only compared with zero.

Task-number: QTBUG-23488
Change-Id: I3c586d1ada76465fc045a82661f289920c657a4c
Reviewed-by: Richard J. Moore <rich@kde.org>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Reviewed-by: Andreas Holzammer <andreas.holzammer@kdab.com>
src/network/socket/qnativesocketengine_win.cpp
tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp

index d7bbe7e..93a470c 100644 (file)
@@ -427,10 +427,14 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
         break;
     }
 
-    int v = -1;
+#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN
+#error code assumes windows is little endian
+#endif
+    int v = 0; //note: windows doesn't write to all bytes if the option type is smaller than int
     QT_SOCKOPTLEN_T len = sizeof(v);
-    if (getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
+    if (getsockopt(socketDescriptor, level, n, (char *) &v, &len) == 0)
         return v;
+    WS_ERROR_DEBUG(WSAGetLastError());
     return -1;
 }
 
@@ -563,12 +567,10 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
 #if defined (IPV6_V6ONLY)
     // determine if local address is dual mode
     DWORD ipv6only = 0;
-    int optlen = sizeof(ipv6only);
+    QT_SOCKOPTLEN_T 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;
index 2c2b551..8b65c31 100644 (file)
@@ -201,6 +201,8 @@ private slots:
 
     void qtbug14268_peek();
 
+    void setSocketOption();
+
 
 protected slots:
     void nonBlockingIMAP_hostFound();
@@ -2699,7 +2701,41 @@ void tst_QTcpSocket::qtbug14268_peek()
     QVERIFY(incoming->read(128*1024) == QByteArray("abc\ndef\nghi\n"));
 }
 
+void tst_QTcpSocket::setSocketOption()
+{
+    QFETCH_GLOBAL(bool, setProxy);
+    if (setProxy)
+        return;
+
+    SocketPair socketPair;
+    QVERIFY(socketPair.create());
+    QTcpSocket *outgoing = socketPair.endPoints[0];
+    QTcpSocket *incoming = socketPair.endPoints[1];
+
+    QVERIFY(incoming->state() == QTcpSocket::ConnectedState);
+    QVERIFY(outgoing->state() == QTcpSocket::ConnectedState);
+
+    outgoing->setSocketOption(QAbstractSocket::LowDelayOption, true);
+    QVariant v = outgoing->socketOption(QAbstractSocket::LowDelayOption);
+    QVERIFY(v.isValid() && v.toBool());
+    outgoing->setSocketOption(QAbstractSocket::KeepAliveOption, true);
+    v = outgoing->socketOption(QAbstractSocket::KeepAliveOption);
+    QVERIFY(v.isValid() && v.toBool());
 
+    outgoing->setSocketOption(QAbstractSocket::LowDelayOption, false);
+    v = outgoing->socketOption(QAbstractSocket::LowDelayOption);
+    QVERIFY(v.isValid() && !v.toBool());
+    outgoing->setSocketOption(QAbstractSocket::KeepAliveOption, false);
+    v = outgoing->socketOption(QAbstractSocket::KeepAliveOption);
+    QVERIFY(v.isValid() && !v.toBool());
+
+#ifdef Q_OS_WIN
+    QEXPECT_FAIL("", "QTBUG-23323", Abort);
+#endif
+    outgoing->setSocketOption(QAbstractSocket::TypeOfServiceOption, 32); //high priority
+    v = outgoing->socketOption(QAbstractSocket::TypeOfServiceOption);
+    QVERIFY(v.isValid() && v.toInt() == 32);
+}
 
 QTEST_MAIN(tst_QTcpSocket)
 #include "tst_qtcpsocket.moc"