Merge pull request #2511 from Nexarian/egfx_tests

A simple working unit test for the newly introduced EGFX functions
This commit is contained in:
Nexarian 2023-01-24 17:43:07 -05:00 committed by GitHub
commit 29ef7f896a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 414 additions and 196 deletions

View File

@ -1692,12 +1692,7 @@ int
g_set_wait_obj(tintptr obj)
{
#ifdef _WIN32
if (obj == 0)
{
return 0;
}
SetEvent((HANDLE)obj);
return 0;
#error "Win32 is no longer supported."
#else
int error;
int fd;
@ -1709,7 +1704,7 @@ g_set_wait_obj(tintptr obj)
{
return 0;
}
fd = obj & 0xffff;
fd = obj & USHRT_MAX;
if (g_fd_can_read(fd))
{
/* already signalled */

View File

@ -23,6 +23,8 @@
#include "xrdp_rail.h"
struct list;
/* struct xrdp_client_info moved to xrdp_client_info.h */
struct xrdp_brush

View File

@ -19,6 +19,8 @@
#if !defined(_XRDP_ORDERS_RAIL_H)
#define _XRDP_ORDERS_RAIL_H
#include "libxrdp.h"
int
xrdp_orders_send_window_delete(struct xrdp_orders *self, int window_id);
int

View File

@ -26,6 +26,7 @@ check_PROGRAMS = test_xrdp
test_xrdp_SOURCES = \
test_xrdp.h \
test_xrdp_main.c \
test_xrdp_egfx.c \
test_bitmap_load.c
test_xrdp_CFLAGS = \
@ -37,5 +38,24 @@ test_xrdp_LDADD = \
$(top_builddir)/xrdp/xrdp_bitmap_common.o \
$(top_builddir)/xrdp/funcs.o \
$(top_builddir)/common/libcommon.la \
$(top_builddir)/libipm/libipm.la \
$(top_builddir)/libxrdp/libxrdp.la \
$(top_builddir)/libpainter/src/libpainter.la \
$(top_builddir)/librfxcodec/src/librfxencode.la \
$(top_builddir)/xrdp/lang.o \
$(top_builddir)/xrdp/xrdp_mm.o \
$(top_builddir)/xrdp/xrdp_wm.o \
$(top_builddir)/xrdp/xrdp_font.o \
$(top_builddir)/xrdp/xrdp_egfx.o \
$(top_builddir)/xrdp/xrdp_cache.o \
$(top_builddir)/xrdp/xrdp_region.o \
$(top_builddir)/xrdp/xrdp_listen.o \
$(top_builddir)/xrdp/xrdp_bitmap.o \
$(top_builddir)/xrdp/xrdp_painter.o \
$(top_builddir)/xrdp/xrdp_encoder.o \
$(top_builddir)/xrdp/xrdp_process.o \
$(top_builddir)/xrdp/xrdp_login_wnd.o \
$(top_builddir)/xrdp/xrdp_main_utils.o \
$(PIXMAN_LIBS) \
$(IMLIB2_LIBS) \
@CHECK_LIBS@

View File

@ -4,5 +4,6 @@
#include <check.h>
Suite *make_suite_test_bitmap_load(void);
Suite *make_suite_egfx_base_functions(void);
#endif /* TEST_XRDP_H */

View File

@ -0,0 +1,76 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Test driver for XRDP routines
*
* If you want to run this driver under valgrind to check for memory leaks,
* use the following command line:-
*
* CK_FORK=no valgrind --leak-check=full --show-leak-kinds=all \
* .libs/test_xrdp
*
* without the 'CK_FORK=no', memory still allocated by the test driver will
* be logged
*/
#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include "log.h"
#include "os_calls.h"
#include <stdlib.h>
#include "xrdp_egfx.h"
#include "test_xrdp.h"
START_TEST(test_xrdp_egfx_send_create_surface__happy_path)
{
struct xrdp_egfx_bulk *bulk = g_new0(struct xrdp_egfx_bulk, 1);
const int surface_id = 0xFF;
const int width = 640;
const int height = 480;
const int pixel_format = 32;
struct stream *s = xrdp_egfx_create_surface(
bulk, surface_id, width, height, pixel_format);
s->p = s->data;
unsigned char descriptor;
in_uint8(s, descriptor);
ck_assert_int_eq(0xE0, descriptor);
}
END_TEST
/******************************************************************************/
Suite *
make_suite_egfx_base_functions(void)
{
Suite *s;
TCase *tc_process_monitors;
s = suite_create("test_xrdp_egfx_base_functions");
tc_process_monitors = tcase_create("xrdp_egfx_base_functions");
tcase_add_test(tc_process_monitors,
test_xrdp_egfx_send_create_surface__happy_path);
suite_add_tcase(s, tc_process_monitors);
return s;
}

View File

@ -51,6 +51,7 @@ int main (void)
log_config_free(logging);
sr = srunner_create (make_suite_test_bitmap_load());
srunner_add_suite(sr, make_suite_egfx_base_functions());
srunner_set_tap(sr, "-");
srunner_run_all (sr, CK_ENV);

View File

@ -60,7 +60,8 @@ xrdp_SOURCES = \
xrdp_types.h \
xrdp_egfx.c \
xrdp_egfx.h \
xrdp_wm.c
xrdp_wm.c \
xrdp_main_utils.c
xrdp_LDADD = \
$(top_builddir)/common/libcommon.la \

View File

@ -33,21 +33,7 @@
#define PACKAGE_VERSION "???"
#endif
#define THREAD_WAITING 100
static struct xrdp_listen *g_listen = 0;
static long g_threadid = 0; /* main threadid */
static long g_sync_mutex = 0;
static long g_sync1_mutex = 0;
static tbus g_term_event = 0;
static tbus g_sync_event = 0;
/* synchronize stuff */
static int g_sync_command = 0;
static long g_sync_result = 0;
static long g_sync_param1 = 0;
static long g_sync_param2 = 0;
static long (*g_sync_func)(long param1, long param2);
/*****************************************************************************/
static void
@ -84,63 +70,6 @@ print_help(void)
g_writeln(" --dump-config display config on stdout on startup");
}
/*****************************************************************************/
/* This function is used to run a function from the main thread.
Sync_func is the function pointer that will run from main thread
The function can have two long in parameters and must return long */
long
g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1,
long sync_param2)
{
long sync_result;
int sync_command;
/* If the function is called from the main thread, the function can
* be called directly. g_threadid= main thread ID*/
if (tc_threadid_equal(tc_get_threadid(), g_threadid))
{
/* this is the main thread, call the function directly */
/* in fork mode, this always happens too */
sync_result = sync_func(sync_param1, sync_param2);
LOG_DEVEL(LOG_LEVEL_DEBUG, "g_xrdp_sync processed IN main thread -> continue");
}
else
{
/* All threads have to wait here until the main thread
* process the function. g_process_waiting_function() is called
* from the listening thread. g_process_waiting_function() process the function*/
tc_mutex_lock(g_sync1_mutex);
tc_mutex_lock(g_sync_mutex);
g_sync_param1 = sync_param1;
g_sync_param2 = sync_param2;
g_sync_func = sync_func;
/* set a value THREAD_WAITING so the g_process_waiting_function function
* know if any function must be processed */
g_sync_command = THREAD_WAITING;
tc_mutex_unlock(g_sync_mutex);
/* set this event so that the main thread know if
* g_process_waiting_function() must be called */
g_set_wait_obj(g_sync_event);
do
{
g_sleep(100);
tc_mutex_lock(g_sync_mutex);
/* load new value from global to see if the g_process_waiting_function()
* function has processed the function */
sync_command = g_sync_command;
sync_result = g_sync_result;
tc_mutex_unlock(g_sync_mutex);
}
while (sync_command != 0); /* loop until g_process_waiting_function()
* has processed the request */
tc_mutex_unlock(g_sync1_mutex);
LOG_DEVEL(LOG_LEVEL_DEBUG, "g_xrdp_sync processed BY main thread -> continue");
}
return sync_result;
}
/*****************************************************************************/
/* Signal handler for SIGINT and SIGTERM
* Note: only signal safe code (eg. setting wait event) should be executed in
@ -149,10 +78,7 @@ g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1,
static void
xrdp_shutdown(int sig)
{
if (!g_is_wait_obj_set(g_term_event))
{
g_set_wait_obj(g_term_event);
}
g_set_wait_obj(g_get_term());
}
/*****************************************************************************/
@ -168,95 +94,6 @@ xrdp_child(int sig)
}
}
/*****************************************************************************/
/* No-op signal handler.
* Note: only signal safe code (eg. setting wait event) should be executed in
* this function. For more details see `man signal-safety`
*/
static void
xrdp_sig_no_op(int sig)
{
/* no-op */
}
/*****************************************************************************/
/* called in child just after fork */
int
xrdp_child_fork(void)
{
int pid;
char text[256];
/* close, don't delete these */
g_close_wait_obj(g_term_event);
g_close_wait_obj(g_sync_event);
pid = g_getpid();
g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid);
g_term_event = g_create_wait_obj(text);
g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid);
g_sync_event = g_create_wait_obj(text);
return 0;
}
/*****************************************************************************/
int
g_is_term(void)
{
return g_is_wait_obj_set(g_term_event);
}
/*****************************************************************************/
void
g_set_term(int in_val)
{
if (in_val)
{
g_set_wait_obj(g_term_event);
}
else
{
g_reset_wait_obj(g_term_event);
}
}
/*****************************************************************************/
tbus
g_get_term_event(void)
{
return g_term_event;
}
/*****************************************************************************/
tbus
g_get_sync_event(void)
{
return g_sync_event;
}
/*****************************************************************************/
/*Some function must be called from the main thread.
if g_sync_command==THREAD_WAITING a function is waiting to be processed*/
void
g_process_waiting_function(void)
{
tc_mutex_lock(g_sync_mutex);
if (g_sync_command != 0)
{
if (g_sync_func != 0)
{
if (g_sync_command == THREAD_WAITING)
{
g_sync_result = g_sync_func(g_sync_param1, g_sync_param2);
}
}
g_sync_command = 0;
}
tc_mutex_unlock(g_sync_mutex);
}
/*****************************************************************************/
/**
* @brief looks for a case-insensitive match of a string in a list
@ -284,6 +121,16 @@ static int nocase_matches(const char *candidate, ...)
return result;
}
/*****************************************************************************/
/* No-op signal handler.
* Note: only signal safe code (eg. setting wait event) should be executed in
* this function. For more details see `man signal-safety`
*/
static void
xrdp_sig_no_op(int sig)
{
/* no-op */
}
/*****************************************************************************/
/**
@ -672,29 +519,29 @@ main(int argc, char **argv)
/* end of daemonizing code */
}
g_threadid = tc_get_threadid();
g_set_threadid(tc_get_threadid());
g_listen = xrdp_listen_create();
g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */
g_signal_pipe(xrdp_sig_no_op); /* SIGPIPE */
g_signal_terminate(xrdp_shutdown); /* SIGTERM */
g_signal_child_stop(xrdp_child); /* SIGCHLD */
g_signal_hang_up(xrdp_sig_no_op); /* SIGHUP */
g_sync_mutex = tc_mutex_create();
g_sync1_mutex = tc_mutex_create();
g_set_sync_mutex(tc_mutex_create());
g_set_sync1_mutex(tc_mutex_create());
pid = g_getpid();
LOG(LOG_LEVEL_INFO, "starting xrdp with pid %d", pid);
g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid);
g_term_event = g_create_wait_obj(text);
g_set_term_event(g_create_wait_obj(text));
if (g_term_event == 0)
if (g_get_term() == 0)
{
LOG(LOG_LEVEL_WARNING, "error creating g_term_event");
}
g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid);
g_sync_event = g_create_wait_obj(text);
g_set_sync_event(g_create_wait_obj(text));
if (g_sync_event == 0)
if (g_get_sync_event() == 0)
{
LOG(LOG_LEVEL_WARNING, "error creating g_sync_event");
}
@ -702,10 +549,18 @@ main(int argc, char **argv)
g_listen->startup_params = &startup_params;
exit_status = xrdp_listen_main_loop(g_listen);
xrdp_listen_delete(g_listen);
tc_mutex_delete(g_sync_mutex);
tc_mutex_delete(g_sync1_mutex);
g_delete_wait_obj(g_term_event);
g_delete_wait_obj(g_sync_event);
tc_mutex_delete(g_get_sync_mutex());
g_set_sync_mutex(0);
tc_mutex_delete(g_get_sync1_mutex());
g_set_sync1_mutex(0);
g_delete_wait_obj(g_get_term());
g_set_term_event(0);
g_delete_wait_obj(g_get_sync_event());
g_set_sync_event(0);
/* only main process should delete pid file */
if (daemon && (pid == g_getpid()))

