feat: Рабочая версия сервиса
This commit is contained in:
parent
53cc2a08ce
commit
72bf8d917a
6 changed files with 388 additions and 2 deletions
|
@ -12,7 +12,7 @@ endif()
|
||||||
project ("shell-server")
|
project ("shell-server")
|
||||||
|
|
||||||
# Добавьте источник в исполняемый файл этого проекта.
|
# Добавьте источник в исполняемый файл этого проекта.
|
||||||
add_executable (shell-server "main.c" "server.c" "server.h" "client.c" "client.h")
|
add_executable (shell-server "main.c" "server.c" "server.h" "client.c" "client.h" "service.c" "service.h")
|
||||||
|
|
||||||
if (CMAKE_VERSION VERSION_GREATER 3.12)
|
if (CMAKE_VERSION VERSION_GREATER 3.12)
|
||||||
set_property(TARGET shell-server PROPERTY CXX_STANDARD 20)
|
set_property(TARGET shell-server PROPERTY CXX_STANDARD 20)
|
||||||
|
|
135
client.c
Normal file
135
client.c
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
#include "client.h"
|
||||||
|
#include "server.h"
|
||||||
|
|
||||||
|
#define DEFAULT_BUFLEN 512
|
||||||
|
|
||||||
|
SOCKET ConnectSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
DWORD WINAPI ClientWriteToPipe(LPDWORD dummy);
|
||||||
|
DWORD WINAPI ClientReadFromPipe(LPDWORD dummy);
|
||||||
|
|
||||||
|
VOID StartShellClient(TCHAR *ServerIP) {
|
||||||
|
WSADATA wsaData;
|
||||||
|
int iResult;
|
||||||
|
struct addrinfo* result = NULL, *ptr = NULL, hints;
|
||||||
|
|
||||||
|
// Initialize Winsock
|
||||||
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
if (iResult != 0) {
|
||||||
|
printf("WSAStartup failed: %d\n", iResult);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create socket for client
|
||||||
|
|
||||||
|
ZeroMemory(&hints, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
|
||||||
|
// Resolve the server address and port
|
||||||
|
iResult = getaddrinfo(ServerIP, DEFAULT_PORT, &hints, &result);
|
||||||
|
if (iResult != 0) {
|
||||||
|
printf("getaddrinfo failed: %d\n", iResult);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to connect to the first address returned by the call to getaddrinfo
|
||||||
|
ptr = result;
|
||||||
|
|
||||||
|
// Create a SOCKET for connecting to server
|
||||||
|
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
|
||||||
|
ptr->ai_protocol);
|
||||||
|
|
||||||
|
if (ConnectSocket == INVALID_SOCKET) {
|
||||||
|
printf("Error at socket(): %ld\n", WSAGetLastError());
|
||||||
|
freeaddrinfo(result);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to a socket
|
||||||
|
//
|
||||||
|
// Connect to server.
|
||||||
|
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
|
||||||
|
if (iResult == SOCKET_ERROR) {
|
||||||
|
closesocket(ConnectSocket);
|
||||||
|
ConnectSocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(result);
|
||||||
|
|
||||||
|
if (ConnectSocket == INVALID_SOCKET) {
|
||||||
|
printf("Unable to connect to server!\n");
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE threads[2];
|
||||||
|
threads[0] = CreateThread(NULL, 0, ClientWriteToPipe, NULL, 0, NULL);
|
||||||
|
threads[1] = CreateThread(NULL, 0, ClientReadFromPipe, NULL, 0, NULL);
|
||||||
|
|
||||||
|
WaitForMultipleObjects(2, threads, TRUE, INFINITE);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
CloseHandle(threads[i]);
|
||||||
|
|
||||||
|
// Finalize
|
||||||
|
// shutdown the send half of the connection since no more data will be sent
|
||||||
|
iResult = shutdown(ConnectSocket, SD_SEND);
|
||||||
|
if (iResult == SOCKET_ERROR) {
|
||||||
|
printf("shutdown failed: %d\n", WSAGetLastError());
|
||||||
|
closesocket(ConnectSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
closesocket(ConnectSocket);
|
||||||
|
WSACleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI ClientWriteToPipe(LPDWORD dummy) {
|
||||||
|
UNREFERENCED_PARAMETER(dummy);
|
||||||
|
DWORD iResult, dwRead, bSuccess;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
CHAR chBuf[DEFAULT_BUFLEN] = "";
|
||||||
|
|
||||||
|
bSuccess =
|
||||||
|
ReadFile(GetStdHandle(STD_INPUT_HANDLE), chBuf, DEFAULT_BUFLEN, &dwRead, NULL);
|
||||||
|
if (!bSuccess) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iResult = send(ConnectSocket, chBuf, dwRead, 0);
|
||||||
|
if (iResult == SOCKET_ERROR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI ClientReadFromPipe(LPDWORD dummy) {
|
||||||
|
UNREFERENCED_PARAMETER(dummy);
|
||||||
|
DWORD iResult, dwRead, bSuccess;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
CHAR chBuf[DEFAULT_BUFLEN + 1] = "";
|
||||||
|
|
||||||
|
iResult = recv(ConnectSocket, chBuf, DEFAULT_BUFLEN, 0);
|
||||||
|
if (iResult > 0) {
|
||||||
|
chBuf[strlen(chBuf)] = 0;
|
||||||
|
bSuccess = WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), chBuf,
|
||||||
|
strlen(chBuf), &dwRead, NULL);
|
||||||
|
if (!bSuccess) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
client.h
Normal file
16
client.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma comment(lib, "Ws2_32.lib")
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
// Defined functions
|
||||||
|
VOID StartShellClient(TCHAR *ServerIP);
|
72
main.c
72
main.c
|
@ -2,13 +2,31 @@
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
SERVICE_STATUS gSvcStatus;
|
||||||
|
SERVICE_STATUS_HANDLE gSvcStatusHandle;
|
||||||
|
HANDLE ghSvcStopEvent = NULL;
|
||||||
|
HANDLE ghExecuteService = NULL;
|
||||||
|
|
||||||
|
int _tmain(int argc, TCHAR *argv[]) {
|
||||||
|
SERVICE_TABLE_ENTRY DispatchTable[] = {
|
||||||
|
{SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain},
|
||||||
|
{NULL, NULL} };
|
||||||
|
|
||||||
int _tmain(int argc, char *argv[]) {
|
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
if (lstrcmpi(argv[1], TEXT("-s")) == 0) {
|
if (lstrcmpi(argv[1], TEXT("-s")) == 0) {
|
||||||
StartShellServer();
|
StartShellServer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else if (lstrcmpi(argv[1], TEXT("-sc")) == 0) {
|
||||||
|
if (!StartServiceCtrlDispatcher(DispatchTable)) {
|
||||||
|
printf("Error while starting Dispatcher Table : %d\n", GetLastError());
|
||||||
|
ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
|
||||||
|
SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
goto help_message;
|
goto help_message;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +40,7 @@ int _tmain(int argc, char *argv[]) {
|
||||||
// TODO: implement service
|
// TODO: implement service
|
||||||
else if (lstrcmpi(argv[1], TEXT("-s")) == 0 && lstrcmpi(argv[2], TEXT("-service")) == 0) {
|
else if (lstrcmpi(argv[1], TEXT("-s")) == 0 && lstrcmpi(argv[2], TEXT("-service")) == 0) {
|
||||||
// CreateService
|
// CreateService
|
||||||
|
SvcInstall();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -38,3 +57,54 @@ help_message:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR* lpszArgv) {
|
||||||
|
// Register the handler function for the service
|
||||||
|
gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME, SvcCtrlHandler);
|
||||||
|
|
||||||
|
if (!gSvcStatusHandle) {
|
||||||
|
SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These SERVICE_STATUS members remain as set here
|
||||||
|
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||||
|
gSvcStatus.dwServiceSpecificExitCode = 0;
|
||||||
|
|
||||||
|
// Report initial status to the SCM
|
||||||
|
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
|
||||||
|
// Perform service-specific initialization and work.
|
||||||
|
SvcInit(dwArgc, lpszArgv);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI ServerThreadStart(LPDWORD dummy) {
|
||||||
|
UNREFERENCED_PARAMETER(dummy);
|
||||||
|
|
||||||
|
StartShellServer();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SvcInit(DWORD dwArgc, LPTSTR* lpszArgv) {
|
||||||
|
ghSvcStopEvent = CreateEvent(NULL, // default security attributes
|
||||||
|
TRUE, // manual reset event
|
||||||
|
FALSE, // not signaled
|
||||||
|
NULL); // no name
|
||||||
|
|
||||||
|
if (ghSvcStopEvent == NULL) {
|
||||||
|
ReportSvcStatus(SERVICE_STOPPED, GetLastError(), 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report running status when initialization is complete.
|
||||||
|
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
|
||||||
|
|
||||||
|
ghExecuteService = CreateThread(NULL, 0, ServerThreadStart, NULL, 0, NULL);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Check whether to stop the service.
|
||||||
|
WaitForSingleObject(ghSvcStopEvent, INFINITE);
|
||||||
|
TerminateThread(ghExecuteService, 0);
|
||||||
|
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
149
service.c
Normal file
149
service.c
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
|
extern SERVICE_STATUS gSvcStatus;
|
||||||
|
extern SERVICE_STATUS_HANDLE gSvcStatusHandle;
|
||||||
|
extern HANDLE ghSvcStopEvent;
|
||||||
|
|
||||||
|
VOID SvcInstall() {
|
||||||
|
SC_HANDLE schSCManager;
|
||||||
|
SC_HANDLE schService;
|
||||||
|
TCHAR szUnquotedPath[MAX_PATH];
|
||||||
|
|
||||||
|
if (!GetModuleFileName(NULL, szUnquotedPath, MAX_PATH)) {
|
||||||
|
printf("Cannot install service (%d)\n", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCHAR szPath[MAX_PATH];
|
||||||
|
StringCbPrintf(szPath, MAX_PATH, TEXT("\"%s\" -sc"), szUnquotedPath);
|
||||||
|
|
||||||
|
// Get a handle to the SCM database.
|
||||||
|
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||||
|
|
||||||
|
if (NULL == schSCManager) {
|
||||||
|
printf("OpenSCManager failed (%d)\n", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Installing %s as service...\n", szPath);
|
||||||
|
|
||||||
|
schService = CreateService(schSCManager, // SCM database
|
||||||
|
SVCNAME, // name of service
|
||||||
|
SVCNAME, // service name to display
|
||||||
|
SERVICE_ALL_ACCESS, // desired access
|
||||||
|
SERVICE_WIN32_OWN_PROCESS, // service type
|
||||||
|
SERVICE_DEMAND_START, // start type
|
||||||
|
SERVICE_ERROR_NORMAL, // error control type
|
||||||
|
szPath, // path to service's binary
|
||||||
|
NULL, // no load ordering group
|
||||||
|
NULL, // no tag identifier
|
||||||
|
NULL, // no dependencies
|
||||||
|
NULL, // LocalSystem account
|
||||||
|
NULL); // no password
|
||||||
|
|
||||||
|
if (schService == NULL) {
|
||||||
|
printf("CreateService failed (%d)\n", GetLastError());
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf("Service installed successfully\n");
|
||||||
|
|
||||||
|
CloseServiceHandle(schService);
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
|
||||||
|
DWORD dwWaitHint) {
|
||||||
|
static DWORD dwCheckPoint = 1;
|
||||||
|
|
||||||
|
// Fill in the SERVICE_STATUS structure.
|
||||||
|
gSvcStatus.dwCurrentState = dwCurrentState;
|
||||||
|
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
|
||||||
|
gSvcStatus.dwWaitHint = dwWaitHint;
|
||||||
|
|
||||||
|
if (dwCurrentState == SERVICE_START_PENDING)
|
||||||
|
gSvcStatus.dwControlsAccepted = 0;
|
||||||
|
else
|
||||||
|
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||||
|
|
||||||
|
if ((dwCurrentState == SERVICE_RUNNING) ||
|
||||||
|
(dwCurrentState == SERVICE_STOPPED))
|
||||||
|
gSvcStatus.dwCheckPoint = 0;
|
||||||
|
else
|
||||||
|
gSvcStatus.dwCheckPoint = dwCheckPoint++;
|
||||||
|
|
||||||
|
// Report the status of the service to the SCM.
|
||||||
|
SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID WINAPI SvcCtrlHandler(DWORD dwCtrl) {
|
||||||
|
// Handle the requested control code.
|
||||||
|
switch (dwCtrl) {
|
||||||
|
case SERVICE_CONTROL_STOP:
|
||||||
|
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
||||||
|
|
||||||
|
// Signal the service to stop.
|
||||||
|
SetEvent(ghSvcStopEvent);
|
||||||
|
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SvcReportEvent(LPTSTR szFunction) {
|
||||||
|
HANDLE hEventSource;
|
||||||
|
LPCTSTR lpszStrings[2];
|
||||||
|
TCHAR Buffer[80];
|
||||||
|
|
||||||
|
hEventSource = RegisterEventSource(NULL, SVCNAME);
|
||||||
|
|
||||||
|
if (NULL != hEventSource) {
|
||||||
|
StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction,
|
||||||
|
GetLastError());
|
||||||
|
|
||||||
|
lpszStrings[0] = SVCNAME;
|
||||||
|
lpszStrings[1] = Buffer;
|
||||||
|
|
||||||
|
ReportEvent(hEventSource, // event log handle
|
||||||
|
EVENTLOG_ERROR_TYPE, // event type
|
||||||
|
0, // event category
|
||||||
|
SVC_ERROR, // event identifier
|
||||||
|
NULL, // no security identifier
|
||||||
|
2, // size of lpszStrings array
|
||||||
|
0, // no binary data
|
||||||
|
lpszStrings, // array of strings
|
||||||
|
NULL); // no binary data
|
||||||
|
|
||||||
|
DeregisterEventSource(hEventSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SvcRemove(void) {
|
||||||
|
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||||
|
if (!hSCManager) {
|
||||||
|
printf("Error: Can't open Service Control Manager\n");
|
||||||
|
// addLogMessage("Error: Can't open Service Control Manager");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_HANDLE hService = OpenService(hSCManager, SVCNAME, SERVICE_STOP | DELETE);
|
||||||
|
if (!hService) {
|
||||||
|
printf("Error: Can't remove service\n");
|
||||||
|
// addLogMessage("Error: Can't remove service");
|
||||||
|
CloseServiceHandle(hSCManager);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteService(hService);
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
CloseServiceHandle(hSCManager);
|
||||||
|
// addLogMessage("Success remove service!");
|
||||||
|
printf("Service deleted successfully\n");
|
||||||
|
}
|
16
service.h
Normal file
16
service.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
|
||||||
|
#pragma comment(lib, "advapi32.lib")
|
||||||
|
|
||||||
|
#define SVCNAME TEXT("ShellServer")
|
||||||
|
#define SVC_ERROR ((DWORD)0xC0020001L)
|
||||||
|
|
||||||
|
VOID SvcInstall(void);
|
||||||
|
VOID WINAPI SvcCtrlHandler(DWORD);
|
||||||
|
VOID WINAPI SvcMain(DWORD, LPTSTR*);
|
||||||
|
|
||||||
|
VOID ReportSvcStatus(DWORD, DWORD, DWORD);
|
||||||
|
VOID SvcInit(DWORD, LPTSTR*);
|
||||||
|
VOID SvcReportEvent(LPTSTR);
|
Loading…
Reference in a new issue