diff options
author | Rory Byrne <[email protected]> | 2015-04-16 18:01:23 +0100 |
---|---|---|
committer | Rory Byrne <[email protected]> | 2015-06-09 21:51:29 +0100 |
commit | eed21b4fd99c8ab71dcefd3802104186af1cb6b0 (patch) | |
tree | f4191a382894c67ee002c2087749a251e5316b05 /erts/emulator/drivers/common/inet_drv.c | |
parent | 0098eed847516cc6760d961421c83527816e35ae (diff) | |
download | otp-eed21b4fd99c8ab71dcefd3802104186af1cb6b0.tar.gz otp-eed21b4fd99c8ab71dcefd3802104186af1cb6b0.tar.bz2 otp-eed21b4fd99c8ab71dcefd3802104186af1cb6b0.zip |
Fix socket option {linger, {true, 0}} to abort TCP connections
Up until now, if {linger, {true, 0}} is set on the socket and there is
data in the port driver queue, the connection is not aborted until
the port queue is empty and close() is called on the underlying file
descriptor. This bug allows an idle TCP client to prevent a server
from terminating the connection and freeing resources. This patch
fixes the problem by discarding the port queue if the socket is closed
when {linger, {true, 0}} is set.
Diffstat (limited to 'erts/emulator/drivers/common/inet_drv.c')
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index a8c58a8149..80cb705896 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -838,6 +838,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define TCP_ADDF_SHOW_ECONNRESET 64 /* Tell user about incoming RST */ #define TCP_ADDF_DELAYED_ECONNRESET 128 /* An ECONNRESET error occured on send or shutdown */ #define TCP_ADDF_SHUTDOWN_WR_DONE 256 /* A shutdown(sock, SHUT_WR) or SHUT_RDWR was made */ +#define TCP_ADDF_LINGER_ZERO 512 /* Discard driver queue on port close */ /* *_REQ_* replies */ #define INET_REP_ERROR 0 @@ -6318,6 +6319,13 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof(li_val); DEBUGF(("inet_set_opts(%ld): s=%d, SO_LINGER=%d,%d", (long)desc->port, desc->s, li_val.l_onoff,li_val.l_linger)); + if (desc->sprotocol == IPPROTO_TCP) { + tcp_descriptor* tdesc = (tcp_descriptor*) desc; + if (li_val.l_onoff && li_val.l_linger == 0) + tdesc->tcp_add_flags |= TCP_ADDF_LINGER_ZERO; + else + tdesc->tcp_add_flags &= ~TCP_ADDF_LINGER_ZERO; + } break; case INET_OPT_PRIORITY: @@ -9699,6 +9707,8 @@ static void tcp_inet_flush(ErlDrvData e) /* Discard send queue to avoid hanging port (OTP-7615) */ tcp_clear_output(desc); } + if (desc->tcp_add_flags & TCP_ADDF_LINGER_ZERO) + tcp_clear_output(desc); } static void tcp_inet_process_exit(ErlDrvData e, ErlDrvMonitor *monitorp) |