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