Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2016 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 "osx/osxbtservicerecord_p.h"
41#include "qbluetoothserviceinfo_p.h"
42#include "qbluetoothserviceinfo.h"
43#include "qbluetoothdeviceinfo.h"
44#include "qbluetoothserver_p.h"
45#include "osx/osxbtutility_p.h"
46#include "osx/osxbluetooth_p.h"
47
48#include <QtCore/qloggingcategory.h>
49#include <QtCore/qvariant.h>
50#include <QtCore/qglobal.h>
51#include <QtCore/qmutex.h>
52#include <QtCore/qmap.h>
53#include <QtCore/qurl.h>
54
55#include <Foundation/Foundation.h>
56
57QT_BEGIN_NAMESPACE
58
59namespace {
60
61using DarwinBluetooth::RetainPolicy;
62using ServiceInfo = QBluetoothServiceInfo;
63
64// Alas, since there is no d_ptr<->q_ptr link (which is not that bad in itself),
65// I need these getters duplicated here:
66ServiceInfo::Protocol socket_protocol(const QBluetoothServiceInfoPrivate &privateInfo)
67{
68 ServiceInfo::Sequence parameters = privateInfo.protocolDescriptor(QBluetoothUuid::Rfcomm);
69 if (!parameters.isEmpty())
70 return ServiceInfo::RfcommProtocol;
71
72 parameters = privateInfo.protocolDescriptor(QBluetoothUuid::L2cap);
73 if (!parameters.isEmpty())
74 return ServiceInfo::L2capProtocol;
75
76 return ServiceInfo::UnknownProtocol;
77}
78
79int channel_or_psm(const QBluetoothServiceInfoPrivate &privateInfo, QBluetoothUuid::ProtocolUuid uuid)
80{
81 const auto parameters = privateInfo.protocolDescriptor(uuid);
82 if (parameters.isEmpty())
83 return -1;
84 else if (parameters.count() == 1)
85 return 0;
86
87 return parameters.at(1).toInt();
88}
89
90} // unnamed namespace
91
92QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate()
93{
94}
95
96QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
97{
98}
99
100bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAddress)
101{
102 Q_UNUSED(localAddress);
103 return false;
104}
105
106bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothServiceInfo &info)
107{
108 using namespace OSXBluetooth;
109
110 if (isRegistered())
111 return false;
112
113 using namespace OSXBluetooth;
114
115 ObjCStrongReference<NSMutableDictionary> serviceDict(iobluetooth_service_dictionary(info));
116 if (!serviceDict) {
117 qCWarning(QT_BT_OSX) << "failed to create a service dictionary";
118 return false;
119 }
120
121 Q_ASSERT(!registered);
122 Q_ASSERT_X(!serviceRecord, Q_FUNC_INFO, "not registered, but serviceRecord is not nil");
123
124 SDPRecord newRecord;
125 newRecord.reset([IOBluetoothSDPServiceRecord
126 publishedServiceRecordWithDictionary:serviceDict], RetainPolicy::doInitialRetain);
127 if (!newRecord) {
128 qCWarning(QT_BT_OSX) << "failed to register a service record";
129 return false;
130 }
131
132 BluetoothSDPServiceRecordHandle newRecordHandle = 0;
133 auto *ioSDPRecord = newRecord.getAs<IOBluetoothSDPServiceRecord>();
134 if ([ioSDPRecord getServiceRecordHandle:&newRecordHandle] != kIOReturnSuccess) {
135 qCWarning(QT_BT_OSX) << "failed to register a service record";
136 [ioSDPRecord removeServiceRecord];
137 return false;
138 }
139
140 const ServiceInfo::Protocol type = info.socketProtocol();
141 quint16 realPort = 0;
142 QBluetoothServerPrivate *server = nullptr;
143 bool configured = false;
144
145 if (type == QBluetoothServiceInfo::L2capProtocol) {
146 BluetoothL2CAPPSM psm = 0;
147 server = QBluetoothServerPrivate::registeredServer(info.protocolServiceMultiplexer(), type);
148 if ([ioSDPRecord getL2CAPPSM:&psm] == kIOReturnSuccess) {
149 configured = true;
150 realPort = psm;
151 }
152 } else if (type == QBluetoothServiceInfo::RfcommProtocol) {
153 BluetoothRFCOMMChannelID channelID = 0;
154 server = QBluetoothServerPrivate::registeredServer(info.serverChannel(), type);
155 if ([ioSDPRecord getRFCOMMChannelID:&channelID] == kIOReturnSuccess) {
156 configured = true;
157 realPort = channelID;
158 }
159 }
160
161 if (!configured) {
162 [ioSDPRecord removeServiceRecord];
163 qCWarning(QT_BT_OSX) << "failed to register a service record";
164 return false;
165 }
166
167 registered = true;
168 serviceRecord.swap(newRecord);
169 serviceRecordHandle = newRecordHandle;
170
171 if (server)
172 server->startListener(realPort);
173
174 return true;
175}
176
177bool QBluetoothServiceInfoPrivate::isRegistered() const
178{
179 return registered;
180}
181
182bool QBluetoothServiceInfoPrivate::unregisterService()
183{
184 if (!registered)
185 return false;
186
187 Q_ASSERT_X(serviceRecord, Q_FUNC_INFO, "service registered, but serviceRecord is nil");
188
189 auto *nativeRecord = serviceRecord.getAs<IOBluetoothSDPServiceRecord>();
190 [nativeRecord removeServiceRecord];
191 serviceRecord.reset();
192
193 const ServiceInfo::Protocol type = socket_protocol(*this);
194 QBluetoothServerPrivate *server = nullptr;
195
196 const QMutexLocker lock(&QBluetoothServerPrivate::channelMapMutex());
197 if (type == ServiceInfo::RfcommProtocol)
198 server = QBluetoothServerPrivate::registeredServer(channel_or_psm(*this, QBluetoothUuid::Rfcomm), type);
199 else if (type == ServiceInfo::L2capProtocol)
200 server = QBluetoothServerPrivate::registeredServer(channel_or_psm(*this, QBluetoothUuid::L2cap), type);
201
202 if (server)
203 server->stopListener();
204
205 registered = false;
206 serviceRecordHandle = 0;
207
208 return true;
209}
210
211QT_END_NAMESPACE
212

Warning: That file was not part of the compilation database. It may have many parsing errors.