diff --git a/sesman/sesexec/Makefile.am b/sesman/sesexec/Makefile.am index 7adb959150..c2913a511c 100644 --- a/sesman/sesexec/Makefile.am +++ b/sesman/sesexec/Makefile.am @@ -29,6 +29,8 @@ xrdp_sesexec_SOURCES = \ env.h \ login_info.c \ login_info.h \ + sesexec_restart.c \ + sesexec_restart.h \ sessionrecord.c \ sessionrecord.h \ xauth.c \ diff --git a/sesman/sesexec/eicp_server.c b/sesman/sesexec/eicp_server.c index 80255fdf04..7745db6704 100644 --- a/sesman/sesexec/eicp_server.c +++ b/sesman/sesexec/eicp_server.c @@ -37,6 +37,7 @@ #include "ercp.h" #include "scp.h" #include "sesexec.h" +#include "sesexec_restart.h" #include "session.h" /******************************************************************************/ @@ -146,17 +147,22 @@ handle_create_session_request(struct trans *self) if (scp_status == E_SCP_SCREATE_OK) { - rv = ercp_send_session_announce_event( - self, - sp.display, - g_login_info->uid, - sp.type, - sp.width, - sp.height, - sp.bpp, - &sp.guid, - g_login_info->ip_addr, - session_get_start_time(g_session_data)); + // Now we're in charge of a session, we need to enable + // the restart functionality so we can cope if sesman fails + if ((rv = sesexec_restart_enable()) == 0) + { + rv = ercp_send_session_announce_event( + self, + sp.display, + g_login_info->uid, + sp.type, + sp.width, + sp.height, + sp.bpp, + &sp.guid, + g_login_info->ip_addr, + session_get_start_time(g_session_data)); + } } else { diff --git a/sesman/sesexec/sesexec.c b/sesman/sesexec/sesexec.c index 67b493e8d2..3fc4ed964c 100644 --- a/sesman/sesexec/sesexec.c +++ b/sesman/sesexec/sesexec.c @@ -38,6 +38,7 @@ #include "ercp_server.h" #include "login_info.h" #include "sesexec.h" +#include "sesexec_restart.h" #include "sesman_config.h" #include "log.h" #include "os_calls.h" @@ -262,7 +263,8 @@ sesexec_main_loop(void) { int error = 0; int robjs_count; - intptr_t robjs[32]; +#define MAX_ROBJS 32 + intptr_t robjs[MAX_ROBJS]; g_terminate_loop = 0; g_terminate_status = 0; @@ -274,11 +276,25 @@ sesexec_main_loop(void) robjs[robjs_count++] = g_term_event; robjs[robjs_count++] = g_sigchld_event; - error = trans_get_wait_objs(g_ecp_trans, robjs, &robjs_count); + // ECP transport may be null if sesman has gone away + if (g_ecp_trans != NULL) + { + error = trans_get_wait_objs(g_ecp_trans, robjs, &robjs_count); + if (error != 0) + { + LOG(LOG_LEVEL_ERROR, "sesexec_main_loop: " + "trans_get_wait_objs(ECP) failed"); + sesexec_terminate_main_loop(error); + continue; + } + } + + // Add any objects from the restart module + error = sesexec_restart_get_wait_objs(robjs, &robjs_count, MAX_ROBJS); if (error != 0) { LOG(LOG_LEVEL_ERROR, "sesexec_main_loop: " - "trans_get_wait_objs(ECP) failed"); + "sesexec_restart_get_wait_objs() failed"); sesexec_terminate_main_loop(error); continue; } @@ -326,7 +342,10 @@ sesexec_main_loop(void) { // We've finished the session. Tell sesman and // finish up. - (void)ercp_send_session_finished_event(g_ecp_trans); + if (g_ecp_trans != NULL) + { + (void)ercp_send_session_finished_event(g_ecp_trans); + } session_data_free(g_session_data); g_session_data = NULL; @@ -335,19 +354,47 @@ sesexec_main_loop(void) } } - error = trans_check_wait_objs(g_ecp_trans); + if (g_ecp_trans != NULL) + { + error = trans_check_wait_objs(g_ecp_trans); + if (error != 0) + { + LOG(LOG_LEVEL_ERROR, "sesexec_main_loop: " + "trans_check_wait_objs failed for ECP transport"); + if (g_ecp_trans->status != TRANS_STATUS_UP && + session_active(g_session_data)) + { + // sesman has gone away. We have an active session + // to keep track of, so sesman can pick it up when it + // restarts + trans_delete(g_ecp_trans); + g_ecp_trans = NULL; + } + else + { + // A callback has failed, or sesman has gone away and + // we have no active session + sesexec_terminate_main_loop(error); + } + continue; + } + } + + error = sesexec_restart_check_wait_objs(); if (error != 0) { LOG(LOG_LEVEL_ERROR, "sesexec_main_loop: " - "trans_check_wait_objs failed for ECP transport"); + "sesexec_restart_check_wait_objs failed"); sesexec_terminate_main_loop(error); continue; } + } login_info_free(g_login_info); return g_terminate_status; +#undef MAX_ROBJS } /******************************************************************************/ @@ -508,6 +555,7 @@ main(int argc, char **argv) LOG(LOG_LEVEL_INFO, "starting xrdp-sesexec with pid %d", g_pid); error = sesexec_main_loop(); trans_delete(g_ecp_trans); + sesexec_restart_disable(); } g_delete_wait_obj(g_term_event); diff --git a/sesman/sesexec/sesexec_restart.c b/sesman/sesexec/sesexec_restart.c new file mode 100644 index 0000000000..a6b62c4764 --- /dev/null +++ b/sesman/sesexec/sesexec_restart.c @@ -0,0 +1,63 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2024 + * + * 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 login_info.c + * @brief Declare functionality associated with sesman restart support + * @author Matt Burt + * + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include "sesexec_restart.h" + +/******************************************************************************/ +int +sesexec_restart_enable(void) +{ + return 0; +} + +/******************************************************************************/ + +int +sesexec_restart_disable(void) +{ + return 0; +} + +/******************************************************************************/ + +int +sesexec_restart_get_wait_objs(intptr_t robjs[], int *robjs_count, + int max_count) +{ + return 0; +} + +/******************************************************************************/ + +int +sesexec_restart_check_wait_objs(void) +{ + return 0; +} diff --git a/sesman/sesexec/sesexec_restart.h b/sesman/sesexec/sesexec_restart.h new file mode 100644 index 0000000000..3a892cfc55 --- /dev/null +++ b/sesman/sesexec/sesexec_restart.h @@ -0,0 +1,77 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2024 + * + * 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 sesexec_restart.h + * @brief Declare functionality associated with sesman restart support + * for sesexec + * + * @author Matt Burt + * + */ + +#ifndef SESEXEC_RESTART_H +#define SESEXEC_RESTART_H + +#include + +/** + * Start the listening object used when sesman restarts + * + * @return != 0 for error + */ +int +sesexec_restart_enable(void); + +/** + * Stop the listening object used when sesman restarts, and deallocate all + * module resources. + * + * @return != 0 for error + */ +int +sesexec_restart_disable(void); + +/** + * Add any file descriptors in use by the module to an array + * + * @param robjs Array to add fds to + * @param[in,out] robjs_count Index where elements are to be added + * @param max_count Max value of robjs_count + * @return != 0 for error + * + * This function can be called before sesexec_restart_enable(), + * in which case it does nothing. + */ +int +sesexec_restart_get_wait_objs(intptr_t robjs[], int *robjs_count, + int max_count); + + +/** + * Check any file descriptors in use by the module for actionable events + * @return != 0 for error + * + * This function can be called before sesexec_restart_enable(), + * in which case it does nothing. + */ +int +sesexec_restart_check_wait_objs(void); + +#endif // SESEXEC_RESTART_H