diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2015-01-03 17:44:01 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2015-01-03 17:44:01 +0100 |
commit | 87fad50310f2bd0dcc990e80e23b09768918cf5b (patch) | |
tree | 68550f66228a82a37f6efdbb02ae864fd15cbc07 /pfinet | |
parent | 29a30c44bb8cecb341df211bcb3b330f515c9003 (diff) |
Backport Linux changes for proper TCP EOF handling
Notably when remote eagerly sends a RST: we want to return EOF to the
application, not EPIPE.
* pfinet/linux-src/net/ipv4/tcp_output.c (tcp_connect): Set sk->done to 0.
* pfinet/linux-src/net/ipv4/tcp_input.c (tcp_fin): Set RCV_SHUTDOWN, and
sk->done to 1.
* pfinet/linux-src/net/ipv4/tcp.c (tcp_recv_urg): Only return ENOTCONN when
we never actually connect. Always return 0 when reception is closed.
(tcp_recvmsg): When any data is available, ignore errors and EOF. When no
data is available, first check for reception being closed, then for errors.
Diffstat (limited to 'pfinet')
-rw-r--r-- | pfinet/linux-src/net/ipv4/tcp.c | 59 | ||||
-rw-r--r-- | pfinet/linux-src/net/ipv4/tcp_input.c | 3 | ||||
-rw-r--r-- | pfinet/linux-src/net/ipv4/tcp_output.c | 1 |
3 files changed, 31 insertions, 32 deletions
diff --git a/pfinet/linux-src/net/ipv4/tcp.c b/pfinet/linux-src/net/ipv4/tcp.c index 8cde3854..1a057439 100644 --- a/pfinet/linux-src/net/ipv4/tcp.c +++ b/pfinet/linux-src/net/ipv4/tcp.c @@ -1059,13 +1059,11 @@ static int tcp_recv_urg(struct sock * sk, int nonblock, if (sk->err) return sock_error(sk); - if (sk->done) + if (sk->state == TCP_CLOSE && !sk->done) return -ENOTCONN; - if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN)) { - sk->done = 1; + if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN)) return 0; - } lock_sock(sk); if (tp->urg_data & URG_VALID) { @@ -1177,9 +1175,6 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, int err = 0; int target = 1; /* Read at least this many bytes */ - if (sk->err) - return sock_error(sk); - if (sk->state == TCP_LISTEN) return -ENOTCONN; @@ -1261,36 +1256,36 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, if (copied >= target) break; - /* - These three lines and clause if (sk->state == TCP_CLOSE) - are unlikely to be correct, if target > 1. - I DO NOT FIX IT, because I have no idea, what - POSIX prescribes to make here. Probably, it really - wants to lose data 8), if not all target is received. - --ANK - */ - if (sk->err && !(flags&MSG_PEEK)) { - copied = sock_error(sk); - break; - } + if (copied) { + if (sk->err || + sk->state == TCP_CLOSE || + (sk->shutdown & RCV_SHUTDOWN) || + nonblock) + break; + } else { + if (sk->done) + break; - if (sk->shutdown & RCV_SHUTDOWN) { - sk->done = 1; - break; - } + if (sk->err) { + copied = sock_error(sk); + break; + } + + if (sk->shutdown & RCV_SHUTDOWN) + break; - if (sk->state == TCP_CLOSE) { - if (!sk->done) { - sk->done = 1; + if (sk->state == TCP_CLOSE) { + if (!sk->done) { + copied = -ENOTCONN; + break; + } break; } - copied = -ENOTCONN; - break; - } - if (nonblock) { - copied = -EAGAIN; - break; + if (nonblock) { + copied = -EAGAIN; + break; + } } cleanup_rbuf(sk, copied); diff --git a/pfinet/linux-src/net/ipv4/tcp_input.c b/pfinet/linux-src/net/ipv4/tcp_input.c index e84eaf43..e2dfc156 100644 --- a/pfinet/linux-src/net/ipv4/tcp_input.c +++ b/pfinet/linux-src/net/ipv4/tcp_input.c @@ -1129,6 +1129,9 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) tcp_send_ack(sk); + sk->shutdown |= RCV_SHUTDOWN; + sk->done = 1; + if (!sk->dead) { sk->state_change(sk); sock_wake_async(sk->socket, 1); diff --git a/pfinet/linux-src/net/ipv4/tcp_output.c b/pfinet/linux-src/net/ipv4/tcp_output.c index 9ea4b7ad..a15b7b30 100644 --- a/pfinet/linux-src/net/ipv4/tcp_output.c +++ b/pfinet/linux-src/net/ipv4/tcp_output.c @@ -922,6 +922,7 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mtu) tp->rcv_nxt = 0; sk->err = 0; + sk->done = 0; /* We'll fix this up when we get a response from the other end. * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. |