Skip to content
Open
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
9 changes: 3 additions & 6 deletions src/conns.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "conns.h"
#include "heap.h"
#include "log.h"
#include "sock.h"
#include "stats.h"

void conn_struct_init(struct conn_s *connptr) {
Expand Down Expand Up @@ -82,14 +83,10 @@ void conn_destroy_contents (struct conn_s *connptr)
assert (connptr != NULL);

if (connptr->client_fd != -1)
if (close (connptr->client_fd) < 0)
log_message (LOG_INFO, "Client (%d) close message: %s",
connptr->client_fd, strerror (errno));
close_socket (connptr->client_fd);
connptr->client_fd = -1;
if (connptr->server_fd != -1)
if (close (connptr->server_fd) < 0)
log_message (LOG_INFO, "Server (%d) close message: %s",
connptr->server_fd, strerror (errno));
close_socket (connptr->server_fd);
connptr->server_fd = -1;

if (connptr->cbuffer)
Expand Down
1 change: 1 addition & 0 deletions src/reqs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,7 @@ static void relay_connection (struct conn_s *connptr)
if (write_buffer (connptr->server_fd, connptr->cbuffer) < 0)
break;
}
shutdown (connptr->server_fd, SHUT_WR);

return;
}
Expand Down
34 changes: 34 additions & 0 deletions src/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,40 @@ int opensock (const char *host, int port, const char *bind_to)
return sockfd;
}

/*
* Gracefully close a socket by completing the TCP close handshake.
*
* shutdown(SHUT_WR) sends our FIN while the fd stays open, then we
* drain whatever the peer still sends until read() returns 0, which
* signals that the peer's FIN has arrived. Only then do we close().
* By that point the four-way handshake is complete and the socket
* moves to TIME_WAIT, which the kernel reaps on its own.
*
* Calling close() on a socket still in FIN_WAIT_2 orphans it. Linux
* reaps orphaned FIN_WAIT_2 sockets via net.ipv4.tcp_fin_timeout, but
* OpenBSD has no equivalent, so they accumulate until the proxy
* stalls. See RFC 793 sec. 3.5 and Stevens, UNIX Network
* Programming Vol. 1 sec. 6.6.
*/
void close_socket (int fd)
{
char drain[4096];
ssize_t n;
struct timeval tv;

shutdown (fd, SHUT_WR);

tv.tv_sec = 10;
tv.tv_usec = 0;
setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof (tv));

do {
n = read (fd, drain, sizeof (drain));
} while (n > 0 || (n < 0 && errno == EINTR));

close (fd);
}

/**
* Try to listen on one socket based on the addrinfo
* as returned from getaddrinfo.
Expand Down
1 change: 1 addition & 0 deletions src/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ union sockaddr_union {

extern int opensock (const char *host, int port, const char *bind_to);
extern int listen_sock (const char *addr, uint16_t port, sblist* listen_fds);
extern void close_socket (int fd);

extern void set_socket_timeout(int fd);

Expand Down