1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qbluetoothserver.h"
5#include "qbluetoothserver_p.h"
6#include "qbluetoothsocket.h"
7#include "qbluetoothsocket_bluez_p.h"
8#include "qbluetoothlocaldevice.h"
9#include "bluez/bluez_data_p.h"
10
11#include <QtCore/QLoggingCategory>
12#include <QtCore/QSocketNotifier>
13
14#include <errno.h>
15
16QT_BEGIN_NAMESPACE
17
18Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
19
20QBluetoothSocket *QBluetoothServerPrivate::createSocketForServer(
21 QBluetoothServiceInfo::Protocol socketType)
22{
23 // QBluetoothServer does not work with the BluetoothSocket implementation for DBus.
24 // Fall back to the raw socket implementation.
25 // Usually the private implementation is picked based on detected BlueZ version.
26
27 // ownership of these objects is taken care of inside QBluetoothSocket and QBluetoothServer
28 QBluetoothSocketPrivateBluez *rawSocketPrivate = new QBluetoothSocketPrivateBluez();
29 QBluetoothSocket *socket = new QBluetoothSocket(rawSocketPrivate, socketType);
30 return socket;
31}
32
33QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType,
34 QBluetoothServer *parent)
35 : securityFlags(QBluetooth::Security::Authorization),
36 serverType(sType),
37 q_ptr(parent)
38{
39 if (sType == QBluetoothServiceInfo::RfcommProtocol)
40 socket = createSocketForServer(socketType: QBluetoothServiceInfo::RfcommProtocol);
41 else
42 socket = createSocketForServer(socketType: QBluetoothServiceInfo::L2capProtocol);
43}
44
45QBluetoothServerPrivate::~QBluetoothServerPrivate()
46{
47 delete socketNotifier;
48
49 delete socket;
50}
51
52void QBluetoothServerPrivate::_q_newConnection()
53{
54 // disable socket notifier until application calls nextPendingConnection().
55 socketNotifier->setEnabled(false);
56
57 emit q_ptr->newConnection();
58}
59
60void QBluetoothServerPrivate::setSocketSecurityLevel(
61 QBluetooth::SecurityFlags requestedSecLevel, int *errnoCode)
62{
63 if (requestedSecLevel == QBluetooth::SecurityFlags(QBluetooth::Security::NoSecurity)) {
64 qCWarning(QT_BT_BLUEZ) << "Cannot set NoSecurity on server socket";
65 return;
66 }
67
68 struct bt_security security;
69 memset(s: &security, c: 0, n: sizeof(security));
70
71 // ignore QBluetooth::Security::Authentication -> not used anymore
72 if (requestedSecLevel & QBluetooth::Security::Authorization)
73 security.level = BT_SECURITY_LOW;
74 if (requestedSecLevel & QBluetooth::Security::Encryption)
75 security.level = BT_SECURITY_MEDIUM;
76 if (requestedSecLevel & QBluetooth::Security::Secure)
77 security.level = BT_SECURITY_HIGH;
78
79 if (setsockopt(fd: socket->socketDescriptor(), SOL_BLUETOOTH, BT_SECURITY,
80 optval: &security, optlen: sizeof(security)) != 0) {
81 if (errnoCode)
82 *errnoCode = errno;
83 }
84}
85
86QBluetooth::SecurityFlags QBluetoothServerPrivate::socketSecurityLevel() const
87{
88 struct bt_security security;
89 memset(s: &security, c: 0, n: sizeof(security));
90 socklen_t length = sizeof(security);
91
92 if (getsockopt(fd: socket->socketDescriptor(), SOL_BLUETOOTH, BT_SECURITY,
93 optval: &security, optlen: &length) != 0) {
94 qCWarning(QT_BT_BLUEZ) << "Failed to get security flags" << qt_error_string(errno);
95 return QBluetooth::Security::NoSecurity;
96 }
97
98 switch (security.level) {
99 case BT_SECURITY_LOW:
100 return QBluetooth::Security::Authorization;
101 case BT_SECURITY_MEDIUM:
102 return QBluetooth::Security::Encryption;
103 case BT_SECURITY_HIGH:
104 return QBluetooth::Security::Secure;
105 default:
106 qCWarning(QT_BT_BLUEZ) << "Unknown server socket security level" << security.level;
107 return QBluetooth::Security::NoSecurity;
108 }
109}
110
111void QBluetoothServer::close()
112{
113 Q_D(QBluetoothServer);
114
115 delete d->socketNotifier;
116 d->socketNotifier = nullptr;
117
118 d->socket->close();
119}
120
121bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
122{
123 Q_D(QBluetoothServer);
124
125 if (d->socket->state() == QBluetoothSocket::SocketState::ListeningState) {
126 qCWarning(QT_BT_BLUEZ) << "Socket already in listen mode, close server first";
127 return false; //already listening, nothing to do
128 }
129
130 QBluetoothLocalDevice device(address);
131 if (!device.isValid()) {
132 qCWarning(QT_BT_BLUEZ) << "Device does not support Bluetooth or"
133 << address.toString() << "is not a valid local adapter";
134 d->m_lastError = QBluetoothServer::UnknownError;
135 emit errorOccurred(error: d->m_lastError);
136 return false;
137 }
138
139 QBluetoothLocalDevice::HostMode hostMode = device.hostMode();
140 if (hostMode == QBluetoothLocalDevice::HostPoweredOff) {
141 d->m_lastError = QBluetoothServer::PoweredOffError;
142 emit errorOccurred(error: d->m_lastError);
143 qCWarning(QT_BT_BLUEZ) << "Bluetooth device is powered off";
144 return false;
145 }
146
147 int sock = d->socket->socketDescriptor();
148 if (sock < 0) {
149 /* Negative socket descriptor is not always an error case
150 * Another cause could be a call to close()/abort()
151 * Check whether we can recover by re-creating the socket
152 * we should really call Bluez::QBluetoothSocketPrivateDarwin::ensureNativeSocket
153 * but a re-creation of the socket will do as well.
154 */
155
156 delete d->socket;
157 if (serverType() == QBluetoothServiceInfo::RfcommProtocol)
158 d->socket = QBluetoothServerPrivate::createSocketForServer(socketType: QBluetoothServiceInfo::RfcommProtocol);
159 else
160 d->socket = QBluetoothServerPrivate::createSocketForServer(socketType: QBluetoothServiceInfo::L2capProtocol);
161
162 sock = d->socket->socketDescriptor();
163 if (sock < 0) {
164 d->m_lastError = InputOutputError;
165 emit errorOccurred(error: d->m_lastError);
166 return false;
167 }
168 }
169
170 if (d->serverType == QBluetoothServiceInfo::RfcommProtocol) {
171 sockaddr_rc addr;
172
173 addr.rc_family = AF_BLUETOOTH;
174 addr.rc_channel = port;
175
176 if (!address.isNull())
177 convertAddress(from: address.toUInt64(), to&: addr.rc_bdaddr.b);
178 else
179 convertAddress(from: device.address().toUInt64(), to&: addr.rc_bdaddr.b);
180
181 if (::bind(fd: sock, addr: reinterpret_cast<sockaddr *>(&addr), len: sizeof(sockaddr_rc)) < 0) {
182 if (errno == EADDRINUSE)
183 d->m_lastError = ServiceAlreadyRegisteredError;
184 else
185 d->m_lastError = InputOutputError;
186 emit errorOccurred(error: d->m_lastError);
187 return false;
188 }
189 } else {
190 sockaddr_l2 addr;
191
192 memset(s: &addr, c: 0, n: sizeof(sockaddr_l2));
193 addr.l2_family = AF_BLUETOOTH;
194 addr.l2_psm = port;
195
196 if (!address.isNull())
197 convertAddress(from: address.toUInt64(), to&: addr.l2_bdaddr.b);
198 else
199 convertAddress(Q_UINT64_C(0), to&: addr.l2_bdaddr.b);
200
201 if (::bind(fd: sock, addr: reinterpret_cast<sockaddr *>(&addr), len: sizeof(sockaddr_l2)) < 0) {
202 d->m_lastError = InputOutputError;
203 emit errorOccurred(error: d->m_lastError);
204 return false;
205 }
206 }
207
208 d->setSocketSecurityLevel(requestedSecLevel: d->securityFlags, errnoCode: nullptr);
209
210 if (::listen(fd: sock, n: d->maxPendingConnections) < 0) {
211 d->m_lastError = InputOutputError;
212 emit errorOccurred(error: d->m_lastError);
213 return false;
214 }
215
216 d->socket->setSocketState(QBluetoothSocket::SocketState::ListeningState);
217
218 if (!d->socketNotifier) {
219 d->socketNotifier = new QSocketNotifier(d->socket->socketDescriptor(),
220 QSocketNotifier::Read);
221 connect(sender: d->socketNotifier, signal: &QSocketNotifier::activated,
222 context: this, slot: [d](){
223 d->_q_newConnection();
224 });
225 }
226
227 return true;
228}
229
230void QBluetoothServer::setMaxPendingConnections(int numConnections)
231{
232 Q_D(QBluetoothServer);
233
234 if (d->socket->state() == QBluetoothSocket::SocketState::UnconnectedState)
235 d->maxPendingConnections = numConnections;
236}
237
238bool QBluetoothServer::hasPendingConnections() const
239{
240 Q_D(const QBluetoothServer);
241
242 if (!d || !d->socketNotifier)
243 return false;
244
245 // if the socket notifier is disabled there is a pending connection waiting for us to accept.
246 return !d->socketNotifier->isEnabled();
247}
248
249QBluetoothSocket *QBluetoothServer::nextPendingConnection()
250{
251 Q_D(QBluetoothServer);
252
253 if (!hasPendingConnections())
254 return nullptr;
255
256 int pending;
257 if (d->serverType == QBluetoothServiceInfo::RfcommProtocol) {
258 sockaddr_rc addr;
259 socklen_t length = sizeof(sockaddr_rc);
260 pending = ::accept(fd: d->socket->socketDescriptor(),
261 addr: reinterpret_cast<sockaddr *>(&addr), addr_len: &length);
262 } else {
263 sockaddr_l2 addr;
264 socklen_t length = sizeof(sockaddr_l2);
265 pending = ::accept(fd: d->socket->socketDescriptor(),
266 addr: reinterpret_cast<sockaddr *>(&addr), addr_len: &length);
267 }
268
269 if (pending >= 0) {
270 QBluetoothSocket *newSocket = QBluetoothServerPrivate::createSocketForServer();
271 if (d->serverType == QBluetoothServiceInfo::RfcommProtocol)
272 newSocket->setSocketDescriptor(socketDescriptor: pending, socketType: QBluetoothServiceInfo::RfcommProtocol);
273 else
274 newSocket->setSocketDescriptor(socketDescriptor: pending, socketType: QBluetoothServiceInfo::L2capProtocol);
275
276 d->socketNotifier->setEnabled(true);
277
278 return newSocket;
279 } else {
280 d->socketNotifier->setEnabled(true);
281 }
282
283 return nullptr;
284}
285
286QBluetoothAddress QBluetoothServer::serverAddress() const
287{
288 Q_D(const QBluetoothServer);
289
290 return d->socket->localAddress();
291}
292
293quint16 QBluetoothServer::serverPort() const
294{
295 Q_D(const QBluetoothServer);
296
297 return d->socket->localPort();
298}
299
300void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
301{
302 Q_D(QBluetoothServer);
303
304 if (d->socket->state() == QBluetoothSocket::SocketState::UnconnectedState) {
305 // nothing to set beyond the fact to remember the sec level for the next listen()
306 d->securityFlags = security;
307 return;
308 }
309
310 int errorCode = 0;
311 d->setSocketSecurityLevel(requestedSecLevel: security, errnoCode: &errorCode);
312 if (errorCode) {
313 qCWarning(QT_BT_BLUEZ) << "Failed to set socket option, closing socket for safety" << errorCode;
314 qCWarning(QT_BT_BLUEZ) << "Error: " << qt_error_string(errorCode);
315 d->m_lastError = InputOutputError;
316 emit errorOccurred(error: d->m_lastError);
317 d->socket->close();
318 }
319}
320
321QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
322{
323 Q_D(const QBluetoothServer);
324
325 if (d->socket->state() == QBluetoothSocket::SocketState::UnconnectedState)
326 return d->securityFlags;
327
328 return d->socketSecurityLevel();
329}
330
331QT_END_NAMESPACE
332

source code of qtconnectivity/src/bluetooth/qbluetoothserver_bluez.cpp