FreeRDP
Loading...
Searching...
No Matches
pf_channel_drdynvc.c
1
19#include <winpr/assert.h>
20
21#include <freerdp/channels/drdynvc.h>
22#include <freerdp/utils/drdynvc.h>
23#include <freerdp/server/proxy/proxy_log.h>
24
25#include "pf_channel_drdynvc.h"
26#include "../pf_channel.h"
27#include "../proxy_modules.h"
28#include "../pf_utils.h"
29
30#define DTAG PROXY_TAG("drdynvc")
31
33typedef enum
34{
35 CHANNEL_OPENSTATE_WAITING_OPEN_STATUS,
36 CHANNEL_OPENSTATE_OPENED,
37 CHANNEL_OPENSTATE_CLOSED
38} PfDynChannelOpenStatus;
39
40typedef struct p_server_dynamic_channel_context pServerDynamicChannelContext;
41typedef struct DynChannelTrackerState DynChannelTrackerState;
42
43typedef PfChannelResult (*dynamic_channel_on_data_fn)(pServerContext* ps,
44 pServerDynamicChannelContext* channel,
45 BOOL isBackData, ChannelStateTracker* tracker,
46 BOOL firstPacket, BOOL lastPacket);
47
49struct DynChannelTrackerState
50{
51 UINT32 currentDataLength;
52 UINT32 CurrentDataReceived;
53 UINT32 CurrentDataFragments;
54 wStream* currentPacket;
55 dynamic_channel_on_data_fn dataCallback;
56};
57
58typedef void (*channel_data_dtor_fn)(void** user_data);
59
60struct p_server_dynamic_channel_context
61{
62 char* channelName;
63 UINT32 channelId;
64 PfDynChannelOpenStatus openStatus;
65 pf_utils_channel_mode channelMode;
66 BOOL packetReassembly;
67 DynChannelTrackerState backTracker;
68 DynChannelTrackerState frontTracker;
69
70 void* channelData;
71 channel_data_dtor_fn channelDataDtor;
72};
73
75typedef struct
76{
77 wHashTable* channels;
78 ChannelStateTracker* backTracker;
79 ChannelStateTracker* frontTracker;
80 wLog* log;
81} DynChannelContext;
82
84typedef enum
85{
86 DYNCVC_READ_OK,
87 DYNCVC_READ_ERROR,
88 DYNCVC_READ_INCOMPLETE
89} DynvcReadResult;
90
91static const char* openstatus2str(PfDynChannelOpenStatus status)
92{
93 switch (status)
94 {
95 case CHANNEL_OPENSTATE_WAITING_OPEN_STATUS:
96 return "CHANNEL_OPENSTATE_WAITING_OPEN_STATUS";
97 case CHANNEL_OPENSTATE_CLOSED:
98 return "CHANNEL_OPENSTATE_CLOSED";
99 case CHANNEL_OPENSTATE_OPENED:
100 return "CHANNEL_OPENSTATE_OPENED";
101 default:
102 return "CHANNEL_OPENSTATE_UNKNOWN";
103 }
104}
105
106static PfChannelResult data_cb(pServerContext* ps, pServerDynamicChannelContext* channel,
107 BOOL isBackData, ChannelStateTracker* tracker, BOOL firstPacket,
108 BOOL lastPacket)
109{
110 WINPR_ASSERT(ps);
111 WINPR_ASSERT(channel);
112 WINPR_ASSERT(tracker);
113 WINPR_ASSERT(ps->pdata);
114
115 wStream* currentPacket = channelTracker_getCurrentPacket(tracker);
116 proxyDynChannelInterceptData dyn = { .name = channel->channelName,
117 .channelId = channel->channelId,
118 .data = currentPacket,
119 .isBackData = isBackData,
120 .first = firstPacket,
121 .last = lastPacket,
122 .rewritten = FALSE,
123 .packetSize = channelTracker_getCurrentPacketSize(tracker),
124 .result = PF_CHANNEL_RESULT_ERROR };
125 Stream_SealLength(dyn.data);
126 if (!pf_modules_run_filter(ps->pdata->module, FILTER_TYPE_INTERCEPT_CHANNEL, ps->pdata, &dyn))
127 return PF_CHANNEL_RESULT_ERROR;
128
129 channelTracker_setCurrentPacketSize(tracker, dyn.packetSize);
130 if (dyn.rewritten)
131 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, !isBackData);
132 return dyn.result;
133}
134
135static pServerDynamicChannelContext* DynamicChannelContext_new(wLog* log, pServerContext* ps,
136 const char* name, UINT32 id)
137{
138 WINPR_ASSERT(log);
139
140 pServerDynamicChannelContext* ret = calloc(1, sizeof(*ret));
141 if (!ret)
142 {
143 WLog_Print(log, WLOG_ERROR, "error allocating dynamic channel context '%s'", name);
144 return NULL;
145 }
146
147 ret->channelId = id;
148 ret->channelName = _strdup(name);
149 if (!ret->channelName)
150 {
151 WLog_Print(log, WLOG_ERROR, "error allocating name in dynamic channel context '%s'", name);
152 free(ret);
153 return NULL;
154 }
155
156 ret->frontTracker.dataCallback = data_cb;
157 ret->backTracker.dataCallback = data_cb;
158
159 proxyChannelToInterceptData dyn = { .name = name, .channelId = id, .intercept = FALSE };
160 if (pf_modules_run_filter(ps->pdata->module, FILTER_TYPE_DYN_INTERCEPT_LIST, ps->pdata, &dyn) &&
161 dyn.intercept)
162 ret->channelMode = PF_UTILS_CHANNEL_INTERCEPT;
163 else
164 ret->channelMode = pf_utils_get_channel_mode(ps->pdata->config, name);
165 ret->openStatus = CHANNEL_OPENSTATE_OPENED;
166 ret->packetReassembly = (ret->channelMode == PF_UTILS_CHANNEL_INTERCEPT);
167
168 return ret;
169}
170
171static void DynamicChannelContext_free(void* ptr)
172{
173 pServerDynamicChannelContext* c = (pServerDynamicChannelContext*)ptr;
174 if (!c)
175 return;
176
177 if (c->backTracker.currentPacket)
178 Stream_Free(c->backTracker.currentPacket, TRUE);
179
180 if (c->frontTracker.currentPacket)
181 Stream_Free(c->frontTracker.currentPacket, TRUE);
182
183 if (c->channelDataDtor)
184 c->channelDataDtor(&c->channelData);
185
186 free(c->channelName);
187 free(c);
188}
189
190static UINT32 ChannelId_Hash(const void* key)
191{
192 const UINT32* v = (const UINT32*)key;
193 return *v;
194}
195
196static BOOL ChannelId_Compare(const void* objA, const void* objB)
197{
198 const UINT32* v1 = objA;
199 const UINT32* v2 = objB;
200 return (*v1 == *v2);
201}
202
203static DynvcReadResult dynvc_read_varInt(wLog* log, wStream* s, size_t len, UINT64* varInt,
204 BOOL last)
205{
206 WINPR_ASSERT(varInt);
207 switch (len)
208 {
209 case 0x00:
210 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
211 return last ? DYNCVC_READ_ERROR : DYNCVC_READ_INCOMPLETE;
212 Stream_Read_UINT8(s, *varInt);
213 break;
214 case 0x01:
215 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
216 return last ? DYNCVC_READ_ERROR : DYNCVC_READ_INCOMPLETE;
217 Stream_Read_UINT16(s, *varInt);
218 break;
219 case 0x02:
220 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
221 return last ? DYNCVC_READ_ERROR : DYNCVC_READ_INCOMPLETE;
222 Stream_Read_UINT32(s, *varInt);
223 break;
224 case 0x03:
225 default:
226 WLog_Print(log, WLOG_ERROR, "Unknown int len %" PRIuz, len);
227 return DYNCVC_READ_ERROR;
228 }
229 return DYNCVC_READ_OK;
230}
231
232static PfChannelResult DynvcTrackerPeekFn(ChannelStateTracker* tracker, BOOL firstPacket,
233 BOOL lastPacket)
234{
235 BYTE cmd = 0;
236 BYTE byte0 = 0;
237 wStream* s = NULL;
238 wStream sbuffer;
239 BOOL haveChannelId = 0;
240 BOOL haveLength = 0;
241 UINT64 dynChannelId = 0;
242 UINT64 Length = 0;
243 pServerDynamicChannelContext* dynChannel = NULL;
244
245 WINPR_ASSERT(tracker);
246
247 DynChannelContext* dynChannelContext =
248 (DynChannelContext*)channelTracker_getCustomData(tracker);
249 WINPR_ASSERT(dynChannelContext);
250
251 BOOL isBackData = (tracker == dynChannelContext->backTracker);
252 DynChannelTrackerState* trackerState = NULL;
253
254 UINT32 flags = lastPacket ? CHANNEL_FLAG_LAST : 0;
255 proxyData* pdata = channelTracker_getPData(tracker);
256 WINPR_ASSERT(pdata);
257
258 const char* direction = isBackData ? "B->F" : "F->B";
259
260 {
261 wStream* currentPacket = channelTracker_getCurrentPacket(tracker);
262 s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(currentPacket),
263 Stream_GetPosition(currentPacket));
264 }
265
266 if (!Stream_CheckAndLogRequiredLengthWLog(dynChannelContext->log, s, 1))
267 return PF_CHANNEL_RESULT_ERROR;
268
269 Stream_Read_UINT8(s, byte0);
270 cmd = byte0 >> 4;
271
272 switch (cmd)
273 {
274 case CREATE_REQUEST_PDU:
275 case CLOSE_REQUEST_PDU:
276 case DATA_PDU:
277 case DATA_COMPRESSED_PDU:
278 haveChannelId = TRUE;
279 haveLength = FALSE;
280 break;
281 case DATA_FIRST_PDU:
282 case DATA_FIRST_COMPRESSED_PDU:
283 haveLength = TRUE;
284 haveChannelId = TRUE;
285 break;
286 default:
287 haveChannelId = FALSE;
288 haveLength = FALSE;
289 break;
290 }
291
292 if (haveChannelId)
293 {
294 BYTE cbId = byte0 & 0x03;
295
296 switch (dynvc_read_varInt(dynChannelContext->log, s, cbId, &dynChannelId, lastPacket))
297 {
298 case DYNCVC_READ_OK:
299 break;
300 case DYNCVC_READ_INCOMPLETE:
301 return PF_CHANNEL_RESULT_DROP;
302 case DYNCVC_READ_ERROR:
303 default:
304 WLog_Print(dynChannelContext->log, WLOG_ERROR,
305 "DynvcTrackerPeekFn: invalid channelId field");
306 return PF_CHANNEL_RESULT_ERROR;
307 }
308
309 /* we always try to retrieve the dynamic channel in case it would have been opened
310 * and closed
311 */
312 dynChannel = (pServerDynamicChannelContext*)HashTable_GetItemValue(
313 dynChannelContext->channels, &dynChannelId);
314 if ((cmd != CREATE_REQUEST_PDU) || !isBackData)
315 {
316 if (!dynChannel || (dynChannel->openStatus == CHANNEL_OPENSTATE_CLOSED))
317 {
318 /* we've not found the target channel, so we drop this chunk, plus all the rest of
319 * the packet */
320 channelTracker_setMode(tracker, CHANNEL_TRACKER_DROP);
321 return PF_CHANNEL_RESULT_DROP;
322 }
323 }
324 }
325
326 if (haveLength)
327 {
328 BYTE lenLen = (byte0 >> 2) & 0x03;
329 switch (dynvc_read_varInt(dynChannelContext->log, s, lenLen, &Length, lastPacket))
330 {
331 case DYNCVC_READ_OK:
332 break;
333 case DYNCVC_READ_INCOMPLETE:
334 return PF_CHANNEL_RESULT_DROP;
335 case DYNCVC_READ_ERROR:
336 default:
337 WLog_Print(dynChannelContext->log, WLOG_ERROR,
338 "DynvcTrackerPeekFn: invalid length field");
339 return PF_CHANNEL_RESULT_ERROR;
340 }
341 }
342
343 switch (cmd)
344 {
345 case CAPABILITY_REQUEST_PDU:
346 WLog_Print(dynChannelContext->log, WLOG_DEBUG, "DynvcTracker: %s CAPABILITY_%s",
347 direction, isBackData ? "REQUEST" : "RESPONSE");
348 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
349 return PF_CHANNEL_RESULT_PASS;
350
351 case CREATE_REQUEST_PDU:
352 {
353 UINT32 creationStatus = 0;
354
355 /* we only want the full packet */
356 if (!lastPacket)
357 return PF_CHANNEL_RESULT_DROP;
358
359 if (isBackData)
360 {
361 proxyChannelDataEventInfo dev = { 0 };
362 const char* name = Stream_ConstPointer(s);
363 const size_t nameLen = Stream_GetRemainingLength(s);
364
365 const size_t len = strnlen(name, nameLen);
366 if ((len == 0) || (len == nameLen) || (dynChannelId > UINT16_MAX))
367 return PF_CHANNEL_RESULT_ERROR;
368
369 wStream* currentPacket = channelTracker_getCurrentPacket(tracker);
370 dev.channel_id = (UINT16)dynChannelId;
371 dev.channel_name = name;
372 dev.data = Stream_Buffer(s);
373 dev.data_len = Stream_GetPosition(currentPacket);
374 dev.flags = flags;
375 dev.total_size = Stream_GetPosition(currentPacket);
376
377 if (dynChannel)
378 {
379 WLog_Print(
380 dynChannelContext->log, WLOG_WARN,
381 "Reusing channel id %" PRIu32 ", previously %s [state %s, mode %s], now %s",
382 dynChannel->channelId, dynChannel->channelName,
383 openstatus2str(dynChannel->openStatus),
384 pf_utils_channel_mode_string(dynChannel->channelMode), dev.channel_name);
385
386 HashTable_Remove(dynChannelContext->channels, &dynChannel->channelId);
387 }
388
389 if (!pf_modules_run_filter(pdata->module,
390 FILTER_TYPE_CLIENT_PASSTHROUGH_DYN_CHANNEL_CREATE, pdata,
391 &dev))
392 return PF_CHANNEL_RESULT_DROP; /* Silently drop */
393
394 dynChannel = DynamicChannelContext_new(dynChannelContext->log, pdata->ps, name,
395 (UINT32)dynChannelId);
396 if (!dynChannel)
397 {
398 WLog_Print(dynChannelContext->log, WLOG_ERROR,
399 "unable to create dynamic channel context data");
400 return PF_CHANNEL_RESULT_ERROR;
401 }
402
403 WLog_Print(dynChannelContext->log, WLOG_DEBUG, "Adding channel '%s'[%d]",
404 dynChannel->channelName, dynChannel->channelId);
405 if (!HashTable_Insert(dynChannelContext->channels, &dynChannel->channelId,
406 dynChannel))
407 {
408 WLog_Print(dynChannelContext->log, WLOG_ERROR,
409 "unable register dynamic channel context data");
410 DynamicChannelContext_free(dynChannel);
411 return PF_CHANNEL_RESULT_ERROR;
412 }
413
414 dynChannel->openStatus = CHANNEL_OPENSTATE_WAITING_OPEN_STATUS;
415
416 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert owns dynChannel
417 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, FALSE);
418 }
419
420 /* CREATE_REQUEST_PDU response */
421 if (!Stream_CheckAndLogRequiredLengthWLog(dynChannelContext->log, s, 4))
422 return PF_CHANNEL_RESULT_ERROR;
423
424 Stream_Read_UINT32(s, creationStatus);
425 WLog_Print(dynChannelContext->log, WLOG_DEBUG,
426 "DynvcTracker(%" PRIu64 ",%s): %s CREATE_RESPONSE openStatus=%" PRIu32,
427 dynChannelId, dynChannel->channelName, direction, creationStatus);
428
429 if (creationStatus == 0)
430 dynChannel->openStatus = CHANNEL_OPENSTATE_OPENED;
431
432 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, TRUE);
433 }
434
435 case CLOSE_REQUEST_PDU:
436 if (!lastPacket)
437 return PF_CHANNEL_RESULT_DROP;
438
439 WLog_Print(dynChannelContext->log, WLOG_DEBUG,
440 "DynvcTracker(%s): %s Close request on channel", dynChannel->channelName,
441 direction);
442 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
443 if (dynChannel->openStatus != CHANNEL_OPENSTATE_OPENED)
444 {
445 WLog_Print(dynChannelContext->log, WLOG_WARN,
446 "DynvcTracker(%s): is in state %s, expected %s", dynChannel->channelName,
447 openstatus2str(dynChannel->openStatus),
448 openstatus2str(CHANNEL_OPENSTATE_OPENED));
449 }
450 dynChannel->openStatus = CHANNEL_OPENSTATE_CLOSED;
451 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, !isBackData);
452
453 case SOFT_SYNC_REQUEST_PDU:
454 /* just pass then as is for now */
455 WLog_Print(dynChannelContext->log, WLOG_DEBUG, "SOFT_SYNC_REQUEST_PDU");
456 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
457 /*TODO: return pf_treat_softsync_req(pdata, s);*/
458 return PF_CHANNEL_RESULT_PASS;
459
460 case SOFT_SYNC_RESPONSE_PDU:
461 /* just pass then as is for now */
462 WLog_Print(dynChannelContext->log, WLOG_DEBUG, "SOFT_SYNC_RESPONSE_PDU");
463 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
464 return PF_CHANNEL_RESULT_PASS;
465
466 case DATA_FIRST_PDU:
467 case DATA_PDU:
468 /* treat these below */
469 trackerState = isBackData ? &dynChannel->backTracker : &dynChannel->frontTracker;
470 break;
471
472 case DATA_FIRST_COMPRESSED_PDU:
473 case DATA_COMPRESSED_PDU:
474 WLog_Print(dynChannelContext->log, WLOG_DEBUG,
475 "TODO: compressed data packets, pass them as is for now");
476 channelTracker_setMode(tracker, CHANNEL_TRACKER_PASS);
477 return channelTracker_flushCurrent(tracker, firstPacket, lastPacket, !isBackData);
478
479 default:
480 return PF_CHANNEL_RESULT_ERROR;
481 }
482
483 if (dynChannel->openStatus != CHANNEL_OPENSTATE_OPENED)
484 {
485 WLog_Print(dynChannelContext->log, WLOG_ERROR,
486 "DynvcTracker(%s [%s]): channel is not opened", dynChannel->channelName,
487 drdynvc_get_packet_type(cmd));
488 return PF_CHANNEL_RESULT_ERROR;
489 }
490
491 if ((cmd == DATA_FIRST_PDU) || (cmd == DATA_FIRST_COMPRESSED_PDU))
492 {
493 WLog_Print(dynChannelContext->log, WLOG_DEBUG,
494 "DynvcTracker(%s [%s]): %s DATA_FIRST currentPacketLength=%" PRIu64 "",
495 dynChannel->channelName, drdynvc_get_packet_type(cmd), direction, Length);
496 if (Length > UINT32_MAX)
497 return PF_CHANNEL_RESULT_ERROR;
498 trackerState->currentDataLength = (UINT32)Length;
499 trackerState->CurrentDataReceived = 0;
500 trackerState->CurrentDataFragments = 0;
501
502 if (dynChannel->packetReassembly)
503 {
504 if (trackerState->currentPacket)
505 Stream_SetPosition(trackerState->currentPacket, 0);
506 }
507 }
508
509 if (cmd == DATA_PDU || cmd == DATA_FIRST_PDU)
510 {
511 size_t extraSize = Stream_GetRemainingLength(s);
512
513 trackerState->CurrentDataFragments++;
514 trackerState->CurrentDataReceived += WINPR_ASSERTING_INT_CAST(uint32_t, extraSize);
515
516 if (dynChannel->packetReassembly)
517 {
518 if (!trackerState->currentPacket)
519 {
520 trackerState->currentPacket = Stream_New(NULL, 1024);
521 if (!trackerState->currentPacket)
522 {
523 WLog_Print(dynChannelContext->log, WLOG_ERROR,
524 "unable to create current packet");
525 return PF_CHANNEL_RESULT_ERROR;
526 }
527 }
528
529 if (!Stream_EnsureRemainingCapacity(trackerState->currentPacket, extraSize))
530 {
531 WLog_Print(dynChannelContext->log, WLOG_ERROR, "unable to grow current packet");
532 return PF_CHANNEL_RESULT_ERROR;
533 }
534
535 Stream_Write(trackerState->currentPacket, Stream_ConstPointer(s), extraSize);
536 }
537 WLog_Print(dynChannelContext->log, WLOG_DEBUG,
538 "DynvcTracker(%s [%s]): %s frags=%" PRIu32 " received=%" PRIu32 "(%" PRIu32 ")",
539 dynChannel->channelName, drdynvc_get_packet_type(cmd), direction,
540 trackerState->CurrentDataFragments, trackerState->CurrentDataReceived,
541 trackerState->currentDataLength);
542 }
543
544 if (cmd == DATA_PDU)
545 {
546 if (trackerState->currentDataLength)
547 {
548 if (trackerState->CurrentDataReceived > trackerState->currentDataLength)
549 {
550 WLog_Print(dynChannelContext->log, WLOG_ERROR,
551 "DynvcTracker (%s [%s]): reassembled packet (%" PRIu32
552 ") is bigger than announced length (%" PRIu32 ")",
553 dynChannel->channelName, drdynvc_get_packet_type(cmd),
554 trackerState->CurrentDataReceived, trackerState->currentDataLength);
555 return PF_CHANNEL_RESULT_ERROR;
556 }
557 }
558 else
559 {
560 trackerState->CurrentDataFragments = 0;
561 trackerState->CurrentDataReceived = 0;
562 }
563 }
564
565 PfChannelResult result = PF_CHANNEL_RESULT_ERROR;
566 switch (dynChannel->channelMode)
567 {
568 case PF_UTILS_CHANNEL_PASSTHROUGH:
569 result = channelTracker_flushCurrent(tracker, firstPacket, lastPacket, !isBackData);
570 break;
571 case PF_UTILS_CHANNEL_BLOCK:
572 channelTracker_setMode(tracker, CHANNEL_TRACKER_DROP);
573 result = PF_CHANNEL_RESULT_DROP;
574 break;
575 case PF_UTILS_CHANNEL_INTERCEPT:
576 if (trackerState->dataCallback)
577 {
578 result = trackerState->dataCallback(pdata->ps, dynChannel, isBackData, tracker,
579 firstPacket, lastPacket);
580 }
581 else
582 {
583 WLog_Print(dynChannelContext->log, WLOG_ERROR,
584 "no intercept callback for channel %s(fromBack=%d), dropping packet",
585 dynChannel->channelName, isBackData);
586 result = PF_CHANNEL_RESULT_DROP;
587 }
588 break;
589 default:
590 WLog_Print(dynChannelContext->log, WLOG_ERROR, "unknown channel mode %d",
591 dynChannel->channelMode);
592 result = PF_CHANNEL_RESULT_ERROR;
593 break;
594 }
595
596 if (!trackerState->currentDataLength ||
597 (trackerState->CurrentDataReceived == trackerState->currentDataLength))
598 {
599 trackerState->currentDataLength = 0;
600 trackerState->CurrentDataFragments = 0;
601 trackerState->CurrentDataReceived = 0;
602
603 if (dynChannel->packetReassembly && trackerState->currentPacket)
604 Stream_SetPosition(trackerState->currentPacket, 0);
605 }
606
607 return result;
608}
609
610static void DynChannelContext_free(void* context)
611{
612 DynChannelContext* c = context;
613 if (!c)
614 return;
615 channelTracker_free(c->backTracker);
616 channelTracker_free(c->frontTracker);
617 HashTable_Free(c->channels);
618 free(c);
619}
620
621static const char* dynamic_context(void* arg)
622{
623 proxyData* pdata = arg;
624 if (!pdata)
625 return "pdata=null";
626 return pdata->session_id;
627}
628
629static DynChannelContext* DynChannelContext_new(proxyData* pdata,
630 pServerStaticChannelContext* channel)
631{
632 DynChannelContext* dyn = calloc(1, sizeof(DynChannelContext));
633 if (!dyn)
634 return NULL;
635
636 dyn->log = WLog_Get(DTAG);
637 WINPR_ASSERT(dyn->log);
638 WLog_SetContext(dyn->log, dynamic_context, pdata);
639
640 dyn->backTracker = channelTracker_new(channel, DynvcTrackerPeekFn, dyn);
641 if (!dyn->backTracker)
642 goto fail;
643 if (!channelTracker_setPData(dyn->backTracker, pdata))
644 goto fail;
645
646 dyn->frontTracker = channelTracker_new(channel, DynvcTrackerPeekFn, dyn);
647 if (!dyn->frontTracker)
648 goto fail;
649 if (!channelTracker_setPData(dyn->frontTracker, pdata))
650 goto fail;
651
652 dyn->channels = HashTable_New(FALSE);
653 if (!dyn->channels)
654 goto fail;
655
656 if (!HashTable_SetHashFunction(dyn->channels, ChannelId_Hash))
657 goto fail;
658
659 wObject* kobj = HashTable_KeyObject(dyn->channels);
660 WINPR_ASSERT(kobj);
661 kobj->fnObjectEquals = ChannelId_Compare;
662
663 wObject* vobj = HashTable_ValueObject(dyn->channels);
664 WINPR_ASSERT(vobj);
665 vobj->fnObjectFree = DynamicChannelContext_free;
666
667 return dyn;
668
669fail:
670 DynChannelContext_free(dyn);
671 return NULL;
672}
673
674static PfChannelResult pf_dynvc_back_data(proxyData* pdata,
675 const pServerStaticChannelContext* channel,
676 const BYTE* xdata, size_t xsize, UINT32 flags,
677 size_t totalSize)
678{
679 WINPR_ASSERT(channel);
680
681 DynChannelContext* dyn = (DynChannelContext*)channel->context;
682 WINPR_UNUSED(pdata);
683 WINPR_ASSERT(dyn);
684
685 return channelTracker_update(dyn->backTracker, xdata, xsize, flags, totalSize);
686}
687
688static PfChannelResult pf_dynvc_front_data(proxyData* pdata,
689 const pServerStaticChannelContext* channel,
690 const BYTE* xdata, size_t xsize, UINT32 flags,
691 size_t totalSize)
692{
693 WINPR_ASSERT(channel);
694
695 DynChannelContext* dyn = (DynChannelContext*)channel->context;
696 WINPR_UNUSED(pdata);
697 WINPR_ASSERT(dyn);
698
699 return channelTracker_update(dyn->frontTracker, xdata, xsize, flags, totalSize);
700}
701
702BOOL pf_channel_setup_drdynvc(proxyData* pdata, pServerStaticChannelContext* channel)
703{
704 DynChannelContext* ret = DynChannelContext_new(pdata, channel);
705 if (!ret)
706 return FALSE;
707
708 channel->onBackData = pf_dynvc_back_data;
709 channel->onFrontData = pf_dynvc_front_data;
710 channel->contextDtor = DynChannelContext_free;
711 channel->context = ret;
712 return TRUE;
713}
This struct contains function pointer to initialize/free objects.
Definition collections.h:57