From e65d488a51496fddbbf38dddbd693371f03b3b15 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 8 Jan 2026 15:41:47 +0100 Subject: [PATCH] [core,tcp] refactor freerdp_tcp_default_connect --- libfreerdp/core/tcp.c | 236 ++++++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 114 deletions(-) diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 3ae38c6ec..dd2847e2d 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -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);