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