xrdp: work on trans list
This commit is contained in:
parent
bacd76f9a2
commit
d6229df5a1
@ -4,8 +4,18 @@ ini_version=1
|
|||||||
|
|
||||||
; fork a new process for each incoming connection
|
; fork a new process for each incoming connection
|
||||||
fork=true
|
fork=true
|
||||||
; tcp port to listen
|
|
||||||
|
; ports to listen on, examples
|
||||||
|
;unix://./tmp/xrdp.socket
|
||||||
|
;tcp://.:3389/ (<- Localhost 127.0.0.1:3389)
|
||||||
|
;tcp://:3389/ (<- *:3389)
|
||||||
|
;tcp://<any ipv4 format addr>:3389) (<- 192.168.1.1:3389)
|
||||||
|
;tcp6://.:3389/
|
||||||
|
;tcp6://:3389/
|
||||||
|
;tcp6://<any ipv6 format>:3389/
|
||||||
|
;vsock://<cid>:<port>/
|
||||||
port=3389
|
port=3389
|
||||||
|
|
||||||
; 'port' above should be connected to with vsock instead of tcp
|
; 'port' above should be connected to with vsock instead of tcp
|
||||||
use_vsock=false
|
use_vsock=false
|
||||||
; regulate if the listening socket use socket option tcp_nodelay
|
; regulate if the listening socket use socket option tcp_nodelay
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
static tbus g_process_sem = 0;
|
static tbus g_process_sem = 0;
|
||||||
static struct xrdp_process *g_process = 0;
|
static struct xrdp_process *g_process = 0;
|
||||||
|
|
||||||
|
int
|
||||||
|
xrdp_listen_conn_in(struct trans *self, struct trans *new_self);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
static int
|
static int
|
||||||
xrdp_listen_create_pro_done(struct xrdp_listen *self)
|
xrdp_listen_create_pro_done(struct xrdp_listen *self)
|
||||||
@ -150,104 +153,65 @@ xrdp_process_run(void *in_val)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
static int
|
static int
|
||||||
xrdp_listen_get_port_address(char *port, int port_bytes,
|
xrdp_listen_get_startup_params(struct xrdp_listen *self)
|
||||||
char *address, int address_bytes,
|
|
||||||
int *tcp_nodelay, int *tcp_keepalive,
|
|
||||||
int *mode,
|
|
||||||
struct xrdp_startup_params *startup_param)
|
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int error;
|
|
||||||
int index;
|
int index;
|
||||||
char *val;
|
char *val;
|
||||||
struct list *names;
|
struct list *names;
|
||||||
struct list *values;
|
struct list *values;
|
||||||
char cfg_file[256];
|
char cfg_file[256];
|
||||||
|
struct xrdp_startup_params *startup_params;
|
||||||
|
|
||||||
/* default to port 3389 */
|
startup_params = self->startup_params;
|
||||||
g_strncpy(port, "3389", port_bytes - 1);
|
|
||||||
/* Default to all */
|
|
||||||
g_strncpy(address, "0.0.0.0", address_bytes - 1);
|
|
||||||
/* see if port or address is in xrdp.ini file */
|
|
||||||
g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH);
|
g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH);
|
||||||
fd = g_file_open(cfg_file);
|
fd = g_file_open(cfg_file);
|
||||||
*mode = TRANS_MODE_TCP;
|
|
||||||
*tcp_nodelay = 0 ;
|
|
||||||
*tcp_keepalive = 0 ;
|
|
||||||
|
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
{
|
{
|
||||||
names = list_create();
|
names = list_create();
|
||||||
names->auto_free = 1;
|
names->auto_free = 1;
|
||||||
values = list_create();
|
values = list_create();
|
||||||
values->auto_free = 1;
|
values->auto_free = 1;
|
||||||
|
|
||||||
if (file_read_section(fd, "globals", names, values) == 0)
|
if (file_read_section(fd, "globals", names, values) == 0)
|
||||||
{
|
{
|
||||||
for (index = 0; index < names->count; index++)
|
for (index = 0; index < names->count; index++)
|
||||||
{
|
{
|
||||||
val = (char *)list_get_item(names, index);
|
val = (char *)list_get_item(names, index);
|
||||||
|
|
||||||
if (val != 0)
|
if (val != 0)
|
||||||
{
|
{
|
||||||
if (g_strcasecmp(val, "port") == 0)
|
if (g_strcasecmp(val, "port") == 0)
|
||||||
{
|
{
|
||||||
val = (char *)list_get_item(values, index);
|
val = (char *)list_get_item(values, index);
|
||||||
if (val[0] == '/')
|
g_strncpy(startup_params->port, val, sizeof(startup_params->port) - 1);
|
||||||
{
|
|
||||||
g_strncpy(port, val, port_bytes - 1);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
error = g_atoi(val);
|
|
||||||
if ((error > 0) && (error < 65000))
|
|
||||||
{
|
|
||||||
g_strncpy(port, val, port_bytes - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (g_strcasecmp(val, "use_vsock") == 0)
|
|
||||||
{
|
|
||||||
val = (char *)list_get_item(values, index);
|
|
||||||
if (g_text2bool(val) == 1)
|
|
||||||
{
|
|
||||||
*mode = TRANS_MODE_VSOCK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (g_strcasecmp(val, "address") == 0)
|
|
||||||
{
|
|
||||||
val = (char *)list_get_item(values, index);
|
|
||||||
g_strncpy(address, val, address_bytes - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_strcasecmp(val, "fork") == 0)
|
if (g_strcasecmp(val, "fork") == 0)
|
||||||
{
|
{
|
||||||
val = (char *)list_get_item(values, index);
|
val = (char *)list_get_item(values, index);
|
||||||
startup_param->fork = g_text2bool(val);
|
startup_params->fork = g_text2bool(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_strcasecmp(val, "tcp_nodelay") == 0)
|
if (g_strcasecmp(val, "tcp_nodelay") == 0)
|
||||||
{
|
{
|
||||||
val = (char *)list_get_item(values, index);
|
val = (char *)list_get_item(values, index);
|
||||||
*tcp_nodelay = g_text2bool(val);
|
startup_params->tcp_nodelay = g_text2bool(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_strcasecmp(val, "tcp_keepalive") == 0)
|
if (g_strcasecmp(val, "tcp_keepalive") == 0)
|
||||||
{
|
{
|
||||||
val = (char *)list_get_item(values, index);
|
val = (char *)list_get_item(values, index);
|
||||||
*tcp_keepalive = g_text2bool(val);
|
startup_params->tcp_keepalive = g_text2bool(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_strcasecmp(val, "tcp_send_buffer_bytes") == 0)
|
if (g_strcasecmp(val, "tcp_send_buffer_bytes") == 0)
|
||||||
{
|
{
|
||||||
val = (char *)list_get_item(values, index);
|
val = (char *)list_get_item(values, index);
|
||||||
startup_param->send_buffer_bytes = g_atoi(val);
|
startup_params->tcp_send_buffer_bytes = g_atoi(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_strcasecmp(val, "tcp_recv_buffer_bytes") == 0)
|
if (g_strcasecmp(val, "tcp_recv_buffer_bytes") == 0)
|
||||||
{
|
{
|
||||||
val = (char *)list_get_item(values, index);
|
val = (char *)list_get_item(values, index);
|
||||||
startup_param->recv_buffer_bytes = g_atoi(val);
|
startup_params->tcp_recv_buffer_bytes = g_atoi(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,17 +219,137 @@ xrdp_listen_get_port_address(char *port, int port_bytes,
|
|||||||
|
|
||||||
list_delete(names);
|
list_delete(names);
|
||||||
list_delete(values);
|
list_delete(values);
|
||||||
}
|
|
||||||
|
|
||||||
if (fd != -1)
|
|
||||||
g_file_close(fd);
|
g_file_close(fd);
|
||||||
|
}
|
||||||
/* startup_param overrides */
|
return 0;
|
||||||
if (startup_param->port[0] != 0)
|
|
||||||
{
|
|
||||||
g_strncpy(port, startup_param->port, port_bytes - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
static int
|
||||||
|
xrdp_listen_stop_all_listen(struct xrdp_listen *self)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
struct trans *ltrans;
|
||||||
|
|
||||||
|
for (index = 0; index < self->trans_list->count; index++)
|
||||||
|
{
|
||||||
|
ltrans = (struct trans *)
|
||||||
|
list_get_item(self->trans_list, index);
|
||||||
|
trans_delete(ltrans);
|
||||||
|
}
|
||||||
|
list_clear(self->trans_list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
static int
|
||||||
|
xrdp_listen_process_startup_params(struct xrdp_listen *self)
|
||||||
|
{
|
||||||
|
int mode; /* TRANS_MODE_TCP, TRANS_MODE_UNIX, TRANS_MODE_VSOCK */
|
||||||
|
int error;
|
||||||
|
int cont;
|
||||||
|
int bytes;
|
||||||
|
struct trans *ltrans;
|
||||||
|
char address[128];
|
||||||
|
char port[128];
|
||||||
|
struct xrdp_startup_params *startup_params;
|
||||||
|
|
||||||
|
startup_params = self->startup_params;
|
||||||
|
|
||||||
|
cont = 1;
|
||||||
|
while (cont)
|
||||||
|
{
|
||||||
|
|
||||||
|
cont = 0;
|
||||||
|
g_strncpy(address, "0.0.0.0", 127);
|
||||||
|
g_strncpy(port, startup_params->port, 127);
|
||||||
|
mode = TRANS_MODE_TCP;
|
||||||
|
|
||||||
|
ltrans = trans_create(mode, 16, 16);
|
||||||
|
if (ltrans == NULL)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "trans_create failed");
|
||||||
|
xrdp_listen_stop_all_listen(self);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
log_message(LOG_LEVEL_INFO, "listening to port %s on %s",
|
||||||
|
port, address);
|
||||||
|
error = trans_listen_address(ltrans, port, address);
|
||||||
|
if (error != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "trans_listen_address failed");
|
||||||
|
trans_delete(ltrans);
|
||||||
|
xrdp_listen_stop_all_listen(self);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (mode == TRANS_MODE_TCP)
|
||||||
|
{
|
||||||
|
if (startup_params->tcp_nodelay)
|
||||||
|
{
|
||||||
|
if (g_tcp_set_no_delay(ltrans->sck))
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "Error setting tcp_nodelay");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startup_params->tcp_keepalive)
|
||||||
|
{
|
||||||
|
if (g_tcp_set_keepalive(ltrans->sck))
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "Error setting "
|
||||||
|
"tcp_keepalive");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startup_params->tcp_send_buffer_bytes > 0)
|
||||||
|
{
|
||||||
|
bytes = startup_params->tcp_send_buffer_bytes;
|
||||||
|
log_message(LOG_LEVEL_INFO, "setting send buffer to %d bytes",
|
||||||
|
bytes);
|
||||||
|
if (g_sck_set_send_buffer_bytes(ltrans->sck, bytes) != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "error setting send buffer");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_sck_get_send_buffer_bytes(ltrans->sck, &bytes) != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "error getting send "
|
||||||
|
"buffer");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_INFO, "send buffer set to %d "
|
||||||
|
"bytes", bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startup_params->tcp_recv_buffer_bytes > 0)
|
||||||
|
{
|
||||||
|
bytes = startup_params->tcp_recv_buffer_bytes;
|
||||||
|
log_message(LOG_LEVEL_INFO, "setting recv buffer to %d bytes",
|
||||||
|
bytes);
|
||||||
|
if (g_sck_set_recv_buffer_bytes(ltrans->sck, bytes) != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "error setting recv buffer");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_sck_get_recv_buffer_bytes(ltrans->sck, &bytes) != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "error getting recv "
|
||||||
|
"buffer");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_INFO, "recv buffer set to %d "
|
||||||
|
"bytes", bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ltrans->trans_conn_in = xrdp_listen_conn_in;
|
||||||
|
ltrans->callback_data = self;
|
||||||
|
list_add_item(self->trans_list, (intptr_t) ltrans);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,129 +440,30 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
|
|||||||
int robjs_count;
|
int robjs_count;
|
||||||
int cont;
|
int cont;
|
||||||
int index;
|
int index;
|
||||||
int timeout = 0;
|
int timeout;
|
||||||
char port[128];
|
intptr_t robjs[32];
|
||||||
char address[256];
|
intptr_t term_obj;
|
||||||
tbus robjs[8];
|
intptr_t sync_obj;
|
||||||
tbus term_obj;
|
intptr_t done_obj;
|
||||||
tbus sync_obj;
|
|
||||||
tbus done_obj;
|
|
||||||
int tcp_nodelay;
|
|
||||||
int tcp_keepalive;
|
|
||||||
int bytes;
|
|
||||||
int mode;
|
|
||||||
struct trans *ltrans;
|
struct trans *ltrans;
|
||||||
|
|
||||||
self->status = 1;
|
self->status = 1;
|
||||||
|
if (xrdp_listen_get_startup_params(self) != 0)
|
||||||
if (xrdp_listen_get_port_address(port, sizeof(port),
|
|
||||||
address, sizeof(address),
|
|
||||||
&tcp_nodelay, &tcp_keepalive,
|
|
||||||
//&self->listen_trans[0]->mode,
|
|
||||||
&mode,
|
|
||||||
self->startup_params) != 0)
|
|
||||||
{
|
{
|
||||||
log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: xrdp_listen_get_port failed");
|
log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: xrdp_listen_get_port failed");
|
||||||
self->status = -1;
|
self->status = -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (xrdp_listen_process_startup_params(self) != 0)
|
||||||
if (port[0] == '/')
|
|
||||||
{
|
{
|
||||||
ltrans = trans_create(TRANS_MODE_UNIX, 16, 16);
|
log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: xrdp_listen_get_port failed");
|
||||||
/* not valid with UDS */
|
self->status = -1;
|
||||||
tcp_nodelay = 0;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (mode == TRANS_MODE_VSOCK)
|
|
||||||
{
|
|
||||||
ltrans = trans_create(TRANS_MODE_VSOCK, 16, 16);
|
|
||||||
/* not valid with VSOCK */
|
|
||||||
tcp_nodelay = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ltrans = trans_create(TRANS_MODE_TCP, 16, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create socket */
|
|
||||||
error = trans_listen_address(ltrans, port, address);
|
|
||||||
if (port[0] == '/')
|
|
||||||
{
|
|
||||||
g_chmod_hex(port, 0x0666);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error == 0)
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_INFO, "listening to port %s on %s",
|
|
||||||
port, address);
|
|
||||||
if (tcp_nodelay)
|
|
||||||
{
|
|
||||||
if (g_tcp_set_no_delay(ltrans->sck))
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_ERROR,"Error setting tcp_nodelay");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tcp_keepalive)
|
|
||||||
{
|
|
||||||
if (g_tcp_set_keepalive(ltrans->sck))
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_ERROR,"Error setting tcp_keepalive");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->startup_params->send_buffer_bytes > 0)
|
|
||||||
{
|
|
||||||
bytes = self->startup_params->send_buffer_bytes;
|
|
||||||
log_message(LOG_LEVEL_INFO, "setting send buffer to %d bytes",
|
|
||||||
bytes);
|
|
||||||
if (g_sck_set_send_buffer_bytes(ltrans->sck, bytes) != 0)
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_ERROR, "error setting send buffer");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (g_sck_get_send_buffer_bytes(ltrans->sck, &bytes) != 0)
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_ERROR, "error getting send buffer");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_INFO, "send buffer set to %d bytes", bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->startup_params->recv_buffer_bytes > 0)
|
|
||||||
{
|
|
||||||
bytes = self->startup_params->recv_buffer_bytes;
|
|
||||||
log_message(LOG_LEVEL_INFO, "setting recv buffer to %d bytes",
|
|
||||||
bytes);
|
|
||||||
if (g_sck_set_recv_buffer_bytes(ltrans->sck, bytes) != 0)
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_ERROR, "error setting recv buffer");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (g_sck_get_recv_buffer_bytes(ltrans->sck, &bytes) != 0)
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_ERROR, "error getting recv buffer");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_INFO, "recv buffer set to %d bytes", bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ltrans->trans_conn_in = xrdp_listen_conn_in;
|
|
||||||
ltrans->callback_data = self;
|
|
||||||
list_add_item(self->trans_list, (intptr_t) ltrans);
|
|
||||||
term_obj = g_get_term_event(); /*Global termination event */
|
term_obj = g_get_term_event(); /*Global termination event */
|
||||||
sync_obj = g_get_sync_event();
|
sync_obj = g_get_sync_event();
|
||||||
done_obj = self->pro_done_event;
|
done_obj = self->pro_done_event;
|
||||||
cont = 1;
|
cont = 1;
|
||||||
|
|
||||||
while (cont)
|
while (cont)
|
||||||
{
|
{
|
||||||
/* build the wait obj list */
|
/* build the wait obj list */
|
||||||
@ -547,13 +532,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* stop listening */
|
/* stop listening */
|
||||||
for (index = 0; index < self->trans_list->count; index++)
|
xrdp_listen_stop_all_listen(self);
|
||||||
{
|
|
||||||
ltrans = (struct trans *)
|
|
||||||
list_get_item(self->trans_list, index);
|
|
||||||
trans_delete(ltrans);
|
|
||||||
}
|
|
||||||
list_clear(self->trans_list);
|
|
||||||
|
|
||||||
/* second loop to wait for all process threads to close */
|
/* second loop to wait for all process threads to close */
|
||||||
cont = 1;
|
cont = 1;
|
||||||
@ -591,20 +570,6 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
|
|||||||
xrdp_listen_delete_done_pro(self);
|
xrdp_listen_delete_done_pro(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trans_delete(ltrans);
|
|
||||||
log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: listen error, possible port "
|
|
||||||
"already in use");
|
|
||||||
#if !defined(XRDP_ENABLE_VSOCK)
|
|
||||||
if (ltrans->mode == TRANS_MODE_VSOCK)
|
|
||||||
{
|
|
||||||
log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: listen error, "
|
|
||||||
"vsock support not compiled and config requested");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
self->status = -1;
|
self->status = -1;
|
||||||
return error;
|
return error;
|
||||||
|
@ -527,14 +527,16 @@ struct xrdp_mod_data
|
|||||||
|
|
||||||
struct xrdp_startup_params
|
struct xrdp_startup_params
|
||||||
{
|
{
|
||||||
char port[128];
|
char port[1024];
|
||||||
int kill;
|
int kill;
|
||||||
int no_daemon;
|
int no_daemon;
|
||||||
int help;
|
int help;
|
||||||
int version;
|
int version;
|
||||||
int fork;
|
int fork;
|
||||||
int send_buffer_bytes;
|
int tcp_send_buffer_bytes;
|
||||||
int recv_buffer_bytes;
|
int tcp_recv_buffer_bytes;
|
||||||
|
int tcp_nodelay;
|
||||||
|
int tcp_keepalive;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user