Refactored channel error handling

* Fix WINPR_ASSERT if a client can not allocate new resources,
  terminated cleanly instead.
* Add WINPR_ASSERT for lots of channel arguments
This commit is contained in:
Armin Novak 2021-09-06 16:46:01 +02:00 committed by akallabeth
parent cde002f460
commit 95ecc6929a
8 changed files with 151 additions and 106 deletions

View File

@ -608,28 +608,25 @@ UINT channel_client_quit_handler(void* MsgsHandle)
WINPR_ASSERT(internals->ctx);
WINPR_ASSERT(internals->ctx->settings);
if (!(internals->ctx->settings->ThreadingFlags & THREADING_FLAGS_DISABLE_THREADS))
{
if (MessageQueue_PostQuit(internals->queue, 0) &&
(WaitForSingleObject(internals->thread, INFINITE) == WAIT_FAILED))
if (internals->queue && internals->thread)
{
rc = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
return rc;
if (MessageQueue_PostQuit(internals->queue, 0) &&
(WaitForSingleObject(internals->thread, INFINITE) == WAIT_FAILED))
{
rc = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
return rc;
}
}
MessageQueue_Free(internals->queue);
CloseHandle(internals->thread);
}
if (internals->data_in)
{
Stream_Free(internals->data_in, TRUE);
internals->data_in = NULL;
}
if (internals->channel_name)
{
free(internals->channel_name);
}
Stream_Free(internals->data_in, TRUE);
free(internals->channel_name);
free(internals);
return CHANNEL_RC_OK;
}

View File

@ -775,6 +775,7 @@ static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s)
status = CHANNEL_RC_BAD_CHANNEL_HANDLE;
else
{
WINPR_ASSERT(drdynvc->channelEntryPoints.pVirtualChannelWriteEx);
status = drdynvc->channelEntryPoints.pVirtualChannelWriteEx(
drdynvc->InitHandle, drdynvc->OpenHandle, Stream_Buffer(s),
(UINT32)Stream_GetPosition(s), s);
@ -1499,6 +1500,7 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO
if (!drdynvc)
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
WINPR_ASSERT(drdynvc->channelEntryPoints.pVirtualChannelOpenEx);
status = drdynvc->channelEntryPoints.pVirtualChannelOpenEx(
drdynvc->InitHandle, &drdynvc->OpenHandle, drdynvc->channelDef.name,
drdynvc_virtual_channel_open_event_ex);
@ -1556,24 +1558,32 @@ static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc)
if (drdynvc->OpenHandle == 0)
return CHANNEL_RC_OK;
if (!MessageQueue_PostQuit(drdynvc->queue, 0))
if (drdynvc->queue)
{
status = GetLastError();
WLog_Print(drdynvc->log, WLOG_ERROR, "MessageQueue_PostQuit failed with error %" PRIu32 "",
status);
return status;
if (!MessageQueue_PostQuit(drdynvc->queue, 0))
{
status = GetLastError();
WLog_Print(drdynvc->log, WLOG_ERROR,
"MessageQueue_PostQuit failed with error %" PRIu32 "", status);
return status;
}
}
if (WaitForSingleObject(drdynvc->thread, INFINITE) != WAIT_OBJECT_0)
if (drdynvc->thread)
{
status = GetLastError();
WLog_Print(drdynvc->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "",
status);
return status;
if (WaitForSingleObject(drdynvc->thread, INFINITE) != WAIT_OBJECT_0)
{
status = GetLastError();
WLog_Print(drdynvc->log, WLOG_ERROR,
"WaitForSingleObject failed with error %" PRIu32 "", status);
return status;
}
CloseHandle(drdynvc->thread);
drdynvc->thread = NULL;
}
CloseHandle(drdynvc->thread);
drdynvc->thread = NULL;
WINPR_ASSERT(drdynvc->channelEntryPoints.pVirtualChannelCloseEx);
status = drdynvc->channelEntryPoints.pVirtualChannelCloseEx(drdynvc->InitHandle,
drdynvc->OpenHandle);
@ -1584,7 +1594,8 @@ static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc)
}
dvcman_clear(drdynvc, drdynvc->channel_mgr);
MessageQueue_Clear(drdynvc->queue);
if (drdynvc->queue)
MessageQueue_Clear(drdynvc->queue);
drdynvc->OpenHandle = 0;
if (drdynvc->data_in)
@ -1811,6 +1822,8 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI
CopyMemory(&(drdynvc->channelEntryPoints), pEntryPoints,
sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
drdynvc->InitHandle = pInitHandle;
WINPR_ASSERT(drdynvc->channelEntryPoints.pVirtualChannelInitEx);
rc = drdynvc->channelEntryPoints.pVirtualChannelInitEx(
drdynvc, context, pInitHandle, &drdynvc->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
drdynvc_virtual_channel_init_event_ex);

View File

@ -1175,18 +1175,23 @@ static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp)
if (encomsp->OpenHandle == 0)
return CHANNEL_RC_OK;
if (MessageQueue_PostQuit(encomsp->queue, 0) &&
(WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED))
if (encomsp->queue && encomsp->thread)
{
rc = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
return rc;
if (MessageQueue_PostQuit(encomsp->queue, 0) &&
(WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED))
{
rc = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
return rc;
}
}
MessageQueue_Free(encomsp->queue);
CloseHandle(encomsp->thread);
encomsp->queue = NULL;
encomsp->thread = NULL;
WINPR_ASSERT(encomsp->channelEntryPoints.pVirtualChannelCloseEx);
rc = encomsp->channelEntryPoints.pVirtualChannelCloseEx(encomsp->InitHandle,
encomsp->OpenHandle);

