summaryrefslogtreecommitdiff
path: root/pfinet
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2015-01-03 17:44:01 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2015-01-03 17:44:01 +0100
commit87fad50310f2bd0dcc990e80e23b09768918cf5b (patch)
tree68550f66228a82a37f6efdbb02ae864fd15cbc07 /pfinet
parent29a30c44bb8cecb341df211bcb3b330f515c9003 (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.c59
-rw-r--r--pfinet/linux-src/net/ipv4/tcp_input.c3
-rw-r--r--pfinet/linux-src/net/ipv4/tcp_output.c1
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.