Blame libfreerdp/core/listener.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * RDP Server Listener
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Vic Lee
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 <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
#include <fcntl.h>
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/windows.h>
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
#include <netdb.h>
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
#include <sys/un.h>
Packit 1fb8d4
#include <sys/ioctl.h>
Packit 1fb8d4
#include <sys/socket.h>
Packit 1fb8d4
#include <arpa/inet.h>
Packit 1fb8d4
#include <netinet/in.h>
Packit 1fb8d4
#include <net/if.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/handle.h>
Packit 1fb8d4
Packit 1fb8d4
#include "listener.h"
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("core.listener")
Packit 1fb8d4
Packit 1fb8d4
static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_address, UINT16 port)
Packit 1fb8d4
{
Packit 1fb8d4
	int ai_flags = 0;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	int sockfd;
Packit 1fb8d4
	char addr[64];
Packit 1fb8d4
	void* sin_addr;
Packit 1fb8d4
	int option_value;
Packit 1fb8d4
	struct addrinfo* ai;
Packit 1fb8d4
	struct addrinfo* res;
Packit 1fb8d4
	rdpListener* listener = (rdpListener*) instance->listener;
Packit 1fb8d4
#ifdef _WIN32
Packit 1fb8d4
	u_long arg;
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if (!bind_address)
Packit 1fb8d4
		ai_flags = AI_PASSIVE;
Packit 1fb8d4
Packit 1fb8d4
	res = freerdp_tcp_resolve_host(bind_address, port, ai_flags);
Packit 1fb8d4
Packit 1fb8d4
	if (!res)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	for (ai = res; ai && (listener->num_sockfds < 5); ai = ai->ai_next)
Packit 1fb8d4
	{
Packit 1fb8d4
		if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6))
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
		if (listener->num_sockfds == MAX_LISTENER_HANDLES)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "too many listening sockets");
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
Packit 1fb8d4
Packit 1fb8d4
		if (sockfd == -1)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "socket");
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (ai->ai_family == AF_INET)
Packit 1fb8d4
			sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr);
Packit 1fb8d4
		else
Packit 1fb8d4
			sin_addr = &(((struct sockaddr_in6*) ai->ai_addr)->sin6_addr);
Packit 1fb8d4
Packit 1fb8d4
		inet_ntop(ai->ai_family, sin_addr, addr, sizeof(addr));
Packit 1fb8d4
		option_value = 1;
Packit 1fb8d4
Packit 1fb8d4
		if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*) &option_value, sizeof(option_value)) == -1)
Packit 1fb8d4
			WLog_ERR(TAG, "setsockopt");
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
		fcntl(sockfd, F_SETFL, O_NONBLOCK);
Packit 1fb8d4
#else
Packit 1fb8d4
		arg = 1;
