4#include "darwin/btsocketlistener_p.h"
14#include "darwin/btutility_p.h"
18#include <QtCore/qloggingcategory.h>
19#include <QtCore/qvariant.h>
20#include <QtCore/qglobal.h>
21#include <QtCore/qmutex.h>
23#include <Foundation/Foundation.h>
25#include <IOBluetooth/IOBluetooth.h>
34using ServiceInfo = QBluetoothServiceInfo;
38 static QMap<quint16, QBluetoothServerPrivate *> psms;
44 static QMap<quint16, QBluetoothServerPrivate *> channels;
53 QBluetoothServer *parent)
58 if (serverType == ServiceInfo::UnknownProtocol)
59 qCWarning(QT_BT_DARWIN) <<
"unknown protocol";
64 const QMutexLocker lock(&channelMapMutex());
65 unregisterServer(
this);
70 Q_ASSERT_X(realPort, Q_FUNC_INFO,
"invalid port");
72 if (serverType == ServiceInfo::UnknownProtocol) {
73 qCWarning(QT_BT_DARWIN) <<
"invalid protocol";
78 listener.reset([[DarwinBTSocketListener alloc] initWithListener:
this],
79 RetainPolicy::noInitialRetain);
83 if (serverType == ServiceInfo::RfcommProtocol)
84 result = [listener.getAs<DarwinBTSocketListener>() listenRFCOMMConnectionsWithChannelID:realPort];
86 result = [listener.getAs<DarwinBTSocketListener>() listenL2CAPConnectionsWithPSM:realPort];
94bool QBluetoothServerPrivate::isListening()
const
96 if (serverType == ServiceInfo::UnknownProtocol)
99 const QMutexLocker lock(&QBluetoothServerPrivate::channelMapMutex());
100 return QBluetoothServerPrivate::registeredServer(q_ptr->serverPort(), serverType);
103void QBluetoothServerPrivate::stopListener()
108void QBluetoothServerPrivate::openNotifyRFCOMM(
void *generic)
110 auto channel =
static_cast<IOBluetoothRFCOMMChannel *>(generic);
112 Q_ASSERT_X(listener, Q_FUNC_INFO,
"invalid listener (nil)");
113 Q_ASSERT_X(channel, Q_FUNC_INFO,
"invalid channel (nil)");
114 Q_ASSERT_X(q_ptr, Q_FUNC_INFO,
"invalid q_ptr (null)");
116 PendingConnection newConnection(channel, RetainPolicy::doInitialRetain);
117 pendingConnections.append(newConnection);
119 emit q_ptr->newConnection();
122void QBluetoothServerPrivate::openNotifyL2CAP(
void *generic)
124 auto channel =
static_cast<IOBluetoothL2CAPChannel *>(generic);
126 Q_ASSERT_X(listener, Q_FUNC_INFO,
"invalid listener (nil)");
127 Q_ASSERT_X(channel, Q_FUNC_INFO,
"invalid channel (nil)");
128 Q_ASSERT_X(q_ptr, Q_FUNC_INFO,
"invalid q_ptr (null)");
130 PendingConnection newConnection(channel, RetainPolicy::doInitialRetain);
131 pendingConnections.append(newConnection);
133 emit q_ptr->newConnection();
136QMutex &QBluetoothServerPrivate::channelMapMutex()
142bool QBluetoothServerPrivate::channelIsBusy(quint16 channelID)
145 return busyChannels().contains(channelID);
148quint16 QBluetoothServerPrivate::findFreeChannel()
151 for (quint16 i = 1; i <= 30; ++i) {
152 if (!busyChannels().contains(i))
159bool QBluetoothServerPrivate::psmIsBusy(quint16 psm)
162 return busyPSMs().contains(psm);
165quint16 QBluetoothServerPrivate::findFreePSM()
168 for (quint16 i = 1, e = std::numeric_limits<qint16>::max(); i < e; i += 2) {
176void QBluetoothServerPrivate::registerServer(QBluetoothServerPrivate *server, quint16 port)
179 Q_ASSERT_X(server, Q_FUNC_INFO,
"invalid server (null)");
181 const ServiceInfo::Protocol type = server->serverType;
182 if (type == ServiceInfo::RfcommProtocol) {
183 Q_ASSERT_X(!channelIsBusy(port), Q_FUNC_INFO,
"port is busy");
184 busyChannels()[port] = server;
185 }
else if (type == ServiceInfo::L2capProtocol) {
186 Q_ASSERT_X(!psmIsBusy(port), Q_FUNC_INFO,
"port is busy");
187 busyPSMs()[port] = server;
189 qCWarning(QT_BT_DARWIN) <<
"can not register a server "
190 "with unknown protocol type";
194QBluetoothServerPrivate *QBluetoothServerPrivate::registeredServer(quint16 port, QBluetoothServiceInfo::Protocol protocol)
197 if (protocol == ServiceInfo::RfcommProtocol) {
198 ServerMapIterator it = busyChannels().find(port);
199 if (it != busyChannels().end())
201 }
else if (protocol == ServiceInfo::L2capProtocol) {
202 ServerMapIterator it = busyPSMs().find(port);
203 if (it != busyPSMs().end())
206 qCWarning(QT_BT_DARWIN) <<
"invalid protocol";
212void QBluetoothServerPrivate::unregisterServer(QBluetoothServerPrivate *server)
215 const ServiceInfo::Protocol type = server->serverType;
216 const quint16 port = server->port;
218 if (type == ServiceInfo::RfcommProtocol) {
219 ServerMapIterator it = busyChannels().find(port);
220 if (it != busyChannels().end()) {
221 busyChannels().erase(it);
223 qCWarning(QT_BT_DARWIN) <<
"server is not registered";
225 }
else if (type == ServiceInfo::L2capProtocol) {
226 ServerMapIterator it = busyPSMs().find(port);
227 if (it != busyPSMs().end()) {
228 busyPSMs().erase(it);
230 qCWarning(QT_BT_DARWIN) <<
"server is not registered";
233 qCWarning(QT_BT_DARWIN) <<
"invalid protocol";
237void QBluetoothServer::close()
239 d_ptr->listener.reset();
242 const QMutexLocker lock(&d_ptr->channelMapMutex());
243 d_ptr->unregisterServer(d_ptr);
247bool QBluetoothServer::listen(
const QBluetoothAddress &address, quint16 port)
249 DarwinBluetooth::qt_test_iobluetooth_runloop();
251 if (d_ptr->listener) {
252 qCWarning(QT_BT_DARWIN) <<
"already in listen mode, close server first";
256 const QBluetoothLocalDevice device(address);
257 if (!device.isValid()) {
258 qCWarning(QT_BT_DARWIN) <<
"device does not support Bluetooth or"
259 << address.toString()
260 <<
"is not a valid local adapter";
261 d_ptr->m_lastError = UnknownError;
262 emit errorOccurred(UnknownError);
266 const QBluetoothLocalDevice::HostMode hostMode = device.hostMode();
267 if (hostMode == QBluetoothLocalDevice::HostPoweredOff) {
268 qCWarning(QT_BT_DARWIN) <<
"Bluetooth device is powered off";
269 d_ptr->m_lastError = PoweredOffError;
270 emit errorOccurred(PoweredOffError);
274 const ServiceInfo::Protocol type = d_ptr->serverType;
276 if (type == ServiceInfo::UnknownProtocol) {
277 qCWarning(QT_BT_DARWIN) <<
"invalid protocol";
278 d_ptr->m_lastError = UnsupportedProtocolError;
279 emit errorOccurred(d_ptr->m_lastError);
283 d_ptr->m_lastError = QBluetoothServer::NoError;
286 const QMutexLocker lock(&d_ptr->channelMapMutex());
289 if (type == ServiceInfo::RfcommProtocol) {
290 if (d_ptr->channelIsBusy(port)) {
291 qCWarning(QT_BT_DARWIN) <<
"server port:" << port
292 <<
"already registered";
293 d_ptr->m_lastError = ServiceAlreadyRegisteredError;
296 if (d_ptr->psmIsBusy(port)) {
297 qCWarning(QT_BT_DARWIN) <<
"server port:" << port
298 <<
"already registered";
299 d_ptr->m_lastError = ServiceAlreadyRegisteredError;
303 type == ServiceInfo::RfcommProtocol ? port = d_ptr->findFreeChannel()
304 : port = d_ptr->findFreePSM();
307 if (d_ptr->m_lastError != QBluetoothServer::NoError) {
308 emit errorOccurred(d_ptr->m_lastError);
313 qCWarning(QT_BT_DARWIN) <<
"all ports are busy";
314 d_ptr->m_lastError = ServiceAlreadyRegisteredError;
315 emit errorOccurred(d_ptr->m_lastError);
322 d_ptr->registerServer(d_ptr, port);
323 d_ptr->listener.reset([[DarwinBTSocketListener alloc] initWithListener:d_ptr],
324 RetainPolicy::noInitialRetain);
329void QBluetoothServer::setMaxPendingConnections(
int numConnections)
331 d_ptr->maxPendingConnections = numConnections;
334bool QBluetoothServer::hasPendingConnections()
const
336 return d_ptr->pendingConnections.size();
339QBluetoothSocket *QBluetoothServer::nextPendingConnection()
341 if (!d_ptr->pendingConnections.size())
344 std::unique_ptr<QBluetoothSocket> newSocket = std::make_unique<QBluetoothSocket>();
345 QBluetoothServerPrivate::PendingConnection channel(d_ptr->pendingConnections.front());
348 d_ptr->pendingConnections.pop_front();
350 if (d_ptr->serverType == ServiceInfo::RfcommProtocol) {
351 if (!
static_cast<QBluetoothSocketPrivateDarwin *>(newSocket->d_ptr)->setRFCOMChannel(channel.getAs<IOBluetoothRFCOMMChannel>()))
354 if (!
static_cast<QBluetoothSocketPrivateDarwin *>(newSocket->d_ptr)->setL2CAPChannel(channel.getAs<IOBluetoothL2CAPChannel>()))
358 return newSocket.release();
361QBluetoothAddress QBluetoothServer::serverAddress()
const
363 return QBluetoothLocalDevice().address();
366quint16 QBluetoothServer::serverPort()
const
371void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
377QBluetooth::SecurityFlags QBluetoothServer::securityFlags()
const
380 return QBluetooth::Security::NoSecurity;
~QBluetoothServerPrivate()
QMap< quint16, QBluetoothServerPrivate * > & busyPSMs()
QMap< quint16, QBluetoothServerPrivate * > & busyChannels()
QMap< quint16, QBluetoothServerPrivate * >::iterator ServerMapIterator