public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Yaniv Kaul <ykaul@redhat.com>
To: Michael Goldish <mgoldish@redhat.com>
Cc: autotest@test.kernel.org, kvm@vger.kernel.org
Subject: Re: [KVM-AUTOTEST PATCH] [RFC] KVM test: rss.cpp: add file transfer support
Date: Thu, 24 Jun 2010 14:25:31 +0300	[thread overview]
Message-ID: <4C2340AB.6040105@redhat.com> (raw)
In-Reply-To: <1277377432-32756-1-git-send-email-mgoldish@redhat.com>

  On 6/24/2010 2:03 PM, Michael Goldish wrote:
> Enable RSS to send/receive files and directory trees (recursively).

Are you slowly developing a competitor to STAF 
(http://staf.sourceforge.net/) ?
And re. the file transfer protocol, why not use TFTP, instead of 
creating your own protocol?
Y.

> See protocol details in rss.cpp.
>
> Signed-off-by: Michael Goldish<mgoldish@redhat.com>
> ---
>   client/tests/kvm/deps/rss.cpp | 1429 ++++++++++++++++++++++++++++-------------
>   1 files changed, 970 insertions(+), 459 deletions(-)
>
> diff --git a/client/tests/kvm/deps/rss.cpp b/client/tests/kvm/deps/rss.cpp
> index 66d9a5b..b2f6049 100644
> --- a/client/tests/kvm/deps/rss.cpp
> +++ b/client/tests/kvm/deps/rss.cpp
> @@ -1,459 +1,970 @@
> -// Simple remote shell server
> -// Author: Michael Goldish<mgoldish@redhat.com>
> -// Much of the code here was adapted from Microsoft code samples.
> -
> -// Usage: rss.exe [port]
> -// If no port is specified the default is 22.
> -
> -#define _WIN32_WINNT 0x0500
> -
> -#include<windows.h>
> -#include<winsock2.h>
> -#include<stdio.h>
> -
> -#pragma comment(lib, "ws2_32.lib")
> -
> -int port = 22;
> -
> -HWND hMainWindow = NULL;
> -HWND hTextBox = NULL;
> -
> -struct client_info {
> -    SOCKET socket;
> -    sockaddr_in addr;
> -    int pid;
> -    HWND hwnd;
> -    HANDLE hJob;
> -    HANDLE hChildOutputRead;
> -    HANDLE hThreadChildToSocket;
> -};
> -
> -void ExitOnError(char *message, BOOL winsock = 0)
> -{
> -    LPVOID system_message;
> -    char buffer[512];
> -
> -    int error_code;
> -    if (winsock)
> -        error_code = WSAGetLastError();
> -    else
> -        error_code = GetLastError();
> -
> -    WSACleanup();
> -
> -    FormatMessage(
> -        FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
> -        NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
> -        (LPTSTR)&system_message, 0, NULL);
> -
> -    sprintf(buffer,
> -            "%s!\n"
> -            "Error code = %d\n"
> -            "Error message = %s",
> -            message, error_code, (char *)system_message);
> -
> -    MessageBox(hMainWindow, buffer, "Error", MB_OK | MB_ICONERROR);
> -
> -    LocalFree(system_message);
> -    ExitProcess(1);
> -}
> -
> -void AppendMessage(char *message)
> -{
> -    int length = GetWindowTextLength(hTextBox);
> -    SendMessage(hTextBox, EM_SETSEL, (WPARAM)length, (LPARAM)length);
> -    SendMessage(hTextBox, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)message);
> -}
> -
> -void FormatStringForPrinting(char *dst, char *src, int size)
> -{
> -    int j = 0;
> -
> -    for (int i = 0; i<  size&&  src[i]; i++) {
> -        if (src[i] == '\n') {
> -            dst[j++] = '\\';
> -            dst[j++] = 'n';
> -        } else if (src[i] == '\r') {
> -            dst[j++] = '\\';
> -            dst[j++] = 'r';
> -        } else if (src[i] == '\t') {
> -            dst[j++] = '\\';
> -            dst[j++] = 't';
> -        } else if (src[i] == '\\') {
> -            dst[j++] = '\\';
> -            dst[j++] = '\\';
> -        } else dst[j++] = src[i];
> -    }
> -    dst[j] = 0;
> -}
> -
> -char* GetClientIPAddress(client_info *ci)
> -{
> -    char *address = inet_ntoa(ci->addr.sin_addr);
> -    if (address)
> -        return address;
> -    else
> -        return "unknown";
> -}
> -
> -DWORD WINAPI ChildToSocket(LPVOID client_info_ptr)
> -{
> -    char buffer[1024], message[1024];
> -    client_info ci;
> -    DWORD bytes_read;
> -    int bytes_sent;
> -
> -    memcpy(&ci, client_info_ptr, sizeof(ci));
> -
> -    while (1) {
> -        // Read data from the child's STDOUT/STDERR pipes
> -        if (!ReadFile(ci.hChildOutputRead,
> -                      buffer, sizeof(buffer),
> -&bytes_read, NULL) || !bytes_read) {
> -            if (GetLastError() == ERROR_BROKEN_PIPE)
> -                break; // Pipe done -- normal exit path
> -            else
> -                ExitOnError("ReadFile failed"); // Something bad happened
> -        }
> -        // Send data to the client
> -        bytes_sent = send(ci.socket, buffer, bytes_read, 0);
> -        /*
> -        // Make sure all the data was sent
> -        if (bytes_sent != bytes_read) {
> -            sprintf(message,
> -                    "ChildToSocket: bytes read (%d) != bytes sent (%d)",
> -                    bytes_read, bytes_sent);
> -            ExitOnError(message, 1);
> -        }
> -        */
> -    }
> -
> -    AppendMessage("Child exited\r\n");
> -    shutdown(ci.socket, SD_BOTH);
> -
> -    return 0;
> -}
> -
> -DWORD WINAPI SocketToChild(LPVOID client_info_ptr)
> -{
> -    char buffer[256], formatted_buffer[768];
> -    char message[1024], client_info_str[256];
> -    client_info ci;
> -    DWORD bytes_written;
> -    int bytes_received;
> -
> -    memcpy(&ci, client_info_ptr, sizeof(ci));
> -
> -    sprintf(client_info_str, "address %s, port %d",
> -            GetClientIPAddress(&ci), ci.addr.sin_port);
> -
> -    sprintf(message, "New client connected (%s)\r\n", client_info_str);
> -    AppendMessage(message);
> -
> -    while (1) {
> -        // Receive data from the socket
> -        ZeroMemory(buffer, sizeof(buffer));
> -        bytes_received = recv(ci.socket, buffer, sizeof(buffer), 0);
> -        if (bytes_received<= 0)
> -            break;
> -        // Report the data received
> -        FormatStringForPrinting(formatted_buffer, buffer, sizeof(buffer));
> -        sprintf(message, "Client (%s) entered text: \"%s\"\r\n",
> -                client_info_str, formatted_buffer);
> -        AppendMessage(message);
> -        // Send the data as a series of WM_CHAR messages to the console window
> -        for (int i=0; i<bytes_received; i++) {
> -            SendMessage(ci.hwnd, WM_CHAR, (WPARAM)buffer[i], 0);
> -            SendMessage(ci.hwnd, WM_SETFOCUS, 0, 0);
> -        }
> -    }
> -
> -    sprintf(message, "Client disconnected (%s)\r\n", client_info_str);
> -    AppendMessage(message);
> -
> -    // Attempt to terminate the child's process tree:
> -    // Using taskkill (where available)
> -    sprintf(buffer, "taskkill /PID %d /T /F", ci.pid);
> -    system(buffer);
> -    // .. and using TerminateJobObject()
> -    TerminateJobObject(ci.hJob, 0);
> -    // Wait for the ChildToSocket thread to terminate
> -    WaitForSingleObject(ci.hThreadChildToSocket, 10000);
> -    // In case the thread refuses to exit -- terminate it
> -    TerminateThread(ci.hThreadChildToSocket, 0);
> -    // Close the socket
> -    shutdown(ci.socket, SD_BOTH);
> -    closesocket(ci.socket);
> -
> -    // Close unnecessary handles
> -    CloseHandle(ci.hJob);
> -    CloseHandle(ci.hThreadChildToSocket);
> -    CloseHandle(ci.hChildOutputRead);
> -
> -    AppendMessage("SocketToChild thread exited\r\n");
> -
> -    return 0;
> -}
> -
> -void PrepAndLaunchRedirectedChild(client_info *ci,
> -                                  HANDLE hChildStdOut,
> -                                  HANDLE hChildStdErr)
> -{
> -    PROCESS_INFORMATION pi;
> -    STARTUPINFO si;
> -
> -    // Allocate a new console for the child
> -    HWND hwnd = GetForegroundWindow();
> -    FreeConsole();
> -    AllocConsole();
> -    ShowWindow(GetConsoleWindow(), SW_HIDE);
> -    if (hwnd)
> -        SetForegroundWindow(hwnd);
> -
> -    // Set up the start up info struct.
> -    ZeroMemory(&si, sizeof(STARTUPINFO));
> -    si.cb = sizeof(STARTUPINFO);
> -    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
> -    si.hStdOutput = hChildStdOut;
> -    si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
> -    si.hStdError  = hChildStdErr;
> -    // Use this if you want to hide the child:
> -    si.wShowWindow = SW_HIDE;
> -    // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
> -    // use the wShowWindow flags.
> -
> -    // Launch the process that you want to redirect.
> -    if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE,
> -                       0, NULL, "C:\\",&si,&pi))
> -        ExitOnError("CreateProcess failed");
> -
> -    // Close any unnecessary handles.
> -    if (!CloseHandle(pi.hThread))
> -        ExitOnError("CloseHandle failed");
> -
> -    // Keep the process ID
> -    ci->pid = pi.dwProcessId;
> -    // Assign the process to a newly created JobObject
> -    ci->hJob = CreateJobObject(NULL, NULL);
> -    AssignProcessToJobObject(ci->hJob, pi.hProcess);
> -    // Keep the console window's handle
> -    ci->hwnd = GetConsoleWindow();
> -
> -    // Detach from the child's console
> -    FreeConsole();
> -}
> -
> -void SpawnSession(client_info *ci)
> -{
> -    HANDLE hOutputReadTmp, hOutputRead, hOutputWrite;
> -    HANDLE hErrorWrite;
> -    SECURITY_ATTRIBUTES sa;
> -
> -    // Set up the security attributes struct.
> -    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
> -    sa.lpSecurityDescriptor = NULL;
> -    sa.bInheritHandle = TRUE;
> -
> -    // Create the child output pipe.
> -    if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa, 0))
> -        ExitOnError("CreatePipe failed");
> -
> -    // Create a duplicate of the output write handle for the std error
> -    // write handle. This is necessary in case the child application
> -    // closes one of its std output handles.
> -    if (!DuplicateHandle(GetCurrentProcess(), hOutputWrite,
> -                         GetCurrentProcess(),&hErrorWrite, 0,
> -                         TRUE, DUPLICATE_SAME_ACCESS))
> -        ExitOnError("DuplicateHandle failed");
> -
> -    // Create new output read handle and the input write handles. Set
> -    // the Properties to FALSE. Otherwise, the child inherits the
> -    // properties and, as a result, non-closeable handles to the pipes
> -    // are created.
> -    if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp,
> -                         GetCurrentProcess(),
> -&hOutputRead, // Address of new handle.
> -                         0, FALSE, // Make it uninheritable.
> -                         DUPLICATE_SAME_ACCESS))
> -        ExitOnError("DuplicateHandle failed");
> -
> -    // Close inheritable copies of the handles you do not want to be
> -    // inherited.
> -    if (!CloseHandle(hOutputReadTmp))
> -        ExitOnError("CloseHandle failed");
> -
> -    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hErrorWrite);
> -
> -    ci->hChildOutputRead = hOutputRead;
> -
> -    // Close pipe handles (do not continue to modify the parent).
> -    // You need to make sure that no handles to the write end of the
> -    // output pipe are maintained in this process or else the pipe will
> -    // not close when the child process exits and the ReadFile will hang.
> -    if (!CloseHandle(hOutputWrite)) ExitOnError("CloseHandle failed");
> -    if (!CloseHandle(hErrorWrite)) ExitOnError("CloseHandle failed");
> -}
> -
> -DWORD WINAPI ListenThread(LPVOID param)
> -{
> -    WSADATA wsaData;
> -    SOCKET ListenSocket = INVALID_SOCKET;
> -    sockaddr_in addr;
> -    int result, addrlen;
> -    client_info ci;
> -    HANDLE hThread;
> -
> -    // Initialize Winsock
> -    result = WSAStartup(MAKEWORD(2,2),&wsaData);
> -    if (result)
> -        ExitOnError("Winsock initialization failed");
> -
> -    // Create socket
> -    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
> -    if (ListenSocket == INVALID_SOCKET)
> -        ExitOnError("Socket creation failed", 1);
> -
> -    // Bind the socket
> -    addr.sin_family = AF_INET;
> -    addr.sin_addr.s_addr = htonl(INADDR_ANY);
> -    addr.sin_port = htons(port);
> -
> -    result = bind(ListenSocket, (sockaddr *)&addr, sizeof(addr));
> -    if (result == SOCKET_ERROR)
> -        ExitOnError("bind failed", 1);
> -
> -    // Start listening for incoming connections
> -    result = listen(ListenSocket, SOMAXCONN);
> -    if (result == SOCKET_ERROR)
> -        ExitOnError("listen failed", 1);
> -
> -    // Inform the user
> -    AppendMessage("Waiting for clients to connect...\r\n");
> -
> -    while (1) {
> -        addrlen = sizeof(ci.addr);
> -        ci.socket = accept(ListenSocket, (sockaddr *)&ci.addr,&addrlen);
> -        if (ci.socket == INVALID_SOCKET) {
> -            if (WSAGetLastError() == WSAEINTR)
> -                break;
> -            else
> -                ExitOnError("accept failed", 1);
> -        }
> -
> -        // Under heavy load, spawning cmd.exe might take a while, so tell the
> -        // client to be patient
> -        char *message = "Please wait...\r\n";
> -        send(ci.socket, message, strlen(message), 0);
> -        // Spawn a new redirected cmd.exe process
> -        SpawnSession(&ci);
> -        // Start transferring data from the child process to the client
> -        hThread = CreateThread(NULL, 0, ChildToSocket, (LPVOID)&ci, 0, NULL);
> -        if (!hThread)
> -            ExitOnError("Could not create ChildToSocket thread");
> -        ci.hThreadChildToSocket = hThread;
> -        // ... and from the client to the child process
> -        hThread = CreateThread(NULL, 0, SocketToChild, (LPVOID)&ci, 0, NULL);
> -        if (!hThread)
> -            ExitOnError("Could not create SocketToChild thread");
> -    }
> -
> -    return 0;
> -}
> -
> -LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
> -{
> -    RECT rect;
> -    HANDLE hListenThread;
> -
> -    switch (msg) {
> -        case WM_CREATE:
> -            // Create text box
> -            GetClientRect(hwnd,&rect);
> -            hTextBox = CreateWindowEx(WS_EX_CLIENTEDGE,
> -                                      "EDIT", "",
> -                                      WS_CHILD|WS_VISIBLE|WS_VSCROLL|
> -                                      ES_MULTILINE|ES_AUTOVSCROLL,
> -                                      20, 20,
> -                                      rect.right - 40,
> -                                      rect.bottom - 40,
> -                                      hwnd,
> -                                      NULL,
> -                                      GetModuleHandle(NULL),
> -                                      NULL);
> -            if (!hTextBox)
> -                ExitOnError("Could not create text box");
> -
> -            // Set the font
> -            SendMessage(hTextBox, WM_SETFONT,
> -                        (WPARAM)GetStockObject(DEFAULT_GUI_FONT),
> -                        MAKELPARAM(FALSE, 0));
> -
> -            // Start the listening thread
> -            hListenThread =
> -                CreateThread(NULL, 0, ListenThread, NULL, 0, NULL);
> -            if (!hListenThread)
> -                ExitOnError("Could not create server thread");
> -            break;
> -
> -        case WM_DESTROY:
> -            WSACleanup();
> -            PostQuitMessage(0);
> -            break;
> -
> -        default:
> -            return DefWindowProc(hwnd, msg, wParam, lParam);
> -    }
> -
> -    return 0;
> -}
> -
> -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
> -                   LPSTR lpCmdLine, int nShowCmd)
> -{
> -    WNDCLASSEX wc;
> -    MSG msg;
> -
> -    if (strlen(lpCmdLine))
> -        sscanf(lpCmdLine, "%d",&port);
> -
> -    // Make sure the firewall is disabled
> -    system("netsh firewall set opmode disable");
> -
> -    // Create the window class
> -    wc.cbSize        = sizeof(WNDCLASSEX);
> -    wc.style         = CS_HREDRAW | CS_VREDRAW;
> -    wc.lpfnWndProc   = WndProc;
> -    wc.cbClsExtra    = 0;
> -    wc.cbWndExtra    = 0;
> -    wc.hInstance     = hInstance;
> -    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
> -    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
> -    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
> -    wc.lpszMenuName  = NULL;
> -    wc.lpszClassName = "RemoteShellServerWindowClass";
> -    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
> -
> -    if (!RegisterClassEx(&wc))
> -        ExitOnError("Could not register window class");
> -
> -    // Create the main window
> -    hMainWindow =
> -        CreateWindow("RemoteShellServerWindowClass",
> -                     "Remote Shell Server",
> -                     WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,
> -                     20, 20, 500, 300,
> -                     NULL, NULL, hInstance, NULL);
> -    if (!hMainWindow)
> -        ExitOnError("Could not create window");
> -
> -    ShowWindow(hMainWindow, SW_SHOWMINNOACTIVE);
> -    UpdateWindow(hMainWindow);
> -
> -    // Main message loop
> -    while (GetMessage(&msg, NULL, 0, 0)) {
> -        TranslateMessage(&msg);
> -        DispatchMessage(&msg);
> -    }
> -
> -    ExitProcess(0);
> -}
> +// Simple remote shell server (and file transfer server)
> +// Author: Michael Goldish<mgoldish@redhat.com>
> +// Much of the code here was adapted from Microsoft code samples.
> +
> +// Usage: rss.exe [shell port] [file transfer port]
> +// If no shell port is specified the default is 22.
> +// If no file transfer port is specified the default is 23.
> +
> +// Definitions:
> +// A 'msg' is a 32 bit integer.
> +// A 'packet' is a 64 bit unsigned integer followed by a string of bytes.
> +// The 64 bit integer indicates the length of the string.
> +
> +// Protocol for file transfers:
> +//
> +// When uploading files to the server:
> +// 1. The client connects.
> +// 2. The server sends RSS_MAGIC.
> +// 3. The client sends RSS_SET_PATH, followed by a packet (as defined above)
> +//    containing the path (in the server's filesystem) where files are to be
> +//    stored.  The 'current path' is set to the path given.
> +// Uploading a file (optional, can be repeated many times):
> +//   4. The client sends RSS_CREATE_FILE, followed by a packet containing the
> +//      filename (filename only, without a path), followed by a packet
> +//      containing the file's contents.  The file is stored in the current
> +//      path.
> +// Uploading a directory (optional, can be repeated many times):
> +//   5. The client sends RSS_CREATE_DIR, followed by a packet containing the
> +//      name of the directory to be created (directory name only, without a
> +//      path).  The directory is created in the current path.  Then, the
> +//      'current path' becomes the path of that new directory.
> +//   6. Steps 4-5 may be repeated to upload files and directories to the new
> +//      directory.
> +//   7. The client sends RSS_LEAVE_DIR, and the current path is set to the path
> +//      of its parent directory (e.g. C:\Foobar ->  C:\).
> +// 8. The client sends RSS_DONE and waits for a response.
> +// 9. The server sends RSS_OK to indicate that it's still listening.
> +// 10. Steps 3-9 are repeated as many times as necessary.
> +// If a critical error occurs at any time, the server may send RSS_ERROR
> +// followed by a packet containing an error message, and the connection is
> +// closed.
> +//
> +// When downloading files from the server:
> +// 1. The client connects.
> +// 2. The server sends RSS_MAGIC.
> +// 3. The client sends RSS_SET_PATH, followed by a packet (as defined above)
> +//    containing a path (in the server's filesystem) or a wildcard pattern
> +//    indicating the files/directories the client wants to download.
> +// The server then searches the given path.  For every file found:
> +//   4. The server sends RSS_CREATE_FILE, followed by a packet containing the
> +//      filename (filename only, without a path), followed by a packet
> +//      containing the file's contents.
> +// For every directory found:
> +//   5. The server sends RSS_CREATE_DIR, followed by a packet containing the
> +//      name of the directory to be created (directory name only, without a
> +//      path).
> +//   6. Steps 4-5 are repeated as many times as necessary.
> +//   7. The server sends RSS_LEAVE_DIR.
> +// 8. The server sends RSS_DONE.
> +// 9. Steps 3-8 are repeated as many times as necessary.
> +// If a critical error occurs, the server may send RSS_ERROR followed by a
> +// packet containing an error message, and the connection is closed.
> +// RSS_ERROR may only be sent when the client expects a msg.
> +
> +#define _WIN32_WINNT 0x0500
> +
> +#include<winsock2.h>
> +#include<windows.h>
> +#include<stdio.h>
> +#include<stdarg.h>
> +#include<shlwapi.h>
> +
> +#pragma comment(lib, "ws2_32.lib")
> +#pragma comment(lib, "shlwapi.lib")
> +
> +#define TEXTBOX_LIMIT 32767
> +
> +// Constants for file transfer server
> +#define RSS_MAGIC           0x525353
> +#define RSS_OK              1
> +#define RSS_ERROR           2
> +#define RSS_UPLOAD          3
> +#define RSS_DOWNLOAD        4
> +#define RSS_SET_PATH        5
> +#define RSS_CREATE_FILE     6
> +#define RSS_CREATE_DIR      7
> +#define RSS_LEAVE_DIR       8
> +#define RSS_DONE            9
> +
> +// Globals
> +int shell_port = 22;
> +int file_transfer_port = 23;
> +
> +HWND hMainWindow = NULL;
> +HWND hTextBox = NULL;
> +
> +struct client_info {
> +    SOCKET socket;
> +    sockaddr_in addr;
> +    char addr_str[256];
> +    int pid;
> +    HWND hwnd;
> +    HANDLE hJob;
> +    HANDLE hChildOutputRead;
> +    HANDLE hThreadChildToSocket;
> +};
> +
> +void ExitOnError(char *message, BOOL winsock = FALSE)
> +{
> +    LPVOID system_message;
> +    char buffer[512];
> +    int error_code;
> +
> +    if (winsock)
> +        error_code = WSAGetLastError();
> +    else
> +        error_code = GetLastError();
> +    WSACleanup();
> +
> +    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
> +                  FORMAT_MESSAGE_FROM_SYSTEM,
> +                  NULL,
> +                  error_code,
> +                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
> +                  (LPTSTR)&system_message,
> +                  0,
> +                  NULL);
> +    sprintf(buffer,
> +            "%s!\n"
> +            "Error code = %d\n"
> +            "Error message = %s",
> +            message, error_code, (char *)system_message);
> +    MessageBox(hMainWindow, buffer, "Error", MB_OK | MB_ICONERROR);
> +
> +    LocalFree(system_message);
> +    ExitProcess(1);
> +}
> +
> +void _vAppendMessage(char *message, va_list args)
> +{
> +    char str[512] = {0};
> +
> +    vsnprintf(str, sizeof(str) - 1, message, args);
> +    strncat(str, "\r\n", sizeof(str) - 1 - strlen(str));
> +
> +    int length = GetWindowTextLength(hTextBox);
> +    SendMessage(hTextBox, EM_SETSEL, (WPARAM)length, (LPARAM)length);
> +    SendMessage(hTextBox, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)str);
> +}
> +
> +// Append text to the textbox
> +// (if the textbox is full, do nothing)
> +void _AppendMessage(char *message, ...)
> +{
> +    va_list args;
> +
> +    va_start(args, message);
> +    _vAppendMessage(message, args);
> +    va_end(args);
> +}
> +
> +// Append text to the textbox
> +// (if the textbox is full or nearly full, remove old text first)
> +void AppendMessage(char *message, ...)
> +{
> +    va_list args;
> +
> +    int length = GetWindowTextLength(hTextBox);
> +    if (length>  TEXTBOX_LIMIT - 512) {
> +        SendMessage(hTextBox, EM_SETSEL, (WPARAM)0,
> +                    (LPARAM)(TEXTBOX_LIMIT / 2));
> +        SendMessage(hTextBox, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"...");
> +        if (length == TEXTBOX_LIMIT) _AppendMessage("...");
> +    }
> +    va_start(args, message);
> +    _vAppendMessage(message, args);
> +    va_end(args);
> +}
> +
> +void FormatStringForPrinting(char *dst, char *src, int size)
> +{
> +    int j = 0;
> +
> +    for (int i = 0; i<  size&&  src[i]; i++) {
> +        if (src[i] == '\n') {
> +            dst[j++] = '\\';
> +            dst[j++] = 'n';
> +        } else if (src[i] == '\r') {
> +            dst[j++] = '\\';
> +            dst[j++] = 'r';
> +        } else if (src[i] == '\t') {
> +            dst[j++] = '\\';
> +            dst[j++] = 't';
> +        } else if (src[i] == '\\') {
> +            dst[j++] = '\\';
> +            dst[j++] = '\\';
> +        } else dst[j++] = src[i];
> +    }
> +    dst[j] = 0;
> +}
> +
> +char* GetClientIPAddress(client_info *ci)
> +{
> +    char *address = inet_ntoa(ci->addr.sin_addr);
> +    if (address)
> +        return address;
> +    else
> +        return "unknown";
> +}
> +
> +// Read a small chunk of data into a buffer
> +BOOL Receive(SOCKET socket, char *buffer, int len)
> +{
> +    while (len>  0) {
> +        int bytes_received = recv(socket, buffer, len, 0);
> +        if (bytes_received<= 0)
> +            return FALSE;
> +        buffer += bytes_received;
> +        len -= bytes_received;
> +    }
> +    return TRUE;
> +}
> +
> +// Send data from a buffer
> +BOOL Send(SOCKET socket, char *buffer, int len)
> +{
> +    while (len>  0) {
> +        int bytes_sent = send(socket, buffer, len, 0);
> +        if (bytes_sent<= 0)
> +            return FALSE;
> +        buffer += bytes_sent;
> +        len -= bytes_sent;
> +    }
> +    return TRUE;
> +}
> +
> +/*-------------
> + * Shell server
> + *-------------*/
> +
> +DWORD WINAPI ChildToSocket(LPVOID client_info_ptr)
> +{
> +    client_info *ci = (client_info *)client_info_ptr;
> +    char buffer[1024];
> +    DWORD bytes_read;
> +
> +    while (1) {
> +        // Read data from the child's STDOUT/STDERR pipes
> +        if (!ReadFile(ci->hChildOutputRead,
> +                      buffer, sizeof(buffer),
> +&bytes_read, NULL) || !bytes_read) {
> +            if (GetLastError() == ERROR_BROKEN_PIPE)
> +                break; // Pipe done -- normal exit path
> +            else
> +                ExitOnError("ReadFile failed"); // Something bad happened
> +        }
> +        // Send data to the client
> +        Send(ci->socket, buffer, bytes_read);
> +    }
> +
> +    AppendMessage("Child exited");
> +    closesocket(ci->socket);
> +    return 0;
> +}
> +
> +DWORD WINAPI SocketToChild(LPVOID client_info_ptr)
> +{
> +    client_info *ci = (client_info *)client_info_ptr;
> +    char buffer[256], formatted_buffer[768];
> +    int bytes_received;
> +
> +    AppendMessage("Shell server: new client connected (%s)", ci->addr_str);
> +
> +    while (1) {
> +        // Receive data from the socket
> +        ZeroMemory(buffer, sizeof(buffer));
> +        bytes_received = recv(ci->socket, buffer, sizeof(buffer), 0);
> +        if (bytes_received<= 0)
> +            break;
> +        // Report the data received
> +        FormatStringForPrinting(formatted_buffer, buffer, sizeof(buffer));
> +        _AppendMessage("Client (%s) entered text: \"%s\"",
> +                       ci->addr_str, formatted_buffer);
> +        // Send the data as a series of WM_CHAR messages to the console window
> +        for (int i = 0; i<  bytes_received; i++) {
> +            SendMessage(ci->hwnd, WM_CHAR, (WPARAM)buffer[i], 0);
> +            SendMessage(ci->hwnd, WM_SETFOCUS, 0, 0);
> +        }
> +    }
> +
> +    AppendMessage("Shell server: client disconnected (%s)", ci->addr_str);
> +
> +    // Attempt to terminate the child's process tree:
> +    // Using taskkill (where available)
> +    sprintf(buffer, "taskkill /PID %d /T /F", ci->pid);
> +    system(buffer);
> +    // .. and using TerminateJobObject()
> +    TerminateJobObject(ci->hJob, 0);
> +    // Wait for the ChildToSocket thread to terminate
> +    WaitForSingleObject(ci->hThreadChildToSocket, 10000);
> +    // In case the thread refuses to exit, terminate it
> +    TerminateThread(ci->hThreadChildToSocket, 0);
> +    // Close the socket
> +    closesocket(ci->socket);
> +
> +    // Free resources
> +    CloseHandle(ci->hJob);
> +    CloseHandle(ci->hThreadChildToSocket);
> +    CloseHandle(ci->hChildOutputRead);
> +    free(ci);
> +
> +    AppendMessage("SocketToChild thread exited");
> +    return 0;
> +}
> +
> +void PrepAndLaunchRedirectedChild(client_info *ci,
> +                                  HANDLE hChildStdOut,
> +                                  HANDLE hChildStdErr)
> +{
> +    PROCESS_INFORMATION pi;
> +    STARTUPINFO si;
> +
> +    // Allocate a new console for the child
> +    HWND hwnd = GetForegroundWindow();
> +    FreeConsole();
> +    AllocConsole();
> +    ShowWindow(GetConsoleWindow(), SW_HIDE);
> +    if (hwnd)
> +        SetForegroundWindow(hwnd);
> +
> +    // Set up the start up info struct.
> +    ZeroMemory(&si, sizeof(STARTUPINFO));
> +    si.cb = sizeof(STARTUPINFO);
> +    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
> +    si.hStdOutput = hChildStdOut;
> +    si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
> +    si.hStdError  = hChildStdErr;
> +    // Use this if you want to hide the child:
> +    si.wShowWindow = SW_HIDE;
> +    // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
> +    // use the wShowWindow flags.
> +
> +    // Launch the process that you want to redirect.
> +    if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE,
> +                       0, NULL, "C:\\",&si,&pi))
> +        ExitOnError("CreateProcess failed");
> +
> +    // Close any unnecessary handles.
> +    if (!CloseHandle(pi.hThread))
> +        ExitOnError("CloseHandle failed");
> +
> +    // Keep the process ID
> +    ci->pid = pi.dwProcessId;
> +    // Assign the process to a newly created JobObject
> +    ci->hJob = CreateJobObject(NULL, NULL);
> +    AssignProcessToJobObject(ci->hJob, pi.hProcess);
> +    // Keep the console window's handle
> +    ci->hwnd = GetConsoleWindow();
> +
> +    // Detach from the child's console
> +    FreeConsole();
> +}
> +
> +void SpawnSession(client_info *ci)
> +{
> +    HANDLE hOutputReadTmp, hOutputRead, hOutputWrite;
> +    HANDLE hErrorWrite;
> +    SECURITY_ATTRIBUTES sa;
> +
> +    // Set up the security attributes struct.
> +    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
> +    sa.lpSecurityDescriptor = NULL;
> +    sa.bInheritHandle = TRUE;
> +
> +    // Create the child output pipe.
> +    if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa, 0))
> +        ExitOnError("CreatePipe failed");
> +
> +    // Create a duplicate of the output write handle for the std error
> +    // write handle. This is necessary in case the child application
> +    // closes one of its std output handles.
> +    if (!DuplicateHandle(GetCurrentProcess(), hOutputWrite,
> +                         GetCurrentProcess(),&hErrorWrite, 0,
> +                         TRUE, DUPLICATE_SAME_ACCESS))
> +        ExitOnError("DuplicateHandle failed");
> +
> +    // Create new output read handle and the input write handles. Set
> +    // the Properties to FALSE. Otherwise, the child inherits the
> +    // properties and, as a result, non-closeable handles to the pipes
> +    // are created.
> +    if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp,
> +                         GetCurrentProcess(),
> +&hOutputRead, // Address of new handle.
> +                         0, FALSE, // Make it uninheritable.
> +                         DUPLICATE_SAME_ACCESS))
> +        ExitOnError("DuplicateHandle failed");
> +
> +    // Close inheritable copies of the handles you do not want to be
> +    // inherited.
> +    if (!CloseHandle(hOutputReadTmp))
> +        ExitOnError("CloseHandle failed");
> +
> +    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hErrorWrite);
> +
> +    ci->hChildOutputRead = hOutputRead;
> +
> +    // Close pipe handles (do not continue to modify the parent).
> +    // You need to make sure that no handles to the write end of the
> +    // output pipe are maintained in this process or else the pipe will
> +    // not close when the child process exits and the ReadFile will hang.
> +    if (!CloseHandle(hOutputWrite)) ExitOnError("CloseHandle failed");
> +    if (!CloseHandle(hErrorWrite)) ExitOnError("CloseHandle failed");
> +}
> +
> +SOCKET PrepListenSocket(int port)
> +{
> +    sockaddr_in addr;
> +    linger l;
> +    int result;
> +
> +    // Create socket
> +    SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
> +    if (ListenSocket == INVALID_SOCKET)
> +        ExitOnError("Socket creation failed", TRUE);
> +
> +    // Enable lingering
> +    l.l_linger = 10;
> +    l.l_onoff = 1;
> +    setsockopt(ListenSocket, SOL_SOCKET, SO_LINGER, (char *)&l, sizeof(l));
> +
> +    // Bind the socket
> +    addr.sin_family = AF_INET;
> +    addr.sin_addr.s_addr = htonl(INADDR_ANY);
> +    addr.sin_port = htons(port);
> +
> +    result = bind(ListenSocket, (sockaddr *)&addr, sizeof(addr));
> +    if (result == SOCKET_ERROR)
> +        ExitOnError("bind failed", TRUE);
> +
> +    // Start listening for incoming connections
> +    result = listen(ListenSocket, SOMAXCONN);
> +    if (result == SOCKET_ERROR)
> +        ExitOnError("listen failed", TRUE);
> +
> +    return ListenSocket;
> +}
> +
> +DWORD WINAPI ShellListenThread(LPVOID param)
> +{
> +    client_info _ci, *ci;
> +    HANDLE hThread;
> +
> +    SOCKET ListenSocket = PrepListenSocket(shell_port);
> +
> +    // Inform the user
> +    AppendMessage("Shell server: waiting for clients to connect...");
> +
> +    while (1) {
> +        int addrlen = sizeof(_ci.addr);
> +        _ci.socket = accept(ListenSocket, (sockaddr *)&_ci.addr,&addrlen);
> +        if (_ci.socket == INVALID_SOCKET) {
> +            if (WSAGetLastError() == WSAEINTR)
> +                break;
> +            else
> +                ExitOnError("accept failed", TRUE);
> +        }
> +
> +        if (!(ci = (client_info *)malloc(sizeof(client_info))))
> +            ExitOnError("Could not allocate client_info struct");
> +        memcpy(ci,&_ci, sizeof(client_info));
> +        sprintf(ci->addr_str, "%s:%d", GetClientIPAddress(ci),
> +                ci->addr.sin_port);
> +
> +        // Under heavy load, spawning cmd.exe might take a while, so tell the
> +        // client to be patient
> +        char *message = "Please wait...\r\n";
> +        Send(ci->socket, message, strlen(message));
> +        // Spawn a new redirected cmd.exe process
> +        SpawnSession(ci);
> +        // Start transferring data from the child process to the client
> +        hThread = CreateThread(NULL, 0, ChildToSocket, (LPVOID)ci, 0, NULL);
> +        if (!hThread)
> +            ExitOnError("Could not create ChildToSocket thread");
> +        ci->hThreadChildToSocket = hThread;
> +        // ... and from the client to the child process
> +        hThread = CreateThread(NULL, 0, SocketToChild, (LPVOID)ci, 0, NULL);
> +        if (!hThread)
> +            ExitOnError("Could not create SocketToChild thread");
> +    }
> +
> +    return 0;
> +}
> +
> +/*---------------------
> + * File transfer server
> + *---------------------*/
> +
> +#define BUFSIZE 65536
> +
> +// Receive up to 4GB into a file
> +BOOL ReceiveIntoFile(SOCKET socket, char *filename, DWORD len)
> +{
> +    char *buffer = (char *)malloc(BUFSIZE);
> +    if (!buffer) return FALSE;
> +
> +    FILE *fp = fopen(filename, "wb");
> +    if (!fp) {
> +        free(buffer);
> +        return FALSE;
> +    }
> +
> +    while (len>  0) {
> +        int bytes_received = recv(socket, buffer, min(BUFSIZE, len), 0);
> +        if (bytes_received<= 0)
> +            break;
> +        if (fwrite(buffer, bytes_received, 1, fp)<  1)
> +            break;
> +        len -= bytes_received;
> +    }
> +
> +    fclose(fp);
> +    free(buffer);
> +    return len == 0;
> +}
> +
> +// Send data from a file (unlimited size)
> +BOOL SendFromFile(SOCKET socket, char *filename)
> +{
> +    char *buffer = (char *)malloc(BUFSIZE);
> +    if (!buffer) return FALSE;
> +
> +    FILE *fp = fopen(filename, "rb");
> +    if (!fp) {
> +        free(buffer);
> +        return FALSE;
> +    }
> +
> +    while (!feof(fp)) {
> +        int bytes_read = fread(buffer, 1, BUFSIZE, fp);
> +        if (bytes_read<= 0)
> +            break;
> +        if (!Send(socket, buffer, bytes_read)) {
> +            fclose(fp);
> +            free(buffer);
> +            return FALSE;
> +        }
> +    }
> +
> +    BOOL success = feof(fp);
> +    fclose(fp);
> +    free(buffer);
> +    return success;
> +}
> +
> +BOOL ReceivePacket(SOCKET socket, char *buffer, DWORD max_size)
> +{
> +    DWORD packet_size = 0, padding;
> +
> +    if (!Receive(socket, (char *)&packet_size, 4)) return FALSE;
> +    if (!Receive(socket, (char *)&padding, 4)) return FALSE;
> +    if (packet_size>  max_size) return FALSE;
> +    return Receive(socket, buffer, packet_size);
> +}
> +
> +BOOL ReceiveStrPacket(SOCKET socket, char *buffer, DWORD max_size)
> +{
> +    memset(buffer, 0, max_size);
> +    return ReceivePacket(socket, buffer, max_size - 1);
> +}
> +
> +BOOL SendPacket(SOCKET socket, char *buffer, DWORD len)
> +{
> +    DWORD padding = 0;
> +
> +    if (!Send(socket, (char *)&len, 4)) return FALSE;
> +    if (!Send(socket, (char *)&padding, 4)) return FALSE;
> +    return Send(socket, buffer, len);
> +}
> +
> +BOOL ReceivePacketIntoFile(SOCKET socket, char *filename)
> +{
> +    DWORD packet_size = 0, padding;
> +
> +    if (!Receive(socket, (char *)&packet_size, 4)) return FALSE;
> +    if (!Receive(socket, (char *)&padding, 4)) return FALSE;
> +    return ReceiveIntoFile(socket, filename, packet_size);
> +}
> +
> +BOOL SendPacketFromFile(SOCKET socket, char *filename,
> +                        DWORD size_low, DWORD size_high)
> +{
> +    if (!Send(socket, (char *)&size_low, 4)) return FALSE;
> +    if (!Send(socket, (char *)&size_high, 4)) return FALSE;
> +    return SendFromFile(socket, filename);
> +}
> +
> +BOOL SendMsg(SOCKET socket, int msg)
> +{
> +    return Send(socket, (char *)&msg, 4);
> +}
> +
> +int TerminateTransfer(client_info *ci, char *message)
> +{
> +    AppendMessage(message);
> +    AppendMessage("File transfer server: client disconnected (%s)",
> +                  ci->addr_str);
> +    closesocket(ci->socket);
> +    free(ci);
> +    return 0;
> +}
> +
> +int TerminateWithError(client_info *ci, char *message)
> +{
> +    SendMsg(ci->socket, RSS_ERROR);
> +    SendPacket(ci->socket, message, strlen(message));
> +    return TerminateTransfer(ci, message);
> +}
> +
> +int ReceiveThread(client_info *ci)
> +{
> +    char path[512], filename[512];
> +    int msg = 0;
> +
> +    AppendMessage("Client (%s) wants to upload files", ci->addr_str);
> +
> +    while (1) {
> +        if (!Receive(ci->socket, (char *)&msg, 4))
> +            return TerminateTransfer(ci, "Could not receive further msgs");
> +
> +        switch (msg) {
> +        case RSS_SET_PATH:
> +            if (!ReceiveStrPacket(ci->socket, path, sizeof(path)))
> +                return TerminateWithError(ci,
> +                    "RSS_SET_PATH: could not receive path");
> +            _AppendMessage("Client (%s) set path to %s", ci->addr_str, path);
> +            break;
> +
> +        case RSS_CREATE_FILE:
> +            if (!ReceiveStrPacket(ci->socket, filename, sizeof(filename)))
> +                return TerminateWithError(ci,
> +                    "RSS_CREATE_FILE: could not receive filename");
> +            if (PathIsDirectory(path))
> +                PathAppend(path, filename);
> +            _AppendMessage("Client (%s) is uploading %s", ci->addr_str, path);
> +            if (!ReceivePacketIntoFile(ci->socket, path))
> +                return TerminateWithError(ci,
> +                    "RSS_CREATE_FILE: error receiving or writing file "
> +                    "contents");
> +            PathAppend(path, "..");
> +            break;
> +
> +        case RSS_CREATE_DIR:
> +            if (!ReceiveStrPacket(ci->socket, filename, sizeof(filename)))
> +                return TerminateWithError(ci,
> +                    "RSS_CREATE_DIR: could not receive dirname");
> +            if (PathIsDirectory(path))
> +                PathAppend(path, filename);
> +            _AppendMessage("Entering dir %s", path);
> +            if (PathFileExists(path)) {
> +                if (!PathIsDirectory(path))
> +                    return TerminateWithError(ci,
> +                        "RSS_CREATE_DIR: path exists and is not a directory");
> +            } else {
> +                if (!CreateDirectory(path, NULL))
> +                    return TerminateWithError(ci,
> +                        "RSS_CREATE_DIR: could not create directory");
> +            }
> +            break;
> +
> +        case RSS_LEAVE_DIR:
> +            PathAppend(path, "..");
> +            _AppendMessage("Returning to dir %s", path);
> +            break;
> +
> +        case RSS_DONE:
> +            if (!SendMsg(ci->socket, RSS_OK))
> +                return TerminateTransfer(ci,
> +                    "RSS_DONE: could not send OK msg");
> +            break;
> +
> +        default:
> +            return TerminateWithError(ci, "Received unexpected msg");
> +        }
> +    }
> +}
> +
> +// Given a path or a pattern with wildcards, send files or directory trees to
> +// the client
> +int SendFiles(client_info *ci, char *pattern)
> +{
> +    char path[MAX_PATH];
> +    WIN32_FIND_DATA ffd;
> +    FILE *fp;
> +
> +    HANDLE hFind = FindFirstFile(pattern,&ffd);
> +    if (hFind == INVALID_HANDLE_VALUE) {
> +        // If a weird error occurred (like failure to list directory contents
> +        // due to insufficient permissions) print a warning and continue.
> +        if (GetLastError() != ERROR_FILE_NOT_FOUND)
> +            AppendMessage("WARNING: FindFirstFile failed on pattern %s",
> +                          pattern);
> +        return 1;
> +    }
> +
> +    strncpy(path, pattern, sizeof(path) - 1);
> +    PathAppend(path, "..");
> +
> +    do {
> +        if (ffd.dwFileAttributes&  FILE_ATTRIBUTE_REPARSE_POINT)
> +            continue;
> +        if (ffd.dwFileAttributes&  FILE_ATTRIBUTE_DIRECTORY) {
> +            // Directory
> +            if (!strcmp(ffd.cFileName, ".") || !strcmp(ffd.cFileName, ".."))
> +                continue;
> +            PathAppend(path, ffd.cFileName);
> +            _AppendMessage("Entering dir %s", path);
> +            PathAppend(path, "*");
> +            if (!SendMsg(ci->socket, RSS_CREATE_DIR)) {
> +                FindClose(hFind);
> +                return TerminateTransfer(ci,
> +                    "Could not send RSS_CREATE_DIR msg");
> +            }
> +            if (!SendPacket(ci->socket, ffd.cFileName,
> +                            strlen(ffd.cFileName))) {
> +                FindClose(hFind);
> +                return TerminateTransfer(ci, "Could not send dirname");
> +            }
> +            if (!SendFiles(ci, path)) {
> +                FindClose(hFind);
> +                return 0;
> +            }
> +            if (!SendMsg(ci->socket, RSS_LEAVE_DIR)) {
> +                FindClose(hFind);
> +                return TerminateTransfer(ci,
> +                    "Could not send RSS_LEAVE_DIR msg");
> +            }
> +            PathAppend(path, "..");
> +            PathAppend(path, "..");
> +            _AppendMessage("Returning to dir %s", path);
> +        } else {
> +            // File
> +            PathAppend(path, ffd.cFileName);
> +            _AppendMessage("Client (%s) is downloading %s",
> +                           ci->addr_str, path);
> +            // Make sure the file is readable
> +            fp = fopen(path, "rb");
> +            if (fp) fclose(fp);
> +            else {
> +                AppendMessage("WARNING: could not read file %s", path);
> +                PathAppend(path, "..");
> +                continue;
> +            }
> +            if (!SendMsg(ci->socket, RSS_CREATE_FILE)) {
> +                FindClose(hFind);
> +                return TerminateTransfer(ci,
> +                    "Could not send RSS_CREATE_FILE msg");
> +            }
> +            if (!SendPacket(ci->socket, ffd.cFileName,
> +                            strlen(ffd.cFileName))) {
> +                FindClose(hFind);
> +                return TerminateTransfer(ci, "Could not send filename");
> +            }
> +            if (!SendPacketFromFile(ci->socket, path,
> +                                    ffd.nFileSizeLow, ffd.nFileSizeHigh)) {
> +                FindClose(hFind);
> +                return TerminateTransfer(ci, "Could not send file contents");
> +            }
> +            PathAppend(path, "..");
> +        }
> +    } while (FindNextFile(hFind,&ffd));
> +
> +    if (GetLastError() == ERROR_NO_MORE_FILES) {
> +        FindClose(hFind);
> +        return 1;
> +    } else {
> +        FindClose(hFind);
> +        return TerminateWithError(ci, "FindNextFile failed");
> +    }
> +}
> +
> +int SendThread(client_info *ci)
> +{
> +    char pattern[512];
> +    int msg = 0;
> +
> +    AppendMessage("Client (%s) wants to download files", ci->addr_str);
> +
> +    while (1) {
> +        if (!Receive(ci->socket, (char *)&msg, 4))
> +            return TerminateTransfer(ci, "Could not receive further msgs");
> +
> +        switch (msg) {
> +        case RSS_SET_PATH:
> +            if (!ReceiveStrPacket(ci->socket, pattern, sizeof(pattern)))
> +                return TerminateWithError(ci,
> +                    "RSS_SET_PATH: could not receive path");
> +            AppendMessage("Client (%s) asked for %s", ci->addr_str, pattern);
> +            PathRemoveBackslash(pattern);
> +            if (!SendFiles(ci, pattern))
> +                return 0;
> +            if (!SendMsg(ci->socket, RSS_DONE))
> +                return TerminateTransfer(ci,
> +                    "RSS_SET_PATH: could not send RSS_DONE msg");
> +            break;
> +
> +        default:
> +            return TerminateWithError(ci, "Received unexpected msg");
> +        }
> +    }
> +}
> +
> +DWORD WINAPI TransferThreadEntry(LPVOID client_info_ptr)
> +{
> +    client_info *ci = (client_info *)client_info_ptr;
> +    int msg = 0;
> +
> +    AppendMessage("File transfer server: new client connected (%s)",
> +                  ci->addr_str);
> +
> +    if (!SendMsg(ci->socket, RSS_MAGIC))
> +        return TerminateTransfer(ci, "Could not send greeting message");
> +    if (!Receive(ci->socket, (char *)&msg, 4))
> +        return TerminateTransfer(ci, "Error receiving msg");
> +
> +    if (msg == RSS_UPLOAD)
> +        return ReceiveThread(ci);
> +    else if (msg == RSS_DOWNLOAD)
> +        return SendThread(ci);
> +    return TerminateWithError(ci, "Received unexpected msg");
> +}
> +
> +DWORD WINAPI FileTransferListenThread(LPVOID param)
> +{
> +    client_info _ci, *ci;
> +    HANDLE hThread;
> +
> +    SOCKET ListenSocket = PrepListenSocket(file_transfer_port);
> +
> +    // Inform the user
> +    AppendMessage("File transfer server: waiting for clients to connect...");
> +
> +    while (1) {
> +        int addrlen = sizeof(_ci.addr);
> +        _ci.socket = accept(ListenSocket, (sockaddr *)&_ci.addr,&addrlen);
> +        if (_ci.socket == INVALID_SOCKET) {
> +            if (WSAGetLastError() == WSAEINTR)
> +                break;
> +            else
> +                ExitOnError("accept failed", TRUE);
> +        }
> +
> +        if (!(ci = (client_info *)malloc(sizeof(client_info))))
> +            ExitOnError("Could not allocate client_info struct");
> +        memcpy(ci,&_ci, sizeof(client_info));
> +        sprintf(ci->addr_str, "%s:%d", GetClientIPAddress(ci),
> +                ci->addr.sin_port);
> +        hThread = CreateThread(NULL, 0, TransferThreadEntry, (LPVOID)ci, 0,
> +                               NULL);
> +        if (!hThread)
> +            ExitOnError("Could not create MainTransferThread");
> +    }
> +
> +    return 0;
> +}
> +
> +/*--------------------
> + * WndProc and WinMain
> + *--------------------*/
> +
> +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
> +{
> +    RECT rect;
> +    WSADATA wsaData;
> +
> +    switch (msg) {
> +    case WM_CREATE:
> +        // Create text box
> +        GetClientRect(hwnd,&rect);
> +        hTextBox = CreateWindowEx(WS_EX_CLIENTEDGE,
> +                                  "EDIT", "",
> +                                  WS_CHILD | WS_VISIBLE | WS_VSCROLL |
> +                                  ES_MULTILINE | ES_AUTOVSCROLL,
> +                                  20, 20,
> +                                  rect.right - 40,
> +                                  rect.bottom - 40,
> +                                  hwnd,
> +                                  NULL,
> +                                  GetModuleHandle(NULL),
> +                                  NULL);
> +        if (!hTextBox)
> +            ExitOnError("Could not create text box");
> +        // Set font
> +        SendMessage(hTextBox, WM_SETFONT,
> +                    (WPARAM)GetStockObject(DEFAULT_GUI_FONT),
> +                    MAKELPARAM(FALSE, 0));
> +        // Set size limit
> +        SendMessage(hTextBox, EM_LIMITTEXT, (WPARAM)TEXTBOX_LIMIT, (LPARAM)0);
> +        // Initialize Winsock
> +        if (WSAStartup(MAKEWORD(2,2),&wsaData))
> +            ExitOnError("Winsock initialization failed");
> +        // Start the listening threads
> +        if (!CreateThread(NULL, 0, ShellListenThread, NULL, 0, NULL))
> +            ExitOnError("Could not create shell server thread");
> +        if (!CreateThread(NULL, 0, FileTransferListenThread, NULL, 0, NULL))
> +            ExitOnError("Could not create file transfer server thread");
> +        break;
> +
> +    case WM_DESTROY:
> +        if (WSACleanup())
> +            ExitOnError("WSACleanup failed");
> +        PostQuitMessage(0);
> +        break;
> +
> +    default:
> +        return DefWindowProc(hwnd, msg, wParam, lParam);
> +    }
> +
> +    return 0;
> +}
> +
> +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
> +                   LPSTR lpCmdLine, int nShowCmd)
> +{
> +    WNDCLASSEX wc;
> +    MSG msg;
> +
> +    if (strlen(lpCmdLine))
> +        sscanf(lpCmdLine, "%d %d",&shell_port,&file_transfer_port);
> +
> +    // Make sure the firewall is disabled
> +    system("netsh firewall set opmode disable");
> +
> +    // Create the window class
> +    wc.cbSize        = sizeof(WNDCLASSEX);
> +    wc.style         = CS_HREDRAW | CS_VREDRAW;
> +    wc.lpfnWndProc   = WndProc;
> +    wc.cbClsExtra    = 0;
> +    wc.cbWndExtra    = 0;
> +    wc.hInstance     = hInstance;
> +    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
> +    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
> +    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
> +    wc.lpszMenuName  = NULL;
> +    wc.lpszClassName = "RemoteShellServerWindowClass";
> +    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
> +
> +    if (!RegisterClassEx(&wc))
> +        ExitOnError("Could not register window class");
> +
> +    // Create the main window
> +    hMainWindow =
> +        CreateWindow("RemoteShellServerWindowClass",
> +                     "Remote Shell Server",
> +                     WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
> +                     20, 20, 600, 400,
> +                     NULL, NULL, hInstance, NULL);
> +    if (!hMainWindow)
> +        ExitOnError("Could not create window");
> +
> +    ShowWindow(hMainWindow, SW_SHOWMINNOACTIVE);
> +    UpdateWindow(hMainWindow);
> +
> +    // Main message loop
> +    while (GetMessage(&msg, NULL, 0, 0)) {
> +        TranslateMessage(&msg);
> +        DispatchMessage(&msg);
> +    }
> +
> +    ExitProcess(0);
> +}


  parent reply	other threads:[~2010-06-24 11:25 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-24 11:03 [KVM-AUTOTEST PATCH] [RFC] KVM test: rss.cpp: add file transfer support Michael Goldish
2010-06-24 11:03 ` [KVM-AUTOTEST PATCH] [RFC] KVM test: add python client for rss file transfer services Michael Goldish
2010-06-24 11:25 ` Yaniv Kaul [this message]
2010-06-24 11:37   ` [KVM-AUTOTEST PATCH] [RFC] KVM test: rss.cpp: add file transfer support Lucas Meneghel Rodrigues
2010-06-24 12:23   ` Michael Goldish

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4C2340AB.6040105@redhat.com \
    --to=ykaul@redhat.com \
    --cc=autotest@test.kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=mgoldish@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox