1/* 2 * Copyright (C) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include "base.h" 16#include <algorithm> 17#include <chrono> 18#include <cstdio> 19#include <cstring> 20#include <dirent.h> 21#include <iomanip> 22#include <openssl/bio.h> 23#include <openssl/buffer.h> 24#include <openssl/evp.h> 25#include <openssl/md5.h> 26#include <random> 27#include <sstream> 28#include <sys/stat.h> 29#include <thread> 30#include <vector> 31#ifdef HDC_HILOG 32#include "hilog/log.h" 33#endif 34#ifdef _WIN32 35#include <windows.h> 36#include <codecvt> 37#include <wchar.h> 38#include <wincrypt.h> 39#else 40#include <sys/wait.h> 41#endif 42#include <fstream> 43using namespace std::chrono; 44 45namespace Hdc { 46namespace Base { 47 constexpr int DEF_FILE_PERMISSION = 0750; 48#ifndef _WIN32 49 sigset_t g_blockList; 50#endif 51 uint8_t GetLogLevel() 52 { 53 return g_logLevel; 54 } 55#ifndef HDC_HILOG 56 std::atomic<bool> g_logCache = true; 57#endif 58 uint8_t g_logLevel = LOG_DEBUG; // tmp set,now debugmode.LOG_OFF when release;; 59 void SetLogLevel(const uint8_t logLevel) 60 { 61 g_logLevel = logLevel; 62 } 63 64 uint8_t GetLogLevelByEnv() 65 { 66 char *env = getenv(ENV_SERVER_LOG.c_str()); 67 if (!env) { 68 return GetLogLevel(); 69 } 70 size_t len = strlen(env); 71 72 size_t maxLen = 1; 73 if (len > maxLen) { 74 WRITE_LOG(LOG_WARN, "OHOS_HDC_LOG_LEVEL %s is not in (0, 6] range", env); 75 return GetLogLevel(); 76 } 77 78 for (size_t i = 0; i < len; i++) { 79 if (isdigit(env[i]) == 0) { 80 WRITE_LOG(LOG_WARN, "OHOS_HDC_LOG_LEVEL %s is not digit", env); 81 return GetLogLevel(); 82 } 83 } 84 85 uint8_t logLevel = static_cast<uint8_t>(atoi(env)); 86 if (logLevel < 0 || logLevel > LOG_LAST) { 87 WRITE_LOG(LOG_WARN, "OHOS_HDC_LOG_LEVEL %d is not in (0, 6] range", logLevel); 88 } else { 89 return logLevel; 90 } 91 92 return GetLogLevel(); 93 } 94 95// Commenting the code will optimize and tune all log codes, and the compilation volume will be greatly reduced 96#define ENABLE_DEBUGLOG 97#ifdef ENABLE_DEBUGLOG 98 void GetLogDebugFunctionName(string &debugInfo, int line, string &threadIdString) 99 { 100 string tmpString = GetFileNameAny(debugInfo); 101 debugInfo = StringFormat("%s:%d", tmpString.c_str(), line); 102 if (g_logLevel < LOG_DEBUG) { 103 debugInfo = ""; 104 threadIdString = ""; 105 } else { 106 debugInfo = "[" + debugInfo + "]"; 107 threadIdString = StringFormat("[%x]", std::hash<std::thread::id> {}(std::this_thread::get_id())); 108 } 109 } 110 111 void GetLogLevelAndTime(uint8_t logLevel, string &logLevelString, string &timeString) 112 { 113 system_clock::time_point timeNow = system_clock::now(); // now time 114 system_clock::duration sinceUnix0 = timeNow.time_since_epoch(); // since 1970 115 time_t sSinceUnix0 = duration_cast<seconds>(sinceUnix0).count(); 116 std::tm *tim = std::localtime(&sSinceUnix0); 117 switch (logLevel) { 118 case LOG_FATAL: 119 logLevelString = "F"; 120 break; 121 case LOG_INFO: 122 logLevelString = "I"; 123 break; 124 case LOG_WARN: 125 logLevelString = "W"; 126 break; 127 case LOG_DEBUG: // will reduce performance 128 logLevelString = "D"; 129 break; 130 default: // all, just more IO/Memory information 131 logLevelString = "A"; 132 break; 133 } 134 string msTimeSurplus; 135 if (g_logLevel >= LOG_DEBUG) { 136 const auto sSinceUnix0Rest = duration_cast<milliseconds>(sinceUnix0).count() % TIME_BASE; 137 msTimeSurplus = StringFormat(".%03llu", sSinceUnix0Rest); 138 } 139 timeString = msTimeSurplus; 140 if (tim != nullptr) { 141 char buffer[TIME_BUF_SIZE]; 142 (void)strftime(buffer, TIME_BUF_SIZE, "%Y-%m-%d %H:%M:%S", tim); 143 timeString = StringFormat("%s%s", buffer, msTimeSurplus.c_str()); 144 } 145 } 146 147#ifndef HDC_HILOG 148 void LogToPath(const char *path, const char *str) 149 { 150 // logfile, not thread-safe 151#ifdef HDC_DEBUG_UART 152 // make a log path print. 153 static std::once_flag firstLog; 154 std::call_once(firstLog, [&]() { printf("log at %s\n", path); }); 155 // better than open log file every time. 156 static std::unique_ptr<FILE, decltype(&fclose)> file(fopen(path, "w"), &fclose); 157 FILE *fp = file.get(); 158 if (fp == nullptr) { 159 return; 160 } 161 if (fprintf(fp, "%s", str) > 0 && fflush(fp)) { 162 // make ci happy 163 } 164 fclose(fp); 165#else 166 int flags = UV_FS_O_RDWR | UV_FS_O_APPEND | UV_FS_O_CREAT; 167 uv_fs_t req; 168 int fd = uv_fs_open(nullptr, &req, path, flags, S_IWUSR | S_IRUSR, nullptr); 169 if (fd < 0) { 170 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 171 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 172 uv_fs_req_cleanup(&req); 173 PrintMessage("LogToPath uv_fs_open %s error %s", path, buffer); 174 return; 175 } 176 string text(str); 177 uv_buf_t wbf = uv_buf_init((char *)str, text.size()); 178 uv_fs_req_cleanup(&req); 179 uv_fs_write(nullptr, &req, fd, &wbf, 1, -1, nullptr); 180 uv_fs_close(nullptr, &req, fd, nullptr); 181#endif 182 } 183 184 void GetTimeString(string &timeString) 185 { 186 system_clock::time_point timeNow = system_clock::now(); 187 system_clock::duration sinceUnix0 = timeNow.time_since_epoch(); // since 1970 188 time_t sinceUnix0Time = duration_cast<seconds>(sinceUnix0).count(); 189 std::tm *timeTm = std::localtime(&sinceUnix0Time); 190 191 const auto sinceUnix0Rest = duration_cast<milliseconds>(sinceUnix0).count() % TIME_BASE; 192 string msTimeSurplus = StringFormat("%03llu", sinceUnix0Rest); 193 timeString = msTimeSurplus; 194 if (timeTm != nullptr) { 195 char buffer[TIME_BUF_SIZE] = {0}; 196 if (strftime(buffer, TIME_BUF_SIZE, "%Y%m%d-%H%M%S", timeTm) > 0) { 197 timeString = StringFormat("%s%s", buffer, msTimeSurplus.c_str()); 198 } 199 } 200 } 201 202 bool CompareLogFileName(const string &a, const string &b) 203 { 204 return strcmp(a.c_str(), b.c_str()) > 0; 205 } 206 207 bool CreateLogDir() 208 { 209 string errMsg; 210 if (!TryCreateDirectory(GetLogDirName(), errMsg)) { 211 // Warning: no log dir, so the log here can not save into the log file. 212 WRITE_LOG(LOG_WARN, "[E002102]Create hdc_logs directory failed, the logs could not be saved into files."); 213 return false; 214 } 215 return true; 216 } 217 218 string GetCompressLogFileName(string fileName) 219 { 220 // example: hdc-20230228-123456789.log.tgz 221 return fileName + LOG_FILE_COMPRESS_SUFFIX; 222 } 223 224 uint32_t GetLogOverCount(vector<string> files, uint64_t limitDirSize) 225 { 226 WRITE_LOG(LOG_DEBUG, "GetLogDirSize, file size: %d", files.size()); 227 if (files.size() == 0) { 228 return 0; 229 } 230 uint64_t totalSize = 0; 231 uint32_t overCount = 0; 232 int value = -1; 233 for (auto name : files) { 234 uv_fs_t req; 235 string last = GetLogDirName() + name; 236 string utfName = UnicodeToUtf8(last.c_str(), false); 237 value = uv_fs_stat(nullptr, &req, utfName.c_str(), nullptr); 238 uv_fs_req_cleanup(&req); 239 if (value != 0) { 240 constexpr int bufSize = BUF_SIZE_DEFAULT; 241 char buf[bufSize] = { 0 }; 242 uv_strerror_r(value, buf, bufSize); 243 uv_fs_req_cleanup(&req); 244 WRITE_LOG(LOG_FATAL, "GetLogDirSize error file %s not exist %s", utfName.c_str(), buf); 245 } 246 if (req.result == 0) { 247 totalSize += req.statbuf.st_size; 248 } 249 if (totalSize > limitDirSize) { 250 overCount++; 251 } 252 } 253 WRITE_LOG(LOG_INFO, "overCount: %u", overCount); 254 return overCount; 255 } 256 257 static void ThreadCompressLog(string bakName) 258 { 259 string bakPath = GetLogDirName() + bakName; 260 if (bakName.empty()) { 261 WRITE_LOG(LOG_FATAL, "ThreadCompressLog file name empty"); 262 return; 263 } 264 if ((access(bakPath.c_str(), F_OK) != 0) || !CompressLogFile(bakName)) { 265 WRITE_LOG(LOG_FATAL, "ThreadCompressLog file %s not exist", bakPath.c_str()); 266 return; 267 } 268 WRITE_LOG(LOG_INFO, "ThreadCompressLog file %s.tgz success", bakPath.c_str()); 269 unlink(bakPath.c_str()); 270 } 271 272#ifdef _WIN32 273 bool CompressLogFile(string fileName) 274 { 275 bool retVal = false; 276 string full = GetLogDirName() + fileName; 277 if (access(full.c_str(), F_OK) != 0) { 278 WRITE_LOG(LOG_FATAL, "CompressLogFile file %s not exist", full.c_str()); 279 return retVal; 280 } 281 WRITE_LOG(LOG_DEBUG, "compress log file, fileName: %s", fileName.c_str()); 282 char currentDir[BUF_SIZE_DEFAULT]; 283 getcwd(currentDir, sizeof(currentDir)); 284 285 char buf[BUF_SIZE_SMALL] = ""; 286 if (sprintf_s(buf, sizeof(buf), "tar czfp %s %s", GetCompressLogFileName(fileName).c_str(), 287 fileName.c_str()) < 0) { 288 return retVal; 289 } 290 chdir(GetLogDirName().c_str()); 291 STARTUPINFO si; 292 PROCESS_INFORMATION pi; 293 ZeroMemory(&si, sizeof(si)); 294 si.cb = sizeof(si); 295 ZeroMemory(&pi, sizeof(pi)); 296 if (!CreateProcess(GetTarBinFile().c_str(), buf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 297 DWORD errorCode = GetLastError(); 298 LPVOID messageBuffer; 299 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 300 NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&messageBuffer, 0, NULL); 301 WRITE_LOG(LOG_FATAL, "compress log file failed, cmd: %s, error: %s", buf, (LPCTSTR)messageBuffer); 302 LocalFree(messageBuffer); 303 } else { 304 DWORD waitResult = WaitForSingleObject(pi.hProcess, INFINITE); 305 if (waitResult == WAIT_OBJECT_0) { 306 retVal = true; 307 } else if (waitResult == WAIT_TIMEOUT) { 308 retVal = true; 309 } 310 CloseHandle(pi.hProcess); 311 CloseHandle(pi.hThread); 312 } 313 chdir(currentDir); 314 return retVal; 315 } 316 317#else 318 bool CompressLogFile(string fileName) 319 { 320 bool retVal = false; 321 string full = GetLogDirName() + fileName; 322 if (access(full.c_str(), F_OK) != 0) { 323 WRITE_LOG(LOG_FATAL, "CompressLogFile file %s not exist", full.c_str()); 324 return retVal; 325 } 326 WRITE_LOG(LOG_DEBUG, "compress log file, fileName: %s", fileName.c_str()); 327 char currentDir[BUF_SIZE_DEFAULT]; 328 getcwd(currentDir, sizeof(currentDir)); 329 pid_t pc = fork(); // create process 330 chdir(GetLogDirName().c_str()); 331 if (pc < 0) { 332 WRITE_LOG(LOG_WARN, "fork subprocess failed."); 333 } else if (!pc) { 334 if ((execlp(GetTarToolName().c_str(), GetTarToolName().c_str(), GetTarParams().c_str(), 335 GetCompressLogFileName(fileName).c_str(), fileName.c_str(), nullptr)) == -1) { 336 WRITE_LOG(LOG_WARN, "CompressLogFile execlp failed."); 337 } 338 } else { 339 int status; 340 waitpid(pc, &status, 0); 341 if (WIFEXITED(status)) { 342 int exitCode = WEXITSTATUS(status); 343 WRITE_LOG(LOG_DEBUG, "subprocess exited with status %d", exitCode); 344 retVal = true; 345 } else { 346 WRITE_LOG(LOG_FATAL, "compress log file failed, filename:%s, error: %s", 347 fileName.c_str(), strerror(errno)); 348 } 349 } 350 chdir(currentDir); 351 return retVal; 352 } 353#endif 354 355 void CompressLogFiles() 356 { 357 vector<string> files = GetDirFileName(); 358 WRITE_LOG(LOG_DEBUG, "search log dir files, get files count: %d", files.size()); 359 if (files.size() == 0) { 360 return; 361 } 362 for (auto name : files) { 363 if (name.find(LOG_FILE_NAME) != string::npos) { 364 continue; 365 } 366 if (name.find(LOG_FILE_COMPRESS_SUFFIX) != string::npos) { 367 continue; 368 } 369 if ((name.find(LOG_FILE_SUFFIX) != string::npos && CompressLogFile(name))) { 370 string full = GetLogDirName() + name; 371 unlink(full.c_str()); 372 } 373 } 374 } 375 376 uint16_t GetLogLimitByEnv() 377 { 378 char *env = getenv(ENV_SERVER_LOG_LIMIT.c_str()); 379 size_t maxLen = 5; 380 if (!env || strlen(env) > maxLen) { 381 return MAX_LOG_FILE_COUNT; 382 } 383 int limitCount = atoi(env); 384 WRITE_LOG(LOG_DEBUG, "get log limit count from env: %d", limitCount); 385 if (limitCount <= 0) { 386 WRITE_LOG(LOG_WARN, "invalid log limit count: %d", limitCount); 387 return MAX_LOG_FILE_COUNT; 388 } else { 389 return static_cast<uint16_t>(limitCount); 390 } 391 } 392 393 394#ifdef _WIN32 395 void RemoveOlderLogFilesOnWindows() 396 { 397 vector<string> files; 398 WIN32_FIND_DATA findData; 399 HANDLE hFind = FindFirstFile((GetLogDirName() + "/*").c_str(), &findData); 400 if (hFind == INVALID_HANDLE_VALUE) { 401 WRITE_LOG(LOG_WARN, "Failed to open TEMP dir"); 402 return; 403 } 404 405 do { 406 if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { 407 SetErrorMode(SEM_FAILCRITICALERRORS); 408 if (strncmp(findData.cFileName, LOG_FILE_NAME_PREFIX.c_str(), LOG_FILE_NAME_PREFIX.size()) == 0) { 409 files.push_back(findData.cFileName); 410 } 411 } 412 } while (FindNextFile(hFind, &findData)); 413 FindClose(hFind); 414 415 if (files.size() <= MAX_LOG_FILE_COUNT) { 416 return; 417 } 418 419 // Sort file names by time, with earlier ones coming first 420 sort(files.begin(), files.end(), CompareLogFileName); 421 422 uint16_t deleteCount = files.size() - MAX_LOG_FILE_COUNT; 423 WRITE_LOG(LOG_INFO, "will delete log file, count: %u", deleteCount); 424 uint16_t count = 0; 425 for (auto name : files) { 426 if (count >= deleteCount) { 427 break; 428 } 429 string deleteFile = GetLogDirName() + name; 430 LPCTSTR lpFileName = TEXT(deleteFile.c_str()); 431 BOOL ret = DeleteFile(lpFileName); 432 WRITE_LOG(LOG_INFO, "delete: %s ret:%d", deleteFile.c_str(), ret); 433 count++; 434 } 435 } 436#endif 437 438 vector<string> GetDirFileName() 439 { 440 vector<string> files; 441#ifdef _WIN32 442 WIN32_FIND_DATA findData; 443 HANDLE hFind = FindFirstFile((GetLogDirName() + "/*").c_str(), &findData); 444 if (hFind == INVALID_HANDLE_VALUE) { 445 WRITE_LOG(LOG_WARN, "Failed to open log dir"); 446 return; 447 } 448 449 do { 450 if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { 451 SetErrorMode(SEM_FAILCRITICALERRORS); 452 if (strncmp(findData.cFileName, LOG_FILE_NAME_PREFIX.c_str(), LOG_FILE_NAME_PREFIX.size()) == 0) { 453 files.push_back(findData.cFileName); 454 } 455 } 456 } while (FindNextFile(hFind, &findData)); 457 FindClose(hFind); 458#else 459 DIR* dir = opendir(GetLogDirName().c_str()); 460 if (dir == nullptr) { 461 WRITE_LOG(LOG_WARN, "open log dir failed"); 462 return files; 463 } 464 465 struct dirent* entry; 466 while ((entry = readdir(dir)) != nullptr) { 467 string fileName = entry->d_name; 468 if (strncmp(fileName.c_str(), LOG_FILE_NAME_PREFIX.c_str(), LOG_FILE_NAME_PREFIX.size()) == 0) { 469 files.push_back(fileName); 470 } 471 } 472 closedir(dir); 473#endif 474 return files; 475 } 476 477 inline string GetLogDirName() 478 { 479 return GetTmpDir() + LOG_DIR_NAME + GetPathSep(); 480 } 481 482 string GetLogNameWithTime() 483 { 484 string timeStr; 485 GetTimeString(timeStr); 486 // example: hdc-20230228-123456789.log 487 return LOG_FILE_NAME_PREFIX + timeStr + LOG_FILE_SUFFIX; 488 } 489 490 void RemoveOlderLogFiles() 491 { 492 vector<string> files = GetDirFileName(); 493 uint16_t logLimitSize = GetLogLimitByEnv(); 494 if (files.size() <= logLimitSize) { 495 return; 496 } 497 // Sort file names by time, with newer ones coming first 498 sort(files.begin(), files.end(), CompareLogFileName); 499 uint32_t deleteCount = GetLogOverCount(files, MAX_LOG_DIR_SIZE); 500 WRITE_LOG(LOG_INFO, "log file count: %u, logLimit: %u", files.size(), logLimitSize); 501 if (deleteCount == 0 || files.size() < deleteCount) { 502 return; 503 } 504 WRITE_LOG(LOG_INFO, "will delete log file, count: %u", deleteCount); 505 uint32_t count = 0; 506 uint32_t beginCount = files.size() - deleteCount; 507 for (auto name : files) { 508 count++; 509 if (count < beginCount) { 510 continue; 511 } 512 string deleteFile = GetLogDirName() + name; 513 WRITE_LOG(LOG_INFO, "delete: %s", deleteFile.c_str()); 514 unlink(deleteFile.c_str()); 515 } 516 } 517 518 void LogToFile(const char *str) 519 { 520 string path = GetLogDirName() + LOG_FILE_NAME; 521 RollLogFile(path.c_str()); 522 LogToPath(path.c_str(), str); 523 } 524 525 void LogToCache(const char *str) 526 { 527 string path = GetLogDirName() + LOG_CACHE_NAME; 528 LogToPath(path.c_str(), str); 529 } 530 531 void RollLogFile(const char *path) 532 { 533 // Here cannot use WRITE_LOG, because WRITE_LOG will call RollLogFile again. 534 int value = -1; 535 uv_fs_t fs; 536 value = uv_fs_stat(nullptr, &fs, path, nullptr); 537 if (value != 0) { 538 constexpr int bufSize = 1024; 539 char buf[bufSize] = { 0 }; 540 uv_strerror_r(value, buf, bufSize); 541 PrintMessage("RollLogFile error log file %s not exist %s", path, buf); 542 return; 543 } 544 uint64_t size = fs.statbuf.st_size; 545 if (size < MAX_LOG_FILE_SIZE) { 546 return; 547 } 548 string last = GetLogDirName() + GetLogNameWithTime(); 549 value = uv_fs_rename(nullptr, &fs, path, last.c_str(), nullptr); 550 PrintMessage("rename %s to %s", path, last.c_str()); 551 if (value != 0) { 552 constexpr int bufSize = 1024; 553 char buf[bufSize] = { 0 }; 554 uv_strerror_r(value, buf, bufSize); 555 uv_fs_req_cleanup(&fs); 556 PrintMessage("RollLogFile error rename %s to %s %s", path, last.c_str(), buf); 557 return; 558 } 559 uv_fs_req_cleanup(&fs); 560 // creat thread 561 std::thread compressDirThread(CompressLogFiles); 562 compressDirThread.detach(); 563 RemoveOlderLogFiles(); 564 } 565 566 void ChmodLogFile() 567 { 568 string path = GetLogDirName() + LOG_FILE_NAME; 569 uv_fs_t req = {}; 570 int rc = uv_fs_chmod(nullptr, &req, path.c_str(), 0664, nullptr); 571 if (rc < 0) { 572 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 573 uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT); 574 WRITE_LOG(LOG_FATAL, "uv_fs_chmod %s failed %s", path.c_str(), buffer); 575 } 576 uv_fs_req_cleanup(&req); 577 } 578#endif 579 580void PrintLogEx(const char *functionName, int line, uint8_t logLevel, const char *msg, ...) 581 { 582 if (logLevel > g_logLevel) { 583 return; 584 } 585 586 char buf[BUF_SIZE_DEFAULT4] = { 0 }; // only 4k to avoid stack overflow in 32bit or L0 587 va_list vaArgs; 588 va_start(vaArgs, msg); 589 const int retSize = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, msg, vaArgs); 590 va_end(vaArgs); 591 if (retSize < 0) { 592 return; 593 } 594 595#ifdef HDC_HILOG 596 string tmpPath = functionName; 597 string filePath = GetFileNameAny(tmpPath); 598 switch (static_cast<int>(logLevel)) { 599 case static_cast<int>(LOG_DEBUG): 600 // Info level log can be printed default in hilog, debug can't 601 HDC_LOG_INFO("[%{public}s:%{public}d] %{public}s", 602 filePath.c_str(), line, buf); 603 break; 604 case static_cast<int>(LOG_INFO): 605 HDC_LOG_INFO("[%{public}s:%{public}d] %{public}s", 606 filePath.c_str(), line, buf); 607 break; 608 case static_cast<int>(LOG_WARN): 609 HDC_LOG_WARN("[%{public}s:%{public}d] %{public}s", 610 filePath.c_str(), line, buf); 611 break; 612 case static_cast<int>(LOG_FATAL): 613 HDC_LOG_FATAL("[%{public}s:%{public}d] %{public}s", 614 filePath.c_str(), line, buf); 615 break; 616 default: 617 break; 618 } 619#else 620 string logLevelString; 621 string threadIdString; 622 string sep = "\n"; 623 string timeString; 624 if (string(buf).back() == '\n') { 625 sep = "\r\n"; 626 } 627 string debugInfo = functionName; 628 GetLogDebugFunctionName(debugInfo, line, threadIdString); 629 GetLogLevelAndTime(logLevel, logLevelString, timeString); 630 string logBuf = StringFormat("[%s][%s]%s%s %s%s", logLevelString.c_str(), timeString.c_str(), 631 threadIdString.c_str(), debugInfo.c_str(), buf, sep.c_str()); 632 633 printf("%s", logBuf.c_str()); 634 fflush(stdout); 635 636 if (!g_logCache) { 637 LogToFile(logBuf.c_str()); 638 } else { 639 LogToCache(logBuf.c_str()); 640 } 641#endif 642 return; 643 } 644#else // else ENABLE_DEBUGLOG.If disabled, the entire output code will be optimized by the compiler 645 void PrintLogEx(const char *functionName, int line, uint8_t logLevel, char *msg, ...) 646 { 647 } 648#endif // ENABLE_DEBUGLOG 649 650 void PrintMessage(const char *fmt, ...) 651 { 652 va_list ap; 653 va_start(ap, fmt); 654 if (vfprintf(stdout, fmt, ap) > 0) { 655 fprintf(stdout, "\n"); 656 } 657 va_end(ap); 658 } 659 660 // if can linkwith -lstdc++fs, use std::filesystem::path(path).filename(); 661 string GetFileNameAny(string &path) 662 { 663 string tmpString = path; 664 size_t tmpNum = tmpString.rfind('/'); 665 if (tmpNum == std::string::npos) { 666 tmpNum = tmpString.rfind('\\'); 667 if (tmpNum == std::string::npos) { 668 return tmpString; 669 } 670 } 671 tmpString = tmpString.substr(tmpNum + 1, tmpString.size() - tmpNum); 672 return tmpString; 673 } 674 675 void SetTcpOptions(uv_tcp_t *tcpHandle, int bufMaxSize) 676 { 677 if (!tcpHandle) { 678 return; 679 } 680 uv_tcp_keepalive(tcpHandle, 1, GLOBAL_TIMEOUT); 681 // if MAX_SIZE_IOBUF==5k,bufMaxSize at least 40k. It must be set to io 8 times is more appropriate, 682 // otherwise asynchronous IO is too fast, a lot of IO is wasted on IOloop, transmission speed will decrease 683 684 uv_recv_buffer_size((uv_handle_t *)tcpHandle, &bufMaxSize); 685 uv_send_buffer_size((uv_handle_t *)tcpHandle, &bufMaxSize); 686 } 687 688 void ReallocBuf(uint8_t **origBuf, int *nOrigSize, size_t sizeWanted) 689 { 690 if (*nOrigSize > 0) { 691 return; 692 } 693 if (sizeWanted <= 0 || sizeWanted >= HDC_BUF_MAX_BYTES) { 694 WRITE_LOG(LOG_WARN, "ReallocBuf failed, sizeWanted:%d", sizeWanted); 695 return; 696 } 697 *origBuf = new uint8_t[sizeWanted]; 698 if (!*origBuf) { 699 WRITE_LOG(LOG_WARN, "ReallocBuf failed, origBuf is null. sizeWanted:%d", sizeWanted); 700 return; 701 } 702 *nOrigSize = sizeWanted; 703 } 704 705 // As an uv_alloc_cb it must keep the same as prototype 706 void AllocBufferCallback(uv_handle_t *handle, size_t sizeSuggested, uv_buf_t *buf) 707 { 708 const int size = GetMaxBufSizeStable(); 709 buf->base = (char *)new uint8_t[size](); 710 if (buf->base) { 711 buf->len = size - 1; 712 } 713 } 714 715 // As an uv_write_cb it must keep the same as prototype 716 void SendCallback(uv_write_t *req, int status) 717 { 718 StartTraceScope("Base::SendCallback"); 719 if (status < 0) { 720 constexpr int bufSize = 1024; 721 char buf[bufSize] = { 0 }; 722 uv_strerror_r(status, buf, bufSize); 723 WRITE_LOG(LOG_WARN, "SendCallback failed,status:%d %s", status, buf); 724 } 725 delete[]((uint8_t *)req->data); 726 delete req; 727 } 728 729 // xxx must keep sync with uv_loop_close/uv_walk etc. 730 bool TryCloseLoop(uv_loop_t *ptrLoop, const char *callerName) 731 { 732 // UV_RUN_DEFAULT: Runs the event loop until the reference count drops to zero. Always returns zero. 733 // UV_RUN_ONCE: Poll for new events once. Note that this function blocks if there are no pending events. 734 // Returns zero when done (no active handles or requests left), or non-zero if more events are 735 // expected meaning you should run the event loop again sometime in the future). 736 // UV_RUN_NOWAIT: Poll for new events once but don't block if there are no pending events. 737 uint8_t closeRetry = 0; 738 bool ret = false; 739 constexpr int maxRetry = 3; 740 for (closeRetry = 0; closeRetry < maxRetry; ++closeRetry) { 741 if (uv_loop_close(ptrLoop) == UV_EBUSY) { 742 if (closeRetry > 2) { // 2:try 2 times close,the 3rd try shows uv loop cannot close. 743 WRITE_LOG(LOG_WARN, "%s close busy,try:%d", callerName, closeRetry); 744 } 745 746 if (ptrLoop->active_handles >= 2) { // 2:at least 2 handles for read & write. 747 WRITE_LOG(LOG_DEBUG, "TryCloseLoop issue"); 748 } 749 auto clearLoopTask = [](uv_handle_t *handle, void *arg) -> void { TryCloseHandle(handle); }; 750 uv_walk(ptrLoop, clearLoopTask, nullptr); 751 // If all processing ends, Then return0,this call will block 752 if (!ptrLoop->active_handles) { 753 ret = true; 754 break; 755 } 756 if (!uv_run(ptrLoop, UV_RUN_ONCE)) { 757 ret = true; 758 break; 759 } 760 usleep(10000); // 10000:sleep for 10s 761 } else { 762 WRITE_LOG(LOG_DEBUG, "Try close loop success"); 763 ret = true; 764 break; 765 } 766 } 767 return ret; 768 } 769 770 // xxx must keep sync with uv_loop_close/uv_walk etc. 771 bool TryCloseChildLoop(uv_loop_t *ptrLoop, const char *callerName) 772 { 773 // UV_RUN_DEFAULT: Runs the event loop until the reference count drops to zero. Always returns zero. 774 // UV_RUN_ONCE: Poll for new events once. Note that this function blocks if there are no pending events. 775 // Returns zero when done (no active handles or requests left), or non-zero if more events are 776 // expected meaning you should run the event loop again sometime in the future). 777 // UV_RUN_NOWAIT: Poll for new events once but don't block if there are no pending events. 778 uint8_t closeRetry = 0; 779 bool ret = false; 780 constexpr int maxRetry = 3; 781 for (closeRetry = 0; closeRetry < maxRetry; ++closeRetry) { 782 if (uv_loop_close(ptrLoop) == UV_EBUSY) { 783 if (closeRetry > 2) { // 2:try 2 times close,the 3rd try shows uv loop cannot close. 784 WRITE_LOG(LOG_WARN, "%s close busy,try:%d", callerName, closeRetry); 785 } 786 787 if (ptrLoop->active_handles >= 2) { // 2:at least 2 handles for read & write. 788 WRITE_LOG(LOG_DEBUG, "TryCloseLoop issue"); 789 } 790 auto clearLoopTask = [](uv_handle_t *handle, void *arg) -> void { TryCloseHandle(handle); }; 791 uv_walk(ptrLoop, clearLoopTask, nullptr); 792#ifdef _WIN32 793 // If all processing ends, Then return0,this call will block 794 if (!ptrLoop->active_handles) { 795 ret = true; 796 break; 797 } 798 if (!uv_run(ptrLoop, UV_RUN_ONCE)) { 799 ret = true; 800 break; 801 } 802 usleep(10000); // 10000:sleep for 10s 803#else 804 int r = 0; 805 int count = 0; 806 do { 807 count++; 808 r = uv_run(ptrLoop, UV_RUN_NOWAIT); 809 uv_sleep(MILL_SECONDS); //10 millseconds 810 } while (r != 0 && count <= COUNT); 811#endif 812 } else { 813 WRITE_LOG(LOG_DEBUG, "Try close loop success"); 814 ret = true; 815 break; 816 } 817 } 818 return ret; 819 } 820 821 // Some handles may not be initialized or activated yet or have been closed, skip the closing process 822 void TryCloseHandle(const uv_handle_t *handle) 823 { 824 TryCloseHandle(handle, nullptr); 825 } 826 827 void TryCloseHandle(const uv_handle_t *handle, uv_close_cb closeCallBack) 828 { 829 TryCloseHandle(handle, false, closeCallBack); 830 } 831 832 void TryCloseHandle(const uv_handle_t *handle, bool alwaysCallback, uv_close_cb closeCallBack) 833 { 834 bool hasCallClose = false; 835 if (handle->loop && !uv_is_closing(handle)) { 836 DispUvStreamInfo((const uv_stream_t *)handle, "before uv handle close"); 837 uv_close((uv_handle_t *)handle, closeCallBack); 838 hasCallClose = true; 839 } 840 if (!hasCallClose && alwaysCallback) { 841 closeCallBack((uv_handle_t *)handle); 842 } 843 } 844 845 void DispUvStreamInfo(const uv_stream_t *handle, const char *prefix) 846 { 847 uv_handle_type type = handle->type; 848 string name = "unknown"; 849 if (type == UV_TCP) { 850 name = "tcp"; 851 } else if (type == UV_NAMED_PIPE) { 852 name = "named_pipe"; 853 } else { 854 WRITE_LOG(LOG_DEBUG, "%s, the uv handle type is %d", prefix, type); 855 return; 856 } 857 858 size_t bufNotSended = uv_stream_get_write_queue_size(handle); 859 if (bufNotSended != 0) { 860 WRITE_LOG(LOG_DEBUG, "%s, the uv handle type is %s, has %u bytes data", prefix, name.c_str(), bufNotSended); 861 } 862 } 863 int SendToStream(uv_stream_t *handleStream, const uint8_t *buf, const int bufLen) 864 { 865 StartTraceScope("Base::SendToStream"); 866 if (bufLen > static_cast<int>(HDC_BUF_MAX_BYTES)) { 867 return ERR_BUF_ALLOC; 868 } 869 uint8_t *pDynBuf = new uint8_t[bufLen]; 870 if (!pDynBuf) { 871 WRITE_LOG(LOG_WARN, "SendToStream, alloc failed, size:%d", bufLen); 872 return ERR_BUF_ALLOC; 873 } 874 if (memcpy_s(pDynBuf, bufLen, buf, bufLen)) { 875 WRITE_LOG(LOG_WARN, "SendToStream, memory copy failed, size:%d", bufLen); 876 delete[] pDynBuf; 877 return ERR_BUF_COPY; 878 } 879 return SendToStreamEx(handleStream, pDynBuf, bufLen, nullptr, 880 reinterpret_cast<void *>(SendCallback), reinterpret_cast<void *>(pDynBuf)); 881 } 882 883 // handleSend is used for pipe thread sending, set nullptr for tcp, and dynamically allocated by malloc when buf 884 // is required 885 int SendToStreamEx(uv_stream_t *handleStream, const uint8_t *buf, const int bufLen, uv_stream_t *handleSend, 886 const void *finishCallback, const void *pWriteReqData) 887 { 888 StartTraceScope("Base::SendToStreamEx"); 889 int ret = ERR_GENERIC; 890 uv_write_t *reqWrite = new uv_write_t(); 891 if (!reqWrite) { 892 WRITE_LOG(LOG_WARN, "SendToStreamEx, new write_t failed, size:%d", bufLen); 893 return ERR_BUF_ALLOC; 894 } 895 uv_buf_t bfr; 896 while (true) { 897 reqWrite->data = (void *)pWriteReqData; 898 bfr.base = (char *)buf; 899 bfr.len = bufLen; 900 if (!uv_is_writable(handleStream)) { 901 WRITE_LOG(LOG_WARN, "SendToStreamEx, uv_is_writable false, size:%d", bufLen); 902 delete reqWrite; 903 break; 904 } 905 // handleSend must be a TCP socket or pipe, which is a server or a connection (listening or 906 // connected state). Bound sockets or pipes will be assumed to be servers. 907 if (handleSend) { 908 ret = uv_write2(reqWrite, handleStream, &bfr, 1, handleSend, (uv_write_cb)finishCallback); 909 } else { 910 ret = uv_write(reqWrite, handleStream, &bfr, 1, (uv_write_cb)finishCallback); 911 } 912 if (ret < 0) { 913 WRITE_LOG(LOG_WARN, "SendToStreamEx, uv_write false, size:%d", bufLen); 914 delete reqWrite; 915 ret = ERR_IO_FAIL; 916 break; 917 } 918 ret = bufLen; 919 break; 920 } 921 return ret; 922 } 923 924 int SendToPollFd(int fd, const uint8_t *buf, const int bufLen) 925 { 926 if (bufLen > static_cast<int>(HDC_BUF_MAX_BYTES)) { 927 return ERR_BUF_ALLOC; 928 } 929 uint8_t *pDynBuf = new uint8_t[bufLen]; 930 if (!pDynBuf) { 931 WRITE_LOG(LOG_WARN, "SendToPollFd, alloc failed, size:%d", bufLen); 932 return ERR_BUF_ALLOC; 933 } 934 if (memcpy_s(pDynBuf, bufLen, buf, bufLen)) { 935 WRITE_LOG(LOG_WARN, "SendToPollFd, memory copy failed, size:%d", bufLen); 936 delete[] pDynBuf; 937 return ERR_BUF_COPY; 938 } 939 int ret = Base::WriteToFd(fd, pDynBuf, bufLen); 940 delete[] pDynBuf; 941 if (ret <= 0) { 942 hdc_strerrno(buf); 943 WRITE_LOG(LOG_WARN, "SendToPollFd, send %d bytes to fd %d failed [%d][%s]", bufLen, fd, ret, buf); 944 } 945 return ret; 946 } 947 948 uint64_t GetRuntimeMSec() 949 { 950 struct timespec times = { 0, 0 }; 951 long time; 952 clock_gettime(CLOCK_MONOTONIC, ×); 953 time = times.tv_sec * TIME_BASE + times.tv_nsec / (TIME_BASE * TIME_BASE); 954 return time; 955 } 956 957 uint32_t GetRandomU32() 958 { 959 uint32_t ret; 960 std::random_device rd; 961 std::mt19937 gen(rd()); 962 std::uniform_int_distribution<uint32_t> dis(0, UINT32_MAX); 963 ret = dis(gen); 964 return ret; 965 } 966 967 uint64_t GetRandom(const uint64_t min, const uint64_t max) 968 { 969#ifdef HARMONY_PROJECT 970 uint64_t ret; 971 uv_random(nullptr, nullptr, &ret, sizeof(ret), 0, nullptr); 972#else 973 uint64_t ret; 974 std::random_device rd; 975 std::mt19937 gen(rd()); 976 std::uniform_int_distribution<uint64_t> dis(min, max); 977 ret = dis(gen); 978#endif 979 return ret; 980 } 981 982 uint32_t GetSecureRandom(void) 983 { 984 uint32_t result = static_cast<uint32_t>(GetRandom()); 985#ifdef _WIN32 986 const int randomByteCount = 4; 987 HCRYPTPROV hCryptProv; 988 BYTE pbData[randomByteCount]; 989 do { 990 if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) { 991 if (GetLastError() != NTE_BAD_KEYSET) { 992 WRITE_LOG(LOG_FATAL, "CryptAcquireContext first failed %x", GetLastError()); 993 break; 994 } 995 if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { 996 WRITE_LOG(LOG_FATAL, "CryptAcquireContext second failed %x", GetLastError()); 997 break; 998 } 999 } 1000 if (!CryptGenRandom(hCryptProv, randomByteCount, pbData)) { 1001 WRITE_LOG(LOG_FATAL, "CryptGenRandom failed %x", GetLastError()); 1002 } 1003 if (hCryptProv) { 1004 CryptReleaseContext(hCryptProv, 0); 1005 } 1006 result = *(reinterpret_cast<uint32_t*>(pbData)); 1007 } while (0); 1008#else 1009 std::ifstream randomFile("/dev/random", std::ios::binary); 1010 do { 1011 if (!randomFile.is_open()) { 1012 WRITE_LOG(LOG_FATAL, "open /dev/random failed"); 1013 break; 1014 } 1015 randomFile.read(reinterpret_cast<char*>(&result), sizeof(result)); 1016 } while (0); 1017 randomFile.close(); 1018#endif 1019 return result; 1020 } 1021 1022 string GetRandomString(const uint16_t expectedLen) 1023 { 1024 srand(static_cast<unsigned int>(GetRandom())); 1025 string ret = string(expectedLen, '0'); 1026 std::stringstream val; 1027 for (auto i = 0; i < expectedLen; ++i) { 1028 val << std::hex << (rand() % BUF_SIZE_MICRO); 1029 } 1030 ret = val.str(); 1031 return ret; 1032 } 1033 1034#ifndef HDC_HOST 1035 string GetSecureRandomString(const uint16_t expectedLen) 1036 { 1037 string ret = string(expectedLen, '0'); 1038 std::ifstream randomFile("/dev/random", std::ios::binary); 1039 do { 1040 if (!randomFile.is_open()) { 1041 WRITE_LOG(LOG_FATAL, "open /dev/random failed"); 1042 break; 1043 } 1044 std::stringstream val; 1045 unsigned char tmpByte; 1046 for (auto i = 0; i < expectedLen; ++i) { 1047 randomFile.read(reinterpret_cast<char*>(&tmpByte), 1); 1048 val << std::hex << (tmpByte % BUF_SIZE_MICRO); 1049 } 1050 ret = val.str(); 1051 } while (0); 1052 randomFile.close(); 1053 1054 return ret; 1055 } 1056#endif 1057 1058 int GetRandomNum(const int min, const int max) 1059 { 1060 return static_cast<int>(GetRandom(min, max)); 1061 } 1062 1063 int ConnectKey2IPPort(const char *connectKey, char *outIP, uint16_t *outPort, size_t outSize) 1064 { 1065 char bufString[BUF_SIZE_TINY] = ""; 1066 if (strncpy_s(bufString, sizeof(bufString), connectKey, strlen(connectKey))) { 1067 return ERR_BUF_COPY; 1068 } 1069 char *p = strrchr(bufString, ':'); 1070 if (!p) { 1071 return ERR_PARM_FORMAT; 1072 } 1073 *p = '\0'; 1074 if (!strlen(bufString) || strlen(bufString) > 40) { // 40 : bigger than length of ipv6 1075 return ERR_PARM_SIZE; 1076 } 1077 uint16_t wPort = static_cast<uint16_t>(atoi(p + 1)); 1078 if (EOK != strcpy_s(outIP, outSize, bufString)) { 1079 return ERR_BUF_COPY; 1080 } 1081 *outPort = wPort; 1082 return RET_SUCCESS; 1083 } 1084 1085 // After creating the session worker thread, execute it on the main thread 1086 void FinishWorkThread(uv_work_t *req, int status) 1087 { 1088 // This is operated in the main thread 1089 delete req; 1090 } 1091 1092 // at the finish of pFuncAfterThread must free uv_work_t* 1093 // clang-format off 1094 int StartWorkThread(uv_loop_t *loop, uv_work_cb pFuncWorkThread, 1095 uv_after_work_cb pFuncAfterThread, void *pThreadData) 1096 { 1097 uv_work_t *workThread = new uv_work_t(); 1098 if (!workThread) { 1099 return -1; 1100 } 1101 workThread->data = pThreadData; 1102 uv_queue_work(loop, workThread, pFuncWorkThread, pFuncAfterThread); 1103 return 0; 1104 } 1105 // clang-format on 1106 1107 char **SplitCommandToArgs(const char *cmdStringLine, int *slotIndex) 1108 { 1109 constexpr int extraBufSize = 2; 1110 char **argv; 1111 char *temp = nullptr; 1112 int argc = 0; 1113 char a = 0; 1114 size_t i = 0; 1115 size_t j = 0; 1116 size_t len = 0; 1117 bool isQuoted = false; 1118 bool isText = false; 1119 bool isSpace = false; 1120 1121 len = strlen(cmdStringLine); 1122 if (len < 1) { 1123 return nullptr; 1124 } 1125 i = ((len + extraBufSize) / extraBufSize) * sizeof(void *) + sizeof(void *); 1126 argv = reinterpret_cast<char **>(new(std::nothrow) char[i + (len + extraBufSize) * sizeof(char)]); 1127 if (argv == nullptr) { 1128 WRITE_LOG(LOG_FATAL, "SplitCommandToArgs new argv failed"); 1129 return nullptr; 1130 } 1131 temp = reinterpret_cast<char *>((reinterpret_cast<uint8_t *>(argv)) + i); 1132 argc = 0; 1133 argv[argc] = temp; 1134 isQuoted = false; 1135 isText = false; 1136 isSpace = true; 1137 i = 0; 1138 j = 0; 1139 1140 while ((a = cmdStringLine[i]) != 0) { 1141 if (isQuoted) { 1142 if (a == '\"') { 1143 isQuoted = false; 1144 } else { 1145 temp[j] = a; 1146 ++j; 1147 } 1148 } else { 1149 switch (a) { 1150 case '\"': 1151 isQuoted = true; 1152 isText = true; 1153 if (isSpace) { 1154 argv[argc] = temp + j; 1155 ++argc; 1156 } 1157 isSpace = false; 1158 break; 1159 case ' ': 1160 case '\t': 1161 case '\n': 1162 case '\r': 1163 if (isText) { 1164 temp[j] = '\0'; 1165 ++j; 1166 } 1167 isText = false; 1168 isSpace = true; 1169 break; 1170 default: 1171 isText = true; 1172 if (isSpace) { 1173 argv[argc] = temp + j; 1174 ++argc; 1175 } 1176 temp[j] = a; 1177 ++j; 1178 isSpace = false; 1179 break; 1180 } 1181 } 1182 ++i; 1183 } 1184 temp[j] = '\0'; 1185 argv[argc] = nullptr; 1186 1187 (*slotIndex) = argc; 1188 return argv; 1189 } 1190 1191 bool RunPipeComand(const char *cmdString, char *outBuf, uint16_t sizeOutBuf, bool ignoreTailLf) 1192 { 1193 FILE *pipeHandle = popen(cmdString, "r"); 1194 if (pipeHandle == nullptr) { 1195 return false; 1196 } 1197 int bytesRead = 0; 1198 int bytesOnce = 0; 1199 while (!feof(pipeHandle)) { 1200 bytesOnce = fread(outBuf, 1, sizeOutBuf - bytesRead, pipeHandle); 1201 if (bytesOnce <= 0) { 1202 break; 1203 } 1204 bytesRead += bytesOnce; 1205 } 1206 if (bytesRead && ignoreTailLf) { 1207 if (outBuf[bytesRead - 1] == '\n') { 1208 outBuf[bytesRead - 1] = '\0'; 1209 } 1210 } 1211 pclose(pipeHandle); 1212 return bytesRead; 1213 } 1214 1215 // bufLen == 0: alloc buffer in heap, need free it later 1216 // >0: read max nBuffLen bytes to *buff 1217 // ret value: <0 or bytes read 1218 int ReadBinFile(const char *pathName, void **buf, const size_t bufLen) 1219 { 1220 uint8_t *pDst = nullptr; 1221 size_t byteIO = 0; 1222 uv_fs_t req; 1223 int ret = uv_fs_stat(nullptr, &req, pathName, nullptr); 1224 if (ret < 0) { 1225 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 1226 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 1227 uv_fs_req_cleanup(&req); 1228 WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_stat %s error %s", pathName, buffer); 1229 return -1; 1230 } 1231 size_t nFileSize = req.statbuf.st_size; 1232 size_t readMax = 0; 1233 uint8_t dynamicBuf = 0; 1234 ret = -3; // -3:error for ReadBinFile 1235 if (bufLen == 0) { 1236 dynamicBuf = 1; 1237 pDst = new uint8_t[nFileSize + 1](); // tail \0 1238 if (!pDst) { 1239 return -1; 1240 } 1241 readMax = nFileSize; 1242 } else { 1243 if (nFileSize > bufLen) { 1244 return -2; // -2:error for bufLen 1245 } 1246 readMax = nFileSize; 1247 pDst = reinterpret_cast<uint8_t *>(buf); // The first address of the static array is the array address 1248 } 1249 1250 string srcPath(pathName); 1251 string resolvedPath = CanonicalizeSpecPath(srcPath); 1252 uv_buf_t rbf = uv_buf_init((char *)pDst, readMax); 1253 uv_fs_req_cleanup(&req); 1254 int fd = uv_fs_open(nullptr, &req, resolvedPath.c_str(), O_RDONLY, 0, nullptr); 1255 if (fd < 0) { 1256 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 1257 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 1258 WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_open %s error %s", resolvedPath.c_str(), buffer); 1259 goto ReadFileFromPath_Finish; 1260 } 1261 uv_fs_req_cleanup(&req); 1262 byteIO = uv_fs_read(nullptr, &req, fd, &rbf, 1, 0, nullptr); 1263 uv_fs_close(nullptr, nullptr, fd, nullptr); 1264 if (byteIO != readMax) { 1265 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 1266 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 1267 WRITE_LOG(LOG_FATAL, "ReadBinFile uv_fs_read %s error %s byteIO:%llu readMax:%llu", 1268 resolvedPath.c_str(), buffer, byteIO, readMax); 1269 goto ReadFileFromPath_Finish; 1270 } 1271 ret = 0; 1272 ReadFileFromPath_Finish: 1273 if (ret) { 1274 if (dynamicBuf) { 1275 delete[] pDst; 1276 } 1277 } else { 1278 if (dynamicBuf) { 1279 *buf = pDst; 1280 } 1281 ret = byteIO; 1282 } 1283 return ret; 1284 } 1285 1286 int WriteBinFile(const char *pathName, const uint8_t *buf, const size_t bufLen, bool newFile) 1287 { 1288 string resolvedPath; 1289 string srcPath(pathName); 1290 int flags = 0; 1291 if (newFile) { 1292 flags = UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC; 1293 // no std::fs supoort, else std::filesystem::canonical,-lstdc++fs 1294 if (srcPath.find("..") != string::npos) { 1295 return ERR_FILE_PATH_CHECK; 1296 } 1297 resolvedPath = srcPath.c_str(); 1298 } else { 1299 flags = UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_APPEND; 1300 resolvedPath = CanonicalizeSpecPath(srcPath); 1301 } 1302 uv_fs_t req; 1303 int fd = uv_fs_open(nullptr, &req, resolvedPath.c_str(), flags, S_IWUSR | S_IRUSR, nullptr); 1304 if (fd < 0) { 1305 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 1306 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 1307 uv_fs_req_cleanup(&req); 1308 WRITE_LOG(LOG_FATAL, "WriteBinFile uv_fs_open %s error %s", resolvedPath.c_str(), buffer); 1309 return ERR_FILE_OPEN; 1310 } 1311 uv_buf_t wbf = uv_buf_init((char *)buf, bufLen); 1312 uv_fs_req_cleanup(&req); 1313 size_t bytesDone = uv_fs_write(nullptr, &req, fd, &wbf, 1, 0, nullptr); 1314 uv_fs_close(nullptr, &req, fd, nullptr); 1315 if (bytesDone != bufLen) { 1316 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 1317 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 1318 uv_fs_req_cleanup(&req); 1319 WRITE_LOG(LOG_FATAL, "WriteBinFile uv_fs_write %s error %s bytesDone:%llu bufLen:%llu", 1320 resolvedPath.c_str(), buffer, bytesDone, bufLen); 1321 return ERR_BUF_SIZE; 1322 } 1323 return RET_SUCCESS; 1324 } 1325 1326 void CloseIdleCallback(uv_handle_t *handle) 1327 { 1328 delete (uv_idle_t *)handle; 1329 }; 1330 1331 void CloseTimerCallback(uv_handle_t *handle) 1332 { 1333 delete (uv_timer_t *)handle; 1334 }; 1335 1336 // return value: <0 error; 0 can start new server instance; >0 server already exists 1337 int ProgramMutex(const char *procname, bool checkOrNew) 1338 { 1339 char bufPath[BUF_SIZE_DEFAULT] = ""; 1340 char buf[BUF_SIZE_DEFAULT] = ""; 1341 char pidBuf[BUF_SIZE_TINY] = ""; 1342 size_t size = sizeof(buf); 1343 if (uv_os_tmpdir(buf, &size) < 0) { 1344 WRITE_LOG(LOG_FATAL, "Tmppath failed"); 1345 return ERR_API_FAIL; 1346 } 1347 if (snprintf_s(bufPath, sizeof(bufPath), sizeof(bufPath) - 1, "%s%c.%s.pid", buf, Base::GetPathSep(), procname) 1348 < 0) { 1349 return ERR_BUF_OVERFLOW; 1350 } 1351 int pid = static_cast<int>(getpid()); 1352 if (snprintf_s(pidBuf, sizeof(pidBuf), sizeof(pidBuf) - 1, "%d", pid) < 0) { 1353 return ERR_BUF_OVERFLOW; 1354 } 1355 // no need to CanonicalizeSpecPath, else not work 1356 umask(0); 1357 uv_fs_t req; 1358 int fd = uv_fs_open(nullptr, &req, bufPath, O_RDWR | O_CREAT, 0666, nullptr); // 0666:permission 1359 if (fd < 0) { 1360 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 1361 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 1362 uv_fs_req_cleanup(&req); 1363 WRITE_LOG(LOG_DEBUG, "Open mutex file %s failed!!! %s", bufPath, buffer); 1364 return ERR_FILE_OPEN; 1365 } 1366#ifdef _WIN32 1367 if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "Global\\%s", procname) < 0) { 1368 uv_fs_close(nullptr, &req, fd, nullptr); 1369 return ERR_BUF_OVERFLOW; 1370 } 1371 if (checkOrNew) { 1372 // CheckOrNew is true means to confirm whether the service is running 1373 uv_fs_close(nullptr, &req, fd, nullptr); 1374 HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, buf); 1375 if (hMutex != nullptr) { 1376 CloseHandle(hMutex); 1377 WRITE_LOG(LOG_DEBUG, "Mutex \"%s\" locked. Server already exist.", procname); 1378 return 1; 1379 } else { 1380 WRITE_LOG(LOG_DEBUG, "Server is not exist"); 1381 return 0; 1382 } 1383 } else { 1384 HANDLE hMutex = CreateMutex(nullptr, TRUE, buf); 1385 DWORD dwError = GetLastError(); 1386 if (ERROR_ALREADY_EXISTS == dwError || ERROR_ACCESS_DENIED == dwError) { 1387 uv_fs_close(nullptr, &req, fd, nullptr); 1388 WRITE_LOG(LOG_DEBUG, "Creat mutex, \"%s\" locked. proc already exit!!!\n", procname); 1389 return 1; 1390 } 1391 } 1392#else 1393 struct flock fl; 1394 fl.l_type = F_WRLCK; 1395 fl.l_start = 0; 1396 fl.l_whence = SEEK_SET; 1397 fl.l_len = 0; 1398 int retChild = fcntl(fd, F_SETLK, &fl); 1399 if (retChild == -1) { 1400 WRITE_LOG(LOG_DEBUG, "File \"%s\" locked. proc already exit!!!\n", bufPath); 1401 uv_fs_close(nullptr, &req, fd, nullptr); 1402 return 1; 1403 } 1404#endif 1405 int rc = 0; 1406 uv_fs_req_cleanup(&req); 1407 rc = uv_fs_ftruncate(nullptr, &req, fd, 0, nullptr); 1408 if (rc == -1) { 1409 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 1410 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 1411 uv_fs_close(nullptr, &req, fd, nullptr); 1412 WRITE_LOG(LOG_FATAL, "ftruncate file %s failed!!! %s", bufPath, buffer); 1413 return ERR_FILE_STAT; 1414 } 1415 uv_buf_t wbf = uv_buf_init(pidBuf, strlen(pidBuf)); 1416 uv_fs_req_cleanup(&req); 1417 rc = uv_fs_write(nullptr, &req, fd, &wbf, 1, 0, nullptr); 1418 if (rc == -1) { 1419 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 1420 uv_strerror_r((int)req.result, buffer, BUF_SIZE_DEFAULT); 1421 uv_fs_close(nullptr, &req, fd, nullptr); 1422 WRITE_LOG(LOG_FATAL, "write file %s failed!!! %s", bufPath, buffer); 1423 return ERR_FILE_WRITE; 1424 } 1425 WRITE_LOG(LOG_DEBUG, "Write mutext to %s, pid:%s", bufPath, pidBuf); 1426 if (checkOrNew) { 1427 // close it for check only 1428 uv_fs_close(nullptr, &req, fd, nullptr); 1429 } 1430 // Do not close the file descriptor, the process will be mutext effect under no-Win32 OS 1431 return RET_SUCCESS; 1432 } 1433 1434 void SplitString(const string &origString, const string &seq, vector<string> &resultStrings) 1435 { 1436 string::size_type p1 = 0; 1437 string::size_type p2 = origString.find(seq); 1438 1439 while (p2 != string::npos) { 1440 if (p2 == p1) { 1441 ++p1; 1442 p2 = origString.find(seq, p1); 1443 continue; 1444 } 1445 resultStrings.push_back(origString.substr(p1, p2 - p1)); 1446 p1 = p2 + seq.size(); 1447 p2 = origString.find(seq, p1); 1448 } 1449 1450 if (p1 != origString.size()) { 1451 resultStrings.push_back(origString.substr(p1)); 1452 } 1453 } 1454 1455 string GetShellPath() 1456 { 1457 struct stat filecheck; 1458 string shellPath = "/bin/sh"; 1459 if (stat(shellPath.c_str(), &filecheck) < 0) { 1460 shellPath = "/system/bin/sh"; 1461 if (stat(shellPath.c_str(), &filecheck) < 0) { 1462 shellPath = "sh"; 1463 } 1464 } 1465 return shellPath; 1466 } 1467 1468 // Not supported on some platforms, Can only be achieved manually 1469 uint64_t HostToNet(uint64_t val) 1470 { 1471 if (htonl(1) == 1) { 1472 return val; 1473 } 1474 int offset = 32; 1475 return ((static_cast<uint64_t>(htonl(val))) << offset) + htonl(val >> offset); 1476 } 1477 1478 uint64_t NetToHost(uint64_t val) 1479 { 1480 if (htonl(1) == 1) { 1481 return val; 1482 } 1483 int offset = 32; 1484 return ((static_cast<uint64_t>(ntohl(val))) << offset) + ntohl(val >> offset); 1485 } 1486 1487 char GetPathSep() 1488 { 1489#ifdef _WIN32 1490 const char sep = '\\'; 1491#else 1492 const char sep = '/'; 1493#endif 1494 return sep; 1495 } 1496 1497 string GetFullFilePath(string &s) 1498 { // cannot use s.rfind(std::filesystem::path::preferred_separator 1499 // remove last sep, and update input 1500 while (s.back() == GetPathSep()) { 1501 s.pop_back(); 1502 } 1503 1504 size_t i = s.rfind(GetPathSep(), s.length()); 1505 if (i != string::npos) { 1506 return (s.substr(i + 1, s.length() - i)); 1507 } 1508 return s; 1509 } 1510 1511 string GetPathWithoutFilename(const string &s) 1512 { 1513 size_t i = s.rfind(GetPathSep(), s.length()); 1514 if (i != string::npos) { 1515 return (s.substr(0, i + 1)); 1516 } 1517 return s; 1518 } 1519 1520 string GetHdcAbsolutePath() 1521 { 1522 char path[BUF_SIZE_DEFAULT4] = { 0 }; 1523 size_t nPathSize = sizeof(path); 1524 int ret = uv_exepath(path, &nPathSize); 1525 if (ret < 0) { 1526 char buf[BUF_SIZE_DEFAULT] = { 0 }; 1527 uv_err_name_r(ret, buf, BUF_SIZE_DEFAULT); 1528 WRITE_LOG(LOG_WARN, "uvexepath ret:%d error:%s", ret, buf); 1529 return ""; 1530 } 1531 1532 return string(path); 1533 } 1534 1535 int CreateSocketPair(int *fds) 1536 { 1537#ifndef _WIN32 1538#ifdef HOST_MAC 1539 int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); 1540 if (ret == 0) { 1541 for (auto i = 0; i < STREAM_SIZE; ++i) { 1542 if (fcntl(fds[i], F_SETFD, FD_CLOEXEC) == -1) { 1543 CloseFd(fds[0]); 1544 CloseFd(fds[1]); 1545 constexpr int bufSize = 1024; 1546 char buf[bufSize] = { 0 }; 1547 strerror_r(errno, buf, bufSize); 1548 WRITE_LOG(LOG_WARN, "fcntl failed to set FD_CLOEXEC: %s", buf); 1549 return -1; 1550 } 1551 } 1552 } 1553 return ret; 1554#else 1555 return socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds); 1556#endif 1557#else 1558 struct sockaddr_in addr; 1559 socklen_t addrlen = sizeof(addr); 1560 int reuse = 1; 1561 if (fds == 0) { 1562 return -1; 1563 } 1564 int listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 1565 if (listener == -1) { 1566 return -2; // -2:sockets error 1567 } 1568 Base::ZeroStruct(addr); 1569 addr.sin_family = AF_INET; 1570 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1571 addr.sin_port = 0; 1572 fds[0] = fds[1] = (int)-1; 1573 do { 1574 if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, (socklen_t)sizeof(reuse))) { 1575 break; 1576 } 1577 if (::bind(listener, (struct sockaddr *)&addr, sizeof(addr))) { 1578 break; 1579 } 1580 if (getsockname(listener, (struct sockaddr *)&addr, &addrlen)) { 1581 break; 1582 } 1583 if (listen(listener, 1)) { 1584 break; 1585 } 1586 fds[0] = socket(AF_INET, SOCK_STREAM, 0); 1587 if (fds[0] == -1) { 1588 break; 1589 } 1590 if (connect(fds[0], (struct sockaddr *)&addr, sizeof(addr)) == -1) { 1591 break; 1592 } 1593 fds[1] = accept(listener, nullptr, nullptr); 1594 if (fds[1] == -1) { 1595 break; 1596 } 1597 closesocket(listener); 1598 return 0; 1599 } while (0); 1600 1601 closesocket(listener); 1602 closesocket(fds[0]); 1603 closesocket(fds[1]); 1604 return -1; 1605#endif 1606 } 1607 1608 void CloseSocketPair(int *fds) 1609 { 1610#ifndef _WIN32 1611 CloseFd(fds[0]); 1612 CloseFd(fds[1]); 1613#else 1614 closesocket(fds[0]); 1615 closesocket(fds[1]); 1616#endif 1617 } 1618 1619 int StringEndsWith(string s, string sub) 1620 { 1621 return s.rfind(sub) == (s.length() - sub.length()) ? 1 : 0; 1622 } 1623 1624 const char *GetFileType(mode_t mode) 1625 { 1626 switch (mode & S_IFMT) { 1627 case S_IFDIR: 1628 return "directory"; 1629 case S_IFLNK: 1630 return "symlink"; 1631 case S_IFREG: 1632 return "regular file"; 1633#ifndef _WIN32 1634 case S_IFBLK: 1635 return "block device"; 1636 case S_IFCHR: 1637 return "character device"; 1638 case S_IFIFO: 1639 return "FIFO/pipe"; 1640 case S_IFSOCK: 1641 return "socket"; 1642#endif 1643 default: 1644 return "Unknown"; 1645 } 1646 } 1647 1648 void BuildErrorString(const char *localPath, const char *op, const char *err, string &str) 1649 { 1650 // avoid to use stringstream 1651 str = op; 1652 str += " "; 1653 str += localPath; 1654 str += " failed, "; 1655 str += err; 1656 } 1657 1658 // Both absolute and relative paths support 1659 bool CheckDirectoryOrPath(const char *localPath, bool pathOrDir, bool readWrite, string &errStr, mode_t &fm) 1660 { 1661 if (pathOrDir) { // filepath 1662 uv_fs_t req; 1663 mode_t mode; 1664 fm = mode_t(~S_IFMT); 1665 int r = uv_fs_lstat(nullptr, &req, localPath, nullptr); 1666 if (r) { 1667 constexpr int bufSize = 1024; 1668 char buf[bufSize] = { 0 }; 1669 uv_strerror_r((int)req.result, buf, bufSize); 1670 BuildErrorString(localPath, "lstat", buf, errStr); 1671 } 1672 1673 mode = req.statbuf.st_mode; 1674 uv_fs_req_cleanup(&req); 1675 1676 if ((r == 0) && (mode & S_IFDIR)) { 1677 fm = S_IFDIR; 1678 } else if ((r == 0) && (mode & S_IFREG)) { // is file 1679 uv_fs_access(nullptr, &req, localPath, readWrite ? R_OK : W_OK, nullptr); 1680 if (req.result) { 1681 const char *op = readWrite ? "access R_OK" : "access W_OK"; 1682 constexpr int bufSize = 1024; 1683 char buf[bufSize] = { 0 }; 1684 uv_strerror_r((int)req.result, buf, bufSize); 1685 BuildErrorString(localPath, op, buf, errStr); 1686 } 1687 uv_fs_req_cleanup(&req); 1688 if (req.result == 0) { 1689 return true; 1690 } 1691 } else if (r == 0) { 1692 const char *type = GetFileType(mode); 1693 errStr = "Not support "; 1694 errStr += type; 1695 errStr += ": "; 1696 errStr += localPath; 1697 } 1698 } else { // dir 1699 errStr = "Not support dir: "; 1700 errStr += localPath; 1701 } 1702 return false; 1703 } 1704 1705 bool TryCreateDirectory(const string &path, string &err) 1706 { 1707 uv_fs_t req; 1708 int r = uv_fs_lstat(nullptr, &req, path.c_str(), nullptr); 1709 mode_t mode = req.statbuf.st_mode; 1710 uv_fs_req_cleanup(&req); 1711 if (r < 0) { 1712 r = uv_fs_mkdir(nullptr, &req, path.c_str(), DEF_FILE_PERMISSION, nullptr); 1713 WRITE_LOG(LOG_DEBUG, "path not exist create dir = %s", path.c_str()); 1714 uv_fs_req_cleanup(&req); 1715 if (r < 0) { 1716 constexpr int bufSize = 1024; 1717 char buf[bufSize] = { 0 }; 1718 uv_strerror_r((int)req.result, buf, bufSize); 1719 WRITE_LOG(LOG_WARN, "create dir %s failed %s", path.c_str(), buf); 1720 err = "Error create directory, path:"; 1721 err += path.c_str(); 1722 return false; 1723 } 1724 } else { 1725 if (!((mode & S_IFMT) == S_IFDIR)) { 1726 WRITE_LOG(LOG_WARN, "%s exist, not directory", path.c_str()); 1727 err = "File exists, path:"; 1728 err += path.c_str(); 1729 return false; 1730 } 1731 } 1732 return true; 1733 } 1734 1735 bool CheckDirectoryOrPath(const char *localPath, bool pathOrDir, bool readWrite) 1736 { 1737 string strUnused; 1738 mode_t mode = mode_t(~S_IFMT); 1739 return CheckDirectoryOrPath(localPath, pathOrDir, readWrite, strUnused, mode); 1740 } 1741 1742 // Using openssl encryption and decryption method, high efficiency; when encrypting more than 64 bytes, 1743 // the carriage return will not be added, and the tail padding 00 is removed when decrypting 1744 // The return value is the length of the string after Base64 1745 int Base64EncodeBuf(const uint8_t *input, const int length, uint8_t *bufOut) 1746 { 1747 return EVP_EncodeBlock(bufOut, input, length); 1748 } 1749 1750 vector<uint8_t> Base64Encode(const uint8_t *input, const int length) 1751 { 1752 vector<uint8_t> retVec; 1753 uint8_t *pBuf = nullptr; 1754 while (true) { 1755 if (static_cast<uint32_t>(length) > HDC_BUF_MAX_BYTES) { 1756 break; 1757 } 1758 int base64Size = length * 1.4 + 256; 1759 if (!(pBuf = new uint8_t[base64Size]())) { 1760 break; 1761 } 1762 int childRet = Base64EncodeBuf(input, length, pBuf); 1763 if (childRet <= 0) { 1764 break; 1765 } 1766 retVec.insert(retVec.begin(), pBuf, pBuf + childRet); 1767 break; 1768 } 1769 if (pBuf) { 1770 delete[] pBuf; 1771 } 1772 1773 return retVec; 1774 } 1775 1776 inline int CalcDecodeLength(const uint8_t *b64input) 1777 { 1778 int len = strlen(reinterpret_cast<char *>(const_cast<uint8_t *>(b64input))); 1779 if (!len) { 1780 return 0; 1781 } 1782 int padding = 0; 1783 if (b64input[len - 1] == '=' && b64input[len - LAST_EQUAL_NUM] == '=') { 1784 // last two chars are = 1785 padding = 2; // 2 : last two chars 1786 } else if (b64input[len - 1] == '=') { 1787 // last char is = 1788 padding = 1; 1789 } 1790 return static_cast<int>(len * DECODE_SCALE - padding); 1791 } 1792 1793 // return -1 error; >0 decode size 1794 int Base64DecodeBuf(const uint8_t *input, const int length, uint8_t *bufOut) 1795 { 1796 int nRetLen = CalcDecodeLength(input); 1797 if (!nRetLen) { 1798 return 0; 1799 } 1800 1801 if (EVP_DecodeBlock(bufOut, input, length) > 0) { 1802 return nRetLen; 1803 } 1804 return 0; 1805 } 1806 1807 string Base64Decode(const uint8_t *input, const int length) 1808 { 1809 string retString; 1810 uint8_t *pBuf = nullptr; 1811 while (true) { 1812 if (static_cast<uint32_t>(length) > HDC_BUF_MAX_BYTES) { 1813 break; 1814 } 1815 // must less than length 1816 if (!(pBuf = new uint8_t[length]())) { 1817 break; 1818 } 1819 int childRet = Base64DecodeBuf(input, length, pBuf); 1820 if (childRet <= 0) { 1821 break; 1822 } 1823 retString = (reinterpret_cast<char *>(pBuf)); 1824 break; 1825 } 1826 if (pBuf) { 1827 delete[] pBuf; 1828 } 1829 return retString; 1830 } 1831 1832 void ReverseBytes(void *start, int size) 1833 { 1834 uint8_t *istart = (uint8_t *)start; 1835 uint8_t *iend = istart + size; 1836 std::reverse(istart, iend); 1837 } 1838 1839 string Convert2HexStr(uint8_t arr[], int length) 1840 { 1841 std::stringstream ss; 1842 const int byteHexStrLen = 2; 1843 for (int i = 0; i < length; i++) { 1844 ss << std::hex << std::setw(byteHexStrLen) << std::setfill('0') 1845 << static_cast<int>(arr[i]); 1846 if (i < length - 1) { 1847 ss << ":"; 1848 } 1849 } 1850 string result = ss.str(); 1851 transform(result.begin(), result.end(), result.begin(), ::toupper); 1852 return result; 1853 } 1854 1855 // clang-format off 1856 const string StringFormat(const char * const formater, ...) 1857 { 1858 va_list vaArgs; 1859 va_start(vaArgs, formater); 1860 string ret = StringFormat(formater, vaArgs); 1861 va_end(vaArgs); 1862 return ret; 1863 } 1864 1865 const string StringFormat(const char * const formater, va_list &vaArgs) 1866 { 1867 std::vector<char> args(GetMaxBufSizeStable()); 1868 const int retSize = vsnprintf_s( 1869 args.data(), GetMaxBufSizeStable(), (args.size() >= 1) ? (args.size() - 1) : 0, formater, vaArgs); 1870 if (retSize < 0) { 1871 return std::string(""); 1872 } else { 1873 return std::string(args.data(), retSize); 1874 } 1875 } 1876 // clang-format on 1877 1878 string GetVersion() 1879 { 1880 const uint8_t a = 'a'; 1881 uint8_t major = (HDC_VERSION_NUMBER >> 28) & 0xff; 1882 uint8_t minor = (HDC_VERSION_NUMBER << 4 >> 24) & 0xff; 1883 uint8_t version = (HDC_VERSION_NUMBER << 12 >> 24) & 0xff; 1884 uint8_t fix = (HDC_VERSION_NUMBER << 20 >> 28) & 0xff; // max 16, tail is p 1885 string ver = StringFormat("%x.%x.%x%c", major, minor, version, a + fix); 1886 return "Ver: " + ver; 1887 } 1888 1889 bool IdleUvTask(uv_loop_t *loop, void *data, uv_idle_cb cb) 1890 { 1891 uv_idle_t *idle = new(std::nothrow) uv_idle_t(); 1892 if (idle == nullptr) { 1893 return false; 1894 } 1895 idle->data = data; 1896 uv_idle_init(loop, idle); 1897 uv_idle_start(idle, cb); 1898 // delete by callback 1899 return true; 1900 } 1901 1902 bool TimerUvTask(uv_loop_t *loop, void *data, uv_timer_cb cb, int repeatTimeout) 1903 { 1904 uv_timer_t *timer = new(std::nothrow) uv_timer_t(); 1905 if (timer == nullptr) { 1906 return false; 1907 } 1908 timer->data = data; 1909 uv_timer_init(loop, timer); 1910 uv_timer_start(timer, cb, 0, repeatTimeout); 1911 // delete by callback 1912 return true; 1913 } 1914 1915 // callback, uint8_t flag, string msg, const void * data 1916 bool DelayDo(uv_loop_t *loop, const int delayMs, const uint8_t flag, string msg, void *data, 1917 std::function<void(const uint8_t, string &, const void *)> cb) 1918 { 1919 struct DelayDoParam { 1920 uv_timer_t handle; 1921 uint8_t flag; 1922 string msg; 1923 void *data; 1924 std::function<void(const uint8_t, string &, const void *)> cb; 1925 }; 1926 auto funcDelayDo = [](uv_timer_t *handle) -> void { 1927 DelayDoParam *st = (DelayDoParam *)handle->data; 1928 st->cb(st->flag, st->msg, st->data); 1929 uv_close((uv_handle_t *)handle, [](uv_handle_t *handle) { 1930 DelayDoParam *st = (DelayDoParam *)handle->data; 1931 delete st; 1932 }); 1933 }; 1934 DelayDoParam *st = new(std::nothrow) DelayDoParam(); 1935 if (st == nullptr) { 1936 return false; 1937 } 1938 st->cb = cb; 1939 st->flag = flag; 1940 st->msg = msg; 1941 st->data = data; 1942 st->handle.data = st; 1943 uv_timer_init(loop, &st->handle); 1944 uv_timer_start(&st->handle, funcDelayDo, delayMs, 0); 1945 return true; 1946 } 1947 1948 string ReplaceAll(string str, const string from, const string to) 1949 { 1950 string::size_type startPos = 0; 1951 while ((startPos = str.find(from, startPos)) != string::npos) { 1952 str.replace(startPos, from.length(), to); 1953 startPos += to.length(); // Handles case where 'to' is a substring of 'from' 1954 } 1955 return str; 1956 } 1957 1958 string CanonicalizeSpecPath(string &src) 1959 { 1960 char resolvedPath[PATH_MAX] = { 0 }; 1961#if defined(_WIN32) 1962 if (!_fullpath(resolvedPath, src.c_str(), PATH_MAX)) { 1963 WRITE_LOG(LOG_FATAL, "_fullpath %s failed", src.c_str()); 1964 return ""; 1965 } 1966#else 1967 if (realpath(src.c_str(), resolvedPath) == nullptr) { 1968 WRITE_LOG(LOG_FATAL, "realpath %s failed", src.c_str()); 1969 return ""; 1970 } 1971#endif 1972 string res(resolvedPath); 1973 return res; 1974 } 1975 1976 string UnicodeToUtf8(const char *src, bool reverse) 1977 { 1978#if defined(_WIN32) 1979 UINT from = CP_ACP; 1980 UINT to = CP_UTF8; 1981 int count = 0; 1982 if (reverse) { 1983 from = CP_UTF8; 1984 to = CP_ACP; 1985 } 1986 count = MultiByteToWideChar(from, 0, src, -1, nullptr, 0); 1987 if (count <= 0) { 1988 DWORD err = GetLastError(); 1989 WRITE_LOG(LOG_FATAL, "MultiByteToWideChar failed %s error:%lu", src, err); 1990 return ""; 1991 } 1992 wchar_t *wstr = new(std::nothrow) wchar_t[count + 1](); 1993 if (wstr == nullptr) { 1994 WRITE_LOG(LOG_FATAL, "new wstr failed count:%d", count); 1995 return ""; 1996 } 1997 count = MultiByteToWideChar(from, 0, src, -1, wstr, count); 1998 if (count <= 0) { 1999 DWORD err = GetLastError(); 2000 WRITE_LOG(LOG_FATAL, "MultiByteToWideChar failed to wstr %s error:%lu", src, err); 2001 delete[] wstr; 2002 return ""; 2003 } 2004 count = WideCharToMultiByte(to, 0, wstr, -1, nullptr, 0, nullptr, nullptr); 2005 if (count <= 0) { 2006 DWORD err = GetLastError(); 2007 WRITE_LOG(LOG_FATAL, "WideCharToMultiByte failed %s error:%lu", wstr, err); 2008 delete[] wstr; 2009 return ""; 2010 } 2011 char *ustr = new(std::nothrow) char[count + 1](); 2012 if (ustr == nullptr) { 2013 WRITE_LOG(LOG_FATAL, "new ustr failed count:%d", count); 2014 delete[] wstr; 2015 return ""; 2016 } 2017 count = WideCharToMultiByte(to, 0, wstr, -1, ustr, count, nullptr, nullptr); 2018 if (count <= 0) { 2019 DWORD err = GetLastError(); 2020 WRITE_LOG(LOG_FATAL, "WideCharToMultiByte failed to ustr %s error:%lu", wstr, err); 2021 delete[] wstr; 2022 delete[] ustr; 2023 return ""; 2024 } 2025 string rc(ustr); 2026 delete[] wstr; 2027 delete[] ustr; 2028 return rc; 2029#else 2030 string rc(src); 2031 return rc; 2032#endif 2033 } 2034 2035 uint8_t CalcCheckSum(const uint8_t *data, int len) 2036 { 2037 uint8_t ret = 0; 2038 for (int i = 0; i < len; ++i) { 2039 ret += data[i]; 2040 } 2041 return ret; 2042 } 2043 2044 uv_os_sock_t DuplicateUvSocket(uv_tcp_t *tcp) 2045 { 2046 uv_os_sock_t dupFd = -1; 2047#ifdef _WIN32 2048 WSAPROTOCOL_INFO info; 2049 ZeroStruct(info); 2050 if (WSADuplicateSocketA(tcp->socket, GetCurrentProcessId(), &info) < 0) { 2051 return dupFd; 2052 } 2053 dupFd = WSASocketA(0, 0, 0, &info, 0, 0); 2054#else 2055 uv_os_fd_t fdOs; 2056 if (uv_fileno((const uv_handle_t *)tcp, &fdOs) < 0) { 2057 return ERR_API_FAIL; 2058 } 2059#ifdef HDC_HOST 2060 dupFd = dup(uv_open_osfhandle(fdOs)); 2061#else 2062 dupFd = fcntl(uv_open_osfhandle(fdOs), F_DUPFD_CLOEXEC, uv_open_osfhandle(fdOs)); 2063#endif // HDC_HOST 2064#endif 2065 return dupFd; 2066 } 2067 2068 string GetCwd() 2069 { 2070 int value = -1; 2071 char path[PATH_MAX] = ""; 2072 size_t size = sizeof(path); 2073 string res; 2074 value = uv_cwd(path, &size); 2075 if (value < 0) { 2076 constexpr int bufSize = 1024; 2077 char buf[bufSize] = { 0 }; 2078 uv_strerror_r(value, buf, bufSize); 2079 WRITE_LOG(LOG_FATAL, "get path failed: %s", buf); 2080 return res; 2081 } 2082 size_t len = 0; 2083 len = strlen(path); 2084 if (len < 1 || len >= PATH_MAX - 1) { 2085 WRITE_LOG(LOG_FATAL, "get path failed: buffer space max"); 2086 return res; 2087 } 2088 if (path[len - 1] != Base::GetPathSep()) { 2089 path[len] = Base::GetPathSep(); 2090 } 2091 res = path; 2092 return res; 2093 } 2094 2095 string GetTmpDir() 2096 { 2097 string res; 2098#ifdef HDC_HOST 2099 int value = -1; 2100 char path[PATH_MAX] = ""; 2101 size_t size = sizeof(path); 2102 value = uv_os_tmpdir(path, &size); 2103 if (value < 0) { 2104 constexpr int bufSize = 1024; 2105 char buf[bufSize] = { 0 }; 2106 uv_strerror_r(value, buf, bufSize); 2107 WRITE_LOG(LOG_FATAL, "get tmppath failed: %s", buf); 2108 return res; 2109 } 2110 if (strlen(path) >= PATH_MAX - 1) { 2111 WRITE_LOG(LOG_FATAL, "get tmppath failed: buffer space max"); 2112 return res; 2113 } 2114 if (path[strlen(path) - 1] != Base::GetPathSep()) { 2115 path[strlen(path)] = Base::GetPathSep(); 2116 } 2117 res = path; 2118#else 2119 res = "/data/local/tmp/"; 2120#endif 2121 return res; 2122 } 2123 2124#ifndef HDC_HILOG 2125 void SetLogCache(bool enable) 2126 { 2127 g_logCache = enable; 2128 } 2129 2130 void RemoveLogFile() 2131 { 2132 if (g_logCache) { 2133 string path = GetLogDirName() + LOG_FILE_NAME; 2134 string bakName = GetLogNameWithTime(); 2135 string bakPath = GetLogDirName() + bakName; 2136 string cachePath = GetLogDirName() + LOG_CACHE_NAME; 2137 if (rename(path.c_str(), bakPath.c_str()) != 0) { 2138 WRITE_LOG(LOG_FATAL, "rename log file failed."); 2139 } 2140 if (rename(cachePath.c_str(), path.c_str()) != 0) { 2141 WRITE_LOG(LOG_FATAL, "rename log cache file failed."); 2142 } 2143 std::thread compressThread(ThreadCompressLog, bakName); 2144 compressThread.detach(); 2145 g_logCache = false; 2146 std::thread removeThread(RemoveOlderLogFiles); 2147 removeThread.detach(); 2148 } 2149 } 2150 2151 void RemoveLogCache() 2152 { 2153 string cachePath = GetLogDirName() + LOG_CACHE_NAME; 2154 unlink(cachePath.c_str()); 2155 } 2156#endif 2157 2158 bool IsRoot() 2159 { 2160#ifdef _WIN32 2161 // reserve 2162 return true; 2163#else 2164 if (getuid() == 0) { 2165 return true; 2166 } 2167#endif 2168 return false; 2169 } 2170 2171 bool IsAbsolutePath(string &path) 2172 { 2173 bool ret = false; 2174#ifdef _WIN32 2175 // shlwapi.h PathIsRelativeA not link in harmony project 2176 // c:\ or UNC path '\\hostname\share\file' 2177 ret = path.find(":\\") == 1 || path.find("\\\\") == 0; 2178#else 2179 ret = path[0] == '/'; 2180#endif 2181 return ret; 2182 } 2183 2184 int CloseFd(int &fd) 2185 { 2186 int rc = 0; 2187 if (fd > 0) { 2188 rc = close(fd); 2189 if (rc < 0) { 2190 char buffer[BUF_SIZE_DEFAULT] = { 0 }; 2191#ifdef _WIN32 2192 strerror_s(buffer, BUF_SIZE_DEFAULT, errno); 2193#else 2194 strerror_r(errno, buffer, BUF_SIZE_DEFAULT); 2195#endif 2196 WRITE_LOG(LOG_WARN, "close fd: %d failed errno:%d %s", fd, errno, buffer); 2197 } else { 2198 fd = -1; 2199 } 2200 } 2201 return rc; 2202 } 2203 2204 void InitProcess(void) 2205 { 2206#ifndef _WIN32 2207 umask(0); 2208 signal(SIGPIPE, SIG_IGN); 2209 signal(SIGCHLD, SIG_IGN); 2210 signal(SIGALRM, SIG_IGN); 2211 signal(SIGTTIN, SIG_IGN); 2212 signal(SIGTTOU, SIG_IGN); 2213 sigemptyset(&g_blockList); 2214 constexpr int crashSignal = 35; 2215 sigaddset(&g_blockList, crashSignal); 2216 sigprocmask(SIG_BLOCK, &g_blockList, nullptr); 2217#endif 2218 } 2219 2220 void DeInitProcess(void) 2221 { 2222#ifndef _WIN32 2223 mode_t writePermission = 022; 2224 umask(writePermission); 2225 signal(SIGPIPE, SIG_DFL); 2226 signal(SIGCHLD, SIG_DFL); 2227 signal(SIGALRM, SIG_DFL); 2228 signal(SIGTTIN, SIG_DFL); 2229 signal(SIGTTOU, SIG_DFL); 2230#endif 2231 } 2232 2233 int ReadFromFd(int fd, void *buf, size_t count) 2234 { 2235#ifdef _WIN32 2236 DWORD bytesRead = 0; 2237 OVERLAPPED ov = {}; 2238 SOCKET s = fd; 2239 BOOL bWriteStat = ReadFile((HANDLE)s, buf, count, &bytesRead, &ov); 2240 if (bWriteStat) { 2241 return bytesRead; 2242 } else { 2243 return -1; 2244 } 2245#else 2246 return TEMP_FAILURE_RETRY(read(fd, buf, count)); 2247#endif 2248 } 2249 2250 int WriteToFd(int fd, const void *buf, size_t count) 2251 { 2252#ifdef _WIN32 2253 DWORD bytesWrite = 0; 2254 OVERLAPPED ov = {}; 2255 SOCKET s = fd; 2256 BOOL bWriteStat = WriteFile((HANDLE)s, buf, count, &bytesWrite, &ov); 2257 if (bWriteStat) { 2258 return 1; 2259 } else { 2260 return -1; 2261 } 2262#else 2263 return TEMP_FAILURE_RETRY(write(fd, buf, count)); 2264#endif 2265 } 2266 2267 bool IsValidIpv4(const std::string& ip) 2268 { 2269 std::vector<int> segments; 2270 std::stringstream ss(ip); 2271 std::string segment; 2272 const int ipCount = 4; 2273 const int maxValue = 255; 2274 2275 // 分解字符串为四部分 2276 while (std::getline(ss, segment, '.')) { 2277 if (segments.size() >= ipCount) { 2278 return false; 2279 } 2280 if (!IsDigitString(segment)) { 2281 return false; 2282 } 2283 int num = std::stoi(segment); 2284 if (num < 0 || num > maxValue) { 2285 return false; 2286 } 2287 if (segment.size() > 1 && segment[0] == '0' && segment != "0") { 2288 return false; 2289 } 2290 segments.push_back(num); 2291 } 2292 // 必须正好有四部分 2293 return segments.size() == ipCount; 2294 } 2295 2296 // Trim from both sides and paired 2297 string &ShellCmdTrim(string &cmd) 2298 { 2299 const string pairedQuot("\"\""); 2300 if (cmd.empty()) { 2301 return cmd; 2302 } 2303 cmd = Trim(cmd); 2304 if (cmd.length() < pairedQuot.length()) { 2305 return cmd; 2306 } 2307 if (*cmd.begin() == '"' && cmd.back() == '"') { 2308 cmd.erase(cmd.begin()); 2309 cmd.pop_back(); 2310 } 2311 return cmd; 2312 } 2313 2314 void TrimSubString(string &str, string substr) 2315 { 2316 std::string::size_type pos = 0; 2317 while ((pos = str.find(substr, pos)) != std::string::npos) { 2318 str.erase(pos, substr.length()); 2319 } 2320 } 2321 // first 16 bytes is tag 2322 // second 16 bytes is length 2323 // flow the value 2324 bool TlvAppend(string &tlv, string tag, string val) 2325 { 2326 if (tag.empty()) { 2327 return false; 2328 } 2329 unsigned int tlen = tag.length(); 2330 if (tlen < TLV_TAG_LEN) { 2331 tag.append(TLV_TAG_LEN - tlen, ' '); 2332 } 2333 tlv.append(tag); 2334 string vallen = std::to_string(val.length()); 2335 unsigned int vlen = vallen.length(); 2336 if (vlen < TLV_VAL_LEN) { 2337 vallen.append(TLV_VAL_LEN - vlen, ' '); 2338 } 2339 tlv.append(vallen); 2340 tlv.append(val); 2341 return true; 2342 } 2343 bool TlvToStringMap(string tlv, std::map<string, string> &tlvmap) 2344 { 2345 if (tlv.length() < TLV_MIN_LEN) { 2346 return false; 2347 } 2348 while (tlv.length() >= TLV_MIN_LEN) { 2349 string tag = tlv.substr(0, TLV_TAG_LEN); 2350 TrimSubString(tag, " "); 2351 tlv.erase(0, TLV_TAG_LEN); 2352 2353 string vallen = tlv.substr(0, TLV_VAL_LEN); 2354 TrimSubString(vallen, " "); 2355 int len = atoi(vallen.c_str()); 2356 if (len < 0) { 2357 return false; 2358 } 2359 tlv.erase(0, TLV_VAL_LEN); 2360 2361 if (tlv.length() < static_cast<uint32_t>(len)) { 2362 return false; 2363 } 2364 string val = tlv.substr(0, len); 2365 tlv.erase(0, len); 2366 2367 tlvmap[tag] = val; 2368 } 2369 return true; 2370 } 2371 2372 // NOTE: This function relies on the caller to guarantee that 2373 // the input parameter is not null and to check the opened handle state. 2374 FILE *Fopen(const char *fileName, const char *mode) 2375 { 2376#ifdef _WIN32 2377 wchar_t resolvedPath[PATH_MAX + 1] = { 0 }; 2378 // windows platform open file with wide char 2379 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; 2380 std::wstring wideFileName = converter.from_bytes(fileName); 2381 std::wstring wideMode = converter.from_bytes(mode); 2382 if (!_wfullpath(resolvedPath, wideFileName.c_str(), PATH_MAX + 1)) { 2383 WRITE_LOG(LOG_FATAL, "_wfullpath %s failed", wideFileName.c_str()); 2384 return nullptr; 2385 } 2386 return _wfopen(resolvedPath, wideMode.c_str()); 2387#else 2388 // unix paltform open file with default char 2389 return fopen(fileName, mode); 2390#endif 2391 } 2392 2393 std::set<uint32_t> g_deletedSessionIdSet; 2394 std::queue<uint32_t> g_deletedSessionIdQueue; 2395 std::mutex g_deletedSessionIdRecordMutex; 2396 void AddDeletedSessionId(uint32_t sessionId) 2397 { 2398 std::lock_guard<std::mutex> lock(g_deletedSessionIdRecordMutex); 2399 if (g_deletedSessionIdSet.find(sessionId) != g_deletedSessionIdSet.end()) { 2400 WRITE_LOG(LOG_INFO, "SessionId:%u is already in the cache", sessionId); 2401 return; 2402 } 2403 WRITE_LOG(LOG_INFO, "AddDeletedSessionId:%u", sessionId); 2404 g_deletedSessionIdSet.insert(sessionId); 2405 g_deletedSessionIdQueue.push(sessionId); 2406 2407 // Delete old records and only save MAX_DELETED_SESSION_ID_RECORD_COUNT records 2408 if (g_deletedSessionIdQueue.size() > MAX_DELETED_SESSION_ID_RECORD_COUNT) { 2409 uint32_t id = g_deletedSessionIdQueue.front(); 2410 WRITE_LOG(LOG_INFO, "g_deletedSessionIdQueue size:%u, g_deletedSessionIdSet size:%u, pop session id:%u", 2411 g_deletedSessionIdQueue.size(), g_deletedSessionIdSet.size(), id); 2412 g_deletedSessionIdQueue.pop(); 2413 g_deletedSessionIdSet.erase(id); 2414 } 2415 } 2416 2417 bool IsSessionDeleted(uint32_t sessionId) 2418 { 2419 std::lock_guard<std::mutex> lock(g_deletedSessionIdRecordMutex); 2420 if (g_deletedSessionIdSet.find(sessionId) != g_deletedSessionIdSet.end()) { 2421 return true; 2422 } 2423 return false; 2424 } 2425} 2426} // namespace Hdc 2427