From 8df39fdad40e8fb70298e5e7527bc5cd2d7231bd Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 12 Nov 2018 12:37:33 +0100 Subject: [PATCH] Use blocking sockets in freerdp_tcp_connect_multi The non blocking connect in freerdp_tcp_connect_multi did not work reliably. Fall back to blocking connect (which might take longer until the connection is established) instead of not being able to connect at all. --- libfreerdp/core/tcp.c | 124 +++++++++++++----------------------------- 1 file changed, 39 insertions(+), 85 deletions(-) diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 646a09a08..6b07b6b9b 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -881,32 +881,42 @@ fail: return rc; } +typedef struct +{ + SOCKET s; + struct addrinfo* addr; + struct addrinfo* result; +} t_peer; + +static BOOL peer_free(t_peer* peer) +{ + if (peer->s != INVALID_SOCKET) + closesocket(peer->s); + + freeaddrinfo(peer->addr); + memset(peer, 0, sizeof(t_peer)); + peer->s = INVALID_SOCKET; +} + static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, UINT32* ports, UINT32 count, int port, int timeout) { UINT32 index; - int sindex; - int status; - SOCKET sockfd = (SOCKET) - 1; - SOCKET* sockfds; + UINT32 sindex = count; + int status = -1; + SOCKET sockfd = INVALID_SOCKET; HANDLE* events; - DWORD waitStatus; struct addrinfo* addr; struct addrinfo* result; - struct addrinfo** addrs; - struct addrinfo** results; - sockfds = (SOCKET*) calloc(count, sizeof(SOCKET)); + t_peer* peers; events = (HANDLE*) calloc(count + 1, sizeof(HANDLE)); - addrs = (struct addrinfo**) calloc(count, sizeof(struct addrinfo*)); - results = (struct addrinfo**) calloc(count, sizeof(struct addrinfo*)); + peers = (t_peer*)calloc(count, sizeof(t_peer)); - if (!sockfds || !events || !addrs || !results) + if (!peers || !events || (count < 1)) { - free(sockfds); + free(peers); free(events); - free(addrs); - free(results); return -1; } @@ -936,104 +946,48 @@ static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, addr = result; } - sockfds[index] = _socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + peers[index].s = _socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); - if (sockfds[index] == INVALID_SOCKET) + if (peers[index].s == INVALID_SOCKET) { freeaddrinfo(result); - sockfds[index] = 0; continue; } - addrs[index] = addr; - results[index] = result; + peers[index].addr = addr; + peers[index].result = result; } for (index = 0; index < count; index++) { - if (!sockfds[index]) + if (peers[index].s == INVALID_SOCKET) continue; - sockfd = sockfds[index]; - addr = addrs[index]; - /* set socket in non-blocking mode */ - events[index] = WSACreateEvent(); - - if (!events[index]) - { - WLog_ERR(TAG, "WSACreateEvent returned 0x%08X", WSAGetLastError()); - continue; - } - - if (WSAEventSelect(sockfd, events[index], FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE)) - { - WLog_ERR(TAG, "WSAEventSelect returned 0x%08X", WSAGetLastError()); - continue; - } - - /* non-blocking tcp connect */ + sockfd = peers[index].s; + addr = peers[index].addr; + /* blocking tcp connect */ status = _connect(sockfd, addr->ai_addr, addr->ai_addrlen); if (status >= 0) { /* connection success */ + sindex = index; break; } } - events[count] = context->abortEvent; - waitStatus = WaitForMultipleObjects(count + 1, events, FALSE, timeout * 1000); - sindex = waitStatus - WAIT_OBJECT_0; - - for (index = 0; index < count; index++) + if (sindex < count) { - const char* host = hostnames[index]; - UINT32 curPort = port; - u_long arg = 0; - - if (ports) - curPort = ports[index]; - - if (!sockfds[index]) - continue; - - sockfd = sockfds[index]; - - /* set socket in blocking mode */ - if (WSAEventSelect(sockfd, events[index], 0)) - { - WLog_ERR(TAG, "[%s:%"PRId32"] WSAEventSelect returned 0x%08X", host, port, WSAGetLastError()); - continue; - } - - if (_ioctlsocket(sockfd, FIONBIO, &arg)) - { - WLog_ERR(TAG, "[%s:%"PRId32"] _ioctlsocket failed", host, port); - } + sockfd = peers[sindex].s; + peers[sindex].s = INVALID_SOCKET; } - - if ((sindex >= 0) && (sindex < count)) - { - sockfd = sockfds[sindex]; - } - - if (sindex == count) + else freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); for (index = 0; index < count; index++) - { - if (results[index]) - freeaddrinfo(results[index]); + peer_free(&peers[index]); - if (sindex != index) - closesocket(sockfds[index]); - - CloseHandle(events[index]); - } - - free(addrs); - free(results); - free(sockfds); + free(peers); free(events); return sockfd; }