From 5b2a4434d8becd7b527d5b329eee9915ff8ca77a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 12 May 2020 10:21:06 +0200 Subject: [PATCH 1/2] drdynvc channel cleanup. * Clean channel listeners on channel close * Remove limit on listeners for channels * Remove limit on channels --- channels/drdynvc/client/drdynvc_main.c | 395 +++++++++++++------------ channels/drdynvc/client/drdynvc_main.h | 11 +- 2 files changed, 207 insertions(+), 199 deletions(-) diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index fa09cd08f..93de13318 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -30,6 +30,7 @@ #define TAG CHANNELS_TAG("drdynvc.client") +static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr); static void dvcman_channel_free(void* channel); static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, const BYTE* data, UINT32 dataSize); @@ -67,64 +68,50 @@ static UINT dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr, DVCMAN* dvcman = (DVCMAN*)pChannelMgr; DVCMAN_LISTENER* listener; - if (dvcman->num_listeners < MAX_PLUGINS) + WLog_DBG(TAG, "create_listener: %d.%s.", ArrayList_Count(dvcman->listeners) + 1, + pszChannelName); + listener = (DVCMAN_LISTENER*)calloc(1, sizeof(DVCMAN_LISTENER)); + + if (!listener) { - WLog_DBG(TAG, "create_listener: %d.%s.", dvcman->num_listeners, pszChannelName); - listener = (DVCMAN_LISTENER*)calloc(1, sizeof(DVCMAN_LISTENER)); - - if (!listener) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - listener->iface.GetConfiguration = dvcman_get_configuration; - listener->iface.pInterface = NULL; - listener->dvcman = dvcman; - listener->channel_name = _strdup(pszChannelName); - - if (!listener->channel_name) - { - WLog_ERR(TAG, "_strdup failed!"); - dvcman_wtslistener_free(listener); - return CHANNEL_RC_NO_MEMORY; - } - - listener->flags = ulFlags; - listener->listener_callback = pListenerCallback; - - if (ppListener) - *ppListener = (IWTSListener*)listener; - - dvcman->listeners[dvcman->num_listeners++] = (IWTSListener*)listener; - return CHANNEL_RC_OK; + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; } - else + + listener->iface.GetConfiguration = dvcman_get_configuration; + listener->iface.pInterface = NULL; + listener->dvcman = dvcman; + listener->channel_name = _strdup(pszChannelName); + + if (!listener->channel_name) { - WLog_ERR(TAG, "create_listener: Maximum DVC listener number reached."); + WLog_ERR(TAG, "_strdup failed!"); + dvcman_wtslistener_free(listener); + return CHANNEL_RC_NO_MEMORY; + } + + listener->flags = ulFlags; + listener->listener_callback = pListenerCallback; + + if (ppListener) + *ppListener = (IWTSListener*)listener; + + if (ArrayList_Add(dvcman->listeners, listener) < 0) return ERROR_INTERNAL_ERROR; - } + return CHANNEL_RC_OK; } static UINT dvcman_destroy_listener(IWTSVirtualChannelManager* pChannelMgr, IWTSListener* pListener) { - size_t x; DVCMAN_LISTENER* listener = (DVCMAN_LISTENER*)pListener; + WINPR_UNUSED(pChannelMgr); + if (listener) { DVCMAN* dvcman = listener->dvcman; - for (x = 0; x < dvcman->num_listeners; x++) - { - if (dvcman->listeners[x] == pListener) - { - size_t rest = (dvcman->num_listeners - x - 1) * sizeof(IWTSListener*); - MoveMemory(&dvcman->listeners[x], &dvcman->listeners[x + 1], rest); - dvcman->num_listeners--; - dvcman_wtslistener_free(listener); - break; - } - } + if (dvcman) + ArrayList_Remove(dvcman->listeners, listener); } return CHANNEL_RC_OK; @@ -140,34 +127,42 @@ static UINT dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const ch { DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*)pEntryPoints)->dvcman; - if (dvcman->num_plugins < MAX_PLUGINS) - { - dvcman->plugin_names[dvcman->num_plugins] = name; - dvcman->plugins[dvcman->num_plugins++] = pPlugin; - WLog_DBG(TAG, "register_plugin: num_plugins %d", dvcman->num_plugins); - return CHANNEL_RC_OK; - } - else - { - WLog_ERR(TAG, "register_plugin: Maximum DVC plugin number %u reached.", MAX_PLUGINS); + if (ArrayList_Add(dvcman->plugin_names, _strdup(name)) < 0) return ERROR_INTERNAL_ERROR; - } + if (ArrayList_Add(dvcman->plugins, pPlugin) < 0) + return ERROR_INTERNAL_ERROR; + + WLog_DBG(TAG, "register_plugin: num_plugins %d", ArrayList_Count(dvcman->plugins)); + return CHANNEL_RC_OK; } static IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name) { - size_t i; + IWTSPlugin* plugin = NULL; + size_t i, nc, pc; DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*)pEntryPoints)->dvcman; + if (!dvcman || !pEntryPoints || !name) + return NULL; - for (i = 0; i < dvcman->num_plugins; i++) + nc = ArrayList_Count(dvcman->plugin_names); + pc = ArrayList_Count(dvcman->plugins); + if (nc != pc) + return NULL; + + ArrayList_Lock(dvcman->plugin_names); + ArrayList_Lock(dvcman->plugins); + for (i = 0; i < pc; i++) { - if (dvcman->plugin_names[i] == name || strcmp(dvcman->plugin_names[i], name) == 0) + const char* cur = ArrayList_GetItem(dvcman->plugin_names, i); + if (strcmp(cur, name) == 0) { - return dvcman->plugins[i]; + plugin = ArrayList_GetItem(dvcman->plugins, i); + break; } } - - return NULL; + ArrayList_Unlock(dvcman->plugin_names); + ArrayList_Unlock(dvcman->plugins); + return plugin; } static ADDIN_ARGV* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints) @@ -196,38 +191,40 @@ static IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* UINT32 ChannelId) { int index; - BOOL found = FALSE; - DVCMAN_CHANNEL* channel; + IWTSVirtualChannel* channel = NULL; DVCMAN* dvcman = (DVCMAN*)pChannelMgr; ArrayList_Lock(dvcman->channels); - index = 0; - channel = (DVCMAN_CHANNEL*)ArrayList_GetItem(dvcman->channels, index++); - - while (channel) + for (index = 0; index < ArrayList_Count(dvcman->channels); index++) { - if (channel->channel_id == ChannelId) + DVCMAN_CHANNEL* cur = (DVCMAN_CHANNEL*)ArrayList_GetItem(dvcman->channels, index); + if (cur->channel_id == ChannelId) { - found = TRUE; + channel = &cur->iface; break; } - - channel = (DVCMAN_CHANNEL*)ArrayList_GetItem(dvcman->channels, index++); } ArrayList_Unlock(dvcman->channels); - return (found) ? ((IWTSVirtualChannel*)channel) : NULL; + return channel; +} + +static void dvcman_plugin_terminate(void* plugin) +{ + IWTSPlugin* pPlugin = plugin; + + UINT error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Terminated, pPlugin); + if (error != CHANNEL_RC_OK) + WLog_ERR(TAG, "Terminated failed with error %" PRIu32 "!", error); } static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) { + wObject* obj; DVCMAN* dvcman; dvcman = (DVCMAN*)calloc(1, sizeof(DVCMAN)); if (!dvcman) - { - WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!"); return NULL; - } dvcman->iface.CreateListener = dvcman_create_listener; dvcman->iface.DestroyListener = dvcman_destroy_listener; @@ -238,24 +235,36 @@ static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) dvcman->channels = ArrayList_New(TRUE); if (!dvcman->channels) - { - WLog_Print(plugin->log, WLOG_ERROR, "ArrayList_New failed!"); - free(dvcman); - return NULL; - } + goto fail; + + obj = ArrayList_Object(dvcman->channels); + obj->fnObjectFree = dvcman_channel_free; - dvcman->channels->object.fnObjectFree = dvcman_channel_free; dvcman->pool = StreamPool_New(TRUE, 10); - if (!dvcman->pool) - { - WLog_Print(plugin->log, WLOG_ERROR, "StreamPool_New failed!"); - ArrayList_Free(dvcman->channels); - free(dvcman); - return NULL; - } + goto fail; - return (IWTSVirtualChannelManager*)dvcman; + dvcman->listeners = ArrayList_New(TRUE); + if (!dvcman->listeners) + goto fail; + obj = ArrayList_Object(dvcman->listeners); + obj->fnObjectFree = dvcman_wtslistener_free; + + dvcman->plugin_names = ArrayList_New(TRUE); + if (!dvcman->plugin_names) + goto fail; + obj = ArrayList_Object(dvcman->plugin_names); + obj->fnObjectFree = free; + + dvcman->plugins = ArrayList_New(TRUE); + if (!dvcman->plugins) + goto fail; + obj = ArrayList_Object(dvcman->plugins); + obj->fnObjectFree = dvcman_plugin_terminate; + return &dvcman->iface; +fail: + dvcman_free(plugin, &dvcman->iface); + return NULL; } /** @@ -304,31 +313,22 @@ static DVCMAN_CHANNEL* dvcman_channel_new(drdynvcPlugin* drdynvc, channel = (DVCMAN_CHANNEL*)calloc(1, sizeof(DVCMAN_CHANNEL)); if (!channel) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "calloc failed!"); - return NULL; - } + goto fail; channel->dvcman = (DVCMAN*)pChannelMgr; channel->channel_id = ChannelId; channel->channel_name = _strdup(ChannelName); if (!channel->channel_name) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "_strdup failed!"); - free(channel); - return NULL; - } + goto fail; if (!InitializeCriticalSectionEx(&(channel->lock), 0, 0)) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "InitializeCriticalSectionEx failed!"); - free(channel->channel_name); - free(channel); - return NULL; - } + goto fail; return channel; +fail: + dvcman_channel_free(channel); + return NULL; } static void dvcman_channel_free(void* arg) @@ -376,31 +376,13 @@ static void dvcman_channel_free(void* arg) static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr) { - size_t i; - IWTSPlugin* pPlugin; DVCMAN* dvcman = (DVCMAN*)pChannelMgr; - UINT error; + + ArrayList_Free(dvcman->listeners); ArrayList_Free(dvcman->channels); + ArrayList_Free(dvcman->plugin_names); + ArrayList_Free(dvcman->plugins); - for (i = 0; i < dvcman->num_listeners; i++) - { - DVCMAN_LISTENER* listener = (DVCMAN_LISTENER*)dvcman->listeners[i]; - dvcman_wtslistener_free(listener); - } - - dvcman->num_listeners = 0; - - for (i = 0; i < dvcman->num_plugins; i++) - { - pPlugin = dvcman->plugins[i]; - - if (pPlugin->Terminated) - if ((error = pPlugin->Terminated(pPlugin))) - WLog_Print(drdynvc->log, WLOG_ERROR, "Terminated failed with error %" PRIu32 "!", - error); - } - - dvcman->num_plugins = 0; StreamPool_Free(dvcman->pool); free(dvcman); } @@ -413,24 +395,26 @@ static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChan static UINT dvcman_init(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr) { size_t i; - IWTSPlugin* pPlugin; DVCMAN* dvcman = (DVCMAN*)pChannelMgr; - UINT error; + UINT error = CHANNEL_RC_OK; - for (i = 0; i < dvcman->num_plugins; i++) + ArrayList_Lock(dvcman->plugins); + for (i = 0; i < ArrayList_Count(dvcman->plugins); i++) { - pPlugin = dvcman->plugins[i]; + IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i); - if (pPlugin->Initialize) - if ((error = pPlugin->Initialize(pPlugin, pChannelMgr))) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "Initialize failed with error %" PRIu32 "!", - error); - return error; - } + error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Initialize, pPlugin, pChannelMgr); + if (error != CHANNEL_RC_OK) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "Initialize failed with error %" PRIu32 "!", + error); + goto fail; + } } - return CHANNEL_RC_OK; +fail: + ArrayList_Unlock(dvcman->plugins); + return error; } /** @@ -493,11 +477,13 @@ static UINT dvcman_create_channel(drdynvcPlugin* drdynvc, IWTSVirtualChannelMana } channel->status = ERROR_NOT_CONNECTED; - ArrayList_Add(dvcman->channels, channel); + if (ArrayList_Add(dvcman->channels, channel) < 0) + return ERROR_INTERNAL_ERROR; - for (i = 0; i < dvcman->num_listeners; i++) + ArrayList_Lock(dvcman->listeners); + for (i = 0; i < ArrayList_Count(dvcman->listeners); i++) { - DVCMAN_LISTENER* listener = (DVCMAN_LISTENER*)dvcman->listeners[i]; + DVCMAN_LISTENER* listener = (DVCMAN_LISTENER*)ArrayList_GetItem(dvcman->listeners, i); if (strcmp(listener->channel_name, ChannelName) == 0) { @@ -524,7 +510,7 @@ static UINT dvcman_create_channel(drdynvcPlugin* drdynvc, IWTSVirtualChannelMana WLog_Print(drdynvc->log, WLOG_ERROR, "context.OnChannelConnected failed with error %" PRIu32 "", error); - return error; + goto fail; } else { @@ -532,19 +518,23 @@ static UINT dvcman_create_channel(drdynvcPlugin* drdynvc, IWTSVirtualChannelMana { WLog_Print(drdynvc->log, WLOG_ERROR, "OnNewChannelConnection failed with error %" PRIu32 "!", error); - return error; + goto fail; } else { WLog_Print(drdynvc->log, WLOG_ERROR, "OnNewChannelConnection returned with bAccept FALSE!"); - return ERROR_INTERNAL_ERROR; + error = ERROR_INTERNAL_ERROR; + goto fail; } } } } + error = ERROR_INTERNAL_ERROR; +fail: + ArrayList_Unlock(dvcman->listeners); - return ERROR_INTERNAL_ERROR; + return error; } /** @@ -590,6 +580,7 @@ static UINT dvcman_open_channel(drdynvcPlugin* drdynvc, IWTSVirtualChannelManage static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BOOL bSendClosePDU) { + size_t i; DVCMAN_CHANNEL* channel; UINT error = CHANNEL_RC_OK; DVCMAN* dvcman = (DVCMAN*)pChannelMgr; @@ -608,10 +599,10 @@ static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 if (drdynvc && bSendClosePDU) { - wStream* s = Stream_New(NULL, 5); + wStream* s = StreamPool_Take(dvcman->pool, 5); if (!s) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); error = CHANNEL_RC_NO_MEMORY; } else @@ -619,9 +610,18 @@ static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Stream_Write_UINT8(s, (CLOSE_REQUEST_PDU << 4) | 0x02); Stream_Write_UINT32(s, ChannelId); error = drdynvc_send(drdynvc, s); + Stream_Release(s); } } + ArrayList_Lock(dvcman->listeners); + for (i = ArrayList_Count(dvcman->listeners); i > 0; i--) + { + DVCMAN_LISTENER* listener = ArrayList_GetItem(dvcman->listeners, i - 1); + if (strcmp(listener->channel_name, channel->channel_name) == 0) + ArrayList_Remove(dvcman->listeners, listener); + } + ArrayList_Unlock(dvcman->listeners); ArrayList_Remove(dvcman->channels, channel); return error; } @@ -689,7 +689,7 @@ static UINT dvcman_receive_channel_data(drdynvcPlugin* drdynvc, if (channel->dvc_data) { /* Fragmented data */ - if (Stream_GetPosition(channel->dvc_data) + dataSize > Stream_Capacity(channel->dvc_data)) + if (Stream_GetPosition(channel->dvc_data) + dataSize > channel->dvc_data_length) { WLog_Print(drdynvc->log, WLOG_ERROR, "data exceeding declared length!"); Stream_Release(channel->dvc_data); @@ -761,19 +761,17 @@ static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s) switch (status) { case CHANNEL_RC_OK: + Stream_AddRef(s); return CHANNEL_RC_OK; case CHANNEL_RC_NOT_CONNECTED: - Stream_Free(s, TRUE); return CHANNEL_RC_OK; case CHANNEL_RC_BAD_CHANNEL_HANDLE: - Stream_Free(s, TRUE); WLog_ERR(TAG, "VirtualChannelWriteEx failed with CHANNEL_RC_BAD_CHANNEL_HANDLE"); return status; default: - Stream_Free(s, TRUE); WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); @@ -795,17 +793,20 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, const B UINT8 cbLen; unsigned long chunkLength; UINT status = CHANNEL_RC_BAD_INIT_HANDLE; + DVCMAN* dvcman; if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; + dvcman = (DVCMAN*)drdynvc->channel_mgr; + WLog_Print(drdynvc->log, WLOG_DEBUG, "write_data: ChannelId=%" PRIu32 " size=%" PRIu32 "", ChannelId, dataSize); - data_out = Stream_New(NULL, CHANNEL_CHUNK_LENGTH); + data_out = StreamPool_Take(dvcman->pool, CHANNEL_CHUNK_LENGTH); if (!data_out) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -815,7 +816,7 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, const B if (dataSize == 0) { - status = dvcman_close_channel(drdynvc->channel_mgr, ChannelId, TRUE); + dvcman_close_channel(drdynvc->channel_mgr, ChannelId, TRUE); } else if (dataSize <= CHANNEL_CHUNK_LENGTH - pos) { @@ -841,11 +842,11 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, const B while (status == CHANNEL_RC_OK && dataSize > 0) { - data_out = Stream_New(NULL, CHANNEL_CHUNK_LENGTH); + data_out = StreamPool_Take(dvcman->pool, CHANNEL_CHUNK_LENGTH); if (!data_out) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -886,12 +887,14 @@ static UINT drdynvc_send_capability_response(drdynvcPlugin* drdynvc) { UINT status; wStream* s; + DVCMAN* dvcman; if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; + dvcman = (DVCMAN*)drdynvc->channel_mgr; WLog_Print(drdynvc->log, WLOG_TRACE, "capability_response"); - s = Stream_New(NULL, 4); + s = StreamPool_Take(dvcman->pool, 4); if (!s) { @@ -1002,11 +1005,13 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int c UINT channel_status; char* name; size_t length; + DVCMAN* dvcman; WINPR_UNUSED(Sp); if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; + dvcman = (DVCMAN*)drdynvc->channel_mgr; if (drdynvc->state == DRDYNVC_STATE_CAPABILITIES) { /** @@ -1039,11 +1044,11 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int c WLog_Print(drdynvc->log, WLOG_DEBUG, "process_create_request: ChannelId=%" PRIu32 " ChannelName=%s", ChannelId, name); channel_status = dvcman_create_channel(drdynvc, drdynvc->channel_mgr, ChannelId, name); - data_out = Stream_New(NULL, pos + 4); + data_out = StreamPool_Take(dvcman->pool, pos + 4); if (!data_out) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -1231,22 +1236,23 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, if (dataFlags & CHANNEL_FLAG_FIRST) { + DVCMAN* mgr = (DVCMAN*)drdynvc->channel_mgr; if (drdynvc->data_in) - Stream_Free(drdynvc->data_in, TRUE); + Stream_Release(drdynvc->data_in); - drdynvc->data_in = Stream_New(NULL, totalLength); + drdynvc->data_in = StreamPool_Take(mgr->pool, totalLength); } if (!(data_in = drdynvc->data_in)) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); return CHANNEL_RC_NO_MEMORY; } if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); - Stream_Free(drdynvc->data_in, TRUE); + Stream_Release(drdynvc->data_in); drdynvc->data_in = NULL; return ERROR_INTERNAL_ERROR; } @@ -1255,7 +1261,9 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, if (dataFlags & CHANNEL_FLAG_LAST) { - if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) + const size_t cap = Stream_Capacity(data_in); + const size_t pos = Stream_GetPosition(data_in); + if (cap < pos) { WLog_Print(drdynvc->log, WLOG_ERROR, "drdynvc_plugin_process_received: read error"); return ERROR_INVALID_DATA; @@ -1304,7 +1312,7 @@ static void VCAPITYPE drdynvc_virtual_channel_open_event_ex(LPVOID lpUserParam, case CHANNEL_EVENT_WRITE_COMPLETE: { wStream* s = (wStream*)pData; - Stream_Free(s, TRUE); + Stream_Release(s); } break; @@ -1359,7 +1367,7 @@ static DWORD WINAPI drdynvc_virtual_channel_client_thread(LPVOID arg) "drdynvc_order_recv failed with error %" PRIu32 "!", error); } - Stream_Free(data, TRUE); + Stream_Release(data); } } @@ -1397,7 +1405,7 @@ static void drdynvc_queue_object_free(void* obj) s = (wStream*)msg->wParam; if (s) - Stream_Free(s, TRUE); + Stream_Release(s); } /** @@ -1529,7 +1537,7 @@ static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc) if (drdynvc->data_in) { - Stream_Free(drdynvc->data_in, TRUE); + Stream_Release(drdynvc->data_in); drdynvc->data_in = NULL; } @@ -1560,6 +1568,7 @@ static UINT drdynvc_virtual_channel_event_terminated(drdynvcPlugin* drdynvc) static UINT drdynvc_virtual_channel_event_attached(drdynvcPlugin* drdynvc) { + UINT error = CHANNEL_RC_OK; size_t i; DVCMAN* dvcman; @@ -1571,25 +1580,27 @@ static UINT drdynvc_virtual_channel_event_attached(drdynvcPlugin* drdynvc) if (!dvcman) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - for (i = 0; i < dvcman->num_plugins; i++) + ArrayList_Lock(dvcman->plugins); + for (i = 0; i < ArrayList_Count(dvcman->plugins); i++) { - UINT error; - IWTSPlugin* pPlugin = dvcman->plugins[i]; + IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i); - if (pPlugin->Attached) - if ((error = pPlugin->Attached(pPlugin))) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "Attach failed with error %" PRIu32 "!", - error); - return error; - } + error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Attached, pPlugin); + if (error != CHANNEL_RC_OK) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "Attach failed with error %" PRIu32 "!", error); + goto fail; + } } - return CHANNEL_RC_OK; +fail: + ArrayList_Unlock(dvcman->plugins); + return error; } static UINT drdynvc_virtual_channel_event_detached(drdynvcPlugin* drdynvc) { + UINT error = CHANNEL_RC_OK; size_t i; DVCMAN* dvcman; @@ -1601,21 +1612,23 @@ static UINT drdynvc_virtual_channel_event_detached(drdynvcPlugin* drdynvc) if (!dvcman) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - for (i = 0; i < dvcman->num_plugins; i++) + ArrayList_Lock(dvcman->plugins); + for (i = 0; i < ArrayList_Count(dvcman->plugins); i++) { - UINT error; - IWTSPlugin* pPlugin = dvcman->plugins[i]; + IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i); - if (pPlugin->Detached) - if ((error = pPlugin->Detached(pPlugin))) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "Detach failed with error %" PRIu32 "!", - error); - return error; - } + error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Detached, pPlugin); + if (error != CHANNEL_RC_OK) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "Detach failed with error %" PRIu32 "!", error); + goto fail; + } } - return CHANNEL_RC_OK; +fail: + ArrayList_Unlock(dvcman->plugins); + + return error; } static VOID VCAPITYPE drdynvc_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, diff --git a/channels/drdynvc/client/drdynvc_main.h b/channels/drdynvc/client/drdynvc_main.h index f91059988..646c8fdfb 100644 --- a/channels/drdynvc/client/drdynvc_main.h +++ b/channels/drdynvc/client/drdynvc_main.h @@ -37,21 +37,16 @@ typedef struct drdynvc_plugin drdynvcPlugin; -#define MAX_PLUGINS 32 - struct _DVCMAN { IWTSVirtualChannelManager iface; drdynvcPlugin* drdynvc; - size_t num_plugins; - const char* plugin_names[MAX_PLUGINS]; - IWTSPlugin* plugins[MAX_PLUGINS]; - - size_t num_listeners; - IWTSListener* listeners[MAX_PLUGINS]; + wArrayList* plugin_names; + wArrayList* plugins; + wArrayList* listeners; wArrayList* channels; wStreamPool* pool; }; From 2f5e5359f60c26a2de244cd6d9f7957b039cd121 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 12 May 2020 10:54:07 +0200 Subject: [PATCH 2/2] Destroy channel listeners on terminate --- channels/audin/client/audin_main.c | 9 ++++++++- channels/disp/client/disp_main.c | 11 +++++++++-- channels/echo/client/echo_main.c | 11 ++++++++--- channels/geometry/client/geometry_main.c | 13 ++++++++++--- channels/rdpei/client/rdpei_main.c | 9 +++++++-- channels/rdpgfx/client/rdpgfx_main.c | 9 +++++++-- channels/rdpsnd/client/rdpsnd_main.c | 9 +++++++-- channels/urbdrc/client/urbdrc_main.c | 7 ++++++- channels/video/client/video_main.c | 17 +++++++++++++++-- 9 files changed, 77 insertions(+), 18 deletions(-) diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 1b14fd3b7..d843b21f5 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -687,7 +687,7 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag audin->listener_callback->plugin = pPlugin; audin->listener_callback->channel_mgr = pChannelMgr; return pChannelMgr->CreateListener(pChannelMgr, "AUDIO_INPUT", 0, - (IWTSListenerCallback*)audin->listener_callback, NULL); + &audin->listener_callback->iface, NULL); } /** @@ -704,6 +704,13 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin) return CHANNEL_RC_BAD_CHANNEL_HANDLE; WLog_Print(audin->log, WLOG_TRACE, "..."); + + if (audin->listener_callback) + { + IWTSVirtualChannelManager* mgr = audin->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &audin->iface); + } audio_formats_free(audin->fixed_format, 1); if (audin->device) diff --git a/channels/disp/client/disp_main.c b/channels/disp/client/disp_main.c index d3e9a22cf..58a902a30 100644 --- a/channels/disp/client/disp_main.c +++ b/channels/disp/client/disp_main.c @@ -308,8 +308,7 @@ static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage disp->listener_callback->plugin = pPlugin; disp->listener_callback->channel_mgr = pChannelMgr; status = pChannelMgr->CreateListener(pChannelMgr, DISP_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)disp->listener_callback, - &(disp->listener)); + &disp->listener_callback->iface, &(disp->listener)); disp->listener->pInterface = disp->iface.pInterface; return status; } @@ -322,6 +321,14 @@ static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage static UINT disp_plugin_terminated(IWTSPlugin* pPlugin) { DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin; + + if (disp && disp->listener_callback) + { + IWTSVirtualChannelManager* mgr = disp->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &disp->iface); + } + free(disp->listener_callback); free(disp->iface.pInterface); free(pPlugin); diff --git a/channels/echo/client/echo_main.c b/channels/echo/client/echo_main.c index e830122a7..83f27f94d 100644 --- a/channels/echo/client/echo_main.c +++ b/channels/echo/client/echo_main.c @@ -142,8 +142,8 @@ static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage echo->listener_callback->plugin = pPlugin; echo->listener_callback->channel_mgr = pChannelMgr; - return pChannelMgr->CreateListener(pChannelMgr, "ECHO", 0, - (IWTSListenerCallback*)echo->listener_callback, NULL); + return pChannelMgr->CreateListener(pChannelMgr, "ECHO", 0, &echo->listener_callback->iface, + NULL); } /** @@ -154,7 +154,12 @@ static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage static UINT echo_plugin_terminated(IWTSPlugin* pPlugin) { ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin; - + if (echo && echo->listener_callback) + { + IWTSVirtualChannelManager* mgr = echo->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &echo->iface); + } free(echo); return CHANNEL_RC_OK; diff --git a/channels/geometry/client/geometry_main.c b/channels/geometry/client/geometry_main.c index f08b76cf1..d3373e0c4 100644 --- a/channels/geometry/client/geometry_main.c +++ b/channels/geometry/client/geometry_main.c @@ -410,9 +410,9 @@ static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMa geometry->listener_callback->iface.OnNewChannelConnection = geometry_on_new_channel_connection; geometry->listener_callback->plugin = pPlugin; geometry->listener_callback->channel_mgr = pChannelMgr; - status = pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)geometry->listener_callback, - &(geometry->listener)); + status = + pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0, + &geometry->listener_callback->iface, &(geometry->listener)); geometry->listener->pInterface = geometry->iface.pInterface; return status; } @@ -427,6 +427,13 @@ static UINT geometry_plugin_terminated(IWTSPlugin* pPlugin) GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin; GeometryClientContext* context = (GeometryClientContext*)geometry->iface.pInterface; + if (geometry && geometry->listener_callback) + { + IWTSVirtualChannelManager* mgr = geometry->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &geometry->iface); + } + if (context) HashTable_Free(context->geometries); diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index 7dd65211d..82f56aec1 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -571,8 +571,7 @@ static UINT rdpei_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag rdpei->listener_callback->channel_mgr = pChannelMgr; if ((error = pChannelMgr->CreateListener(pChannelMgr, RDPEI_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)rdpei->listener_callback, - &(rdpei->listener)))) + &rdpei->listener_callback->iface, &(rdpei->listener)))) { WLog_ERR(TAG, "ChannelMgr->CreateListener failed with error %" PRIu32 "!", error); goto error_out; @@ -598,6 +597,12 @@ static UINT rdpei_plugin_terminated(IWTSPlugin* pPlugin) if (!pPlugin) return ERROR_INVALID_PARAMETER; + if (rdpei && rdpei->listener_callback) + { + IWTSVirtualChannelManager* mgr = rdpei->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &rdpei->iface); + } free(rdpei->listener_callback); free(rdpei->context); free(rdpei); diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 7bc25dba9..e8591a017 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -1896,8 +1896,7 @@ static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMana gfx->listener_callback->plugin = pPlugin; gfx->listener_callback->channel_mgr = pChannelMgr; error = pChannelMgr->CreateListener(pChannelMgr, RDPGFX_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)gfx->listener_callback, - &(gfx->listener)); + &gfx->listener_callback->iface, &(gfx->listener)); gfx->listener->pInterface = gfx->iface.pInterface; DEBUG_RDPGFX(gfx->log, "Initialize"); return error; @@ -1913,6 +1912,12 @@ static UINT rdpgfx_plugin_terminated(IWTSPlugin* pPlugin) RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin; RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; DEBUG_RDPGFX(gfx->log, "Terminated"); + if (gfx && gfx->listener_callback) + { + IWTSVirtualChannelManager* mgr = gfx->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &gfx->iface); + } rdpgfx_client_context_free(context); return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 2526ec55d..3f400a55f 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -1541,8 +1541,7 @@ static UINT rdpsnd_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMana rdpsnd->listener_callback->plugin = pPlugin; rdpsnd->listener_callback->channel_mgr = pChannelMgr; status = pChannelMgr->CreateListener(pChannelMgr, RDPSND_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)rdpsnd->listener_callback, - &(rdpsnd->listener)); + &rdpsnd->listener_callback->iface, &(rdpsnd->listener)); rdpsnd->listener->pInterface = rdpsnd->iface.pInterface; return rdpsnd_virtual_channel_event_initialized(rdpsnd); } @@ -1557,6 +1556,12 @@ static UINT rdpsnd_plugin_terminated(IWTSPlugin* pPlugin) rdpsndPlugin* rdpsnd = (rdpsndPlugin*)pPlugin; if (rdpsnd) { + if (rdpsnd->listener_callback) + { + IWTSVirtualChannelManager* mgr = rdpsnd->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &rdpsnd->iface); + } free(rdpsnd->listener_callback); free(rdpsnd->iface.pInterface); } diff --git a/channels/urbdrc/client/urbdrc_main.c b/channels/urbdrc/client/urbdrc_main.c index 6dbdc5a41..b6449cd47 100644 --- a/channels/urbdrc/client/urbdrc_main.c +++ b/channels/urbdrc/client/urbdrc_main.c @@ -709,7 +709,12 @@ static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin) if (!urbdrc) return ERROR_INVALID_DATA; - + if (urbdrc->listener_callback) + { + IWTSVirtualChannelManager* mgr = urbdrc->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &urbdrc->iface); + } udevman = urbdrc->udevman; if (udevman) diff --git a/channels/video/client/video_main.c b/channels/video/client/video_main.c index 1efadb399..3fecb63a7 100644 --- a/channels/video/client/video_main.c +++ b/channels/video/client/video_main.c @@ -1048,7 +1048,7 @@ static UINT video_plugin_initialize(IWTSPlugin* plugin, IWTSVirtualChannelManage callback->channel_mgr = channelMgr; status = channelMgr->CreateListener(channelMgr, VIDEO_CONTROL_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)callback, &(video->controlListener)); + &callback->iface, &(video->controlListener)); if (status != CHANNEL_RC_OK) return status; @@ -1067,7 +1067,7 @@ static UINT video_plugin_initialize(IWTSPlugin* plugin, IWTSVirtualChannelManage callback->channel_mgr = channelMgr; status = channelMgr->CreateListener(channelMgr, VIDEO_DATA_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)callback, &(video->dataListener)); + &callback->iface, &(video->dataListener)); if (status == CHANNEL_RC_OK) video->dataListener->pInterface = video->wtsPlugin.pInterface; @@ -1084,6 +1084,19 @@ static UINT video_plugin_terminated(IWTSPlugin* pPlugin) { VIDEO_PLUGIN* video = (VIDEO_PLUGIN*)pPlugin; + if (video->control_callback) + { + IWTSVirtualChannelManager* mgr = video->control_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &video->control_callback->iface); + } + if (video->data_callback) + { + IWTSVirtualChannelManager* mgr = video->data_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, &video->data_callback->iface); + } + if (video->context) VideoClientContextPriv_free(video->context->priv);