diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 6ba1fef8e..4451c97f7 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -42,9 +44,8 @@ #include #include #include -#include +#include #include -#include #include "rdpsnd_main.h" @@ -52,9 +53,16 @@ struct rdpsnd_plugin { - rdpSvcPlugin plugin; + CHANNEL_DEF channelDef; + CHANNEL_ENTRY_POINTS_EX channelEntryPoints; HANDLE thread; + wStream* data_in; + void* InitHandle; + UINT32 OpenHandle; + wMessagePipe* MsgPipe; + + HANDLE ScheduleThread; wMessageQueue* queue; BYTE cBlockNo; @@ -135,7 +143,7 @@ void rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd) Stream_Write_UINT16(pdu, HIGH_QUALITY); /* wQualityMode */ Stream_Write_UINT16(pdu, 0); /* Reserved */ - svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu); + rdpsnd_virtual_channel_write(rdpsnd, pdu); } void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) @@ -251,7 +259,7 @@ void rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) Stream_Write(pdu, clientFormat->data, clientFormat->cbSize); } - svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu); + rdpsnd_virtual_channel_write(rdpsnd, pdu); } void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s) @@ -316,7 +324,7 @@ void rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, U Stream_Write_UINT16(pdu, wTimeStamp); Stream_Write_UINT16(pdu, wPackSize); - svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu); + rdpsnd_virtual_channel_write(rdpsnd, pdu); } static void rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s) @@ -382,7 +390,7 @@ void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE Stream_Write_UINT8(pdu, cConfirmedBlockNo); /* cConfirmedBlockNo */ Stream_Write_UINT8(pdu, 0); /* bPad */ - svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu); + rdpsnd_virtual_channel_write(rdpsnd, pdu); } static void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) @@ -454,8 +462,6 @@ static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s) static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) { - DEBUG_SVC("server closes."); - if (rdpsnd->device) { IFCALL(rdpsnd->device->Close, rdpsnd->device); @@ -469,7 +475,6 @@ static void rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) UINT32 dwVolume; Stream_Read_UINT32(s, dwVolume); - DEBUG_SVC("dwVolume 0x%X", dwVolume); if (rdpsnd->device) { @@ -477,11 +482,10 @@ static void rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) } } -static void rdpsnd_recv_pdu(rdpSvcPlugin* plugin, wStream* s) +static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) { BYTE msgType; UINT16 BodySize; - rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin; if (rdpsnd->expectingWave) { @@ -646,20 +650,18 @@ static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); } -static void rdpsnd_process_connect(rdpSvcPlugin* plugin) +static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd) { ADDIN_ARGV* args; - rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin; - - DEBUG_SVC("connecting"); rdpsnd->latency = -1; rdpsnd->queue = MessageQueue_New(); - rdpsnd->thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread, - (void*) plugin, 0, NULL); - args = (ADDIN_ARGV*) plugin->channel_entry_points.pExtendedData; + rdpsnd->ScheduleThread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread, + (void*) rdpsnd, 0, NULL); + + args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData; if (args) rdpsnd_process_addin_args(rdpsnd, args); @@ -733,23 +735,16 @@ static void rdpsnd_process_connect(rdpSvcPlugin* plugin) } } -static void rdpsnd_process_event(rdpSvcPlugin* plugin, wMessage* event) +static void rdpsnd_process_terminate(rdpsndPlugin* rdpsnd) { - freerdp_event_free(event); -} - -static void rdpsnd_process_terminate(rdpSvcPlugin* plugin) -{ - rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin; - if (rdpsnd->device) IFCALL(rdpsnd->device->Free, rdpsnd->device); MessageQueue_PostQuit(rdpsnd->queue, 0); - WaitForSingleObject(rdpsnd->thread, INFINITE); + WaitForSingleObject(rdpsnd->ScheduleThread, INFINITE); MessageQueue_Free(rdpsnd->queue); - CloseHandle(rdpsnd->thread); + CloseHandle(rdpsnd->ScheduleThread); if (rdpsnd->subsystem) free(rdpsnd->subsystem); @@ -766,37 +761,276 @@ static void rdpsnd_process_terminate(rdpSvcPlugin* plugin) rdpsnd->ClientFormats = NULL; } + +/****************************************************************************************/ + + +static wListDictionary* g_InitHandles; +static wListDictionary* g_OpenHandles; + +void rdpsnd_add_init_handle_data(void* pInitHandle, void* pUserData) +{ + if (!g_InitHandles) + g_InitHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_InitHandles, pInitHandle, pUserData); +} + +void* rdpsnd_get_init_handle_data(void* pInitHandle) +{ + void* pUserData = NULL; + pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle); + return pUserData; +} + +void rdpsnd_remove_init_handle_data(void* pInitHandle) +{ + ListDictionary_Remove(g_InitHandles, pInitHandle); +} + +void rdpsnd_add_open_handle_data(DWORD openHandle, void* pUserData) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + + if (!g_OpenHandles) + g_OpenHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData); +} + +void* rdpsnd_get_open_handle_data(DWORD openHandle) +{ + void* pUserData = NULL; + void* pOpenHandle = (void*) (size_t) openHandle; + pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle); + return pUserData; +} + +void rdpsnd_remove_open_handle_data(DWORD openHandle) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + ListDictionary_Remove(g_OpenHandles, pOpenHandle); +} + +int rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) +{ + UINT32 status = 0; + + if (!rdpsnd) + status = CHANNEL_RC_BAD_INIT_HANDLE; + else + status = rdpsnd->channelEntryPoints.pVirtualChannelWrite(rdpsnd->OpenHandle, + Stream_Buffer(s), Stream_GetPosition(s), s); + + if (status != CHANNEL_RC_OK) + { + Stream_Free(s, TRUE); + fprintf(stderr, "rdpdr_virtual_channel_write: VirtualChannelWrite failed %d\n", status); + } + + return status; +} + +static void rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin, + void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + wStream* s; + + if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME)) + { + return; + } + + if (dataFlags & CHANNEL_FLAG_FIRST) + { + if (plugin->data_in != NULL) + Stream_Free(plugin->data_in, TRUE); + + plugin->data_in = Stream_New(NULL, totalLength); + } + + s = plugin->data_in; + Stream_EnsureRemainingCapacity(s, (int) dataLength); + Stream_Write(s, pData, dataLength); + + if (dataFlags & CHANNEL_FLAG_LAST) + { + if (Stream_Capacity(s) != Stream_GetPosition(s)) + { + fprintf(stderr, "rdpsnd_virtual_channel_event_data_received: read error\n"); + } + + plugin->data_in = NULL; + Stream_SealLength(s); + Stream_SetPosition(s, 0); + + MessageQueue_Post(plugin->MsgPipe->In, NULL, 0, (void*) s, NULL); + } +} + +static void rdpsnd_virtual_channel_open_event(UINT32 openHandle, UINT32 event, + void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + rdpsndPlugin* plugin; + + plugin = (rdpsndPlugin*) rdpsnd_get_open_handle_data(openHandle); + + if (!plugin) + { + fprintf(stderr, "rdpsnd_virtual_channel_open_event: error no match\n"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_DATA_RECEIVED: + rdpsnd_virtual_channel_event_data_received(plugin, pData, dataLength, totalLength, dataFlags); + break; + + case CHANNEL_EVENT_WRITE_COMPLETE: + Stream_Free((wStream*) pData, TRUE); + break; + + case CHANNEL_EVENT_USER: + break; + } +} + +static void* rdpsnd_virtual_channel_client_thread(void* arg) +{ + wStream* data; + wMessage message; + rdpsndPlugin* plugin = (rdpsndPlugin*) arg; + + rdpsnd_process_connect(plugin); + + while (1) + { + if (!MessageQueue_Wait(plugin->MsgPipe->In)) + break; + + if (MessageQueue_Peek(plugin->MsgPipe->In, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + if (message.id == 0) + { + data = (wStream*) message.wParam; + rdpsnd_recv_pdu(plugin, data); + } + } + } + + ExitThread(0); + return NULL; +} + +static void rdpsnd_virtual_channel_event_connected(rdpsndPlugin* plugin, void* pData, UINT32 dataLength) +{ + UINT32 status; + + status = plugin->channelEntryPoints.pVirtualChannelOpen(plugin->InitHandle, + &plugin->OpenHandle, plugin->channelDef.name, rdpsnd_virtual_channel_open_event); + + rdpsnd_add_open_handle_data(plugin->OpenHandle, plugin); + + if (status != CHANNEL_RC_OK) + { + fprintf(stderr, "rdpsnd_virtual_channel_event_connected: open failed: status: %d\n", status); + return; + } + + plugin->MsgPipe = MessagePipe_New(); + + plugin->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) rdpsnd_virtual_channel_client_thread, (void*) plugin, 0, NULL); +} + +static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* plugin) +{ + MessagePipe_PostQuit(plugin->MsgPipe, 0); + WaitForSingleObject(plugin->thread, INFINITE); + + MessagePipe_Free(plugin->MsgPipe); + CloseHandle(plugin->thread); + + plugin->channelEntryPoints.pVirtualChannelClose(plugin->OpenHandle); + + if (plugin->data_in) + { + Stream_Free(plugin->data_in, TRUE); + plugin->data_in = NULL; + } + + rdpsnd_process_terminate(plugin); + + rdpsnd_remove_open_handle_data(plugin->OpenHandle); + rdpsnd_remove_init_handle_data(plugin->InitHandle); +} + +static void rdpsnd_virtual_channel_init_event(void* pInitHandle, UINT32 event, void* pData, UINT32 dataLength) +{ + rdpsndPlugin* plugin; + + plugin = (rdpsndPlugin*) rdpsnd_get_init_handle_data(pInitHandle); + + if (!plugin) + { + fprintf(stderr, "rdpsnd_virtual_channel_init_event: error no match\n"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_CONNECTED: + rdpsnd_virtual_channel_event_connected(plugin, pData, dataLength); + break; + + case CHANNEL_EVENT_DISCONNECTED: + break; + + case CHANNEL_EVENT_TERMINATED: + rdpsnd_virtual_channel_event_terminated(plugin); + break; + } +} + /* rdpsnd is always built-in */ #define VirtualChannelEntry rdpsnd_VirtualChannelEntry int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) { - rdpsndPlugin* _p; + rdpsndPlugin* rdpsnd; - _p = (rdpsndPlugin*) malloc(sizeof(rdpsndPlugin)); - ZeroMemory(_p, sizeof(rdpsndPlugin)); + rdpsnd = (rdpsndPlugin*) malloc(sizeof(rdpsndPlugin)); - _p->plugin.channel_def.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP; - - strcpy(_p->plugin.channel_def.name, "rdpsnd"); - - _p->plugin.connect_callback = rdpsnd_process_connect; - _p->plugin.receive_callback = rdpsnd_recv_pdu; - _p->plugin.event_callback = rdpsnd_process_event; - _p->plugin.terminate_callback = rdpsnd_process_terminate; + if (rdpsnd) + { + ZeroMemory(rdpsnd, sizeof(rdpsndPlugin)); #if !defined(_WIN32) && !defined(ANDROID) - { - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGIO); - pthread_sigmask(SIG_BLOCK, &mask, NULL); - } + { + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGIO); + pthread_sigmask(SIG_BLOCK, &mask, NULL); + } #endif - svc_plugin_init((rdpSvcPlugin*) _p, pEntryPoints); + rdpsnd->channelDef.options = + CHANNEL_OPTION_INITIALIZED | + CHANNEL_OPTION_ENCRYPT_RDP; + + strcpy(rdpsnd->channelDef.name, "rdpsnd"); + + CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints, pEntryPoints->cbSize); + + rdpsnd->channelEntryPoints.pVirtualChannelInit(&rdpsnd->InitHandle, + &rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpsnd_virtual_channel_init_event); + + rdpsnd_add_init_handle_data(rdpsnd->InitHandle, (void*) rdpsnd); + } return 1; } diff --git a/channels/rdpsnd/client/rdpsnd_main.h b/channels/rdpsnd/client/rdpsnd_main.h index 242001dc6..84508a1d5 100644 --- a/channels/rdpsnd/client/rdpsnd_main.h +++ b/channels/rdpsnd/client/rdpsnd_main.h @@ -21,6 +21,9 @@ #ifndef __RDPSND_MAIN_H #define __RDPSND_MAIN_H +#include +#include +#include #include #if defined(WITH_DEBUG_SND) @@ -29,4 +32,6 @@ #define DEBUG_SND(fmt, ...) do { } while (0) #endif +int rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s); + #endif /* __RDPSND_MAIN_H */