diff --git a/common/os_calls.c b/common/os_calls.c index 211adc82..a0a8304c 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -321,9 +321,11 @@ g_getchar(void) } /*****************************************************************************/ +/*Returns 0 on success*/ int APP_CC g_tcp_set_no_delay(int sck) { + int ret = 1 ; /*error*/ #if defined(_WIN32) int option_value; int option_len; @@ -341,11 +343,55 @@ g_tcp_set_no_delay(int sck) { option_value = 1; option_len = sizeof(option_value); - setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&option_value, - option_len); + if(setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&option_value, + option_len)==0) + { + ret = 0 ; /* success */ + } } } - return 0; + else + { + g_writeln("Error getting tcp_nodelay"); + } + return ret; +} + +/*****************************************************************************/ +/*Returns 0 on success*/ +int APP_CC +g_tcp_set_keepalive(int sck) +{ + int ret = 1 ; /*error*/ +#if defined(_WIN32) + int option_value; + int option_len; +#else + int option_value; + unsigned int option_len; +#endif + + option_len = sizeof(option_value); + /* SOL_TCP IPPROTO_TCP */ + if (getsockopt(sck, SOL_SOCKET, SO_KEEPALIVE, (char*)&option_value, + &option_len) == 0) + { + if (option_value == 0) + { + option_value = 1; + option_len = sizeof(option_value); + if(setsockopt(sck, SOL_SOCKET, SO_KEEPALIVE, (char*)&option_value, + option_len)==0) + { + ret = 0 ; /* success */ + } + } + } + else + { + g_writeln("Error getting tcp_keepalive"); + } + return ret; } /*****************************************************************************/ diff --git a/common/os_calls.h b/common/os_calls.h index ddcb59d8..e23550fc 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -64,6 +64,8 @@ g_getchar(void); int APP_CC g_tcp_set_no_delay(int sck); int APP_CC +g_tcp_set_keepalive(int sck); +int APP_CC g_tcp_socket(void); int APP_CC g_tcp_local_socket(void); diff --git a/xrdp/xrdp.ini b/xrdp/xrdp.ini index af5f2650..be59be45 100644 --- a/xrdp/xrdp.ini +++ b/xrdp/xrdp.ini @@ -7,6 +7,12 @@ crypt_level=low channel_code=1 max_bpp=24 fork=yes +# regulate if the listening socket use socket option tcp_nodelay +# no buffering will be performed in the TCP stack +tcp_nodelay=yes +# regulate if the listening socket use socket option keepalive +# if the network connection disappear without close messages the connection will be closed +tcp_keepalive=yes #black=000000 #grey=d6d3ce #dark_grey=808080 diff --git a/xrdp/xrdp_listen.c b/xrdp/xrdp_listen.c index bbdd729a..d3529ce5 100644 --- a/xrdp/xrdp_listen.c +++ b/xrdp/xrdp_listen.c @@ -130,6 +130,7 @@ xrdp_process_run(void* in_val) static int xrdp_listen_get_port_address(char* port, int port_bytes, char* address, int address_bytes, + int *tcp_nodelay, int *tcp_keepalive, struct xrdp_startup_params* startup_param) { int fd; @@ -147,6 +148,8 @@ xrdp_listen_get_port_address(char* port, int port_bytes, /* see if port or address is in xrdp.ini file */ g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); fd = g_file_open(cfg_file); + *tcp_nodelay = 0 ; + *tcp_keepalive = 0 ; if (fd > 0) { names = list_create(); @@ -185,6 +188,28 @@ xrdp_listen_get_port_address(char* port, int port_bytes, startup_param->fork = 1; } } + if (g_strcasecmp(val, "tcp_nodelay") == 0) + { + val = (char*)list_get_item(values, index); + if ((g_strcasecmp(val, "yes") == 0) || + (g_strcasecmp(val, "on") == 0) || + (g_strcasecmp(val, "true") == 0) || + (g_atoi(val) != 0)) + { + *tcp_nodelay = 1 ; + } + } + if (g_strcasecmp(val, "tcp_keepalive") == 0) + { + val = (char*)list_get_item(values, index); + if ((g_strcasecmp(val, "yes") == 0) || + (g_strcasecmp(val, "on") == 0) || + (g_strcasecmp(val, "true") == 0) || + (g_atoi(val) != 0)) + { + *tcp_keepalive = 1 ; + } + } } } } @@ -280,19 +305,37 @@ xrdp_listen_main_loop(struct xrdp_listen* self) tbus sync_obj; tbus sck_obj; tbus done_obj; + int tcp_nodelay; + int tcp_keepalive; self->status = 1; if (xrdp_listen_get_port_address(port, sizeof(port), address, sizeof(address), + &tcp_nodelay, &tcp_keepalive, self->startup_params) != 0) { g_writeln("xrdp_listen_main_loop: xrdp_listen_get_port failed"); self->status = -1; return 1; } + /*Create socket*/ error = trans_listen_address(self->listen_trans, port, address); if (error == 0) { + if(tcp_nodelay) + { + if(g_tcp_set_no_delay(self->listen_trans->sck)) + { + g_writeln("Error setting tcp_nodelay"); + } + } + if(tcp_keepalive) + { + if(g_tcp_set_keepalive(self->listen_trans->sck)) + { + g_writeln("Error setting tcp_keepalive"); + } + } self->listen_trans->trans_conn_in = xrdp_listen_conn_in; self->listen_trans->callback_data = self; term_obj = g_get_term_event();