shadow: start hooking X11 code as subsystem

This commit is contained in:
Marc-André Moreau 2014-07-11 19:30:40 -04:00
parent 7caf48bcf4
commit 8ae00f7385
10 changed files with 168 additions and 479 deletions

View File

@ -58,6 +58,7 @@ struct rdp_freerdp_peer
rdpUpdate* update;
rdpSettings* settings;
void* ContextExtra;
size_t ContextSize;
psPeerContextNew ContextNew;
psPeerContextFree ContextFree;

View File

@ -23,7 +23,27 @@
#include <freerdp/api.h>
#include <freerdp/types.h>
#include <freerdp/listener.h>
typedef struct rdp_shadow_client rdpShadowClient;
typedef struct rdp_shadow_server rdpShadowServer;
struct rdp_shadow_client
{
rdpContext context;
rdpShadowServer* server;
void* ext;
};
struct rdp_shadow_server
{
DWORD port;
HANDLE thread;
freerdp_listener* listener;
void* ext;
};
#endif /* FREERDP_SERVER_SHADOW_H */

View File

@ -346,8 +346,10 @@ freerdp_listener* freerdp_listener_new(void)
freerdp_listener* instance;
rdpListener* listener;
instance = (freerdp_listener*) malloc(sizeof(freerdp_listener));
ZeroMemory(instance, sizeof(freerdp_listener));
instance = (freerdp_listener*) calloc(1, sizeof(freerdp_listener));
if (!instance)
return NULL;
instance->Open = freerdp_listener_open;
instance->OpenLocal = freerdp_listener_open_local;
@ -356,8 +358,10 @@ freerdp_listener* freerdp_listener_new(void)
instance->CheckFileDescriptor = freerdp_listener_check_fds;
instance->Close = freerdp_listener_close;
listener = (rdpListener*) malloc(sizeof(rdpListener));
ZeroMemory(listener, sizeof(rdpListener));
listener = (rdpListener*) calloc(1, sizeof(rdpListener));
if (!listener)
return NULL;
listener->instance = instance;

View File

