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