Skip to content

Commit d73ce46

Browse files
authored
Merge pull request #3483 from matt335672/add_startup_wait_time
Add a StartupWaitTime parameter
2 parents c65c734 + 5de642c commit d73ce46

File tree

9 files changed

+177
-58
lines changed

9 files changed

+177
-58
lines changed

docs/man/sesman.ini.5.in

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,16 @@ Note that the \fBU\fR and \fBB\fR criteria cannot be turned
237237
off. \fBDisplaySize\fR refers to the initial geometry of a connection,
238238
as actual display sizes can change dynamically.
239239

240+
.TP
241+
\fBStartupWaitTime\fR=\fInumber\fR
242+
Milliseconds to wait to ensure the session has started. The default is 1500
243+
milli-seconds.
244+
.IP
245+
Making this larger does not increase the session startup time, but
246+
will increase the time for the first connection to a session.
247+
The value can be set to zero. If this is done, sessions which fail
248+
early will not be reported to the user.
249+
240250
.SH "SECURITY"
241251
Following parameters can be used in the \fB[Security]\fR section.
242252

libipm/scp_application_types.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ scp_screate_status_to_str(enum scp_screate_status n,
6868
(n == E_SCP_SCREATE_MAX_REACHED) ? "Max session limit reached" :
6969
(n == E_SCP_SCREATE_NO_DISPLAY) ? "No X displays are available" :
7070
(n == E_SCP_SCREATE_X_SERVER_FAIL) ? "X server could not be started" :
71+
(n == E_SCP_SCREATE_SESSION_FAIL) ? "Session failed immediately" :
7172
(n == E_SCP_SCREATE_GENERAL_ERROR) ? "General session creation error" :
7273
/* Default */ NULL;
7374

libipm/scp_application_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ enum scp_screate_status
9898
E_SCP_SCREATE_MAX_REACHED, ///< Max number of sessions already reached
9999
E_SCP_SCREATE_NO_DISPLAY, ///< No X server display number is available
100100
E_SCP_SCREATE_X_SERVER_FAIL, ///< X server could not be started
101+
E_SCP_SCREATE_SESSION_FAIL, ///< The session failed quickly
101102
E_SCP_SCREATE_GENERAL_ERROR ///< An unspecific error has occurred
102103
};
103104

sesman/libsesman/sesman_config.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#define SESMAN_CFG_SESS_DISC_LIMIT "DisconnectedTimeLimit"
8282
#define SESMAN_CFG_SESS_X11DISPLAYOFFSET "X11DisplayOffset"
8383
#define SESMAN_CFG_SESS_MAX_DISPLAY "MaxDisplayNumber"
84+
#define SESMAN_CFG_SESS_STARTUP_WAIT_TIME "StartupWaitTime"
8485

8586
#define SESMAN_CFG_SESS_POLICY_S "Policy"
8687
#define SESMAN_CFG_SESS_POLICY_DFLT_S "Default"
@@ -428,6 +429,7 @@ config_read_sessions(int file, struct config_sessions *se, struct list *param_n,
428429
se->max_disc_time = 0;
429430
se->kill_disconnected = 0;
430431
se->policy = SESMAN_CFG_SESS_POLICY_DEFAULT;
432+
se->startup_wait_time = 1500;
431433

432434
file_read_section(file, SESMAN_CFG_SESSIONS, param_n, param_v);
433435

@@ -482,6 +484,20 @@ config_read_sessions(int file, struct config_sessions *se, struct list *param_n,
482484
{
483485
se->policy = parse_policy_string(value);
484486
}
487+
488+
else if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_STARTUP_WAIT_TIME))
489+
{
490+
int startup_wait_time = g_atoi(value);
491+
if (startup_wait_time > 0 && startup_wait_time <= 15 * 1000)
492+
{
493+
se->startup_wait_time = startup_wait_time;
494+
}
495+
else
496+
{
497+
LOG(LOG_LEVEL_WARNING,
498+
"Ignoring bad " SESMAN_CFG_SESS_STARTUP_WAIT_TIME " value");
499+
}
500+
}
485501
}
486502

487503
return 0;
@@ -673,6 +689,7 @@ config_dump(struct config_sesman *config)
673689
g_writeln(" IdleTimeLimit: %d", se->max_idle_time);
674690
g_writeln(" DisconnectedTimeLimit: %d", se->max_disc_time);
675691
g_writeln(" Policy: %s", policy_s);
692+
g_writeln(" StartupWaitTime: %u", se->startup_wait_time);
676693

677694
/* Security configuration */
678695
g_writeln("Security configuration:");

sesman/libsesman/sesman_config.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ struct config_sessions
166166
* @brief session allocation policy
167167
*/
168168
unsigned int policy;
169+
/**
170+
* @var start wait time
171+
* @brief Wait time to make sure a session has started.
172+
*/
173+
unsigned int startup_wait_time;
169174
};
170175