@ -431,7 +431,7 @@ void freerdp_peer_context_new(freerdp_peer* client)
{
rdpRdp* rdp;
client->context = (rdpContext *)calloc(1, client->ContextSize);
client->context = (rdpContext*) calloc(1, client->ContextSize);
client->context->ServerMode = TRUE;

View File

@ -20,7 +20,6 @@
#include "config.h"
#endif
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@ -28,6 +27,7 @@
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/select.h>
@ -169,7 +169,7 @@ int x11_shadow_xshm_init(x11ShadowServer* server)
return 0;
}
void x11_shadow_peer_context_new(freerdp_peer* client, x11ShadowClient* context)
x11ShadowClient* x11_shadow_client_new(rdpShadowClient* rdp)
{
int i;
int pf_count;
@ -180,9 +180,15 @@ void x11_shadow_peer_context_new(freerdp_peer* client, x11ShadowClient* context)
XPixmapFormatValues* pf;
XPixmapFormatValues* pfs;
x11ShadowServer* server;
x11ShadowClient* client;
server = (x11ShadowServer*) client->context;
context->server = server;
client = (x11ShadowClient*) calloc(1, sizeof(x11ShadowClient));
if (!client)
return NULL;
server = (x11ShadowServer*) rdp->server->ext;
client->server = server;
/**
* Recent X11 servers drop support for shared pixmaps
@ -279,78 +285,33 @@ void x11_shadow_peer_context_new(freerdp_peer* client, x11ShadowClient* context)
freerdp_keyboard_init(0);
context->rfx_context = rfx_context_new(TRUE);
context->rfx_context->mode = RLGR3;
context->rfx_context->width = server->width;
context->rfx_context->height = server->height;
client->rfx_context = rfx_context_new(TRUE);
client->rfx_context->mode = RLGR3;
client->rfx_context->width = server->width;
client->rfx_context->height = server->height;
rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8);
rfx_context_set_pixel_format(client->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8);
context->s = Stream_New(NULL, 65536);
Stream_Clear(context->s);
client->s = Stream_New(NULL, 65536);
Stream_Clear(client->s);
return client;
}
void x11_shadow_peer_context_free(freerdp_peer* client, x11ShadowClient* context)
void x11_shadow_client_free(x11ShadowClient* client)
{
x11ShadowServer* server;
if (context)
{
server = context->server;
if (!client)
return;
if (server->display)
XCloseDisplay(server->display);
server = client->server;
Stream_Free(context->s, TRUE);
rfx_context_free(context->rfx_context);
}
}
if (server->display)
XCloseDisplay(server->display);
void x11_shadow_peer_init(freerdp_peer* client)
{
client->ContextSize = sizeof(x11ShadowClient);
client->ContextNew = (psPeerContextNew) x11_shadow_peer_context_new;
client->ContextFree = (psPeerContextFree) x11_shadow_peer_context_free;
freerdp_peer_context_new(client);
}
BOOL x11_shadow_peer_capabilities(freerdp_peer* client)
{
return TRUE;
}
BOOL x11_shadow_peer_post_connect(freerdp_peer* client)
{
x11ShadowClient* context;
x11ShadowServer* server;
context = (x11ShadowClient*) client->context;
server = context->server;
fprintf(stderr, "Client %s is activated", client->hostname);
if (client->settings->AutoLogonEnabled)
{
fprintf(stderr, " and wants to login automatically as %s\\%s",
client->settings->Domain ? client->settings->Domain : "",
client->settings->Username);
}
fprintf(stderr, "\n");
fprintf(stderr, "Client requested desktop: %dx%dx%d\n",
client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth);
if (!client->settings->RemoteFxCodec)
{
fprintf(stderr, "Client does not support RemoteFX\n");
return FALSE;
}
client->settings->DesktopWidth = server->width;
client->settings->DesktopHeight = server->height;
client->update->DesktopResize(client->update->context);
return TRUE;
Stream_Free(client->s, TRUE);
rfx_context_free(client->rfx_context);
}
BOOL x11_shadow_peer_activate(freerdp_peer* client)
@ -363,163 +324,8 @@ BOOL x11_shadow_peer_activate(freerdp_peer* client)
server->activePeerCount++;
context->monitorThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) x11_shadow_update_thread, (void*) client, 0, NULL);
context->monitorThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
x11_shadow_update_thread, (void*) client, 0, NULL);
return TRUE;
}
const char* makecert_argv[4] =
{
"makecert",
"-rdp",
"-live",
"-silent"
};
int makecert_argc = (sizeof(makecert_argv) / sizeof(char*));
int x11_shadow_generate_certificate(rdpSettings* settings)
{
char* server_file_path;
MAKECERT_CONTEXT* context;
server_file_path = GetCombinedPath(settings->ConfigPath, "server");
if (!PathFileExistsA(server_file_path))
CreateDirectoryA(server_file_path, 0);
settings->CertificateFile = GetCombinedPath(server_file_path, "server.crt");
settings->PrivateKeyFile = GetCombinedPath(server_file_path, "server.key");
if ((!PathFileExistsA(settings->CertificateFile)) ||
(!PathFileExistsA(settings->PrivateKeyFile)))
{
context = makecert_context_new();
makecert_context_process(context, makecert_argc, (char**) makecert_argv);
makecert_context_set_output_file_name(context, "server");
if (!PathFileExistsA(settings->CertificateFile))
makecert_context_output_certificate_file(context, server_file_path);
if (!PathFileExistsA(settings->PrivateKeyFile))
makecert_context_output_private_key_file(context, server_file_path);
makecert_context_free(context);
}
free(server_file_path);
return 0;
}
static void* x11_shadow_client_thread(void* arg)
{
int i;
int fds;
int max_fds;
int rcount;
void* rfds[32];
fd_set rfds_set;
rdpSettings* settings;
x11ShadowClient* xfp;
struct timeval timeout;
freerdp_peer* client = (freerdp_peer*) arg;
ZeroMemory(rfds, sizeof(rfds));
ZeroMemory(&timeout, sizeof(struct timeval));
fprintf(stderr, "We've got a client %s\n", client->hostname);
x11_shadow_peer_init(client);
xfp = (x11ShadowClient*) client->context;
settings = client->settings;
x11_shadow_generate_certificate(settings);
settings->RemoteFxCodec = TRUE;
settings->ColorDepth = 32;
settings->NlaSecurity = FALSE;
settings->TlsSecurity = TRUE;
settings->RdpSecurity = FALSE;
client->Capabilities = x11_shadow_peer_capabilities;
client->PostConnect = x11_shadow_peer_post_connect;
client->Activate = x11_shadow_peer_activate;
x11_shadow_input_register_callbacks(client->input);
client->Initialize(client);
while (1)
{
rcount = 0;
if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE)
{
fprintf(stderr, "Failed to get FreeRDP file descriptor\n");
break;
}
max_fds = 0;
FD_ZERO(&rfds_set);
for (i = 0; i < rcount; i++)
{
fds = (int)(long)(rfds[i]);
if (fds > max_fds)
max_fds = fds;
FD_SET(fds, &rfds_set);
}
if (max_fds == 0)
break;
timeout.tv_sec = 0;
timeout.tv_usec = 100;
if (select(max_fds + 1, &rfds_set, NULL, NULL, &timeout) == -1)
{
/* these are not really errors */
if (!((errno == EAGAIN) ||
(errno == EWOULDBLOCK) ||
(errno == EINPROGRESS) ||
(errno == EINTR))) /* signal occurred */
{
fprintf(stderr, "select failed\n");
break;
}
}
if (client->CheckFileDescriptor(client) != TRUE)
{
//fprintf(stderr, "Failed to check freerdp file descriptor\n");
//break;
}
}
fprintf(stderr, "Client %s disconnected.\n", client->hostname);
client->Disconnect(client);
freerdp_peer_context_free(client);
freerdp_peer_free(client);
ExitThread(0);
return NULL;
}
void x11_shadow_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
{
HANDLE thread;
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
x11_shadow_client_thread, client, 0, NULL);
}

