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