171176
/**

sesman/sesexec/sesexec.c

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -266,39 +266,6 @@ sesexec_is_ecp_active(void)
266266

267267
}
268268

269-
/******************************************************************************/
270-
static void
271-
process_sigchld_event(void)
272-
{
273-
struct proc_exit_status e;
274-
int pid;
275-
276-
// Check for any finished children
277-
while ((pid = g_waitchild(&e)) > 0)
278-
{
279-
session_process_child_exit(g_session_data, pid, &e);
280-
}
281-
}
282-
283-
/******************************************************************************/
284-
static void
285-
sesexec_terminate_session_and_wait(void)
286-
{
287-
session_send_term(g_session_data);
288-
do
289-
{
290-
g_sleep(1000);
291-
// Process SIGCHLD events while waiting for the session
292-
// to exit.
293-
if (g_is_wait_obj_set(g_sigchld_event))
294-
{
295-
g_reset_wait_obj(g_sigchld_event);
296-
process_sigchld_event();
297-
}
298-
}
299-
while (session_active(g_session_data));
300-
}
301-
302269
/******************************************************************************/
303270
static void
304271
sesexec_main_loop_cleanup(void)
@@ -314,7 +281,7 @@ sesexec_main_loop_cleanup(void)
314281
{
315282
LOG(LOG_LEVEL_INFO,
316283
"Stopping session on xrdp-sesexec exit");
317-
sesexec_terminate_session_and_wait();
284+
session_send_term(g_session_data, 1);
318285
}
319286
session_data_free(g_session_data);
320287
}
@@ -400,7 +367,7 @@ sesexec_main_loop(void)
400367
// See whether the session goes from active to inactive
401368
// after processing SIGCHLD
402369
int session_was_active = session_active(g_session_data);
403-
process_sigchld_event();
370+
session_process_sigchld_event(g_session_data);
404371
if (session_was_active && !session_active(g_session_data))
405372
{
406373
// We've finished the session. Tell sesman and

sesman/sesexec/session.c

Lines changed: 129 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,65 @@ fork_child(
600600
return pid;
601601
}
602602

603+
/******************************************************************************/
604+
static int
605+
process_startup_wait_time(struct session_data *sd)
606+
{
607+
int rv = 0;
608+
int robjs_count;
609+
intptr_t robjs[10];
610+
unsigned int start = g_get_elapsed_ms();
611+
612+
LOG(LOG_LEVEL_INFO, "Waiting for %u ms for session to start",
613+
g_cfg->sess.startup_wait_time);
614+
while (1)
615+
{
616+
unsigned int elapsed = g_get_elapsed_ms() - start;
617+
if (elapsed >= g_cfg->sess.startup_wait_time)
618+
{
619+
break;
620+
}
621+
622+
robjs_count = 0;
623+
robjs[robjs_count++] = g_term_event;
624+
robjs[robjs_count++] = g_sigchld_event;
625+
626+
if (g_obj_wait(robjs, robjs_count, NULL, 0,
627+
g_cfg->sess.startup_wait_time - elapsed) != 0)
628+
{
629+
/* should not get here */
630+
LOG(LOG_LEVEL_WARNING, "process_startup_wait_time: "
631+
"Unexpected error from g_obj_wait()");
632+
g_sleep(100);
633+
continue;
634+
}
635+
636+
if (g_is_wait_obj_set(g_term_event)) /* term */
637+
{
638+
// Simulate success for now, but leave g_term_event set. The
639+
// main loop will also pick up the terminate event and the
640+
// session will be closed normally
641+
break;
642+
}
643+
644+
if (g_is_wait_obj_set(g_sigchld_event)) /* SIGCHLD */
645+
{
646+
g_reset_wait_obj(g_sigchld_event);
647+
session_process_sigchld_event(sd);
648+
if (sd->win_mgr < 0)
649+
{
650+
// Session has failed in the StartupWaitTime
651+
// Wait for the rest of the session to finish
652+
rv = 1;
653+
session_send_term(sd, 1);
654+
break;
655+
}
656+
}
657+
}
658+
659+
return rv;
660+
}
661+
603662
/******************************************************************************/
604663
static enum scp_screate_status
605664
session_start_wrapped(struct login_info *login_info,
@@ -709,17 +768,27 @@ session_start_wrapped(struct login_info *login_info,
709768
chansrv_pid = fork_child(start_chansrv, login_info,
710769
s, display_pid);
711770

712-
// Tell the caller we've started
713-
LOG(LOG_LEVEL_INFO,
714-
"Session in progress on display :%d. Waiting until the "
715-
"window manager (pid %d) exits to end the session",
716-
s->display, window_manager_pid);
717-
718771
sd->win_mgr = window_manager_pid;
719772
sd->x_server = display_pid;
720773
sd->chansrv = chansrv_pid;
721774
sd->start_time = time(NULL);
722-
status = E_SCP_SCREATE_OK;
775+
776+
if (process_startup_wait_time(sd) == 0)
777+
{
778+
// Tell the caller we've started
779+
LOG(LOG_LEVEL_INFO,
780+
"Session in progress on display :%d. Waiting until the "
781+
"window manager (pid %d) exits to end the session",
782+
s->display, window_manager_pid);
783+
784+
status = E_SCP_SCREATE_OK;
785+
}
786+
else
787+
{
788+
LOG(LOG_LEVEL_ERROR,
789+
"Session failed during startup wait time");
790+
status = E_SCP_SCREATE_SESSION_FAIL;
791+
}
723792
}
724793
}
725794
}
@@ -883,10 +952,19 @@ exit_status_to_str(const struct proc_exit_status *e, char buff[], int bufflen)
883952
}
884953

