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; - - SECURITY_ATTRIBUTES saAttr; - HANDLE PipeThreads[2]; + SOCKET ListenSocket = INVALID_SOCKET; - /* - * 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