• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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