mirror of
https://github.com/yrutschle/sslh.git
synced 2025-04-12 15:17:14 +03:00
sslh-select sets O_NONBLOCK *before* calling connect, which prevents hanging on an unresposive server (fix #258)
This commit is contained in:
parent
300e1916c3
commit
1ad450a444
51
common.c
51
common.c
@ -286,11 +286,28 @@ int bind_peer(int fd, int fd_from)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make the file descriptor non-block */
|
||||
int set_nonblock(int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
CHECK_RES_RETURN(flags, "fcntl", -1);
|
||||
|
||||
flags |= O_NONBLOCK;
|
||||
|
||||
flags = fcntl(fd, F_SETFL, flags);
|
||||
CHECK_RES_RETURN(flags, "fcntl", -1);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
/* Connect to first address that works and returns a file descriptor, or -1 if
|
||||
* none work.
|
||||
* If transparent proxying is on, use fd_from peer address on external address
|
||||
* of new file descriptor. */
|
||||
int connect_addr(struct connection *cnx, int fd_from)
|
||||
int connect_addr(struct connection *cnx, int fd_from, connect_blocking blocking)
|
||||
{
|
||||
struct addrinfo *a, from;
|
||||
struct sockaddr_storage ss;
|
||||
@ -324,29 +341,29 @@ int connect_addr(struct connection *cnx, int fd_from)
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, &one, sizeof(one));
|
||||
/* no need to check return value; if it's not supported, that's okay */
|
||||
|
||||
if (blocking == NON_BLOCKING) {
|
||||
set_nonblock(fd);
|
||||
}
|
||||
|
||||
if (transparent) {
|
||||
res = bind_peer(fd, fd_from);
|
||||
CHECK_RES_RETURN(res, "bind_peer", res);
|
||||
}
|
||||
res = connect(fd, a->ai_addr, a->ai_addrlen);
|
||||
if (res == -1) {
|
||||
switch (errno) {
|
||||
case EINPROGRESS:
|
||||
/* Can't be done yet, or TFO already done */
|
||||
break;
|
||||
|
||||
default:
|
||||
log_message(LOG_ERR, "forward to %s failed:connect: %s\n",
|
||||
cnx->proto->name, strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
} else {
|
||||
if (cnx->proto->keepalive) {
|
||||
res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(one));
|
||||
CHECK_RES_RETURN(res, "setsockopt(SO_KEEPALIVE)", res);
|
||||
}
|
||||
return fd;
|
||||
/* EINPROGRESS indicates it might take time. If it eventually
|
||||
* fails, it'll be caught as a failed read */
|
||||
if ((res == -1) && (errno != EINPROGRESS)) {
|
||||
log_message(LOG_ERR, "forward to %s failed:connect: %s\n",
|
||||
cnx->proto->name, strerror(errno));
|
||||
close(fd);
|
||||
continue; /* Try the next address */
|
||||
}
|
||||
if (cnx->proto->keepalive) {
|
||||
res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(one));
|
||||
CHECK_RES_RETURN(res, "setsockopt(SO_KEEPALIVE)", res);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
8
common.h
8
common.h
@ -122,10 +122,16 @@ struct connection_desc {
|
||||
local[MAX_NAMELENGTH], target[MAX_NAMELENGTH];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
NON_BLOCKING = 0,
|
||||
BLOCKING = 1
|
||||
} connect_blocking;
|
||||
|
||||
|
||||
/* common.c */
|
||||
void init_cnx(struct connection *cnx);
|
||||
int connect_addr(struct connection *cnx, int fd_from);
|
||||
int set_nonblock(int fd);
|
||||
int connect_addr(struct connection *cnx, int fd_from, connect_blocking blocking);
|
||||
int fd2fd(struct queue *target, struct queue *from);
|
||||
char* sprintaddr(char* buf, size_t size, struct addrinfo *a);
|
||||
void resolve_name(struct addrinfo **out, char* fullname);
|
||||
|
@ -111,7 +111,7 @@ void start_shoveler(int in_socket)
|
||||
}
|
||||
|
||||
/* Connect the target socket */
|
||||
out_socket = connect_addr(&cnx, in_socket);
|
||||
out_socket = connect_addr(&cnx, in_socket, BLOCKING);
|
||||
CHECK_RES_DIE(out_socket, "connect");
|
||||
|
||||
set_capabilities(0);
|
||||
|
@ -53,21 +53,6 @@ struct select_info {
|
||||
};
|
||||
|
||||
|
||||
/* Make the file descriptor non-block */
|
||||
static int set_nonblock(int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
CHECK_RES_RETURN(flags, "fcntl", -1);
|
||||
|
||||
flags |= O_NONBLOCK;
|
||||
|
||||
flags = fcntl(fd, F_SETFL, flags);
|
||||
CHECK_RES_RETURN(flags, "fcntl", -1);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int tidy_connection(struct connection *cnx, struct select_info* fd_info)
|
||||
{
|
||||
@ -141,10 +126,9 @@ static int connect_queue(struct connection* cnx,
|
||||
{
|
||||
struct queue *q = &cnx->q[1];
|
||||
|
||||
q->fd = connect_addr(cnx, cnx->q[0].fd);
|
||||
q->fd = connect_addr(cnx, cnx->q[0].fd, NON_BLOCKING);
|
||||
if ((q->fd != -1) && fd_is_in_range(q->fd)) {
|
||||
log_connection(NULL, cnx);
|
||||
set_nonblock(q->fd);
|
||||
flush_deferred(q);
|
||||
if (q->deferred_data) {
|
||||
FD_SET(q->fd, &fd_info->fds_w);
|
||||
@ -257,7 +241,7 @@ static void connect_proxy(struct connection *cnx)
|
||||
}
|
||||
|
||||
/* Connect the target socket */
|
||||
out_socket = connect_addr(cnx, in_socket);
|
||||
out_socket = connect_addr(cnx, in_socket, BLOCKING);
|
||||
CHECK_RES_DIE(out_socket, "connect");
|
||||
|
||||
cnx->q[1].fd = out_socket;
|
||||
@ -430,6 +414,7 @@ void cnx_accept_process(struct select_info* fd_info, int fd)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Main loop: the idea is as follow:
|
||||
* - fds_r and fds_w contain the file descriptors to monitor in read and write
|
||||
* - When a file descriptor goes off, process it: read from it, write the data
|
||||
|
Loading…
x
Reference in New Issue
Block a user