FreeRDP
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 
33 typedef enum
34 {
35  CHANNEL_OPENSTATE_WAITING_OPEN_STATUS,
36  CHANNEL_OPENSTATE_OPENED,
37  CHANNEL_OPENSTATE_CLOSED
38 } PfDynChannelOpenStatus;
39 
40 typedef struct p_server_dynamic_channel_context pServerDynamicChannelContext;
41 typedef struct DynChannelTrackerState DynChannelTrackerState;
42 
43 typedef PfChannelResult (*dynamic_channel_on_data_fn)(pServerContext* ps,
44  pServerDynamicChannelContext* channel,
45  BOOL isBackData, ChannelStateTracker* tracker,
46  BOOL firstPacket, BOOL lastPacket);
47 
49 struct DynChannelTrackerState
50 {
51  UINT32 currentDataLength;
52  UINT32 CurrentDataReceived;
53  UINT32 CurrentDataFragments;
54  wStream* currentPacket;
55  dynamic_channel_on_data_fn dataCallback;
56 };
57 
58 typedef void (*channel_data_dtor_fn)(void** user_data);
59 
60 struct 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 
75 typedef struct
76 {
77  wHashTable* channels;
78  ChannelStateTracker* backTracker;
79  ChannelStateTracker* frontTracker;
80  wLog* log;
81 } DynChannelContext;
82 
84 typedef enum
85 {
86  DYNCVC_READ_OK,
87  DYNCVC_READ_ERROR,
88  DYNCVC_READ_INCOMPLETE
89 } DynvcReadResult;
90 
91 static 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 
106 static 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 
135 static 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 
171 static 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 
190 static UINT32 ChannelId_Hash(const void* key)
191 {
192  const UINT32* v = (const UINT32*)key;
193  return *v;
194 }
195 
196 static 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 
203 static 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 
232 static 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 += 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 
610 static 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 
621 static 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 
629 static DynChannelContext* DynChannelContext_new(proxyData* pdata,
630  pServerStaticChannelContext* channel)
631 {
632  DynChannelContext* dyn = calloc(1, sizeof(DynChannelContext));
633  if (!dyn)
634  return FALSE;
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 
669 fail:
670  DynChannelContext_free(dyn);
671  return NULL;
672 }
673 
674 static 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 
688 static 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 
702 BOOL 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