Packit 1fb8d4
		ioctlsocket(sockfd, FIONBIO, &arg;;
Packit 1fb8d4
#endif
Packit 1fb8d4
		status = _bind((SOCKET) sockfd, ai->ai_addr, ai->ai_addrlen);
Packit 1fb8d4
Packit 1fb8d4
		if (status != 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			closesocket((SOCKET) sockfd);
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		status = _listen((SOCKET) sockfd, 10);
Packit 1fb8d4
Packit 1fb8d4
		if (status != 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "listen");
Packit 1fb8d4
			closesocket((SOCKET) sockfd);
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/* FIXME: these file descriptors do not work on Windows */
Packit 1fb8d4
		listener->sockfds[listener->num_sockfds] = sockfd;
Packit 1fb8d4
		listener->events[listener->num_sockfds] = WSACreateEvent();
Packit 1fb8d4
Packit 1fb8d4
		if (!listener->events[listener->num_sockfds])
Packit 1fb8d4
		{
Packit 1fb8d4
			listener->num_sockfds = 0;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		WSAEventSelect(sockfd, listener->events[listener->num_sockfds], FD_READ | FD_ACCEPT | FD_CLOSE);
Packit 1fb8d4
		listener->num_sockfds++;
Packit 1fb8d4
		WLog_INFO(TAG, "Listening on %s:%d", addr, port);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	freeaddrinfo(res);
Packit 1fb8d4
	return (listener->num_sockfds > 0 ? TRUE : FALSE);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL freerdp_listener_open_local(freerdp_listener* instance, 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
	rdpListener* listener = (rdpListener*) instance->listener;
Packit 1fb8d4
	HANDLE hevent;
Packit 1fb8d4
Packit 1fb8d4
	if (listener->num_sockfds == MAX_LISTENER_HANDLES)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "too many listening sockets");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
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 FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	fcntl(sockfd, F_SETFL, O_NONBLOCK);
Packit 1fb8d4
	addr.sun_family = AF_UNIX;
Packit 1fb8d4
	strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
Packit 1fb8d4
	unlink(path);
Packit 1fb8d4
	status = _bind(sockfd, (struct sockaddr*) &addr, sizeof(addr));
Packit 1fb8d4
Packit 1fb8d4
	if (status != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "bind");
Packit 1fb8d4
		closesocket((SOCKET) sockfd);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = _listen(sockfd, 10);
Packit 1fb8d4
Packit 1fb8d4
	if (status != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "listen");
Packit 1fb8d4
		closesocket((SOCKET) sockfd);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	hevent = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd, WINPR_FD_READ);
Packit 1fb8d4
Packit 1fb8d4
	if (!hevent)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "failed to create sockfd event");
Packit 1fb8d4
		closesocket((SOCKET) sockfd);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	listener->sockfds[listener->num_sockfds] = sockfd;
Packit 1fb8d4
	listener->events[listener->num_sockfds] = hevent;
Packit 1fb8d4
	listener->num_sockfds++;
Packit 1fb8d4
	WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
#else
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL freerdp_listener_open_from_socket(freerdp_listener* instance, int fd)
Packit 1fb8d4
{
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
	rdpListener* listener = (rdpListener*) instance->listener;
Packit 1fb8d4
Packit 1fb8d4
	if (listener->num_sockfds == MAX_LISTENER_HANDLES)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "too many listening sockets");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	listener->sockfds[listener->num_sockfds] = fd;
Packit 1fb8d4
	listener->events[listener->num_sockfds] =
Packit 1fb8d4
	    CreateFileDescriptorEvent(NULL, FALSE, FALSE, fd, WINPR_FD_READ);
Packit 1fb8d4
Packit 1fb8d4
	if (!listener->events[listener->num_sockfds])
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	listener->num_sockfds++;
Packit 1fb8d4
	WLog_INFO(TAG, "Listening on socket %d.", fd);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
#else
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void freerdp_listener_close(freerdp_listener* instance)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	rdpListener* listener = (rdpListener*) instance->listener;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < listener->num_sockfds; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		closesocket((SOCKET) listener->sockfds[i]);
Packit 1fb8d4
		CloseHandle(listener->events[i]);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	listener->num_sockfds = 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	rdpListener* listener = (rdpListener*) instance->listener;
Packit 1fb8d4
Packit 1fb8d4
	if (listener->num_sockfds < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < listener->num_sockfds; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		rfds[*rcount] = (void*)(long)(listener->sockfds[index]);
Packit 1fb8d4
		(*rcount)++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
DWORD freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events, DWORD nCount)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	rdpListener* listener = (rdpListener*) instance->listener;
Packit 1fb8d4
Packit 1fb8d4
	if (listener->num_sockfds < 1)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	if (listener->num_sockfds > nCount)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < listener->num_sockfds; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		events[index] = listener->events[index];
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return listener->num_sockfds;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	void* sin_addr;
Packit 1fb8d4
	int peer_sockfd;
Packit 1fb8d4
	freerdp_peer* client = NULL;
Packit 1fb8d4
	int peer_addr_size;
Packit 1fb8d4
	struct sockaddr_storage peer_addr;
Packit 1fb8d4
	rdpListener* listener = (rdpListener*) instance->listener;
Packit 1fb8d4
	static const BYTE localhost6_bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
Packit 1fb8d4
	BOOL peer_accepted;
Packit 1fb8d4
Packit 1fb8d4
	if (listener->num_sockfds < 1)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < listener->num_sockfds; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		WSAResetEvent(listener->events[i]);
Packit 1fb8d4
		peer_addr_size = sizeof(peer_addr);
Packit 1fb8d4
		peer_sockfd = _accept(listener->sockfds[i], (struct sockaddr*) &peer_addr, &peer_addr_size);
Packit 1fb8d4
		peer_accepted = FALSE;
Packit 1fb8d4
Packit 1fb8d4
		if (peer_sockfd == -1)
Packit 1fb8d4
		{
Packit 1fb8d4
#ifdef _WIN32
Packit 1fb8d4
			int wsa_error = WSAGetLastError();
Packit 1fb8d4
Packit 1fb8d4
			/* No data available */
Packit 1fb8d4
			if (wsa_error == WSAEWOULDBLOCK)
Packit 1fb8d4
				continue;
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
Packit 1fb8d4
			if (errno == EAGAIN || errno == EWOULDBLOCK)
Packit 1fb8d4
				continue;
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
			WLog_DBG(TAG, "accept");
Packit 1fb8d4
			free(client);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		client = freerdp_peer_new(peer_sockfd);
Packit 1fb8d4
Packit 1fb8d4
		if (!client)
Packit 1fb8d4
		{
Packit 1fb8d4
			closesocket((SOCKET) peer_sockfd);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		sin_addr = NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (peer_addr.ss_family == AF_INET)
Packit 1fb8d4
		{
Packit 1fb8d4
			sin_addr = &(((struct sockaddr_in*) &peer_addr)->sin_addr);
Packit 1fb8d4
Packit 1fb8d4
			if ((*(UINT32*) sin_addr) == 0x0100007f)
Packit 1fb8d4
				client->local = TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (peer_addr.ss_family == AF_INET6)
Packit 1fb8d4
		{
Packit 1fb8d4
			sin_addr = &(((struct sockaddr_in6*) &peer_addr)->sin6_addr);
Packit 1fb8d4
Packit 1fb8d4
			if (memcmp(sin_addr, localhost6_bytes, 16) == 0)
Packit 1fb8d4
				client->local = TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
		else if (peer_addr.ss_family == AF_UNIX)
Packit 1fb8d4
			client->local = TRUE;
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
		if (sin_addr)
Packit 1fb8d4
			inet_ntop(peer_addr.ss_family, sin_addr, client->hostname, sizeof(client->hostname));
Packit 1fb8d4
Packit 1fb8d4
		IFCALLRET(instance->PeerAccepted, peer_accepted, instance, client);
Packit 1fb8d4
Packit 1fb8d4
		if (!peer_accepted)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "PeerAccepted callback failed");
Packit 1fb8d4
			closesocket((SOCKET) peer_sockfd);
Packit 1fb8d4
			freerdp_peer_free(client);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
freerdp_listener* freerdp_listener_new(void)
Packit 1fb8d4
{
Packit 1fb8d4
	freerdp_listener* instance;
Packit 1fb8d4
	rdpListener* listener;
Packit 1fb8d4
	instance = (freerdp_listener*) calloc(1, sizeof(freerdp_listener));
Packit 1fb8d4
Packit 1fb8d4
	if (!instance)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	instance->Open = freerdp_listener_open;
Packit 1fb8d4
	instance->OpenLocal = freerdp_listener_open_local;
Packit 1fb8d4
	instance->OpenFromSocket = freerdp_listener_open_from_socket;
Packit 1fb8d4
	instance->GetFileDescriptor = freerdp_listener_get_fds;
Packit 1fb8d4
	instance->GetEventHandles = freerdp_listener_get_event_handles;
Packit 1fb8d4
	instance->CheckFileDescriptor = freerdp_listener_check_fds;
Packit 1fb8d4
	instance->Close = freerdp_listener_close;
Packit 1fb8d4
	listener = (rdpListener*) calloc(1, sizeof(rdpListener));
Packit 1fb8d4
Packit 1fb8d4
	if (!listener)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(instance);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	listener->instance = instance;
Packit 1fb8d4
	instance->listener = (void*) listener;
Packit 1fb8d4
	return instance;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void freerdp_listener_free(freerdp_listener* instance)
Packit 1fb8d4
{
Packit 1fb8d4
	if (instance)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(instance->listener);
Packit 1fb8d4
		free(instance);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4