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