• 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 <chrono>
17 #include <cstdio>
18 #include <cstring>
19 #include <openssl/bio.h>
20 #include <openssl/buffer.h>
21 #include <openssl/evp.h>
22 #include <openssl/md5.h>
23 #include <random>
24 #include <sstream>
25 #include <thread>
26 using namespace std::chrono;
27 
28 namespace Hdc {
29 namespace Base {
30     constexpr int DEF_FILE_PERMISSION = 0750;
GetLogLevel()31     uint8_t GetLogLevel()
32     {
33         return g_logLevel;
34     }
35     std::atomic<bool> g_logCache = true;
36     uint8_t g_logLevel = LOG_DEBUG;  // tmp set,now debugmode.LOG_OFF when release;;
SetLogLevel(const uint8_t logLevel)37     void SetLogLevel(const uint8_t logLevel)
38     {
39         g_logLevel = logLevel;
40     }
41 
42 // Commenting the code will optimize and tune all log codes, and the compilation volume will be greatly reduced
43 #define ENABLE_DEBUGLOG
44 #ifdef ENABLE_DEBUGLOG
GetLogDebugFunctionName(string & debugInfo,int line,string & threadIdString)45     void GetLogDebugFunctionName(string &debugInfo, int line, string &threadIdString)
46     {
47         string tmpString = GetFileNameAny(debugInfo);
48         debugInfo = StringFormat("%s:%d", tmpString.c_str(), line);
49         if (g_logLevel < LOG_DEBUG) {
50             debugInfo = "";
51             threadIdString = "";
52         } else {
53             debugInfo = "[" + debugInfo + "]";
54             threadIdString = StringFormat("[%x]", std::hash<std::thread::id> {}(std::this_thread::get_id()));
55         }
56     }
57 
IsWindowsSupportAnsiColor()58     bool IsWindowsSupportAnsiColor()
59     {
60 #ifdef _WIN32
61         // Set output mode to handle virtual terminal sequences
62         HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
63         if (hOut == INVALID_HANDLE_VALUE) {
64             return false;
65         }
66         DWORD dwMode = 0;
67         if (!GetConsoleMode(hOut, &dwMode)) {
68             return false;
69         }
70         dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
71         if (!SetConsoleMode(hOut, dwMode)) {
72             return false;
73         }
74 #endif
75         return true;
76     }
77 
GetLogLevelAndTime(uint8_t logLevel,string & logLevelString,string & timeString)78     void GetLogLevelAndTime(uint8_t logLevel, string &logLevelString, string &timeString)
79     {
80         system_clock::time_point timeNow = system_clock::now();          // now time
81         system_clock::duration sinceUnix0 = timeNow.time_since_epoch();  // since 1970
82         time_t sSinceUnix0 = duration_cast<seconds>(sinceUnix0).count();
83         std::tm *tim = std::localtime(&sSinceUnix0);
84         bool enableAnsiColor = false;
85 #ifdef _WIN32
86         enableAnsiColor = IsWindowsSupportAnsiColor();
87 #else
88         enableAnsiColor = true;
89 #endif
90         if (enableAnsiColor) {
91             switch (logLevel) {
92                 case LOG_FATAL:
93                     logLevelString = "\033[1;31mF\033[0m";
94                     break;
95                 case LOG_INFO:
96                     logLevelString = "\033[1;32mI\033[0m";
97                     break;
98                 case LOG_WARN:
99                     logLevelString = "\033[1;33mW\033[0m";
100                     break;
101                 case LOG_DEBUG:  // will reduce performance
102                     logLevelString = "\033[1;36mD\033[0m";
103                     break;
104                 default:  // all, just more IO/Memory information
105                     logLevelString = "\033[1;38;5;21mA\033[0m";
106                     break;
107             }
108         } else {
109             logLevelString = std::to_string(logLevel);
110         }
111         string msTimeSurplus;
112         if (g_logLevel >= LOG_DEBUG) {
113             const auto sSinceUnix0Rest = duration_cast<milliseconds>(sinceUnix0).count() % TIME_BASE;
114             msTimeSurplus = StringFormat(".%03llu", sSinceUnix0Rest);
115         }
116         timeString = msTimeSurplus;
117         if (tim != nullptr) {
118             char buffer[TIME_BUF_SIZE];
119             (void)strftime(buffer, TIME_BUF_SIZE, "%Y-%m-%d %H:%M:%S", tim);
120             timeString = StringFormat("%s%s", buffer, msTimeSurplus.c_str());
121         }
122     }
123 
LogToPath(const char * path,const char * str)124     void LogToPath(const char *path, const char *str)
125     {
126         // logfile, not thread-safe
127 #ifdef HDC_DEBUG_UART
128         // make a log path print.
129         static std::once_flag firstLog;
130         std::call_once(firstLog, [&]() { printf("log at %s\n", path); });
131         // better than open log file every time.
132         static std::unique_ptr<FILE, decltype(&fclose)> file(fopen(path, "w"), &fclose);
133         FILE *fp = file.get();
134         if (fp == nullptr) {
135             return;
136         }
137         if (fprintf(fp, "%s", str) > 0 && fflush(fp)) {
138             // make ci happy
139         }
140         fclose(fp);
141 #else
142         int flags = UV_FS_O_RDWR | UV_FS_O_APPEND | UV_FS_O_CREAT;
143         uv_fs_t req;
144         int fd = uv_fs_open(nullptr, &req, path, flags, S_IWUSR | S_IRUSR, nullptr);
145         if (fd < 0) {
146             char buffer[BUF_SIZE_DEFAULT] = { 0 };
147             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
148             uv_fs_req_cleanup(&req);
149             PrintMessage("LogToPath uv_fs_open %s error %s", path, buffer);
150             return;
151         }
152         string text(str);
153         uv_buf_t wbf = uv_buf_init((char *)str, text.size());
154         uv_fs_req_cleanup(&req);
155         uv_fs_write(nullptr, &req, fd, &wbf, 1, 0, nullptr);
156         uv_fs_close(nullptr, &req, fd, nullptr);
157 #endif
158     }
159 
LogToFile(const char * str)160     void LogToFile(const char *str)
161     {
162         string path = GetTmpDir() + LOG_FILE_NAME;
163         RollLogFile(path.c_str());
164         LogToPath(path.c_str(), str);
165     }
166 
LogToCache(const char * str)167     void LogToCache(const char *str)
168     {
169         string path = GetTmpDir() + LOG_CACHE_NAME;
170         LogToPath(path.c_str(), str);
171     }
172 
RollLogFile(const char * path)173     void RollLogFile(const char *path)
174     {
175         int value = -1;
176         uv_fs_t fs;
177         value = uv_fs_stat(nullptr, &fs, path, nullptr);
178         if (value != 0) {
179             constexpr int bufSize = 1024;
180             char buf[bufSize] = { 0 };
181             uv_strerror_r(value, buf, bufSize);
182             PrintMessage("RollLogFile error log file %s not exist %s", path, buf);
183             return;
184         }
185         uint64_t size = fs.statbuf.st_size;
186         if (size < LOG_FILE_MAX_SIZE) {
187             return;
188         }
189         string last = StringFormat("%s.%d", path, 0);
190         value = uv_fs_unlink(nullptr, &fs, last.c_str(), nullptr);
191         if (value != 0) {
192             constexpr int bufSize = 1024;
193             char buf[bufSize] = { 0 };
194             uv_strerror_r(value, buf, bufSize);
195             PrintMessage("RollLogFile error unlink last:%s %s", last.c_str(), buf);
196         }
197         value = uv_fs_rename(nullptr, &fs, path, last.c_str(), nullptr);
198         if (value != 0) {
199             constexpr int bufSize = 1024;
200             char buf[bufSize] = { 0 };
201             uv_strerror_r(value, buf, bufSize);
202             PrintMessage("RollLogFile error rename %s to %s %s", path, last.c_str(), buf);
203         }
204     }
205 
PrintLogEx(const char * functionName,int line,uint8_t logLevel,const char * msg,...)206     void PrintLogEx(const char *functionName, int line, uint8_t logLevel, const char *msg, ...)
207     {
208         if (logLevel > g_logLevel) {
209             return;
210         }
211         string debugInfo;
212         string logBuf;
213         string logLevelString;
214         string threadIdString;
215         string sep = "\n";
216         string timeString;
217 
218         va_list vaArgs;
219         va_start(vaArgs, msg);
220         string logDetail = Base::StringFormat(msg, vaArgs);
221         va_end(vaArgs);
222         if (logDetail.back() == '\n') {
223             sep = "\r\n";
224         }
225         debugInfo = functionName;
226         GetLogDebugFunctionName(debugInfo, line, threadIdString);
227         GetLogLevelAndTime(logLevel, logLevelString, timeString);
228         logBuf = StringFormat("[%s][%s]%s%s %s%s", logLevelString.c_str(), timeString.c_str(), threadIdString.c_str(),
229                               debugInfo.c_str(), logDetail.c_str(), sep.c_str());
230 
231         printf("%s", logBuf.c_str());
232         fflush(stdout);
233 
234         if (!g_logCache) {
235             LogToFile(logBuf.c_str());
236         } else {
237             LogToCache(logBuf.c_str());
238         }
239 
240         return;
241     }
242 #else   // else ENABLE_DEBUGLOG.If disabled, the entire output code will be optimized by the compiler
PrintLogEx(uint8_t logLevel,char * msg,...)243     void PrintLogEx(uint8_t logLevel, char *msg, ...)
244     {
245     }
246 #endif  // ENABLE_DEBUGLOG
247 
PrintMessage(const char * fmt,...)248     void PrintMessage(const char *fmt, ...)
249     {
250         va_list ap;
251         va_start(ap, fmt);
252         if (vfprintf(stdout, fmt, ap) > 0) {
253             fprintf(stdout, "\n");
254         }
255         va_end(ap);
256     }
257 
258     // if can linkwith -lstdc++fs, use std::filesystem::path(path).filename();
GetFileNameAny(string & path)259     string GetFileNameAny(string &path)
260     {
261         string tmpString = path;
262         size_t tmpNum = tmpString.rfind('/');
263         if (tmpNum == std::string::npos) {
264             tmpNum = tmpString.rfind('\\');
265             if (tmpNum == std::string::npos) {
266                 return tmpString;
267             }
268         }
269         tmpString = tmpString.substr(tmpNum + 1, tmpString.size() - tmpNum);
270         return tmpString;
271     }
272 
SetTcpOptions(uv_tcp_t * tcpHandle)273     void SetTcpOptions(uv_tcp_t *tcpHandle)
274     {
275         if (!tcpHandle) {
276             return;
277         }
278         uv_tcp_keepalive(tcpHandle, 1, GLOBAL_TIMEOUT);
279         // if MAX_SIZE_IOBUF==5k,bufMaxSize at least 40k. It must be set to io 8 times is more appropriate,
280         // otherwise asynchronous IO is too fast, a lot of IO is wasted on IOloop, transmission speed will decrease
281         int bufMaxSize = HDC_SOCKETPAIR_SIZE;
282         uv_recv_buffer_size((uv_handle_t *)tcpHandle, &bufMaxSize);
283         uv_send_buffer_size((uv_handle_t *)tcpHandle, &bufMaxSize);
284     }
285 
ReallocBuf(uint8_t ** origBuf,int * nOrigSize,size_t sizeWanted)286     void ReallocBuf(uint8_t **origBuf, int *nOrigSize, size_t sizeWanted)
287     {
288         if (*nOrigSize > 0)
289             return;
290         if (sizeWanted <= 0 || sizeWanted >= HDC_BUF_MAX_BYTES) {
291             WRITE_LOG(LOG_WARN, "ReallocBuf failed, sizeWanted:%d", sizeWanted);
292             return;
293         }
294         *origBuf = new uint8_t[sizeWanted];
295         if (!*origBuf)
296             return;
297         *nOrigSize = sizeWanted;
298     }
299 
300     // As an uv_alloc_cb it must keep the same as prototype
AllocBufferCallback(uv_handle_t * handle,size_t sizeSuggested,uv_buf_t * buf)301     void AllocBufferCallback(uv_handle_t *handle, size_t sizeSuggested, uv_buf_t *buf)
302     {
303         const int size = GetMaxBufSize();
304         buf->base = (char *)new uint8_t[size]();
305         if (buf->base) {
306             buf->len = size - 1;
307         }
308     }
309 
310     // As an uv_write_cb it must keep the same as prototype
SendCallback(uv_write_t * req,int status)311     void SendCallback(uv_write_t *req, int status)
312     {
313         if (status < 0) {
314             constexpr int bufSize = 1024;
315             char buf[bufSize] = { 0 };
316             uv_strerror_r(status, buf, bufSize);
317             WRITE_LOG(LOG_WARN, "SendCallback failed,status:%d %s", status, buf);
318         }
319         delete[]((uint8_t *)req->data);
320         delete req;
321     }
322 
323     // xxx must keep sync with uv_loop_close/uv_walk etc.
TryCloseLoop(uv_loop_t * ptrLoop,const char * callerName)324     bool TryCloseLoop(uv_loop_t *ptrLoop, const char *callerName)
325     {
326         // UV_RUN_DEFAULT: Runs the event loop until the reference count drops to zero. Always returns zero.
327         // UV_RUN_ONCE:    Poll for new events once. Note that this function blocks if there are no pending events.
328         //                 Returns zero when done (no active handles or requests left), or non-zero if more events are
329         //                 expected meaning you should run the event loop again sometime in the future).
330         // UV_RUN_NOWAIT:  Poll for new events once but don't block if there are no pending events.
331         uint8_t closeRetry = 0;
332         bool ret = false;
333         constexpr int maxRetry = 3;
334         for (closeRetry = 0; closeRetry < maxRetry; ++closeRetry) {
335             if (uv_loop_close(ptrLoop) == UV_EBUSY) {
336                 if (closeRetry > 2) {
337                     WRITE_LOG(LOG_WARN, "%s close busy,try:%d", callerName, closeRetry);
338                 }
339 
340                 if (ptrLoop->active_handles >= 2) {
341                     WRITE_LOG(LOG_DEBUG, "TryCloseLoop issue");
342                 }
343                 auto clearLoopTask = [](uv_handle_t *handle, void *arg) -> void { TryCloseHandle(handle); };
344                 uv_walk(ptrLoop, clearLoopTask, nullptr);
345                 // If all processing ends, Then return0,this call will block
346                 if (!ptrLoop->active_handles) {
347                     ret = true;
348                     break;
349                 }
350                 if (!uv_run(ptrLoop, UV_RUN_ONCE)) {
351                     ret = true;
352                     break;
353                 }
354             } else {
355                 ret = true;
356                 break;
357             }
358         }
359         return ret;
360     }
361 
362     // Some handles may not be initialized or activated yet or have been closed, skip the closing process
TryCloseHandle(const uv_handle_t * handle)363     void TryCloseHandle(const uv_handle_t *handle)
364     {
365         TryCloseHandle(handle, nullptr);
366     }
367 
TryCloseHandle(const uv_handle_t * handle,uv_close_cb closeCallBack)368     void TryCloseHandle(const uv_handle_t *handle, uv_close_cb closeCallBack)
369     {
370         TryCloseHandle(handle, false, closeCallBack);
371     }
372 
TryCloseHandle(const uv_handle_t * handle,bool alwaysCallback,uv_close_cb closeCallBack)373     void TryCloseHandle(const uv_handle_t *handle, bool alwaysCallback, uv_close_cb closeCallBack)
374     {
375         bool hasCallClose = false;
376         if (handle->loop && !uv_is_closing(handle)) {
377             uv_close((uv_handle_t *)handle, closeCallBack);
378             hasCallClose = true;
379         }
380         if (!hasCallClose && alwaysCallback) {
381             closeCallBack((uv_handle_t *)handle);
382         }
383     }
384 
SendToStream(uv_stream_t * handleStream,const uint8_t * buf,const int bufLen)385     int SendToStream(uv_stream_t *handleStream, const uint8_t *buf, const int bufLen)
386     {
387         if (bufLen > static_cast<int>(HDC_BUF_MAX_BYTES)) {
388             return ERR_BUF_ALLOC;
389         }
390         uint8_t *pDynBuf = new uint8_t[bufLen];
391         if (!pDynBuf) {
392             WRITE_LOG(LOG_WARN, "SendToStream, alloc failed, size:%d", bufLen);
393             return ERR_BUF_ALLOC;
394         }
395         if (memcpy_s(pDynBuf, bufLen, buf, bufLen)) {
396             WRITE_LOG(LOG_WARN, "SendToStream, memory copy failed, size:%d", bufLen);
397             delete[] pDynBuf;
398             return ERR_BUF_COPY;
399         }
400         return SendToStreamEx(handleStream, pDynBuf, bufLen, nullptr, (void *)SendCallback, (void *)pDynBuf);
401     }
402 
403     // handleSend is used for pipe thread sending, set nullptr for tcp, and dynamically allocated by malloc when buf
404     // is required
SendToStreamEx(uv_stream_t * handleStream,const uint8_t * buf,const int bufLen,uv_stream_t * handleSend,const void * finishCallback,const void * pWriteReqData)405     int SendToStreamEx(uv_stream_t *handleStream, const uint8_t *buf, const int bufLen, uv_stream_t *handleSend,
406                        const void *finishCallback, const void *pWriteReqData)
407     {
408         int ret = ERR_GENERIC;
409         uv_write_t *reqWrite = new uv_write_t();
410         if (!reqWrite) {
411             WRITE_LOG(LOG_WARN, "SendToStreamEx, new write_t failed, size:%d", bufLen);
412             return ERR_BUF_ALLOC;
413         }
414         uv_buf_t bfr;
415         while (true) {
416             reqWrite->data = (void *)pWriteReqData;
417             bfr.base = (char *)buf;
418             bfr.len = bufLen;
419             if (!uv_is_writable(handleStream)) {
420                 WRITE_LOG(LOG_WARN, "SendToStreamEx, uv_is_writable false, size:%d", bufLen);
421                 delete reqWrite;
422                 break;
423             }
424 #ifdef HDC_DEBUG
425             WRITE_LOG(LOG_ALL, "SendToStreamEx %p, uv_write %p:%p, size:%lu", handleStream,
426                       reqWrite, reqWrite->data, bfr.len);
427 #endif
428             // handleSend must be a TCP socket or pipe, which is a server or a connection (listening or
429             // connected state). Bound sockets or pipes will be assumed to be servers.
430             if (handleSend) {
431                 ret = uv_write2(reqWrite, handleStream, &bfr, 1, handleSend, (uv_write_cb)finishCallback);
432             } else {
433                 ret = uv_write(reqWrite, handleStream, &bfr, 1, (uv_write_cb)finishCallback);
434             }
435             if (ret < 0) {
436                 WRITE_LOG(LOG_WARN, "SendToStreamEx, uv_write false, size:%d", bufLen);
437                 delete reqWrite;
438                 ret = ERR_IO_FAIL;
439                 break;
440             }
441             ret = bufLen;
442             break;
443         }
444         return ret;
445     }
446 
GetRuntimeMSec()447     uint64_t GetRuntimeMSec()
448     {
449         struct timespec times = { 0, 0 };
450         long time;
451         clock_gettime(CLOCK_MONOTONIC, &times);
452         time = times.tv_sec * TIME_BASE + times.tv_nsec / (TIME_BASE * TIME_BASE);
453         return time;
454     }
455 
GetRandom(const uint64_t min,const uint64_t max)456     uint64_t GetRandom(const uint64_t min, const uint64_t max)
457     {
458 #ifdef HARMONY_PROJECT
459         uint64_t ret;
460         uv_random(nullptr, nullptr, &ret, sizeof(ret), 0, nullptr);
461 #else
462         uint64_t ret;
463         std::random_device rd;
464         std::mt19937 gen(rd());
465         std::uniform_int_distribution<uint64_t> dis(min, max);
466         ret = dis(gen);
467 #endif
468         return ret;
469     }
470 
GetRandomString(const uint16_t expectedLen)471     string GetRandomString(const uint16_t expectedLen)
472     {
473         srand(static_cast<unsigned int>(GetRandom()));
474         string ret = string(expectedLen, '0');
475         std::stringstream val;
476         for (auto i = 0; i < expectedLen; ++i) {
477             val << std::hex << (rand() % BUF_SIZE_MICRO);
478         }
479         ret = val.str();
480         return ret;
481     }
482 
GetRandomNum(const int min,const int max)483     int GetRandomNum(const int min, const int max)
484     {
485         return static_cast<int>(GetRandom(min, max));
486     }
487 
ConnectKey2IPPort(const char * connectKey,char * outIP,uint16_t * outPort)488     int ConnectKey2IPPort(const char *connectKey, char *outIP, uint16_t *outPort)
489     {
490         char bufString[BUF_SIZE_TINY] = "";
491         if (strncpy_s(bufString, sizeof(bufString), connectKey, strlen(connectKey))) {
492             return ERR_BUF_COPY;
493         }
494         char *p = strrchr(bufString, ':');
495         if (!p) {
496             return ERR_PARM_FORMAT;
497         }
498         *p = '\0';
499         if (!strlen(bufString) || strlen(bufString) > 40) { // 40 : bigger than length of ipv6
500             return ERR_PARM_SIZE;
501         }
502         uint16_t wPort = static_cast<uint16_t>(atoi(p + 1));
503         if (EOK != strcpy_s(outIP, BUF_SIZE_TINY, bufString)) {
504             return ERR_BUF_COPY;
505         }
506         *outPort = wPort;
507         return RET_SUCCESS;
508     }
509 
510     // After creating the session worker thread, execute it on the main thread
FinishWorkThread(uv_work_t * req,int status)511     void FinishWorkThread(uv_work_t *req, int status)
512     {
513         // This is operated in the main thread
514         delete req;
515     }
516 
517     // at the finish of pFuncAfterThread must free uv_work_t*
518     // clang-format off
StartWorkThread(uv_loop_t * loop,uv_work_cb pFuncWorkThread,uv_after_work_cb pFuncAfterThread,void * pThreadData)519     int StartWorkThread(uv_loop_t *loop, uv_work_cb pFuncWorkThread,
520                         uv_after_work_cb pFuncAfterThread, void *pThreadData)
521     {
522         uv_work_t *workThread = new uv_work_t();
523         if (!workThread) {
524             return -1;
525         }
526         workThread->data = pThreadData;
527         uv_queue_work(loop, workThread, pFuncWorkThread, pFuncAfterThread);
528         return 0;
529     }
530     // clang-format on
531 
SplitCommandToArgs(const char * cmdStringLine,int * slotIndex)532     char **SplitCommandToArgs(const char *cmdStringLine, int *slotIndex)
533     {
534         constexpr int extraBufSize = 2;
535         char **argv;
536         char *temp = nullptr;
537         int argc = 0;
538         char a = 0;
539         size_t i = 0;
540         size_t j = 0;
541         size_t len = 0;
542         bool isQuoted = false;
543         bool isText = false;
544         bool isSpace = false;
545 
546         len = strlen(cmdStringLine);
547         if (len < 1) {
548             return nullptr;
549         }
550         i = ((len + extraBufSize) / extraBufSize) * sizeof(void *) + sizeof(void *);
551         argv = reinterpret_cast<char **>(new(std::nothrow) char[i + (len + extraBufSize) * sizeof(char)]);
552         if (argv == nullptr) {
553             WRITE_LOG(LOG_FATAL, "SplitCommandToArgs new argv failed");
554             return nullptr;
555         }
556         temp = reinterpret_cast<char *>((reinterpret_cast<uint8_t *>(argv)) + i);
557         argc = 0;
558         argv[argc] = temp;
559         isQuoted = false;
560         isText = false;
561         isSpace = true;
562         i = 0;
563         j = 0;
564 
565         while ((a = cmdStringLine[i]) != 0) {
566             if (isQuoted) {
567                 if (a == '\"') {
568                     isQuoted = false;
569                 } else {
570                     temp[j] = a;
571                     ++j;
572                 }
573             } else {
574                 switch (a) {
575                     case '\"':
576                         isQuoted = true;
577                         isText = true;
578                         if (isSpace) {
579                             argv[argc] = temp + j;
580                             ++argc;
581                         }
582                         isSpace = false;
583                         break;
584                     case ' ':
585                     case '\t':
586                     case '\n':
587                     case '\r':
588                         if (isText) {
589                             temp[j] = '\0';
590                             ++j;
591                         }
592                         isText = false;
593                         isSpace = true;
594                         break;
595                     default:
596                         isText = true;
597                         if (isSpace) {
598                             argv[argc] = temp + j;
599                             ++argc;
600                         }
601                         temp[j] = a;
602                         ++j;
603                         isSpace = false;
604                         break;
605                 }
606             }
607             ++i;
608         }
609         temp[j] = '\0';
610         argv[argc] = nullptr;
611 
612         (*slotIndex) = argc;
613         return argv;
614     }
615 
RunPipeComand(const char * cmdString,char * outBuf,uint16_t sizeOutBuf,bool ignoreTailLf)616     bool RunPipeComand(const char *cmdString, char *outBuf, uint16_t sizeOutBuf, bool ignoreTailLf)
617     {
618         FILE *pipeHandle = popen(cmdString, "r");
619         if (pipeHandle == nullptr) {
620             return false;
621         }
622         int bytesRead = 0;
623         int bytesOnce = 0;
624         while (!feof(pipeHandle)) {
625             bytesOnce = fread(outBuf, 1, sizeOutBuf - bytesRead, pipeHandle);
626             if (bytesOnce <= 0) {
627                 break;
628             }
629             bytesRead += bytesOnce;
630         }
631         if (bytesRead && ignoreTailLf) {
632             if (outBuf[bytesRead - 1] == '\n') {
633                 outBuf[bytesRead - 1] = '\0';
634             }
635         }
636         pclose(pipeHandle);
637         return bytesRead;
638     }
639 
640     // bufLen == 0: alloc buffer in heap, need free it later
641     // >0: read max nBuffLen bytes to *buff
642     // ret value: <0 or bytes read
ReadBinFile(const char * pathName,void ** buf,const size_t bufLen)643     int ReadBinFile(const char *pathName, void **buf, const size_t bufLen)
644     {
645         uint8_t *pDst = nullptr;
646         size_t byteIO = 0;
647         uv_fs_t req;
648         int ret = uv_fs_stat(nullptr, &req, pathName, nullptr);
649         if (ret < 0) {
650             char buffer[BUF_SIZE_DEFAULT] = { 0 };
651             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
652             uv_fs_req_cleanup(&req);
653             WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_stat %s error %s", pathName, buffer);
654             return -1;
655         }
656         size_t nFileSize = req.statbuf.st_size;
657         size_t readMax = 0;
658         uint8_t dynamicBuf = 0;
659         ret = -3;
660         if (bufLen == 0) {
661             dynamicBuf = 1;
662             pDst = new uint8_t[nFileSize + 1]();  // tail \0
663             if (!pDst) {
664                 return -1;
665             }
666             readMax = nFileSize;
667         } else {
668             if (nFileSize > bufLen) {
669                 return -2;
670             }
671             readMax = nFileSize;
672             pDst = reinterpret_cast<uint8_t *>(buf);  // The first address of the static array is the array address
673         }
674 
675         string srcPath(pathName);
676         string resolvedPath = CanonicalizeSpecPath(srcPath);
677         uv_buf_t rbf = uv_buf_init((char *)pDst, readMax);
678         uv_fs_req_cleanup(&req);
679         int fd = uv_fs_open(nullptr, &req, resolvedPath.c_str(), O_RDONLY, 0, nullptr);
680         if (fd < 0) {
681             char buffer[BUF_SIZE_DEFAULT] = { 0 };
682             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
683             WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_open %s error %s", resolvedPath.c_str(), buffer);
684             goto ReadFileFromPath_Finish;
685         }
686         uv_fs_req_cleanup(&req);
687         byteIO = uv_fs_read(nullptr, &req, fd, &rbf, 1, 0, nullptr);
688         uv_fs_close(nullptr, nullptr, fd, nullptr);
689         if (byteIO != readMax) {
690             char buffer[BUF_SIZE_DEFAULT] = { 0 };
691             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
692             WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_read %s error %s byteIO:%llu readMax:%llu",
693                 resolvedPath.c_str(), buffer, byteIO, readMax);
694             goto ReadFileFromPath_Finish;
695         }
696         ret = 0;
697     ReadFileFromPath_Finish:
698         if (ret) {
699             if (dynamicBuf) {
700                 delete[] pDst;
701             }
702         } else {
703             if (dynamicBuf) {
704                 *buf = pDst;
705             }
706             ret = byteIO;
707         }
708         return ret;
709     }
710 
WriteBinFile(const char * pathName,const uint8_t * buf,const size_t bufLen,bool newFile)711     int WriteBinFile(const char *pathName, const uint8_t *buf, const size_t bufLen, bool newFile)
712     {
713         string resolvedPath;
714         string srcPath(pathName);
715         int flags = 0;
716         if (newFile) {
717             flags = UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC;
718             // no std::fs supoort, else std::filesystem::canonical,-lstdc++fs
719             if (srcPath.find("..") != string::npos) {
720                 return ERR_FILE_PATH_CHECK;
721             }
722             resolvedPath = srcPath.c_str();
723         } else {
724             flags = UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND;
725             resolvedPath = CanonicalizeSpecPath(srcPath);
726         }
727         uv_fs_t req;
728         int fd = uv_fs_open(nullptr, &req, resolvedPath.c_str(), flags, S_IWUSR | S_IRUSR, nullptr);
729         if (fd < 0) {
730             char buffer[BUF_SIZE_DEFAULT] = { 0 };
731             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
732             uv_fs_req_cleanup(&req);
733             WRITE_LOG(LOG_FATAL, "WriteBinFile uv_fs_open %s error %s", resolvedPath.c_str(), buffer);
734             return ERR_FILE_OPEN;
735         }
736         uv_buf_t wbf = uv_buf_init((char *)buf, bufLen);
737         uv_fs_req_cleanup(&req);
738         size_t bytesDone = uv_fs_write(nullptr, &req, fd, &wbf, 1, 0, nullptr);
739         uv_fs_close(nullptr, &req, fd, nullptr);
740         if (bytesDone != bufLen) {
741             char buffer[BUF_SIZE_DEFAULT] = { 0 };
742             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
743             uv_fs_req_cleanup(&req);
744             WRITE_LOG(LOG_FATAL, "WriteBinFile uv_fs_write %s error %s bytesDone:%llu bufLen:%llu",
745                 resolvedPath.c_str(), buffer, bytesDone, bufLen);
746             return ERR_BUF_SIZE;
747         }
748         return RET_SUCCESS;
749     }
750 
CloseIdleCallback(uv_handle_t * handle)751     void CloseIdleCallback(uv_handle_t *handle)
752     {
753         delete (uv_idle_t *)handle;
754     };
755 
CloseTimerCallback(uv_handle_t * handle)756     void CloseTimerCallback(uv_handle_t *handle)
757     {
758         delete (uv_timer_t *)handle;
759     };
760 
761     // return value: <0 error; 0 can start new server instance; >0 server already exists
ProgramMutex(const char * procname,bool checkOrNew)762     int ProgramMutex(const char *procname, bool checkOrNew)
763     {
764         char bufPath[BUF_SIZE_DEFAULT] = "";
765         char buf[BUF_SIZE_DEFAULT] = "";
766         char pidBuf[BUF_SIZE_TINY] = "";
767         size_t size = sizeof(buf);
768         if (uv_os_tmpdir(buf, &size) < 0) {
769             WRITE_LOG(LOG_FATAL, "Tmppath failed");
770             return ERR_API_FAIL;
771         }
772         if (snprintf_s(bufPath, sizeof(bufPath), sizeof(bufPath) - 1, "%s%c.%s.pid", buf, Base::GetPathSep(), procname)
773             < 0) {
774             return ERR_BUF_OVERFLOW;
775         }
776         int pid = static_cast<int>(getpid());
777         if (snprintf_s(pidBuf, sizeof(pidBuf), sizeof(pidBuf) - 1, "%d", pid) < 0) {
778             return ERR_BUF_OVERFLOW;
779         }
780         // no need to CanonicalizeSpecPath, else not work
781         umask(0);
782         uv_fs_t req;
783         int fd = uv_fs_open(nullptr, &req, bufPath, O_RDWR | O_CREAT, 0666, nullptr);  // 0666:permission
784         if (fd < 0) {
785             char buffer[BUF_SIZE_DEFAULT] = { 0 };
786             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
787             uv_fs_req_cleanup(&req);
788             WRITE_LOG(LOG_FATAL, "Open mutex file %s failed!!! %s", bufPath, buffer);
789             return ERR_FILE_OPEN;
790         }
791 #ifdef _WIN32
792         if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "Global\\%s", procname) < 0) {
793             uv_fs_close(nullptr, &req, fd, nullptr);
794             return ERR_BUF_OVERFLOW;
795         }
796         HANDLE hMutex = CreateMutex(nullptr, FALSE, buf);
797         DWORD dwError = GetLastError();
798         if (ERROR_ALREADY_EXISTS == dwError || ERROR_ACCESS_DENIED == dwError) {
799             uv_fs_close(nullptr, &req, fd, nullptr);
800             WRITE_LOG(LOG_DEBUG, "File \"%s\" locked. proc already exit!!!\n", procname);
801             return 1;
802         }
803         if (checkOrNew) {
804             CloseHandle(hMutex);
805         }
806 #else
807         struct flock fl;
808         fl.l_type = F_WRLCK;
809         fl.l_start = 0;
810         fl.l_whence = SEEK_SET;
811         fl.l_len = 0;
812         int retChild = fcntl(fd, F_SETLK, &fl);
813         if (-1 == retChild) {
814             WRITE_LOG(LOG_DEBUG, "File \"%s\" locked. proc already exit!!!\n", bufPath);
815             uv_fs_close(nullptr, &req, fd, nullptr);
816             return 1;
817         }
818 #endif
819         int rc = 0;
820         uv_fs_req_cleanup(&req);
821         rc = uv_fs_ftruncate(nullptr, &req, fd, 0, nullptr);
822         if (rc == -1) {
823             char buffer[BUF_SIZE_DEFAULT] = { 0 };
824             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
825             uv_fs_close(nullptr, &req, fd, nullptr);
826             WRITE_LOG(LOG_FATAL, "ftruncate file %s failed!!! %s", bufPath, buffer);
827             return ERR_FILE_STAT;
828         }
829         uv_buf_t wbf = uv_buf_init(pidBuf, strlen(pidBuf));
830         uv_fs_req_cleanup(&req);
831         rc = uv_fs_write(nullptr, &req, fd, &wbf, 1, 0, nullptr);
832         if (rc == -1) {
833             char buffer[BUF_SIZE_DEFAULT] = { 0 };
834             uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT);
835             uv_fs_close(nullptr, &req, fd, nullptr);
836             WRITE_LOG(LOG_FATAL, "write file %s failed!!! %s", bufPath, buffer);
837             return ERR_FILE_WRITE;
838         }
839         WRITE_LOG(LOG_DEBUG, "Write mutext to %s, pid:%s", bufPath, pidBuf);
840         if (checkOrNew) {
841             // close it for check only
842             uv_fs_close(nullptr, &req, fd, nullptr);
843         }
844         // Do not close the file descriptor, the process will be mutext effect under no-Win32 OS
845         return RET_SUCCESS;
846     }
847 
SplitString(const string & origString,const string & seq,vector<string> & resultStrings)848     void SplitString(const string &origString, const string &seq, vector<string> &resultStrings)
849     {
850         string::size_type p1 = 0;
851         string::size_type p2 = origString.find(seq);
852 
853         while (p2 != string::npos) {
854             if (p2 == p1) {
855                 ++p1;
856                 p2 = origString.find(seq, p1);
857                 continue;
858             }
859             resultStrings.push_back(origString.substr(p1, p2 - p1));
860             p1 = p2 + seq.size();
861             p2 = origString.find(seq, p1);
862         }
863 
864         if (p1 != origString.size()) {
865             resultStrings.push_back(origString.substr(p1));
866         }
867     }
868 
GetShellPath()869     string GetShellPath()
870     {
871         struct stat filecheck;
872         string shellPath = "/bin/sh";
873         if (stat(shellPath.c_str(), &filecheck) < 0) {
874             shellPath = "/system/bin/sh";
875             if (stat(shellPath.c_str(), &filecheck) < 0) {
876                 shellPath = "sh";
877             }
878         }
879         return shellPath;
880     }
881 
882     // Not supported on some platforms, Can only be achieved manually
HostToNet(uint64_t val)883     uint64_t HostToNet(uint64_t val)
884     {
885         if (htonl(1) == 1) {
886             return val;
887         }
888         return ((static_cast<uint64_t>(htonl(val))) << 32) + htonl(val >> 32);
889     }
890 
NetToHost(uint64_t val)891     uint64_t NetToHost(uint64_t val)
892     {
893         if (htonl(1) == 1) {
894             return val;
895         }
896         return ((static_cast<uint64_t>(ntohl(val))) << 32) + ntohl(val >> 32);
897     }
898 
GetPathSep()899     char GetPathSep()
900     {
901 #ifdef _WIN32
902         const char sep = '\\';
903 #else
904         const char sep = '/';
905 #endif
906         return sep;
907     }
908 
GetFullFilePath(string & s)909     string GetFullFilePath(string &s)
910     {  // cannot use s.rfind(std::filesystem::path::preferred_separator
911         // remove last sep, and update input
912         while (s.back() == GetPathSep()) {
913             s.pop_back();
914         }
915 
916         size_t i = s.rfind(GetPathSep(), s.length());
917         if (i != string::npos) {
918             return (s.substr(i + 1, s.length() - i));
919         }
920         return s;
921     }
922 
GetPathWithoutFilename(const string & s)923     string GetPathWithoutFilename(const string &s)
924     {
925         size_t i = s.rfind(GetPathSep(), s.length());
926         if (i != string::npos) {
927             return (s.substr(0, i + 1));
928         }
929         return s;
930     }
931 
GetHdcAbsolutePath()932     string GetHdcAbsolutePath()
933     {
934         char path[BUF_SIZE_DEFAULT4] = { 0 };
935         size_t nPathSize = sizeof(path);
936         int ret = uv_exepath(path, &nPathSize);
937         if (ret < 0) {
938             char buf[BUF_SIZE_DEFAULT] = { 0 };
939             uv_err_name_r(ret, buf, BUF_SIZE_DEFAULT);
940             WRITE_LOG(LOG_WARN, "uvexepath ret:%d error:%s", ret, buf);
941             return "";
942         }
943 
944         return string(path);
945     }
946 
947 
CreateSocketPair(int * fds)948     int CreateSocketPair(int *fds)
949     {
950 #ifndef _WIN32
951 #ifdef HOST_MAC
952         int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
953         if (ret == 0) {
954             for (auto i = 0; i < 2; ++i) {
955                 if (fcntl(fds[i], F_SETFD, FD_CLOEXEC) == -1) {
956                     CloseFd(fds[0]);
957                     CloseFd(fds[1]);
958                     constexpr int bufSize = 1024;
959                     char buf[bufSize] = { 0 };
960                     strerror_r(errno, buf, bufSize);
961                     WRITE_LOG(LOG_WARN, "fcntl failed to set FD_CLOEXEC: %s", buf);
962                     return -1;
963                 }
964             }
965         }
966         return ret;
967 #else
968         return socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds);
969 #endif
970 #else
971         struct sockaddr_in addr;
972         socklen_t addrlen = sizeof(addr);
973         int reuse = 1;
974         if (fds == 0) {
975             return -1;
976         }
977         int listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
978         if (listener == -1) {
979             return -2;
980         }
981         Base::ZeroStruct(addr);
982         addr.sin_family = AF_INET;
983         addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
984         addr.sin_port = 0;
985         fds[0] = fds[1] = (int)-1;
986         do {
987             if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, (socklen_t)sizeof(reuse))) {
988                 break;
989             }
990             if (::bind(listener, (struct sockaddr *)&addr, sizeof(addr))) {
991                 break;
992             }
993             if (getsockname(listener, (struct sockaddr *)&addr, &addrlen)) {
994                 break;
995             }
996             if (listen(listener, 1)) {
997                 break;
998             }
999             fds[0] = socket(AF_INET, SOCK_STREAM, 0);
1000             if (fds[0] == -1) {
1001                 break;
1002             }
1003             if (connect(fds[0], (struct sockaddr *)&addr, sizeof(addr)) == -1) {
1004                 break;
1005             }
1006             fds[1] = accept(listener, nullptr, nullptr);
1007             if (fds[1] == -1) {
1008                 break;
1009             }
1010             closesocket(listener);
1011             return 0;
1012         } while (0);
1013 
1014         closesocket(listener);
1015         closesocket(fds[0]);
1016         closesocket(fds[1]);
1017         return -1;
1018 #endif
1019     }
1020 
CloseSocketPair(int * fds)1021     void CloseSocketPair(int *fds)
1022     {
1023 #ifndef _WIN32
1024         CloseFd(fds[0]);
1025         CloseFd(fds[1]);
1026 #else
1027         closesocket(fds[0]);
1028         closesocket(fds[1]);
1029 #endif
1030     }
1031 
StringEndsWith(string s,string sub)1032     int StringEndsWith(string s, string sub)
1033     {
1034         return s.rfind(sub) == (s.length() - sub.length()) ? 1 : 0;
1035     }
1036 
GetFileType(mode_t mode)1037     const char *GetFileType(mode_t mode)
1038     {
1039         switch (mode & S_IFMT) {
1040             case S_IFDIR:
1041                 return "directory";
1042             case S_IFLNK:
1043                 return "symlink";
1044             case S_IFREG:
1045                 return "regular file";
1046 #ifndef _WIN32
1047             case S_IFBLK:
1048                 return "block device";
1049             case S_IFCHR:
1050                 return "character device";
1051             case S_IFIFO:
1052                 return "FIFO/pipe";
1053             case S_IFSOCK:
1054                 return "socket";
1055 #endif
1056             default:
1057                 return "Unknown";
1058         }
1059     }
1060 
BuildErrorString(const char * localPath,const char * op,const char * err,string & str)1061     void BuildErrorString(const char *localPath, const char *op, const char *err, string &str)
1062     {
1063         // avoid to use stringstream
1064         str = op;
1065         str += " ";
1066         str += localPath;
1067         str += " failed, ";
1068         str += err;
1069     }
1070 
1071     // Both absolute and relative paths support
CheckDirectoryOrPath(const char * localPath,bool pathOrDir,bool readWrite,string & errStr,mode_t & fm)1072     bool CheckDirectoryOrPath(const char *localPath, bool pathOrDir, bool readWrite, string &errStr, mode_t &fm)
1073     {
1074         if (pathOrDir) {  // filepath
1075             uv_fs_t req;
1076             mode_t mode;
1077             fm = mode_t(~S_IFMT);
1078             int r = uv_fs_lstat(nullptr, &req, localPath, nullptr);
1079             if (r) {
1080                 constexpr int bufSize = 1024;
1081                 char buf[bufSize] = { 0 };
1082                 uv_strerror_r((int)req.result, buf, bufSize);
1083                 BuildErrorString(localPath, "lstat", buf, errStr);
1084             }
1085 
1086             mode = req.statbuf.st_mode;
1087             uv_fs_req_cleanup(&req);
1088 
1089             if ((r == 0) && (mode & S_IFDIR)) {
1090                 fm = S_IFDIR;
1091             } else if ((r == 0) && (mode & S_IFREG)) {  // is file
1092                 uv_fs_access(nullptr, &req, localPath, readWrite ? R_OK : W_OK, nullptr);
1093                 if (req.result) {
1094                     const char *op = readWrite ? "access R_OK" : "access W_OK";
1095                     constexpr int bufSize = 1024;
1096                     char buf[bufSize] = { 0 };
1097                     uv_strerror_r((int)req.result, buf, bufSize);
1098                     BuildErrorString(localPath, op, buf, errStr);
1099                 }
1100                 uv_fs_req_cleanup(&req);
1101                 if (req.result == 0) {
1102                     return true;
1103                 }
1104             } else if (r == 0) {
1105                 const char *type = GetFileType(mode);
1106                 errStr = "Not support ";
1107                 errStr += type;
1108                 errStr += ": ";
1109                 errStr += localPath;
1110             }
1111         } else {  // dir
1112             errStr = "Not support dir: ";
1113             errStr += localPath;
1114         }
1115         return false;
1116     }
1117 
TryCreateDirectory(const string & path,string & err)1118     bool TryCreateDirectory(const string &path, string &err)
1119     {
1120         uv_fs_t req;
1121         WRITE_LOG(LOG_DEBUG, "TryCreateDirectory path = %s", path.c_str());
1122         int r = uv_fs_lstat(nullptr, &req, path.c_str(), nullptr);
1123         mode_t mode = req.statbuf.st_mode;
1124         uv_fs_req_cleanup(&req);
1125         if (r < 0) {
1126             WRITE_LOG(LOG_DEBUG, "path not exist create dir = %s", path.c_str());
1127             r = uv_fs_mkdir(nullptr, &req, path.c_str(), DEF_FILE_PERMISSION, nullptr);
1128             uv_fs_req_cleanup(&req);
1129             if (r < 0) {
1130                 WRITE_LOG(LOG_WARN, "create dir %s failed", path.c_str());
1131                 err = "Error create directory, path:";
1132                 err += path.c_str();
1133                 return false;
1134             }
1135         } else {
1136             if (!((mode & S_IFMT) == S_IFDIR)) {
1137                 WRITE_LOG(LOG_WARN, "%s exist, not directory", path.c_str());
1138                 err = "Not a directoty, path:";
1139                 err += path.c_str();
1140                 return false;
1141             }
1142         }
1143         return true;
1144     }
1145 
CheckDirectoryOrPath(const char * localPath,bool pathOrDir,bool readWrite)1146     bool CheckDirectoryOrPath(const char *localPath, bool pathOrDir, bool readWrite)
1147     {
1148         string strUnused;
1149         mode_t mode = mode_t(~S_IFMT);
1150         return CheckDirectoryOrPath(localPath, pathOrDir, readWrite, strUnused, mode);
1151     }
1152 
1153     // Using openssl encryption and decryption method, high efficiency; when encrypting more than 64 bytes,
1154     // the carriage return will not be added, and the tail padding 00 is removed when decrypting
1155     // The return value is the length of the string after Base64
Base64EncodeBuf(const uint8_t * input,const int length,uint8_t * bufOut)1156     int Base64EncodeBuf(const uint8_t *input, const int length, uint8_t *bufOut)
1157     {
1158         return EVP_EncodeBlock(bufOut, input, length);
1159     }
1160 
Base64Encode(const uint8_t * input,const int length)1161     vector<uint8_t> Base64Encode(const uint8_t *input, const int length)
1162     {
1163         vector<uint8_t> retVec;
1164         uint8_t *pBuf = nullptr;
1165         while (true) {
1166             if (static_cast<uint32_t>(length) > HDC_BUF_MAX_BYTES) {
1167                 break;
1168             }
1169             int base64Size = length * 1.4 + 256;
1170             if (!(pBuf = new uint8_t[base64Size]())) {
1171                 break;
1172             }
1173             int childRet = Base64EncodeBuf(input, length, pBuf);
1174             if (childRet <= 0) {
1175                 break;
1176             }
1177             retVec.insert(retVec.begin(), pBuf, pBuf + childRet);
1178             break;
1179         }
1180         if (pBuf) {
1181             delete[] pBuf;
1182         }
1183 
1184         return retVec;
1185     }
1186 
CalcDecodeLength(const uint8_t * b64input)1187     inline int CalcDecodeLength(const uint8_t *b64input)
1188     {
1189         int len = strlen(reinterpret_cast<char *>(const_cast<uint8_t *>(b64input)));
1190         if (!len) {
1191             return 0;
1192         }
1193         int padding = 0;
1194         if (b64input[len - 1] == '=' && b64input[len - 2] == '=') {
1195             // last two chars are =
1196             padding = 2;  // 2 : last two chars
1197         } else if (b64input[len - 1] == '=') {
1198             // last char is =
1199             padding = 1;
1200         }
1201         return static_cast<int>(len * 0.75 - padding);
1202     }
1203 
1204     // return -1 error; >0 decode size
Base64DecodeBuf(const uint8_t * input,const int length,uint8_t * bufOut)1205     int Base64DecodeBuf(const uint8_t *input, const int length, uint8_t *bufOut)
1206     {
1207         int nRetLen = CalcDecodeLength(input);
1208         if (!nRetLen) {
1209             return 0;
1210         }
1211 
1212         if (EVP_DecodeBlock(bufOut, input, length) > 0) {
1213             return nRetLen;
1214         }
1215         return 0;
1216     }
1217 
Base64Decode(const uint8_t * input,const int length)1218     string Base64Decode(const uint8_t *input, const int length)
1219     {
1220         string retString;
1221         uint8_t *pBuf = nullptr;
1222         while (true) {
1223             if (static_cast<uint32_t>(length) > HDC_BUF_MAX_BYTES) {
1224                 break;
1225             }
1226             // must less than length
1227             if (!(pBuf = new uint8_t[length]())) {
1228                 break;
1229             }
1230             int childRet = Base64DecodeBuf(input, length, pBuf);
1231             if (childRet <= 0) {
1232                 break;
1233             }
1234             retString = (reinterpret_cast<char *>(pBuf));
1235             break;
1236         }
1237         if (pBuf) {
1238             delete[] pBuf;
1239         }
1240         return retString;
1241     }
1242 
ReverseBytes(void * start,int size)1243     void ReverseBytes(void *start, int size)
1244     {
1245         uint8_t *istart = (uint8_t *)start;
1246         uint8_t *iend = istart + size;
1247         std::reverse(istart, iend);
1248     }
1249 
1250     // clang-format off
StringFormat(const char * const formater,...)1251     const string StringFormat(const char * const formater, ...)
1252     {
1253         va_list vaArgs;
1254         va_start(vaArgs, formater);
1255         string ret = StringFormat(formater, vaArgs);
1256         va_end(vaArgs);
1257         return ret;
1258     }
1259 
StringFormat(const char * const formater,va_list & vaArgs)1260     const string StringFormat(const char * const formater, va_list &vaArgs)
1261     {
1262         std::vector<char> args(GetMaxBufSize());
1263         const int retSize = vsnprintf_s(args.data(), GetMaxBufSize(), args.size() - 1, formater, vaArgs);
1264         if (retSize < 0) {
1265             return std::string("");
1266         } else {
1267             return std::string(args.data(), retSize);
1268         }
1269     }
1270     // clang-format on
1271 
GetVersion()1272     string GetVersion()
1273     {
1274         const uint8_t a = 'a';
1275         uint8_t major = (HDC_VERSION_NUMBER >> 28) & 0xff;
1276         uint8_t minor = (HDC_VERSION_NUMBER << 4 >> 24) & 0xff;
1277         uint8_t version = (HDC_VERSION_NUMBER << 12 >> 24) & 0xff;
1278         uint8_t fix = (HDC_VERSION_NUMBER << 20 >> 28) & 0xff;  // max 16, tail is p
1279         string ver = StringFormat("%x.%x.%x%c", major, minor, version, a + fix);
1280         return "Ver: " + ver;
1281     }
1282 
IdleUvTask(uv_loop_t * loop,void * data,uv_idle_cb cb)1283     bool IdleUvTask(uv_loop_t *loop, void *data, uv_idle_cb cb)
1284     {
1285         uv_idle_t *idle = new(std::nothrow) uv_idle_t();
1286         if (idle == nullptr) {
1287             return false;
1288         }
1289         idle->data = data;
1290         uv_idle_init(loop, idle);
1291         uv_idle_start(idle, cb);
1292         // delete by callback
1293         return true;
1294     }
1295 
TimerUvTask(uv_loop_t * loop,void * data,uv_timer_cb cb,int repeatTimeout)1296     bool TimerUvTask(uv_loop_t *loop, void *data, uv_timer_cb cb, int repeatTimeout)
1297     {
1298         uv_timer_t *timer = new(std::nothrow) uv_timer_t();
1299         if (timer == nullptr) {
1300             return false;
1301         }
1302         timer->data = data;
1303         uv_timer_init(loop, timer);
1304         uv_timer_start(timer, cb, 0, repeatTimeout);
1305         // delete by callback
1306         return true;
1307     }
1308 
1309     // 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)1310     bool DelayDo(uv_loop_t *loop, const int delayMs, const uint8_t flag, string msg, void *data,
1311                  std::function<void(const uint8_t, string &, const void *)> cb)
1312     {
1313         struct DelayDoParam {
1314             uv_timer_t handle;
1315             uint8_t flag;
1316             string msg;
1317             void *data;
1318             std::function<void(const uint8_t, string &, const void *)> cb;
1319         };
1320         auto funcDelayDo = [](uv_timer_t *handle) -> void {
1321             DelayDoParam *st = (DelayDoParam *)handle->data;
1322             st->cb(st->flag, st->msg, st->data);
1323             uv_close((uv_handle_t *)handle, [](uv_handle_t *handle) {
1324                 DelayDoParam *st = (DelayDoParam *)handle->data;
1325                 delete st;
1326             });
1327         };
1328         DelayDoParam *st = new(std::nothrow) DelayDoParam();
1329         if (st == nullptr) {
1330             return false;
1331         }
1332         st->cb = cb;
1333         st->flag = flag;
1334         st->msg = msg;
1335         st->data = data;
1336         st->handle.data = st;
1337         uv_timer_init(loop, &st->handle);
1338         uv_timer_start(&st->handle, funcDelayDo, delayMs, 0);
1339         return true;
1340     }
1341 
ReplaceAll(string str,const string from,const string to)1342     string ReplaceAll(string str, const string from, const string to)
1343     {
1344         string::size_type startPos = 0;
1345         while ((startPos = str.find(from, startPos)) != string::npos) {
1346             str.replace(startPos, from.length(), to);
1347             startPos += to.length();  // Handles case where 'to' is a substring of 'from'
1348         }
1349         return str;
1350     }
1351 
CanonicalizeSpecPath(string & src)1352     string CanonicalizeSpecPath(string &src)
1353     {
1354         char resolvedPath[PATH_MAX] = { 0 };
1355 #if defined(_WIN32)
1356         if (!_fullpath(resolvedPath, src.c_str(), PATH_MAX)) {
1357             WRITE_LOG(LOG_FATAL, "_fullpath %s failed", src.c_str());
1358             return "";
1359         }
1360 #else
1361         if (realpath(src.c_str(), resolvedPath) == nullptr) {
1362             WRITE_LOG(LOG_FATAL, "realpath %s failed", src.c_str());
1363             return "";
1364         }
1365 #endif
1366         string res(resolvedPath);
1367         return res;
1368     }
1369 
UnicodeToUtf8(const char * src,bool reverse)1370     string UnicodeToUtf8(const char *src, bool reverse)
1371     {
1372 #if defined(_WIN32)
1373         UINT from = CP_ACP;
1374         UINT to = CP_UTF8;
1375         int count = 0;
1376         if (reverse) {
1377             from = CP_UTF8;
1378             to = CP_ACP;
1379         }
1380         count = MultiByteToWideChar(from, 0, src, -1, nullptr, 0);
1381         if (count <= 0) {
1382             DWORD err = GetLastError();
1383             WRITE_LOG(LOG_FATAL, "MultiByteToWideChar failed %s error:%lu", src, err);
1384             return "";
1385         }
1386         wchar_t *wstr = new(std::nothrow) wchar_t[count + 1]();
1387         if (wstr == nullptr) {
1388             WRITE_LOG(LOG_FATAL, "new wstr failed count:%d", count);
1389             return "";
1390         }
1391         count = MultiByteToWideChar(from, 0, src, -1, wstr, count);
1392         if (count <= 0) {
1393             DWORD err = GetLastError();
1394             WRITE_LOG(LOG_FATAL, "MultiByteToWideChar failed to wstr %s error:%lu", src, err);
1395             delete[] wstr;
1396             return "";
1397         }
1398         count = WideCharToMultiByte(to, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
1399         if (count <= 0) {
1400             DWORD err = GetLastError();
1401             WRITE_LOG(LOG_FATAL, "WideCharToMultiByte failed %s error:%lu", wstr, err);
1402             delete[] wstr;
1403             return "";
1404         }
1405         char *ustr = new(std::nothrow) char[count + 1]();
1406         if (ustr == nullptr) {
1407             DWORD err = GetLastError();
1408             WRITE_LOG(LOG_FATAL, "new ustr failed count:%d", count);
1409             delete[] wstr;
1410             return "";
1411         }
1412         count = WideCharToMultiByte(to, 0, wstr, -1, ustr, count, nullptr, nullptr);
1413         if (count <= 0) {
1414             DWORD err = GetLastError();
1415             WRITE_LOG(LOG_FATAL, "WideCharToMultiByte failed to ustr %s error:%lu", wstr, err);
1416             delete[] wstr;
1417             delete[] ustr;
1418             return "";
1419         }
1420         string rc(ustr);
1421         delete[] wstr;
1422         delete[] ustr;
1423         return rc;
1424 #else
1425         string rc(src);
1426         return rc;
1427 #endif
1428     }
1429 
CalcCheckSum(const uint8_t * data,int len)1430     uint8_t CalcCheckSum(const uint8_t *data, int len)
1431     {
1432         uint8_t ret = 0;
1433         for (int i = 0; i < len; ++i) {
1434             ret += data[i];
1435         }
1436         return ret;
1437     }
1438 
DuplicateUvSocket(uv_tcp_t * tcp)1439     uv_os_sock_t DuplicateUvSocket(uv_tcp_t *tcp)
1440     {
1441         uv_os_sock_t dupFd = -1;
1442 #ifdef _WIN32
1443         WSAPROTOCOL_INFO info;
1444         ZeroStruct(info);
1445         if (WSADuplicateSocketA(tcp->socket, GetCurrentProcessId(), &info) < 0) {
1446             return dupFd;
1447         }
1448         dupFd = WSASocketA(0, 0, 0, &info, 0, 0);
1449 #else
1450         uv_os_fd_t fdOs;
1451         if (uv_fileno((const uv_handle_t *)tcp, &fdOs) < 0) {
1452             return ERR_API_FAIL;
1453         }
1454         dupFd = dup(uv_open_osfhandle(fdOs));
1455 #endif
1456         return dupFd;
1457     }
1458 
GetCwd()1459     string GetCwd()
1460     {
1461         int value = -1;
1462         char path[PATH_MAX] = "";
1463         size_t size = sizeof(path);
1464         string res;
1465         value = uv_cwd(path, &size);
1466         if (value < 0) {
1467             constexpr int bufSize = 1024;
1468             char buf[bufSize] = { 0 };
1469             uv_strerror_r(value, buf, bufSize);
1470             WRITE_LOG(LOG_FATAL, "get path failed: %s", buf);
1471             return res;
1472         }
1473         if (strlen(path) >= PATH_MAX - 1) {
1474             WRITE_LOG(LOG_FATAL, "get path failed: buffer space max");
1475             return res;
1476         }
1477         if (path[strlen(path) - 1] != Base::GetPathSep()) {
1478             path[strlen(path)] = Base::GetPathSep();
1479         }
1480         res = path;
1481         return res;
1482     }
1483 
GetTmpDir()1484     string GetTmpDir()
1485     {
1486         string res;
1487 #ifdef HDC_HOST
1488         int value = -1;
1489         char path[PATH_MAX] = "";
1490         size_t size = sizeof(path);
1491         value = uv_os_tmpdir(path, &size);
1492         if (value < 0) {
1493             constexpr int bufSize = 1024;
1494             char buf[bufSize] = { 0 };
1495             uv_strerror_r(value, buf, bufSize);
1496             WRITE_LOG(LOG_FATAL, "get tmppath failed: %s", buf);
1497             return res;
1498         }
1499         if (strlen(path) >= PATH_MAX - 1) {
1500             WRITE_LOG(LOG_FATAL, "get tmppath failed: buffer space max");
1501             return res;
1502         }
1503         if (path[strlen(path) - 1] != Base::GetPathSep()) {
1504             path[strlen(path)] = Base::GetPathSep();
1505         }
1506         res = path;
1507 #else
1508         res = "/data/local/tmp/";
1509 #endif
1510         return res;
1511     }
1512 
SetLogCache(bool enable)1513     void SetLogCache(bool enable)
1514     {
1515         g_logCache = enable;
1516     }
1517 
RemoveLogFile()1518     void RemoveLogFile()
1519     {
1520         if (g_logCache) {
1521             string path = GetTmpDir() + LOG_FILE_NAME;
1522             string bakPath = GetTmpDir() + LOG_BAK_NAME;
1523             string cachePath = GetTmpDir() + LOG_CACHE_NAME;
1524             unlink(bakPath.c_str());
1525             rename(path.c_str(), bakPath.c_str());
1526             rename(cachePath.c_str(), path.c_str());
1527             g_logCache = false;
1528         }
1529     }
1530 
RemoveLogCache()1531     void RemoveLogCache()
1532     {
1533         string cachePath = GetTmpDir() + LOG_CACHE_NAME;
1534         unlink(cachePath.c_str());
1535     }
1536 
IsRoot()1537     bool IsRoot()
1538     {
1539 #ifdef _WIN32
1540         // reserve
1541         return true;
1542 #else
1543         if (getuid() == 0) {
1544             return true;
1545         }
1546 #endif
1547         return false;
1548     }
1549 
IsAbsolutePath(string & path)1550     bool IsAbsolutePath(string &path)
1551     {
1552         bool ret = false;
1553 #ifdef _WIN32
1554         // shlwapi.h PathIsRelativeA not link in harmony project
1555         // c:\ or UNC path '\\hostname\share\file'
1556         ret = path.find(":\\") == 1 || path.find("\\\\") == 0;
1557 #else
1558         ret = path[0] == '/';
1559 #endif
1560         return ret;
1561     }
1562 
CloseFd(int & fd)1563     int CloseFd(int &fd)
1564     {
1565         int rc = 0;
1566         if (fd > 0) {
1567             rc = close(fd);
1568             if (rc < 0) {
1569                 char buffer[BUF_SIZE_DEFAULT] = { 0 };
1570 #ifdef _WIN32
1571                 strerror_s(buffer, BUF_SIZE_DEFAULT, errno);
1572 #else
1573                 strerror_r(errno, buffer, BUF_SIZE_DEFAULT);
1574 #endif
1575                 WRITE_LOG(LOG_WARN, "close failed errno:%d %s", errno, buffer);
1576             } else {
1577                 fd = -1;
1578             }
1579         }
1580         return rc;
1581     }
1582 
InitProcess(void)1583     void InitProcess(void)
1584     {
1585 #ifndef HDC_HOST
1586         umask(0);
1587         signal(SIGPIPE, SIG_IGN);
1588         signal(SIGCHLD, SIG_IGN);
1589         signal(SIGALRM, SIG_IGN);
1590 #endif
1591     }
1592 
DeInitProcess(void)1593     void DeInitProcess(void)
1594     {
1595 #ifndef HDC_HOST
1596         mode_t writePermission = 022;
1597         umask(writePermission);
1598         signal(SIGPIPE, SIG_DFL);
1599         signal(SIGCHLD, SIG_DFL);
1600         signal(SIGALRM, SIG_DFL);
1601 #endif
1602     }
1603 }
1604 }  // namespace Hdc
1605