/* * Copyright (C) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #ifdef _WIN32 #include #include #include #include #include #else #include #endif #include #include #include "log.h" constexpr uint16_t BUF_SIZE_TINY = 64; constexpr uint16_t BUF_SIZE_DEFAULT = 1024; constexpr int ERR_API_FAIL = -13000; constexpr int ERR_BUF_OVERFLOW = -9998; constexpr int ERR_FILE_OPEN = -11000; constexpr int ERR_FILE_WRITE = -10996; constexpr int ERR_FILE_STAT = -10997; #ifdef _WIN32 constexpr uint16_t BUF_SIZE_SMALL = 256; #endif extern "C" { static char GetPathSep() { #ifdef _WIN32 const char sep = '\\'; #else const char sep = '/'; #endif return sep; } #ifdef _WIN32 // return value: <0 error; 0 can start new server instance; >0 server already exists __declspec(dllexport) int ProgramMutex(const char* procname, bool checkOrNew, const char* tmpDir) { char bufPath[BUF_SIZE_DEFAULT] = ""; if (tmpDir == nullptr) { return ERR_API_FAIL; } if (snprintf_s(bufPath, sizeof(bufPath), sizeof(bufPath) - 1, "%s%c.%s.pid", tmpDir, GetPathSep(), procname) < 0) { return ERR_BUF_OVERFLOW; } char pidBuf[BUF_SIZE_TINY] = ""; int pid = static_cast(getpid()); if (snprintf_s(pidBuf, sizeof(pidBuf), sizeof(pidBuf) - 1, "%d", pid) < 0) { return ERR_BUF_OVERFLOW; } FILE *fp = fopen(bufPath, "a+"); if (fp == nullptr) { return ERR_FILE_OPEN; } char buf[BUF_SIZE_DEFAULT] = ""; if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "Global\\%s", procname) < 0) { fclose(fp); return ERR_BUF_OVERFLOW; } HANDLE hMutex = CreateMutex(nullptr, FALSE, buf); DWORD dwError = GetLastError(); if (ERROR_ALREADY_EXISTS == dwError || ERROR_ACCESS_DENIED == dwError) { fclose(fp); return 1; } if (checkOrNew) { CloseHandle(hMutex); } int fd = fileno(fp); int rc = ftruncate(fd, 0); if (rc == -1) { fclose(fp); return ERR_FILE_STAT; } rc = fwrite(&pidBuf, sizeof(char), strlen(pidBuf), fp); if (rc == -1) { fclose(fp); return ERR_FILE_WRITE; } if (checkOrNew) { fclose(fp); } return 0; } #else // return value: <0 error; 0 can start new server instance; >0 server already exists int ProgramMutex(const char* procname, bool checkOrNew, const char* tmpDir) { char bufPath[BUF_SIZE_DEFAULT] = ""; if (tmpDir == nullptr) { return ERR_API_FAIL; } if (snprintf_s(bufPath, sizeof(bufPath), sizeof(bufPath) - 1, "%s%c.%s.pid", tmpDir, GetPathSep(), procname) < 0) { return ERR_BUF_OVERFLOW; } char pidBuf[BUF_SIZE_TINY] = ""; int pid = static_cast(getpid()); if (snprintf_s(pidBuf, sizeof(pidBuf), sizeof(pidBuf) - 1, "%d", pid) < 0) { return ERR_BUF_OVERFLOW; } int fd = open(bufPath, O_RDWR | O_CREAT, 0644); // 0644:-rw-r--r-- if (fd < 0) { return ERR_FILE_OPEN; } struct flock fl; fl.l_type = F_WRLCK; fl.l_start = 0; fl.l_whence = SEEK_SET; fl.l_len = 0; int retChild = fcntl(fd, F_SETLK, &fl); if (retChild == -1) { close(fd); return 1; } int rc = ftruncate(fd, 0); if (rc == -1) { close(fd); return ERR_FILE_STAT; } rc = write(fd, &pidBuf, strlen(pidBuf)); if (rc == -1) { close(fd); return ERR_FILE_WRITE; } if (checkOrNew) { close(fd); } return 0; } #endif #ifdef _WIN32 __declspec(dllexport) bool LaunchServerWin32(const char *runPath, const char *listenString, int logLevel) { bool retVal = false; STARTUPINFO si = {}; PROCESS_INFORMATION pi = {}; ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi)); char buf[BUF_SIZE_SMALL] = ""; // here we give a dummy option first, because getopt will assume the first option is command. it // begin from 2nd args. if (sprintf_s(buf, sizeof(buf), "dummy -b -l %d -s %s -m", logLevel, listenString) < 0) { return retVal; } si.cb = sizeof(STARTUPINFO); if (!CreateProcess(runPath, buf, nullptr, nullptr, false, DETACHED_PROCESS, nullptr, nullptr, &si, &pi)) { retVal = false; } else { retVal = true; } CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return retVal; } #endif }