server: proxy: sync server and client channels
authorkubistika <kmizrachi18@gmail.com>
Thu, 1 Aug 2019 13:55:50 +0000 (16:55 +0300)
committerakallabeth <akallabeth@users.noreply.github.com>
Fri, 2 Aug 2019 08:17:45 +0000 (10:17 +0200)
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.

server/proxy/pf_channels.c
server/proxy/pf_channels.h
server/proxy/pf_context.h
server/proxy/pf_rdpgfx.c
server/proxy/pf_server.c

index f728d71..922a29b 100644 (file)
 
 #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;
+       }
+}
index 023ab00..cdfb90e 100644 (file)
 #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 */
index 7777500..815a740 100644 (file)
@@ -50,8 +50,6 @@ struct p_server_context
 
        RdpgfxServerContext* gfx;
        DispServerContext* disp;
-
-       BOOL dispOpened;
 };
 typedef struct p_server_context pServerContext;
 
index f7a42fc..de885d1 100644 (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,
index 12252d4..f2c284a 100644 (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);