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