• 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 #include "base.h"
16 #include <algorithm>
17 #include <chrono>
18 #include <cstdio>
19 #include <regex>
20 #include <cstring>
21 #include <dirent.h>
22 #include <iomanip>
23 #include <openssl/bio.h>
24 #include <openssl/buffer.h>
25 #include <openssl/evp.h>
26 #include <openssl/md5.h>
27 #include <random>
28 #include <sstream>
29 #include <sys/stat.h>
30 #include <thread>
31 #include <vector>
32 #ifdef HDC_HILOG
33 #include "hilog/log.h"
34 #endif
35 #ifdef _WIN32
36 #include <windows.h>
37 #include <codecvt>
38 #include <wchar.h>
39 #include <wincrypt.h>
40 #endif
41 #include <fstream>
42 using namespace std::chrono;
43 
44 namespace Hdc {
45 namespace Base {
46     constexpr int DEF_FILE_PERMISSION = 0750;
47 #ifndef _WIN32
48     sigset_t g_blockList;
49 #endif
GetLogLevel()50     uint8_t GetLogLevel()
51     {
52         return g_logLevel;
53     }
54 #ifndef  HDC_HILOG
55     std::atomic<bool> g_logCache = true;
56 #endif
57     uint8_t g_logLevel = LOG_DEBUG;  // tmp set,now debugmode.LOG_OFF when release;;
SetLogLevel(const uint8_t logLevel)58     void SetLogLevel(const uint8_t logLevel)
59     {
60         g_logLevel = logLevel;
61     }
62 
GetLogLevelByEnv()63     uint8_t GetLogLevelByEnv()
64     {
65         char *env = getenv(ENV_SERVER_LOG.c_str());
66         if (!env) {
67             return GetLogLevel();
68         }
69         size_t len = strlen(env);
70 
71         size_t maxLen = 1;
72         if (len > maxLen) {
73             WRITE_LOG(LOG_WARN, "OHOS_HDC_LOG_LEVEL %s is not in (0, 6] range", env);
74             return GetLogLevel();
75         }
76 
77         for (size_t i = 0; i < len; i++) {
78             if (isdigit(env[i]) == 0) {
79                 WRITE_LOG(LOG_WARN, "OHOS_HDC_LOG_LEVEL %s is not digit", env);
80                 return GetLogLevel();
81             }
82         }
83 
84         uint8_t logLevel = static_cast<uint8_t>(atoi(env));
85         if (logLevel < 0 || logLevel > LOG_LAST) {
86             WRITE_LOG(LOG_WARN, "OHOS_HDC_LOG_LEVEL %d is not in (0, 6] range", logLevel);
87         } else {
88             return logLevel;
89         }
90 
91         return GetLogLevel();
92     }
93 
94 // Commenting the code will optimize and tune all log codes, and the compilation volume will be greatly reduced
95 #define ENABLE_DEBUGLOG
96 #ifdef ENABLE_DEBUGLOG
GetLogDebugFunctionName(string & debugInfo,int line,string & threadIdString)97     void GetLogDebugFunctionName(string &debugInfo, int line, string &threadIdString)
98     {
99         string tmpString = GetFileNameAny(debugInfo);
100         debugInfo = StringFormat("%s:%d", tmpString.c_str(), line);
101         if (g_logLevel < LOG_DEBUG) {
102             debugInfo = "";
103             threadIdString = "";
104         } else {
105             debugInfo = "[" + debugInfo + "]";
106             threadIdString = StringFormat("[%x]", std::hash<std::thread::id> {}(std::this_thread::get_id()));
107         }
108     }
109 
GetLogLevelAndTime(uint8_t logLevel,string & logLevelString,string & timeString)110     void GetLogLevelAndTime(uint8_t logLevel, string &logLevelString, string &timeString)
111     {
112         system_clock::time_point timeNow = system_clock::now();          // now time
113         system_clock::duration sinceUnix0 = timeNow.time_since_epoch();  // since 1970
114         time_t sSinceUnix0 = duration_cast<seconds>(sinceUnix0).count();
115         std::tm *tim = std::localtime(&sSinceUnix0);
116         switch (logLevel) {
117             case LOG_FATAL:
118                 logLevelString = "F";
119                 break;
120             case LOG_INFO:
121                 logLevelString = "I";
122                 break;
123             case LOG_WARN:
124                 logLevelString = "W";
125                 break;
126             case LOG_DEBUG:  // will reduce performance
127                 logLevelString = "D";
128                 break;
129             default:  // all, just more IO/Memory information
130                 logLevelString = "A";
131                 break;
132         }
133         string msTimeSurplus;
134         if (g_logLevel >= LOG_DEBUG) {
135             const auto sSinceUnix0Rest = duration_cast<milliseconds>(sinceUnix0).count() % TIME_BASE;
136             msTimeSurplus = StringFormat(".%03llu", sSinceUnix0Rest);
137         }
138         timeString = msTimeSurplus;
139         if (tim != nullptr) {
140             char buffer[TIME_BUF_SIZE];
141             (void)strftime(buffer, TIME_BUF_SIZE, "%Y-%m-%d %H:%M:%S", tim);
142             timeString = StringFormat("%s%s", buffer, msTimeSurplus.c_str());
143         }
144     }
145 
146 #ifndef  HDC_HILOG
LogToPath(const char * path,const char * str)147     void LogToPath(const char *path, const char *str)
148     {
149         // logfile, not thread-safe
150 #ifdef HDC_DEBUG_UART
151         // make a log path print.
152         static std::once_flag firstLog;
153         std::call_once(firstLog, [&]() { printf("log at %s\n", path); });
154         // better than open log file every time.
155         static std::unique_ptr<FILE, decltype(&fclose)> file(fopen(path, "w"), &fclose);
156         FILE *fp = file.get();
157         if (fp == nullptr) {
158             return;
159         }
160         if (fprintf(fp, "%s", str) > 0 && fflush(fp)) {
161             // make ci happy
162         }
163         fclose(fp);
164 #else
165         int flags = UV_FS_O_RDWR | UV_FS_O_APPEND | UV_FS_O_CREAT;
166         uv_fs_t req;
167         int fd = uv_fs_open(nullptr, &req, path, flags, S_IWUSR | S_IRUSR, nullptr);
168         if (fd < 0) {
169             char buffer[BUF_SIZE_DEFAULT] = { 0 };
170             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
171             uv_fs_req_cleanup(&req);
172             PrintMessage("LogToPath uv_fs_open %s error %s", path, buffer);
173             return;
174         }
175         string text(str);
176         uv_buf_t wbf = uv_buf_init((char *)str, text.size());
177         uv_fs_req_cleanup(&req);
178         uv_fs_write(nullptr, &req, fd, &wbf, 1, -1, nullptr);
179         uv_fs_close(nullptr, &req, fd, nullptr);
180 #endif
181     }
182 
GetTimeString(string & timeString)183     void GetTimeString(string &timeString)
184     {
185         system_clock::time_point timeNow = system_clock::now();
186         system_clock::duration sinceUnix0 = timeNow.time_since_epoch(); // since 1970
187         time_t sinceUnix0Time = duration_cast<seconds>(sinceUnix0).count();
188         std::tm *timeTm = std::localtime(&sinceUnix0Time);
189 
190         const auto sinceUnix0Rest = duration_cast<milliseconds>(sinceUnix0).count() % TIME_BASE;
191         string msTimeSurplus = StringFormat("%03llu", sinceUnix0Rest);
192         timeString = msTimeSurplus;
193         if (timeTm != nullptr) {
194             char buffer[TIME_BUF_SIZE] = {0};
195             if (strftime(buffer, TIME_BUF_SIZE, "%Y%m%d-%H%M%S", timeTm) > 0) {
196                 timeString = StringFormat("%s%s", buffer, msTimeSurplus.c_str());
197             }
198         }
199     }
200 
CompareLogFileName(const string & a,const string & b)201     bool CompareLogFileName(const string &a, const string &b)
202     {
203         return strcmp(a.c_str(), b.c_str()) < 0;
204     }
205 
206 #ifdef _WIN32
RemoveOlderLogFilesOnWindows()207     void RemoveOlderLogFilesOnWindows()
208     {
209         vector<string> files;
210         WIN32_FIND_DATA findData;
211         HANDLE hFind = FindFirstFile((GetTmpDir() + "/*").c_str(), &findData);
212         if (hFind == INVALID_HANDLE_VALUE) {
213             WRITE_LOG(LOG_WARN, "Failed to open TEMP dir");
214             return;
215         }
216 
217         do {
218             if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
219                 SetErrorMode(SEM_FAILCRITICALERRORS);
220                 if (strncmp(findData.cFileName, LOG_FILE_NAME_PREFIX.c_str(), LOG_FILE_NAME_PREFIX.size()) == 0) {
221                     files.push_back(findData.cFileName);
222                 }
223             }
224         } while (FindNextFile(hFind, &findData));
225         FindClose(hFind);
226 
227         if (files.size() <= MAX_LOG_FILE_COUNT) {
228             return;
229         }
230 
231         // Sort file names by time, with earlier ones coming first
232         sort(files.begin(), files.end(), CompareLogFileName);
233 
234         uint16_t deleteCount = files.size() - MAX_LOG_FILE_COUNT;
235         WRITE_LOG(LOG_INFO, "will delete log file, count: %u", deleteCount);
236         uint16_t count = 0;
237         for (auto name : files) {
238             if (count >= deleteCount) {
239                 break;
240             }
241             string deleteFile = GetTmpDir() + name;
242             LPCTSTR lpFileName = TEXT(deleteFile.c_str());
243             BOOL ret = DeleteFile(lpFileName);
244             WRITE_LOG(LOG_INFO, "delete: %s ret:%d", deleteFile.c_str(), ret);
245             count++;
246         }
247     }
248 #endif
249 
RemoveOlderLogFiles()250     void RemoveOlderLogFiles()
251     {
252 #ifdef _WIN32
253         RemoveOlderLogFilesOnWindows();
254         return;
255 #endif
256         vector<string> files;
257         DIR* dir = opendir(GetTmpDir().c_str());
258         if (dir == nullptr) {
259             WRITE_LOG(LOG_WARN, "open log dir failed");
260             return;
261         }
262 
263         struct dirent* entry;
264         while ((entry = readdir(dir)) != nullptr) {
265             string fileName = entry->d_name;
266             if (strncmp(fileName.c_str(), LOG_FILE_NAME_PREFIX.c_str(), LOG_FILE_NAME_PREFIX.size()) == 0) {
267                 files.push_back(fileName);
268             }
269         }
270         closedir(dir);
271 
272         if (files.size() <= MAX_LOG_FILE_COUNT) {
273             return;
274         }
275 
276         // Sort file names by time, with earlier ones coming first
277         sort(files.begin(), files.end(), CompareLogFileName);
278 
279         uint16_t deleteCount = files.size() - MAX_LOG_FILE_COUNT;
280         WRITE_LOG(LOG_INFO, "will delete log file, count: %u", deleteCount);
281         uint16_t count = 0;
282         for (auto name : files) {
283             if (count >= deleteCount) {
284                 break;
285             }
286             string deleteFile = GetTmpDir() + name;
287             WRITE_LOG(LOG_INFO, "delete: %s", deleteFile.c_str());
288             unlink(deleteFile.c_str());
289             count++;
290         }
291     }
292 
LogToFile(const char * str)293     void LogToFile(const char *str)
294     {
295         string path = GetTmpDir() + LOG_FILE_NAME;
296         RollLogFile(path.c_str());
297         LogToPath(path.c_str(), str);
298     }
299 
LogToCache(const char * str)300     void LogToCache(const char *str)
301     {
302         string path = GetTmpDir() + LOG_CACHE_NAME;
303         LogToPath(path.c_str(), str);
304     }
305 
RollLogFile(const char * path)306     void RollLogFile(const char *path)
307     {
308         int value = -1;
309         uv_fs_t fs;
310         value = uv_fs_stat(nullptr, &fs, path, nullptr);
311         if (value != 0) {
312             constexpr int bufSize = 1024;
313             char buf[bufSize] = { 0 };
314             uv_strerror_r(value, buf, bufSize);
315             PrintMessage("RollLogFile error log file %s not exist %s", path, buf);
316             return;
317         }
318         uint64_t size = fs.statbuf.st_size;
319         if (size < LOG_FILE_MAX_SIZE) {
320             return;
321         }
322         string timeStr;
323         GetTimeString(timeStr);
324         string last = GetTmpDir() + LOG_FILE_NAME_PREFIX + timeStr + ".log";
325         value = uv_fs_rename(nullptr, &fs, path, last.c_str(), nullptr);
326         if (value != 0) {
327             constexpr int bufSize = 1024;
328             char buf[bufSize] = { 0 };
329             uv_strerror_r(value, buf, bufSize);
330             PrintMessage("RollLogFile error rename %s to %s %s", path, last.c_str(), buf);
331             return;
332         }
333         RemoveOlderLogFiles();
334     }
335 
ChmodLogFile()336     void ChmodLogFile()
337     {
338         string path = GetTmpDir() + LOG_FILE_NAME;
339         uv_fs_t req = {};
340         uv_fs_req_cleanup(&req);
341         int rc = uv_fs_chmod(nullptr, &req, path.c_str(), 0664, nullptr);
342         if (rc < 0) {
343             char buffer[BUF_SIZE_DEFAULT] = { 0 };
344             uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
345             WRITE_LOG(LOG_FATAL, "uv_fs_chmod %s failed %s", path.c_str(), buffer);
346         }
347     }
348 #endif
349 
PrintLogEx(const char * functionName,int line,uint8_t logLevel,const char * msg,...)350     void PrintLogEx(const char *functionName, int line, uint8_t logLevel, const char *msg, ...)
351     {
352         if (logLevel > g_logLevel) {
353             return;
354         }
355 
356         char buf[BUF_SIZE_DEFAULT4] = { 0 }; // only 4k to avoid stack overflow in 32bit or L0
357         va_list vaArgs;
358         va_start(vaArgs, msg);
359         const int retSize = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, msg, vaArgs);
360         va_end(vaArgs);
361         if (retSize < 0) {
362             return;
363         }
364 
365 #ifdef  HDC_HILOG
366         string tmpPath = functionName;
367         string filePath = GetFileNameAny(tmpPath);
368         switch (static_cast<int>(logLevel)) {
369             case static_cast<int>(LOG_DEBUG):
370                 // Info level log can be printed default in hilog, debug can't
371                 HDC_LOG_INFO("[%{public}s:%{public}d] %{public}s",
372                     filePath.c_str(), line, buf);
373                 break;
374             case static_cast<int>(LOG_INFO):
375                 HDC_LOG_INFO("[%{public}s:%{public}d] %{public}s",
376                     filePath.c_str(), line, buf);
377                 break;
378             case static_cast<int>(LOG_WARN):
379                 HDC_LOG_WARN("[%{public}s:%{public}d] %{public}s",
380                     filePath.c_str(), line, buf);
381                 break;
382             case static_cast<int>(LOG_FATAL):
383                 HDC_LOG_FATAL("[%{public}s:%{public}d] %{public}s",
384                     filePath.c_str(), line, buf);
385                 break;
386             default:
387                 break;
388         }
389 #else
390         string logLevelString;
391         string threadIdString;
392         string sep = "\n";
393         string timeString;
394         if (string(buf).back() == '\n') {
395             sep = "\r\n";
396         }
397         string debugInfo = functionName;
398         GetLogDebugFunctionName(debugInfo, line, threadIdString);
399         GetLogLevelAndTime(logLevel, logLevelString, timeString);
400         string logBuf = StringFormat("[%s][%s]%s%s %s%s", logLevelString.c_str(), timeString.c_str(),
401                                      threadIdString.c_str(), debugInfo.c_str(), buf, sep.c_str());
402 
403         printf("%s", logBuf.c_str());
404         fflush(stdout);
405 
406         if (!g_logCache) {
407             LogToFile(logBuf.c_str());
408         } else {
409             LogToCache(logBuf.c_str());
410         }
411 #endif
412         return;
413     }
414 #else   // else ENABLE_DEBUGLOG.If disabled, the entire output code will be optimized by the compiler
PrintLogEx(const char * functionName,int line,uint8_t logLevel,char * msg,...)415     void PrintLogEx(const char *functionName, int line, uint8_t logLevel, char *msg, ...)
416     {
417     }
418 #endif  // ENABLE_DEBUGLOG
419 
PrintMessage(const char * fmt,...)420     void PrintMessage(const char *fmt, ...)
421     {
422         va_list ap;
423         va_start(ap, fmt);
424         if (vfprintf(stdout, fmt, ap) > 0) {
425             fprintf(stdout, "\n");
426         }
427         va_end(ap);
428     }
429 
430     // if can linkwith -lstdc++fs, use std::filesystem::path(path).filename();
GetFileNameAny(string & path)431     string GetFileNameAny(string &path)
432     {
433         string tmpString = path;
434         size_t tmpNum = tmpString.rfind('/');
435         if (tmpNum == std::string::npos) {
436             tmpNum = tmpString.rfind('\\');
437             if (tmpNum == std::string::npos) {
438                 return tmpString;
439             }
440         }
441         tmpString = tmpString.substr(tmpNum + 1, tmpString.size() - tmpNum);
442         return tmpString;
443     }
444 
SetTcpOptions(uv_tcp_t * tcpHandle,int bufMaxSize)445     void SetTcpOptions(uv_tcp_t *tcpHandle, int bufMaxSize)
446     {
447         if (!tcpHandle) {
448             return;
449         }
450         uv_tcp_keepalive(tcpHandle, 1, GLOBAL_TIMEOUT);
451         // if MAX_SIZE_IOBUF==5k,bufMaxSize at least 40k. It must be set to io 8 times is more appropriate,
452         // otherwise asynchronous IO is too fast, a lot of IO is wasted on IOloop, transmission speed will decrease
453 
454         uv_recv_buffer_size((uv_handle_t *)tcpHandle, &bufMaxSize);
455         uv_send_buffer_size((uv_handle_t *)tcpHandle, &bufMaxSize);
456     }
457 
ReallocBuf(uint8_t ** origBuf,int * nOrigSize,size_t sizeWanted)458     void ReallocBuf(uint8_t **origBuf, int *nOrigSize, size_t sizeWanted)
459     {
460         if (*nOrigSize > 0) {
461             return;
462         }
463         if (sizeWanted <= 0 || sizeWanted >= HDC_BUF_MAX_BYTES) {
464             WRITE_LOG(LOG_WARN, "ReallocBuf failed, sizeWanted:%d", sizeWanted);
465             return;
466         }
467         *origBuf = new uint8_t[sizeWanted];
468         if (!*origBuf) {
469             WRITE_LOG(LOG_WARN, "ReallocBuf failed, origBuf is null. sizeWanted:%d", sizeWanted);
470             return;
471         }
472         *nOrigSize = sizeWanted;
473     }
474 
475     // As an uv_alloc_cb it must keep the same as prototype
AllocBufferCallback(uv_handle_t * handle,size_t sizeSuggested,uv_buf_t * buf)476     void AllocBufferCallback(uv_handle_t *handle, size_t sizeSuggested, uv_buf_t *buf)
477     {
478         const int size = GetMaxBufSizeStable();
479         buf->base = (char *)new uint8_t[size]();
480         if (buf->base) {
481             buf->len = size - 1;
482         }
483     }
484 
485     // As an uv_write_cb it must keep the same as prototype
SendCallback(uv_write_t * req,int status)486     void SendCallback(uv_write_t *req, int status)
487     {
488         StartTraceScope("Base::SendCallback");
489         if (status < 0) {
490             constexpr int bufSize = 1024;
491             char buf[bufSize] = { 0 };
492             uv_strerror_r(status, buf, bufSize);
493             WRITE_LOG(LOG_WARN, "SendCallback failed,status:%d %s", status, buf);
494         }
495         delete[]((uint8_t *)req->data);
496         delete req;
497     }
498 
499     // xxx must keep sync with uv_loop_close/uv_walk etc.
TryCloseLoop(uv_loop_t * ptrLoop,const char * callerName)500     bool TryCloseLoop(uv_loop_t *ptrLoop, const char *callerName)
501     {
502         // UV_RUN_DEFAULT: Runs the event loop until the reference count drops to zero. Always returns zero.
503         // UV_RUN_ONCE:    Poll for new events once. Note that this function blocks if there are no pending events.
504         //                 Returns zero when done (no active handles or requests left), or non-zero if more events are
505         //                 expected meaning you should run the event loop again sometime in the future).
506         // UV_RUN_NOWAIT:  Poll for new events once but don't block if there are no pending events.
507         uint8_t closeRetry = 0;
508         bool ret = false;
509         constexpr int maxRetry = 3;
510         for (closeRetry = 0; closeRetry < maxRetry; ++closeRetry) {
511             if (uv_loop_close(ptrLoop) == UV_EBUSY) {
512                 if (closeRetry > 2) { // 2:try 2 times close,the 3rd try shows uv loop cannot close.
513                     WRITE_LOG(LOG_WARN, "%s close busy,try:%d", callerName, closeRetry);
514                 }
515 
516                 if (ptrLoop->active_handles >= 2) { // 2:at least 2 handles for read & write.
517                     WRITE_LOG(LOG_DEBUG, "TryCloseLoop issue");
518                 }
519                 auto clearLoopTask = [](uv_handle_t *handle, void *arg) -> void { TryCloseHandle(handle); };
520                 uv_walk(ptrLoop, clearLoopTask, nullptr);
521                 // If all processing ends, Then return0,this call will block
522                 if (!ptrLoop->active_handles) {
523                     ret = true;
524                     break;
525                 }
526                 if (!uv_run(ptrLoop, UV_RUN_ONCE)) {
527                     ret = true;
528                     break;
529                 }
530                 usleep(10000); // 10000:sleep for 10s
531             } else {
532                 WRITE_LOG(LOG_DEBUG, "Try close loop success");
533                 ret = true;
534                 break;
535             }
536         }
537         return ret;
538     }
539 
540     // xxx must keep sync with uv_loop_close/uv_walk etc.
TryCloseChildLoop(uv_loop_t * ptrLoop,const char * callerName)541     bool TryCloseChildLoop(uv_loop_t *ptrLoop, const char *callerName)
542     {
543         // UV_RUN_DEFAULT: Runs the event loop until the reference count drops to zero. Always returns zero.
544         // UV_RUN_ONCE:    Poll for new events once. Note that this function blocks if there are no pending events.
545         //                 Returns zero when done (no active handles or requests left), or non-zero if more events are
546         //                 expected meaning you should run the event loop again sometime in the future).
547         // UV_RUN_NOWAIT:  Poll for new events once but don't block if there are no pending events.
548         uint8_t closeRetry = 0;
549         bool ret = false;
550         constexpr int maxRetry = 3;
551         for (closeRetry = 0; closeRetry < maxRetry; ++closeRetry) {
552             if (uv_loop_close(ptrLoop) == UV_EBUSY) {
553                 if (closeRetry > 2) { // 2:try 2 times close,the 3rd try shows uv loop cannot close.
554                     WRITE_LOG(LOG_WARN, "%s close busy,try:%d", callerName, closeRetry);
555                 }
556 
557                 if (ptrLoop->active_handles >= 2) { // 2:at least 2 handles for read & write.
558                     WRITE_LOG(LOG_DEBUG, "TryCloseLoop issue");
559                 }
560                 auto clearLoopTask = [](uv_handle_t *handle, void *arg) -> void { TryCloseHandle(handle); };
561                 uv_walk(ptrLoop, clearLoopTask, nullptr);
562 #if defined(HDC_HOST) && !defined(HOST_LINUX)
563                 // If all processing ends, Then return0,this call will block
564                 if (!ptrLoop->active_handles) {
565                     ret = true;
566                     break;
567                 }
568                 if (!uv_run(ptrLoop, UV_RUN_ONCE)) {
569                     ret = true;
570                     break;
571                 }
572                 usleep(10000); // 10000:sleep for 10s
573 #else
574                 int r = 0;
575                 int count = 0;
576                 do {
577                     count++;
578                     r = uv_run(ptrLoop, UV_RUN_NOWAIT);
579                     uv_sleep(MILL_SECONDS); //10 millseconds
580                 } while (r != 0 && count <= COUNT);
581 #endif
582             } else {
583                 WRITE_LOG(LOG_DEBUG, "Try close loop success");
584                 ret = true;
585                 break;
586             }
587         }
588         return ret;
589     }
590 
591     // Some handles may not be initialized or activated yet or have been closed, skip the closing process
TryCloseHandle(const uv_handle_t * handle)592     void TryCloseHandle(const uv_handle_t *handle)
593     {
594         TryCloseHandle(handle, nullptr);
595     }
596 
TryCloseHandle(const uv_handle_t * handle,uv_close_cb closeCallBack)597     void TryCloseHandle(const uv_handle_t *handle, uv_close_cb closeCallBack)
598     {
599         TryCloseHandle(handle, false, closeCallBack);
600     }
601 
TryCloseHandle(const uv_handle_t * handle,bool alwaysCallback,uv_close_cb closeCallBack)602     void TryCloseHandle(const uv_handle_t *handle, bool alwaysCallback, uv_close_cb closeCallBack)
603     {
604         bool hasCallClose = false;
605         if (handle->loop && !uv_is_closing(handle)) {
606             DispUvStreamInfo((const uv_stream_t *)handle, "before uv handle close");
607             uv_close((uv_handle_t *)handle, closeCallBack);
608             hasCallClose = true;
609         }
610         if (!hasCallClose && alwaysCallback) {
611             closeCallBack((uv_handle_t *)handle);
612         }
613     }
614 
DispUvStreamInfo(const uv_stream_t * handle,const char * prefix)615     void DispUvStreamInfo(const uv_stream_t *handle, const char *prefix)
616     {
617         uv_handle_type type = handle->type;
618         string name = "unknown";
619         if (type == UV_TCP) {
620             name = "tcp";
621         } else if (type == UV_NAMED_PIPE) {
622             name = "named_pipe";
623         } else {
624             WRITE_LOG(LOG_DEBUG, "%s, the uv handle type is %d", prefix, type);
625             return;
626         }
627 
628         size_t bufNotSended = uv_stream_get_write_queue_size(handle);
629         if (bufNotSended != 0) {
630             WRITE_LOG(LOG_DEBUG, "%s, the uv handle type is %s, has %u bytes data", prefix, name.c_str(), bufNotSended);
631         }
632     }
SendToStream(uv_stream_t * handleStream,const uint8_t * buf,const int bufLen)633     int SendToStream(uv_stream_t *handleStream, const uint8_t *buf, const int bufLen)
634     {
635         StartTraceScope("Base::SendToStream");
636         if (bufLen > static_cast<int>(HDC_BUF_MAX_BYTES)) {
637             return ERR_BUF_ALLOC;
638         }
639         uint8_t *pDynBuf = new uint8_t[bufLen];
640         if (!pDynBuf) {
641             WRITE_LOG(LOG_WARN, "SendToStream, alloc failed, size:%d", bufLen);
642             return ERR_BUF_ALLOC;
643         }
644         if (memcpy_s(pDynBuf, bufLen, buf, bufLen)) {
645             WRITE_LOG(LOG_WARN, "SendToStream, memory copy failed, size:%d", bufLen);
646             delete[] pDynBuf;
647             return ERR_BUF_COPY;
648         }
649         return SendToStreamEx(handleStream, pDynBuf, bufLen, nullptr,
650                               reinterpret_cast<void *>(SendCallback), reinterpret_cast<void *>(pDynBuf));
651     }
652 
653     // handleSend is used for pipe thread sending, set nullptr for tcp, and dynamically allocated by malloc when buf
654     // is required
SendToStreamEx(uv_stream_t * handleStream,const uint8_t * buf,const int bufLen,uv_stream_t * handleSend,const void * finishCallback,const void * pWriteReqData)655     int SendToStreamEx(uv_stream_t *handleStream, const uint8_t *buf, const int bufLen, uv_stream_t *handleSend,
656                        const void *finishCallback, const void *pWriteReqData)
657     {
658         StartTraceScope("Base::SendToStreamEx");
659         int ret = ERR_GENERIC;
660         uv_write_t *reqWrite = new uv_write_t();
661         if (!reqWrite) {
662             WRITE_LOG(LOG_WARN, "SendToStreamEx, new write_t failed, size:%d", bufLen);
663             return ERR_BUF_ALLOC;
664         }
665         uv_buf_t bfr;
666         while (true) {
667             reqWrite->data = (void *)pWriteReqData;
668             bfr.base = (char *)buf;
669             bfr.len = bufLen;
670             if (!uv_is_writable(handleStream)) {
671                 WRITE_LOG(LOG_WARN, "SendToStreamEx, uv_is_writable false, size:%d", bufLen);
672                 delete reqWrite;
673                 break;
674             }
675             // handleSend must be a TCP socket or pipe, which is a server or a connection (listening or
676             // connected state). Bound sockets or pipes will be assumed to be servers.
677             if (handleSend) {
678                 ret = uv_write2(reqWrite, handleStream, &bfr, 1, handleSend, (uv_write_cb)finishCallback);
679             } else {
680                 ret = uv_write(reqWrite, handleStream, &bfr, 1, (uv_write_cb)finishCallback);
681             }
682             if (ret < 0) {
683                 WRITE_LOG(LOG_WARN, "SendToStreamEx, uv_write false, size:%d", bufLen);
684                 delete reqWrite;
685                 ret = ERR_IO_FAIL;
686                 break;
687             }
688             ret = bufLen;
689             break;
690         }
691         return ret;
692     }
693 
SendToPollFd(int fd,const uint8_t * buf,const int bufLen)694     int SendToPollFd(int fd, const uint8_t *buf, const int bufLen)
695     {
696         if (bufLen > static_cast<int>(HDC_BUF_MAX_BYTES)) {
697             return ERR_BUF_ALLOC;
698         }
699         uint8_t *pDynBuf = new uint8_t[bufLen];
700         if (!pDynBuf) {
701             WRITE_LOG(LOG_WARN, "SendToPollFd, alloc failed, size:%d", bufLen);
702             return ERR_BUF_ALLOC;
703         }
704         if (memcpy_s(pDynBuf, bufLen, buf, bufLen)) {
705             WRITE_LOG(LOG_WARN, "SendToPollFd, memory copy failed, size:%d", bufLen);
706             delete[] pDynBuf;
707             return ERR_BUF_COPY;
708         }
709         int ret = Base::WriteToFd(fd, pDynBuf, bufLen);
710         delete[] pDynBuf;
711         if (ret <= 0) {
712             hdc_strerrno(buf);
713             WRITE_LOG(LOG_WARN, "SendToPollFd, send %d bytes to fd %d failed [%d][%s]", bufLen, fd, ret, buf);
714         }
715         return ret;
716     }
717 
GetRuntimeMSec()718     uint64_t GetRuntimeMSec()
719     {
720         struct timespec times = { 0, 0 };
721         long time;
722         clock_gettime(CLOCK_MONOTONIC, &times);
723         time = times.tv_sec * TIME_BASE + times.tv_nsec / (TIME_BASE * TIME_BASE);
724         return time;
725     }
726 
GetRandomU32()727     uint32_t GetRandomU32()
728     {
729         uint32_t ret;
730         std::random_device rd;
731         std::mt19937 gen(rd());
732         std::uniform_int_distribution<uint32_t> dis(0, UINT32_MAX);
733         ret = dis(gen);
734         return ret;
735     }
736 
GetRandom(const uint64_t min,const uint64_t max)737     uint64_t GetRandom(const uint64_t min, const uint64_t max)
738     {
739 #ifdef HARMONY_PROJECT
740         uint64_t ret;
741         uv_random(nullptr, nullptr, &ret, sizeof(ret), 0, nullptr);
742 #else
743         uint64_t ret;
744         std::random_device rd;
745         std::mt19937 gen(rd());
746         std::uniform_int_distribution<uint64_t> dis(min, max);
747         ret = dis(gen);
748 #endif
749         return ret;
750     }
751 
GetSecureRandom(void)752     uint32_t GetSecureRandom(void)
753     {
754         uint32_t result = static_cast<uint32_t>(GetRandom());
755 #ifdef _WIN32
756         const int randomByteCount = 4;
757         HCRYPTPROV hCryptProv;
758         BYTE pbData[randomByteCount];
759         do {
760             if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
761                 if (GetLastError() != NTE_BAD_KEYSET) {
762                     WRITE_LOG(LOG_FATAL, "CryptAcquireContext first failed %x", GetLastError());
763                     break;
764                 }
765                 if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
766                     WRITE_LOG(LOG_FATAL, "CryptAcquireContext second failed %x", GetLastError());
767                     break;
768                 }
769             }
770             if (!CryptGenRandom(hCryptProv, randomByteCount, pbData)) {
771                 WRITE_LOG(LOG_FATAL, "CryptGenRandom failed %x", GetLastError());
772             }
773             if (hCryptProv) {
774                 CryptReleaseContext(hCryptProv, 0);
775             }
776             result = *(reinterpret_cast<uint32_t*>(pbData));
777         } while (0);
778 #else
779         std::ifstream randomFile("/dev/random", std::ios::binary);
780         do {
781             if (!randomFile.is_open()) {
782                 WRITE_LOG(LOG_FATAL, "open /dev/random failed");
783                 break;
784             }
785             randomFile.read(reinterpret_cast<char*>(&result), sizeof(result));
786         } while (0);
787         randomFile.close();
788 #endif
789         return result;
790     }
791 
GetRandomString(const uint16_t expectedLen)792     string GetRandomString(const uint16_t expectedLen)
793     {
794         srand(static_cast<unsigned int>(GetRandom()));
795         string ret = string(expectedLen, '0');
796         std::stringstream val;
797         for (auto i = 0; i < expectedLen; ++i) {
798             val << std::hex << (rand() % BUF_SIZE_MICRO);
799         }
800         ret = val.str();
801         return ret;
802     }
803 
804 #ifndef HDC_HOST
GetSecureRandomString(const uint16_t expectedLen)805     string GetSecureRandomString(const uint16_t expectedLen)
806     {
807         string ret = string(expectedLen, '0');
808         std::ifstream randomFile("/dev/random", std::ios::binary);
809         do {
810             if (!randomFile.is_open()) {
811                 WRITE_LOG(LOG_FATAL, "open /dev/random failed");
812                 break;
813             }
814             std::stringstream val;
815             unsigned char tmpByte;
816             for (auto i = 0; i < expectedLen; ++i) {
817                 randomFile.read(reinterpret_cast<char*>(&tmpByte), 1);
818                 val << std::hex << (tmpByte % BUF_SIZE_MICRO);
819             }
820             ret = val.str();
821         } while (0);
822         randomFile.close();
823 
824         return ret;
825     }
826 #endif
827 
GetRandomNum(const int min,const int max)828     int GetRandomNum(const int min, const int max)
829     {
830         return static_cast<int>(GetRandom(min, max));
831     }
832 
ConnectKey2IPPort(const char * connectKey,char * outIP,uint16_t * outPort,size_t outSize)833     int ConnectKey2IPPort(const char *connectKey, char *outIP, uint16_t *outPort, size_t outSize)
834     {
835         char bufString[BUF_SIZE_TINY] = "";
836         if (strncpy_s(bufString, sizeof(bufString), connectKey, strlen(connectKey))) {
837             return ERR_BUF_COPY;
838         }
839         char *p = strrchr(bufString, ':');
840         if (!p) {
841             return ERR_PARM_FORMAT;
842         }
843         *p = '\0';
844         if (!strlen(bufString) || strlen(bufString) > 40) { // 40 : bigger than length of ipv6
845             return ERR_PARM_SIZE;
846         }
847         uint16_t wPort = static_cast<uint16_t>(atoi(p + 1));
848         if (EOK != strcpy_s(outIP, outSize, bufString)) {
849             return ERR_BUF_COPY;
850         }
851         *outPort = wPort;
852         return RET_SUCCESS;
853     }
854 
855     // After creating the session worker thread, execute it on the main thread
FinishWorkThread(uv_work_t * req,int status)856     void FinishWorkThread(uv_work_t *req, int status)
857     {
858         // This is operated in the main thread
859         delete req;
860     }
861 
862     // at the finish of pFuncAfterThread must free uv_work_t*
863     // clang-format off
StartWorkThread(uv_loop_t * loop,uv_work_cb pFuncWorkThread,uv_after_work_cb pFuncAfterThread,void * pThreadData)864     int StartWorkThread(uv_loop_t *loop, uv_work_cb pFuncWorkThread,
865                         uv_after_work_cb pFuncAfterThread, void *pThreadData)
866     {
867         uv_work_t *workThread = new uv_work_t();
868         if (!workThread) {
869             return -1;
870         }
871         workThread->data = pThreadData;
872         uv_queue_work(loop, workThread, pFuncWorkThread, pFuncAfterThread);
873         return 0;
874     }
875     // clang-format on
876 
SplitCommandToArgs(const char * cmdStringLine,int * slotIndex)877     char **SplitCommandToArgs(const char *cmdStringLine, int *slotIndex)
878     {
879         constexpr int extraBufSize = 2;
880         char **argv;
881         char *temp = nullptr;
882         int argc = 0;
883         char a = 0;
884         size_t i = 0;
885         size_t j = 0;
886         size_t len = 0;
887         bool isQuoted = false;
888         bool isText = false;
889         bool isSpace = false;
890 
891         len = strlen(cmdStringLine);
892         if (len < 1) {
893             return nullptr;
894         }
895         i = ((len + extraBufSize) / extraBufSize) * sizeof(void *) + sizeof(void *);
896         argv = reinterpret_cast<char **>(new(std::nothrow) char[i + (len + extraBufSize) * sizeof(char)]);
897         if (argv == nullptr) {
898             WRITE_LOG(LOG_FATAL, "SplitCommandToArgs new argv failed");
899             return nullptr;
900         }
901         temp = reinterpret_cast<char *>((reinterpret_cast<uint8_t *>(argv)) + i);
902         argc = 0;
903         argv[argc] = temp;
904         isQuoted = false;
905         isText = false;
906         isSpace = true;
907         i = 0;
908         j = 0;
909 
910         while ((a = cmdStringLine[i]) != 0) {
911             if (isQuoted) {
912                 if (a == '\"') {
913                     isQuoted = false;
914                 } else {
915                     temp[j] = a;
916                     ++j;
917                 }
918             } else {
919                 switch (a) {
920                     case '\"':
921                         isQuoted = true;
922                         isText = true;
923                         if (isSpace) {
924                             argv[argc] = temp + j;
925                             ++argc;
926                         }
927                         isSpace = false;
928                         break;
929                     case ' ':
930                     case '\t':
931                     case '\n':
932                     case '\r':
933                         if (isText) {
934                             temp[j] = '\0';
935                             ++j;
936                         }
937                         isText = false;
938                         isSpace = true;
939                         break;
940                     default:
941                         isText = true;
942                         if (isSpace) {
943                             argv[argc] = temp + j;
944                             ++argc;
945                         }
946                         temp[j] = a;
947                         ++j;
948                         isSpace = false;
949                         break;
950                 }
951             }
952             ++i;
953         }
954         temp[j] = '\0';
955         argv[argc] = nullptr;
956 
957         (*slotIndex) = argc;
958         return argv;
959     }
960 
RunPipeComand(const char * cmdString,char * outBuf,uint16_t sizeOutBuf,bool ignoreTailLf)961     bool RunPipeComand(const char *cmdString, char *outBuf, uint16_t sizeOutBuf, bool ignoreTailLf)
962     {
963         FILE *pipeHandle = popen(cmdString, "r");
964         if (pipeHandle == nullptr) {
965             return false;
966         }
967         int bytesRead = 0;
968         int bytesOnce = 0;
969         while (!feof(pipeHandle)) {
970             bytesOnce = fread(outBuf, 1, sizeOutBuf - bytesRead, pipeHandle);
971             if (bytesOnce <= 0) {
972                 break;
973             }
974             bytesRead += bytesOnce;
975         }
976         if (bytesRead && ignoreTailLf) {
977             if (outBuf[bytesRead - 1] == '\n') {
978                 outBuf[bytesRead - 1] = '\0';
979             }
980         }
981         pclose(pipeHandle);
982         return bytesRead;
983     }
984 
985     // bufLen == 0: alloc buffer in heap, need free it later
986     // >0: read max nBuffLen bytes to *buff
987     // ret value: <0 or bytes read
ReadBinFile(const char * pathName,void ** buf,const size_t bufLen)988     int ReadBinFile(const char *pathName, void **buf, const size_t bufLen)
989     {
990         uint8_t *pDst = nullptr;
991         size_t byteIO = 0;
992         uv_fs_t req;
993         int ret = uv_fs_stat(nullptr, &req, pathName, nullptr);
994         if (ret < 0) {
995             char buffer[BUF_SIZE_DEFAULT] = { 0 };
996             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
997             uv_fs_req_cleanup(&req);
998             WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_stat %s error %s", pathName, buffer);
999             return -1;
1000         }
1001         size_t nFileSize = req.statbuf.st_size;
1002         size_t readMax = 0;
1003         uint8_t dynamicBuf = 0;
1004         ret = -3;  // -3:error for ReadBinFile
1005         if (bufLen == 0) {
1006             dynamicBuf = 1;
1007             pDst = new uint8_t[nFileSize + 1]();  // tail \0
1008             if (!pDst) {
1009                 return -1;
1010             }
1011             readMax = nFileSize;
1012         } else {
1013             if (nFileSize > bufLen) {
1014                 return -2;  // -2:error for bufLen
1015             }
1016             readMax = nFileSize;
1017             pDst = reinterpret_cast<uint8_t *>(buf);  // The first address of the static array is the array address
1018         }
1019 
1020         string srcPath(pathName);
1021         string resolvedPath = CanonicalizeSpecPath(srcPath);
1022         uv_buf_t rbf = uv_buf_init((char *)pDst, readMax);
1023         uv_fs_req_cleanup(&req);
1024         int fd = uv_fs_open(nullptr, &req, resolvedPath.c_str(), O_RDONLY, 0, nullptr);
1025         if (fd < 0) {
1026             char buffer[BUF_SIZE_DEFAULT] = { 0 };
1027             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
1028             WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_open %s error %s", resolvedPath.c_str(), buffer);
1029             goto ReadFileFromPath_Finish;
1030         }
1031         uv_fs_req_cleanup(&req);
1032         byteIO = uv_fs_read(nullptr, &req, fd, &rbf, 1, 0, nullptr);
1033         uv_fs_close(nullptr, nullptr, fd, nullptr);
1034         if (byteIO != readMax) {
1035             char buffer[BUF_SIZE_DEFAULT] = { 0 };
1036             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
1037             WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_read %s error %s byteIO:%llu readMax:%llu",
1038                 resolvedPath.c_str(), buffer, byteIO, readMax);
1039             goto ReadFileFromPath_Finish;
1040         }
1041         ret = 0;
1042     ReadFileFromPath_Finish:
1043         if (ret) {
1044             if (dynamicBuf) {
1045                 delete[] pDst;
1046             }
1047         } else {
1048             if (dynamicBuf) {
1049                 *buf = pDst;
1050             }
1051             ret = byteIO;
1052         }
1053         return ret;
1054     }
1055 
WriteBinFile(const char * pathName,const uint8_t * buf,const size_t bufLen,bool newFile)1056     int WriteBinFile(const char *pathName, const uint8_t *buf, const size_t bufLen, bool newFile)
1057     {
1058         string resolvedPath;
1059         string srcPath(pathName);
1060         int flags = 0;
1061         if (newFile) {
1062             flags = UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC;
1063             // no std::fs supoort, else std::filesystem::canonical,-lstdc++fs
1064             if (srcPath.find("..") != string::npos) {
1065                 return ERR_FILE_PATH_CHECK;
1066             }
1067             resolvedPath = srcPath.c_str();
1068         } else {
1069             flags = UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND;
1070             resolvedPath = CanonicalizeSpecPath(srcPath);
1071         }
1072         uv_fs_t req;
1073         int fd = uv_fs_open(nullptr, &req, resolvedPath.c_str(), flags, S_IWUSR | S_IRUSR, nullptr);
1074         if (fd < 0) {
1075             char buffer[BUF_SIZE_DEFAULT] = { 0 };
1076             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
1077             uv_fs_req_cleanup(&req);
1078             WRITE_LOG(LOG_FATAL, "WriteBinFile uv_fs_open %s error %s", resolvedPath.c_str(), buffer);
1079             return ERR_FILE_OPEN;
1080         }
1081         uv_buf_t wbf = uv_buf_init((char *)buf, bufLen);
1082         uv_fs_req_cleanup(&req);
1083         size_t bytesDone = uv_fs_write(nullptr, &req, fd, &wbf, 1, 0, nullptr);
1084         uv_fs_close(nullptr, &req, fd, nullptr);
1085         if (bytesDone != bufLen) {
1086             char buffer[BUF_SIZE_DEFAULT] = { 0 };
1087             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
1088             uv_fs_req_cleanup(&req);
1089             WRITE_LOG(LOG_FATAL, "WriteBinFile uv_fs_write %s error %s bytesDone:%llu bufLen:%llu",
1090                 resolvedPath.c_str(), buffer, bytesDone, bufLen);
1091             return ERR_BUF_SIZE;
1092         }
1093         return RET_SUCCESS;
1094     }
1095 
CloseIdleCallback(uv_handle_t * handle)1096     void CloseIdleCallback(uv_handle_t *handle)
1097     {
1098         delete (uv_idle_t *)handle;
1099     };
1100 
CloseTimerCallback(uv_handle_t * handle)1101     void CloseTimerCallback(uv_handle_t *handle)
1102     {
1103         delete (uv_timer_t *)handle;
1104     };
1105 
1106     // return value: <0 error; 0 can start new server instance; >0 server already exists
ProgramMutex(const char * procname,bool checkOrNew)1107     int ProgramMutex(const char *procname, bool checkOrNew)
1108     {
1109         char bufPath[BUF_SIZE_DEFAULT] = "";
1110         char buf[BUF_SIZE_DEFAULT] = "";
1111         char pidBuf[BUF_SIZE_TINY] = "";
1112         size_t size = sizeof(buf);
1113         if (uv_os_tmpdir(buf, &size) < 0) {
1114             WRITE_LOG(LOG_FATAL, "Tmppath failed");
1115             return ERR_API_FAIL;
1116         }
1117         if (snprintf_s(bufPath, sizeof(bufPath), sizeof(bufPath) - 1, "%s%c.%s.pid", buf, Base::GetPathSep(), procname)
1118             < 0) {
1119             return ERR_BUF_OVERFLOW;
1120         }
1121         int pid = static_cast<int>(getpid());
1122         if (snprintf_s(pidBuf, sizeof(pidBuf), sizeof(pidBuf) - 1, "%d", pid) < 0) {
1123             return ERR_BUF_OVERFLOW;
1124         }
1125         // no need to CanonicalizeSpecPath, else not work
1126         umask(0);
1127         uv_fs_t req;
1128         int fd = uv_fs_open(nullptr, &req, bufPath, O_RDWR | O_CREAT, 0666, nullptr);  // 0666:permission
1129         if (fd < 0) {
1130             char buffer[BUF_SIZE_DEFAULT] = { 0 };
1131             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
1132             uv_fs_req_cleanup(&req);
1133             WRITE_LOG(LOG_DEBUG, "Open mutex file %s failed!!! %s", bufPath, buffer);
1134             return ERR_FILE_OPEN;
1135         }
1136 #ifdef _WIN32
1137         if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "Global\\%s", procname) < 0) {
1138             uv_fs_close(nullptr, &req, fd, nullptr);
1139             return ERR_BUF_OVERFLOW;
1140         }
1141         if (checkOrNew) {
1142             // CheckOrNew is true means to confirm whether the service is running
1143             uv_fs_close(nullptr, &req, fd, nullptr);
1144             HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, buf);
1145             if (hMutex != nullptr) {
1146                 CloseHandle(hMutex);
1147                 WRITE_LOG(LOG_DEBUG, "Mutex \"%s\" locked. Server already exist.", procname);
1148                 return 1;
1149             } else {
1150                 WRITE_LOG(LOG_DEBUG, "Server is not exist");
1151                 return 0;
1152             }
1153         } else {
1154             HANDLE hMutex = CreateMutex(nullptr, TRUE, buf);
1155             DWORD dwError = GetLastError();
1156             if (ERROR_ALREADY_EXISTS == dwError || ERROR_ACCESS_DENIED == dwError) {
1157                 uv_fs_close(nullptr, &req, fd, nullptr);
1158                 WRITE_LOG(LOG_DEBUG, "Creat mutex, \"%s\" locked. proc already exit!!!\n", procname);
1159                 return 1;
1160             }
1161         }
1162 #else
1163         struct flock fl;
1164         fl.l_type = F_WRLCK;
1165         fl.l_start = 0;
1166         fl.l_whence = SEEK_SET;
1167         fl.l_len = 0;
1168         int retChild = fcntl(fd, F_SETLK, &fl);
1169         if (retChild == -1) {
1170             WRITE_LOG(LOG_DEBUG, "File \"%s\" locked. proc already exit!!!\n", bufPath);
1171             uv_fs_close(nullptr, &req, fd, nullptr);
1172             return 1;
1173         }
1174 #endif
1175         int rc = 0;
1176         uv_fs_req_cleanup(&req);
1177         rc = uv_fs_ftruncate(nullptr, &req, fd, 0, nullptr);
1178         if (rc == -1) {
1179             char buffer[BUF_SIZE_DEFAULT] = { 0 };
1180             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
1181             uv_fs_close(nullptr, &req, fd, nullptr);
1182             WRITE_LOG(LOG_FATAL, "ftruncate file %s failed!!! %s", bufPath, buffer);
1183             return ERR_FILE_STAT;
1184         }
1185         uv_buf_t wbf = uv_buf_init(pidBuf, strlen(pidBuf));
1186         uv_fs_req_cleanup(&req);
1187         rc = uv_fs_write(nullptr, &req, fd, &wbf, 1, 0, nullptr);
1188         if (rc == -1) {
1189             char buffer[BUF_SIZE_DEFAULT] = { 0 };
1190             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
1191             uv_fs_close(nullptr, &req, fd, nullptr);
1192             WRITE_LOG(LOG_FATAL, "write file %s failed!!! %s", bufPath, buffer);
1193             return ERR_FILE_WRITE;
1194         }
1195         WRITE_LOG(LOG_DEBUG, "Write mutext to %s, pid:%s", bufPath, pidBuf);
1196         if (checkOrNew) {
1197             // close it for check only
1198             uv_fs_close(nullptr, &req, fd, nullptr);
1199         }
1200         // Do not close the file descriptor, the process will be mutext effect under no-Win32 OS
1201         return RET_SUCCESS;
1202     }
1203 
SplitString(const string & origString,const string & seq,vector<string> & resultStrings)1204     void SplitString(const string &origString, const string &seq, vector<string> &resultStrings)
1205     {
1206         string::size_type p1 = 0;
1207         string::size_type p2 = origString.find(seq);
1208 
1209         while (p2 != string::npos) {
1210             if (p2 == p1) {
1211                 ++p1;
1212                 p2 = origString.find(seq, p1);
1213                 continue;
1214             }
1215             resultStrings.push_back(origString.substr(p1, p2 - p1));
1216             p1 = p2 + seq.size();
1217             p2 = origString.find(seq, p1);
1218         }
1219 
1220         if (p1 != origString.size()) {
1221             resultStrings.push_back(origString.substr(p1));
1222         }
1223     }
1224 
GetShellPath()1225     string GetShellPath()
1226     {
1227         struct stat filecheck;
1228         string shellPath = "/bin/sh";
1229         if (stat(shellPath.c_str(), &filecheck) < 0) {
1230             shellPath = "/system/bin/sh";
1231             if (stat(shellPath.c_str(), &filecheck) < 0) {
1232                 shellPath = "sh";
1233             }
1234         }
1235         return shellPath;
1236     }
1237 
1238     // Not supported on some platforms, Can only be achieved manually
HostToNet(uint64_t val)1239     uint64_t HostToNet(uint64_t val)
1240     {
1241         if (htonl(1) == 1) {
1242             return val;
1243         }
1244         int offset = 32;
1245         return ((static_cast<uint64_t>(htonl(val))) << offset) + htonl(val >> offset);
1246     }
1247 
NetToHost(uint64_t val)1248     uint64_t NetToHost(uint64_t val)
1249     {
1250         if (htonl(1) == 1) {
1251             return val;
1252         }
1253         int offset = 32;
1254         return ((static_cast<uint64_t>(ntohl(val))) << offset) + ntohl(val >> offset);
1255     }
1256 
GetPathSep()1257     char GetPathSep()
1258     {
1259 #ifdef _WIN32
1260         const char sep = '\\';
1261 #else
1262         const char sep = '/';
1263 #endif
1264         return sep;
1265     }
1266 
GetFullFilePath(string & s)1267     string GetFullFilePath(string &s)
1268     {  // cannot use s.rfind(std::filesystem::path::preferred_separator
1269         // remove last sep, and update input
1270         while (s.back() == GetPathSep()) {
1271             s.pop_back();
1272         }
1273 
1274         size_t i = s.rfind(GetPathSep(), s.length());
1275         if (i != string::npos) {
1276             return (s.substr(i + 1, s.length() - i));
1277         }
1278         return s;
1279     }
1280 
GetPathWithoutFilename(const string & s)1281     string GetPathWithoutFilename(const string &s)
1282     {
1283         size_t i = s.rfind(GetPathSep(), s.length());
1284         if (i != string::npos) {
1285             return (s.substr(0, i + 1));
1286         }
1287         return s;
1288     }
1289 
GetHdcAbsolutePath()1290     string GetHdcAbsolutePath()
1291     {
1292         char path[BUF_SIZE_DEFAULT4] = { 0 };
1293         size_t nPathSize = sizeof(path);
1294         int ret = uv_exepath(path, &nPathSize);
1295         if (ret < 0) {
1296             char buf[BUF_SIZE_DEFAULT] = { 0 };
1297             uv_err_name_r(ret, buf, BUF_SIZE_DEFAULT);
1298             WRITE_LOG(LOG_WARN, "uvexepath ret:%d error:%s", ret, buf);
1299             return "";
1300         }
1301 
1302         return string(path);
1303     }
1304 
CreateSocketPair(int * fds)1305     int CreateSocketPair(int *fds)
1306     {
1307 #ifndef _WIN32
1308 #ifdef HOST_MAC
1309         int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
1310         if (ret == 0) {
1311             for (auto i = 0; i < STREAM_SIZE; ++i) {
1312                 if (fcntl(fds[i], F_SETFD, FD_CLOEXEC) == -1) {
1313                     CloseFd(fds[0]);
1314                     CloseFd(fds[1]);
1315                     constexpr int bufSize = 1024;
1316                     char buf[bufSize] = { 0 };
1317                     strerror_r(errno, buf, bufSize);
1318                     WRITE_LOG(LOG_WARN, "fcntl failed to set FD_CLOEXEC: %s", buf);
1319                     return -1;
1320                 }
1321             }
1322         }
1323         return ret;
1324 #else
1325         return socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds);
1326 #endif
1327 #else
1328         struct sockaddr_in addr;
1329         socklen_t addrlen = sizeof(addr);
1330         int reuse = 1;
1331         if (fds == 0) {
1332             return -1;
1333         }
1334         int listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1335         if (listener == -1) {
1336             return -2;  // -2:sockets error
1337         }
1338         Base::ZeroStruct(addr);
1339         addr.sin_family = AF_INET;
1340         addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1341         addr.sin_port = 0;
1342         fds[0] = fds[1] = (int)-1;
1343         do {
1344             if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, (socklen_t)sizeof(reuse))) {
1345                 break;
1346             }
1347             if (::bind(listener, (struct sockaddr *)&addr, sizeof(addr))) {
1348                 break;
1349             }
1350             if (getsockname(listener, (struct sockaddr *)&addr, &addrlen)) {
1351                 break;
1352             }
1353             if (listen(listener, 1)) {
1354                 break;
1355             }
1356             fds[0] = socket(AF_INET, SOCK_STREAM, 0);
1357             if (fds[0] == -1) {
1358                 break;
1359             }
1360             if (connect(fds[0], (struct sockaddr *)&addr, sizeof(addr)) == -1) {
1361                 break;
1362             }
1363             fds[1] = accept(listener, nullptr, nullptr);
1364             if (fds[1] == -1) {
1365                 break;
1366             }
1367             closesocket(listener);
1368             return 0;
1369         } while (0);
1370 
1371         closesocket(listener);
1372         closesocket(fds[0]);
1373         closesocket(fds[1]);
1374         return -1;
1375 #endif
1376     }
1377 
CloseSocketPair(int * fds)1378     void CloseSocketPair(int *fds)
1379     {
1380 #ifndef _WIN32
1381         CloseFd(fds[0]);
1382         CloseFd(fds[1]);
1383 #else
1384         closesocket(fds[0]);
1385         closesocket(fds[1]);
1386 #endif
1387     }
1388 
StringEndsWith(string s,string sub)1389     int StringEndsWith(string s, string sub)
1390     {
1391         return s.rfind(sub) == (s.length() - sub.length()) ? 1 : 0;
1392     }
1393 
GetFileType(mode_t mode)1394     const char *GetFileType(mode_t mode)
1395     {
1396         switch (mode & S_IFMT) {
1397             case S_IFDIR:
1398                 return "directory";
1399             case S_IFLNK:
1400                 return "symlink";
1401             case S_IFREG:
1402                 return "regular file";
1403 #ifndef _WIN32
1404             case S_IFBLK:
1405                 return "block device";
1406             case S_IFCHR:
1407                 return "character device";
1408             case S_IFIFO:
1409                 return "FIFO/pipe";
1410             case S_IFSOCK:
1411                 return "socket";
1412 #endif
1413             default:
1414                 return "Unknown";
1415         }
1416     }
1417 
BuildErrorString(const char * localPath,const char * op,const char * err,string & str)1418     void BuildErrorString(const char *localPath, const char *op, const char *err, string &str)
1419     {
1420         // avoid to use stringstream
1421         str = op;
1422         str += " ";
1423         str += localPath;
1424         str += " failed, ";
1425         str += err;
1426     }
1427 
1428     // Both absolute and relative paths support
CheckDirectoryOrPath(const char * localPath,bool pathOrDir,bool readWrite,string & errStr,mode_t & fm)1429     bool CheckDirectoryOrPath(const char *localPath, bool pathOrDir, bool readWrite, string &errStr, mode_t &fm)
1430     {
1431         if (pathOrDir) {  // filepath
1432             uv_fs_t req;
1433             mode_t mode;
1434             fm = mode_t(~S_IFMT);
1435             int r = uv_fs_lstat(nullptr, &req, localPath, nullptr);
1436             if (r) {
1437                 constexpr int bufSize = 1024;
1438                 char buf[bufSize] = { 0 };
1439                 uv_strerror_r((int)req.result, buf, bufSize);
1440                 BuildErrorString(localPath, "lstat", buf, errStr);
1441             }
1442 
1443             mode = req.statbuf.st_mode;
1444             uv_fs_req_cleanup(&req);
1445 
1446             if ((r == 0) && (mode & S_IFDIR)) {
1447                 fm = S_IFDIR;
1448             } else if ((r == 0) && (mode & S_IFREG)) {  // is file
1449                 uv_fs_access(nullptr, &req, localPath, readWrite ? R_OK : W_OK, nullptr);
1450                 if (req.result) {
1451                     const char *op = readWrite ? "access R_OK" : "access W_OK";
1452                     constexpr int bufSize = 1024;
1453                     char buf[bufSize] = { 0 };
1454                     uv_strerror_r((int)req.result, buf, bufSize);
1455                     BuildErrorString(localPath, op, buf, errStr);
1456                 }
1457                 uv_fs_req_cleanup(&req);
1458                 if (req.result == 0) {
1459                     return true;
1460                 }
1461             } else if (r == 0) {
1462                 const char *type = GetFileType(mode);
1463                 errStr = "Not support ";
1464                 errStr += type;
1465                 errStr += ": ";
1466                 errStr += localPath;
1467             }
1468         } else {  // dir
1469             errStr = "Not support dir: ";
1470             errStr += localPath;
1471         }
1472         return false;
1473     }
1474 
TryCreateDirectory(const string & path,string & err)1475     bool TryCreateDirectory(const string &path, string &err)
1476     {
1477         uv_fs_t req;
1478         int r = uv_fs_lstat(nullptr, &req, path.c_str(), nullptr);
1479         mode_t mode = req.statbuf.st_mode;
1480         uv_fs_req_cleanup(&req);
1481         if (r < 0) {
1482             WRITE_LOG(LOG_DEBUG, "path not exist create dir = %s", path.c_str());
1483             r = uv_fs_mkdir(nullptr, &req, path.c_str(), DEF_FILE_PERMISSION, nullptr);
1484             uv_fs_req_cleanup(&req);
1485             if (r < 0) {
1486                 constexpr int bufSize = 1024;
1487                 char buf[bufSize] = { 0 };
1488                 uv_strerror_r((int)req.result, buf, bufSize);
1489                 WRITE_LOG(LOG_WARN, "create dir %s failed %s", path.c_str(), buf);
1490                 err = "Error create directory, path:";
1491                 err += path.c_str();
1492                 return false;
1493             }
1494         } else {
1495             if (!((mode & S_IFMT) == S_IFDIR)) {
1496                 WRITE_LOG(LOG_WARN, "%s exist, not directory", path.c_str());
1497                 err = "File exists, path:";
1498                 err += path.c_str();
1499                 return false;
1500             }
1501         }
1502         return true;
1503     }
1504 
CheckDirectoryOrPath(const char * localPath,bool pathOrDir,bool readWrite)1505     bool CheckDirectoryOrPath(const char *localPath, bool pathOrDir, bool readWrite)
1506     {
1507         string strUnused;
1508         mode_t mode = mode_t(~S_IFMT);
1509         return CheckDirectoryOrPath(localPath, pathOrDir, readWrite, strUnused, mode);
1510     }
1511 
1512     // Using openssl encryption and decryption method, high efficiency; when encrypting more than 64 bytes,
1513     // the carriage return will not be added, and the tail padding 00 is removed when decrypting
1514     // The return value is the length of the string after Base64
Base64EncodeBuf(const uint8_t * input,const int length,uint8_t * bufOut)1515     int Base64EncodeBuf(const uint8_t *input, const int length, uint8_t *bufOut)
1516     {
1517         return EVP_EncodeBlock(bufOut, input, length);
1518     }
1519 
Base64Encode(const uint8_t * input,const int length)1520     vector<uint8_t> Base64Encode(const uint8_t *input, const int length)
1521     {
1522         vector<uint8_t> retVec;
1523         uint8_t *pBuf = nullptr;
1524         while (true) {
1525             if (static_cast<uint32_t>(length) > HDC_BUF_MAX_BYTES) {
1526                 break;
1527             }
1528             int base64Size = length * 1.4 + 256;
1529             if (!(pBuf = new uint8_t[base64Size]())) {
1530                 break;
1531             }
1532             int childRet = Base64EncodeBuf(input, length, pBuf);
1533             if (childRet <= 0) {
1534                 break;
1535             }
1536             retVec.insert(retVec.begin(), pBuf, pBuf + childRet);
1537             break;
1538         }
1539         if (pBuf) {
1540             delete[] pBuf;
1541         }
1542 
1543         return retVec;
1544     }
1545 
CalcDecodeLength(const uint8_t * b64input)1546     inline int CalcDecodeLength(const uint8_t *b64input)
1547     {
1548         int len = strlen(reinterpret_cast<char *>(const_cast<uint8_t *>(b64input)));
1549         if (!len) {
1550             return 0;
1551         }
1552         int padding = 0;
1553         if (b64input[len - 1] == '=' && b64input[len - LAST_EQUAL_NUM] == '=') {
1554             // last two chars are =
1555             padding = 2;  // 2 : last two chars
1556         } else if (b64input[len - 1] == '=') {
1557             // last char is =
1558             padding = 1;
1559         }
1560         return static_cast<int>(len * DECODE_SCALE - padding);
1561     }
1562 
1563     // return -1 error; >0 decode size
Base64DecodeBuf(const uint8_t * input,const int length,uint8_t * bufOut)1564     int Base64DecodeBuf(const uint8_t *input, const int length, uint8_t *bufOut)
1565     {
1566         int nRetLen = CalcDecodeLength(input);
1567         if (!nRetLen) {
1568             return 0;
1569         }
1570 
1571         if (EVP_DecodeBlock(bufOut, input, length) > 0) {
1572             return nRetLen;
1573         }
1574         return 0;
1575     }
1576 
Base64Decode(const uint8_t * input,const int length)1577     string Base64Decode(const uint8_t *input, const int length)
1578     {
1579         string retString;
1580         uint8_t *pBuf = nullptr;
1581         while (true) {
1582             if (static_cast<uint32_t>(length) > HDC_BUF_MAX_BYTES) {
1583                 break;
1584             }
1585             // must less than length
1586             if (!(pBuf = new uint8_t[length]())) {
1587                 break;
1588             }
1589             int childRet = Base64DecodeBuf(input, length, pBuf);
1590             if (childRet <= 0) {
1591                 break;
1592             }
1593             retString = (reinterpret_cast<char *>(pBuf));
1594             break;
1595         }
1596         if (pBuf) {
1597             delete[] pBuf;
1598         }
1599         return retString;
1600     }
1601 
ReverseBytes(void * start,int size)1602     void ReverseBytes(void *start, int size)
1603     {
1604         uint8_t *istart = (uint8_t *)start;
1605         uint8_t *iend = istart + size;
1606         std::reverse(istart, iend);
1607     }
1608 
Convert2HexStr(uint8_t arr[],int length)1609     string Convert2HexStr(uint8_t arr[], int length)
1610     {
1611         std::stringstream ss;
1612         const int byteHexStrLen = 2;
1613         for (int i = 0; i < length; i++) {
1614             ss << std::hex << std::setw(byteHexStrLen) << std::setfill('0')
1615                 << static_cast<int>(arr[i]);
1616             if (i < length - 1) {
1617                 ss << ":";
1618             }
1619         }
1620         string result = ss.str();
1621         transform(result.begin(), result.end(), result.begin(), ::toupper);
1622         return result;
1623     }
1624 
1625     // clang-format off
StringFormat(const char * const formater,...)1626     const string StringFormat(const char * const formater, ...)
1627     {
1628         va_list vaArgs;
1629         va_start(vaArgs, formater);
1630         string ret = StringFormat(formater, vaArgs);
1631         va_end(vaArgs);
1632         return ret;
1633     }
1634 
StringFormat(const char * const formater,va_list & vaArgs)1635     const string StringFormat(const char * const formater, va_list &vaArgs)
1636     {
1637         std::vector<char> args(GetMaxBufSizeStable());
1638         const int retSize = vsnprintf_s(
1639             args.data(), GetMaxBufSizeStable(), (args.size() >= 1) ? (args.size() - 1) : 0, formater, vaArgs);
1640         if (retSize < 0) {
1641             return std::string("");
1642         } else {
1643             return std::string(args.data(), retSize);
1644         }
1645     }
1646     // clang-format on
1647 
GetVersion()1648     string GetVersion()
1649     {
1650         const uint8_t a = 'a';
1651         uint8_t major = (HDC_VERSION_NUMBER >> 28) & 0xff;
1652         uint8_t minor = (HDC_VERSION_NUMBER << 4 >> 24) & 0xff;
1653         uint8_t version = (HDC_VERSION_NUMBER << 12 >> 24) & 0xff;
1654         uint8_t fix = (HDC_VERSION_NUMBER << 20 >> 28) & 0xff;  // max 16, tail is p
1655         string ver = StringFormat("%x.%x.%x%c", major, minor, version, a + fix);
1656         return "Ver: " + ver;
1657     }
1658 
IdleUvTask(uv_loop_t * loop,void * data,uv_idle_cb cb)1659     bool IdleUvTask(uv_loop_t *loop, void *data, uv_idle_cb cb)
1660     {
1661         uv_idle_t *idle = new(std::nothrow) uv_idle_t();
1662         if (idle == nullptr) {
1663             return false;
1664         }
1665         idle->data = data;
1666         uv_idle_init(loop, idle);
1667         uv_idle_start(idle, cb);
1668         // delete by callback
1669         return true;
1670     }
1671 
TimerUvTask(uv_loop_t * loop,void * data,uv_timer_cb cb,int repeatTimeout)1672     bool TimerUvTask(uv_loop_t *loop, void *data, uv_timer_cb cb, int repeatTimeout)
1673     {
1674         uv_timer_t *timer = new(std::nothrow) uv_timer_t();
1675         if (timer == nullptr) {
1676             return false;
1677         }
1678         timer->data = data;
1679         uv_timer_init(loop, timer);
1680         uv_timer_start(timer, cb, 0, repeatTimeout);
1681         // delete by callback
1682         return true;
1683     }
1684 
1685     // callback, uint8_t flag, string msg, const void * data
DelayDo(uv_loop_t * loop,const int delayMs,const uint8_t flag,string msg,void * data,std::function<void (const uint8_t,string &,const void *)> cb)1686     bool DelayDo(uv_loop_t *loop, const int delayMs, const uint8_t flag, string msg, void *data,
1687                  std::function<void(const uint8_t, string &, const void *)> cb)
1688     {
1689         struct DelayDoParam {
1690             uv_timer_t handle;
1691             uint8_t flag;
1692             string msg;
1693             void *data;
1694             std::function<void(const uint8_t, string &, const void *)> cb;
1695         };
1696         auto funcDelayDo = [](uv_timer_t *handle) -> void {
1697             DelayDoParam *st = (DelayDoParam *)handle->data;
1698             st->cb(st->flag, st->msg, st->data);
1699             uv_close((uv_handle_t *)handle, [](uv_handle_t *handle) {
1700                 DelayDoParam *st = (DelayDoParam *)handle->data;
1701                 delete st;
1702             });
1703         };
1704         DelayDoParam *st = new(std::nothrow) DelayDoParam();
1705         if (st == nullptr) {
1706             return false;
1707         }
1708         st->cb = cb;
1709         st->flag = flag;
1710         st->msg = msg;
1711         st->data = data;
1712         st->handle.data = st;
1713         uv_timer_init(loop, &st->handle);
1714         uv_timer_start(&st->handle, funcDelayDo, delayMs, 0);
1715         return true;
1716     }
1717 
ReplaceAll(string str,const string from,const string to)1718     string ReplaceAll(string str, const string from, const string to)
1719     {
1720         string::size_type startPos = 0;
1721         while ((startPos = str.find(from, startPos)) != string::npos) {
1722             str.replace(startPos, from.length(), to);
1723             startPos += to.length();  // Handles case where 'to' is a substring of 'from'
1724         }
1725         return str;
1726     }
1727 
CanonicalizeSpecPath(string & src)1728     string CanonicalizeSpecPath(string &src)
1729     {
1730         char resolvedPath[PATH_MAX] = { 0 };
1731 #if defined(_WIN32)
1732         if (!_fullpath(resolvedPath, src.c_str(), PATH_MAX)) {
1733             WRITE_LOG(LOG_FATAL, "_fullpath %s failed", src.c_str());
1734             return "";
1735         }
1736 #else
1737         if (realpath(src.c_str(), resolvedPath) == nullptr) {
1738             WRITE_LOG(LOG_FATAL, "realpath %s failed", src.c_str());
1739             return "";
1740         }
1741 #endif
1742         string res(resolvedPath);
1743         return res;
1744     }
1745 
UnicodeToUtf8(const char * src,bool reverse)1746     string UnicodeToUtf8(const char *src, bool reverse)
1747     {
1748 #if defined(_WIN32)
1749         UINT from = CP_ACP;
1750         UINT to = CP_UTF8;
1751         int count = 0;
1752         if (reverse) {
1753             from = CP_UTF8;
1754             to = CP_ACP;
1755         }
1756         count = MultiByteToWideChar(from, 0, src, -1, nullptr, 0);
1757         if (count <= 0) {
1758             DWORD err = GetLastError();
1759             WRITE_LOG(LOG_FATAL, "MultiByteToWideChar failed %s error:%lu", src, err);
1760             return "";
1761         }
1762         wchar_t *wstr = new(std::nothrow) wchar_t[count + 1]();
1763         if (wstr == nullptr) {
1764             WRITE_LOG(LOG_FATAL, "new wstr failed count:%d", count);
1765             return "";
1766         }
1767         count = MultiByteToWideChar(from, 0, src, -1, wstr, count);
1768         if (count <= 0) {
1769             DWORD err = GetLastError();
1770             WRITE_LOG(LOG_FATAL, "MultiByteToWideChar failed to wstr %s error:%lu", src, err);
1771             delete[] wstr;
1772             return "";
1773         }
1774         count = WideCharToMultiByte(to, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
1775         if (count <= 0) {
1776             DWORD err = GetLastError();
1777             WRITE_LOG(LOG_FATAL, "WideCharToMultiByte failed %s error:%lu", wstr, err);
1778             delete[] wstr;
1779             return "";
1780         }
1781         char *ustr = new(std::nothrow) char[count + 1]();
1782         if (ustr == nullptr) {
1783             WRITE_LOG(LOG_FATAL, "new ustr failed count:%d", count);
1784             delete[] wstr;
1785             return "";
1786         }
1787         count = WideCharToMultiByte(to, 0, wstr, -1, ustr, count, nullptr, nullptr);
1788         if (count <= 0) {
1789             DWORD err = GetLastError();
1790             WRITE_LOG(LOG_FATAL, "WideCharToMultiByte failed to ustr %s error:%lu", wstr, err);
1791             delete[] wstr;
1792             delete[] ustr;
1793             return "";
1794         }
1795         string rc(ustr);
1796         delete[] wstr;
1797         delete[] ustr;
1798         return rc;
1799 #else
1800         string rc(src);
1801         return rc;
1802 #endif
1803     }
1804 
CalcCheckSum(const uint8_t * data,int len)1805     uint8_t CalcCheckSum(const uint8_t *data, int len)
1806     {
1807         uint8_t ret = 0;
1808         for (int i = 0; i < len; ++i) {
1809             ret += data[i];
1810         }
1811         return ret;
1812     }
1813 
DuplicateUvSocket(uv_tcp_t * tcp)1814     uv_os_sock_t DuplicateUvSocket(uv_tcp_t *tcp)
1815     {
1816         uv_os_sock_t dupFd = -1;
1817 #ifdef _WIN32
1818         WSAPROTOCOL_INFO info;
1819         ZeroStruct(info);
1820         if (WSADuplicateSocketA(tcp->socket, GetCurrentProcessId(), &info) < 0) {
1821             return dupFd;
1822         }
1823         dupFd = WSASocketA(0, 0, 0, &info, 0, 0);
1824 #else
1825         uv_os_fd_t fdOs;
1826         if (uv_fileno((const uv_handle_t *)tcp, &fdOs) < 0) {
1827             return ERR_API_FAIL;
1828         }
1829 #ifdef HDC_HOST
1830         dupFd = dup(uv_open_osfhandle(fdOs));
1831 #else
1832         dupFd = fcntl(uv_open_osfhandle(fdOs), F_DUPFD_CLOEXEC, uv_open_osfhandle(fdOs));
1833 #endif // HDC_HOST
1834 #endif
1835         return dupFd;
1836     }
1837 
GetCwd()1838     string GetCwd()
1839     {
1840         int value = -1;
1841         char path[PATH_MAX] = "";
1842         size_t size = sizeof(path);
1843         string res;
1844         value = uv_cwd(path, &size);
1845         if (value < 0) {
1846             constexpr int bufSize = 1024;
1847             char buf[bufSize] = { 0 };
1848             uv_strerror_r(value, buf, bufSize);
1849             WRITE_LOG(LOG_FATAL, "get path failed: %s", buf);
1850             return res;
1851         }
1852         size_t len = 0;
1853         len = strlen(path);
1854         if (len < 1 || len >= PATH_MAX - 1) {
1855             WRITE_LOG(LOG_FATAL, "get path failed: buffer space max");
1856             return res;
1857         }
1858         if (path[len - 1] != Base::GetPathSep()) {
1859             path[len] = Base::GetPathSep();
1860         }
1861         res = path;
1862         return res;
1863     }
1864 
GetTmpDir()1865     string GetTmpDir()
1866     {
1867         string res;
1868 #ifdef HDC_HOST
1869         int value = -1;
1870         char path[PATH_MAX] = "";
1871         size_t size = sizeof(path);
1872         value = uv_os_tmpdir(path, &size);
1873         if (value < 0) {
1874             constexpr int bufSize = 1024;
1875             char buf[bufSize] = { 0 };
1876             uv_strerror_r(value, buf, bufSize);
1877             WRITE_LOG(LOG_FATAL, "get tmppath failed: %s", buf);
1878             return res;
1879         }
1880         if (strlen(path) >= PATH_MAX - 1) {
1881             WRITE_LOG(LOG_FATAL, "get tmppath failed: buffer space max");
1882             return res;
1883         }
1884         if (path[strlen(path) - 1] != Base::GetPathSep()) {
1885             path[strlen(path)] = Base::GetPathSep();
1886         }
1887         res = path;
1888 #else
1889         res = "/data/local/tmp/";
1890 #endif
1891         return res;
1892     }
1893 
1894 #ifndef  HDC_HILOG
SetLogCache(bool enable)1895     void SetLogCache(bool enable)
1896     {
1897         g_logCache = enable;
1898     }
1899 
RemoveLogFile()1900     void RemoveLogFile()
1901     {
1902         if (g_logCache) {
1903             string path = GetTmpDir() + LOG_FILE_NAME;
1904             string timeStr;
1905             GetTimeString(timeStr);
1906             string bakPath = GetTmpDir() + LOG_FILE_NAME_PREFIX + timeStr + ".log";
1907             string cachePath = GetTmpDir() + LOG_CACHE_NAME;
1908             rename(path.c_str(), bakPath.c_str());
1909             rename(cachePath.c_str(), path.c_str());
1910             g_logCache = false;
1911             RemoveOlderLogFiles();
1912         }
1913     }
1914 
RemoveLogCache()1915     void RemoveLogCache()
1916     {
1917         string cachePath = GetTmpDir() + LOG_CACHE_NAME;
1918         unlink(cachePath.c_str());
1919     }
1920 #endif
1921 
IsRoot()1922     bool IsRoot()
1923     {
1924 #ifdef _WIN32
1925         // reserve
1926         return true;
1927 #else
1928         if (getuid() == 0) {
1929             return true;
1930         }
1931 #endif
1932         return false;
1933     }
1934 
IsAbsolutePath(string & path)1935     bool IsAbsolutePath(string &path)
1936     {
1937         bool ret = false;
1938 #ifdef _WIN32
1939         // shlwapi.h PathIsRelativeA not link in harmony project
1940         // c:\ or UNC path '\\hostname\share\file'
1941         ret = path.find(":\\") == 1 || path.find("\\\\") == 0;
1942 #else
1943         ret = path[0] == '/';
1944 #endif
1945         return ret;
1946     }
1947 
CloseFd(int & fd)1948     int CloseFd(int &fd)
1949     {
1950         int rc = 0;
1951         if (fd > 0) {
1952             rc = close(fd);
1953             if (rc < 0) {
1954                 char buffer[BUF_SIZE_DEFAULT] = { 0 };
1955 #ifdef _WIN32
1956                 strerror_s(buffer, BUF_SIZE_DEFAULT, errno);
1957 #else
1958                 strerror_r(errno, buffer, BUF_SIZE_DEFAULT);
1959 #endif
1960                 WRITE_LOG(LOG_WARN, "close fd: %d failed errno:%d %s", fd, errno, buffer);
1961             } else {
1962                 fd = -1;
1963             }
1964         }
1965         return rc;
1966     }
1967 
InitProcess(void)1968     void InitProcess(void)
1969     {
1970 #ifndef _WIN32
1971         umask(0);
1972         signal(SIGPIPE, SIG_IGN);
1973         signal(SIGCHLD, SIG_IGN);
1974         signal(SIGALRM, SIG_IGN);
1975         signal(SIGTTIN, SIG_IGN);
1976         signal(SIGTTOU, SIG_IGN);
1977         sigemptyset(&g_blockList);
1978         constexpr int crashSignal = 35;
1979         sigaddset(&g_blockList, crashSignal);
1980         sigprocmask(SIG_BLOCK, &g_blockList, NULL);
1981 #endif
1982     }
1983 
DeInitProcess(void)1984     void DeInitProcess(void)
1985     {
1986 #ifndef _WIN32
1987         mode_t writePermission = 022;
1988         umask(writePermission);
1989         signal(SIGPIPE, SIG_DFL);
1990         signal(SIGCHLD, SIG_DFL);
1991         signal(SIGALRM, SIG_DFL);
1992         signal(SIGTTIN, SIG_DFL);
1993         signal(SIGTTOU, SIG_DFL);
1994 #endif
1995     }
1996 
ReadFromFd(int fd,void * buf,size_t count)1997     int ReadFromFd(int fd, void *buf, size_t count)
1998     {
1999 #ifdef _WIN32
2000         DWORD bytesRead = 0;
2001         OVERLAPPED ov = {};
2002         SOCKET s = fd;
2003         BOOL bWriteStat = ReadFile((HANDLE)s, buf, count, &bytesRead, &ov);
2004         if (bWriteStat) {
2005             return bytesRead;
2006         } else {
2007             return -1;
2008         }
2009 #else
2010         return TEMP_FAILURE_RETRY(read(fd, buf, count));
2011 #endif
2012     }
2013 
WriteToFd(int fd,const void * buf,size_t count)2014     int WriteToFd(int fd, const void *buf, size_t count)
2015     {
2016 #ifdef _WIN32
2017         DWORD bytesWrite = 0;
2018         OVERLAPPED ov = {};
2019         SOCKET s = fd;
2020         BOOL bWriteStat = WriteFile((HANDLE)s, buf, count, &bytesWrite, &ov);
2021         if (bWriteStat) {
2022             return 1;
2023         } else {
2024             return -1;
2025         }
2026 #else
2027         return TEMP_FAILURE_RETRY(write(fd, buf, count));
2028 #endif
2029     }
2030 
2031     // Trim from both sides and paired
ShellCmdTrim(string & cmd)2032     string &ShellCmdTrim(string &cmd)
2033     {
2034         const string pairedQuot("\"\"");
2035         if (cmd.empty()) {
2036             return cmd;
2037         }
2038         cmd = Trim(cmd);
2039         if (cmd.length() < pairedQuot.length()) {
2040             return cmd;
2041         }
2042         if (*cmd.begin() == '"' && cmd.back() == '"') {
2043             cmd.erase(cmd.begin());
2044             cmd.pop_back();
2045         }
2046         return cmd;
2047     }
2048 
TrimSubString(string & str,string substr)2049     void TrimSubString(string &str, string substr)
2050     {
2051         std::string::size_type pos = 0;
2052         while ((pos = str.find(substr, pos)) != std::string::npos) {
2053             str.erase(pos, substr.length());
2054         }
2055     }
2056     // first 16 bytes is tag
2057     // second 16 bytes is length
2058     // flow the value
TlvAppend(string & tlv,string tag,string val)2059     bool TlvAppend(string &tlv, string tag, string val)
2060     {
2061         if (tag.empty()) {
2062             return false;
2063         }
2064         unsigned int tlen = tag.length();
2065         if (tlen < TLV_TAG_LEN) {
2066             tag.append(TLV_TAG_LEN - tlen, ' ');
2067         }
2068         tlv.append(tag);
2069         string vallen = std::to_string(val.length());
2070         unsigned int vlen = vallen.length();
2071         if (vlen < TLV_VAL_LEN) {
2072             vallen.append(TLV_VAL_LEN - vlen, ' ');
2073         }
2074         tlv.append(vallen);
2075         tlv.append(val);
2076         return true;
2077     }
TlvToStringMap(string tlv,std::map<string,string> & tlvmap)2078     bool TlvToStringMap(string tlv, std::map<string, string> &tlvmap)
2079     {
2080         if (tlv.length() < TLV_MIN_LEN) {
2081             return false;
2082         }
2083         while (tlv.length() >= TLV_MIN_LEN) {
2084             string tag = tlv.substr(0, TLV_TAG_LEN);
2085             TrimSubString(tag, " ");
2086             tlv.erase(0, TLV_TAG_LEN);
2087 
2088             string vallen = tlv.substr(0, TLV_VAL_LEN);
2089             TrimSubString(vallen, " ");
2090             int len = atoi(vallen.c_str());
2091             if (len < 0) {
2092                 return false;
2093             }
2094             tlv.erase(0, TLV_VAL_LEN);
2095 
2096             if (tlv.length() < static_cast<uint32_t>(len)) {
2097                 return false;
2098             }
2099             string val = tlv.substr(0, len);
2100             tlv.erase(0, len);
2101 
2102             tlvmap[tag] = val;
2103         }
2104         return true;
2105     }
2106 
2107     // NOTE: This function relies on the caller to guarantee that
2108     // the input parameter is not null and to check the opened handle state.
Fopen(const char * fileName,const char * mode)2109     FILE *Fopen(const char *fileName, const char *mode)
2110     {
2111 #ifdef _WIN32
2112         wchar_t resolvedPath[PATH_MAX + 1] = { 0 };
2113         // windows platform open file with wide char
2114         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
2115         std::wstring wideFileName = converter.from_bytes(fileName);
2116         std::wstring wideMode = converter.from_bytes(mode);
2117         if (!_wfullpath(resolvedPath, wideFileName.c_str(), PATH_MAX + 1)) {
2118             WRITE_LOG(LOG_FATAL, "_wfullpath %s failed", wideFileName.c_str());
2119             return nullptr;
2120         }
2121         return _wfopen(resolvedPath, wideMode.c_str());
2122 #else
2123         // unix paltform open file with default char
2124         return fopen(fileName, mode);
2125 #endif
2126     }
2127 
CheckBundleName(const string & bundleName)2128     bool CheckBundleName(const string &bundleName)
2129     {
2130         if (bundleName.empty()) {
2131             WRITE_LOG(LOG_WARN, "bundleName is empty");
2132             return false;
2133         }
2134         size_t length = bundleName.size();
2135         if (length < BUNDLE_MIN_SIZE) {
2136             WRITE_LOG(LOG_WARN, "bundleName length:%d is less than %d", length, BUNDLE_MIN_SIZE);
2137             return false;
2138         }
2139 
2140         if (length > BUNDLE_MAX_SIZE) {
2141             WRITE_LOG(LOG_WARN, "bundleName length:%d is bigger than %d", length, BUNDLE_MAX_SIZE);
2142             return false;
2143         }
2144         // 校验bundle是0-9,a-Z,_,.组成的字符串
2145         if (regex_match(bundleName, std::regex("^[0-9a-zA-Z_\\.]+$"))) {
2146             return true;
2147         }
2148         WRITE_LOG(LOG_WARN, "bundleName:%s contains invalid characters", bundleName.c_str());
2149         return false;
2150     }
2151 }
2152 }  // namespace Hdc
2153