• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "mms_network_client.h"
17 
18 #include "core_manager_inner.h"
19 #include "mms_apn_info.h"
20 #include "mms_persist_helper.h"
21 #include "net_conn_client.h"
22 #include "net_handle.h"
23 #include "net_link_info.h"
24 #include "securec.h"
25 #include "telephony_errors.h"
26 #include "telephony_log_wrapper.h"
27 
28 namespace OHOS {
29 namespace Telephony {
30 using namespace NetManagerStandard;
31 std::string METHOD_POST = "POST";
32 std::string METHOD_GET = "GET";
33 static constexpr int32_t URL_SIZE = 1024;
34 static constexpr uint32_t CODE_BUFFER_MAX_SIZE = 300 * 1024;
35 static constexpr int64_t CONNECTION_TIMEOUT = 60000;
36 static constexpr int64_t TRANS_OP_TIMEOUT = 60000;
37 static constexpr uint8_t LOW_DOWNLOAD_RATE = 5;
38 constexpr const char *SIMID_IDENT_PREFIX = "simId";
39 const bool STORE_MMS_PDU_TO_FILE = false;
40 
MmsNetworkClient(int32_t slotId)41 MmsNetworkClient::MmsNetworkClient(int32_t slotId)
42 {
43     slotId_ = slotId;
44     connectionTimeout_ = CONNECTION_TIMEOUT;
45     transOpTimeout_ = TRANS_OP_TIMEOUT;
46 }
47 
~MmsNetworkClient()48 MmsNetworkClient::~MmsNetworkClient() {}
49 
Execute(const std::string & method,const std::string & mmsc,const std::string & data)50 int32_t MmsNetworkClient::Execute(const std::string &method, const std::string &mmsc, const std::string &data)
51 {
52     if (METHOD_POST.compare(method) == 0) {
53         return PostUrl(mmsc, data);
54     } else if (METHOD_GET.compare(method) == 0) {
55         return GetUrl(mmsc, data);
56     }
57     TELEPHONY_LOGI("Execute method error");
58     return TELEPHONY_ERR_FAIL;
59 }
60 
InitLibCurl()61 void MmsNetworkClient::InitLibCurl()
62 {
63     CURLcode errCode = curl_global_init(CURL_GLOBAL_ALL);
64     if (errCode != CURLE_OK) {
65         TELEPHONY_LOGE("curl init failed, errCode:[%{public}x]!", errCode);
66     }
67 }
68 
DestoryLibCurl()69 void MmsNetworkClient::DestoryLibCurl()
70 {
71     curl_global_cleanup();
72 }
73 
PostUrl(const std::string & mmsc,const std::string & fileName)74 int32_t MmsNetworkClient::PostUrl(const std::string &mmsc, const std::string &fileName)
75 {
76     std::shared_ptr<MmsApnInfo> mmsApnInfo = std::make_shared<MmsApnInfo>(slotId_);
77     if (mmsApnInfo == nullptr) {
78         TELEPHONY_LOGE("mmsApnInfo is nullptr");
79         return TELEPHONY_ERR_MMS_FAIL_APN_INVALID;
80     }
81     std::string mmscFromDataBase = mmsApnInfo->getMmscUrl();
82     if (mmsc != mmscFromDataBase) {
83         TELEPHONY_LOGE("mmsc is invalid");
84         return TELEPHONY_ERR_ARGUMENT_INVALID;
85     }
86 
87     std::string strBuf;
88     if (STORE_MMS_PDU_TO_FILE) {
89         if (!GetMmsPduFromFile(fileName, strBuf)) {
90             TELEPHONY_LOGE("Get MmsPdu from file fail");
91             return TELEPHONY_ERR_READ_DATA_FAIL;
92         }
93     } else {
94         if (!GetMmsPduFromDataBase(fileName, strBuf)) {
95             TELEPHONY_LOGE("Get MmsPdu from data base fail");
96             return TELEPHONY_ERR_DATABASE_READ_FAIL;
97         }
98     }
99 
100     SetIfaceName(GetIfaceName());
101     TELEPHONY_LOGI("strBuf length:%{public}d", static_cast<uint32_t>(strBuf.size()));
102     std::string strResponse = "";
103     int32_t ret = HttpPost(mmscFromDataBase, strBuf, strResponse);
104     TELEPHONY_LOGI("ret: %{public}d,strResponse len: %{public}d", ret, static_cast<uint32_t>(strResponse.size()));
105 
106     CURLcode errCode = static_cast<CURLcode>(ret);
107     if (!STORE_MMS_PDU_TO_FILE) {
108         DeleteMmsPdu(fileName);
109     }
110     if (errCode != CURLE_OK) {
111         return TELEPHONY_ERR_MMS_FAIL_HTTP_ERROR;
112     } else {
113         TELEPHONY_LOGI("send mms successed");
114         return TELEPHONY_ERR_SUCCESS;
115     }
116 }
117 
GetMmsPduFromFile(const std::string & fileName,std::string & strBuf)118 bool MmsNetworkClient::GetMmsPduFromFile(const std::string &fileName, std::string &strBuf)
119 {
120     FILE *pFile = nullptr;
121     char realPath[PATH_MAX] = { 0 };
122     if (fileName.empty() || realpath(fileName.c_str(), realPath) == nullptr) {
123         TELEPHONY_LOGE("path or realPath is nullptr");
124         return false;
125     }
126 
127     pFile = fopen(realPath, "rb");
128     if (pFile == nullptr) {
129         TELEPHONY_LOGE("openFile Error");
130         return false;
131     }
132 
133     (void)fseek(pFile, 0, SEEK_END);
134     long fileLen = ftell(pFile);
135     if (fileLen <= 0 || fileLen > static_cast<long>(CODE_BUFFER_MAX_SIZE)) {
136         (void)fclose(pFile);
137         TELEPHONY_LOGE("Mms Over Long Error");
138         return false;
139     }
140 
141     std::unique_ptr<char[]> pduBuffer = std::make_unique<char[]>(fileLen);
142     if (!pduBuffer) {
143         (void)fclose(pFile);
144         TELEPHONY_LOGE("make unique pduBuffer nullptr Error");
145         return false;
146     }
147     (void)fseek(pFile, 0, SEEK_SET);
148     int32_t totolLength = static_cast<int32_t>(fread(pduBuffer.get(), 1, CODE_BUFFER_MAX_SIZE, pFile));
149     TELEPHONY_LOGI("sendMms fread totolLength%{public}d", totolLength);
150     (void)fclose(pFile);
151 
152     long i = 0;
153     while (i < fileLen) {
154         strBuf += pduBuffer[i];
155         i++;
156     }
157     return true;
158 }
159 
GetMmsPduFromDataBase(const std::string & dbUrl,std::string & strBuf)160 bool MmsNetworkClient::GetMmsPduFromDataBase(const std::string &dbUrl, std::string &strBuf)
161 {
162     if (dbUrl.empty()) {
163         TELEPHONY_LOGE("dbUrl is empty");
164         return false;
165     }
166     std::shared_ptr<MmsPersistHelper> mmsPdu = std::make_shared<MmsPersistHelper>();
167     if (mmsPdu == nullptr) {
168         TELEPHONY_LOGE("mmsPdu nullptr");
169         return false;
170     }
171     strBuf = mmsPdu->GetMmsPdu(dbUrl);
172     if (strBuf.empty()) {
173         TELEPHONY_LOGE("strBuf is empty");
174         return false;
175     }
176     return true;
177 }
178 
DeleteMmsPdu(const std::string & dbUrl)179 void MmsNetworkClient::DeleteMmsPdu(const std::string &dbUrl)
180 {
181     std::shared_ptr<MmsPersistHelper> mmsPdu = std::make_shared<MmsPersistHelper>();
182     if (mmsPdu == nullptr) {
183         TELEPHONY_LOGE("mmsPdu is nullptr");
184         return;
185     }
186     mmsPdu->DeleteMmsPdu(dbUrl);
187 }
188 
GetUrl(const std::string & mmsc,const std::string & storeDirName)189 int32_t MmsNetworkClient::GetUrl(const std::string &mmsc, const std::string &storeDirName)
190 {
191     std::string strResponse;
192     SetIfaceName(GetIfaceName());
193     int32_t getResult = HttpGet(mmsc, strResponse);
194     if (getResult != CURLE_OK) {
195         TELEPHONY_LOGE("LibCurl HttpGet fail");
196         return getResult;
197     }
198 
199     uint32_t len = strResponse.size();
200     if (len > CODE_BUFFER_MAX_SIZE || len == 0) {
201         TELEPHONY_LOGE("MMS pdu length invalid");
202         return TELEPHONY_ERR_LOCAL_PTR_NULL;
203     }
204 
205     std::unique_ptr<char[]> resultResponse = std::make_unique<char[]>(len);
206     if (STORE_MMS_PDU_TO_FILE) {
207         if (memset_s(resultResponse.get(), len, 0x00, len) != EOK) {
208             TELEPHONY_LOGE("memset_s err");
209             return TELEPHONY_ERR_MEMSET_FAIL;
210         }
211         if (memcpy_s(resultResponse.get(), len, &strResponse[0], len) != EOK) {
212             TELEPHONY_LOGE("memcpy_s error");
213             return TELEPHONY_ERR_MEMCPY_FAIL;
214         }
215         if (!WriteBufferToFile(std::move(resultResponse), len, storeDirName)) {
216             TELEPHONY_LOGE("write to file error");
217             return TELEPHONY_ERR_WRITE_DATA_FAIL;
218         }
219         return TELEPHONY_ERR_SUCCESS;
220     } else {
221         std::shared_ptr<MmsPersistHelper> mmsPduObj = std::make_shared<MmsPersistHelper>();
222         if (mmsPduObj == nullptr) {
223             TELEPHONY_LOGE("GetUrl mmsPduObj nullptr");
224             return TELEPHONY_ERR_LOCAL_PTR_NULL;
225         }
226         bool ret = mmsPduObj->UpdateMmsPdu(strResponse, storeDirName);
227         TELEPHONY_LOGI("ret:%{public}d, length:%{public}d", ret, len);
228         return ret ? TELEPHONY_ERR_SUCCESS : TELEPHONY_ERR_FAIL;
229     }
230 }
231 
GetIfaceName()232 std::string MmsNetworkClient::GetIfaceName()
233 {
234     int32_t simId = CoreManagerInner::GetInstance().GetSimId(slotId_);
235     TELEPHONY_LOGI("slot = %{public}d, simId = %{public}d", slotId_, simId);
236     std::list<int32_t> netIdList;
237     int32_t ret =
238         NetConnClient::GetInstance().GetNetIdByIdentifier(SIMID_IDENT_PREFIX + std::to_string(simId), netIdList);
239     TELEPHONY_LOGI("netIdList size = %{public}zu", netIdList.size());
240     std::string ifaceName;
241     if (ret != NETMANAGER_SUCCESS) {
242         TELEPHONY_LOGE("get netIdList by identifier fail, ret = %{public}d", ret);
243         return ifaceName;
244     }
245     std::list<sptr<NetHandle>> netList;
246     int32_t result = NetConnClient::GetInstance().GetAllNets(netList);
247     if (result != NETMANAGER_SUCCESS) {
248         TELEPHONY_LOGE("get all nets fail, ret = %{public}d", result);
249         return ifaceName;
250     }
251     for (sptr<NetHandle> netHandle : netList) {
252         TELEPHONY_LOGI("netHandle->GetNetId() = %{public}d", netHandle->GetNetId());
253         for (auto netId : netIdList) {
254             if (netId == netHandle->GetNetId()) {
255                 NetLinkInfo info;
256                 NetConnClient::GetInstance().GetConnectionProperties(*netHandle, info);
257                 ifaceName = info.ifaceName_;
258                 TELEPHONY_LOGI("data is connected ifaceName = %{public}s", ifaceName.c_str());
259                 return ifaceName;
260             }
261         }
262     }
263 
264     TELEPHONY_LOGI("slot = %{public}d data is not connected for this slot", slotId_);
265     return ifaceName;
266 }
267 
SetIfaceName(const std::string & name)268 void MmsNetworkClient::SetIfaceName(const std::string &name)
269 {
270     const std::string prefix("if!");
271     const auto preLen = prefix.length();
272     if ((name.length() > preLen && name.substr(0, preLen) == prefix) || name.empty()) {
273         ifaceName_ = name;
274     } else {
275         ifaceName_ = prefix + name;
276     }
277 }
278 
HttpGet(const std::string & strUrl,std::string & strResponse)279 int32_t MmsNetworkClient::HttpGet(const std::string &strUrl, std::string &strResponse)
280 {
281     return HttpRequestExec(HttpReqType::HTTP_REQUEST_TYPE_GET, strUrl, "", strResponse);
282 }
283 
HttpPost(const std::string & strUrl,const std::string & strData,std::string & strResponse)284 int32_t MmsNetworkClient::HttpPost(const std::string &strUrl, const std::string &strData, std::string &strResponse)
285 {
286     return HttpRequestExec(HttpReqType::HTTP_REQUEST_TYPE_POST, strUrl, strData, strResponse);
287 }
288 
operator ()(CURL * p) const289 void CURLClean::operator()(CURL *p) const
290 {
291     if (p) {
292         curl_easy_cleanup(p);
293     }
294 }
295 
HttpRequestExec(HttpReqType type,const std::string & strUrl,const std::string & strData,std::string & strResponse)296 int32_t MmsNetworkClient::HttpRequestExec(
297     HttpReqType type, const std::string &strUrl, const std::string &strData, std::string &strResponse)
298 {
299     if (strUrl.empty() || strUrl.length() > URL_SIZE) {
300         TELEPHONY_LOGE("URL error!");
301         return -1;
302     }
303 
304     std::unique_ptr<CURL, CURLClean> mmsCurl(curl_easy_init(), CURLClean());
305     if (mmsCurl.get() == nullptr) {
306         TELEPHONY_LOGE("mmsCurl nullptr");
307         return -1;
308     }
309 
310     int32_t result = SetCurlOpt(mmsCurl, type, strUrl, strData, strResponse);
311     if (result == 0) {
312         CURLcode errCode = CURLE_OK;
313         TELEPHONY_LOGI("HttpRequestExec send http request");
314         errCode = curl_easy_perform(mmsCurl.get());
315         result = static_cast<int32_t>(errCode);
316     }
317     if (mmsHttpHeaderlist_ != nullptr) {
318         curl_slist_free_all(mmsHttpHeaderlist_);
319     }
320     return ParseExecResult(mmsCurl, result);
321 }
322 
ParseExecResult(const std::unique_ptr<CURL,CURLClean> & mmsCurl,int32_t result)323 int32_t MmsNetworkClient::ParseExecResult(const std::unique_ptr<CURL, CURLClean> &mmsCurl, int32_t result)
324 {
325     CURLcode retCode = static_cast<CURLcode>(result);
326     if (retCode != CURLE_OK) {
327         TELEPHONY_LOGE("HTTP request failed, errStr:[%{public}s], errorBuffer_:[%{public}s]!",
328             curl_easy_strerror(retCode), errorBuffer_);
329         return result;
330     }
331 
332     lastTransTime_ = 0;
333     curl_off_t totalTimeUs = 0L;
334     retCode = curl_easy_getinfo(mmsCurl.get(), CURLINFO_TOTAL_TIME_T, &totalTimeUs);
335     if (retCode == CURLE_OK) {
336         lastTransTime_ = static_cast<int64_t>(totalTimeUs / 1000L);
337         TELEPHONY_LOGI("HTTP request OK,total time in ms:[%{public}" PRId64 "]", lastTransTime_);
338     }
339     return static_cast<int32_t>(retCode);
340 }
341 
SetCurlOpt(const std::unique_ptr<CURL,CURLClean> & mmsCurl,HttpReqType type,const std::string & strUrl,const std::string & strData,std::string & strResponse)342 int32_t MmsNetworkClient::SetCurlOpt(const std::unique_ptr<CURL, CURLClean> &mmsCurl, HttpReqType type,
343     const std::string &strUrl, const std::string &strData, std::string &strResponse)
344 {
345     int32_t rlt = SetCurlOptCommon(mmsCurl, strUrl);
346     if (rlt != 0) {
347         return rlt;
348     }
349 
350     /* receive the http header */
351     curl_easy_setopt(mmsCurl.get(), CURLOPT_HEADERFUNCTION, nullptr);
352     curl_easy_setopt(mmsCurl.get(), CURLOPT_HEADERDATA, nullptr);
353 
354     /* receive the whole http response */
355     strResponse.clear();
356     curl_easy_setopt(mmsCurl.get(), CURLOPT_WRITEFUNCTION, DataCallback);
357     curl_easy_setopt(mmsCurl.get(), CURLOPT_WRITEDATA, &strResponse);
358     curl_easy_setopt(mmsCurl.get(), CURLOPT_FAILONERROR, 1L);
359     curl_easy_setopt(mmsCurl.get(), CURLOPT_LOW_SPEED_LIMIT, 1);
360     curl_easy_setopt(mmsCurl.get(), CURLOPT_LOW_SPEED_TIME, LOW_DOWNLOAD_RATE);
361     if (type == HttpReqType::HTTP_REQUEST_TYPE_POST) {
362         /* Specify post content */
363         curl_easy_setopt(mmsCurl.get(), CURLOPT_POST, 1L);
364         curl_easy_setopt(mmsCurl.get(), CURLOPT_POSTFIELDSIZE, strData.length());
365         curl_easy_setopt(mmsCurl.get(), CURLOPT_POSTFIELDS, strData.c_str());
366 
367         mmsHttpHeaderlist_ =
368             curl_slist_append(mmsHttpHeaderlist_, "Content-Type:application/vnd.wap.mms-message; charset=utf-8");
369         mmsHttpHeaderlist_ =
370             curl_slist_append(mmsHttpHeaderlist_, "Accept:application/vnd.wap.mms-message, application/vnd.wap.sic");
371         curl_easy_setopt(mmsCurl.get(), CURLOPT_HTTPHEADER, mmsHttpHeaderlist_);
372     }
373     return 0;
374 }
375 
SetCurlOptCommon(const std::unique_ptr<CURL,CURLClean> & mmsCurl,const std::string & strUrl)376 int32_t MmsNetworkClient::SetCurlOptCommon(const std::unique_ptr<CURL, CURLClean> &mmsCurl, const std::string &strUrl)
377 {
378     /* Print request connection process and return http data on the screen */
379     curl_easy_setopt(mmsCurl.get(), CURLOPT_VERBOSE, 0L);
380 
381     curl_easy_setopt(mmsCurl.get(), CURLOPT_ERRORBUFFER, errorBuffer_);
382     /* not include the headers in the write callback */
383     curl_easy_setopt(mmsCurl.get(), CURLOPT_HEADER, 0L);
384     /* Specify url content */
385     if (memset_s(mmscChar_, MAX_MMSC_SIZE, 0x00, MAX_MMSC_SIZE) != EOK) {
386         TELEPHONY_LOGE("set mmsc memset_s err");
387         return CURLE_FAILED_INIT;
388     }
389     if (memcpy_s(mmscChar_, strUrl.length(), &strUrl[0], strUrl.length()) != EOK) {
390         TELEPHONY_LOGE("set mmsc memcpy_s err");
391         return CURLE_FAILED_INIT;
392     }
393     curl_easy_setopt(mmsCurl.get(), CURLOPT_URL, mmscChar_);
394 
395     /* https support */
396     /* the connection succeeds regardless of the peer certificate validation */
397     curl_easy_setopt(mmsCurl.get(), CURLOPT_SSL_VERIFYPEER, 0L);
398     /* the connection succeeds regardless of the names in the certificate. */
399     curl_easy_setopt(mmsCurl.get(), CURLOPT_SSL_VERIFYHOST, 0L);
400 
401     curl_easy_setopt(mmsCurl.get(), CURLOPT_NOSIGNAL, 1L);
402 
403     /* Allow redirect */
404     curl_easy_setopt(mmsCurl.get(), CURLOPT_FOLLOWLOCATION, 1L);
405     /* Set the maximum number of subsequent redirects */
406     curl_easy_setopt(mmsCurl.get(), CURLOPT_MAXREDIRS, 1L);
407 
408     /* connection timeout time */
409     curl_easy_setopt(mmsCurl.get(), CURLOPT_CONNECTTIMEOUT_MS, connectionTimeout_);
410     /* transfer operation timeout time */
411     curl_easy_setopt(mmsCurl.get(), CURLOPT_TIMEOUT_MS, transOpTimeout_);
412 
413     std::shared_ptr<MmsApnInfo> mmsApnInfo = std::make_shared<MmsApnInfo>(slotId_);
414     if (mmsApnInfo == nullptr) {
415         TELEPHONY_LOGE("mmsApnInfo is nullptr");
416         return CURLE_FAILED_INIT;
417     }
418 
419     std::string proxy = mmsApnInfo->getMmsProxyAddressAndProxyPort();
420     if (proxy.empty() || static_cast<int32_t>(proxy.length()) > MAX_MMSC_PROXY_SIZE) {
421         return static_cast<int32_t>(CURLE_BAD_FUNCTION_ARGUMENT);
422     }
423     if (memset_s(proxyChar_, MAX_MMSC_PROXY_SIZE, 0x00, MAX_MMSC_PROXY_SIZE) != EOK) {
424         TELEPHONY_LOGE("set mmsc proxy memset_s err");
425         return CURLE_FAILED_INIT;
426     }
427     if (memcpy_s(proxyChar_, proxy.length(), &proxy[0], proxy.length()) != EOK) {
428         TELEPHONY_LOGE("set mmsc proxy memcpy_s err");
429         return CURLE_FAILED_INIT;
430     }
431     curl_easy_setopt(mmsCurl.get(), CURLOPT_PROXY, proxyChar_);
432     curl_easy_setopt(mmsCurl.get(), CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
433 
434     CURLcode errCode = CURLE_OK;
435     if (!ifaceName_.empty()) {
436         errCode = curl_easy_setopt(mmsCurl.get(), CURLOPT_INTERFACE, ifaceName_.c_str());
437         if (errCode != CURLE_OK) {
438             TELEPHONY_LOGE("CURLOPT_INTERFACE failed errCode:%{public}d", errCode);
439         }
440     }
441     return static_cast<int32_t>(errCode);
442 }
443 
DataCallback(const std::string & data,size_t size,size_t nmemb,std::string * strBuffer)444 int32_t MmsNetworkClient::DataCallback(const std::string &data, size_t size, size_t nmemb, std::string *strBuffer)
445 {
446     if (strBuffer == nullptr || size == 0) {
447         return 0;
448     }
449 
450     int32_t writtenLen = static_cast<int32_t>(size * nmemb);
451     strBuffer->append(data, writtenLen);
452     return writtenLen;
453 }
454 
WriteBufferToFile(const std::unique_ptr<char[]> & buff,uint32_t len,const std::string & strPathName) const455 bool MmsNetworkClient::WriteBufferToFile(
456     const std::unique_ptr<char[]> &buff, uint32_t len, const std::string &strPathName) const
457 {
458     if (buff == nullptr) {
459         TELEPHONY_LOGE("buff nullptr");
460         return false;
461     }
462     char realPath[PATH_MAX] = { 0 };
463     if (strPathName.empty() || realpath(strPathName.c_str(), realPath) == nullptr) {
464         TELEPHONY_LOGE("path or realPath is nullptr");
465         return false;
466     }
467     FILE *pFile = nullptr;
468     pFile = fopen(realPath, "wb");
469     if (!pFile) {
470         TELEPHONY_LOGE("open file fail");
471         return false;
472     }
473     uint32_t fileLen = fwrite(buff.get(), len, 1, pFile);
474     if (fileLen == 0) {
475         TELEPHONY_LOGI("write mms buffer to file error");
476         (void)fclose(pFile);
477         return false;
478     }
479     (void)fclose(pFile);
480     return true;
481 }
482 } // namespace Telephony
483 } // namespace OHOS
484