Subject: kern/18185: shutdown(s, SHUT_RD); doesn't.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <seanb@qnx.com>
List: netbsd-bugs
Date: 09/05/2002 12:00:39
>Number: 18185
>Category: kern
>Synopsis: shutdown(s, SHUT_RD); doesn't.
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Sep 05 12:01:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator: Sean Boudreau
>Release: 1-5
>Organization:
QNX
>Environment:
>Description:
After calling shutdown(s, SHUT_RD), data can still be
appended to socket recv buffer. If data present when
read() and friends called, it will be returned out.
>How-To-Repeat:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
int s, ret;
struct sockaddr_in sad;
char buf[] = "This shouldn't have come back.";
if(argc < 2) {
fprintf(stderr, "usage: %s host\n", argv[0]);
return 1;
}
memset(&sad, 0x00, sizeof sad);
sad.sin_family = AF_INET;
sad.sin_len = sizeof sad;
sad.sin_port = htons(7); /* echo */
if(inet_aton(argv[1], &sad.sin_addr) == 0) {
fprintf(stderr, "invalid addr: %s\n", argv[1]);
return 1;
}
if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return 1;
}
if(connect(s, (struct sockaddr *)&sad, sizeof sad) == -1) {
perror("connect");
return 1;
}
if(shutdown(s, SHUT_RD) == -1) {
perror("shutdown");
return 1;
}
if(write(s, buf, sizeof buf) == -1) {
perror("write");
return 1;
}
/*
* Attempt to ensure it's already in the recv buffer
* when read () is called.
*/
sleep(1);
if((ret = read(s, buf, sizeof buf - 1)) != 0) {
if(ret == -1) {
perror("read");
return 1;
}
buf[ret] = '\0';
fprintf(stderr, "%s\n", buf);
return 1;
}
printf("Success.\n");
return 0;
}
>Fix:
Appears SS_CANTRCVMORE flag not consulted on fast insertion paths.
Following is against 1-5 branch. Still appears to be present on head:
Index: netinet/tcp_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_input.c,v
retrieving revision 1.108.4.12
diff -c -r1.108.4.12 tcp_input.c
*** netinet/tcp_input.c 2002/04/03 21:17:06 1.108.4.12
--- netinet/tcp_input.c 2002/09/05 18:50:06
***************
*** 1345,1352 ****
* Drop TCP, IP headers and TCP options then add data
* to socket buffer.
*/
! m_adj(m, toff + off);
! sbappend(&so->so_rcv, m);
sorwakeup(so);
TCP_SETUP_ACK(tp, th);
if (tp->t_flags & TF_ACKNOW)
--- 1345,1357 ----
* Drop TCP, IP headers and TCP options then add data
* to socket buffer.
*/
! if (so->so_state & SS_CANTRCVMORE) {
! m_freem(m);
! }
! else {
! m_adj(m, toff + off);
! sbappend(&so->so_rcv, m);
! }
sorwakeup(so);
TCP_SETUP_ACK(tp, th);
if (tp->t_flags & TF_ACKNOW)
***************
*** 2084,2091 ****
tcpstat.tcps_rcvpack++;
tcpstat.tcps_rcvbyte += tlen;
ND6_HINT(tp);
! m_adj(m, hdroptlen);
! sbappend(&(so)->so_rcv, m);
sorwakeup(so);
} else {
m_adj(m, hdroptlen);
--- 2089,2101 ----
tcpstat.tcps_rcvpack++;
tcpstat.tcps_rcvbyte += tlen;
ND6_HINT(tp);
! if (so->so_state & SS_CANTRCVMORE) {
! m_freem(m);
! }
! else {
! m_adj(m, hdroptlen);
! sbappend(&(so)->so_rcv, m);
! }
sorwakeup(so);
} else {
m_adj(m, hdroptlen);
>Release-Note:
>Audit-Trail:
>Unformatted: