• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "opp_obex_server.h"
17 
18 #include <codecvt>
19 #include <dirent.h>
20 #include "../obex/obex_server.h"
21 #include "bt_def.h"
22 #include "log.h"
23 #include "opp_defines.h"
24 #include "opp_service.h"
25 
26 namespace OHOS {
27 namespace bluetooth {
OppReceiveFileBodyObject(const std::string & file,const std::string address)28 OppReceiveFileBodyObject::OppReceiveFileBodyObject(const std::string &file, const std::string address)
29 {
30     address_ = address;
31     file_ = file;
32     OpenFile(file);
33 }
34 
~OppReceiveFileBodyObject()35 OppReceiveFileBodyObject::~OppReceiveFileBodyObject()
36 {
37     try {
38         Close();
39     } catch(std::exception &e) {
40         LOG_ERROR("[OPP OBEX SERVER]%{public}s():Catch exception %{public}s", __FUNCTION__, e.what());
41     }
42 }
43 
OpenFile(const std::string & file)44 void OppReceiveFileBodyObject::OpenFile(const std::string &file)
45 {
46     ofs_.open(file, std::ios::out);
47     if (!ofs_.is_open()) {
48         HILOGE("[OPP OBEX SERVER] file open failed");
49         return;
50     } else {
51         HILOGI("[OPP OBEX SERVER] file=%{public}s  opened.", file.c_str());
52     }
53 }
54 
Read(uint8_t * buf,size_t bufLen)55 size_t OppReceiveFileBodyObject::Read(uint8_t *buf, size_t bufLen)
56 {
57     return bufLen;
58 }
59 
Write(const uint8_t * buf,size_t bufLen)60 size_t OppReceiveFileBodyObject::Write(const uint8_t *buf, size_t bufLen)
61 {
62     size_t writeSize = 0;
63     if (ofs_.is_open()) {
64         auto buffer = reinterpret_cast<const char *>(buf);
65         ofs_.write(buffer, bufLen);
66         fileReceiveSize_ += bufLen;
67         writeSize = bufLen;
68         OppService::GetService()->OnTransferPositionChange(address_, fileReceiveSize_);
69         HILOGI("[OPP OBEX SERVER] write file bufLen=%zu", bufLen);
70     } else {
71         OppService::GetService()->CancelTransfer(address_);
72         HILOGE("[OPP OBEX SERVER] file open failed");
73     }
74     return writeSize;
75 }
76 
SetFileReceiveSuccess()77 void OppReceiveFileBodyObject::SetFileReceiveSuccess()
78 {
79     fileReceiveSuccess_ = true;
80 }
81 
Close()82 int OppReceiveFileBodyObject::Close()
83 {
84     ofs_.close();
85     if (!fileReceiveSuccess_) {
86         remove(file_.c_str());
87     }
88     return RET_NO_ERROR;
89 }
90 
OppObexServer(const ObexServerConfig & config,utility::Dispatcher & dispatcher)91 OppObexServer::OppObexServer(const ObexServerConfig &config, utility::Dispatcher &dispatcher)
92 {
93     HILOGI("[OPP OBEX SERVER] Enter");
94     oppObexObserver_ = std::make_unique<OppObexObserver>();
95     obexServer_ = std::make_unique<ObexServer>(OPP_SERVICE_NAME, config, *oppObexObserver_, dispatcher);
96 }
97 
StartUp() const98 int OppObexServer::StartUp() const
99 {
100     HILOGI("[OPP OBEX SERVER] Enter");
101     int ret = obexServer_->Startup();
102     if (ret != RET_NO_ERROR) {
103         HILOGE("[OPP OBEX SERVER]:Obex Startup Error ret = %{public}d", ret);
104     }
105     return ret;
106 }
107 
ShutDown() const108 int OppObexServer::ShutDown() const
109 {
110     HILOGI("[OPP OBEX SERVER] Enter");
111     obexServer_->Shutdown();
112     return RET_NO_ERROR;
113 }
114 
SendOppDisconnected(const std::string & btAddr) const115 void OppObexServer::OppObexObserver::SendOppDisconnected(const std::string &btAddr) const
116 {
117     OppMessage event(OPP_DISCONNECTED_EVT);
118     event.dev_ = btAddr;
119     OppService::GetService()->PostEvent(event);
120 }
121 
OnTransportDisconnected(const std::string & btAddr)122 void OppObexServer::OppObexObserver::OnTransportDisconnected(const std::string &btAddr)
123 {
124     HILOGI("[OPP OBEX SERVER] Enter");
125     SendOppDisconnected(btAddr);
126 }
127 
OnTransportError(const std::string & btAddr,int errCd,const std::string & msg)128 void OppObexServer::OppObexObserver::OnTransportError(const std::string &btAddr, int errCd, const std::string &msg)
129 {
130     HILOGI("[OPP OBEX SERVER] Enter");
131     SendOppDisconnected(btAddr);
132 }
133 
OnTransportConnect(ObexIncomingConnect & incomingConnect)134 void OppObexServer::OppObexObserver::OnTransportConnect(ObexIncomingConnect &incomingConnect)
135 {
136     HILOGI("[OPP OBEX SERVER] Enter");
137     incomingConnect.AcceptConnection();
138 }
139 
OnConnect(ObexServerSession & session,const ObexHeader & req)140 void OppObexServer::OppObexObserver::OnConnect(ObexServerSession &session, const ObexHeader &req)
141 {
142     HILOGI("[OPP OBEX SERVER] Enter");
143     OppService::GetService()->OnReceiveIncomingConnect(session, connectionId_);
144 }
145 
OnDisconnect(ObexServerSession & session,const ObexHeader & req)146 void OppObexServer::OppObexObserver::OnDisconnect(ObexServerSession &session, const ObexHeader &req)
147 {
148     HILOGI("[OPP OBEX SERVER] Enter");
149     auto header = ObexHeader::CreateResponse(ObexRspCode::SUCCESS, false);
150     auto connectId = req.GetItemConnectionId();
151     if (connectId != nullptr) {
152         header->AppendItemConnectionId(connectId->GetWord());
153     }
154     session.SendResponse(*header);
155     session.Disconnect();
156 }
157 
OnPut(ObexServerSession & session,const ObexHeader & req)158 void OppObexServer::OppObexObserver::OnPut(ObexServerSession &session, const ObexHeader &req)
159 {
160     HILOGI("[OPP OBEX SERVER] Enter");
161     bool isHeader = false;
162     int ret = RET_NO_ERROR;
163     if (session.GetReceivedObject() == nullptr) {
164         ret = ReceiveFileHeader(session, req);
165         isHeader = true;
166     }
167     if (ret == RET_NO_ERROR) {
168         ReceiveFileBody(session, req, isHeader);
169     }
170 }
171 
OnAbort(ObexServerSession & session,const ObexHeader & req)172 void OppObexServer::OppObexObserver::OnAbort(ObexServerSession &session, const ObexHeader &req)
173 {
174     HILOGI("[OPP OBEX SERVER] Enter");
175     auto header = ObexHeader::CreateResponse(ObexRspCode::SUCCESS, false);
176     auto connectId = req.GetItemConnectionId();
177     if (connectId != nullptr) {
178         header->AppendItemConnectionId(connectId->GetWord());
179     }
180     session.SendResponse(*header);
181     OppService::GetService()->OnTransferStateChange(
182         session.GetRemoteAddr().GetAddress(), OPP_TRANSFER_STATUS_FAILD, OPP_TRANSFER_FAILED_CANCELED);
183 }
184 
OnBusy(ObexServerSession & session,bool isBusy) const185 void OppObexServer::OppObexObserver::OnBusy(ObexServerSession &session, bool isBusy) const
186 {
187     HILOGI("[OPP OBEX SERVER] Enter");
188 }
189 
ReceiveFileHeader(ObexServerSession & session,const ObexHeader & req)190 int OppObexServer::OppObexObserver::ReceiveFileHeader(ObexServerSession &session, const ObexHeader &req)
191 {
192     auto nameItem = req.GetItemName();
193     std::u16string name;
194     if (nameItem != nullptr) {
195         name = nameItem->GetUnicodeText();
196     }
197     if (name.empty()) {
198         HILOGE("[OPP OBEX SERVER]:name is empty");
199         session.SendSimpleResponse(ObexRspCode::BAD_REQUEST);
200         return RET_BAD_STATUS;
201     }
202     std::string fileName = U16stringToString(name);
203     if (NeedRejectFileForPts(fileName)) {
204         HILOGE("[OPP OBEX SERVER]:name is pts reject");
205         session.SendSimpleResponse(ObexRspCode::UNSUPPORTED_MEDIA_TYPE);
206         return RET_BAD_STATUS;
207     }
208 
209     auto typeItem = req.GetItemType();
210     std::string type;
211     if (typeItem != nullptr) {
212         type = typeItem->GetString();
213     }
214 
215     auto lengthItem = req.GetItemLength();
216     size_t length = 0;
217     if (lengthItem != nullptr) {
218         length = lengthItem->GetWord();
219     }
220     if (length <= 0) {
221         HILOGE("[OPP OBEX SERVER]:length is 0");
222         session.SendSimpleResponse(ObexRspCode::LENGTH_REQUIRED);
223         return RET_BAD_STATUS;
224     }
225 
226     std::string filePath = OPP_RECEIVE_FILE_PATH + RenameFile(fileName);
227 
228     std::shared_ptr<ObexBodyObject> writer =
229         std::make_shared<OppReceiveFileBodyObject>(filePath, session.GetRemoteAddr().GetAddress());
230     std::unique_ptr<ObexServerReceivedObject> &receivedObject = session.CreateReceivedObject(req, writer);
231     if ((receivedObject != nullptr) && session.IsSupportSrmMode() && req.GetItemSrm()) {
232         receivedObject->SetSrmEnable(true);
233     }
234 
235     IOppTransferInformation info;
236     info.SetDeviceAddress(session.GetRemoteAddr().GetAddress());
237     info.SetFileName(fileName);
238     info.SetFilePath(filePath);
239     info.SetFileType(type);
240     info.SetTotalBytes(static_cast<uint64_t>(length));
241     OppService::GetService()->OnReceiveIncomingFile(info);
242     return RET_NO_ERROR;
243 }
244 
245 // For PTS OPP/SR/OPH/BV-xxx.
NeedRejectFileForPts(std::string fileName) const246 bool OppObexServer::OppObexObserver::NeedRejectFileForPts(std::string fileName) const
247 {
248     // regect OPHBV10,OPHBV14,OPHBV18.
249     std::string ptsRejectName = "OPHBV";
250     std::string::size_type idx = fileName.find(ptsRejectName);
251     if (idx == fileName.npos) {
252         return false;
253     }
254     return true;
255 }
256 
ReceiveFileBody(ObexServerSession & session,const ObexHeader & req,bool isHead) const257 void OppObexServer::OppObexObserver::ReceiveFileBody(ObexServerSession &session,
258     const ObexHeader &req, bool isHead) const
259 {
260     std::unique_ptr<ObexServerReceivedObject> &receivedObject = session.GetReceivedObject();
261     if (receivedObject == nullptr) {
262         session.SendSimpleResponse(ObexRspCode::BAD_REQUEST);
263         OppService::GetService()->OnTransferStateChange(
264             session.GetRemoteAddr().GetAddress(), OPP_TRANSFER_STATUS_FAILD, OPP_TRANSFER_FAILED_PROTOCOL);
265         return;
266     }
267     auto body = req.GetItemBody();
268     if (body != nullptr) {
269         HILOGI("[OPP OBEX SERVER]:Server Received Body From Request!");
270         receivedObject->AppendBody(body->GetBytes().get(), body->GetHeaderDataSize());
271     }
272     if (req.GetFieldCode() == static_cast<uint8_t>(ObexOpeId::PUT_FINAL)) {
273         auto fbody = req.GetItemEndBody();
274         if (fbody != nullptr) {
275             HILOGI("[OPP OBEX SERVER]:Server Received End-Body From Request!");
276             receivedObject->AppendBody(fbody->GetBytes().get(), fbody->GetHeaderDataSize());
277         }
278         auto header = ObexHeader::CreateResponse(ObexRspCode::SUCCESS, false);
279         auto connectId = req.GetItemConnectionId();
280         if (connectId != nullptr) {
281             header->AppendItemConnectionId(connectId->GetWord());
282         }
283         header->AppendItemEndBody(nullptr, 0);
284         session.SendResponse(*header);
285 
286         OppReceiveFileBodyObject *bodyObject = static_cast<OppReceiveFileBodyObject *>(
287             receivedObject->GetWriter().get());
288         if (bodyObject != nullptr) {
289             bodyObject->SetFileReceiveSuccess();
290             session.FreeReceivedObject();
291             OppService::GetService()->OnTransferStateChange(
292                 session.GetRemoteAddr().GetAddress(), OPP_TRANSFER_STATUS_SUCCESS, 0);
293             return;
294         }
295         session.FreeReceivedObject();
296         OppService::GetService()->OnTransferStateChange(
297             session.GetRemoteAddr().GetAddress(), OPP_TRANSFER_STATUS_FAILD, OPP_TRANSFER_FAILED_PROTOCOL);
298     } else if (!isHead) {
299         if (!session.IsSupportSrmMode() || req.GetItemSrm()) {
300             auto respHeader = ObexHeader::CreateResponse(ObexRspCode::CONTINUE);
301             auto connectId = req.GetItemConnectionId();
302             if (connectId != nullptr) {
303                 respHeader->AppendItemConnectionId(connectId->GetWord());
304             }
305             if (session.IsSupportSrmMode() && req.GetItemSrm()) {
306                 respHeader->AppendItemSrm(true);
307             }
308             session.SendResponse(*respHeader);
309         }
310     }
311 }
312 
U16stringToString(const std::u16string & u16str) const313 std::string OppObexServer::OppObexObserver::U16stringToString(const std::u16string &u16str) const
314 {
315     return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.to_bytes(u16str);
316 }
317 
RenameFile(std::string fileName) const318 std::string OppObexServer::OppObexObserver::RenameFile(std::string fileName) const
319 {
320     if (!HasSameName(OPP_RECEIVE_FILE_PATH, fileName)) {
321         return fileName;
322     }
323 
324     time_t timeStamp = 0;
325     (void)time(&timeStamp);
326     char *name = strchr(&fileName[0], '.');
327     if (name == nullptr) {
328         HILOGI("[OPP OBEX SERVER] opendir error");
329         return fileName;
330     }
331     size_t namelen = name - &fileName[0];
332     std::string rename = fileName.substr(0, namelen);
333     std::string type = fileName.erase(0, fileName.find_last_of('.') + 1);
334     std::string fileNewName = rename + "_" + std::to_string(timeStamp) + "." + type;
335     return fileNewName;
336 }
337 
HasSameName(std::string path,std::string name) const338 bool OppObexServer::OppObexObserver::HasSameName(std::string path, std::string name) const
339 {
340     DIR *dir = opendir(path.c_str());
341     if (dir == nullptr) {
342         HILOGI("[OPP OBEX SERVER] opendir error");
343         return false;
344     }
345 
346     struct dirent *ent;
347     while ((ent = readdir(dir)) != nullptr) {
348         if (strcmp(ent->d_name, name.c_str()) == 0) {
349             HILOGI("[OPP OBEX SERVER] has same name");
350             return true;
351         }
352     }
353     return false;
354 }
355 }  // namespace bluetooth
356 }  // namespace OHOS
357