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