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