Blame channels/echo/server/echo_main.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * Echo Virtual Channel Extension
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2014 Vic Lee
Packit Service fa4841
 * Copyright 2015 Thincast Technologies GmbH
Packit Service fa4841
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *	 http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <stdio.h>
Packit Service fa4841
#include <stdlib.h>
Packit Service fa4841
#include <string.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/synch.h>
Packit Service fa4841
#include <winpr/thread.h>
Packit Service fa4841
#include <winpr/stream.h>
Packit Service fa4841
#include <winpr/sysinfo.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/server/echo.h>
Packit Service fa4841
#include <freerdp/channels/log.h>
Packit Service fa4841
Packit Service fa4841
#define TAG CHANNELS_TAG("echo.server")
Packit Service fa4841
Packit Service fa4841
typedef struct _echo_server
Packit Service fa4841
{
Packit Service fa4841
	echo_server_context context;
Packit Service fa4841
Packit Service fa4841
	BOOL opened;
Packit Service fa4841
Packit Service fa4841
	HANDLE stopEvent;
Packit Service fa4841
Packit Service fa4841
	HANDLE thread;
Packit Service fa4841
	void* echo_channel;
Packit Service fa4841
Packit Service fa4841
	DWORD SessionId;
Packit Service fa4841
Packit Service fa4841
} echo_server;
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT echo_server_open_channel(echo_server* echo)
Packit Service fa4841
{
Packit Service fa4841
	DWORD Error;
Packit Service fa4841
	HANDLE hEvent;
Packit Service fa4841
	DWORD StartTick;
Packit Service fa4841
	DWORD BytesReturned = 0;
Packit Service fa4841
	PULONG pSessionId = NULL;
Packit Service fa4841
Packit Service b1ea74
	if (WTSQuerySessionInformationA(echo->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
Packit Service b1ea74
	                                (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
Packit Service fa4841
		return ERROR_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	echo->SessionId = (DWORD)*pSessionId;
Packit Service fa4841
	WTSFreeMemory(pSessionId);
Packit Service fa4841
	hEvent = WTSVirtualChannelManagerGetEventHandle(echo->context.vcm);
Packit Service fa4841
	StartTick = GetTickCount();
Packit Service fa4841
Packit Service fa4841
	while (echo->echo_channel == NULL)
Packit Service fa4841
	{
Packit Service fa4841
		if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			Error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
Packit Service fa4841
			return Error;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service b1ea74
		echo->echo_channel =
Packit Service b1ea74
		    WTSVirtualChannelOpenEx(echo->SessionId, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC);
Packit Service fa4841
Packit Service fa4841
		if (echo->echo_channel)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Error = GetLastError();
Packit Service fa4841
Packit Service fa4841
		if (Error == ERROR_NOT_FOUND)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		if (GetTickCount() - StartTick > 5000)
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return echo->echo_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD WINAPI echo_server_thread_func(LPVOID arg)
Packit Service fa4841
{
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	void* buffer;
Packit Service fa4841
	DWORD nCount;
Packit Service fa4841
	HANDLE events[8];
Packit Service fa4841
	BOOL ready = FALSE;
Packit Service fa4841
	HANDLE ChannelEvent;
Packit Service fa4841
	DWORD BytesReturned = 0;
Packit Service b1ea74
	echo_server* echo = (echo_server*)arg;
Packit Service fa4841
	UINT error;
Packit Service fa4841
	DWORD status;
Packit Service fa4841
Packit Service fa4841
	if ((error = echo_server_open_channel(echo)))
Packit Service fa4841
	{
Packit Service fa4841
		UINT error2 = 0;
Packit Service b1ea74
		WLog_ERR(TAG, "echo_server_open_channel failed with error %" PRIu32 "!", error);
Packit Service fa4841
		IFCALLRET(echo->context.OpenResult, error2, &echo->context,
Packit Service fa4841
		          ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED);
Packit Service fa4841
Packit Service fa4841
		if (error2)
Packit Service b1ea74
			WLog_ERR(TAG, "echo server's OpenResult callback failed with error %" PRIu32 "",
Packit Service fa4841
			         error2);
Packit Service fa4841
Packit Service fa4841
		goto out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	buffer = NULL;
Packit Service fa4841
	BytesReturned = 0;
Packit Service fa4841
	ChannelEvent = NULL;
Packit Service fa4841
Packit Service fa4841
	if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualEventHandle, &buffer,
Packit Service fa4841
	                           &BytesReturned) == TRUE)
Packit Service fa4841
	{
Packit Service fa4841
		if (BytesReturned == sizeof(HANDLE))
Packit Service fa4841
			CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
Packit Service fa4841
Packit Service fa4841
		WTSFreeMemory(buffer);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	nCount = 0;
Packit Service fa4841
	events[nCount++] = echo->stopEvent;
Packit Service fa4841
	events[nCount++] = ChannelEvent;
Packit Service fa4841
Packit Service fa4841
	/* Wait for the client to confirm that the Graphics Pipeline dynamic channel is ready */
Packit Service fa4841
Packit Service fa4841
	while (1)
Packit Service fa4841
	{
Packit Service fa4841
		status = WaitForMultipleObjects(nCount, events, FALSE, 100);
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_OBJECT_0)
Packit Service fa4841
		{
Packit Service fa4841
			IFCALLRET(echo->context.OpenResult, error, &echo->context,
Packit Service fa4841
			          ECHO_SERVER_OPEN_RESULT_CLOSED);
Packit Service fa4841
Packit Service fa4841
			if (error)
Packit Service b1ea74
				WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error);
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualChannelReady, &buffer,
Packit Service fa4841
		                           &BytesReturned) == FALSE)
Packit Service fa4841
		{
Packit Service fa4841
			IFCALLRET(echo->context.OpenResult, error, &echo->context,
Packit Service fa4841
			          ECHO_SERVER_OPEN_RESULT_ERROR);
Packit Service fa4841
Packit Service fa4841
			if (error)
Packit Service b1ea74
				WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error);
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service b1ea74
		ready = *((BOOL*)buffer);
Packit Service fa4841
		WTSFreeMemory(buffer);
Packit Service fa4841
Packit Service fa4841
		if (ready)
Packit Service fa4841
		{
Packit Service b1ea74
			IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_OK);
Packit Service fa4841
Packit Service fa4841
			if (error)
Packit Service b1ea74
				WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error);
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	s = Stream_New(NULL, 4096);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Stream_New failed!");
Packit Service fa4841
		WTSVirtualChannelClose(echo->echo_channel);
Packit Service fa4841
		ExitThread(ERROR_NOT_ENOUGH_MEMORY);
Packit Service fa4841
		return ERROR_NOT_ENOUGH_MEMORY;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	while (ready)
Packit Service fa4841
	{
Packit Service fa4841
		status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (status == WAIT_OBJECT_0)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_SetPosition(s, 0);
Packit Service fa4841
		WTSVirtualChannelRead(echo->echo_channel, 0, NULL, 0, &BytesReturned);
Packit Service fa4841
Packit Service fa4841
		if (BytesReturned < 1)
Packit Service fa4841
			continue;
Packit Service fa4841
Packit Service fa4841
		if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit Service fa4841
			error = CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service b1ea74
		if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR)Stream_Buffer(s),
Packit Service b1ea74
		                          (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
Packit Service fa4841
			error = ERROR_INTERNAL_ERROR;
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service b1ea74
		IFCALLRET(echo->context.Response, error, &echo->context, (BYTE*)Stream_Buffer(s),
Packit Service b1ea74
		          BytesReturned);
Packit Service fa4841
Packit Service fa4841
		if (error)
Packit Service fa4841
		{
Packit Service b1ea74
			WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Free(s, TRUE);
Packit Service fa4841
	WTSVirtualChannelClose(echo->echo_channel);
Packit Service fa4841
	echo->echo_channel = NULL;
Packit Service fa4841
out:
Packit Service fa4841
Packit Service fa4841
	if (error && echo->context.rdpcontext)
Packit Service fa4841
		setChannelError(echo->context.rdpcontext, error,
Packit Service fa4841
		                "echo_server_thread_func reported an error");
Packit Service fa4841
Packit Service fa4841
	ExitThread(error);
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT echo_server_open(echo_server_context* context)
Packit Service fa4841
{
Packit Service b1ea74
	echo_server* echo = (echo_server*)context;
Packit Service fa4841
Packit Service fa4841
	if (echo->thread == NULL)
Packit Service fa4841
	{
Packit Service fa4841
		if (!(echo->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "CreateEvent failed!");
Packit Service fa4841
			return ERROR_INTERNAL_ERROR;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service b1ea74
		if (!(echo->thread = CreateThread(NULL, 0, echo_server_thread_func, (void*)echo, 0, NULL)))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "CreateEvent failed!");
Packit Service fa4841
			CloseHandle(echo->stopEvent);
Packit Service fa4841
			echo->stopEvent = NULL;
Packit Service fa4841
			return ERROR_INTERNAL_ERROR;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT echo_server_close(echo_server_context* context)
Packit Service fa4841
{
Packit Service fa4841
	UINT error = CHANNEL_RC_OK;
Packit Service b1ea74
	echo_server* echo = (echo_server*)context;
Packit Service fa4841
Packit Service fa4841
	if (echo->thread)
Packit Service fa4841
	{
Packit Service fa4841
		SetEvent(echo->stopEvent);
Packit Service fa4841
Packit Service fa4841
		if (WaitForSingleObject(echo->thread, INFINITE) == WAIT_FAILED)
Packit Service fa4841
		{
Packit Service fa4841
			error = GetLastError();
Packit Service b1ea74
			WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
Packit Service fa4841
			return error;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		CloseHandle(echo->thread);
Packit Service fa4841
		CloseHandle(echo->stopEvent);
Packit Service fa4841
		echo->thread = NULL;
Packit Service fa4841
		echo->stopEvent = NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL echo_server_request(echo_server_context* context, const BYTE* buffer, UINT32 length)
Packit Service fa4841
{
Packit Service b1ea74
	echo_server* echo = (echo_server*)context;
Packit Service b1ea74
	return WTSVirtualChannelWrite(echo->echo_channel, (PCHAR)buffer, length, NULL);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
echo_server_context* echo_server_context_new(HANDLE vcm)
Packit Service fa4841
{
Packit Service fa4841
	echo_server* echo;
Packit Service b1ea74
	echo = (echo_server*)calloc(1, sizeof(echo_server));
Packit Service fa4841
Packit Service fa4841
	if (echo)
Packit Service fa4841
	{
Packit Service fa4841
		echo->context.vcm = vcm;
Packit Service fa4841
		echo->context.Open = echo_server_open;
Packit Service fa4841
		echo->context.Close = echo_server_close;
Packit Service fa4841
		echo->context.Request = echo_server_request;
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
		WLog_ERR(TAG, "calloc failed!");
Packit Service fa4841
Packit Service b1ea74
	return (echo_server_context*)echo;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void echo_server_context_free(echo_server_context* context)
Packit Service fa4841
{
Packit Service b1ea74
	echo_server* echo = (echo_server*)context;
Packit Service fa4841
	echo_server_close(context);
Packit Service fa4841
	free(echo);
Packit Service fa4841
}