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