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