Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qbluetoothserver_bluez.cpp
Go to the documentation of this file.
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"
6#include "qbluetoothsocket.h"
10
11#include <QtCore/QLoggingCategory>
12#include <QtCore/QSocketNotifier>
13
14#include <errno.h>
15
17
19
20QBluetoothSocket *QBluetoothServerPrivate::createSocketForServer(
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
29 QBluetoothSocket *socket = new QBluetoothSocket(rawSocketPrivate, socketType);
30 return socket;
31}
32
34 QBluetoothServer *parent)
35 : securityFlags(QBluetooth::Security::Authorization),
36 serverType(sType),
37 q_ptr(parent)
38{
40 socket = createSocketForServer(QBluetoothServiceInfo::RfcommProtocol);
41 else
42 socket = createSocketForServer(QBluetoothServiceInfo::L2capProtocol);
43}
44
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
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(&security, 0, 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
80 &security, 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(&security, 0, sizeof(security));
90 socklen_t length = sizeof(security);
91
93 &security, &length) != 0) {
94 qCWarning(QT_BT_BLUEZ) << "Failed to get security flags" << qt_error_string(errno);
96 }
97
98 switch (security.level) {
99 case BT_SECURITY_LOW:
103 case BT_SECURITY_HIGH:
105 default:
106 qCWarning(QT_BT_BLUEZ) << "Unknown server socket security level" << security.level;
108 }
109}
110
112{
113 Q_D(QBluetoothServer);
114
115 delete d->socketNotifier;
116 d->socketNotifier = nullptr;
117
118 d->socket->close();
119}
120
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
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(d->m_lastError);
136 return false;
137 }
138
139 QBluetoothLocalDevice::HostMode hostMode = device.hostMode();
142 emit errorOccurred(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;
158 d->socket = QBluetoothServerPrivate::createSocketForServer(QBluetoothServiceInfo::RfcommProtocol);
159 else
160 d->socket = QBluetoothServerPrivate::createSocketForServer(QBluetoothServiceInfo::L2capProtocol);
161
162 sock = d->socket->socketDescriptor();
163 if (sock < 0) {
164 d->m_lastError = InputOutputError;
165 emit errorOccurred(d->m_lastError);
166 return false;
167 }
168 }
169
170 if (d->serverType == QBluetoothServiceInfo::RfcommProtocol) {
172
173 addr.rc_family = AF_BLUETOOTH;
174 addr.rc_channel = port;
175
176 if (!address.isNull())
177 convertAddress(address.toUInt64(), addr.rc_bdaddr.b);
178 else
179 convertAddress(device.address().toUInt64(), addr.rc_bdaddr.b);
180
181 if (::bind(sock, reinterpret_cast<sockaddr *>(&addr), sizeof(sockaddr_rc)) < 0) {
182 if (errno == EADDRINUSE)
183 d->m_lastError = ServiceAlreadyRegisteredError;
184 else
185 d->m_lastError = InputOutputError;
186 emit errorOccurred(d->m_lastError);
187 return false;
188 }
189 } else {
191
192 memset(&addr, 0, sizeof(sockaddr_l2));
193 addr.l2_family = AF_BLUETOOTH;
194 addr.l2_psm = port;
195
196 if (!address.isNull())
197 convertAddress(address.toUInt64(), addr.l2_bdaddr.b);
198 else
199 convertAddress(Q_UINT64_C(0), addr.l2_bdaddr.b);
200
201 if (::bind(sock, reinterpret_cast<sockaddr *>(&addr), sizeof(sockaddr_l2)) < 0) {
202 d->m_lastError = InputOutputError;
203 emit errorOccurred(d->m_lastError);
204 return false;
205 }
206 }
207
208 d->setSocketSecurityLevel(d->securityFlags, nullptr);
209
210 if (::listen(sock, d->maxPendingConnections) < 0) {
211 d->m_lastError = InputOutputError;
212 emit errorOccurred(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(),
221 connect(d->socketNotifier, &QSocketNotifier::activated,
222 this, [d](){
223 d->_q_newConnection();
224 });
225 }
226
227 return true;
228}
229
230void QBluetoothServer::setMaxPendingConnections(int numConnections)
231{
232 Q_D(QBluetoothServer);
233
235 d->maxPendingConnections = numConnections;
236}
237
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
250{
251 Q_D(QBluetoothServer);
252
254 return nullptr;
255
256 int pending;
257 if (d->serverType == QBluetoothServiceInfo::RfcommProtocol) {
259 socklen_t length = sizeof(sockaddr_rc);
260 pending = ::accept(d->socket->socketDescriptor(),
261 reinterpret_cast<sockaddr *>(&addr), &length);
262 } else {
264 socklen_t length = sizeof(sockaddr_l2);
265 pending = ::accept(d->socket->socketDescriptor(),
266 reinterpret_cast<sockaddr *>(&addr), &length);
267 }
268
269 if (pending >= 0) {
270 QBluetoothSocket *newSocket = QBluetoothServerPrivate::createSocketForServer();
271 if (d->serverType == QBluetoothServiceInfo::RfcommProtocol)
273 else
275
276 d->socketNotifier->setEnabled(true);
277
278 return newSocket;
279 } else {
280 d->socketNotifier->setEnabled(true);
281 }
282
283 return nullptr;
284}
285
287{
288 Q_D(const QBluetoothServer);
289
290 return d->socket->localAddress();
291}
292
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(security, &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(d->m_lastError);
317 d->socket->close();
318 }
319}
320
321QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
322{
323 Q_D(const QBluetoothServer);
324
326 return d->securityFlags;
327
328 return d->socketSecurityLevel();
329}
330
#define BT_SECURITY_LOW
#define BT_SECURITY
#define SOL_BLUETOOTH
#define BT_SECURITY_MEDIUM
#define BT_SECURITY_HIGH
IOBluetoothDevice * device
virtual qintptr socketDescriptor() const
Returns the native socket descriptor of the QAbstractSocket object if this is available; otherwise re...
\inmodule QtBluetooth
\inmodule QtBluetooth
HostMode
This enum describes the most of the local Bluetooth device.
QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol serverType, QBluetoothServer *parent)
QBluetoothSocket * socket
\inmodule QtBluetooth
bool hasPendingConnections() const
Returns true if a connection is pending, otherwise false.
void setSecurityFlags(QBluetooth::SecurityFlags security)
Sets the Bluetooth security flags to security.
QBluetoothSocket * nextPendingConnection()
Returns a pointer to the QBluetoothSocket for the next pending connection.
bool listen(const QBluetoothAddress &address=QBluetoothAddress(), quint16 port=0)
Start listening for incoming connections to address on port.
void close()
Closes and resets the listening socket.
void errorOccurred(QBluetoothServer::Error error)
This signal is emitted when an error occurs.
quint16 serverPort() const
Returns the server port number.
QBluetoothAddress serverAddress() const
Returns the server address.
QBluetooth::SecurityFlags securityFlags() const
Returns the Bluetooth security flags.
void newConnection()
This signal is emitted when a new connection is available.
void setMaxPendingConnections(int numConnections)
Sets the maximum number of pending connections to numConnections.
QBluetoothServiceInfo::Protocol serverType() const
Returns the type of the QBluetoothServer.
Protocol
This enum describes the socket protocol used by the service.
\inmodule QtBluetooth
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType, SocketState socketState=SocketState::ConnectedState, OpenMode openMode=ReadWrite)
Sets the socket to use socketDescriptor with a type of socketType, which is in state socketState,...
int socketDescriptor() const
Returns the platform-specific socket descriptor, if available.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\inmodule QtCore
void activated(QSocketDescriptor socket, QSocketNotifier::Type activationEvent, QPrivateSignal)
\inmodule QtBluetooth
Combined button and popup list for selecting options.
static void convertAddress(const quint64 from, quint8(&to)[6])
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall * pending
EGLOutputPortEXT port
static QT_BEGIN_NAMESPACE const char * socketType(QSocketNotifier::Type type)
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define qCWarning(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLenum GLuint GLenum GLsizei length
GLenum const void * addr
GLuint GLuint64EXT address
#define emit
#define Q_UINT64_C(c)
Definition qtypes.h:58
unsigned short quint16
Definition qtypes.h:48
QTcpSocket sock
[2]
QTcpSocket * socket
[1]
socketLayer bind(QHostAddress::Any, 4000)
socketLayer listen()
sa_family_t rc_family