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