View File

@ -41,13 +41,29 @@ g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1,
long sync_param2);
int
xrdp_child_fork(void);
long
g_get_sync_mutex(void);
void
g_set_sync_mutex(long mutex);
long
g_get_sync1_mutex(void);
void
g_set_sync1_mutex(long mutex);
void
g_set_term_event(tbus event);
void
g_set_sync_event(tbus event);
long
g_get_threadid(void);
void
g_set_threadid(long id);
tbus
g_get_term(void);
int
g_is_term(void);
void
g_set_term(int in_val);
tbus
g_get_term_event(void);
tbus
g_get_sync_event(void);
void
g_process_waiting_function(void);

View File

@ -18,6 +18,14 @@
* MS-RDPEGFX
*/
/**
*
* @file xrdp_egfx.c
* @brief Stream functions for the EGFX extension to the MSRDP protocol.
* @author Jay Sorg, Christopher Pitstick
*
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
@ -29,7 +37,6 @@
#include "arch.h"
#include "os_calls.h"
#include "parse.h"
#include "xrdp.h"
#include "xrdp_egfx.h"
#include "libxrdp.h"
#include "xrdp_channel.h"

View File

@ -18,9 +18,19 @@
* MS-RDPEGFX
*/
/**
*
* @file xrdp_egfx.h
* @brief Stream function headers for the EGFX extension to the MSRDP protocol.
* @author Jay Sorg, Christopher Pitstick
*
*/
#ifndef _XRDP_EGFX_H
#define _XRDP_EGFX_H
#include "xrdp.h"
#define XR_RDPGFX_CAPVERSION_8 0x00080004
#define XR_RDPGFX_CAPVERSION_81 0x00080105
#define XR_RDPGFX_CAPVERSION_10 0x000A0002

