Skip to content

Issue 105 #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Oct 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ ui_*.h
*.jsc
Makefile*
*build-*
*build_*

# Qt unit tests
target_wrapper.*
Expand Down
4 changes: 2 additions & 2 deletions 3rdparty/gtest/src/gtest-death-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1296,8 +1296,8 @@ static void StackLowerThanAddress(const void* ptr, bool* result) {
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
static bool StackGrowsDown() {
int dummy;
bool result;
int dummy {};
bool result {};
StackLowerThanAddress(&dummy, &result);
return result;
}
Expand Down
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ 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)
else()
add_subdirectory(demo/linux_service/service)
add_subdirectory(demo/linux_service/client)
endif()
endif()

install(
Expand Down
8 changes: 8 additions & 0 deletions demo/linux_service/client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
28 changes: 28 additions & 0 deletions demo/linux_service/client/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/// \brief To create a basic command line program.

#include <stdio.h>
#include <thread>
#include <chrono>

#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;
}
8 changes: 8 additions & 0 deletions demo/linux_service/service/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
34 changes: 34 additions & 0 deletions demo/linux_service/service/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// \brief To create a basic command line program.

#include <stdio.h>
#include <string>
#include <thread>
#include <chrono>

#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<char const *>() + "]").c_str());
}
}
std::this_thread::sleep_for(std::chrono::seconds(3));
}

printf("My Sample Service: Main: Exit\n");
return 0;
}
8 changes: 8 additions & 0 deletions demo/win_service/client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
41 changes: 41 additions & 0 deletions demo/win_service/client/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/// \brief To create a basic Windows command line program.

#include <Windows.h>
#include <tchar.h>
#include <stdio.h>

#include "libipc/ipc.h"

int _tmain (int argc, TCHAR *argv[]) {
_tprintf(_T("My Sample Client: Entry\n"));
ipc::channel ipc_r{ipc::prefix{"Global\\"}, "service ipc r", ipc::receiver};
ipc::channel ipc_w{ipc::prefix{"Global\\"}, "service ipc w", ipc::sender};
while (1) {
if (!ipc_r.reconnect(ipc::receiver)) {
Sleep(1000);
continue;
}
auto msg = ipc_r.recv();
if (msg.empty()) {
_tprintf(_T("My Sample Client: message recv error\n"));
ipc_r.disconnect();
continue;
}
printf("My Sample Client: message recv: [%s]\n", (char const *)msg.data());
for (;;) {
if (!ipc_w.reconnect(ipc::sender)) {
Sleep(1000);
continue;
}
if (ipc_w.send("Copy.")) {
break;
}
_tprintf(_T("My Sample Client: message send error\n"));
ipc_w.disconnect();
Sleep(1000);
}
_tprintf(_T("My Sample Client: message send [Copy]\n"));
}
_tprintf(_T("My Sample Client: Exit\n"));
return 0;
}
8 changes: 8 additions & 0 deletions demo/win_service/service/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
189 changes: 189 additions & 0 deletions demo/win_service/service/main.cpp
Original file line number Diff line number Diff line change
@@ -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 <Windows.h>
#include <tchar.h>
#include <string>

#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{ipc::prefix{"Global\\"}, "service ipc r", ipc::sender};
ipc::channel ipc_w{ipc::prefix{"Global\\"}, "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<char const *>() + "]").c_str());
}
}
Sleep(3000);
}

OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));

return ERROR_SUCCESS;
}
5 changes: 5 additions & 0 deletions include/libipc/def.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,9 @@ struct relat_trait<wr<Rp, Rc, Ts>> {
template <template <typename> class Policy, typename Flag>
struct relat_trait<Policy<Flag>> : relat_trait<Flag> {};

// the prefix tag of a channel
struct prefix {
char const *str;
};

} // namespace ipc
Loading