19#include <winpr/assert.h>
21#include <freerdp/channels/drdynvc.h>
22#include <freerdp/utils/drdynvc.h>
23#include <freerdp/server/proxy/proxy_log.h>
25#include "pf_channel_drdynvc.h"
26#include "../pf_channel.h"
27#include "../proxy_modules.h"
28#include "../pf_utils.h"
29#include "../pf_server.h"
31#define DTAG PROXY_TAG("drdynvc")
33#define Stream_CheckAndLogRequiredLengthWLogWithBackend(log, s, nmemb, backdata) \
34 Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, nmemb, 1, "%s(%s:%" PRIuz ")[%s]", \
35 __func__, __FILE__, (size_t)__LINE__, \
36 getDirection(backdata))
41 CHANNEL_OPENSTATE_WAITING_OPEN_STATUS,
42 CHANNEL_OPENSTATE_OPENED,
43 CHANNEL_OPENSTATE_CLOSED
44} PfDynChannelOpenStatus;
46typedef struct p_server_dynamic_channel_context pServerDynamicChannelContext;
47typedef struct DynChannelTrackerState DynChannelTrackerState;
49typedef PfChannelResult (*dynamic_channel_on_data_fn)(pServerContext* ps,
50 pServerDynamicChannelContext* channel,
51 BOOL isBackData, ChannelStateTracker* tracker,
52 BOOL firstPacket, BOOL lastPacket);
55struct DynChannelTrackerState
57 UINT32 currentDataLength;
58 UINT32 CurrentDataReceived;
59 UINT32 CurrentDataFragments;
61 WINPR_ATTR_NODISCARD dynamic_channel_on_data_fn dataCallback;
64typedef void (*channel_data_dtor_fn)(
void** user_data);
66struct p_server_dynamic_channel_context
70 PfDynChannelOpenStatus openStatus;
71 pf_utils_channel_mode channelMode;
72 BOOL packetReassembly;
73 DynChannelTrackerState backTracker;
74 DynChannelTrackerState frontTracker;
77 channel_data_dtor_fn channelDataDtor;
84 ChannelStateTracker* backTracker;
85 ChannelStateTracker* frontTracker;
94 DYNCVC_READ_INCOMPLETE
97static const char* openstatus2str(PfDynChannelOpenStatus status)
101 case CHANNEL_OPENSTATE_WAITING_OPEN_STATUS:
102 return "CHANNEL_OPENSTATE_WAITING_OPEN_STATUS";
103 case CHANNEL_OPENSTATE_CLOSED:
104 return "CHANNEL_OPENSTATE_CLOSED";
105 case CHANNEL_OPENSTATE_OPENED:
106 return "CHANNEL_OPENSTATE_OPENED";
108 return "CHANNEL_OPENSTATE_UNKNOWN";
112#define DynvcTrackerLog(log, level, dynChannel, cmd, isBackData, ...) \
113 dyn_log_((log), (level), (dynChannel), (cmd), (isBackData), __func__, __FILE__, __LINE__, \
117static const char* getDirection(BOOL isBackData)
119 return isBackData ?
"B->F" :
"F->B";
122static void dyn_log_(wLog* log, DWORD level,
const pServerDynamicChannelContext* dynChannel,
123 BYTE cmd, BOOL isBackData,
const char* fkt,
const char* file,
size_t line,
124 const char* fmt, ...)
126 if (!WLog_IsLevelActive(log, level))
129 char* prefix =
nullptr;
131 size_t prefixlen = 0;
134 uint32_t channelId = dynChannel ? dynChannel->channelId : UINT32_MAX;
135 const char* channelName = dynChannel ? dynChannel->channelName :
"<nullptr>";
136 (void)winpr_asprintf(&prefix, &prefixlen,
"DynvcTracker[%s](%s [%s:%" PRIu32
"])",
137 getDirection(isBackData), channelName, drdynvc_get_packet_type(cmd),
140 va_list ap = WINPR_C_ARRAY_INIT;
142 (void)winpr_vasprintf(&msg, &msglen, fmt, ap);
145 WLog_PrintTextMessage(log, level, line, file, fkt,
"%s: %s", prefix, msg);
151static PfChannelResult data_cb(pServerContext* ps, pServerDynamicChannelContext* channel,
152 BOOL isBackData, ChannelStateTracker* tracker, BOOL firstPacket,
156 WINPR_ASSERT(channel);
157 WINPR_ASSERT(tracker);
158 WINPR_ASSERT(ps->pdata);
160 wStream* currentPacket = channelTracker_getCurrentPacket(tracker);
162 .channelId = channel->channelId,
163 .data = currentPacket,
164 .isBackData = isBackData,
165 .first = firstPacket,
168 .packetSize = channelTracker_getCurrentPacketSize(tracker),
169 .result = PF_CHANNEL_RESULT_ERROR };
170 Stream_SealLength(dyn.data);
171 if (!pf_modules_run_filter(ps->pdata->module, FILTER_TYPE_INTERCEPT_CHANNEL, ps->pdata, &dyn))
172 return PF_CHANNEL_RESULT_ERROR;
174 channelTracker_setCurrentPacketSize(tracker, dyn.packetSize);
176 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, !isBackData);
180static void DynamicChannelContext_free(
void* ptr)
182 pServerDynamicChannelContext* c = (pServerDynamicChannelContext*)ptr;
186 if (c->backTracker.currentPacket)
187 Stream_Free(c->backTracker.currentPacket, TRUE);
189 if (c->frontTracker.currentPacket)
190 Stream_Free(c->frontTracker.currentPacket, TRUE);
192 if (c->channelDataDtor)
193 c->channelDataDtor(&c->channelData);
195 free(c->channelName);
199WINPR_ATTR_MALLOC(DynamicChannelContext_free, 1)
201static pServerDynamicChannelContext* DynamicChannelContext_new(wLog* log, pServerContext* ps,
202 const
char* name, UINT32
id)
206 pServerDynamicChannelContext* ret = calloc(1,
sizeof(*ret));
209 WLog_Print(log, WLOG_ERROR,
"error allocating dynamic channel context '%s'", name);
214 ret->channelName = _strdup(name);
215 if (!ret->channelName)
217 WLog_Print(log, WLOG_ERROR,
"error allocating name in dynamic channel context '%s'", name);
222 ret->frontTracker.dataCallback = data_cb;
223 ret->backTracker.dataCallback = data_cb;
226 if (pf_modules_run_filter(ps->pdata->module, FILTER_TYPE_DYN_INTERCEPT_LIST, ps->pdata, &dyn) &&
228 ret->channelMode = PF_UTILS_CHANNEL_INTERCEPT;
230 ret->channelMode = pf_utils_get_channel_mode(ps->pdata->config, name);
231 ret->openStatus = CHANNEL_OPENSTATE_OPENED;
232 ret->packetReassembly = (ret->channelMode == PF_UTILS_CHANNEL_INTERCEPT);
238static UINT32 ChannelId_Hash(
const void* key)
240 const UINT32* v = (
const UINT32*)key;
245static BOOL ChannelId_Compare(
const void* objA,
const void* objB)
247 const UINT32* v1 = objA;
248 const UINT32* v2 = objB;
253static DynvcReadResult dynvc_read_varInt(wLog* log,
wStream* s,
size_t len, UINT64* varInt,
256 WINPR_ASSERT(varInt);
260 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
261 return last ? DYNCVC_READ_ERROR : DYNCVC_READ_INCOMPLETE;
262 Stream_Read_UINT8(s, *varInt);
265 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
266 return last ? DYNCVC_READ_ERROR : DYNCVC_READ_INCOMPLETE;
267 Stream_Read_UINT16(s, *varInt);
270 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
271 return last ? DYNCVC_READ_ERROR : DYNCVC_READ_INCOMPLETE;
272 Stream_Read_UINT32(s, *varInt);
276 WLog_Print(log, WLOG_ERROR,
"Unknown int len %" PRIuz, len);
277 return DYNCVC_READ_ERROR;
279 return DYNCVC_READ_OK;
283static PfChannelResult DynvcTrackerPeekHandleByMode(ChannelStateTracker* tracker,
284 DynChannelTrackerState* trackerState,
285 pServerDynamicChannelContext* dynChannel,
286 BYTE cmd, BOOL firstPacket, BOOL lastPacket)
288 WINPR_ASSERT(tracker);
289 WINPR_ASSERT(trackerState);
290 WINPR_ASSERT(dynChannel);
291 PfChannelResult result = PF_CHANNEL_RESULT_ERROR;
293 DynChannelContext* dynChannelContext =
294 (DynChannelContext*)channelTracker_getCustomData(tracker);
295 WINPR_ASSERT(dynChannelContext);
297 proxyData* pdata = channelTracker_getPData(tracker);
300 const BOOL isBackData = (tracker == dynChannelContext->backTracker);
301 switch (dynChannel->channelMode)
303 case PF_UTILS_CHANNEL_PASSTHROUGH:
304 result = channelTracker_flushCurrent(tracker, firstPacket, lastPacket, !isBackData);
306 case PF_UTILS_CHANNEL_BLOCK:
307 channelTracker_setMode(tracker, CHANNEL_TRACKER_DROP);
308 result = PF_CHANNEL_RESULT_DROP;
310 case PF_UTILS_CHANNEL_INTERCEPT:
311 if (trackerState->dataCallback)
313 pServerContext* ps = proxy_data_get_server_context(pdata);
314 result = trackerState->dataCallback(ps, dynChannel, isBackData, tracker,
315 firstPacket, lastPacket);
319 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
320 "no intercept callback for channel, dropping packet");
321 result = PF_CHANNEL_RESULT_DROP;
325 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
326 "unknown channel mode %u", dynChannel->channelMode);
327 result = PF_CHANNEL_RESULT_ERROR;
331 if (!trackerState->currentDataLength ||
332 (trackerState->CurrentDataReceived == trackerState->currentDataLength))
334 trackerState->currentDataLength = 0;
335 trackerState->CurrentDataFragments = 0;
336 trackerState->CurrentDataReceived = 0;
338 if (dynChannel->packetReassembly && trackerState->currentPacket)
339 Stream_ResetPosition(trackerState->currentPacket);
346static PfChannelResult DynvcTrackerHandleClose(ChannelStateTracker* tracker,
347 pServerDynamicChannelContext* dynChannel,
348 DynChannelContext* dynChannelContext,
349 BOOL firstPacket, BOOL lastPacket)
351 WINPR_ASSERT(dynChannelContext);
353 const BOOL isBackData = (tracker == dynChannelContext->backTracker);
355 if (!lastPacket || !dynChannel)
356 return PF_CHANNEL_RESULT_DROP;
358 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, CLOSE_REQUEST_PDU, isBackData,
360 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
361 if (dynChannel->openStatus != CHANNEL_OPENSTATE_OPENED)
363 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, CLOSE_REQUEST_PDU,
364 isBackData,
"is in state %s, expected %s",
365 openstatus2str(dynChannel->openStatus),
366 openstatus2str(CHANNEL_OPENSTATE_OPENED));
368 dynChannel->openStatus = CHANNEL_OPENSTATE_CLOSED;
369 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, !isBackData);
373static PfChannelResult DynvcTrackerHandleCreateBack(ChannelStateTracker* tracker,
wStream* s,
374 DWORD flags, proxyData* pdata,
375 pServerDynamicChannelContext* dynChannel,
376 DynChannelContext* dynChannelContext,
380 const char* name = Stream_ConstPointer(s);
381 const size_t nameLen = Stream_GetRemainingLength(s);
382 const size_t len = strnlen(name, nameLen);
383 const BOOL isBackData = (tracker == dynChannelContext->backTracker);
384 const BYTE cmd = CREATE_REQUEST_PDU;
386 if ((len == 0) || (len == nameLen) || (dynChannelId > UINT16_MAX))
388 char namebuffer[64] = WINPR_C_ARRAY_INIT;
389 (void)_snprintf(namebuffer,
sizeof(namebuffer) - 1,
"%s", name);
391 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
392 "channel id %" PRIu64
", name=%s [%" PRIuz
"|%" PRIuz
"], status=%s",
393 dynChannelId, namebuffer, len, nameLen,
394 dynChannel ? openstatus2str(dynChannel->openStatus) :
"nullptr");
395 return PF_CHANNEL_RESULT_ERROR;
398 wStream* currentPacket = channelTracker_getCurrentPacket(tracker);
399 dev.channel_id = (UINT16)dynChannelId;
400 dev.channel_name = name;
401 dev.data = Stream_Buffer(s);
402 dev.data_len = Stream_GetPosition(currentPacket);
404 dev.total_size = Stream_GetPosition(currentPacket);
408 DynvcTrackerLog(dynChannelContext->log, WLOG_WARN, dynChannel, cmd, isBackData,
409 "Reusing channel id, now %s", name);
411 HashTable_Remove(dynChannelContext->channels, &dynChannel->channelId);
414 if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE,
416 return PF_CHANNEL_RESULT_DROP;
418 pServerContext* ps = proxy_data_get_server_context(pdata);
419 dynChannel = DynamicChannelContext_new(dynChannelContext->log, ps, name, (UINT32)dynChannelId);
422 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
423 "unable to create dynamic channel context data");
424 return PF_CHANNEL_RESULT_ERROR;
427 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, cmd, isBackData,
429 if (!HashTable_Insert(dynChannelContext->channels, &dynChannel->channelId, dynChannel))
431 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
432 "unable register dynamic channel context data");
433 DynamicChannelContext_free(dynChannel);
434 return PF_CHANNEL_RESULT_ERROR;
437 dynChannel->openStatus = CHANNEL_OPENSTATE_WAITING_OPEN_STATUS;
439 const BOOL firstPacket = (flags & CHANNEL_FLAG_FIRST) != 0;
440 const BOOL lastPacket = (flags & CHANNEL_FLAG_LAST) != 0;
443 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, FALSE);
447static PfChannelResult DynvcTrackerHandleCreateFront(ChannelStateTracker* tracker,
wStream* s,
449 WINPR_ATTR_UNUSED proxyData* pdata,
450 pServerDynamicChannelContext* dynChannel,
451 DynChannelContext* dynChannelContext,
452 WINPR_ATTR_UNUSED UINT64 dynChannelId)
454 const BOOL isBackData = (tracker == dynChannelContext->backTracker);
455 const BYTE cmd = CREATE_REQUEST_PDU;
458 if (!Stream_CheckAndLogRequiredLengthWLogWithBackend(dynChannelContext->log, s, 4, FALSE))
459 return PF_CHANNEL_RESULT_ERROR;
461 const UINT32 creationStatus = Stream_Get_UINT32(s);
462 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, cmd, isBackData,
463 "CREATE_RESPONSE openStatus=%" PRIu32, creationStatus);
465 if (dynChannel && (creationStatus == 0))
466 dynChannel->openStatus = CHANNEL_OPENSTATE_OPENED;
468 const BOOL firstPacket = (flags & CHANNEL_FLAG_FIRST) != 0;
469 const BOOL lastPacket = (flags & CHANNEL_FLAG_LAST) != 0;
471 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, TRUE);
475static PfChannelResult DynvcTrackerHandleCreate(ChannelStateTracker* tracker,
wStream* s,
477 pServerDynamicChannelContext* dynChannel,
480 WINPR_ASSERT(tracker);
483 DynChannelContext* dynChannelContext =
484 (DynChannelContext*)channelTracker_getCustomData(tracker);
485 WINPR_ASSERT(dynChannelContext);
487 const BOOL lastPacket = (flags & CHANNEL_FLAG_LAST) != 0;
488 const BOOL isBackData = (tracker == dynChannelContext->backTracker);
490 proxyData* pdata = channelTracker_getPData(tracker);
495 return PF_CHANNEL_RESULT_DROP;
498 return DynvcTrackerHandleCreateBack(tracker, s, flags, pdata, dynChannel, dynChannelContext,
501 return DynvcTrackerHandleCreateFront(tracker, s, flags, pdata, dynChannel, dynChannelContext,
506static PfChannelResult DynvcTrackerHandleCmdDATA(ChannelStateTracker* tracker,
507 pServerDynamicChannelContext* dynChannel,
508 wStream* s, BYTE cmd, UINT64 Length,
509 BOOL firstPacket, BOOL lastPacket)
511 WINPR_ASSERT(tracker);
514 DynChannelContext* dynChannelContext =
515 (DynChannelContext*)channelTracker_getCustomData(tracker);
516 WINPR_ASSERT(dynChannelContext);
518 const BOOL isBackData = (tracker == dynChannelContext->backTracker);
522 DynvcTrackerLog(dynChannelContext->log, WLOG_WARN, dynChannel, cmd, isBackData,
523 "channel is nullptr, dropping packet");
524 return PF_CHANNEL_RESULT_DROP;
527 DynChannelTrackerState* trackerState =
528 isBackData ? &dynChannel->backTracker : &dynChannel->frontTracker;
529 if (dynChannel->openStatus != CHANNEL_OPENSTATE_OPENED)
531 DynvcTrackerLog(dynChannelContext->log, WLOG_WARN, dynChannel, cmd, isBackData,
532 "channel is not opened, dropping packet");
533 return PF_CHANNEL_RESULT_DROP;
539 case DATA_FIRST_COMPRESSED_PDU:
541 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, cmd, isBackData,
542 "DATA_FIRST currentPacketLength=%" PRIu64
"", Length);
543 if (Length > UINT32_MAX)
545 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
546 "Length out of bounds: %" PRIu64, Length);
547 return PF_CHANNEL_RESULT_ERROR;
549 trackerState->currentDataLength = (UINT32)Length;
550 trackerState->CurrentDataReceived = 0;
551 trackerState->CurrentDataFragments = 0;
553 if (dynChannel->packetReassembly)
555 if (trackerState->currentPacket)
556 Stream_ResetPosition(trackerState->currentPacket);
569 size_t extraSize = Stream_GetRemainingLength(s);
571 trackerState->CurrentDataFragments++;
572 trackerState->CurrentDataReceived += WINPR_ASSERTING_INT_CAST(uint32_t, extraSize);
574 if (dynChannel->packetReassembly)
576 if (!trackerState->currentPacket)
578 trackerState->currentPacket = Stream_New(
nullptr, 1024);
579 if (!trackerState->currentPacket)
581 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd,
582 isBackData,
"unable to create current packet",
583 getDirection(isBackData), dynChannel->channelName,
584 drdynvc_get_packet_type(cmd));
585 return PF_CHANNEL_RESULT_ERROR;
589 if (!Stream_EnsureRemainingCapacity(trackerState->currentPacket, extraSize))
591 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
592 "unable to grow current packet", getDirection(isBackData),
593 dynChannel->channelName, drdynvc_get_packet_type(cmd));
594 return PF_CHANNEL_RESULT_ERROR;
597 Stream_Write(trackerState->currentPacket, Stream_ConstPointer(s), extraSize);
599 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, cmd, isBackData,
600 "frags=%" PRIu32
" received=%" PRIu32
"(%" PRIu32
")",
601 trackerState->CurrentDataFragments, trackerState->CurrentDataReceived,
602 trackerState->currentDataLength);
613 if (trackerState->currentDataLength)
615 if (trackerState->CurrentDataReceived > trackerState->currentDataLength)
617 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
618 "reassembled packet (%" PRIu32
619 ") is bigger than announced length (%" PRIu32
")",
620 trackerState->CurrentDataReceived,
621 trackerState->currentDataLength);
622 return PF_CHANNEL_RESULT_ERROR;
627 trackerState->CurrentDataFragments = 0;
628 trackerState->CurrentDataReceived = 0;
636 return DynvcTrackerPeekHandleByMode(tracker, trackerState, dynChannel, cmd, firstPacket,
641static PfChannelResult DynvcTrackerHandleCmd(ChannelStateTracker* tracker,
642 pServerDynamicChannelContext* dynChannel,
wStream* s,
643 BYTE cmd, UINT32 flags, UINT64 Length,
644 UINT64 dynChannelId, BOOL firstPacket, BOOL lastPacket)
646 WINPR_ASSERT(tracker);
649 DynChannelContext* dynChannelContext =
650 (DynChannelContext*)channelTracker_getCustomData(tracker);
651 WINPR_ASSERT(dynChannelContext);
653 const BOOL isBackData = (tracker == dynChannelContext->backTracker);
656 case CAPABILITY_REQUEST_PDU:
657 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, cmd, isBackData,
658 "CAPABILITY_%s", isBackData ?
"REQUEST" :
"RESPONSE");
659 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
660 return PF_CHANNEL_RESULT_PASS;
662 case CREATE_REQUEST_PDU:
663 return DynvcTrackerHandleCreate(tracker, s, flags, dynChannel, dynChannelId);
665 case CLOSE_REQUEST_PDU:
666 return DynvcTrackerHandleClose(tracker, dynChannel, dynChannelContext, firstPacket,
669 case SOFT_SYNC_REQUEST_PDU:
671 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, cmd, isBackData,
672 "SOFT_SYNC_REQUEST_PDU");
673 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
675 return PF_CHANNEL_RESULT_PASS;
677 case SOFT_SYNC_RESPONSE_PDU:
679 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, cmd, isBackData,
680 "SOFT_SYNC_RESPONSE_PDU");
681 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
682 return PF_CHANNEL_RESULT_PASS;
686 return DynvcTrackerHandleCmdDATA(tracker, dynChannel, s, cmd, Length, firstPacket,
689 case DATA_FIRST_COMPRESSED_PDU:
690 case DATA_COMPRESSED_PDU:
691 DynvcTrackerLog(dynChannelContext->log, WLOG_DEBUG, dynChannel, cmd, isBackData,
692 "TODO: compressed data packets, pass them as is for now");
693 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
694 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, !isBackData);
697 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
698 "Invalid command ID");
699 return PF_CHANNEL_RESULT_ERROR;
704static PfChannelResult DynvcTrackerPeekFn(ChannelStateTracker* tracker, BOOL firstPacket,
709 BOOL haveChannelId = 0;
711 UINT64 dynChannelId = 0;
713 pServerDynamicChannelContext* dynChannel =
nullptr;
715 WINPR_ASSERT(tracker);
717 DynChannelContext* dynChannelContext =
718 (DynChannelContext*)channelTracker_getCustomData(tracker);
719 WINPR_ASSERT(dynChannelContext);
721 const BOOL isBackData = (tracker == dynChannelContext->backTracker);
723 UINT32 flags = lastPacket ? CHANNEL_FLAG_LAST : 0;
725 flags |= CHANNEL_FLAG_FIRST;
728 wStream* currentPacket = channelTracker_getCurrentPacket(tracker);
729 s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(currentPacket),
730 Stream_GetPosition(currentPacket));
733 if (!Stream_CheckAndLogRequiredLengthWLogWithBackend(dynChannelContext->log, s, 1, isBackData))
734 return PF_CHANNEL_RESULT_ERROR;
736 const BYTE byte0 = Stream_Get_UINT8(s);
737 const BYTE cmd = byte0 >> 4;
741 case CREATE_REQUEST_PDU:
742 case CLOSE_REQUEST_PDU:
744 case DATA_COMPRESSED_PDU:
745 haveChannelId = TRUE;
749 case DATA_FIRST_COMPRESSED_PDU:
751 haveChannelId = TRUE;
754 haveChannelId = FALSE;
761 BYTE cbId = byte0 & 0x03;
763 switch (dynvc_read_varInt(dynChannelContext->log, s, cbId, &dynChannelId, lastPacket))
767 case DYNCVC_READ_INCOMPLETE:
768 return PF_CHANNEL_RESULT_DROP;
769 case DYNCVC_READ_ERROR:
771 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
772 "invalid channelId field");
773 return PF_CHANNEL_RESULT_ERROR;
779 dynChannel = (pServerDynamicChannelContext*)HashTable_GetItemValue(
780 dynChannelContext->channels, &dynChannelId);
781 if ((cmd != CREATE_REQUEST_PDU) || !isBackData)
783 if (!dynChannel || (dynChannel->openStatus == CHANNEL_OPENSTATE_CLOSED))
787 channelTracker_setMode(tracker, CHANNEL_TRACKER_DROP);
788 return PF_CHANNEL_RESULT_DROP;
795 BYTE lenLen = (byte0 >> 2) & 0x03;
796 switch (dynvc_read_varInt(dynChannelContext->log, s, lenLen, &Length, lastPacket))
800 case DYNCVC_READ_INCOMPLETE:
801 return PF_CHANNEL_RESULT_DROP;
802 case DYNCVC_READ_ERROR:
804 DynvcTrackerLog(dynChannelContext->log, WLOG_ERROR, dynChannel, cmd, isBackData,
805 "invalid length field");
806 return PF_CHANNEL_RESULT_ERROR;
810 return DynvcTrackerHandleCmd(tracker, dynChannel, s, cmd, flags, Length, dynChannelId,
811 firstPacket, lastPacket);
814static void DynChannelContext_free(
void* context)
816 DynChannelContext* c = context;
819 channelTracker_free(c->backTracker);
820 channelTracker_free(c->frontTracker);
821 HashTable_Free(c->channels);
822 WLog_Discard(c->log);
827static const char* dynamic_context(
void* arg)
829 proxyData* pdata = arg;
832 return pdata->session_id;
835WINPR_ATTR_MALLOC(DynChannelContext_free, 1)
836static DynChannelContext* DynChannelContext_new(proxyData* pdata,
837 pServerStaticChannelContext* channel)
839 DynChannelContext* dyn = calloc(1,
sizeof(DynChannelContext));
843 dyn->log = WLog_Create(DTAG, WLog_GetRoot());
847 if (!WLog_SetContext(dyn->log, dynamic_context, pdata))
850 dyn->backTracker = channelTracker_new(channel, DynvcTrackerPeekFn, dyn);
851 if (!dyn->backTracker)
853 if (!channelTracker_setPData(dyn->backTracker, pdata))
856 dyn->frontTracker = channelTracker_new(channel, DynvcTrackerPeekFn, dyn);
857 if (!dyn->frontTracker)
859 if (!channelTracker_setPData(dyn->frontTracker, pdata))
862 dyn->channels = HashTable_New(FALSE);
866 if (!HashTable_SetHashFunction(dyn->channels, ChannelId_Hash))
870 wObject* kobj = HashTable_KeyObject(dyn->channels);
876 wObject* vobj = HashTable_ValueObject(dyn->channels);
884 DynChannelContext_free(dyn);
889static PfChannelResult pf_dynvc_back_data(proxyData* pdata,
890 const pServerStaticChannelContext* channel,
891 const BYTE* xdata,
size_t xsize, UINT32 flags,
894 WINPR_ASSERT(channel);
896 DynChannelContext* dyn = (DynChannelContext*)channel->context;
900 return channelTracker_update(dyn->backTracker, xdata, xsize, flags, totalSize);
904static PfChannelResult pf_dynvc_front_data(proxyData* pdata,
905 const pServerStaticChannelContext* channel,
906 const BYTE* xdata,
size_t xsize, UINT32 flags,
909 WINPR_ASSERT(channel);
911 DynChannelContext* dyn = (DynChannelContext*)channel->context;
915 return channelTracker_update(dyn->frontTracker, xdata, xsize, flags, totalSize);
918BOOL pf_channel_setup_drdynvc(proxyData* pdata, pServerStaticChannelContext* channel)
920 DynChannelContext* ret = DynChannelContext_new(pdata, channel);
924 channel->onBackData = pf_dynvc_back_data;
925 channel->onFrontData = pf_dynvc_front_data;
926 channel->contextDtor = DynChannelContext_free;
927 channel->context = ret;
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree
WINPR_ATTR_NODISCARD OBJECT_EQUALS_FN fnObjectEquals