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