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