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