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