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