summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/socket/qabstractsocketengine_p.h2
-rw-r--r--src/network/socket/qhttpsocketengine.cpp13
-rw-r--r--src/network/socket/qhttpsocketengine_p.h2
-rw-r--r--src/network/socket/qnativesocketengine.cpp20
-rw-r--r--src/network/socket/qnativesocketengine_p.h4
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp111
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp63
-rw-r--r--src/network/socket/qsocks5socketengine.cpp14
-rw-r--r--src/network/socket/qsocks5socketengine_p.h2
-rw-r--r--src/network/socket/qudpsocket.cpp46
-rw-r--r--src/network/socket/qudpsocket.h3
-rw-r--r--tests/auto/qudpsocket/tst_qudpsocket.cpp44
12 files changed, 313 insertions, 11 deletions
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
index 616fdb2..ec5fbd3 100644
--- a/src/network/socket/qabstractsocketengine_p.h
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -125,6 +125,8 @@ public:
const QNetworkInterface &iface) = 0;
virtual bool leaveMulticastGroup(const QHostAddress &groupAddress,
const QNetworkInterface &iface) = 0;
+ virtual QNetworkInterface multicastInterface() const = 0;
+ virtual bool setMulticastInterface(const QNetworkInterface &iface) = 0;
virtual qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
quint16 *port = 0) = 0;
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index e467df8..cb0e296 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -45,6 +45,7 @@
#include "qurl.h"
#include "qhttp.h"
#include "qelapsedtimer.h"
+#include "qnetworkinterface.h"
#if !defined(QT_NO_NETWORKPROXY) && !defined(QT_NO_HTTP)
#include <qdebug.h>
@@ -255,6 +256,18 @@ bool QHttpSocketEngine::leaveMulticastGroup(const QHostAddress &,
return false;
}
+QNetworkInterface QHttpSocketEngine::multicastInterface() const
+{
+ return QNetworkInterface();
+}
+
+bool QHttpSocketEngine::setMulticastInterface(const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+
qint64 QHttpSocketEngine::readDatagram(char *, qint64, QHostAddress *,
quint16 *)
{
diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h
index 1a6b4f6..b68b7117 100644
--- a/src/network/socket/qhttpsocketengine_p.h
+++ b/src/network/socket/qhttpsocketengine_p.h
@@ -106,6 +106,8 @@ public:
const QNetworkInterface &interface);
bool leaveMulticastGroup(const QHostAddress &groupAddress,
const QNetworkInterface &interface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
quint16 *port = 0);
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index 7cb3a1b..df73b9c 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -98,6 +98,7 @@
#include <qabstracteventdispatcher.h>
#include <qsocketnotifier.h>
+#include <qnetworkinterface.h>
#include "qnativesocketengine_p.h"
#include <private/qthread_p.h>
@@ -672,6 +673,25 @@ bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress,
return d->nativeLeaveMulticastGroup(groupAddress, iface);
}
+/*! \since 4.8 */
+QNetworkInterface QNativeSocketEngine::multicastInterface() const
+{
+ Q_D(const QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::multicastInterface(), QNetworkInterface());
+ Q_CHECK_TYPE(QNativeSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface());
+ return d->nativeMulticastInterface();
+}
+
+
+/*! \since 4.8 */
+bool QNativeSocketEngine::setMulticastInterface(const QNetworkInterface &iface)
+{
+ Q_D(QNativeSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setMulticastInterface(), false);
+ Q_CHECK_TYPE(QNativeSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false);
+ return d->nativeSetMulticastInterface(iface);
+}
+
/*!
Returns the number of bytes that are currently available for
reading. On error, -1 is returned.
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index ce00747..9baacf0 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -128,6 +128,8 @@ public:
const QNetworkInterface &iface);
bool leaveMulticastGroup(const QHostAddress &groupAddress,
const QNetworkInterface &iface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
qint64 bytesAvailable() const;
@@ -247,6 +249,8 @@ public:
const QNetworkInterface &iface);
bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
const QNetworkInterface &iface);
+ QNetworkInterface nativeMulticastInterface() const;
+ bool nativeSetMulticastInterface(const QNetworkInterface &iface);
qint64 nativeBytesAvailable() const;
bool nativeHasPendingDatagrams() const;
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 737e35a..e7f6c7e 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -249,12 +249,28 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
n = SO_KEEPALIVE;
break;
case QNativeSocketEngine::MulticastTtlOption:
- level = IPPROTO_IP;
- n = IP_MULTICAST_TTL;
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_HOPS;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_TTL;
+ }
break;
case QNativeSocketEngine::MulticastLoopbackOption:
- level = IPPROTO_IP;
- n = IP_MULTICAST_LOOP;
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_LOOP;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_LOOP;
+ }
break;
}
@@ -340,12 +356,28 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
n = SO_KEEPALIVE;
break;
case QNativeSocketEngine::MulticastTtlOption:
- level = IPPROTO_IP;
- n = IP_MULTICAST_TTL;
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_HOPS;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_TTL;
+ }
break;
case QNativeSocketEngine::MulticastLoopbackOption:
- level = IPPROTO_IP;
- n = IP_MULTICAST_LOOP;
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_LOOP;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_LOOP;
+ }
break;
}
@@ -693,6 +725,69 @@ bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &g
interface);
}
+QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v;
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ return QNetworkInterface::interfaceFromIndex(v);
+ }
+#endif
+
+ struct in_addr v = { 0 };
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ if (v.s_addr != 0 && sizeofv >= sizeof(v)) {
+ QHostAddress ipv4(ntohl(v.s_addr));
+ QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
+ for (int i = 0; i < ifaces.count(); ++i) {
+ const QNetworkInterface &iface = ifaces.at(i);
+ if (!(iface.flags() & QNetworkInterface::CanMulticast))
+ continue;
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int j = 0; j < entries.count(); ++j) {
+ const QNetworkAddressEntry &entry = entries.at(j);
+ if (entry.ip() == ipv4)
+ return iface;
+ }
+ }
+ }
+ return QNetworkInterface();
+}
+
+bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface)
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v = iface.isValid() ? iface.index() : 0;
+ return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, sizeof(v)) != -1);
+ }
+#endif
+
+ struct in_addr v;
+ if (iface.isValid()) {
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int i = 0; i < entries.count(); ++i) {
+ const QNetworkAddressEntry &entry = entries.at(i);
+ const QHostAddress &ip = entry.ip();
+ if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
+ v.s_addr = htonl(ip.toIPv4Address());
+ int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v));
+ if (r != -1)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ v.s_addr = INADDR_ANY;
+ return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v)) != -1);
+}
+
qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
{
int nbytes = 0;
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index a922b45..2ca1f41 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -853,6 +853,69 @@ bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &g
iface);
}
+QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v;
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ return QNetworkInterface::interfaceFromIndex(v);
+ }
+#endif
+
+ struct in_addr v = { 0 };
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ if (v.s_addr != 0 && sizeofv >= sizeof(v)) {
+ QHostAddress ipv4(ntohl(v.s_addr));
+ QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
+ for (int i = 0; i < ifaces.count(); ++i) {
+ const QNetworkInterface &iface = ifaces.at(i);
+ if (!(iface.flags() & QNetworkInterface::CanMulticast))
+ continue;
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int j = 0; j < entries.count(); ++j) {
+ const QNetworkAddressEntry &entry = entries.at(j);
+ if (entry.ip() == ipv4)
+ return iface;
+ }
+ }
+ }
+ return QNetworkInterface();
+}
+
+bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface)
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v = iface.isValid() ? iface.index() : 0;
+ return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, sizeof(v)) != -1);
+ }
+#endif
+
+ struct in_addr v;
+ if (iface.isValid()) {
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int i = 0; i < entries.count(); ++i) {
+ const QNetworkAddressEntry &entry = entries.at(i);
+ const QHostAddress &ip = entry.ip();
+ if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
+ v.s_addr = htonl(ip.toIPv4Address());
+ int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v));
+ if (r != -1)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ v.s_addr = INADDR_ANY;
+ return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v)) != -1);
+}
+
qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
{
unsigned long nbytes = 0;
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index dcaf561..17cf5b1 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -56,6 +56,7 @@
#include "qurl.h"
#include "qauthenticator.h"
#include <qendian.h>
+#include <qnetworkinterface.h>
QT_BEGIN_NAMESPACE
@@ -1560,6 +1561,19 @@ bool QSocks5SocketEngine::leaveMulticastGroup(const QHostAddress &,
return false;
}
+
+QNetworkInterface QSocks5SocketEngine::multicastInterface() const
+{
+ return QNetworkInterface();
+}
+
+bool QSocks5SocketEngine::setMulticastInterface(const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+
qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr,
quint16 *port)
{
diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h
index 298595a..06fcad2 100644
--- a/src/network/socket/qsocks5socketengine_p.h
+++ b/src/network/socket/qsocks5socketengine_p.h
@@ -96,6 +96,8 @@ public:
const QNetworkInterface &interface);
bool leaveMulticastGroup(const QHostAddress &groupAddress,
const QNetworkInterface &interface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
quint16 *port = 0);
diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp
index dffb5df..5d8f4c0 100644
--- a/src/network/socket/qudpsocket.cpp
+++ b/src/network/socket/qudpsocket.cpp
@@ -77,11 +77,12 @@
\snippet doc/src/snippets/code/src_network_socket_qudpsocket.cpp 0
- QUdpSocket also supports UDP multicast. Use the joinMulticastGroup() and
- leaveMulticastGroup() to control group membership, and the
+ QUdpSocket also supports UDP multicast. Use joinMulticastGroup() and
+ leaveMulticastGroup() to control group membership, and
QAbstractSocket::MulticastTtlOption and
QAbstractSocket::MulticastLoopbackOption to set the TTL and loopback socket
- options.
+ options. Use setMulticastInterface() to control the outgoing interface for
+ multicast datagrams, and multicastInterface() to query it.
With QUdpSocket, you can also establish a virtual connection to a
UDP server using connectToHost() and then use read() and write()
@@ -405,6 +406,45 @@ bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress,
}
/*!
+ \since 4.8
+
+ Returns the interface for the outgoing interface for multicast datagrams.
+ This corresponds to the IP_MULTICAST_IF socket option for IPv4 sockets and
+ the IPV6_MULTICAST_IF socket option for IPv6 sockets. If no interface has
+ been previously set, this function returns an invalid QNetworkInterface.
+ The socket must be in BoundState, otherwise an invalid QNetworkInterface is
+ returned.
+
+ \sa setMulticastInterface()
+*/
+QNetworkInterface QUdpSocket::multicastInterface() const
+{
+ Q_D(const QUdpSocket);
+ QT_CHECK_BOUND("QUdpSocket::multicastInterface()", QNetworkInterface());
+ return d->socketEngine->multicastInterface();
+}
+
+/*!
+ \since 4.8
+
+ Sets the outgoing interface for multicast datagrams to the interface \a
+ iface. This corresponds to the IP_MULTICAST_IF socket option for IPv4
+ sockets and the IPV6_MULTICAST_IF socket option for IPv6 sockets. The
+ socket must be in BoundState, otherwise this function does nothing.
+
+ \sa multicastInterface(), joinMulticastGroup(), leaveMulticastGroup()
+*/
+void QUdpSocket::setMulticastInterface(const QNetworkInterface &iface)
+{
+ Q_D(QUdpSocket);
+ if (!isValid()) {
+ qWarning("QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
+ return;
+ }
+ d->socketEngine->setMulticastInterface(iface);
+}
+
+/*!
Returns true if at least one datagram is waiting to be read;
otherwise returns false.
diff --git a/src/network/socket/qudpsocket.h b/src/network/socket/qudpsocket.h
index 54f82c9..b277d3f 100644
--- a/src/network/socket/qudpsocket.h
+++ b/src/network/socket/qudpsocket.h
@@ -84,6 +84,9 @@ public:
bool leaveMulticastGroup(const QHostAddress &groupAddress,
const QNetworkInterface &iface);
+ QNetworkInterface multicastInterface() const;
+ void setMulticastInterface(const QNetworkInterface &iface);
+
bool hasPendingDatagrams() const;
qint64 pendingDatagramSize() const;
qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *host = 0, quint16 *port = 0);
diff --git a/tests/auto/qudpsocket/tst_qudpsocket.cpp b/tests/auto/qudpsocket/tst_qudpsocket.cpp
index a1dd200..2b78706 100644
--- a/tests/auto/qudpsocket/tst_qudpsocket.cpp
+++ b/tests/auto/qudpsocket/tst_qudpsocket.cpp
@@ -50,11 +50,13 @@
#include <qhostinfo.h>
#include <qmap.h>
#include <QNetworkProxy>
+#include <QNetworkInterface>
#include <qstringlist.h>
#include "../network-settings.h"
Q_DECLARE_METATYPE(QHostAddress)
+Q_DECLARE_METATYPE(QNetworkInterface)
//TESTED_CLASS=
//TESTED_FILES=
@@ -102,6 +104,8 @@ private slots:
void multicastJoinBeforeBind();
void multicastLeaveAfterClose_data();
void multicastLeaveAfterClose();
+ void setMulticastInterface_data();
+ void setMulticastInterface();
void multicast_data();
void multicast();
@@ -954,6 +958,46 @@ void tst_QUdpSocket::multicastLeaveAfterClose()
QVERIFY(!udpSocket.leaveMulticastGroup(groupAddress));
}
+void tst_QUdpSocket::setMulticastInterface_data()
+{
+ QTest::addColumn<QNetworkInterface>("iface");
+ QTest::addColumn<QHostAddress>("address");
+ QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
+ foreach (const QNetworkInterface &iface, interfaces) {
+ foreach (const QNetworkAddressEntry &entry, iface.addressEntries()) {
+ QTest::newRow(QString("%1:%2").arg(iface.name()).arg(entry.ip().toString()).toAscii())
+ << iface
+ << entry.ip();
+ }
+ }
+}
+
+void tst_QUdpSocket::setMulticastInterface()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH(QNetworkInterface, iface);
+ QFETCH(QHostAddress, address);
+
+ QUdpSocket udpSocket;
+ // bind initializes the socket
+ bool bound = udpSocket.bind((address.protocol() == QAbstractSocket::IPv6Protocol
+ ? QHostAddress(QHostAddress::AnyIPv6)
+ : QHostAddress(QHostAddress::Any)),
+ 0);
+ if (!bound)
+ QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
+ udpSocket.setMulticastInterface(iface);
+ if (!bound)
+ QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::multicastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
+ QNetworkInterface iface2 = udpSocket.multicastInterface();
+ if (!setProxy) {
+ QVERIFY(iface2.isValid());
+ QCOMPARE(iface.name(), iface2.name());
+ } else {
+ QVERIFY(!iface2.isValid());
+ }
+}
+
void tst_QUdpSocket::multicast_data()
{
QHostAddress anyAddress = QHostAddress(QHostAddress::Any);