diff options
Diffstat (limited to 'src/network')
20 files changed, 257 insertions, 189 deletions
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 483589b..7a616aa 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -201,6 +201,7 @@ bool QHttpNetworkReply::isFinished() const QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) : QHttpNetworkHeaderPrivate(newUrl), state(NothingDoneState), statusCode(100), majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0), + chunkedTransferEncoding(0), currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false), autoDecompress(false), responseData(0), requestIsPrepared(false) { @@ -506,6 +507,9 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket) state = ReadingDataState; fragment.clear(); // next fragment bodyLength = contentLength(); // cache the length + + // cache isChunked() since it is called often + chunkedTransferEncoding = headerField("transfer-encoding").toLower().contains("chunked"); } return bytes; } @@ -546,7 +550,7 @@ void QHttpNetworkReplyPrivate::parseHeader(const QByteArray &header) bool QHttpNetworkReplyPrivate::isChunked() { - return headerField("transfer-encoding").toLower().contains("chunked"); + return chunkedTransferEncoding; } bool QHttpNetworkReplyPrivate::connectionCloseEnabled() diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index b86cfaa..5eb70ce 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -198,6 +198,7 @@ public: qint64 contentRead; qint64 totalProgress; QByteArray fragment; // used for header, status, chunk header etc, not for reply data + bool chunkedTransferEncoding; qint64 currentChunkSize; qint64 currentChunkRead; QPointer<QHttpNetworkConnection> connection; diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index 1b0d9f5..e807d29 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -442,6 +442,31 @@ QNetworkReply::NetworkError QNetworkReply::error() const } /*! + \since 4.6 + + Returns true when the reply has finished or was aborted. + + \sa isRunning() +*/ +bool QNetworkReply::isFinished() const +{ + return d_func()->isFinished(); +} + +/*! + \since 4.6 + + Returns true when the request is still processing and the + reply has not finished or was aborted yet. + + \sa isFinished() +*/ +bool QNetworkReply::isRunning() const +{ + return !isFinished(); +} + +/*! Returns the URL of the content downloaded or uploaded. Note that the URL may be different from that of the original request. diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index 7cb082f..30e89f1 100644 --- a/src/network/access/qnetworkreply.h +++ b/src/network/access/qnetworkreply.h @@ -116,6 +116,8 @@ public: QNetworkAccessManager::Operation operation() const; QNetworkRequest request() const; NetworkError error() const; + bool isFinished() const; + bool isRunning() const; QUrl url() const; // "cooked" headers diff --git a/src/network/access/qnetworkreply_p.h b/src/network/access/qnetworkreply_p.h index c8543f0..b51e3fb 100644 --- a/src/network/access/qnetworkreply_p.h +++ b/src/network/access/qnetworkreply_p.h @@ -75,6 +75,8 @@ public: static inline void setManager(QNetworkReply *reply, QNetworkAccessManager *manager) { reply->d_func()->manager = manager; } + virtual bool isFinished() const { return false; } + Q_DECLARE_PUBLIC(QNetworkReply) }; diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index de39970..55b8b7f 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -91,6 +91,8 @@ void QNetworkReplyImplPrivate::_q_startOperation() void QNetworkReplyImplPrivate::_q_copyReadyRead() { Q_Q(QNetworkReplyImpl); + if (state != Working) + return; if (!copyDevice || !q->isOpen()) return; @@ -461,8 +463,8 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data) void QNetworkReplyImplPrivate::finished() { Q_Q(QNetworkReplyImpl); - Q_ASSERT_X(state != Finished, "QNetworkReplyImpl", - "Backend called finished/finishedWithError more than once"); + if (state == Finished || state == Aborted) + return; state = Finished; pendingNotifications.clear(); @@ -530,6 +532,11 @@ void QNetworkReplyImplPrivate::sslErrors(const QList<QSslError> &errors) #endif } +bool QNetworkReplyImplPrivate::isFinished() const +{ + return (state == Finished || state == Aborted); +} + QNetworkReplyImpl::QNetworkReplyImpl(QObject *parent) : QNetworkReply(*new QNetworkReplyImplPrivate, parent) { diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 3e89a00..454185a 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -152,6 +152,8 @@ public: void redirectionRequested(const QUrl &target); void sslErrors(const QList<QSslError> &errors); + bool isFinished() const; + QNetworkAccessBackend *backend; QIODevice *outgoingData; QRingBuffer *outgoingDataBuffer; diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index 032e575..fef488b 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -52,13 +52,12 @@ static const int RESOLVER_TIMEOUT = 2000; #include <qurl.h> #include <qfile.h> #include <private/qmutexpool_p.h> +#include <private/qnet_unix_p.h> -extern "C" { #include <sys/types.h> #include <netdb.h> #include <arpa/inet.h> #include <resolv.h> -} #if defined (QT_NO_GETADDRINFO) #include <qmutex.h> @@ -180,7 +179,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) } results.setHostName(QString::fromLatin1(hbuf)); #else - in_addr_t inetaddr = inet_addr(hostName.toLatin1().constData()); + in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData()); struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET); if (!ent) { results.setError(QHostInfo::HostNotFound); diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp index aa27726..4efbe45 100644 --- a/src/network/kernel/qnetworkinterface_unix.cpp +++ b/src/network/kernel/qnetworkinterface_unix.cpp @@ -43,6 +43,7 @@ #include "qnetworkinterface.h" #include "qnetworkinterface_p.h" #include "qalgorithms.h" +#include "private/qnet_unix_p.h" #ifndef QT_NO_NETWORKINTERFACE @@ -123,7 +124,7 @@ static QSet<QByteArray> interfaceNames(int socket) interfaceList.ifc_len = storageBuffer.size(); // get the interface list - if (::ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) { + if (qt_safe_ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) { if (int(interfaceList.ifc_len + sizeof(ifreq) + 64) < storageBuffer.size()) { // if the buffer was big enough, break storageBuffer.resize(interfaceList.ifc_len); @@ -198,7 +199,7 @@ static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfa #ifdef SIOCGIFNAME // Get the canonical name QByteArray oldName = req.ifr_name; - if (::ioctl(socket, SIOCGIFNAME, &req) >= 0) { + if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) { iface->name = QString::fromLatin1(req.ifr_name); // reset the name: @@ -211,13 +212,13 @@ static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfa } // Get interface flags - if (::ioctl(socket, SIOCGIFFLAGS, &req) >= 0) { + if (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) { iface->flags = convertFlags(req.ifr_flags); } #ifdef SIOCGIFHWADDR // Get the HW address - if (::ioctl(socket, SIOCGIFHWADDR, &req) >= 0) { + if (qt_safe_ioctl(socket, SIOCGIFHWADDR, &req) >= 0) { uchar *addr = (uchar *)&req.ifr_addr; iface->hardwareAddress = iface->makeHwAddress(6, addr); } @@ -232,7 +233,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() QList<QNetworkInterfacePrivate *> interfaces; int socket; - if ((socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1) + if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1) return interfaces; // error QSet<QByteArray> names = interfaceNames(socket); @@ -247,7 +248,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() // Get the interface broadcast address QNetworkAddressEntry entry; if (iface->flags & QNetworkInterface::CanBroadcast) { - if (::ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) { + if (qt_safe_ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) { sockaddr *sa = &req.ifr_addr; if (sa->sa_family == AF_INET) entry.setBroadcast(addressFromSockaddr(sa)); @@ -255,13 +256,13 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() } // Get the interface netmask - if (::ioctl(socket, SIOCGIFNETMASK, &req) >= 0) { + if (qt_safe_ioctl(socket, SIOCGIFNETMASK, &req) >= 0) { sockaddr *sa = &req.ifr_addr; entry.setNetmask(addressFromSockaddr(sa)); } // Get the address of the interface - if (::ioctl(socket, SIOCGIFADDR, &req) >= 0) { + if (qt_safe_ioctl(socket, SIOCGIFADDR, &req) >= 0) { sockaddr *sa = &req.ifr_addr; entry.setIp(addressFromSockaddr(sa)); } @@ -392,7 +393,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() QList<QNetworkInterfacePrivate *> interfaces; int socket; - if ((socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1) + if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1) return interfaces; // error ifaddrs *interfaceListing; diff --git a/src/network/kernel/qnetworkinterface_win_p.h b/src/network/kernel/qnetworkinterface_win_p.h index c4dff76..15b4859 100644 --- a/src/network/kernel/qnetworkinterface_win_p.h +++ b/src/network/kernel/qnetworkinterface_win_p.h @@ -54,7 +54,7 @@ // #include <winsock2.h> -#include <windows.h> +#include <qt_windows.h> #include <time.h> QT_BEGIN_NAMESPACE diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp index 1d968c2..608db65 100644 --- a/src/network/kernel/qnetworkproxy.cpp +++ b/src/network/kernel/qnetworkproxy.cpp @@ -366,7 +366,7 @@ static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::Pro int(QNetworkProxy::HostNameLookupCapability)), }; - if (int(type) < 0 && int(type) > int(QNetworkProxy::FtpCachingProxy)) + if (int(type) < 0 || int(type) > int(QNetworkProxy::FtpCachingProxy)) type = QNetworkProxy::DefaultProxy; return QNetworkProxy::Capabilities(defaults[int(type)]); } diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp index 7052bcc2..9fab545 100644 --- a/src/network/kernel/qnetworkproxy_win.cpp +++ b/src/network/kernel/qnetworkproxy_win.cpp @@ -49,7 +49,7 @@ #include <qurl.h> #include <string.h> -#include <windows.h> +#include <qt_windows.h> #include <wininet.h> /* diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index c18026b..7809226 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -63,6 +63,9 @@ 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 versions of Windows earlier than + Windows XP. + \sa QLocalServer */ @@ -100,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() @@ -205,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() */ /*! @@ -241,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. @@ -253,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() */ @@ -272,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() */ @@ -307,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} */ /*! @@ -319,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} */ /*! @@ -363,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 bdbba42..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> @@ -135,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_win.cpp b/src/network/socket/qlocalsocket_win.cpp index b1b69fc..794b2b7 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) { @@ -166,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(); } @@ -176,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) @@ -273,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; @@ -300,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; } @@ -327,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(); @@ -336,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(); @@ -347,7 +370,6 @@ void QLocalSocket::close() delete d->pipeWriter; d->pipeWriter = 0; } - d->dataNotifier.stop(); } bool QLocalSocket::flush() @@ -381,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; } @@ -400,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(); } } @@ -446,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()); @@ -470,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.", GetLastError()); return false; } @@ -495,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 7811635..a9479d3 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -63,35 +63,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 - -// 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 0c1fa19..3991ae6 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -508,7 +508,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) @@ -634,8 +634,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l ssize_t sentBytes; do { - sentBytes = ::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) { diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h index ffd5b39..03ed3b4 100644 --- a/src/network/socket/qnet_unix_p.h +++ b/src/network/socket/qnet_unix_p.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtNetwork module of the Qt Toolkit. ** @@ -34,7 +34,7 @@ ** 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 qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -59,6 +59,12 @@ #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. @@ -132,7 +138,8 @@ static inline int qt_safe_listen(int s, int backlog) static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SOCKLEN_T addrlen) { register int ret; - EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, addr, addrlen)); + // 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 @@ -148,6 +155,28 @@ static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SO # 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/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index a38433b..7dc9fab 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -57,7 +57,7 @@ #include "qsslsocket_p.h" #ifdef Q_OS_WIN -#include <windows.h> +#include <qt_windows.h> #if defined(OCSP_RESPONSE) #undef OCSP_RESPONSE #endif |