22#include <freerdp/config.h>
25#include <winpr/cast.h>
26#include <winpr/stream.h>
27#include <winpr/interlocked.h>
29#include <freerdp/freerdp.h>
30#include <freerdp/multitransport.h>
31#if defined(WITH_RDPEUDP)
32#include <freerdp/channels/channels.h>
34#include <freerdp/channels/drdynvc.h>
35#include <freerdp/utils/drdynvc.h>
36#include <freerdp/codec/zgfx.h>
38#include "drdynvc_main.h"
40#define TAG CHANNELS_TAG("drdynvc.client")
43typedef enum WINPR_C23_ENUM_TYPE(uint32_t)
46 DRDYNVC_MSG_TUNNEL_DATA = 1,
47 DRDYNVC_MSG_TUNNEL_STATE = 2
51#define DRDYNVC_MAX_TUNNEL_BACKLOG 4096
54#define DRDYNVC_MAX_SOFT_SYNC_TUNNELS 8
57static const char* channel_state2str(DVC_CHANNEL_STATE state)
61 case DVC_CHANNEL_INIT:
62 return "DVC_CHANNEL_INIT";
63 case DVC_CHANNEL_RUNNING:
64 return "DVC_CHANNEL_RUNNING";
65 case DVC_CHANNEL_CLOSED:
66 return "DVC_CHANNEL_CLOSED";
68 return "DVC_CHANNEL_UNKNOWN";
74static UINT dvcman_channel_close(
DVCMAN_CHANNEL* channel, BOOL perRequest, BOOL fromHashTableFn);
75static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr);
78static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, UINT32 tunnelType,
79 const BYTE* data, UINT32 dataSize, BOOL* close,
86 UINT32* tunnelType, BOOL continuation);
91 free(listener->channel_name);
101static UINT dvcman_get_configuration(IWTSListener* pListener,
void** ppPropertyBag)
103 WINPR_ASSERT(ppPropertyBag);
104 WINPR_UNUSED(pListener);
105 *ppPropertyBag =
nullptr;
106 return ERROR_INTERNAL_ERROR;
115static UINT dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr,
116 const char* pszChannelName, ULONG ulFlags,
117 IWTSListenerCallback* pListenerCallback,
118 IWTSListener** ppListener)
123 WINPR_ASSERT(dvcman);
124 WLog_DBG(TAG,
"create_listener: %" PRIuz
".%s.", HashTable_Count(dvcman->listeners) + 1,
130 WLog_ERR(TAG,
"calloc failed!");
131 return CHANNEL_RC_NO_MEMORY;
134 listener->iface.GetConfiguration = dvcman_get_configuration;
135 listener->iface.pInterface =
nullptr;
136 listener->dvcman = dvcman;
137 listener->channel_name = _strdup(pszChannelName);
139 if (!listener->channel_name)
141 WLog_ERR(TAG,
"_strdup failed!");
142 dvcman_wtslistener_free(listener);
143 return CHANNEL_RC_NO_MEMORY;
146 listener->flags = ulFlags;
147 listener->listener_callback = pListenerCallback;
150 *ppListener = (IWTSListener*)listener;
152 if (!HashTable_Insert(dvcman->listeners, listener->channel_name, listener))
154 dvcman_wtslistener_free(listener);
155 return ERROR_INTERNAL_ERROR;
159 return CHANNEL_RC_OK;
163static UINT dvcman_destroy_listener(IWTSVirtualChannelManager* pChannelMgr, IWTSListener* pListener)
167 WINPR_UNUSED(pChannelMgr);
171 DVCMAN* dvcman = listener->dvcman;
173 HashTable_Remove(dvcman->listeners, listener->channel_name);
176 return CHANNEL_RC_OK;
185static UINT dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints,
const char* name,
188 WINPR_ASSERT(pEntryPoints);
191 WINPR_ASSERT(dvcman);
192 if (!ArrayList_Append(dvcman->plugin_names, name))
193 return ERROR_INTERNAL_ERROR;
194 if (!ArrayList_Append(dvcman->plugins, pPlugin))
195 return ERROR_INTERNAL_ERROR;
197 WLog_DBG(TAG,
"register_plugin: num_plugins %" PRIuz, ArrayList_Count(dvcman->plugins));
198 return CHANNEL_RC_OK;
202static IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints,
const char* name)
204 IWTSPlugin* plugin =
nullptr;
207 WINPR_ASSERT(pEntryPoints);
209 if (!dvcman || !pEntryPoints || !name)
212 nc = ArrayList_Count(dvcman->plugin_names);
213 pc = ArrayList_Count(dvcman->plugins);
217 ArrayList_Lock(dvcman->plugin_names);
218 ArrayList_Lock(dvcman->plugins);
219 for (
size_t i = 0; i < pc; i++)
221 const char* cur = ArrayList_GetItem(dvcman->plugin_names, i);
222 if (strcmp(cur, name) == 0)
224 plugin = ArrayList_GetItem(dvcman->plugins, i);
228 ArrayList_Unlock(dvcman->plugin_names);
229 ArrayList_Unlock(dvcman->plugins);
234static const ADDIN_ARGV* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
236 WINPR_ASSERT(pEntryPoints);
241static rdpContext* dvcman_get_rdp_context(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
245 return entry->context;
249static rdpSettings* dvcman_get_rdp_settings(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
251 rdpContext* context = dvcman_get_rdp_context(pEntryPoints);
252 WINPR_ASSERT(context);
254 return context->settings;
258static UINT32 dvcman_get_channel_id(IWTSVirtualChannel* channel)
262 return dvc->channel_id;
266static const char* dvcman_get_channel_name(IWTSVirtualChannel* channel)
270 return dvc->channel_name;
274static DVCMAN_CHANNEL* dvcman_get_channel_by_id(IWTSVirtualChannelManager* pChannelMgr,
275 UINT32 ChannelId, BOOL doRef)
280 WINPR_ASSERT(dvcman);
281 HashTable_Lock(dvcman->channelsById);
282 dvcChannel = HashTable_GetItemValue(dvcman->channelsById, &ChannelId);
286 InterlockedIncrement(&dvcChannel->refCounter);
289 HashTable_Unlock(dvcman->channelsById);
294static void dvcman_return_channel(IWTSVirtualChannelManager* pChannelMgr,
DVCMAN_CHANNEL* channel)
301 WINPR_ASSERT(dvcman);
302 HashTable_Unlock(dvcman->channelsById);
306static IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr,
309 DVCMAN_CHANNEL* channel = dvcman_get_channel_by_id(pChannelMgr, ChannelId, FALSE);
312 dvcman_return_channel(pChannelMgr, channel);
314 return &channel->iface;
317static void dvcman_plugin_terminate(
void* plugin)
319 IWTSPlugin* pPlugin = plugin;
321 WINPR_ASSERT(pPlugin);
322 UINT error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Terminated, pPlugin);
323 if (error != CHANNEL_RC_OK)
324 WLog_ERR(TAG,
"Terminated failed with error %" PRIu32
"!", error);
327static void wts_listener_free(
void* arg)
330 dvcman_wtslistener_free(listener);
334static BOOL channelIdMatch(
const void* k1,
const void* k2)
338 return *((
const UINT32*)k1) == *((
const UINT32*)k2);
342static UINT32 channelIdHash(
const void*
id)
345 return *((
const UINT32*)
id);
348static void channelByIdCleanerFn(
void* value)
353 dvcman_channel_close(channel, FALSE, TRUE);
354 dvcman_channel_free(channel);
358WINPR_ATTR_MALLOC(dvcman_free, 2)
359static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
367 dvcman->iface.CreateListener = dvcman_create_listener;
368 dvcman->iface.DestroyListener = dvcman_destroy_listener;
369 dvcman->iface.FindChannelById = dvcman_find_channel_by_id;
370 dvcman->iface.GetChannelId = dvcman_get_channel_id;
371 dvcman->iface.GetChannelName = dvcman_get_channel_name;
372 dvcman->drdynvc = plugin;
373 dvcman->channelsById = HashTable_New(TRUE);
375 if (!dvcman->channelsById)
378 if (!HashTable_SetHashFunction(dvcman->channelsById, channelIdHash))
381 obj = HashTable_KeyObject(dvcman->channelsById);
385 obj = HashTable_ValueObject(dvcman->channelsById);
389 dvcman->pool = StreamPool_New(TRUE, 10);
393 dvcman->listeners = HashTable_New(TRUE);
394 if (!dvcman->listeners)
397 if (!HashTable_SetHashFunction(dvcman->listeners, HashTable_StringHash))
400 obj = HashTable_KeyObject(dvcman->listeners);
403 obj = HashTable_ValueObject(dvcman->listeners);
406 dvcman->plugin_names = ArrayList_New(TRUE);
407 if (!dvcman->plugin_names)
409 obj = ArrayList_Object(dvcman->plugin_names);
413 dvcman->plugins = ArrayList_New(TRUE);
414 if (!dvcman->plugins)
416 obj = ArrayList_Object(dvcman->plugins);
418 return &dvcman->iface;
420 dvcman_free(plugin, &dvcman->iface);
430static UINT dvcman_load_addin(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr,
433 WINPR_ASSERT(drdynvc);
434 WINPR_ASSERT(pChannelMgr);
436 WINPR_ASSERT(context);
438 WLog_Print(drdynvc->log, WLOG_INFO,
"Loading Dynamic Virtual Channel %s", args->argv[0]);
440 PVIRTUALCHANNELENTRY pvce = freerdp_load_channel_addin_entry(args->argv[0],
nullptr,
nullptr,
441 FREERDP_ADDIN_CHANNEL_DYNAMIC);
442 PDVC_PLUGIN_ENTRY pDVCPluginEntry = WINPR_FUNC_PTR_CAST(pvce, PDVC_PLUGIN_ENTRY);
448 entryPoints.iface.RegisterPlugin = dvcman_register_plugin;
449 entryPoints.iface.GetPlugin = dvcman_get_plugin;
450 entryPoints.iface.GetPluginData = dvcman_get_plugin_data;
451 entryPoints.iface.GetRdpSettings = dvcman_get_rdp_settings;
452 entryPoints.iface.GetRdpContext = dvcman_get_rdp_context;
453 entryPoints.dvcman = (
DVCMAN*)pChannelMgr;
454 entryPoints.args = args;
455 entryPoints.context = context;
456 return pDVCPluginEntry(&entryPoints.iface);
459 return ERROR_INVALID_FUNCTION;
469 drdynvcPlugin* plugin = channel->dvcman->drdynvc;
472 rdpContext* context = plugin->rdpcontext;
475 ChannelTerminatedEventArgs e = WINPR_C_ARRAY_INIT;
476 EventArgsInit(&e,
"freerdp");
477 e.name = channel->channel_name;
478 e.pInterface = channel->pInterface;
480 const int rc = PubSub_OnChannelTerminated(context->pubSub, context, &e);
482 WLog_WARN(TAG,
"PubSub_OnChannelTerminated(%s) failed", channel->channel_name);
487 if (channel->dvc_data)
488 Stream_Release(channel->dvc_data);
490 zgfx_context_free(channel->decompressor);
491 DeleteCriticalSection(&(channel->lock));
492 free(channel->channel_name);
498 WINPR_ASSERT(channel);
499 if (InterlockedDecrement(&channel->refCounter))
502 DVCMAN* dvcman = channel->dvcman;
504 HashTable_Remove(dvcman->channelsById, &channel->channel_id);
510 WINPR_ASSERT(channel);
511 EnterCriticalSection(&channel->lock);
512 const UINT32 tunnelType = channel->tunnelType;
513 LeaveCriticalSection(&channel->lock);
518static void dvcman_channel_set_tunnel(
DVCMAN_CHANNEL* channel, UINT32 tunnelType)
520 WINPR_ASSERT(channel);
521 EnterCriticalSection(&channel->lock);
522 channel->tunnelType = tunnelType;
523 LeaveCriticalSection(&channel->lock);
529 WINPR_ASSERT(channel);
530 DVCMAN* dvcman = channel->dvcman;
531 drdynvcPlugin* drdynvc = dvcman->drdynvc;
532 wStream* s = StreamPool_Take(dvcman->pool, 5);
536 WLog_Print(drdynvc->log, WLOG_ERROR,
"StreamPool_Take failed!");
537 return CHANNEL_RC_NO_MEMORY;
540 Stream_Write_UINT8(s, (CLOSE_REQUEST_PDU << 4) | 0x02);
541 Stream_Write_UINT32(s, channel->channel_id);
542 UINT32 tunnelType = dvcman_channel_get_tunnel(channel);
543 return drdynvc_send_on(drdynvc, s, &channel->stats, &tunnelType, FALSE);
548 WINPR_ASSERT(channel);
550 IWTSVirtualChannelCallback* cb = channel->channel_callback;
551 const char* name = channel->channel_name;
552 const UINT32
id = channel->channel_id;
555 if (!cb->OnOpen || !cb->OnClose || !cb->OnDataReceived)
556 WLog_VRB(TAG,
"{%s:%" PRIu32
"} OnOpen=%p, OnClose=%p, OnDataReceived=%p", name,
id,
557 WINPR_FUNC_PTR_CAST(cb->OnOpen,
const void*),
558 WINPR_FUNC_PTR_CAST(cb->OnClose,
const void*),
559 WINPR_FUNC_PTR_CAST(cb->OnDataReceived,
const void*));
565 WINPR_ASSERT(channel);
568 channel->stats.packetsIn++;
570 IWTSVirtualChannelCallback* cb = channel->channel_callback;
573 check_open_close_receive(channel);
574 WINPR_ASSERT(cb->OnDataReceived);
575 return cb->OnDataReceived(cb, data);
578static UINT dvcman_channel_close(
DVCMAN_CHANNEL* channel, BOOL perRequest, BOOL fromHashTableFn)
580 UINT error = CHANNEL_RC_OK;
581 DrdynvcClientContext* context =
nullptr;
583 WINPR_ASSERT(channel);
584 switch (channel->state)
586 case DVC_CHANNEL_INIT:
588 case DVC_CHANNEL_RUNNING:
591 drdynvcPlugin* drdynvc = channel->dvcman->drdynvc;
592 WINPR_ASSERT(drdynvc);
593 context = drdynvc->context;
595 WLog_Print(drdynvc->log, WLOG_DEBUG,
"sending close confirm for '%s'",
596 channel->channel_name);
598 error = dvcchannel_send_close(channel);
599 if (error != CHANNEL_RC_OK)
602 WLog_Print(drdynvc->log, WLOG_DEBUG,
603 "error when sending closeRequest for '%s'",
604 channel->channel_name);
606 WLog_Print(drdynvc->log, WLOG_DEBUG,
607 "error when sending close confirm for '%s'",
608 channel->channel_name);
610 WLog_Print(drdynvc->log, WLOG_DEBUG,
"listener %s destroyed channel %" PRIu32
"",
611 channel->channel_name, channel->channel_id);
614 channel->state = DVC_CHANNEL_CLOSED;
617 check_open_close_receive(channel);
619 IWTSVirtualChannelCallback* cb = channel->channel_callback;
620 channel->channel_callback =
nullptr;
622 error = IFCALLRESULT(CHANNEL_RC_OK, cb->OnClose, cb);
625#if defined(WITH_RDPEUDP)
627 if (channel->staticBridge)
630 if (channel->dvcman && channel->dvcman->drdynvc)
634 IFCALLRET(context->OnChannelDisconnected, error, context, channel->channel_name,
635 channel->pInterface);
639 if (!fromHashTableFn)
640 dvcman_channel_unref(channel);
642 case DVC_CHANNEL_CLOSED:
651WINPR_ATTR_MALLOC(dvcman_channel_free, 1)
653 IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId,
654 const
char* ChannelName)
656 WINPR_ASSERT(drdynvc);
657 WINPR_ASSERT(pChannelMgr);
663 channel->dvcman = (
DVCMAN*)pChannelMgr;
664 channel->channel_id = ChannelId;
665 channel->refCounter = 1;
666 channel->state = DVC_CHANNEL_INIT;
667 channel->channel_name = _strdup(ChannelName);
668 if (!channel->channel_name)
671 channel->decompressor = zgfx_context_new(FALSE);
672 if (!channel->decompressor)
675 if (!InitializeCriticalSectionEx(&(channel->lock), 0, 0))
680 rdpContext* context = drdynvc->rdpcontext;
683 ChannelInitializedEventArgs e = WINPR_C_ARRAY_INIT;
684 EventArgsInit(&e,
"freerdp");
685 e.name = channel->channel_name;
686 e.pInterface = channel->pInterface;
688 const int rc = PubSub_OnChannelInitialized(context->pubSub, context, &e);
690 WLog_WARN(TAG,
"PubSub_OnChannelInitialized(%s) failed", channel->channel_name);
696 dvcman_channel_free(channel);
700static void dvcman_clear(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr)
704 WINPR_ASSERT(dvcman);
705 WINPR_UNUSED(drdynvc);
707 HashTable_Clear(dvcman->channelsById);
708 ArrayList_Clear(dvcman->plugins);
709 ArrayList_Clear(dvcman->plugin_names);
710 HashTable_Clear(dvcman->listeners);
713static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr)
717 WINPR_ASSERT(dvcman);
718 WINPR_UNUSED(drdynvc);
720 HashTable_Free(dvcman->channelsById);
721 ArrayList_Free(dvcman->plugins);
722 ArrayList_Free(dvcman->plugin_names);
723 HashTable_Free(dvcman->listeners);
725 StreamPool_Free(dvcman->pool);
735static UINT dvcman_init(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr)
738 UINT error = CHANNEL_RC_OK;
740 WINPR_ASSERT(dvcman);
741 ArrayList_Lock(dvcman->plugins);
742 for (
size_t i = 0; i < ArrayList_Count(dvcman->plugins); i++)
744 IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i);
746 error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Initialize, pPlugin, pChannelMgr);
747 if (error != CHANNEL_RC_OK)
749 WLog_Print(drdynvc->log, WLOG_ERROR,
"Initialize failed with error %" PRIu32
"!",
756 ArrayList_Unlock(dvcman->plugins);
766static UINT dvcman_write_channel(IWTSVirtualChannel* pChannel, ULONG cbSize,
const BYTE* pBuffer,
773 WINPR_UNUSED(pReserved);
774 if (!channel || !channel->dvcman)
775 return CHANNEL_RC_BAD_CHANNEL;
777 EnterCriticalSection(&(channel->lock));
778 status = drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, channel->tunnelType,
779 pBuffer, cbSize, &close, &channel->stats);
780 LeaveCriticalSection(&(channel->lock));
783 dvcman_channel_close(channel, FALSE, FALSE);
794static UINT dvcman_close_channel_iface(IWTSVirtualChannel* pChannel)
799 return CHANNEL_RC_BAD_CHANNEL;
801 WLog_DBG(TAG,
"close_channel_iface: id=%" PRIu32
"", channel->channel_id);
802 return dvcman_channel_close(channel, FALSE, FALSE);
805struct stats_collector_argument
813static BOOL stats_collector(WINPR_ATTR_UNUSED
const void* key,
void* value,
void* arg)
815 struct stats_collector_argument* args = arg;
819 WINPR_ASSERT(channel);
820 if (args->used >= args->count)
825 if (channel->channel_name)
827 const size_t len = strnlen(channel->channel_name, ARRAYSIZE(stat->channelName) - 1);
828 strncpy(stat->channelName, channel->channel_name, len);
831 memset(stat->channelName, 0,
sizeof(stat->channelName));
832 stat->channelId = channel->channel_id;
833 stat->bytesIn = channel->stats.bytesIn;
834 stat->bytesOut = channel->stats.bytesOut;
835 stat->fragmentsIn = channel->stats.fragmentsIn;
836 stat->fragmentsOut = channel->stats.fragmentsOut;
837 stat->packetsIn = channel->stats.packetsIn;
838 stat->packetsOut = channel->stats.packetsOut;
842WINPR_ATTR_MALLOC(free, 1)
846 WINPR_ASSERT(context);
847 WINPR_ASSERT(pCount);
849 drdynvcPlugin* drdynvc = (drdynvcPlugin*)context->handle;
850 WINPR_ASSERT(drdynvc);
857 struct stats_collector_argument args = { .stats =
nullptr, .count = 0 };
859 HashTable_Lock(dvcman->channelsById);
860 const size_t count = HashTable_Count(dvcman->channelsById);
867 const BOOL rc = HashTable_Foreach(dvcman->channelsById, stats_collector, &args);
870 HashTable_Unlock(dvcman->channelsById);
876 HashTable_Unlock(dvcman->channelsById);
881#if defined(WITH_RDPEUDP)
892 IWTSVirtualChannelCallback iface;
894 UINT16 staticChannelId;
895 char staticChannelName[CHANNEL_NAME_LEN + 1];
901} DVCMAN_STATIC_BRIDGE;
906 drdynvcPlugin* drdynvc;
908} DVCMAN_STATIC_BRIDGE_TARGET;
914static BOOL dvcman_static_bridge_send(
void* custom,
const BYTE* data,
size_t length)
916 const DVCMAN_STATIC_BRIDGE_TARGET* target = custom;
917 WINPR_ASSERT(target);
918 WINPR_ASSERT(target->drdynvc);
920 if (length > UINT32_MAX)
924 IWTSVirtualChannelManager* mgr = target->drdynvc->channel_mgr;
925 DVCMAN_CHANNEL* channel = dvcman_get_channel_by_id(mgr, target->channelId, TRUE);
928 dvcman_return_channel(mgr, channel);
930 UINT rc = CHANNEL_RC_OK;
931 if ((channel->state == DVC_CHANNEL_RUNNING) && channel->staticBridge)
932 rc = dvcman_write_channel(&channel->iface, (ULONG)length, data,
nullptr);
933 dvcman_channel_unref(channel);
934 return rc == CHANNEL_RC_OK;
940static void dvcman_static_bridge_deliver(DVCMAN_STATIC_BRIDGE* bridge,
const BYTE* data,
941 size_t length, UINT32 flags,
size_t totalLength)
943 WINPR_ASSERT(bridge);
945 if ((length > 0) && !freerdp_channels_data(bridge->instance, bridge->staticChannelId, data,
946 length, flags, totalLength))
947 WLog_DBG(TAG,
"static channel %" PRIu16
" took no data, %" PRIuz
" bytes discarded",
948 bridge->staticChannelId, length);
954static UINT dvcman_static_bridge_on_data(IWTSVirtualChannelCallback* pChannelCallback,
958 const size_t length = Stream_GetRemainingLength(data);
959 dvcman_static_bridge_deliver((DVCMAN_STATIC_BRIDGE*)pChannelCallback, Stream_ConstPointer(data),
960 length, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, length);
961 return CHANNEL_RC_OK;
971 WINPR_ASSERT(channel);
974 const size_t length = Stream_GetRemainingLength(data);
975 UINT32 flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
976 size_t totalLength = length;
978 if (channel->bridgeFragmented)
980 if (length > channel->dvc_data_length - channel->bridgeReceived)
982 WLog_Print(channel->dvcman->drdynvc->log, WLOG_ERROR,
983 "data exceeding declared length!");
984 channel->bridgeFragmented = FALSE;
985 return ERROR_INVALID_DATA;
988 flags = (channel->bridgeReceived == 0) ? CHANNEL_FLAG_FIRST : 0;
989 channel->bridgeReceived += (UINT32)length;
990 totalLength = channel->dvc_data_length;
991 channel->stats.fragmentsIn++;
992 if (channel->bridgeReceived >= channel->dvc_data_length)
994 flags |= CHANNEL_FLAG_LAST;
995 channel->bridgeFragmented = FALSE;
998 if (flags & CHANNEL_FLAG_LAST)
999 channel->stats.packetsIn++;
1001 dvcman_static_bridge_deliver((DVCMAN_STATIC_BRIDGE*)channel->channel_callback,
1002 Stream_ConstPointer(data), length, flags, totalLength);
1003 return CHANNEL_RC_OK;
1007static UINT dvcman_static_bridge_on_close(IWTSVirtualChannelCallback* pChannelCallback)
1009 DVCMAN_STATIC_BRIDGE* bridge = (DVCMAN_STATIC_BRIDGE*)pChannelCallback;
1010 WINPR_ASSERT(bridge);
1014 if (bridge->target &&
1015 !freerdp_channels_set_static_bridge(bridge->instance, bridge->staticChannelName,
nullptr,
1016 nullptr, bridge->target))
1017 WLog_DBG(TAG,
"static channel %s is gone already", bridge->staticChannelName);
1018 free(bridge->pending);
1020 return CHANNEL_RC_OK;
1025static void dvcman_static_bridge_publish(drdynvcPlugin* drdynvc,
DVCMAN_CHANNEL* channel)
1027 WINPR_ASSERT(drdynvc);
1028 WINPR_ASSERT(channel);
1030 if (!channel->staticBridge)
1032 DVCMAN_STATIC_BRIDGE* bridge = (DVCMAN_STATIC_BRIDGE*)channel->channel_callback;
1033 WINPR_ASSERT(bridge);
1034 void* target = bridge->pending;
1035 bridge->pending =
nullptr;
1036 if (target && freerdp_channels_set_static_bridge(bridge->instance, bridge->staticChannelName,
1037 dvcman_static_bridge_send, free, target))
1038 bridge->target = target;
1041 WLog_Print(drdynvc->log, WLOG_WARN,
1042 "static channel %s goes on sending on itself, the server may not read it",
1043 bridge->staticChannelName);
1050static DVCMAN_STATIC_BRIDGE* dvcman_static_bridge_new(drdynvcPlugin* drdynvc,
1051 const char* ChannelName)
1053 WINPR_ASSERT(drdynvc);
1054 WINPR_ASSERT(ChannelName);
1057 if (_stricmp(ChannelName, DRDYNVC_SVC_CHANNEL_NAME) == 0)
1059 if (!drdynvc->rdpcontext || !drdynvc->rdpcontext->instance)
1064 const rdpSettings* settings = drdynvc->rdpcontext->settings;
1067 SOFTSYNC_TCP_TO_UDP) == 0))
1070 freerdp* instance = drdynvc->rdpcontext->instance;
1071 const UINT16
id = freerdp_channels_get_id_by_name(instance, ChannelName);
1075 DVCMAN_STATIC_BRIDGE* bridge = calloc(1,
sizeof(DVCMAN_STATIC_BRIDGE));
1078 bridge->iface.OnDataReceived = dvcman_static_bridge_on_data;
1079 bridge->iface.OnClose = dvcman_static_bridge_on_close;
1080 bridge->instance = instance;
1081 bridge->staticChannelId = id;
1082 (void)_snprintf(bridge->staticChannelName,
sizeof(bridge->staticChannelName),
"%s",
1094static DVCMAN_CHANNEL* dvcman_create_channel(drdynvcPlugin* drdynvc,
1095 IWTSVirtualChannelManager* pChannelMgr,
1096 UINT32 ChannelId,
const char* ChannelName, UINT* res)
1099 DrdynvcClientContext* context =
nullptr;
1101 IWTSVirtualChannelCallback* pCallback =
nullptr;
1103 WINPR_ASSERT(dvcman);
1106 HashTable_Lock(dvcman->listeners);
1110 (
DVCMAN_LISTENER*)HashTable_GetItemValue(dvcman->listeners, ChannelName);
1111#if defined(WITH_RDPEUDP)
1113 DVCMAN_STATIC_BRIDGE* bridge =
1114 listener ? nullptr : dvcman_static_bridge_new(drdynvc, ChannelName);
1115 if (!listener && !bridge)
1120 HashTable_Unlock(dvcman->listeners);
1121 *res = ERROR_NOT_FOUND;
1125 DVCMAN_CHANNEL* channel = dvcman_get_channel_by_id(pChannelMgr, ChannelId, FALSE);
1128 switch (channel->state)
1130 case DVC_CHANNEL_RUNNING:
1131 WLog_Print(drdynvc->log, WLOG_ERROR,
1132 "Protocol error: Duplicated ChannelId %" PRIu32
" (%s)!", ChannelId,
1134 *res = CHANNEL_RC_ALREADY_OPEN;
1137 case DVC_CHANNEL_CLOSED:
1138 case DVC_CHANNEL_INIT:
1141 WLog_Print(drdynvc->log, WLOG_ERROR,
"not expecting a createChannel from state %s",
1142 channel_state2str(channel->state));
1143 *res = CHANNEL_RC_INITIALIZATION_ERROR;
1150 HashTable_Lock(dvcman->channelsById);
1151 channel = dvcman_channel_new(drdynvc, pChannelMgr, ChannelId, ChannelName);
1154 WLog_Print(drdynvc->log, WLOG_ERROR,
"dvcman_channel_new failed!");
1155 *res = CHANNEL_RC_NO_MEMORY;
1160 if (!HashTable_Insert(dvcman->channelsById, &channel->channel_id, channel))
1162 WLog_Print(drdynvc->log, WLOG_ERROR,
"unable to register channel in our channel list");
1163 *res = ERROR_INTERNAL_ERROR;
1164 dvcman_channel_free(channel);
1169 channel->iface.Write = dvcman_write_channel;
1170 channel->iface.Close = dvcman_close_channel_iface;
1173#if defined(WITH_RDPEUDP)
1178 WLog_Print(drdynvc->log, WLOG_INFO,
1179 "dynamic channel %" PRIu32
" carries the data of static channel %s",
1180 channel->channel_id, ChannelName);
1181 channel->staticBridge = TRUE;
1182 channel->state = DVC_CHANNEL_RUNNING;
1183 channel->channel_callback = &bridge->iface;
1186 DVCMAN_STATIC_BRIDGE_TARGET* target = calloc(1,
sizeof(DVCMAN_STATIC_BRIDGE_TARGET));
1189 target->drdynvc = drdynvc;
1190 target->channelId = channel->channel_id;
1192 bridge->pending = target;
1194 *res = CHANNEL_RC_OK;
1199 *res = listener->listener_callback->OnNewChannelConnection(
1200 listener->listener_callback, &channel->iface,
nullptr, &bAccept, &pCallback);
1202 if (*res != CHANNEL_RC_OK)
1204 WLog_Print(drdynvc->log, WLOG_ERROR,
1205 "OnNewChannelConnection failed with error %" PRIu32
"!", *res);
1206 *res = ERROR_INTERNAL_ERROR;
1207 dvcman_channel_unref(channel);
1214 WLog_Print(drdynvc->log, WLOG_ERROR,
"OnNewChannelConnection returned with bAccept FALSE!");
1215 *res = ERROR_INTERNAL_ERROR;
1216 dvcman_channel_unref(channel);
1221 WLog_Print(drdynvc->log, WLOG_DEBUG,
"listener %s created new channel %" PRIu32
"",
1222 listener->channel_name, channel->channel_id);
1223 channel->state = DVC_CHANNEL_RUNNING;
1224 channel->channel_callback = pCallback;
1225 channel->pInterface = listener->iface.pInterface;
1226 context = dvcman->drdynvc->context;
1228 IFCALLRET(context->OnChannelConnected, *res, context, ChannelName, listener->iface.pInterface);
1229 if (*res != CHANNEL_RC_OK)
1231 WLog_Print(drdynvc->log, WLOG_ERROR,
1232 "context.OnChannelConnected failed with error %" PRIu32
"", *res);
1236 HashTable_Unlock(dvcman->listeners);
1237 HashTable_Unlock(dvcman->channelsById);
1238#if defined(WITH_RDPEUDP)
1251static UINT dvcman_open_channel(drdynvcPlugin* drdynvc,
DVCMAN_CHANNEL* channel)
1253 UINT error = CHANNEL_RC_OK;
1255 WINPR_ASSERT(drdynvc);
1256 WINPR_ASSERT(channel);
1257 if (channel->state == DVC_CHANNEL_RUNNING)
1259 IWTSVirtualChannelCallback* pCallback = channel->channel_callback;
1261 if (pCallback->OnOpen)
1263 check_open_close_receive(channel);
1264 error = pCallback->OnOpen(pCallback);
1267 WLog_Print(drdynvc->log, WLOG_ERROR,
"OnOpen failed with error %" PRIu32
"!",
1273 WLog_Print(drdynvc->log, WLOG_DEBUG,
"open_channel: ChannelId %" PRIu32
"",
1274 channel->channel_id);
1287static UINT dvcman_receive_channel_data_first(
DVCMAN_CHANNEL* channel, UINT32 length)
1289 WINPR_ASSERT(channel);
1290 WINPR_ASSERT(channel->dvcman);
1291#if defined(WITH_RDPEUDP)
1292 if (channel->staticBridge)
1295 channel->dvc_data_length = length;
1296 channel->bridgeReceived = 0;
1297 channel->bridgeFragmented = TRUE;
1298 return CHANNEL_RC_OK;
1301 if (channel->dvc_data)
1302 Stream_Release(channel->dvc_data);
1304 channel->dvc_data = StreamPool_Take(channel->dvcman->pool, 1600);
1306 if (!channel->dvc_data)
1308 drdynvcPlugin* drdynvc = channel->dvcman->drdynvc;
1309 WLog_Print(drdynvc->log, WLOG_ERROR,
"StreamPool_Take failed!");
1310 return CHANNEL_RC_NO_MEMORY;
1313 channel->dvc_data_length = length;
1314 return CHANNEL_RC_OK;
1324 WINPR_ATTR_UNUSED UINT32 ThreadingFlags)
1326 UINT status = CHANNEL_RC_OK;
1327 size_t dataSize = Stream_GetRemainingLength(data);
1329 WINPR_ASSERT(channel);
1330 WINPR_ASSERT(channel->dvcman);
1332 channel->stats.bytesIn += Stream_Length(data);
1333#if defined(WITH_RDPEUDP)
1334 if (channel->staticBridge)
1335 return dvcman_static_bridge_receive(channel, data);
1337 if (channel->dvc_data)
1339 drdynvcPlugin* drdynvc = channel->dvcman->drdynvc;
1342 if (Stream_GetPosition(channel->dvc_data) + dataSize > channel->dvc_data_length)
1344 WLog_Print(drdynvc->log, WLOG_ERROR,
"data exceeding declared length!");
1345 Stream_Release(channel->dvc_data);
1346 channel->dvc_data =
nullptr;
1347 status = ERROR_INVALID_DATA;
1350 if (!Stream_EnsureRemainingCapacity(channel->dvc_data, dataSize))
1352 Stream_Release(channel->dvc_data);
1353 channel->dvc_data =
nullptr;
1354 status = ERROR_INVALID_DATA;
1358 Stream_Copy(data, channel->dvc_data, dataSize);
1359 channel->stats.fragmentsIn++;
1361 if (Stream_GetPosition(channel->dvc_data) >= channel->dvc_data_length)
1363 Stream_SealLength(channel->dvc_data);
1364 Stream_ResetPosition(channel->dvc_data);
1366 status = dvcman_call_on_receive(channel, channel->dvc_data);
1367 Stream_Release(channel->dvc_data);
1368 channel->dvc_data =
nullptr;
1372 status = dvcman_call_on_receive(channel, data);
1379static UINT8 drdynvc_write_variable_uint(
wStream* s, UINT32 val)
1386 Stream_Write_UINT8(s, (UINT8)val);
1388 else if (val <= 0xFFFF)
1391 Stream_Write_UINT16(s, (UINT16)val);
1396 Stream_Write_UINT32(s, val);
1413 status = CHANNEL_RC_BAD_CHANNEL_HANDLE;
1416 const size_t len = Stream_GetPosition(s);
1419 stats->bytesOut += len;
1421 WINPR_ASSERT(drdynvc->channelEntryPoints.pVirtualChannelWriteEx);
1422 status = drdynvc->channelEntryPoints.pVirtualChannelWriteEx(
1423 drdynvc->InitHandle, drdynvc->OpenHandle, Stream_Buffer(s), (UINT32)len, s);
1429 return CHANNEL_RC_OK;
1431 case CHANNEL_RC_NOT_CONNECTED:
1433 return CHANNEL_RC_OK;
1435 case CHANNEL_RC_BAD_CHANNEL_HANDLE:
1437 WLog_ERR(TAG,
"VirtualChannelWriteEx failed with CHANNEL_RC_BAD_CHANNEL_HANDLE");
1442 WLog_Print(drdynvc->log, WLOG_ERROR,
1443 "VirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
1444 WTSErrorToString(status), status);
1453static void drdynvc_tunnel_abort(drdynvcPlugin* drdynvc,
const char* why)
1455 WINPR_ASSERT(drdynvc);
1458 WLog_Print(drdynvc->log, WLOG_ERROR,
"%s, ending the session", why);
1459 if (!drdynvc->rdpcontext)
1461 freerdp_set_last_error_if_not(drdynvc->rdpcontext, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
1462 (void)freerdp_abort_connect_context(drdynvc->rdpcontext);
1477 UINT32* tunnelType, BOOL continuation)
1480 WINPR_ASSERT(tunnelType);
1481 if (drdynvc && (*tunnelType != 0))
1483 const size_t len = Stream_GetPosition(s);
1484 if (freerdp_multitransport_send_dvc(drdynvc->rdpcontext, *tunnelType, Stream_Buffer(s),
1488 stats->bytesOut += len;
1490 return CHANNEL_RC_OK;
1495 drdynvc_tunnel_abort(drdynvc,
"the tunnel failed in the middle of a message");
1496 return ERROR_BROKEN_PIPE;
1500 return drdynvc_send(drdynvc, s, stats);
1509static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, UINT32 tunnelType,
1510 const BYTE* data, UINT32 dataSize, BOOL* close,
1516 UINT status = CHANNEL_RC_BAD_INIT_HANDLE;
1517 DVCMAN* dvcman =
nullptr;
1520 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1522 dvcman = (
DVCMAN*)drdynvc->channel_mgr;
1523 WINPR_ASSERT(dvcman);
1527 if ((tunnelType != 0) &&
1528 (freerdp_multitransport_get_tunnel_state(drdynvc->rdpcontext, tunnelType) !=
1529 FREERDP_MULTITRANSPORT_TUNNEL_READY))
1532 WLog_Print(drdynvc->log, WLOG_TRACE,
"write_data: ChannelId=%" PRIu32
" size=%" PRIu32
"",
1533 ChannelId, dataSize);
1534 wStream* data_out = StreamPool_Take(dvcman->pool, CHANNEL_CHUNK_LENGTH);
1538 WLog_Print(drdynvc->log, WLOG_ERROR,
"StreamPool_Take failed!");
1539 return CHANNEL_RC_NO_MEMORY;
1542 if (!Stream_SetPosition(data_out, 1))
1544 Stream_Release(data_out);
1545 return ERROR_INVALID_DATA;
1547 cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
1548 pos = Stream_GetPosition(data_out);
1554 Stream_Release(data_out);
1556 else if (dataSize <= CHANNEL_CHUNK_LENGTH - pos)
1558 Stream_ResetPosition(data_out);
1559 Stream_Write_UINT8(data_out, (DATA_PDU << 4) | cbChId);
1560 if (!Stream_SetPosition(data_out, pos))
1562 Stream_Release(data_out);
1563 return ERROR_INVALID_DATA;
1565 Stream_Write(data_out, data, dataSize);
1566 stats->packetsOut++;
1567 status = drdynvc_send_on(drdynvc, data_out, stats, &tunnelType, FALSE);
1572 cbLen = drdynvc_write_variable_uint(data_out, dataSize);
1573 pos = Stream_GetPosition(data_out);
1574 Stream_ResetPosition(data_out);
1576 const INT32 pdu = (DATA_FIRST_PDU << 4) | cbChId | (cbLen << 2);
1577 Stream_Write_UINT8(data_out, WINPR_ASSERTING_INT_CAST(UINT8, pdu));
1578 if (!Stream_SetPosition(data_out, pos))
1580 Stream_Release(data_out);
1581 return ERROR_INVALID_DATA;
1585 WINPR_ASSERT(pos <= CHANNEL_CHUNK_LENGTH);
1586 const uint32_t chunkLength =
1587 CHANNEL_CHUNK_LENGTH - WINPR_ASSERTING_INT_CAST(uint32_t, pos);
1588 Stream_Write(data_out, data, chunkLength);
1590 data += chunkLength;
1591 dataSize -= chunkLength;
1594 stats->fragmentsOut++;
1596 status = drdynvc_send_on(drdynvc, data_out, stats, &tunnelType, FALSE);
1598 while (status == CHANNEL_RC_OK && dataSize > 0)
1600 data_out = StreamPool_Take(dvcman->pool, CHANNEL_CHUNK_LENGTH);
1604 WLog_Print(drdynvc->log, WLOG_ERROR,
"StreamPool_Take failed!");
1605 return CHANNEL_RC_NO_MEMORY;
1608 if (!Stream_SetPosition(data_out, 1))
1610 Stream_Release(data_out);
1611 return ERROR_INVALID_DATA;
1614 cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
1615 pos = Stream_GetPosition(data_out);
1616 Stream_ResetPosition(data_out);
1617 Stream_Write_UINT8(data_out, (DATA_PDU << 4) | cbChId);
1618 if (!Stream_SetPosition(data_out, pos))
1620 Stream_Release(data_out);
1621 return ERROR_INVALID_DATA;
1624 uint32_t chunkLength = dataSize;
1626 WINPR_ASSERT(pos <= CHANNEL_CHUNK_LENGTH);
1627 const uint32_t clen = CHANNEL_CHUNK_LENGTH - WINPR_ASSERTING_INT_CAST(uint32_t, pos);
1628 if (chunkLength > clen)
1630 stats->fragmentsOut++;
1634 stats->packetsOut++;
1636 Stream_Write(data_out, data, chunkLength);
1637 data += chunkLength;
1638 dataSize -= chunkLength;
1640 status = drdynvc_send_on(drdynvc, data_out, stats, &tunnelType, TRUE);
1644 if (status != CHANNEL_RC_OK)
1646 WLog_Print(drdynvc->log, WLOG_ERROR,
"VirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
1647 WTSErrorToString(status), status);
1651 return CHANNEL_RC_OK;
1660static UINT drdynvc_send_capability_response(drdynvcPlugin* drdynvc)
1664 DVCMAN* dvcman =
nullptr;
1667 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1669 dvcman = (
DVCMAN*)drdynvc->channel_mgr;
1670 WINPR_ASSERT(dvcman);
1672 WLog_Print(drdynvc->log, WLOG_TRACE,
"capability_response");
1673 s = StreamPool_Take(dvcman->pool, 4);
1677 WLog_Print(drdynvc->log, WLOG_ERROR,
"Stream_New failed!");
1678 return CHANNEL_RC_NO_MEMORY;
1681 Stream_Write_UINT16(s, 0x0050);
1682 Stream_Write_UINT16(s, drdynvc->version);
1683 status = drdynvc_send(drdynvc, s,
nullptr);
1685 if (status != CHANNEL_RC_OK)
1687 WLog_Print(drdynvc->log, WLOG_ERROR,
"VirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
1688 WTSErrorToString(status), status);
1700static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc,
int Sp,
int cbChId,
1706 return CHANNEL_RC_BAD_INIT_HANDLE;
1708 if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
1709 return ERROR_INVALID_DATA;
1711 WLog_Print(drdynvc->log, WLOG_TRACE,
"capability_request Sp=%d cbChId=%d", Sp, cbChId);
1713 Stream_Read_UINT16(s, drdynvc->version);
1718 if ((drdynvc->version == 2) || (drdynvc->version == 3))
1720 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1721 return ERROR_INVALID_DATA;
1723 Stream_Read_UINT16(s, drdynvc->PriorityCharge0);
1724 Stream_Read_UINT16(s, drdynvc->PriorityCharge1);
1725 Stream_Read_UINT16(s, drdynvc->PriorityCharge2);
1726 Stream_Read_UINT16(s, drdynvc->PriorityCharge3);
1729 status = drdynvc_send_capability_response(drdynvc);
1730 drdynvc->state = DRDYNVC_STATE_READY;
1735static UINT32 drdynvc_cblen_to_bytes(
int cbLen)
1751static UINT32 drdynvc_read_variable_uint(
wStream* s,
int cbLen)
1758 Stream_Read_UINT8(s, val);
1762 Stream_Read_UINT16(s, val);
1766 Stream_Read_UINT32(s, val);
1779static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, UINT8 Sp, UINT8 cbChId,
1780 wStream* s, UINT32 tunnelType)
1784 UINT channel_status = 0;
1785 DVCMAN* dvcman =
nullptr;
1787 INT32 retStatus = 0;
1791 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1793 dvcman = (
DVCMAN*)drdynvc->channel_mgr;
1794 WINPR_ASSERT(dvcman);
1796 if (drdynvc->state == DRDYNVC_STATE_CAPABILITIES)
1803 drdynvc->version = 3;
1805 if ((status = drdynvc_send_capability_response(drdynvc)))
1807 WLog_Print(drdynvc->log, WLOG_ERROR,
"drdynvc_send_capability_response failed!");
1811 drdynvc->state = DRDYNVC_STATE_READY;
1814 if (!Stream_CheckAndLogRequiredLength(TAG, s, drdynvc_cblen_to_bytes(cbChId)))
1815 return ERROR_INVALID_DATA;
1817 const UINT32 ChannelId = drdynvc_read_variable_uint(s, cbChId);
1818 const size_t pos = Stream_GetPosition(s);
1819 const char* name = Stream_ConstPointer(s);
1820 const size_t length = Stream_GetRemainingLength(s);
1822 if (strnlen(name, length) >= length)
1823 return ERROR_INVALID_DATA;
1825 WLog_Print(drdynvc->log, WLOG_DEBUG,
1826 "process_create_request: ChannelId=%" PRIu32
" ChannelName=%s", ChannelId, name);
1828 data_out = StreamPool_Take(dvcman->pool, pos + 4);
1831 WLog_Print(drdynvc->log, WLOG_ERROR,
"StreamPool_Take failed!");
1832 return CHANNEL_RC_NO_MEMORY;
1835 Stream_Write_UINT8(data_out, (CREATE_REQUEST_PDU << 4) | cbChId);
1836 if (!Stream_SetPosition(s, 1))
1837 return ERROR_INVALID_DATA;
1838 Stream_Copy(s, data_out, pos - 1);
1841 dvcman_create_channel(drdynvc, drdynvc->channel_mgr, ChannelId, name, &channel_status);
1842 switch (channel_status)
1845 WLog_Print(drdynvc->log, WLOG_DEBUG,
"channel created");
1848 case CHANNEL_RC_NO_MEMORY:
1849 WLog_Print(drdynvc->log, WLOG_DEBUG,
"not enough memory for channel creation");
1850 retStatus = STATUS_NO_MEMORY;
1852 case ERROR_NOT_FOUND:
1853 WLog_Print(drdynvc->log, WLOG_DEBUG,
"no listener for '%s'", name);
1854 retStatus = STATUS_NOT_FOUND;
1857 WLog_Print(drdynvc->log, WLOG_DEBUG,
"channel creation error");
1858 retStatus = STATUS_UNSUCCESSFUL;
1861 Stream_Write_INT32(data_out, retStatus);
1864 if (channel && (channel_status == CHANNEL_RC_OK))
1865 dvcman_channel_set_tunnel(channel, tunnelType);
1866 UINT32 responseTunnel = tunnelType;
1867 status = drdynvc_send_on(drdynvc, data_out,
nullptr, &responseTunnel, FALSE);
1868 if (status != CHANNEL_RC_OK)
1870 WLog_Print(drdynvc->log, WLOG_ERROR,
"VirtualChannelWriteEx failed with %s [%08" PRIX32
"]",
1871 WTSErrorToString(status), status);
1872 if (channel_status == CHANNEL_RC_OK)
1873 dvcman_channel_unref(channel);
1877 if (channel_status == CHANNEL_RC_OK)
1879#if defined(WITH_RDPEUDP)
1880 dvcman_static_bridge_publish(drdynvc, channel);
1882 if ((status = dvcman_open_channel(drdynvc, channel)))
1884 WLog_Print(drdynvc->log, WLOG_ERROR,
1885 "dvcman_open_channel failed with error %" PRIu32
"!", status);
1899static UINT drdynvc_process_data_first(drdynvcPlugin* drdynvc,
int Sp,
int cbChId,
wStream* s,
1900 BOOL compressed, UINT32 ThreadingFlags, UINT32 tunnelType)
1902 WINPR_ASSERT(drdynvc);
1903 if (!Stream_CheckAndLogRequiredLength(
1904 TAG, s, drdynvc_cblen_to_bytes(cbChId) + drdynvc_cblen_to_bytes(Sp)))
1905 return ERROR_INVALID_DATA;
1907 UINT32 ChannelId = drdynvc_read_variable_uint(s, cbChId);
1908 UINT32 Length = drdynvc_read_variable_uint(s, Sp);
1909 WLog_Print(drdynvc->log, WLOG_TRACE,
1910 "process_data_first: Sp=%d cbChId=%d, ChannelId=%" PRIu32
" Length=%" PRIu32
"", Sp,
1911 cbChId, ChannelId, Length);
1913 DVCMAN_CHANNEL* channel = dvcman_get_channel_by_id(drdynvc->channel_mgr, ChannelId, TRUE);
1921 WLog_Print(drdynvc->log, WLOG_ERROR,
"ChannelId %" PRIu32
" not found!", ChannelId);
1922 return CHANNEL_RC_OK;
1925 UINT status = CHANNEL_RC_OK;
1926 BOOL shouldFree = FALSE;
1927 if (tunnelType != 0)
1928 dvcman_channel_set_tunnel(channel, tunnelType);
1929 if (channel->state != DVC_CHANNEL_RUNNING)
1934 BYTE* data =
nullptr;
1935 UINT32 dataSize = 0;
1936 if (zgfx_decompress(channel->decompressor, Stream_Pointer(s),
1937 WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetRemainingLength(s)), &data,
1940 status = ERROR_INVALID_DATA;
1941 WLog_Print(drdynvc->log, WLOG_ERROR,
"error de-compressing first packet");
1947 status = ERROR_INVALID_DATA;
1948 WLog_Print(drdynvc->log, WLOG_ERROR,
"error de-compressing first packet");
1953 s = Stream_New(data, dataSize);
1956 status = CHANNEL_RC_NO_MEMORY;
1957 WLog_Print(drdynvc->log, WLOG_ERROR,
"error allocating new Stream(len=%" PRIu32
")",
1965 status = dvcman_receive_channel_data_first(channel, Length);
1967 if (status == CHANNEL_RC_OK)
1968 status = dvcman_receive_channel_data(channel, s, ThreadingFlags);
1970 if (status != CHANNEL_RC_OK)
1971 status = dvcman_channel_close(channel, FALSE, FALSE);
1975 Stream_Free(s, TRUE);
1976 dvcman_channel_unref(channel);
1977 dvcman_return_channel(drdynvc->channel_mgr, channel);
1987static UINT drdynvc_process_data(drdynvcPlugin* drdynvc,
int Sp,
int cbChId,
wStream* s,
1988 BOOL compressed, UINT32 ThreadingFlags, UINT32 tunnelType)
1990 WINPR_ASSERT(drdynvc);
1991 if (!Stream_CheckAndLogRequiredLength(TAG, s, drdynvc_cblen_to_bytes(cbChId)))
1992 return ERROR_INVALID_DATA;
1994 UINT32 ChannelId = drdynvc_read_variable_uint(s, cbChId);
1995 WLog_Print(drdynvc->log, WLOG_TRACE,
"process_data: Sp=%d cbChId=%d, ChannelId=%" PRIu32
"", Sp,
1998 DVCMAN_CHANNEL* channel = dvcman_get_channel_by_id(drdynvc->channel_mgr, ChannelId, TRUE);
2006 WLog_Print(drdynvc->log, WLOG_ERROR,
"ChannelId %" PRIu32
" not found!", ChannelId);
2007 return CHANNEL_RC_OK;
2010 BOOL shouldFree = FALSE;
2011 UINT status = CHANNEL_RC_OK;
2012 if (tunnelType != 0)
2013 dvcman_channel_set_tunnel(channel, tunnelType);
2014 if (channel->state != DVC_CHANNEL_RUNNING)
2019 BYTE* data =
nullptr;
2020 UINT32 dataSize = 0;
2022 if (zgfx_decompress(channel->decompressor, Stream_Pointer(s),
2023 WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetRemainingLength(s)), &data,
2026 status = ERROR_INVALID_DATA;
2027 WLog_Print(drdynvc->log, WLOG_ERROR,
"error de-compressing data packet");
2034 status = ERROR_INVALID_DATA;
2035 WLog_Print(drdynvc->log, WLOG_ERROR,
"error de-compressing data packet");
2040 s = Stream_New(data, dataSize);
2043 status = CHANNEL_RC_NO_MEMORY;
2044 WLog_Print(drdynvc->log, WLOG_ERROR,
"error allocating new Stream(len=%" PRIu32
")",
2052 status = dvcman_receive_channel_data(channel, s, ThreadingFlags);
2053 if (status != CHANNEL_RC_OK)
2054 status = dvcman_channel_close(channel, FALSE, FALSE);
2058 Stream_Free(s, TRUE);
2059 dvcman_channel_unref(channel);
2060 dvcman_return_channel(drdynvc->channel_mgr, channel);
2070static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc,
int Sp,
int cbChId,
wStream* s,
2073 UINT32 ChannelId = 0;
2076 WINPR_ASSERT(drdynvc);
2077 if (!Stream_CheckAndLogRequiredLength(TAG, s, drdynvc_cblen_to_bytes(cbChId)))
2078 return ERROR_INVALID_DATA;
2080 ChannelId = drdynvc_read_variable_uint(s, cbChId);
2081 WLog_Print(drdynvc->log, WLOG_DEBUG,
2082 "process_close_request: Sp=%d cbChId=%d, ChannelId=%" PRIu32
"", Sp, cbChId,
2085 channel = dvcman_get_channel_by_id(drdynvc->channel_mgr, ChannelId, TRUE);
2088 WLog_Print(drdynvc->log, WLOG_ERROR,
"dvcman_close_request channel %" PRIu32
" not present",
2090 return CHANNEL_RC_OK;
2093 if (tunnelType != 0)
2094 dvcman_channel_set_tunnel(channel, tunnelType);
2095 dvcman_channel_close(channel, TRUE, FALSE);
2096 dvcman_channel_unref(channel);
2097 dvcman_return_channel(drdynvc->channel_mgr, channel);
2098 return CHANNEL_RC_OK;
2102static BOOL drdynvc_soft_sync_negotiated(drdynvcPlugin* drdynvc)
2104 WINPR_ASSERT(drdynvc);
2105 if (!drdynvc->rdpcontext)
2107 const UINT32 flags =
2109 return (flags & SOFTSYNC_TCP_TO_UDP) != 0;
2113static UINT drdynvc_order_recv(drdynvcPlugin* drdynvc,
wStream* s, UINT32 ThreadingFlags,
2116static void drdynvc_tunnel_backlog_clear(drdynvcPlugin* drdynvc)
2118 WINPR_ASSERT(drdynvc);
2119 for (
size_t x = 0; x < drdynvc->tunnelBacklogCount; x++)
2120 Stream_Release(drdynvc->tunnelBacklog[x]);
2121 drdynvc->tunnelBacklogCount = 0;
2128static UINT drdynvc_tunnel_backlog_flush(drdynvcPlugin* drdynvc)
2130 WINPR_ASSERT(drdynvc);
2132 wStream** backlog = drdynvc->tunnelBacklog;
2133 UINT32* types = drdynvc->tunnelBacklogTypes;
2134 const size_t count = drdynvc->tunnelBacklogCount;
2135 drdynvc->tunnelBacklog =
nullptr;
2136 drdynvc->tunnelBacklogTypes =
nullptr;
2137 drdynvc->tunnelBacklogCount = 0;
2138 drdynvc->tunnelBacklogCapacity = 0;
2140 UINT error = CHANNEL_RC_OK;
2141 for (
size_t x = 0; x < count; x++)
2143 const UINT rc = drdynvc_order_recv(drdynvc, backlog[x], TRUE, types[x]);
2144 Stream_Release(backlog[x]);
2145 if (rc != CHANNEL_RC_OK)
2148 free((
void*)backlog);
2154static BOOL drdynvc_tunnel_backlog_add(drdynvcPlugin* drdynvc,
wStream* s, UINT32 tunnelType)
2156 WINPR_ASSERT(drdynvc);
2159 if (drdynvc->tunnelBacklogCount == drdynvc->tunnelBacklogCapacity)
2162 if (drdynvc->tunnelBacklogCapacity > SIZE_MAX / 2 /
sizeof(
wStream*))
2164 const size_t capacity =
2165 (drdynvc->tunnelBacklogCapacity == 0) ? 32 : drdynvc->tunnelBacklogCapacity * 2;
2167 (
wStream**)realloc((
void*)drdynvc->tunnelBacklog, capacity *
sizeof(
wStream*));
2170 drdynvc->tunnelBacklog = streams;
2171 UINT32* types = realloc(drdynvc->tunnelBacklogTypes, capacity *
sizeof(UINT32));
2174 drdynvc->tunnelBacklogTypes = types;
2175 drdynvc->tunnelBacklogCapacity = capacity;
2177 drdynvc->tunnelBacklog[drdynvc->tunnelBacklogCount] = s;
2178 drdynvc->tunnelBacklogTypes[drdynvc->tunnelBacklogCount] = tunnelType;
2179 drdynvc->tunnelBacklogCount++;
2191static UINT drdynvc_receive_tunnel_pdu(drdynvcPlugin* drdynvc,
wStream* s, UINT32 tunnelType)
2193 WINPR_ASSERT(drdynvc);
2196 if (drdynvc_soft_sync_negotiated(drdynvc) && !drdynvc->softSyncDone)
2200 if (drdynvc->tunnelBacklogCount >= DRDYNVC_MAX_TUNNEL_BACKLOG)
2203 drdynvc_tunnel_backlog_clear(drdynvc);
2204 drdynvc_tunnel_abort(drdynvc,
2205 "no Soft-Sync Request after the tunnel backlog filled up");
2206 return ERROR_INVALID_DATA;
2208 if (!drdynvc_tunnel_backlog_add(drdynvc, s, tunnelType))
2212 drdynvc_tunnel_abort(drdynvc,
"no memory to hold tunnel data until the Soft-Sync");
2213 return CHANNEL_RC_NO_MEMORY;
2215 return CHANNEL_RC_OK;
2218 const UINT error = drdynvc_order_recv(drdynvc, s, TRUE, tunnelType);
2225static void dvcman_move_channel_to_tunnel(drdynvcPlugin* drdynvc, UINT32 channelId,
2228 WINPR_ASSERT(drdynvc);
2230 WINPR_ASSERT(dvcman);
2232 HashTable_Lock(dvcman->channelsById);
2233 DVCMAN_CHANNEL* channel = HashTable_GetItemValue(dvcman->channelsById, &channelId);
2236 dvcman_channel_set_tunnel(channel, tunnelType);
2237 WLog_Print(drdynvc->log, WLOG_DEBUG,
2238 "channel %" PRIu32
" (%s) moves to tunnel 0x%08" PRIx32, channelId,
2239 channel->channel_name, tunnelType);
2241 HashTable_Unlock(dvcman->channelsById);
2245static UINT drdynvc_send_soft_sync_response(drdynvcPlugin* drdynvc,
const UINT32* tunnels,
2248 WINPR_ASSERT(drdynvc);
2249 WINPR_ASSERT(tunnels || (count == 0));
2251 WINPR_ASSERT(dvcman);
2254 if (count > DRDYNVC_MAX_SOFT_SYNC_TUNNELS)
2255 return ERROR_INVALID_PARAMETER;
2256 wStream* s = StreamPool_Take(dvcman->pool, 6 +
sizeof(UINT32) * count);
2258 return CHANNEL_RC_NO_MEMORY;
2261 Stream_Write_UINT8(s, SOFT_SYNC_RESPONSE_PDU << 4);
2262 Stream_Write_UINT8(s, 0);
2263 Stream_Write_UINT32(s, count);
2264 for (UINT32 x = 0; x < count; x++)
2265 Stream_Write_UINT32(s, tunnels[x]);
2268 return drdynvc_send(drdynvc, s,
nullptr);
2275static UINT drdynvc_process_soft_sync_request(drdynvcPlugin* drdynvc,
wStream* s)
2277 WINPR_ASSERT(drdynvc);
2281 const size_t position = Stream_GetPosition(s);
2283 return ERROR_INVALID_DATA;
2284 const size_t start = position - 1;
2285 if (!Stream_CheckAndLogRequiredLength(TAG, s, 9))
2286 return ERROR_INVALID_DATA;
2288 Stream_Seek_UINT8(s);
2289 const UINT32 length = Stream_Get_UINT32(s);
2290 const UINT16 flags = Stream_Get_UINT16(s);
2291 const UINT16 numberOfTunnels = Stream_Get_UINT16(s);
2295 const size_t total = Stream_Length(s);
2296 if ((total < start) || (total - start < 2))
2297 return ERROR_INVALID_DATA;
2298 const size_t available = total - start - 2;
2299 if ((length < 8) || (length > available))
2301 WLog_Print(drdynvc->log, WLOG_ERROR,
2302 "Soft-Sync Request Length %" PRIu32
" with %" PRIuz
" bytes present", length,
2304 return ERROR_INVALID_DATA;
2307 if (!Stream_SetLength(s, total - (available - length)))
2308 return ERROR_INVALID_DATA;
2310 WLog_Print(drdynvc->log, WLOG_DEBUG,
2311 "Soft-Sync Request: flags 0x%04" PRIx16
", %" PRIu16
" tunnel(s)", flags,
2317 if (!(flags & SOFT_SYNC_TCP_FLUSHED))
2319 WLog_Print(drdynvc->log, WLOG_WARN,
2320 "Soft-Sync Request without SOFT_SYNC_TCP_FLUSHED, channels stay on TCP");
2321 const UINT error = drdynvc_send_soft_sync_response(drdynvc,
nullptr, 0);
2322 if (error != CHANNEL_RC_OK)
2324 drdynvc->softSyncDone = TRUE;
2325 return drdynvc_tunnel_backlog_flush(drdynvc);
2328 const size_t lists = Stream_GetPosition(s);
2333 if (flags & SOFT_SYNC_CHANNEL_LIST_PRESENT)
2335 for (UINT16 x = 0; x < numberOfTunnels; x++)
2337 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
2338 return ERROR_INVALID_DATA;
2339 const UINT32 tunnelType = Stream_Get_UINT32(s);
2340 const UINT16 count = Stream_Get_UINT16(s);
2341 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, count,
sizeof(UINT32)))
2342 return ERROR_INVALID_DATA;
2343 Stream_Seek(s, 4ull * count);
2345 if (freerdp_multitransport_get_tunnel_state(drdynvc->rdpcontext, tunnelType) ==
2346 FREERDP_MULTITRANSPORT_TUNNEL_PENDING)
2348 WLog_Print(drdynvc->log, WLOG_DEBUG,
2349 "tunnel 0x%08" PRIx32
" is not up yet, answering Soft-Sync later",
2351 const size_t size = Stream_Length(s) - start;
2352 Stream_Free(drdynvc->pendingSoftSync, TRUE);
2353 drdynvc->pendingSoftSync = Stream_New(
nullptr, size);
2354 if (!drdynvc->pendingSoftSync)
2355 return CHANNEL_RC_NO_MEMORY;
2356 Stream_Write(drdynvc->pendingSoftSync, Stream_Buffer(s) + start, size);
2357 Stream_SealLength(drdynvc->pendingSoftSync);
2358 return CHANNEL_RC_OK;
2363 UINT32 accepted[DRDYNVC_MAX_SOFT_SYNC_TUNNELS] = WINPR_C_ARRAY_INIT;
2364 UINT32 acceptedCount = 0;
2365 if (!Stream_SetPosition(s, lists))
2366 return ERROR_INVALID_DATA;
2368 if (flags & SOFT_SYNC_CHANNEL_LIST_PRESENT)
2370 for (UINT16 x = 0; x < numberOfTunnels; x++)
2372 const UINT32 tunnelType = Stream_Get_UINT32(s);
2373 const UINT16 count = Stream_Get_UINT16(s);
2375 freerdp_multitransport_get_tunnel_state(drdynvc->rdpcontext, tunnelType) ==
2376 FREERDP_MULTITRANSPORT_TUNNEL_READY;
2378 for (UINT16 y = 0; y < count; y++)
2380 const UINT32 channelId = Stream_Get_UINT32(s);
2382 dvcman_move_channel_to_tunnel(drdynvc, channelId, tunnelType);
2385 if (ready && (acceptedCount < ARRAYSIZE(accepted)))
2388 for (UINT32 z = 0; z < acceptedCount; z++)
2389 known |= (accepted[z] == tunnelType);
2391 accepted[acceptedCount++] = tunnelType;
2395 else if (freerdp_multitransport_get_tunnel_state(drdynvc->rdpcontext, TUNNELTYPE_UDPFECR) ==
2396 FREERDP_MULTITRANSPORT_TUNNEL_READY)
2398 accepted[acceptedCount++] = TUNNELTYPE_UDPFECR;
2401 WLog_Print(drdynvc->log, WLOG_INFO,
2402 "Soft-Sync: %" PRIu32
" tunnel(s) will carry dynamic channel data", acceptedCount);
2404 const UINT error = drdynvc_send_soft_sync_response(drdynvc, accepted, acceptedCount);
2405 if (error != CHANNEL_RC_OK)
2408 drdynvc->softSyncDone = TRUE;
2409 return drdynvc_tunnel_backlog_flush(drdynvc);
2414static UINT drdynvc_tunnel_state_changed(drdynvcPlugin* drdynvc)
2416 WINPR_ASSERT(drdynvc);
2417 if (drdynvc->pendingSoftSync)
2419 wStream* s = drdynvc->pendingSoftSync;
2420 drdynvc->pendingSoftSync =
nullptr;
2421 Stream_ResetPosition(s);
2422 const UINT error = drdynvc_order_recv(drdynvc, s, TRUE, 0);
2423 Stream_Free(s, TRUE);
2424 if (error != CHANNEL_RC_OK)
2429 if (!drdynvc->softSyncDone &&
2430 (freerdp_multitransport_get_tunnel_state(drdynvc->rdpcontext, TUNNELTYPE_UDPFECR) ==
2431 FREERDP_MULTITRANSPORT_TUNNEL_NONE))
2432 return drdynvc_tunnel_backlog_flush(drdynvc);
2433 return CHANNEL_RC_OK;
2442static UINT drdynvc_order_recv(drdynvcPlugin* drdynvc,
wStream* s, UINT32 ThreadingFlags,
2445 WINPR_ASSERT(drdynvc);
2446 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
2447 return ERROR_INVALID_DATA;
2449 UINT8 value = Stream_Get_UINT8(s);
2450 const UINT8 Cmd = (value & 0xf0) >> 4;
2451 const UINT8 Sp = (value & 0x0c) >> 2;
2452 const UINT8 cbChId = (value & 0x03) >> 0;
2453 WLog_Print(drdynvc->log, WLOG_TRACE,
"order_recv: Cmd=%s, Sp=%" PRIu8
" cbChId=%" PRIu8,
2454 drdynvc_get_packet_type(Cmd), Sp, cbChId);
2459 if ((tunnelType != 0) && ((Cmd == CAPABILITY_REQUEST_PDU) || (Cmd == SOFT_SYNC_REQUEST_PDU)))
2461 WLog_Print(drdynvc->log, WLOG_ERROR,
"%s on tunnel 0x%08" PRIx32
", rejected",
2462 drdynvc_get_packet_type(Cmd), tunnelType);
2463 return ERROR_INVALID_DATA;
2468 case CAPABILITY_REQUEST_PDU:
2469 return drdynvc_process_capability_request(drdynvc, Sp, cbChId, s);
2471 case CREATE_REQUEST_PDU:
2472 return drdynvc_process_create_request(drdynvc, Sp, cbChId, s, tunnelType);
2474 case DATA_FIRST_PDU:
2475 case DATA_FIRST_COMPRESSED_PDU:
2476 return drdynvc_process_data_first(drdynvc, Sp, cbChId, s,
2477 (Cmd == DATA_FIRST_COMPRESSED_PDU), ThreadingFlags,
2481 case DATA_COMPRESSED_PDU:
2482 return drdynvc_process_data(drdynvc, Sp, cbChId, s, (Cmd == DATA_COMPRESSED_PDU),
2483 ThreadingFlags, tunnelType);
2485 case CLOSE_REQUEST_PDU:
2486 return drdynvc_process_close_request(drdynvc, Sp, cbChId, s, tunnelType);
2488 case SOFT_SYNC_REQUEST_PDU:
2489 return drdynvc_process_soft_sync_request(drdynvc, s);
2491 case SOFT_SYNC_RESPONSE_PDU:
2492 WLog_Print(drdynvc->log, WLOG_ERROR,
2493 "not expecting a SOFT_SYNC_RESPONSE_PDU as a client");
2494 return ERROR_INTERNAL_ERROR;
2497 WLog_Print(drdynvc->log, WLOG_ERROR,
"unknown drdynvc cmd 0x%x", Cmd);
2498 return ERROR_INTERNAL_ERROR;
2508static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc,
void* pData,
2509 UINT32 dataLength, UINT32 totalLength,
2514 WINPR_ASSERT(drdynvc);
2515 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
2517 return CHANNEL_RC_OK;
2520 if (dataFlags & CHANNEL_FLAG_FIRST)
2522 if (drdynvc->firstFlagReceived)
2523 return ERROR_INVALID_DATA;
2524 drdynvc->firstFlagReceived = TRUE;
2527 if (drdynvc->data_in)
2528 Stream_Release(drdynvc->data_in);
2530 drdynvc->data_in = StreamPool_Take(mgr->pool, dataLength);
2531 drdynvc->totalLength = totalLength;
2534 if (!(data_in = drdynvc->data_in))
2536 WLog_Print(drdynvc->log, WLOG_ERROR,
"StreamPool_Take failed!");
2537 return CHANNEL_RC_NO_MEMORY;
2540 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
2542 WLog_Print(drdynvc->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
2543 Stream_Release(drdynvc->data_in);
2544 drdynvc->data_in =
nullptr;
2545 return ERROR_INTERNAL_ERROR;
2548 Stream_Write(data_in, pData, dataLength);
2550 if ((Stream_GetPosition(data_in) > totalLength) || (drdynvc->totalLength != totalLength))
2552 Stream_Release(drdynvc->data_in);
2553 drdynvc->data_in =
nullptr;
2554 return ERROR_INVALID_DATA;
2557 if (dataFlags & CHANNEL_FLAG_LAST)
2559 if (!drdynvc->firstFlagReceived)
2560 return ERROR_INVALID_DATA;
2561 drdynvc->firstFlagReceived = FALSE;
2563 const size_t pos = Stream_GetPosition(data_in);
2564 if (drdynvc->totalLength != pos)
2566 WLog_Print(drdynvc->log, WLOG_ERROR,
"drdynvc_plugin_process_received: read error");
2567 return ERROR_INVALID_DATA;
2570 drdynvc->totalLength = 0;
2571 drdynvc->data_in =
nullptr;
2572 Stream_SealLength(data_in);
2573 Stream_ResetPosition(data_in);
2577 if (!MessageQueue_Post(drdynvc->queue,
nullptr, DRDYNVC_MSG_DATA, (
void*)data_in,
2580 WLog_Print(drdynvc->log, WLOG_ERROR,
"MessageQueue_Post failed!");
2581 return ERROR_INTERNAL_ERROR;
2586 UINT error = drdynvc_order_recv(drdynvc, data_in, TRUE, 0);
2587 Stream_Release(data_in);
2591 WLog_Print(drdynvc->log, WLOG_WARN,
2592 "drdynvc_order_recv failed with error %" PRIu32
"!", error);
2598 return CHANNEL_RC_OK;
2601static void VCAPITYPE drdynvc_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
2602 UINT event, LPVOID pData,
2603 UINT32 dataLength, UINT32 totalLength,
2606 UINT error = CHANNEL_RC_OK;
2607 drdynvcPlugin* drdynvc = (drdynvcPlugin*)lpUserParam;
2609 WINPR_ASSERT(drdynvc);
2612 case CHANNEL_EVENT_DATA_RECEIVED:
2613 if (!drdynvc || (drdynvc->OpenHandle != openHandle))
2615 WLog_ERR(TAG,
"drdynvc_virtual_channel_open_event: error no match");
2618 if ((error = drdynvc_virtual_channel_event_data_received(drdynvc, pData, dataLength,
2619 totalLength, dataFlags)))
2620 WLog_Print(drdynvc->log, WLOG_ERROR,
2621 "drdynvc_virtual_channel_event_data_received failed with error %" PRIu32
2627 case CHANNEL_EVENT_WRITE_CANCELLED:
2628 case CHANNEL_EVENT_WRITE_COMPLETE:
2635 case CHANNEL_EVENT_USER:
2641 if (error && drdynvc && drdynvc->rdpcontext)
2642 setChannelError(drdynvc->rdpcontext, error,
2643 "drdynvc_virtual_channel_open_event reported an error");
2647static DWORD WINAPI drdynvc_virtual_channel_client_thread(LPVOID arg)
2651 wMessage message = WINPR_C_ARRAY_INIT;
2652 UINT error = CHANNEL_RC_OK;
2653 drdynvcPlugin* drdynvc = (drdynvcPlugin*)arg;
2657 ExitThread((DWORD)CHANNEL_RC_BAD_CHANNEL_HANDLE);
2658 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
2663 if (!MessageQueue_Wait(drdynvc->queue))
2665 WLog_Print(drdynvc->log, WLOG_ERROR,
"MessageQueue_Wait failed!");
2666 error = ERROR_INTERNAL_ERROR;
2670 if (!MessageQueue_Peek(drdynvc->queue, &message, TRUE))
2672 WLog_Print(drdynvc->log, WLOG_ERROR,
"MessageQueue_Peek failed!");
2673 error = ERROR_INTERNAL_ERROR;
2677 if (message.id == WMQ_QUIT)
2680 if (message.id == DRDYNVC_MSG_DATA)
2682 UINT32 ThreadingFlags = TRUE;
2683 data = (
wStream*)message.wParam;
2685 if ((error = drdynvc_order_recv(drdynvc, data, ThreadingFlags, 0)))
2687 WLog_Print(drdynvc->log, WLOG_WARN,
2688 "drdynvc_order_recv failed with error %" PRIu32
"!", error);
2691 Stream_Release(data);
2693 else if (message.id == DRDYNVC_MSG_TUNNEL_DATA)
2695 data = (
wStream*)message.wParam;
2696 const UINT32 tunnelType = WINPR_ASSERTING_INT_CAST(UINT32, (UINT_PTR)message.lParam);
2698 if ((error = drdynvc_receive_tunnel_pdu(drdynvc, data, tunnelType)))
2700 WLog_Print(drdynvc->log, WLOG_WARN,
2701 "drdynvc_receive_tunnel_pdu failed with error %" PRIu32
"!", error);
2704 else if (message.id == DRDYNVC_MSG_TUNNEL_STATE)
2706 if ((error = drdynvc_tunnel_state_changed(drdynvc)))
2708 WLog_Print(drdynvc->log, WLOG_WARN,
2709 "drdynvc_tunnel_state_changed failed with error %" PRIu32
"!", error);
2720 HashTable_Clear(drdynvcMgr->channelsById);
2723 if (error && drdynvc->rdpcontext)
2724 setChannelError(drdynvc->rdpcontext, error,
2725 "drdynvc_virtual_channel_client_thread reported an error");
2727 ExitThread((DWORD)error);
2731static void drdynvc_queue_object_free(
void* obj)
2734 wMessage* msg = (wMessage*)obj;
2736 if (!msg || ((msg->id != DRDYNVC_MSG_DATA) && (msg->id != DRDYNVC_MSG_TUNNEL_DATA)))
2749static BOOL drdynvc_on_tunnel_data(
void* custom, UINT32 tunnelType,
wStream* s)
2751 drdynvcPlugin* drdynvc = custom;
2752 WINPR_ASSERT(drdynvc);
2755 if (!drdynvc->channel_mgr || (Stream_Length(s) == 0))
2763 if (!MessageQueue_Post(drdynvc->queue,
nullptr, DRDYNVC_MSG_TUNNEL_DATA, s,
2764 (
void*)(UINT_PTR)tunnelType))
2766 WLog_Print(drdynvc->log, WLOG_ERROR,
"MessageQueue_Post failed!");
2773 const UINT error = drdynvc_receive_tunnel_pdu(drdynvc, s, tunnelType);
2776 WLog_Print(drdynvc->log, WLOG_WARN,
2777 "drdynvc_receive_tunnel_pdu failed with error %" PRIu32
"!", error);
2784static BOOL drdynvc_on_tunnel_state(
void* custom, UINT32 tunnelType,
2785 FreeRDP_MultitransportTunnelState state)
2787 drdynvcPlugin* drdynvc = custom;
2788 WINPR_ASSERT(drdynvc);
2790 WLog_Print(drdynvc->log, WLOG_DEBUG,
"tunnel 0x%08" PRIx32
" is %s", tunnelType,
2791 (state == FREERDP_MULTITRANSPORT_TUNNEL_READY) ?
"ready" :
"gone");
2795 if (!MessageQueue_Post(drdynvc->queue,
nullptr, DRDYNVC_MSG_TUNNEL_STATE,
nullptr,
nullptr))
2797 WLog_Print(drdynvc->log, WLOG_ERROR,
"MessageQueue_Post failed!");
2803 const UINT error = drdynvc_tunnel_state_changed(drdynvc);
2806 WLog_Print(drdynvc->log, WLOG_WARN,
2807 "drdynvc_tunnel_state_changed failed with error %" PRIu32
"!", error);
2813static void drdynvc_soft_sync_reset(drdynvcPlugin* drdynvc)
2815 WINPR_ASSERT(drdynvc);
2816 drdynvc->softSyncDone = FALSE;
2817 Stream_Free(drdynvc->pendingSoftSync, TRUE);
2818 drdynvc->pendingSoftSync =
nullptr;
2819 drdynvc_tunnel_backlog_clear(drdynvc);
2823static void drdynvc_tunnel_hooks_remove(drdynvcPlugin* drdynvc)
2825 WINPR_ASSERT(drdynvc);
2828 if (!freerdp_multitransport_set_dvc_callbacks(drdynvc->rdpcontext,
nullptr,
nullptr))
2829 WLog_Print(drdynvc->log, WLOG_DEBUG,
"no multitransport tunnel hooks to remove");
2833static UINT drdynvc_virtual_channel_event_initialized(drdynvcPlugin* drdynvc, LPVOID pData,
2837 WINPR_UNUSED(pData);
2838 WINPR_UNUSED(dataLength);
2843 drdynvc->queue = MessageQueue_New(
nullptr);
2845 if (!drdynvc->queue)
2847 WLog_Print(drdynvc->log, WLOG_ERROR,
"MessageQueue_New failed!");
2851 obj = MessageQueue_Object(drdynvc->queue);
2853 drdynvc->channel_mgr = dvcman_new(drdynvc);
2855 if (!drdynvc->channel_mgr)
2857 WLog_Print(drdynvc->log, WLOG_ERROR,
"dvcman_new failed!");
2861 return CHANNEL_RC_OK;
2863 return ERROR_INTERNAL_ERROR;
2872static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVOID pData,
2877 rdpSettings* settings =
nullptr;
2879 WINPR_ASSERT(drdynvc);
2880 WINPR_UNUSED(pData);
2881 WINPR_UNUSED(dataLength);
2884 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
2886 WINPR_ASSERT(drdynvc->channelEntryPoints.pVirtualChannelOpenEx);
2887 status = drdynvc->channelEntryPoints.pVirtualChannelOpenEx(
2888 drdynvc->InitHandle, &drdynvc->OpenHandle, drdynvc->channelDef.name,
2889 drdynvc_virtual_channel_open_event_ex);
2891 if (status != CHANNEL_RC_OK)
2893 WLog_Print(drdynvc->log, WLOG_ERROR,
"pVirtualChannelOpen failed with %s [%08" PRIX32
"]",
2894 WTSErrorToString(status), status);
2898 WINPR_ASSERT(drdynvc->rdpcontext);
2899 settings = drdynvc->rdpcontext->settings;
2900 WINPR_ASSERT(settings);
2902 for (UINT32 index = 0;
2906 freerdp_settings_get_pointer_array(settings, FreeRDP_DynamicChannelArray, index);
2907 error = dvcman_load_addin(drdynvc, drdynvc->channel_mgr, args, drdynvc->rdpcontext);
2909 if (CHANNEL_RC_OK != error)
2913 if ((error = dvcman_init(drdynvc, drdynvc->channel_mgr)))
2915 WLog_Print(drdynvc->log, WLOG_ERROR,
"dvcman_init failed with error %" PRIu32
"!", error);
2919 drdynvc->state = DRDYNVC_STATE_CAPABILITIES;
2923 if (!(drdynvc->thread = CreateThread(
nullptr, 0, drdynvc_virtual_channel_client_thread,
2924 (
void*)drdynvc, 0,
nullptr)))
2926 error = ERROR_INTERNAL_ERROR;
2927 WLog_Print(drdynvc->log, WLOG_ERROR,
"CreateThread failed!");
2931 if (!SetThreadPriority(drdynvc->thread, THREAD_PRIORITY_HIGHEST))
2932 WLog_Print(drdynvc->log, WLOG_WARN,
"SetThreadPriority failed, ignoring.");
2936 drdynvc_soft_sync_reset(drdynvc);
2939 .TunnelStateChanged = drdynvc_on_tunnel_state,
2940 .DataOnTunnelThread = drdynvc->async
2942 if (!freerdp_multitransport_set_dvc_callbacks(drdynvc->rdpcontext, &callbacks, drdynvc))
2943 WLog_Print(drdynvc->log, WLOG_WARN,
2944 "multitransport tunnels unavailable, using the static channel only");
2957static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc)
2962 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
2965 drdynvc_tunnel_hooks_remove(drdynvc);
2967 if (drdynvc->OpenHandle == 0)
2968 return CHANNEL_RC_OK;
2972 if (!MessageQueue_PostQuit(drdynvc->queue, 0))
2974 status = GetLastError();
2975 WLog_Print(drdynvc->log, WLOG_ERROR,
2976 "MessageQueue_PostQuit failed with error %" PRIu32
"", status);
2981 if (drdynvc->thread)
2983 if (WaitForSingleObject(drdynvc->thread, INFINITE) != WAIT_OBJECT_0)
2985 status = GetLastError();
2986 WLog_Print(drdynvc->log, WLOG_ERROR,
2987 "WaitForSingleObject failed with error %" PRIu32
"", status);
2991 (void)CloseHandle(drdynvc->thread);
2992 drdynvc->thread =
nullptr;
3002 HashTable_Clear(drdynvcMgr->channelsById);
3006 WINPR_ASSERT(drdynvc->channelEntryPoints.pVirtualChannelCloseEx);
3007 status = drdynvc->channelEntryPoints.pVirtualChannelCloseEx(drdynvc->InitHandle,
3008 drdynvc->OpenHandle);
3010 if (status != CHANNEL_RC_OK)
3012 WLog_Print(drdynvc->log, WLOG_ERROR,
"pVirtualChannelClose failed with %s [%08" PRIX32
"]",
3013 WTSErrorToString(status), status);
3016 drdynvc_soft_sync_reset(drdynvc);
3017 dvcman_clear(drdynvc, drdynvc->channel_mgr);
3019 MessageQueue_Clear(drdynvc->queue);
3020 drdynvc->OpenHandle = 0;
3022 if (drdynvc->data_in)
3024 Stream_Release(drdynvc->data_in);
3025 drdynvc->data_in =
nullptr;
3037static UINT drdynvc_virtual_channel_event_terminated(drdynvcPlugin* drdynvc)
3040 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
3043 drdynvc_tunnel_hooks_remove(drdynvc);
3045 MessageQueue_Free(drdynvc->queue);
3046 drdynvc->queue =
nullptr;
3048 drdynvc_soft_sync_reset(drdynvc);
3049 free((
void*)drdynvc->tunnelBacklog);
3050 free(drdynvc->tunnelBacklogTypes);
3052 if (drdynvc->channel_mgr)
3054 dvcman_free(drdynvc, drdynvc->channel_mgr);
3055 drdynvc->channel_mgr =
nullptr;
3057 drdynvc->InitHandle =
nullptr;
3058 free(drdynvc->context);
3060 return CHANNEL_RC_OK;
3064static UINT drdynvc_virtual_channel_event_attached(drdynvcPlugin* drdynvc)
3066 UINT error = CHANNEL_RC_OK;
3067 DVCMAN* dvcman =
nullptr;
3070 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
3072 dvcman = (
DVCMAN*)drdynvc->channel_mgr;
3075 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
3077 ArrayList_Lock(dvcman->plugins);
3078 for (
size_t i = 0; i < ArrayList_Count(dvcman->plugins); i++)
3080 IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i);
3082 error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Attached, pPlugin);
3083 if (error != CHANNEL_RC_OK)
3085 WLog_Print(drdynvc->log, WLOG_ERROR,
"Attach failed with error %" PRIu32
"!", error);
3091 ArrayList_Unlock(dvcman->plugins);
3096static UINT drdynvc_virtual_channel_event_detached(drdynvcPlugin* drdynvc)
3098 UINT error = CHANNEL_RC_OK;
3099 DVCMAN* dvcman =
nullptr;
3102 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
3104 dvcman = (
DVCMAN*)drdynvc->channel_mgr;
3107 return CHANNEL_RC_BAD_CHANNEL_HANDLE;
3109 ArrayList_Lock(dvcman->plugins);
3110 for (
size_t i = 0; i < ArrayList_Count(dvcman->plugins); i++)
3112 IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i);
3114 error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Detached, pPlugin);
3115 if (error != CHANNEL_RC_OK)
3117 WLog_Print(drdynvc->log, WLOG_ERROR,
"Detach failed with error %" PRIu32
"!", error);
3123 ArrayList_Unlock(dvcman->plugins);
3128static VOID VCAPITYPE drdynvc_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
3129 UINT event, LPVOID pData,
3132 UINT error = CHANNEL_RC_OK;
3133 drdynvcPlugin* drdynvc = (drdynvcPlugin*)lpUserParam;
3135 if (!drdynvc || (drdynvc->InitHandle != pInitHandle))
3137 WLog_ERR(TAG,
"drdynvc_virtual_channel_init_event: error no match");
3143 case CHANNEL_EVENT_INITIALIZED:
3144 error = drdynvc_virtual_channel_event_initialized(drdynvc, pData, dataLength);
3146 case CHANNEL_EVENT_CONNECTED:
3147 if ((error = drdynvc_virtual_channel_event_connected(drdynvc, pData, dataLength)))
3148 WLog_Print(drdynvc->log, WLOG_ERROR,
3149 "drdynvc_virtual_channel_event_connected failed with error %" PRIu32
"",
3154 case CHANNEL_EVENT_DISCONNECTED:
3155 if ((error = drdynvc_virtual_channel_event_disconnected(drdynvc)))
3156 WLog_Print(drdynvc->log, WLOG_ERROR,
3157 "drdynvc_virtual_channel_event_disconnected failed with error %" PRIu32
3163 case CHANNEL_EVENT_TERMINATED:
3164 if ((error = drdynvc_virtual_channel_event_terminated(drdynvc)))
3165 WLog_Print(drdynvc->log, WLOG_ERROR,
3166 "drdynvc_virtual_channel_event_terminated failed with error %" PRIu32
"",
3171 case CHANNEL_EVENT_ATTACHED:
3172 if ((error = drdynvc_virtual_channel_event_attached(drdynvc)))
3173 WLog_Print(drdynvc->log, WLOG_ERROR,
3174 "drdynvc_virtual_channel_event_attached failed with error %" PRIu32
"",
3179 case CHANNEL_EVENT_DETACHED:
3180 if ((error = drdynvc_virtual_channel_event_detached(drdynvc)))
3181 WLog_Print(drdynvc->log, WLOG_ERROR,
3182 "drdynvc_virtual_channel_event_detached failed with error %" PRIu32
"",
3191 if (error && drdynvc->rdpcontext)
3192 setChannelError(drdynvc->rdpcontext, error,
3193 "drdynvc_virtual_channel_init_event_ex reported an error");
3201static int drdynvc_get_version(DrdynvcClientContext* context)
3203 WINPR_ASSERT(context);
3204 drdynvcPlugin* drdynvc = (drdynvcPlugin*)context->handle;
3205 WINPR_ASSERT(drdynvc);
3206 return drdynvc->version;
3210#define VirtualChannelEntryEx drdynvc_VirtualChannelEntryEx
3212FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
3216 drdynvcPlugin* drdynvc =
nullptr;
3217 DrdynvcClientContext* context =
nullptr;
3219 drdynvc = (drdynvcPlugin*)calloc(1,
sizeof(drdynvcPlugin));
3221 WINPR_ASSERT(pEntryPoints);
3224 WLog_ERR(TAG,
"calloc failed!");
3228 drdynvc->channelDef.options =
3229 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
3230 (void)sprintf_s(drdynvc->channelDef.name, ARRAYSIZE(drdynvc->channelDef.name),
3231 DRDYNVC_SVC_CHANNEL_NAME);
3232 drdynvc->state = DRDYNVC_STATE_INITIAL;
3236 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
3238 context = (DrdynvcClientContext*)calloc(1,
sizeof(DrdynvcClientContext));
3242 WLog_Print(drdynvc->log, WLOG_ERROR,
"calloc failed!");
3247 context->handle = (
void*)drdynvc;
3248 context->custom =
nullptr;
3249 drdynvc->context = context;
3250 context->GetVersion = drdynvc_get_version;
3251 context->GetChannelStats = drdynvc_get_channel_stats;
3252 drdynvc->rdpcontext = pEntryPointsEx->context;
3254 FreeRDP_TransportDumpReplay) &&
3256 FreeRDP_SynchronousDynamicChannels))
3257 drdynvc->async = TRUE;
3260 drdynvc->log = WLog_Get(TAG);
3261 WLog_Print(drdynvc->log, WLOG_DEBUG,
"VirtualChannelEntryEx");
3262 CopyMemory(&(drdynvc->channelEntryPoints), pEntryPoints,
3264 drdynvc->InitHandle = pInitHandle;
3266 WINPR_ASSERT(drdynvc->channelEntryPoints.pVirtualChannelInitEx);
3267 rc = drdynvc->channelEntryPoints.pVirtualChannelInitEx(
3268 drdynvc, context, pInitHandle, &drdynvc->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
3269 drdynvc_virtual_channel_init_event_ex);
3271 if (CHANNEL_RC_OK != rc)
3273 WLog_Print(drdynvc->log, WLOG_ERROR,
"pVirtualChannelInit failed with %s [%08" PRIX32
"]",
3274 WTSErrorToString(rc), rc);
3275 free(drdynvc->context);
3280 drdynvc->channelEntryPoints.pInterface = context;
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
Dynamic channel stats struct. Contains statistic information for a single dynamic channel.
Dynamic virtual channel hooks of the client side tunnels.
WINPR_ATTR_NODISCARD BOOL(* TunnelDataReceived)(void *custom, UINT32 tunnelType, wStream *s)
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree
WINPR_ATTR_NODISCARD OBJECT_EQUALS_FN fnObjectEquals
WINPR_ATTR_NODISCARD OBJECT_NEW_FN fnObjectNew