[core,tcp] refactor freerdp_tcp_default_connect

This commit is contained in:
Armin Novak
2026-01-08 15:41:47 +01:00
parent 1b51752bbd
commit e65d488a51

View File

@@ -704,17 +704,21 @@ char* freerdp_tcp_address_to_string(const struct sockaddr_storage* addr, BOOL* p
return _strdup(ipAddress);
}
static char* freerdp_tcp_get_ip_address(int sockfd, BOOL* pIPv6)
static bool freerdp_tcp_get_ip_address(rdpSettings* settings, int sockfd)
{
WINPR_ASSERT(settings);
struct sockaddr_storage saddr = { 0 };
socklen_t length = sizeof(struct sockaddr_storage);
if (!freerdp_settings_set_string(settings, FreeRDP_ClientAddress, NULL))
return false;
if (sockfd < 0)
return false;
if (getsockname(sockfd, (struct sockaddr*)&saddr, &length) != 0)
{
return NULL;
}
return freerdp_tcp_address_to_string(&saddr, pIPv6);
return false;
settings->ClientAddress = freerdp_tcp_address_to_string(&saddr, &settings->IPv6Enabled);
return settings->ClientAddress != NULL;
}
char* freerdp_tcp_get_peer_address(SOCKET sockfd)
@@ -1116,13 +1120,121 @@ static int get_next_addrinfo(rdpContext* context, struct addrinfo* input, struct
fail:
freerdp_set_last_error_if_not(context, errorCode);
freeaddrinfo(input);
*result = NULL;
return -1;
}
static int freerdp_vsock_connect(rdpContext* context, const char* hostname, int port)
{
#if defined(HAVE_AF_VSOCK_H)
int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
if (sockfd < 0)
{
char buffer[256] = { 0 };
WLog_WARN(TAG, "socket(AF_VSOCK, SOCK_STREAM, 0) failed with %s [%d]",
winpr_strerror(errno, buffer, sizeof(buffer)));
freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
return -1;
}
struct sockaddr_vm addr = { 0 };
addr.svm_family = AF_VSOCK;
addr.svm_port = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_port), port);
errno = 0;
char* ptr = NULL;
unsigned long val = strtoul(hostname, &ptr, 10);
if (errno || (val > UINT32_MAX))
{
char ebuffer[256] = { 0 };
WLog_ERR(TAG, "could not extract port from '%s', value=%ul, error=%s", hostname, val,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
return -1;
}
addr.svm_cid = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_cid), val);
if (addr.svm_cid == 2)
{
addr.svm_flags = VMADDR_FLAG_TO_HOST;
}
if ((connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm))) == -1)
{
WLog_ERR(TAG, "failed to connect to %s", hostname);
return -1;
}
return sockfd;
#else
WLog_ERR(TAG, "Compiled without AF_VSOCK, '%s' not supported", hostname);
return -1;
#endif
}
static void log_connection_address(const char* hostname, struct addrinfo* addr)
{
WINPR_ASSERT(addr);
char* peerAddress =
freerdp_tcp_address_to_string((const struct sockaddr_storage*)addr->ai_addr, NULL);
if (peerAddress)
WLog_DBG(TAG, "resolved %s: try to connect to %s", hostname, peerAddress);
free(peerAddress);
}
static int freerdp_host_connect(rdpContext* context, const char* hostname, int port, DWORD timeout)
{
int sockfd = -1;
struct addrinfo* addr = NULL;
struct addrinfo* result = freerdp_tcp_resolve_host(hostname, port, 0);
if (!result)
{
freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
return -1;
}
freerdp_set_last_error_log(context, 0);
/* By default we take the first returned entry.
* * If PreferIPv6OverIPv4 = TRUE we force to IPv6 if there
* is such an address available, but fall back to first if not found
*/
const int rc = get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
if (rc < 0)
goto fail;
do
{
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sockfd < 0)
{
const int lrc =
get_next_addrinfo(context, addr->ai_next, &addr, FREERDP_ERROR_CONNECT_FAILED);
if (lrc < 0)
goto fail;
}
} while (sockfd < 0);
log_connection_address(hostname, addr);
if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen, timeout))
{
close(sockfd);
sockfd = -1;
freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
WLog_ERR(TAG, "failed to connect to %s", hostname);
goto fail;
}
fail:
freeaddrinfo(result);
return sockfd;
}
int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, const char* hostname,
int port, DWORD timeout)
{
int sockfd = 0;
int sockfd = -1;
BOOL ipcSocket = FALSE;
BOOL useExternalDefinedSocket = FALSE;
@@ -1153,53 +1265,9 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
else if (useExternalDefinedSocket)
sockfd = port;
else if (vsock)
{
#if defined(HAVE_AF_VSOCK_H)
hostname = vsock;
sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
if (sockfd < 0)
{
char buffer[256] = { 0 };
WLog_WARN(TAG, "socket(AF_VSOCK, SOCK_STREAM, 0) failed with %s [%d]",
winpr_strerror(errno, buffer, sizeof(buffer)));
freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
return -1;
}
struct sockaddr_vm addr = { 0 };
addr.svm_family = AF_VSOCK;
addr.svm_port = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_port), port);
errno = 0;
char* ptr = NULL;
unsigned long val = strtoul(hostname, &ptr, 10);
if (errno || (val > UINT32_MAX))
{
char ebuffer[256] = { 0 };
WLog_ERR(TAG, "could not extract port from '%s', value=%ul, error=%s", hostname, val,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
return -1;
}
addr.svm_cid = WINPR_ASSERTING_INT_CAST(typeof(addr.svm_cid), val);
if (addr.svm_cid == 2)
{
addr.svm_flags = VMADDR_FLAG_TO_HOST;
}
if ((connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm))) == -1)
{
WLog_ERR(TAG, "failed to connect to %s", hostname);
return -1;
}
#else
WLog_ERR(TAG, "Compiled without AF_VSOCK, '%s' not supported", hostname);
return -1;
#endif
}
sockfd = freerdp_vsock_connect(context, vsock, port);
else
{
sockfd = -1;
if (!settings->GatewayEnabled)
{
if (!freerdp_tcp_is_hostname_resolvable(context, hostname) ||
@@ -1216,72 +1284,12 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
}
if (sockfd <= 0)
{
char* peerAddress = NULL;
struct addrinfo* addr = NULL;
struct addrinfo* result = NULL;
result = freerdp_tcp_resolve_host(hostname, port, 0);
if (!result)
{
freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
return -1;
}
freerdp_set_last_error_log(context, 0);
/* By default we take the first returned entry.
*
* If PreferIPv6OverIPv4 = TRUE we force to IPv6 if there
* is such an address available, but fall back to first if not found
*/
const int rc =
get_next_addrinfo(context, result, &addr, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
if (rc < 0)
return rc;
do
{
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sockfd < 0)
{
const int lrc = get_next_addrinfo(context, addr->ai_next, &addr,
FREERDP_ERROR_CONNECT_FAILED);
if (lrc < 0)
return lrc;
}
} while (sockfd < 0);
if ((peerAddress = freerdp_tcp_address_to_string(
(const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL)
{
WLog_DBG(TAG, "connecting to peer %s", peerAddress);
free(peerAddress);
}
if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
timeout))
{
freeaddrinfo(result);
close(sockfd);
freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
WLog_ERR(TAG, "failed to connect to %s", hostname);
return -1;
}
freeaddrinfo(result);
}
sockfd = freerdp_host_connect(context, hostname, port, timeout);
}
if (!vsock)
{
free(settings->ClientAddress);
settings->ClientAddress = freerdp_tcp_get_ip_address(sockfd, &settings->IPv6Enabled);
if (!settings->ClientAddress)
if (!freerdp_tcp_get_ip_address(settings, sockfd))
{
if (!useExternalDefinedSocket)
close(sockfd);