1cc290419Sopenharmony_ci/* 2cc290419Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd. 3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License. 5cc290419Sopenharmony_ci * You may obtain a copy of the License at 6cc290419Sopenharmony_ci * 7cc290419Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8cc290419Sopenharmony_ci * 9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and 13cc290419Sopenharmony_ci * limitations under the License. 14cc290419Sopenharmony_ci */ 15cc290419Sopenharmony_ci#include <cstdio> 16cc290419Sopenharmony_ci#include <cstring> 17cc290419Sopenharmony_ci#include <random> 18cc290419Sopenharmony_ci#include <sstream> 19cc290419Sopenharmony_ci#include <thread> 20cc290419Sopenharmony_ci#include <fcntl.h> 21cc290419Sopenharmony_ci#ifdef _WIN32 22cc290419Sopenharmony_ci#include <synchapi.h> 23cc290419Sopenharmony_ci#include <errhandlingapi.h> 24cc290419Sopenharmony_ci#include <winerror.h> 25cc290419Sopenharmony_ci#include <handleapi.h> 26cc290419Sopenharmony_ci#include <windows.h> 27cc290419Sopenharmony_ci#else 28cc290419Sopenharmony_ci#include <pthread.h> 29cc290419Sopenharmony_ci#endif 30cc290419Sopenharmony_ci#include <unistd.h> 31cc290419Sopenharmony_ci#include <securec.h> 32cc290419Sopenharmony_ci#include "log.h" 33cc290419Sopenharmony_ci 34cc290419Sopenharmony_ciconstexpr uint16_t BUF_SIZE_TINY = 64; 35cc290419Sopenharmony_ciconstexpr uint16_t BUF_SIZE_DEFAULT = 1024; 36cc290419Sopenharmony_ciconstexpr int ERR_API_FAIL = -13000; 37cc290419Sopenharmony_ciconstexpr int ERR_BUF_OVERFLOW = -9998; 38cc290419Sopenharmony_ciconstexpr int ERR_FILE_OPEN = -11000; 39cc290419Sopenharmony_ciconstexpr int ERR_FILE_WRITE = -10996; 40cc290419Sopenharmony_ciconstexpr int ERR_FILE_STAT = -10997; 41cc290419Sopenharmony_ci 42cc290419Sopenharmony_ci#ifdef _WIN32 43cc290419Sopenharmony_ciconstexpr uint16_t BUF_SIZE_SMALL = 256; 44cc290419Sopenharmony_ci#endif 45cc290419Sopenharmony_ci 46cc290419Sopenharmony_ciextern "C" { 47cc290419Sopenharmony_ci static char GetPathSep() 48cc290419Sopenharmony_ci { 49cc290419Sopenharmony_ci#ifdef _WIN32 50cc290419Sopenharmony_ci const char sep = '\\'; 51cc290419Sopenharmony_ci#else 52cc290419Sopenharmony_ci const char sep = '/'; 53cc290419Sopenharmony_ci#endif 54cc290419Sopenharmony_ci return sep; 55cc290419Sopenharmony_ci } 56cc290419Sopenharmony_ci 57cc290419Sopenharmony_ci#ifdef _WIN32 58cc290419Sopenharmony_ci // return value: <0 error; 0 can start new server instance; >0 server already exists 59cc290419Sopenharmony_ci __declspec(dllexport) int ProgramMutex(const char* procname, bool checkOrNew, const char* tmpDir) 60cc290419Sopenharmony_ci { 61cc290419Sopenharmony_ci char bufPath[BUF_SIZE_DEFAULT] = ""; 62cc290419Sopenharmony_ci if (tmpDir == nullptr) { 63cc290419Sopenharmony_ci return ERR_API_FAIL; 64cc290419Sopenharmony_ci } 65cc290419Sopenharmony_ci 66cc290419Sopenharmony_ci if (snprintf_s(bufPath, sizeof(bufPath), sizeof(bufPath) - 1, "%s%c.%s.pid", 67cc290419Sopenharmony_ci tmpDir, GetPathSep(), procname) < 0) { 68cc290419Sopenharmony_ci return ERR_BUF_OVERFLOW; 69cc290419Sopenharmony_ci } 70cc290419Sopenharmony_ci 71cc290419Sopenharmony_ci char pidBuf[BUF_SIZE_TINY] = ""; 72cc290419Sopenharmony_ci int pid = static_cast<int>(getpid()); 73cc290419Sopenharmony_ci if (snprintf_s(pidBuf, sizeof(pidBuf), sizeof(pidBuf) - 1, "%d", pid) < 0) { 74cc290419Sopenharmony_ci return ERR_BUF_OVERFLOW; 75cc290419Sopenharmony_ci } 76cc290419Sopenharmony_ci 77cc290419Sopenharmony_ci FILE *fp = fopen(bufPath, "a+"); 78cc290419Sopenharmony_ci if (fp == nullptr) { 79cc290419Sopenharmony_ci return ERR_FILE_OPEN; 80cc290419Sopenharmony_ci } 81cc290419Sopenharmony_ci 82cc290419Sopenharmony_ci char buf[BUF_SIZE_DEFAULT] = ""; 83cc290419Sopenharmony_ci if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "Global\\%s", procname) < 0) { 84cc290419Sopenharmony_ci fclose(fp); 85cc290419Sopenharmony_ci return ERR_BUF_OVERFLOW; 86cc290419Sopenharmony_ci } 87cc290419Sopenharmony_ci HANDLE hMutex = CreateMutex(nullptr, FALSE, buf); 88cc290419Sopenharmony_ci DWORD dwError = GetLastError(); 89cc290419Sopenharmony_ci if (ERROR_ALREADY_EXISTS == dwError || ERROR_ACCESS_DENIED == dwError) { 90cc290419Sopenharmony_ci fclose(fp); 91cc290419Sopenharmony_ci return 1; 92cc290419Sopenharmony_ci } 93cc290419Sopenharmony_ci if (checkOrNew) { 94cc290419Sopenharmony_ci CloseHandle(hMutex); 95cc290419Sopenharmony_ci } 96cc290419Sopenharmony_ci 97cc290419Sopenharmony_ci int fd = fileno(fp); 98cc290419Sopenharmony_ci int rc = ftruncate(fd, 0); 99cc290419Sopenharmony_ci if (rc == -1) { 100cc290419Sopenharmony_ci fclose(fp); 101cc290419Sopenharmony_ci return ERR_FILE_STAT; 102cc290419Sopenharmony_ci } 103cc290419Sopenharmony_ci rc = fwrite(&pidBuf, sizeof(char), strlen(pidBuf), fp); 104cc290419Sopenharmony_ci if (rc == -1) { 105cc290419Sopenharmony_ci fclose(fp); 106cc290419Sopenharmony_ci return ERR_FILE_WRITE; 107cc290419Sopenharmony_ci } 108cc290419Sopenharmony_ci 109cc290419Sopenharmony_ci if (checkOrNew) { 110cc290419Sopenharmony_ci fclose(fp); 111cc290419Sopenharmony_ci } 112cc290419Sopenharmony_ci 113cc290419Sopenharmony_ci return 0; 114cc290419Sopenharmony_ci } 115cc290419Sopenharmony_ci 116cc290419Sopenharmony_ci#else 117cc290419Sopenharmony_ci // return value: <0 error; 0 can start new server instance; >0 server already exists 118cc290419Sopenharmony_ci int ProgramMutex(const char* procname, bool checkOrNew, const char* tmpDir) 119cc290419Sopenharmony_ci { 120cc290419Sopenharmony_ci char bufPath[BUF_SIZE_DEFAULT] = ""; 121cc290419Sopenharmony_ci if (tmpDir == nullptr) { 122cc290419Sopenharmony_ci return ERR_API_FAIL; 123cc290419Sopenharmony_ci } 124cc290419Sopenharmony_ci 125cc290419Sopenharmony_ci if (snprintf_s(bufPath, sizeof(bufPath), sizeof(bufPath) - 1, "%s%c.%s.pid", 126cc290419Sopenharmony_ci tmpDir, GetPathSep(), procname) < 0) { 127cc290419Sopenharmony_ci return ERR_BUF_OVERFLOW; 128cc290419Sopenharmony_ci } 129cc290419Sopenharmony_ci 130cc290419Sopenharmony_ci char pidBuf[BUF_SIZE_TINY] = ""; 131cc290419Sopenharmony_ci int pid = static_cast<int>(getpid()); 132cc290419Sopenharmony_ci if (snprintf_s(pidBuf, sizeof(pidBuf), sizeof(pidBuf) - 1, "%d", pid) < 0) { 133cc290419Sopenharmony_ci return ERR_BUF_OVERFLOW; 134cc290419Sopenharmony_ci } 135cc290419Sopenharmony_ci 136cc290419Sopenharmony_ci int fd = open(bufPath, O_RDWR | O_CREAT, 0644); // 0644:-rw-r--r-- 137cc290419Sopenharmony_ci if (fd < 0) { 138cc290419Sopenharmony_ci return ERR_FILE_OPEN; 139cc290419Sopenharmony_ci } 140cc290419Sopenharmony_ci 141cc290419Sopenharmony_ci struct flock fl; 142cc290419Sopenharmony_ci fl.l_type = F_WRLCK; 143cc290419Sopenharmony_ci fl.l_start = 0; 144cc290419Sopenharmony_ci fl.l_whence = SEEK_SET; 145cc290419Sopenharmony_ci fl.l_len = 0; 146cc290419Sopenharmony_ci int retChild = fcntl(fd, F_SETLK, &fl); 147cc290419Sopenharmony_ci if (retChild == -1) { 148cc290419Sopenharmony_ci close(fd); 149cc290419Sopenharmony_ci return 1; 150cc290419Sopenharmony_ci } 151cc290419Sopenharmony_ci 152cc290419Sopenharmony_ci int rc = ftruncate(fd, 0); 153cc290419Sopenharmony_ci if (rc == -1) { 154cc290419Sopenharmony_ci close(fd); 155cc290419Sopenharmony_ci return ERR_FILE_STAT; 156cc290419Sopenharmony_ci } 157cc290419Sopenharmony_ci rc = write(fd, &pidBuf, strlen(pidBuf)); 158cc290419Sopenharmony_ci if (rc == -1) { 159cc290419Sopenharmony_ci close(fd); 160cc290419Sopenharmony_ci return ERR_FILE_WRITE; 161cc290419Sopenharmony_ci } 162cc290419Sopenharmony_ci 163cc290419Sopenharmony_ci if (checkOrNew) { 164cc290419Sopenharmony_ci close(fd); 165cc290419Sopenharmony_ci } 166cc290419Sopenharmony_ci 167cc290419Sopenharmony_ci return 0; 168cc290419Sopenharmony_ci } 169cc290419Sopenharmony_ci#endif 170cc290419Sopenharmony_ci 171cc290419Sopenharmony_ci#ifdef _WIN32 172cc290419Sopenharmony_ci__declspec(dllexport) bool LaunchServerWin32(const char *runPath, const char *listenString, int logLevel) 173cc290419Sopenharmony_ci{ 174cc290419Sopenharmony_ci bool retVal = false; 175cc290419Sopenharmony_ci STARTUPINFO si = {}; 176cc290419Sopenharmony_ci PROCESS_INFORMATION pi = {}; 177cc290419Sopenharmony_ci ZeroMemory(&si, sizeof(si)); 178cc290419Sopenharmony_ci ZeroMemory(&pi, sizeof(pi)); 179cc290419Sopenharmony_ci 180cc290419Sopenharmony_ci char buf[BUF_SIZE_SMALL] = ""; 181cc290419Sopenharmony_ci // here we give a dummy option first, because getopt will assume the first option is command. it 182cc290419Sopenharmony_ci // begin from 2nd args. 183cc290419Sopenharmony_ci if (sprintf_s(buf, sizeof(buf), "dummy -b -l %d -s %s -m", logLevel, listenString) < 0) { 184cc290419Sopenharmony_ci return retVal; 185cc290419Sopenharmony_ci } 186cc290419Sopenharmony_ci 187cc290419Sopenharmony_ci si.cb = sizeof(STARTUPINFO); 188cc290419Sopenharmony_ci if (!CreateProcess(runPath, buf, nullptr, nullptr, false, DETACHED_PROCESS, nullptr, nullptr, &si, &pi)) { 189cc290419Sopenharmony_ci retVal = false; 190cc290419Sopenharmony_ci } else { 191cc290419Sopenharmony_ci retVal = true; 192cc290419Sopenharmony_ci } 193cc290419Sopenharmony_ci CloseHandle(pi.hThread); 194cc290419Sopenharmony_ci CloseHandle(pi.hProcess); 195cc290419Sopenharmony_ci return retVal; 196cc290419Sopenharmony_ci} 197cc290419Sopenharmony_ci#endif 198cc290419Sopenharmony_ci} 199cc290419Sopenharmony_ci 200