From 6e635934c1ec68996bb3f4d5d1172092952d73b5 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 23 Sep 2023 12:47:00 +0800 Subject: [PATCH 01/14] disable warning C4858 --- .gitignore | 1 + src/libipc/waiter.h | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9bca0610..b8573713 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ ui_*.h *.jsc Makefile* *build-* +*build_* # Qt unit tests target_wrapper.* diff --git a/src/libipc/waiter.h b/src/libipc/waiter.h index ee45fe35..bb5b3b34 100644 --- a/src/libipc/waiter.h +++ b/src/libipc/waiter.h @@ -64,12 +64,16 @@ class waiter { } bool notify() noexcept { - std::lock_guard{lock_}; // barrier + { + IPC_UNUSED_ std::lock_guard barrier{lock_}; // barrier + } return cond_.notify(lock_); } bool broadcast() noexcept { - std::lock_guard{lock_}; // barrier + { + IPC_UNUSED_ std::lock_guard barrier{lock_}; // barrier + } return cond_.broadcast(lock_); } From 2d8d6facc32154471f70bb75f7f1f4ec4ca166ed Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 23 Sep 2023 14:03:13 +0800 Subject: [PATCH 02/14] Windows services can communicate with common processes. --- CMakeLists.txt | 4 + demo/win_service/client/CMakeLists.txt | 8 + demo/win_service/client/main.cpp | 28 ++++ demo/win_service/service/CMakeLists.txt | 8 + demo/win_service/service/main.cpp | 189 ++++++++++++++++++++++++ src/libipc/platform/win/mutex.h | 2 +- src/libipc/platform/win/semaphore.h | 2 +- src/libipc/platform/win/shm_win.cpp | 2 +- 8 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 demo/win_service/client/CMakeLists.txt create mode 100644 demo/win_service/client/main.cpp create mode 100644 demo/win_service/service/CMakeLists.txt create mode 100644 demo/win_service/service/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d9b2a57..12cebd4e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,10 @@ if (LIBIPC_BUILD_DEMOS) add_subdirectory(demo/chat) add_subdirectory(demo/msg_que) add_subdirectory(demo/send_recv) + if (MSVC) + add_subdirectory(demo/win_service/service) + add_subdirectory(demo/win_service/client) + endif() endif() install( diff --git a/demo/win_service/client/CMakeLists.txt b/demo/win_service/client/CMakeLists.txt new file mode 100644 index 00000000..2dc03d5a --- /dev/null +++ b/demo/win_service/client/CMakeLists.txt @@ -0,0 +1,8 @@ +project(win_client) + +file(GLOB SRC_FILES ./*.cpp) +file(GLOB HEAD_FILES ./*.h) + +add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES}) + +target_link_libraries(${PROJECT_NAME} ipc) diff --git a/demo/win_service/client/main.cpp b/demo/win_service/client/main.cpp new file mode 100644 index 00000000..fea348e9 --- /dev/null +++ b/demo/win_service/client/main.cpp @@ -0,0 +1,28 @@ +/// \brief To create a basic Windows command line program. + +#include +#include +#include + +#include "libipc/ipc.h" + +int _tmain (int argc, TCHAR *argv[]) { + _tprintf(_T("My Sample Client: Entry\n")); + ipc::channel ipc_r{"service ipc r", ipc::receiver}; + ipc::channel ipc_w{"service ipc w", ipc::sender}; + while (1) { + auto msg = ipc_r.recv(); + if (msg.empty()) { + _tprintf(_T("My Sample Client: message recv error\n")); + return -1; + } + printf("My Sample Client: message recv: [%s]\n", (char const *)msg.data()); + while (!ipc_w.send("Copy.")) { + _tprintf(_T("My Sample Client: message send error\n")); + Sleep(1000); + } + _tprintf(_T("My Sample Client: message send [Copy]\n")); + } + _tprintf(_T("My Sample Client: Exit\n")); + return 0; +} diff --git a/demo/win_service/service/CMakeLists.txt b/demo/win_service/service/CMakeLists.txt new file mode 100644 index 00000000..b7bb3574 --- /dev/null +++ b/demo/win_service/service/CMakeLists.txt @@ -0,0 +1,8 @@ +project(win_service) + +file(GLOB SRC_FILES ./*.cpp) +file(GLOB HEAD_FILES ./*.h) + +add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES}) + +target_link_libraries(${PROJECT_NAME} ipc) diff --git a/demo/win_service/service/main.cpp b/demo/win_service/service/main.cpp new file mode 100644 index 00000000..109c5603 --- /dev/null +++ b/demo/win_service/service/main.cpp @@ -0,0 +1,189 @@ +/// \brief To create a basic Windows Service in C++. +/// \see https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus + +#include +#include +#include + +#include "libipc/ipc.h" + +SERVICE_STATUS g_ServiceStatus = {0}; +SERVICE_STATUS_HANDLE g_StatusHandle = NULL; +HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE; + +VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv); +VOID WINAPI ServiceCtrlHandler (DWORD); +DWORD WINAPI ServiceWorkerThread (LPVOID lpParam); + +#define SERVICE_NAME _T("My Sample Service") + +int _tmain (int argc, TCHAR *argv[]) { + OutputDebugString(_T("My Sample Service: Main: Entry")); + + SERVICE_TABLE_ENTRY ServiceTable[] = { + {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, + {NULL, NULL} + }; + + if (StartServiceCtrlDispatcher (ServiceTable) == FALSE) { + OutputDebugString(_T("My Sample Service: Main: StartServiceCtrlDispatcher returned error")); + return GetLastError (); + } + + OutputDebugString(_T("My Sample Service: Main: Exit")); + return 0; +} + +VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv) { + DWORD Status = E_FAIL; + + OutputDebugString(_T("My Sample Service: ServiceMain: Entry")); + + g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler); + + if (g_StatusHandle == NULL) { + OutputDebugString(_T("My Sample Service: ServiceMain: RegisterServiceCtrlHandler returned error")); + goto EXIT; + } + + // Tell the service controller we are starting + ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus)); + g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwServiceSpecificExitCode = 0; + g_ServiceStatus.dwCheckPoint = 0; + + if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { + OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + + /* + * Perform tasks neccesary to start the service here + */ + OutputDebugString(_T("My Sample Service: ServiceMain: Performing Service Start Operations")); + + // Create stop event to wait on later. + g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL); + if (g_ServiceStopEvent == NULL) { + OutputDebugString(_T("My Sample Service: ServiceMain: CreateEvent(g_ServiceStopEvent) returned error")); + + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = GetLastError(); + g_ServiceStatus.dwCheckPoint = 1; + + if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { + OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + goto EXIT; + } + + // Tell the service controller we are started + g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 0; + + if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { + OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + + // Start the thread that will perform the main task of the service + HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL); + + OutputDebugString(_T("My Sample Service: ServiceMain: Waiting for Worker Thread to complete")); + + // Wait until our worker thread exits effectively signaling that the service needs to stop + WaitForSingleObject (hThread, INFINITE); + + OutputDebugString(_T("My Sample Service: ServiceMain: Worker Thread Stop Event signaled")); + + + /* + * Perform any cleanup tasks + */ + OutputDebugString(_T("My Sample Service: ServiceMain: Performing Cleanup Operations")); + + CloseHandle (g_ServiceStopEvent); + + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 3; + + if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { + OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + +EXIT: + OutputDebugString(_T("My Sample Service: ServiceMain: Exit")); + return; +} + +VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode) { + OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: Entry")); + + switch (CtrlCode) { + case SERVICE_CONTROL_STOP : + + OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SERVICE_CONTROL_STOP Request")); + + if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING) + break; + + /* + * Perform tasks neccesary to stop the service here + */ + + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 4; + + if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { + OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error")); + } + + // This will signal the worker thread to start shutting down + SetEvent (g_ServiceStopEvent); + + break; + + default: + break; + } + + OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: Exit")); +} + +DWORD WINAPI ServiceWorkerThread (LPVOID lpParam) { + OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry")); + ipc::channel ipc_r{"service ipc r", ipc::sender}; + ipc::channel ipc_w{"service ipc w", ipc::receiver}; + + // Periodically check if the service has been requested to stop + while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) { + /* + * Perform main service function here + */ + if (!ipc_r.send("Hello, World!")) { + OutputDebugString(_T("My Sample Service: send failed.")); + } + else { + OutputDebugString(_T("My Sample Service: send [Hello, World!]")); + auto msg = ipc_w.recv(1000); + if (msg.empty()) { + OutputDebugString(_T("My Sample Service: recv error")); + } else { + OutputDebugStringA((std::string{"My Sample Service: recv ["} + msg.get() + "]").c_str()); + } + } + Sleep(3000); + } + + OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit")); + + return ERROR_SUCCESS; +} diff --git a/src/libipc/platform/win/mutex.h b/src/libipc/platform/win/mutex.h index 8ecaf476..97f4a64c 100644 --- a/src/libipc/platform/win/mutex.h +++ b/src/libipc/platform/win/mutex.h @@ -33,7 +33,7 @@ class mutex { bool open(char const *name) noexcept { close(); - h_ = ::CreateMutex(detail::get_sa(), FALSE, ipc::detail::to_tchar(name).c_str()); + h_ = ::CreateMutex(detail::get_sa(), FALSE, ipc::detail::to_tchar(ipc::string{"Global\\"} + name).c_str()); if (h_ == NULL) { ipc::error("fail CreateMutex[%lu]: %s\n", ::GetLastError(), name); return false; diff --git a/src/libipc/platform/win/semaphore.h b/src/libipc/platform/win/semaphore.h index 47fd45d1..b979ba3a 100644 --- a/src/libipc/platform/win/semaphore.h +++ b/src/libipc/platform/win/semaphore.h @@ -32,7 +32,7 @@ class semaphore { close(); h_ = ::CreateSemaphore(detail::get_sa(), static_cast(count), LONG_MAX, - ipc::detail::to_tchar(name).c_str()); + ipc::detail::to_tchar(ipc::string{"Global\\"} + name).c_str()); if (h_ == NULL) { ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name); return false; diff --git a/src/libipc/platform/win/shm_win.cpp b/src/libipc/platform/win/shm_win.cpp index 366e8bd1..be3fd45c 100755 --- a/src/libipc/platform/win/shm_win.cpp +++ b/src/libipc/platform/win/shm_win.cpp @@ -33,7 +33,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) { return nullptr; } HANDLE h; - auto fmt_name = ipc::detail::to_tchar(ipc::string{"__IPC_SHM__"} + name); + auto fmt_name = ipc::detail::to_tchar(ipc::string{"Global\\__IPC_SHM__"} + name); // Opens a named file mapping object. if (mode == open) { h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, fmt_name.c_str()); From b6c25760cfecd921e2293522119fb5005152ac4a Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 23 Sep 2023 14:19:12 +0800 Subject: [PATCH 03/14] Supplement similar demo under linux. --- CMakeLists.txt | 3 ++ demo/linux_service/client/CMakeLists.txt | 8 ++++++ demo/linux_service/client/main.cpp | 28 ++++++++++++++++++ demo/linux_service/service/CMakeLists.txt | 8 ++++++ demo/linux_service/service/main.cpp | 35 +++++++++++++++++++++++ src/libipc/platform/posix/shm_posix.cpp | 4 ++- 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 demo/linux_service/client/CMakeLists.txt create mode 100644 demo/linux_service/client/main.cpp create mode 100644 demo/linux_service/service/CMakeLists.txt create mode 100644 demo/linux_service/service/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 12cebd4e..7e07dd3c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,9 @@ if (LIBIPC_BUILD_DEMOS) if (MSVC) add_subdirectory(demo/win_service/service) add_subdirectory(demo/win_service/client) + else() + add_subdirectory(demo/linux_service/service) + add_subdirectory(demo/linux_service/client) endif() endif() diff --git a/demo/linux_service/client/CMakeLists.txt b/demo/linux_service/client/CMakeLists.txt new file mode 100644 index 00000000..b7d83920 --- /dev/null +++ b/demo/linux_service/client/CMakeLists.txt @@ -0,0 +1,8 @@ +project(linux_client) + +file(GLOB SRC_FILES ./*.cpp) +file(GLOB HEAD_FILES ./*.h) + +add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES}) + +target_link_libraries(${PROJECT_NAME} ipc) diff --git a/demo/linux_service/client/main.cpp b/demo/linux_service/client/main.cpp new file mode 100644 index 00000000..9839be92 --- /dev/null +++ b/demo/linux_service/client/main.cpp @@ -0,0 +1,28 @@ +/// \brief To create a basic command line program. + +#include +#include +#include + +#include "libipc/ipc.h" + +int main(int argc, char *argv[]) { + printf("My Sample Client: Entry\n"); + ipc::channel ipc_r{"service ipc r", ipc::receiver}; + ipc::channel ipc_w{"service ipc w", ipc::sender}; + while (1) { + auto msg = ipc_r.recv(); + if (msg.empty()) { + printf("My Sample Client: message recv error\n"); + return -1; + } + printf("My Sample Client: message recv: [%s]\n", (char const *)msg.data()); + while (!ipc_w.send("Copy.")) { + printf("My Sample Client: message send error\n"); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + printf("My Sample Client: message send [Copy]\n"); + } + printf("My Sample Client: Exit\n"); + return 0; +} diff --git a/demo/linux_service/service/CMakeLists.txt b/demo/linux_service/service/CMakeLists.txt new file mode 100644 index 00000000..a8773377 --- /dev/null +++ b/demo/linux_service/service/CMakeLists.txt @@ -0,0 +1,8 @@ +project(linux_service) + +file(GLOB SRC_FILES ./*.cpp) +file(GLOB HEAD_FILES ./*.h) + +add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES}) + +target_link_libraries(${PROJECT_NAME} ipc) diff --git a/demo/linux_service/service/main.cpp b/demo/linux_service/service/main.cpp new file mode 100644 index 00000000..ec2f4a9a --- /dev/null +++ b/demo/linux_service/service/main.cpp @@ -0,0 +1,35 @@ +/// \brief To create a basic Windows Service in C++. +/// \see https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus + +#include +#include +#include +#include + +#include "libipc/ipc.h" + +int main(int argc, char *argv[]) { + printf("My Sample Service: Main: Entry\n"); + + ipc::channel ipc_r{"service ipc r", ipc::sender}; + ipc::channel ipc_w{"service ipc w", ipc::receiver}; + + while (1) { + if (!ipc_r.send("Hello, World!")) { + printf("My Sample Service: send failed.\n"); + } + else { + printf("My Sample Service: send [Hello, World!]\n"); + auto msg = ipc_w.recv(1000); + if (msg.empty()) { + printf("My Sample Service: recv error\n"); + } else { + printf("%s\n", (std::string{"My Sample Service: recv ["} + msg.get() + "]").c_str()); + } + } + std::this_thread::sleep_for(std::chrono::seconds(3)); + } + + printf("My Sample Service: Main: Exit\n"); + return 0; +} diff --git a/src/libipc/platform/posix/shm_posix.cpp b/src/libipc/platform/posix/shm_posix.cpp index 7f70b070..b0bfdef6 100644 --- a/src/libipc/platform/posix/shm_posix.cpp +++ b/src/libipc/platform/posix/shm_posix.cpp @@ -49,7 +49,9 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) { ipc::error("fail acquire: name is empty\n"); return nullptr; } - ipc::string op_name = ipc::string{"__IPC_SHM__"} + name; + // For portable use, a shared memory object should be identified by name of the form /somename. + // see: https://man7.org/linux/man-pages/man3/shm_open.3.html + ipc::string op_name = ipc::string{"/__IPC_SHM__"} + name; // Open the object for read-write access. int flag = O_RDWR; switch (mode) { From 3824b8f6e22e3656d43597970a46e35d4864e363 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 23 Sep 2023 14:29:00 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/linux_service/service/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo/linux_service/service/main.cpp b/demo/linux_service/service/main.cpp index ec2f4a9a..cf8dec37 100644 --- a/demo/linux_service/service/main.cpp +++ b/demo/linux_service/service/main.cpp @@ -1,5 +1,4 @@ -/// \brief To create a basic Windows Service in C++. -/// \see https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus +/// \brief To create a basic command line program. #include #include From 8064e50bcf72b820264406ded489d0942f42bf81 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 23 Sep 2023 14:31:37 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=A9=BA=E7=99=BD?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/win_service/service/main.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/demo/win_service/service/main.cpp b/demo/win_service/service/main.cpp index 109c5603..d61b08d5 100644 --- a/demo/win_service/service/main.cpp +++ b/demo/win_service/service/main.cpp @@ -75,8 +75,8 @@ VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv) { g_ServiceStatus.dwCheckPoint = 1; if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { - OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); - } + OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); + } goto EXIT; } @@ -87,7 +87,7 @@ VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv) { g_ServiceStatus.dwCheckPoint = 0; if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { - OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); + OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); } // Start the thread that will perform the main task of the service @@ -114,7 +114,7 @@ VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv) { g_ServiceStatus.dwCheckPoint = 3; if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { - OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); + OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error")); } EXIT: @@ -143,8 +143,8 @@ VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode) { g_ServiceStatus.dwCheckPoint = 4; if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { - OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error")); - } + OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error")); + } // This will signal the worker thread to start shutting down SetEvent (g_ServiceStopEvent); From 1753178db8c6681d8db05a780a4a57199a32607b Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 23 Sep 2023 19:15:52 +0800 Subject: [PATCH 06/14] Identify the user group and add the appropriate prefix to the names. --- src/libipc/platform/win/comfortable_prefix.h | 44 ++++++++++++++++++++ src/libipc/platform/win/mutex.h | 4 +- src/libipc/platform/win/semaphore.h | 3 +- src/libipc/platform/win/shm_win.cpp | 3 +- src/libipc/sync/condition.cpp | 5 +++ src/libipc/sync/mutex.cpp | 5 +++ src/libipc/sync/semaphore.cpp | 5 +++ 7 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 src/libipc/platform/win/comfortable_prefix.h diff --git a/src/libipc/platform/win/comfortable_prefix.h b/src/libipc/platform/win/comfortable_prefix.h new file mode 100644 index 00000000..92f7ac18 --- /dev/null +++ b/src/libipc/platform/win/comfortable_prefix.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include "libipc/memory/resource.h" + +namespace ipc { +namespace detail { + +/// \brief This routine returns `true` if the caller's process is a member of the Administrators local group. +/// Caller is NOT expected to be impersonating anyone and is expected to be able to open its own process and process token. +/// \return true - Caller has Administrators local group. +/// false - Caller does not have Administrators local group. +/// \see https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership +inline bool is_user_admin() { + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + PSID AdministratorsGroup; + BOOL b = AllocateAndInitializeSid(&NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdministratorsGroup); + if (b) { + if (!CheckTokenMembership(NULL, AdministratorsGroup, &b)) { + b = FALSE; + } + FreeSid(AdministratorsGroup); + } + return !!(b); +} + +/// \brief Identify the user group and add the appropriate prefix to the string. +/// \see http://msdn.microsoft.com/en-us/library/aa366551(v=VS.85).aspx +/// https://stackoverflow.com/questions/3999157/system-error-0x5-createfilemapping +inline ipc::string make_comfortable_prefix(ipc::string &&txt) { + if (is_user_admin()) { + return ipc::string{"Global\\"} + txt; + } + return txt; +} + +} // namespace detail +} // namespace ipc diff --git a/src/libipc/platform/win/mutex.h b/src/libipc/platform/win/mutex.h index 97f4a64c..49244d8b 100644 --- a/src/libipc/platform/win/mutex.h +++ b/src/libipc/platform/win/mutex.h @@ -9,6 +9,7 @@ #include "to_tchar.h" #include "get_sa.h" +#include "comfortable_prefix.h" namespace ipc { namespace detail { @@ -33,7 +34,8 @@ class mutex { bool open(char const *name) noexcept { close(); - h_ = ::CreateMutex(detail::get_sa(), FALSE, ipc::detail::to_tchar(ipc::string{"Global\\"} + name).c_str()); + h_ = ::CreateMutex(detail::get_sa(), FALSE, + detail::to_tchar(detail::make_comfortable_prefix(name)).c_str()); if (h_ == NULL) { ipc::error("fail CreateMutex[%lu]: %s\n", ::GetLastError(), name); return false; diff --git a/src/libipc/platform/win/semaphore.h b/src/libipc/platform/win/semaphore.h index b979ba3a..39184e97 100644 --- a/src/libipc/platform/win/semaphore.h +++ b/src/libipc/platform/win/semaphore.h @@ -8,6 +8,7 @@ #include "to_tchar.h" #include "get_sa.h" +#include "comfortable_prefix.h" namespace ipc { namespace detail { @@ -32,7 +33,7 @@ class semaphore { close(); h_ = ::CreateSemaphore(detail::get_sa(), static_cast(count), LONG_MAX, - ipc::detail::to_tchar(ipc::string{"Global\\"} + name).c_str()); + detail::to_tchar(detail::make_comfortable_prefix(name)).c_str()); if (h_ == NULL) { ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name); return false; diff --git a/src/libipc/platform/win/shm_win.cpp b/src/libipc/platform/win/shm_win.cpp index be3fd45c..c1718350 100755 --- a/src/libipc/platform/win/shm_win.cpp +++ b/src/libipc/platform/win/shm_win.cpp @@ -13,6 +13,7 @@ #include "to_tchar.h" #include "get_sa.h" +#include "comfortable_prefix.h" namespace { @@ -33,7 +34,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) { return nullptr; } HANDLE h; - auto fmt_name = ipc::detail::to_tchar(ipc::string{"Global\\__IPC_SHM__"} + name); + auto fmt_name = ipc::detail::to_tchar(detail::make_comfortable_prefix("__IPC_SHM__") + name); // Opens a named file mapping object. if (mode == open) { h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, fmt_name.c_str()); diff --git a/src/libipc/sync/condition.cpp b/src/libipc/sync/condition.cpp index 06d90e19..b97d09be 100644 --- a/src/libipc/sync/condition.cpp +++ b/src/libipc/sync/condition.cpp @@ -2,6 +2,7 @@ #include "libipc/condition.h" #include "libipc/utility/pimpl.h" +#include "libipc/utility/log.h" #include "libipc/memory/resource.h" #include "libipc/platform/detail.h" #if defined(IPC_OS_WINDOWS_) @@ -49,6 +50,10 @@ bool condition::valid() const noexcept { } bool condition::open(char const *name) noexcept { + if (name == nullptr || name[0] == '\0') { + ipc::error("fail condition open: name is empty\n"); + return false; + } return impl(p_)->cond_.open(name); } diff --git a/src/libipc/sync/mutex.cpp b/src/libipc/sync/mutex.cpp index 79f1a910..40aad651 100644 --- a/src/libipc/sync/mutex.cpp +++ b/src/libipc/sync/mutex.cpp @@ -2,6 +2,7 @@ #include "libipc/mutex.h" #include "libipc/utility/pimpl.h" +#include "libipc/utility/log.h" #include "libipc/memory/resource.h" #include "libipc/platform/detail.h" #if defined(IPC_OS_WINDOWS_) @@ -49,6 +50,10 @@ bool mutex::valid() const noexcept { } bool mutex::open(char const *name) noexcept { + if (name == nullptr || name[0] == '\0') { + ipc::error("fail mutex open: name is empty\n"); + return false; + } return impl(p_)->lock_.open(name); } diff --git a/src/libipc/sync/semaphore.cpp b/src/libipc/sync/semaphore.cpp index 23f6bdce..33539f10 100644 --- a/src/libipc/sync/semaphore.cpp +++ b/src/libipc/sync/semaphore.cpp @@ -2,6 +2,7 @@ #include "libipc/semaphore.h" #include "libipc/utility/pimpl.h" +#include "libipc/utility/log.h" #include "libipc/memory/resource.h" #include "libipc/platform/detail.h" #if defined(IPC_OS_WINDOWS_) @@ -47,6 +48,10 @@ bool semaphore::valid() const noexcept { } bool semaphore::open(char const *name, std::uint32_t count) noexcept { + if (name == nullptr || name[0] == '\0') { + ipc::error("fail semaphore open: name is empty\n"); + return false; + } return impl(p_)->sem_.open(name, count); } From e99fe22e9c27005a43db2a94ee36fd3f7a1591e0 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 23 Sep 2023 21:38:47 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E5=BE=AE=E8=B0=83=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/libipc/ipc.h | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/include/libipc/ipc.h b/include/libipc/ipc.h index 882367c8..99a6b100 100755 --- a/include/libipc/ipc.h +++ b/include/libipc/ipc.h @@ -169,26 +169,22 @@ template using chan = chan_wrapper>; /** - * class route + * \class route * - * You could use one producer/server/sender for sending messages to a route, - * then all the consumers/clients/receivers which are receiving with this route, - * would receive your sent messages. - * - * A route could only be used in 1 to N - * (one producer/writer to multi consumers/readers) + * \note You could use one producer/server/sender for sending messages to a route, + * then all the consumers/clients/receivers which are receiving with this route, + * would receive your sent messages. + * A route could only be used in 1 to N (one producer/writer to multi consumers/readers). */ - using route = chan; /** - * class channel + * \class channel * - * You could use multi producers/writers for sending messages to a channel, - * then all the consumers/readers which are receiving with this channel, - * would receive your sent messages. + * \note You could use multi producers/writers for sending messages to a channel, + * then all the consumers/readers which are receiving with this channel, + * would receive your sent messages. */ - using channel = chan; } // namespace ipc From 6d4cf141325acbdcd565a7d55e109285c63f45fc Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 24 Sep 2023 14:25:46 +0800 Subject: [PATCH 08/14] Check illegal parameter. --- src/libipc/shm.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libipc/shm.cpp b/src/libipc/shm.cpp index 92f96ef4..c8763a84 100755 --- a/src/libipc/shm.cpp +++ b/src/libipc/shm.cpp @@ -5,6 +5,7 @@ #include "libipc/shm.h" #include "libipc/utility/pimpl.h" +#include "libipc/utility/log.h" #include "libipc/memory/resource.h" namespace ipc { @@ -68,8 +69,17 @@ void handle::sub_ref() noexcept { } bool handle::acquire(char const * name, std::size_t size, unsigned mode) { + if (name == nullptr || name[0] == '\0') { + ipc::error("fail acquire: name is empty\n"); + return false; + } + if (size == 0) { + ipc::error("fail acquire: size is 0\n"); + return false; + } release(); - impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode); + impl(p_)->n_ = name; + impl(p_)->id_ = shm::acquire(name, size, mode); impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_)); return valid(); } From 21648c5f47c46ecd41fc4941bc6495d5f9ebab37 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 24 Sep 2023 15:42:10 +0800 Subject: [PATCH 09/14] Add a user interface with a custom name prefix. --- include/libipc/def.h | 5 + include/libipc/ipc.h | 10 + src/libipc/circ/elem_array.h | 4 +- src/libipc/ipc.cpp | 188 +++++++++++-------- src/libipc/memory/resource.h | 20 ++ src/libipc/platform/detail.h | 3 +- src/libipc/platform/posix/shm_posix.cpp | 13 +- src/libipc/platform/win/comfortable_prefix.h | 44 ----- src/libipc/platform/win/condition.h | 2 +- src/libipc/platform/win/mutex.h | 4 +- src/libipc/platform/win/semaphore.h | 3 +- src/libipc/platform/win/shm_win.cpp | 3 +- src/libipc/platform/win/to_tchar.h | 4 +- 13 files changed, 160 insertions(+), 143 deletions(-) delete mode 100644 src/libipc/platform/win/comfortable_prefix.h diff --git a/include/libipc/def.h b/include/libipc/def.h index 8c1a72ba..45cd7801 100755 --- a/include/libipc/def.h +++ b/include/libipc/def.h @@ -65,4 +65,9 @@ struct relat_trait> { template