View File

@ -481,7 +481,7 @@ proc_enc_msg(void *arg)
mutex = self->mutex;
event_to_proc = self->xrdp_encoder_event_to_proc;
term_obj = g_get_term_event();
term_obj = g_get_term();
lterm_obj = self->xrdp_encoder_term;
cont = 1;

View File

@ -875,7 +875,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
self->status = -1;
return 1;
}
term_obj = g_get_term_event(); /*Global termination event */
term_obj = g_get_term(); /*Global termination event */
sync_obj = g_get_sync_event();
done_obj = self->pro_done_event;
cont = 1;

239
xrdp/xrdp_main_utils.c Normal file
View File

@ -0,0 +1,239 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/**
*
* @file xrdp_main_utils.c
* @brief Functions used by XRDP's main() routine and needed elsewhere.
* @author Jay Sorg, Christopher Pitstick
*
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include "xrdp.h"
#include "log.h"
#define THREAD_WAITING 100
static long g_threadid = 0; /* main threadid */
static long g_sync_mutex = 0;
static long g_sync1_mutex = 0;
static tbus g_term_event = 0;
static tbus g_sync_event = 0;
/* synchronize stuff */
static int g_sync_command = 0;
static long g_sync_result = 0;
static long g_sync_param1 = 0;
static long g_sync_param2 = 0;
static long (*g_sync_func)(long param1, long param2);
/*****************************************************************************/
/* This function is used to run a function from the main thread.
Sync_func is the function pointer that will run from main thread
The function can have two long in parameters and must return long */
long
g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1,
long sync_param2)
{
long sync_result;
int sync_command;
/* If the function is called from the main thread, the function can
* be called directly. g_threadid= main thread ID*/
if (tc_threadid_equal(tc_get_threadid(), g_threadid))
{
/* this is the main thread, call the function directly */
/* in fork mode, this always happens too */
sync_result = sync_func(sync_param1, sync_param2);
LOG_DEVEL(LOG_LEVEL_DEBUG, "g_xrdp_sync processed IN main thread -> continue");
}
else
{
/* All threads have to wait here until the main thread
* process the function. g_process_waiting_function() is called
* from the listening thread. g_process_waiting_function() process the function*/
tc_mutex_lock(g_sync1_mutex);
tc_mutex_lock(g_sync_mutex);
g_sync_param1 = sync_param1;
g_sync_param2 = sync_param2;
g_sync_func = sync_func;
/* set a value THREAD_WAITING so the g_process_waiting_function function
* know if any function must be processed */
g_sync_command = THREAD_WAITING;
tc_mutex_unlock(g_sync_mutex);
/* set this event so that the main thread know if
* g_process_waiting_function() must be called */
g_set_wait_obj(g_sync_event);
do
{
g_sleep(100);
tc_mutex_lock(g_sync_mutex);
/* load new value from global to see if the g_process_waiting_function()
* function has processed the function */
sync_command = g_sync_command;
sync_result = g_sync_result;
tc_mutex_unlock(g_sync_mutex);
}
while (sync_command != 0); /* loop until g_process_waiting_function()
* has processed the request */
tc_mutex_unlock(g_sync1_mutex);
LOG_DEVEL(LOG_LEVEL_DEBUG, "g_xrdp_sync processed BY main thread -> continue");
}
return sync_result;
}
/*****************************************************************************/
/* called in child just after fork */
int
xrdp_child_fork(void)
{
int pid;
char text[256];
/* close, don't delete these */
g_close_wait_obj(g_term_event);
g_close_wait_obj(g_sync_event);
pid = g_getpid();
g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid);
g_term_event = g_create_wait_obj(text);
g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid);
g_sync_event = g_create_wait_obj(text);
return 0;
}
/*****************************************************************************/
long
g_get_sync_mutex(void)
{
return g_sync_mutex;
}
/*****************************************************************************/
void
g_set_sync_mutex(long mutex)
{
g_sync_mutex = mutex;
}
/*****************************************************************************/
long
g_get_sync1_mutex(void)
{
return g_sync1_mutex;
}
/*****************************************************************************/
void
g_set_sync1_mutex(long mutex)
{
g_sync1_mutex = mutex;
}
/*****************************************************************************/
void
g_set_term_event(tbus event)
{
g_term_event = event;
}
/*****************************************************************************/
tbus
g_get_sync_event(void)
{
return g_sync_event;
}
/*****************************************************************************/
void
g_set_sync_event(tbus event)
{
g_sync_event = event;
}
/*****************************************************************************/
long
g_get_threadid(void)
{
return g_threadid;
}
/*****************************************************************************/
void
g_set_threadid(long id)
{
g_threadid = id;
}
/*****************************************************************************/
tbus
g_get_term(void)
{
return g_term_event;
}
/*****************************************************************************/
int
g_is_term(void)
{
return g_is_wait_obj_set(g_term_event);
}
/*****************************************************************************/
void
g_set_term(int in_val)
{
if (in_val)
{
g_set_wait_obj(g_term_event);
}
else
{
g_reset_wait_obj(g_term_event);
}
}
/*****************************************************************************/
/*Some function must be called from the main thread.
if g_sync_command==THREAD_WAITING a function is waiting to be processed*/
void
g_process_waiting_function(void)
{
tc_mutex_lock(g_sync_mutex);
if (g_sync_command != 0)
{
if (g_sync_func != 0)
{
if (g_sync_command == THREAD_WAITING)
{
g_sync_result = g_sync_func(g_sync_param1, g_sync_param2);
}
}
g_sync_command = 0;
}
tc_mutex_unlock(g_sync_mutex);
}

View File

@ -249,7 +249,7 @@ xrdp_process_main_loop(struct xrdp_process *self)
{
init_stream(self->server_trans->in_s, 32 * 1024);
term_obj = g_get_term_event();
term_obj = g_get_term();
cont = 1;
while (cont)

View File

@ -122,13 +122,6 @@ g_set_term(int in_val)
}
}
/*****************************************************************************/
tbus
g_get_term_event(void)
{
return g_term_event;
}
/*****************************************************************************/
tbus
g_get_sync_event(void)