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, ×); 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