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