From b00651a9e6ca00c31dd0601d3cdbe1db623c6204 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Mon, 18 Jul 2016 13:39:10 +0200 Subject: Improve failed ::write() handling in QBluetoothSocket When the Bluetooth connection is flooded with information, EAGAIN is returned. So far this was considered an unrecoverable error which is not consistent with the meaning of EAGAIN. In buffered mode we'll put the data back into the buffer and in unbuffered mode the QIODevice::write() call returns 0 which leaves the developer the option to retry. At the same time this patch ensures that write() calls always return the actual number of written bytes and not the amount of bytes the caller asked for to be written. Partial writes in buffered mode are returned to the buffer too. Task-number: QTBUG-54475 Change-Id: Iffc7980d2477e1fc0b45808431af6b7fecd38ded Reviewed-by: Thiago Macieira Reviewed-by: Timur Pocheptsov --- src/bluetooth/qbluetoothsocket_bluez.cpp | 50 +++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 13 deletions(-) (limited to 'src/bluetooth/qbluetoothsocket_bluez.cpp') diff --git a/src/bluetooth/qbluetoothsocket_bluez.cpp b/src/bluetooth/qbluetoothsocket_bluez.cpp index cfcba8af..803df6df 100644 --- a/src/bluetooth/qbluetoothsocket_bluez.cpp +++ b/src/bluetooth/qbluetoothsocket_bluez.cpp @@ -48,6 +48,7 @@ #include "bluez/bluez_data_p.h" #include +#include #include @@ -241,13 +242,28 @@ void QBluetoothSocketPrivate::_q_writeNotify() char buf[1024]; int size = txBuffer.read(buf, 1024); - - if (::write(socket, buf, size) != size) { - errorString = QBluetoothSocket::tr("Network Error"); - q->setSocketError(QBluetoothSocket::NetworkError); - } - else { - emit q->bytesWritten(size); + int writtenBytes = qt_safe_write(socket, buf, size); + if (writtenBytes < 0) { + switch (errno) { + case EAGAIN: + writtenBytes = 0; + txBuffer.ungetBlock(buf, size); + break; + default: + // every other case returns error + errorString = QBluetoothSocket::tr("Network Error: %1"); + errorString.arg(qt_error_string(errno)); + q->setSocketError(QBluetoothSocket::NetworkError); + break; + } + } else { + if (writtenBytes < size) { + // add remainder back to buffer + char* remainder = buf + writtenBytes; + txBuffer.ungetBlock(remainder, size - writtenBytes); + } + if (writtenBytes > 0) + emit q->bytesWritten(writtenBytes); } if (txBuffer.size()) { @@ -484,15 +500,23 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize) } if (q->openMode() & QIODevice::Unbuffered) { - if (::write(socket, data, maxSize) != maxSize) { - errorString = QBluetoothSocket::tr("Network Error"); - q->setSocketError(QBluetoothSocket::NetworkError); - return -1; + int sz = ::qt_safe_write(socket, data, maxSize); + if (sz < 0) { + switch (errno) { + case EAGAIN: + sz = 0; + break; + default: + errorString = QBluetoothSocket::tr("Network Error: %1"); + errorString.arg(qt_error_string(errno)); + q->setSocketError(QBluetoothSocket::NetworkError); + } } - emit q->bytesWritten(maxSize); + if (sz > 0) + emit q->bytesWritten(sz); - return maxSize; + return sz; } else { -- cgit v1.2.3