Initial commit
Первая версия программы - реализовано создание дочернего процесса cmd.exe, создание нужных пайпов и черновая реализация работы по сети
This commit is contained in:
commit
4c6087fe9d
5 changed files with 454 additions and 0 deletions
21
CMakeLists.txt
Normal file
21
CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
# CMakeList.txt: проект CMake для shell-server; включите исходный код и определения,
|
||||
# укажите здесь логику для конкретного проекта.
|
||||
#
|
||||
cmake_minimum_required (VERSION 3.8)
|
||||
|
||||
# Включение горячей перезагрузки для компиляторов MSVC, если поддерживается.
|
||||
if (POLICY CMP0141)
|
||||
cmake_policy(SET CMP0141 NEW)
|
||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
|
||||
endif()
|
||||
|
||||
project ("shell-server")
|
||||
|
||||
# Добавьте источник в исполняемый файл этого проекта.
|
||||
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)
|
||||
endif()
|
||||
|
||||
# TODO: Добавьте тесты и целевые объекты, если это необходимо.
|
61
CMakePresets.json
Normal file
61
CMakePresets.json
Normal file
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "windows-base",
|
||||
"hidden": true,
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"installDir": "${sourceDir}/out/install/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "cl.exe",
|
||||
"CMAKE_CXX_COMPILER": "cl.exe"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-debug",
|
||||
"displayName": "x64 Debug",
|
||||
"inherits": "windows-base",
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-release",
|
||||
"displayName": "x64 Release",
|
||||
"inherits": "x64-debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x86-debug",
|
||||
"displayName": "x86 Debug",
|
||||
"inherits": "windows-base",
|
||||
"architecture": {
|
||||
"value": "x86",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x86-release",
|
||||
"displayName": "x86 Release",
|
||||
"inherits": "x86-debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
33
main.c
Normal file
33
main.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#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) {
|
||||
if (lstrcmpi(argv[1], TEXT("-c")) == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (lstrcmpi(argv[1], TEXT("-s")) == 0) {
|
||||
StartShellServer();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
PrintHelpMessage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
PrintHelpMessage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
317
server.c
Normal file
317
server.c
Normal file
|
@ -0,0 +1,317 @@
|
|||
#include "server.h"
|
||||
|
||||
#define BUFSIZE 4096
|
||||
#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;
|
||||
|
||||
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;
|
||||
SOCKET ListenSocket = INVALID_SOCKET;
|
||||
|
||||
int iResult;
|
||||
|
||||
// Initialize Winsock
|
||||
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (iResult != 0) {
|
||||
printf("WSAStartup failed: %d\n", iResult);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Creating socket
|
||||
ZeroMemory(&hints, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
// Resolve the local address and port to be used by the server
|
||||
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
|
||||
if (iResult != 0) {
|
||||
printf("getaddrinfo failed: %d\n", iResult);
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||
|
||||
if (ListenSocket == INVALID_SOCKET) {
|
||||
printf("Error at socket(): %ld\n", WSAGetLastError());
|
||||
freeaddrinfo(result);
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Binding socket
|
||||
// Setup the TCP listening socket
|
||||
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
|
||||
if (iResult == SOCKET_ERROR) {
|
||||
printf("bind failed with error: %d\n", WSAGetLastError());
|
||||
freeaddrinfo(result);
|
||||
closesocket(ListenSocket);
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
// No longer needed
|
||||
freeaddrinfo(result);
|
||||
|
||||
// Listening socket
|
||||
if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) {
|
||||
printf("Listen failed with error: %ld\n", WSAGetLastError());
|
||||
closesocket(ListenSocket);
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
// No longer needed
|
||||
closesocket(ListenSocket);
|
||||
}
|
||||
|
||||
void CreateChildProcess()
|
||||
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
|
||||
{
|
||||
TCHAR szCmdline[] = TEXT("C:\\Windows\\System32\\cmd.exe");
|
||||
PROCESS_INFORMATION piProcInfo;
|
||||
STARTUPINFO siStartInfo;
|
||||
BOOL bSuccess = FALSE;
|
||||
|
||||
// Set up members of the PROCESS_INFORMATION structure.
|
||||
|
||||
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
// Set up members of the STARTUPINFO structure.
|
||||
// This structure specifies the STDIN and STDOUT handles for redirection.
|
||||
|
||||
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
|
||||
siStartInfo.cb = sizeof(STARTUPINFO);
|
||||
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
|
||||
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
|
||||
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
|
||||
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
// Create the child process.
|
||||
|
||||
bSuccess = CreateProcess(NULL,
|
||||
szCmdline, // command line
|
||||
NULL, // process security attributes
|
||||
NULL, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
0, // creation flags
|
||||
NULL, // use parent's environment
|
||||
NULL, // use parent's current directory
|
||||
&siStartInfo, // STARTUPINFO pointer
|
||||
&piProcInfo); // receives PROCESS_INFORMATION
|
||||
|
||||
// If an error occurs, exit the application.
|
||||
if (!bSuccess)
|
||||
ErrorExit(TEXT("CreateProcess"));
|
||||
else
|
||||
{
|
||||
// Close handles to the child process and its primary thread.
|
||||
// Some applications might keep these handles to monitor the status
|
||||
// of the child process, for example.
|
||||
|
||||
CloseHandle(piProcInfo.hProcess);
|
||||
CloseHandle(piProcInfo.hThread);
|
||||
|
||||
// Close handles to the stdin and stdout pipes no longer needed by the child process.
|
||||
// If they are not explicitly closed, there is no way to recognize that the child process has ended.
|
||||
|
||||
CloseHandle(g_hChildStd_OUT_Wr);
|
||||
CloseHandle(g_hChildStd_IN_Rd);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
else if (iResult == 0)
|
||||
printf("Connection closing...\n");
|
||||
else {
|
||||
printf("recv failed: %d\n", WSAGetLastError());
|
||||
closesocket(ClientSocket);
|
||||
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.
|
||||
|
||||
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 dwRead, dwWritten;
|
||||
CHAR chBuf[BUFSIZE];
|
||||
BOOL bSuccess = FALSE;
|
||||
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
int iSendResult;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
|
||||
if (!bSuccess || dwRead == 0) break;
|
||||
|
||||
iSendResult = send(ClientSocket, chBuf, dwRead, 0);
|
||||
if (iSendResult == SOCKET_ERROR) {
|
||||
printf("send failed: %d\n", WSAGetLastError());
|
||||
closesocket(ClientSocket);
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
// Write to console
|
||||
bSuccess = WriteFile(hParentStdOut, chBuf,
|
||||
dwRead, &dwWritten, NULL);
|
||||
if (!bSuccess) break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorExit(PCTSTR lpszFunction)
|
||||
|
||||
// Format a readable error message, display a message box,
|
||||
// and exit from the application.
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
LPVOID lpDisplayBuf;
|
||||
DWORD dw = GetLastError();
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0, NULL);
|
||||
|
||||
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
|
||||
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
|
||||
StringCchPrintf((LPTSTR)lpDisplayBuf,
|
||||
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
|
||||
TEXT("%s failed with error %d: %s"),
|
||||
lpszFunction, dw, lpMsgBuf);
|
||||
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
|
||||
|
||||
LocalFree(lpMsgBuf);
|
||||
LocalFree(lpDisplayBuf);
|
||||
ExitProcess(1);
|
||||
}
|
22
server.h
Normal file
22
server.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#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 StartShellServer();
|
||||
void CreatePipes();
|
||||
void CreateChildProcess(void);
|
||||
void WriteToPipe(void);
|
||||
void ReadFromPipe(void);
|
||||
void ErrorExit(PCTSTR);
|
||||
void CreateSocket();
|
Loading…
Reference in a new issue