diff --git a/sesman/Makefile b/sesman/Makefile index dfedf852..b64f3e31 100644 --- a/sesman/Makefile +++ b/sesman/Makefile @@ -1,9 +1,9 @@ # sesman makefile SESMANOBJ = sesman.o config.o tcp.o sig.o session.o env.o \ os_calls.o d3des.o list.o file.o log.o access.o \ - scp.o scp_v0.o + scp.o scp_v0.o thread.o lock.o -SESRUNOBJ = sesrun.o config.o tcp.o \ +SESRUNOBJ = sesrun.o config.o tcp.o lock.o \ os_calls.o d3des.o list.o file.o log.o DESTDIR = /usr/local/xrdp @@ -15,8 +15,8 @@ DOCDIR = /usr/doc/xrdp DEFINES = -DSESMAN_CFG_FILE=\"$(CFGDIR)/sesman.ini\" \ -DSESMAN_PID_FILE=\"$(PIDDIR)/sesman.pid\" -CFLAGS = -Wall -O2 -I../common $(DEFINES) -LDFLAGS = -L /usr/gnu/lib $(DEFINES) +CFLAGS = -Wall -O2 -I../common -I/usr/include/nptl $(DEFINES) +LDFLAGS = -L /usr/gnu/lib -I/usr/include/nptl -L/usr/lib/nptl -lpthread $(DEFINES) C_OS_FLAGS = $(CFLAGS) -c CC = gcc @@ -70,4 +70,4 @@ file.o: ../common/file.c $(CC) $(C_OS_FLAGS) ../common/file.c log.o: ../common/log.c - $(CC) $(C_OS_FLAGS) ../common/log.c + $(CC) $(C_OS_FLAGS) -DLOG_ENABLE_THREAD ../common/log.c diff --git a/sesman/lock.c b/sesman/lock.c new file mode 100644 index 00000000..1db8b51d --- /dev/null +++ b/sesman/lock.c @@ -0,0 +1,200 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2005-2006 + + session manager + linux only + +*/ + +#include "sesman.h" + +#include +#include + +pthread_mutex_t lock_chain; /* session chain lock */ +pthread_mutexattr_t lock_chain_attr; /* mutex attributes */ + +pthread_mutex_t lock_config; /* configuration access lock */ +pthread_mutexattr_t lock_config_attr; /* mutex attributes */ + +pthread_mutex_t lock_fork; /* this lock protects the counters */ +pthread_mutexattr_t lock_fork_attr; /* mutex attributes */ +sem_t lock_fork_req; /* semaphore on which the process that are going to fork suspend on */ +sem_t lock_fork_wait; /* semaphore on which the suspended process wait on */ +int lock_fork_forkers_count; /* threads that want to fork */ +int lock_fork_blockers_count; /* threads thar are blocking fork */ +int lock_fork_waiting_count; /* threads suspended until the fork finishes */ + +sem_t lock_socket; + +void DEFAULT_CC +lock_init() +{ + /* initializing socket lock */ + sem_init(&lock_socket, 0, 1); + + /* initializing chain lock */ + pthread_mutexattr_init(&lock_chain_attr); + pthread_mutex_init(&lock_chain, &lock_chain_attr); + + /* initializing config lock */ + pthread_mutexattr_init(&lock_config_attr); + pthread_mutex_init(&lock_config, &lock_config_attr); + + /* initializing fork lock */ + pthread_mutexattr_init(&lock_fork_attr); + pthread_mutex_init(&lock_chain, &lock_fork_attr); + sem_init(&lock_fork_req, 0, 0); + sem_init(&lock_fork_wait, 0, 0); + + /* here we don't use locking because lock_init() should be called BEFORE */ + /* any thread is created */ + lock_fork_blockers_count=0; + lock_fork_waiting_count=0; + lock_fork_forkers_count=0; +} + +/******************************************************************************/ +void DEFAULT_CC +lock_chain_acquire() +{ + /*lock the chain*/ + LOG_DBG("lock_chain_acquire()",0); + pthread_mutex_lock(&lock_chain); +} + +/******************************************************************************/ +void DEFAULT_CC +lock_chain_release() +{ + /*unlock the chain*/ + LOG_DBG("lock_chain_release()",0); + pthread_mutex_unlock(&lock_chain); +} + +/******************************************************************************/ +void DEFAULT_CC +lock_socket_acquire() +{ + /* lock socket variable */ + LOG_DBG("lock_socket_acquire()",0); + sem_wait(&lock_socket); +} + +/******************************************************************************/ +void DEFAULT_CC +lock_socket_release() +{ + /* unlock socket variable */ + LOG_DBG("lock_socket_release()",0); + sem_post(&lock_socket); +} + +/******************************************************************************/ +void DEFAULT_CC +lock_fork_request() +{ + /* lock mutex */ + pthread_mutex_lock(&lock_fork); + if (lock_fork_blockers_count == 0) + { + /* if noone is blocking fork(), then we're allowed to fork */ + sem_post(&lock_fork_req); + } + lock_fork_forkers_count++; + pthread_mutex_unlock(&lock_fork); + + /* we wait to be allowed to fork() */ + sem_wait(&lock_fork_req); +} + +/******************************************************************************/ +void DEFAULT_CC +lock_fork_release() +{ + pthread_mutex_lock(&lock_fork); + lock_fork_forkers_count--; + + /* if there's someone else that want to fork, we let him fork() */ + if (lock_fork_forkers_count > 0) + { + sem_post(&lock_fork_req); + } + + for (;lock_fork_waiting_count > 0; lock_fork_waiting_count--) + { + /* waking up the other processes */ + sem_post(&lock_fork_wait); + } + pthread_mutex_unlock(&lock_fork); +} + +/******************************************************************************/ +void DEFAULT_CC +lock_fork_critical_section_end(int blocking) +{ + LOG_DBG("lock_fork_critical_secection_end()",0); + /* lock mutex */ + pthread_mutex_lock(&lock_fork); + + if (blocking == SESMAN_LOCK_FORK_BLOCKER) + { + lock_fork_blockers_count--; + } + + /* if there's someone who wants to fork and we're the last blocking */ + /* then we let him go */ + if ((lock_fork_blockers_count == 0) && (lock_fork_forkers_count>0)) + { + sem_post(&lock_fork_req); + } + pthread_mutex_unlock(&lock_fork); +} + +/******************************************************************************/ +int DEFAULT_CC +lock_fork_critical_section_start() +{ + LOG_DBG("lock_fork_critical_secection_start()",0); + do + { + pthread_mutex_lock(&lock_fork); + + /* someone requested to fork */ + if (lock_fork_forkers_count > 0) + { + lock_fork_waiting_count++; + pthread_mutex_unlock(&lock_fork); + + /* we wait until the fork finishes */ + sem_wait(&lock_fork_wait); + + } + else + { + /* no fork, so we can go on... */ + lock_fork_blockers_count++; + pthread_mutex_unlock(&lock_fork); + + return SESMAN_LOCK_FORK_BLOCKER; + } + } while (1); + + /* we'll never get here */ + return SESMAN_LOCK_FORK_WAITING; +} diff --git a/sesman/lock.h b/sesman/lock.h new file mode 100644 index 00000000..1f687c94 --- /dev/null +++ b/sesman/lock.h @@ -0,0 +1,122 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2005-2006 +*/ + +#ifndef LOCK_H +#define LOCK_H + +#include "sesman.h" + +#define SESMAN_LOCK_FORK_BLOCKER 1 +#define SESMAN_LOCK_FORK_WAITING 0 + +/** + * + * @brief initializes all the locks + * + */ +void DEFAULT_CC +lock_init(); + +/** + * + * @brief acquires the lock for the session chain + * + */ +void DEFAULT_CC +lock_chain_acquire(); + +/** + * + * @brief releases the sessiona chain lock + * + */ +void DEFAULT_CC +lock_chain_release(); + +/** + * + * @brief acquires config lock + * + */ +void DEFAULT_CC +lock_cfg_acquire(); + +/** + * + * @brief releases config lock + * + */ +void DEFAULT_CC +lock_cfg_release(); + +/** + * + * @brief request the socket lock + * + */ +void DEFAULT_CC +lock_socket_acquire(); + +/** + * + * @brief releases the socket lock + * + */ +void DEFAULT_CC +lock_socket_release(); + +/** + * + * @brief requires to fork a new child process + * + */ +void DEFAULT_CC +lock_fork_request(); + +/** + * + * @brief releases a fork() request + * + */ +void DEFAULT_CC +lock_fork_release(); + +/** + * + * @brief starts a section that is critical for forking + * + * starts a section that is critical for forking, that is noone can fork() + * while i'm in a critical section. But if someone wanted to fork we have + * to wait until he finishes with lock_fork_release() + * + * @return + * + */ +int DEFAULT_CC +lock_fork_critical_section_start(); + +/** + * + * @brief closes the critical section + * + */ +void DEFAULT_CC +lock_fork_critical_section_end(int blocking); + +#endif diff --git a/sesman/scp.c b/sesman/scp.c index a89b3d7b..45ca8ee4 100644 --- a/sesman/scp.c +++ b/sesman/scp.c @@ -29,9 +29,11 @@ #include "sesman.h" +extern int thread_sck; + /******************************************************************************/ -void DEFAULT_CC -scp_process_start(int sck) +void* DEFAULT_CC +scp_process_start(void* sck) { int socket; int version; @@ -39,12 +41,14 @@ scp_process_start(int sck) struct stream* in_s; struct stream* out_s; - /* making a local copy of the socket */ - /* sck should NEVER be used after lock_socket_release() */ - /* probably this is just paranoia */ - socket = sck; -#warning locking disabled -// lock_socket_release(); + /* making a local copy of the socket (it's on the stack) */ + /* probably this is just paranoia */ + //socket = *((int*) sck); + socket = thread_sck; + LOG_DBG("started scp thread on socket %d", socket); + + /* unlocking thread_sck */ + lock_socket_release(); make_stream(in_s); make_stream(out_s); @@ -63,7 +67,7 @@ scp_process_start(int sck) scp_v0_process(socket, in_s, out_s); } #warning scp v1 is disabled -/* this is temporarily disabled... + /* this is temporarily disabled... else if (version == 1) { / * starts processing an scp v0 connection * / @@ -80,5 +84,6 @@ scp_process_start(int sck) g_tcp_close(socket); free_stream(in_s); free_stream(out_s); + return 0; } diff --git a/sesman/scp.h b/sesman/scp.h index 99d6aae1..713c7836 100644 --- a/sesman/scp.h +++ b/sesman/scp.h @@ -39,7 +39,7 @@ * @param socket the connection socket * */ -void DEFAULT_CC -scp_process_start(int socket); +void* DEFAULT_CC +scp_process_start(void* sck); #endif diff --git a/sesman/sesman.c b/sesman/sesman.c index 7d3797b3..7ea17414 100644 --- a/sesman/sesman.c +++ b/sesman/sesman.c @@ -30,48 +30,9 @@ int g_sck; int g_pid; unsigned char g_fixedkey[8] = { 23, 82, 107, 6, 35, 78, 88, 7 }; -#ifdef OLDSESSION -struct session_item g_session_items[100]; /* sesman.h */ -extern int g_session_count; -#endif struct config_sesman g_cfg; /* config.h */ -//int g_server_type = 0; /* Xvnc 0 Xrdp 10 */ -/** - * - * @brief triggered when a child process (a session) dies - * @param s received signal - * - */ -static void DEFAULT_CC -cterm(int s) -{ -#ifdef OLDSESSION - int i; -#endif - int pid; - - if (g_getpid() != g_pid) - { - return; - } - pid = g_waitchild(); - if (pid > 0) - { -#ifdef OLDSESSION - for (i = 0; i < 100; i++) - { - if (g_session_items[i].pid == pid) - { - g_memset(g_session_items + i, 0, sizeof(struct session_item)); - g_session_count--; - } - } -#else - session_kill(pid); -#endif - } -} +extern int thread_sck; /******************************************************************************/ /** @@ -104,7 +65,10 @@ sesman_main_loop() while (in_sck > 0) { /* we've got a connection, so we pass it to scp code */ - scp_process_start(in_sck); + LOG_DBG("new connection",0); + thread_sck=in_sck; + //scp_process_start((void*)in_sck); + thread_scp_start(in_sck); /* once we've processed the connection, we go back listening */ in_sck = g_tcp_accept(g_sck); @@ -260,17 +224,23 @@ main(int argc, char** argv) g_file_open("/dev/null"); g_file_open("/dev/null"); } + + /* initializing locks */ + lock_init(); /* signal handling */ -#ifdef OLDSESSION - g_memset(&g_session_items, 0, sizeof(g_session_items)); -#endif g_pid = g_getpid(); - g_signal(1, sig_sesman_reload_cfg); /* SIGHUP */ - g_signal(2, sig_sesman_shutdown); /* SIGINT */ - g_signal(9, sig_sesman_shutdown); /* SIGKILL */ - g_signal(15, sig_sesman_shutdown); /* SIGTERM */ - g_signal_child_stop(cterm); /* SIGCHLD */ + /* old style signal handling is now managed synchronously by a + * separate thread. uncomment this block if you need old style + * signal handling and comment out thread_sighandler_start() */ + /* + g_signal(1, sig_sesman_reload_cfg); / * SIGHUP * / + g_signal(2, sig_sesman_shutdown); / * SIGINT * / + g_signal(9, sig_sesman_shutdown); / * SIGKILL * / + g_signal(15, sig_sesman_shutdown); / * SIGTERM * / + g_signal_child_stop(cterm); / * SIGCHLD * / + */ + thread_sighandler_start(); /* writing pid file */ fd = g_file_open(SESMAN_PID_FILE); diff --git a/sesman/sesman.h b/sesman/sesman.h index 45dac852..057044d8 100644 --- a/sesman/sesman.h +++ b/sesman/sesman.h @@ -41,6 +41,8 @@ #include "session.h" #include "access.h" #include "scp.h" +#include "thread.h" +#include "lock.h" #ifndef SESMAN_PID_FILE #define SESMAN_PID_FILE "./sesman.pid" diff --git a/sesman/session.c b/sesman/session.c index 7ef75206..fa7b15b2 100644 --- a/sesman/session.c +++ b/sesman/session.c @@ -29,35 +29,18 @@ extern unsigned char g_fixedkey[8]; extern struct config_sesman g_cfg; /* config.h */ -//extern int g_server_type; -#ifdef OLDSESSION -extern struct session_item g_session_items[100]; /* sesman.h */ -#else struct session_chain* g_sessions; -#endif int g_session_count; /******************************************************************************/ struct session_item* DEFAULT_CC session_get_bydata(char* name, int width, int height, int bpp) { -#ifdef OLDSESSION - int i; - - for (i = 0; i < 100; i++) - { - if (g_strncmp(name, g_session_items[i].name, 255) == 0 && - g_session_items[i].width == width && - g_session_items[i].height == height && - g_session_items[i].bpp == bpp) - { - return g_session_items + i; - } - } -#else struct session_chain* tmp; /*THREAD-FIX require chain lock */ + lock_chain_acquire(); + tmp=g_sessions; while (tmp != 0) @@ -68,13 +51,14 @@ session_get_bydata(char* name, int width, int height, int bpp) tmp->item->bpp == bpp) { /*THREAD-FIX release chain lock */ + lock_chain_release(); return tmp->item; } tmp=tmp->next; } /*THREAD-FIX release chain lock */ -#endif + lock_chain_release(); return 0; } @@ -139,20 +123,23 @@ session_start(int width, int height, int bpp, char* username, char* password, char cur_dir[256]; char text[256]; char passwd_file[256]; -#ifndef OLDSESSION struct session_chain* temp; -#endif /*THREAD-FIX lock to control g_session_count*/ + lock_chain_acquire(); /* check to limit concurrent sessions */ if (g_session_count >= g_cfg.sess.max_sessions) { + /*THREAD-FIX unlock chain*/ + lock_chain_release(); log_message(LOG_LEVEL_INFO, "max concurrent session limit exceeded. login \ for user %s denied", username); return 0; } -#ifndef OLDSESSION + /*THREAD-FIX unlock chain*/ + lock_chain_release(); + temp = (struct session_chain*)g_malloc(sizeof(struct session_chain), 0); if (temp == 0) { @@ -168,13 +155,15 @@ for user %s denied", username); username); return 0; } -#endif g_get_current_dir(cur_dir, 255); display = 10; /*while (x_server_running(display) && display < 50)*/ /* we search for a free display up to max_sessions */ /* we should need no more displays than this */ + + /* block all the threads running to enable forking */ + lock_fork_request(); while (x_server_running(display)) { display++; @@ -256,7 +245,7 @@ for user %s denied", username); g_exit(1); } /* should not get here */ - log_message(LOG_LEVEL_ALWAYS,"error doing execve for user %s - pid %d", + log_message(LOG_LEVEL_ALWAYS,"error doing execve (%s) for user %s - pid %d", username, g_getpid()); g_exit(1); } @@ -273,32 +262,9 @@ for user %s denied", username); } else /* parent */ { -#ifdef OLDSESSION - g_session_items[display].pid = pid; - g_strcpy(g_session_items[display].name, username); - g_session_items[display].display = display; - g_session_items[display].width = width; - g_session_items[display].height = height; - g_session_items[display].bpp = bpp; - g_session_items[display].data = data; - - g_session_items[display].connect_time=g_time1(); - g_session_items[display].disconnect_time=(time_t) 0; - g_session_items[display].idle_time=(time_t) 0; - - i/*if (type==0) - { - g_session_items[display].type=SESMAN_SESSION_TYPE_XVNC; - } - else - { - g_session_items[display].type=SESMAN_SESSION_TYPE_XRDP; - }*/ - g_session_items[display].type = type; - g_session_items[display].status = SESMAN_SESSION_STATUS_ACTIVE; - - g_session_count++; -#else + /* let the other threads go on */ + lock_fork_release(); + temp->item->pid = pid; temp->item->display = display; temp->item->width = width; @@ -311,24 +277,17 @@ for user %s denied", username); temp->item->disconnect_time = 0; temp->item->idle_time = 0; -/* if (type==0) - { - temp->item->type=SESMAN_SESSION_TYPE_XVNC; - } - else - { - temp->item->type=SESMAN_SESSION_TYPE_XRDP; - }*/ - temp->item->type=type; temp->item->status=SESMAN_SESSION_STATUS_ACTIVE; - /*THREAD-FIX lock the chain*/ + /*THREAD-FIX lock the chain*/ + lock_chain_acquire(); temp->next=g_sessions; g_sessions=temp; g_session_count++; /*THERAD-FIX free the chain*/ -#endif + lock_chain_release(); + g_sleep(5000); } return display; @@ -371,8 +330,6 @@ struct session_chain }; */ -#ifndef OLDSESSION - /******************************************************************************/ int DEFAULT_CC session_kill(int pid) @@ -381,6 +338,8 @@ session_kill(int pid) struct session_chain* prev; /*THREAD-FIX require chain lock */ + lock_chain_acquire(); + tmp=g_sessions; prev=0; @@ -401,6 +360,7 @@ session_kill(int pid) prev->next = tmp->next; } /*THREAD-FIX release chain lock */ + lock_chain_release(); return SESMAN_SESSION_KILL_NULLITEM; } @@ -423,6 +383,7 @@ session_kill(int pid) g_free(tmp); g_session_count--; /*THREAD-FIX release chain lock */ + lock_chain_release(); return SESMAN_SESSION_KILL_OK; } @@ -432,6 +393,7 @@ session_kill(int pid) } /*THREAD-FIX release chain lock */ + lock_chain_release(); return SESMAN_SESSION_KILL_NOTFOUND; } @@ -441,7 +403,9 @@ session_get_bypid(int pid) { struct session_chain* tmp; - /*THREAD-FIX require chain lock */ + /*THREAD-FIX require chain lock */ + lock_chain_acquire(); + tmp = g_sessions; while (tmp != 0) { @@ -450,12 +414,14 @@ session_get_bypid(int pid) log_message(LOG_LEVEL_ERROR, "session descriptor for pid %d is null!", pid); /*THREAD-FIX release chain lock */ + lock_chain_release(); return 0; } if (tmp->item->pid == pid) { /*THREAD-FIX release chain lock */ + lock_chain_release(); return tmp->item; } @@ -464,8 +430,7 @@ session_get_bypid(int pid) } /*THREAD-FIX release chain lock */ + lock_chain_release(); return 0; } -#endif - diff --git a/sesman/sig.c b/sesman/sig.c index 940254c7..fc702bb6 100644 --- a/sesman/sig.c +++ b/sesman/sig.c @@ -27,6 +27,8 @@ #include "sesman.h" +#include "signal.h" + extern int g_sck; extern int g_pid; extern struct config_sesman g_cfg; @@ -73,3 +75,78 @@ sig_sesman_reload_cfg(int sig) log_message(LOG_LEVEL_INFO, "configuration reloaded"); } + +/******************************************************************************/ +void DEFAULT_CC +sig_sesman_session_end(int sig) +{ + int pid; + + if (g_getpid() != g_pid) + { + return; + } + pid = g_waitchild(); + if (pid > 0) + { + session_kill(pid); + } +} + +/******************************************************************************/ +void* DEFAULT_CC +sig_handler_thread(void* arg) +{ + int recv_signal; + sigset_t sigmask; + sigset_t oldmask; + sigset_t waitmask; + + /* mask signals to be able to wait for them... */ + sigfillset(&sigmask); + /* it is a good idea not to block SIGILL SIGSEGV */ + /* SIGFPE -- see sigaction(2) NOTES */ + pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); + + /* building the signal wait mask... */ + sigemptyset(&waitmask); + sigaddset(&waitmask, SIGHUP); + sigaddset(&waitmask, SIGCHLD); + sigaddset(&waitmask, SIGTERM); +// sigaddset(&waitmask, SIGFPE); +// sigaddset(&waitmask, SIGILL); +// sigaddset(&waitmask, SIGSEGV); + + do + { + LOG_DBG("calling sigwait()",0); + sigwait(&waitmask, &recv_signal); + + switch (recv_signal) + { + case SIGHUP: + //reload cfg + LOG_DBG("sesman received SIGHUP",0); + //return 0; + break; + case SIGCHLD: + /* a session died */ + LOG_DBG("sesman received SIGCHLD",0); + sig_sesman_session_end(SIGCHLD); + break; + /*case SIGKILL; + /* we die * / + LOG_DBG("sesman received SIGKILL",0); + sig_sesman_shutdown(recv_signal); + break;*/ + case SIGTERM: + /* we die */ + LOG_DBG("sesman received SIGTERM",0); + sig_sesman_shutdown(recv_signal); + break; + } + } while (1); + + return 0; +} + diff --git a/sesman/sig.h b/sesman/sig.h index 98f1bda7..e876e22a 100644 --- a/sesman/sig.h +++ b/sesman/sig.h @@ -46,5 +46,22 @@ sig_sesman_shutdown(int sig); void DEFAULT_CC sig_sesman_reload_cfg(int sig); +/** + * + * @brief SIGCHLD handling code + * @param sig The received signal + * + */ +void DEFAULT_CC +sig_sesman_session_end(int sig); + +/** + * + * @brief signal handling thread + * + */ +void* DEFAULT_CC +sig_handler_thread(void* arg); + #endif diff --git a/sesman/tcp.c b/sesman/tcp.c index 06c7f99d..372ec491 100644 --- a/sesman/tcp.c +++ b/sesman/tcp.c @@ -32,6 +32,9 @@ int DEFAULT_CC tcp_force_recv(int sck, char* data, int len) { int rcvd; + int block; + + block = lock_fork_critical_section_start(); while (len > 0) { @@ -57,6 +60,9 @@ tcp_force_recv(int sck, char* data, int len) len -= rcvd; } } + + lock_fork_critical_section_end(block); + return 0; } @@ -65,7 +71,10 @@ int DEFAULT_CC tcp_force_send(int sck, char* data, int len) { int sent; + int block; + block = lock_fork_critical_section_start(); + while (len > 0) { sent = g_tcp_send(sck, data, len, 0); @@ -90,6 +99,9 @@ tcp_force_send(int sck, char* data, int len) len -= sent; } } + + lock_fork_critical_section_end(block); + return 0; } diff --git a/sesman/thread.c b/sesman/thread.c new file mode 100644 index 00000000..46960b7a --- /dev/null +++ b/sesman/thread.c @@ -0,0 +1,173 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2005-2006 +*/ + +/** + * + * @file thread.c + * @brief thread stuff... + * @author Simone Fedele + * + */ + +#include "sesman.h" + +#include +#include +#include + +static pthread_t thread_sighandler; +//static pthread_t thread_updater; + +/* a variable to pass the socket of s connection to a thread */ +int thread_sck; + +/******************************************************************************/ +int DEFAULT_CC +thread_sighandler_start() +{ + int ret; + sigset_t sigmask; + sigset_t oldmask; + sigset_t waitmask; + + /* mask signals to be able to wait for them... */ + sigfillset(&sigmask); + pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); + + /* unblock some signals... */ + sigemptyset(&waitmask); + + /* it is a good idea not to block SIGILL SIGSEGV */ + /* SIGFPE -- see sigaction(2) NOTES */ + sigaddset(&waitmask, SIGILL); + sigaddset(&waitmask, SIGSEGV); + sigaddset(&waitmask, SIGFPE); + pthread_sigmask(SIG_UNBLOCK, &waitmask, NULL); + + log_message(LOG_LEVEL_INFO,"starting signal handling thread..."); + + ret = pthread_create(&thread_sighandler, NULL, sig_handler_thread, ""); + pthread_detach(thread_sighandler); + + if (ret==0) + { + log_message(LOG_LEVEL_INFO, "signal handler thread started successfully"); + return 0; + } + + /* if something happened while starting a new thread... */ + switch (ret) + { + case EINVAL: + log_message(LOG_LEVEL_ERROR, "invalid attributes for signal handling thread (creation returned EINVAL)"); + break; + case EAGAIN: + log_message(LOG_LEVEL_ERROR, "not enough resources to start signal handling thread (creation returned EAGAIN)"); + break; + case EPERM: + log_message(LOG_LEVEL_ERROR, "invalid permissions for signal handling thread (creation returned EPERM)"); + break; + default: + log_message(LOG_LEVEL_ERROR, "unknown error starting signal handling thread"); + } + + return 1; +} + +#ifdef JUST_TO_AVOID_COMPILER_ERRORS +/******************************************************************************/ +int DEFAULT_CC +thread_session_update_start() +{ + int ret; + //starts the session update thread + //that checks for idle time, destroys sessions, ecc... + +#warning this thread should always request lock_fork before read or write +#warning (so we can Fork() In Peace) + ret = pthread_create(&thread_updater, NULL, , ""); + pthread_detach(thread_updater); + + if (ret==0) + { + log_message(LOG_LEVEL_INFO, "session update thread started successfully"); + return 0; + } + + /* if something happened while starting a new thread... */ + switch (ret) + { + case EINVAL: + log_message(LOG_LEVEL_ERROR, "invalid attributes for session update thread (creation returned EINVAL)"); + break; + case EAGAIN: + log_message(LOG_LEVEL_ERROR, "not enough resources to start session update thread (creation returned EAGAIN)"); + break; + case EPERM: + log_message(LOG_LEVEL_ERROR, "invalid permissions for session update thread (creation returned EPERM)"); + break; + default: + log_message(LOG_LEVEL_ERROR, "unknown error starting session update thread"); + } + + return 1; +} +#endif + +/******************************************************************************/ +int DEFAULT_CC +thread_scp_start(int skt) +{ + int ret; + pthread_t th; + + /* blocking the use of thread_skt */ + lock_socket_acquire(); + thread_sck=skt; + + /* start a thread that processes a connection */ + ret = pthread_create(&th, NULL, scp_process_start, ""); + //ret = pthread_create(&th, NULL, scp_process_start, (void*) (&thread_sck)); + pthread_detach(th); + + if (ret==0) + { + log_message(LOG_LEVEL_INFO, "scp thread on sck %d started successfully", skt); + return 0; + } + + /* if something happened while starting a new thread... */ + switch (ret) + { + case EINVAL: + log_message(LOG_LEVEL_ERROR, "invalid attributes for scp thread on sck %d (creation returned EINVAL)", skt); + break; + case EAGAIN: + log_message(LOG_LEVEL_ERROR, "not enough resources to start scp thread on sck %d (creation returned EAGAIN)", skt); + break; + case EPERM: + log_message(LOG_LEVEL_ERROR, "invalid permissions for scp thread on sck %d (creation returned EPERM)", skt); + break; + default: + log_message(LOG_LEVEL_ERROR, "unknown error starting scp thread on sck %d"); + } + + return 1; +} + diff --git a/sesman/thread.h b/sesman/thread.h new file mode 100644 index 00000000..dc0c92f8 --- /dev/null +++ b/sesman/thread.h @@ -0,0 +1,57 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2005-2006 +*/ + +/** + * + * @file thread.h + * @brief thread stuff... + * @author Simone Fedele + * + */ + +#ifndef THREAD_H +#define THREAD_H + +/** + * + * @brief Starts the signal handling thread + * @retval 0 on success + * @retval 1 on error + * + */ +int DEFAULT_CC +thread_sighandler_start(); + +/** + * + * @brief Starts the session update thread + * + */ +int DEFAULT_CC +thread_session_update_start(); + +/** + * + * @brief Starts a thread to handle an incoming connection + * + */ +int DEFAULT_CC +thread_scp_start(); + +#endif