FreeRDP
Loading...
Searching...
No Matches
channel_pdu_tracker.c
1
20#include <freerdp/utils/channel_pdu_tracker.h>
21
22#include <winpr/wtsapi.h>
23
24#include <freerdp/log.h>
25#define TTAG FREERDP_TAG("utils.ChannelPduTracker")
26
27struct ChannelPduTracker
28{
29 HANDLE vc;
30 wStream* currentPacket;
31 char buffer[CHANNEL_PDU_LENGTH];
32 size_t offset;
33 wLog* log;
34};
35
36wStream* ChannelPduTracker_poll(ChannelPduTracker* tracker, BOOL* ok)
37{
38 WINPR_ASSERT(tracker);
39 WINPR_ASSERT(ok);
40
41 ULONG sz = 0;
42 *ok = FALSE;
43
44 WINPR_ASSERT(tracker->offset <= CHANNEL_PDU_LENGTH);
45 const ULONG readSz = WINPR_ASSERTING_INT_CAST(ULONG, CHANNEL_PDU_LENGTH - tracker->offset);
46 if (!WTSVirtualChannelRead(tracker->vc, INFINITE, &tracker->buffer[tracker->offset], readSz,
47 &sz))
48 return nullptr;
49
50 tracker->offset += sz;
51 WINPR_ASSERT(tracker->offset <= CHANNEL_PDU_LENGTH);
52
53 const size_t recvSz = tracker->offset;
54 if (recvSz < sizeof(CHANNEL_PDU_HEADER))
55 {
56 *ok = TRUE;
57 return nullptr;
58 }
59
60 const CHANNEL_PDU_HEADER* header =
61 WINPR_PACKED_ALIGN_CAST(const CHANNEL_PDU_HEADER*, tracker->buffer);
62 if (header->length > CHANNEL_CHUNK_LENGTH)
63 {
64 WLog_Print(tracker->log, WLOG_ERROR, "chunk size %" PRIu32 " is too big", header->length);
65 return nullptr;
66 }
67
68 const size_t actual = recvSz - sizeof(CHANNEL_PDU_HEADER);
69 if (actual != header->length)
70 {
71 WLog_Print(tracker->log, WLOG_ERROR,
72 "Expected chunk size %" PRIu32 " does not match received data size %" PRIuz,
73 header->length, actual);
74 return nullptr;
75 }
76
77 tracker->offset = 0;
78 if ((header->flags & CHANNEL_FLAG_FIRST) != 0)
79 Stream_ResetPosition(tracker->currentPacket);
80
81 if (!Stream_EnsureRemainingCapacity(tracker->currentPacket, header->length))
82 return nullptr;
83
84 Stream_Write(tracker->currentPacket, &tracker->buffer[sizeof(CHANNEL_PDU_HEADER)],
85 header->length);
86
87 if ((header->flags & CHANNEL_FLAG_LAST) == 0)
88 {
89 *ok = TRUE;
90 return nullptr;
91 }
92
93 Stream_SealLength(tracker->currentPacket);
94 Stream_ResetPosition(tracker->currentPacket);
95 wStream* ret = tracker->currentPacket;
96
97 tracker->currentPacket = Stream_New(nullptr, 4096);
98 if (!tracker->currentPacket)
99 {
100 Stream_Release(ret);
101 WLog_Print(tracker->log, WLOG_ERROR, "error allocating new currentPacket");
102 return nullptr;
103 }
104
105 *ok = TRUE;
106 return ret;
107}
108
109void ChannelPduTracker_free(ChannelPduTracker* tracker)
110{
111 if (!tracker)
112 return;
113
114 Stream_Release(tracker->currentPacket);
115 free(tracker);
116}
117
118ChannelPduTracker* ChannelPduTracker_new(HANDLE vc)
119{
120 ChannelPduTracker* ret = calloc(1, sizeof(*ret));
121 if (!ret)
122 return nullptr;
123
124 ret->currentPacket = Stream_New(nullptr, 4096);
125 if (!ret->currentPacket)
126 goto fail;
127
128 ret->vc = vc;
129 ret->log = WLog_Get(TTAG);
130 if (!ret->log)
131 goto fail;
132 return ret;
133fail:
134 ChannelPduTracker_free(ret);
135 return nullptr;
136}