View File

@ -602,11 +602,11 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
{
UINT rc;
channel_client_quit_handler(rail->MsgsHandle);
if (rail->OpenHandle == 0)
return CHANNEL_RC_OK;
channel_client_quit_handler(rail->MsgsHandle);
WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx);
rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
if (CHANNEL_RC_OK != rc)

View File

@ -182,6 +182,8 @@ static void closeChannel(Plugin* plugin)
if (debug)
puts("rdp2tcp closing channel");
WINPR_ASSERT(plugin);
WINPR_ASSERT(plugin->channelEntryPoints.pVirtualChannelCloseEx);
plugin->channelEntryPoints.pVirtualChannelCloseEx(plugin->initHandle, plugin->openHandle);
}

View File

@ -1908,12 +1908,15 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr)
if (rdpdr->OpenHandle == 0)
return CHANNEL_RC_OK;
if (MessageQueue_PostQuit(rdpdr->queue, 0) &&
(WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED))
if (rdpdr->queue && rdpdr->thread)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
return error;
if (MessageQueue_PostQuit(rdpdr->queue, 0) &&
(WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED))
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
return error;
}
}
MessageQueue_Free(rdpdr->queue);
@ -1921,6 +1924,7 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr)
rdpdr->queue = NULL;
rdpdr->thread = NULL;
WINPR_ASSERT(rdpdr->channelEntryPoints.pVirtualChannelCloseEx);
error = rdpdr->channelEntryPoints.pVirtualChannelCloseEx(rdpdr->InitHandle, rdpdr->OpenHandle);
if (CHANNEL_RC_OK != error)

View File

