From 9d71f3343211d31d4e653ac9167ba02b98358775 Mon Sep 17 00:00:00 2001 From: nihonium Date: Sun, 1 Dec 2024 19:58:51 +0300 Subject: [PATCH 1/2] =?UTF-8?q?feat(server):=20=D0=A4=D1=83=D0=BD=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D0=BE=D0=BD=D0=B0=D0=BB=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D0=BD=20=D0=B4=D0=BB=D1=8F=20=D1=82=D0=BE=D0=B3=D0=BE,?= =?UTF-8?q?=20=D1=87=D1=82=D0=BE=D0=B1=20=D0=B2=D0=BF=D0=BE=D1=81=D0=BB?= =?UTF-8?q?=D0=B5=D0=B4=D1=81=D1=82=D0=B2=D0=B8=D0=B8=20=D1=80=D0=B5=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D1=83=20=D1=81=20=D0=BD=D0=B5=D1=81=D0=BA?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=BA=D0=B8=D0=BC=D0=B8=20=D0=BA=D0=BB=D0=B8?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.c | 26 +++++--- server.c | 181 ++++++++++++++++++++++++++----------------------------- server.h | 12 ++-- 3 files changed, 109 insertions(+), 110 deletions(-) diff --git a/main.c b/main.c index c422661..9cddbec 100644 --- a/main.c +++ b/main.c @@ -3,14 +3,11 @@ #include "server.h" -void PrintHelpMessage() { - printf("Usage error: I know 3 arguments \n\t\"install\"\n\t\"delete\"\n\t\"app\"\n"); -} - int _tmain(int argc, TCHAR *argv[]) { - printf("\n->Start of parent execution.\n"); if (argc == 2) { + // TODO: implement client if (lstrcmpi(argv[1], TEXT("-c")) == 0) { + // StartShellClient(); return 0; } else if (lstrcmpi(argv[1], TEXT("-s")) == 0) { @@ -18,16 +15,27 @@ int _tmain(int argc, TCHAR *argv[]) { return 0; } else { - PrintHelpMessage(); - return -1; + goto help_message; } } + else if (argc == 3) { + // TODO: implement service + if (lstrcmpi(argv[1], TEXT("-s")) == 0 && lstrcmpi(argv[2], TEXT("-service")) == 0) { + // CreateService + return 0; + } + else { + goto help_message; + } + } else { - PrintHelpMessage(); - return -1; + goto help_message; } return 0; +help_message: + printf("Wrong usage\nUsage: %s [-c | -s [-service]]\n", argv[0]); + return -1; } diff --git a/server.c b/server.c index 53b6759..646b573 100644 --- a/server.c +++ b/server.c @@ -4,75 +4,44 @@ #define DEFAULT_PORT "50113" #define DEFAULT_BUFLEN 512 -// Handles for child process STDIN and STDOUT -HANDLE g_hChildStd_IN_Rd = NULL; -HANDLE g_hChildStd_IN_Wr = NULL; -HANDLE g_hChildStd_OUT_Rd = NULL; -HANDLE g_hChildStd_OUT_Wr = NULL; +typedef struct PipeThreadInfo_t { + HANDLE Pipe; + SOCKET ClientSocket; +} PipeThreadInfo; -SOCKET ClientSocket = INVALID_SOCKET; - -//HANDLE g_hInputFile = NULL; +void CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr); +DWORD WINAPI WriteToPipe(LPVOID lpParam); +DWORD WINAPI ReadFromPipe(LPVOID lpParam); +void ErrorExit(PCTSTR); void StartShellServer() { printf("\n->Start of shell server execution.\n"); - CreatePipes(); - CreateSocket(); - - // Create the child process. - CreateChildProcess(); - - // TODO: split into threads - WriteToPipe(); - // Read from pipe that is the standard output for child process. - ReadFromPipe(); - - printf("\n->End of shell server execution.\n"); - - // The remaining open handles are cleaned up when this process terminates. - // To avoid resource leaks in a larger application, close handles explicitly. - -} - -void CreatePipes() { - SECURITY_ATTRIBUTES saAttr; - - // Set the bInheritHandle flag so pipe handles are inherited. - - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - // Create a pipe for the child process's STDOUT. - - if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) - ErrorExit(TEXT("StdoutRd CreatePipe")); - - // Ensure the read handle to the pipe for STDOUT is not inherited. - - if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) - ErrorExit(TEXT("Stdout SetHandleInformation")); - - // Create a pipe for the child process's STDIN. - - if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) - ErrorExit(TEXT("Stdin CreatePipe")); - - // Ensure the write handle to the pipe for STDIN is not inherited. - - if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) - ErrorExit(TEXT("Stdin SetHandleInformation")); -} - -// TODO: to review -void CreateSocket() { + /* + * Server variables + */ WSADATA wsaData; struct addrinfo* result = NULL, * ptr = NULL, hints; SOCKET ListenSocket = INVALID_SOCKET; - int iResult; + /* + * Client variables + */ + SOCKET ClientSocket = INVALID_SOCKET; + // Pipe handles for child STDIN/STDOUT + HANDLE g_hChildStd_IN_Rd = NULL; + HANDLE g_hChildStd_IN_Wr = NULL; + HANDLE g_hChildStd_OUT_Rd = NULL; + HANDLE g_hChildStd_OUT_Wr = NULL; + + SECURITY_ATTRIBUTES saAttr; + HANDLE PipeThreads[2]; + + /* + * Initialize listening socket + */ + // Initialize Winsock iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != 0) { @@ -125,6 +94,39 @@ void CreateSocket() { return 1; } + /* + * Initialize pipes + */ + // Set the bInheritHandle flag so pipe handles are inherited. + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + // Create a pipe for the child process's STDOUT. + if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) + ErrorExit(TEXT("StdoutRd CreatePipe")); + + // Ensure the read handle to the pipe for STDOUT is not inherited. + if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) + ErrorExit(TEXT("Stdout SetHandleInformation")); + + // Create a pipe for the child process's STDIN. + if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) + ErrorExit(TEXT("Stdin CreatePipe")); + + // Ensure the write handle to the pipe for STDIN is not inherited. + if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) + ErrorExit(TEXT("Stdin SetHandleInformation")); + + /* + * Create child process + */ + CreateChildProcess(g_hChildStd_IN_Rd, g_hChildStd_OUT_Wr); + + /* + * Process client connection + */ + // Accepting a connection ClientSocket = INVALID_SOCKET; @@ -136,11 +138,24 @@ void CreateSocket() { WSACleanup(); return 1; } - // No longer needed + + PipeThreadInfo WriteThreadInfo = { g_hChildStd_IN_Wr, ClientSocket }; + PipeThreadInfo ReadThreadInfo = { g_hChildStd_OUT_Rd, ClientSocket }; + PipeThreads[0] = CreateThread(NULL, 0, WriteToPipe, &WriteThreadInfo, 0, NULL); + PipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &ReadThreadInfo, 0, NULL); + + WaitForMultipleObjects(2, PipeThreads, TRUE, INFINITE); + + printf("\n->Client disconnected.\n"); + + /* + * Finalization + */ + // TODO: properly close all handles closesocket(ListenSocket); } -void CreateChildProcess() +void CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr) // Create a child process that uses the previously created pipes for STDIN and STDOUT. { TCHAR szCmdline[] = TEXT("C:\\Windows\\System32\\cmd.exe"); @@ -195,36 +210,25 @@ void CreateChildProcess() } } -void WriteToPipe(void) - -// Read from a file and write its contents to the pipe for the child's STDIN. -// Stop when there is no more data. +DWORD WINAPI WriteToPipe(LPVOID lpParam) { DWORD dwRead, dwWritten; - //CHAR chBuf[BUFSIZE] = "dir\r\n"; BOOL bSuccess = FALSE; int i = 0; + SOCKET ClientSocket = ((PipeThreadInfo*)lpParam)->ClientSocket; + HANDLE g_hChildStd_IN_Wr = ((PipeThreadInfo*)lpParam)->Pipe; + char recvbuf[DEFAULT_BUFLEN]; int iResult, iSendResult; int recvbuflen = DEFAULT_BUFLEN; - do { iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); if (iResult > 0) { - printf("Bytes received: %d\n", iResult); - - // Echo the buffer back to the sender - iSendResult = send(ClientSocket, recvbuf, iResult, 0); - if (iSendResult == SOCKET_ERROR) { - printf("send failed: %d\n", WSAGetLastError()); - closesocket(ClientSocket); - WSACleanup(); - return 1; - } - printf("Bytes sent: %d\n", iSendResult); + bSuccess = WriteFile(g_hChildStd_IN_Wr, recvbuf, iResult, &dwWritten, NULL); + if (!bSuccess) break; } else if (iResult == 0) printf("Connection closing...\n"); @@ -234,33 +238,21 @@ void WriteToPipe(void) WSACleanup(); return 1; } - - //dwRead = strlen(chBuf) + 1; - bSuccess = WriteFile(g_hChildStd_IN_Wr, recvbuf, iResult, &dwWritten, NULL); - if (!bSuccess) break; - //break; - //dwRead = strlen(chBuf) + 1; - //bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL); - //if (!bSuccess) break; - ReadFromPipe(); } while (iResult > 0); - // Close the pipe handle so the child process stops reading. - + // Closing STDIN => cmd.exe exit if (!CloseHandle(g_hChildStd_IN_Wr)) ErrorExit(TEXT("StdInWr CloseHandle")); } -void ReadFromPipe(void) - -// Read output from the child process's pipe for STDOUT -// and write to the parent process's pipe for STDOUT. -// Stop when there is no more data. +DWORD WINAPI ReadFromPipe(LPVOID lpParam) { DWORD dwRead, dwWritten; CHAR chBuf[BUFSIZE]; BOOL bSuccess = FALSE; HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + SOCKET ClientSocket = ((PipeThreadInfo*)lpParam)->ClientSocket; + HANDLE g_hChildStd_OUT_Rd = ((PipeThreadInfo*)lpParam)->Pipe; int iSendResult; @@ -280,7 +272,6 @@ void ReadFromPipe(void) bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL); if (!bSuccess) break; - break; } } diff --git a/server.h b/server.h index 249948d..ae27f3e 100644 --- a/server.h +++ b/server.h @@ -14,9 +14,9 @@ // Defined functions void StartShellServer(); -void CreatePipes(); -void CreateChildProcess(void); -void WriteToPipe(void); -void ReadFromPipe(void); -void ErrorExit(PCTSTR); -void CreateSocket(); \ No newline at end of file +//void CreatePipes(); +//void CreateChildProcess(void); +//DWORD WINAPI WriteToPipe(LPVOID lpParam); +//DWORD WINAPI ReadFromPipe(LPVOID lpParam); +//void ErrorExit(PCTSTR); +//void CreateSocket(); \ No newline at end of file From 53cc2a08ce05941a1321d0aab0bcc1bc713299b1 Mon Sep 17 00:00:00 2001 From: nihonium Date: Thu, 12 Dec 2024 23:57:54 +0300 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=D0=A0=D0=B0=D0=B1=D0=BE=D1=87?= =?UTF-8?q?=D0=B0=D1=8F=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8F=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- main.c | 17 ++++---- server.c | 110 ++++++++++++++++++++++++++++--------------------- server.h | 10 ++--- 4 files changed, 74 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f3049b..5c0dc9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ endif() project ("shell-server") # Добавьте источник в исполняемый файл этого проекта. -add_executable (shell-server "main.c" "server.c" "server.h") +add_executable (shell-server "main.c" "server.c" "server.h" "client.c" "client.h") if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET shell-server PROPERTY CXX_STANDARD 20) diff --git a/main.c b/main.c index 9cddbec..e7477bb 100644 --- a/main.c +++ b/main.c @@ -3,14 +3,9 @@ #include "server.h" -int _tmain(int argc, TCHAR *argv[]) { +int _tmain(int argc, char *argv[]) { if (argc == 2) { - // TODO: implement client - if (lstrcmpi(argv[1], TEXT("-c")) == 0) { - // StartShellClient(); - return 0; - } - else if (lstrcmpi(argv[1], TEXT("-s")) == 0) { + if (lstrcmpi(argv[1], TEXT("-s")) == 0) { StartShellServer(); return 0; } @@ -20,8 +15,12 @@ int _tmain(int argc, TCHAR *argv[]) { } else if (argc == 3) { + if (lstrcmpi(argv[1], TEXT("-c")) == 0) { + StartShellClient(argv[2]); + return 0; + } // TODO: implement service - 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 return 0; } @@ -35,7 +34,7 @@ int _tmain(int argc, TCHAR *argv[]) { return 0; help_message: - printf("Wrong usage\nUsage: %s [-c | -s [-service]]\n", argv[0]); + printf("Wrong usage\nUsage: %s [-c {remote ip} | -s [-service]]\n", argv[0]); return -1; } diff --git a/server.c b/server.c index 646b573..d406ad8 100644 --- a/server.c +++ b/server.c @@ -1,7 +1,6 @@ #include "server.h" #define BUFSIZE 4096 -#define DEFAULT_PORT "50113" #define DEFAULT_BUFLEN 512 typedef struct PipeThreadInfo_t { @@ -10,6 +9,7 @@ typedef struct PipeThreadInfo_t { } PipeThreadInfo; void CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr); +DWORD WINAPI WorkWithClient(LPVOID lpParam); DWORD WINAPI WriteToPipe(LPVOID lpParam); DWORD WINAPI ReadFromPipe(LPVOID lpParam); void ErrorExit(PCTSTR); @@ -17,29 +17,15 @@ void ErrorExit(PCTSTR); void StartShellServer() { printf("\n->Start of shell server execution.\n"); - /* - * Server variables - */ WSADATA wsaData; struct addrinfo* result = NULL, * ptr = NULL, hints; - SOCKET ListenSocket = INVALID_SOCKET; int iResult; - /* - * Client variables - */ SOCKET ClientSocket = INVALID_SOCKET; - // Pipe handles for child STDIN/STDOUT - HANDLE g_hChildStd_IN_Rd = NULL; - HANDLE g_hChildStd_IN_Wr = NULL; - HANDLE g_hChildStd_OUT_Rd = NULL; - HANDLE g_hChildStd_OUT_Wr = NULL; + SOCKET ListenSocket = INVALID_SOCKET; - SECURITY_ATTRIBUTES saAttr; - HANDLE PipeThreads[2]; - - /* - * Initialize listening socket + /* + * Initialize listening socket */ // Initialize Winsock @@ -94,6 +80,46 @@ void StartShellServer() { return 1; } + /* + * Process client connection + */ + for (;;) { + // Accepting a client connection + ClientSocket = INVALID_SOCKET; + + ClientSocket = accept(ListenSocket, NULL, NULL); + if (ClientSocket == INVALID_SOCKET) { + printf("accept failed: %d\n", WSAGetLastError()); + break; + } + printf("Client connected\n"); + // Create separate thread to process client connection + CreateThread(NULL, 0, WorkWithClient, ClientSocket, 0, NULL); + } + + /* + * Finalization + */ + // TODO: properly close all handles + closesocket(ListenSocket); + WSACleanup(); +} + +DWORD WINAPI WorkWithClient(LPVOID lpParam) { + /* + * Client variables + */ + // Pipe handles for child STDIN/STDOUT + HANDLE g_hChildStd_IN_Rd = NULL; + HANDLE g_hChildStd_IN_Wr = NULL; + HANDLE g_hChildStd_OUT_Rd = NULL; + HANDLE g_hChildStd_OUT_Wr = NULL; + + SECURITY_ATTRIBUTES saAttr; + HANDLE PipeThreads[2]; + + SOCKET ClientSocket = (SOCKET)lpParam; + /* * Initialize pipes */ @@ -119,26 +145,11 @@ void StartShellServer() { ErrorExit(TEXT("Stdin SetHandleInformation")); /* - * Create child process + * Create child process cmd.exe */ CreateChildProcess(g_hChildStd_IN_Rd, g_hChildStd_OUT_Wr); - - /* - * Process client connection - */ - - // Accepting a connection - ClientSocket = INVALID_SOCKET; - - // Accept a client socket - ClientSocket = accept(ListenSocket, NULL, NULL); - if (ClientSocket == INVALID_SOCKET) { - printf("accept failed: %d\n", WSAGetLastError()); - closesocket(ListenSocket); - WSACleanup(); - return 1; - } + // Create threads for STDIN/STDOUT PipeThreadInfo WriteThreadInfo = { g_hChildStd_IN_Wr, ClientSocket }; PipeThreadInfo ReadThreadInfo = { g_hChildStd_OUT_Rd, ClientSocket }; PipeThreads[0] = CreateThread(NULL, 0, WriteToPipe, &WriteThreadInfo, 0, NULL); @@ -147,12 +158,6 @@ void StartShellServer() { WaitForMultipleObjects(2, PipeThreads, TRUE, INFINITE); printf("\n->Client disconnected.\n"); - - /* - * Finalization - */ - // TODO: properly close all handles - closesocket(ListenSocket); } void CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr) @@ -222,13 +227,19 @@ DWORD WINAPI WriteToPipe(LPVOID lpParam) char recvbuf[DEFAULT_BUFLEN]; int iResult, iSendResult; int recvbuflen = DEFAULT_BUFLEN; - + + // Change codepage to UTF-8 + //CHAR chcpCommand[] = "chcp 65001\n"; + //bSuccess = WriteFile(g_hChildStd_IN_Wr, chcpCommand, strlen(chcpCommand), &dwWritten, NULL); + //if (!bSuccess) goto WriteToPipe_end; + do { iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); if (iResult > 0) { bSuccess = WriteFile(g_hChildStd_IN_Wr, recvbuf, iResult, &dwWritten, NULL); if (!bSuccess) break; + printf("Received command: %s\n"); } else if (iResult == 0) printf("Connection closing...\n"); @@ -240,6 +251,7 @@ DWORD WINAPI WriteToPipe(LPVOID lpParam) } } while (iResult > 0); +WriteToPipe_end: // Closing STDIN => cmd.exe exit if (!CloseHandle(g_hChildStd_IN_Wr)) ErrorExit(TEXT("StdInWr CloseHandle")); @@ -247,19 +259,24 @@ DWORD WINAPI WriteToPipe(LPVOID lpParam) DWORD WINAPI ReadFromPipe(LPVOID lpParam) { - DWORD dwRead, dwWritten; - CHAR chBuf[BUFSIZE]; + DWORD dwRead; + CHAR chBuf[BUFSIZE + 1]; + BOOL bSuccess = FALSE; - HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + //HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE); SOCKET ClientSocket = ((PipeThreadInfo*)lpParam)->ClientSocket; HANDLE g_hChildStd_OUT_Rd = ((PipeThreadInfo*)lpParam)->Pipe; int iSendResult; + for (;;) { bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL); if (!bSuccess || dwRead == 0) break; + printf("STDOUT: %s\n", chBuf); + + chBuf[dwRead] = '\0'; iSendResult = send(ClientSocket, chBuf, dwRead, 0); if (iSendResult == SOCKET_ERROR) { @@ -268,9 +285,6 @@ DWORD WINAPI ReadFromPipe(LPVOID lpParam) WSACleanup(); return 1; } - // Write to console - bSuccess = WriteFile(hParentStdOut, chBuf, - dwRead, &dwWritten, NULL); if (!bSuccess) break; } } diff --git a/server.h b/server.h index ae27f3e..f1f32fc 100644 --- a/server.h +++ b/server.h @@ -12,11 +12,7 @@ #include #include +#define DEFAULT_PORT "50113" + // Defined functions -void StartShellServer(); -//void CreatePipes(); -//void CreateChildProcess(void); -//DWORD WINAPI WriteToPipe(LPVOID lpParam); -//DWORD WINAPI ReadFromPipe(LPVOID lpParam); -//void ErrorExit(PCTSTR); -//void CreateSocket(); \ No newline at end of file +void StartShellServer(); \ No newline at end of file