1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2018 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtBluetooth module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qbluetoothsocket.h" |
41 | #include "qbluetoothsocket_bluez_p.h" |
42 | #include "qbluetoothdeviceinfo.h" |
43 | |
44 | #include "bluez/manager_p.h" |
45 | #include "bluez/adapter_p.h" |
46 | #include "bluez/device_p.h" |
47 | #include "bluez/objectmanager_p.h" |
48 | #include <QtBluetooth/QBluetoothLocalDevice> |
49 | #include "bluez/bluez_data_p.h" |
50 | |
51 | #include <qplatformdefs.h> |
52 | #include <QtCore/private/qcore_unix_p.h> |
53 | |
54 | #include <QtCore/QLoggingCategory> |
55 | |
56 | #include <errno.h> |
57 | #include <unistd.h> |
58 | #include <string.h> |
59 | |
60 | #include <QtCore/QSocketNotifier> |
61 | |
62 | QT_BEGIN_NAMESPACE |
63 | |
64 | Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) |
65 | |
66 | QBluetoothSocketPrivateBluez::QBluetoothSocketPrivateBluez() |
67 | : QBluetoothSocketBasePrivate() |
68 | { |
69 | secFlags = QBluetooth::Authorization; |
70 | } |
71 | |
72 | QBluetoothSocketPrivateBluez::~QBluetoothSocketPrivateBluez() |
73 | { |
74 | delete readNotifier; |
75 | readNotifier = nullptr; |
76 | delete connectWriteNotifier; |
77 | connectWriteNotifier = nullptr; |
78 | } |
79 | |
80 | bool QBluetoothSocketPrivateBluez::ensureNativeSocket(QBluetoothServiceInfo::Protocol type) |
81 | { |
82 | if (socket != -1) { |
83 | if (socketType == type) |
84 | return true; |
85 | |
86 | delete readNotifier; |
87 | readNotifier = nullptr; |
88 | delete connectWriteNotifier; |
89 | connectWriteNotifier = nullptr; |
90 | QT_CLOSE(socket); |
91 | } |
92 | |
93 | socketType = type; |
94 | |
95 | switch (type) { |
96 | case QBluetoothServiceInfo::L2capProtocol: |
97 | socket = ::socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); |
98 | break; |
99 | case QBluetoothServiceInfo::RfcommProtocol: |
100 | socket = ::socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); |
101 | break; |
102 | default: |
103 | socket = -1; |
104 | } |
105 | |
106 | if (socket == -1) |
107 | return false; |
108 | |
109 | int flags = fcntl(socket, F_GETFL, 0); |
110 | fcntl(socket, F_SETFL, flags | O_NONBLOCK); |
111 | |
112 | Q_Q(QBluetoothSocket); |
113 | readNotifier = new QSocketNotifier(socket, QSocketNotifier::Read); |
114 | QObject::connect(readNotifier, SIGNAL(activated(int)), this, SLOT(_q_readNotify())); |
115 | connectWriteNotifier = new QSocketNotifier(socket, QSocketNotifier::Write, q); |
116 | QObject::connect(connectWriteNotifier, SIGNAL(activated(int)), this, SLOT(_q_writeNotify())); |
117 | |
118 | connectWriteNotifier->setEnabled(false); |
119 | readNotifier->setEnabled(false); |
120 | |
121 | |
122 | return true; |
123 | } |
124 | |
125 | void QBluetoothSocketPrivateBluez::connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode) |
126 | { |
127 | Q_Q(QBluetoothSocket); |
128 | int result = -1; |
129 | |
130 | if (socket == -1 && !ensureNativeSocket(socketType)) { |
131 | errorString = QBluetoothSocket::tr("Unknown socket error" ); |
132 | q->setSocketError(QBluetoothSocket::UnknownSocketError); |
133 | return; |
134 | } |
135 | |
136 | // apply preferred security level |
137 | // ignore QBluetooth::Authentication -> not used anymore by kernel |
138 | struct bt_security security; |
139 | memset(&security, 0, sizeof(security)); |
140 | |
141 | if (secFlags & QBluetooth::Authorization) |
142 | security.level = BT_SECURITY_LOW; |
143 | if (secFlags & QBluetooth::Encryption) |
144 | security.level = BT_SECURITY_MEDIUM; |
145 | if (secFlags & QBluetooth::Secure) |
146 | security.level = BT_SECURITY_HIGH; |
147 | |
148 | if (setsockopt(socket, SOL_BLUETOOTH, BT_SECURITY, |
149 | &security, sizeof(security)) != 0) { |
150 | qCWarning(QT_BT_BLUEZ) << "Failed to set socket option, closing socket for safety" << errno; |
151 | qCWarning(QT_BT_BLUEZ) << "Error: " << qt_error_string(errno); |
152 | errorString = QBluetoothSocket::tr("Cannot set connection security level" ); |
153 | q->setSocketError(QBluetoothSocket::UnknownSocketError); |
154 | return; |
155 | } |
156 | |
157 | if (socketType == QBluetoothServiceInfo::RfcommProtocol) { |
158 | sockaddr_rc addr; |
159 | |
160 | memset(&addr, 0, sizeof(addr)); |
161 | addr.rc_family = AF_BLUETOOTH; |
162 | addr.rc_channel = port; |
163 | |
164 | convertAddress(address.toUInt64(), addr.rc_bdaddr.b); |
165 | |
166 | connectWriteNotifier->setEnabled(true); |
167 | readNotifier->setEnabled(true); |
168 | |
169 | result = ::connect(socket, (sockaddr *)&addr, sizeof(addr)); |
170 | } else if (socketType == QBluetoothServiceInfo::L2capProtocol) { |
171 | sockaddr_l2 addr; |
172 | |
173 | memset(&addr, 0, sizeof(addr)); |
174 | addr.l2_family = AF_BLUETOOTH; |
175 | // This is an ugly hack but the socket class does what's needed already. |
176 | // For L2CP GATT we need a channel rather than a socket and the LE address type |
177 | // We don't want to make this public API offering for now especially since |
178 | // only Linux (of all platforms supported by this library) supports this type |
179 | // of socket. |
180 | |
181 | #if QT_CONFIG(bluez) && !defined(QT_BLUEZ_NO_BTLE) |
182 | if (lowEnergySocketType) { |
183 | addr.l2_cid = htobs(port); |
184 | addr.l2_bdaddr_type = lowEnergySocketType; |
185 | } else { |
186 | addr.l2_psm = htobs(port); |
187 | } |
188 | #else |
189 | addr.l2_psm = htobs(port); |
190 | #endif |
191 | |
192 | convertAddress(address.toUInt64(), addr.l2_bdaddr.b); |
193 | |
194 | connectWriteNotifier->setEnabled(true); |
195 | readNotifier->setEnabled(true); |
196 | |
197 | result = ::connect(socket, (sockaddr *)&addr, sizeof(addr)); |
198 | } |
199 | |
200 | if (result >= 0 || (result == -1 && errno == EINPROGRESS)) { |
201 | connecting = true; |
202 | q->setSocketState(QBluetoothSocket::ConnectingState); |
203 | q->setOpenMode(openMode); |
204 | } else { |
205 | errorString = qt_error_string(errno); |
206 | q->setSocketError(QBluetoothSocket::UnknownSocketError); |
207 | } |
208 | } |
209 | |
210 | void QBluetoothSocketPrivateBluez::connectToService( |
211 | const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode) |
212 | { |
213 | Q_Q(QBluetoothSocket); |
214 | |
215 | if (q->state() != QBluetoothSocket::UnconnectedState |
216 | && q->state() != QBluetoothSocket::ServiceLookupState) { |
217 | qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket" ; |
218 | errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress" ); |
219 | q->setSocketError(QBluetoothSocket::OperationError); |
220 | return; |
221 | } |
222 | |
223 | // we are checking the service protocol and not socketType() |
224 | // socketType will change in ensureNativeSocket() |
225 | if (service.socketProtocol() == QBluetoothServiceInfo::UnknownProtocol) { |
226 | qCWarning(QT_BT_BLUEZ) << "QBluetoothSocket::connectToService cannot " |
227 | "connect with 'UnknownProtocol' (type provided by given service)" ; |
228 | errorString = QBluetoothSocket::tr("Socket type not supported" ); |
229 | q->setSocketError(QBluetoothSocket::UnsupportedProtocolError); |
230 | return; |
231 | } |
232 | |
233 | if (service.protocolServiceMultiplexer() > 0) { |
234 | Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::L2capProtocol); |
235 | |
236 | if (!ensureNativeSocket(QBluetoothServiceInfo::L2capProtocol)) { |
237 | errorString = QBluetoothSocket::tr("Unknown socket error" ); |
238 | q->setSocketError(QBluetoothSocket::UnknownSocketError); |
239 | return; |
240 | } |
241 | connectToServiceHelper(service.device().address(), service.protocolServiceMultiplexer(), |
242 | openMode); |
243 | } else if (service.serverChannel() > 0) { |
244 | Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol); |
245 | |
246 | if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) { |
247 | errorString = QBluetoothSocket::tr("Unknown socket error" ); |
248 | q->setSocketError(QBluetoothSocket::UnknownSocketError); |
249 | return; |
250 | } |
251 | connectToServiceHelper(service.device().address(), service.serverChannel(), openMode); |
252 | } else { |
253 | // try doing service discovery to see if we can find the socket |
254 | if (service.serviceUuid().isNull() |
255 | && !service.serviceClassUuids().contains(QBluetoothUuid::SerialPort)) { |
256 | qCWarning(QT_BT_BLUEZ) << "No port, no PSM, and no UUID provided. Unable to connect" ; |
257 | return; |
258 | } |
259 | qCDebug(QT_BT_BLUEZ) << "Need a port/psm, doing discovery" ; |
260 | q->doDeviceDiscovery(service, openMode); |
261 | } |
262 | } |
263 | |
264 | void QBluetoothSocketPrivateBluez::connectToService( |
265 | const QBluetoothAddress &address, const QBluetoothUuid &uuid, |
266 | QIODevice::OpenMode openMode) |
267 | { |
268 | Q_Q(QBluetoothSocket); |
269 | |
270 | if (q->state() != QBluetoothSocket::UnconnectedState) { |
271 | qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket" ; |
272 | errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress" ); |
273 | q->setSocketError(QBluetoothSocket::OperationError); |
274 | return; |
275 | } |
276 | |
277 | if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) { |
278 | qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService cannot " |
279 | "connect with 'UnknownProtocol' (type provided by given service)" ; |
280 | errorString = QBluetoothSocket::tr("Socket type not supported" ); |
281 | q->setSocketError(QBluetoothSocket::UnsupportedProtocolError); |
282 | return; |
283 | } |
284 | |
285 | QBluetoothServiceInfo service; |
286 | QBluetoothDeviceInfo device(address, QString(), QBluetoothDeviceInfo::MiscellaneousDevice); |
287 | service.setDevice(device); |
288 | service.setServiceUuid(uuid); |
289 | q->doDeviceDiscovery(service, openMode); |
290 | } |
291 | |
292 | void QBluetoothSocketPrivateBluez::connectToService( |
293 | const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode) |
294 | { |
295 | Q_Q(QBluetoothSocket); |
296 | |
297 | if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) { |
298 | qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService cannot " |
299 | "connect with 'UnknownProtocol' (type provided by given service)" ; |
300 | errorString = QBluetoothSocket::tr("Socket type not supported" ); |
301 | q->setSocketError(QBluetoothSocket::UnsupportedProtocolError); |
302 | return; |
303 | } |
304 | |
305 | if (q->state() != QBluetoothSocket::UnconnectedState) { |
306 | qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket" ; |
307 | errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress" ); |
308 | q->setSocketError(QBluetoothSocket::OperationError); |
309 | return; |
310 | } |
311 | connectToServiceHelper(address, port, openMode); |
312 | } |
313 | |
314 | void QBluetoothSocketPrivateBluez::_q_writeNotify() |
315 | { |
316 | Q_Q(QBluetoothSocket); |
317 | if(connecting && state == QBluetoothSocket::ConnectingState){ |
318 | int errorno, len; |
319 | len = sizeof(errorno); |
320 | ::getsockopt(socket, SOL_SOCKET, SO_ERROR, &errorno, (socklen_t*)&len); |
321 | if(errorno) { |
322 | errorString = qt_error_string(errorno); |
323 | q->setSocketError(QBluetoothSocket::UnknownSocketError); |
324 | return; |
325 | } |
326 | |
327 | q->setSocketState(QBluetoothSocket::ConnectedState); |
328 | |
329 | connectWriteNotifier->setEnabled(false); |
330 | connecting = false; |
331 | } |
332 | else { |
333 | if (txBuffer.size() == 0) { |
334 | connectWriteNotifier->setEnabled(false); |
335 | return; |
336 | } |
337 | |
338 | char buf[1024]; |
339 | |
340 | int size = txBuffer.read(buf, 1024); |
341 | int writtenBytes = qt_safe_write(socket, buf, size); |
342 | if (writtenBytes < 0) { |
343 | switch (errno) { |
344 | case EAGAIN: |
345 | writtenBytes = 0; |
346 | txBuffer.ungetBlock(buf, size); |
347 | break; |
348 | default: |
349 | // every other case returns error |
350 | errorString = QBluetoothSocket::tr("Network Error: %1" ).arg(qt_error_string(errno)) ; |
351 | q->setSocketError(QBluetoothSocket::NetworkError); |
352 | break; |
353 | } |
354 | } else { |
355 | if (writtenBytes < size) { |
356 | // add remainder back to buffer |
357 | char* remainder = buf + writtenBytes; |
358 | txBuffer.ungetBlock(remainder, size - writtenBytes); |
359 | } |
360 | if (writtenBytes > 0) |
361 | emit q->bytesWritten(writtenBytes); |
362 | } |
363 | |
364 | if (txBuffer.size()) { |
365 | connectWriteNotifier->setEnabled(true); |
366 | } |
367 | else if (state == QBluetoothSocket::ClosingState) { |
368 | connectWriteNotifier->setEnabled(false); |
369 | this->close(); |
370 | } |
371 | } |
372 | } |
373 | |
374 | void QBluetoothSocketPrivateBluez::_q_readNotify() |
375 | { |
376 | Q_Q(QBluetoothSocket); |
377 | char *writePointer = buffer.reserve(QPRIVATELINEARBUFFER_BUFFERSIZE); |
378 | // qint64 readFromDevice = q->readData(writePointer, QPRIVATELINEARBUFFER_BUFFERSIZE); |
379 | int readFromDevice = ::read(socket, writePointer, QPRIVATELINEARBUFFER_BUFFERSIZE); |
380 | buffer.chop(QPRIVATELINEARBUFFER_BUFFERSIZE - (readFromDevice < 0 ? 0 : readFromDevice)); |
381 | if(readFromDevice <= 0){ |
382 | int errsv = errno; |
383 | readNotifier->setEnabled(false); |
384 | connectWriteNotifier->setEnabled(false); |
385 | errorString = qt_error_string(errsv); |
386 | qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << socket << "error:" << readFromDevice << errorString; |
387 | if (errsv == EHOSTDOWN) |
388 | q->setSocketError(QBluetoothSocket::HostNotFoundError); |
389 | else if (errsv == ECONNRESET) |
390 | q->setSocketError(QBluetoothSocket::RemoteHostClosedError); |
391 | else |
392 | q->setSocketError(QBluetoothSocket::UnknownSocketError); |
393 | |
394 | q->disconnectFromService(); |
395 | } |
396 | else { |
397 | emit q->readyRead(); |
398 | } |
399 | } |
400 | |
401 | void QBluetoothSocketPrivateBluez::abort() |
402 | { |
403 | delete readNotifier; |
404 | readNotifier = nullptr; |
405 | delete connectWriteNotifier; |
406 | connectWriteNotifier = nullptr; |
407 | |
408 | // We don't transition through Closing for abort, so |
409 | // we don't call disconnectFromService or |
410 | // QBluetoothSocket::close |
411 | QT_CLOSE(socket); |
412 | socket = -1; |
413 | |
414 | Q_Q(QBluetoothSocket); |
415 | |
416 | q->setOpenMode(QIODevice::NotOpen); |
417 | q->setSocketState(QBluetoothSocket::UnconnectedState); |
418 | emit q->readChannelFinished(); |
419 | emit q->disconnected(); |
420 | } |
421 | |
422 | QString QBluetoothSocketPrivateBluez::localName() const |
423 | { |
424 | const QBluetoothAddress address = localAddress(); |
425 | if (address.isNull()) |
426 | return QString(); |
427 | |
428 | QBluetoothLocalDevice device(address); |
429 | return device.name(); |
430 | } |
431 | |
432 | QBluetoothAddress QBluetoothSocketPrivateBluez::localAddress() const |
433 | { |
434 | if (socketType == QBluetoothServiceInfo::RfcommProtocol) { |
435 | sockaddr_rc addr; |
436 | socklen_t addrLength = sizeof(addr); |
437 | |
438 | if (::getsockname(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0) |
439 | return QBluetoothAddress(convertAddress(addr.rc_bdaddr.b)); |
440 | } else if (socketType == QBluetoothServiceInfo::L2capProtocol) { |
441 | sockaddr_l2 addr; |
442 | socklen_t addrLength = sizeof(addr); |
443 | |
444 | if (::getsockname(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0) |
445 | return QBluetoothAddress(convertAddress(addr.l2_bdaddr.b)); |
446 | } |
447 | |
448 | return QBluetoothAddress(); |
449 | } |
450 | |
451 | quint16 QBluetoothSocketPrivateBluez::localPort() const |
452 | { |
453 | if (socketType == QBluetoothServiceInfo::RfcommProtocol) { |
454 | sockaddr_rc addr; |
455 | socklen_t addrLength = sizeof(addr); |
456 | |
457 | if (::getsockname(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0) |
458 | return addr.rc_channel; |
459 | } else if (socketType == QBluetoothServiceInfo::L2capProtocol) { |
460 | sockaddr_l2 addr; |
461 | socklen_t addrLength = sizeof(addr); |
462 | |
463 | if (::getsockname(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0) |
464 | return addr.l2_psm; |
465 | } |
466 | |
467 | return 0; |
468 | } |
469 | |
470 | QString QBluetoothSocketPrivateBluez::peerName() const |
471 | { |
472 | quint64 bdaddr; |
473 | |
474 | if (socketType == QBluetoothServiceInfo::RfcommProtocol) { |
475 | sockaddr_rc addr; |
476 | socklen_t addrLength = sizeof(addr); |
477 | |
478 | if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) < 0) |
479 | return QString(); |
480 | |
481 | convertAddress(addr.rc_bdaddr.b, &bdaddr); |
482 | } else if (socketType == QBluetoothServiceInfo::L2capProtocol) { |
483 | sockaddr_l2 addr; |
484 | socklen_t addrLength = sizeof(addr); |
485 | |
486 | if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) < 0) |
487 | return QString(); |
488 | |
489 | convertAddress(addr.l2_bdaddr.b, &bdaddr); |
490 | } else { |
491 | qCWarning(QT_BT_BLUEZ) << "peerName() called on socket of unknown type" ; |
492 | return QString(); |
493 | } |
494 | |
495 | const QString peerAddress = QBluetoothAddress(bdaddr).toString(); |
496 | const QString localAdapter = localAddress().toString(); |
497 | |
498 | if (isBluez5()) { |
499 | OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez" ), |
500 | QStringLiteral("/" ), |
501 | QDBusConnection::systemBus()); |
502 | QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects(); |
503 | reply.waitForFinished(); |
504 | if (reply.isError()) |
505 | return QString(); |
506 | |
507 | ManagedObjectList managedObjectList = reply.value(); |
508 | for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) { |
509 | const InterfaceList &ifaceList = it.value(); |
510 | |
511 | for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) { |
512 | const QString &iface = jt.key(); |
513 | const QVariantMap &ifaceValues = jt.value(); |
514 | |
515 | if (iface == QStringLiteral("org.bluez.Device1" )) { |
516 | if (ifaceValues.value(QStringLiteral("Address" )).toString() == peerAddress) |
517 | return ifaceValues.value(QStringLiteral("Alias" )).toString(); |
518 | } |
519 | } |
520 | } |
521 | return QString(); |
522 | } else { |
523 | OrgBluezManagerInterface manager(QStringLiteral("org.bluez" ), QStringLiteral("/" ), |
524 | QDBusConnection::systemBus()); |
525 | |
526 | QDBusPendingReply<QDBusObjectPath> reply = manager.FindAdapter(localAdapter); |
527 | reply.waitForFinished(); |
528 | if (reply.isError()) |
529 | return QString(); |
530 | |
531 | OrgBluezAdapterInterface adapter(QStringLiteral("org.bluez" ), reply.value().path(), |
532 | QDBusConnection::systemBus()); |
533 | |
534 | QDBusPendingReply<QDBusObjectPath> deviceObjectPath = adapter.FindDevice(peerAddress); |
535 | deviceObjectPath.waitForFinished(); |
536 | if (deviceObjectPath.isError()) { |
537 | if (deviceObjectPath.error().name() != QStringLiteral("org.bluez.Error.DoesNotExist" )) |
538 | return QString(); |
539 | |
540 | deviceObjectPath = adapter.CreateDevice(peerAddress); |
541 | deviceObjectPath.waitForFinished(); |
542 | if (deviceObjectPath.isError()) |
543 | return QString(); |
544 | } |
545 | |
546 | OrgBluezDeviceInterface device(QStringLiteral("org.bluez" ), deviceObjectPath.value().path(), |
547 | QDBusConnection::systemBus()); |
548 | |
549 | QDBusPendingReply<QVariantMap> properties = device.GetProperties(); |
550 | properties.waitForFinished(); |
551 | if (properties.isError()) |
552 | return QString(); |
553 | |
554 | return properties.value().value(QStringLiteral("Alias" )).toString(); |
555 | } |
556 | } |
557 | |
558 | QBluetoothAddress QBluetoothSocketPrivateBluez::peerAddress() const |
559 | { |
560 | if (socketType == QBluetoothServiceInfo::RfcommProtocol) { |
561 | sockaddr_rc addr; |
562 | socklen_t addrLength = sizeof(addr); |
563 | |
564 | if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0) |
565 | return QBluetoothAddress(convertAddress(addr.rc_bdaddr.b)); |
566 | } else if (socketType == QBluetoothServiceInfo::L2capProtocol) { |
567 | sockaddr_l2 addr; |
568 | socklen_t addrLength = sizeof(addr); |
569 | |
570 | if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0) |
571 | return QBluetoothAddress(convertAddress(addr.l2_bdaddr.b)); |
572 | } |
573 | |
574 | return QBluetoothAddress(); |
575 | } |
576 | |
577 | quint16 QBluetoothSocketPrivateBluez::peerPort() const |
578 | { |
579 | if (socketType == QBluetoothServiceInfo::RfcommProtocol) { |
580 | sockaddr_rc addr; |
581 | socklen_t addrLength = sizeof(addr); |
582 | |
583 | if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0) |
584 | return addr.rc_channel; |
585 | } else if (socketType == QBluetoothServiceInfo::L2capProtocol) { |
586 | sockaddr_l2 addr; |
587 | socklen_t addrLength = sizeof(addr); |
588 | |
589 | if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0) |
590 | return addr.l2_psm; |
591 | } |
592 | |
593 | return 0; |
594 | } |
595 | |
596 | qint64 QBluetoothSocketPrivateBluez::writeData(const char *data, qint64 maxSize) |
597 | { |
598 | Q_Q(QBluetoothSocket); |
599 | |
600 | if (state != QBluetoothSocket::ConnectedState) { |
601 | errorString = QBluetoothSocket::tr("Cannot write while not connected" ); |
602 | q->setSocketError(QBluetoothSocket::OperationError); |
603 | return -1; |
604 | } |
605 | |
606 | if (q->openMode() & QIODevice::Unbuffered) { |
607 | int sz = ::qt_safe_write(socket, data, maxSize); |
608 | if (sz < 0) { |
609 | switch (errno) { |
610 | case EAGAIN: |
611 | sz = 0; |
612 | break; |
613 | default: |
614 | errorString = QBluetoothSocket::tr("Network Error: %1" ).arg(qt_error_string(errno)); |
615 | q->setSocketError(QBluetoothSocket::NetworkError); |
616 | } |
617 | } |
618 | |
619 | if (sz > 0) |
620 | emit q->bytesWritten(sz); |
621 | |
622 | return sz; |
623 | } |
624 | else { |
625 | |
626 | if(!connectWriteNotifier) |
627 | return -1; |
628 | |
629 | if(txBuffer.size() == 0) { |
630 | connectWriteNotifier->setEnabled(true); |
631 | QMetaObject::invokeMethod(this, "_q_writeNotify" , Qt::QueuedConnection); |
632 | } |
633 | |
634 | char *txbuf = txBuffer.reserve(maxSize); |
635 | memcpy(txbuf, data, maxSize); |
636 | |
637 | return maxSize; |
638 | } |
639 | } |
640 | |
641 | qint64 QBluetoothSocketPrivateBluez::readData(char *data, qint64 maxSize) |
642 | { |
643 | Q_Q(QBluetoothSocket); |
644 | |
645 | if (state != QBluetoothSocket::ConnectedState) { |
646 | errorString = QBluetoothSocket::tr("Cannot read while not connected" ); |
647 | q->setSocketError(QBluetoothSocket::OperationError); |
648 | return -1; |
649 | } |
650 | |
651 | if (!buffer.isEmpty()) { |
652 | int i = buffer.read(data, maxSize); |
653 | return i; |
654 | } |
655 | |
656 | return 0; |
657 | } |
658 | |
659 | void QBluetoothSocketPrivateBluez::close() |
660 | { |
661 | if (txBuffer.size() > 0) |
662 | connectWriteNotifier->setEnabled(true); |
663 | else |
664 | abort(); |
665 | } |
666 | |
667 | bool QBluetoothSocketPrivateBluez::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType_, |
668 | QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode) |
669 | { |
670 | Q_Q(QBluetoothSocket); |
671 | delete readNotifier; |
672 | readNotifier = nullptr; |
673 | delete connectWriteNotifier; |
674 | connectWriteNotifier = nullptr; |
675 | |
676 | socketType = socketType_; |
677 | if (socket != -1) |
678 | QT_CLOSE(socket); |
679 | |
680 | socket = socketDescriptor; |
681 | |
682 | // ensure that O_NONBLOCK is set on new connections. |
683 | int flags = fcntl(socket, F_GETFL, 0); |
684 | if (!(flags & O_NONBLOCK)) |
685 | fcntl(socket, F_SETFL, flags | O_NONBLOCK); |
686 | |
687 | readNotifier = new QSocketNotifier(socket, QSocketNotifier::Read); |
688 | QObject::connect(readNotifier, SIGNAL(activated(int)), this, SLOT(_q_readNotify())); |
689 | connectWriteNotifier = new QSocketNotifier(socket, QSocketNotifier::Write, q); |
690 | QObject::connect(connectWriteNotifier, SIGNAL(activated(int)), this, SLOT(_q_writeNotify())); |
691 | |
692 | q->setSocketState(socketState); |
693 | q->setOpenMode(openMode); |
694 | |
695 | return true; |
696 | } |
697 | |
698 | qint64 QBluetoothSocketPrivateBluez::bytesAvailable() const |
699 | { |
700 | return buffer.size(); |
701 | } |
702 | |
703 | qint64 QBluetoothSocketPrivateBluez::bytesToWrite() const |
704 | { |
705 | return txBuffer.size(); |
706 | } |
707 | |
708 | bool QBluetoothSocketPrivateBluez::canReadLine() const |
709 | { |
710 | return buffer.canReadLine(); |
711 | } |
712 | |
713 | QT_END_NAMESPACE |
714 | |