diff options
author | Jason Barron <jbarron@trolltech.com> | 2009-07-24 09:45:33 (GMT) |
---|---|---|
committer | Jason Barron <jbarron@trolltech.com> | 2009-07-27 13:04:30 (GMT) |
commit | 3643028959f0b38350e57e60ba4000435b75e592 (patch) | |
tree | c129e4dee11487abd437ab8ebd993ba261e06fa6 /src/network/socket | |
parent | cf66c667a97c0079141eb3f2d9e997b7378ae792 (diff) | |
parent | c36139c665e61866aff4bf8572890a735167a7d0 (diff) | |
download | Qt-3643028959f0b38350e57e60ba4000435b75e592.zip Qt-3643028959f0b38350e57e60ba4000435b75e592.tar.gz Qt-3643028959f0b38350e57e60ba4000435b75e592.tar.bz2 |
Merge commit 'qt/master-stable'
Conflicts:
configure.exe
qmake/Makefile.unix
qmake/generators/makefile.cpp
src/corelib/global/qglobal.h
src/corelib/kernel/kernel.pri
src/corelib/kernel/qcoreevent.cpp
src/corelib/kernel/qsharedmemory_unix.cpp
src/gui/graphicsview/qgraphicsscene.cpp
src/gui/kernel/qaction.cpp
src/gui/kernel/qaction.h
src/gui/kernel/qaction_p.h
src/gui/kernel/qapplication.cpp
src/gui/kernel/qapplication.h
src/gui/kernel/qwidget.cpp
src/gui/kernel/qwidget.h
src/gui/kernel/qwidget_mac.mm
src/gui/painting/qgraphicssystemfactory.cpp
src/gui/styles/qwindowsstyle.cpp
src/gui/text/qfontengine_qpf.cpp
src/gui/widgets/qabstractscrollarea_p.h
src/network/access/qnetworkaccessdebugpipebackend.cpp
src/network/socket/qlocalsocket_unix.cpp
src/network/socket/qnativesocketengine_p.h
src/network/socket/qnativesocketengine_unix.cpp
src/openvg/qpaintengine_vg.cpp
tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp
tests/auto/qcssparser/qcssparser.pro
tests/auto/qdir/tst_qdir.cpp
tests/auto/qfile/tst_qfile.cpp
tests/auto/qobject/tst_qobject.cpp
tests/auto/qpathclipper/qpathclipper.pro
tests/auto/qprocess/tst_qprocess.cpp
tests/auto/qsettings/tst_qsettings.cpp
tests/auto/qsharedpointer/qsharedpointer.pro
tests/auto/qsqlquerymodel/qsqlquerymodel.pro
tests/auto/qsqlrelationaltablemodel/qsqlrelationaltablemodel.pro
tests/auto/qsqltablemodel/qsqltablemodel.pro
tests/auto/qsqlthread/qsqlthread.pro
tests/auto/qwidget/tst_qwidget.cpp
Diffstat (limited to 'src/network/socket')
20 files changed, 621 insertions, 415 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index f45b77d..9545291 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -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" @@ -1549,6 +1565,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. diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index ed187e5..50a38bb 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 b784f65..39c00cc 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 7bac1f2..84b7c14 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; } @@ -454,6 +471,7 @@ void QHttpSocketEngine::slotSocketConnected() data += path; data += " HTTP/1.1\r\n"; data += "Proxy-Connection: keep-alive\r\n" + "User-Agent: Mozilla/5.0\r\n" "Host: " + peerAddress + "\r\n"; QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator); //qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1); diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index aa32763..7bb0b01 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 */ diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index e4bc1aa..01732e4 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 @@ -88,7 +89,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(); @@ -125,7 +126,7 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) #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) @@ -138,7 +139,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; @@ -190,7 +191,7 @@ void QLocalServerPrivate::_q_onNewConnection() ::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(); diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp index 6af5ca5..c4f8f3c 100644 --- a/src/network/socket/qlocalserver_win.cpp +++ b/src/network/socket/qlocalserver_win.cpp @@ -62,9 +62,8 @@ bool QLocalServerPrivate::addListener() listeners << Listener(); Listener &listener = listeners.last(); - QT_WA({ - listener.handle = CreateNamedPipeW( - (TCHAR*)fullServerName.utf16(), // 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 @@ -74,19 +73,7 @@ bool QLocalServerPrivate::addListener() BUFSIZE, // input buffer size 3000, // client time-out NULL); - }, { - listener.handle = CreateNamedPipeA( - fullServerName.toLocal8Bit().constData(), // 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); - }); + if (listener.handle == INVALID_HANDLE_VALUE) { setError(QLatin1String("QLocalServerPrivate::addListener")); listeners.removeLast(); diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index acacdf2..7809226 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() */ diff --git a/src/network/socket/qlocalsocket.h b/src/network/socket/qlocalsocket.h index 417671a..4bff62e 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 24b5dd6..2dae7d9 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 cba5a7f..9f39bef 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 @@ -232,7 +233,7 @@ 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; @@ -283,7 +284,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)) && errno != EISCONN) { + if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) { QString function = QLatin1String("QLocalSocket::connectToServer"); switch (errno) { diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp index 2b8d7e5..3a36ac0 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_p.h b/src/network/socket/qnativesocketengine_p.h index a8d7fff..9136faa 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -67,29 +67,6 @@ 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 -#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 -#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 - static inline int qt_socket_connect(int s, const struct sockaddr * addrptr, socklen_t namelen) { return ::connect(s, addrptr, namelen); @@ -216,17 +193,6 @@ static inline int qt_socket_setsockopt(int socket, int level, int optname, void # undef setsockopt #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 - // Use our own defines and structs which we know are correct # define QT_SS_MAXSIZE 128 # define QT_SS_ALIGNSIZE (sizeof(qint64)) diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 58adaff..ea8e756 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -41,6 +41,7 @@ //#define QNATIVESOCKETENGINE_DEBUG #include "qnativesocketengine_p.h" +#include "private/qnet_unix_p.h" #include "qiodevice.h" #include "qhostaddress.h" #include "qvarlengtharray.h" @@ -67,6 +68,8 @@ #include <ctype.h> #endif +#include <netinet/tcp.h> + QT_BEGIN_NAMESPACE #if defined QNATIVESOCKETENGINE_DEBUG @@ -169,7 +172,7 @@ 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); + int socket = qt_safe_socket(protocol, type, 0); if (socket <= 0) { switch (errno) { @@ -211,6 +214,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; @@ -230,11 +235,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 (qt_socket_getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1) + if (qt_socket_getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1) return v; return -1; @@ -251,6 +263,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; @@ -281,7 +295,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt } case QNativeSocketEngine::AddressReusable: #ifdef Q_OS_SYMBIAN - n = SO_REUSEADDR; + n = SO_REUSEADDR; #elif SO_REUSEPORT n = SO_REUSEPORT; #else @@ -293,10 +307,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; } - return qt_socket_setsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, sizeof(v)) == 0; - + return qt_socket_setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0; } bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) @@ -485,7 +505,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 bool QNativeSocketEnginePrivate::nativeListen(int backlog) { - if (qt_socket_listen(socketDescriptor, backlog) < 0) { + if (qt_safe_listen(socketDescriptor, backlog) < 0) { switch (errno) { case EADDRINUSE: setError(QAbstractSocket::AddressInUseError, @@ -512,7 +532,7 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog) int QNativeSocketEnginePrivate::nativeAccept() { - int acceptedDescriptor = qt_socket_accept(socketDescriptor, 0, 0); + int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0); #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor); #endif @@ -533,7 +553,7 @@ 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) + if (qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0) available = (qint64) nbytes; #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -571,7 +591,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const #ifdef Q_OS_SYMBIAN qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const { - size_t nbytes = 0; + size_t nbytes = 0; qt_socket_ioctl(socketDescriptor, E32IONREAD, (char *) &nbytes); return qint64(nbytes-28); } @@ -579,7 +599,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const { QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192); - ssize_t recvResult = -1; + ssize_t recvResult = -1; for (;;) { // the data written to udpMessagePeekBuffer is discarded, so @@ -595,7 +615,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2); } - + #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %i", recvResult); #endif @@ -667,8 +687,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l qt_ignore_sigpipe(); ssize_t sentBytes; do { - sentBytes = qt_socket_sendto(socketDescriptor, data, len, - 0, sockAddrPtr, sockAddrSize); + sentBytes = qt_safe_sendto(socketDescriptor, data, len, + 0, sockAddrPtr, sockAddrSize); } while (sentBytes == -1 && errno == EINTR); if (sentBytes < 0) { @@ -870,32 +890,27 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; -#ifdef Q_OS_SYMBIAN +#ifdef Q_OS_SYMBIAN fd_set fdexec; FD_ZERO(&fdexec); - FD_SET(socketDescriptor, &fdexec); + FD_SET(socketDescriptor, &fdexec); #endif - QTime timer; - timer.start(); - int retval; - do { - if (selectForRead) + if (selectForRead) #ifndef Q_OS_SYMBIAN - retval = qt_socket_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); -#else - retval = qt_socket_select(socketDescriptor + 1, &fds, 0, &fdexec, timeout < 0 ? 0 : &tv); -#endif - else + retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); +#else + retval = qt_safe_select(socketDescriptor + 1, &fds, 0, &fdexec, timeout < 0 ? 0 : &tv); +#endif + else #ifndef Q_OS_SYMBIAN - retval = qt_socket_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); -#else - retval = qt_socket_select(socketDescriptor + 1, 0, &fds, &fdexec, timeout < 0 ? 0 : &tv); -#endif + retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); +#else + retval = qt_safe_select(socketDescriptor + 1, 0, &fds, &fdexec, timeout < 0 ? 0 : &tv); +#endif - -#ifdef Q_OS_SYMBIAN +#ifdef Q_OS_SYMBIAN bool selectForExec = false; if(retval != 0) { if(retval < 0) { @@ -905,27 +920,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co } if(selectForExec) { qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected expectfds ready in fd %d", - selectForRead, retval, errno, socketDescriptor); + selectForRead, retval, errno, socketDescriptor); } -#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; - } - - tv.tv_sec = t / 1000; - tv.tv_usec = (t % 1000) * 1000; - } - } while (true); +#endif return retval; } @@ -942,25 +939,25 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c FD_ZERO(&fdwrite); if (checkWrite) FD_SET(socketDescriptor, &fdwrite); - -#ifdef Q_OS_SYMBIAN + +#ifdef Q_OS_SYMBIAN fd_set fdexec; FD_ZERO(&fdexec); - FD_SET(socketDescriptor, &fdexec); -#endif + FD_SET(socketDescriptor, &fdexec); +#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 { -#ifndef Q_OS_SYMBIAN - ret = qt_socket_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); -#else ret = qt_socket_select(socketDescriptor + 1, &fdread, &fdwrite, &fdexec, timeout < 0 ? 0 : &tv); bool selectForExec = false; if(ret != 0) { @@ -970,18 +967,18 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c selectForExec = FD_ISSET(socketDescriptor, &fdexec); } 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 )) + 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; - + } -#endif + if (ret != -1 || errno != EINTR) { break; } @@ -999,6 +996,8 @@ 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); diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 59a3b60..f0b9f0b 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..03ed3b4 --- /dev/null +++ b/src/network/socket/qnet_unix_p.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** 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://www.qtsoftware.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> + +// for inet_addr +#include <netdb.h> +#include <arpa/inet.h> +#include <resolv.h> + + +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; +#ifdef SOCK_CLOEXEC + 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 + +template <typename T> +static inline int qt_safe_ioctl(int sockfd, int request, T arg) +{ + return ::ioctl(sockfd, request, arg); +} + +static inline in_addr_t qt_safe_inet_addr(const char *cp) +{ + return ::inet_addr(cp); +} + +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; + EINTR_LOOP(ret, ::sendto(sockfd, buf, len, flags, to, tolen)); + 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 46a45c6..25873c6 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -1625,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; } diff --git a/src/network/socket/qtcpsocket.h b/src/network/socket/qtcpsocket.h index 81f81de..4e1003a 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 61b28ba..32f72df 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -70,6 +70,9 @@ pendingDatagramSize() to obtain the size of the first pending datagram, and readDatagram() to read it. + \note An incoming datagram should be read when you receive the readyRead() + signal, otherwise this signal will not be emitted for the next datagram. + Example: \snippet doc/src/snippets/code/src_network_socket_qudpsocket.cpp 0 diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index dad43d2..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 \ |