885954
/******************************************************************************/
886-
void
887-
session_process_child_exit(struct session_data *sd,
888-
int pid,
889-
const struct proc_exit_status *e)
955+
/**
956+
* Processes an exited child
957+
*
958+
* The PID of the child process is removed from the session_data.
959+
*
960+
* @param sd session_data for this session
961+
* @param pid PID of exited process
962+
* @param e Exit status of the exited process
963+
*/
964+
static void
965+
process_child_exit(struct session_data *sd,
966+
int pid,
967+
const struct proc_exit_status *e)
890968
{
891969
if (pid == sd->x_server)
892970
{
@@ -956,6 +1034,20 @@ session_process_child_exit(struct session_data *sd,
9561034
}
9571035
}
9581036

1037+
/******************************************************************************/
1038+
void
1039+
session_process_sigchld_event(struct session_data *sd)
1040+
{
1041+
struct proc_exit_status e;
1042+
int pid;
1043+
1044+
// Check for any finished children
1045+
while ((pid = g_waitchild(&e)) > 0)
1046+
{
1047+
process_child_exit(sd, pid, &e);
1048+
}
1049+
}
1050+
9591051
/******************************************************************************/
9601052
unsigned int
9611053
session_active(const struct session_data *sd)
@@ -982,14 +1074,34 @@ session_get_parameters(const struct session_data *sd)
9821074

9831075
/******************************************************************************/
9841076
void
985-
session_send_term(struct session_data *sd)
1077+
session_send_term(struct session_data *sd, int wait_for_all)
9861078
{
987-
if (sd != NULL && sd->win_mgr > 0)
1079+
if (sd != NULL)
9881080
{
989-
// Killing the window manager only is appropriate here.
990-
// When we process SIGCHLD for the windowe manager, we
991-
// will kill other processes as appropriate
992-
g_sigterm(sd->win_mgr);
1081+
if (sd->win_mgr > 0)
1082+
{
1083+
// Killing the window manager only is appropriate here.
1084+
// When we process SIGCHLD for the window manager, we
1085+
// will kill other processes as appropriate
1086+
g_sigterm(sd->win_mgr);
1087+
}
1088+
1089+
while (session_active(sd))
1090+
{
1091+
/* Don't check SIGTERM - we shouldn't be here long */
1092+
if (g_obj_wait(&g_sigchld_event, 1, NULL, 0, -1) != 0)
1093+
{
1094+
/* should not get here */
1095+
LOG(LOG_LEVEL_WARNING, "session_send_term: "
1096+
"Unexpected error from g_obj_wait()");
1097+
g_sleep(100);
1098+
}
1099+
else
1100+
{
1101+
g_reset_wait_obj(g_sigchld_event);
1102+
session_process_sigchld_event(sd);
1103+
}
1104+
}
9931105
}
9941106
}
9951107

sesman/sesexec/session.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,18 @@ session_start(struct login_info *login_info,
7878
struct session_data **session_data);
7979

8080
/**
81-
* Processes an exited child process
81+
* Processes a SIGCHLD event
8282
*
83-
* The PID of the child process is removed from the session_data.
83+
* Any pending SIGCHLD events are processed.
84+
*
85+
* The PID of a failed child process is removed from the session_data.
8486
*
8587
* @param sd session_data for this session
8688
* @param pid PID of exited process
8789
* @param e Exit status of the exited process
8890
*/
8991
void
90-
session_process_child_exit(struct session_data *sd,
91-
int pid,
92-
const struct proc_exit_status *e);
92+
session_process_sigchld_event(struct session_data *sd);
9393

9494
/**
9595
* Returns a count of active processes in the session
@@ -124,9 +124,11 @@ session_get_parameters(const struct session_data *sd);
124124
* Ask a session to terminate by signalling the window manager
125125
*
126126
* @param sd session_data for this session
127+
* @param wait_for_all != 0 to wait for all processes in the session
128+
* to terminate
127129
*/
128130
void
129-
session_send_term(struct session_data *sd);
131+
session_send_term(struct session_data *sd, int wait_for_all);
130132

131133
/**
132134
* Frees a session_data object

sesman/sesman.ini.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ IdleTimeLimit=0
112112
; the string
113113
Policy=Default
114114

115+
;; Startup wait time
116+
; Milliseconds to wait to ensure the session has started
117+
StartupWaitTime=1500
118+
115119
[Logging]
116120
; Note: Log levels can be any of: core, error, warning, info, debug, or trace
117121
LogFile=xrdp-sesman.log

0 commit comments

Comments
 (0)