View File

@ -29,114 +29,14 @@
#include "x11_shadow.h"
void* x11_shadow_server_thread(void* param)
{
int i;
int fds;
int max_fds;
int rcount;
void* rfds[32];
fd_set rfds_set;
x11ShadowServer* server;
freerdp_listener* listener;
server = (x11ShadowServer*) param;
listener = server->listener;
while (1)
{
rcount = 0;
ZeroMemory(rfds, sizeof(rfds));
if (listener->GetFileDescriptor(listener, rfds, &rcount) != TRUE)
{
fprintf(stderr, "Failed to get FreeRDP file descriptor\n");
break;
}
max_fds = 0;
FD_ZERO(&rfds_set);
for (i = 0; i < rcount; i++)
{
fds = (int)(long)(rfds[i]);
if (fds > max_fds)
max_fds = fds;
FD_SET(fds, &rfds_set);
}
if (max_fds == 0)
break;
if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1)
{
/* these are not really errors */
if (!((errno == EAGAIN) ||
(errno == EWOULDBLOCK) ||
(errno == EINPROGRESS) ||
(errno == EINTR))) /* signal occurred */
{
fprintf(stderr, "select failed\n");
break;
}
}
if (listener->CheckFileDescriptor(listener) != TRUE)
{
fprintf(stderr, "Failed to check FreeRDP file descriptor\n");
break;
}
}
ExitThread(0);
return NULL;
}
int x11_shadow_server_start(x11ShadowServer* server)
{
server->thread = NULL;
if (server->listener->Open(server->listener, NULL, 3389))
{
server->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
x11_shadow_server_thread, (void*) server, 0, NULL);
}
return 0;
}
int x11_shadow_server_stop(x11ShadowServer* server)
{
if (server->thread)
{
TerminateThread(server->thread, 0);
WaitForSingleObject(server->thread, INFINITE);
CloseHandle(server->thread);
server->listener->Close(server->listener);
}
return 0;
}
HANDLE x11_shadow_server_get_thread(x11ShadowServer* server)
{
return server->thread;
}
x11ShadowServer* x11_shadow_server_new(int argc, char** argv)
x11ShadowServer* x11_shadow_server_new(rdpShadowServer* rdp)
{
x11ShadowServer* server;
server = (x11ShadowServer*) malloc(sizeof(x11ShadowServer));
server = (x11ShadowServer*) calloc(1, sizeof(x11ShadowServer));
if (server)
{
server->listener = freerdp_listener_new();
server->listener->PeerAccepted = x11_shadow_peer_accepted;
}
if (!server)
return NULL;
signal(SIGPIPE, SIG_IGN);
@ -145,9 +45,8 @@ x11ShadowServer* x11_shadow_server_new(int argc, char** argv)
void x11_shadow_server_free(x11ShadowServer* server)
{
if (server)
{
freerdp_listener_free(server->listener);
free(server);
}
if (!server)
return;
free(server);
}

View File

@ -19,33 +19,23 @@
#ifndef FREERDP_SHADOW_SERVER_X11_H
#define FREERDP_SHADOW_SERVER_X11_H
#include <winpr/crt.h>
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#include <freerdp/server/shadow.h>
typedef struct x11_shadow_client x11ShadowClient;
typedef struct x11_shadow_server x11ShadowServer;
#ifdef __cplusplus
extern "C" {
#endif
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
FREERDP_API int x11_shadow_server_start(x11ShadowServer* server);
FREERDP_API int x11_shadow_server_stop(x11ShadowServer* server);
FREERDP_API HANDLE x11_shadow_server_get_thread(x11ShadowServer* server);
FREERDP_API x11ShadowServer* x11_shadow_server_new(int argc, char** argv);
FREERDP_API void x11_shadow_server_free(x11ShadowServer* server);
#ifdef __cplusplus
}
#endif
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/gdi/dc.h>
#include <freerdp/gdi/region.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/listener.h>
#include <freerdp/codec/color.h>
#include <freerdp/utils/stopwatch.h>
#include <X11/Xlib.h>
@ -103,21 +93,6 @@ struct x11_shadow_server
#endif
};
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/gdi/dc.h>
#include <freerdp/gdi/region.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/listener.h>
#include <freerdp/utils/stopwatch.h>
typedef struct x11_shadow_client x11ShadowClient;
struct x11_shadow_client
{
rdpContext _p;
@ -129,16 +104,24 @@ struct x11_shadow_client
x11ShadowServer* server;
};
void x11_shadow_peer_accepted(freerdp_listener* instance, freerdp_peer* client);
#ifdef __cplusplus
extern "C" {
#endif
void* x11_shadow_server_thread(void* param);
FREERDP_API x11ShadowServer* x11_shadow_server_new(rdpShadowServer* rdp);
FREERDP_API void x11_shadow_server_free(x11ShadowServer* server);
x11ShadowClient* x11_shadow_client_new(rdpShadowClient* rdp);
void x11_shadow_client_free(x11ShadowClient* client);
void* x11_shadow_update_thread(void* param);
int x11_shadow_cursor_init(x11ShadowServer* server);
void x11_shadow_input_register_callbacks(rdpInput* input);
int x11_shadow_update_encode(freerdp_peer* client, int x, int y, int width, int height);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_SHADOW_SERVER_X11_H */

View File

@ -22,18 +22,14 @@
#include "shadow.h"
#include "X11/x11_shadow.h"
void* shadow_server_thread(void* param)
void* shadow_server_thread(rdpShadowServer* server)
{
DWORD status;
DWORD nCount;
HANDLE events[32];
rdpShadowServer* server;
freerdp_listener* listener;
server = (rdpShadowServer*) param;
listener = (freerdp_listener*) server->listener;
listener = server->listener;
while (1)
{
@ -95,51 +91,45 @@ rdpShadowServer* shadow_server_new(int argc, char** argv)
{
rdpShadowServer* server;
server = (rdpShadowServer*) malloc(sizeof(rdpShadowServer));
server = (rdpShadowServer*) calloc(1, sizeof(rdpShadowServer));
if (server)
{
server->port = 3389;
if (!server)
return NULL;
server->listener = freerdp_listener_new();
server->listener->PeerAccepted = shadow_client_accepted;
}
server->port = 3389;
server->listener = freerdp_listener_new();
if (!server->listener)
return NULL;
server->listener->info = (void*) server;
server->listener->PeerAccepted = shadow_client_accepted;
server->ext = x11_shadow_server_new(server);
if (!server->ext)
return NULL;
return server;
}
void shadow_server_free(rdpShadowServer* server)
{
if (server)
{
freerdp_listener_free(server->listener);
free(server);
}
if (!server)
return;
freerdp_listener_free(server->listener);
x11_shadow_server_free(server->ext);
free(server);
}
int main(int argc, char* argv[])
{
HANDLE thread;
DWORD dwExitCode;
#if 1
x11ShadowServer* server;
server = x11_shadow_server_new(argc, argv);
if (!server)
return 0;
x11_shadow_server_start(server);
thread = x11_shadow_server_get_thread(server);
WaitForSingleObject(thread, INFINITE);
GetExitCodeThread(thread, &dwExitCode);
x11_shadow_server_free(server);
#else
rdpShadowServer* server;
server = shadow_server_new(argc, argv);
@ -156,7 +146,6 @@ int main(int argc, char* argv[])
GetExitCodeThread(thread, &dwExitCode);
shadow_server_free(server);
#endif
return 0;
}

View File

@ -20,28 +20,9 @@
#ifndef FREERDP_SHADOW_SERVER_H
#define FREERDP_SHADOW_SERVER_H
#include <winpr/crt.h>
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#include <freerdp/listener.h>
#include <freerdp/server/shadow.h>
typedef struct rdp_shadow_client rdpShadowClient;
typedef struct rdp_shadow_server rdpShadowServer;
struct rdp_shadow_client
{
rdpContext context;
};
struct rdp_shadow_server
{
DWORD port;
HANDLE thread;
freerdp_listener* listener;
};
#include "X11/x11_shadow.h"
#ifdef __cplusplus
extern "C" {

View File

@ -30,55 +30,52 @@
#include "shadow.h"
void shadow_client_context_new(freerdp_peer* client, rdpShadowClient* context)
void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
{
rdpShadowServer* server;
server = (rdpShadowServer*) peer->ContextExtra;
client->server = server;
client->ext = x11_shadow_client_new(client);
}
void shadow_client_context_free(freerdp_peer* client, rdpShadowClient* context)
void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
{
x11_shadow_client_free(client->ext);
}
void shadow_client_init(freerdp_peer* client)
{
client->ContextSize = sizeof(rdpShadowClient);
client->ContextNew = (psPeerContextNew) shadow_client_context_new;
client->ContextFree = (psPeerContextFree) shadow_client_context_free;
freerdp_peer_context_new(client);
}
BOOL shadow_client_get_fds(freerdp_peer* client, void** rfds, int* rcount)
BOOL shadow_client_get_fds(freerdp_peer* peer, void** rfds, int* rcount)
{
return TRUE;
}
BOOL shadow_client_check_fds(freerdp_peer* client)
BOOL shadow_client_check_fds(freerdp_peer* peer)
{
return TRUE;
}
BOOL shadow_client_capabilities(freerdp_peer* client)
BOOL shadow_client_capabilities(freerdp_peer* peer)
{
return TRUE;
}
BOOL shadow_client_post_connect(freerdp_peer* client)
BOOL shadow_client_post_connect(freerdp_peer* peer)
{
fprintf(stderr, "Client %s is activated", client->hostname);
fprintf(stderr, "Client %s is activated", peer->hostname);
if (client->settings->AutoLogonEnabled)
if (peer->settings->AutoLogonEnabled)
{
fprintf(stderr, " and wants to login automatically as %s\\%s",
client->settings->Domain ? client->settings->Domain : "",
client->settings->Username);
peer->settings->Domain ? peer->settings->Domain : "",
peer->settings->Username);
}
fprintf(stderr, "\n");
fprintf(stderr, "Client requested desktop: %dx%dx%d\n",
client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth);
peer->settings->DesktopWidth, peer->settings->DesktopHeight, peer->settings->ColorDepth);
if (!client->settings->RemoteFxCodec)
if (!peer->settings->RemoteFxCodec)
{
fprintf(stderr, "Client does not support RemoteFX\n");
return FALSE;
@ -87,12 +84,12 @@ BOOL shadow_client_post_connect(freerdp_peer* client)
//client->settings->DesktopWidth = 1024;
//client->settings->DesktopHeight = 768;
client->update->DesktopResize(client->update->context);
peer->update->DesktopResize(peer->update->context);
return TRUE;
}
BOOL shadow_client_activate(freerdp_peer* client)
BOOL shadow_client_activate(freerdp_peer* peer)
{
return TRUE;
}
@ -143,20 +140,17 @@ int shadow_generate_certificate(rdpSettings* settings)
return 0;
}
void* shadow_client_thread(void* param)
void* shadow_client_thread(rdpShadowClient* client)
{
DWORD status;
DWORD nCount;
HANDLE events[32];
HANDLE ClientEvent;
freerdp_peer* peer;
rdpSettings* settings;
rdpShadowClient* context;
freerdp_peer* client = (freerdp_peer*) param;
shadow_client_init(client);
settings = client->settings;
context = (rdpShadowClient*) client->context;
peer = ((rdpContext*) client)->peer;
settings = peer->settings;
shadow_generate_certificate(settings);
@ -167,15 +161,15 @@ void* shadow_client_thread(void* param)
settings->TlsSecurity = TRUE;
settings->RdpSecurity = FALSE;
client->Capabilities = shadow_client_capabilities;
client->PostConnect = shadow_client_post_connect;
client->Activate = shadow_client_activate;
peer->Capabilities = shadow_client_capabilities;
peer->PostConnect = shadow_client_post_connect;
peer->Activate = shadow_client_activate;
shadow_input_register_callbacks(client->input);
shadow_input_register_callbacks(peer->input);
client->Initialize(client);
peer->Initialize(peer);
ClientEvent = client->GetEventHandle(client);
ClientEvent = peer->GetEventHandle(peer);
while (1)
{
@ -186,7 +180,7 @@ void* shadow_client_thread(void* param)
if (WaitForSingleObject(ClientEvent, 0) == WAIT_OBJECT_0)
{
if (!client->CheckFileDescriptor(client))
if (!peer->CheckFileDescriptor(peer))
{
fprintf(stderr, "Failed to check FreeRDP file descriptor\n");
break;
@ -194,20 +188,32 @@ void* shadow_client_thread(void* param)
}
}
client->Disconnect(client);
peer->Disconnect(peer);
freerdp_peer_context_free(client);
freerdp_peer_free(client);
freerdp_peer_context_free(peer);
freerdp_peer_free(peer);
ExitThread(0);
return NULL;
}
void shadow_client_accepted(freerdp_listener* instance, freerdp_peer* client)
void shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
{
HANDLE thread;
rdpShadowClient* client;
rdpShadowServer* server;
thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) shadow_client_thread, client, 0, NULL);
server = (rdpShadowServer*) listener->info;
peer->ContextExtra = (void*) server;
peer->ContextSize = sizeof(rdpShadowClient);
peer->ContextNew = (psPeerContextNew) shadow_client_context_new;
peer->ContextFree = (psPeerContextFree) shadow_client_context_free;
freerdp_peer_context_new(peer);
client = (rdpShadowClient*) peer->context;
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
shadow_client_thread, client, 0, NULL);
}