summaryrefslogtreecommitdiffstats
path: root/src/network/socket
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket')
-rw-r--r--src/network/socket/qabstractsocket.cpp227
-rw-r--r--src/network/socket/qabstractsocket.h5
-rw-r--r--src/network/socket/qabstractsocket_p.h5
-rw-r--r--src/network/socket/qabstractsocketengine.cpp14
-rw-r--r--src/network/socket/qabstractsocketengine_p.h18
-rw-r--r--src/network/socket/qhttpsocketengine.cpp46
-rw-r--r--src/network/socket/qhttpsocketengine_p.h9
-rw-r--r--src/network/socket/qlocalserver.cpp2
-rw-r--r--src/network/socket/qlocalserver_p.h2
-rw-r--r--src/network/socket/qlocalsocket.cpp2
-rw-r--r--src/network/socket/qlocalsocket_p.h2
-rw-r--r--src/network/socket/qlocalsocket_win.cpp15
-rw-r--r--src/network/socket/qnativesocketengine.cpp60
-rw-r--r--src/network/socket/qnativesocketengine_p.h25
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp383
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp269
-rw-r--r--src/network/socket/qsocks5socketengine.cpp48
-rw-r--r--src/network/socket/qsocks5socketengine_p.h9
-rw-r--r--src/network/socket/qsymbiansocketengine.cpp1770
-rw-r--r--src/network/socket/qsymbiansocketengine_p.h258
-rw-r--r--src/network/socket/qtcpserver.cpp15
-rw-r--r--src/network/socket/qudpsocket.cpp138
-rw-r--r--src/network/socket/qudpsocket.h13
-rw-r--r--src/network/socket/socket.pri31
24 files changed, 3073 insertions, 293 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index bd4c9e4..5316626 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -356,6 +356,10 @@
to enable.
\value KeepAliveOption Set this to 1 to enable the SO_KEEPALIVE socket option
+ \value MulticastTtlOption Set this to an integer value to set IP_MULTICAST_TTL (TTL for multicast datagrams) socket option.
+
+ \value MulticastLoopbackOption Set this to 1 to enable the IP_MULTICAST_LOOP (multicast loopback) socket option.
+
\sa QAbstractSocket::setSocketOption(), QAbstractSocket::socketOption()
*/
@@ -363,6 +367,7 @@
#include "qabstractsocket_p.h"
#include "private/qhostinfo_p.h"
+#include "private/qnetworksession_p.h"
#include <qabstracteventdispatcher.h>
#include <qhostaddress.h>
@@ -371,6 +376,7 @@
#include <qpointer.h>
#include <qtimer.h>
#include <qelapsedtimer.h>
+#include <qscopedvaluerollback.h>
#ifndef QT_NO_OPENSSL
#include <QtNetwork/qsslsocket.h>
@@ -466,9 +472,6 @@ QAbstractSocketPrivate::QAbstractSocketPrivate()
peerPort(0),
socketEngine(0),
cachedSocketDescriptor(-1),
-#ifdef Q_OS_LINUX
- addToBytesAvailable(0),
-#endif
readBufferMaxSize(0),
readBuffer(QABSTRACTSOCKET_BUFFERSIZE),
writeBuffer(QABSTRACTSOCKET_BUFFERSIZE),
@@ -549,6 +552,10 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
q->setErrorString(QAbstractSocket::tr("Operation on socket is not supported"));
return false;
}
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the socket engine (if it has been set)
+ socketEngine->setProperty("_q_networksession", q->property("_q_networksession"));
+#endif
#ifndef QT_NO_NETWORKPROXY
//copy user agent to socket engine (if it has been set)
socketEngine->setProperty("_q_user-agent", q->property("_q_user-agent"));
@@ -595,6 +602,7 @@ bool QAbstractSocketPrivate::canReadNotification()
socketEngine->setReadNotificationEnabled(false);
}
}
+ QScopedValueRollback<bool> rsncrollback(readSocketNotifierCalled);
readSocketNotifierCalled = true;
if (!isBuffered)
@@ -608,7 +616,6 @@ bool QAbstractSocketPrivate::canReadNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canReadNotification() buffer is full");
#endif
- readSocketNotifierCalled = false;
return false;
}
@@ -620,7 +627,6 @@ bool QAbstractSocketPrivate::canReadNotification()
qDebug("QAbstractSocketPrivate::canReadNotification() disconnecting socket");
#endif
q->disconnectFromHost();
- readSocketNotifierCalled = false;
return false;
}
newBytes = readBuffer.size() - newBytes;
@@ -634,14 +640,15 @@ bool QAbstractSocketPrivate::canReadNotification()
// only emit readyRead() when not recursing, and only if there is data available
bool hasData = newBytes > 0
#ifndef QT_NO_UDPSOCKET
- || (!isBuffered && socketEngine && socketEngine->hasPendingDatagrams())
+ || (!isBuffered && socketType != QAbstractSocket::TcpSocket && socketEngine && socketEngine->hasPendingDatagrams())
#endif
+ || (!isBuffered && socketType == QAbstractSocket::TcpSocket && socketEngine)
;
if (!emittedReadyRead && hasData) {
+ QScopedValueRollback<bool> r(emittedReadyRead);
emittedReadyRead = true;
emit q->readyRead();
- emittedReadyRead = false;
}
// If we were closed as a result of the readyRead() signal,
@@ -650,7 +657,6 @@ bool QAbstractSocketPrivate::canReadNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canReadNotification() socket is closing - returning");
#endif
- readSocketNotifierCalled = false;
return true;
}
@@ -664,7 +670,6 @@ bool QAbstractSocketPrivate::canReadNotification()
socketEngine->setReadNotificationEnabled(readSocketNotifierState);
readSocketNotifierStateSet = false;
}
- readSocketNotifierCalled = false;
return true;
}
@@ -751,11 +756,11 @@ bool QAbstractSocketPrivate::flush()
if (written < 0) {
socketError = socketEngine->error();
q->setErrorString(socketEngine->errorString());
- emit q->error(socketError);
- // an unexpected error so close the socket.
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug() << "QAbstractSocketPrivate::flush() write error, aborting." << socketEngine->errorString();
#endif
+ emit q->error(socketError);
+ // an unexpected error so close the socket.
q->abort();
return false;
}
@@ -770,9 +775,9 @@ bool QAbstractSocketPrivate::flush()
if (written > 0) {
// Don't emit bytesWritten() recursively.
if (!emittedBytesWritten) {
+ QScopedValueRollback<bool> r(emittedBytesWritten);
emittedBytesWritten = true;
emit q->bytesWritten(written);
- emittedBytesWritten = false;
}
}
@@ -1136,10 +1141,6 @@ bool QAbstractSocketPrivate::readFromSocket()
Q_Q(QAbstractSocket);
// Find how many bytes we can read from the socket layer.
qint64 bytesToRead = socketEngine->bytesAvailable();
-#ifdef Q_OS_LINUX
- if (bytesToRead > 0) // ### See setSocketDescriptor()
- bytesToRead += addToBytesAvailable;
-#endif
if (bytesToRead == 0) {
// Under heavy load, certain conditions can trigger read notifications
// for socket notifiers on which there is no activity. If we continue
@@ -1374,10 +1375,6 @@ void QAbstractSocket::connectToHostImplementation(const QString &hostName, quint
d->localAddress.clear();
d->peerAddress.clear();
d->peerName = hostName;
-#ifdef Q_OS_LINUX
- // ### See setSocketDescriptor().
- d->addToBytesAvailable = 0;
-#endif
if (d->hostLookupId != -1) {
QHostInfo::abortHostLookup(d->hostLookupId);
d->hostLookupId = -1;
@@ -1395,8 +1392,11 @@ void QAbstractSocket::connectToHostImplementation(const QString &hostName, quint
}
#endif
- if (!d_func()->isBuffered)
- openMode |= QAbstractSocket::Unbuffered;
+ if (openMode & QIODevice::Unbuffered)
+ d->isBuffered = false; // Unbuffered QTcpSocket
+ else if (!d_func()->isBuffered)
+ openMode |= QAbstractSocket::Unbuffered; // QUdpSocket
+
QIODevice::open(openMode);
d->state = HostLookupState;
emit stateChanged(d->state);
@@ -1476,10 +1476,12 @@ qint64 QAbstractSocket::bytesAvailable() const
{
Q_D(const QAbstractSocket);
qint64 available = QIODevice::bytesAvailable();
- if (d->isBuffered)
- available += (qint64) d->readBuffer.size();
- else if (d->socketEngine && d->socketEngine->isValid())
+
+ available += (qint64) d->readBuffer.size();
+
+ if (!d->isBuffered && d->socketEngine && d->socketEngine->isValid())
available += d->socketEngine->bytesAvailable();
+
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::bytesAvailable() == %llu", available);
#endif
@@ -1612,6 +1614,10 @@ bool QAbstractSocket::setSocketDescriptor(int socketDescriptor, SocketState sock
setErrorString(tr("Operation on socket is not supported"));
return false;
}
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the socket engine (if it has been set)
+ d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
+#endif
bool result = d->socketEngine->initialize(socketDescriptor, socketState);
if (!result) {
d->socketError = d->socketEngine->error();
@@ -1637,17 +1643,6 @@ bool QAbstractSocket::setSocketDescriptor(int socketDescriptor, SocketState sock
d->peerAddress = d->socketEngine->peerAddress();
d->cachedSocketDescriptor = socketDescriptor;
-#ifdef Q_OS_LINUX
- // ### This is a workaround for certain broken Linux kernels, when using
- // QTcpSocket with a Unix domain socket. It was introduced around 2.6.9,
- // and fixed at some point after that.
- // http://archive.linux-usenet.com/index-t-73300.html
- // We can provide a better workaround for this: readFromSocket() can loop
- // while reading, but this must happen without triggering an implicit
- // close because of reading after the socket has closed.
- d->addToBytesAvailable = 4096;
-#endif
-
return true;
}
@@ -1677,6 +1672,14 @@ void QAbstractSocket::setSocketOption(QAbstractSocket::SocketOption option, cons
case KeepAliveOption:
d_func()->socketEngine->setOption(QAbstractSocketEngine::KeepAliveOption, value.toInt());
break;
+
+ case MulticastTtlOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::MulticastTtlOption, value.toInt());
+ break;
+
+ case MulticastLoopbackOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::MulticastLoopbackOption, value.toInt());
+ break;
}
}
@@ -1706,6 +1709,13 @@ QVariant QAbstractSocket::socketOption(QAbstractSocket::SocketOption option)
case KeepAliveOption:
ret = d_func()->socketEngine->option(QAbstractSocketEngine::KeepAliveOption);
break;
+
+ case MulticastTtlOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::MulticastTtlOption);
+ break;
+ case MulticastLoopbackOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::MulticastLoopbackOption);
+ break;
}
if (ret == -1)
return QVariant();
@@ -1781,6 +1791,14 @@ bool QAbstractSocket::waitForConnected(int msecs)
#endif
QHostInfo::abortHostLookup(d->hostLookupId);
d->hostLookupId = -1;
+#ifndef QT_NO_BEARERMANAGEMENT
+ QSharedPointer<QNetworkSession> networkSession;
+ QVariant v(property("_q_networksession"));
+ if (v.isValid()) {
+ networkSession = qvariant_cast< QSharedPointer<QNetworkSession> >(v);
+ d->_q_startConnecting(QHostInfoPrivate::fromName(d->hostName, networkSession));
+ } else
+#endif
d->_q_startConnecting(QHostInfo::fromName(d->hostName));
}
if (state() == UnconnectedState)
@@ -1863,7 +1881,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
}
Q_ASSERT(d->socketEngine);
- forever {
+ do {
bool readyToRead = false;
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
@@ -1890,7 +1908,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
if (state() != ConnectedState)
return false;
- }
+ } while (msecs == -1 || qt_timeout_value(msecs, stopWatch.elapsed()) > 0);
return false;
}
@@ -2123,42 +2141,51 @@ bool QAbstractSocket::flush()
qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
{
Q_D(QAbstractSocket);
- if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())
- d->socketEngine->setReadNotificationEnabled(true);
-
- if (!d->isBuffered) {
- if (!d->socketEngine)
- return -1; // no socket engine is probably EOF
- qint64 readBytes = d->socketEngine->read(data, maxSize);
- if (readBytes < 0) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
- }
- if (!d->socketEngine->isReadNotificationEnabled())
- d->socketEngine->setReadNotificationEnabled(true);
-#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld",
- data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
- readBytes);
-#endif
- return readBytes;
- }
- if (d->readBuffer.isEmpty())
+ // This is for a buffered QTcpSocket
+ if (d->isBuffered && d->readBuffer.isEmpty())
// if we're still connected, return 0 indicating there may be more data in the future
// if we're not connected, return -1 indicating EOF
return d->state == QAbstractSocket::ConnectedState ? qint64(0) : qint64(-1);
- // If readFromSocket() read data, copy it to its destination.
- if (maxSize == 1) {
+ // short cut for a char read if we have something in the buffer
+ if (maxSize == 1 && !d->readBuffer.isEmpty()) {
*data = d->readBuffer.getChar();
#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1",
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1 [char buffer]",
data, isprint(int(uchar(*data))) ? *data : '?', *data);
#endif
+ if (d->readBuffer.isEmpty() && d->socketEngine && d->socketEngine->isValid())
+ d->socketEngine->setReadNotificationEnabled(true);
return 1;
}
+ // Special case for an Unbuffered QTcpSocket
+ // Re-filling the buffer.
+ if (d->socketType == TcpSocket
+ && !d->isBuffered
+ && d->readBuffer.size() < maxSize
+ && d->readBufferMaxSize > 0
+ && maxSize < d->readBufferMaxSize
+ && d->socketEngine
+ && d->socketEngine->isValid()) {
+ // Our buffer is empty and a read() was requested for a byte amount that is smaller
+ // than the readBufferMaxSize. This means that we should fill our buffer since we want
+ // such small reads come from the buffer and not always go to the costly socket engine read()
+ qint64 bytesToRead = d->socketEngine->bytesAvailable();
+ if (bytesToRead > 0) {
+ char *ptr = d->readBuffer.reserve(bytesToRead);
+ qint64 readBytes = d->socketEngine->read(ptr, bytesToRead);
+ if (readBytes == -2) {
+ // No bytes currently available for reading.
+ d->readBuffer.chop(bytesToRead);
+ } else {
+ d->readBuffer.chop(int(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes)));
+ }
+ }
+ }
+
+ // First try to satisfy the read from the buffer
qint64 bytesToRead = qMin(qint64(d->readBuffer.size()), maxSize);
qint64 readSoFar = 0;
while (readSoFar < bytesToRead) {
@@ -2170,8 +2197,56 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
d->readBuffer.free(bytesToReadFromThisBlock);
}
+ if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())
+ d->socketEngine->setReadNotificationEnabled(true);
+
+ if (readSoFar > 0) {
+ // we read some data from buffer.
+ // Just return, readyRead will be emitted again
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', %lli) == %lli [buffer]",
+ data, isprint(int(uchar(*data))) ? *data : '?', *data, maxSize, readSoFar);
+#endif
+
+ if (d->readBuffer.isEmpty() && d->socketEngine)
+ d->socketEngine->setReadNotificationEnabled(true);
+ return readSoFar;
+ }
+
+ // This code path is for Unbuffered QTcpSocket or for connected UDP
+
+ if (!d->isBuffered) {
+ if (!d->socketEngine)
+ return -1; // no socket engine is probably EOF
+ if (!d->socketEngine->isValid())
+ return -1; // This is for unbuffered TCP when we already had been disconnected
+ if (d->state != QAbstractSocket::ConnectedState)
+ return -1; // This is for unbuffered TCP if we're not connected yet
+ qint64 readBytes = d->socketEngine->read(data, maxSize);
+ if (readBytes == -2) {
+ // -2 from the engine means no bytes available (EAGAIN) so read more later
+ return 0;
+ } else if (readBytes < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ d->resetSocketLayer();
+ d->state = QAbstractSocket::UnconnectedState;
+ } else if (!d->socketEngine->isReadNotificationEnabled()) {
+ // Only do this when there was no error
+ d->socketEngine->setReadNotificationEnabled(true);
+ }
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [engine]",
+ data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
+ readBytes);
+#endif
+ return readBytes;
+ }
+
+
#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld",
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [unreachable]",
data, qt_prettyDebug(data, qMin<qint64>(32, readSoFar), readSoFar).data(),
maxSize, readSoFar);
#endif
@@ -2196,7 +2271,23 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
return -1;
}
- if (!d->isBuffered) {
+ if (!d->isBuffered && d->socketType == TcpSocket && d->writeBuffer.isEmpty()) {
+ // This code is for the new Unbuffered QTcpSocket use case
+ qint64 written = d->socketEngine->write(data, size);
+ if (written < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ return written;
+ } else if (written < size) {
+ // Buffer what was not written yet
+ char *ptr = d->writeBuffer.reserve(size - written);
+ memcpy(ptr, data + written, size - written);
+ if (d->socketEngine)
+ d->socketEngine->setWriteNotificationEnabled(true);
+ }
+ return size; // size=actually written + what has been buffered
+ } else if (!d->isBuffered && d->socketType != TcpSocket) {
+ // This is for a QUdpSocket that was connect()ed
qint64 written = d->socketEngine->write(data, size);
if (written < 0) {
d->socketError = d->socketEngine->error();
@@ -2215,6 +2306,12 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
return written;
}
+ // This is the code path for normal buffered QTcpSocket or
+ // unbuffered QTcpSocket when there was already something in the
+ // write buffer and therefore we could not do a direct engine write.
+ // We just write to our write buffer and enable the write notifier
+ // The write notifier then flush()es the buffer.
+
char *ptr = d->writeBuffer.reserve(size);
if (size == 1)
*ptr = *data;
@@ -2553,7 +2650,7 @@ void QAbstractSocket::setReadBufferSize(qint64 size)
// ensure that the read notification is enabled if we've now got
// room in the read buffer
// but only if we're not inside canReadNotification -- that will take care on its own
- if (size == 0 || d->readBuffer.size() < size)
+ if ((size == 0 || d->readBuffer.size() < size) && d->state == QAbstractSocket::ConnectedState) // Do not change the notifier unless we are connected.
d->socketEngine->setReadNotificationEnabled(true);
}
}
diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h
index 348824a..1959fab 100644
--- a/src/network/socket/qabstractsocket.h
+++ b/src/network/socket/qabstractsocket.h
@@ -64,6 +64,7 @@ class QAuthenticator;
class Q_NETWORK_EXPORT QAbstractSocket : public QIODevice
{
Q_OBJECT
+ Q_ENUMS(SocketType NetworkLayerProtocol SocketError SocketState SocketOption)
public:
enum SocketType {
TcpSocket,
@@ -118,7 +119,9 @@ public:
};
enum SocketOption {
LowDelayOption, // TCP_NODELAY
- KeepAliveOption // SO_KEEPALIVE
+ KeepAliveOption, // SO_KEEPALIVE
+ MulticastTtlOption, // IP_MULTICAST_TTL
+ MulticastLoopbackOption // IP_MULTICAST_LOOPBACK
};
QAbstractSocket(SocketType socketType, QObject *parent);
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
index b600b30..cf7d988 100644
--- a/src/network/socket/qabstractsocket_p.h
+++ b/src/network/socket/qabstractsocket_p.h
@@ -59,7 +59,7 @@
#include "QtCore/qtimer.h"
#include "private/qringbuffer_p.h"
#include "private/qiodevice_p.h"
-#include "private/qnativesocketengine_p.h"
+#include "private/qabstractsocketengine_p.h"
#include "qnetworkproxy.h"
QT_BEGIN_NAMESPACE
@@ -138,9 +138,6 @@ public:
void setupSocketNotifiers();
bool readFromSocket();
-#ifdef Q_OS_LINUX
- qint64 addToBytesAvailable;
-#endif
qint64 readBufferMaxSize;
QRingBuffer readBuffer;
QRingBuffer writeBuffer;
diff --git a/src/network/socket/qabstractsocketengine.cpp b/src/network/socket/qabstractsocketengine.cpp
index 41bf5df..2c5b5dc 100644
--- a/src/network/socket/qabstractsocketengine.cpp
+++ b/src/network/socket/qabstractsocketengine.cpp
@@ -40,7 +40,13 @@
****************************************************************************/
#include "qabstractsocketengine_p.h"
+
+#ifdef Q_OS_SYMBIAN
+#include "qsymbiansocketengine_p.h"
+#else
#include "qnativesocketengine_p.h"
+#endif
+
#include "qmutex.h"
#include "qnetworkproxy.h"
@@ -113,7 +119,11 @@ QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(QAbstractSocket
return 0;
#endif
+#ifdef Q_OS_SYMBIAN
+ return new QSymbianSocketEngine(parent);
+#else
return new QNativeSocketEngine(parent);
+#endif
}
QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(int socketDescripter, QObject *parent)
@@ -123,7 +133,11 @@ QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(int socketDescr
if (QAbstractSocketEngine *ret = socketHandlers()->at(i)->createSocketEngine(socketDescripter, parent))
return ret;
}
+#ifdef Q_OS_SYMBIAN
+ return new QSymbianSocketEngine(parent);
+#else
return new QNativeSocketEngine(parent);
+#endif
}
QAbstractSocket::SocketError QAbstractSocketEngine::error() const
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
index 9ed007b..a8be98a 100644
--- a/src/network/socket/qabstractsocketengine_p.h
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -61,6 +61,9 @@ QT_BEGIN_NAMESPACE
class QAuthenticator;
class QAbstractSocketEnginePrivate;
+#ifndef QT_NO_NETWORKINTERFACE
+class QNetworkInterface;
+#endif
class QNetworkProxy;
class QAbstractSocketEngineReceiver {
@@ -94,7 +97,9 @@ public:
BindExclusively,
ReceiveOutOfBandData,
LowDelayOption,
- KeepAliveOption
+ KeepAliveOption,
+ MulticastTtlOption,
+ MulticastLoopbackOption
};
virtual bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) = 0;
@@ -118,13 +123,22 @@ public:
virtual qint64 write(const char *data, qint64 len) = 0;
#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+ virtual bool joinMulticastGroup(const QHostAddress &groupAddress,
+ 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;
+#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 bool hasPendingDatagrams() const = 0;
virtual qint64 pendingDatagramSize() const = 0;
-#endif
+#endif // QT_NO_UDPSOCKET
virtual qint64 bytesToWrite() const = 0;
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index 81a2c61..5f5db17 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>
@@ -71,6 +72,9 @@ bool QHttpSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSo
setProtocol(protocol);
setSocketType(type);
d->socket = new QTcpSocket(this);
+#ifndef QT_NO_BEARERMANAGEMENT
+ d->socket->setProperty("_q_networkSession", property("_q_networkSession"));
+#endif
// Explicitly disable proxying on the proxy socket itself to avoid
// unwanted recursion.
@@ -239,6 +243,36 @@ qint64 QHttpSocketEngine::write(const char *data, qint64 len)
}
#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+bool QHttpSocketEngine::joinMulticastGroup(const QHostAddress &,
+ const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+
+bool QHttpSocketEngine::leaveMulticastGroup(const QHostAddress &,
+ const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ 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;
+}
+#endif // QT_NO_NETWORKINTERFACE
+
qint64 QHttpSocketEngine::readDatagram(char *, qint64, QHostAddress *,
quint16 *)
{
@@ -681,11 +715,10 @@ void QHttpSocketEngine::slotSocketError(QAbstractSocket::SocketError error)
d->state = None;
setError(error, d->socket->errorString());
- if (error == QAbstractSocket::RemoteHostClosedError) {
- emitReadNotification();
- } else {
+ if (error != QAbstractSocket::RemoteHostClosedError)
qDebug() << "QHttpSocketEngine::slotSocketError: got weird error =" << error;
- }
+ //read notification needs to always be emitted, otherwise the higher layer doesn't get the disconnected signal
+ emitReadNotification();
}
void QHttpSocketEngine::slotSocketStateChanged(QAbstractSocket::SocketState state)
@@ -720,7 +753,10 @@ void QHttpSocketEngine::emitReadNotification()
{
Q_D(QHttpSocketEngine);
d->readNotificationActivated = true;
- if (d->readNotificationEnabled && !d->readNotificationPending) {
+ // if there is a connection notification pending we have to emit the readNotification
+ // incase there is connection error. This is only needed for Windows, but it does not
+ // hurt in other cases.
+ if ((d->readNotificationEnabled && !d->readNotificationPending) || d->connectionNotificationPending) {
d->readNotificationPending = true;
QMetaObject::invokeMethod(this, "emitPendingReadNotification", Qt::QueuedConnection);
}
diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h
index 00744f3..d7cc7c1 100644
--- a/src/network/socket/qhttpsocketengine_p.h
+++ b/src/network/socket/qhttpsocketengine_p.h
@@ -102,6 +102,15 @@ public:
qint64 write(const char *data, qint64 len);
#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+#endif // QT_NO_NETWORKINTERFACE
+
qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
quint16 *port = 0);
qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
index f322e23..d4f847a 100644
--- a/src/network/socket/qlocalserver.cpp
+++ b/src/network/socket/qlocalserver.cpp
@@ -274,11 +274,11 @@ QLocalSocket *QLocalServer::nextPendingConnection()
if (d->pendingConnections.isEmpty())
return 0;
QLocalSocket *nextSocket = d->pendingConnections.dequeue();
+#ifndef QT_LOCALSOCKET_TCP
#ifdef Q_OS_SYMBIAN
if(!d->socketNotifier)
return nextSocket;
#endif
-#ifndef QT_LOCALSOCKET_TCP
if (d->pendingConnections.size() <= d->maxPendingConnections)
#ifndef Q_OS_WIN
d->socketNotifier->setEnabled(true);
diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h
index 699fb2c..67b7000 100644
--- a/src/network/socket/qlocalserver_p.h
+++ b/src/network/socket/qlocalserver_p.h
@@ -65,7 +65,7 @@
# include <qt_windows.h>
# include <private/qwineventnotifier_p.h>
#else
-# include <private/qnativesocketengine_p.h>
+# include <private/qabstractsocketengine_p.h>
# include <qsocketnotifier.h>
#endif
diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp
index 029af79..219d2aa 100644
--- a/src/network/socket/qlocalsocket.cpp
+++ b/src/network/socket/qlocalsocket.cpp
@@ -346,7 +346,7 @@ QLocalSocket::QLocalSocket(QObject * parent)
QLocalSocket::~QLocalSocket()
{
close();
-#ifndef Q_OS_WIN
+#if !defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
Q_D(QLocalSocket);
d->unixSocket.setParent(0);
#endif
diff --git a/src/network/socket/qlocalsocket_p.h b/src/network/socket/qlocalsocket_p.h
index aaef998..2671258 100644
--- a/src/network/socket/qlocalsocket_p.h
+++ b/src/network/socket/qlocalsocket_p.h
@@ -67,7 +67,7 @@
# include "private/qringbuffer_p.h"
# include <private/qwineventnotifier_p.h>
#else
-# include "private/qnativesocketengine_p.h"
+# include "private/qabstractsocketengine_p.h"
# include <qtcpsocket.h>
# include <qsocketnotifier.h>
# include <errno.h>
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
index b5dcb05..f595ba7 100644
--- a/src/network/socket/qlocalsocket_win.cpp
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -79,6 +79,11 @@ void QLocalSocketPrivate::setErrorString(const QString &function)
errorString = QLocalSocket::tr("%1: Invalid name").arg(function);
state = QLocalSocket::UnconnectedState;
break;
+ case ERROR_ACCESS_DENIED:
+ error = QLocalSocket::SocketAccessError;
+ errorString = QLocalSocket::tr("%1: Access denied").arg(function);
+ state = QLocalSocket::UnconnectedState;
+ break;
default:
error = QLocalSocket::UnknownSocketError;
errorString = QLocalSocket::tr("%1: Unknown error %2").arg(function).arg(windowsError);
@@ -348,6 +353,11 @@ qint64 QLocalSocket::writeData(const char *data, qint64 maxSize)
void QLocalSocket::abort()
{
+ Q_D(QLocalSocket);
+ if (d->pipeWriter) {
+ delete d->pipeWriter;
+ d->pipeWriter = 0;
+ }
close();
}
@@ -569,10 +579,7 @@ bool QLocalSocket::waitForDisconnected(int msecs)
bool QLocalSocket::isValid() const
{
Q_D(const QLocalSocket);
- if (d->handle == INVALID_HANDLE_VALUE)
- return false;
-
- return PeekNamedPipe(d->handle, NULL, 0, NULL, NULL, NULL);
+ return d->handle != INVALID_HANDLE_VALUE;
}
bool QLocalSocket::waitForReadyRead(int msecs)
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index eb2024d..8758522 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>
@@ -157,12 +158,12 @@ QT_BEGIN_NAMESPACE
concurrent QNativeSocketEngine. This is safe, because WSAStartup and
WSACleanup are reference counted.
*/
-QNativeSocketEnginePrivate::QNativeSocketEnginePrivate()
+QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() :
+ socketDescriptor(-1),
+ readNotifier(0),
+ writeNotifier(0),
+ exceptNotifier(0)
{
- socketDescriptor = -1;
- readNotifier = 0;
- writeNotifier = 0;
- exceptNotifier = 0;
}
/*! \internal
@@ -386,7 +387,6 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb
// Make sure we receive out-of-band data
- // On Symbian OS this works only with native IP stack, not with WinSock
if (socketType == QAbstractSocket::TcpSocket
&& !setOption(ReceiveOutOfBandData, 1)) {
qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data");
@@ -646,6 +646,54 @@ int QNativeSocketEngine::accept()
return d->nativeAccept();
}
+#ifndef QT_NO_NETWORKINTERFACE
+
+/*!
+ \since 4.8
+*/
+bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress,
+ 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, iface);
+}
+
+/*!
+ \since 4.8
+*/
+bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress,
+ 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, 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);
+}
+
+#endif // QT_NO_NETWORKINTERFACE
+
/*!
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 fa52816..c5c4b32 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -60,11 +60,6 @@
# include <winsock2.h>
#endif
-#ifdef Q_OS_SYMBIAN
-#include <private/qeventdispatcher_symbian_p.h>
-#include <unistd.h>
-#endif
-
QT_BEGIN_NAMESPACE
// Use our own defines and structs which we know are correct
@@ -101,6 +96,9 @@ union qt_sockaddr {
};
class QNativeSocketEnginePrivate;
+#ifndef QT_NO_NETWORKINTERFACE
+class QNetworkInterface;
+#endif
class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine
{
@@ -123,6 +121,15 @@ public:
int accept();
void close();
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+#endif
+
qint64 bytesAvailable() const;
qint64 read(char *data, qint64 maxlen);
@@ -237,6 +244,14 @@ public:
bool nativeBind(const QHostAddress &address, quint16 port);
bool nativeListen(int backlog);
int nativeAccept();
+#ifndef QT_NO_NETWORKINTERFACE
+ bool nativeJoinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ QNetworkInterface nativeMulticastInterface() const;
+ bool nativeSetMulticastInterface(const QNetworkInterface &iface);
+#endif
qint64 nativeBytesAvailable() const;
bool nativeHasPendingDatagrams() const;
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 5cf27ce..39570c8 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -46,6 +46,7 @@
#include "qhostaddress.h"
#include "qelapsedtimer.h"
#include "qvarlengtharray.h"
+#include "qnetworkinterface.h"
#include <time.h>
#include <errno.h>
#include <fcntl.h>
@@ -64,12 +65,7 @@
#include <ctype.h>
#endif
-#ifdef Q_OS_SYMBIAN // ### TODO: Are these headers right?
-#include <sys/socket.h>
-#include <netinet/in.h>
-#else
#include <netinet/tcp.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -173,11 +169,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
int protocol = AF_INET;
#endif
int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
-#ifdef Q_OS_SYMBIAN
- int socket = ::socket(protocol, type, 0);
-#else
+
int socket = qt_safe_socket(protocol, type, 0);
-#endif
if (socket <= 0) {
switch (errno) {
@@ -244,6 +237,30 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
case QNativeSocketEngine::KeepAliveOption:
n = SO_KEEPALIVE;
break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#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:
+#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;
}
int v = -1;
@@ -295,11 +312,9 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
}
#else // Q_OS_VXWORKS
int onoff = 1;
-#ifdef Q_OS_SYMBIAN
- if (::ioctl(socketDescriptor, FIONBIO, &onoff) < 0) {
-#else
+
if (qt_safe_ioctl(socketDescriptor, FIONBIO, &onoff) < 0) {
-#endif
+
#ifdef QNATIVESOCKETENGINE_DEBUG
perror("QNativeSocketEnginePrivate::setOption(): ioctl(FIONBIO, 1) failed");
#endif
@@ -309,7 +324,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
return true;
}
case QNativeSocketEngine::AddressReusable:
-#if defined(SO_REUSEPORT) && !defined(Q_OS_SYMBIAN)
+#if defined(SO_REUSEPORT)
n = SO_REUSEPORT;
#else
n = SO_REUSEADDR;
@@ -327,6 +342,30 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
case QNativeSocketEngine::KeepAliveOption:
n = SO_KEEPALIVE;
break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#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:
+#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;
}
return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0;
@@ -378,11 +417,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
} else {
// unreachable
}
-#ifdef Q_OS_SYMBIAN
- int connectResult = ::connect(socketDescriptor, sockAddrPtr, sockAddrSize);
-#else
+
int connectResult = qt_safe_connect(socketDescriptor, sockAddrPtr, sockAddrSize);
-#endif
if (connectResult == -1) {
switch (errno) {
case EISCONN:
@@ -425,9 +461,6 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
case EBADF:
case EFAULT:
case ENOTSOCK:
-#ifdef Q_OS_SYMBIAN
- case EPIPE:
-#endif
socketState = QAbstractSocket::UnconnectedState;
default:
break;
@@ -526,11 +559,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16
bool QNativeSocketEnginePrivate::nativeListen(int backlog)
{
-#ifdef Q_OS_SYMBIAN
- if (::listen(socketDescriptor, backlog) < 0) {
-#else
if (qt_safe_listen(socketDescriptor, backlog) < 0) {
-#endif
switch (errno) {
case EADDRINUSE:
setError(QAbstractSocket::AddressInUseError,
@@ -557,25 +586,185 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog)
int QNativeSocketEnginePrivate::nativeAccept()
{
-#ifdef Q_OS_SYMBIAN
- int acceptedDescriptor = ::accept(socketDescriptor, 0, 0);
-#else
int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0);
-#endif
return acceptedDescriptor;
}
+#ifndef QT_NO_NETWORKINTERFACE
+
+static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
+ int how6,
+ int how4,
+ const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ int level = 0;
+ int sockOpt = 0;
+ void *sockArg;
+ int sockArgSize;
+
+ ip_mreq mreq4;
+#ifndef QT_NO_IPV6
+ ipv6_mreq mreq6;
+
+ if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ sockOpt = how6;
+ sockArg = &mreq6;
+ sockArgSize = sizeof(mreq6);
+ memset(&mreq6, 0, sizeof(mreq6));
+ Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
+ memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6));
+ mreq6.ipv6mr_interface = interface.index();
+ } else
+#endif
+ if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
+ level = IPPROTO_IP;
+ sockOpt = how4;
+ sockArg = &mreq4;
+ sockArgSize = sizeof(mreq4);
+ memset(&mreq4, 0, sizeof(mreq4));
+ mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address());
+
+ if (interface.isValid()) {
+ QList<QNetworkAddressEntry> addressEntries = interface.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, level, sockOpt, sockArg, sockArgSize);
+ if (res == -1) {
+ switch (errno) {
+ case ENOPROTOOPT:
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::OperationUnsupportedErrorString);
+ break;
+ case EADDRNOTAVAIL:
+ d->setError(QAbstractSocket::SocketAddressNotAvailableError,
+ QNativeSocketEnginePrivate::AddressNotAvailableErrorString);
+ break;
+ default:
+ d->setError(QAbstractSocket::UnknownSocketError,
+ QNativeSocketEnginePrivate::UnknownSocketErrorString);
+ break;
+ }
+ return false;
+ }
+ return true;
+}
+
+bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ return multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_JOIN_GROUP,
+#else
+ 0,
+#endif
+ IP_ADD_MEMBERSHIP,
+ groupAddress,
+ interface);
+}
+
+bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ return multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_LEAVE_GROUP,
+#else
+ 0,
+#endif
+ IP_DROP_MEMBERSHIP,
+ groupAddress,
+ 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);
+ 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.index();
+ 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);
+}
+
+#endif // QT_NO_NETWORKINTERFACE
+
qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
{
int nbytes = 0;
// gives shorter than true amounts on Unix domain sockets.
qint64 available = 0;
-#ifdef Q_OS_SYMBIAN
- if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
-#else
if (qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
-#endif
available = (qint64) nbytes;
#if defined (QNATIVESOCKETENGINE_DEBUG)
@@ -594,15 +783,10 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
// Peek 0 bytes into the next message. The size of the message may
// well be 0, so we can't check recvfrom's return value.
ssize_t readBytes;
-#ifdef Q_OS_SYMBIAN
- char c;
- readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize);
-#else
do {
char c;
readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize);
} while (readBytes == -1 && errno == EINTR);
-#endif
// If there's no error, or if our buffer was too small, there must be a
// pending datagram.
@@ -615,14 +799,6 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
return result;
}
-#ifdef Q_OS_SYMBIAN
-qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
-{
- size_t nbytes = 0;
- ::ioctl(socketDescriptor, E32IONREAD, (char *) &nbytes);
- return qint64(nbytes-28);
-}
-#else
qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
{
QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192);
@@ -649,7 +825,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
return qint64(recvResult);
}
-#endif
+
qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize,
QHostAddress *address, quint16 *port)
{
@@ -659,17 +835,11 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
sz = sizeof(aa);
ssize_t recvFromResult = 0;
-#ifdef Q_OS_SYMBIAN
- char c;
- recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1,
- 0, &aa.a, &sz);
-#else
do {
char c;
recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1,
0, &aa.a, &sz);
} while (recvFromResult == -1 && errno == EINTR);
-#endif
if (recvFromResult == -1) {
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
@@ -718,13 +888,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
// ignore the SIGPIPE signal
qt_ignore_sigpipe();
-#ifdef Q_OS_SYMBIAN
- ssize_t sentBytes = ::sendto(socketDescriptor, data, len,
- 0, sockAddrPtr, sockAddrSize);
-#else
ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len,
0, sockAddrPtr, sockAddrSize);
-#endif
if (sentBytes < 0) {
switch (errno) {
@@ -822,11 +987,7 @@ void QNativeSocketEnginePrivate::nativeClose()
qDebug("QNativeSocketEngine::nativeClose()");
#endif
-#ifdef Q_OS_SYMBIAN
- ::close(socketDescriptor);
-#else
- qt_safe_close(socketDescriptor);
-#endif
+ qt_safe_close(socketDescriptor);
}
qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
@@ -837,12 +998,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
qt_ignore_sigpipe();
ssize_t writtenBytes;
-#ifdef Q_OS_SYMBIAN
- // Symbian does not support signals natively and Open C returns EINTR when moving to offline
- writtenBytes = ::write(socketDescriptor, data, len);
-#else
writtenBytes = qt_safe_write(socketDescriptor, data, len);
-#endif
if (writtenBytes < 0) {
switch (errno) {
@@ -877,16 +1033,12 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
{
Q_Q(QNativeSocketEngine);
if (!q->isValid()) {
- qWarning("QNativeSocketEngine::unbufferedRead: Invalid socket");
+ qWarning("QNativeSocketEngine::nativeRead: Invalid socket");
return -1;
}
ssize_t r = 0;
-#ifdef Q_OS_SYMBIAN
- r = ::read(socketDescriptor, data, maxSize);
-#else
r = qt_safe_read(socketDescriptor, data, maxSize);
-#endif
if (r < 0) {
r = -1;
@@ -903,9 +1055,6 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
case EIO:
//error string is now set in read(), not here in nativeRead()
break;
-#ifdef Q_OS_SYMBIAN
- case EPIPE:
-#endif
case ECONNRESET:
#if defined(Q_OS_VXWORKS)
case ESHUTDOWN:
@@ -936,40 +1085,11 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
-#ifdef Q_OS_SYMBIAN
- fd_set fdexception;
- FD_ZERO(&fdexception);
- FD_SET(socketDescriptor, &fdexception);
-#endif
-
int retval;
if (selectForRead)
-#ifdef Q_OS_SYMBIAN
- retval = ::select(socketDescriptor + 1, &fds, 0, &fdexception, timeout < 0 ? 0 : &tv);
-#else
retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
-#endif
else
-#ifdef Q_OS_SYMBIAN
- retval = ::select(socketDescriptor + 1, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv);
-#else
retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
-#endif
-
-
-#ifdef Q_OS_SYMBIAN
- bool selectForExec = false;
- if(retval != 0) {
- if(retval < 0) {
- qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor);
- }
- selectForExec = FD_ISSET(socketDescriptor, &fdexception);
- }
- if(selectForExec) {
- qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected exception for fd %d",
- selectForRead, retval, errno, socketDescriptor);
- }
-#endif
return retval;
}
@@ -987,65 +1107,12 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
if (checkWrite)
FD_SET(socketDescriptor, &fdwrite);
-#ifdef Q_OS_SYMBIAN
- fd_set fdexception;
- FD_ZERO(&fdexception);
- FD_SET(socketDescriptor, &fdexception);
-#endif
-
struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
int ret;
-#ifndef Q_OS_SYMBIAN
ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
-#else
- QElapsedTimer timer;
- timer.start();
-
- do {
- ret = ::select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv);
- bool selectForExec = false;
- if(ret != 0) {
- if(ret < 0) {
- qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor);
- }
- selectForExec = FD_ISSET(socketDescriptor, &fdexception);
- }
- if(selectForExec) {
- qWarning("nativeSelect (checkRead %d, checkWrite %d, ret %d, errno %d): Unexpected expectfds ready in fd %d",
- checkRead, checkWrite, ret, errno, socketDescriptor);
- if (checkWrite){
- FD_CLR(socketDescriptor, &fdread);
- FD_SET(socketDescriptor, &fdwrite);
- } else if (checkRead)
- FD_SET(socketDescriptor, &fdread);
-
-
- if ((ret == -1) && ( errno == ECONNREFUSED || errno == EPIPE ))
- ret = 1;
-
- }
-
- if (ret != -1 || errno != EINTR) {
- break;
- }
-
- if (timeout > 0) {
- // recalculate the timeout
- int t = timeout - timer.elapsed();
- if (t < 0) {
- // oops, timeout turned negative?
- ret = -1;
- break;
- }
-
- tv.tv_sec = t / 1000;
- tv.tv_usec = (t % 1000) * 1000;
- }
- } while (true);
-#endif
if (ret <= 0)
return ret;
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 6350651..88b87b9 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)
@@ -335,15 +337,17 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
}
#if !defined(Q_OS_WINCE)
- // enable new behavior using
- // SIO_UDP_CONNRESET
- DWORD dwBytesReturned = 0;
- int bNewBehavior = 1;
- if (::WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior),
- NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) {
- // not to worry isBogusUdpReadNotification() should handle this otherwise
- int err = WSAGetLastError();
- WS_ERROR_DEBUG(err);
+ if (socketType == QAbstractSocket::UdpSocket) {
+ // enable new behavior using
+ // SIO_UDP_CONNRESET
+ DWORD dwBytesReturned = 0;
+ int bNewBehavior = 1;
+ if (::WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior),
+ NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) {
+ // not to worry isBogusUdpReadNotification() should handle this otherwise
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ }
}
#endif
@@ -399,6 +403,30 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
case QNativeSocketEngine::KeepAliveOption:
n = SO_KEEPALIVE;
break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#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:
+#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;
}
int v = -1;
@@ -459,6 +487,30 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
case QNativeSocketEngine::KeepAliveOption:
n = SO_KEEPALIVE;
break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#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:
+#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;
}
if (::setsockopt(socketDescriptor, level, n, (char*)&v, sizeof(v)) != 0) {
@@ -589,6 +641,11 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
socketState = QAbstractSocket::UnconnectedState;
break;
}
+ if (value == WSAEADDRNOTAVAIL) {
+ setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
}
// fall through
}
@@ -648,8 +705,26 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
}
-bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port)
+bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &a, quint16 port)
{
+ QHostAddress address = a;
+ switch (address.protocol()) {
+ case QAbstractSocket::IPv6Protocol:
+ if (address.toIPv6Address()[0] == 0xff) {
+ // binding to a multicast address
+ address = QHostAddress(QHostAddress::AnyIPv6);
+ }
+ break;
+ case QAbstractSocket::IPv4Protocol:
+ if ((address.toIPv4Address() & 0xffff0000) == 0xefff0000) {
+ // binding to a multicast address
+ address = QHostAddress(QHostAddress::Any);
+ }
+ break;
+ default:
+ break;
+ }
+
struct sockaddr_in sockAddrIPv4;
qt_sockaddr_in6 sockAddrIPv6;
struct sockaddr *sockAddrPtr = 0;
@@ -747,6 +822,160 @@ int QNativeSocketEnginePrivate::nativeAccept()
return acceptedDescriptor;
}
+static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
+ int how6,
+ int how4,
+ const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ int level = 0;
+ int sockOpt = 0;
+ char *sockArg;
+ int sockArgSize;
+
+ struct ip_mreq mreq4;
+#ifndef QT_NO_IPV6
+ struct ipv6_mreq mreq6;
+
+ if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ 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) {
+ level = IPPROTO_IP;
+ 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, level, 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 multicastMembershipHelper(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 multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_LEAVE_GROUP,
+#else
+ 0,
+#endif
+ IP_DROP_MEMBERSHIP,
+ groupAddress,
+ 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;
+ v.s_addr = 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 >= QT_SOCKOPTLEN_T(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
{
@@ -816,7 +1045,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
bool result = false;
fd_set readS;
FD_ZERO(&readS);
- FD_SET(socketDescriptor, &readS);
+ FD_SET((SOCKET)socketDescriptor, &readS);
timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 5000;
@@ -1111,7 +1340,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
memset(&fds, 0, sizeof(fd_set));
fds.fd_count = 1;
- fds.fd_array[0] = socketDescriptor;
+ fds.fd_array[0] = (SOCKET)socketDescriptor;
struct timeval tv;
tv.tv_sec = timeout / 1000;
@@ -1125,12 +1354,12 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
// Windows needs this to report errors when connecting a socket ...
fd_set fdexception;
FD_ZERO(&fdexception);
- FD_SET(socketDescriptor, &fdexception);
+ FD_SET((SOCKET)socketDescriptor, &fdexception);
ret = select(0, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv);
// ... but if it is actually set, pretend it did not happen
- if (ret > 0 && FD_ISSET(socketDescriptor, &fdexception))
+ if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
ret--;
}
@@ -1157,16 +1386,16 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout,
memset(&fdread, 0, sizeof(fd_set));
if (checkRead) {
fdread.fd_count = 1;
- fdread.fd_array[0] = socketDescriptor;
+ fdread.fd_array[0] = (SOCKET)socketDescriptor;
}
memset(&fdwrite, 0, sizeof(fd_set));
FD_ZERO(&fdexception);
if (checkWrite) {
fdwrite.fd_count = 1;
- fdwrite.fd_array[0] = socketDescriptor;
+ fdwrite.fd_array[0] = (SOCKET)socketDescriptor;
// Windows needs this to report errors when connecting a socket
- FD_SET(socketDescriptor, &fdexception);
+ FD_SET((SOCKET)socketDescriptor, &fdexception);
}
struct timeval tv;
@@ -1180,7 +1409,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout,
#endif
//... but if it is actually set, pretend it did not happen
- if (ret > 0 && FD_ISSET(socketDescriptor, &fdexception))
+ if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
ret--;
if (readEnabled)
@@ -1189,8 +1418,8 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout,
if (ret <= 0)
return ret;
- *selectForRead = FD_ISSET(socketDescriptor, &fdread);
- *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
+ *selectForRead = FD_ISSET((SOCKET)socketDescriptor, &fdread);
+ *selectForWrite = FD_ISSET((SOCKET)socketDescriptor, &fdwrite);
return ret;
}
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 87e7700..575c0bc 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
@@ -555,6 +556,9 @@ void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode)
udpData = new QSocks5UdpAssociateData;
data = udpData;
udpData->udpSocket = new QUdpSocket(q);
+#ifndef QT_NO_BEARERMANAGEMENT
+ udpData->udpSocket->setProperty("_q_networksession", q->property("_q_networksession"));
+#endif
udpData->udpSocket->setProxy(QNetworkProxy::NoProxy);
QObject::connect(udpData->udpSocket, SIGNAL(readyRead()),
q, SLOT(_q_udpSocketReadNotification()),
@@ -566,6 +570,9 @@ void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode)
}
data->controlSocket = new QTcpSocket(q);
+#ifndef QT_NO_BEARERMANAGEMENT
+ data->controlSocket->setProperty("_q_networksession", q->property("_q_networksession"));
+#endif
data->controlSocket->setProxy(QNetworkProxy::NoProxy);
QObject::connect(data->controlSocket, SIGNAL(connected()), q, SLOT(_q_controlSocketConnected()),
Qt::DirectConnection);
@@ -1375,6 +1382,9 @@ bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port)
d->udpData->associatePort = d->localPort;
d->localPort = 0;
QUdpSocket dummy;
+#ifndef QT_NO_BEARERMANAGEMENT
+ dummy.setProperty("_q_networksession", property("_q_networksession"));
+#endif
dummy.setProxy(QNetworkProxy::NoProxy);
if (!dummy.bind()
|| writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0
@@ -1530,8 +1540,13 @@ qint64 QSocks5SocketEngine::write(const char *data, qint64 len)
// ### Handle this error.
}
- d->data->controlSocket->write(sealedBuf);
+ qint64 written = d->data->controlSocket->write(sealedBuf);
+ if (written <= 0) {
+ QSOCKS5_Q_DEBUG << "native write returned" << written;
+ return written;
+ }
d->data->controlSocket->waitForBytesWritten(0);
+ //NB: returning len rather than written for the OK case, because the "sealing" may increase the length
return len;
#ifndef QT_NO_UDPSOCKET
} else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {
@@ -1544,6 +1559,37 @@ qint64 QSocks5SocketEngine::write(const char *data, qint64 len)
}
#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+bool QSocks5SocketEngine::joinMulticastGroup(const QHostAddress &,
+ const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ return false;
+}
+
+bool QSocks5SocketEngine::leaveMulticastGroup(const QHostAddress &,
+ const QNetworkInterface &)
+{
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QLatin1String("Operation on socket is not supported"));
+ 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;
+}
+#endif // QT_NO_NETWORKINTERFACE
+
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 7c1b762..9b2f6e3 100644
--- a/src/network/socket/qsocks5socketengine_p.h
+++ b/src/network/socket/qsocks5socketengine_p.h
@@ -92,6 +92,15 @@ public:
qint64 write(const char *data, qint64 len);
#ifndef QT_NO_UDPSOCKET
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+#endif // QT_NO_NETWORKINTERFACE
+
qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0,
quint16 *port = 0);
qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr,
diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp
new file mode 100644
index 0000000..15635ff
--- /dev/null
+++ b/src/network/socket/qsymbiansocketengine.cpp
@@ -0,0 +1,1770 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QNATIVESOCKETENGINE_DEBUG
+#include "qsymbiansocketengine_p.h"
+
+#include "qiodevice.h"
+#include "qhostaddress.h"
+#include "qelapsedtimer.h"
+#include "qvarlengtharray.h"
+#include "qnetworkinterface.h"
+#include <private/qnetworksession_p.h>
+#include <es_sock.h>
+#include <in_sock.h>
+#include <net/if.h>
+
+#include <private/qcore_symbian_p.h>
+
+#if !defined(QT_NO_NETWORKPROXY)
+# include "qnetworkproxy.h"
+# include "qabstractsocket.h"
+# include "qtcpserver.h"
+#endif
+
+#include <QCoreApplication>
+
+#include <qabstracteventdispatcher.h>
+#include <private/qeventdispatcher_symbian_p.h>
+#include <qsocketnotifier.h>
+#include <qnetworkinterface.h>
+
+#include <private/qthread_p.h>
+#include <private/qobject_p.h>
+#include <private/qsystemerror_p.h>
+
+#if defined QNATIVESOCKETENGINE_DEBUG
+#include <qstring.h>
+#include <ctype.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#define Q_VOID
+// Common constructs
+#define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \
+ if (!isValid()) { \
+ qWarning(""#function" was called on an uninitialized socket device"); \
+ return returnValue; \
+ } } while (0)
+#define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \
+ if (isValid()) { \
+ qWarning(""#function" was called on an already initialized socket device"); \
+ return returnValue; \
+ } } while (0)
+#define Q_CHECK_STATE(function, checkState, returnValue) do { \
+ if (d->socketState != (checkState)) { \
+ qWarning(""#function" was not called in "#checkState); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \
+ if (d->socketState == (checkState)) { \
+ qWarning(""#function" was called in "#checkState); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_STATES(function, state1, state2, returnValue) do { \
+ if (d->socketState != (state1) && d->socketState != (state2)) { \
+ qWarning(""#function" was called" \
+ " not in "#state1" or "#state2); \
+ return (returnValue); \
+ } } while (0)
+#define Q_CHECK_TYPE(function, type, returnValue) do { \
+ if (d->socketType != (type)) { \
+ qWarning(#function" was called by a" \
+ " socket other than "#type""); \
+ return (returnValue); \
+ } } while (0)
+
+#if defined QNATIVESOCKETENGINE_DEBUG
+
+/*
+ Returns a human readable representation of the first \a len
+ characters in \a data.
+*/
+static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
+{
+ if (!data) return "(null)";
+ QByteArray out;
+ for (int i = 0; i < len; ++i) {
+ char c = data[i];
+ if (isprint(c)) {
+ out += c;
+ } else switch (c) {
+ case '\n': out += "\\n"; break;
+ case '\r': out += "\\r"; break;
+ case '\t': out += "\\t"; break;
+ default:
+ QString tmp;
+ tmp.sprintf("\\%o", c);
+ out += tmp.toLatin1();
+ }
+ }
+
+ if (len < maxSize)
+ out += "...";
+
+ return out;
+}
+#endif
+
+void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr)
+{
+ if (a.Family() == KAfInet6 && !a.IsV4Compat() && !a.IsV4Mapped()) {
+ Q_IPV6ADDR tmp;
+ memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp));
+ if (addr) {
+ QHostAddress tmpAddress;
+ tmpAddress.setAddress(tmp);
+ *addr = tmpAddress;
+ TPckgBuf<TSoInetIfQuery> query;
+ query().iSrcAddr = a;
+ TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query);
+ if (!err)
+ addr->setScopeId(qt_TDesC2QString(query().iName));
+ else
+ addr->setScopeId(QString::number(a.Scope()));
+ }
+ if (port)
+ *port = a.Port();
+ return;
+ }
+ if (port)
+ *port = a.Port();
+ if (addr) {
+ QHostAddress tmpAddress;
+ tmpAddress.setAddress(a.Address());
+ *addr = tmpAddress;
+ }
+}
+/*! \internal
+
+ Creates and returns a new socket descriptor of type \a socketType
+ and \a socketProtocol. Returns -1 on failure.
+*/
+bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType,
+ QAbstractSocket::NetworkLayerProtocol socketProtocol)
+{
+ Q_Q(QSymbianSocketEngine);
+ TUint family = KAfInet; // KAfInet6 is only used as an address family, not as a protocol family
+ TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream;
+ TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp;
+
+ //Check if there is a user specified session
+ QVariant v(q->property("_q_networksession"));
+ TInt err;
+ if (v.isValid()) {
+ QSharedPointer<QNetworkSession> s = qvariant_cast<QSharedPointer<QNetworkSession> >(v);
+ err = QNetworkSessionPrivate::nativeOpenSocket(*s, nativeSocket, family, type, protocol);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - _q_networksession was set" << err;
+#endif
+ } else
+ err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead
+
+ if (err != KErrNone) {
+ switch (err) {
+ case KErrNotSupported:
+ case KErrNotFound:
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ ProtocolUnsupportedErrorString);
+ break;
+ default:
+ setError(err);
+ break;
+ }
+
+ return false;
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - created" << nativeSocket.SubSessionHandle();
+#endif
+ socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << " - allocated socket descriptor" << socketDescriptor;
+#endif
+ return true;
+}
+
+void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr)
+{
+ nativeAddr.SetPort(port);
+ if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
+ TPckgBuf<TSoInetIfQuery> query;
+ query().iName = qt_QString2TPtrC(addr.scopeId());
+ TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query);
+ if (!err)
+ nativeAddr.SetScope(query().iIndex);
+ else
+ nativeAddr.SetScope(0);
+ Q_IPV6ADDR ip6 = addr.toIPv6Address();
+ TIp6Addr v6addr;
+ memcpy(v6addr.u.iAddr8, ip6.c, 16);
+ nativeAddr.SetAddress(v6addr);
+ } else if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
+ nativeAddr.SetAddress(addr.toIPv4Address());
+ } else {
+ qWarning("unsupported network protocol (%d)", addr.protocol());
+ }
+}
+
+QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() :
+ socketDescriptor(-1),
+ socketServer(QSymbianSocketManager::instance().getSocketServer()),
+ readNotificationsEnabled(false),
+ writeNotificationsEnabled(false),
+ exceptNotificationsEnabled(false),
+ asyncSelect(0),
+ hasReceivedBufferedDatagram(false)
+{
+}
+
+QSymbianSocketEnginePrivate::~QSymbianSocketEnginePrivate()
+{
+}
+
+
+QSymbianSocketEngine::QSymbianSocketEngine(QObject *parent)
+ : QAbstractSocketEngine(*new QSymbianSocketEnginePrivate(), parent)
+{
+}
+
+
+QSymbianSocketEngine::~QSymbianSocketEngine()
+{
+ close();
+}
+
+/*!
+ Initializes a QSymbianSocketEngine by creating a new socket of type \a
+ socketType and network layer protocol \a protocol. Returns true on
+ success; otherwise returns false.
+
+ If the socket was already initialized, this function closes the
+ socket before reeinitializing it.
+
+ The new socket is non-blocking, and for UDP sockets it's also
+ broadcast enabled.
+*/
+bool QSymbianSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol)
+{
+ Q_D(QSymbianSocketEngine);
+ if (isValid())
+ close();
+
+ // Create the socket
+ if (!d->createNewSocket(socketType, protocol)) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ QString typeStr = QLatin1String("UnknownSocketType");
+ if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
+ else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
+ QString protocolStr = QLatin1String("UnknownProtocol");
+ if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
+ else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
+ qDebug("QSymbianSocketEngine::initialize(type == %s, protocol == %s) failed: %s",
+ typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+
+ // Make the socket nonblocking.
+ if (!setOption(NonBlockingSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ d->NonBlockingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Set the broadcasting flag if it's a UDP socket.
+ if (socketType == QAbstractSocket::UdpSocket
+ && !setOption(BroadcastSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ d->BroadcastingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+
+ // Make sure we receive out-of-band data
+ if (socketType == QAbstractSocket::TcpSocket
+ && !setOption(ReceiveOutOfBandData, 1)) {
+ qWarning("QSymbianSocketEngine::initialize unable to inline out-of-band data");
+ }
+
+
+ d->socketType = socketType;
+ d->socketProtocol = protocol;
+ return true;
+}
+
+/*! \overload
+
+ Initializes the socket using \a socketDescriptor instead of
+ creating a new one. The socket type and network layer protocol are
+ determined automatically. The socket's state is set to \a
+ socketState.
+
+ If the socket type is either TCP or UDP, it is made non-blocking.
+ UDP sockets are also broadcast enabled.
+ */
+bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::SocketState socketState)
+{
+ Q_D(QSymbianSocketEngine);
+
+ if (isValid())
+ close();
+
+ if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, d->nativeSocket)) {
+ qWarning("QSymbianSocketEngine::initialize - socket descriptor not found");
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QSymbianSocketEnginePrivate::InvalidSocketErrorString);
+ return false;
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::initialize - attached to" << d->nativeSocket.SubSessionHandle() << socketDescriptor;
+#endif
+ Q_ASSERT(d->socketDescriptor == socketDescriptor || d->socketDescriptor == -1);
+ d->socketDescriptor = socketDescriptor;
+
+ // determine socket type and protocol
+ if (!d->fetchConnectionParameters()) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::initialize(socketDescriptor == %i) failed: %s",
+ socketDescriptor, d->socketErrorString.toLatin1().constData());
+#endif
+ d->socketDescriptor = -1;
+ return false;
+ }
+
+ if (d->socketType != QAbstractSocket::UnknownSocketType) {
+ // Make the socket nonblocking.
+ if (!setOption(NonBlockingSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ d->NonBlockingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Set the broadcasting flag if it's a UDP socket.
+ if (d->socketType == QAbstractSocket::UdpSocket
+ && !setOption(BroadcastSocketOption, 1)) {
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ d->BroadcastingInitFailedErrorString);
+ close();
+ return false;
+ }
+
+ // Make sure we receive out-of-band data
+ if (d->socketType == QAbstractSocket::TcpSocket
+ && !setOption(ReceiveOutOfBandData, 1)) {
+ qWarning("QSymbianSocketEngine::initialize unable to inline out-of-band data");
+ }
+ }
+
+ d->socketState = socketState;
+ return true;
+}
+
+/*!
+ Returns true if the socket is valid; otherwise returns false. A
+ socket is valid if it has not been successfully initialized, or if
+ it has been closed.
+*/
+bool QSymbianSocketEngine::isValid() const
+{
+ Q_D(const QSymbianSocketEngine);
+ return d->socketDescriptor != -1;
+}
+
+
+/*!
+ Returns the native socket descriptor. Any use of this descriptor
+ stands the risk of being non-portable.
+*/
+int QSymbianSocketEngine::socketDescriptor() const
+{
+ Q_D(const QSymbianSocketEngine);
+ return d->socketDescriptor;
+}
+
+/*
+ Sets the socket option \a opt to \a v.
+*/
+bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, int v)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setOption(), false);
+
+ TUint n = 0;
+ TUint level = KSOLSocket; // default
+
+ if (!QSymbianSocketEnginePrivate::translateSocketOption(opt, n, level))
+ return false;
+
+ if (!level && !n)
+ return true;
+
+ return (KErrNone == d->nativeSocket.SetOpt(n, level, v));
+}
+
+/*
+ Returns the value of the socket option \a opt.
+*/
+int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::option(), -1);
+
+ TUint n;
+ TUint level = KSOLSocket; // default
+
+ if (!QSymbianSocketEnginePrivate::translateSocketOption(opt, n, level))
+ return false;
+
+ if (!level && !n)
+ return 1;
+
+ int v = -1;
+ //GetOpt() is non const
+ TInt err = d->nativeSocket.GetOpt(n, level, v);
+ if (!err)
+ return v;
+
+ return -1;
+}
+
+bool QSymbianSocketEnginePrivate::translateSocketOption(QAbstractSocketEngine::SocketOption opt, TUint &n, TUint &level)
+{
+
+ switch (opt) {
+ case QAbstractSocketEngine::ReceiveBufferSocketOption:
+ n = KSORecvBuf;
+ break;
+ case QAbstractSocketEngine::SendBufferSocketOption:
+ n = KSOSendBuf;
+ break;
+ case QAbstractSocketEngine::NonBlockingSocketOption:
+ n = KSONonBlockingIO;
+ break;
+ case QAbstractSocketEngine::AddressReusable:
+ level = KSolInetIp;
+ n = KSoReuseAddr;
+ break;
+ case QAbstractSocketEngine::BroadcastSocketOption:
+ case QAbstractSocketEngine::BindExclusively:
+ level = 0;
+ n = 0;
+ return true;
+ case QAbstractSocketEngine::ReceiveOutOfBandData:
+ level = KSolInetTcp;
+ n = KSoTcpOobInline;
+ break;
+ case QAbstractSocketEngine::LowDelayOption:
+ level = KSolInetTcp;
+ n = KSoTcpNoDelay;
+ break;
+ case QAbstractSocketEngine::KeepAliveOption:
+ level = KSolInetTcp;
+ n = KSoTcpKeepAlive;
+ break;
+ case QAbstractSocketEngine::MulticastLoopbackOption:
+ level = KSolInetIp;
+ n = KSoIp6MulticastLoop;
+ break;
+ case QAbstractSocketEngine::MulticastTtlOption:
+ level = KSolInetIp;
+ n = KSoIp6MulticastHops;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+qint64 QSymbianSocketEngine::receiveBufferSize() const
+{
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::receiveBufferSize(), -1);
+ return option(ReceiveBufferSocketOption);
+}
+
+void QSymbianSocketEngine::setReceiveBufferSize(qint64 size)
+{
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setReceiveBufferSize(), Q_VOID);
+ setOption(ReceiveBufferSocketOption, size);
+}
+
+qint64 QSymbianSocketEngine::sendBufferSize() const
+{
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setSendBufferSize(), -1);
+ return option(SendBufferSocketOption);
+}
+
+void QSymbianSocketEngine::setSendBufferSize(qint64 size)
+{
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setSendBufferSize(), Q_VOID);
+ setOption(SendBufferSocketOption, size);
+}
+
+/*!
+ Connects to the remote host name given by \a name on port \a
+ port. When this function is called, the upper-level will not
+ perform a hostname lookup.
+
+ The native socket engine does not support this operation,
+ but some other socket engines (notably proxy-based ones) do.
+*/
+bool QSymbianSocketEngine::connectToHostByName(const QString &name, quint16 port)
+{
+ Q_UNUSED(name);
+ Q_UNUSED(port);
+ Q_D(QSymbianSocketEngine);
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QSymbianSocketEnginePrivate::OperationUnsupportedErrorString);
+ return false;
+}
+
+/*!
+ If there's a connection activity on the socket, process it. Then
+ notify our parent if there really was activity.
+*/
+void QSymbianSocketEngine::connectionNotification()
+{
+ // FIXME check if we really need to do it like that in Symbian
+ Q_D(QSymbianSocketEngine);
+ Q_ASSERT(state() == QAbstractSocket::ConnectingState);
+
+ connectToHost(d->peerAddress, d->peerPort);
+ if (state() != QAbstractSocket::ConnectingState) {
+ // we changed states
+ QAbstractSocketEngine::connectionNotification();
+ }
+}
+
+
+bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::connectToHost(), false);
+
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug("QSymbianSocketEngine::connectToHost() : %d ", d->socketDescriptor);
+#endif
+
+ if (!d->checkProxy(addr))
+ return false;
+
+ d->peerAddress = addr;
+ d->peerPort = port;
+
+ TInetAddr nativeAddr;
+ d->setPortAndAddress(nativeAddr, port, addr);
+ TRequestStatus status;
+ d->nativeSocket.Connect(nativeAddr, status);
+ User::WaitForRequest(status);
+ TInt err = status.Int();
+ //For non blocking connect, KErrAlreadyExists is returned from the second Connect() to indicate
+ //the connection is up. So treat this the same as KErrNone which would be returned from the first
+ //call if it wouldn't block. (e.g. winsock wrapper in the emulator ignores the nonblocking flag)
+ if (err && err != KErrAlreadyExists) {
+ switch (err) {
+ case KErrWouldBlock:
+ d->socketState = QAbstractSocket::ConnectingState;
+ break;
+ default:
+ d->setError(err);
+ d->socketState = QAbstractSocket::UnconnectedState;
+ break;
+ }
+
+ if (d->socketState != QAbstractSocket::ConnectedState) {
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::connectToHost(%s, %i) == false (%s)",
+ addr.toString().toLatin1().constData(), port,
+ d->socketState == QAbstractSocket::ConnectingState
+ ? "Connection in progress" : d->socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::Connect(%s, %i) == true",
+ addr.toString().toLatin1().constData(), port);
+#endif
+
+ d->socketState = QAbstractSocket::ConnectedState;
+ d->fetchConnectionParameters();
+ return true;
+}
+
+bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::bind(), false);
+
+ if (!d->checkProxy(address))
+ return false;
+
+ Q_CHECK_STATE(QSymbianSocketEngine::bind(), QAbstractSocket::UnconnectedState, false);
+
+ TInetAddr nativeAddr;
+ if (address == QHostAddress::Any || address == QHostAddress::AnyIPv6) {
+ //Should allow both IPv4 and IPv6
+ //Listening on "0.0.0.0" accepts ONLY ipv4 connections
+ //Listening on "::" accepts ONLY ipv6 connections
+ nativeAddr.SetFamily(KAFUnspec);
+ nativeAddr.SetPort(port);
+ } else {
+ d->setPortAndAddress(nativeAddr, port, address);
+ }
+
+ TInt err = d->nativeSocket.Bind(nativeAddr);
+#ifdef __WINS__
+ if (err == KErrArgument) // winsock prt returns wrong error code
+ err = KErrInUse;
+#endif
+
+ if (err) {
+ switch (err) {
+ case KErrNotFound:
+ // the specified interface was not found - use the error code expected
+ d->setError(QAbstractSocket::SocketAddressNotAvailableError, QSymbianSocketEnginePrivate::AddressNotAvailableErrorString);
+ break;
+ default:
+ d->setError(err);
+ break;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::bind(%s, %i) == false (%s)",
+ address.toString().toLatin1().constData(), port, d->socketErrorString.toLatin1().constData());
+#endif
+
+ return false;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::bind(%s, %i) == true",
+ address.toString().toLatin1().constData(), port);
+#endif
+ d->socketState = QAbstractSocket::BoundState;
+
+ d->fetchConnectionParameters();
+
+ // When we bind to unspecified address (to get a dual mode socket), report back the
+ // same type of address that was requested. This is required for SOCKS proxy to work.
+ if (nativeAddr.Family() == KAFUnspec)
+ d->localAddress = address;
+ return true;
+}
+
+bool QSymbianSocketEngine::listen()
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::listen(), false);
+ Q_CHECK_STATE(QSymbianSocketEngine::listen(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
+ TInt err = d->nativeSocket.Listen(50);
+ if (err) {
+ d->setError(err);
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::listen() == false (%s)",
+ d->socketErrorString.toLatin1().constData());
+#endif
+ return false;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::listen() == true");
+#endif
+
+ d->socketState = QAbstractSocket::ListeningState;
+ return true;
+}
+
+int QSymbianSocketEngine::accept()
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::accept(), -1);
+ Q_CHECK_STATE(QSymbianSocketEngine::accept(), QAbstractSocket::ListeningState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::accept(), QAbstractSocket::TcpSocket, false);
+ RSocket blankSocket;
+ blankSocket.Open(d->socketServer);
+ TRequestStatus status;
+ d->nativeSocket.Accept(blankSocket, status);
+ User::WaitForRequest(status);
+ if (status.Int()) {
+ blankSocket.Close();
+ if (status != KErrWouldBlock)
+ qWarning("QSymbianSocketEngine::accept() - error %d", status.Int());
+ return -1;
+ }
+
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::accept - created" << blankSocket.SubSessionHandle();
+#endif
+ int fd = QSymbianSocketManager::instance().addSocket(blankSocket);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << " - allocated socket descriptor" << fd;
+#endif
+ return fd;
+}
+
+qint64 QSymbianSocketEngine::bytesAvailable() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::bytesAvailable(), -1);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, false);
+ int nbytes = 0;
+ qint64 available = 0;
+ TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes);
+ if (err)
+ return 0;
+ available = (qint64) nbytes;
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::bytesAvailable() == %lli", available);
+#endif
+ return available;
+}
+
+bool QSymbianSocketEngine::hasPendingDatagrams() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::hasPendingDatagrams(), false);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false);
+ int nbytes;
+ TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes);
+ return err == KErrNone && nbytes > 0;
+}
+
+qint64 QSymbianSocketEngine::pendingDatagramSize() const
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::pendingDatagramSize(), false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false);
+ //can only buffer one datagram at a time
+ if (d->hasReceivedBufferedDatagram)
+ return d->receivedDataBuffer.size();
+ int nbytes = 0;
+ TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes);
+ if (nbytes > 0) {
+ //nbytes includes IP header, which is of variable length (IPv4 with or without options, IPv6...)
+ //therefore read the datagram into a buffer to find its true size
+ d->receivedDataBuffer.resize(nbytes);
+ TPtr8 buffer((TUint8*)d->receivedDataBuffer.data(), nbytes);
+ //nbytes = size including IP header, buffer is a pointer descriptor backed by the receivedDataBuffer
+ TInetAddr addr;
+ TRequestStatus status;
+ //RecvFrom copies only the payload (we don't want the header so don't specify the option to retrieve it)
+ d->nativeSocket.RecvFrom(buffer, addr, 0, status);
+ User::WaitForRequest(status);
+ if (status != KErrNone) {
+ d->receivedDataBuffer.clear();
+ return 0;
+ }
+ nbytes = buffer.Length();
+ //nbytes = size of payload, resize the receivedDataBuffer to the final size
+ d->receivedDataBuffer.resize(nbytes);
+ d->hasReceivedBufferedDatagram = true;
+ //now receivedDataBuffer contains one datagram, which has been removed from the socket's internal buffer
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug() << "QSymbianSocketEngine::pendingDatagramSize buffering" << nbytes << "bytes";
+#endif
+ }
+ return qint64(nbytes);
+}
+
+
+qint64 QSymbianSocketEngine::readDatagram(char *data, qint64 maxSize,
+ QHostAddress *address, quint16 *port)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::readDatagram(), -1);
+ Q_CHECK_TYPE(QSymbianSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, false);
+
+ // if a datagram was buffered in pendingDatagramSize(), return it now
+ if (d->hasReceivedBufferedDatagram) {
+ qint64 size = qMin(maxSize, (qint64)d->receivedDataBuffer.size());
+ memcpy(data, d->receivedDataBuffer.constData(), size);
+ d->receivedDataBuffer.clear();
+ d->hasReceivedBufferedDatagram = false;
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug() << "QSymbianSocketEngine::readDatagram returning" << size << "bytes from buffer";
+#endif
+ return size;
+ }
+
+ TPtr8 buffer((TUint8*)data, (int)maxSize);
+ TInetAddr addr;
+ TRequestStatus status;
+ d->nativeSocket.RecvFrom(buffer, addr, 0, status);
+ User::WaitForRequest(status); //Non blocking receive
+
+ if (status.Int()) {
+ d->setError(QAbstractSocket::NetworkError, d->ReceiveDatagramErrorString);
+ } else if (port || address) {
+ d->getPortAndAddress(addr, port, address);
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ int len = buffer.Length();
+ qDebug("QSymbianSocketEngine::receiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
+ data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize,
+ address ? address->toString().toLatin1().constData() : "(nil)",
+ port ? *port : 0, (qint64) len);
+#endif
+
+ if (status.Int())
+ return -1;
+ return qint64(buffer.Length());
+}
+
+
+qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len,
+ const QHostAddress &host, quint16 port)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::writeDatagram(), -1);
+ Q_CHECK_TYPE(QSymbianSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1);
+ TPtrC8 buffer((TUint8*)data, (int)len);
+ TInetAddr addr;
+ d->setPortAndAddress(addr, port, host);
+ TSockXfrLength sentBytes;
+ TRequestStatus status;
+ d->nativeSocket.SendTo(buffer, addr, 0, status, sentBytes);
+ User::WaitForRequest(status); //Non blocking send
+ TInt err = status.Int();
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::writeDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli (err=%d)", data,
+ qt_prettyDebug(data, qMin<int>(len, 16), len).data(), len, host.toString().toLatin1().constData(),
+ port, (qint64) sentBytes(), err);
+#endif
+
+ if (err) {
+ switch (err) {
+ case KErrWouldBlock:
+ // do not error the socket. (otherwise socket layer is reset)
+ // On symbian^1 and earlier, KErrWouldBlock is returned when interface is not up yet
+ // On symbian^3, KErrNone is returned but sentBytes = 0
+ return 0;
+ case KErrTooBig:
+ d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString);
+ break;
+ default:
+ d->setError(QAbstractSocket::NetworkError, d->SendDatagramErrorString);
+ }
+ return -1;
+ }
+
+ if (QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0) {
+ // This is evil hack, but for some reason native RSocket::SendTo returns 0,
+ // for large datagrams (such as 600 bytes). Based on comments from Open C team
+ // this should happen only in platforms <= S60 5.0.
+ return len;
+ }
+ return sentBytes();
+}
+
+// FIXME check where the native socket engine called that..
+bool QSymbianSocketEnginePrivate::fetchConnectionParameters()
+{
+ localPort = 0;
+ localAddress.clear();
+ peerPort = 0;
+ peerAddress.clear();
+
+ if (socketDescriptor == -1)
+ return false;
+
+ if (!nativeSocket.SubSessionHandle()) {
+ if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) {
+ setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString);
+ return false;
+ }
+ }
+
+ // Determine local address
+ TSockAddr addr;
+ nativeSocket.LocalName(addr);
+ getPortAndAddress(addr, &localPort, &localAddress);
+
+ // Determine protocol family
+ socketProtocol = localAddress.protocol();
+
+ // Determine the remote address
+ nativeSocket.RemoteName(addr);
+ getPortAndAddress(addr, &peerPort, &peerAddress);
+
+ // Determine the socket type (UDP/TCP)
+ TProtocolDesc protocol;
+ TInt err = nativeSocket.Info(protocol);
+ if (err) {
+ setError(err);
+ return false;
+ } else {
+ switch (protocol.iProtocol) {
+ case KProtocolInetTcp:
+ socketType = QAbstractSocket::TcpSocket;
+ break;
+ case KProtocolInetUdp:
+ socketType = QAbstractSocket::UdpSocket;
+ break;
+ default:
+ socketType = QAbstractSocket::UnknownSocketType;
+ break;
+ }
+ }
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ QString socketProtocolStr = QLatin1String("UnknownProtocol");
+ if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QLatin1String("IPv4Protocol");
+ else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = QLatin1String("IPv6Protocol");
+
+ QString socketTypeStr = QLatin1String("UnknownSocketType");
+ if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QLatin1String("TcpSocket");
+ else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QLatin1String("UdpSocket");
+
+ qDebug("QSymbianSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
+ " peer == %s:%i, socket == %s - %s",
+ localAddress.toString().toLatin1().constData(), localPort,
+ peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(),
+ socketProtocolStr.toLatin1().constData());
+#endif
+ return true;
+}
+
+void QSymbianSocketEngine::close()
+{
+ if (!isValid())
+ return;
+ Q_D(QSymbianSocketEngine);
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::close()");
+#endif
+
+ d->readNotificationsEnabled = false;
+ d->writeNotificationsEnabled = false;
+ d->exceptNotificationsEnabled = false;
+ if (d->asyncSelect) {
+ d->asyncSelect->deleteLater();
+ d->asyncSelect = 0;
+ }
+
+ //TODO: call nativeSocket.Shutdown(EImmediate) in some cases?
+ if (d->socketType == QAbstractSocket::UdpSocket) {
+ //TODO: Close hangs without this, but only for UDP - why?
+ TRequestStatus stat;
+ d->nativeSocket.Shutdown(RSocket::EImmediate, stat);
+ User::WaitForRequest(stat);
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::close - closing socket" << d->nativeSocket.SubSessionHandle() << d->socketDescriptor;
+#endif
+ //remove must come before close to avoid a race where another thread gets the old subsession handle
+ //reused & asserts when calling QSymbianSocketManager::instance->addSocket
+ QSymbianSocketManager::instance().removeSocket(d->nativeSocket);
+ d->nativeSocket.Close();
+ d->socketDescriptor = -1;
+
+ d->socketState = QAbstractSocket::UnconnectedState;
+ d->hasSetSocketError = false;
+ d->localPort = 0;
+ d->localAddress.clear();
+ d->peerPort = 0;
+ d->peerAddress.clear();
+
+ d->hasReceivedBufferedDatagram = false;
+ d->receivedDataBuffer.clear();
+}
+
+qint64 QSymbianSocketEngine::write(const char *data, qint64 len)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::write(), -1);
+ Q_CHECK_STATE(QSymbianSocketEngine::write(), QAbstractSocket::ConnectedState, -1);
+ TPtrC8 buffer((TUint8*)data, (int)len);
+ TSockXfrLength sentBytes = 0;
+ TRequestStatus status;
+ d->nativeSocket.Send(buffer, 0, status, sentBytes);
+ User::WaitForRequest(status); //TODO: on emulator this blocks for write >16kB (non blocking IO not implemented properly?)
+ TInt err = status.Int();
+
+ if (err) {
+ switch (err) {
+ case KErrDisconnected:
+ case KErrEof:
+ sentBytes = -1;
+ d->setError(QAbstractSocket::RemoteHostClosedError, d->RemoteHostClosedErrorString);
+ close();
+ break;
+ case KErrTooBig:
+ d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString);
+ break;
+ case KErrWouldBlock:
+ break;
+ default:
+ sentBytes = -1;
+ d->setError(err);
+ close();
+ break;
+ }
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::write(%p \"%s\", %llu) == %i",
+ data, qt_prettyDebug(data, qMin((int) len, 16),
+ (int) len).data(), len, (int) sentBytes());
+#endif
+
+ return qint64(sentBytes());
+}
+/*
+*/
+qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::read(), -1);
+ Q_CHECK_STATES(QSymbianSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1);
+
+ // if a datagram was buffered in pendingDatagramSize(), return it now
+ if (d->hasReceivedBufferedDatagram) {
+ qint64 size = qMin(maxSize, (qint64)d->receivedDataBuffer.size());
+ memcpy(data, d->receivedDataBuffer.constData(), size);
+ d->receivedDataBuffer.clear();
+ d->hasReceivedBufferedDatagram = false;
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug() << "QSymbianSocketEngine::read returning" << size << "bytes from buffer";
+#endif
+ return size;
+ }
+
+ TPtr8 buffer((TUint8*)data, (int)maxSize);
+ TSockXfrLength received = 0;
+ TRequestStatus status;
+ TSockAddr dummy;
+ if (d->socketType == QAbstractSocket::UdpSocket) {
+ //RecvOneOrMore() can only be used with stream-interfaced connected sockets; datagram interface sockets will return KErrNotSupported.
+ d->nativeSocket.RecvFrom(buffer, dummy, 0, status);
+ } else {
+ d->nativeSocket.RecvOneOrMore(buffer, 0, status, received);
+ }
+ User::WaitForRequest(status); //Non blocking receive
+ TInt err = status.Int();
+ int r = buffer.Length();
+
+ if (err == KErrWouldBlock) {
+ // No data was available for reading
+ r = -2;
+ } else if (err != KErrNone) {
+ d->setError(err);
+ close();
+ r = -1;
+ }
+
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug("QSymbianSocketEngine::read(%p \"%s\", %llu) == %i (err = %d)",
+ data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(),
+ maxSize, r, err);
+#endif
+
+ return qint64(r);
+}
+
+int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+{
+ bool readyRead = false;
+ bool readyWrite = false;
+ if (selectForRead)
+ return nativeSelect(timeout, true, false, &readyRead, &readyWrite);
+ else
+ return nativeSelect(timeout, false, true, &readyRead, &readyWrite);
+}
+
+/*!
+ \internal
+ \param timeout timeout in milliseconds
+ \param checkRead caller is interested if the socket is ready to read
+ \param checkWrite caller is interested if the socket is ready for write
+ \param selectForRead (out) should set to true if ready to read
+ \param selectForWrite (out) should set to true if ready to write
+ \return 0 on timeout, >0 on success, <0 on error
+ */
+int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
+ bool *selectForRead, bool *selectForWrite) const
+{
+ //cancel asynchronous notifier (only one IOCTL allowed at a time)
+ if (asyncSelect)
+ asyncSelect->Cancel();
+
+ TPckgBuf<TUint> selectFlags;
+ selectFlags() = KSockSelectExcept;
+ if (checkRead)
+ selectFlags() |= KSockSelectRead;
+ if (checkWrite)
+ selectFlags() |= KSockSelectWrite;
+ TInt err;
+ if (timeout == 0) {
+ //if timeout is zero, poll
+ err = nativeSocket.GetOpt(KSOSelectPoll, KSOLSocket, selectFlags);
+ } else {
+ TRequestStatus selectStat;
+ nativeSocket.Ioctl(KIOctlSelect, selectStat, &selectFlags, KSOLSocket);
+
+ if (timeout < 0)
+ User::WaitForRequest(selectStat); //negative means no timeout
+ else {
+ if (!selectTimer.Handle())
+ qt_symbian_throwIfError(selectTimer.CreateLocal());
+ TRequestStatus timerStat;
+ selectTimer.HighRes(timerStat, timeout * 1000);
+ User::WaitForRequest(timerStat, selectStat);
+ if (selectStat == KRequestPending) {
+ nativeSocket.CancelIoctl();
+ //CancelIoctl completes the request (most likely with KErrCancel)
+ //We need to wait for this to keep the thread semaphore balanced (or active scheduler will panic)
+ User::WaitForRequest(selectStat);
+ //restart asynchronous notifier (only one IOCTL allowed at a time)
+ if (asyncSelect)
+ asyncSelect->IssueRequest();
+ #ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select timeout";
+ #endif
+ return 0; //timeout
+ } else {
+ selectTimer.Cancel();
+ User::WaitForRequest(timerStat);
+ }
+ }
+
+ #ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select status" << selectStat.Int() << (int)selectFlags();
+ #endif
+ err = selectStat.Int();
+ }
+
+ if (!err && (selectFlags() & KSockSelectExcept)) {
+ nativeSocket.GetOpt(KSOSelectLastError, KSOLSocket, err);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select last error" << err;
+#endif
+ }
+ if (err) {
+ //TODO: avoidable cast?
+ //set the error here, because read won't always return the same error again as select.
+ const_cast<QSymbianSocketEnginePrivate*>(this)->setError(err);
+ //restart asynchronous notifier (only one IOCTL allowed at a time)
+ if (asyncSelect)
+ asyncSelect->IssueRequest(); //TODO: in error case should we restart or not?
+ return err;
+ }
+ if (checkRead && (selectFlags() & KSockSelectRead)) {
+ Q_ASSERT(selectForRead);
+ *selectForRead = true;
+ }
+ if (checkWrite && (selectFlags() & KSockSelectWrite)) {
+ Q_ASSERT(selectForWrite);
+ *selectForWrite = true;
+ }
+ //restart asynchronous notifier (only one IOCTL allowed at a time)
+ if (asyncSelect)
+ asyncSelect->IssueRequest();
+ return 1;
+}
+
+bool QSymbianSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::joinMulticastGroup(), false);
+ Q_CHECK_STATE(QSymbianSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false);
+ return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6JoinGroup);
+}
+
+bool QSymbianSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::leaveMulticastGroup(), false);
+ Q_CHECK_STATE(QSymbianSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false);
+ return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6LeaveGroup);
+}
+
+bool QSymbianSocketEnginePrivate::multicastGroupMembershipHelper(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface,
+ TUint operation)
+{
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug() << "QSymbianSocketEnginePrivate::multicastGroupMembershipHelper" << groupAddress << iface << operation;
+#endif
+ //translate address
+ TPckgBuf<TIp6Mreq> option;
+ if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
+ memcpy(option().iAddr.u.iAddr8, ip6.c, 16);
+ } else {
+ TInetAddr wrapped;
+ wrapped.SetAddress(groupAddress.toIPv4Address());
+ wrapped.ConvertToV4Mapped();
+ option().iAddr = wrapped.Ip6Address();
+ }
+ option().iInterface = iface.index();
+ //join or leave group
+ TInt err = nativeSocket.SetOpt(operation, KSolInetIp, option);
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug() << "address" << qt_prettyDebug((const char *)(option().iAddr.u.iAddr8), 16, 16);
+ qDebug() << "interface" << option().iInterface;
+ qDebug() << "error" << err;
+#endif
+ if (err) {
+ setError(err);
+ }
+ return (KErrNone == err);
+}
+
+QNetworkInterface QSymbianSocketEngine::multicastInterface() const
+{
+ //TODO
+ const Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::multicastInterface(), QNetworkInterface());
+ Q_CHECK_TYPE(QSymbianSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface());
+ return QNetworkInterface();
+}
+
+bool QSymbianSocketEngine::setMulticastInterface(const QNetworkInterface &iface)
+{
+ //TODO - this is possibly a unix'ism as the RConnection on which the socket was created is probably controlling this
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setMulticastInterface(), false);
+ Q_CHECK_TYPE(QSymbianSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false);
+ return false;
+}
+
+bool QSymbianSocketEnginePrivate::checkProxy(const QHostAddress &address)
+{
+ if (address == QHostAddress::LocalHost || address == QHostAddress::LocalHostIPv6)
+ return true;
+
+#if !defined(QT_NO_NETWORKPROXY)
+ QObject *parent = q_func()->parent();
+ QNetworkProxy proxy;
+ if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(parent)) {
+ proxy = socket->proxy();
+ } else if (QTcpServer *server = qobject_cast<QTcpServer *>(parent)) {
+ proxy = server->proxy();
+ } else {
+ // no parent -> no proxy
+ return true;
+ }
+
+ if (proxy.type() == QNetworkProxy::DefaultProxy)
+ proxy = QNetworkProxy::applicationProxy();
+
+ if (proxy.type() != QNetworkProxy::DefaultProxy &&
+ proxy.type() != QNetworkProxy::NoProxy) {
+ // QSymbianSocketEngine doesn't do proxies
+ setError(QAbstractSocket::UnsupportedSocketOperationError,
+ InvalidProxyTypeString);
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+// FIXME this is also in QNativeSocketEngine, unify it
+/*! \internal
+
+ Sets the error and error string if not set already. The only
+ interesting error is the first one that occurred, and not the last
+ one.
+*/
+void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const
+{
+ if (hasSetSocketError) {
+ // Only set socket errors once for one engine; expect the
+ // socket to recreate its engine after an error. Note: There's
+ // one exception: SocketError(11) bypasses this as it's purely
+ // a temporary internal error condition.
+ // Another exception is the way the waitFor*() functions set
+ // an error when a timeout occurs. After the call to setError()
+ // they reset the hasSetSocketError to false
+ return;
+ }
+ if (error != QAbstractSocket::SocketError(11))
+ hasSetSocketError = true;
+
+ socketError = error;
+
+ switch (errorString) {
+ case NonBlockingInitFailedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to initialize non-blocking socket");
+ break;
+ case BroadcastingInitFailedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to initialize broadcast socket");
+ break;
+ case NoIpV6ErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Attempt to use IPv6 socket on a platform with no IPv6 support");
+ break;
+ case RemoteHostClosedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The remote host closed the connection");
+ break;
+ case TimeOutErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Network operation timed out");
+ break;
+ case ResourceErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Out of resources");
+ break;
+ case OperationUnsupportedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unsupported socket operation");
+ break;
+ case ProtocolUnsupportedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Protocol type not supported");
+ break;
+ case InvalidSocketErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Invalid socket descriptor");
+ break;
+ case HostUnreachableErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Host unreachable");
+ break;
+ case NetworkUnreachableErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Network unreachable");
+ break;
+ case AccessErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Permission denied");
+ break;
+ case ConnectionTimeOutErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Connection timed out");
+ break;
+ case ConnectionRefusedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Connection refused");
+ break;
+ case AddressInuseErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The bound address is already in use");
+ break;
+ case AddressNotAvailableErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The address is not available");
+ break;
+ case AddressProtectedErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The address is protected");
+ break;
+ case DatagramTooLargeErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Datagram was too large to send");
+ break;
+ case SendDatagramErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to send a message");
+ break;
+ case ReceiveDatagramErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to receive a message");
+ break;
+ case WriteErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unable to write");
+ break;
+ case ReadErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Network error");
+ break;
+ case PortInuseErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Another socket is already listening on the same port");
+ break;
+ case NotSocketErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Operation on non-socket");
+ break;
+ case InvalidProxyTypeString:
+ socketErrorString = QSymbianSocketEngine::tr("The proxy type is invalid for this operation");
+ break;
+ case InvalidAddressErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The address is invalid for this operation");
+ break;
+ case SessionNotOpenErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("The specified network session is not opened");
+ break;
+ case UnknownSocketErrorString:
+ socketErrorString = QSymbianSocketEngine::tr("Unknown error");
+ break;
+ }
+}
+
+void QSymbianSocketEnginePrivate::setError(TInt symbianError)
+{
+ switch (symbianError) {
+ case KErrDisconnected:
+ case KErrEof:
+ case KErrConnectionTerminated: //interface stopped externally - RConnection::Stop(EStopAuthoritative)
+ setError(QAbstractSocket::RemoteHostClosedError,
+ QSymbianSocketEnginePrivate::RemoteHostClosedErrorString);
+ break;
+ case KErrNetUnreach:
+ setError(QAbstractSocket::NetworkError,
+ QSymbianSocketEnginePrivate::NetworkUnreachableErrorString);
+ break;
+ case KErrHostUnreach:
+ setError(QAbstractSocket::NetworkError,
+ QSymbianSocketEnginePrivate::HostUnreachableErrorString);
+ break;
+ case KErrNoProtocolOpt:
+ setError(QAbstractSocket::NetworkError,
+ QSymbianSocketEnginePrivate::ProtocolUnsupportedErrorString);
+ break;
+ case KErrInUse:
+ setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
+ break;
+ case KErrPermissionDenied:
+ setError(QAbstractSocket::SocketAccessError, AccessErrorString);
+ break;
+ case KErrNotSupported:
+ setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString);
+ break;
+ case KErrNoMemory:
+ setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
+ break;
+ case KErrCouldNotConnect:
+ setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
+ break;
+ case KErrTimedOut:
+ setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
+ break;
+ case KErrBadName:
+ setError(QAbstractSocket::NetworkError, InvalidAddressErrorString);
+ break;
+ default:
+ socketError = QAbstractSocket::NetworkError;
+ socketErrorString = QSystemError(symbianError, QSystemError::NativeError).toString();
+ break;
+ }
+ hasSetSocketError = true;
+}
+
+void QSymbianSocketEngine::startNotifications()
+{
+ Q_D(QSymbianSocketEngine);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::startNotifications" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled;
+#endif
+ if (!d->asyncSelect && (d->readNotificationsEnabled || d->writeNotificationsEnabled || d->exceptNotificationsEnabled)) {
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::startNotifications(), Q_VOID);
+ if (d->threadData->eventDispatcher) {
+ d->asyncSelect = q_check_ptr(new QAsyncSelect(
+ static_cast<QEventDispatcherSymbian*> (d->threadData->eventDispatcher), d->nativeSocket,
+ this));
+ } else {
+ // call again when event dispatcher has been created
+ QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection);
+ }
+ }
+ if (d->asyncSelect)
+ d->asyncSelect->IssueRequest();
+}
+
+bool QSymbianSocketEngine::isReadNotificationEnabled() const
+{
+ Q_D(const QSymbianSocketEngine);
+ return d->readNotificationsEnabled;
+}
+
+void QSymbianSocketEngine::setReadNotificationEnabled(bool enable)
+{
+ Q_D(QSymbianSocketEngine);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::setReadNotificationEnabled" << enable << "socket" << d->socketDescriptor;
+#endif
+ d->readNotificationsEnabled = enable;
+ startNotifications();
+}
+
+bool QSymbianSocketEngine::isWriteNotificationEnabled() const
+{
+ Q_D(const QSymbianSocketEngine);
+ return d->writeNotificationsEnabled;
+}
+
+void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable)
+{
+ Q_D(QSymbianSocketEngine);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::setWriteNotificationEnabled" << enable << "socket" << d->socketDescriptor;
+#endif
+ d->writeNotificationsEnabled = enable;
+ startNotifications();
+}
+
+bool QSymbianSocketEngine::isExceptionNotificationEnabled() const
+{
+ Q_D(const QSymbianSocketEngine);
+ return d->exceptNotificationsEnabled;
+ return false;
+}
+
+void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable)
+{
+ Q_D(QSymbianSocketEngine);
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::setExceptionNotificationEnabled" << enable << "socket" << d->socketDescriptor;
+#endif
+ d->exceptNotificationsEnabled = enable;
+ startNotifications();
+}
+
+bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut)
+{
+ Q_D(const QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForRead(), false);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForRead(),
+ QAbstractSocket::UnconnectedState, false);
+
+ if (timedOut)
+ *timedOut = false;
+
+ int ret = d->nativeSelect(msecs, true);
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ d->TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+bool QSymbianSocketEngine::waitForWrite(int msecs, bool *timedOut)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForWrite(), false);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForWrite(),
+ QAbstractSocket::UnconnectedState, false);
+
+ if (timedOut)
+ *timedOut = false;
+
+ int ret = d->nativeSelect(msecs, false);
+
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ d->TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+bool QSymbianSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs, bool *timedOut)
+{
+ Q_D(QSymbianSocketEngine);
+ Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForWrite(), false);
+ Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForReadOrWrite(),
+ QAbstractSocket::UnconnectedState, false);
+
+ int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite);
+
+ if (ret == 0) {
+ if (timedOut)
+ *timedOut = true;
+ d->setError(QAbstractSocket::SocketTimeoutError,
+ d->TimeOutErrorString);
+ d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
+ return false;
+ } else if (state() == QAbstractSocket::ConnectingState) {
+ connectToHost(d->peerAddress, d->peerPort);
+ }
+
+ return ret > 0;
+}
+
+qint64 QSymbianSocketEngine::bytesToWrite() const
+{
+ // This is what the QNativeSocketEngine does
+ return 0;
+}
+
+bool QSymbianSocketEngine::event(QEvent* ev)
+{
+ Q_D(QSymbianSocketEngine);
+ if (ev->type() == QEvent::ThreadChange) {
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QSymbianSocketEngine::event - ThreadChange" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled;
+#endif
+ if (d->asyncSelect) {
+ delete d->asyncSelect;
+ d->asyncSelect = 0;
+ // recreate select in new thread (because it is queued, the method is called in the new thread context)
+ QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection);
+ }
+ d->selectTimer.Close();
+ return true;
+ }
+ return QAbstractSocketEngine::event(ev);
+}
+
+QAsyncSelect::QAsyncSelect(QEventDispatcherSymbian *dispatcher, RSocket& sock, QSymbianSocketEngine *parent)
+ : QActiveObject(CActive::EPriorityStandard, dispatcher),
+ m_inSocketEvent(false),
+ m_deleteLater(false),
+ m_socket(sock),
+ m_selectFlags(0),
+ engine(parent)
+{
+ CActiveScheduler::Add(this);
+}
+
+QAsyncSelect::~QAsyncSelect()
+{
+ Cancel();
+}
+
+void QAsyncSelect::DoCancel()
+{
+ m_socket.CancelIoctl();
+}
+
+void QAsyncSelect::RunL()
+{
+ QT_TRYCATCH_LEAVING(run());
+}
+
+//RunError is called by the active scheduler if RunL leaves.
+//Typically this will happen if a std::bad_alloc propagates down from the application
+TInt QAsyncSelect::RunError(TInt aError)
+{
+ if (engine) {
+ QT_TRY {
+ engine->d_func()->setError(aError);
+ if (engine->isExceptionNotificationEnabled())
+ engine->exceptionNotification();
+ if (engine->isReadNotificationEnabled())
+ engine->readNotification();
+ }
+ QT_CATCH(...) {}
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QAsyncSelect::RunError" << aError;
+#endif
+ return KErrNone;
+}
+
+void QAsyncSelect::run()
+{
+ //when event loop disabled socket events, defer until later
+ if (maybeDeferSocketEvent())
+ return;
+#if defined (QNATIVESOCKETENGINE_DEBUG)
+ qDebug() << "QAsyncSelect::run" << m_selectBuf() << m_selectFlags;
+#endif
+ m_inSocketEvent = true;
+ m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested
+ //KSockSelectReadContinuation is for reading datagrams in a mode that doesn't discard when the
+ //datagram is larger than the read buffer - Qt doesn't need to use this.
+ if (engine && engine->isReadNotificationEnabled()
+ && ((m_selectBuf() & KSockSelectRead) || iStatus != KErrNone)) {
+ engine->readNotification();
+ }
+ if (engine && engine->isWriteNotificationEnabled()
+ && ((m_selectBuf() & KSockSelectWrite) || iStatus != KErrNone)) {
+ if (engine->state() == QAbstractSocket::ConnectingState)
+ engine->connectionNotification();
+ else
+ engine->writeNotification();
+ }
+ if (engine && engine->isExceptionNotificationEnabled()
+ && ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone)) {
+ engine->exceptionNotification();
+ }
+ m_inSocketEvent = false;
+ if (m_deleteLater) {
+ delete this;
+ return;
+ }
+ // select again (unless disabled by one of the callbacks)
+ IssueRequest();
+}
+
+void QAsyncSelect::deleteLater()
+{
+ if (m_inSocketEvent) {
+ engine = 0;
+ m_deleteLater = true;
+ } else {
+ delete this;
+ }
+}
+
+void QAsyncSelect::IssueRequest()
+{
+ if (m_inSocketEvent)
+ return; //prevent thrashing during a callback - socket engine enables/disables multiple notifiers
+ TUint selectFlags = 0;
+ if (engine->isReadNotificationEnabled())
+ selectFlags |= KSockSelectRead;
+ if (engine->isWriteNotificationEnabled())
+ selectFlags |= KSockSelectWrite;
+ if (engine->isExceptionNotificationEnabled())
+ selectFlags |= KSockSelectExcept;
+ if (selectFlags != m_selectFlags) {
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QAsyncSelect::IssueRequest() - select flags" << m_selectFlags << "->" << selectFlags;
+#endif
+ Cancel();
+ m_selectFlags = selectFlags;
+ }
+ if (m_selectFlags && !IsActive()) {
+ //always request errors (write notification does not complete on connect errors)
+ m_selectBuf() = m_selectFlags | KSockSelectExcept;
+ m_socket.Ioctl(KIOctlSelect, iStatus, &m_selectBuf, KSOLSocket);
+ SetActive();
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QAsyncSelect::IssueRequest() - IsActive" << IsActive();
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h
new file mode 100644
index 0000000..81156fc
--- /dev/null
+++ b/src/network/socket/qsymbiansocketengine_p.h
@@ -0,0 +1,258 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSYMBIANSOCKETENGINE_P_H
+#define QSYMBIANSOCKETENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+#include "QtNetwork/qhostaddress.h"
+#include "private/qabstractsocketengine_p.h"
+#include "qplatformdefs.h"
+
+#include <private/qeventdispatcher_symbian_p.h>
+#include <unistd.h>
+#include <es_sock.h>
+#include <in_sock.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QSymbianSocketEnginePrivate;
+class QNetworkInterface;
+
+class Q_AUTOTEST_EXPORT QSymbianSocketEngine : public QAbstractSocketEngine
+{
+ Q_OBJECT
+ friend class QAsyncSelect;
+public:
+ QSymbianSocketEngine(QObject *parent = 0);
+ ~QSymbianSocketEngine();
+
+ bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol);
+ bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState);
+
+ int socketDescriptor() const;
+
+ bool isValid() const;
+
+ bool connectToHost(const QHostAddress &address, quint16 port);
+ bool connectToHostByName(const QString &name, quint16 port);
+ bool bind(const QHostAddress &address, quint16 port);
+ bool listen();
+ int accept();
+ void close();
+
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ QNetworkInterface multicastInterface() const;
+ bool setMulticastInterface(const QNetworkInterface &iface);
+
+ qint64 bytesAvailable() const;
+
+ 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);
+ bool hasPendingDatagrams() const;
+ qint64 pendingDatagramSize() const;
+
+ qint64 bytesToWrite() const;
+
+ qint64 receiveBufferSize() const;
+ void setReceiveBufferSize(qint64 bufferSize);
+
+ qint64 sendBufferSize() const;
+ void setSendBufferSize(qint64 bufferSize);
+
+ int option(SocketOption option) const;
+ bool setOption(SocketOption option, int value);
+
+ bool waitForRead(int msecs = 30000, bool *timedOut = 0);
+ bool waitForWrite(int msecs = 30000, bool *timedOut = 0);
+ bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
+ bool checkRead, bool checkWrite,
+ int msecs = 30000, bool *timedOut = 0);
+
+ bool isReadNotificationEnabled() const;
+ void setReadNotificationEnabled(bool enable);
+ bool isWriteNotificationEnabled() const;
+ void setWriteNotificationEnabled(bool enable);
+ bool isExceptionNotificationEnabled() const;
+ void setExceptionNotificationEnabled(bool enable);
+
+ bool event(QEvent* ev);
+
+ Q_INVOKABLE void startNotifications();
+
+public Q_SLOTS:
+ // TODO: Why do we do this? This is private Qt implementation stuff anyway, no need for it
+ // non-virtual override;
+ void connectionNotification();
+
+private:
+ Q_DECLARE_PRIVATE(QSymbianSocketEngine)
+ Q_DISABLE_COPY(QSymbianSocketEngine)
+};
+
+class QSocketNotifier;
+
+class QReadNotifier;
+class QWriteNotifier;
+class QExceptionNotifier;
+class QAsyncSelect : public QActiveObject
+{
+public:
+ QAsyncSelect(QEventDispatcherSymbian *dispatcher, RSocket& sock, QSymbianSocketEngine *parent);
+ ~QAsyncSelect();
+
+ void deleteLater();
+ void IssueRequest();
+
+ void refresh();
+
+protected:
+ void DoCancel();
+ void RunL();
+ void run();
+ TInt RunError(TInt aError);
+
+private:
+ bool m_inSocketEvent;
+ bool m_deleteLater;
+ RSocket &m_socket;
+
+ TUint m_selectFlags;
+ TPckgBuf<TUint> m_selectBuf; //in & out IPC buffer
+ QSymbianSocketEngine *engine;
+};
+
+class QSymbianSocketEnginePrivate : public QAbstractSocketEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QSymbianSocketEngine)
+public:
+ QSymbianSocketEnginePrivate();
+ ~QSymbianSocketEnginePrivate();
+
+ int socketDescriptor;
+ mutable RSocket nativeSocket;
+ // From QtCore:
+ RSocketServ& socketServer;
+ mutable RTimer selectTimer;
+
+ bool readNotificationsEnabled;
+ bool writeNotificationsEnabled;
+ bool exceptNotificationsEnabled;
+ QAsyncSelect* asyncSelect;
+
+ mutable QByteArray receivedDataBuffer;
+ mutable bool hasReceivedBufferedDatagram;
+ // FIXME this is duplicated from qnativesocketengine_p.h
+ enum ErrorString {
+ NonBlockingInitFailedErrorString,
+ BroadcastingInitFailedErrorString,
+ NoIpV6ErrorString,
+ RemoteHostClosedErrorString,
+ TimeOutErrorString,
+ ResourceErrorString,
+ OperationUnsupportedErrorString,
+ ProtocolUnsupportedErrorString,
+ InvalidSocketErrorString,
+ HostUnreachableErrorString,
+ NetworkUnreachableErrorString,
+ AccessErrorString,
+ ConnectionTimeOutErrorString,
+ ConnectionRefusedErrorString,
+ AddressInuseErrorString,
+ AddressNotAvailableErrorString,
+ AddressProtectedErrorString,
+ DatagramTooLargeErrorString,
+ SendDatagramErrorString,
+ ReceiveDatagramErrorString,
+ WriteErrorString,
+ ReadErrorString,
+ PortInuseErrorString,
+ NotSocketErrorString,
+ InvalidProxyTypeString,
+ //symbian specific
+ InvalidAddressErrorString,
+ SessionNotOpenErrorString,
+
+ UnknownSocketErrorString = -1
+ };
+ void setError(QAbstractSocket::SocketError error, ErrorString errorString) const;
+
+ void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr);
+ void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr);
+ void setError(TInt symbianError);
+
+ int nativeSelect(int timeout, bool selectForRead) const;
+ int nativeSelect(int timeout, bool checkRead, bool checkWrite,
+ bool *selectForRead, bool *selectForWrite) const;
+
+ bool createNewSocket(QAbstractSocket::SocketType socketType,
+ QAbstractSocket::NetworkLayerProtocol socketProtocol);
+
+ bool checkProxy(const QHostAddress &address);
+ bool fetchConnectionParameters();
+
+ bool multicastGroupMembershipHelper(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface,
+ TUint operation);
+ static bool translateSocketOption(QAbstractSocketEngine::SocketOption opt, TUint &n, TUint &level);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSYMBIANSOCKETENGINE_P_H
diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp
index 5a52084..ccdc50e 100644
--- a/src/network/socket/qtcpserver.cpp
+++ b/src/network/socket/qtcpserver.cpp
@@ -105,7 +105,7 @@
#include "qhostaddress.h"
#include "qlist.h"
#include "qpointer.h"
-#include "qnativesocketengine_p.h"
+#include "qabstractsocketengine_p.h"
#include "qtcpserver.h"
#include "qtcpsocket.h"
#include "qnetworkproxy.h"
@@ -292,6 +292,10 @@ bool QTcpServer::listen(const QHostAddress &address, quint16 port)
d->serverSocketErrorString = tr("Operation on socket is not supported");
return false;
}
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the socket engine (if it has been set)
+ d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
+#endif
if (!d->socketEngine->initialize(QAbstractSocket::TcpSocket, proto)) {
d->serverSocketError = d->socketEngine->error();
d->serverSocketErrorString = d->socketEngine->errorString();
@@ -412,6 +416,15 @@ bool QTcpServer::setSocketDescriptor(int socketDescriptor)
if (d->socketEngine)
delete d->socketEngine;
d->socketEngine = QAbstractSocketEngine::createSocketEngine(socketDescriptor, this);
+ if (!d->socketEngine) {
+ d->serverSocketError = QAbstractSocket::UnsupportedSocketOperationError;
+ d->serverSocketErrorString = tr("Operation on socket is not supported");
+ return false;
+ }
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the socket engine (if it has been set)
+ d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
+#endif
if (!d->socketEngine->initialize(socketDescriptor, QAbstractSocket::ListeningState)) {
d->serverSocketError = d->socketEngine->error();
d->serverSocketErrorString = d->socketEngine->errorString();
diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp
index e3480b1..6bc93dd 100644
--- a/src/network/socket/qudpsocket.cpp
+++ b/src/network/socket/qudpsocket.cpp
@@ -77,14 +77,23 @@
\snippet doc/src/snippets/code/src_network_socket_qudpsocket.cpp 0
+ 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. 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()
to exchange datagrams without specifying the receiver for each
datagram.
- The \l{network/broadcastsender}{Broadcast Sender} and
- \l{network/broadcastreceiver}{Broadcast Receiver} examples
- illustrate how to use QUdpSocket in applications.
+ The \l{network/broadcastsender}{Broadcast Sender},
+ \l{network/broadcastreceiver}{Broadcast Receiver},
+ \l{network/multicastsender}{Multicast Sender}, and
+ \l{network/multicastreceiver}{Multicast Receiver} examples illustrate how
+ to use QUdpSocket in applications.
\section1 Symbian Platform Security Requirements
@@ -145,6 +154,7 @@
*/
#include "qhostaddress.h"
+#include "qnetworkinterface.h"
#include "qabstractsocket_p.h"
#include "qudpsocket.h"
@@ -192,7 +202,7 @@ bool QUdpSocketPrivate::doEnsureInitialized(const QHostAddress &bindAddress, qui
#endif
// now check if the socket engine is initialized and to the right type
- if (!socketEngine || !socketEngine->isValid() || socketEngine->protocol() != proto) {
+ if (!socketEngine || !socketEngine->isValid()) {
resolveProxy(remoteAddress.toString(), bindPort);
if (!initSocketLayer(address->protocol()))
return false;
@@ -328,6 +338,116 @@ bool QUdpSocket::bind(quint16 port, BindMode mode)
return bind(QHostAddress::Any, port, mode);
}
+#ifndef QT_NO_NETWORKINTERFACE
+
+/*!
+ \since 4.8
+
+ Joins the the multicast group specified by \a groupAddress on the default
+ interface chosen by the operating system. The socket must be in BoundState,
+ otherwise an error occurs.
+
+ This function returns true if successful; otherwise it returns false
+ and sets the socket error accordingly.
+
+ \sa leaveMulticastGroup()
+*/
+bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress)
+{
+ return joinMulticastGroup(groupAddress, QNetworkInterface());
+}
+
+/*!
+ \since 4.8
+ \overload
+
+ Joins the multicast group address \a groupAddress on the interface \a
+ iface.
+
+ \sa leaveMulticastGroup()
+*/
+bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ Q_D(QUdpSocket);
+ QT_CHECK_BOUND("QUdpSocket::joinMulticastGroup()", false);
+ return d->socketEngine->joinMulticastGroup(groupAddress, iface);
+}
+
+/*!
+ \since 4.8
+
+ Leaves the multicast group specified by \a groupAddress on the default
+ interface chosen by the operating system. The socket must be in BoundState,
+ otherwise an error occurs.
+
+ This function returns true if successful; otherwise it returns false and
+ sets the socket error accordingly.
+
+ \sa joinMulticastGroup()
+*/
+bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress)
+{
+ return leaveMulticastGroup(groupAddress, QNetworkInterface());
+}
+
+/*!
+ \since 4.8
+ \overload
+
+ Leaves the multicast group specified by \a groupAddress on the interface \a
+ iface.
+
+ \sa joinMulticastGroup()
+*/
+bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface)
+{
+ QT_CHECK_BOUND("QUdpSocket::leaveMulticastGroup()", false);
+ return d_func()->socketEngine->leaveMulticastGroup(groupAddress, iface);
+}
+
+/*!
+ \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);
+}
+
+#endif // QT_NO_NETWORKINTERFACE
+
/*!
Returns true if at least one datagram is waiting to be read;
otherwise returns false.
@@ -388,16 +508,6 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre
return -1;
qint64 sent = d->socketEngine->writeDatagram(data, size, address, port);
-#ifdef Q_OS_SYMBIAN
- if( QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0 ) {
- // This is evil hack, but for some reason native RSocket::SendTo returns 0,
- // for large datagrams (such as 600 bytes). Based on comments from Open C team
- // this should happen only in platforms <= S60 5.0.
- // As an workaround, we just set sent = size
- if( sent == 0 )
- sent = size;
- }
-#endif
d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
if (sent >= 0) {
diff --git a/src/network/socket/qudpsocket.h b/src/network/socket/qudpsocket.h
index aafef5c..c477abd 100644
--- a/src/network/socket/qudpsocket.h
+++ b/src/network/socket/qudpsocket.h
@@ -53,6 +53,7 @@ QT_MODULE(Network)
#ifndef QT_NO_UDPSOCKET
+class QNetworkInterface;
class QUdpSocketPrivate;
class Q_NETWORK_EXPORT QUdpSocket : public QAbstractSocket
@@ -76,6 +77,18 @@ public:
bool bind(quint16 port, BindMode mode);
// ### Qt 5: Merge the bind functions
+#ifndef QT_NO_NETWORKINTERFACE
+ bool joinMulticastGroup(const QHostAddress &groupAddress);
+ bool joinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress);
+ bool leaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+
+ QNetworkInterface multicastInterface() const;
+ void setMulticastInterface(const QNetworkInterface &iface);
+#endif
+
bool hasPendingDatagrams() const;
qint64 pendingDatagramSize() const;
qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *host = 0, quint16 *port = 0);
diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri
index 2bafe13..ac90012 100644
--- a/src/network/socket/socket.pri
+++ b/src/network/socket/socket.pri
@@ -1,7 +1,6 @@
# Qt network socket
HEADERS += socket/qabstractsocketengine_p.h \
- socket/qnativesocketengine_p.h \
socket/qhttpsocketengine_p.h \
socket/qsocks5socketengine_p.h \
socket/qabstractsocket.h \
@@ -15,7 +14,6 @@ HEADERS += socket/qabstractsocketengine_p.h \
socket/qlocalsocket_p.h
SOURCES += socket/qabstractsocketengine.cpp \
- socket/qnativesocketengine.cpp \
socket/qhttpsocketengine.cpp \
socket/qsocks5socketengine.cpp \
socket/qabstractsocket.cpp \
@@ -25,9 +23,26 @@ SOURCES += socket/qabstractsocketengine.cpp \
socket/qlocalsocket.cpp \
socket/qlocalserver.cpp
-unix:SOURCES += socket/qnativesocketengine_unix.cpp \
+# On Symbian we use QSymbianSocketEngine
+symbian:SOURCES += socket/qsymbiansocketengine.cpp
+symbian:HEADERS += socket/qsymbiansocketengine_p.h
+# On others we use QNativeSocketEngine
+!symbian:SOURCES += socket/qnativesocketengine.cpp
+!symbian:HEADERS += socket/qnativesocketengine_p.h
+
+unix:!symbian: {
+ SOURCES += socket/qnativesocketengine_unix.cpp \
socket/qlocalsocket_unix.cpp \
socket/qlocalserver_unix.cpp
+}
+
+symbian: {
+ SOURCES += socket/qlocalsocket_tcp.cpp \
+ socket/qlocalserver_tcp.cpp
+
+ DEFINES += QT_LOCALSOCKET_TCP
+}
+
unix:HEADERS += \
socket/qnet_unix_p.h
@@ -43,3 +58,13 @@ wince*: {
DEFINES += QT_LOCALSOCKET_TCP
}
+
+integrity: {
+ SOURCES -= socket/qlocalsocket_unix.cpp \
+ socket/qlocalserver_unix.cpp
+ SOURCES += socket/qlocalsocket_tcp.cpp \
+ socket/qlocalserver_tcp.cpp \
+ socket/qnativesocketengine_unix.cpp
+
+ DEFINES += QT_LOCALSOCKET_TCP
+}