From 6234ccd2f4eec4287dd4152ff7062d8ae88e2041 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 16 Oct 2025 12:03:09 +0100 Subject: [PATCH] xrdpapi: Add demo program for session events --- xrdpapi/Makefile.am | 15 +++- xrdpapi/connectmon.c | 180 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 xrdpapi/connectmon.c diff --git a/xrdpapi/Makefile.am b/xrdpapi/Makefile.am index 266b07a5..a9801635 100644 --- a/xrdpapi/Makefile.am +++ b/xrdpapi/Makefile.am @@ -1,5 +1,6 @@ EXTRA_DIST = \ simple.c \ + connectmon.c \ vrplayer.c \ vrplayer.mk @@ -17,8 +18,18 @@ libxrdpapi_la_SOURCES = \ libxrdpapi_la_LIBADD = \ $(top_builddir)/common/libcommon.la -# Build the 'simple' example program, so it's added to the CI -noinst_PROGRAMS = xrdp-xrdpapi-simple +# Build the 'simple' example programs, so they are added to the CI +noinst_PROGRAMS = \ + xrdp-xrdpapi-connectmon \ + xrdp-xrdpapi-simple + +xrdp_xrdpapi_connectmon_SOURCES = \ + connectmon.c + +# If you change this, update the standalone build instructions in connectmon.c +xrdp_xrdpapi_connectmon_LDADD = \ + libxrdpapi.la \ + $(top_builddir)/common/libcommon.la xrdp_xrdpapi_simple_SOURCES = \ simple.c diff --git a/xrdpapi/connectmon.c b/xrdpapi/connectmon.c new file mode 100644 index 00000000..38b5dfc0 --- /dev/null +++ b/xrdpapi/connectmon.c @@ -0,0 +1,180 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2012-2013 + * Copyright (C) Laxmikant Rashinkar 2012-2013 + * + * 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. + * + * sample program to demonstrate use of xrdpapi connection monitoring + * + */ + +/* + * build instructions: + * gcc connectmon.c -o connectmon \ + * -I.. -I../common -L./.libs -L../common/.libs \ + * -DHAVE_CONFIG_H -lxrdpapi -lcommon + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include "xrdpapi.h" +#include "log.h" + +#include +#include +#include +#include + +/******************************************************************************/ +static void +print_current_connection_state(void) +{ + WTS_CONNECTSTATE_CLASS connect_state; + char buff[64]; + const char *statestr = "unavailable"; + if (WTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, + WTS_CURRENT_SESSION, + WTSConnectState, + &connect_state, NULL, NULL)) + { + if (connect_state == WTSConnected) + { + statestr = "connected"; + } + else if (connect_state == WTSDisconnected) + { + statestr = "disconnected"; + } + else + { + snprintf(buff, sizeof(buff), + "unrecognised val %d", (int)connect_state); + statestr = buff; + } + } + printf("Current connect state is %s\n", statestr); +} + +/******************************************************************************/ +static LRESULT +callback (void *cbdata, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result = 1; + int *countptr = (int *)cbdata; + + switch (wParam) + { + case WTS_REMOTE_CONNECT: + ++*countptr; + printf("State change %d : Connect to session\n", *countptr); + print_current_connection_state(); + break; + + case WTS_REMOTE_DISCONNECT: + ++*countptr; + printf("State change %d : Disconnect from session\n", *countptr); + print_current_connection_state(); + break; + + default: + printf("** Unexpected callback reason %ld\n", (long)wParam); + result = 0; + } + + return result; +} + +/******************************************************************************/ +int +main(int argc, char **argv) +{ + int result = 0; + int changes = 10; + int fd; + struct log_config *lc; + + if ((lc = log_config_init_for_console(LOG_LEVEL_DEBUG, NULL)) != NULL) + { + log_start_from_param(lc); + } + + if (argc > 1 && atoi(argv[1]) > 0) + { + changes = atoi(argv[1]); + } + printf("Connection monitor : exiting after %d state changes\n", changes); + + print_current_connection_state(); + + + if (!WTSRegisterSessionNotificationEx(WTS_CURRENT_SERVER_HANDLE, &fd, 0, NULL)) + { + result = 1; // Error occurred (should be logged) + } + else + { + int count = 0; + while (count < changes && result == 0) + { + struct pollfd pollarg = + { + .fd = fd, + .events = (POLLIN | POLLERR), + .revents = 0 + }; + int pollstat; + LRESULT cbresult; + + if ((pollstat = poll(&pollarg, 1, -1)) < 0) + { + printf("** Error from poll() : %s\n", strerror(errno)); + result = 1; + } + else if (pollstat == 0) + { + printf("** Timeout from poll() !?\n"); + result = 1; + } + else if ((pollarg.revents & POLLERR)) + { + printf("** File descriptor was closed\n"); + result = 1; + } + else if (!WTSGetDispatchMessage(&count, callback, &cbresult)) + { + printf("** Unexpected faiure to dispatch message\n"); + result = 1; + } + else if (!cbresult) + { + printf("** Callback failed\n"); + result = 1; + } + } + + (void)WTSUnRegisterSessionNotificationEx(WTS_CURRENT_SERVER_HANDLE, + fd, NULL); + } + + if (lc != NULL) + { + log_config_free(lc); + log_end(); + } + + return result; +}