示例#1
0
文件: tcp.c 项目: kdienes/FreeRDP
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;
}
示例#2
0
文件: tcp.c 项目: MrRecovery/FreeRDP
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;
}