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