11#include "darwin/btrfcommchannel_p.h"
12#include "darwin/btl2capchannel_p.h"
15#include "darwin/btutility_p.h"
16#include "darwin/uistrings_p.h"
19#include <QtCore/qloggingcategory.h>
20#include <QtCore/qcoreapplication.h>
21#include <QtCore/qmetaobject.h>
22#include <QtCore/q26numeric.h>
35QBluetoothSocketPrivateDarwin::QBluetoothSocketPrivateDarwin()
36 : writeChunk(std::numeric_limits<UInt16>::max())
41QBluetoothSocketPrivateDarwin::~QBluetoothSocketPrivateDarwin()
45bool QBluetoothSocketPrivateDarwin::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
50 Q_ASSERT(socketType == QBluetoothServiceInfo::UnknownProtocol);
52 return type != QBluetoothServiceInfo::UnknownProtocol;
55QString QBluetoothSocketPrivateDarwin::localName()
const
57 const QBluetoothLocalDevice device;
61QBluetoothAddress QBluetoothSocketPrivateDarwin::localAddress()
const
63 const QBluetoothLocalDevice device;
64 return device.address();
67quint16 QBluetoothSocketPrivateDarwin::localPort()
const
72QString QBluetoothSocketPrivateDarwin::peerName()
const
76 NSString *nsName = nil;
77 if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
79 nsName = [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() peerName];
80 }
else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
82 nsName = [l2capChannel.getAs<DarwinBTL2CAPChannel>() peerName];
86 return QString::fromNSString(nsName);
91QBluetoothAddress QBluetoothSocketPrivateDarwin::peerAddress()
const
93 BluetoothDeviceAddress addr = {};
94 if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
96 addr = [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() peerAddress];
97 }
else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
99 addr = [l2capChannel.getAs<DarwinBTL2CAPChannel>() peerAddress];
102 return DarwinBluetooth::qt_address(&addr);
105quint16 QBluetoothSocketPrivateDarwin::peerPort()
const
107 if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
109 return [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() getChannelID];
110 }
else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
112 return [l2capChannel.getAs<DarwinBTL2CAPChannel>() getPSM];
118void QBluetoothSocketPrivateDarwin::abort()
121 Q_ASSERT_X(!isConnecting, Q_FUNC_INFO,
"internal inconsistency - "
122 "still in connectToService()");
124 if (socketType == QBluetoothServiceInfo::RfcommProtocol)
125 rfcommChannel.reset();
126 else if (socketType == QBluetoothServiceInfo::L2capProtocol)
127 l2capChannel.reset();
131 q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
132 emit q_ptr->readChannelFinished();
136void QBluetoothSocketPrivateDarwin::close()
139 Q_ASSERT_X(!isConnecting, Q_FUNC_INFO,
"internal inconsistency - "
140 "still in connectToService()");
142 if (!txBuffer.size())
147qint64 QBluetoothSocketPrivateDarwin::writeData(
const char *data, qint64 maxSize)
149 Q_ASSERT_X(data, Q_FUNC_INFO,
"invalid data (null)");
150 Q_ASSERT_X(maxSize > 0, Q_FUNC_INFO,
"invalid data size");
152 if (state != QBluetoothSocket::SocketState::ConnectedState) {
153 errorString = QCoreApplication::translate(SOCKET, SOC_NOWRITE);
154 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
161 if (!txBuffer.size())
162 QMetaObject::invokeMethod(
this, [
this](){_q_writeNotify();}, Qt::QueuedConnection);
164 const int adjustedMaxSize = q26::saturate_cast<
int>(maxSize);
165 char *dst = txBuffer.reserve(adjustedMaxSize);
166 std::copy(data, data + adjustedMaxSize, dst);
168 return adjustedMaxSize;
171qint64 QBluetoothSocketPrivateDarwin::readData(
char *data, qint64 maxSize)
176 if (state != QBluetoothSocket::SocketState::ConnectedState) {
177 errorString = QCoreApplication::translate(SOCKET, SOC_NOREAD);
178 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
182 if (!rxBuffer.isEmpty())
183 return rxBuffer.read(data,
int(maxSize));
188qint64 QBluetoothSocketPrivateDarwin::bytesAvailable()
const
190 return rxBuffer.size();
193bool QBluetoothSocketPrivateDarwin::canReadLine()
const
195 return rxBuffer.canReadLine();
198qint64 QBluetoothSocketPrivateDarwin::bytesToWrite()
const
200 return txBuffer.size();
203bool QBluetoothSocketPrivateDarwin::setSocketDescriptor(
int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
204 QBluetoothSocket::SocketState socketState, QIODevice::OpenMode openMode)
206 Q_UNUSED(socketDescriptor);
207 Q_UNUSED(socketType);
208 Q_UNUSED(socketState);
211 qCWarning(QT_BT_DARWIN) <<
"setting a socket descriptor is not supported by IOBluetooth";
216void QBluetoothSocketPrivateDarwin::connectToServiceHelper(
const QBluetoothAddress &address, quint16 port,
217 QIODevice::OpenMode openMode)
224void QBluetoothSocketPrivateDarwin::connectToService(
const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
228 DarwinBluetooth::qt_test_iobluetooth_runloop();
230 if (state!= QBluetoothSocket::SocketState::UnconnectedState && state != QBluetoothSocket::SocketState::ServiceLookupState) {
231 qCWarning(QT_BT_DARWIN) <<
"called on a busy socket";
232 errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
233 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
238 if (service.socketProtocol() == QBluetoothServiceInfo::UnknownProtocol) {
239 qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO <<
"cannot connect with 'UnknownProtocol' type";
240 errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
241 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
245 socketType = service.socketProtocol();
247 if (service.protocolServiceMultiplexer() > 0) {
248 connectToService(service.device().address(),
249 quint16(service.protocolServiceMultiplexer()),
251 }
else if (service.serverChannel() > 0) {
252 connectToService(service.device().address(),
253 quint16(service.serverChannel()),
257 if (service.serviceUuid().isNull()) {
258 qCWarning(QT_BT_DARWIN) <<
"No port, no PSM, and no "
259 "UUID provided, unable to connect";
263 q_ptr->doDeviceDiscovery(service, openMode);
267void QBluetoothSocketPrivateDarwin::connectToService(
const QBluetoothAddress &address,
const QBluetoothUuid &uuid,
268 QIODevice::OpenMode openMode)
272 DarwinBluetooth::qt_test_iobluetooth_runloop();
275 if (socketType == QBluetoothServiceInfo::UnknownProtocol) {
276 qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO <<
"cannot connect with 'UnknownProtocol' type";
277 errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
278 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
282 if (state != QBluetoothSocket::SocketState::UnconnectedState) {
283 qCWarning(QT_BT_DARWIN) <<
"called on a busy socket";
284 errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
285 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
289 QBluetoothDeviceInfo device(address, QString(), QBluetoothDeviceInfo::MiscellaneousDevice);
290 QBluetoothServiceInfo service;
291 service.setDevice(device);
292 service.setServiceUuid(uuid);
293 q_ptr->doDeviceDiscovery(service, openMode);
296void QBluetoothSocketPrivateDarwin::connectToService(
const QBluetoothAddress &address, quint16 port,
297 QIODevice::OpenMode mode)
301 DarwinBluetooth::qt_test_iobluetooth_runloop();
303 if (socketType == QBluetoothServiceInfo::UnknownProtocol) {
304 qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO <<
"cannot connect with 'UnknownProtocol' type";
305 errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
306 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
310 Q_ASSERT_X(state == QBluetoothSocket::SocketState::ServiceLookupState || state == QBluetoothSocket::SocketState::UnconnectedState,
311 Q_FUNC_INFO,
"invalid state");
313 q_ptr->setOpenMode(mode);
315 socketError = QBluetoothSocket::SocketError::NoSocketError;
320 IOReturn status = kIOReturnError;
323 const QBluetoothSocket::SocketState oldState = state;
326 state = QBluetoothSocket::SocketState::ConnectingState;
333 if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
334 rfcommChannel.reset([[DarwinBTRFCOMMChannel alloc] initWithDelegate:
this], RetainPolicy::noInitialRetain);
336 status = [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() connectAsyncToDevice:address withChannelID:port];
338 status = kIOReturnNoMemory;
339 }
else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
340 l2capChannel.reset([[DarwinBTL2CAPChannel alloc] initWithDelegate:
this], RetainPolicy::noInitialRetain);
342 status = [l2capChannel.getAs<DarwinBTL2CAPChannel>() connectAsyncToDevice:address withPSM:port];
344 status = kIOReturnNoMemory;
348 isConnecting =
false;
352 if (status == kIOReturnSuccess && socketError == QBluetoothSocket::SocketError::NoSocketError) {
353 if (state == QBluetoothSocket::SocketState::ConnectedState) {
358 q_ptr->setOpenMode(openMode);
359 q_ptr->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
361 emit q_ptr->readyRead();
362 }
else if (state == QBluetoothSocket::SocketState::UnconnectedState) {
367 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
371 q_ptr->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
375 if (status != kIOReturnSuccess)
376 errorString = DarwinBluetooth::qt_error_string(status);
377 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
381void QBluetoothSocketPrivateDarwin::_q_writeNotify()
383 Q_ASSERT_X(socketType == QBluetoothServiceInfo::L2capProtocol
384 || socketType == QBluetoothServiceInfo::RfcommProtocol,
385 Q_FUNC_INFO,
"invalid socket type");
386 Q_ASSERT_X(l2capChannel || rfcommChannel, Q_FUNC_INFO,
387 "invalid socket (no open channel)");
388 Q_ASSERT_X(q_ptr, Q_FUNC_INFO,
"invalid q_ptr (null)");
390 if (txBuffer.size()) {
391 const bool isL2CAP = socketType == QBluetoothServiceInfo::L2capProtocol;
392 writeChunk.resize(isL2CAP ? std::numeric_limits<UInt16>::max() :
393 [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() getMTU]);
395 const auto size = txBuffer.read(writeChunk.data(), writeChunk.size());
396 IOReturn status = kIOReturnError;
398 status = [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() writeAsync:writeChunk.data() length:UInt16(size)];
400 status = [l2capChannel.getAs<DarwinBTL2CAPChannel>() writeAsync:writeChunk.data() length:UInt16(size)];
402 if (status != kIOReturnSuccess) {
403 errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
404 q_ptr->setSocketError(QBluetoothSocket::SocketError::NetworkError);
407 emit q_ptr->bytesWritten(size);
411 if (!txBuffer.size() && state == QBluetoothSocket::SocketState::ClosingState)
415bool QBluetoothSocketPrivateDarwin::setRFCOMChannel(
void *generic)
422 auto channel =
static_cast<IOBluetoothRFCOMMChannel *>(generic);
424 Q_ASSERT_X(socketError == QBluetoothSocket::SocketError::NoSocketError
425 && state == QBluetoothSocket::SocketState::UnconnectedState && !rfcommChannel && !l2capChannel,
426 Q_FUNC_INFO,
"unexpected socket state");
428 openMode = QIODevice::ReadWrite;
429 rfcommChannel.reset([[DarwinBTRFCOMMChannel alloc] initWithDelegate:
this channel:channel],
430 RetainPolicy::noInitialRetain);
432 q_ptr->setOpenMode(QIODevice::ReadWrite);
433 state = QBluetoothSocket::SocketState::ConnectedState;
434 socketType = QBluetoothServiceInfo::RfcommProtocol;
437 return rfcommChannel;
440bool QBluetoothSocketPrivateDarwin::setL2CAPChannel(
void *generic)
447 auto channel =
static_cast<IOBluetoothL2CAPChannel *>(generic);
450 Q_ASSERT_X(socketError == QBluetoothSocket::SocketError::NoSocketError
451 && state == QBluetoothSocket::SocketState::UnconnectedState && !l2capChannel && !rfcommChannel,
452 Q_FUNC_INFO,
"unexpected socket state");
454 openMode = QIODevice::ReadWrite;
455 l2capChannel.reset([[DarwinBTL2CAPChannel alloc] initWithDelegate:
this channel:channel], RetainPolicy::noInitialRetain);
457 q_ptr->setOpenMode(QIODevice::ReadWrite);
458 state = QBluetoothSocket::SocketState::ConnectedState;
459 socketType = QBluetoothServiceInfo::L2capProtocol;
465void QBluetoothSocketPrivateDarwin::setChannelError(IOReturn errorCode)
469 Q_ASSERT_X(q_ptr, Q_FUNC_INFO,
"invalid q_ptr (null)");
474 socketError = QBluetoothSocket::SocketError::UnknownSocketError;
476 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
480void QBluetoothSocketPrivateDarwin::channelOpenComplete()
482 Q_ASSERT_X(q_ptr, Q_FUNC_INFO,
"invalid q_ptr (null)");
485 q_ptr->setOpenMode(openMode);
486 q_ptr->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
488 state = QBluetoothSocket::SocketState::ConnectedState;
494void QBluetoothSocketPrivateDarwin::channelClosed()
496 Q_ASSERT_X(q_ptr, Q_FUNC_INFO,
"invalid q_ptr (null)");
502 if (state == QBluetoothSocket::SocketState::ConnectedState)
503 q_ptr->setSocketError(QBluetoothSocket::SocketError::RemoteHostClosedError);
504 q_ptr->setOpenMode(QIODevice::NotOpen);
505 q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
506 emit q_ptr->readChannelFinished();
508 state = QBluetoothSocket::SocketState::UnconnectedState;
514void QBluetoothSocketPrivateDarwin::readChannelData(
void *data, std::size_t size)
516 Q_ASSERT_X(data, Q_FUNC_INFO,
"invalid data (null)");
517 Q_ASSERT_X(size, Q_FUNC_INFO,
"invalid data size (0)");
518 Q_ASSERT_X(q_ptr, Q_FUNC_INFO,
"invalid q_ptr (null)");
520 const char *src =
static_cast<
char *>(data);
522 if (size > std::numeric_limits<
int>::max())
523 qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO <<
"Truncating the incoming data to INT_MAX";
525 const int adjustedSize = q26::saturate_cast<
int>(size);
526 char *dst = rxBuffer.reserve(adjustedSize);
527 std::copy(src, src + adjustedSize, dst);
531 emit q_ptr->readyRead();
535void QBluetoothSocketPrivateDarwin::writeComplete()
#define QT_BT_MAC_AUTORELEASEPOOL