mirror of
https://github.com/morgan9e/grd
synced 2026-04-14 00:14:18 +09:00
644 lines
22 KiB
C
644 lines
22 KiB
C
/*
|
|
* Copyright (C) 2023 Pascal Nowack
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "grd-rdp-connect-time-autodetection.h"
|
|
|
|
#define CT_BW_MAX_TOLERABLE_RESPONSE_LATENCY_US (400 * 1000)
|
|
#define CT_BW_MAX_TOLERABLE_TIME_DELTA_MS 100
|
|
|
|
#define CT_N_PINGS 10
|
|
#define CT_PING_INTERVAL_MS 10
|
|
|
|
#define BW_MEASURE_SEQUENCE_NUMBER 0
|
|
#define CT_NON_RTT_SEQUENCE_NUMBER 0
|
|
|
|
typedef enum
|
|
{
|
|
CT_AUTODETECT_STATE_NONE,
|
|
CT_AUTODETECT_STATE_MEASURE_BW_1,
|
|
CT_AUTODETECT_STATE_MEASURE_BW_2,
|
|
CT_AUTODETECT_STATE_MEASURE_BW_3,
|
|
CT_AUTODETECT_STATE_AWAIT_BW_RESULT_1,
|
|
CT_AUTODETECT_STATE_AWAIT_BW_RESULT_2,
|
|
CT_AUTODETECT_STATE_AWAIT_BW_RESULT_3,
|
|
CT_AUTODETECT_STATE_START_RTT_DETECTION,
|
|
CT_AUTODETECT_STATE_AWAIT_LAST_RTT_RESPONSE,
|
|
CT_AUTODETECT_STATE_SEND_NET_CHAR_RESULT,
|
|
CT_AUTODETECT_STATE_COMPLETE,
|
|
} CtAutodetectState;
|
|
|
|
struct _GrdRdpConnectTimeAutodetection
|
|
{
|
|
GObject parent;
|
|
|
|
GrdRdpNetworkAutodetection *network_autodetection;
|
|
rdpAutoDetect *rdp_autodetect;
|
|
gboolean protocol_stopped;
|
|
|
|
GMutex ct_autodetection_mutex;
|
|
CtAutodetectState state;
|
|
|
|
GSource *sync_source;
|
|
GCond net_char_sync_cond;
|
|
GMutex net_char_sync_mutex;
|
|
gboolean pending_net_char_sync;
|
|
|
|
GSource *ping_source;
|
|
uint32_t pending_pings;
|
|
gboolean pending_last_sequence_number;
|
|
uint16_t last_sequence_number;
|
|
|
|
int64_t base_round_trip_time_us;
|
|
int64_t avg_round_trip_time_us;
|
|
|
|
int64_t bw_measure_time_us;
|
|
|
|
uint32_t last_time_delta_ms;
|
|
uint32_t last_byte_count;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GrdRdpConnectTimeAutodetection, grd_rdp_connect_time_autodetection,
|
|
G_TYPE_OBJECT)
|
|
|
|
gboolean
|
|
grd_rdp_connect_time_autodetection_is_complete (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
g_autoptr (GMutexLocker) locker = NULL;
|
|
|
|
locker = g_mutex_locker_new (&ct_autodetection->ct_autodetection_mutex);
|
|
return ct_autodetection->state == CT_AUTODETECT_STATE_COMPLETE;
|
|
}
|
|
|
|
static void
|
|
determine_bw_measure_payloads (GrdRdpConnectTimeAutodetection *ct_autodetection,
|
|
uint16_t *payload_lengths,
|
|
uint32_t *n_payloads)
|
|
{
|
|
switch (ct_autodetection->state)
|
|
{
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_1:
|
|
*payload_lengths = 15 * 1024 + 512 + 256 + 128 + 64;
|
|
*n_payloads = 1;
|
|
break;
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_2:
|
|
*payload_lengths = 15 * 1024 + 512 + 256 + 128 + 64;
|
|
*n_payloads = 4;
|
|
break;
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_3:
|
|
*payload_lengths = 15 * 1024 + 512 + 256 + 128 + 64;
|
|
*n_payloads = 16;
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
static CtAutodetectState
|
|
get_next_bw_measure_state (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
switch (ct_autodetection->state)
|
|
{
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_1:
|
|
return CT_AUTODETECT_STATE_AWAIT_BW_RESULT_1;
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_2:
|
|
return CT_AUTODETECT_STATE_AWAIT_BW_RESULT_2;
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_3:
|
|
return CT_AUTODETECT_STATE_AWAIT_BW_RESULT_3;
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_1:
|
|
return CT_AUTODETECT_STATE_MEASURE_BW_2;
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_2:
|
|
return CT_AUTODETECT_STATE_MEASURE_BW_3;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
return CT_AUTODETECT_STATE_NONE;
|
|
}
|
|
|
|
static void
|
|
measure_connect_time_bandwidth (GrdRdpConnectTimeAutodetection *ct_autodetection,
|
|
uint16_t payload_lengths,
|
|
uint32_t n_payloads)
|
|
{
|
|
rdpAutoDetect *rdp_autodetect = ct_autodetection->rdp_autodetect;
|
|
uint32_t i;
|
|
|
|
g_assert (payload_lengths > 0);
|
|
g_assert (n_payloads >= 1);
|
|
|
|
rdp_autodetect->BandwidthMeasureStart (rdp_autodetect, RDP_TRANSPORT_TCP,
|
|
BW_MEASURE_SEQUENCE_NUMBER);
|
|
for (i = 0; i < n_payloads - 1; ++i)
|
|
{
|
|
rdp_autodetect->BandwidthMeasurePayload (rdp_autodetect,
|
|
RDP_TRANSPORT_TCP,
|
|
BW_MEASURE_SEQUENCE_NUMBER,
|
|
payload_lengths);
|
|
}
|
|
rdp_autodetect->BandwidthMeasureStop (rdp_autodetect, RDP_TRANSPORT_TCP,
|
|
BW_MEASURE_SEQUENCE_NUMBER,
|
|
payload_lengths);
|
|
}
|
|
|
|
static const char *
|
|
ct_autodetect_state_to_string (CtAutodetectState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case CT_AUTODETECT_STATE_NONE:
|
|
return "NONE";
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_1:
|
|
return "MEASURE_BW_1";
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_2:
|
|
return "MEASURE_BW_2";
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_3:
|
|
return "MEASURE_BW_3";
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_1:
|
|
return "AWAIT_BW_RESULT_1";
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_2:
|
|
return "AWAIT_BW_RESULT_2";
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_3:
|
|
return "AWAIT_BW_RESULT_3";
|
|
case CT_AUTODETECT_STATE_START_RTT_DETECTION:
|
|
return "START_RTT_DETECTION";
|
|
case CT_AUTODETECT_STATE_AWAIT_LAST_RTT_RESPONSE:
|
|
return "AWAIT_LAST_RTT_RESPONSE";
|
|
case CT_AUTODETECT_STATE_SEND_NET_CHAR_RESULT:
|
|
return "SEND_NET_CHAR_RESULT";
|
|
case CT_AUTODETECT_STATE_COMPLETE:
|
|
return "COMPLETE";
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static void
|
|
transition_to_state (GrdRdpConnectTimeAutodetection *ct_autodetection,
|
|
CtAutodetectState state)
|
|
{
|
|
g_assert (ct_autodetection->state != state);
|
|
|
|
g_debug ("[RDP] Connect-Time Autodetect: Updating state from %s to %s",
|
|
ct_autodetect_state_to_string (ct_autodetection->state),
|
|
ct_autodetect_state_to_string (state));
|
|
|
|
ct_autodetection->state = state;
|
|
}
|
|
|
|
static void
|
|
last_sequence_number_ready (gpointer user_data,
|
|
uint16_t sequence_number)
|
|
{
|
|
GrdRdpConnectTimeAutodetection *ct_autodetection = user_data;
|
|
|
|
g_mutex_lock (&ct_autodetection->ct_autodetection_mutex);
|
|
ct_autodetection->last_sequence_number = sequence_number;
|
|
ct_autodetection->pending_last_sequence_number = FALSE;
|
|
g_mutex_unlock (&ct_autodetection->ct_autodetection_mutex);
|
|
}
|
|
|
|
static gboolean
|
|
emit_ping (gpointer user_data)
|
|
{
|
|
GrdRdpConnectTimeAutodetection *ct_autodetection = user_data;
|
|
GrdRdpNetworkAutodetection *network_autodetection =
|
|
ct_autodetection->network_autodetection;
|
|
GrdRdpNwAutodetectSequenceNumberReadyCallback sequence_number_ready = NULL;
|
|
|
|
g_assert (!ct_autodetection->protocol_stopped);
|
|
|
|
g_assert (ct_autodetection->pending_pings > 0);
|
|
--ct_autodetection->pending_pings;
|
|
|
|
if (ct_autodetection->pending_pings == 0)
|
|
{
|
|
g_mutex_lock (&ct_autodetection->ct_autodetection_mutex);
|
|
g_clear_pointer (&ct_autodetection->ping_source, g_source_unref);
|
|
g_mutex_unlock (&ct_autodetection->ct_autodetection_mutex);
|
|
|
|
sequence_number_ready = last_sequence_number_ready;
|
|
}
|
|
|
|
grd_rdp_network_autodetection_emit_ping (network_autodetection,
|
|
sequence_number_ready,
|
|
ct_autodetection);
|
|
|
|
if (ct_autodetection->pending_pings == 0)
|
|
return G_SOURCE_REMOVE;
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
static void
|
|
start_ping_emission (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
emit_ping (ct_autodetection);
|
|
|
|
g_mutex_lock (&ct_autodetection->ct_autodetection_mutex);
|
|
ct_autodetection->ping_source = g_timeout_source_new (CT_PING_INTERVAL_MS);
|
|
|
|
g_source_set_callback (ct_autodetection->ping_source, emit_ping,
|
|
ct_autodetection, NULL);
|
|
g_source_attach (ct_autodetection->ping_source, NULL);
|
|
g_mutex_unlock (&ct_autodetection->ct_autodetection_mutex);
|
|
}
|
|
|
|
static void
|
|
notify_network_characteristics_result (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
rdpAutoDetect *rdp_autodetect = ct_autodetection->rdp_autodetect;
|
|
rdpNetworkCharacteristicsResult result = {};
|
|
uint64_t bit_count;
|
|
uint32_t bandwidth_kbits;
|
|
|
|
bit_count = ((uint64_t) ct_autodetection->last_byte_count) * UINT64_C (8);
|
|
bandwidth_kbits = bit_count / MAX (ct_autodetection->last_time_delta_ms, 1);
|
|
|
|
result.type = RDP_NETCHAR_RESULT_TYPE_BASE_RTT_BW_AVG_RTT;
|
|
result.baseRTT = ct_autodetection->base_round_trip_time_us / 1000;
|
|
result.averageRTT = ct_autodetection->avg_round_trip_time_us / 1000;
|
|
result.bandwidth = bandwidth_kbits;
|
|
|
|
rdp_autodetect->NetworkCharacteristicsResult (rdp_autodetect,
|
|
RDP_TRANSPORT_TCP,
|
|
CT_NON_RTT_SEQUENCE_NUMBER,
|
|
&result);
|
|
}
|
|
|
|
static FREERDP_AUTODETECT_STATE
|
|
detect_network_characteristics (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
CtAutodetectState new_state = CT_AUTODETECT_STATE_NONE;
|
|
g_autoptr (GMutexLocker) locker = NULL;
|
|
gboolean pending_bw_request = FALSE;
|
|
gboolean pending_ping_emission = FALSE;
|
|
gboolean pending_net_char_result = FALSE;
|
|
uint16_t payload_lengths = 0;
|
|
uint32_t n_payloads = 1;
|
|
|
|
locker = g_mutex_locker_new (&ct_autodetection->ct_autodetection_mutex);
|
|
switch (ct_autodetection->state)
|
|
{
|
|
case CT_AUTODETECT_STATE_NONE:
|
|
g_assert_not_reached ();
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_1:
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_2:
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_3:
|
|
determine_bw_measure_payloads (ct_autodetection,
|
|
&payload_lengths, &n_payloads);
|
|
ct_autodetection->bw_measure_time_us = g_get_monotonic_time ();
|
|
new_state = get_next_bw_measure_state (ct_autodetection);
|
|
pending_bw_request = TRUE;
|
|
break;
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_1:
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_2:
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_3:
|
|
return FREERDP_AUTODETECT_STATE_REQUEST;
|
|
case CT_AUTODETECT_STATE_START_RTT_DETECTION:
|
|
g_assert (!ct_autodetection->ping_source);
|
|
g_assert (ct_autodetection->pending_pings >= 2);
|
|
|
|
new_state = CT_AUTODETECT_STATE_AWAIT_LAST_RTT_RESPONSE;
|
|
pending_ping_emission = TRUE;
|
|
break;
|
|
case CT_AUTODETECT_STATE_AWAIT_LAST_RTT_RESPONSE:
|
|
return FREERDP_AUTODETECT_STATE_REQUEST;
|
|
case CT_AUTODETECT_STATE_SEND_NET_CHAR_RESULT:
|
|
new_state = CT_AUTODETECT_STATE_COMPLETE;
|
|
pending_net_char_result = TRUE;
|
|
break;
|
|
case CT_AUTODETECT_STATE_COMPLETE:
|
|
return FREERDP_AUTODETECT_STATE_COMPLETE;
|
|
}
|
|
|
|
g_assert (new_state != CT_AUTODETECT_STATE_NONE);
|
|
transition_to_state (ct_autodetection, new_state);
|
|
g_clear_pointer (&locker, g_mutex_locker_free);
|
|
|
|
if (pending_bw_request)
|
|
{
|
|
measure_connect_time_bandwidth (ct_autodetection, payload_lengths,
|
|
n_payloads);
|
|
}
|
|
|
|
if (pending_ping_emission)
|
|
start_ping_emission (ct_autodetection);
|
|
|
|
if (pending_net_char_result)
|
|
{
|
|
notify_network_characteristics_result (ct_autodetection);
|
|
return FREERDP_AUTODETECT_STATE_COMPLETE;
|
|
}
|
|
|
|
return FREERDP_AUTODETECT_STATE_REQUEST;
|
|
}
|
|
|
|
void
|
|
grd_rdp_connect_time_autodetection_start_detection (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
g_mutex_lock (&ct_autodetection->ct_autodetection_mutex);
|
|
g_assert (ct_autodetection->state == CT_AUTODETECT_STATE_NONE);
|
|
|
|
transition_to_state (ct_autodetection, CT_AUTODETECT_STATE_MEASURE_BW_1);
|
|
g_mutex_unlock (&ct_autodetection->ct_autodetection_mutex);
|
|
|
|
detect_network_characteristics (ct_autodetection);
|
|
}
|
|
|
|
void
|
|
grd_rdp_connect_time_autodetection_invoke_shutdown (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
g_mutex_lock (&ct_autodetection->net_char_sync_mutex);
|
|
ct_autodetection->protocol_stopped = TRUE;
|
|
g_cond_signal (&ct_autodetection->net_char_sync_cond);
|
|
g_mutex_unlock (&ct_autodetection->net_char_sync_mutex);
|
|
}
|
|
|
|
static uint32_t
|
|
get_bw_measure_phase (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
switch (ct_autodetection->state)
|
|
{
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_1:
|
|
return 1;
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_2:
|
|
return 2;
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_3:
|
|
return 3;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
grd_rdp_connect_time_autodetection_notify_bw_measure_results (GrdRdpConnectTimeAutodetection *ct_autodetection,
|
|
uint32_t time_delta_ms,
|
|
uint32_t byte_count)
|
|
{
|
|
CtAutodetectState new_state = CT_AUTODETECT_STATE_NONE;
|
|
g_autoptr (GMutexLocker) locker = NULL;
|
|
int64_t current_time_us;
|
|
int64_t response_latency_us;
|
|
|
|
locker = g_mutex_locker_new (&ct_autodetection->ct_autodetection_mutex);
|
|
switch (ct_autodetection->state)
|
|
{
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_1:
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_2:
|
|
current_time_us = g_get_monotonic_time ();
|
|
response_latency_us = current_time_us - ct_autodetection->bw_measure_time_us;
|
|
|
|
if (response_latency_us < CT_BW_MAX_TOLERABLE_RESPONSE_LATENCY_US &&
|
|
time_delta_ms < CT_BW_MAX_TOLERABLE_TIME_DELTA_MS)
|
|
new_state = get_next_bw_measure_state (ct_autodetection);
|
|
else
|
|
new_state = CT_AUTODETECT_STATE_START_RTT_DETECTION;
|
|
break;
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_3:
|
|
new_state = CT_AUTODETECT_STATE_START_RTT_DETECTION;
|
|
break;
|
|
default:
|
|
g_warning ("[RDP] Connect-Time Autodetect: Received stray Bandwidth "
|
|
"Measure Results PDU (current state: %s)",
|
|
ct_autodetect_state_to_string (ct_autodetection->state));
|
|
return FALSE;
|
|
}
|
|
|
|
g_debug ("[RDP] Connect-Time Autodetect: BW Measure Phase %u: "
|
|
"time delta: %ums, byte count: %u => %uKB/s",
|
|
get_bw_measure_phase (ct_autodetection), time_delta_ms, byte_count,
|
|
byte_count / MAX (time_delta_ms, 1));
|
|
|
|
ct_autodetection->last_time_delta_ms = time_delta_ms;
|
|
ct_autodetection->last_byte_count = byte_count;
|
|
|
|
g_assert (new_state != CT_AUTODETECT_STATE_NONE);
|
|
transition_to_state (ct_autodetection, new_state);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
grd_rdp_connect_time_autodetection_notify_rtt_measure_response (GrdRdpConnectTimeAutodetection *ct_autodetection,
|
|
uint16_t sequence_number,
|
|
int64_t base_round_trip_time_us,
|
|
int64_t avg_round_trip_time_us)
|
|
{
|
|
g_autoptr (GMutexLocker) locker = NULL;
|
|
|
|
locker = g_mutex_locker_new (&ct_autodetection->ct_autodetection_mutex);
|
|
if (ct_autodetection->pending_last_sequence_number ||
|
|
ct_autodetection->last_sequence_number != sequence_number)
|
|
return;
|
|
|
|
g_assert (ct_autodetection->state == CT_AUTODETECT_STATE_AWAIT_LAST_RTT_RESPONSE);
|
|
|
|
g_debug ("[RDP] Connect-Time Autodetect: base RTT: %lims, average RTT: %lims",
|
|
base_round_trip_time_us / 1000, avg_round_trip_time_us / 1000);
|
|
|
|
ct_autodetection->base_round_trip_time_us = base_round_trip_time_us;
|
|
ct_autodetection->avg_round_trip_time_us = avg_round_trip_time_us;
|
|
|
|
transition_to_state (ct_autodetection, CT_AUTODETECT_STATE_SEND_NET_CHAR_RESULT);
|
|
}
|
|
|
|
static gboolean
|
|
sync_with_main_context (gpointer user_data)
|
|
{
|
|
GrdRdpConnectTimeAutodetection *ct_autodetection = user_data;
|
|
|
|
g_mutex_lock (&ct_autodetection->ct_autodetection_mutex);
|
|
if (ct_autodetection->ping_source)
|
|
{
|
|
g_source_destroy (ct_autodetection->ping_source);
|
|
g_clear_pointer (&ct_autodetection->ping_source, g_source_unref);
|
|
}
|
|
g_mutex_unlock (&ct_autodetection->ct_autodetection_mutex);
|
|
|
|
g_mutex_lock (&ct_autodetection->net_char_sync_mutex);
|
|
g_clear_pointer (&ct_autodetection->sync_source, g_source_unref);
|
|
|
|
ct_autodetection->pending_net_char_sync = FALSE;
|
|
g_cond_signal (&ct_autodetection->net_char_sync_cond);
|
|
g_mutex_unlock (&ct_autodetection->net_char_sync_mutex);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
sync_ct_autodetect_handling (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
g_mutex_lock (&ct_autodetection->net_char_sync_mutex);
|
|
ct_autodetection->pending_net_char_sync = TRUE;
|
|
|
|
ct_autodetection->sync_source = g_idle_source_new ();
|
|
g_source_set_callback (ct_autodetection->sync_source, sync_with_main_context,
|
|
ct_autodetection, NULL);
|
|
g_source_attach (ct_autodetection->sync_source, NULL);
|
|
|
|
while (!ct_autodetection->protocol_stopped &&
|
|
ct_autodetection->pending_net_char_sync)
|
|
{
|
|
g_cond_wait (&ct_autodetection->net_char_sync_cond,
|
|
&ct_autodetection->net_char_sync_mutex);
|
|
}
|
|
g_mutex_unlock (&ct_autodetection->net_char_sync_mutex);
|
|
}
|
|
|
|
static BOOL
|
|
autodetect_network_characteristics_sync (rdpAutoDetect *rdp_autodetect,
|
|
RDP_TRANSPORT_TYPE transport_type,
|
|
uint16_t sequenceNumber,
|
|
uint32_t bandwidth,
|
|
uint32_t rtt)
|
|
{
|
|
GrdRdpNetworkAutodetection *network_autodetection = rdp_autodetect->custom;
|
|
GrdRdpConnectTimeAutodetection *ct_autodetection =
|
|
grd_rdp_network_autodetection_get_ct_handler (network_autodetection);
|
|
g_autoptr (GMutexLocker) locker = NULL;
|
|
gboolean pending_sync = FALSE;
|
|
|
|
locker = g_mutex_locker_new (&ct_autodetection->ct_autodetection_mutex);
|
|
switch (ct_autodetection->state)
|
|
{
|
|
case CT_AUTODETECT_STATE_NONE:
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_1:
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_2:
|
|
case CT_AUTODETECT_STATE_MEASURE_BW_3:
|
|
g_assert_not_reached ();
|
|
break;
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_1:
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_2:
|
|
case CT_AUTODETECT_STATE_AWAIT_BW_RESULT_3:
|
|
g_assert (!pending_sync);
|
|
break;
|
|
case CT_AUTODETECT_STATE_START_RTT_DETECTION:
|
|
g_assert_not_reached ();
|
|
break;
|
|
case CT_AUTODETECT_STATE_AWAIT_LAST_RTT_RESPONSE:
|
|
pending_sync = TRUE;
|
|
break;
|
|
case CT_AUTODETECT_STATE_SEND_NET_CHAR_RESULT:
|
|
g_assert_not_reached ();
|
|
break;
|
|
case CT_AUTODETECT_STATE_COMPLETE:
|
|
g_warning ("[RDP] Connect-Time Autodetect: Received stray Network "
|
|
"Characteristics Sync PDU (current state: %s). Ignoring PDU...",
|
|
ct_autodetect_state_to_string (ct_autodetection->state));
|
|
return TRUE;
|
|
}
|
|
g_clear_pointer (&locker, g_mutex_locker_free);
|
|
|
|
if (pending_sync)
|
|
sync_ct_autodetect_handling (ct_autodetection);
|
|
|
|
g_debug ("[RDP] Connect-Time Autodetect: Received Sync PDU: "
|
|
"RTT: %ums, bandwidth: %uKBit/s", rtt, bandwidth);
|
|
|
|
locker = g_mutex_locker_new (&ct_autodetection->ct_autodetection_mutex);
|
|
transition_to_state (ct_autodetection, CT_AUTODETECT_STATE_COMPLETE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static FREERDP_AUTODETECT_STATE
|
|
autodetect_on_connect_time_autodetect_progress (rdpAutoDetect *rdp_autodetect)
|
|
{
|
|
GrdRdpNetworkAutodetection *network_autodetection = rdp_autodetect->custom;
|
|
GrdRdpConnectTimeAutodetection *ct_autodetection =
|
|
grd_rdp_network_autodetection_get_ct_handler (network_autodetection);
|
|
|
|
return detect_network_characteristics (ct_autodetection);
|
|
}
|
|
|
|
GrdRdpConnectTimeAutodetection *
|
|
grd_rdp_connect_time_autodetection_new (GrdRdpNetworkAutodetection *network_autodetection,
|
|
rdpAutoDetect *rdp_autodetect)
|
|
{
|
|
GrdRdpConnectTimeAutodetection *ct_autodetection;
|
|
|
|
ct_autodetection = g_object_new (GRD_TYPE_RDP_CONNECT_TIME_AUTODETECTION, NULL);
|
|
ct_autodetection->network_autodetection = network_autodetection;
|
|
ct_autodetection->rdp_autodetect = rdp_autodetect;
|
|
|
|
rdp_autodetect->NetworkCharacteristicsSync = autodetect_network_characteristics_sync;
|
|
rdp_autodetect->OnConnectTimeAutoDetectProgress = autodetect_on_connect_time_autodetect_progress;
|
|
|
|
return ct_autodetection;
|
|
}
|
|
|
|
static void
|
|
grd_rdp_connect_time_autodetection_dispose (GObject *object)
|
|
{
|
|
GrdRdpConnectTimeAutodetection *ct_autodetection = GRD_RDP_CONNECT_TIME_AUTODETECTION (object);
|
|
|
|
g_assert (ct_autodetection->protocol_stopped);
|
|
|
|
if (ct_autodetection->sync_source)
|
|
{
|
|
g_source_destroy (ct_autodetection->sync_source);
|
|
g_clear_pointer (&ct_autodetection->sync_source, g_source_unref);
|
|
}
|
|
if (ct_autodetection->ping_source)
|
|
{
|
|
g_source_destroy (ct_autodetection->ping_source);
|
|
g_clear_pointer (&ct_autodetection->ping_source, g_source_unref);
|
|
}
|
|
|
|
G_OBJECT_CLASS (grd_rdp_connect_time_autodetection_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
grd_rdp_connect_time_autodetection_finalize (GObject *object)
|
|
{
|
|
GrdRdpConnectTimeAutodetection *ct_autodetection = GRD_RDP_CONNECT_TIME_AUTODETECTION (object);
|
|
|
|
g_cond_clear (&ct_autodetection->net_char_sync_cond);
|
|
g_mutex_clear (&ct_autodetection->net_char_sync_mutex);
|
|
g_mutex_clear (&ct_autodetection->ct_autodetection_mutex);
|
|
|
|
G_OBJECT_CLASS (grd_rdp_connect_time_autodetection_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
grd_rdp_connect_time_autodetection_init (GrdRdpConnectTimeAutodetection *ct_autodetection)
|
|
{
|
|
ct_autodetection->state = CT_AUTODETECT_STATE_NONE;
|
|
|
|
ct_autodetection->pending_pings = CT_N_PINGS;
|
|
ct_autodetection->pending_last_sequence_number = TRUE;
|
|
|
|
g_mutex_init (&ct_autodetection->ct_autodetection_mutex);
|
|
g_mutex_init (&ct_autodetection->net_char_sync_mutex);
|
|
g_cond_init (&ct_autodetection->net_char_sync_cond);
|
|
}
|
|
|
|
static void
|
|
grd_rdp_connect_time_autodetection_class_init (GrdRdpConnectTimeAutodetectionClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->dispose = grd_rdp_connect_time_autodetection_dispose;
|
|
object_class->finalize = grd_rdp_connect_time_autodetection_finalize;
|
|
}
|