From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mout.kundenserver.de (mout.kundenserver.de [212.227.126.131]) by sourceware.org (Postfix) with ESMTPS id 9D2DC3857819 for ; Tue, 6 Apr 2021 18:24:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9D2DC3857819 Authentication-Results: sourceware.org; dmarc=fail (p=none dis=none) header.from=cygwin.com Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=corinna-cygwin@cygwin.com Received: from calimero.vinschen.de ([24.134.7.25]) by mrelayeu.kundenserver.de (mreue009 [212.227.15.167]) with ESMTPSA (Nemesis) id 1MmlfS-1ltVx31Ooo-00jnQE for ; Tue, 06 Apr 2021 20:24:07 +0200 Received: by calimero.vinschen.de (Postfix, from userid 500) id 157A1A80773; Tue, 6 Apr 2021 20:24:06 +0200 (CEST) Date: Tue, 6 Apr 2021 20:24:06 +0200 From: Corinna Vinschen To: cygwin-developers@cygwin.com Subject: Re: Questions about select for sockets Message-ID: Reply-To: cygwin-developers@cygwin.com Mail-Followup-To: cygwin-developers@cygwin.com References: <6b50ec89-5c02-c49f-ad85-e581589d21d3@cornell.edu> <6306d8f3-cf05-07bb-e944-05aed69266f3@cornell.edu> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <6306d8f3-cf05-07bb-e944-05aed69266f3@cornell.edu> X-Provags-ID: V03:K1:YPvFURmpWbYEovTcxVyk5tHJSZT9FMKdVU5DQWdd4ZOrVvIq1UX RBokVWG4jh0uuRV80A39WdKKDZW1qcqCLQ9YIn8sjNkm2HAtnCq7o8ANoGbAw9YC1TG/kTI gwbojbFLhgbU4rfHYmBnk8sb60qxgakNd+sf38GmfulAoyLxdY3BGV1yf934gV9QWQlROrs n6NHMH6+rL0I2kuFGbbZw== X-UI-Out-Filterresults: notjunk:1;V03:K0:bqEQw4yAmZQ=:6s96suwcoBIWdRI9a7warb vf5NjUNNLumtxEDHlrSeDP2isNdTnlDzEJeVPS/+qf57CtZlaQsE5mpWxY+BpCMWNmAeb5j5n NdPwKxYZdNTBIExx1YZk/95PNCPr/+1yp0v1xGwERg4w+vG6zR/tRbwSkyGuIKmu2oq/ww/LS K0I4HNEgdWJK+F2E38kSndvg7QwQDtUxlllqjAf7U3vaOUhMO43lJRHw4TA/1cJTvr0zoI4a6 3xes3i0Y0hu+3+Ym/xFk8xwsw/Y1EsUxxg9RJ8TPt1wjZ5vKw+dFVjcjXfzpOk+c2CkUBNqG0 thhJ8wYmCYaI+J53545X6ulGgiX3yvZp3Ya8gbLrI8DsXNLfKEDo9FFWWYKpILcdQqZ3yAx5r DJ1Enj2P9yUfKK07aHhddZtU6oIh+5uEID1IhYGbnisLIWDDIIX35gdhAi45W0cDxlUakAyvv A6CTSBqx7LPzYjIeEKabmXrAgAVHuwH5Yl/hkIThFSXnTG7MR2gZ X-Spam-Status: No, score=-101.2 required=5.0 tests=BAYES_00, GOOD_FROM_CORINNA_CYGWIN, KAM_DMARC_NONE, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NEUTRAL, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: cygwin-developers@cygwin.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Cygwin core component developers mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 06 Apr 2021 18:24:11 -0000 On Apr 6 13:37, Ken Brown wrote: > On 4/6/2021 12:28 PM, Corinna Vinschen wrote: > > On Apr 6 11:44, Ken Brown wrote: > > > On 4/6/2021 10:33 AM, Corinna Vinschen wrote: > > > > We may also have to change the saw_shutdown_read/saw_shutdown_write > > > > handling. I checked this on Linux and what happens is: > > > > > > > > After shutdown (fd, SHUT_RD), the socket is ready for reading and writing > > > > > > This seems surprising to me. Is it really the shutdown that caused it to be > > > ready for writing in your test, or was it ready for writing anyway (e.g., > > > because the relevant buffer was empty)? > > > > I guess so, too. How to make sure the socket isn't ready for writing > > without going to great lengths? > > I guess you could have a subprocess write to the socket in a loop, so that > its buffer will quickly fill up and a further write will block. Yeah, I was trying to minimize work, but I now lazily created a blocking server in the same process with a non-blocking client, calling send(2) until it fails. And now everything is as expected. SHUT_RD -> ready for reading, SHUT_WR -> ready for writing, SHUT_RDWR -> ready for both. I attached my STC, for completeness. Call with an argument 0 (== SHUT_RD), 1 (== SHUT_WR), or 2 (== SHUT_RDWR). Corinna #include #include #include #include #include #include #include #include #include int sel (int fd, const char *when) { fd_set r, w, e; int ret; struct timeval tv; printf ("%s\n", when); FD_ZERO (&r); FD_ZERO (&w); FD_ZERO (&e); FD_SET (fd, &r); FD_SET (fd, &w); FD_SET (fd, &e); tv.tv_sec = 1; tv.tv_usec = 0; errno = 0; ret = select (fd + 1, &r, &w, &e, &tv); printf ("select: %d", ret); if (select < 0) printf ("%d <%s>\n", errno, strerror (errno)); putchar ('\n'); if (FD_ISSET (fd, &r)) printf ("ready for reading\n"); if (FD_ISSET (fd, &w)) printf ("ready for writing\n"); if (FD_ISSET (fd, &r) || FD_ISSET (fd, &w)) { int err, len; len = sizeof err; getsockopt (fd, SOL_SOCKET, SO_ERROR, &err, &len); printf ("SO_ERROR: %d <%s>\n", err, strerror (err)); } if (FD_ISSET (fd, &e)) printf ("ready for exception\n"); putchar ('\n'); } int sfd; int server_1 () { struct sockaddr_in in; sfd = socket (AF_INET, SOCK_STREAM, 0); if (sfd < 0) { printf ("SRV socket: %d <%s>\n", errno, strerror (errno)); return -1; } in.sin_family = AF_INET; in.sin_port = htons (65444); in.sin_addr.s_addr = inet_addr ("127.0.0.1"); if (bind (sfd, (const struct sockaddr *) &in, sizeof in) < 0) { printf ("SRV bind: %d <%s>\n", errno, strerror (errno)); return -1; } if (listen (sfd, 5) < 0) { printf ("SRV listen: %d <%s>\n", errno, strerror (errno)); return -1; } return 0; } int server_2 () { if (accept (sfd, NULL, NULL) < 0) { printf ("SRV accept: %d <%s>\n", errno, strerror (errno)); return -1; } return 0; } char buf[65536]; int main (int argc, char **argv) { int fd, arg; struct sockaddr_in in; fd = socket (AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (fd < 0) { printf ("socket: %d <%s>\n", errno, strerror (errno)); return 1; } if (server_1 ()) return 2; in.sin_family = AF_INET; in.sin_port = htons (65444); in.sin_addr.s_addr = inet_addr ("127.0.0.1"); sel (fd, "Pre connect"); if (connect (fd, (const struct sockaddr *) &in, sizeof in) != 0 && errno != EINPROGRESS) { printf ("connect: %d <%s>\n", errno, strerror (errno)); return 3; } if (server_2 () < 0) return 4; sel (fd, "Post shutdown"); /* write until buffer full */ while (send (fd, buf, sizeof buf, 0) > 0) ; sel (fd, "Pre shutdown"); arg = argc > 1 ? atoi (argv[1]) : SHUT_RDWR; if (shutdown (fd, argc > 1 ? atoi (argv[1]) : SHUT_RDWR) < 0) { printf ("shutdown: %d <%s>\n", errno, strerror (errno)); return 4; } sel (fd, "Post shutdown"); }