Refactored proxy

* Removed unnecessary global data lists
* Improved error handling
* Do not initialize channel code in passthrough mode
This commit is contained in:
akallabeth 2021-09-17 09:27:25 +02:00 committed by akallabeth
parent 3ce622b638
commit 695e38398d
6 changed files with 199 additions and 142 deletions

View File

@ -81,8 +81,11 @@ void pf_channels_on_client_channel_connect(void* data, ChannelConnectedEventArgs
}
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
{
if (!ps->rail)
return;
pc->rail = (RailClientContext*)e->pInterface;
WINPR_ASSERT(ps->rail->Start);
if (ps->rail->Start(ps->rail) != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "failed to start RAIL server");
@ -94,9 +97,12 @@ void pf_channels_on_client_channel_connect(void* data, ChannelConnectedEventArgs
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
{
pf_channels_wait_for_server_dynvc(ps);
if (!ps->gfx)
return;
pc->gfx_proxy = (RdpgfxClientContext*)e->pInterface;
pf_rdpgfx_pipeline_init(pc->gfx_proxy, ps->gfx, pc->pdata);
WINPR_ASSERT(ps->gfx->Open);
if (!ps->gfx->Open(ps->gfx))
{
WLog_ERR(TAG, "failed to open GFX server");
@ -109,6 +115,10 @@ void pf_channels_on_client_channel_connect(void* data, ChannelConnectedEventArgs
{
UINT ret;
if (!ps->disp)
return;
WINPR_ASSERT(ps->disp->Open);
ret = ps->disp->Open(ps->disp);
if (ret != CHANNEL_RC_OK)
{
@ -133,6 +143,10 @@ void pf_channels_on_client_channel_connect(void* data, ChannelConnectedEventArgs
}
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
{
if (!ps->cliprdr)
return;
WINPR_ASSERT(ps->cliprdr->Start);
if (ps->cliprdr->Start(ps->cliprdr) != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "failed to open cliprdr channel");
@ -148,6 +162,7 @@ void pf_channels_on_client_channel_connect(void* data, ChannelConnectedEventArgs
if (ps->rdpsnd == NULL)
return;
WINPR_ASSERT(ps->rdpsnd->Initialize);
if (ps->rdpsnd->Initialize(ps->rdpsnd, TRUE) != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "failed to open rdpsnd channel");

View File

@ -47,6 +47,7 @@
#define TAG PROXY_TAG("client")
static void channel_data_free(void* obj);
static BOOL proxy_server_reactivate(rdpContext* ps, const rdpContext* pc)
{
WINPR_ASSERT(ps);
@ -231,10 +232,13 @@ static BOOL pf_client_pre_connect(freerdp* instance)
* Register the channel listeners.
* They are required to set up / tear down channels if they are loaded.
*/
PubSub_SubscribeChannelConnected(instance->context->pubSub,
pf_channels_on_client_channel_connect);
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
pf_channels_on_client_channel_disconnect);
if (!config->PassthroughIsBlacklist || (config->PassthroughCount != 0))
{
PubSub_SubscribeChannelConnected(instance->context->pubSub,
pf_channels_on_client_channel_connect);
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
pf_channels_on_client_channel_disconnect);
}
PubSub_SubscribeErrorInfo(instance->context->pubSub, pf_client_on_error_info);
PubSub_SubscribeActivated(instance->context->pubSub, pf_client_on_activated);
/**
@ -416,35 +420,42 @@ static BOOL pf_client_send_channel_data(pClientContext* pc, const proxyChannelDa
WINPR_ASSERT(pc);
WINPR_ASSERT(ev);
if (!pc->connected)
{
ArrayList_Append(pc->cached_server_channel_data, ev);
return TRUE;
}
else
{
UINT16 channelId;
WINPR_ASSERT(pc->context.instance);
channelId = freerdp_channels_get_id_by_name(pc->context.instance, ev->channel_name);
/* Ignore unmappable channels */
if ((channelId == 0) || (channelId == UINT16_MAX))
return TRUE;
WINPR_ASSERT(pc->context.instance->SendChannelPacket);
return pc->context.instance->SendChannelPacket(
pc->context.instance, channelId, ev->total_size, ev->flags, ev->data, ev->data_len);
}
return Queue_Enqueue(pc->cached_server_channel_data, ev);
}
static BOOL send_channel_data(void* data, size_t index, va_list ap)
static BOOL sendQueuedChannelData(pClientContext* pc)
{
pClientContext* pc = va_arg(ap, pClientContext*);
proxyChannelDataEventInfo* ev = data;
WINPR_ASSERT(ev);
WINPR_ASSERT(pc);
WINPR_UNUSED(index);
BOOL rc = TRUE;
return pf_client_send_channel_data(pc, ev);
WINPR_ASSERT(pc);
if (pc->connected)
{
proxyChannelDataEventInfo* ev;
Queue_Lock(pc->cached_server_channel_data);
while (rc && (ev = Queue_Dequeue(pc->cached_server_channel_data)))
{
UINT16 channelId;
WINPR_ASSERT(pc->context.instance);
channelId = freerdp_channels_get_id_by_name(pc->context.instance, ev->channel_name);
/* Ignore unmappable channels */
if ((channelId == 0) || (channelId == UINT16_MAX))
rc = TRUE;
else
{
WINPR_ASSERT(pc->context.instance->SendChannelPacket);
rc = pc->context.instance->SendChannelPacket(pc->context.instance, channelId,
ev->total_size, ev->flags, ev->data,
ev->data_len);
}
channel_data_free(ev);
}
Queue_Unlock(pc->cached_server_channel_data);
}
return rc;
}
/**
@ -516,10 +527,7 @@ static BOOL pf_client_post_connect(freerdp* instance)
pc->connected = TRUE;
/* Send cached channel data */
ArrayList_Lock(pc->cached_server_channel_data);
ArrayList_ForEach(pc->cached_server_channel_data, send_channel_data, pc);
ArrayList_Clear(pc->cached_server_channel_data);
ArrayList_Unlock(pc->cached_server_channel_data);
sendQueuedChannelData(pc);
/*
* after the connection fully established and settings were negotiated with target server,
@ -630,7 +638,7 @@ static BOOL pf_client_connect_without_nla(pClientContext* pc)
/* do not allow next connection failure */
pc->allow_next_conn_failure = FALSE;
return freerdp_connect(instance);
return freerdp_reconnect(instance);
}
static BOOL pf_client_connect(freerdp* instance)
@ -717,13 +725,14 @@ static DWORD WINAPI pf_client_thread_proc(pClientContext* pc)
proxy_data_abort_connect(pdata);
return FALSE;
}
handles[nCount++] = Queue_Event(pc->cached_server_channel_data);
while (!freerdp_shall_disconnect(instance))
{
UINT32 tmp = freerdp_get_event_handles(instance->context, &handles[nCount],
ARRAYSIZE(handles) - nCount);
if (tmp == 0)
if ((tmp == 0) || (nCount + tmp > ARRAYSIZE(handles)))
{
PROXY_LOG_ERR(TAG, pc, "freerdp_get_event_handles failed!");
break;
@ -755,6 +764,7 @@ static DWORD WINAPI pf_client_thread_proc(pClientContext* pc)
break;
}
sendQueuedChannelData(pc);
}
freerdp_disconnect(instance);
@ -785,7 +795,7 @@ static void pf_client_context_free(freerdp* instance, rdpContext* context)
return;
pc->sendChannelData = NULL;
ArrayList_Free(pc->cached_server_channel_data);
Queue_Free(pc->cached_server_channel_data);
Stream_Free(pc->remote_pem, TRUE);
free(pc->remote_hostname);
}
@ -824,7 +834,7 @@ static int pf_client_verify_X509_certificate(freerdp* instance, const BYTE* data
return 1;
}
static void channel_data_free(void* obj)
void channel_data_free(void* obj)
{
proxyChannelDataEventInfo* dst = obj;
if (dst)
@ -883,10 +893,10 @@ static BOOL pf_client_client_new(freerdp* instance, rdpContext* context)
return FALSE;
pc->sendChannelData = pf_client_send_channel_data;
pc->cached_server_channel_data = ArrayList_New(TRUE);
pc->cached_server_channel_data = Queue_New(TRUE, -1, -1);
if (!pc->cached_server_channel_data)
return FALSE;
obj = ArrayList_Object(pc->cached_server_channel_data);
obj = Queue_Object(pc->cached_server_channel_data);
WINPR_ASSERT(obj);
obj->fnObjectNew = channel_data_copy;
obj->fnObjectFree = channel_data_free;

View File

@ -266,8 +266,8 @@ static BOOL pf_config_load_modules(wIniFile* ini, proxyConfig* config)
const char* modules_to_load;
const char* required_modules;
modules_to_load = IniFile_GetKeyValueString(ini, "Plugins", "Modules");
required_modules = IniFile_GetKeyValueString(ini, "Plugins", "Required");
modules_to_load = pf_config_get_str(ini, "Plugins", "Modules", FALSE);
required_modules = pf_config_get_str(ini, "Plugins", "Required", FALSE);
WINPR_ASSERT(config);
config->Modules = pf_config_parse_comma_separated_list(modules_to_load, &config->ModulesCount);

View File

@ -30,6 +30,7 @@
#include <freerdp/server/proxy/proxy_context.h>
/* Proxy context initialization callback */
static void client_to_proxy_context_free(freerdp_peer* client, rdpContext* ctx);
static BOOL client_to_proxy_context_new(freerdp_peer* client, rdpContext* ctx)
{
pServerContext* context = (pServerContext*)ctx;
@ -50,27 +51,24 @@ static BOOL client_to_proxy_context_new(freerdp_peer* client, rdpContext* ctx)
return TRUE;
error:
WTSCloseServer((HANDLE)context->vcm);
context->vcm = NULL;
if (context->dynvcReady)
{
CloseHandle(context->dynvcReady);
context->dynvcReady = NULL;
}
client_to_proxy_context_free(client, ctx);
return FALSE;
}
/* Proxy context free callback */
static void client_to_proxy_context_free(freerdp_peer* client, rdpContext* ctx)
void client_to_proxy_context_free(freerdp_peer* client, rdpContext* ctx)
{
pServerContext* context = (pServerContext*)ctx;
if (!client || !context)
WINPR_UNUSED(client);
if (!context)
return;
WTSCloseServer((HANDLE)context->vcm);
if (context->vcm && (context->vcm != INVALID_HANDLE_VALUE))
WTSCloseServer((HANDLE)context->vcm);
context->vcm = NULL;
if (context->dynvcReady)
{
@ -270,6 +268,8 @@ void proxy_data_abort_connect(proxyData* pdata)
WINPR_ASSERT(pdata);
WINPR_ASSERT(pdata->abort_event);
SetEvent(pdata->abort_event);
if (pdata->pc)
freerdp_abort_connect(pdata->pc->context.instance);
}
BOOL proxy_data_shall_disconnect(proxyData* pdata)

View File

@ -21,8 +21,12 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/ssl.h>
#include <winpr/path.h>
#include <winpr/synch.h>
#include <winpr/string.h>
#include <winpr/winsock.h>
@ -377,9 +381,10 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
pdata = proxy_data_new();
if (!pdata)
return FALSE;
server = (proxyServer*)peer->ContextExtra;
WINPR_ASSERT(server);
proxy_data_set_server_context(pdata, ps);
server = (proxyServer*)peer->ContextExtra;
pdata->module = server->module;
config = pdata->config = server->config;
@ -390,6 +395,13 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
settings->SupportMonitorLayoutPdu = TRUE;
settings->SupportGraphicsPipeline = config->GFX;
if ((config->PassthroughCount > 0) || config->PassthroughIsBlacklist)
{
if (!freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, TRUE))
return FALSE;
}
if (!freerdp_settings_set_string(settings, FreeRDP_CertificateFile, config->CertificateFile) ||
!freerdp_settings_set_string(settings, FreeRDP_CertificateContent,
config->CertificateContent) ||
@ -433,10 +445,6 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
pdata->server_receive_channel_data_original = peer->ReceiveChannelData;
peer->ReceiveChannelData = pf_server_receive_channel_data_hook;
if (!ArrayList_Append(server->clients, pdata))
return FALSE;
CountdownEvent_AddCount(server->waitGroup, 1);
return TRUE;
}
@ -447,21 +455,28 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
*/
static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
{
HANDLE eventHandles[32] = { 0 };
HANDLE ChannelEvent;
DWORD eventCount;
HANDLE eventHandles[MAXIMUM_WAIT_OBJECTS] = { 0 };
DWORD tmp;
DWORD status;
pServerContext* ps;
proxyData* pdata;
pServerContext* ps = NULL;
proxyData* pdata = NULL;
freerdp_peer* client = (freerdp_peer*)arg;
proxyServer* server;
size_t count;
BOOL rc;
WINPR_ASSERT(client);
server = (proxyServer*)client->ContextExtra;
WINPR_ASSERT(server);
ArrayList_Lock(server->peer_list);
rc = ArrayList_Append(server->peer_list, _GetCurrentThread());
count = ArrayList_Count(server->peer_list);
ArrayList_Unlock(server->peer_list);
if (!rc)
goto out_free_peer;
if (!pf_context_init_server_context(client))
goto out_free_peer;
@ -470,6 +485,7 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
ps = (pServerContext*)client->context;
WINPR_ASSERT(ps);
PROXY_LOG_DBG(TAG, ps, "Added peer, %" PRIuz " connected", count);
pdata = ps->pdata;
WINPR_ASSERT(pdata);
@ -479,17 +495,17 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
PROXY_LOG_INFO(TAG, ps, "new connection: proxy address: %s, client address: %s",
pdata->config->Host, client->hostname);
/* Main client event handling loop */
ChannelEvent = WTSVirtualChannelManagerGetEventHandle(ps->vcm);
while (1)
{
eventCount = 0;
HANDLE ChannelEvent = INVALID_HANDLE_VALUE;
DWORD eventCount = 0;
{
WINPR_ASSERT(client->GetEventHandles);
tmp = client->GetEventHandles(client, &eventHandles[eventCount], 32 - eventCount);
tmp = client->GetEventHandles(client, &eventHandles[eventCount],
ARRAYSIZE(eventHandles) - eventCount);
if (tmp == 0)
if ((tmp == 0) || (tmp >= ARRAYSIZE(eventHandles) - 2))
{
WLog_ERR(TAG, "Failed to get FreeRDP transport event handles");
break;
@ -497,10 +513,17 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
eventCount += tmp;
}
/* Main client event handling loop */
ChannelEvent = WTSVirtualChannelManagerGetEventHandle(ps->vcm);
WINPR_ASSERT(ChannelEvent && (ChannelEvent != INVALID_HANDLE_VALUE));
WINPR_ASSERT(pdata->abort_event && (pdata->abort_event != INVALID_HANDLE_VALUE));
eventHandles[eventCount++] = ChannelEvent;
eventHandles[eventCount++] = pdata->abort_event;
eventHandles[eventCount++] = WTSVirtualChannelManagerGetEventHandle(ps->vcm);
status = WaitForMultipleObjects(eventCount, eventHandles, FALSE, INFINITE);
eventHandles[eventCount++] = server->stopEvent;
status = WaitForMultipleObjects(eventCount, eventHandles, FALSE,
1000); /* Do periodic polling to avoid client hang */
if (status == WAIT_FAILED)
{
@ -528,6 +551,12 @@ static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
break;
}
if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
{
WLog_INFO(TAG, "Server shutting down, terminating peer");
break;
}
switch (WTSVirtualChannelManagerGetDrdynvcState(ps->vcm))
{
/* Dynamic channel status may have been changed after processing */
@ -560,45 +589,14 @@ fail:
PROXY_LOG_INFO(TAG, ps, "starting shutdown of connection");
PROXY_LOG_INFO(TAG, ps, "stopping proxy's client");
if (pdata->client_thread)
{
if (pdata->pc)
freerdp_abort_connect(pdata->pc->context.instance);
/*
* Wait for client thread to finish. No need to call CloseHandle() here, as
* it is the responsibility of `proxy_data_free`.
*/
PROXY_LOG_DBG(TAG, pdata->pc, "waiting for client thread to finish");
WaitForSingleObject(pdata->client_thread, INFINITE);
PROXY_LOG_DBG(TAG, pdata->pc, "thread finished");
}
/* Abort the client. */
proxy_data_abort_connect(pdata);
pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_END, pdata, client);
if (pdata->client_thread)
{
if (pdata->pc)
freerdp_abort_connect(pdata->pc->context.instance);
/*
* Wait for client thread to finish. No need to call CloseHandle() here, as
* it is the responsibility of `proxy_data_free`.
*/
PROXY_LOG_DBG(TAG, pdata->pc, "waiting for client thread to finish");
WaitForSingleObject(pdata->client_thread, INFINITE);
PROXY_LOG_DBG(TAG, pdata->pc, "thread finished");
if (pdata->pc)
{
freerdp_client_context_free(&pdata->pc->context);
pdata->pc = NULL;
}
}
PROXY_LOG_INFO(TAG, ps, "freeing server's channels");
pf_server_channels_free(ps, client);
PROXY_LOG_INFO(TAG, ps, "freeing proxy data");
ArrayList_Remove(server->clients, pdata);
proxy_data_free(pdata);
WINPR_ASSERT(client->Close);
client->Close(client);
@ -607,9 +605,26 @@ fail:
client->Disconnect(client);
out_free_peer:
PROXY_LOG_INFO(TAG, ps, "freeing proxy data");
if (pdata && pdata->client_thread)
{
proxy_data_abort_connect(pdata);
WaitForSingleObject(pdata->client_thread, INFINITE);
}
ArrayList_Lock(server->peer_list);
ArrayList_Remove(server->peer_list, _GetCurrentThread());
count = ArrayList_Count(server->peer_list);
ArrayList_Unlock(server->peer_list);
PROXY_LOG_DBG(TAG, ps, "Removed peer, %" PRIuz " connected", count);
freerdp_peer_context_free(client);
freerdp_peer_free(client);
CountdownEvent_Signal(server->waitGroup, 1);
proxy_data_free(pdata);
#if defined(WITH_DEBUG_EVENTS)
DumpEventHandles();
#endif
ExitThread(0);
return 0;
}
@ -617,13 +632,17 @@ out_free_peer:
static BOOL pf_server_start_peer(freerdp_peer* client)
{
HANDLE hThread;
proxyServer* server;
WINPR_ASSERT(client);
if (!(hThread = CreateThread(NULL, 0, pf_server_handle_peer, (void*)client, 0, NULL)))
server = (proxyServer*)client->ContextExtra;
WINPR_ASSERT(server);
hThread = CreateThread(NULL, 0, pf_server_handle_peer, (void*)client, 0, NULL);
if (!hThread)
return FALSE;
CloseHandle(hThread);
return TRUE;
}
@ -746,12 +765,6 @@ fail:
return FALSE;
}
static void pf_server_clients_list_client_free(void* obj)
{
proxyData* pdata = (proxyData*)obj;
proxy_data_abort_connect(pdata);
}
static BOOL are_all_required_modules_loaded(proxyModule* module, const proxyConfig* config)
{
size_t i;
@ -770,6 +783,17 @@ static BOOL are_all_required_modules_loaded(proxyModule* module, const proxyConf
return TRUE;
}
static void peer_free(void* obj)
{
HANDLE hdl = (HANDLE)obj;
// TODO: Stop thread
if (hdl != _GetCurrentThread())
WaitForSingleObject(hdl, INFINITE);
CloseHandle(hdl);
}
proxyServer* pf_server_new(const proxyConfig* config)
{
wObject* obj;
@ -800,21 +824,19 @@ proxyServer* pf_server_new(const proxyConfig* config)
if (!server->stopEvent)
goto out;
server->clients = ArrayList_New(TRUE);
if (!server->clients)
goto out;
obj = ArrayList_Object(server->clients);
obj->fnObjectFree = pf_server_clients_list_client_free;
server->waitGroup = CountdownEvent_New(0);
if (!server->waitGroup)
goto out;
server->listener = freerdp_listener_new();
if (!server->listener)
goto out;
server->peer_list = ArrayList_New(TRUE);
if (!server->peer_list)
goto out;
obj = ArrayList_Object(server->peer_list);
WINPR_ASSERT(obj);
obj->fnObjectFree = peer_free;
server->listener->info = server;
server->listener->PeerAccepted = pf_server_peer_accepted;
return server;
@ -827,7 +849,7 @@ out:
BOOL pf_server_run(proxyServer* server)
{
BOOL rc = TRUE;
HANDLE eventHandles[32] = { 0 };
HANDLE eventHandles[MAXIMUM_WAIT_OBJECTS] = { 0 };
DWORD eventCount;
DWORD status;
freerdp_listener* listener;
@ -840,9 +862,9 @@ BOOL pf_server_run(proxyServer* server)
while (1)
{
WINPR_ASSERT(listener->GetEventHandles);
eventCount = listener->GetEventHandles(listener, eventHandles, 32);
eventCount = listener->GetEventHandles(listener, eventHandles, ARRAYSIZE(eventHandles));
if (0 == eventCount)
if ((0 == eventCount) || (eventCount >= ARRAYSIZE(eventHandles)))
{
WLog_ERR(TAG, "Failed to get FreeRDP event handles");
break;
@ -850,7 +872,10 @@ BOOL pf_server_run(proxyServer* server)
WINPR_ASSERT(server->stopEvent);
eventHandles[eventCount++] = server->stopEvent;
status = WaitForMultipleObjects(eventCount, eventHandles, FALSE, INFINITE);
status = WaitForMultipleObjects(eventCount, eventHandles, FALSE, 1000);
if (WAIT_FAILED == status)
break;
if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
break;
@ -865,9 +890,9 @@ BOOL pf_server_run(proxyServer* server)
WINPR_ASSERT(listener->CheckFileDescriptor);
if (listener->CheckFileDescriptor(listener) != TRUE)
{
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
rc = FALSE;
break;
WLog_ERR(TAG, "Failed to accept new peer");
// TODO: Set out of resource error
continue;
}
}
@ -876,20 +901,23 @@ BOOL pf_server_run(proxyServer* server)
return rc;
}
static BOOL disconnect_client(void* data, size_t index, va_list ap)
{
proxyData* pdata = data;
WINPR_UNUSED(index);
WINPR_UNUSED(ap);
proxy_data_abort_connect(pdata);
return TRUE;
}
void pf_server_stop(proxyServer* server)
{
HANDLE waitHandle = INVALID_HANDLE_VALUE;
if (!server)
return;
/* clear clients list, also disconnects every client */
ArrayList_Clear(server->clients);
/* block until all clients are disconnected */
waitHandle = CountdownEvent_WaitHandle(server->waitGroup);
if (WaitForSingleObject(waitHandle, INFINITE) != WAIT_OBJECT_0)
WLog_ERR(TAG, "[%s]: WaitForSingleObject failed!", __FUNCTION__);
/* signal main thread to stop and wait for the thread to exit */
SetEvent(server->stopEvent);
@ -900,9 +928,10 @@ void pf_server_free(proxyServer* server)
if (!server)
return;
pf_server_stop(server);
ArrayList_Free(server->peer_list);
freerdp_listener_free(server->listener);
ArrayList_Free(server->clients);
CountdownEvent_Free(server->waitGroup);
if (server->stopEvent)
CloseHandle(server->stopEvent);
@ -910,6 +939,10 @@ void pf_server_free(proxyServer* server)
pf_server_config_free(server->config);
pf_modules_free(server->module);
free(server);
#if defined(WITH_DEBUG_EVENTS)
DumpEventHandles();
#endif
}
BOOL pf_server_add_module(proxyServer* server, proxyModuleEntryPoint ep, void* userdata)

View File

@ -36,9 +36,8 @@ struct proxy_server
proxyConfig* config;
freerdp_listener* listener;
wArrayList* clients; /* maintain a list of active sessions, for stats */
wCountdownEvent* waitGroup; /* wait group used for gracefull shutdown */
HANDLE stopEvent; /* an event used to signal the main thread to stop */
wArrayList* peer_list;
};
#endif /* INT_FREERDP_SERVER_PROXY_SERVER_H */