Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] use g_fork_execvp instead of g_fork #2598

Draft
wants to merge 15 commits into
base: devel
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions common/os_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -2921,6 +2921,29 @@ g_fork(void)
#endif
}

/*****************************************************************************/
int
g_fork_execvp(const char *p1, char *args[])
{
int pid;

pid = g_fork();

if (pid == 0)
{
g_execvp(p1, args);

/* should not get here */
LOG(LOG_LEVEL_ERROR,
"Failed to execute %s: execvp(3) failed with %s (%d)",
p1, g_get_strerror(), g_get_errno());

exit(1);
}

return pid;
}

/*****************************************************************************/
/* does not work in win32 */
int
Expand Down Expand Up @@ -3049,6 +3072,26 @@ g_set_allusercontext(int uid)
return (rv != 0); /* Return 0 or 1 */
}
#endif

/*****************************************************************************/
void
g_get_executable_path(enum xrdp_exe xe, char *buf, int bufsize)
{
switch (xe)
{
case E_XE_XRDP:
g_snprintf(buf, bufsize, XRDP_SBIN_PATH "/xrdp");
break;
case E_XE_SESMAN:
g_snprintf(buf, bufsize, XRDP_SBIN_PATH "/xrdp-sesman");
break;

default:
LOG(LOG_LEVEL_WARNING, "g_get_executable_path(): Unsupported exe %d", (int)xe);
}
}


/*****************************************************************************/
/* does not work in win32
returns pid of process that exits or zero if signal occurred */
Expand Down
10 changes: 10 additions & 0 deletions common/os_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@

#include "arch.h"

enum xrdp_exe
{
E_XE_XRDP = 0,
E_XE_SESMAN = 1,

/* TODO: add others below */
};

struct exit_status
{
/* set to -1 when the process exited via a signal */
Expand Down Expand Up @@ -258,6 +266,7 @@ void g_signal_terminate(void (*func)(int));
void g_signal_pipe(void (*func)(int));
void g_signal_usr1(void (*func)(int));
int g_fork(void);
int g_fork_execvp(const char *p1, char *args[]);
int g_setgid(int pid);
int g_initgroups(const char *user);
int g_getuid(void);
Expand All @@ -273,6 +282,7 @@ int g_setlogin(const char *name);
*/
int g_set_allusercontext(int uid);
#endif
void g_get_executable_path(enum xrdp_exe xe, char *buf, int bufsize);
int g_waitchild(void);
int g_waitpid(int pid);
struct exit_status g_waitpid_status(int pid);
Expand Down
32 changes: 32 additions & 0 deletions xrdp/xrdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@ xrdp_process_params(int argc, char **argv,
index++;
startup_params->xrdp_ini = value;
}
else if (nocase_matches(option, "--child-process", NULL))
{
startup_params->is_child = 1;
}
else if (nocase_matches(option, "--child-fd", NULL))
{
index++;
startup_params->child_fd = g_atoi(value);
}
else /* unknown option */
{
return index;
Expand Down Expand Up @@ -405,7 +414,30 @@ main(int argc, char **argv)
g_exit(1);
}

if (startup_params.is_child)
{
if (startup_params.child_fd < 3)
{
g_writeln("requested act as child process, but --child-fd option is not given");
g_deinit();
g_exit(1);
}

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_listen->startup_params = &startup_params;

xrdp_process_child_entrypoint(g_listen, startup_params.child_fd);

g_deinit();
g_exit(0);
}

if (g_file_exist(pid_file)) /* xrdp.pid */
{
Expand Down
2 changes: 2 additions & 0 deletions xrdp/xrdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ void
xrdp_process_delete(struct xrdp_process *self);
int
xrdp_process_main_loop(struct xrdp_process *self);
int
xrdp_process_child_entrypoint(struct xrdp_listen *owner, int socket_fd);

/* xrdp_listen.c */
struct xrdp_listen *
Expand Down
52 changes: 28 additions & 24 deletions xrdp/xrdp_listen.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,41 +771,45 @@ xrdp_listen_process_startup_params(struct xrdp_listen *self)
static int
xrdp_listen_fork(struct xrdp_listen *self, struct trans *server_trans)
{
char server_trans_fd_str[32];
char executable_path[4096];
struct list *child_arguments;

int pid;
int index;
struct xrdp_process *process;
struct trans *ltrans;

pid = g_fork();
g_get_executable_path(E_XE_XRDP, executable_path, 4096);
g_snprintf(server_trans_fd_str, 32, "%d", (int) server_trans->sck);

child_arguments = list_create();

if (pid == 0)
if (child_arguments != NULL)
{
/* child */
/* recreate some main globals */
xrdp_child_fork();
/* recreate the process done wait object, not used in fork mode */
/* close, don't delete this */
g_close_wait_obj(self->pro_done_event);
xrdp_listen_create_pro_done(self);
/* delete listener, child need not listen */
for (index = 0; index < self->trans_list->count; index++)
/* FIXME: pass log_fd to child */
child_arguments->auto_free = 1;
if (!list_add_strdup_multi(child_arguments,
"xrdp",
"--child-process",
"--child-fd", server_trans_fd_str,
NULL))
{
ltrans = (struct trans *) list_get_item(self->trans_list, index);
trans_delete_from_child(ltrans);
list_delete(child_arguments);
child_arguments = NULL;
}
list_delete(self->trans_list);
self->trans_list = NULL;
/* new connect instance */
process = xrdp_process_create(self, 0);
process->server_trans = server_trans;
g_process = process;
xrdp_process_run(0);
tc_sem_dec(g_process_sem);
xrdp_process_delete(process);
/* mark this process to exit */
g_set_term(1);
}

if (!child_arguments)
{
LOG(LOG_LEVEL_ERROR, "xrdp_listen_fork(): could not prepare arguments list for child process");
return 1;
}
else
{
pid = g_fork_execvp(executable_path, (char **) child_arguments->items);
list_delete(child_arguments);
}

/* parent */
trans_delete(server_trans);
Expand Down
21 changes: 21 additions & 0 deletions xrdp/xrdp_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,24 @@ xrdp_process_main_loop(struct xrdp_process *self)
g_set_wait_obj(self->done_event);
return 0;
}

/*****************************************************************************/
int
xrdp_process_child_entrypoint(struct xrdp_listen *owner, int socket_fd)
{
struct trans *server_trans;
struct xrdp_process *process;

server_trans = trans_create(TRANS_MODE_TCP, 16, 16);
server_trans->status = TRANS_STATUS_UP;
server_trans->sck = socket_fd;

process = xrdp_process_create(owner, 0);
process->server_trans = server_trans;

xrdp_process_main_loop(process);

xrdp_process_delete(process);
g_set_term(1);
return 0;
}
2 changes: 2 additions & 0 deletions xrdp/xrdp_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,8 @@ struct xrdp_startup_params
int tcp_nodelay;
int tcp_keepalive;
int use_vsock;
int is_child;
int child_fd;
};

/*
Expand Down