diff options
-rw-r--r-- | src/network/socket/qabstractsocketengine_p.h | 4 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine.cpp | 8 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_p.h | 9 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_win.cpp | 104 | ||||
-rw-r--r-- | src/network/socket/qudpsocket.cpp | 8 | ||||
-rw-r--r-- | src/network/socket/qudpsocket.h | 4 | ||||
-rw-r--r-- | tests/auto/qudpsocket/tst_qudpsocket.cpp | 6 |
7 files changed, 125 insertions, 18 deletions
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h index 0632891..bfd9b05 100644 --- a/src/network/socket/qabstractsocketengine_p.h +++ b/src/network/socket/qabstractsocketengine_p.h @@ -121,9 +121,9 @@ public: #ifndef QT_NO_UDPSOCKET virtual bool joinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) = 0; + const QNetworkInterface &iface) = 0; virtual bool leaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) = 0; + const QNetworkInterface &iface) = 0; virtual qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0, quint16 *port = 0) = 0; diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index ae2cad2..7cb3a1b 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -650,26 +650,26 @@ int QNativeSocketEngine::accept() \since 4.8 */ bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) + const QNetworkInterface &iface) { Q_D(QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::joinMulticastGroup(), false); Q_CHECK_STATE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false); Q_CHECK_TYPE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false); - return d->nativeJoinMulticastGroup(groupAddress, interface); + return d->nativeJoinMulticastGroup(groupAddress, iface); } /*! \since 4.8 */ bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) + const QNetworkInterface &iface) { Q_D(QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::leaveMulticastGroup(), false); Q_CHECK_STATE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false); Q_CHECK_TYPE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false); - return d->nativeLeaveMulticastGroup(groupAddress, interface); + return d->nativeLeaveMulticastGroup(groupAddress, iface); } /*! diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index e44aa2e..ce00747 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -101,6 +101,7 @@ union qt_sockaddr { }; class QNativeSocketEnginePrivate; +class QNetworkInterface; class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine { @@ -124,9 +125,9 @@ public: void close(); bool joinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface); + const QNetworkInterface &iface); bool leaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface); + const QNetworkInterface &iface); qint64 bytesAvailable() const; @@ -243,9 +244,9 @@ public: bool nativeListen(int backlog); int nativeAccept(); bool nativeJoinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface); + const QNetworkInterface &iface); bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface); + const QNetworkInterface &iface); qint64 nativeBytesAvailable() const; bool nativeHasPendingDatagrams() const; diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 477ef45..d222fd1 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include <winsock2.h> +#include <ws2tcpip.h> #include "qnativesocketengine_p.h" @@ -47,6 +48,7 @@ #include <qsocketnotifier.h> #include <qdebug.h> #include <qdatetime.h> +#include <qnetworkinterface.h> //#define QNATIVESOCKETENGINE_DEBUG #if defined(QNATIVESOCKETENGINE_DEBUG) @@ -399,6 +401,13 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co case QNativeSocketEngine::KeepAliveOption: n = SO_KEEPALIVE; break; + case QNativeSocketEngine::MulticastLoopback: + { + unsigned long val = 0; + if (WSAIoctl(socketDescriptor, SIO_MULTIPOINT_LOOPBACK, 0, 0, &val, sizeof(val), 0, 0, 0) == 0) + return val; + return -1; + } } int v = -1; @@ -459,6 +468,14 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt case QNativeSocketEngine::KeepAliveOption: n = SO_KEEPALIVE; break; + case QNativeSocketEngine::MulticastLoopback: + { + unsigned long val = v, outval; + if (WSAIoctl(socketDescriptor, SIO_MULTIPOINT_LOOPBACK, &val, sizeof(val), &outval, sizeof(outval), 0, 0, 0) == 0) + return true; + WS_ERROR_DEBUG(WSAGetLastError()); + return false; + } } if (::setsockopt(socketDescriptor, level, n, (char*)&v, sizeof(v)) != 0) { @@ -747,6 +764,93 @@ int QNativeSocketEnginePrivate::nativeAccept() return acceptedDescriptor; } +static bool doMulticast(QNativeSocketEnginePrivate *d, + int how6, + int how4, + const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + int sockOpt = 0; + char *sockArg; + int sockArgSize; + + struct ip_mreq mreq4; +#ifndef QT_NO_IPV6 + struct ipv6_mreq mreq6; + + if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) { + sockOpt = how6; + sockArg = reinterpret_cast<char *>(&mreq6); + sockArgSize = sizeof(mreq6); + memset(&mreq6, 0, sizeof(mreq6)); + Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); + memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6)); + mreq6.ipv6mr_interface = iface.index(); + } else +#endif + if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { + sockOpt = how4; + sockArg = reinterpret_cast<char *>(&mreq4); + sockArgSize = sizeof(mreq4); + memset(&mreq4, 0, sizeof(mreq4)); + mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address()); + + if (iface.isValid()) { + QList<QNetworkAddressEntry> addressEntries = iface.addressEntries(); + if (!addressEntries.isEmpty()) { + QHostAddress firstIP = addressEntries.first().ip(); + mreq4.imr_interface.s_addr = htonl(firstIP.toIPv4Address()); + } else { + d->setError(QAbstractSocket::NetworkError, + QNativeSocketEnginePrivate::NetworkUnreachableErrorString); + return false; + } + } else { + mreq4.imr_interface.s_addr = INADDR_ANY; + } + } else { + // unreachable + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QNativeSocketEnginePrivate::ProtocolUnsupportedErrorString); + return false; + } + + int res = setsockopt(d->socketDescriptor, IPPROTO_IP, sockOpt, sockArg, sockArgSize); + if (res == -1) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QNativeSocketEnginePrivate::OperationUnsupportedErrorString); + return false; + } + return true; +} + +bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + return doMulticast(this, +#ifndef QT_NO_IPV6 + IPV6_JOIN_GROUP, +#else + 0, +#endif + IP_ADD_MEMBERSHIP, + groupAddress, + iface); +} + +bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + return doMulticast(this, +#ifndef QT_NO_IPV6 + IPV6_LEAVE_GROUP, +#else + 0, +#endif + IP_DROP_MEMBERSHIP, + groupAddress, + iface); +} qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const { diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index 84657b4..29345ca 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -342,14 +342,14 @@ bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress, MulticastM \overload */ bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface, + const QNetworkInterface &iface, MulticastMode mode) { Q_D(QUdpSocket); QT_CHECK_BOUND("QUdpSocket::joinMulticastGroup()", false); d->socketEngine->setOption(QAbstractSocketEngine::MulticastLoopback, (mode & MulticastLoopback) ? 1 : 0); - return d->socketEngine->joinMulticastGroup(groupAddress, interface); + return d->socketEngine->joinMulticastGroup(groupAddress, iface); } /*! @@ -365,10 +365,10 @@ bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress) \overload */ bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) + const QNetworkInterface &iface) { QT_CHECK_BOUND("QUdpSocket::leaveMulticastGroup()", false); - return d_func()->socketEngine->leaveMulticastGroup(groupAddress, interface); + return d_func()->socketEngine->leaveMulticastGroup(groupAddress, iface); } /*! diff --git a/src/network/socket/qudpsocket.h b/src/network/socket/qudpsocket.h index ff80712..c8a9678 100644 --- a/src/network/socket/qudpsocket.h +++ b/src/network/socket/qudpsocket.h @@ -86,11 +86,11 @@ public: bool joinMulticastGroup(const QHostAddress &groupAddress, MulticastMode mode = DefaultMulticastFlagForPlatform); bool joinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface, + const QNetworkInterface &iface, MulticastMode mode = DefaultMulticastFlagForPlatform); bool leaveMulticastGroup(const QHostAddress &groupAddress); bool leaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface); + const QNetworkInterface &iface); bool hasPendingDatagrams() const; qint64 pendingDatagramSize() const; diff --git a/tests/auto/qudpsocket/tst_qudpsocket.cpp b/tests/auto/qudpsocket/tst_qudpsocket.cpp index 39a7ab1..3c08cd7 100644 --- a/tests/auto/qudpsocket/tst_qudpsocket.cpp +++ b/tests/auto/qudpsocket/tst_qudpsocket.cpp @@ -876,8 +876,10 @@ void tst_QUdpSocket::multicast() << QByteArray("cdef"); QUdpSocket sender; - foreach (const QByteArray &datagram, datagrams) - sender.writeDatagram(datagram, receiver.localAddress(), receiver.localPort()); + foreach (const QByteArray &datagram, datagrams) { + QCOMPARE(int(sender.writeDatagram(datagram, groupAddress, receiver.localPort())), + int(datagram.size())); + } QVERIFY2(receiver.waitForReadyRead(), qPrintable(receiver.errorString())); |