1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2018 The Qt Company Ltd. |
4 | ** Copyright (C) 2016 BlackBerry Limited. All rights reserved. |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the QtBluetooth module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU Lesser General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
22 | ** packaging of this file. Please review the following information to |
23 | ** ensure the GNU Lesser General Public License version 3 requirements |
24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
25 | ** |
26 | ** GNU General Public License Usage |
27 | ** Alternatively, this file may be used under the terms of the GNU |
28 | ** General Public License version 2.0 or (at your option) the GNU General |
29 | ** Public license version 3 or any later version approved by the KDE Free |
30 | ** Qt Foundation. The licenses are as published by the Free Software |
31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
32 | ** included in the packaging of this file. Please review the following |
33 | ** information to ensure the GNU General Public License requirements will |
34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
35 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
36 | ** |
37 | ** $QT_END_LICENSE$ |
38 | ** |
39 | ****************************************************************************/ |
40 | |
41 | #include "qbluetoothsocket.h" |
42 | #if QT_CONFIG(bluez) |
43 | #include "qbluetoothsocket_bluez_p.h" |
44 | #include "qbluetoothsocket_bluezdbus_p.h" |
45 | #include "bluez/bluez5_helper_p.h" |
46 | #elif defined(QT_ANDROID_BLUETOOTH) |
47 | #include "qbluetoothsocket_android_p.h" |
48 | #elif defined(QT_WINRT_BLUETOOTH) |
49 | #include "qbluetoothsocket_winrt_p.h" |
50 | #elif defined(QT_WIN_BLUETOOTH) |
51 | #include "qbluetoothsocket_win_p.h" |
52 | #elif defined(QT_OSX_BLUETOOTH) |
53 | #include "qbluetoothsocket_osx_p.h" |
54 | #else |
55 | #include "qbluetoothsocket_dummy_p.h" |
56 | #endif |
57 | |
58 | #include "qbluetoothservicediscoveryagent.h" |
59 | |
60 | #include <QtCore/QLoggingCategory> |
61 | #include <QSocketNotifier> |
62 | |
63 | QT_BEGIN_NAMESPACE |
64 | |
65 | Q_DECLARE_LOGGING_CATEGORY(QT_BT) |
66 | |
67 | /*! |
68 | \class QBluetoothSocket |
69 | \inmodule QtBluetooth |
70 | \brief The QBluetoothSocket class enables connection to a Bluetooth device |
71 | running a bluetooth server. |
72 | |
73 | \since 5.2 |
74 | |
75 | QBluetoothSocket supports two socket types, \l {QBluetoothServiceInfo::L2capProtocol}{L2CAP} and |
76 | \l {QBluetoothServiceInfo::RfcommProtocol}{RFCOMM}. |
77 | |
78 | \l {QBluetoothServiceInfo::L2capProtocol}{L2CAP} is a low level datagram-oriented Bluetooth socket. |
79 | Android does not support \l {QBluetoothServiceInfo::L2capProtocol}{L2CAP} for socket |
80 | connections. |
81 | |
82 | \l {QBluetoothServiceInfo::RfcommProtocol}{RFCOMM} is a reliable, stream-oriented socket. RFCOMM |
83 | sockets emulate an RS-232 serial port. |
84 | |
85 | To create a connection to a Bluetooth service, create a socket of the appropriate type and call |
86 | connectToService() passing the Bluetooth address and port number. QBluetoothSocket will emit |
87 | the connected() signal when the connection is established. |
88 | |
89 | If the \l {QBluetoothServiceInfo::Protocol}{Protocol} is not supported on a platform, calling |
90 | \l connectToService() will emit a \l {QBluetoothSocket::UnsupportedProtocolError}{UnsupportedProtocolError} error. |
91 | |
92 | \note QBluetoothSocket does not support synchronous read and write operations. Functions such |
93 | as \l waitForReadyRead() and \l waitForBytesWritten() are not implemented. I/O operations should be |
94 | performed using \l readyRead(), \l read() and \l write(). |
95 | |
96 | On iOS, this class cannot be used because the platform does not expose |
97 | an API which may permit access to QBluetoothSocket related features. |
98 | |
99 | \note On macOS Monterey (12) the socket data flow is paused when a |
100 | modal dialogue is executing, or an event tracking mode is entered (for |
101 | example by long-pressing a Window close button). This may change in the |
102 | future releases of macOS. |
103 | */ |
104 | |
105 | /*! |
106 | \enum QBluetoothSocket::SocketState |
107 | |
108 | This enum describes the state of the Bluetooth socket. |
109 | |
110 | \value UnconnectedState Socket is not connected. |
111 | \value ServiceLookupState Socket is querying connection parameters. |
112 | \value ConnectingState Socket is attempting to connect to a device. |
113 | \value ConnectedState Socket is connected to a device. |
114 | \value BoundState Socket is bound to a local address and port. |
115 | \value ClosingState Socket is connected and will be closed once all pending data is |
116 | written to the socket. |
117 | \value ListeningState Socket is listening for incoming connections. |
118 | */ |
119 | |
120 | /*! |
121 | \enum QBluetoothSocket::SocketError |
122 | |
123 | This enum describes Bluetooth socket error types. |
124 | |
125 | \value UnknownSocketError An unknown error has occurred. |
126 | \value NoSocketError No error. Used for testing. |
127 | \value HostNotFoundError Could not find the remote host. |
128 | \value ServiceNotFoundError Could not find the service UUID on remote host. |
129 | \value NetworkError Attempt to read or write from socket returned an error |
130 | \value UnsupportedProtocolError The \l {QBluetoothServiceInfo::Protocol}{Protocol} is not |
131 | supported on this platform. |
132 | \value OperationError An operation was attempted while the socket was in a state |
133 | that did not permit it. |
134 | \value RemoteHostClosedError The remote host closed the connection. This value was |
135 | introduced by Qt 5.10. |
136 | */ |
137 | |
138 | /*! |
139 | \fn void QBluetoothSocket::connected() |
140 | |
141 | This signal is emitted when a connection is established. |
142 | |
143 | \sa QBluetoothSocket::ConnectedState, stateChanged() |
144 | */ |
145 | |
146 | /*! |
147 | \fn void QBluetoothSocket::disconnected() |
148 | |
149 | This signal is emitted when the socket is disconnected. |
150 | |
151 | \sa QBluetoothSocket::UnconnectedState, stateChanged() |
152 | */ |
153 | |
154 | /*! |
155 | \fn void QBluetoothSocket::error(QBluetoothSocket::SocketError error) |
156 | |
157 | This signal is emitted when an \a error occurs. |
158 | |
159 | \sa error() |
160 | */ |
161 | |
162 | /*! |
163 | \fn QBluetoothSocket::stateChanged(QBluetoothSocket::SocketState state) |
164 | |
165 | This signal is emitted when the socket state changes to \a state. |
166 | |
167 | \sa connected(), disconnected(), state(), QBluetoothSocket::SocketState |
168 | */ |
169 | |
170 | /*! |
171 | \fn void QBluetoothSocket::abort() |
172 | |
173 | Aborts the current connection and resets the socket. Unlike disconnectFromService(), this |
174 | function immediately closes the socket, discarding any pending data in the write buffer. |
175 | |
176 | \note On Android, aborting the socket requires asynchronous interaction with Android threads. |
177 | Therefore the associated \l disconnected() and \l stateChanged() signals are delayed |
178 | until the threads have finished the closure. |
179 | |
180 | \sa disconnectFromService(), close() |
181 | */ |
182 | |
183 | /*! |
184 | \fn void QBluetoothSocket::close() |
185 | |
186 | Disconnects the socket's connection with the device. |
187 | |
188 | \note On Android, closing the socket requires asynchronous interaction with Android threads. |
189 | Therefore the associated \l disconnected() and \l stateChanged() signals are delayed |
190 | until the threads have finished the closure. |
191 | |
192 | */ |
193 | |
194 | /*! |
195 | \fn void QBluetoothSocket::disconnectFromService() |
196 | |
197 | Attempts to close the socket. If there is pending data waiting to be written QBluetoothSocket |
198 | will enter ClosingState and wait until all data has been written. Eventually, it will enter |
199 | UnconnectedState and emit the disconnected() signal. |
200 | |
201 | \sa connectToService() |
202 | */ |
203 | |
204 | /*! |
205 | \fn QString QBluetoothSocket::localName() const |
206 | |
207 | Returns the name of the local device. |
208 | |
209 | Although some platforms may differ the socket must generally be connected to guarantee |
210 | the return of a valid name. In particular, this is true when dealing with platforms |
211 | that support multiple local Bluetooth adapters. |
212 | */ |
213 | |
214 | /*! |
215 | \fn QBluetoothAddress QBluetoothSocket::localAddress() const |
216 | |
217 | Returns the address of the local device. |
218 | |
219 | Although some platforms may differ the socket must generally be connected to guarantee |
220 | the return of a valid address. In particular, this is true when dealing with platforms |
221 | that support multiple local Bluetooth adapters. |
222 | */ |
223 | |
224 | /*! |
225 | \fn quint16 QBluetoothSocket::localPort() const |
226 | |
227 | Returns the port number of the local socket if available, otherwise returns 0. |
228 | Although some platforms may differ the socket must generally be connected to guarantee |
229 | the return of a valid port number. |
230 | |
231 | On Android and \macos, this feature is not supported and returns 0. |
232 | */ |
233 | |
234 | /*! |
235 | \fn QString QBluetoothSocket::peerName() const |
236 | |
237 | Returns the name of the peer device. |
238 | */ |
239 | |
240 | /*! |
241 | \fn QBluetoothAddress QBluetoothSocket::peerAddress() const |
242 | |
243 | Returns the address of the peer device. |
244 | */ |
245 | |
246 | /*! |
247 | \fn quint16 QBluetoothSocket::peerPort() const |
248 | |
249 | Return the port number of the peer socket if available, otherwise returns 0. |
250 | On Android, this feature is not supported. |
251 | */ |
252 | |
253 | /*! |
254 | \fn qint64 QBluetoothSocket::readData(char *data, qint64 maxSize) |
255 | |
256 | \reimp |
257 | */ |
258 | |
259 | /*! |
260 | \fn qint64 QBluetoothSocket::writeData(const char *data, qint64 maxSize) |
261 | |
262 | \reimp |
263 | */ |
264 | |
265 | static QBluetoothSocketBasePrivate *createSocketPrivate() |
266 | { |
267 | #if QT_CONFIG(bluez) |
268 | if (bluetoothdVersion() >= QVersionNumber(5, 46)) { |
269 | qCDebug(QT_BT) << "Using Bluetooth dbus socket implementation" ; |
270 | return new QBluetoothSocketPrivateBluezDBus(); |
271 | } else { |
272 | qCDebug(QT_BT) << "Using Bluetooth raw socket implementation" ; |
273 | return new QBluetoothSocketPrivateBluez(); |
274 | } |
275 | #elif defined(QT_ANDROID_BLUETOOTH) |
276 | return new QBluetoothSocketPrivateAndroid(); |
277 | #elif defined(QT_WINRT_BLUETOOTH) |
278 | return new QBluetoothSocketPrivateWinRT(); |
279 | #elif defined(QT_WIN_BLUETOOTH) |
280 | return new QBluetoothSocketPrivateWin(); |
281 | #elif defined(QT_OSX_BLUETOOTH) |
282 | return new QBluetoothSocketPrivate(); |
283 | #else |
284 | return new QBluetoothSocketPrivateDummy(); |
285 | #endif |
286 | } |
287 | |
288 | /*! |
289 | Constructs a Bluetooth socket of \a socketType type, with \a parent. |
290 | */ |
291 | QBluetoothSocket::QBluetoothSocket(QBluetoothServiceInfo::Protocol socketType, QObject *parent) |
292 | : QIODevice(parent) |
293 | { |
294 | d_ptr = createSocketPrivate(); |
295 | d_ptr->q_ptr = this; |
296 | |
297 | Q_D(QBluetoothSocketBase); |
298 | d->ensureNativeSocket(type: socketType); |
299 | |
300 | setOpenMode(QIODevice::NotOpen); |
301 | } |
302 | |
303 | /*! |
304 | Constructs a Bluetooth socket with \a parent. |
305 | */ |
306 | QBluetoothSocket::QBluetoothSocket(QObject *parent) |
307 | : QIODevice(parent) |
308 | { |
309 | d_ptr = createSocketPrivate(); |
310 | d_ptr->q_ptr = this; |
311 | setOpenMode(QIODevice::NotOpen); |
312 | } |
313 | |
314 | #if QT_CONFIG(bluez) |
315 | |
316 | /*! |
317 | \internal |
318 | */ |
319 | QBluetoothSocket::QBluetoothSocket(QBluetoothSocketBasePrivate *dPrivate, |
320 | QBluetoothServiceInfo::Protocol socketType, |
321 | QObject *parent) |
322 | : QIODevice(parent) |
323 | { |
324 | d_ptr = dPrivate; |
325 | d_ptr->q_ptr = this; |
326 | |
327 | Q_D(QBluetoothSocketBase); |
328 | d->ensureNativeSocket(socketType); |
329 | |
330 | setOpenMode(QIODevice::NotOpen); |
331 | } |
332 | |
333 | #endif |
334 | |
335 | /*! |
336 | Destroys the Bluetooth socket. |
337 | */ |
338 | QBluetoothSocket::~QBluetoothSocket() |
339 | { |
340 | delete d_ptr; |
341 | d_ptr = nullptr; |
342 | } |
343 | |
344 | /*! |
345 | \reimp |
346 | */ |
347 | bool QBluetoothSocket::isSequential() const |
348 | { |
349 | return true; |
350 | } |
351 | |
352 | /*! |
353 | Returns the number of incoming bytes that are waiting to be read. |
354 | |
355 | \sa bytesToWrite(), read() |
356 | */ |
357 | qint64 QBluetoothSocket::bytesAvailable() const |
358 | { |
359 | Q_D(const QBluetoothSocketBase); |
360 | return QIODevice::bytesAvailable() + d->bytesAvailable(); |
361 | } |
362 | |
363 | /*! |
364 | Returns the number of bytes that are waiting to be written. The bytes are written when control |
365 | goes back to the event loop. |
366 | */ |
367 | qint64 QBluetoothSocket::bytesToWrite() const |
368 | { |
369 | Q_D(const QBluetoothSocketBase); |
370 | return d->bytesToWrite(); |
371 | } |
372 | |
373 | /*! |
374 | Attempts to connect to the service described by \a service. |
375 | |
376 | The socket is opened in the given \a openMode. The \l socketType() is ignored |
377 | if \a service specifies a differing \l QBluetoothServiceInfo::socketProtocol(). |
378 | |
379 | The socket first enters ConnectingState and attempts to connect to the device providing |
380 | \a service. If a connection is established, QBluetoothSocket enters ConnectedState and |
381 | emits connected(). |
382 | |
383 | At any point, the socket can emit error() to signal that an error occurred. |
384 | |
385 | Note that most platforms require a pairing prior to connecting to the remote device. Otherwise |
386 | the connection process may fail. |
387 | |
388 | On Android, only RFCOMM connections are possible. This function ignores any socket protocol indicator |
389 | and assumes RFCOMM. |
390 | |
391 | \sa state(), disconnectFromService() |
392 | */ |
393 | void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, OpenMode openMode) |
394 | { |
395 | Q_D(QBluetoothSocketBase); |
396 | d->connectToService(service, openMode); |
397 | } |
398 | |
399 | /*! |
400 | \fn void QBluetoothSocket::connectToService(const QBluetoothAddress &address, QBluetoothUuid::ServiceClassUuid uuid, OpenMode mode = ReadWrite) |
401 | |
402 | \internal |
403 | |
404 | Exists to avoid QTBUG-65831. |
405 | */ |
406 | |
407 | /*! |
408 | Attempts to make a connection to the service identified by \a uuid on the device with address |
409 | \a address. |
410 | |
411 | The socket is opened in the given \a openMode. |
412 | |
413 | For BlueZ, the socket first enters the \l ServiceLookupState and queries the connection parameters for |
414 | \a uuid. If the service parameters are successfully retrieved the socket enters |
415 | ConnectingState, and attempts to connect to \a address. If a connection is established, |
416 | QBluetoothSocket enters \l ConnectedState and emits connected(). |
417 | |
418 | On Android, the service connection can directly be established |
419 | using the UUID of the remote service. Therefore the platform does not require |
420 | the \l ServiceLookupState and \l socketType() is always set to |
421 | \l QBluetoothServiceInfo::RfcommProtocol. |
422 | |
423 | At any point, the socket can emit error() to signal that an error occurred. |
424 | |
425 | Note that most platforms require a pairing prior to connecting to the remote device. Otherwise |
426 | the connection process may fail. |
427 | |
428 | \sa state(), disconnectFromService() |
429 | */ |
430 | void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, OpenMode openMode) |
431 | { |
432 | Q_D(QBluetoothSocketBase); |
433 | d->connectToService(address, uuid, openMode); |
434 | } |
435 | |
436 | /*! |
437 | Attempts to make a connection with \a address on the given \a port. |
438 | |
439 | The socket is opened in the given \a openMode. |
440 | |
441 | The socket first enters ConnectingState, and attempts to connect to \a address. If a |
442 | connection is established, QBluetoothSocket enters ConnectedState and emits connected(). |
443 | |
444 | At any point, the socket can emit error() to signal that an error occurred. |
445 | |
446 | On Android and BlueZ (version 5.46 or above), a connection to a service can not be established using a port. |
447 | Calling this function will emit a \l {QBluetoothSocket::ServiceNotFoundError}{ServiceNotFoundError}. |
448 | |
449 | Note that most platforms require a pairing prior to connecting to the remote device. Otherwise |
450 | the connection process may fail. |
451 | |
452 | \sa state(), disconnectFromService() |
453 | */ |
454 | void QBluetoothSocket::connectToService(const QBluetoothAddress &address, quint16 port, OpenMode openMode) |
455 | { |
456 | Q_D(QBluetoothSocketBase); |
457 | d->connectToService(address, port, openMode); |
458 | } |
459 | |
460 | /*! |
461 | Returns the socket type. The socket automatically adjusts to the protocol |
462 | offered by the remote service. |
463 | |
464 | Android only support \l{QBluetoothServiceInfo::RfcommProtocol}{RFCOMM} |
465 | based sockets. |
466 | */ |
467 | QBluetoothServiceInfo::Protocol QBluetoothSocket::socketType() const |
468 | { |
469 | Q_D(const QBluetoothSocketBase); |
470 | return d->socketType; |
471 | } |
472 | |
473 | /*! |
474 | Returns the current state of the socket. |
475 | */ |
476 | QBluetoothSocket::SocketState QBluetoothSocket::state() const |
477 | { |
478 | Q_D(const QBluetoothSocketBase); |
479 | return d->state; |
480 | } |
481 | |
482 | /*! |
483 | Returns the last error. |
484 | */ |
485 | QBluetoothSocket::SocketError QBluetoothSocket::error() const |
486 | { |
487 | Q_D(const QBluetoothSocketBase); |
488 | return d->socketError; |
489 | } |
490 | |
491 | /*! |
492 | Returns a user displayable text string for the error. |
493 | */ |
494 | QString QBluetoothSocket::errorString() const |
495 | { |
496 | Q_D(const QBluetoothSocketBase); |
497 | return d->errorString; |
498 | } |
499 | |
500 | /*! |
501 | Sets the preferred security parameter for the connection attempt to |
502 | \a flags. This value is incorporated when calling \l connectToService(). |
503 | Therefore it is required to reconnect to change this parameter for an |
504 | existing connection. |
505 | |
506 | On Bluez this property is set to QBluetooth::Authorization by default. |
507 | |
508 | On \macos, this value is ignored as the platform does not permit access |
509 | to the security parameter of the socket. By default the platform prefers |
510 | secure/encrypted connections though and therefore this function always |
511 | returns \l QBluetooth::Secure. |
512 | |
513 | Android only supports two levels of security (secure and non-secure). If this flag is set to |
514 | \l QBluetooth::NoSecurity the socket object will not employ any authentication or encryption. |
515 | Any other security flag combination will trigger a secure Bluetooth connection. |
516 | This flag is set to \l QBluetooth::Secure by default. |
517 | |
518 | \note A secure connection requires a pairing between the two devices. On |
519 | some platforms, the pairing is automatically initiated during the establishment |
520 | of the connection. Other platforms require the application to manually trigger |
521 | the pairing before attempting to connect. |
522 | |
523 | \sa preferredSecurityFlags() |
524 | |
525 | \since 5.6 |
526 | */ |
527 | void QBluetoothSocket::setPreferredSecurityFlags(QBluetooth::SecurityFlags flags) |
528 | { |
529 | #ifdef QT_OSX_BLUETOOTH |
530 | return; // not supported on macOS. |
531 | #endif |
532 | Q_D(QBluetoothSocketBase); |
533 | if (d->secFlags != flags) |
534 | d->secFlags = flags; |
535 | } |
536 | |
537 | /*! |
538 | Returns the security parameters used for the initial connection |
539 | attempt. |
540 | |
541 | The security parameters may be renegotiated between the two parties |
542 | during or after the connection has been established. If such a change happens |
543 | it is not reflected in the value of this flag. |
544 | |
545 | On \macos, this flag is always set to \l QBluetooth::Secure. |
546 | |
547 | \sa setPreferredSecurityFlags() |
548 | |
549 | \since 5.6 |
550 | */ |
551 | QBluetooth::SecurityFlags QBluetoothSocket::preferredSecurityFlags() const |
552 | { |
553 | #if QT_OSX_BLUETOOTH |
554 | // not supported on macOS - platform always uses encryption |
555 | return QBluetooth::Secure; |
556 | #else |
557 | Q_D(const QBluetoothSocketBase); |
558 | return d->secFlags; |
559 | #endif // QT_OSX_BLUETOOTH |
560 | } |
561 | |
562 | /*! |
563 | Sets the socket state to \a state. |
564 | */ |
565 | void QBluetoothSocket::setSocketState(QBluetoothSocket::SocketState state) |
566 | { |
567 | Q_D(QBluetoothSocketBase); |
568 | const SocketState old = d->state; |
569 | if (state == old) |
570 | return; |
571 | |
572 | d->state = state; |
573 | if(old != d->state) |
574 | emit stateChanged(state); |
575 | if (state == QBluetoothSocket::ConnectedState) { |
576 | emit connected(); |
577 | } else if ((old == QBluetoothSocket::ConnectedState |
578 | || old == QBluetoothSocket::ClosingState) |
579 | && state == QBluetoothSocket::UnconnectedState) { |
580 | emit disconnected(); |
581 | } |
582 | if(state == ListeningState){ |
583 | #ifdef QT_OSX_BLUETOOTH |
584 | qCWarning(QT_BT) << "listening socket is not supported by IOBluetooth" ; |
585 | #endif |
586 | // TODO: look at this, is this really correct? |
587 | // if we're a listening socket we can't handle connects? |
588 | if (d->readNotifier) { |
589 | d->readNotifier->setEnabled(false); |
590 | } |
591 | } |
592 | } |
593 | |
594 | /*! |
595 | Returns true if you can read at least one line from the device |
596 | */ |
597 | |
598 | bool QBluetoothSocket::canReadLine() const |
599 | { |
600 | Q_D(const QBluetoothSocketBase); |
601 | return d->canReadLine() || QIODevice::canReadLine(); |
602 | } |
603 | |
604 | /*! |
605 | Sets the type of error that last occurred to \a error_. |
606 | */ |
607 | void QBluetoothSocket::setSocketError(QBluetoothSocket::SocketError error_) |
608 | { |
609 | Q_D(QBluetoothSocketBase); |
610 | d->socketError = error_; |
611 | emit error(error: error_); |
612 | } |
613 | |
614 | /*! |
615 | Start device discovery for \a service and open the socket with \a openMode. If the socket |
616 | is created with a service uuid device address, use service discovery to find the |
617 | port number to connect to. |
618 | */ |
619 | |
620 | void QBluetoothSocket::doDeviceDiscovery(const QBluetoothServiceInfo &service, OpenMode openMode) |
621 | { |
622 | Q_D(QBluetoothSocketBase); |
623 | |
624 | setSocketState(QBluetoothSocket::ServiceLookupState); |
625 | qCDebug(QT_BT) << "Starting Bluetooth service discovery" ; |
626 | |
627 | if(d->discoveryAgent) { |
628 | d->discoveryAgent->stop(); |
629 | delete d->discoveryAgent; |
630 | } |
631 | |
632 | d->discoveryAgent = new QBluetoothServiceDiscoveryAgent(this); |
633 | d->discoveryAgent->setRemoteAddress(service.device().address()); |
634 | |
635 | //qDebug() << "Got agent"; |
636 | |
637 | connect(sender: d->discoveryAgent, signal: &QBluetoothServiceDiscoveryAgent::serviceDiscovered, |
638 | receiver: this, slot: &QBluetoothSocket::serviceDiscovered); |
639 | connect(sender: d->discoveryAgent, signal: &QBluetoothServiceDiscoveryAgent::finished, |
640 | receiver: this, slot: &QBluetoothSocket::discoveryFinished); |
641 | |
642 | d->openMode = openMode; |
643 | |
644 | QList<QBluetoothUuid> filterUuids = service.serviceClassUuids(); |
645 | if(!service.serviceUuid().isNull()) |
646 | filterUuids.append(t: service.serviceUuid()); |
647 | |
648 | if (!filterUuids.isEmpty()) |
649 | d->discoveryAgent->setUuidFilter(filterUuids); |
650 | |
651 | // we have to ID the service somehow |
652 | Q_ASSERT(!d->discoveryAgent->uuidFilter().isEmpty()); |
653 | |
654 | qCDebug(QT_BT) << "UUID filter" << d->discoveryAgent->uuidFilter(); |
655 | |
656 | d->discoveryAgent->start(mode: QBluetoothServiceDiscoveryAgent::FullDiscovery); |
657 | } |
658 | |
659 | void QBluetoothSocket::serviceDiscovered(const QBluetoothServiceInfo &service) |
660 | { |
661 | Q_D(QBluetoothSocketBase); |
662 | qCDebug(QT_BT) << "FOUND SERVICE!" << service; |
663 | if (service.protocolServiceMultiplexer() > 0 || service.serverChannel() > 0) { |
664 | connectToService(service, openMode: d->openMode); |
665 | d->discoveryAgent->deleteLater(); |
666 | d->discoveryAgent = nullptr; |
667 | #ifdef QT_WINRT_BLUETOOTH |
668 | } else if (!service.attribute(0xBEEF).isNull() |
669 | && !service.attribute(0xBEF0).isNull()) { |
670 | connectToService(service, d->openMode); |
671 | d->discoveryAgent->deleteLater(); |
672 | d->discoveryAgent = nullptr; |
673 | #endif |
674 | } else { |
675 | qCDebug(QT_BT) << "Could not find port/psm for potential remote service" ; |
676 | } |
677 | } |
678 | |
679 | void QBluetoothSocket::discoveryFinished() |
680 | { |
681 | qCDebug(QT_BT) << "Socket discovery finished" ; |
682 | Q_D(QBluetoothSocketBase); |
683 | if (d->discoveryAgent){ |
684 | qCDebug(QT_BT) << "Didn't find any" ; |
685 | d->errorString = tr(s: "Service cannot be found" ); |
686 | setSocketError(ServiceNotFoundError); |
687 | setSocketState(QBluetoothSocket::UnconnectedState); |
688 | d->discoveryAgent->deleteLater(); |
689 | d->discoveryAgent = nullptr; |
690 | } |
691 | } |
692 | |
693 | void QBluetoothSocket::abort() |
694 | { |
695 | if (state() == UnconnectedState) |
696 | return; |
697 | |
698 | Q_D(QBluetoothSocketBase); |
699 | setOpenMode(QIODevice::NotOpen); |
700 | |
701 | if (state() == ServiceLookupState && d->discoveryAgent) { |
702 | d->discoveryAgent->disconnect(); |
703 | d->discoveryAgent->stop(); |
704 | d->discoveryAgent = nullptr; |
705 | } |
706 | |
707 | setSocketState(ClosingState); |
708 | d->abort(); |
709 | } |
710 | |
711 | void QBluetoothSocket::disconnectFromService() |
712 | { |
713 | close(); |
714 | } |
715 | |
716 | QString QBluetoothSocket::localName() const |
717 | { |
718 | Q_D(const QBluetoothSocketBase); |
719 | return d->localName(); |
720 | } |
721 | |
722 | QBluetoothAddress QBluetoothSocket::localAddress() const |
723 | { |
724 | Q_D(const QBluetoothSocketBase); |
725 | return d->localAddress(); |
726 | } |
727 | |
728 | quint16 QBluetoothSocket::localPort() const |
729 | { |
730 | Q_D(const QBluetoothSocketBase); |
731 | return d->localPort(); |
732 | } |
733 | |
734 | QString QBluetoothSocket::peerName() const |
735 | { |
736 | Q_D(const QBluetoothSocketBase); |
737 | return d->peerName(); |
738 | } |
739 | |
740 | QBluetoothAddress QBluetoothSocket::peerAddress() const |
741 | { |
742 | Q_D(const QBluetoothSocketBase); |
743 | return d->peerAddress(); |
744 | } |
745 | |
746 | quint16 QBluetoothSocket::peerPort() const |
747 | { |
748 | Q_D(const QBluetoothSocketBase); |
749 | return d->peerPort(); |
750 | } |
751 | |
752 | qint64 QBluetoothSocket::writeData(const char *data, qint64 maxSize) |
753 | { |
754 | Q_D(QBluetoothSocketBase); |
755 | |
756 | if (!data || maxSize <= 0) { |
757 | d_ptr->errorString = tr(s: "Invalid data/data size" ); |
758 | setSocketError(QBluetoothSocket::OperationError); |
759 | return -1; |
760 | } |
761 | |
762 | return d->writeData(data, maxSize); |
763 | } |
764 | |
765 | qint64 QBluetoothSocket::readData(char *data, qint64 maxSize) |
766 | { |
767 | Q_D(QBluetoothSocketBase); |
768 | return d->readData(data, maxSize); |
769 | } |
770 | |
771 | void QBluetoothSocket::close() |
772 | { |
773 | if (state() == UnconnectedState) |
774 | return; |
775 | |
776 | Q_D(QBluetoothSocketBase); |
777 | setOpenMode(QIODevice::NotOpen); |
778 | |
779 | if (state() == ServiceLookupState && d->discoveryAgent) { |
780 | d->discoveryAgent->disconnect(); |
781 | d->discoveryAgent->stop(); |
782 | d->discoveryAgent = nullptr; |
783 | } |
784 | |
785 | setSocketState(ClosingState); |
786 | |
787 | d->close(); |
788 | } |
789 | |
790 | /*! |
791 | Set the socket to use \a socketDescriptor with a type of \a socketType, |
792 | which is in state, \a socketState, and mode, \a openMode. |
793 | |
794 | Returns true on success |
795 | */ |
796 | |
797 | |
798 | bool QBluetoothSocket::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType, |
799 | SocketState socketState, OpenMode openMode) |
800 | { |
801 | Q_D(QBluetoothSocketBase); |
802 | return d->setSocketDescriptor(socketDescriptor, socketType, socketState, openMode); |
803 | } |
804 | |
805 | /*! |
806 | Returns the platform-specific socket descriptor, if available. |
807 | This function returns -1 if the descriptor is not available or an error has occurred. |
808 | */ |
809 | |
810 | int QBluetoothSocket::socketDescriptor() const |
811 | { |
812 | Q_D(const QBluetoothSocketBase); |
813 | return d->socket; |
814 | } |
815 | |
816 | |
817 | |
818 | #ifndef QT_NO_DEBUG_STREAM |
819 | QDebug operator<<(QDebug debug, QBluetoothSocket::SocketError error) |
820 | { |
821 | switch (error) { |
822 | case QBluetoothSocket::UnknownSocketError: |
823 | debug << "QBluetoothSocket::UnknownSocketError" ; |
824 | break; |
825 | case QBluetoothSocket::HostNotFoundError: |
826 | debug << "QBluetoothSocket::HostNotFoundError" ; |
827 | break; |
828 | case QBluetoothSocket::RemoteHostClosedError: |
829 | debug << "QBluetoothSocket::RemoteHostClosedError" ; |
830 | break; |
831 | case QBluetoothSocket::ServiceNotFoundError: |
832 | debug << "QBluetoothSocket::ServiceNotFoundError" ; |
833 | break; |
834 | case QBluetoothSocket::NetworkError: |
835 | debug << "QBluetoothSocket::NetworkError" ; |
836 | break; |
837 | case QBluetoothSocket::UnsupportedProtocolError: |
838 | debug << "QBluetoothSocket::UnsupportedProtocolError" ; |
839 | break; |
840 | default: |
841 | debug << "QBluetoothSocket::SocketError(" << (int)error << ")" ; |
842 | } |
843 | return debug; |
844 | } |
845 | |
846 | QDebug operator<<(QDebug debug, QBluetoothSocket::SocketState state) |
847 | { |
848 | switch (state) { |
849 | case QBluetoothSocket::UnconnectedState: |
850 | debug << "QBluetoothSocket::UnconnectedState" ; |
851 | break; |
852 | case QBluetoothSocket::ConnectingState: |
853 | debug << "QBluetoothSocket::ConnectingState" ; |
854 | break; |
855 | case QBluetoothSocket::ConnectedState: |
856 | debug << "QBluetoothSocket::ConnectedState" ; |
857 | break; |
858 | case QBluetoothSocket::BoundState: |
859 | debug << "QBluetoothSocket::BoundState" ; |
860 | break; |
861 | case QBluetoothSocket::ClosingState: |
862 | debug << "QBluetoothSocket::ClosingState" ; |
863 | break; |
864 | case QBluetoothSocket::ListeningState: |
865 | debug << "QBluetoothSocket::ListeningState" ; |
866 | break; |
867 | case QBluetoothSocket::ServiceLookupState: |
868 | debug << "QBluetoothSocket::ServiceLookupState" ; |
869 | break; |
870 | default: |
871 | debug << "QBluetoothSocket::SocketState(" << (int)state << ")" ; |
872 | } |
873 | return debug; |
874 | } |
875 | #endif |
876 | |
877 | QT_END_NAMESPACE |
878 | |
879 | #include "moc_qbluetoothsocket.cpp" |
880 | |