[arm] add retry callback for transport

If the connection is blocked due to some VM requiring spinup time before
being ready to use call the newly created callback RetryDialog.
This commit is contained in:
akallabeth 2023-09-14 09:35:06 +02:00 committed by akallabeth
parent ab111b07bc
commit bd595d363d
4 changed files with 77 additions and 25 deletions

View File

@ -88,6 +88,7 @@ static void set_default_callbacks(freerdp* instance)
instance->PresentGatewayMessage = client_cli_present_gateway_message;
instance->LogonErrorInfo = client_cli_logon_error_info;
instance->GetAccessToken = client_cli_get_access_token;
instance->RetryDialog = client_common_retry_dialog;
}
static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
@ -1189,6 +1190,48 @@ cleanup:
#endif
}
SSIZE_T client_common_retry_dialog(freerdp* instance, const char* what, size_t current,
void* userarg)
{
WINPR_UNUSED(instance);
WINPR_ASSERT(instance->context);
WINPR_UNUSED(userarg);
WINPR_ASSERT(instance);
WINPR_ASSERT(what);
if (strcmp(what, "arm-transport") != 0)
{
WLog_ERR(TAG, "Unknown module %s, aborting", what);
return -1;
}
if (current == 0)
WLog_INFO(TAG, "[%s] Starting your VM. It may take up to 5 minutes", what);
const rdpSettings* settings = instance->context->settings;
const BOOL enabled = freerdp_settings_get_bool(settings, FreeRDP_AutoReconnectionEnabled);
if (!enabled)
{
WLog_WARN(TAG, "Automatic reconnection disabled, terminating. Try to connect again later");
return -1;
}
const size_t max = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
const size_t delay = freerdp_settings_get_uint32(settings, FreeRDP_TcpConnectTimeout);
if (current >= max)
{
WLog_ERR(TAG,
"[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
"tech support for help if this keeps happening.",
what);
return -1;
}
WLog_INFO(TAG, "[%s] retry %" PRIuz "/%" PRIuz ", delaying %" PRIuz "ms before next attempt",
what, current, max, delay);
return delay;
}
BOOL client_auto_reconnect(freerdp* instance)
{
return client_auto_reconnect_ex(instance, NULL);

View File

@ -175,6 +175,9 @@ extern "C"
FREERDP_API BOOL client_common_get_access_token(freerdp* instance, const char* request,
char** token);
FREERDP_API SSIZE_T client_common_retry_dialog(freerdp* instance, const char* what,
size_t current, void* userarg);
FREERDP_API void
freerdp_client_OnChannelConnectedEventHandler(void* context,
const ChannelConnectedEventArgs* e);

View File

@ -136,6 +136,20 @@ extern "C"
typedef BOOL (*pGetAccessToken)(freerdp* instance, AccessTokenType tokenType, char** token,
size_t count, ...);
/** @brief Callback used to inform about a reconnection attempt
*
* @param instance The instance the information is for
* @param what A '\0' terminated string describing the module attempting to retry an operation
* @param current The current reconnection attempt, the first attempt will always have the
* value \b 0
* @param userarg An optional custom argument
*
* @return \b -1 in case of failure (attempts exceeded, ...) or a \b delay in [ms] to wait
* before the next attempt
*/
typedef SSIZE_T (*pRetryDialog)(freerdp* instance, const char* what, size_t current,
void* userarg);
/** @brief Callback used if user interaction is required to accept
* an unknown certificate.
*
@ -531,7 +545,9 @@ owned by rdpRdp */
ALIGN64 pGetAccessToken GetAccessToken; /* (offset 71)
Callback for obtaining an access token
for \b AccessTokenType authentication */
UINT64 paddingE[80 - 72]; /* 72 */
ALIGN64 pRetryDialog RetryDialog; /* (offset 72) Callback for displaying a dialog in case of
something needs a retry */
UINT64 paddingE[80 - 73]; /* 73 */
};
struct rdp_channel_handles

View File

@ -56,7 +56,6 @@
#include <cjson/cJSON.h>
#endif
#include <time.h>
#include <string.h>
struct rdp_arm
@ -73,9 +72,6 @@ typedef struct rdp_arm rdpArm;
#define TAG FREERDP_TAG("core.gateway.arm")
#ifdef WITH_AAD
static const UINT32 max_retries = 60;
static const UINT32 code_execution_interval = 10000;
static BOOL arm_tls_connect(rdpArm* arm, rdpTls* tls, int timeout)
{
WINPR_ASSERT(arm);
@ -839,22 +835,8 @@ static BOOL arm_handle_bad_request(rdpArm* arm, const HttpResponse* response, BO
if (strcmp(gateway_code_str->valuestring, "E_PROXY_ORCHESTRATION_LB_SESSIONHOST_DEALLOCATED") ==
0)
{
if (arm->gateway_retry >= max_retries)
{
WLog_ERR(TAG, "We couldnt connect because your VM failed to start. Try again later or "
"contact your tech support for help if this keeps happening.");
goto fail;
}
*retry = TRUE;
if (arm->gateway_retry == 0)
{
WLog_INFO(TAG, "Starting your VM. It may take up to 5 minutes");
}
else
{
WLog_INFO(TAG, "Waiting for remote PC");
}
WLog_DBG(TAG, "Starting your VM. It may take up to 5 minutes");
}
else
{
@ -959,13 +941,21 @@ BOOL arm_resolve_endpoint(rdpContext* context, DWORD timeout)
BOOL rc = FALSE;
do
{
if (retry && rc)
{
freerdp* instance = context->instance;
WINPR_ASSERT(instance);
const SSIZE_T delay = IFCALLRESULT(-1, instance->RetryDialog, instance, "arm-transport",
arm->gateway_retry, arm);
arm->gateway_retry++;
if (delay > 0)
{
WLog_DBG(TAG, "Delay for %" PRIdz "ms before next attempt", delay);
Sleep(delay);
}
}
rc = arm_handle_request(arm, &retry, timeout);
if (retry)
{
WLog_INFO(TAG, "Delay for %" PRIu32 "ms before next attempt");
Sleep(code_execution_interval);
}
} while (retry && rc);
arm_free(arm);
return rc;