server: proxy: sync server and client channels

when disconnections/redirections occured, sometimes server/client
channels were not synced, meaning that for example the gfx server
received a message, then tried to use gfx client that was already freed.
This commit is contained in:
kubistika 2019-08-01 16:55:50 +03:00 committed by akallabeth
parent 8e7386a57d
commit 038c933f98
5 changed files with 67 additions and 53 deletions

View File

@ -41,14 +41,13 @@
#define TAG PROXY_TAG("channels")
void pf_OnChannelConnectedEventHandler(void* context,
void pf_OnChannelConnectedEventHandler(void* data,
ChannelConnectedEventArgs* e)
{
pClientContext* pc = (pClientContext*) context;
pClientContext* pc = (pClientContext*) data;
pServerContext* ps = pc->pdata->ps;
RdpgfxClientContext* gfx;
RdpgfxServerContext* server;
WLog_DBG(TAG, "Channel connected: %s", e->name);
WLog_INFO(TAG, "Channel connected: %s", e->name);
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
{
@ -56,40 +55,36 @@ void pf_OnChannelConnectedEventHandler(void* context,
}
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
{
gfx = (RdpgfxClientContext*) e->pInterface;
pc->gfx = gfx;
server = ps->gfx;
pf_rdpgfx_pipeline_init(gfx, server, pc->pdata);
pc->gfx = (RdpgfxClientContext*) e->pInterface;
pf_rdpgfx_pipeline_init(pc->gfx, ps->gfx, pc->pdata);
if (!ps->gfx->Open(ps->gfx))
{
WLog_ERR(TAG, "failed to open GFX server");
return;
}
}
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
{
UINT error;
pc->disp = (DispClientContext*) e->pInterface;
ps->dispOpened = FALSE;
pf_disp_register_callbacks(pc->disp, ps->disp, pc->pdata);
if ((error = ps->disp->Open(ps->disp)) != CHANNEL_RC_OK)
if (ps->disp->Open(ps->disp) != CHANNEL_RC_OK)
{
if (error == ERROR_NOT_FOUND)
{
/* disp is not opened by client, ignore */
return;
}
WLog_WARN(TAG, "Failed to open disp channel");
WLog_ERR(TAG, "failed to open disp channel");
return;
}
ps->dispOpened = TRUE;
pf_disp_register_callbacks(pc->disp, ps->disp, pc->pdata);
}
}
void pf_OnChannelDisconnectedEventHandler(void* context,
void pf_OnChannelDisconnectedEventHandler(void* data,
ChannelDisconnectedEventArgs* e)
{
rdpContext* context = (rdpContext*) data;
pClientContext* pc = (pClientContext*) context;
rdpSettings* settings;
settings = ((rdpContext*)pc)->settings;
pServerContext* ps = pc->pdata->ps;
WLog_INFO(TAG, "Channel disconnected: %s", e->name);
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
{
@ -97,10 +92,42 @@ void pf_OnChannelDisconnectedEventHandler(void* context,
}
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
{
gdi_graphics_pipeline_uninit(((rdpContext*)context)->gdi, (RdpgfxClientContext*) e->pInterface);
if (!ps->gfx->Close(ps->gfx))
WLog_ERR(TAG, "failed to close gfx server");
gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface);
}
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
{
if (ps->disp->Close(ps->disp) != CHANNEL_RC_OK)
WLog_ERR(TAG, "failed to close disp server");
pc->disp = NULL;
}
}
BOOL pf_server_channels_init(pServerContext* ps)
{
if (!pf_server_rdpgfx_init(ps))
return FALSE;
if (!pf_server_disp_init(ps))
return FALSE;
return TRUE;
}
void pf_server_channels_free(pServerContext* ps)
{
if (ps->gfx)
{
rdpgfx_server_context_free(ps->gfx);
ps->gfx = NULL;
}
if (ps->disp)
{
disp_server_context_free(ps->disp);
ps->disp = NULL;
}
}

View File

@ -25,9 +25,14 @@
#include <freerdp/freerdp.h>
#include <freerdp/client/channels.h>
#include "pf_context.h"
void pf_OnChannelConnectedEventHandler(void* context,
ChannelConnectedEventArgs* e);
void pf_OnChannelDisconnectedEventHandler(void* context,
ChannelDisconnectedEventArgs* e);
BOOL pf_server_channels_init(pServerContext* ps);
void pf_server_channels_free(pServerContext* ps);
#endif /* FREERDP_SERVER_PROXY_PFCHANNELS_H */

View File

@ -50,8 +50,6 @@ struct p_server_context
RdpgfxServerContext* gfx;
DispServerContext* disp;
BOOL dispOpened;
};
typedef struct p_server_context pServerContext;

View File

@ -202,7 +202,6 @@ static UINT pf_rdpgfx_on_open(RdpgfxClientContext* context,
BOOL* do_caps_advertise, BOOL* send_frame_acks)
{
proxyData* pdata = (proxyData*) context->custom;
RdpgfxServerContext* server = (RdpgfxServerContext*) pdata->ps->gfx;
WLog_VRB(TAG, __FUNCTION__);
if (NULL != do_caps_advertise)
@ -215,14 +214,7 @@ static UINT pf_rdpgfx_on_open(RdpgfxClientContext* context,
* the GFX DYNVC. */
WLog_DBG(TAG, "Waiting for proxy's server dynvc to be ready");
WaitForSingleObject(pdata->ps->dynvcReady, INFINITE);
/* Check for error since the server's API doesn't return WTSAPI error codes */
if (server->Open(server))
{
return CHANNEL_RC_OK;
}
return CHANNEL_RC_INITIALIZATION_ERROR;
return CHANNEL_RC_OK;
}
static UINT pf_rdpgfx_caps_confirm(RdpgfxClientContext* context,

View File

@ -49,6 +49,7 @@
#include "pf_update.h"
#include "pf_rdpgfx.h"
#include "pf_disp.h"
#include "pf_channels.h"
#define TAG PROXY_TAG("server")
@ -161,8 +162,11 @@ static BOOL pf_server_post_connect(freerdp_peer* client)
WLog_INFO(TAG, "pf_server_post_connect(): target == %s:%"PRIu16"", pc->settings->ServerHostname,
pc->settings->ServerPort);
pf_server_rdpgfx_init(ps);
pf_server_disp_init(ps);
if (!pf_server_channels_init(ps))
{
WLog_ERR(TAG, "pf_server_post_connect(): failed to initialize server's channels!");
return FALSE;
}
/* Start a proxy's client in it's own thread */
if (!(pdata->client_thread = CreateThread(NULL, 0, pf_client_start, pc, 0, NULL)))
@ -336,24 +340,12 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg)
fail:
if (ps->disp)
{
if (ps->dispOpened)
{
WLog_DBG(TAG, "Closing RDPEDISP server");
(void)ps->disp->Close(ps->disp);
}
disp_server_context_free(ps->disp);
}
if (ps->gfx)
rdpgfx_server_context_free(ps->gfx);
pc = (rdpContext*) pdata->pc;
WLog_INFO(TAG, "pf_server_handle_client(): starting shutdown of connection (client %s)", client->hostname);
WLog_INFO(TAG, "pf_server_handle_client(): stopping proxy's client");
freerdp_client_stop(pc);
WLog_INFO(TAG, "pf_server_handle_client(): freeing server's channels");
pf_server_channels_free(ps);
WLog_INFO(TAG, "pf_server_handle_client(): freeing proxy data");
proxy_data_free(pdata);
freerdp_client_context_free(pc);