Date: Tue, 18 May 2010 01:08:50 +0900 From: Yoshihiko Sarumaru <ysarumaru@gmail.com> To: freebsd-net@FreeBSD.org, freebsd-stable@FreeBSD.org Subject: odd behavior on select() after shutdown() Message-ID: <AANLkTilQexT6ZobWYe2MuPcsD5RnTsx3SL0Zru_01Q9C@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
Hi all, Select(2) has three arguments to get socket status for read, write and except. After upgrading to 8.0-RELEASE, select() after shutdown(SHUT_WR) returns with the status exceptfds is set. It means out-of-bound data can be read from the socket, but recv() with OOB flag returns ECONNRESET, and no packets with urgent flag was observed by tcpdump. It seems strange for me, but is it an intentional change on 8.x ? This behavior breaks net/stone on 8.0-RELEASE. http://www.freebsd.org/cgi/query-pr.cgi?pr=ports/141103 The continuous recv() error on PR might lead by incorrectly setted exceptfds on every recv() and it should be fixed, but it doesn't matter if above behavior of select() doesn't occur. You can reproduce this by following example: #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <string.h> int main() { int ret; int s; s = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr("127.0.0.1"); sa.sin_port = htons(22); ret = connect(s, (struct sockaddr*)&sa, sizeof(sa)); if (ret) perror("connect"); /* get OpenSSH greetings */ char buf[BUFSIZ]; memset(buf, 0, sizeof(buf) / sizeof(buf[0])); ret = recv(s, buf, sizeof(buf), 0); if (ret < 0) perror("recv"); printf("recv: %s\n", buf); /* send something incorrect */ printf("send: \\r\\n\n"); ret = send(s, "\r\n", 2, 0); if (ret < 0) perror("send"); /* receive "Protocol mismatch" */ memset(buf, 0, sizeof(buf) / sizeof(buf[0])); ret = recv(s, buf, sizeof(buf), 0); if (ret < 0) perror("recv"); printf("recv: %s\n", buf); /* shutdown */ ret = shutdown(s, SHUT_WR); /* SHUT_RD doesn't make problem. */ if (ret) perror("shutdown"); /* select */ fd_set readfds, exceptfds; FD_ZERO(&readfds); FD_ZERO(&exceptfds); FD_SET(s, &readfds); FD_SET(s, &exceptfds); ret = select(s+1, &readfds, NULL, &exceptfds, NULL); if (ret < 1) perror("select"); printf("select: read:%d except:%d\n", FD_ISSET(s, &readfds), FD_ISSET(s, &exceptfds)); if (FD_ISSET(s, &exceptfds)) { printf("read OOB data\n"); memset(buf, 0, sizeof(buf) / sizeof(buf[0])); ret = recv(s, buf, sizeof(buf), MSG_OOB); if (ret < 0) perror("recv"); printf("recv(OOB): %s\n", buf); } FD_ZERO(&readfds); FD_SET(s, &readfds); ret = select(s+1, &readfds, NULL, NULL, NULL); if (ret < 1) perror("select"); printf("select: read:%d\n", FD_ISSET(s, &readfds)); memset(buf, 0, sizeof(buf) / sizeof(buf[0])); ret = recv(s, buf, sizeof(buf), 0); if (ret < 0) perror("recv"); printf("recv: %s\n", buf); close(s); } Thanks in advance - Yoshihiko
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?AANLkTilQexT6ZobWYe2MuPcsD5RnTsx3SL0Zru_01Q9C>