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