int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* hostname, int port, int timeout) { int status; int sockfd; UINT32 optval; socklen_t optlen; BOOL ipcSocket = FALSE; BOOL useExternalDefinedSocket = FALSE; if (!hostname) return -1; if (hostname[0] == '/') ipcSocket = TRUE; if (hostname[0] == '|') useExternalDefinedSocket = TRUE; if (ipcSocket) { sockfd = freerdp_uds_connect(hostname); if (sockfd < 0) return -1; } else if (useExternalDefinedSocket) sockfd = port; else { sockfd = -1; if (!settings->GatewayEnabled) { if (!freerdp_tcp_resolve_hostname(hostname) || settings->RemoteAssistanceMode) { if (settings->TargetNetAddressCount > 0) { sockfd = freerdp_tcp_connect_multi( context, settings->TargetNetAddresses, settings->TargetNetPorts, settings->TargetNetAddressCount, port, timeout); } } } if (sockfd <= 0) { char port_str[16]; struct addrinfo hints; struct addrinfo* addr; struct addrinfo* result; ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; sprintf_s(port_str, sizeof(port_str) - 1, "%d", port); status = getaddrinfo(hostname, port_str, &hints, &result); if (status) { WLog_ERR(TAG, "getaddrinfo: %s", gai_strerror(status)); return -1; } addr = result; if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0)) { while ((addr = addr->ai_next)) { if (addr->ai_family == AF_INET) break; } if (!addr) addr = result; } sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sockfd < 0) { freeaddrinfo(result); return -1; } if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen, timeout)) { freeaddrinfo(result); close(sockfd); WLog_ERR(TAG, "failed to connect to %s", hostname); return -1; } freeaddrinfo(result); } } settings->IPv6Enabled = FALSE; free(settings->ClientAddress); settings->ClientAddress = freerdp_tcp_get_ip_address(sockfd); if (!settings->ClientAddress) { if (!useExternalDefinedSocket) close(sockfd); WLog_ERR(TAG, "Couldn't get socket ip address"); return -1; } optval = 1; optlen = sizeof(optval); if (!ipcSocket && !useExternalDefinedSocket) { if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &optval, optlen) < 0) WLog_ERR(TAG, "unable to set TCP_NODELAY"); } /* receive buffer must be a least 32 K */ if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &optval, &optlen) == 0) { if (optval < (1024 * 32)) { optval = 1024 * 32; optlen = sizeof(optval); if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &optval, optlen) < 0) { close(sockfd); WLog_ERR(TAG, "unable to set receive buffer len"); return -1; } } } if (!ipcSocket && !useExternalDefinedSocket) { if (!freerdp_tcp_set_keep_alive_mode(sockfd)) { close(sockfd); WLog_ERR(TAG, "Couldn't set keep alive mode."); return -1; } } if (WaitForSingleObject(context->abortEvent, 0) == WAIT_OBJECT_0) { close(sockfd); return -1; } return sockfd; }
BOOL freerdp_tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout) { int status; UINT32 option_value; socklen_t option_len; if (!hostname) return FALSE; if (hostname[0] == '/') tcp->ipcSocket = TRUE; if (tcp->ipcSocket) { tcp->sockfd = uds_connect(hostname); if (tcp->sockfd < 0) return FALSE; tcp->socketBio = BIO_new(BIO_s_simple_socket()); if (!tcp->socketBio) return FALSE; BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE); } else { #ifdef HAVE_POLL_H struct pollfd pollfds; #else fd_set cfds; struct timeval tv; #endif #ifdef NO_IPV6 tcp->socketBio = BIO_new(BIO_s_connect()); if (!tcp->socketBio) return FALSE; if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0) return FALSE; BIO_set_nbio(tcp->socketBio, 1); status = BIO_do_connect(tcp->socketBio); if ((status <= 0) && !BIO_should_retry(tcp->socketBio)) return FALSE; tcp->sockfd = BIO_get_fd(tcp->socketBio, NULL); if (tcp->sockfd < 0) return FALSE; #else /* NO_IPV6 */ struct addrinfo hints = {0}; struct addrinfo *result; struct addrinfo *tmp; char port_str[11]; //ZeroMemory(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_STREAM; /* * FIXME: the following is a nasty workaround. Find a cleaner way: * Either set port manually afterwards or get it passed as string? */ sprintf_s(port_str, 11, "%u", port); status = getaddrinfo(hostname, port_str, &hints, &result); if (status) { WLog_ERR(TAG, "getaddrinfo: %s", gai_strerror(status)); return FALSE; } /* For now prefer IPv4 over IPv6. */ tmp = result; if (tmp->ai_family == AF_INET6 && tmp->ai_next != 0) { while ((tmp = tmp->ai_next)) { if (tmp->ai_family == AF_INET) break; } if (!tmp) tmp = result; } tcp->sockfd = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol); if (tcp->sockfd < 0) { freeaddrinfo(result); return FALSE; } if (connect(tcp->sockfd, tmp->ai_addr, tmp->ai_addrlen) < 0) { WLog_ERR(TAG, "connect: %s", strerror(errno)); freeaddrinfo(result); return FALSE; } freeaddrinfo(result); tcp->socketBio = BIO_new_socket(tcp->sockfd, BIO_NOCLOSE); /* TODO: make sure the handshake is done by querying the bio */ // if (BIO_should_retry(tcp->socketBio)) // return FALSE; #endif /* NO_IPV6 */ if (status <= 0) { #ifdef HAVE_POLL_H pollfds.fd = tcp->sockfd; pollfds.events = POLLOUT; pollfds.revents = 0; do { status = poll(&pollfds, 1, timeout * 1000); } while ((status < 0) && (errno == EINTR)); #else FD_ZERO(&cfds); FD_SET(tcp->sockfd, &cfds); tv.tv_sec = timeout; tv.tv_usec = 0; status = _select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv); #endif if (status == 0) { return FALSE; /* timeout */ } } (void)BIO_set_close(tcp->socketBio, BIO_NOCLOSE); BIO_free(tcp->socketBio); tcp->socketBio = BIO_new(BIO_s_simple_socket()); if (!tcp->socketBio) return FALSE; BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE); } SetEventFileDescriptor(tcp->event, tcp->sockfd); freerdp_tcp_get_ip_address(tcp); freerdp_tcp_get_mac_address(tcp); option_value = 1; option_len = sizeof(option_value); if (!tcp->ipcSocket) { if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0) WLog_ERR(TAG, "unable to set TCP_NODELAY"); } /* receive buffer must be a least 32 K */ if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, &option_len) == 0) { if (option_value < (1024 * 32)) { option_value = 1024 * 32; option_len = sizeof(option_value); if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0) { WLog_ERR(TAG, "unable to set receive buffer len"); return FALSE; } } } if (!tcp->ipcSocket) { if (!freerdp_tcp_set_keep_alive_mode(tcp)) return FALSE; } tcp->bufferedBio = BIO_new(BIO_s_buffered_socket()); if (!tcp->bufferedBio) return FALSE; tcp->bufferedBio->ptr = tcp; tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio); return TRUE; }