/src/FreeRDP/libfreerdp/core/autodetect.c
Line | Count | Source |
1 | | /** |
2 | | * FreeRDP: A Remote Desktop Protocol Implementation |
3 | | * Auto-Detect PDUs |
4 | | * |
5 | | * Copyright 2014 Dell Software <Mike.McDonald@software.dell.com> |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <freerdp/config.h> |
21 | | |
22 | | #include <winpr/crypto.h> |
23 | | #include <winpr/assert.h> |
24 | | |
25 | | #include "autodetect.h" |
26 | | #include "multitransport.h" |
27 | | |
28 | 7.14k | #define TYPE_ID_AUTODETECT_REQUEST 0x00 |
29 | 4.56k | #define TYPE_ID_AUTODETECT_RESPONSE 0x01 |
30 | | |
31 | 264 | #define RDP_RTT_REQUEST_TYPE_CONTINUOUS 0x0001 |
32 | 201 | #define RDP_RTT_REQUEST_TYPE_CONNECTTIME 0x1001 |
33 | | |
34 | 1.20k | #define RDP_RTT_RESPONSE_TYPE 0x0000 |
35 | | |
36 | 31 | #define RDP_BW_START_REQUEST_TYPE_CONTINUOUS 0x0014 |
37 | 28 | #define RDP_BW_START_REQUEST_TYPE_TUNNEL 0x0114 |
38 | 26 | #define RDP_BW_START_REQUEST_TYPE_CONNECTTIME 0x1014 |
39 | 122 | #define RDP_BW_PAYLOAD_REQUEST_TYPE 0x0002 |
40 | 290 | #define RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME 0x002B |
41 | 198 | #define RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS 0x0429 |
42 | 111 | #define RDP_BW_STOP_REQUEST_TYPE_TUNNEL 0x0629 |
43 | | |
44 | 36 | #define RDP_NETCHAR_SYNC_RESPONSE_TYPE 0x0018 |
45 | | |
46 | 102 | #define RDP_NETCHAR_RESULTS_0x0840 0x0840U |
47 | 134 | #define RDP_NETCHAR_RESULTS_0x0880 0x0880U |
48 | 130 | #define RDP_NETCHAR_RESULTS_0x08C0 0x08C0U |
49 | | |
50 | | typedef struct |
51 | | { |
52 | | UINT8 headerLength; |
53 | | UINT8 headerTypeId; |
54 | | UINT16 sequenceNumber; |
55 | | UINT16 requestType; |
56 | | } AUTODETECT_REQ_PDU; |
57 | | |
58 | | typedef struct |
59 | | { |
60 | | UINT8 headerLength; |
61 | | UINT8 headerTypeId; |
62 | | UINT16 sequenceNumber; |
63 | | UINT16 responseType; |
64 | | } AUTODETECT_RSP_PDU; |
65 | | |
66 | | static const char* autodetect_header_type_string(UINT8 headerType, char* buffer, size_t size) |
67 | 6.78k | { |
68 | 6.78k | const char* str = nullptr; |
69 | 6.78k | switch (headerType) |
70 | 6.78k | { |
71 | 2.06k | case TYPE_ID_AUTODETECT_REQUEST: |
72 | 2.06k | str = "TYPE_ID_AUTODETECT_REQUEST"; |
73 | 2.06k | break; |
74 | 105 | case TYPE_ID_AUTODETECT_RESPONSE: |
75 | 105 | str = "TYPE_ID_AUTODETECT_RESPONSE"; |
76 | 105 | break; |
77 | 4.61k | default: |
78 | 4.61k | str = "TYPE_ID_AUTODETECT_UNKNOWN"; |
79 | 4.61k | break; |
80 | 6.78k | } |
81 | | |
82 | 6.78k | (void)_snprintf(buffer, size, "%s [0x%08" PRIx8 "]", str, headerType); |
83 | 6.78k | return buffer; |
84 | 6.78k | } |
85 | | |
86 | | static const char* autodetect_request_type_to_string(UINT32 requestType) |
87 | 6.78k | { |
88 | 6.78k | switch (requestType) |
89 | 6.78k | { |
90 | 1.14k | case RDP_RTT_RESPONSE_TYPE: |
91 | 1.14k | return "RDP_RTT_RESPONSE_TYPE"; |
92 | 34 | case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME: |
93 | 34 | return "RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME"; |
94 | 9 | case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS: |
95 | 9 | return "RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS"; |
96 | 72 | case RDP_RTT_REQUEST_TYPE_CONTINUOUS: |
97 | 72 | return "RDP_RTT_REQUEST_TYPE_CONTINUOUS"; |
98 | 6 | case RDP_RTT_REQUEST_TYPE_CONNECTTIME: |
99 | 6 | return "RDP_RTT_REQUEST_TYPE_CONNECTTIME"; |
100 | 19 | case RDP_BW_START_REQUEST_TYPE_CONTINUOUS: |
101 | 19 | return "RDP_BW_START_REQUEST_TYPE_CONTINUOUS"; |
102 | 14 | case RDP_BW_START_REQUEST_TYPE_TUNNEL: |
103 | 14 | return "RDP_BW_START_REQUEST_TYPE_TUNNEL"; |
104 | 6 | case RDP_BW_START_REQUEST_TYPE_CONNECTTIME: |
105 | 6 | return "RDP_BW_START_REQUEST_TYPE_CONNECTTIME"; |
106 | 34 | case RDP_BW_PAYLOAD_REQUEST_TYPE: |
107 | 34 | return "RDP_BW_PAYLOAD_REQUEST_TYPE"; |
108 | 6 | case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME: |
109 | 6 | return "RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME"; |
110 | 9 | case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS: |
111 | 9 | return "RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS"; |
112 | 6 | case RDP_BW_STOP_REQUEST_TYPE_TUNNEL: |
113 | 6 | return "RDP_BW_STOP_REQUEST_TYPE_TUNNEL"; |
114 | 10 | case RDP_NETCHAR_RESULTS_0x0840: |
115 | 10 | return "RDP_NETCHAR_RESULTS_0x0840"; |
116 | 6 | case RDP_NETCHAR_RESULTS_0x0880: |
117 | 6 | return "RDP_NETCHAR_RESULTS_0x0880"; |
118 | 15 | case RDP_NETCHAR_RESULTS_0x08C0: |
119 | 15 | return "RDP_NETCHAR_RESULTS_0x08C0"; |
120 | 5.39k | default: |
121 | 5.39k | return "UNKNOWN"; |
122 | 6.78k | } |
123 | 6.78k | } |
124 | | |
125 | | static const char* autodetect_request_type_to_string_buffer(UINT32 requestType, char* buffer, |
126 | | size_t size) |
127 | 6.78k | { |
128 | 6.78k | const char* str = autodetect_request_type_to_string(requestType); |
129 | 6.78k | (void)_snprintf(buffer, size, "%s [0x%08" PRIx32 "]", str, requestType); |
130 | 6.78k | return buffer; |
131 | 6.78k | } |
132 | | |
133 | | static BOOL autodetect_send_rtt_measure_request(rdpAutoDetect* autodetect, |
134 | | WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport, |
135 | | UINT16 sequenceNumber) |
136 | 0 | { |
137 | 0 | UINT16 requestType = 0; |
138 | 0 | UINT16 sec_flags = 0; |
139 | 0 | wStream* s = nullptr; |
140 | |
|
141 | 0 | WINPR_ASSERT(autodetect); |
142 | 0 | WINPR_ASSERT(autodetect->context); |
143 | |
|
144 | 0 | s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags); |
145 | 0 | if (!s) |
146 | 0 | return FALSE; |
147 | | |
148 | 0 | if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE) |
149 | 0 | requestType = RDP_RTT_REQUEST_TYPE_CONNECTTIME; |
150 | 0 | else |
151 | 0 | requestType = RDP_RTT_REQUEST_TYPE_CONTINUOUS; |
152 | |
|
153 | 0 | WLog_Print(autodetect->log, WLOG_TRACE, "sending RTT Measure Request PDU"); |
154 | 0 | Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */ |
155 | 0 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */ |
156 | 0 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
157 | 0 | Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */ |
158 | 0 | autodetect->rttMeasureStartTime = GetTickCount64(); |
159 | 0 | return rdp_send_message_channel_pdu(autodetect->context->rdp, s, |
160 | 0 | sec_flags | SEC_AUTODETECT_REQ); |
161 | 0 | } |
162 | | |
163 | | static BOOL autodetect_send_rtt_measure_response(rdpAutoDetect* autodetect, UINT16 sequenceNumber) |
164 | 3 | { |
165 | 3 | UINT16 sec_flags = 0; |
166 | 3 | wStream* s = nullptr; |
167 | | |
168 | 3 | WINPR_ASSERT(autodetect); |
169 | 3 | WINPR_ASSERT(autodetect->context); |
170 | | |
171 | | /* Send the response PDU to the server */ |
172 | 3 | s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags); |
173 | | |
174 | 3 | if (!s) |
175 | 0 | return FALSE; |
176 | | |
177 | 3 | WLog_Print(autodetect->log, WLOG_TRACE, |
178 | 3 | "sending RTT Measure Response PDU (seqNumber=0x%" PRIx16 ")", sequenceNumber); |
179 | 3 | Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */ |
180 | 3 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */ |
181 | 3 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
182 | 3 | Stream_Write_UINT16(s, RDP_RTT_RESPONSE_TYPE); /* responseType (1 byte) */ |
183 | 3 | return rdp_send_message_channel_pdu(autodetect->context->rdp, s, |
184 | 3 | sec_flags | SEC_AUTODETECT_RSP); |
185 | 3 | } |
186 | | |
187 | | static BOOL autodetect_send_netchar_sync(rdpAutoDetect* autodetect, UINT16 sequenceNumber) |
188 | 0 | { |
189 | 0 | UINT16 sec_flags = 0; |
190 | |
|
191 | 0 | WINPR_ASSERT(autodetect); |
192 | 0 | WINPR_ASSERT(autodetect->context); |
193 | |
|
194 | 0 | wStream* s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags); |
195 | 0 | if (!s) |
196 | 0 | return FALSE; |
197 | | |
198 | 0 | WLog_Print(autodetect->log, WLOG_TRACE, |
199 | 0 | "sending Network Characteristics Sync PDU -> bandwidth=%" PRIu32 ", rtt=%" PRIu32, |
200 | 0 | autodetect->netCharBandwidth, autodetect->netCharAverageRTT); |
201 | 0 | Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */ |
202 | 0 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */ |
203 | 0 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
204 | 0 | Stream_Write_UINT16(s, RDP_NETCHAR_SYNC_RESPONSE_TYPE); /* responseType (2 bytes) */ |
205 | 0 | Stream_Write_UINT32(s, autodetect->netCharBandwidth); /* bandwidth (4 bytes) */ |
206 | 0 | Stream_Write_UINT32(s, autodetect->netCharAverageRTT); /* rtt (4 bytes) */ |
207 | 0 | return rdp_send_message_channel_pdu(autodetect->context->rdp, s, |
208 | 0 | sec_flags | SEC_AUTODETECT_RSP); |
209 | 0 | } |
210 | | |
211 | | static BOOL autodetect_send_bandwidth_measure_start(rdpAutoDetect* autodetect, |
212 | | WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport, |
213 | | UINT16 sequenceNumber) |
214 | 0 | { |
215 | 0 | UINT16 requestType = 0; |
216 | 0 | UINT16 sec_flags = 0; |
217 | 0 | wStream* s = nullptr; |
218 | |
|
219 | 0 | WINPR_ASSERT(autodetect); |
220 | 0 | WINPR_ASSERT(autodetect->context); |
221 | |
|
222 | 0 | s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags); |
223 | 0 | if (!s) |
224 | 0 | return FALSE; |
225 | | |
226 | 0 | if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE) |
227 | 0 | requestType = RDP_BW_START_REQUEST_TYPE_CONNECTTIME; |
228 | 0 | else |
229 | 0 | requestType = RDP_BW_START_REQUEST_TYPE_CONTINUOUS; |
230 | |
|
231 | 0 | WLog_Print(autodetect->log, WLOG_TRACE, |
232 | 0 | "sending Bandwidth Measure Start PDU(seqNumber=%" PRIu16 ")", sequenceNumber); |
233 | 0 | Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */ |
234 | 0 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */ |
235 | 0 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
236 | 0 | Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */ |
237 | 0 | return rdp_send_message_channel_pdu(autodetect->context->rdp, s, |
238 | 0 | sec_flags | SEC_AUTODETECT_REQ); |
239 | 0 | } |
240 | | |
241 | | static BOOL |
242 | | autodetect_send_bandwidth_measure_payload(rdpAutoDetect* autodetect, |
243 | | WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport, |
244 | | UINT16 sequenceNumber, UINT16 payloadLength) |
245 | 0 | { |
246 | 0 | UINT16 sec_flags = 0; |
247 | 0 | wStream* s = nullptr; |
248 | |
|
249 | 0 | WINPR_ASSERT(autodetect); |
250 | 0 | WINPR_ASSERT(autodetect->context); |
251 | |
|
252 | 0 | WINPR_ASSERT(freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE); |
253 | |
|
254 | 0 | s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags); |
255 | 0 | if (!s) |
256 | 0 | return FALSE; |
257 | | |
258 | 0 | WLog_Print(autodetect->log, WLOG_TRACE, |
259 | 0 | "sending Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16 "", payloadLength); |
260 | | /* 4-bytes aligned */ |
261 | 0 | payloadLength &= ~3; |
262 | |
|
263 | 0 | if (!Stream_EnsureRemainingCapacity(s, 8ull + payloadLength)) |
264 | 0 | { |
265 | 0 | WLog_Print(autodetect->log, WLOG_ERROR, "Failed to ensure %lu bytes in stream", |
266 | 0 | 8ul + payloadLength); |
267 | 0 | Stream_Release(s); |
268 | 0 | return FALSE; |
269 | 0 | } |
270 | | |
271 | 0 | Stream_Write_UINT8(s, 0x08); /* headerLength (1 byte) */ |
272 | 0 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */ |
273 | 0 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
274 | 0 | Stream_Write_UINT16(s, RDP_BW_PAYLOAD_REQUEST_TYPE); /* requestType (2 bytes) */ |
275 | 0 | Stream_Write_UINT16(s, payloadLength); /* payloadLength (2 bytes) */ |
276 | | /* Random data (better measurement in case the line is compressed) */ |
277 | 0 | if (winpr_RAND(Stream_Pointer(s), payloadLength) < 0) |
278 | 0 | { |
279 | 0 | Stream_Release(s); |
280 | 0 | return FALSE; |
281 | 0 | } |
282 | 0 | Stream_Seek(s, payloadLength); |
283 | 0 | return rdp_send_message_channel_pdu(autodetect->context->rdp, s, |
284 | 0 | sec_flags | SEC_AUTODETECT_REQ); |
285 | 0 | } |
286 | | |
287 | | static BOOL autodetect_send_bandwidth_measure_stop(rdpAutoDetect* autodetect, |
288 | | WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport, |
289 | | UINT16 sequenceNumber, UINT16 payloadLength) |
290 | 0 | { |
291 | 0 | UINT16 requestType = 0; |
292 | 0 | UINT16 sec_flags = 0; |
293 | 0 | wStream* s = nullptr; |
294 | |
|
295 | 0 | WINPR_ASSERT(autodetect); |
296 | 0 | WINPR_ASSERT(autodetect->context); |
297 | |
|
298 | 0 | s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags); |
299 | 0 | if (!s) |
300 | 0 | return FALSE; |
301 | | |
302 | 0 | if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE) |
303 | 0 | requestType = RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME; |
304 | 0 | else |
305 | 0 | requestType = RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS; |
306 | |
|
307 | 0 | if (requestType == RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS) |
308 | 0 | payloadLength = 0; |
309 | |
|
310 | 0 | WLog_Print(autodetect->log, WLOG_TRACE, |
311 | 0 | "sending Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16 "", payloadLength); |
312 | | /* 4-bytes aligned */ |
313 | 0 | payloadLength &= ~3; |
314 | 0 | Stream_Write_UINT8(s, requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME |
315 | 0 | ? 0x08 |
316 | 0 | : 0x06); /* headerLength (1 byte) */ |
317 | 0 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */ |
318 | 0 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
319 | 0 | Stream_Write_UINT16(s, requestType); /* requestType (2 bytes) */ |
320 | |
|
321 | 0 | if (requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME) |
322 | 0 | { |
323 | 0 | Stream_Write_UINT16(s, payloadLength); /* payloadLength (2 bytes) */ |
324 | |
|
325 | 0 | if (payloadLength > 0) |
326 | 0 | { |
327 | 0 | if (!Stream_EnsureRemainingCapacity(s, payloadLength)) |
328 | 0 | { |
329 | 0 | WLog_Print(autodetect->log, WLOG_ERROR, |
330 | 0 | "Failed to ensure %" PRIu16 " bytes in stream", payloadLength); |
331 | 0 | Stream_Release(s); |
332 | 0 | return FALSE; |
333 | 0 | } |
334 | | |
335 | | /* Random data (better measurement in case the line is compressed) */ |
336 | 0 | if (winpr_RAND(Stream_Pointer(s), payloadLength) < 0) |
337 | 0 | { |
338 | 0 | Stream_Release(s); |
339 | 0 | return FALSE; |
340 | 0 | } |
341 | 0 | Stream_Seek(s, payloadLength); |
342 | 0 | } |
343 | 0 | } |
344 | | |
345 | 0 | return rdp_send_message_channel_pdu(autodetect->context->rdp, s, |
346 | 0 | sec_flags | SEC_AUTODETECT_REQ); |
347 | 0 | } |
348 | | |
349 | | /* [MS-RDPBCGR] 2.2.14.2.2 Bandwidth Measure Results (RDP_BW_RESULTS), 14 bytes */ |
350 | | static void autodetect_write_bandwidth_measure_results(const rdpAutoDetect* autodetect, wStream* s, |
351 | | UINT16 responseType, UINT16 sequenceNumber, |
352 | | UINT32 timeDelta) |
353 | 88 | { |
354 | 88 | WINPR_ASSERT(autodetect); |
355 | 88 | WINPR_ASSERT(s); |
356 | | |
357 | 88 | Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */ |
358 | 88 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */ |
359 | 88 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
360 | 88 | Stream_Write_UINT16(s, responseType); /* responseType (2 bytes) */ |
361 | 88 | Stream_Write_UINT32(s, timeDelta); /* timeDelta (4 bytes) */ |
362 | 88 | Stream_Write_UINT32(s, autodetect->bandwidthMeasureByteCount); /* byteCount (4 bytes) */ |
363 | 88 | } |
364 | | |
365 | | static BOOL autodetect_send_bandwidth_measure_results(rdpAutoDetect* autodetect, |
366 | | RDP_TRANSPORT_TYPE transport, |
367 | | UINT16 responseType, UINT16 sequenceNumber) |
368 | 88 | { |
369 | 88 | BOOL success = TRUE; |
370 | 88 | UINT16 sec_flags = 0; |
371 | 88 | UINT64 timeDelta = GetTickCount64(); |
372 | | |
373 | 88 | WINPR_ASSERT(autodetect); |
374 | 88 | WINPR_ASSERT(autodetect->context); |
375 | | |
376 | | /* Compute the total time */ |
377 | 88 | if (autodetect->bandwidthMeasureStartTime > timeDelta) |
378 | 0 | { |
379 | 0 | WLog_Print(autodetect->log, WLOG_WARN, |
380 | 0 | "Invalid bandwidthMeasureStartTime %" PRIu64 " > current %" PRIu64 |
381 | 0 | ", trimming to 0", |
382 | 0 | autodetect->bandwidthMeasureStartTime, timeDelta); |
383 | 0 | timeDelta = 0; |
384 | 0 | } |
385 | 88 | else |
386 | 88 | timeDelta -= autodetect->bandwidthMeasureStartTime; |
387 | | |
388 | 88 | const UINT32 delta = (UINT32)MIN(timeDelta, UINT32_MAX); |
389 | 88 | WLog_Print(autodetect->log, WLOG_TRACE, |
390 | 88 | "sending Bandwidth Measure Results PDU -> timeDelta=%" PRIu32 ", byteCount=%" PRIu32 |
391 | 88 | "%s", |
392 | 88 | delta, autodetect->bandwidthMeasureByteCount, |
393 | 88 | (transport == RDP_TRANSPORT_UDP_R) ? " in the UDP tunnel" : ""); |
394 | | |
395 | 88 | IFCALLRET(autodetect->ClientBandwidthMeasureResult, success, autodetect, transport, |
396 | 88 | responseType, sequenceNumber, delta, autodetect->bandwidthMeasureByteCount); |
397 | 88 | if (!success) |
398 | 0 | { |
399 | 0 | WLog_Print(autodetect->log, WLOG_ERROR, "ClientBandwidthMeasureResult failed"); |
400 | 0 | return FALSE; |
401 | 0 | } |
402 | | |
403 | | /* [MS-RDPBCGR] 3.2.5.17: a measurement stopped in a tunnel subheader is answered in one on |
404 | | * the same tunnel ([MS-RDPEMT] 2.2.1.1.1), all others on the main channel */ |
405 | 88 | if (transport == RDP_TRANSPORT_UDP_R) |
406 | 0 | { |
407 | 0 | BYTE buffer[0x0E] = WINPR_C_ARRAY_INIT; |
408 | 0 | wStream sbuffer = WINPR_C_ARRAY_INIT; |
409 | 0 | wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); |
410 | 0 | autodetect_write_bandwidth_measure_results(autodetect, s, responseType, sequenceNumber, |
411 | 0 | delta); |
412 | 0 | return multitransport_send_autodetect_response(autodetect->context->rdp->multitransport, |
413 | 0 | buffer, sizeof(buffer)); |
414 | 0 | } |
415 | | |
416 | 88 | wStream* s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags); |
417 | 88 | if (!s) |
418 | 0 | return FALSE; |
419 | 88 | autodetect_write_bandwidth_measure_results(autodetect, s, responseType, sequenceNumber, delta); |
420 | 88 | return rdp_send_message_channel_pdu(autodetect->context->rdp, s, |
421 | 88 | sec_flags | SEC_AUTODETECT_RSP); |
422 | 88 | } |
423 | | |
424 | | static BOOL autodetect_send_netchar_result(rdpAutoDetect* autodetect, |
425 | | WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport, |
426 | | UINT16 sequenceNumber, |
427 | | const rdpNetworkCharacteristicsResult* result) |
428 | 31 | { |
429 | 31 | UINT16 sec_flags = 0; |
430 | 31 | wStream* s = nullptr; |
431 | | |
432 | 31 | WINPR_ASSERT(autodetect); |
433 | 31 | WINPR_ASSERT(autodetect->context); |
434 | | |
435 | 31 | s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags); |
436 | | |
437 | 31 | if (!s) |
438 | 0 | return FALSE; |
439 | | |
440 | 31 | WLog_Print(autodetect->log, WLOG_TRACE, "sending Network Characteristics Result PDU"); |
441 | | |
442 | 31 | switch (result->type) |
443 | 31 | { |
444 | 7 | case RDP_NETCHAR_RESULT_TYPE_BASE_RTT_AVG_RTT: |
445 | 7 | Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */ |
446 | 7 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */ |
447 | 7 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
448 | 7 | WINPR_ASSERT((result->type <= UINT16_MAX)); |
449 | 7 | WINPR_ASSERT((result->type >= 0)); |
450 | 7 | Stream_Write_UINT16(s, (UINT16)result->type); /* requestType (2 bytes) */ |
451 | 7 | Stream_Write_UINT32(s, result->baseRTT); /* baseRTT (4 bytes) */ |
452 | 7 | Stream_Write_UINT32(s, result->averageRTT); /* averageRTT (4 bytes) */ |
453 | 7 | break; |
454 | 20 | case RDP_NETCHAR_RESULT_TYPE_BW_AVG_RTT: |
455 | 20 | Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */ |
456 | 20 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */ |
457 | 20 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
458 | 20 | WINPR_ASSERT((result->type <= UINT16_MAX)); |
459 | 20 | WINPR_ASSERT((result->type >= 0)); |
460 | 20 | Stream_Write_UINT16(s, (UINT16)result->type); /* requestType (2 bytes) */ |
461 | 20 | Stream_Write_UINT32(s, result->bandwidth); /* bandwidth (4 bytes) */ |
462 | 20 | Stream_Write_UINT32(s, result->averageRTT); /* averageRTT (4 bytes) */ |
463 | 20 | break; |
464 | 4 | case RDP_NETCHAR_RESULT_TYPE_BASE_RTT_BW_AVG_RTT: |
465 | 4 | Stream_Write_UINT8(s, 0x12); /* headerLength (1 byte) */ |
466 | 4 | Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST); /* headerTypeId (1 byte) */ |
467 | 4 | Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */ |
468 | 4 | WINPR_ASSERT((result->type <= UINT16_MAX)); |
469 | 4 | WINPR_ASSERT((result->type >= 0)); |
470 | 4 | Stream_Write_UINT16(s, (UINT16)result->type); /* requestType (2 bytes) */ |
471 | 4 | Stream_Write_UINT32(s, result->baseRTT); /* baseRTT (4 bytes) */ |
472 | 4 | Stream_Write_UINT32(s, result->bandwidth); /* bandwidth (4 bytes) */ |
473 | 4 | Stream_Write_UINT32(s, result->averageRTT); /* averageRTT (4 bytes) */ |
474 | 4 | break; |
475 | 0 | default: |
476 | 0 | WINPR_ASSERT(FALSE); |
477 | 0 | break; |
478 | 31 | } |
479 | | |
480 | 31 | return rdp_send_message_channel_pdu(autodetect->context->rdp, s, |
481 | 31 | sec_flags | SEC_AUTODETECT_REQ); |
482 | 31 | } |
483 | | |
484 | | static FREERDP_AUTODETECT_STATE |
485 | | autodetect_on_connect_time_auto_detect_begin_default(rdpAutoDetect* autodetect) |
486 | 0 | { |
487 | 0 | WINPR_ASSERT(autodetect); |
488 | 0 | WINPR_ASSERT(autodetect->RTTMeasureRequest); |
489 | |
|
490 | 0 | if (!autodetect->RTTMeasureRequest(autodetect, RDP_TRANSPORT_TCP, 0x23)) |
491 | 0 | return FREERDP_AUTODETECT_STATE_FAIL; |
492 | | |
493 | 0 | return FREERDP_AUTODETECT_STATE_REQUEST; |
494 | 0 | } |
495 | | |
496 | | static FREERDP_AUTODETECT_STATE |
497 | | autodetect_on_connect_time_auto_detect_progress_default(rdpAutoDetect* autodetect) |
498 | 0 | { |
499 | 0 | WINPR_ASSERT(autodetect); |
500 | |
|
501 | 0 | if (autodetect->state == FREERDP_AUTODETECT_STATE_RESPONSE || |
502 | 0 | autodetect->state == FREERDP_AUTODETECT_STATE_COMPLETE) |
503 | 0 | return FREERDP_AUTODETECT_STATE_COMPLETE; |
504 | | |
505 | 0 | return autodetect->state; |
506 | 0 | } |
507 | | |
508 | | static BOOL autodetect_recv_rtt_measure_request(rdpAutoDetect* autodetect, |
509 | | WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport, |
510 | | WINPR_ATTR_UNUSED wStream* s, |
511 | | const AUTODETECT_REQ_PDU* autodetectReqPdu) |
512 | 195 | { |
513 | 195 | WINPR_ASSERT(autodetect); |
514 | 195 | WINPR_ASSERT(s); |
515 | 195 | WINPR_ASSERT(autodetectReqPdu); |
516 | | |
517 | 195 | if (autodetectReqPdu->headerLength != 0x06) |
518 | 192 | { |
519 | 192 | WLog_Print(autodetect->log, WLOG_ERROR, |
520 | 192 | "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8 "]", |
521 | 192 | autodetectReqPdu->headerLength); |
522 | 192 | return FALSE; |
523 | 192 | } |
524 | | |
525 | 3 | WLog_Print(autodetect->log, WLOG_TRACE, "received RTT Measure Request PDU"); |
526 | | /* Send a response to the server */ |
527 | 3 | return autodetect_send_rtt_measure_response(autodetect, autodetectReqPdu->sequenceNumber); |
528 | 195 | } |
529 | | |
530 | | static BOOL autodetect_recv_rtt_measure_response(rdpAutoDetect* autodetect, |
531 | | RDP_TRANSPORT_TYPE transport, |
532 | | WINPR_ATTR_UNUSED wStream* s, |
533 | | const AUTODETECT_RSP_PDU* autodetectRspPdu) |
534 | 69 | { |
535 | 69 | BOOL success = TRUE; |
536 | | |
537 | 69 | WINPR_ASSERT(autodetect); |
538 | 69 | WINPR_ASSERT(autodetectRspPdu); |
539 | | |
540 | 69 | if (autodetectRspPdu->headerLength != 0x06) |
541 | 19 | { |
542 | 19 | WLog_Print(autodetect->log, WLOG_ERROR, |
543 | 19 | "autodetectRspPdu->headerLength != 0x06 [0x%02" PRIx8 "]", |
544 | 19 | autodetectRspPdu->headerLength); |
545 | 19 | return FALSE; |
546 | 19 | } |
547 | | |
548 | 50 | WLog_Print(autodetect->log, WLOG_TRACE, "received RTT Measure Response PDU"); |
549 | 50 | autodetect->netCharAverageRTT = |
550 | 50 | (UINT32)MIN(GetTickCount64() - autodetect->rttMeasureStartTime, UINT32_MAX); |
551 | | |
552 | 50 | if (autodetect->netCharBaseRTT == 0 || |
553 | 32 | autodetect->netCharBaseRTT > autodetect->netCharAverageRTT) |
554 | 42 | autodetect->netCharBaseRTT = autodetect->netCharAverageRTT; |
555 | | |
556 | 50 | IFCALLRET(autodetect->RTTMeasureResponse, success, autodetect, transport, |
557 | 50 | autodetectRspPdu->sequenceNumber); |
558 | 50 | if (!success) |
559 | 0 | WLog_Print(autodetect->log, WLOG_WARN, "RTTMeasureResponse failed"); |
560 | 50 | return success; |
561 | 69 | } |
562 | | |
563 | | static BOOL autodetect_recv_bandwidth_measure_start(rdpAutoDetect* autodetect, |
564 | | WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport, |
565 | | WINPR_ATTR_UNUSED wStream* s, |
566 | | const AUTODETECT_REQ_PDU* autodetectReqPdu) |
567 | 16 | { |
568 | 16 | WINPR_ASSERT(autodetect); |
569 | 16 | WINPR_ASSERT(s); |
570 | 16 | WINPR_ASSERT(autodetectReqPdu); |
571 | | |
572 | 16 | if (autodetectReqPdu->headerLength != 0x06) |
573 | 12 | { |
574 | 12 | WLog_Print(autodetect->log, WLOG_ERROR, |
575 | 12 | "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8 "]", |
576 | 12 | autodetectReqPdu->headerLength); |
577 | 12 | return FALSE; |
578 | 12 | } |
579 | | |
580 | 4 | WLog_Print(autodetect->log, WLOG_TRACE, |
581 | 4 | "received Bandwidth Measure Start PDU - time=%" PRIu64 "", GetTickCount64()); |
582 | | /* Initialize bandwidth measurement parameters */ |
583 | 4 | autodetect->bandwidthMeasureStartTime = GetTickCount64(); |
584 | 4 | autodetect->bandwidthMeasureByteCount = 0; |
585 | | |
586 | | /* [MS-RDPBCGR] 3.2.5.17: an auto-reconnect can answer the connect-time measurement with |
587 | | * the bandwidth and RTT the server reported before, which ends the measurement |
588 | | * ([MS-RDPBCGR] 2.2.14.2.3). */ |
589 | 4 | if ((autodetectReqPdu->requestType == RDP_BW_START_REQUEST_TYPE_CONNECTTIME) && |
590 | 1 | (autodetect->netCharBandwidth > 0)) |
591 | 0 | { |
592 | 0 | const ARC_SC_PRIVATE_PACKET* cookie = freerdp_settings_get_pointer( |
593 | 0 | autodetect->context->settings, FreeRDP_ServerAutoReconnectCookie); |
594 | 0 | if (cookie && (cookie->cbLen > 0)) |
595 | 0 | return autodetect_send_netchar_sync(autodetect, autodetectReqPdu->sequenceNumber); |
596 | 0 | } |
597 | | |
598 | | /* Continuous Auto-Detection: mark the start of the measurement */ |
599 | 4 | if (autodetectReqPdu->requestType == RDP_BW_START_REQUEST_TYPE_CONTINUOUS) |
600 | 2 | { |
601 | 2 | autodetect->bandwidthMeasureStarted = TRUE; |
602 | 2 | } |
603 | | |
604 | 4 | return TRUE; |
605 | 4 | } |
606 | | |
607 | | static BOOL |
608 | | autodetect_recv_bandwidth_measure_payload(rdpAutoDetect* autodetect, |
609 | | WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport, |
610 | | wStream* s, const AUTODETECT_REQ_PDU* autodetectReqPdu) |
611 | 88 | { |
612 | 88 | UINT16 payloadLength = 0; |
613 | | |
614 | 88 | WINPR_ASSERT(autodetect); |
615 | 88 | WINPR_ASSERT(s); |
616 | 88 | WINPR_ASSERT(autodetectReqPdu); |
617 | | |
618 | 88 | if (autodetectReqPdu->headerLength != 0x08) |
619 | 21 | { |
620 | 21 | WLog_Print(autodetect->log, WLOG_ERROR, |
621 | 21 | "autodetectReqPdu->headerLength != 0x08 [0x%02" PRIx8 "]", |
622 | 21 | autodetectReqPdu->headerLength); |
623 | 21 | return FALSE; |
624 | 21 | } |
625 | | |
626 | 67 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 2)) |
627 | 2 | return FALSE; |
628 | | |
629 | 65 | Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */ |
630 | 65 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, payloadLength)) |
631 | 3 | return FALSE; |
632 | 62 | Stream_Seek(s, payloadLength); |
633 | | |
634 | 62 | WLog_Print(autodetect->log, WLOG_DEBUG, |
635 | 62 | "received Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16 "", |
636 | 62 | payloadLength); |
637 | | /* Add the message to the bandwidth measurement parameters: Windows counts the whole |
638 | | * Bandwidth Measure Payload message, header included (mstsc reports 4000 bytes for a |
639 | | * 3992 byte payload), and ends the connect-time detection with a 5 s delay otherwise */ |
640 | 62 | autodetect->bandwidthMeasureByteCount += autodetectReqPdu->headerLength; |
641 | 62 | autodetect->bandwidthMeasureByteCount += payloadLength; |
642 | 62 | return TRUE; |
643 | 65 | } |
644 | | |
645 | | static BOOL autodetect_recv_bandwidth_measure_stop(rdpAutoDetect* autodetect, |
646 | | RDP_TRANSPORT_TYPE transport, wStream* s, |
647 | | const AUTODETECT_REQ_PDU* autodetectReqPdu) |
648 | 105 | { |
649 | 105 | UINT16 payloadLength = 0; |
650 | 105 | UINT16 responseType = 0; |
651 | | |
652 | 105 | WINPR_ASSERT(autodetect); |
653 | 105 | WINPR_ASSERT(s); |
654 | 105 | WINPR_ASSERT(autodetectReqPdu); |
655 | | |
656 | 105 | if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME) |
657 | 91 | { |
658 | 91 | if (autodetectReqPdu->headerLength != 0x08) |
659 | 8 | { |
660 | 8 | WLog_Print(autodetect->log, WLOG_ERROR, |
661 | 8 | "autodetectReqPdu->headerLength != 0x08 [0x%02" PRIx8 "]", |
662 | 8 | autodetectReqPdu->headerLength); |
663 | 8 | return FALSE; |
664 | 8 | } |
665 | | |
666 | 83 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 2)) |
667 | 2 | return FALSE; |
668 | | |
669 | 81 | Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */ |
670 | 81 | } |
671 | 14 | else |
672 | 14 | { |
673 | 14 | if (autodetectReqPdu->headerLength != 0x06) |
674 | 4 | { |
675 | 4 | WLog_Print(autodetect->log, WLOG_ERROR, |
676 | 4 | "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8 "]", |
677 | 4 | autodetectReqPdu->headerLength); |
678 | 4 | return FALSE; |
679 | 4 | } |
680 | | |
681 | 10 | payloadLength = 0; |
682 | 10 | } |
683 | | |
684 | 91 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, payloadLength)) |
685 | 3 | return FALSE; |
686 | 88 | Stream_Seek(s, payloadLength); |
687 | | |
688 | 88 | WLog_Print(autodetect->log, WLOG_TRACE, |
689 | 88 | "received Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16 "", payloadLength); |
690 | | /* Add the payload to the bandwidth measurement parameters, with its header as for a |
691 | | * Bandwidth Measure Payload message (see autodetect_recv_bandwidth_measure_payload) */ |
692 | 88 | if (payloadLength > 0) |
693 | 27 | { |
694 | 27 | autodetect->bandwidthMeasureByteCount += autodetectReqPdu->headerLength; |
695 | 27 | autodetect->bandwidthMeasureByteCount += payloadLength; |
696 | 27 | } |
697 | | |
698 | | /* Continuous Auto-Detection: mark the stop of the measurement */ |
699 | 88 | if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS) |
700 | 7 | { |
701 | 7 | autodetect->bandwidthMeasureStarted = FALSE; |
702 | 7 | } |
703 | | |
704 | | /* Send a response the server */ |
705 | 88 | responseType = autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME |
706 | 88 | ? RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME |
707 | 88 | : RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS; |
708 | 88 | return autodetect_send_bandwidth_measure_results(autodetect, transport, responseType, |
709 | 88 | autodetectReqPdu->sequenceNumber); |
710 | 91 | } |
711 | | |
712 | | static BOOL autodetect_recv_bandwidth_measure_results(rdpAutoDetect* autodetect, |
713 | | RDP_TRANSPORT_TYPE transport, wStream* s, |
714 | | const AUTODETECT_RSP_PDU* autodetectRspPdu) |
715 | 28 | { |
716 | 28 | UINT32 timeDelta = 0; |
717 | 28 | UINT32 byteCount = 0; |
718 | 28 | BOOL success = TRUE; |
719 | | |
720 | 28 | WINPR_ASSERT(autodetect); |
721 | 28 | WINPR_ASSERT(s); |
722 | 28 | WINPR_ASSERT(autodetectRspPdu); |
723 | | |
724 | 28 | if (autodetectRspPdu->headerLength != 0x0E) |
725 | 19 | { |
726 | 19 | WLog_Print(autodetect->log, WLOG_ERROR, |
727 | 19 | "autodetectRspPdu->headerLength != 0x0E [0x%02" PRIx8 "]", |
728 | 19 | autodetectRspPdu->headerLength); |
729 | 19 | return FALSE; |
730 | 19 | } |
731 | | |
732 | 9 | WLog_Print(autodetect->log, WLOG_TRACE, "received Bandwidth Measure Results PDU"); |
733 | 9 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8)) |
734 | 2 | return FALSE; |
735 | 7 | Stream_Read_UINT32(s, timeDelta); /* timeDelta (4 bytes) */ |
736 | 7 | Stream_Read_UINT32(s, byteCount); /* byteCount (4 bytes) */ |
737 | | |
738 | 7 | IFCALLRET(autodetect->BandwidthMeasureResults, success, autodetect, transport, |
739 | 7 | autodetectRspPdu->sequenceNumber, autodetectRspPdu->responseType, timeDelta, |
740 | 7 | byteCount); |
741 | 7 | if (!success) |
742 | 0 | WLog_Print(autodetect->log, WLOG_WARN, "BandwidthMeasureResults failed"); |
743 | 7 | return success; |
744 | 9 | } |
745 | | |
746 | | static BOOL autodetect_recv_netchar_sync(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport, |
747 | | wStream* s, const AUTODETECT_RSP_PDU* autodetectRspPdu) |
748 | 36 | { |
749 | 36 | UINT32 bandwidth = 0; |
750 | 36 | UINT32 rtt = 0; |
751 | 36 | BOOL success = TRUE; |
752 | | |
753 | 36 | WINPR_ASSERT(autodetect); |
754 | 36 | WINPR_ASSERT(s); |
755 | 36 | WINPR_ASSERT(autodetectRspPdu); |
756 | | |
757 | 36 | if (autodetectRspPdu->headerLength != 0x0E) |
758 | 7 | { |
759 | 7 | WLog_Print(autodetect->log, WLOG_ERROR, |
760 | 7 | "autodetectRspPdu->headerLength != 0x0E [0x%02" PRIx8 "]", |
761 | 7 | autodetectRspPdu->headerLength); |
762 | 7 | return FALSE; |
763 | 7 | } |
764 | 29 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8)) |
765 | 2 | return FALSE; |
766 | | |
767 | | /* bandwidth and averageRTT fields are present (baseRTT field is not) */ |
768 | 27 | Stream_Read_UINT32(s, bandwidth); /* bandwidth (4 bytes) */ |
769 | 27 | Stream_Read_UINT32(s, rtt); /* rtt (4 bytes) */ |
770 | | |
771 | 27 | WLog_Print(autodetect->log, WLOG_TRACE, |
772 | 27 | "received Network Characteristics Sync PDU -> bandwidth=%" PRIu32 ", rtt=%" PRIu32 |
773 | 27 | "", |
774 | 27 | bandwidth, rtt); |
775 | | |
776 | 27 | IFCALLRET(autodetect->NetworkCharacteristicsSync, success, autodetect, transport, |
777 | 27 | autodetectRspPdu->sequenceNumber, bandwidth, rtt); |
778 | 27 | if (!success) |
779 | 0 | WLog_Print(autodetect->log, WLOG_WARN, "NetworkCharacteristicsSync failed"); |
780 | 27 | return success; |
781 | 29 | } |
782 | | |
783 | | static BOOL autodetect_recv_netchar_request(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport, |
784 | | wStream* s, const AUTODETECT_REQ_PDU* autodetectReqPdu) |
785 | 101 | { |
786 | 101 | rdpNetworkCharacteristicsResult result = { |
787 | 101 | .type = RDP_NETCHAR_RESERVED, .baseRTT = 0, .averageRTT = 0, .bandwidth = 0 |
788 | 101 | }; |
789 | 101 | BOOL success = TRUE; |
790 | | |
791 | 101 | WINPR_ASSERT(autodetect); |
792 | 101 | WINPR_ASSERT(s); |
793 | 101 | WINPR_ASSERT(autodetectReqPdu); |
794 | | |
795 | 101 | switch (autodetectReqPdu->requestType) |
796 | 101 | { |
797 | 46 | case RDP_NETCHAR_RESULTS_0x0840: |
798 | | |
799 | | /* baseRTT and averageRTT fields are present (bandwidth field is not) */ |
800 | 46 | if (autodetectReqPdu->headerLength != 0x0E) |
801 | 4 | { |
802 | 4 | WLog_Print(autodetect->log, WLOG_ERROR, |
803 | 4 | "autodetectReqPdu->headerLength != 0x0E [0x%02" PRIx8 "]", |
804 | 4 | autodetectReqPdu->headerLength); |
805 | 4 | return FALSE; |
806 | 4 | } |
807 | 42 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8)) |
808 | 2 | return FALSE; |
809 | | |
810 | 40 | result.type = RDP_NETCHAR_RESULT_TYPE_BASE_RTT_AVG_RTT; |
811 | 40 | Stream_Read_UINT32(s, result.baseRTT); /* baseRTT (4 bytes) */ |
812 | 40 | Stream_Read_UINT32(s, result.averageRTT); /* averageRTT (4 bytes) */ |
813 | 40 | autodetect->netCharBaseRTT = result.baseRTT; |
814 | 40 | break; |
815 | | |
816 | 41 | case RDP_NETCHAR_RESULTS_0x0880: |
817 | | |
818 | | /* bandwidth and averageRTT fields are present (baseRTT field is not) */ |
819 | 41 | if (autodetectReqPdu->headerLength != 0x0E) |
820 | 8 | { |
821 | 8 | WLog_Print(autodetect->log, WLOG_ERROR, |
822 | 8 | "autodetectReqPdu->headerLength != 0x0E [0x%02" PRIx8 "]", |
823 | 8 | autodetectReqPdu->headerLength); |
824 | 8 | return FALSE; |
825 | 8 | } |
826 | 33 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8)) |
827 | 2 | return FALSE; |
828 | | |
829 | 31 | result.type = RDP_NETCHAR_RESULT_TYPE_BW_AVG_RTT; |
830 | 31 | Stream_Read_UINT32(s, result.bandwidth); /* bandwidth (4 bytes) */ |
831 | 31 | Stream_Read_UINT32(s, result.averageRTT); /* averageRTT (4 bytes) */ |
832 | 31 | autodetect->netCharBandwidth = result.bandwidth; |
833 | 31 | break; |
834 | | |
835 | 14 | case RDP_NETCHAR_RESULTS_0x08C0: |
836 | | |
837 | | /* baseRTT, bandwidth, and averageRTT fields are present */ |
838 | 14 | if (autodetectReqPdu->headerLength != 0x12) |
839 | 8 | { |
840 | 8 | WLog_Print(autodetect->log, WLOG_ERROR, |
841 | 8 | "autodetectReqPdu->headerLength != 0x012 [0x%02" PRIx8 "]", |
842 | 8 | autodetectReqPdu->headerLength); |
843 | 8 | return FALSE; |
844 | 8 | } |
845 | 6 | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 12)) |
846 | 1 | return FALSE; |
847 | | |
848 | 5 | result.type = RDP_NETCHAR_RESULT_TYPE_BASE_RTT_BW_AVG_RTT; |
849 | 5 | Stream_Read_UINT32(s, result.baseRTT); /* baseRTT (4 bytes) */ |
850 | 5 | Stream_Read_UINT32(s, result.bandwidth); /* bandwidth (4 bytes) */ |
851 | 5 | Stream_Read_UINT32(s, result.averageRTT); /* averageRTT (4 bytes) */ |
852 | 5 | autodetect->netCharBaseRTT = result.baseRTT; |
853 | 5 | autodetect->netCharBandwidth = result.bandwidth; |
854 | 5 | break; |
855 | | |
856 | 0 | default: |
857 | 0 | WINPR_ASSERT(FALSE); |
858 | 0 | break; |
859 | 101 | } |
860 | | /* [MS-RDPBCGR] 3.2.5.17: the metrics are kept for a Network Characteristics Sync */ |
861 | 76 | autodetect->netCharAverageRTT = result.averageRTT; |
862 | | |
863 | 76 | WLog_Print(autodetect->log, WLOG_TRACE, |
864 | 76 | "received Network Characteristics Result PDU -> baseRTT=%" PRIu32 |
865 | 76 | ", bandwidth=%" PRIu32 ", averageRTT=%" PRIu32 "", |
866 | 76 | result.baseRTT, result.bandwidth, result.averageRTT); |
867 | | |
868 | 76 | IFCALLRET(autodetect->NetworkCharacteristicsResult, success, autodetect, transport, |
869 | 76 | autodetectReqPdu->sequenceNumber, &result); |
870 | 76 | if (!success) |
871 | 31 | WLog_Print(autodetect->log, WLOG_WARN, "NetworkCharacteristicsResult failed"); |
872 | 76 | return success; |
873 | 101 | } |
874 | | |
875 | | state_run_t autodetect_recv_request_packet(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport, |
876 | | wStream* s) |
877 | 17.5k | { |
878 | 17.5k | AUTODETECT_REQ_PDU autodetectReqPdu = WINPR_C_ARRAY_INIT; |
879 | 17.5k | const rdpSettings* settings = nullptr; |
880 | 17.5k | BOOL success = FALSE; |
881 | | |
882 | 17.5k | WINPR_ASSERT(autodetect); |
883 | 17.5k | WINPR_ASSERT(autodetect->context); |
884 | | |
885 | 17.5k | settings = autodetect->context->settings; |
886 | 17.5k | WINPR_ASSERT(settings); |
887 | | |
888 | 17.5k | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 6)) |
889 | 12.4k | return STATE_RUN_FAILED; |
890 | | |
891 | 5.07k | Stream_Read_UINT8(s, autodetectReqPdu.headerLength); /* headerLength (1 byte) */ |
892 | 5.07k | Stream_Read_UINT8(s, autodetectReqPdu.headerTypeId); /* headerTypeId (1 byte) */ |
893 | 5.07k | Stream_Read_UINT16(s, autodetectReqPdu.sequenceNumber); /* sequenceNumber (2 bytes) */ |
894 | 5.07k | Stream_Read_UINT16(s, autodetectReqPdu.requestType); /* requestType (2 bytes) */ |
895 | | |
896 | 5.07k | if (WLog_IsLevelActive(autodetect->log, WLOG_TRACE)) |
897 | 0 | { |
898 | 0 | char rbuffer[128] = WINPR_C_ARRAY_INIT; |
899 | 0 | const char* requestTypeStr = autodetect_request_type_to_string_buffer( |
900 | 0 | autodetectReqPdu.requestType, rbuffer, sizeof(rbuffer)); |
901 | |
|
902 | 0 | char hbuffer[128] = WINPR_C_ARRAY_INIT; |
903 | 0 | const char* headerStr = |
904 | 0 | autodetect_header_type_string(autodetectReqPdu.headerTypeId, hbuffer, sizeof(hbuffer)); |
905 | |
|
906 | 0 | WLog_Print(autodetect->log, WLOG_TRACE, |
907 | 0 | "rdp_recv_autodetect_request_packet: headerLength=%" PRIu8 |
908 | 0 | ", headerTypeId=%s, sequenceNumber=%" PRIu16 ", requestType=%s", |
909 | 0 | autodetectReqPdu.headerLength, headerStr, autodetectReqPdu.sequenceNumber, |
910 | 0 | requestTypeStr); |
911 | 0 | } |
912 | | |
913 | 5.07k | if (!freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect)) |
914 | 0 | { |
915 | 0 | char rbuffer[128] = WINPR_C_ARRAY_INIT; |
916 | 0 | const char* requestTypeStr = autodetect_request_type_to_string_buffer( |
917 | 0 | autodetectReqPdu.requestType, rbuffer, sizeof(rbuffer)); |
918 | |
|
919 | 0 | WLog_Print(autodetect->log, WLOG_WARN, |
920 | 0 | "Received a [MS-RDPBCGR] 2.2.14.1.1 RTT Measure Request [%s] " |
921 | 0 | "message but support was not enabled", |
922 | 0 | requestTypeStr); |
923 | 0 | goto fail; |
924 | 0 | } |
925 | | |
926 | 5.07k | if (autodetectReqPdu.headerTypeId != TYPE_ID_AUTODETECT_REQUEST) |
927 | 2.56k | { |
928 | 2.56k | char rbuffer[128] = WINPR_C_ARRAY_INIT; |
929 | 2.56k | const char* requestTypeStr = autodetect_request_type_to_string_buffer( |
930 | 2.56k | autodetectReqPdu.requestType, rbuffer, sizeof(rbuffer)); |
931 | 2.56k | char hbuffer[128] = WINPR_C_ARRAY_INIT; |
932 | 2.56k | const char* headerStr = |
933 | 2.56k | autodetect_header_type_string(autodetectReqPdu.headerTypeId, hbuffer, sizeof(hbuffer)); |
934 | | |
935 | 2.56k | WLog_Print(autodetect->log, WLOG_ERROR, |
936 | 2.56k | "Received a [MS-RDPBCGR] 2.2.14.1.1 RTT Measure Request [%s] " |
937 | 2.56k | "message with invalid headerTypeId=%s", |
938 | 2.56k | requestTypeStr, headerStr); |
939 | 2.56k | goto fail; |
940 | 2.56k | } |
941 | | |
942 | 2.51k | if (!IFCALLRESULT(TRUE, autodetect->RequestReceived, autodetect, transport, |
943 | 2.51k | autodetectReqPdu.requestType, autodetectReqPdu.sequenceNumber)) |
944 | 0 | goto fail; |
945 | | |
946 | 2.51k | switch (autodetectReqPdu.requestType) |
947 | 2.51k | { |
948 | 192 | case RDP_RTT_REQUEST_TYPE_CONTINUOUS: |
949 | 195 | case RDP_RTT_REQUEST_TYPE_CONNECTTIME: |
950 | | /* RTT Measure Request (RDP_RTT_REQUEST) - MS-RDPBCGR 2.2.14.1.1 */ |
951 | 195 | success = |
952 | 195 | autodetect_recv_rtt_measure_request(autodetect, transport, s, &autodetectReqPdu); |
953 | 195 | break; |
954 | | |
955 | 8 | case RDP_BW_START_REQUEST_TYPE_CONTINUOUS: |
956 | 14 | case RDP_BW_START_REQUEST_TYPE_TUNNEL: |
957 | 16 | case RDP_BW_START_REQUEST_TYPE_CONNECTTIME: |
958 | | /* Bandwidth Measure Start (RDP_BW_START) - MS-RDPBCGR 2.2.14.1.2 */ |
959 | 16 | success = autodetect_recv_bandwidth_measure_start(autodetect, transport, s, |
960 | 16 | &autodetectReqPdu); |
961 | 16 | break; |
962 | | |
963 | 88 | case RDP_BW_PAYLOAD_REQUEST_TYPE: |
964 | | /* Bandwidth Measure Payload (RDP_BW_PAYLOAD) - MS-RDPBCGR 2.2.14.1.3 */ |
965 | 88 | success = autodetect_recv_bandwidth_measure_payload(autodetect, transport, s, |
966 | 88 | &autodetectReqPdu); |
967 | 88 | break; |
968 | | |
969 | 91 | case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME: |
970 | 101 | case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS: |
971 | 105 | case RDP_BW_STOP_REQUEST_TYPE_TUNNEL: |
972 | | /* Bandwidth Measure Stop (RDP_BW_STOP) - MS-RDPBCGR 2.2.14.1.4 */ |
973 | 105 | success = |
974 | 105 | autodetect_recv_bandwidth_measure_stop(autodetect, transport, s, &autodetectReqPdu); |
975 | 105 | break; |
976 | | |
977 | 46 | case RDP_NETCHAR_RESULTS_0x0840: |
978 | 87 | case RDP_NETCHAR_RESULTS_0x0880: |
979 | 101 | case RDP_NETCHAR_RESULTS_0x08C0: |
980 | | /* Network Characteristics Result (RDP_NETCHAR_RESULT) - MS-RDPBCGR 2.2.14.1.5 */ |
981 | 101 | success = autodetect_recv_netchar_request(autodetect, transport, s, &autodetectReqPdu); |
982 | 101 | break; |
983 | | |
984 | 2.00k | default: |
985 | 2.00k | WLog_Print(autodetect->log, WLOG_ERROR, "Unknown requestType=0x%04" PRIx16, |
986 | 2.00k | autodetectReqPdu.requestType); |
987 | 2.00k | break; |
988 | 2.51k | } |
989 | | |
990 | 5.07k | fail: |
991 | 5.07k | if (success) |
992 | 111 | autodetect->state = FREERDP_AUTODETECT_STATE_REQUEST; |
993 | 4.96k | else |
994 | 4.96k | autodetect->state = FREERDP_AUTODETECT_STATE_FAIL; |
995 | 5.07k | return success ? STATE_RUN_SUCCESS : STATE_RUN_FAILED; |
996 | 2.51k | } |
997 | | |
998 | | state_run_t autodetect_recv_tunnel_request(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport, |
999 | | wStream* s) |
1000 | 0 | { |
1001 | 0 | WINPR_ASSERT(autodetect); |
1002 | 0 | WINPR_ASSERT(s); |
1003 | | |
1004 | | /* [MS-RDPBCGR] 1.3.9: Continuous Auto-Detection over a sideband channel sends Bandwidth |
1005 | | * Measure Start, Bandwidth Measure Stop and Network Characteristics Result. The result needs |
1006 | | * no answer, a Stop on the reliable tunnel is answered on it ([MS-RDPBCGR] 3.2.5.17). Start |
1007 | | * and Stop of a lossy tunnel (0x0114, 0x0629) are not, there is none. */ |
1008 | 0 | UINT16 requestType = 0; |
1009 | 0 | if (Stream_GetRemainingLength(s) >= 6) |
1010 | 0 | { |
1011 | 0 | const BYTE* header = Stream_ConstPointer(s); |
1012 | 0 | requestType = winpr_Data_Get_UINT16(&header[4]); |
1013 | 0 | } |
1014 | |
|
1015 | 0 | switch (requestType) |
1016 | 0 | { |
1017 | 0 | case RDP_BW_START_REQUEST_TYPE_CONTINUOUS: |
1018 | 0 | case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS: |
1019 | 0 | case RDP_NETCHAR_RESULTS_0x0840: |
1020 | 0 | case RDP_NETCHAR_RESULTS_0x0880: |
1021 | 0 | case RDP_NETCHAR_RESULTS_0x08C0: |
1022 | 0 | return autodetect_recv_request_packet(autodetect, transport, s); |
1023 | | |
1024 | 0 | default: |
1025 | 0 | WLog_Print(autodetect->log, WLOG_DEBUG, |
1026 | 0 | "ignoring auto-detect request 0x%04" PRIx16 " in a tunnel subheader", |
1027 | 0 | requestType); |
1028 | 0 | return STATE_RUN_SUCCESS; |
1029 | 0 | } |
1030 | 0 | } |
1031 | | |
1032 | | state_run_t autodetect_recv_response_packet(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport, |
1033 | | wStream* s) |
1034 | 17.5k | { |
1035 | 17.5k | AUTODETECT_RSP_PDU autodetectRspPdu = WINPR_C_ARRAY_INIT; |
1036 | 17.5k | const rdpSettings* settings = nullptr; |
1037 | 17.5k | BOOL success = FALSE; |
1038 | | |
1039 | 17.5k | WINPR_ASSERT(autodetect); |
1040 | 17.5k | WINPR_ASSERT(autodetect->context); |
1041 | 17.5k | WINPR_ASSERT(s); |
1042 | | |
1043 | 17.5k | settings = autodetect->context->settings; |
1044 | 17.5k | WINPR_ASSERT(settings); |
1045 | | |
1046 | 17.5k | if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 6)) |
1047 | 13.0k | goto fail; |
1048 | | |
1049 | 4.45k | Stream_Read_UINT8(s, autodetectRspPdu.headerLength); /* headerLength (1 byte) */ |
1050 | 4.45k | Stream_Read_UINT8(s, autodetectRspPdu.headerTypeId); /* headerTypeId (1 byte) */ |
1051 | 4.45k | Stream_Read_UINT16(s, autodetectRspPdu.sequenceNumber); /* sequenceNumber (2 bytes) */ |
1052 | 4.45k | Stream_Read_UINT16(s, autodetectRspPdu.responseType); /* responseType (2 bytes) */ |
1053 | | |
1054 | 4.45k | if (WLog_IsLevelActive(autodetect->log, WLOG_TRACE)) |
1055 | 0 | { |
1056 | 0 | char rbuffer[128] = WINPR_C_ARRAY_INIT; |
1057 | 0 | const char* requestStr = autodetect_request_type_to_string_buffer( |
1058 | 0 | autodetectRspPdu.responseType, rbuffer, sizeof(rbuffer)); |
1059 | 0 | char hbuffer[128] = WINPR_C_ARRAY_INIT; |
1060 | 0 | const char* headerStr = |
1061 | 0 | autodetect_header_type_string(autodetectRspPdu.headerTypeId, hbuffer, sizeof(hbuffer)); |
1062 | |
|
1063 | 0 | WLog_Print(autodetect->log, WLOG_TRACE, |
1064 | 0 | "rdp_recv_autodetect_response_packet: headerLength=%" PRIu8 ", headerTypeId=%s" |
1065 | 0 | ", sequenceNumber=%" PRIu16 ", requestType=%s", |
1066 | 0 | autodetectRspPdu.headerLength, headerStr, autodetectRspPdu.sequenceNumber, |
1067 | 0 | requestStr); |
1068 | 0 | } |
1069 | | |
1070 | 4.45k | if (!freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect)) |
1071 | 0 | { |
1072 | 0 | char rbuffer[128] = WINPR_C_ARRAY_INIT; |
1073 | |
|
1074 | 0 | const char* requestStr = autodetect_request_type_to_string_buffer( |
1075 | 0 | autodetectRspPdu.responseType, rbuffer, sizeof(rbuffer)); |
1076 | |
|
1077 | 0 | WLog_Print(autodetect->log, WLOG_WARN, |
1078 | 0 | "Received a [MS-RDPBCGR] 2.2.14.2.1 RTT Measure Response [%s] " |
1079 | 0 | "message but support was not enabled", |
1080 | 0 | requestStr); |
1081 | 0 | return STATE_RUN_FAILED; |
1082 | 0 | } |
1083 | | |
1084 | 4.45k | if (autodetectRspPdu.headerTypeId != TYPE_ID_AUTODETECT_RESPONSE) |
1085 | 4.22k | { |
1086 | 4.22k | char rbuffer[128] = WINPR_C_ARRAY_INIT; |
1087 | 4.22k | const char* requestStr = autodetect_request_type_to_string_buffer( |
1088 | 4.22k | autodetectRspPdu.responseType, rbuffer, sizeof(rbuffer)); |
1089 | 4.22k | char hbuffer[128] = WINPR_C_ARRAY_INIT; |
1090 | 4.22k | const char* headerStr = |
1091 | 4.22k | autodetect_header_type_string(autodetectRspPdu.headerTypeId, hbuffer, sizeof(hbuffer)); |
1092 | 4.22k | WLog_Print(autodetect->log, WLOG_ERROR, |
1093 | 4.22k | "Received a [MS-RDPBCGR] 2.2.14.2.1 RTT Measure Response [%s] " |
1094 | 4.22k | "message with invalid headerTypeId=%s", |
1095 | 4.22k | requestStr, headerStr); |
1096 | 4.22k | goto fail; |
1097 | 4.22k | } |
1098 | | |
1099 | 236 | if (!IFCALLRESULT(TRUE, autodetect->ResponseReceived, autodetect, transport, |
1100 | 236 | autodetectRspPdu.responseType, autodetectRspPdu.sequenceNumber)) |
1101 | 0 | goto fail; |
1102 | | |
1103 | 236 | switch (autodetectRspPdu.responseType) |
1104 | 236 | { |
1105 | 69 | case RDP_RTT_RESPONSE_TYPE: |
1106 | | /* RTT Measure Response (RDP_RTT_RESPONSE) - MS-RDPBCGR 2.2.14.2.1 */ |
1107 | 69 | success = |
1108 | 69 | autodetect_recv_rtt_measure_response(autodetect, transport, s, &autodetectRspPdu); |
1109 | 69 | break; |
1110 | | |
1111 | 19 | case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME: |
1112 | 28 | case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS: |
1113 | | /* Bandwidth Measure Results (RDP_BW_RESULTS) - MS-RDPBCGR 2.2.14.2.2 */ |
1114 | 28 | success = autodetect_recv_bandwidth_measure_results(autodetect, transport, s, |
1115 | 28 | &autodetectRspPdu); |
1116 | 28 | break; |
1117 | | |
1118 | 36 | case RDP_NETCHAR_SYNC_RESPONSE_TYPE: |
1119 | | /* Network Characteristics Sync (RDP_NETCHAR_SYNC) - MS-RDPBCGR 2.2.14.2.3 */ |
1120 | 36 | success = autodetect_recv_netchar_sync(autodetect, transport, s, &autodetectRspPdu); |
1121 | 36 | break; |
1122 | | |
1123 | 103 | default: |
1124 | 103 | WLog_Print(autodetect->log, WLOG_ERROR, "Unknown responseType=0x%04" PRIx16, |
1125 | 103 | autodetectRspPdu.responseType); |
1126 | 103 | break; |
1127 | 236 | } |
1128 | | |
1129 | 17.5k | fail: |
1130 | 17.5k | if (success) |
1131 | 84 | { |
1132 | 84 | if (autodetectRspPdu.responseType == RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME) |
1133 | 2 | autodetect->state = FREERDP_AUTODETECT_STATE_COMPLETE; |
1134 | 82 | else |
1135 | 82 | autodetect->state = FREERDP_AUTODETECT_STATE_RESPONSE; |
1136 | 84 | } |
1137 | 17.4k | else |
1138 | 17.4k | autodetect->state = FREERDP_AUTODETECT_STATE_FAIL; |
1139 | | |
1140 | 17.5k | return success ? STATE_RUN_SUCCESS : STATE_RUN_FAILED; |
1141 | 236 | } |
1142 | | |
1143 | | void autodetect_on_connect_time_auto_detect_begin(rdpAutoDetect* autodetect) |
1144 | 0 | { |
1145 | 0 | WINPR_ASSERT(autodetect); |
1146 | 0 | WINPR_ASSERT(autodetect->OnConnectTimeAutoDetectBegin); |
1147 | |
|
1148 | 0 | autodetect->state = autodetect->OnConnectTimeAutoDetectBegin(autodetect); |
1149 | 0 | } |
1150 | | |
1151 | | void autodetect_on_connect_time_auto_detect_progress(rdpAutoDetect* autodetect) |
1152 | 0 | { |
1153 | 0 | WINPR_ASSERT(autodetect); |
1154 | 0 | WINPR_ASSERT(autodetect->OnConnectTimeAutoDetectProgress); |
1155 | |
|
1156 | 0 | autodetect->state = autodetect->OnConnectTimeAutoDetectProgress(autodetect); |
1157 | 0 | } |
1158 | | |
1159 | | rdpAutoDetect* autodetect_new(rdpContext* context) |
1160 | 26.2k | { |
1161 | 26.2k | rdpAutoDetect* autoDetect = (rdpAutoDetect*)calloc(1, sizeof(rdpAutoDetect)); |
1162 | 26.2k | if (!autoDetect) |
1163 | 0 | return nullptr; |
1164 | 26.2k | autoDetect->context = context; |
1165 | 26.2k | autoDetect->log = WLog_Get(AUTODETECT_TAG); |
1166 | | |
1167 | 26.2k | return autoDetect; |
1168 | 26.2k | } |
1169 | | |
1170 | | void autodetect_free(rdpAutoDetect* autoDetect) |
1171 | 26.2k | { |
1172 | 26.2k | free(autoDetect); |
1173 | 26.2k | } |
1174 | | |
1175 | | void autodetect_register_server_callbacks(rdpAutoDetect* autodetect) |
1176 | 8.09k | { |
1177 | 8.09k | WINPR_ASSERT(autodetect); |
1178 | | |
1179 | 8.09k | autodetect->RTTMeasureRequest = autodetect_send_rtt_measure_request; |
1180 | 8.09k | autodetect->BandwidthMeasureStart = autodetect_send_bandwidth_measure_start; |
1181 | 8.09k | autodetect->BandwidthMeasurePayload = autodetect_send_bandwidth_measure_payload; |
1182 | 8.09k | autodetect->BandwidthMeasureStop = autodetect_send_bandwidth_measure_stop; |
1183 | 8.09k | autodetect->NetworkCharacteristicsResult = autodetect_send_netchar_result; |
1184 | | |
1185 | | /* |
1186 | | * Default handlers for Connect-Time Auto-Detection |
1187 | | * (MAY be overridden by the API user) |
1188 | | */ |
1189 | 8.09k | autodetect->OnConnectTimeAutoDetectBegin = autodetect_on_connect_time_auto_detect_begin_default; |
1190 | 8.09k | autodetect->OnConnectTimeAutoDetectProgress = |
1191 | 8.09k | autodetect_on_connect_time_auto_detect_progress_default; |
1192 | 8.09k | } |
1193 | | |
1194 | | FREERDP_AUTODETECT_STATE autodetect_get_state(rdpAutoDetect* autodetect) |
1195 | 0 | { |
1196 | 0 | WINPR_ASSERT(autodetect); |
1197 | 0 | return autodetect->state; |
1198 | 0 | } |
1199 | | |
1200 | | rdpAutoDetect* autodetect_get(rdpContext* context) |
1201 | 0 | { |
1202 | 0 | WINPR_ASSERT(context); |
1203 | 0 | WINPR_ASSERT(context->rdp); |
1204 | 0 | return context->rdp->autodetect; |
1205 | 0 | } |