/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Intel Corporation.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
#endif
class QNetworkProxy;
+class QIpPacketHeader
+{
+public:
+ QIpPacketHeader(const QHostAddress &dstAddr = QHostAddress(), quint16 port = 0)
+ : destinationAddress(dstAddr), destinationPort(port)
+ {}
+
+ void clear()
+ {
+ senderAddress.clear();
+ destinationAddress.clear();
+ }
+
+ QHostAddress senderAddress;
+ QHostAddress destinationAddress;
+
+ quint16 senderPort;
+ quint16 destinationPort;
+};
+
class QAbstractSocketEngineReceiver {
public:
virtual ~QAbstractSocketEngineReceiver(){}
TypeOfServiceOption
};
+ enum PacketHeaderOption {
+ WantNone = 0,
+ WantDatagramSender,
+
+ WantAll = 0xff
+ };
+ Q_DECLARE_FLAGS(PacketHeaderOptions, PacketHeaderOption)
+
virtual bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) = 0;
virtual bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) = 0;
virtual bool setMulticastInterface(const QNetworkInterface &iface) = 0;
#endif // QT_NO_NETWORKINTERFACE
- virtual qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0) = 0;
- virtual qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port) = 0;
+ virtual qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header = 0,
+ PacketHeaderOptions = WantNone) = 0;
+ virtual qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header) = 0;
virtual bool hasPendingDatagrams() const = 0;
virtual qint64 pendingDatagramSize() const = 0;
#endif // QT_NO_UDPSOCKET
friend class QAbstractSocketEngine;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractSocketEngine::PacketHeaderOptions)
+
QT_END_NAMESPACE
#endif // QABSTRACTSOCKETENGINE_P_H
}
#endif // QT_NO_NETWORKINTERFACE
-qint64 QHttpSocketEngine::readDatagram(char *, qint64, QHostAddress *,
- quint16 *)
+qint64 QHttpSocketEngine::readDatagram(char *, qint64, QIpPacketHeader *, PacketHeaderOptions)
{
return 0;
}
-qint64 QHttpSocketEngine::writeDatagram(const char *, qint64, const QHostAddress &,
- quint16)
+qint64 QHttpSocketEngine::writeDatagram(const char *, qint64, const QIpPacketHeader &)
{
return 0;
}
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
#endif // QT_NO_NETWORKINTERFACE
- qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0) Q_DECL_OVERRIDE;
- qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port) Q_DECL_OVERRIDE;
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *,
+ PacketHeaderOptions) Q_DECL_OVERRIDE;
+ qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
#endif // QT_NO_UDPSOCKET
errorString() can be called to determine the cause of the error.
*/
+/*!
+ \enum QAbstractSocketEngine::PacketHeaderOption
+
+ Specifies which fields in the IP packet header are desired in the call to
+ readDatagram().
+
+ \value WantNone caller isn't interested in the packet metadata
+ \value WantDatagramSender caller wants the sender address and port number
+ \value WantDatagramDestination caller wants the packet's destination address and port number
+ (this option is useful to distinguish multicast packets from unicast)
+ \value WantDatagramHopLimit caller wants the packet's remaining hop limit or time to live
+ (this option is useful in IPv4 multicasting, where the TTL is used
+ to indicate the realm)
+ \value WantAll this is a catch-all value to indicate the caller is
+ interested in all the available information
+
+ \sa readDatagram(), QUdpDatagram
+*/
+
#include "qnativesocketengine_p.h"
#include <qabstracteventdispatcher.h>
/*!
Reads up to \a maxSize bytes of a datagram from the socket,
stores it in \a data and returns the number of bytes read. The
- address and port of the sender are stored in \a address and \a
- port. If either of these pointers is 0, the corresponding value is
- discarded.
+ address, port, and other IP header fields are stored in \a header
+ according to the request in \a options.
To avoid unnecessarily loss of data, call pendingDatagramSize() to
determine the size of the pending message before reading it. If \a
\sa hasPendingDatagrams()
*/
-qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QHostAddress *address,
- quint16 *port)
+qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QIpPacketHeader *header,
+ PacketHeaderOptions options)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::readDatagram(), -1);
Q_CHECK_TYPE(QNativeSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, -1);
- return d->nativeReceiveDatagram(data, maxSize, address, port);
+ return d->nativeReceiveDatagram(data, maxSize, header, options);
}
/*!
Writes a UDP datagram of size \a size bytes to the socket from
- \a data to the address \a host on port \a port, and returns the
- number of bytes written, or -1 if an error occurred.
+ \a data to the destination contained in \a header, and returns the
+ number of bytes written, or -1 if an error occurred. If \a header
+ contains other settings like hop limit or source address, this function
+ will try to pass them to the operating system too, but will not
+ indicate an error if it could not pass them.
Only one datagram is sent, and if there is too much data to fit
into a single datagram, the operation will fail and error()
disadvised, as even if they are sent successfully, they are likely
to be fragmented before arriving at their destination.
- Experience has shown that it is in general safe to send datagrams
- no larger than 512 bytes.
+ Experience has shown that it is in general safe to send IPv4 datagrams
+ no larger than 512 bytes or IPv6 datagrams no larger than 1280 (the
+ minimum MTU).
\sa readDatagram()
*/
-qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size,
- const QHostAddress &host, quint16 port)
+qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size, const QIpPacketHeader &header)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1);
Q_CHECK_TYPE(QNativeSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1);
- return d->nativeSendDatagram(data, size, d->adjustAddressProtocol(host), port);
+
+ return d->nativeSendDatagram(data, size, header);
}
/*!
qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE;
- qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0) Q_DECL_OVERRIDE;
- qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port) Q_DECL_OVERRIDE;
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
+ PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE;
+ qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
bool nativeHasPendingDatagrams() const;
qint64 nativePendingDatagramSize() const;
- qint64 nativeReceiveDatagram(char *data, qint64 maxLength,
- QHostAddress *address, quint16 *port);
- qint64 nativeSendDatagram(const char *data, qint64 length,
- const QHostAddress &host, quint16 port);
+ qint64 nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header,
+ QAbstractSocketEngine::PacketHeaderOptions options);
+ qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header);
qint64 nativeRead(char *data, qint64 maxLength);
qint64 nativeWrite(const char *data, qint64 length);
int nativeSelect(int timeout, bool selectForRead) const;
return qint64(recvResult);
}
-qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize,
- QHostAddress *address, quint16 *port)
+qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QIpPacketHeader *header,
+ QAbstractSocketEngine::PacketHeaderOptions options)
{
qt_sockaddr aa;
memset(&aa, 0, sizeof(aa));
if (recvFromResult == -1) {
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
- } else if (port || address) {
- qt_socket_getPortAndAddress(&aa, port, address);
+ if (header)
+ header->clear();
+ } else if (options != QAbstractSocketEngine::WantNone) {
+ Q_ASSERT(header);
+ qt_socket_getPortAndAddress(&aa, &header->senderPort, &header->senderAddress);
}
#if defined (QNATIVESOCKETENGINE_DEBUG)
return qint64(maxSize ? recvFromResult : recvFromResult == -1 ? -1 : 0);
}
-qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
- const QHostAddress &host, quint16 port)
+qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
{
struct sockaddr_in sockAddrIPv4;
struct sockaddr *sockAddrPtr = 0;
QT_SOCKLEN_T sockAddrSize = 0;
struct sockaddr_in6 sockAddrIPv6;
+ const QHostAddress &host = header.destinationAddress;
+ quint16 port = header.destinationPort;
if (host.protocol() == QAbstractSocket::IPv6Protocol
|| socketProtocol == QAbstractSocket::IPv6Protocol
|| socketProtocol == QAbstractSocket::AnyIPProtocol) {
}
-qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxLength,
- QHostAddress *address, quint16 *port)
+qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header,
+ QAbstractSocketEngine::PacketHeaderOptions options)
{
qint64 ret = 0;
WS_ERROR_DEBUG(err);
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
ret = -1;
+ if (header)
+ header->clear();
}
} else {
ret = qint64(bytesRead);
+ if (options & QNativeSocketEngine::WantDatagramSender)
+ qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress);
}
- qt_socket_getPortAndAddress(socketDescriptor, &aa, port, address);
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %li, %s, %i) == %li",
qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
- const QHostAddress &address, quint16 port)
+ const QIpPacketHeader &header)
{
qint64 ret = -1;
struct sockaddr_in sockAddrIPv4;
struct sockaddr *sockAddrPtr = 0;
QT_SOCKLEN_T sockAddrSize = 0;
- setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
+ setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, header.destinationPort,
+ header.destinationAddress, &sockAddrPtr, &sockAddrSize);
WSABUF buf;
#if !defined(Q_OS_WINCE)
return bytesWritten;
}
-qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr, quint16 *port)
+qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header,
+ PacketHeaderOptions options)
{
Q_D(QNativeSocketEngine);
- if (d->socketType != QAbstractSocket::UdpSocket || d->pendingDatagrams.isEmpty())
+ if (d->socketType != QAbstractSocket::UdpSocket || d->pendingDatagrams.isEmpty()) {
+ if (header)
+ header->clear();
return -1;
+ }
WinRtDatagram datagram = d->pendingDatagrams.takeFirst();
- if (addr)
- *addr = datagram.address;
-
- if (port)
- *port = datagram.port;
+ if (header)
+ *header = datagram.header;
QByteArray readOrigin;
// Do not read the whole datagram. Put the rest of it back into the "queue"
return readOrigin.length();
}
-qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &addr, quint16 port)
+qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
{
Q_D(QNativeSocketEngine);
if (d->socketType != QAbstractSocket::UdpSocket)
remoteHost->get_CanonicalName(remoteHostString.GetAddressOf());
RETURN_OK_IF_FAILED("Could not obtain remote host's canonical name");
returnAddress.setAddress(qt_QStringFromHString(remoteHostString));
- datagram.address = returnAddress;
+ datagram.header.senderAddress = returnAddress;
HString remotePort;
hr = args->get_RemotePort(remotePort.GetAddressOf());
RETURN_OK_IF_FAILED("Could not obtain remote port");
- datagram.port = qt_QStringFromHString(remotePort).toInt();
+ datagram.header.senderPort = qt_QStringFromHString(remotePort).toInt();
ComPtr<IDataReader> reader;
hr = args->GetDataReader(&reader);
struct WinRtDatagram {
QByteArray data;
- int port;
- QHostAddress address;
+ QIpPacketHeader header;
};
class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine
qint64 read(char *data, qint64 maxlen);
qint64 write(const char *data, qint64 len);
- qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0);
- qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port);
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *, PacketHeaderOptions);
+ qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header);
bool hasPendingDatagrams() const;
qint64 pendingDatagramSize() const;
#endif
dummy.setProxy(QNetworkProxy::NoProxy);
if (!dummy.bind()
- || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0
+ || writeDatagram(0,0, QIpPacketHeader(d->data->controlSocket->localAddress(), dummy.localPort())) != 0
|| !dummy.waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))
|| dummy.readDatagram(0,0, &d->localAddress, &d->localPort) != 0) {
QSOCKS5_DEBUG << "udp actual address and port lookup failed";
#ifndef QT_NO_UDPSOCKET
} else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
// send to connected address
- return writeDatagram(data, len, d->peerAddress, d->peerPort);
+ return writeDatagram(data, len, QIpPacketHeader(d->peerAddress, d->peerPort));
#endif
}
//### set an error ???
}
#endif // QT_NO_NETWORKINTERFACE
-qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr,
- quint16 *port)
+qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header, PacketHeaderOptions)
{
Q_D(QSocks5SocketEngine);
QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue();
int copyLen = qMin<int>(maxlen, datagram.data.size());
memcpy(data, datagram.data.constData(), copyLen);
- if (addr)
- *addr = datagram.address;
- if (port)
- *port = datagram.port;
+ header->senderAddress = datagram.address;
+ header->senderPort = datagram.port;
return copyLen;
}
-qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &address,
- quint16 port)
+qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
{
Q_D(QSocks5SocketEngine);
outBuf[0] = 0x00;
outBuf[1] = 0x00;
outBuf[2] = 0x00;
- if (!qt_socks5_set_host_address_and_port(address, port, &outBuf)) {
+ if (!qt_socks5_set_host_address_and_port(header.destinationAddress, header.destinationPort, &outBuf)) {
}
outBuf += QByteArray(data, len);
QSOCKS5_DEBUG << "sending" << dump(outBuf);
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
#endif // QT_NO_NETWORKINTERFACE
- qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
- quint16 *port = 0) Q_DECL_OVERRIDE;
- qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
- quint16 port) Q_DECL_OVERRIDE;
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
+ PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE;
+ qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
#endif // QT_NO_UDPSOCKET
if (state() == UnconnectedState)
bind();
- qint64 sent = d->socketEngine->writeDatagram(data, size, address, port);
+ qint64 sent = d->socketEngine->writeDatagram(data, size, QIpPacketHeader(address, port));
d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
if (sent >= 0) {
qDebug("QUdpSocket::readDatagram(%p, %llu, %p, %p)", data, maxSize, address, port);
#endif
QT_CHECK_BOUND("QUdpSocket::readDatagram()", -1);
- qint64 readBytes = d->socketEngine->readDatagram(data, maxSize, address, port);
+
+ qint64 readBytes;
+ if (address || port) {
+ QIpPacketHeader header;
+ readBytes = d->socketEngine->readDatagram(data, maxSize, &header,
+ QAbstractSocketEngine::WantDatagramSender);
+ if (address)
+ *address = header.senderAddress;
+ if (port)
+ *port = header.senderPort;
+ } else {
+ readBytes = d->socketEngine->readDatagram(data, maxSize);
+ }
+
d_func()->socketEngine->setReadNotificationEnabled(true);
if (readBytes < 0) {
d->socketError = d->socketEngine->error();
QVERIFY(available > 0);
QByteArray answer;
answer.resize(available);
- QHostAddress senderAddress;
- quint16 senderPort = 0;
- QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(),
- &senderAddress,
- &senderPort) == message1.size());
- QCOMPARE(senderAddress, QHostAddress("127.0.0.1"));
- QVERIFY(senderPort != 0);
+ QIpPacketHeader header;
+ QCOMPARE(udpSocket.readDatagram(answer.data(), answer.size(),
+ &header, QAbstractSocketEngine::WantDatagramSender),
+ qint64(message1.size()));
+ QVERIFY(header.senderAddress == QHostAddress("127.0.0.1"));
+ QCOMPARE(header.senderAddress, QHostAddress("127.0.0.1"));
+ QVERIFY(header.senderPort != 0);
}
//---------------------------------------------------------------------------
QVERIFY(available > 0);
QByteArray answer;
answer.resize(available);
- QHostAddress senderAddress;
- quint16 senderPort = 0;
- QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(),
- &senderAddress,
- &senderPort) == message1.size());
- QCOMPARE(senderAddress, QHostAddress("::1"));
- QVERIFY(senderPort != 0);
+ QIpPacketHeader header;
+ QCOMPARE(udpSocket.readDatagram(answer.data(), answer.size(),
+ &header, QAbstractSocketEngine::WantDatagramSender),
+ qint64(message1.size()));
+ QVERIFY(header.senderAddress == QHostAddress("::1"));
+ QCOMPARE(header.senderAddress, QHostAddress("::1"));
+ QVERIFY(header.senderPort != 0);
}
}
= "MOOT wtf is a MOOT? talk english not your sutpiD ENGLISH.";
qint64 written = broadcastSocket.writeDatagram(trollMessage.data(),
trollMessage.size(),
- QHostAddress::Broadcast,
- port);
+ QIpPacketHeader(QHostAddress::Broadcast, port));
QCOMPARE((int)written, trollMessage.size());
QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was"
" called by a socket other than QAbstractSocket::UdpSocket");
- QCOMPARE(socket.writeDatagram("hei", 3, QHostAddress::LocalHost, 143),
+ QCOMPARE(socket.writeDatagram("hei", 3, QIpPacketHeader(QHostAddress::LocalHost, 143)),
(qlonglong) -1);
}
QVERIFY(available > 0);
QByteArray answer;
answer.resize(available);
- QHostAddress senderAddress;
- quint16 senderPort = 0;
- QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(),
- &senderAddress,
- &senderPort) == message1.size());
- QCOMPARE(senderAddress, udpSocket2.localAddress());
- QCOMPARE(senderPort, udpSocket2.localPort());
+ QIpPacketHeader header;
+ QCOMPARE(udpSocket.readDatagram(answer.data(), answer.size(),
+ &header, QAbstractSocketEngine::WantDatagramSender),
+ qint64(message1.size()));
+ QVERIFY(header.senderAddress == udpSocket2.localAddress());
+ QCOMPARE(header.senderAddress, udpSocket2.localAddress());
+ QCOMPARE(header.senderPort, udpSocket2.localPort());
}
void tst_QSocks5SocketEngine::tcpSocketBlockingTest()