Blame libfreerdp/core/tcp.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Transmission Control Protocol (TCP)
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Vic Lee
Packit 1fb8d4
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <time.h>
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
#include <fcntl.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/platform.h>
Packit 1fb8d4
#include <winpr/winsock.h>
Packit 1fb8d4
Packit 1fb8d4
#if !defined(_WIN32)
Packit 1fb8d4
Packit 1fb8d4
#include <netdb.h>
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
#include <sys/ioctl.h>
Packit 1fb8d4
#include <sys/socket.h>
Packit 1fb8d4
#include <netinet/in.h>
Packit 1fb8d4
#include <netinet/tcp.h>
Packit 1fb8d4
#include <net/if.h>
Packit 1fb8d4
#include <sys/types.h>
Packit 1fb8d4
#include <arpa/inet.h>
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_POLL_H
Packit 1fb8d4
#include <poll.h>
Packit 1fb8d4
#else
Packit 1fb8d4
#include <time.h>
Packit 1fb8d4
#include <sys/select.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_SYS_FILIO_H
Packit 1fb8d4
#include <sys/filio.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#if defined(__FreeBSD__) || defined(__OpenBSD__)
Packit 1fb8d4
#ifndef SOL_TCP
Packit Service 5a9772
#define SOL_TCP IPPROTO_TCP
Packit 1fb8d4
#endif
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#ifdef __APPLE__
Packit 1fb8d4
#ifndef SOL_TCP
Packit Service 5a9772
#define SOL_TCP IPPROTO_TCP
Packit 1fb8d4
#endif
Packit 1fb8d4
#ifndef TCP_KEEPIDLE
Packit 1fb8d4
#define TCP_KEEPIDLE TCP_KEEPALIVE
Packit 1fb8d4
#endif
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/windows.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
Packit 1fb8d4
#define SHUT_RDWR SD_BOTH
Packit 1fb8d4
#define close(_fd) closesocket(_fd)
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/stream.h>
Packit 1fb8d4
Packit 1fb8d4
#include "tcp.h"
Packit 1fb8d4
#include "../crypto/opensslcompat.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("core")
Packit 1fb8d4
Packit 1fb8d4
/* Simple Socket BIO */
Packit 1fb8d4
Packit 1fb8d4
struct _WINPR_BIO_SIMPLE_SOCKET
Packit 1fb8d4
{
Packit 1fb8d4
	SOCKET socket;
Packit 1fb8d4
	HANDLE hEvent;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct _WINPR_BIO_SIMPLE_SOCKET WINPR_BIO_SIMPLE_SOCKET;
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_init(BIO* bio, SOCKET socket, int shutdown);
Packit 1fb8d4
static int transport_bio_simple_uninit(BIO* bio);
Packit 1fb8d4
Packit Service 5a9772
static long transport_bio_simple_callback(BIO* bio, int mode, const char* argp, int argi, long argl,
Packit Service 5a9772
                                          long ret)
Packit 1fb8d4
{
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_write(BIO* bio, const char* buf, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	int error;
Packit 1fb8d4
	int status = 0;
Packit Service 5a9772
	WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
Packit 1fb8d4
	if (!buf)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	BIO_clear_flags(bio, BIO_FLAGS_WRITE);
Packit 1fb8d4
	status = _send(ptr->socket, buf, size, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (status <= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		error = WSAGetLastError();
Packit 1fb8d4
Packit Service 5a9772
		if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
Packit Service 5a9772
		    (error == WSAEALREADY))
Packit 1fb8d4
		{
Packit 1fb8d4
			BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY));
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_read(BIO* bio, char* buf, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	int error;
Packit 1fb8d4
	int status = 0;
Packit Service 5a9772
	WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
Packit 1fb8d4
	if (!buf)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	BIO_clear_flags(bio, BIO_FLAGS_READ);
Packit 1fb8d4
	WSAResetEvent(ptr->hEvent);
Packit 1fb8d4
	status = _recv(ptr->socket, buf, size, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (status > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		return status;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (status == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	error = WSAGetLastError();
Packit 1fb8d4
Packit Service 5a9772
	if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) ||
Packit Service 5a9772
	    (error == WSAEALREADY))
Packit 1fb8d4
	{
Packit 1fb8d4
		BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_puts(BIO* bio, const char* str)
Packit 1fb8d4
{
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_gets(BIO* bio, char* str, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static long transport_bio_simple_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = -1;
Packit Service 5a9772
	WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
Packit 1fb8d4
	if (cmd == BIO_C_SET_SOCKET)
Packit 1fb8d4
	{
Packit 1fb8d4
		transport_bio_simple_uninit(bio);
Packit Service 5a9772
		transport_bio_simple_init(bio, (SOCKET)arg2, (int)arg1);
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (cmd == BIO_C_GET_SOCKET)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!BIO_get_init(bio) || !arg2)
Packit 1fb8d4
			return 0;
Packit 1fb8d4
Packit Service 5a9772
		*((SOCKET*)arg2) = ptr->socket;
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (cmd == BIO_C_GET_EVENT)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!BIO_get_init(bio) || !arg2)
Packit 1fb8d4
			return 0;
Packit 1fb8d4
Packit Service 5a9772
		*((HANDLE*)arg2) = ptr->hEvent;
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (cmd == BIO_C_SET_NONBLOCK)
Packit 1fb8d4
	{
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
		int flags;
Packit Service 5a9772
		flags = fcntl((int)ptr->socket, F_GETFL);
Packit 1fb8d4
Packit 1fb8d4
		if (flags == -1)
Packit 1fb8d4
			return 0;
Packit 1fb8d4
Packit 1fb8d4
		if (arg1)
Packit Service 5a9772
			fcntl((int)ptr->socket, F_SETFL, flags | O_NONBLOCK);
Packit 1fb8d4
		else
Packit Service 5a9772
			fcntl((int)ptr->socket, F_SETFL, flags & ~(O_NONBLOCK));
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
		/* the internal socket is always non-blocking */
Packit 1fb8d4
#endif
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (cmd == BIO_C_WAIT_READ)
Packit 1fb8d4
	{
Packit Service 5a9772
		int timeout = (int)arg1;
Packit Service 5a9772
		int sockfd = (int)ptr->socket;
Packit 1fb8d4
#ifdef HAVE_POLL_H
Packit 1fb8d4
		struct pollfd pollset;
Packit 1fb8d4
		pollset.fd = sockfd;
Packit 1fb8d4
		pollset.events = POLLIN;
Packit 1fb8d4
		pollset.revents = 0;
Packit 1fb8d4
Packit 1fb8d4
		do
Packit 1fb8d4
		{
Packit 1fb8d4
			status = poll(&pollset, 1, timeout);
Packit Service 5a9772
		} while ((status < 0) && (errno == EINTR));
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
		fd_set rset;
Packit 1fb8d4
		struct timeval tv;
Packit 1fb8d4
		FD_ZERO(&rset);
Packit 1fb8d4
		FD_SET(sockfd, &rset);
Packit 1fb8d4
Packit 1fb8d4
		if (timeout)
Packit 1fb8d4
		{
Packit 1fb8d4
			tv.tv_sec = timeout / 1000;
Packit 1fb8d4
			tv.tv_usec = (timeout % 1000) * 1000;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		do
Packit 1fb8d4
		{
Packit 1fb8d4
			status = select(sockfd + 1, &rset, NULL, NULL, timeout ? &tv : NULL);
Packit Service 5a9772
		} while ((status < 0) && (errno == EINTR));
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (cmd == BIO_C_WAIT_WRITE)
Packit 1fb8d4
	{
Packit Service 5a9772
		int timeout = (int)arg1;
Packit Service 5a9772
		int sockfd = (int)ptr->socket;
Packit 1fb8d4
#ifdef HAVE_POLL_H
Packit 1fb8d4
		struct pollfd pollset;
Packit 1fb8d4
		pollset.fd = sockfd;
Packit 1fb8d4
		pollset.events = POLLOUT;
Packit 1fb8d4
		pollset.revents = 0;
Packit 1fb8d4
Packit 1fb8d4
		do
Packit 1fb8d4
		{
Packit 1fb8d4
			status = poll(&pollset, 1, timeout);
Packit Service 5a9772
		} while ((status < 0) && (errno == EINTR));
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
		fd_set rset;
Packit 1fb8d4
		struct timeval tv;
Packit 1fb8d4
		FD_ZERO(&rset);
Packit 1fb8d4
		FD_SET(sockfd, &rset);
Packit 1fb8d4
Packit 1fb8d4
		if (timeout)
Packit 1fb8d4
		{
Packit 1fb8d4
			tv.tv_sec = timeout / 1000;
Packit 1fb8d4
			tv.tv_usec = (timeout % 1000) * 1000;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		do
Packit 1fb8d4
		{
Packit 1fb8d4
			status = select(sockfd + 1, NULL, &rset, NULL, timeout ? &tv : NULL);
Packit Service 5a9772
		} while ((status < 0) && (errno == EINTR));
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	switch (cmd)
Packit 1fb8d4
	{
Packit 1fb8d4
		case BIO_C_SET_FD:
Packit 1fb8d4
			if (arg2)
Packit 1fb8d4
			{
Packit 1fb8d4
				transport_bio_simple_uninit(bio);
Packit Service 5a9772
				transport_bio_simple_init(bio, (SOCKET) * ((int*)arg2), (int)arg1);
Packit 1fb8d4
				status = 1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_C_GET_FD:
Packit 1fb8d4
			if (BIO_get_init(bio))
Packit 1fb8d4
			{
Packit 1fb8d4
				if (arg2)
Packit Service 5a9772
					*((int*)arg2) = (int)ptr->socket;
Packit 1fb8d4
Packit Service 5a9772
				status = (int)ptr->socket;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_CTRL_GET_CLOSE:
Packit 1fb8d4
			status = BIO_get_shutdown(bio);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_CTRL_SET_CLOSE:
Packit Service 5a9772
			BIO_set_shutdown(bio, (int)arg1);
Packit 1fb8d4
			status = 1;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_CTRL_DUP:
Packit 1fb8d4
			status = 1;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_CTRL_FLUSH:
Packit 1fb8d4
			status = 1;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			status = 0;
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_init(BIO* bio, SOCKET socket, int shutdown)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
	ptr->socket = socket;
Packit 1fb8d4
	BIO_set_shutdown(bio, shutdown);
Packit 1fb8d4
	BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit 1fb8d4
	BIO_set_init(bio, 1);
Packit 1fb8d4
	ptr->hEvent = WSACreateEvent();
Packit 1fb8d4
Packit 1fb8d4
	if (!ptr->hEvent)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	/* WSAEventSelect automatically sets the socket in non-blocking mode */
Packit 1fb8d4
	if (WSAEventSelect(ptr->socket, ptr->hEvent, FD_READ | FD_ACCEPT | FD_CLOSE))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "WSAEventSelect returned 0x%08X", WSAGetLastError());
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_uninit(BIO* bio)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
Packit 1fb8d4
	if (BIO_get_shutdown(bio))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (BIO_get_init(bio) && ptr)
Packit 1fb8d4
		{
Packit 1fb8d4
			_shutdown(ptr->socket, SD_BOTH);
Packit 1fb8d4
			closesocket(ptr->socket);
Packit 1fb8d4
			ptr->socket = 0;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (ptr && ptr->hEvent)
Packit 1fb8d4
	{
Packit 1fb8d4
		CloseHandle(ptr->hEvent);
Packit 1fb8d4
		ptr->hEvent = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	BIO_set_init(bio, 0);
Packit 1fb8d4
	BIO_set_flags(bio, 0);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_new(BIO* bio)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_BIO_SIMPLE_SOCKET* ptr;
Packit 1fb8d4
	BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit Service 5a9772
	ptr = (WINPR_BIO_SIMPLE_SOCKET*)calloc(1, sizeof(WINPR_BIO_SIMPLE_SOCKET));
Packit 1fb8d4
Packit 1fb8d4
	if (!ptr)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	BIO_set_data(bio, ptr);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_simple_free(BIO* bio)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_BIO_SIMPLE_SOCKET* ptr;
Packit 1fb8d4
Packit 1fb8d4
	if (!bio)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	transport_bio_simple_uninit(bio);
Packit Service 5a9772
	ptr = (WINPR_BIO_SIMPLE_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
Packit 1fb8d4
	if (ptr)
Packit 1fb8d4
	{
Packit 1fb8d4
		BIO_set_data(bio, NULL);
Packit 1fb8d4
		free(ptr);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BIO_METHOD* BIO_s_simple_socket(void)
Packit 1fb8d4
{
Packit 1fb8d4
	static BIO_METHOD* bio_methods = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (bio_methods == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!(bio_methods = BIO_meth_new(BIO_TYPE_SIMPLE, "SimpleSocket")))
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		BIO_meth_set_write(bio_methods, transport_bio_simple_write);
Packit 1fb8d4
		BIO_meth_set_read(bio_methods, transport_bio_simple_read);
Packit 1fb8d4
		BIO_meth_set_puts(bio_methods, transport_bio_simple_puts);
Packit 1fb8d4
		BIO_meth_set_gets(bio_methods, transport_bio_simple_gets);
Packit 1fb8d4
		BIO_meth_set_ctrl(bio_methods, transport_bio_simple_ctrl);
Packit 1fb8d4
		BIO_meth_set_create(bio_methods, transport_bio_simple_new);
Packit 1fb8d4
		BIO_meth_set_destroy(bio_methods, transport_bio_simple_free);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return bio_methods;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* Buffered Socket BIO */
Packit 1fb8d4
Packit 1fb8d4
struct _WINPR_BIO_BUFFERED_SOCKET
Packit 1fb8d4
{
Packit 1fb8d4
	BIO* bufferedBio;
Packit 1fb8d4
	BOOL readBlocked;
Packit 1fb8d4
	BOOL writeBlocked;
Packit 1fb8d4
	RingBuffer xmitBuffer;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct _WINPR_BIO_BUFFERED_SOCKET WINPR_BIO_BUFFERED_SOCKET;
Packit 1fb8d4
Packit Service 5a9772
static long transport_bio_buffered_callback(BIO* bio, int mode, const char* argp, int argi,
Packit Service 5a9772
                                            long argl, long ret)
Packit 1fb8d4
{
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
Packit 1fb8d4
{
Packit 1fb8d4
	int i, ret;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	int nchunks;
Packit 1fb8d4
	int committedBytes;
Packit 1fb8d4
	DataChunk chunks[2];
Packit Service 5a9772
	WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
	BIO* next_bio = NULL;
Packit 1fb8d4
	ret = num;
Packit 1fb8d4
	ptr->writeBlocked = FALSE;
Packit 1fb8d4
	BIO_clear_flags(bio, BIO_FLAGS_WRITE);
Packit 1fb8d4
Packit 1fb8d4
	/* we directly append extra bytes in the xmit buffer, this could be prevented
Packit 1fb8d4
	 * but for now it makes the code more simple.
Packit 1fb8d4
	 */
Packit Service 5a9772
	if (buf && num && !ringbuffer_write(&ptr->xmitBuffer, (const BYTE*)buf, num))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "an error occurred when writing (num: %d)", num);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	committedBytes = 0;
Packit 1fb8d4
	nchunks = ringbuffer_peek(&ptr->xmitBuffer, chunks, ringbuffer_used(&ptr->xmitBuffer));
Packit 1fb8d4
	next_bio = BIO_next(bio);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < nchunks; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		while (chunks[i].size)
Packit 1fb8d4
		{
Packit 1fb8d4
			status = BIO_write(next_bio, chunks[i].data, chunks[i].size);
Packit 1fb8d4
Packit 1fb8d4
			if (status <= 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!BIO_should_retry(next_bio))
Packit 1fb8d4
				{
Packit 1fb8d4
					BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit 1fb8d4
					ret = -1; /* fatal error */
Packit 1fb8d4
					goto out;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (BIO_should_write(next_bio))
Packit 1fb8d4
				{
Packit 1fb8d4
					BIO_set_flags(bio, BIO_FLAGS_WRITE);
Packit 1fb8d4
					ptr->writeBlocked = TRUE;
Packit 1fb8d4
					goto out; /* EWOULDBLOCK */
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			committedBytes += status;
Packit 1fb8d4
			chunks[i].size -= status;
Packit 1fb8d4
			chunks[i].data += status;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out:
Packit 1fb8d4
	ringbuffer_commit_read_bytes(&ptr->xmitBuffer, committedBytes);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit Service 5a9772
	WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
	BIO* next_bio = BIO_next(bio);
Packit 1fb8d4
	ptr->readBlocked = FALSE;
Packit 1fb8d4
	BIO_clear_flags(bio, BIO_FLAGS_READ);
Packit 1fb8d4
	status = BIO_read(next_bio, buf, size);
Packit 1fb8d4
Packit 1fb8d4
	if (status <= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!BIO_should_retry(next_bio))
Packit 1fb8d4
		{
Packit 1fb8d4
			BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit 1fb8d4
			goto out;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit 1fb8d4
Packit 1fb8d4
		if (BIO_should_read(next_bio))
Packit 1fb8d4
		{
Packit 1fb8d4
			BIO_set_flags(bio, BIO_FLAGS_READ);
Packit 1fb8d4
			ptr->readBlocked = TRUE;
Packit 1fb8d4
			goto out;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out:
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_buffered_puts(BIO* bio, const char* str)
Packit 1fb8d4
{
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_buffered_gets(BIO* bio, char* str, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static long transport_bio_buffered_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = -1;
Packit Service 5a9772
	WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
Packit 1fb8d4
	switch (cmd)
Packit 1fb8d4
	{
Packit 1fb8d4
		case BIO_CTRL_FLUSH:
Packit 1fb8d4
			if (!ringbuffer_used(&ptr->xmitBuffer))
Packit 1fb8d4
				status = 1;
Packit 1fb8d4
			else
Packit 1fb8d4
				status = (transport_bio_buffered_write(bio, NULL, 0) >= 0) ? 1 : -1;
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_CTRL_WPENDING:
Packit 1fb8d4
			status = ringbuffer_used(&ptr->xmitBuffer);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_CTRL_PENDING:
Packit 1fb8d4
			status = 0;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_C_READ_BLOCKED:
Packit Service 5a9772
			status = (int)ptr->readBlocked;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case BIO_C_WRITE_BLOCKED:
Packit Service 5a9772
			status = (int)ptr->writeBlocked;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			status = BIO_ctrl(BIO_next(bio), cmd, arg1, arg2);
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int transport_bio_buffered_new(BIO* bio)
Packit 1fb8d4
{
Packit 1fb8d4
	WINPR_BIO_BUFFERED_SOCKET* ptr;
Packit 1fb8d4
	BIO_set_init(bio, 1);
Packit 1fb8d4
	BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
Packit Service 5a9772
	ptr = (WINPR_BIO_BUFFERED_SOCKET*)calloc(1, sizeof(WINPR_BIO_BUFFERED_SOCKET));
Packit 1fb8d4
Packit 1fb8d4
	if (!ptr)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	BIO_set_data(bio, (void*)ptr);
Packit 1fb8d4
Packit 1fb8d4
	if (!ringbuffer_init(&ptr->xmitBuffer, 0x10000))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* Free the buffered BIO.
Packit 1fb8d4
 * Do not free other elements in the BIO stack,
Packit 1fb8d4
 * let BIO_free_all handle that. */
Packit 1fb8d4
static int transport_bio_buffered_free(BIO* bio)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*)BIO_get_data(bio);
Packit 1fb8d4
Packit 1fb8d4
	if (!ptr)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	ringbuffer_destroy(&ptr->xmitBuffer);
Packit 1fb8d4
	free(ptr);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BIO_METHOD* BIO_s_buffered_socket(void)
Packit 1fb8d4
{
Packit 1fb8d4
	static BIO_METHOD* bio_methods = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (bio_methods == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!(bio_methods = BIO_meth_new(BIO_TYPE_BUFFERED, "BufferedSocket")))
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		BIO_meth_set_write(bio_methods, transport_bio_buffered_write);
Packit 1fb8d4
		BIO_meth_set_read(bio_methods, transport_bio_buffered_read);
Packit 1fb8d4
		BIO_meth_set_puts(bio_methods, transport_bio_buffered_puts);
Packit 1fb8d4
		BIO_meth_set_gets(bio_methods, transport_bio_buffered_gets);
Packit 1fb8d4
		BIO_meth_set_ctrl(bio_methods, transport_bio_buffered_ctrl);
Packit 1fb8d4
		BIO_meth_set_create(bio_methods, transport_bio_buffered_new);
Packit 1fb8d4
		BIO_meth_set_destroy(bio_methods, transport_bio_buffered_free);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return bio_methods;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
char* freerdp_tcp_address_to_string(const struct sockaddr_storage* addr, BOOL* pIPv6)
Packit 1fb8d4
{
Packit 1fb8d4
	char ipAddress[INET6_ADDRSTRLEN + 1] = { 0 };
Packit 1fb8d4
	struct sockaddr_in6* sockaddr_ipv6 = (struct sockaddr_in6*)addr;
Packit 1fb8d4
	struct sockaddr_in* sockaddr_ipv4 = (struct sockaddr_in*)addr;
Packit 1fb8d4
Packit 1fb8d4
	if (addr == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	switch (sockaddr_ipv4->sin_family)
Packit 1fb8d4
	{
Packit 1fb8d4
		case AF_INET:
Packit Service 5a9772
			if (!inet_ntop(sockaddr_ipv4->sin_family, &sockaddr_ipv4->sin_addr, ipAddress,
Packit Service 5a9772
			               sizeof(ipAddress)))
Packit 1fb8d4
				return NULL;
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case AF_INET6:
Packit Service 5a9772
			if (!inet_ntop(sockaddr_ipv6->sin6_family, &sockaddr_ipv6->sin6_addr, ipAddress,
Packit Service 5a9772
			               sizeof(ipAddress)))
Packit 1fb8d4
				return NULL;
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case AF_UNIX:
Packit 1fb8d4
			sprintf_s(ipAddress, ARRAYSIZE(ipAddress), "127.0.0.1");
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (pIPv6 != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		*pIPv6 = (sockaddr_ipv4->sin_family == AF_INET6);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return _strdup(ipAddress);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static char* freerdp_tcp_get_ip_address(int sockfd, BOOL* pIPv6)
Packit 1fb8d4
{
Packit 1fb8d4
	struct sockaddr_storage saddr = { 0 };
Packit 1fb8d4
	socklen_t length = sizeof(struct sockaddr_storage);
Packit 1fb8d4
Packit 1fb8d4
	if (getsockname(sockfd, (struct sockaddr*)&saddr, &length) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return freerdp_tcp_address_to_string(&saddr, pIPv6);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
char* freerdp_tcp_get_peer_address(SOCKET sockfd)
Packit 1fb8d4
{
Packit 1fb8d4
	struct sockaddr_storage saddr = { 0 };
Packit 1fb8d4
	socklen_t length = sizeof(struct sockaddr_storage);
Packit 1fb8d4
Packit 1fb8d4
	if (getpeername(sockfd, (struct sockaddr*)&saddr, &length) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return freerdp_tcp_address_to_string(&saddr, NULL);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int freerdp_uds_connect(const char* path)
Packit 1fb8d4
{
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
	int status;
Packit 1fb8d4
	int sockfd;
Packit 1fb8d4
	struct sockaddr_un addr = { 0 };
Packit 1fb8d4
	sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (sockfd == -1)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "socket");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	addr.sun_family = AF_UNIX;
Packit 1fb8d4
	strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
Packit Service 5a9772
	status = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "connect");
Packit 1fb8d4
		close(sockfd);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return sockfd;
Packit 1fb8d4
#else /* ifndef _WIN32 */
Packit 1fb8d4
	return -1;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
struct addrinfo* freerdp_tcp_resolve_host(const char* hostname, int port, int ai_flags)
Packit 1fb8d4
{
Packit 1fb8d4
	char* service = NULL;
Packit 1fb8d4
	char port_str[16];
Packit 1fb8d4
	int status;
Packit 1fb8d4
	struct addrinfo hints = { 0 };
Packit 1fb8d4
	struct addrinfo* result = NULL;
Packit 1fb8d4
	hints.ai_family = AF_UNSPEC;
Packit 1fb8d4
	hints.ai_socktype = SOCK_STREAM;
Packit 1fb8d4
	hints.ai_flags = ai_flags;
Packit 1fb8d4
Packit 1fb8d4
	if (port >= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		sprintf_s(port_str, sizeof(port_str) - 1, "%d", port);
Packit 1fb8d4
		service = port_str;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = getaddrinfo(hostname, service, &hints, &result);
Packit 1fb8d4
Packit 1fb8d4
	if (status)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	return result;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL freerdp_tcp_is_hostname_resolvable(rdpContext* context, const char* hostname)
Packit 1fb8d4
{
Packit 1fb8d4
	struct addrinfo* result = freerdp_tcp_resolve_host(hostname, -1, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (!result)
Packit 1fb8d4
	{
Packit Service 5a9772
		freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
Packit 1fb8d4
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	freerdp_set_last_error_log(context, 0);
Packit 1fb8d4
	freeaddrinfo(result);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct sockaddr* addr,
Packit 1fb8d4
                                        socklen_t addrlen, int timeout)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL rc = FALSE;
Packit 1fb8d4
	HANDLE handles[2];
Packit 1fb8d4
	int status = 0;
Packit 1fb8d4
	int count = 0;
Packit 1fb8d4
	u_long arg = 0;
Packit Service 5a9772
	DWORD tout = (timeout > 0) ? (DWORD)timeout * 1000U : INFINITE;
Packit Service 5a9772
Packit 1fb8d4
	handles[count] = CreateEvent(NULL, TRUE, FALSE, NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (!handles[count])
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	status = WSAEventSelect(sockfd, handles[count++], FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	handles[count++] = context->abortEvent;
Packit 1fb8d4
	status = _connect(sockfd, addr, addrlen);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = WSAGetLastError();
Packit 1fb8d4
Packit 1fb8d4
		switch (status)
Packit 1fb8d4
		{
Packit 1fb8d4
			case WSAEINPROGRESS:
Packit 1fb8d4
			case WSAEWOULDBLOCK:
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = WaitForMultipleObjects(count, handles, FALSE, tout);
Packit 1fb8d4
Packit 1fb8d4
	if (WAIT_OBJECT_0 != status)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (status == WAIT_OBJECT_0 + 1)
Packit Service 5a9772
			freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_CANCELLED);
Packit 1fb8d4
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = recv(sockfd, NULL, 0, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (status == SOCKET_ERROR)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (WSAGetLastError() == WSAECONNRESET)
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = WSAEventSelect(sockfd, handles[0], 0);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "WSAEventSelect failed with %d", WSAGetLastError());
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (_ioctlsocket(sockfd, FIONBIO, &arg) != 0)
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	rc = TRUE;
Packit 1fb8d4
fail:
Packit 1fb8d4
	CloseHandle(handles[0]);
Packit 1fb8d4
	return rc;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
typedef struct
Packit 1fb8d4
{
Packit Service 5a9772
	SOCKET s;
Packit Service 5a9772
	struct addrinfo* addr;
Packit Service 5a9772
	struct addrinfo* result;
Packit Service 5a9772
} t_peer;
Packit Service 5a9772
Packit Service 5a9772
static void peer_free(t_peer* peer)
Packit Service 5a9772
{
Packit Service 5a9772
	if (peer->s != INVALID_SOCKET)
Packit Service 5a9772
		closesocket(peer->s);
Packit Service 5a9772
Packit Service 5a9772
	freeaddrinfo(peer->addr);
Packit Service 5a9772
	memset(peer, 0, sizeof(t_peer));
Packit Service 5a9772
	peer->s = INVALID_SOCKET;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, UINT32* ports,
Packit Service 5a9772
                                     UINT32 count, int port, int timeout)
Packit Service 5a9772
{
Packit Service 5a9772
	UINT32 index;
Packit Service 5a9772
	UINT32 sindex = count;
Packit Service 5a9772
	int status = -1;
Packit Service 5a9772
	SOCKET sockfd = INVALID_SOCKET;
Packit 1fb8d4
	HANDLE* events;
Packit 1fb8d4
	struct addrinfo* addr;
Packit 1fb8d4
	struct addrinfo* result;
Packit Service 5a9772
	t_peer* peers;
Packit Service 5a9772
	events = (HANDLE*)calloc(count + 1, sizeof(HANDLE));
Packit Service 5a9772
	peers = (t_peer*)calloc(count, sizeof(t_peer));
Packit Service 5a9772
Packit Service 5a9772
	if (!peers || !events || (count < 1))
Packit 1fb8d4
	{
Packit Service 5a9772
		free(peers);
Packit 1fb8d4
		free(events);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < count; index++)
Packit 1fb8d4
	{
Packit Service 5a9772
		int curPort = port;
Packit 1fb8d4
Packit 1fb8d4
		if (ports)
Packit Service 5a9772
			curPort = ports[index];
Packit 1fb8d4
Packit Service 5a9772
		result = freerdp_tcp_resolve_host(hostnames[index], curPort, 0);
Packit 1fb8d4
Packit 1fb8d4
		if (!result)
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
		addr = result;
Packit 1fb8d4
Packit 1fb8d4
		if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0))
Packit 1fb8d4
		{
Packit 1fb8d4
			while ((addr = addr->ai_next))
Packit 1fb8d4
			{
Packit 1fb8d4
				if (addr->ai_family == AF_INET)
Packit 1fb8d4
					break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (!addr)
Packit 1fb8d4
				addr = result;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		peers[index].s = _socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
Packit 1fb8d4
Packit Service 5a9772
		if (peers[index].s == INVALID_SOCKET)
Packit 1fb8d4
		{
Packit 1fb8d4
			freeaddrinfo(result);
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		peers[index].addr = addr;
Packit Service 5a9772
		peers[index].result = result;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < count; index++)
Packit 1fb8d4
	{
Packit Service 5a9772
		sockfd = peers[index].s;
Packit Service 5a9772
		addr = peers[index].addr;
Packit 1fb8d4
Packit Service 5a9772
		if ((sockfd == INVALID_SOCKET) || (!addr))
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit Service 5a9772
		/* blocking tcp connect */
Packit 1fb8d4
		status = _connect(sockfd, addr->ai_addr, addr->ai_addrlen);
Packit 1fb8d4
Packit 1fb8d4
		if (status >= 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* connection success */
Packit Service 5a9772
			sindex = index;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (sindex < count)
Packit 1fb8d4
	{
Packit Service 5a9772
		sockfd = peers[sindex].s;
Packit Service 5a9772
		peers[sindex].s = INVALID_SOCKET;
Packit 1fb8d4
	}
Packit Service 5a9772
	else
Packit Service 5a9772
		freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_CANCELLED);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < count; index++)
Packit Service 5a9772
		peer_free(&peers[index]);
Packit 1fb8d4
Packit Service 5a9772
	free(peers);
Packit 1fb8d4
	free(events);
Packit 1fb8d4
	return sockfd;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int sockfd)
Packit 1fb8d4
{
Packit Service 5a9772
	const BOOL keepalive = (freerdp_settings_get_bool(settings, FreeRDP_TcpKeepAlive));
Packit 1fb8d4
	UINT32 optval;
Packit 1fb8d4
	socklen_t optlen;
Packit Service 5a9772
	optval = keepalive ? 1 : 0;
Packit 1fb8d4
	optlen = sizeof(optval);
Packit 1fb8d4
Packit Service 5a9772
	if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&optval, optlen) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
#ifndef _WIN32
Packit 1fb8d4
#ifdef TCP_KEEPIDLE
Packit Service 5a9772
	optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveDelay) : 0;
Packit 1fb8d4
	optlen = sizeof(optval);
Packit 1fb8d4
Packit Service 5a9772
	if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&optval, optlen) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_WARN(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
#ifndef SOL_TCP
Packit 1fb8d4
	/* "tcp" from /etc/protocols as getprotobyname(3C) */
Packit 1fb8d4
#define SOL_TCP 6
Packit 1fb8d4
#endif
Packit 1fb8d4
#ifdef TCP_KEEPCNT
Packit Service 5a9772
	optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveRetries) : 0;
Packit 1fb8d4
	optlen = sizeof(optval);
Packit 1fb8d4
Packit Service 5a9772
	if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void*)&optval, optlen) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
#ifdef TCP_KEEPINTVL
Packit Service 5a9772
	optval = keepalive ? freerdp_settings_get_uint32(settings, FreeRDP_TcpKeepAliveInterval) : 0;
Packit 1fb8d4
	optlen = sizeof(optval);
Packit 1fb8d4
Packit Service 5a9772
	if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void*)&optval, optlen) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
#endif
Packit 1fb8d4
#if defined(__MACOSX__) || defined(__IOS__)
Packit 1fb8d4
	optval = 1;
Packit 1fb8d4
	optlen = sizeof(optval);
Packit 1fb8d4
Packit Service 5a9772
	if (setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&optval, optlen) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_WARN(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
#ifdef TCP_USER_TIMEOUT
Packit Service 5a9772
	optval = freerdp_settings_get_uint32(settings, FreeRDP_TcpAckTimeout);
Packit 1fb8d4
	optlen = sizeof(optval);
Packit 1fb8d4
Packit Service 5a9772
	if (setsockopt(sockfd, SOL_TCP, TCP_USER_TIMEOUT, (void*)&optval, optlen) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_WARN(TAG, "setsockopt() SOL_TCP, TCP_USER_TIMEOUT");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* hostname, int port,
Packit Service 5a9772
                        int timeout)
Packit 1fb8d4
{
Packit 1fb8d4
	int sockfd;
Packit 1fb8d4
	UINT32 optval;
Packit 1fb8d4
	socklen_t optlen;
Packit 1fb8d4
	BOOL ipcSocket = FALSE;
Packit 1fb8d4
	BOOL useExternalDefinedSocket = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!hostname)
Packit 1fb8d4
	{
Packit Service 5a9772
		freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
Packit 1fb8d4
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (hostname[0] == '/')
Packit 1fb8d4
		ipcSocket = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (hostname[0] == '|')
Packit 1fb8d4
		useExternalDefinedSocket = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (ipcSocket)
Packit 1fb8d4
	{
Packit 1fb8d4
		sockfd = freerdp_uds_connect(hostname);
Packit 1fb8d4
Packit 1fb8d4
		if (sockfd < 0)
Packit 1fb8d4
		{
Packit Service 5a9772
			freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
Packit 1fb8d4
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (useExternalDefinedSocket)
Packit 1fb8d4
		sockfd = port;
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		sockfd = -1;
Packit 1fb8d4
Packit 1fb8d4
		if (!settings->GatewayEnabled)
Packit 1fb8d4
		{
Packit Service 5a9772
			if (!freerdp_tcp_is_hostname_resolvable(context, hostname) ||
Packit Service 5a9772
			    settings->RemoteAssistanceMode)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (settings->TargetNetAddressCount > 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					sockfd = freerdp_tcp_connect_multi(
Packit Service 5a9772
					    context, settings->TargetNetAddresses, settings->TargetNetPorts,
Packit Service 5a9772
					    settings->TargetNetAddressCount, port, timeout);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (sockfd <= 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			char* peerAddress;
Packit 1fb8d4
			struct addrinfo* addr;
Packit 1fb8d4
			struct addrinfo* result;
Packit Service 5a9772
Packit 1fb8d4
			result = freerdp_tcp_resolve_host(hostname, port, 0);
Packit 1fb8d4
Packit 1fb8d4
			if (!result)
Packit 1fb8d4
			{
Packit Service 5a9772
				freerdp_set_last_error_if_not(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);
Packit 1fb8d4
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit Service 5a9772
			freerdp_set_last_error_log(context, 0);
Packit 1fb8d4
Packit 1fb8d4
			addr = result;
Packit 1fb8d4
Packit Service 5a9772
			if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0) &&
Packit Service 5a9772
			    !settings->PreferIPv6OverIPv4)
Packit 1fb8d4
			{
Packit 1fb8d4
				while ((addr = addr->ai_next))
Packit 1fb8d4
				{
Packit 1fb8d4
					if (addr->ai_family == AF_INET)
Packit 1fb8d4
						break;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!addr)
Packit 1fb8d4
					addr = result;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
Packit 1fb8d4
Packit 1fb8d4
			if (sockfd < 0)
Packit 1fb8d4
			{
Packit Service 5a9772
				freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
Packit 1fb8d4
Packit 1fb8d4
				freeaddrinfo(result);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit Service 5a9772
			if ((peerAddress = freerdp_tcp_address_to_string(
Packit Service 5a9772
			         (const struct sockaddr_storage*)addr->ai_addr, NULL)) != NULL)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_DBG(TAG, "connecting to peer %s", peerAddress);
Packit 1fb8d4
				free(peerAddress);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit Service 5a9772
			if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr, addr->ai_addrlen,
Packit Service 5a9772
			                                 timeout))
Packit 1fb8d4
			{
Packit 1fb8d4
				freeaddrinfo(result);
Packit 1fb8d4
				close(sockfd);
Packit 1fb8d4
Packit Service 5a9772
				freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
Packit 1fb8d4
Packit 1fb8d4
				WLog_ERR(TAG, "failed to connect to %s", hostname);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			freeaddrinfo(result);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(settings->ClientAddress);
Packit 1fb8d4
	settings->ClientAddress = freerdp_tcp_get_ip_address(sockfd, &settings->IPv6Enabled);
Packit 1fb8d4
Packit 1fb8d4
	if (!settings->ClientAddress)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!useExternalDefinedSocket)
Packit 1fb8d4
			close(sockfd);
Packit 1fb8d4
Packit Service 5a9772
		freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
Packit 1fb8d4
Packit 1fb8d4
		WLog_ERR(TAG, "Couldn't get socket ip address");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	optval = 1;
Packit 1fb8d4
	optlen = sizeof(optval);
Packit 1fb8d4
Packit 1fb8d4
	if (!ipcSocket && !useExternalDefinedSocket)
Packit 1fb8d4
	{
Packit Service 5a9772
		if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&optval, optlen) < 0)
Packit 1fb8d4
			WLog_ERR(TAG, "unable to set TCP_NODELAY");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* receive buffer must be a least 32 K */
Packit Service 5a9772
	if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, &optlen) == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (optval < (1024 * 32))
Packit 1fb8d4
		{
Packit 1fb8d4
			optval = 1024 * 32;
Packit 1fb8d4
			optlen = sizeof(optval);
Packit 1fb8d4
Packit Service 5a9772
			if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&optval, optlen) < 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				close(sockfd);
Packit 1fb8d4
Packit Service 5a9772
				freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
Packit 1fb8d4
Packit 1fb8d4
				WLog_ERR(TAG, "unable to set receive buffer len");
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!ipcSocket && !useExternalDefinedSocket)
Packit 1fb8d4
	{
Packit Service 5a9772
		if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
Packit 1fb8d4
		{
Packit 1fb8d4
			close(sockfd);
Packit 1fb8d4
Packit Service 5a9772
			freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
Packit 1fb8d4
Packit 1fb8d4
			WLog_ERR(TAG, "Couldn't set keep alive mode.");
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (WaitForSingleObject(context->abortEvent, 0) == WAIT_OBJECT_0)
Packit 1fb8d4
	{
Packit 1fb8d4
		close(sockfd);
Packit 1fb8d4
Packit Service 5a9772
		freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
Packit 1fb8d4
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return sockfd;
Packit 1fb8d4
}