From ca56d9e3626fb87a786ebdebc52e63210a9a2522 Mon Sep 17 00:00:00 2001 From: Matthew Stickney Date: Mon, 27 Feb 2017 17:32:49 -0500 Subject: [PATCH] Add an option to flush writes. There is a bug with QLocalSockets on Windows where data will be silently dropped if two consecutive writes are performed without flushing and the remote end hasn't read all the data between the two (see https://bugreports.qt.io/browse/QTBUG-18385). Since qmsgpack performs several write operations as part of a single stream output, it must allow callers to specify whether to flush writes in order to work around this bug. --- src/msgpackstream.cpp | 28 ++++++++++++++++++++++++---- src/msgpackstream.h | 3 +++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/msgpackstream.cpp b/src/msgpackstream.cpp index bbbcc37..d4d28b3 100644 --- a/src/msgpackstream.cpp +++ b/src/msgpackstream.cpp @@ -24,15 +24,15 @@ return retVal; MsgPackStream::MsgPackStream() : - dev(0), owndev(false), q_status(Ok) + dev(0), owndev(false), q_status(Ok), flushWrites(false) { } MsgPackStream::MsgPackStream(QIODevice *d) : - dev(d), owndev(false), q_status(Ok) + dev(d), owndev(false), q_status(Ok), flushWrites(false) { } MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : - owndev(true), q_status(Ok) + owndev(true), q_status(Ok), flushWrites(false) { QBuffer *buf = new QBuffer(a); buf->open(mode); @@ -40,7 +40,7 @@ MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : } MsgPackStream::MsgPackStream(const QByteArray &a) : - owndev(true), q_status(Ok) + owndev(true), q_status(Ok), flushWrites(false) { QBuffer *buf = new QBuffer(); buf->setData(a); @@ -87,6 +87,16 @@ void MsgPackStream::setStatus(Status status) q_status = status; } +void MsgPackStream::setFlushWrites(bool flush) +{ + flushWrites = flush; +} + +bool MsgPackStream::willFlushWrites() +{ + return flushWrites; +} + MsgPackStream &MsgPackStream::operator>>(bool &b) { CHECK_STREAM_PRECOND(*this) @@ -503,6 +513,16 @@ bool MsgPackStream::writeBytes(const char *data, uint len) setStatus(WriteFailed); return false; } + /* Apparently on Windows, the buffer size for named pipes is 0, and + * any data that is written before the remote end reads it is + * dropped (!!) without error (see https://bugreports.qt.io/browse/QTBUG-18385). + * We must be very sure that the data has been written before we try + * another write. This degrades performance in other cases, so callers + * must enable this behavior explicitly. + */ + if (this->flushWrites) { + dev->waitForBytesWritten(-1); + } /* Increment the write pointer and the total byte count. */ data += thisWrite; diff --git a/src/msgpackstream.h b/src/msgpackstream.h index 37f7222..61cd440 100644 --- a/src/msgpackstream.h +++ b/src/msgpackstream.h @@ -26,6 +26,8 @@ class MSGPACK_EXPORT MsgPackStream Status status() const; void resetStatus(); void setStatus(Status status); + void setFlushWrites(bool flushWrites); + bool willFlushWrites(); MsgPackStream &operator>>(bool &b); MsgPackStream &operator>>(quint8 &u8); @@ -60,6 +62,7 @@ class MSGPACK_EXPORT MsgPackStream QIODevice *dev; bool owndev; Status q_status; + bool flushWrites; bool unpack_longlong(qint64 &i64); bool unpack_ulonglong(quint64 &u64);