summaryrefslogtreecommitdiffstats
path: root/src/network/socket
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket')
-rw-r--r--src/network/socket/qabstractsocket.cpp86
-rw-r--r--src/network/socket/qabstractsocket.h8
-rw-r--r--src/network/socket/qabstractsocketengine_p.h4
-rw-r--r--src/network/socket/qhttpsocketengine.cpp21
-rw-r--r--src/network/socket/qlocalserver.cpp14
-rw-r--r--src/network/socket/qlocalserver.h8
-rw-r--r--src/network/socket/qlocalserver_p.h61
-rw-r--r--src/network/socket/qlocalserver_unix.cpp37
-rw-r--r--src/network/socket/qlocalserver_win.cpp234
-rw-r--r--src/network/socket/qlocalsocket.cpp33
-rw-r--r--src/network/socket/qlocalsocket.h1
-rw-r--r--src/network/socket/qlocalsocket_p.h53
-rw-r--r--src/network/socket/qlocalsocket_unix.cpp29
-rw-r--r--src/network/socket/qlocalsocket_win.cpp285
-rw-r--r--src/network/socket/qnativesocketengine.cpp11
-rw-r--r--src/network/socket/qnativesocketengine_p.h37
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp268
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp153
-rw-r--r--src/network/socket/qnet_unix_p.h204
-rw-r--r--src/network/socket/qsocks5socketengine.cpp42
-rw-r--r--src/network/socket/qtcpserver.cpp9
-rw-r--r--src/network/socket/qtcpsocket.cpp10
-rw-r--r--src/network/socket/qtcpsocket.h1
-rw-r--r--src/network/socket/qudpsocket.cpp24
-rw-r--r--src/network/socket/socket.pri5
25 files changed, 1007 insertions, 631 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 5c4dcdf..b85a9d2 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -48,7 +48,7 @@
common to all socket types.
\reentrant
- \ingroup io
+ \ingroup network
\inmodule QtNetwork
QAbstractSocket is the base class for QTcpSocket and QUdpSocket
@@ -160,7 +160,7 @@
issue to be aware of, though: You must make sure that enough data
is available before attempting to read it using operator>>().
- \sa QFtp, QHttp, QTcpServer
+ \sa QFtp, QNetworkAccessManager, QTcpServer
*/
/*!
@@ -332,6 +332,22 @@
\sa QAbstractSocket::state()
*/
+/*!
+ \enum QAbstractSocket::SocketOption
+ \since 4.6
+
+ This enum represents the options that can be set on a socket.
+ If desired, they can be set after having received the connected() signal from
+ the socket or after having received a new socket from a QTcpServer.
+
+ \value LowDelayOption Try to optimize the socket for low latency. For a QTcpSocket
+ this would set the TCP_NODELAY option and disable Nagle's algorithm. Set this to 1
+ to enable.
+ \value KeepAliveOption Set this to 1 to enable the SO_KEEPALIVE socket option
+
+ \sa QAbstractSocket::setSocketOption(), QAbstractSocket::socketOption()
+*/
+
#include "qabstractsocket.h"
#include "qabstractsocket_p.h"
@@ -852,7 +868,7 @@ void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo)
if (i != 0) s += ", ";
s += addresses.at(i).toString();
}
- s += "}";
+ s += '}';
qDebug("QAbstractSocketPrivate::_q_startConnecting(hostInfo == %s)", s.toLatin1().constData());
#endif
@@ -1053,6 +1069,7 @@ void QAbstractSocketPrivate::_q_abortConnectionAttempt()
#endif
if (socketEngine)
socketEngine->setWriteNotificationEnabled(false);
+
connectTimer->stop();
if (addresses.isEmpty()) {
@@ -1265,8 +1282,9 @@ void QAbstractSocket::connectToHostImplementation(const QString &hostName, quint
(int) openMode);
#endif
- if (d->state == ConnectedState || d->state == ConnectingState || d->state == ClosingState) {
- qWarning("QAbstractSocket::connectToHost() called when already connecting/connected to \"%s\"", qPrintable(hostName));
+ if (d->state == ConnectedState || d->state == ConnectingState
+ || d->state == ClosingState || d->state == HostLookupState) {
+ qWarning("QAbstractSocket::connectToHost() called when already looking up or connecting/connected to \"%s\"", qPrintable(hostName));
return;
}
@@ -1548,6 +1566,56 @@ bool QAbstractSocket::setSocketDescriptor(int socketDescriptor, SocketState sock
return true;
}
+/*!
+ Sets the option \a option to the value described by \a value.
+
+ \sa socketOption()
+ \since 4.6
+*/
+void QAbstractSocket::setSocketOption(QAbstractSocket::SocketOption option, QVariant value)
+{
+ if (!d_func()->socketEngine)
+ return;
+
+ switch (option) {
+ case LowDelayOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::LowDelayOption, value.toInt());
+ break;
+
+ case KeepAliveOption:
+ d_func()->socketEngine->setOption(QAbstractSocketEngine::KeepAliveOption, value.toInt());
+ break;
+ }
+}
+
+/*!
+ Returns the value of the \a option option.
+
+ \sa setSocketOption()
+ \since 4.6
+*/
+QVariant QAbstractSocket::socketOption(QAbstractSocket::SocketOption option)
+{
+ if (!d_func()->socketEngine)
+ return QVariant();
+
+ int ret = -1;
+ switch (option) {
+ case LowDelayOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::LowDelayOption);
+ break;
+
+ case KeepAliveOption:
+ ret = d_func()->socketEngine->option(QAbstractSocketEngine::KeepAliveOption);
+ break;
+ }
+ if (ret == -1)
+ return QVariant();
+ else
+ return QVariant(ret);
+}
+
+
/*
Returns the difference between msecs and elapsed. If msecs is -1,
however, -1 is returned.
@@ -1658,13 +1726,13 @@ bool QAbstractSocket::waitForConnected(int msecs)
}
/*!
- This function blocks until data is available for reading and the
+ This function blocks until new data is available for reading and the
\l{QIODevice::}{readyRead()} signal has been emitted. The function
will timeout after \a msecs milliseconds; the default timeout is
30000 milliseconds.
The function returns true if the readyRead() signal is emitted and
- there is data available for reading; otherwise it returns false
+ there is new data available for reading; otherwise it returns false
(if an error occurred or the operation timed out).
\sa waitForBytesWritten()
@@ -2596,7 +2664,7 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QAbstractSocket::SocketError er
debug << "QAbstractSocket::ProxyProtocolError";
break;
default:
- debug << "QAbstractSocket::SocketError(" << int(error) << ")";
+ debug << "QAbstractSocket::SocketError(" << int(error) << ')';
break;
}
return debug;
@@ -2627,7 +2695,7 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QAbstractSocket::SocketState st
debug << "QAbstractSocket::ClosingState";
break;
default:
- debug << "QAbstractSocket::SocketState(" << int(state) << ")";
+ debug << "QAbstractSocket::SocketState(" << int(state) << ')';
break;
}
return debug;
diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h
index c0a71cd..6cc86ef 100644
--- a/src/network/socket/qabstractsocket.h
+++ b/src/network/socket/qabstractsocket.h
@@ -116,6 +116,10 @@ public:
Connection = ConnectedState
#endif
};
+ enum SocketOption {
+ LowDelayOption, // TCP_NODELAY
+ KeepAliveOption // SO_KEEPALIVE
+ };
QAbstractSocket(SocketType socketType, QObject *parent);
virtual ~QAbstractSocket();
@@ -149,6 +153,10 @@ public:
bool setSocketDescriptor(int socketDescriptor, SocketState state = ConnectedState,
OpenMode openMode = ReadWrite);
+ // ### Qt 5: Make virtual?
+ void setSocketOption(QAbstractSocket::SocketOption o, QVariant v);
+ QVariant socketOption(QAbstractSocket::SocketOption o);
+
SocketType socketType() const;
SocketState state() const;
SocketError error() const;
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
index 630fd0a..0d7f84f 100644
--- a/src/network/socket/qabstractsocketengine_p.h
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -92,7 +92,9 @@ public:
SendBufferSocketOption,
AddressReusable,
BindExclusively,
- ReceiveOutOfBandData
+ ReceiveOutOfBandData,
+ LowDelayOption,
+ KeepAliveOption
};
virtual bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) = 0;
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index 334ff1d..bb0915a 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -276,13 +276,30 @@ qint64 QHttpSocketEngine::pendingDatagramSize() const
}
#endif // QT_NO_UDPSOCKET
-int QHttpSocketEngine::option(SocketOption) const
+int QHttpSocketEngine::option(SocketOption option) const
{
+ Q_D(const QHttpSocketEngine);
+ if (d->socket) {
+ // convert the enum and call the real socket
+ if (option == QAbstractSocketEngine::LowDelayOption)
+ return d->socket->socketOption(QAbstractSocket::LowDelayOption).toInt();
+ if (option == QAbstractSocketEngine::KeepAliveOption)
+ return d->socket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
+ }
return -1;
}
-bool QHttpSocketEngine::setOption(SocketOption, int)
+bool QHttpSocketEngine::setOption(SocketOption option, int value)
{
+ Q_D(QHttpSocketEngine);
+ if (d->socket) {
+ // convert the enum and call the real socket
+ if (option == QAbstractSocketEngine::LowDelayOption)
+ d->socket->setSocketOption(QAbstractSocket::LowDelayOption, value);
+ if (option == QAbstractSocketEngine::KeepAliveOption)
+ d->socket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
+ return true;
+ }
return false;
}
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
index 1cdcb70..20291d1 100644
--- a/src/network/socket/qlocalserver.cpp
+++ b/src/network/socket/qlocalserver.cpp
@@ -78,8 +78,6 @@ QT_BEGIN_NAMESPACE
to use it without one. In that case, you must use waitForNewConnection(),
which blocks until either a connection is available or a timeout expires.
- Note that this feature is not supported on Windows 9x.
-
\sa QLocalSocket, QTcpServer
*/
@@ -276,9 +274,17 @@ QLocalSocket *QLocalServer::nextPendingConnection()
if (d->pendingConnections.isEmpty())
return 0;
QLocalSocket *nextSocket = d->pendingConnections.dequeue();
+#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(d->pendingConnections.size()
- <= d->maxPendingConnections);
+ d->socketNotifier->setEnabled(true);
+#else
+ d->connectionEventNotifier->setEnabled(true);
+#endif
#endif
return nextSocket;
}
diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h
index cf91002..acc3eb5 100644
--- a/src/network/socket/qlocalserver.h
+++ b/src/network/socket/qlocalserver.h
@@ -86,15 +86,7 @@ protected:
private:
Q_DISABLE_COPY(QLocalServer)
-#if defined(QT_LOCALSOCKET_TCP)
Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection())
-#elif defined(Q_OS_WIN)
- Q_PRIVATE_SLOT(d_func(), void _q_openSocket(HANDLE handle))
- Q_PRIVATE_SLOT(d_func(), void _q_stoppedListening())
- Q_PRIVATE_SLOT(d_func(), void _q_setError(QAbstractSocket::SocketError error, const QString &errorString))
-#else
- Q_PRIVATE_SLOT(d_func(), void _q_socketActivated())
-#endif
};
#endif // QT_NO_LOCALSERVER
diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h
index d431c19..09f40c2 100644
--- a/src/network/socket/qlocalserver_p.h
+++ b/src/network/socket/qlocalserver_p.h
@@ -63,7 +63,7 @@
# include <qtcpserver.h>
#elif defined(Q_OS_WIN)
# include <qt_windows.h>
-# include <qthread.h>
+# include <private/qwineventnotifier_p.h>
#else
# include <private/qnativesocketengine_p.h>
# include <qsocketnotifier.h>
@@ -71,52 +71,13 @@
QT_BEGIN_NAMESPACE
-#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
-
-/*!
- \internal
- QLocalServerThread exists because Windows does not have a
- way to provide notifications when there is a new connections to
- the server.
- */
-class QLocalServerThread : public QThread
-{
- Q_OBJECT
-
-Q_SIGNALS:
- void connected(HANDLE newSocket);
- void error(QAbstractSocket::SocketError error, const QString &errorString);
-
-public:
- QLocalServerThread(QObject *parent = 0);
- ~QLocalServerThread();
- void closeServer();
-
-public:
- QString setName(const QString &name);
- void run();
- void stop();
- bool makeHandle();
-
- HANDLE gotConnectionEvent;
- QQueue<HANDLE> pendingHandles;
- int maxPendingConnections;
-private:
- HANDLE stopEvent;
- QString fullServerName;
-};
-
-#endif
-
class QLocalServerPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QLocalServer)
public:
QLocalServerPrivate() :
-#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
- inWaitingFunction(false),
-#elif !defined(QT_LOCALSOCKET_TCP)
+#if !defined(QT_LOCALSOCKET_TCP) && !defined(Q_OS_WIN)
listenSocket(-1), socketNotifier(0),
#endif
maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError)
@@ -128,22 +89,26 @@ public:
static bool removeServer(const QString &name);
void closeServer();
void waitForNewConnection(int msec, bool *timedOut);
+ void _q_onNewConnection();
#if defined(QT_LOCALSOCKET_TCP)
- void _q_onNewConnection();
QTcpServer tcpServer;
QMap<quintptr, QTcpSocket*> socketMap;
#elif defined(Q_OS_WIN)
- void _q_openSocket(HANDLE socket);
- void _q_stoppedListening();
- void _q_setError(QAbstractSocket::SocketError error, const QString &errorString);
+ struct Listener {
+ HANDLE handle;
+ OVERLAPPED overlapped;
+ };
+
+ void setError(const QString &function);
+ bool addListener();
- QLocalServerThread waitForConnection;
- bool inWaitingFunction;
+ QList<Listener> listeners;
+ HANDLE eventHandle;
+ QWinEventNotifier *connectionEventNotifier;
#else
void setError(const QString &function);
- void _q_socketActivated();
int listenSocket;
QSocketNotifier *socketNotifier;
diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp
index f3baf9b..01452ea 100644
--- a/src/network/socket/qlocalserver_unix.cpp
+++ b/src/network/socket/qlocalserver_unix.cpp
@@ -43,6 +43,7 @@
#include "qlocalserver_p.h"
#include "qlocalsocket.h"
#include "qlocalsocket_p.h"
+#include "qnet_unix_p.h"
#ifndef QT_NO_LOCALSERVER
@@ -53,6 +54,10 @@
#include <qdir.h>
#include <qdatetime.h>
+#ifdef Q_OS_VXWORKS
+# include <selectLib.h>
+#endif
+
QT_BEGIN_NAMESPACE
void QLocalServerPrivate::init()
@@ -88,7 +93,7 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
serverName = requestedServerName;
// create the unix socket
- listenSocket = qSocket(PF_UNIX, SOCK_STREAM, 0);
+ listenSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0);
if (-1 == listenSocket) {
setError(QLatin1String("QLocalServer::listen"));
closeServer();
@@ -106,8 +111,26 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
::memcpy(addr.sun_path, fullServerName.toLatin1().data(),
fullServerName.toLatin1().size() + 1);
+#ifdef Q_OS_SYMBIAN
+ // In SYMBIAN OS it can currently happen that accept is called twice,
+ // once from waitForNewConnection and once via QSocketNotfier activity
+ //
+ // As an workaround, we set the socket to non blocking so possible
+ // subsequent call to accept will not block in any case
+ //
+ // This change can be removed once more generic fix to select thread
+ // syncronization problem is implemented.
+ int flags = fcntl(listenSocket, F_GETFL, 0);
+ if (-1 == flags
+ || -1 == (fcntl(listenSocket, F_SETFL, flags | O_NONBLOCK))) {
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ return false;
+ }
+#endif
+
// bind
- if(-1 == qBind(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un))) {
+ if(-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un))) {
setError(QLatin1String("QLocalServer::listen"));
// if address is in use already, just close the socket, but do not delete the file
if(errno == EADDRINUSE)
@@ -120,7 +143,7 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
}
// listen for connections
- if (-1 == qListen(listenSocket, 50)) {
+ if (-1 == qt_safe_listen(listenSocket, 50)) {
setError(QLatin1String("QLocalServer::listen"));
closeServer();
listenSocket = -1;
@@ -132,7 +155,7 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
socketNotifier = new QSocketNotifier(listenSocket,
QSocketNotifier::Read, q);
q->connect(socketNotifier, SIGNAL(activated(int)),
- q, SLOT(_q_socketActivated()));
+ q, SLOT(_q_onNewConnection()));
socketNotifier->setEnabled(maxPendingConnections > 0);
return true;
}
@@ -164,7 +187,7 @@ void QLocalServerPrivate::closeServer()
We have received a notification that we can read on the listen socket.
Accept the new socket.
*/
-void QLocalServerPrivate::_q_socketActivated()
+void QLocalServerPrivate::_q_onNewConnection()
{
Q_Q(QLocalServer);
if (-1 == listenSocket)
@@ -172,7 +195,7 @@ void QLocalServerPrivate::_q_socketActivated()
::sockaddr_un addr;
QT_SOCKLEN_T length = sizeof(sockaddr_un);
- int connectedSocket = qAccept(listenSocket, (sockaddr *)&addr, &length);
+ int connectedSocket = qt_safe_accept(listenSocket, (sockaddr *)&addr, &length);
if(-1 == connectedSocket) {
setError(QLatin1String("QLocalSocket::activated"));
closeServer();
@@ -209,7 +232,7 @@ void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
break;
}
if (result > 0)
- _q_socketActivated();
+ _q_onNewConnection();
}
if (timedOut)
*timedOut = (result == 0);
diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp
index 16369f0..93cbe92 100644
--- a/src/network/socket/qlocalserver_win.cpp
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -44,81 +44,26 @@
#include "qlocalsocket.h"
#include <qdebug.h>
-#include <qdatetime.h>
-#include <qcoreapplication.h>
-#include <QMetaType>
// The buffer size need to be 0 otherwise data could be
// lost if the socket that has written data closes the connection
// before it is read. Pipewriter is used for write buffering.
#define BUFSIZE 0
-QT_BEGIN_NAMESPACE
+// ###: This should be a property. Should replace the insane 50 on unix as well.
+#define SYSTEM_MAX_PENDING_SOCKETS 8
-QLocalServerThread::QLocalServerThread(QObject *parent) : QThread(parent),
- maxPendingConnections(1)
-{
- stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- gotConnectionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-}
-
-QLocalServerThread::~QLocalServerThread()
-{
- stop();
- closeServer();
- CloseHandle(stopEvent);
- CloseHandle(gotConnectionEvent);
-}
-
-void QLocalServerThread::stop()
-{
- if (isRunning()) {
- SetEvent(stopEvent);
- wait();
- ResetEvent(stopEvent);
- }
-}
-
-void QLocalServerThread::closeServer()
-{
- while (!pendingHandles.isEmpty())
- CloseHandle(pendingHandles.dequeue());
-}
-
-QString QLocalServerThread::setName(const QString &name)
-{
- QString pipePath = QLatin1String("\\\\.\\pipe\\");
- if (name.startsWith(pipePath))
- fullServerName = name;
- else
- fullServerName = pipePath + name;
- for (int i = pendingHandles.count(); i < maxPendingConnections; ++i)
- if (!makeHandle())
- break;
- return fullServerName;
-}
+QT_BEGIN_NAMESPACE
-bool QLocalServerThread::makeHandle()
+bool QLocalServerPrivate::addListener()
{
- if (pendingHandles.count() >= maxPendingConnections)
- return false;
+ // The object must not change its address once the
+ // contained OVERLAPPED struct is passed to Windows.
+ listeners << Listener();
+ Listener &listener = listeners.last();
- HANDLE handle = INVALID_HANDLE_VALUE;
- QT_WA({
- handle = CreateNamedPipeW(
- (TCHAR*)fullServerName.utf16(), // pipe name
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
- PIPE_TYPE_MESSAGE | // message type pipe
- PIPE_READMODE_MESSAGE | // message-read mode
- PIPE_WAIT, // blocking mode
- PIPE_UNLIMITED_INSTANCES, // max. instances
- BUFSIZE, // output buffer size
- BUFSIZE, // input buffer size
- 3000, // client time-out
- NULL);
- }, {
- handle = CreateNamedPipeA(
- fullServerName.toLocal8Bit().constData(), // pipe name
+ listener.handle = CreateNamedPipe(
+ (const wchar_t *)fullServerName.utf16(), // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
@@ -128,69 +73,44 @@ bool QLocalServerThread::makeHandle()
BUFSIZE, // input buffer size
3000, // client time-out
NULL);
- });
- if (INVALID_HANDLE_VALUE == handle) {
+ if (listener.handle == INVALID_HANDLE_VALUE) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ listeners.removeLast();
return false;
}
- pendingHandles.enqueue(handle);
+
+ memset(&listener.overlapped, 0, sizeof(listener.overlapped));
+ listener.overlapped.hEvent = eventHandle;
+ if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) {
+ switch (GetLastError()) {
+ case ERROR_IO_PENDING:
+ break;
+ case ERROR_PIPE_CONNECTED:
+ SetEvent(eventHandle);
+ break;
+ default:
+ CloseHandle(listener.handle);
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ listeners.removeLast();
+ return false;
+ }
+ } else {
+ Q_ASSERT_X(false, "QLocalServerPrivate::addListener", "The impossible happened");
+ SetEvent(eventHandle);
+ }
return true;
}
-void QLocalServerThread::run()
+void QLocalServerPrivate::setError(const QString &function)
{
- OVERLAPPED op;
- HANDLE handleArray[2];
- memset(&op, 0, sizeof(op));
- handleArray[0] = op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- handleArray[1] = stopEvent;
- HANDLE handle = INVALID_HANDLE_VALUE;
-
- forever {
- if (INVALID_HANDLE_VALUE == handle) {
- makeHandle();
- if (!pendingHandles.isEmpty())
- handle = pendingHandles.dequeue();
- }
- if (INVALID_HANDLE_VALUE == handle) {
- int windowsError = GetLastError();
- QString function = QLatin1String("QLocalServer::run");
- QString errorString = QLocalServer::tr("%1: Unknown error %2").arg(function).arg(windowsError);
- emit error(QAbstractSocket::UnknownSocketError, errorString);
- CloseHandle(handleArray[0]);
- SetEvent(gotConnectionEvent);
- return;
- }
-
- BOOL isConnected = ConnectNamedPipe(handle, &op) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
- if (!isConnected) {
- switch (WaitForMultipleObjects(2, handleArray, FALSE, INFINITE))
- {
- case WAIT_OBJECT_0 + 1:
- CloseHandle(handle);
- CloseHandle(handleArray[0]);
- return;
- }
- }
- emit connected(handle);
- handle = INVALID_HANDLE_VALUE;
- ResetEvent(handleArray[0]);
- SetEvent(gotConnectionEvent);
- }
+ int windowsError = GetLastError();
+ errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError));
+ error = QAbstractSocket::UnknownSocketError;
}
void QLocalServerPrivate::init()
{
- Q_Q(QLocalServer);
- qRegisterMetaType<HANDLE>("HANDLE");
- q->connect(&waitForConnection, SIGNAL(connected(HANDLE)),
- q, SLOT(_q_openSocket(HANDLE)), Qt::QueuedConnection);
- q->connect(&waitForConnection, SIGNAL(finished()),
- q, SLOT(_q_stoppedListening()), Qt::QueuedConnection);
- q->connect(&waitForConnection, SIGNAL(terminated()),
- q, SLOT(_q_stoppedListening()), Qt::QueuedConnection);
- q->connect(&waitForConnection, SIGNAL(error(QAbstractSocket::SocketError, const QString &)),
- q, SLOT(_q_setError(QAbstractSocket::SocketError, const QString &)));
}
bool QLocalServerPrivate::removeServer(const QString &name)
@@ -201,35 +121,71 @@ bool QLocalServerPrivate::removeServer(const QString &name)
bool QLocalServerPrivate::listen(const QString &name)
{
- fullServerName = waitForConnection.setName(name);
- serverName = name;
- waitForConnection.start();
- return true;
-}
+ Q_Q(QLocalServer);
-void QLocalServerPrivate::_q_setError(QAbstractSocket::SocketError e, const QString &eString)
-{
- error = e;
- errorString = eString;
-}
+ QString pipePath = QLatin1String("\\\\.\\pipe\\");
+ if (name.startsWith(pipePath))
+ fullServerName = name;
+ else
+ fullServerName = pipePath + name;
-void QLocalServerPrivate::_q_stoppedListening()
-{
- Q_Q(QLocalServer);
- if (!inWaitingFunction)
- q->close();
+ // Use only one event for all listeners of one socket.
+ // The idea is that listener events are rare, so polling all listeners once in a while is
+ // cheap compared to waiting for N additional events in each iteration of the main loop.
+ eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
+ connectionEventNotifier = new QWinEventNotifier(eventHandle , q);
+ q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection()));
+
+ for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i)
+ if (!addListener())
+ return false;
+ return true;
}
-void QLocalServerPrivate::_q_openSocket(HANDLE handle)
+void QLocalServerPrivate::_q_onNewConnection()
{
Q_Q(QLocalServer);
- q->incomingConnection((int)handle);
+ DWORD dummy;
+
+ // Reset first, otherwise we could reset an event which was asserted
+ // immediately after we checked the conn status.
+ ResetEvent(eventHandle);
+
+ // Testing shows that there is indeed absolutely no guarantee which listener gets
+ // a client connection first, so there is no way around polling all of them.
+ for (int i = 0; i < listeners.size(); ) {
+ HANDLE handle = listeners[i].handle;
+ if (GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE)) {
+ listeners.removeAt(i);
+
+ addListener();
+
+ if (pendingConnections.size() > maxPendingConnections)
+ connectionEventNotifier->setEnabled(false);
+
+ // Make this the last thing so connected slots can wreak the least havoc
+ q->incomingConnection((quintptr)handle);
+ } else {
+ if (GetLastError() != ERROR_IO_INCOMPLETE) {
+ setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection"));
+ closeServer();
+ return;
+ }
+
+ ++i;
+ }
+ }
}
void QLocalServerPrivate::closeServer()
{
- waitForConnection.stop();
- waitForConnection.closeServer();
+ connectionEventNotifier->setEnabled(false); // Otherwise, closed handle is checked before deleter runs
+ connectionEventNotifier->deleteLater();
+ connectionEventNotifier = 0;
+ CloseHandle(eventHandle);
+ for (int i = 0; i < listeners.size(); ++i)
+ CloseHandle(listeners[i].handle);
+ listeners.clear();
}
void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut)
@@ -238,14 +194,12 @@ void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut)
if (!pendingConnections.isEmpty() || !q->isListening())
return;
- DWORD result = WaitForSingleObject(waitForConnection.gotConnectionEvent,
- (msecs == -1) ? INFINITE : msecs);
+ DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs);
if (result == WAIT_TIMEOUT) {
if (timedOut)
*timedOut = true;
} else {
- ResetEvent(waitForConnection.gotConnectionEvent);
- QCoreApplication::instance()->processEvents();
+ _q_onNewConnection();
}
}
diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp
index 32e70ee..54b2be3 100644
--- a/src/network/socket/qlocalsocket.cpp
+++ b/src/network/socket/qlocalsocket.cpp
@@ -63,7 +63,8 @@ QT_BEGIN_NAMESPACE
waitForReadyRead(), waitForBytesWritten(), and waitForDisconnected()
which blocks until the operation is complete or the timeout expires.
- Note that this feature is not supported on Window 9x.
+ Note that this feature is not supported on versions of Windows earlier than
+ Windows XP.
\sa QLocalServer
*/
@@ -102,7 +103,7 @@ QT_BEGIN_NAMESPACE
opened in the mode specified by \a openMode, and enters the socket state
specified by \a socketState.
- Note: It is not possible to initialize two local sockets with the same
+ \note It is not possible to initialize two local sockets with the same
native socket descriptor.
\sa socketDescriptor(), state(), openMode()
@@ -207,10 +208,10 @@ QT_BEGIN_NAMESPACE
Returns true if the socket is valid and ready for use; otherwise
returns false.
- Note: The socket's state must be ConnectedState before reading
+ \note The socket's state must be ConnectedState before reading
and writing can occur.
- \sa state()
+ \sa state(), connectToServer()
*/
/*!
@@ -243,9 +244,9 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool QLocalSocket::waitForConnected(int msec)
+ \fn bool QLocalSocket::waitForConnected(int msecs)
- Waits until the socket is connected, up to \a msec milliseconds. If the
+ Waits until the socket is connected, up to \a msecs milliseconds. If the
connection has been established, this function returns true; otherwise
it returns false. In the case where it returns false, you can call
error() to determine the cause of the error.
@@ -255,7 +256,7 @@ QT_BEGIN_NAMESPACE
\snippet doc/src/snippets/code/src_network_socket_qlocalsocket_unix.cpp 0
- If msecs is -1, this function will not time out.
+ If \a msecs is -1, this function will not time out.
\sa connectToServer(), connected()
*/
@@ -274,7 +275,7 @@ QT_BEGIN_NAMESPACE
\snippet doc/src/snippets/code/src_network_socket_qlocalsocket_unix.cpp 1
- If msecs is -1, this function will not time out.
+ If \a msecs is -1, this function will not time out.
\sa disconnectFromServer(), close()
*/
@@ -309,9 +310,10 @@ QT_BEGIN_NAMESPACE
parameter describes the type of error that occurred.
QLocalSocket::LocalSocketError is not a registered metatype, so for queued
- connections, you will have to register it with Q_DECLARE_METATYPE.
+ connections, you will have to register it with Q_DECLARE_METATYPE() and
+ qRegisterMetaType().
- \sa error(), errorString()
+ \sa error(), errorString(), {Creating Custom Qt Types}
*/
/*!
@@ -321,9 +323,10 @@ QT_BEGIN_NAMESPACE
The \a socketState parameter is the new state.
QLocalSocket::SocketState is not a registered metatype, so for queued
- connections, you will have to register it with Q_DECLARE_METATYPE.
+ connections, you will have to register it with Q_DECLARE_METATYPE() and
+ qRegisterMetaType().
- \sa state()
+ \sa state(), {Creating Custom Qt Types}
*/
/*!
@@ -365,7 +368,7 @@ QString QLocalSocket::serverName() const
/*!
Returns the server path that the socket is connected to.
- Note: This is platform specific
+ \note The return value of this function is platform specific.
\sa connectToServer(), serverName()
*/
@@ -468,7 +471,7 @@ QDebug operator<<(QDebug debug, QLocalSocket::LocalSocketError error)
debug << "QLocalSocket::UnknownSocketError";
break;
default:
- debug << "QLocalSocket::SocketError(" << int(error) << ")";
+ debug << "QLocalSocket::SocketError(" << int(error) << ')';
break;
}
return debug;
@@ -490,7 +493,7 @@ QDebug operator<<(QDebug debug, QLocalSocket::LocalSocketState state)
debug << "QLocalSocket::ClosingState";
break;
default:
- debug << "QLocalSocket::SocketState(" << int(state) << ")";
+ debug << "QLocalSocket::SocketState(" << int(state) << ')';
break;
}
return debug;
diff --git a/src/network/socket/qlocalsocket.h b/src/network/socket/qlocalsocket.h
index 35ae068..7c0fe78 100644
--- a/src/network/socket/qlocalsocket.h
+++ b/src/network/socket/qlocalsocket.h
@@ -134,6 +134,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_notified())
Q_PRIVATE_SLOT(d_func(), void _q_canWrite())
Q_PRIVATE_SLOT(d_func(), void _q_pipeClosed())
+ Q_PRIVATE_SLOT(d_func(), void _q_emitReadyRead())
#else
Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QAbstractSocket::SocketState))
Q_PRIVATE_SLOT(d_func(), void _q_error(QAbstractSocket::SocketError))
diff --git a/src/network/socket/qlocalsocket_p.h b/src/network/socket/qlocalsocket_p.h
index 74ab779..a774cbf 100644
--- a/src/network/socket/qlocalsocket_p.h
+++ b/src/network/socket/qlocalsocket_p.h
@@ -65,6 +65,7 @@
#elif defined(Q_OS_WIN)
# include "private/qwindowspipewriter_p.h"
# include "private/qringbuffer_p.h"
+# include <private/qwineventnotifier_p.h>
#else
# include "private/qnativesocketengine_p.h"
# include <qtcpsocket.h>
@@ -74,43 +75,6 @@
QT_BEGIN_NAMESPACE
-#if !defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
-static inline int qSocket(int af, int socketype, int proto)
-{
- int ret;
- while((ret = qt_socket_socket(af, socketype, proto)) == -1 && errno == EINTR){}
- return ret;
-}
-
-static inline int qBind(int fd, const sockaddr *sa, int len)
-{
- int ret;
- while((ret = QT_SOCKET_BIND(fd, (sockaddr*)sa, len)) == -1 && errno == EINTR){}
- return ret;
-}
-
-static inline int qConnect(int fd, const sockaddr *sa, int len)
-{
- int ret;
- while((ret = QT_SOCKET_CONNECT(fd, (sockaddr*)sa, len)) == -1 && errno == EINTR){}
- return ret;
-}
-
-static inline int qListen(int fd, int backlog)
-{
- int ret;
- while((ret = qt_socket_listen(fd, backlog)) == -1 && errno == EINTR){}
- return ret;
-}
-
-static inline int qAccept(int fd, struct sockaddr *addr, QT_SOCKLEN_T *addrlen)
-{
- int ret;
- while((ret = qt_socket_accept(fd, addr, addrlen)) == -1 && errno == EINTR){}
- return ret;
-}
-#endif //#if !defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
-
#if !defined(Q_OS_WIN) || defined(QT_LOCALSOCKET_TCP)
class QLocalUnixSocket : public QTcpSocket
{
@@ -172,18 +136,23 @@ public:
void _q_notified();
void _q_canWrite();
void _q_pipeClosed();
- qint64 readData(char *data, qint64 maxSize);
- qint64 bytesAvailable();
- bool readFromSocket();
+ void _q_emitReadyRead();
+ DWORD bytesAvailable();
+ void startAsyncRead();
+ void completeAsyncRead();
+ void checkReadyRead();
HANDLE handle;
OVERLAPPED overlapped;
QWindowsPipeWriter *pipeWriter;
qint64 readBufferMaxSize;
QRingBuffer readBuffer;
- QTimer dataNotifier;
+ int actualReadBufferSize;
+ QWinEventNotifier *dataReadNotifier;
QLocalSocket::LocalSocketError error;
- bool readyReadEmitted;
+ bool readSequenceStarted;
+ bool pendingReadyRead;
bool pipeClosed;
+ static const qint64 initialReadBufferSize = 4096;
#else
QLocalUnixSocket unixSocket;
QString generateErrorString(QLocalSocket::LocalSocketError, const QString &function) const;
diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp
index 4b484dd..d3d172b 100644
--- a/src/network/socket/qlocalsocket_unix.cpp
+++ b/src/network/socket/qlocalsocket_unix.cpp
@@ -41,6 +41,7 @@
#include "qlocalsocket.h"
#include "qlocalsocket_p.h"
+#include "qnet_unix_p.h"
#ifndef QT_NO_LOCALSOCKET
@@ -55,6 +56,10 @@
#include <qdir.h>
#include <qdebug.h>
+#ifdef Q_OS_VXWORKS
+# include <selectLib.h>
+#endif
+
#define QT_CONNECT_TIMEOUT 30000
QT_BEGIN_NAMESPACE
@@ -232,12 +237,12 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
}
// create the socket
- if (-1 == (d->connectingSocket = qSocket(PF_UNIX, SOCK_STREAM, 0))) {
+ if (-1 == (d->connectingSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0))) {
d->errorOccurred(UnsupportedSocketOperationError,
QLatin1String("QLocalSocket::connectToServer"));
return;
}
-
+#ifndef Q_OS_SYMBIAN
// set non blocking so we can try to connect and it wont wait
int flags = fcntl(d->connectingSocket, F_GETFL, 0);
if (-1 == flags
@@ -246,6 +251,7 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
QLatin1String("QLocalSocket::connectToServer"));
return;
}
+#endif
// _q_connectToSocket does the actual connecting
d->connectingName = name;
@@ -282,7 +288,7 @@ void QLocalSocketPrivate::_q_connectToSocket()
}
::memcpy(name.sun_path, connectingPathName.toLatin1().data(),
connectingPathName.toLatin1().size() + 1);
- if (-1 == qConnect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) {
+ if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) {
QString function = QLatin1String("QLocalSocket::connectToServer");
switch (errno)
{
@@ -303,7 +309,7 @@ void QLocalSocketPrivate::_q_connectToSocket()
case EAGAIN:
// Try again later, all of the sockets listening are full
if (!delayConnect) {
- delayConnect = new QSocketNotifier(connectingSocket, QSocketNotifier::Write);
+ delayConnect = new QSocketNotifier(connectingSocket, QSocketNotifier::Write, q);
q->connect(delayConnect, SIGNAL(activated(int)), q, SLOT(_q_connectToSocket()));
}
if (!connectTimer) {
@@ -514,9 +520,9 @@ bool QLocalSocket::waitForConnected(int msec)
if (state() != ConnectingState)
return (state() == ConnectedState);
- fd_set readfds;
- FD_ZERO(&readfds);
- FD_SET(d->connectingSocket, &readfds);
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(d->connectingSocket, &fds);
timeval timeout;
timeout.tv_sec = msec / 1000;
@@ -532,7 +538,14 @@ bool QLocalSocket::waitForConnected(int msec)
timer.start();
while (state() == ConnectingState
&& (-1 == msec || timer.elapsed() < msec)) {
- result = ::select(d->connectingSocket + 1, &readfds, 0, 0, &timeout);
+#ifdef Q_OS_SYMBIAN
+ // On Symbian, ready-to-write is signaled when non-blocking socket
+ // connect is finised. Is ready-to-read really used on other
+ // UNIX paltforms when using non-blocking AF_UNIX socket?
+ result = ::select(d->connectingSocket + 1, 0, &fds, 0, &timeout);
+#else
+ result = ::select(d->connectingSocket + 1, &fds, 0, 0, &timeout);
+#endif
if (-1 == result && errno != EINTR) {
d->errorOccurred( QLocalSocket::UnknownSocketError,
QLatin1String("QLocalSocket::waitForConnected"));
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
index 7caddf6..f70a0aa 100644
--- a/src/network/socket/qlocalsocket_win.cpp
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -48,13 +48,13 @@
QT_BEGIN_NAMESPACE
-#define NOTIFYTIMEOUT 100
-
void QLocalSocketPrivate::init()
{
Q_Q(QLocalSocket);
- QObject::connect(&dataNotifier, SIGNAL(timeout()), q, SLOT(_q_notified()));
+ memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ dataReadNotifier = new QWinEventNotifier(overlapped.hEvent, q);
+ q->connect(dataReadNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_notified()));
}
void QLocalSocketPrivate::setErrorString(const QString &function)
@@ -101,8 +101,10 @@ QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
handle(INVALID_HANDLE_VALUE),
pipeWriter(0),
readBufferMaxSize(0),
+ actualReadBufferSize(0),
error(QLocalSocket::UnknownSocketError),
- readyReadEmitted(false),
+ readSequenceStarted(false),
+ pendingReadyRead(false),
pipeClosed(false),
state(QLocalSocket::UnconnectedState)
{
@@ -137,25 +139,14 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
forever {
DWORD permissions = (openMode & QIODevice::ReadOnly) ? GENERIC_READ : 0;
permissions |= (openMode & QIODevice::WriteOnly) ? GENERIC_WRITE : 0;
- QT_WA({
- localSocket = CreateFileW(
- (TCHAR*)d->fullServerName.utf16(), // pipe name
- permissions,
- 0, // no sharing
- NULL, // default security attributes
- OPEN_EXISTING, // opens existing pipe
- FILE_FLAG_OVERLAPPED,
- NULL); // no template file
- }, {
- localSocket = CreateFileA(
- d->fullServerName.toLocal8Bit().constData(), // pipe name
- permissions,
- 0, // no sharing
- NULL, // default security attributes
- OPEN_EXISTING, // opens existing pipe
- FILE_FLAG_OVERLAPPED,
- NULL); // no template file
- });
+ localSocket = CreateFile((const wchar_t *)d->fullServerName.utf16(), // pipe name
+ permissions,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ FILE_FLAG_OVERLAPPED,
+ NULL); // no template file
+
if (localSocket != INVALID_HANDLE_VALUE)
break;
DWORD error = GetLastError();
@@ -165,13 +156,8 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
}
// All pipe instances are busy, so wait until connected or up to 5 seconds.
- QT_WA({
- if (!WaitNamedPipeW((TCHAR*)d->fullServerName.utf16(), 5000))
- break;
- }, {
- if (!WaitNamedPipeA(d->fullServerName.toLocal8Bit().constData(), 5000))
- break;
- });
+ if (!WaitNamedPipe((const wchar_t *)d->fullServerName.utf16(), 5000))
+ break;
}
if (localSocket == INVALID_HANDLE_VALUE) {
@@ -182,7 +168,7 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
// we have a valid handle
d->serverName = name;
- if (setSocketDescriptor((quintptr)localSocket), openMode) {
+ if (setSocketDescriptor((quintptr)localSocket, ConnectedState, openMode)) {
d->handle = localSocket;
emit connected();
}
@@ -192,82 +178,103 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
qint64 QLocalSocket::readData(char *data, qint64 maxSize)
{
Q_D(QLocalSocket);
- if (d->readBuffer.isEmpty()) {
- if (!d->readFromSocket()) {
- if (d->pipeClosed)
- return -1;
- return 0;
- }
- }
- if (!d->dataNotifier.isActive() && d->threadData->eventDispatcher)
- d->dataNotifier.start(NOTIFYTIMEOUT);
-
- if (d->readBuffer.isEmpty())
- return qint64(0);
-
- // If readFromSocket() read data, copy it to its destination.
- if (maxSize == 1) {
+ qint64 readSoFar;
+ // If startAsyncRead() read data, copy it to its destination.
+ if (maxSize == 1 && d->actualReadBufferSize > 0) {
*data = d->readBuffer.getChar();
- return 1;
+ d->actualReadBufferSize--;
+ readSoFar = 1;
+ } else {
+ qint64 bytesToRead = qMin(qint64(d->actualReadBufferSize), maxSize);
+ readSoFar = 0;
+ while (readSoFar < bytesToRead) {
+ const char *ptr = d->readBuffer.readPointer();
+ int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
+ qint64(d->readBuffer.nextDataBlockSize()));
+ memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
+ readSoFar += bytesToReadFromThisBlock;
+ d->readBuffer.free(bytesToReadFromThisBlock);
+ d->actualReadBufferSize -= bytesToReadFromThisBlock;
+ }
}
- qint64 bytesToRead = qMin(qint64(d->readBuffer.size()), maxSize);
- qint64 readSoFar = 0;
- while (readSoFar < bytesToRead) {
- const char *ptr = d->readBuffer.readPointer();
- int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar),
- d->readBuffer.nextDataBlockSize());
- memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
- readSoFar += bytesToReadFromThisBlock;
- d->readBuffer.free(bytesToReadFromThisBlock);
- }
+ if (!d->readSequenceStarted)
+ d->startAsyncRead();
+ d->checkReadyRead();
+
return readSoFar;
}
/*!
\internal
- read from the socket
+ Schedules or cancels a readyRead() emission depending on actual data availability
*/
-qint64 QLocalSocketPrivate::readData(char *data, qint64 maxSize)
+void QLocalSocketPrivate::checkReadyRead()
{
- DWORD bytesRead = 0;
- overlapped.Offset = 0;
- overlapped.OffsetHigh = 0;
- bool success = ReadFile(handle, data, maxSize, &bytesRead, &overlapped);
- if (!success && GetLastError() == ERROR_IO_PENDING)
- if (GetOverlappedResult(handle, &overlapped, &bytesRead, TRUE))
- success = true;
- if (!success) {
- setErrorString(QLatin1String("QLocalSocket::readData"));
- return 0;
+ if (actualReadBufferSize > 0) {
+ if (!pendingReadyRead) {
+ Q_Q(QLocalSocket);
+ QTimer::singleShot(0, q, SLOT(_q_emitReadyRead()));
+ pendingReadyRead = true;
+ }
+ } else {
+ pendingReadyRead = false;
}
- return bytesRead;
}
/*!
\internal
Reads data from the socket into the readbuffer
*/
-bool QLocalSocketPrivate::readFromSocket()
+void QLocalSocketPrivate::startAsyncRead()
{
- qint64 bytesToRead = bytesAvailable();
- if (bytesToRead == 0)
- return false;
+ do {
+ DWORD bytesToRead = bytesAvailable();
+ if (bytesToRead == 0) {
+ // There are no bytes in the pipe but we need to
+ // start the overlapped read with some buffer size.
+ bytesToRead = initialReadBufferSize;
+ }
- if (readBufferMaxSize && bytesToRead
- > (readBufferMaxSize - readBuffer.size()))
- bytesToRead = readBufferMaxSize - readBuffer.size();
+ if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
+ bytesToRead = readBufferMaxSize - readBuffer.size();
+ if (bytesToRead == 0) {
+ // Buffer is full. User must read data from the buffer
+ // before we can read more from the pipe.
+ return;
+ }
+ }
- char *ptr = readBuffer.reserve(bytesToRead);
- qint64 readBytes = readData(ptr, bytesToRead);
- if (readBytes == 0) {
- readBuffer.chop(bytesToRead);
- return false;
+ char *ptr = readBuffer.reserve(bytesToRead);
+
+ readSequenceStarted = true;
+ if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) {
+ completeAsyncRead();
+ } else if (GetLastError() != ERROR_IO_PENDING) {
+ setErrorString(QLatin1String("QLocalSocketPrivate::startAsyncRead"));
+ return;
+ }
+ } while (!readSequenceStarted);
+}
+
+/*!
+ \internal
+ Sets the correct size of the read buffer after a read operation.
+ */
+void QLocalSocketPrivate::completeAsyncRead()
+{
+ ResetEvent(overlapped.hEvent);
+ readSequenceStarted = false;
+
+ DWORD bytesRead;
+ if (!GetOverlappedResult(handle, &overlapped, &bytesRead, TRUE)) {
+ setErrorString(QLatin1String("QLocalSocketPrivate::completeAsyncRead"));
+ return;
}
- readyReadEmitted = false;
- readBuffer.chop(int(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes)));
- return true;
+
+ actualReadBufferSize += bytesRead;
+ readBuffer.truncate(actualReadBufferSize);
}
qint64 QLocalSocket::writeData(const char *data, qint64 maxSize)
@@ -289,11 +296,9 @@ void QLocalSocket::abort()
/*!
The number of bytes available from the pipe
*/
-qint64 QLocalSocketPrivate::bytesAvailable()
+DWORD QLocalSocketPrivate::bytesAvailable()
{
Q_Q(QLocalSocket);
- if (q->state() != QLocalSocket::ConnectedState)
- return 0;
DWORD bytes;
if (PeekNamedPipe(handle, NULL, 0, NULL, &bytes, NULL)) {
return bytes;
@@ -316,7 +321,7 @@ qint64 QLocalSocket::bytesAvailable() const
{
Q_D(const QLocalSocket);
qint64 available = QIODevice::bytesAvailable();
- available += (qint64) d->readBuffer.size();
+ available += (qint64) d->actualReadBufferSize;
return available;
}
@@ -343,7 +348,6 @@ void QLocalSocket::close()
QIODevice::close();
d->state = ClosingState;
emit stateChanged(d->state);
- d->readyReadEmitted = false;
emit readChannelFinished();
d->serverName = QString();
d->fullServerName = QString();
@@ -352,10 +356,13 @@ void QLocalSocket::close()
disconnectFromServer();
return;
}
+ d->readSequenceStarted = false;
+ d->pendingReadyRead = false;
d->pipeClosed = false;
DisconnectNamedPipe(d->handle);
CloseHandle(d->handle);
d->handle = INVALID_HANDLE_VALUE;
+ ResetEvent(d->overlapped.hEvent);
d->state = UnconnectedState;
emit stateChanged(d->state);
emit disconnected();
@@ -363,7 +370,6 @@ void QLocalSocket::close()
delete d->pipeWriter;
d->pipeWriter = 0;
}
- d->dataNotifier.stop();
}
bool QLocalSocket::flush()
@@ -397,12 +403,15 @@ bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
{
Q_D(QLocalSocket);
d->readBuffer.clear();
+ d->actualReadBufferSize = 0;
QIODevice::open(openMode);
d->handle = (int*)socketDescriptor;
d->state = socketState;
emit stateChanged(d->state);
- if (d->threadData->eventDispatcher)
- d->dataNotifier.start(NOTIFYTIMEOUT);
+ if (d->state == ConnectedState && openMode.testFlag(QIODevice::ReadOnly)) {
+ d->startAsyncRead();
+ d->checkReadyRead();
+ }
return true;
}
@@ -416,20 +425,18 @@ void QLocalSocketPrivate::_q_canWrite()
void QLocalSocketPrivate::_q_notified()
{
Q_Q(QLocalSocket);
- if (0 != bytesAvailable()) {
- if (readBufferMaxSize == 0 || readBuffer.size() < readBufferMaxSize) {
- if (!readFromSocket()) {
- return;
- }
- // wait until buffer is cleared before starting again
- if (readBufferMaxSize && readBuffer.size() == readBufferMaxSize) {
- dataNotifier.stop();
- }
- }
- if (!readyReadEmitted) {
- readyReadEmitted = true;
- q->emit readyRead();
- }
+ completeAsyncRead();
+ startAsyncRead();
+ pendingReadyRead = false;
+ emit q->readyRead();
+}
+
+void QLocalSocketPrivate::_q_emitReadyRead()
+{
+ if (pendingReadyRead) {
+ Q_Q(QLocalSocket);
+ pendingReadyRead = false;
+ emit q->readyRead();
}
}
@@ -462,11 +469,15 @@ bool QLocalSocket::waitForDisconnected(int msecs)
Q_D(QLocalSocket);
if (state() == UnconnectedState)
return false;
+ if (!openMode().testFlag(QIODevice::ReadOnly)) {
+ qWarning("QLocalSocket::waitForDisconnected isn't supported for write only pipes.");
+ return false;
+ }
QIncrementalSleepTimer timer(msecs);
forever {
- d->_q_notified();
- if (d->pipeClosed)
- close();
+ d->bytesAvailable(); // to check if PeekNamedPipe fails
+ if (d->pipeClosed)
+ close();
if (state() == UnconnectedState)
return true;
Sleep(timer.nextSleepTime());
@@ -486,22 +497,24 @@ bool QLocalSocket::isValid() const
bool QLocalSocket::waitForReadyRead(int msecs)
{
Q_D(QLocalSocket);
- QIncrementalSleepTimer timer(msecs);
- forever {
- d->_q_notified();
- if (bytesAvailable() > 0) {
- if (!d->readyReadEmitted) {
- d->readyReadEmitted = true;
- emit readyRead();
- }
- return true;
- }
- Sleep(timer.nextSleepTime());
- if (timer.hasTimedOut())
- break;
+ if (bytesAvailable() > 0)
+ return true;
+
+ if (d->state != QLocalSocket::ConnectedState)
+ return false;
+
+ Q_ASSERT(d->readSequenceStarted);
+ DWORD result = WaitForSingleObject(d->overlapped.hEvent, msecs == -1 ? INFINITE : msecs);
+ switch (result) {
+ case WAIT_OBJECT_0:
+ d->_q_notified();
+ return true;
+ case WAIT_TIMEOUT:
+ return false;
}
+ qWarning("QLocalSocket::waitForReadyRead WaitForSingleObject failed with error code %d.", int(GetLastError()));
return false;
}
@@ -511,27 +524,11 @@ bool QLocalSocket::waitForBytesWritten(int msecs)
if (!d->pipeWriter)
return false;
- QIncrementalSleepTimer timer(msecs);
- forever {
- if (d->pipeWriter->hadWritten())
- return true;
-
- if (d->pipeWriter->bytesToWrite() == 0)
- return false;
-
- // Wait for the pipe writer to acknowledge that it has
- // written. This will succeed if either the pipe writer has
- // already written the data, or if it manages to write data
- // within the given timeout.
- if (d->pipeWriter->waitForWrite(0))
- return true;
-
- Sleep(timer.nextSleepTime());
- if (timer.hasTimedOut())
- break;
- }
-
- return false;
+ // Wait for the pipe writer to acknowledge that it has
+ // written. This will succeed if either the pipe writer has
+ // already written the data, or if it manages to write data
+ // within the given timeout.
+ return d->pipeWriter->waitForWrite(msecs);
}
QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index 6cc71e6..3e56995 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -47,7 +47,7 @@
\brief The QNativeSocketEngine class provides low level access to a socket.
\reentrant
- \ingroup io
+ \ingroup network
\inmodule QtNetwork
QtSocketLayer provides basic socket functionality provided by the
@@ -381,7 +381,9 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb
return false;
}
+
// 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");
@@ -911,7 +913,7 @@ bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWri
d_func()->fetchConnectionParameters();
return true;
}
-#endif
+#endif
if (ret == 0) {
if (timedOut)
*timedOut = true;
@@ -1086,7 +1088,10 @@ protected:
bool QExceptionNotifier::event(QEvent *e)
{
if (e->type() == QEvent::SockAct) {
- engine->exceptionNotification();
+ if (engine->state() == QAbstractSocket::ConnectingState)
+ engine->connectionNotification();
+ else
+ engine->exceptionNotification();
return true;
}
return QSocketNotifier::event(e);
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index 42d8145..084775f 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -52,45 +52,20 @@
//
// We mean it.
//
-
#include "QtNetwork/qhostaddress.h"
#include "private/qabstractsocketengine_p.h"
#ifndef Q_OS_WIN
-# include "qplatformdefs.h"
+# include "qplatformdefs.h"
#else
-# include <winsock2.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#ifndef Q_OS_WIN
-// Almost always the same. If not, specify in qplatformdefs.h.
-#if !defined(QT_SOCKOPTLEN_T)
-# define QT_SOCKOPTLEN_T QT_SOCKLEN_T
+# include <winsock2.h>
#endif
-// Tru64 redefines accept -> _accept with _XOPEN_SOURCE_EXTENDED
-static inline int qt_socket_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen)
-{ return ::accept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen)); }
-#if defined(accept)
-# undef accept
+#ifdef Q_OS_SYMBIAN
+#include <private/qeventdispatcher_symbian_p.h>
+#include <unistd.h>
#endif
-// UnixWare 7 redefines listen -> _listen
-static inline int qt_socket_listen(int s, int backlog)
-{ return ::listen(s, backlog); }
-#if defined(listen)
-# undef listen
-#endif
-
-// UnixWare 7 redefines socket -> _socket
-static inline int qt_socket_socket(int domain, int type, int protocol)
-{ return ::socket(domain, type, protocol); }
-#if defined(socket)
-# undef socket
-#endif
-
-#endif
+QT_BEGIN_NAMESPACE
// Use our own defines and structs which we know are correct
# define QT_SS_MAXSIZE 128
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index d30ed93..ec9f103 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -40,8 +40,8 @@
****************************************************************************/
//#define QNATIVESOCKETENGINE_DEBUG
-
#include "qnativesocketengine_p.h"
+#include "private/qnet_unix_p.h"
#include "qiodevice.h"
#include "qhostaddress.h"
#include "qvarlengtharray.h"
@@ -64,6 +64,13 @@
#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
#if defined QNATIVESOCKETENGINE_DEBUG
@@ -100,6 +107,7 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
static void qt_ignore_sigpipe()
{
+#ifndef Q_NO_POSIX_SIGNALS
// Set to ignore SIGPIPE once only.
static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
if (atom.testAndSetRelaxed(0, 1)) {
@@ -108,6 +116,10 @@ static void qt_ignore_sigpipe()
noaction.sa_handler = SIG_IGN;
::sigaction(SIGPIPE, &noaction, 0);
}
+#else
+ // Posix signals are not supported by the underlying platform
+ // so we don't need to ignore sigpipe signal explicitly
+#endif
}
/*
@@ -126,7 +138,7 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po
*addr = tmpAddress;
#ifndef QT_NO_IPV6IFNAME
char scopeid[IFNAMSIZ];
- if (::if_indextoname(s->a6.sin6_scope_id, scopeid) > 0) {
+ if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) {
addr->setScopeId(QLatin1String(scopeid));
} else
#endif
@@ -161,7 +173,11 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
int protocol = AF_INET;
#endif
int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
- int socket = qt_socket_socket(protocol, type, 0);
+#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) {
@@ -188,6 +204,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
// Ensure that the socket is closed on exec*().
::fcntl(socket, F_SETFD, FD_CLOEXEC);
+
socketDescriptor = socket;
return true;
}
@@ -202,6 +219,8 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
return -1;
int n = -1;
+ int level = SOL_SOCKET; // default
+
switch (opt) {
case QNativeSocketEngine::ReceiveBufferSocketOption:
n = SO_RCVBUF;
@@ -221,12 +240,20 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
case QNativeSocketEngine::ReceiveOutOfBandData:
n = SO_OOBINLINE;
break;
+ case QNativeSocketEngine::LowDelayOption:
+ level = IPPROTO_TCP;
+ n = TCP_NODELAY;
+ break;
+ case QNativeSocketEngine::KeepAliveOption:
+ n = SO_KEEPALIVE;
+ break;
}
int v = -1;
QT_SOCKOPTLEN_T len = sizeof(v);
- if (getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1)
+ if (::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
return v;
+
return -1;
}
@@ -241,6 +268,8 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
return false;
int n = 0;
+ int level = SOL_SOCKET; // default
+
switch (opt) {
case QNativeSocketEngine::ReceiveBufferSocketOption:
n = SO_RCVBUF;
@@ -253,6 +282,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
break;
case QNativeSocketEngine::NonBlockingSocketOption: {
// Make the socket nonblocking.
+#if !defined(Q_OS_VXWORKS)
int flags = ::fcntl(socketDescriptor, F_GETFL, 0);
if (flags == -1) {
#ifdef QNATIVESOCKETENGINE_DEBUG
@@ -266,7 +296,19 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
#endif
return false;
}
-
+#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
+ return false;
+ }
+#endif // Q_OS_VXWORKS
return true;
}
case QNativeSocketEngine::AddressReusable:
@@ -281,13 +323,24 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
case QNativeSocketEngine::ReceiveOutOfBandData:
n = SO_OOBINLINE;
break;
+ case QNativeSocketEngine::LowDelayOption:
+ level = IPPROTO_TCP;
+ n = TCP_NODELAY;
+ break;
+ case QNativeSocketEngine::KeepAliveOption:
+ n = SO_KEEPALIVE;
+ break;
}
- return ::setsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, sizeof(v)) == 0;
+ return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0;
}
bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port)
{
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor);
+#endif
+
struct sockaddr_in sockAddrIPv4;
struct sockaddr *sockAddrPtr = 0;
QT_SOCKLEN_T sockAddrSize = 0;
@@ -325,8 +378,11 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
} else {
// unreachable
}
-
- int connectResult = QT_SOCKET_CONNECT(socketDescriptor, sockAddrPtr, sockAddrSize);
+#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:
@@ -430,6 +486,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16
}
int bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize);
+
if (bindResult < 0) {
switch(errno) {
case EADDRINUSE:
@@ -466,7 +523,11 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16
bool QNativeSocketEnginePrivate::nativeListen(int backlog)
{
- if (qt_socket_listen(socketDescriptor, backlog) < 0) {
+#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,
@@ -493,12 +554,19 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog)
int QNativeSocketEnginePrivate::nativeAccept()
{
- int acceptedDescriptor = qt_socket_accept(socketDescriptor, 0, 0);
-#if defined (QNATIVESOCKETENGINE_DEBUG)
- qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);
+#ifdef Q_OS_SYMBIAN
+ int acceptedDescriptor = ::accept(socketDescriptor, 0, 0);
+#else
+ int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0);
#endif
- // Ensure that the socket is closed on exec*()
- ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC);
+ //check if we have vaild descriptor at all
+ if(acceptedDescriptor > 0) {
+ // Ensure that the socket is closed on exec*()
+ ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC);
+ } else {
+ qWarning("QNativeSocketEnginePrivate::nativeAccept() - acceptedDescriptor <= 0");
+ }
+
return acceptedDescriptor;
}
@@ -507,7 +575,11 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
int nbytes = 0;
// gives shorter than true amounts on Unix domain sockets.
qint64 available = 0;
- if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 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)
@@ -542,16 +614,25 @@ 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);
ssize_t recvResult = -1;
+
for (;;) {
// the data written to udpMessagePeekBuffer is discarded, so
// this function is still reentrant although it might not look
// so.
recvResult = ::recv(socketDescriptor, udpMessagePeekBuffer.data(),
- udpMessagePeekBuffer.size(), MSG_PEEK);
+ udpMessagePeekBuffer.size(), MSG_PEEK);
if (recvResult == -1 && errno == EINTR)
continue;
@@ -567,7 +648,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
return qint64(recvResult);
}
-
+#endif
qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize,
QHostAddress *address, quint16 *port)
{
@@ -609,33 +690,34 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
#if !defined(QT_NO_IPV6)
struct sockaddr_in6 sockAddrIPv6;
if (host.protocol() == QAbstractSocket::IPv6Protocol) {
- memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
- sockAddrIPv6.sin6_family = AF_INET6;
- sockAddrIPv6.sin6_port = htons(port);
-
- Q_IPV6ADDR tmp = host.toIPv6Address();
- memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
- sockAddrSize = sizeof(sockAddrIPv6);
- sockAddrPtr = (struct sockaddr *)&sockAddrIPv6;
+ memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
+ sockAddrIPv6.sin6_family = AF_INET6;
+ sockAddrIPv6.sin6_port = htons(port);
+
+ Q_IPV6ADDR tmp = host.toIPv6Address();
+ memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
+ sockAddrSize = sizeof(sockAddrIPv6);
+ sockAddrPtr = (struct sockaddr *)&sockAddrIPv6;
} else
#endif
if (host.protocol() == QAbstractSocket::IPv4Protocol) {
- memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
- sockAddrIPv4.sin_family = AF_INET;
- sockAddrIPv4.sin_port = htons(port);
- sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address());
- sockAddrSize = sizeof(sockAddrIPv4);
- sockAddrPtr = (struct sockaddr *)&sockAddrIPv4;
+ memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
+ sockAddrIPv4.sin_family = AF_INET;
+ sockAddrIPv4.sin_port = htons(port);
+ sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address());
+ sockAddrSize = sizeof(sockAddrIPv4);
+ sockAddrPtr = (struct sockaddr *)&sockAddrIPv4;
}
// ignore the SIGPIPE signal
qt_ignore_sigpipe();
-
- ssize_t sentBytes;
- do {
- sentBytes = ::sendto(socketDescriptor, data, len,
- 0, sockAddrPtr, sockAddrSize);
- } while (sentBytes == -1 && errno == EINTR);
+#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) {
@@ -732,7 +814,12 @@ void QNativeSocketEnginePrivate::nativeClose()
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEngine::nativeClose()");
#endif
+
+#ifdef Q_OS_SYMBIAN
::close(socketDescriptor);
+#else
+ qt_safe_close(socketDescriptor);
+#endif
}
qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
@@ -746,7 +833,12 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
// of an interrupting signal.
ssize_t writtenBytes;
do {
- writtenBytes = ::write(socketDescriptor, data, len);
+#ifdef Q_OS_SYMBIAN
+ writtenBytes = ::write(socketDescriptor, data, len);
+#else
+ writtenBytes = qt_safe_write(socketDescriptor, data, len);
+#endif
+ // writtenBytes = QT_WRITE(socketDescriptor, data, len); ### TODO S60: Should this line be removed or the one above it?
} while (writtenBytes < 0 && errno == EINTR);
if (writtenBytes < 0) {
@@ -788,7 +880,11 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
ssize_t r = 0;
do {
+#ifdef Q_OS_SYMBIAN
r = ::read(socketDescriptor, data, maxSize);
+#else
+ r = qt_safe_read(socketDescriptor, data, maxSize);
+#endif
} while (r == -1 && errno == EINTR);
if (r < 0) {
@@ -806,7 +902,13 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
case EIO:
setError(QAbstractSocket::NetworkError, ReadErrorString);
break;
+#ifdef Q_OS_SYMBIAN
+ case EPIPE:
+#endif
case ECONNRESET:
+#if defined(Q_OS_VXWORKS)
+ case ESHUTDOWN:
+#endif
r = 0;
break;
default:
@@ -833,38 +935,46 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
- QTime timer;
- timer.start();
+#ifdef Q_OS_SYMBIAN
+ fd_set fdexception;
+ FD_ZERO(&fdexception);
+ FD_SET(socketDescriptor, &fdexception);
+#endif
int retval;
- do {
- if (selectForRead)
- retval = select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
- else
- retval = select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
+ 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
- if (retval != -1 || errno != EINTR)
- break;
- if (timeout > 0) {
- // recalculate the timeout
- int t = timeout - timer.elapsed();
- if (t < 0) {
- // oops, timeout turned negative?
- retval = -1;
- break;
+#ifdef Q_OS_SYMBIAN
+ bool selectForExec = false;
+ if(retval != 0) {
+ if(retval < 0) {
+ qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor);
}
-
- tv.tv_sec = t / 1000;
- tv.tv_usec = (t % 1000) * 1000;
+ selectForExec = FD_ISSET(socketDescriptor, &fdexception);
}
- } while (true);
+ if(selectForExec) {
+ qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected exception for fd %d",
+ selectForRead, retval, errno, socketDescriptor);
+ }
+#endif
return retval;
}
int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
- bool *selectForRead, bool *selectForWrite) const
+ bool *selectForRead, bool *selectForWrite) const
{
fd_set fdread;
FD_ZERO(&fdread);
@@ -876,18 +986,48 @@ 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
QTime timer;
timer.start();
- int ret;
do {
- ret = select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
- if (ret != -1 || errno != EINTR)
+ 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 (checkRead)
+ FD_SET(socketDescriptor, &fdread);
+ if (checkWrite)
+ FD_SET(socketDescriptor, &fdwrite);
+
+ if ((ret == -1) && ( errno == ECONNREFUSED || errno == EPIPE ))
+ ret = 1;
+
+ }
+
+ if (ret != -1 || errno != EINTR) {
break;
+ }
if (timeout > 0) {
// recalculate the timeout
@@ -902,11 +1042,13 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
tv.tv_usec = (t % 1000) * 1000;
}
} while (true);
+#endif
+
if (ret <= 0)
return ret;
-
*selectForRead = FD_ISSET(socketDescriptor, &fdread);
*selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
+
return ret;
}
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index b8e6c49..655a18f 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -166,11 +166,11 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxLength)
Extracts the port and address from a sockaddr, and stores them in
\a port and \a addr if they are non-null.
*/
-static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, struct sockaddr *sa, quint16 *port, QHostAddress *address)
+static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt_sockaddr *sa, quint16 *port, QHostAddress *address)
{
#if !defined (QT_NO_IPV6)
- if (sa->sa_family == AF_INET6) {
- qt_sockaddr_in6 *sa6 = (qt_sockaddr_in6 *)sa;
+ if (sa->a.sa_family == AF_INET6) {
+ const qt_sockaddr_in6 *sa6 = &sa->a6;
Q_IPV6ADDR tmp;
for (int i = 0; i < 16; ++i)
tmp.c[i] = sa6->sin6_addr.qt_s6_addr[i];
@@ -182,8 +182,8 @@ static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, struct s
WSANtohs(socketDescriptor, sa6->sin6_port, port);
} else
#endif
- if (sa->sa_family == AF_INET) {
- struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
+ if (sa->a.sa_family == AF_INET) {
+ const sockaddr_in *sa4 = &sa->a4;
unsigned long addr;
WSANtohl(socketDescriptor, sa4->sin_addr.s_addr, &addr);
QHostAddress a;
@@ -362,6 +362,8 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
return -1;
int n = -1;
+ int level = SOL_SOCKET; // default
+
switch (opt) {
case QNativeSocketEngine::ReceiveBufferSocketOption:
n = SO_RCVBUF;
@@ -389,11 +391,18 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
case QNativeSocketEngine::ReceiveOutOfBandData:
n = SO_OOBINLINE;
break;
+ case QNativeSocketEngine::LowDelayOption:
+ level = IPPROTO_TCP;
+ n = TCP_NODELAY;
+ break;
+ case QNativeSocketEngine::KeepAliveOption:
+ n = SO_KEEPALIVE;
+ break;
}
int v = -1;
QT_SOCKOPTLEN_T len = sizeof(v);
- if (getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1)
+ if (getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
return v;
return -1;
}
@@ -409,6 +418,8 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
return false;
int n = 0;
+ int level = SOL_SOCKET; // default
+
switch (opt) {
case QNativeSocketEngine::ReceiveBufferSocketOption:
n = SO_RCVBUF;
@@ -440,9 +451,16 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
case QNativeSocketEngine::ReceiveOutOfBandData:
n = SO_OOBINLINE;
break;
+ case QNativeSocketEngine::LowDelayOption:
+ level = IPPROTO_TCP;
+ n = TCP_NODELAY;
+ break;
+ case QNativeSocketEngine::KeepAliveOption:
+ n = SO_KEEPALIVE;
+ break;
}
- if (::setsockopt(socketDescriptor, SOL_SOCKET, n, (char*)&v, sizeof(v)) != 0) {
+ if (::setsockopt(socketDescriptor, level, n, (char*)&v, sizeof(v)) != 0) {
WS_ERROR_DEBUG(WSAGetLastError());
return false;
}
@@ -463,20 +481,15 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
if (socketDescriptor == -1)
return false;
-#if !defined (QT_NO_IPV6)
- struct qt_sockaddr_storage sa;
-#else
- struct sockaddr_in sa;
-#endif
- struct sockaddr *pSa = (struct sockaddr *) &sa;
-
- QT_SOCKLEN_T sz = sizeof(sa);
+ qt_sockaddr sa;
+ QT_SOCKLEN_T sockAddrSize = sizeof(sa);
+ // Determine local address
memset(&sa, 0, sizeof(sa));
- if (::getsockname(socketDescriptor, pSa, &sz) == 0) {
- qt_socket_getPortAndAddress(socketDescriptor, pSa, &localPort, &localAddress);
+ if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
+ qt_socket_getPortAndAddress(socketDescriptor, &sa, &localPort, &localAddress);
// Determine protocol family
- switch (pSa->sa_family) {
+ switch (sa.a.sa_family) {
case AF_INET:
socketProtocol = QAbstractSocket::IPv4Protocol;
break;
@@ -500,8 +513,8 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
}
memset(&sa, 0, sizeof(sa));
- if (::getpeername(socketDescriptor, pSa, &sz) == 0) {
- qt_socket_getPortAndAddress(socketDescriptor, pSa, &peerPort, &peerAddress);
+ if (::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
+ qt_socket_getPortAndAddress(socketDescriptor, &sa, &peerPort, &peerAddress);
} else {
WS_ERROR_DEBUG(WSAGetLastError());
}
@@ -533,8 +546,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin
struct sockaddr_in sockAddrIPv4;
qt_sockaddr_in6 sockAddrIPv6;
- struct sockaddr *sockAddrPtr;
- QT_SOCKLEN_T sockAddrSize;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
@@ -638,8 +651,8 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16
{
struct sockaddr_in sockAddrIPv4;
qt_sockaddr_in6 sockAddrIPv6;
- struct sockaddr *sockAddrPtr;
- QT_SOCKLEN_T sockAddrSize;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
@@ -766,20 +779,9 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
{
#if !defined(Q_OS_WINCE)
// Create a sockaddr struct and reset its port number.
-#if !defined(QT_NO_IPV6)
- qt_sockaddr_in6 storage;
- qt_sockaddr_in6 *storagePtrIPv6 = reinterpret_cast<qt_sockaddr_in6 *>(&storage);
- storagePtrIPv6->sin6_port = 0;
-#else
- struct sockaddr storage;
-#endif
- sockaddr *storagePtr = reinterpret_cast<sockaddr *>(&storage);
- storagePtr->sa_family = 0;
-
- sockaddr_in *storagePtrIPv4 = reinterpret_cast<sockaddr_in *>(&storage);
- storagePtrIPv4->sin_port = 0;
+ qt_sockaddr storage;
QT_SOCKLEN_T storageSize = sizeof(storage);
-
+ memset(&storage, 0, storageSize);
bool result = false;
@@ -791,7 +793,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
buf.len = sizeof(c);
DWORD available = 0;
DWORD flags = MSG_PEEK;
- int ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, storagePtr, &storageSize,0,0);
+ int ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, &storage.a, &storageSize,0,0);
int err = WSAGetLastError();
if (ret == SOCKET_ERROR && err != WSAEMSGSIZE) {
WS_ERROR_DEBUG(err);
@@ -801,7 +803,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
// notifiers.
flags = 0;
::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags,
- storagePtr, &storageSize, 0, 0);
+ &storage.a, &storageSize, 0, 0);
}
} else {
// If there's no error, or if our buffer was too small, there must be
@@ -893,14 +895,11 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
{
qint64 ret = 0;
-#if !defined(QT_NO_IPV6)
- qt_sockaddr_storage aa;
-#else
- struct sockaddr_in aa;
-#endif
+ qt_sockaddr aa;
memset(&aa, 0, sizeof(aa));
QT_SOCKLEN_T sz;
sz = sizeof(aa);
+
WSABUF buf;
buf.buf = data;
buf.len = maxLength;
@@ -915,23 +914,17 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
DWORD flags = 0;
DWORD bytesRead = 0;
- int wsaRet = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, (struct sockaddr *) &aa, &sz,0,0);
+ int wsaRet = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, &aa.a, &sz,0,0);
if (wsaRet == SOCKET_ERROR) {
int err = WSAGetLastError();
- if (err == WSAEMSGSIZE) {
- // it is ok the buffer was to small if bytesRead is larger than
- // maxLength (win 9x) then assume bytes read is really maxLenth
- ret = qint64(bytesRead) > maxLength ? maxLength : qint64(bytesRead);
- } else {
- WS_ERROR_DEBUG(err);
- setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
- ret = -1;
- }
+ WS_ERROR_DEBUG(err);
+ setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
+ ret = -1;
} else {
ret = qint64(bytesRead);
}
- qt_socket_getPortAndAddress(socketDescriptor, (struct sockaddr *) &aa, port, address);
+ qt_socket_getPortAndAddress(socketDescriptor, &aa, port, address);
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %li, %s, %i) == %li",
@@ -950,41 +943,37 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
qint64 ret = -1;
struct sockaddr_in sockAddrIPv4;
qt_sockaddr_in6 sockAddrIPv6;
- struct sockaddr *sockAddrPtr;
- QT_SOCKLEN_T sockAddrSize;
+ struct sockaddr *sockAddrPtr = 0;
+ QT_SOCKLEN_T sockAddrSize = 0;
qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize);
- if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based && len > qint64(qt_socket_getMaxMsgSize(socketDescriptor))) {
- // WSAEMSGSIZE is not reliable enough (win 9x) so we check max size our self.
- setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
- } else {
- WSABUF buf;
+ WSABUF buf;
#if !defined(Q_OS_WINCE)
- buf.buf = len ? (char*)data : 0;
+ buf.buf = len ? (char*)data : 0;
#else
- char tmp;
- buf.buf = len ? (char*)data : &tmp;
+ char tmp;
+ buf.buf = len ? (char*)data : &tmp;
#endif
- buf.len = len;
- DWORD flags = 0;
- DWORD bytesSent = 0;
- if (::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, sockAddrPtr, sockAddrSize, 0,0) == SOCKET_ERROR) {
- int err = WSAGetLastError();
- WS_ERROR_DEBUG(err);
- switch (err) {
- case WSAEMSGSIZE:
- setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
- break;
- default:
- setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
- break;
- }
- ret = -1;
- } else {
- ret = qint64(bytesSent);
+ buf.len = len;
+ DWORD flags = 0;
+ DWORD bytesSent = 0;
+ if (::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, sockAddrPtr, sockAddrSize, 0,0) == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ WS_ERROR_DEBUG(err);
+ switch (err) {
+ case WSAEMSGSIZE:
+ setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
+ break;
+ default:
+ setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
+ break;
}
+ ret = -1;
+ } else {
+ ret = qint64(bytesSent);
}
+
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %li, \"%s\", %i) == %li", data,
qt_prettyDebug(data, qMin<qint64>(len, 16), len).data(), 0, address.toString().toLatin1().constData(),
diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h
new file mode 100644
index 0000000..5e8ade7
--- /dev/null
+++ b/src/network/socket/qnet_unix_p.h
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNET_UNIX_P_H
+#define QNET_UNIX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of Qt code on Unix. This header file may change from version to
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qcore_unix_p.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#if defined(Q_OS_VXWORKS)
+# include <sockLib.h>
+#endif
+
+// for inet_addr
+#include <netdb.h>
+#include <arpa/inet.h>
+#if defined(Q_OS_VXWORKS)
+# include <hostLib.h>
+#else
+# include <resolv.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// Almost always the same. If not, specify in qplatformdefs.h.
+#if !defined(QT_SOCKOPTLEN_T)
+# define QT_SOCKOPTLEN_T QT_SOCKLEN_T
+#endif
+
+// UnixWare 7 redefines socket -> _socket
+static inline int qt_safe_socket(int domain, int type, int protocol, int flags = 0)
+{
+ Q_ASSERT((flags & ~O_NONBLOCK) == 0);
+
+ register int fd;
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ int newtype = type | SOCK_CLOEXEC;
+ if (flags & O_NONBLOCK)
+ newtype |= SOCK_NONBLOCK;
+ fd = ::socket(domain, newtype, protocol);
+ if (fd != -1 || errno != EINVAL)
+ return fd;
+#endif
+
+ fd = ::socket(domain, type, protocol);
+ if (fd == -1)
+ return -1;
+
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ // set non-block too?
+ if (flags & O_NONBLOCK)
+ ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ return fd;
+}
+
+// Tru64 redefines accept -> _accept with _XOPEN_SOURCE_EXTENDED
+static inline int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen, int flags = 0)
+{
+ Q_ASSERT((flags & ~O_NONBLOCK) == 0);
+
+ register int fd;
+#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ // use accept4
+ int sockflags = SOCK_CLOEXEC;
+ if (flags & O_NONBLOCK)
+ sockflags |= SOCK_NONBLOCK;
+ fd = ::accept4(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen), sockflags);
+ if (fd != -1 || !(errno == ENOSYS || errno == EINVAL))
+ return fd;
+#endif
+
+ fd = ::accept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen));
+ if (fd == -1)
+ return -1;
+
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ // set non-block too?
+ if (flags & O_NONBLOCK)
+ ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ return fd;
+}
+
+// UnixWare 7 redefines listen -> _listen
+static inline int qt_safe_listen(int s, int backlog)
+{
+ return ::listen(s, backlog);
+}
+
+static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SOCKLEN_T addrlen)
+{
+ register int ret;
+ // Solaris e.g. expects a non-const 2nd parameter
+ EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen));
+ return ret;
+}
+#undef QT_SOCKET_CONNECT
+#define QT_SOCKET_CONNECT qt_safe_connect
+
+#if defined(socket)
+# undef socket
+#endif
+#if defined(accept)
+# undef accept
+#endif
+#if defined(listen)
+# undef listen
+#endif
+
+// VxWorks' headers specify 'int' instead of '...' for the 3rd ioctl() parameter.
+template <typename T>
+static inline int qt_safe_ioctl(int sockfd, int request, T arg)
+{
+#ifdef Q_OS_VXWORKS
+ return ::ioctl(sockfd, request, (int) arg);
+#else
+ return ::ioctl(sockfd, request, arg);
+#endif
+}
+
+// VxWorks' headers do not specify any const modifiers
+static inline in_addr_t qt_safe_inet_addr(const char *cp)
+{
+#ifdef Q_OS_VXWORKS
+ return ::inet_addr((char *) cp);
+#else
+ return ::inet_addr(cp);
+#endif
+}
+
+// VxWorks' headers do not specify any const modifiers
+static inline int qt_safe_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *to, QT_SOCKLEN_T tolen)
+{
+#ifdef MSG_NOSIGNAL
+ flags |= MSG_NOSIGNAL;
+#endif
+
+ register int ret;
+#ifdef Q_OS_VXWORKS
+ EINTR_LOOP(ret, ::sendto(sockfd, (char *) buf, len, flags, (struct sockaddr *) to, tolen));
+#else
+ EINTR_LOOP(ret, ::sendto(sockfd, buf, len, flags, to, tolen));
+#endif
+ return ret;
+}
+
+QT_END_NAMESPACE
+
+#endif // QNET_UNIX_P_H
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 431459f..ed84533 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -59,7 +59,11 @@
QT_BEGIN_NAMESPACE
+#ifdef Q_OS_SYMBIAN
+static const int MaxWriteBufferSize = 4*1024;
+#else
static const int MaxWriteBufferSize = 128*1024;
+#endif
//#define QSOCKS5SOCKETLAYER_DEBUG
@@ -153,7 +157,7 @@ static inline QString dump(const QByteArray &) { return QString(); }
*/
static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf)
{
- QSOCKS5_DEBUG << "setting [" << address << ":" << port << "]";
+ QSOCKS5_DEBUG << "setting [" << address << ':' << port << ']';
union {
quint16 port;
@@ -186,7 +190,7 @@ static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, qui
*/
static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 port, QByteArray *pBuf)
{
- QSOCKS5_DEBUG << "setting [" << hostname << ":" << port << "]";
+ QSOCKS5_DEBUG << "setting [" << hostname << ':' << port << ']';
QByteArray encodedHostName = QUrl::toAce(hostname);
QByteArray &buf = *pBuf;
@@ -265,7 +269,7 @@ static bool qt_socks5_get_host_address_and_port(const QByteArray &buf, QHostAddr
}
if (ret) {
- QSOCKS5_DEBUG << "got [" << address << ":" << port << "]";
+ QSOCKS5_DEBUG << "got [" << address << ':' << port << ']';
*pAddress = address;
*pPort = port;
*pPos = pos;
@@ -1124,7 +1128,7 @@ bool QSocks5SocketEngine::connectInternal()
bool QSocks5SocketEngine::connectToHost(const QHostAddress &address, quint16 port)
{
Q_D(QSocks5SocketEngine);
- QSOCKS5_DEBUG << "connectToHost" << address << ":" << port;
+ QSOCKS5_DEBUG << "connectToHost" << address << ':' << port;
setPeerAddress(address);
setPeerPort(port);
@@ -1379,7 +1383,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port)
//### reset and error
return false;
}
- QSOCKS5_DEBUG << "udp actual address and port" << d->localAddress << ":" << d->localPort;
+ QSOCKS5_DEBUG << "udp actual address and port" << d->localAddress << ':' << d->localPort;
return true;
#endif // QT_NO_UDPSOCKET
}
@@ -1478,7 +1482,7 @@ qint64 QSocks5SocketEngine::bytesAvailable() const
qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
{
Q_D(QSocks5SocketEngine);
- QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ")";
+ QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ')';
if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
if (d->connectData->readBuffer.size() == 0) {
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
@@ -1621,14 +1625,28 @@ qint64 QSocks5SocketEngine::pendingDatagramSize() const
int QSocks5SocketEngine::option(SocketOption option) const
{
- Q_UNUSED(option);
+ Q_D(const QSocks5SocketEngine);
+ if (d->data && d->data->controlSocket) {
+ // convert the enum and call the real socket
+ if (option == QAbstractSocketEngine::LowDelayOption)
+ return d->data->controlSocket->socketOption(QAbstractSocket::LowDelayOption).toInt();
+ if (option == QAbstractSocketEngine::KeepAliveOption)
+ return d->data->controlSocket->socketOption(QAbstractSocket::KeepAliveOption).toInt();
+ }
return -1;
}
bool QSocks5SocketEngine::setOption(SocketOption option, int value)
{
- Q_UNUSED(option);
- Q_UNUSED(value);
+ Q_D(QSocks5SocketEngine);
+ if (d->data && d->data->controlSocket) {
+ // convert the enum and call the real socket
+ if (option == QAbstractSocketEngine::LowDelayOption)
+ d->data->controlSocket->setSocketOption(QAbstractSocket::LowDelayOption, value);
+ if (option == QAbstractSocketEngine::KeepAliveOption)
+ d->data->controlSocket->setSocketOption(QAbstractSocket::KeepAliveOption, value);
+ return true;
+ }
return false;
}
@@ -1766,7 +1784,7 @@ void QSocks5SocketEngine::setReadNotificationEnabled(bool enable)
{
Q_D(QSocks5SocketEngine);
- QSOCKS5_Q_DEBUG << "setReadNotificationEnabled(" << enable << ")";
+ QSOCKS5_Q_DEBUG << "setReadNotificationEnabled(" << enable << ')';
bool emitSignal = false;
if (!d->readNotificationEnabled
@@ -1830,9 +1848,9 @@ QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socke
QSOCKS5_DEBUG << "not proxying";
return 0;
}
- QSocks5SocketEngine *engine = new QSocks5SocketEngine(parent);
+ QScopedPointer<QSocks5SocketEngine> engine(new QSocks5SocketEngine(parent));
engine->setProxy(proxy);
- return engine;
+ return engine.take();
}
QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(int socketDescriptor, QObject *parent)
diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp
index 9f49d01..646987a 100644
--- a/src/network/socket/qtcpserver.cpp
+++ b/src/network/socket/qtcpserver.cpp
@@ -46,7 +46,7 @@
\brief The QTcpServer class provides a TCP-based server.
\reentrant
- \ingroup io
+ \ingroup network
\inmodule QtNetwork
This class makes it possible to accept incoming TCP connections.
@@ -354,7 +354,12 @@ void QTcpServer::close()
if (d->socketEngine) {
d->socketEngine->close();
- d->socketEngine->deleteLater();
+ QT_TRY {
+ d->socketEngine->deleteLater();
+ } QT_CATCH(const std::bad_alloc &) {
+ // in out of memory situations, the socketEngine
+ // will be deleted in ~QTcpServer (it's a child-object of this)
+ }
d->socketEngine = 0;
}
diff --git a/src/network/socket/qtcpsocket.cpp b/src/network/socket/qtcpsocket.cpp
index 2770615..e04231c 100644
--- a/src/network/socket/qtcpsocket.cpp
+++ b/src/network/socket/qtcpsocket.cpp
@@ -47,7 +47,7 @@
\brief The QTcpSocket class provides a TCP socket.
\reentrant
- \ingroup io
+ \ingroup network
\inmodule QtNetwork
TCP (Transmission Control Protocol) is a reliable,
@@ -60,10 +60,10 @@
\bold{Note:} TCP sockets cannot be opened in QIODevice::Unbuffered mode.
- \sa QTcpServer, QUdpSocket, QFtp, QHttp, {Fortune Server Example},
- {Fortune Client Example}, {Threaded Fortune Server Example},
- {Blocking Fortune Client Example}, {Loopback Example},
- {Torrent Example}
+ \sa QTcpServer, QUdpSocket, QFtp, QNetworkAccessManager,
+ {Fortune Server Example}, {Fortune Client Example},
+ {Threaded Fortune Server Example}, {Blocking Fortune Client Example},
+ {Loopback Example}, {Torrent Example}
*/
#include "qlist.h"
diff --git a/src/network/socket/qtcpsocket.h b/src/network/socket/qtcpsocket.h
index d6fed15..3005faf 100644
--- a/src/network/socket/qtcpsocket.h
+++ b/src/network/socket/qtcpsocket.h
@@ -43,6 +43,7 @@
#define QTCPSOCKET_H
#include <QtNetwork/qabstractsocket.h>
+#include <QtCore/qvariant.h>
QT_BEGIN_HEADER
diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp
index 858e135..235003a 100644
--- a/src/network/socket/qudpsocket.cpp
+++ b/src/network/socket/qudpsocket.cpp
@@ -46,7 +46,7 @@
\reentrant
\brief The QUdpSocket class provides a UDP socket.
- \ingroup io
+ \ingroup network
\inmodule QtNetwork
UDP (User Datagram Protocol) is a lightweight, unreliable,
@@ -95,6 +95,13 @@
This enum describes the different flags you can pass to modify the
behavior of QUdpSocket::bind().
+ \note On Symbian OS bind flags behaviour depends on process capabilties.
+ If process has NetworkControl capability, the bind attempt with
+ ReuseAddressHint will always succeed even if the address and port is already
+ bound by another socket with any flags. If process does not have
+ NetworkControl capability, the bind attempt to address and port already
+ bound by another socket will always fail.
+
\value ShareAddress Allow other services to bind to the same address
and port. This is useful when multiple processes share
the load of a single service by listening to the same address and port
@@ -350,6 +357,9 @@ qint64 QUdpSocket::pendingDatagramSize() const
fragmented by the IP layer before arriving at their final
destination.
+ \warning In S60 5.0 and earlier versions, the writeDatagram return
+ value is not reliable for large datagrams.
+
\warning Calling this function on a connected UDP socket may
result in an error and no packet being sent. If you are using a
connected socket, use write() to send datagrams.
@@ -368,6 +378,16 @@ 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) {
@@ -380,7 +400,7 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre
return sent;
}
-/*!
+/*!
\fn qint64 QUdpSocket::writeDatagram(const QByteArray &datagram,
const QHostAddress &host, quint16 port)
\overload
diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri
index b1fe64a..2bafe13 100644
--- a/src/network/socket/socket.pri
+++ b/src/network/socket/socket.pri
@@ -28,7 +28,8 @@ SOURCES += socket/qabstractsocketengine.cpp \
unix:SOURCES += socket/qnativesocketengine_unix.cpp \
socket/qlocalsocket_unix.cpp \
socket/qlocalserver_unix.cpp
-
+unix:HEADERS += \
+ socket/qnet_unix_p.h
win32:SOURCES += socket/qnativesocketengine_win.cpp \
socket/qlocalsocket_win.cpp \
@@ -42,5 +43,3 @@ wince*: {
DEFINES += QT_LOCALSOCKET_TCP
}
-
-