diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c0dc9d..5f3049b 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" "client.c" "client.h") +add_executable (shell-server "main.c" "server.c" "server.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 e7477bb..c422661 100644 --- a/main.c +++ b/main.c @@ -3,38 +3,31 @@ #include "server.h" -int _tmain(int argc, char *argv[]) { +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) { - if (lstrcmpi(argv[1], TEXT("-s")) == 0) { + if (lstrcmpi(argv[1], TEXT("-c")) == 0) { + return 0; + } + else if (lstrcmpi(argv[1], TEXT("-s")) == 0) { StartShellServer(); return 0; } else { - goto help_message; + PrintHelpMessage(); + return -1; } } - else if (argc == 3) { - if (lstrcmpi(argv[1], TEXT("-c")) == 0) { - StartShellClient(argv[2]); - return 0; - } - // TODO: implement service - else if (lstrcmpi(argv[1], TEXT("-s")) == 0 && lstrcmpi(argv[2], TEXT("-service")) == 0) { - // CreateService - return 0; - } - else { - goto help_message; - } - } else { - goto help_message; + PrintHelpMessage(); + return -1; } return 0; -help_message: - printf("Wrong usage\nUsage: %s [-c {remote ip} | -s [-service]]\n", argv[0]); - return -1; } diff --git a/server.c b/server.c index d406ad8..53b6759 100644 --- a/server.c +++ b/server.c @@ -1,32 +1,77 @@ #include "server.h" #define BUFSIZE 4096 +#define DEFAULT_PORT "50113" #define DEFAULT_BUFLEN 512 -typedef struct PipeThreadInfo_t { - HANDLE Pipe; - SOCKET ClientSocket; -} PipeThreadInfo; +// 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; -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); +SOCKET ClientSocket = INVALID_SOCKET; + +//HANDLE g_hInputFile = NULL; 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() { WSADATA wsaData; struct addrinfo* result = NULL, * ptr = NULL, hints; - int iResult; - - SOCKET ClientSocket = INVALID_SOCKET; SOCKET ListenSocket = INVALID_SOCKET; - /* - * Initialize listening socket - */ + int iResult; // Initialize Winsock iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); @@ -80,87 +125,22 @@ void StartShellServer() { return 1; } - /* - * Process client connection - */ - for (;;) { - // Accepting a client connection - ClientSocket = INVALID_SOCKET; + // Accepting a 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); + // Accept a client socket + ClientSocket = accept(ListenSocket, NULL, NULL); + if (ClientSocket == INVALID_SOCKET) { + printf("accept failed: %d\n", WSAGetLastError()); + closesocket(ListenSocket); + WSACleanup(); + return 1; } - - /* - * Finalization - */ - // TODO: properly close all handles + // No longer needed 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 - */ - // 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 cmd.exe - */ - CreateChildProcess(g_hChildStd_IN_Rd, g_hChildStd_OUT_Wr); - - // 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); - PipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &ReadThreadInfo, 0, NULL); - - WaitForMultipleObjects(2, PipeThreads, TRUE, INFINITE); - - printf("\n->Client disconnected.\n"); -} - -void CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr) +void CreateChildProcess() // Create a child process that uses the previously created pipes for STDIN and STDOUT. { TCHAR szCmdline[] = TEXT("C:\\Windows\\System32\\cmd.exe"); @@ -215,31 +195,36 @@ void CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr) } } -DWORD WINAPI WriteToPipe(LPVOID lpParam) +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 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; - - // 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"); + 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); } else if (iResult == 0) printf("Connection closing...\n"); @@ -249,34 +234,40 @@ DWORD WINAPI WriteToPipe(LPVOID lpParam) 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); -WriteToPipe_end: - // Closing STDIN => cmd.exe exit + // Close the pipe handle so the child process stops reading. + if (!CloseHandle(g_hChildStd_IN_Wr)) ErrorExit(TEXT("StdInWr CloseHandle")); } -DWORD WINAPI ReadFromPipe(LPVOID lpParam) -{ - DWORD dwRead; - CHAR chBuf[BUFSIZE + 1]; +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 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; + HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 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) { @@ -285,7 +276,11 @@ DWORD WINAPI ReadFromPipe(LPVOID lpParam) WSACleanup(); return 1; } + // Write to console + bSuccess = WriteFile(hParentStdOut, chBuf, + dwRead, &dwWritten, NULL); if (!bSuccess) break; + break; } } diff --git a/server.h b/server.h index f1f32fc..249948d 100644 --- a/server.h +++ b/server.h @@ -12,7 +12,11 @@ #include #include -#define DEFAULT_PORT "50113" - // Defined functions -void StartShellServer(); \ No newline at end of file +void StartShellServer(); +void CreatePipes(); +void CreateChildProcess(void); +void WriteToPipe(void); +void ReadFromPipe(void); +void ErrorExit(PCTSTR); +void CreateSocket(); \ No newline at end of file