20#include <freerdp/config.h>
22#include <winpr/crypto.h>
23#include <winpr/assert.h>
25#include "autodetect.h"
26#include "multitransport.h"
28#define TYPE_ID_AUTODETECT_REQUEST 0x00
29#define TYPE_ID_AUTODETECT_RESPONSE 0x01
31#define RDP_RTT_REQUEST_TYPE_CONTINUOUS 0x0001
32#define RDP_RTT_REQUEST_TYPE_CONNECTTIME 0x1001
34#define RDP_RTT_RESPONSE_TYPE 0x0000
36#define RDP_BW_START_REQUEST_TYPE_CONTINUOUS 0x0014
37#define RDP_BW_START_REQUEST_TYPE_TUNNEL 0x0114
38#define RDP_BW_START_REQUEST_TYPE_CONNECTTIME 0x1014
39#define RDP_BW_PAYLOAD_REQUEST_TYPE 0x0002
40#define RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME 0x002B
41#define RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS 0x0429
42#define RDP_BW_STOP_REQUEST_TYPE_TUNNEL 0x0629
44#define RDP_NETCHAR_SYNC_RESPONSE_TYPE 0x0018
46#define RDP_NETCHAR_RESULTS_0x0840 0x0840U
47#define RDP_NETCHAR_RESULTS_0x0880 0x0880U
48#define RDP_NETCHAR_RESULTS_0x08C0 0x08C0U
54 UINT16 sequenceNumber;
62 UINT16 sequenceNumber;
66static const char* autodetect_header_type_string(UINT8 headerType,
char* buffer,
size_t size)
68 const char* str =
nullptr;
71 case TYPE_ID_AUTODETECT_REQUEST:
72 str =
"TYPE_ID_AUTODETECT_REQUEST";
74 case TYPE_ID_AUTODETECT_RESPONSE:
75 str =
"TYPE_ID_AUTODETECT_RESPONSE";
78 str =
"TYPE_ID_AUTODETECT_UNKNOWN";
82 (void)_snprintf(buffer, size,
"%s [0x%08" PRIx8
"]", str, headerType);
86static const char* autodetect_request_type_to_string(UINT32 requestType)
90 case RDP_RTT_RESPONSE_TYPE:
91 return "RDP_RTT_RESPONSE_TYPE";
92 case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME:
93 return "RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME";
94 case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS:
95 return "RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS";
96 case RDP_RTT_REQUEST_TYPE_CONTINUOUS:
97 return "RDP_RTT_REQUEST_TYPE_CONTINUOUS";
98 case RDP_RTT_REQUEST_TYPE_CONNECTTIME:
99 return "RDP_RTT_REQUEST_TYPE_CONNECTTIME";
100 case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
101 return "RDP_BW_START_REQUEST_TYPE_CONTINUOUS";
102 case RDP_BW_START_REQUEST_TYPE_TUNNEL:
103 return "RDP_BW_START_REQUEST_TYPE_TUNNEL";
104 case RDP_BW_START_REQUEST_TYPE_CONNECTTIME:
105 return "RDP_BW_START_REQUEST_TYPE_CONNECTTIME";
106 case RDP_BW_PAYLOAD_REQUEST_TYPE:
107 return "RDP_BW_PAYLOAD_REQUEST_TYPE";
108 case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME:
109 return "RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME";
110 case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
111 return "RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS";
112 case RDP_BW_STOP_REQUEST_TYPE_TUNNEL:
113 return "RDP_BW_STOP_REQUEST_TYPE_TUNNEL";
114 case RDP_NETCHAR_RESULTS_0x0840:
115 return "RDP_NETCHAR_RESULTS_0x0840";
116 case RDP_NETCHAR_RESULTS_0x0880:
117 return "RDP_NETCHAR_RESULTS_0x0880";
118 case RDP_NETCHAR_RESULTS_0x08C0:
119 return "RDP_NETCHAR_RESULTS_0x08C0";
125static const char* autodetect_request_type_to_string_buffer(UINT32 requestType,
char* buffer,
128 const char* str = autodetect_request_type_to_string(requestType);
129 (void)_snprintf(buffer, size,
"%s [0x%08" PRIx32
"]", str, requestType);
133static BOOL autodetect_send_rtt_measure_request(rdpAutoDetect* autodetect,
134 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
135 UINT16 sequenceNumber)
137 UINT16 requestType = 0;
138 UINT16 sec_flags = 0;
141 WINPR_ASSERT(autodetect);
142 WINPR_ASSERT(autodetect->context);
144 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
148 if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE)
149 requestType = RDP_RTT_REQUEST_TYPE_CONNECTTIME;
151 requestType = RDP_RTT_REQUEST_TYPE_CONTINUOUS;
153 WLog_Print(autodetect->log, WLOG_TRACE,
"sending RTT Measure Request PDU");
154 Stream_Write_UINT8(s, 0x06);
155 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST);
156 Stream_Write_UINT16(s, sequenceNumber);
157 Stream_Write_UINT16(s, requestType);
158 autodetect->rttMeasureStartTime = GetTickCount64();
159 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
160 sec_flags | SEC_AUTODETECT_REQ);
163static BOOL autodetect_send_rtt_measure_response(rdpAutoDetect* autodetect, UINT16 sequenceNumber)
165 UINT16 sec_flags = 0;
168 WINPR_ASSERT(autodetect);
169 WINPR_ASSERT(autodetect->context);
172 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
177 WLog_Print(autodetect->log, WLOG_TRACE,
178 "sending RTT Measure Response PDU (seqNumber=0x%" PRIx16
")", sequenceNumber);
179 Stream_Write_UINT8(s, 0x06);
180 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE);
181 Stream_Write_UINT16(s, sequenceNumber);
182 Stream_Write_UINT16(s, RDP_RTT_RESPONSE_TYPE);
183 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
184 sec_flags | SEC_AUTODETECT_RSP);
187static BOOL autodetect_send_netchar_sync(rdpAutoDetect* autodetect, UINT16 sequenceNumber)
189 UINT16 sec_flags = 0;
191 WINPR_ASSERT(autodetect);
192 WINPR_ASSERT(autodetect->context);
194 wStream* s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
198 WLog_Print(autodetect->log, WLOG_TRACE,
199 "sending Network Characteristics Sync PDU -> bandwidth=%" PRIu32
", rtt=%" PRIu32,
200 autodetect->netCharBandwidth, autodetect->netCharAverageRTT);
201 Stream_Write_UINT8(s, 0x0E);
202 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE);
203 Stream_Write_UINT16(s, sequenceNumber);
204 Stream_Write_UINT16(s, RDP_NETCHAR_SYNC_RESPONSE_TYPE);
205 Stream_Write_UINT32(s, autodetect->netCharBandwidth);
206 Stream_Write_UINT32(s, autodetect->netCharAverageRTT);
207 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
208 sec_flags | SEC_AUTODETECT_RSP);
211static BOOL autodetect_send_bandwidth_measure_start(rdpAutoDetect* autodetect,
212 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
213 UINT16 sequenceNumber)
215 UINT16 requestType = 0;
216 UINT16 sec_flags = 0;
219 WINPR_ASSERT(autodetect);
220 WINPR_ASSERT(autodetect->context);
222 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
226 if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE)
227 requestType = RDP_BW_START_REQUEST_TYPE_CONNECTTIME;
229 requestType = RDP_BW_START_REQUEST_TYPE_CONTINUOUS;
231 WLog_Print(autodetect->log, WLOG_TRACE,
232 "sending Bandwidth Measure Start PDU(seqNumber=%" PRIu16
")", sequenceNumber);
233 Stream_Write_UINT8(s, 0x06);
234 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST);
235 Stream_Write_UINT16(s, sequenceNumber);
236 Stream_Write_UINT16(s, requestType);
237 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
238 sec_flags | SEC_AUTODETECT_REQ);
242autodetect_send_bandwidth_measure_payload(rdpAutoDetect* autodetect,
243 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
244 UINT16 sequenceNumber, UINT16 payloadLength)
246 UINT16 sec_flags = 0;
249 WINPR_ASSERT(autodetect);
250 WINPR_ASSERT(autodetect->context);
252 WINPR_ASSERT(freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE);
254 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
258 WLog_Print(autodetect->log, WLOG_TRACE,
259 "sending Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16
"", payloadLength);
263 if (!Stream_EnsureRemainingCapacity(s, 8ull + payloadLength))
265 WLog_Print(autodetect->log, WLOG_ERROR,
"Failed to ensure %lu bytes in stream",
266 8ul + payloadLength);
271 Stream_Write_UINT8(s, 0x08);
272 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST);
273 Stream_Write_UINT16(s, sequenceNumber);
274 Stream_Write_UINT16(s, RDP_BW_PAYLOAD_REQUEST_TYPE);
275 Stream_Write_UINT16(s, payloadLength);
277 if (winpr_RAND(Stream_Pointer(s), payloadLength) < 0)
282 Stream_Seek(s, payloadLength);
283 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
284 sec_flags | SEC_AUTODETECT_REQ);
287static BOOL autodetect_send_bandwidth_measure_stop(rdpAutoDetect* autodetect,
288 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
289 UINT16 sequenceNumber, UINT16 payloadLength)
291 UINT16 requestType = 0;
292 UINT16 sec_flags = 0;
295 WINPR_ASSERT(autodetect);
296 WINPR_ASSERT(autodetect->context);
298 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
302 if (freerdp_get_state(autodetect->context) < CONNECTION_STATE_ACTIVE)
303 requestType = RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME;
305 requestType = RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS;
307 if (requestType == RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS)
310 WLog_Print(autodetect->log, WLOG_TRACE,
311 "sending Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16
"", payloadLength);
314 Stream_Write_UINT8(s, requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME
317 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST);
318 Stream_Write_UINT16(s, sequenceNumber);
319 Stream_Write_UINT16(s, requestType);
321 if (requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME)
323 Stream_Write_UINT16(s, payloadLength);
325 if (payloadLength > 0)
327 if (!Stream_EnsureRemainingCapacity(s, payloadLength))
329 WLog_Print(autodetect->log, WLOG_ERROR,
330 "Failed to ensure %" PRIu16
" bytes in stream", payloadLength);
336 if (winpr_RAND(Stream_Pointer(s), payloadLength) < 0)
341 Stream_Seek(s, payloadLength);
345 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
346 sec_flags | SEC_AUTODETECT_REQ);
350static void autodetect_write_bandwidth_measure_results(
const rdpAutoDetect* autodetect,
wStream* s,
351 UINT16 responseType, UINT16 sequenceNumber,
354 WINPR_ASSERT(autodetect);
357 Stream_Write_UINT8(s, 0x0E);
358 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE);
359 Stream_Write_UINT16(s, sequenceNumber);
360 Stream_Write_UINT16(s, responseType);
361 Stream_Write_UINT32(s, timeDelta);
362 Stream_Write_UINT32(s, autodetect->bandwidthMeasureByteCount);
365static BOOL autodetect_send_bandwidth_measure_results(rdpAutoDetect* autodetect,
366 RDP_TRANSPORT_TYPE transport,
367 UINT16 responseType, UINT16 sequenceNumber)
370 UINT16 sec_flags = 0;
371 UINT64 timeDelta = GetTickCount64();
373 WINPR_ASSERT(autodetect);
374 WINPR_ASSERT(autodetect->context);
377 if (autodetect->bandwidthMeasureStartTime > timeDelta)
379 WLog_Print(autodetect->log, WLOG_WARN,
380 "Invalid bandwidthMeasureStartTime %" PRIu64
" > current %" PRIu64
382 autodetect->bandwidthMeasureStartTime, timeDelta);
386 timeDelta -= autodetect->bandwidthMeasureStartTime;
388 const UINT32 delta = (UINT32)MIN(timeDelta, UINT32_MAX);
389 WLog_Print(autodetect->log, WLOG_TRACE,
390 "sending Bandwidth Measure Results PDU -> timeDelta=%" PRIu32
", byteCount=%" PRIu32
392 delta, autodetect->bandwidthMeasureByteCount,
393 (transport == RDP_TRANSPORT_UDP_R) ?
" in the UDP tunnel" :
"");
395 IFCALLRET(autodetect->ClientBandwidthMeasureResult, success, autodetect, transport,
396 responseType, sequenceNumber, delta, autodetect->bandwidthMeasureByteCount);
399 WLog_Print(autodetect->log, WLOG_ERROR,
"ClientBandwidthMeasureResult failed");
405 if (transport == RDP_TRANSPORT_UDP_R)
407 BYTE buffer[0x0E] = WINPR_C_ARRAY_INIT;
408 wStream sbuffer = WINPR_C_ARRAY_INIT;
409 wStream* s = Stream_StaticInit(&sbuffer, buffer,
sizeof(buffer));
410 autodetect_write_bandwidth_measure_results(autodetect, s, responseType, sequenceNumber,
412 return multitransport_send_autodetect_response(autodetect->context->rdp->multitransport,
413 buffer,
sizeof(buffer));
416 wStream* s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
419 autodetect_write_bandwidth_measure_results(autodetect, s, responseType, sequenceNumber, delta);
420 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
421 sec_flags | SEC_AUTODETECT_RSP);
424static BOOL autodetect_send_netchar_result(rdpAutoDetect* autodetect,
425 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
426 UINT16 sequenceNumber,
427 const rdpNetworkCharacteristicsResult* result)
429 UINT16 sec_flags = 0;
432 WINPR_ASSERT(autodetect);
433 WINPR_ASSERT(autodetect->context);
435 s = rdp_message_channel_pdu_init(autodetect->context->rdp, &sec_flags);
440 WLog_Print(autodetect->log, WLOG_TRACE,
"sending Network Characteristics Result PDU");
442 switch (result->type)
444 case RDP_NETCHAR_RESULT_TYPE_BASE_RTT_AVG_RTT:
445 Stream_Write_UINT8(s, 0x0E);
446 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST);
447 Stream_Write_UINT16(s, sequenceNumber);
448 WINPR_ASSERT((result->type <= UINT16_MAX));
449 WINPR_ASSERT((result->type >= 0));
450 Stream_Write_UINT16(s, (UINT16)result->type);
451 Stream_Write_UINT32(s, result->baseRTT);
452 Stream_Write_UINT32(s, result->averageRTT);
454 case RDP_NETCHAR_RESULT_TYPE_BW_AVG_RTT:
455 Stream_Write_UINT8(s, 0x0E);
456 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST);
457 Stream_Write_UINT16(s, sequenceNumber);
458 WINPR_ASSERT((result->type <= UINT16_MAX));
459 WINPR_ASSERT((result->type >= 0));
460 Stream_Write_UINT16(s, (UINT16)result->type);
461 Stream_Write_UINT32(s, result->bandwidth);
462 Stream_Write_UINT32(s, result->averageRTT);
464 case RDP_NETCHAR_RESULT_TYPE_BASE_RTT_BW_AVG_RTT:
465 Stream_Write_UINT8(s, 0x12);
466 Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_REQUEST);
467 Stream_Write_UINT16(s, sequenceNumber);
468 WINPR_ASSERT((result->type <= UINT16_MAX));
469 WINPR_ASSERT((result->type >= 0));
470 Stream_Write_UINT16(s, (UINT16)result->type);
471 Stream_Write_UINT32(s, result->baseRTT);
472 Stream_Write_UINT32(s, result->bandwidth);
473 Stream_Write_UINT32(s, result->averageRTT);
480 return rdp_send_message_channel_pdu(autodetect->context->rdp, s,
481 sec_flags | SEC_AUTODETECT_REQ);
484static FREERDP_AUTODETECT_STATE
485autodetect_on_connect_time_auto_detect_begin_default(rdpAutoDetect* autodetect)
487 WINPR_ASSERT(autodetect);
488 WINPR_ASSERT(autodetect->RTTMeasureRequest);
490 if (!autodetect->RTTMeasureRequest(autodetect, RDP_TRANSPORT_TCP, 0x23))
491 return FREERDP_AUTODETECT_STATE_FAIL;
493 return FREERDP_AUTODETECT_STATE_REQUEST;
496static FREERDP_AUTODETECT_STATE
497autodetect_on_connect_time_auto_detect_progress_default(rdpAutoDetect* autodetect)
499 WINPR_ASSERT(autodetect);
501 if (autodetect->state == FREERDP_AUTODETECT_STATE_RESPONSE ||
502 autodetect->state == FREERDP_AUTODETECT_STATE_COMPLETE)
503 return FREERDP_AUTODETECT_STATE_COMPLETE;
505 return autodetect->state;
508static BOOL autodetect_recv_rtt_measure_request(rdpAutoDetect* autodetect,
509 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
511 const AUTODETECT_REQ_PDU* autodetectReqPdu)
513 WINPR_ASSERT(autodetect);
515 WINPR_ASSERT(autodetectReqPdu);
517 if (autodetectReqPdu->headerLength != 0x06)
519 WLog_Print(autodetect->log, WLOG_ERROR,
520 "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8
"]",
521 autodetectReqPdu->headerLength);
525 WLog_Print(autodetect->log, WLOG_TRACE,
"received RTT Measure Request PDU");
527 return autodetect_send_rtt_measure_response(autodetect, autodetectReqPdu->sequenceNumber);
530static BOOL autodetect_recv_rtt_measure_response(rdpAutoDetect* autodetect,
531 RDP_TRANSPORT_TYPE transport,
533 const AUTODETECT_RSP_PDU* autodetectRspPdu)
537 WINPR_ASSERT(autodetect);
538 WINPR_ASSERT(autodetectRspPdu);
540 if (autodetectRspPdu->headerLength != 0x06)
542 WLog_Print(autodetect->log, WLOG_ERROR,
543 "autodetectRspPdu->headerLength != 0x06 [0x%02" PRIx8
"]",
544 autodetectRspPdu->headerLength);
548 WLog_Print(autodetect->log, WLOG_TRACE,
"received RTT Measure Response PDU");
549 autodetect->netCharAverageRTT =
550 (UINT32)MIN(GetTickCount64() - autodetect->rttMeasureStartTime, UINT32_MAX);
552 if (autodetect->netCharBaseRTT == 0 ||
553 autodetect->netCharBaseRTT > autodetect->netCharAverageRTT)
554 autodetect->netCharBaseRTT = autodetect->netCharAverageRTT;
556 IFCALLRET(autodetect->RTTMeasureResponse, success, autodetect, transport,
557 autodetectRspPdu->sequenceNumber);
559 WLog_Print(autodetect->log, WLOG_WARN,
"RTTMeasureResponse failed");
563static BOOL autodetect_recv_bandwidth_measure_start(rdpAutoDetect* autodetect,
564 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
566 const AUTODETECT_REQ_PDU* autodetectReqPdu)
568 WINPR_ASSERT(autodetect);
570 WINPR_ASSERT(autodetectReqPdu);
572 if (autodetectReqPdu->headerLength != 0x06)
574 WLog_Print(autodetect->log, WLOG_ERROR,
575 "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8
"]",
576 autodetectReqPdu->headerLength);
580 WLog_Print(autodetect->log, WLOG_TRACE,
581 "received Bandwidth Measure Start PDU - time=%" PRIu64
"", GetTickCount64());
583 autodetect->bandwidthMeasureStartTime = GetTickCount64();
584 autodetect->bandwidthMeasureByteCount = 0;
589 if ((autodetectReqPdu->requestType == RDP_BW_START_REQUEST_TYPE_CONNECTTIME) &&
590 (autodetect->netCharBandwidth > 0))
593 autodetect->context->settings, FreeRDP_ServerAutoReconnectCookie);
594 if (cookie && (cookie->cbLen > 0))
595 return autodetect_send_netchar_sync(autodetect, autodetectReqPdu->sequenceNumber);
599 if (autodetectReqPdu->requestType == RDP_BW_START_REQUEST_TYPE_CONTINUOUS)
601 autodetect->bandwidthMeasureStarted = TRUE;
608autodetect_recv_bandwidth_measure_payload(rdpAutoDetect* autodetect,
609 WINPR_ATTR_UNUSED RDP_TRANSPORT_TYPE transport,
610 wStream* s,
const AUTODETECT_REQ_PDU* autodetectReqPdu)
612 UINT16 payloadLength = 0;
614 WINPR_ASSERT(autodetect);
616 WINPR_ASSERT(autodetectReqPdu);
618 if (autodetectReqPdu->headerLength != 0x08)
620 WLog_Print(autodetect->log, WLOG_ERROR,
621 "autodetectReqPdu->headerLength != 0x08 [0x%02" PRIx8
"]",
622 autodetectReqPdu->headerLength);
626 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 2))
629 Stream_Read_UINT16(s, payloadLength);
630 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, payloadLength))
632 Stream_Seek(s, payloadLength);
634 WLog_Print(autodetect->log, WLOG_DEBUG,
635 "received Bandwidth Measure Payload PDU -> payloadLength=%" PRIu16
"",
640 autodetect->bandwidthMeasureByteCount += autodetectReqPdu->headerLength;
641 autodetect->bandwidthMeasureByteCount += payloadLength;
645static BOOL autodetect_recv_bandwidth_measure_stop(rdpAutoDetect* autodetect,
646 RDP_TRANSPORT_TYPE transport,
wStream* s,
647 const AUTODETECT_REQ_PDU* autodetectReqPdu)
649 UINT16 payloadLength = 0;
650 UINT16 responseType = 0;
652 WINPR_ASSERT(autodetect);
654 WINPR_ASSERT(autodetectReqPdu);
656 if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME)
658 if (autodetectReqPdu->headerLength != 0x08)
660 WLog_Print(autodetect->log, WLOG_ERROR,
661 "autodetectReqPdu->headerLength != 0x08 [0x%02" PRIx8
"]",
662 autodetectReqPdu->headerLength);
666 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 2))
669 Stream_Read_UINT16(s, payloadLength);
673 if (autodetectReqPdu->headerLength != 0x06)
675 WLog_Print(autodetect->log, WLOG_ERROR,
676 "autodetectReqPdu->headerLength != 0x06 [0x%02" PRIx8
"]",
677 autodetectReqPdu->headerLength);
684 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, payloadLength))
686 Stream_Seek(s, payloadLength);
688 WLog_Print(autodetect->log, WLOG_TRACE,
689 "received Bandwidth Measure Stop PDU -> payloadLength=%" PRIu16
"", payloadLength);
692 if (payloadLength > 0)
694 autodetect->bandwidthMeasureByteCount += autodetectReqPdu->headerLength;
695 autodetect->bandwidthMeasureByteCount += payloadLength;
699 if (autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS)
701 autodetect->bandwidthMeasureStarted = FALSE;
705 responseType = autodetectReqPdu->requestType == RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME
706 ? RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME
707 : RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS;
708 return autodetect_send_bandwidth_measure_results(autodetect, transport, responseType,
709 autodetectReqPdu->sequenceNumber);
712static BOOL autodetect_recv_bandwidth_measure_results(rdpAutoDetect* autodetect,
713 RDP_TRANSPORT_TYPE transport,
wStream* s,
714 const AUTODETECT_RSP_PDU* autodetectRspPdu)
716 UINT32 timeDelta = 0;
717 UINT32 byteCount = 0;
720 WINPR_ASSERT(autodetect);
722 WINPR_ASSERT(autodetectRspPdu);
724 if (autodetectRspPdu->headerLength != 0x0E)
726 WLog_Print(autodetect->log, WLOG_ERROR,
727 "autodetectRspPdu->headerLength != 0x0E [0x%02" PRIx8
"]",
728 autodetectRspPdu->headerLength);
732 WLog_Print(autodetect->log, WLOG_TRACE,
"received Bandwidth Measure Results PDU");
733 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8))
735 Stream_Read_UINT32(s, timeDelta);
736 Stream_Read_UINT32(s, byteCount);
738 IFCALLRET(autodetect->BandwidthMeasureResults, success, autodetect, transport,
739 autodetectRspPdu->sequenceNumber, autodetectRspPdu->responseType, timeDelta,
742 WLog_Print(autodetect->log, WLOG_WARN,
"BandwidthMeasureResults failed");
746static BOOL autodetect_recv_netchar_sync(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
747 wStream* s,
const AUTODETECT_RSP_PDU* autodetectRspPdu)
749 UINT32 bandwidth = 0;
753 WINPR_ASSERT(autodetect);
755 WINPR_ASSERT(autodetectRspPdu);
757 if (autodetectRspPdu->headerLength != 0x0E)
759 WLog_Print(autodetect->log, WLOG_ERROR,
760 "autodetectRspPdu->headerLength != 0x0E [0x%02" PRIx8
"]",
761 autodetectRspPdu->headerLength);
764 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8))
768 Stream_Read_UINT32(s, bandwidth);
769 Stream_Read_UINT32(s, rtt);
771 WLog_Print(autodetect->log, WLOG_TRACE,
772 "received Network Characteristics Sync PDU -> bandwidth=%" PRIu32
", rtt=%" PRIu32
776 IFCALLRET(autodetect->NetworkCharacteristicsSync, success, autodetect, transport,
777 autodetectRspPdu->sequenceNumber, bandwidth, rtt);
779 WLog_Print(autodetect->log, WLOG_WARN,
"NetworkCharacteristicsSync failed");
783static BOOL autodetect_recv_netchar_request(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
784 wStream* s,
const AUTODETECT_REQ_PDU* autodetectReqPdu)
786 rdpNetworkCharacteristicsResult result = {
787 .type = RDP_NETCHAR_RESERVED, .baseRTT = 0, .averageRTT = 0, .bandwidth = 0
791 WINPR_ASSERT(autodetect);
793 WINPR_ASSERT(autodetectReqPdu);
795 switch (autodetectReqPdu->requestType)
797 case RDP_NETCHAR_RESULTS_0x0840:
800 if (autodetectReqPdu->headerLength != 0x0E)
802 WLog_Print(autodetect->log, WLOG_ERROR,
803 "autodetectReqPdu->headerLength != 0x0E [0x%02" PRIx8
"]",
804 autodetectReqPdu->headerLength);
807 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8))
810 result.type = RDP_NETCHAR_RESULT_TYPE_BASE_RTT_AVG_RTT;
811 Stream_Read_UINT32(s, result.baseRTT);
812 Stream_Read_UINT32(s, result.averageRTT);
813 autodetect->netCharBaseRTT = result.baseRTT;
816 case RDP_NETCHAR_RESULTS_0x0880:
819 if (autodetectReqPdu->headerLength != 0x0E)
821 WLog_Print(autodetect->log, WLOG_ERROR,
822 "autodetectReqPdu->headerLength != 0x0E [0x%02" PRIx8
"]",
823 autodetectReqPdu->headerLength);
826 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 8))
829 result.type = RDP_NETCHAR_RESULT_TYPE_BW_AVG_RTT;
830 Stream_Read_UINT32(s, result.bandwidth);
831 Stream_Read_UINT32(s, result.averageRTT);
832 autodetect->netCharBandwidth = result.bandwidth;
835 case RDP_NETCHAR_RESULTS_0x08C0:
838 if (autodetectReqPdu->headerLength != 0x12)
840 WLog_Print(autodetect->log, WLOG_ERROR,
841 "autodetectReqPdu->headerLength != 0x012 [0x%02" PRIx8
"]",
842 autodetectReqPdu->headerLength);
845 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 12))
848 result.type = RDP_NETCHAR_RESULT_TYPE_BASE_RTT_BW_AVG_RTT;
849 Stream_Read_UINT32(s, result.baseRTT);
850 Stream_Read_UINT32(s, result.bandwidth);
851 Stream_Read_UINT32(s, result.averageRTT);
852 autodetect->netCharBaseRTT = result.baseRTT;
853 autodetect->netCharBandwidth = result.bandwidth;
861 autodetect->netCharAverageRTT = result.averageRTT;
863 WLog_Print(autodetect->log, WLOG_TRACE,
864 "received Network Characteristics Result PDU -> baseRTT=%" PRIu32
865 ", bandwidth=%" PRIu32
", averageRTT=%" PRIu32
"",
866 result.baseRTT, result.bandwidth, result.averageRTT);
868 IFCALLRET(autodetect->NetworkCharacteristicsResult, success, autodetect, transport,
869 autodetectReqPdu->sequenceNumber, &result);
871 WLog_Print(autodetect->log, WLOG_WARN,
"NetworkCharacteristicsResult failed");
875state_run_t autodetect_recv_request_packet(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
878 AUTODETECT_REQ_PDU autodetectReqPdu = WINPR_C_ARRAY_INIT;
879 const rdpSettings* settings =
nullptr;
880 BOOL success = FALSE;
882 WINPR_ASSERT(autodetect);
883 WINPR_ASSERT(autodetect->context);
885 settings = autodetect->context->settings;
886 WINPR_ASSERT(settings);
888 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 6))
889 return STATE_RUN_FAILED;
891 Stream_Read_UINT8(s, autodetectReqPdu.headerLength);
892 Stream_Read_UINT8(s, autodetectReqPdu.headerTypeId);
893 Stream_Read_UINT16(s, autodetectReqPdu.sequenceNumber);
894 Stream_Read_UINT16(s, autodetectReqPdu.requestType);
896 if (WLog_IsLevelActive(autodetect->log, WLOG_TRACE))
898 char rbuffer[128] = WINPR_C_ARRAY_INIT;
899 const char* requestTypeStr = autodetect_request_type_to_string_buffer(
900 autodetectReqPdu.requestType, rbuffer,
sizeof(rbuffer));
902 char hbuffer[128] = WINPR_C_ARRAY_INIT;
903 const char* headerStr =
904 autodetect_header_type_string(autodetectReqPdu.headerTypeId, hbuffer,
sizeof(hbuffer));
906 WLog_Print(autodetect->log, WLOG_TRACE,
907 "rdp_recv_autodetect_request_packet: headerLength=%" PRIu8
908 ", headerTypeId=%s, sequenceNumber=%" PRIu16
", requestType=%s",
909 autodetectReqPdu.headerLength, headerStr, autodetectReqPdu.sequenceNumber,
915 char rbuffer[128] = WINPR_C_ARRAY_INIT;
916 const char* requestTypeStr = autodetect_request_type_to_string_buffer(
917 autodetectReqPdu.requestType, rbuffer,
sizeof(rbuffer));
919 WLog_Print(autodetect->log, WLOG_WARN,
920 "Received a [MS-RDPBCGR] 2.2.14.1.1 RTT Measure Request [%s] "
921 "message but support was not enabled",
926 if (autodetectReqPdu.headerTypeId != TYPE_ID_AUTODETECT_REQUEST)
928 char rbuffer[128] = WINPR_C_ARRAY_INIT;
929 const char* requestTypeStr = autodetect_request_type_to_string_buffer(
930 autodetectReqPdu.requestType, rbuffer,
sizeof(rbuffer));
931 char hbuffer[128] = WINPR_C_ARRAY_INIT;
932 const char* headerStr =
933 autodetect_header_type_string(autodetectReqPdu.headerTypeId, hbuffer,
sizeof(hbuffer));
935 WLog_Print(autodetect->log, WLOG_ERROR,
936 "Received a [MS-RDPBCGR] 2.2.14.1.1 RTT Measure Request [%s] "
937 "message with invalid headerTypeId=%s",
938 requestTypeStr, headerStr);
942 if (!IFCALLRESULT(TRUE, autodetect->RequestReceived, autodetect, transport,
943 autodetectReqPdu.requestType, autodetectReqPdu.sequenceNumber))
946 switch (autodetectReqPdu.requestType)
948 case RDP_RTT_REQUEST_TYPE_CONTINUOUS:
949 case RDP_RTT_REQUEST_TYPE_CONNECTTIME:
952 autodetect_recv_rtt_measure_request(autodetect, transport, s, &autodetectReqPdu);
955 case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
956 case RDP_BW_START_REQUEST_TYPE_TUNNEL:
957 case RDP_BW_START_REQUEST_TYPE_CONNECTTIME:
959 success = autodetect_recv_bandwidth_measure_start(autodetect, transport, s,
963 case RDP_BW_PAYLOAD_REQUEST_TYPE:
965 success = autodetect_recv_bandwidth_measure_payload(autodetect, transport, s,
969 case RDP_BW_STOP_REQUEST_TYPE_CONNECTTIME:
970 case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
971 case RDP_BW_STOP_REQUEST_TYPE_TUNNEL:
974 autodetect_recv_bandwidth_measure_stop(autodetect, transport, s, &autodetectReqPdu);
977 case RDP_NETCHAR_RESULTS_0x0840:
978 case RDP_NETCHAR_RESULTS_0x0880:
979 case RDP_NETCHAR_RESULTS_0x08C0:
981 success = autodetect_recv_netchar_request(autodetect, transport, s, &autodetectReqPdu);
985 WLog_Print(autodetect->log, WLOG_ERROR,
"Unknown requestType=0x%04" PRIx16,
986 autodetectReqPdu.requestType);
992 autodetect->state = FREERDP_AUTODETECT_STATE_REQUEST;
994 autodetect->state = FREERDP_AUTODETECT_STATE_FAIL;
995 return success ? STATE_RUN_SUCCESS : STATE_RUN_FAILED;
998state_run_t autodetect_recv_tunnel_request(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
1001 WINPR_ASSERT(autodetect);
1008 UINT16 requestType = 0;
1009 if (Stream_GetRemainingLength(s) >= 6)
1011 const BYTE* header = Stream_ConstPointer(s);
1012 requestType = winpr_Data_Get_UINT16(&header[4]);
1015 switch (requestType)
1017 case RDP_BW_START_REQUEST_TYPE_CONTINUOUS:
1018 case RDP_BW_STOP_REQUEST_TYPE_CONTINUOUS:
1019 case RDP_NETCHAR_RESULTS_0x0840:
1020 case RDP_NETCHAR_RESULTS_0x0880:
1021 case RDP_NETCHAR_RESULTS_0x08C0:
1022 return autodetect_recv_request_packet(autodetect, transport, s);
1025 WLog_Print(autodetect->log, WLOG_DEBUG,
1026 "ignoring auto-detect request 0x%04" PRIx16
" in a tunnel subheader",
1028 return STATE_RUN_SUCCESS;
1032state_run_t autodetect_recv_response_packet(rdpAutoDetect* autodetect, RDP_TRANSPORT_TYPE transport,
1035 AUTODETECT_RSP_PDU autodetectRspPdu = WINPR_C_ARRAY_INIT;
1036 const rdpSettings* settings =
nullptr;
1037 BOOL success = FALSE;
1039 WINPR_ASSERT(autodetect);
1040 WINPR_ASSERT(autodetect->context);
1043 settings = autodetect->context->settings;
1044 WINPR_ASSERT(settings);
1046 if (!Stream_CheckAndLogRequiredLengthWLog(autodetect->log, s, 6))
1049 Stream_Read_UINT8(s, autodetectRspPdu.headerLength);
1050 Stream_Read_UINT8(s, autodetectRspPdu.headerTypeId);
1051 Stream_Read_UINT16(s, autodetectRspPdu.sequenceNumber);
1052 Stream_Read_UINT16(s, autodetectRspPdu.responseType);
1054 if (WLog_IsLevelActive(autodetect->log, WLOG_TRACE))
1056 char rbuffer[128] = WINPR_C_ARRAY_INIT;
1057 const char* requestStr = autodetect_request_type_to_string_buffer(
1058 autodetectRspPdu.responseType, rbuffer,
sizeof(rbuffer));
1059 char hbuffer[128] = WINPR_C_ARRAY_INIT;
1060 const char* headerStr =
1061 autodetect_header_type_string(autodetectRspPdu.headerTypeId, hbuffer,
sizeof(hbuffer));
1063 WLog_Print(autodetect->log, WLOG_TRACE,
1064 "rdp_recv_autodetect_response_packet: headerLength=%" PRIu8
", headerTypeId=%s"
1065 ", sequenceNumber=%" PRIu16
", requestType=%s",
1066 autodetectRspPdu.headerLength, headerStr, autodetectRspPdu.sequenceNumber,
1072 char rbuffer[128] = WINPR_C_ARRAY_INIT;
1074 const char* requestStr = autodetect_request_type_to_string_buffer(
1075 autodetectRspPdu.responseType, rbuffer,
sizeof(rbuffer));
1077 WLog_Print(autodetect->log, WLOG_WARN,
1078 "Received a [MS-RDPBCGR] 2.2.14.2.1 RTT Measure Response [%s] "
1079 "message but support was not enabled",
1081 return STATE_RUN_FAILED;
1084 if (autodetectRspPdu.headerTypeId != TYPE_ID_AUTODETECT_RESPONSE)
1086 char rbuffer[128] = WINPR_C_ARRAY_INIT;
1087 const char* requestStr = autodetect_request_type_to_string_buffer(
1088 autodetectRspPdu.responseType, rbuffer,
sizeof(rbuffer));
1089 char hbuffer[128] = WINPR_C_ARRAY_INIT;
1090 const char* headerStr =
1091 autodetect_header_type_string(autodetectRspPdu.headerTypeId, hbuffer,
sizeof(hbuffer));
1092 WLog_Print(autodetect->log, WLOG_ERROR,
1093 "Received a [MS-RDPBCGR] 2.2.14.2.1 RTT Measure Response [%s] "
1094 "message with invalid headerTypeId=%s",
1095 requestStr, headerStr);
1099 if (!IFCALLRESULT(TRUE, autodetect->ResponseReceived, autodetect, transport,
1100 autodetectRspPdu.responseType, autodetectRspPdu.sequenceNumber))
1103 switch (autodetectRspPdu.responseType)
1105 case RDP_RTT_RESPONSE_TYPE:
1108 autodetect_recv_rtt_measure_response(autodetect, transport, s, &autodetectRspPdu);
1111 case RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME:
1112 case RDP_BW_RESULTS_RESPONSE_TYPE_CONTINUOUS:
1114 success = autodetect_recv_bandwidth_measure_results(autodetect, transport, s,
1118 case RDP_NETCHAR_SYNC_RESPONSE_TYPE:
1120 success = autodetect_recv_netchar_sync(autodetect, transport, s, &autodetectRspPdu);
1124 WLog_Print(autodetect->log, WLOG_ERROR,
"Unknown responseType=0x%04" PRIx16,
1125 autodetectRspPdu.responseType);
1132 if (autodetectRspPdu.responseType == RDP_BW_RESULTS_RESPONSE_TYPE_CONNECTTIME)
1133 autodetect->state = FREERDP_AUTODETECT_STATE_COMPLETE;
1135 autodetect->state = FREERDP_AUTODETECT_STATE_RESPONSE;
1138 autodetect->state = FREERDP_AUTODETECT_STATE_FAIL;
1140 return success ? STATE_RUN_SUCCESS : STATE_RUN_FAILED;
1143void autodetect_on_connect_time_auto_detect_begin(rdpAutoDetect* autodetect)
1145 WINPR_ASSERT(autodetect);
1146 WINPR_ASSERT(autodetect->OnConnectTimeAutoDetectBegin);
1148 autodetect->state = autodetect->OnConnectTimeAutoDetectBegin(autodetect);
1151void autodetect_on_connect_time_auto_detect_progress(rdpAutoDetect* autodetect)
1153 WINPR_ASSERT(autodetect);
1154 WINPR_ASSERT(autodetect->OnConnectTimeAutoDetectProgress);
1156 autodetect->state = autodetect->OnConnectTimeAutoDetectProgress(autodetect);
1159rdpAutoDetect* autodetect_new(rdpContext* context)
1161 rdpAutoDetect* autoDetect = (rdpAutoDetect*)calloc(1,
sizeof(rdpAutoDetect));
1164 autoDetect->context = context;
1165 autoDetect->log = WLog_Get(AUTODETECT_TAG);
1170void autodetect_free(rdpAutoDetect* autoDetect)
1175void autodetect_register_server_callbacks(rdpAutoDetect* autodetect)
1177 WINPR_ASSERT(autodetect);
1179 autodetect->RTTMeasureRequest = autodetect_send_rtt_measure_request;
1180 autodetect->BandwidthMeasureStart = autodetect_send_bandwidth_measure_start;
1181 autodetect->BandwidthMeasurePayload = autodetect_send_bandwidth_measure_payload;
1182 autodetect->BandwidthMeasureStop = autodetect_send_bandwidth_measure_stop;
1183 autodetect->NetworkCharacteristicsResult = autodetect_send_netchar_result;
1189 autodetect->OnConnectTimeAutoDetectBegin = autodetect_on_connect_time_auto_detect_begin_default;
1190 autodetect->OnConnectTimeAutoDetectProgress =
1191 autodetect_on_connect_time_auto_detect_progress_default;
1194FREERDP_AUTODETECT_STATE autodetect_get_state(rdpAutoDetect* autodetect)
1196 WINPR_ASSERT(autodetect);
1197 return autodetect->state;
1200rdpAutoDetect* autodetect_get(rdpContext* context)
1202 WINPR_ASSERT(context);
1203 WINPR_ASSERT(context->rdp);
1204 return context->rdp->autodetect;
WINPR_ATTR_NODISCARD FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.