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