@ -1191,16 +1191,6 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID
WINPR_ASSERT(rdpsnd);
rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE);
if (!rdpsnd->dsp_context)
goto fail;
rdpsnd->pool = StreamPool_New(TRUE, 4096);
if (!rdpsnd->pool)
goto fail;
status = rdpsnd->channelEntryPoints.pVirtualChannelOpenEx(
rdpsnd->InitHandle, &rdpsnd->OpenHandle, rdpsnd->channelDef.name,
rdpsnd_virtual_channel_open_event_ex);
@ -1214,9 +1204,6 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID
return rdpsnd_process_connect(rdpsnd);
fail:
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Free(rdpsnd->pool);
return CHANNEL_RC_NO_MEMORY;
}
@ -1229,26 +1216,26 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd)
{
UINT error;
if (rdpsnd->OpenHandle == 0)
return CHANNEL_RC_OK;
if (rdpsnd->device)
IFCALL(rdpsnd->device->Close, rdpsnd->device);
error =
rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, rdpsnd->OpenHandle);
if (CHANNEL_RC_OK != error)
if (rdpsnd->OpenHandle != 0)
{
WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error);
return error;
if (rdpsnd->device)
IFCALL(rdpsnd->device->Close, rdpsnd->device);
error = rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle,
rdpsnd->OpenHandle);
if (CHANNEL_RC_OK != error)
{
WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error);
return error;
}
rdpsnd->OpenHandle = 0;
}
rdpsnd->OpenHandle = 0;
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
StreamPool_Free(rdpsnd->pool);
if (rdpsnd->pool)
StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
rdpsnd->NumberOfClientFormats = 0;
@ -1272,6 +1259,38 @@ static void _queue_free(void* obj)
Stream_Release(s);
}
static void free_internals(rdpsndPlugin* rdpsnd)
{
if (!rdpsnd)
return;
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Free(rdpsnd->pool);
rdpsnd->pool = NULL;
rdpsnd->dsp_context = NULL;
}
static BOOL allocate_internals(rdpsndPlugin* rdpsnd)
{
WINPR_ASSERT(rdpsnd);
if (!rdpsnd->pool)
{
rdpsnd->pool = StreamPool_New(TRUE, 4096);
if (!rdpsnd->pool)
return FALSE;
}
if (!rdpsnd->dsp_context)
{
rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE);
if (!rdpsnd->dsp_context)
return FALSE;
}
return TRUE;
}
static DWORD WINAPI play_thread(LPVOID arg)
{
UINT error = CHANNEL_RC_OK;
@ -1320,6 +1339,10 @@ static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd)
rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL);
if (!rdpsnd->thread)
return CHANNEL_RC_INITIALIZATION_ERROR;
if (!allocate_internals(rdpsnd))
return CHANNEL_RC_NO_MEMORY;
return CHANNEL_RC_OK;
}
@ -1327,7 +1350,9 @@ static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd)
{
if (rdpsnd)
{
MessageQueue_PostQuit(rdpsnd->queue, 0);
if (rdpsnd->queue)
MessageQueue_PostQuit(rdpsnd->queue, 0);
if (rdpsnd->thread)
{
WaitForSingleObject(rdpsnd->thread, INFINITE);
@ -1335,6 +1360,7 @@ static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd)
}
MessageQueue_Free(rdpsnd->queue);
free_internals(rdpsnd);
audio_formats_free(rdpsnd->fixed_format, 1);
free(rdpsnd->subsystem);
free(rdpsnd->device_name);
@ -1445,6 +1471,8 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints,
sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
rdpsnd->InitHandle = pInitHandle;
WINPR_ASSERT(rdpsnd->channelEntryPoints.pVirtualChannelInitEx);
rc = rdpsnd->channelEntryPoints.pVirtualChannelInitEx(
rdpsnd, NULL, pInitHandle, &rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
rdpsnd_virtual_channel_init_event_ex);
@ -1463,21 +1491,17 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
static UINT rdpsnd_on_open(IWTSVirtualChannelCallback* pChannelCallback)
{
RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback;
rdpsndPlugin* rdpsnd = (rdpsndPlugin*)callback->plugin;
rdpsndPlugin* rdpsnd;
rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE);
if (!rdpsnd->dsp_context)
goto fail;
WINPR_ASSERT(callback);
rdpsnd->pool = StreamPool_New(TRUE, 4096);
if (!rdpsnd->pool)
goto fail;
rdpsnd = (rdpsndPlugin*)callback->plugin;
WINPR_ASSERT(rdpsnd);
if (!allocate_internals(rdpsnd))
return ERROR_OUTOFMEMORY;
return rdpsnd_process_connect(rdpsnd);
fail:
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Free(rdpsnd->pool);
return CHANNEL_RC_NO_MEMORY;
}
static UINT rdpsnd_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
@ -1510,17 +1534,19 @@ static UINT rdpsnd_on_data_received(IWTSVirtualChannelCallback* pChannelCallback
static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback;
rdpsndPlugin* rdpsnd = (rdpsndPlugin*)callback->plugin;
rdpsndPlugin* rdpsnd;
WINPR_ASSERT(callback);
rdpsnd = (rdpsndPlugin*)callback->plugin;
WINPR_ASSERT(rdpsnd);
if (rdpsnd->device)
IFCALL(rdpsnd->device->Close, rdpsnd->device);
freerdp_dsp_context_free(rdpsnd->dsp_context);
rdpsnd->dsp_context = NULL;
if (rdpsnd->pool)
{
StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
StreamPool_Free(rdpsnd->pool);
rdpsnd->pool = NULL;
}
audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
@ -1535,6 +1561,7 @@ static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback)
rdpsnd->device = NULL;
}
free_internals(rdpsnd);
free(pChannelCallback);
return CHANNEL_RC_OK;
}

View File

@ -965,13 +965,10 @@ error_out:
*/
static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
{
UINT rc;
UINT rc = CHANNEL_RC_OK;
WINPR_ASSERT(remdesk);
if (remdesk->OpenHandle == 0)
return CHANNEL_RC_OK;
if (remdesk->queue && remdesk->thread)
{
if (MessageQueue_PostQuit(remdesk->queue, 0) &&
@ -983,26 +980,26 @@ static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
}
}
if (remdesk->OpenHandle != 0)
{
WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
remdesk->OpenHandle);
if (CHANNEL_RC_OK != rc)
{
WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
WTSErrorToString(rc), rc);
}
remdesk->OpenHandle = 0;
}
MessageQueue_Free(remdesk->queue);
CloseHandle(remdesk->thread);
remdesk->queue = NULL;
remdesk->thread = NULL;
WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
remdesk->OpenHandle);
if (CHANNEL_RC_OK != rc)
{
WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
rc);
}
remdesk->OpenHandle = 0;
Stream_Free(remdesk->data_in, TRUE);
remdesk->data_in = NULL;
remdesk->queue = NULL;
remdesk->thread = NULL;
return rc;
}