1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "obex_server.h"
17 #include <cstring>
18 #include "bt_def.h"
19 #include "dispatcher.h"
20 #include "log.h"
21 #include "obex_utils.h"
22
23 namespace bluetooth {
ObexServer(const std::string & serviceName,const ObexServerConfig & config,ObexServerObserver & observer,utility::Dispatcher & dispatcher)24 ObexServer::ObexServer(const std::string &serviceName, const ObexServerConfig &config, ObexServerObserver &observer,
25 utility::Dispatcher &dispatcher)
26 {
27 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
28 serviceName_ = serviceName;
29 if (config.useRfcomm_) {
30 ObexPrivateServer::ObexPrivateServerConfig option;
31 option.isGoepL2capPSM_ = false;
32 option.scn_ = config.rfcommScn_;
33 option.mtu_ = config.rfcommMtu_;
34 option.isSupportSrm_ = false; // rfcomm not support srm mode
35 option.isSupportReliableSession_ = config.isSupportReliableSession_;
36 rfcommServer_ = std::make_unique<ObexPrivateServer>(option, observer, dispatcher);
37 }
38 if (config.useL2cap_) {
39 ObexPrivateServer::ObexPrivateServerConfig option;
40 option.isGoepL2capPSM_ = true;
41 option.scn_ = config.l2capPsm_;
42 option.mtu_ = config.l2capMtu_;
43 option.isSupportSrm_ = config.isSupportSrm_;
44 option.isSupportReliableSession_ = config.isSupportReliableSession_;
45 l2capServer_ = std::make_unique<ObexPrivateServer>(option, observer, dispatcher);
46 }
47 }
48
Startup() const49 int ObexServer::Startup() const
50 {
51 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
52 if (rfcommServer_ == nullptr && l2capServer_ == nullptr) {
53 return -1;
54 }
55 bool rfcommResult = false;
56 if (rfcommServer_ != nullptr) {
57 int retRfcomm = rfcommServer_->Startup();
58 if (retRfcomm != 0) {
59 OBEX_LOG_ERROR("Error: Startup rfcommServer fail with code [0x%02X]", retRfcomm);
60 return retRfcomm;
61 }
62 rfcommResult = true;
63 }
64 if (l2capServer_ != nullptr) {
65 int retL2cap = l2capServer_->Startup();
66 if (retL2cap != 0) {
67 OBEX_LOG_ERROR("Error: Startup l2capServer fail with code [0x%02X]", retL2cap);
68 if (rfcommResult) {
69 rfcommServer_->Shutdown();
70 }
71 return retL2cap;
72 }
73 }
74 return 0;
75 }
76
Shutdown() const77 void ObexServer::Shutdown() const
78 {
79 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
80 if (rfcommServer_ != nullptr) {
81 rfcommServer_->Shutdown();
82 }
83 if (l2capServer_ != nullptr) {
84 l2capServer_->Shutdown();
85 }
86 }
87
OnTransportConnect(ObexIncomingConnect & incomingConnect)88 void ObexServerObserver::OnTransportConnect(ObexIncomingConnect &incomingConnect)
89 {
90 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
91 incomingConnect.AcceptConnection();
92 }
93
OnTransportConnected(const std::string & btAddr)94 void ObexServerObserver::OnTransportConnected(const std::string &btAddr)
95 {
96 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
97 }
98
OnTransportDisconnected(const std::string & btAddr)99 void ObexServerObserver::OnTransportDisconnected(const std::string &btAddr)
100 {
101 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
102 }
103
OnTransportError(const std::string & btAddr,int errCd,const std::string & msg)104 void ObexServerObserver::OnTransportError(const std::string &btAddr, int errCd, const std::string &msg)
105 {
106 OBEX_LOG_ERROR("Call %{public}s, ERROR:%{public}d, %{public}s", __PRETTY_FUNCTION__, errCd, msg.c_str());
107 }
108
109
OnError(const int errCd,const std::string & msg)110 void ObexServerObserver::OnError(const int errCd, const std::string &msg)
111 {
112 OBEX_LOG_ERROR("Call %{public}s, ERROR:%{public}d, %{public}s", __PRETTY_FUNCTION__, errCd, msg.c_str());
113 }
114
OnPut(ObexServerSession & session,const ObexHeader & req)115 void ObexServerObserver::OnPut(ObexServerSession &session, const ObexHeader &req)
116 {
117 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
118 session.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::NOT_IMPLEMENTED, false));
119 }
120
OnGet(ObexServerSession & session,const ObexHeader & req)121 void ObexServerObserver::OnGet(ObexServerSession &session, const ObexHeader &req)
122 {
123 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
124 session.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::NOT_IMPLEMENTED, false));
125 }
126
OnAbort(ObexServerSession & session,const ObexHeader & req)127 void ObexServerObserver::OnAbort(ObexServerSession &session, const ObexHeader &req)
128 {
129 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
130 session.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::NOT_IMPLEMENTED, false));
131 }
132
OnSetPath(ObexServerSession & session,const ObexHeader & req)133 void ObexServerObserver::OnSetPath(ObexServerSession &session, const ObexHeader &req)
134 {
135 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
136 session.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::NOT_IMPLEMENTED, false));
137 }
138
OnAction(ObexServerSession & session,const ObexHeader & req)139 void ObexServerObserver::OnAction(ObexServerSession &session, const ObexHeader &req)
140 {
141 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
142 session.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::NOT_IMPLEMENTED, false));
143 }
144
OnSession(ObexServerSession & session,const ObexHeader & req)145 void ObexServerObserver::OnSession(ObexServerSession &session, const ObexHeader &req)
146 {
147 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
148 session.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::NOT_IMPLEMENTED, false));
149 }
150
OnBusy(ObexServerSession & session,bool isBusy) const151 void ObexServerObserver::OnBusy(ObexServerSession &session, bool isBusy) const
152 {
153 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
154 }
155
156 const uint16_t ObexPrivateServer::MAX_TRASH_SESSION_COUNT = 50;
157
ObexServerTransportObserver(ObexPrivateServer & obexServer)158 ObexPrivateServer::ObexServerTransportObserver::ObexServerTransportObserver(ObexPrivateServer &obexServer)
159 : obexServer_(obexServer)
160 {}
161
OnTransportConnectIncoming(ObexIncomingConnect & incomingConnect)162 void ObexPrivateServer::ObexServerTransportObserver::OnTransportConnectIncoming(ObexIncomingConnect &incomingConnect)
163 {
164 OBEX_LOG_INFO("Call %{public}s start", __PRETTY_FUNCTION__);
165 obexServer_.observer_.OnTransportConnect(incomingConnect);
166 OBEX_LOG_INFO("Call %{public}s end", __PRETTY_FUNCTION__);
167 }
168
OnTransportIncomingDisconnected(const std::string & btAddr)169 void ObexPrivateServer::ObexServerTransportObserver::OnTransportIncomingDisconnected(const std::string &btAddr)
170 {
171 OBEX_LOG_INFO("Call %{public}s start", __PRETTY_FUNCTION__);
172 obexServer_.observer_.OnTransportDisconnected(btAddr);
173 OBEX_LOG_INFO("Call %{public}s end", __PRETTY_FUNCTION__);
174 }
175
OnTransportConnected(ObexTransport & transport)176 void ObexPrivateServer::ObexServerTransportObserver::OnTransportConnected(ObexTransport &transport)
177 {
178 OBEX_LOG_INFO("Call %{public}s start", __PRETTY_FUNCTION__);
179 auto session = std::make_unique<ObexServerSession>(transport,
180 obexServer_.isSupportSrm_,
181 obexServer_.dispatcher_,
182 std::bind(&ObexPrivateServer::RemoveSession, &obexServer_, std::placeholders::_1),
183 std::bind(&ObexPrivateServer::SetBusy, &obexServer_, std::placeholders::_1, std::placeholders::_2));
184 std::string btAddrStr = session->GetRemoteAddr().GetAddress();
185 session->SetMaxPacketLength(obexServer_.initMtu_);
186
187 obexServer_.serverSessionsMap_[&transport] = std::move(session);
188 obexServer_.observer_.OnTransportConnected(btAddrStr);
189 OBEX_LOG_INFO("Call %{public}s end", __PRETTY_FUNCTION__);
190 }
191
OnTransportDisconnected(ObexTransport & transport)192 void ObexPrivateServer::ObexServerTransportObserver::OnTransportDisconnected(ObexTransport &transport)
193 {
194 OBEX_LOG_INFO("Call %{public}s start", __PRETTY_FUNCTION__);
195 std::string btAddrStr = transport.GetRemoteAddress().GetAddress();
196 obexServer_.RemoveSessionByTransport(transport);
197 obexServer_.observer_.OnTransportDisconnected(btAddrStr);
198 OBEX_LOG_INFO("Call %{public}s end", __PRETTY_FUNCTION__);
199 }
200
HandleDataAvailableConnect(ObexServerSession & serverSession,const ObexHeader & req)201 void ObexPrivateServer::ObexServerTransportObserver::HandleDataAvailableConnect(
202 ObexServerSession &serverSession, const ObexHeader &req)
203 {
204 int minPacketSize = std::min(
205 serverSession.GetTransport().GetMaxReceivePacketSize(), serverSession.GetTransport().GetMaxSendPacketSize());
206 minPacketSize = std::min(minPacketSize, (int)serverSession.GetMaxPacketLength());
207 minPacketSize = std::min(minPacketSize, (int)*req.GetFieldMaxPacketLength());
208 if (minPacketSize < OBEX_MINIMUM_MTU) {
209 minPacketSize = OBEX_MINIMUM_MTU;
210 }
211 serverSession.SetMaxPacketLength(minPacketSize);
212 OBEX_LOG_INFO("Server Mtu set to:%{public}d", minPacketSize);
213 obexServer_.observer_.OnConnect(serverSession, req);
214 }
215
OnTransportDataAvailable(ObexTransport & transport,ObexPacket & obexPacket)216 void ObexPrivateServer::ObexServerTransportObserver::OnTransportDataAvailable(
217 ObexTransport &transport, ObexPacket &obexPacket)
218 {
219 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
220 if (obexServer_.serverSessionsMap_.find(&transport) == obexServer_.serverSessionsMap_.end()) {
221 OBEX_LOG_ERROR("ServerSession for has been erased, so skip available data!");
222 return;
223 }
224 ObexServerSession &serverSession = *obexServer_.serverSessionsMap_.at(&transport);
225 auto req = GetObexHeaderFromPacket(obexPacket);
226 if (req == nullptr) {
227 OBEX_LOG_ERROR("error:ParseRequest failure:response BAD_REQUEST");
228 if (serverSession.SendSimpleResponse(ObexRspCode::BAD_REQUEST) != 0) {
229 OBEX_LOG_ERROR("Response BAD_REQUEST send failure!");
230 obexServer_.observer_.OnError(-1, "Response BAD_REQUEST send failure!");
231 }
232 return;
233 }
234 uint8_t code = req->GetFieldCode();
235 switch (code) {
236 case static_cast<uint8_t>(ObexOpeId::CONNECT):
237 HandleDataAvailableConnect(serverSession, *req);
238 break;
239 case static_cast<uint8_t>(ObexOpeId::DISCONNECT):
240 obexServer_.observer_.OnDisconnect(serverSession, *req);
241 break;
242 case static_cast<uint8_t>(ObexOpeId::PUT):
243 case static_cast<uint8_t>(ObexOpeId::PUT_FINAL):
244 obexServer_.HandlePutRequest(serverSession, *req);
245 break;
246 case static_cast<uint8_t>(ObexOpeId::GET):
247 case static_cast<uint8_t>(ObexOpeId::GET_FINAL):
248 obexServer_.HandleGetRequest(serverSession, *req);
249 break;
250 case static_cast<uint8_t>(ObexOpeId::SETPATH):
251 obexServer_.HandleSetPathRequest(serverSession, *req);
252 break;
253 case static_cast<uint8_t>(ObexOpeId::ACTION):
254 obexServer_.observer_.OnAction(serverSession, *req);
255 break;
256 case static_cast<uint8_t>(ObexOpeId::SESSION):
257 obexServer_.observer_.OnSession(serverSession, *req);
258 break;
259 case static_cast<uint8_t>(ObexOpeId::ABORT):
260 obexServer_.HandleAbortRequest(serverSession, *req);
261 break;
262 default:
263 obexServer_.observer_.OnError(-1, "opcode is wrong!");
264 }
265 }
266
GetObexHeaderFromPacket(ObexPacket & obexPacket) const267 std::unique_ptr<bluetooth::ObexHeader> ObexPrivateServer::ObexServerTransportObserver::GetObexHeaderFromPacket(
268 ObexPacket &obexPacket) const
269 {
270 uint8_t *packetBuf = obexPacket.GetBuffer();
271 uint32_t packetBufSize = obexPacket.GetSize();
272 if (packetBufSize < ObexHeader::MIN_PACKET_LENGTH) {
273 OBEX_LOG_ERROR("error:dataSize < 3:%{public}d", int(packetBufSize));
274 obexServer_.observer_.OnError(-1, "error:dataSize < 3");
275 return nullptr;
276 }
277 uint16_t packetLength = ObexUtils::GetBufData16(&packetBuf[0], 1);
278 if (packetLength != packetBufSize) {
279 OBEX_LOG_ERROR("error:packetLength[%{public}d] != packetBufSize[%{public}d]",
280 int(packetLength), int(packetBufSize));
281 obexServer_.observer_.OnError(-1, "packetLength != packetBufSize");
282 return nullptr;
283 }
284 return ObexHeader::ParseRequest(packetBuf, packetLength);
285 }
286
OnTransportDataBusy(ObexTransport & transport,uint8_t isBusy)287 void ObexPrivateServer::ObexServerTransportObserver::OnTransportDataBusy(ObexTransport &transport, uint8_t isBusy)
288 {
289 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
290 if (obexServer_.serverSessionsMap_.find(&transport) == obexServer_.serverSessionsMap_.end()) {
291 OBEX_LOG_ERROR("ServerSession for has been erased, so skip available data!");
292 return;
293 }
294 ObexServerSession &serverSession = *obexServer_.serverSessionsMap_.at(&transport);
295 obexServer_.HandleTransportDataBusy(serverSession, isBusy);
296 }
297
OnTransportError(ObexTransport & transport,int errCd)298 void ObexPrivateServer::ObexServerTransportObserver::OnTransportError(ObexTransport &transport, int errCd)
299 {
300 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
301 obexServer_.observer_.OnError(errCd, "OnTransportError");
302 }
303
ObexPrivateServer(const ObexPrivateServerConfig & config,ObexServerObserver & observer,utility::Dispatcher & dispatcher)304 ObexPrivateServer::ObexPrivateServer(
305 const ObexPrivateServerConfig &config, ObexServerObserver &observer, utility::Dispatcher &dispatcher)
306 : observer_(observer), dispatcher_(dispatcher)
307 {
308 transportObserver_ = std::make_unique<ObexServerTransportObserver>(*this);
309 ObexServerSocketTransport::Option option;
310 option.isGoepL2capPSM_ = config.isGoepL2capPSM_;
311 option.scn_ = config.scn_;
312 option.mtu_ = config.mtu_;
313 initMtu_ = config.mtu_;
314
315 isSupportSrm_ = config.isSupportSrm_;
316 isSupportReliableSession_ = config.isSupportReliableSession_;
317 serverTransport_ = std::make_unique<ObexServerSocketTransport>(option, *transportObserver_, dispatcher);
318 }
319
Startup() const320 int ObexPrivateServer::Startup() const
321 {
322 return serverTransport_->Listen();
323 }
324
Shutdown() const325 void ObexPrivateServer::Shutdown() const
326 {
327 serverTransport_->Disconnect();
328 }
329
RemoveSession(ObexServerSession & session) const330 int ObexPrivateServer::RemoveSession(ObexServerSession &session) const
331 {
332 if (serverSessionsMap_.find(&session.GetTransport()) == serverSessionsMap_.end()) {
333 return RET_NO_SUPPORT;
334 }
335 return serverTransport_->Disconnect(session.GetTransport());
336 }
337
HandlePutRequest(ObexServerSession & session,ObexHeader & req) const338 void ObexPrivateServer::HandlePutRequest(ObexServerSession &session, ObexHeader &req) const
339 {
340 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
341 observer_.OnPut(session, req);
342 }
343
HandleGetRequest(ObexServerSession & session,ObexHeader & req)344 void ObexPrivateServer::HandleGetRequest(ObexServerSession &session, ObexHeader &req)
345 {
346 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
347 observer_.OnGet(session, req);
348 }
349
HandleSetPathRequest(ObexServerSession & session,ObexHeader & req)350 void ObexPrivateServer::HandleSetPathRequest(ObexServerSession &session, ObexHeader &req)
351 {
352 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
353 observer_.OnSetPath(session, req);
354 }
355
HandleAbortRequest(ObexServerSession & session,ObexHeader & req)356 void ObexPrivateServer::HandleAbortRequest(ObexServerSession &session, ObexHeader &req)
357 {
358 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
359 observer_.OnAbort(session, req);
360 }
361
HandleTransportDataBusy(ObexServerSession & session,uint8_t isBusy)362 void ObexPrivateServer::HandleTransportDataBusy(ObexServerSession &session, uint8_t isBusy)
363 {
364 OBEX_LOG_INFO("Call %{public}s", __PRETTY_FUNCTION__);
365 }
366
SetBusy(ObexServerSession & session,bool isBusy) const367 void ObexPrivateServer::SetBusy(ObexServerSession &session, bool isBusy) const
368 {
369 if (session.IsBusy() != isBusy) {
370 session.SetBusy(isBusy);
371 OBEX_LOG_INFO("[%{public}s] ObexBusy=%{public}d", session.GetTransport().GetTransportKey().c_str(), isBusy);
372 observer_.OnBusy(session, isBusy);
373 }
374 }
375
RemoveSessionByTransport(ObexTransport & transport)376 void ObexPrivateServer::RemoveSessionByTransport(ObexTransport &transport)
377 {
378 auto target = serverSessionsMap_.find(&transport);
379 if (target == serverSessionsMap_.end()) {
380 return;
381 }
382 target->second->Invalid();
383 invalidSessions_.push_back(std::move(target->second));
384 serverSessionsMap_.erase(&transport);
385 if (invalidSessions_.size() > MAX_TRASH_SESSION_COUNT) {
386 invalidSessions_.pop_front();
387 }
388 }
389 } // namespace bluetooth