This is the mail archive of the
cygwin@cygwin.com
mailing list for the Cygwin project.
Re: data in socketpair() channel lost if writer closes or exits without shutting down
- To: cygwin at cygwin dot com
- Subject: Re: data in socketpair() channel lost if writer closes or exits without shutting down
- From: Christopher Faylor <cgf at redhat dot com>
- Date: Tue, 7 Aug 2001 15:06:03 -0400
- References: <20010713181435.3695.qmail@lizard.curl.com> <20010713202146.B11377@redhat.com>
- Reply-To: cygwin at cygwin dot com
I'm getting ready to make a new release. Was there ever any movement
on a fix for this?
cgf
On Fri, Jul 13, 2001 at 08:21:46PM -0400, Christopher Faylor wrote:
>Thanks for the diagnosis. Would you be willing to look at the
>Cygwin socket code and suggest a fix?
>
>cgf
>
>On Fri, Jul 13, 2001 at 02:14:35PM -0400, Jonathan Kamens wrote:
>>The test program below creates a socketpair and then forks. The child
>>writes some data to the socketpair and then exits, and the parent
>>tries to read that data.
>>
>>Instead of printing "PARENT: foo (exiting)" as it should, the parent
>>prints "PARENT: read: Connection reset by peer". This is also true if
>>you compile the program with "-DUSE_CLOSE" to tell the child to close
>>the write end of the socketpair before exiting. However, it works
>>properly if you compile the program with "-DUSE_SHUTDOWN" to tell the
>>child to shutdown its end of the socketpair before exiting.
>>
>>There are two different bugs here:
>>
>>1) close() on an end of a socketpair should behave the same as
>> shutdown(..., 2), in terms of flushing data to the other end of the
>> socketpair.
>>
>>2) Data sent by the writer should be flushed to the reader, not lost,
>> when the writer exits.
>>
>>This problem causes recent versions of rsync, when they are compiled
>>to use socketpairs (which is the default), to report a bogus "read
>>error: connection reset by peer" at the end of every rsync, even when
>>it in fact copied everything successfully. I'm going to submit a
>>patch to the rsync maintainers suggesting that they work around this
>>problem by calling shutdown() before exiting.
>>
>> jik
>>
>> *************************
>>
>>#include <unistd.h>
>>#include <stdio.h>
>>#include <sys/types.h>
>>#include <signal.h>
>>#include <sys/socket.h>
>>
>>main()
>>{
>> int pipefds[2];
>> int readfd, writefd;
>> char inbuf[4];
>> char outbuf[4] = "foo";
>> int pid;
>> fd_set readfds, exceptfds;
>>
>> socketpair(AF_UNIX, SOCK_STREAM, 0, pipefds);
>> /* pipe(pipefds); */
>>
>> readfd = pipefds[0];
>> writefd = pipefds[1];
>>
>> if (pid = fork()) {
>> fprintf(stderr, "PARENT: close(writefd)\n");
>> close(writefd);
>>
>> FD_ZERO(&readfds);
>> FD_SET(readfd, &readfds);
>> exceptfds = readfds;
>>
>> fprintf(stderr, "PARENT: selecting\n");
>> if (select(readfd + 1, &readfds, NULL, &exceptfds, NULL) <= 0) {
>> perror("PARENT: select");
>> exit(1);
>> }
>>
>> if (FD_ISSET(readfd, &exceptfds)) {
>> fprintf(stderr, "PARENT: exception is set\n");
>> }
>>
>> if (FD_ISSET(readfd, &readfds)) {
>> fprintf(stderr, "PARENT: read is set\n");
>> }
>>
>> fprintf(stderr, "PARENT: reading\n");
>> if (read(readfd, inbuf, sizeof(inbuf)) != sizeof(inbuf)) {
>> perror("PARENT: read");
>> exit(1);
>> }
>>
>> printf("PARENT: %s (exiting)\n", inbuf);
>> exit(0);
>> }
>> else {
>> fprintf(stderr, "CHILD: close(readfd)\n");
>> close(readfd);
>>
>> fprintf(stderr, "CHILD: writing\n");
>> if (write(writefd, outbuf, sizeof(outbuf)) != sizeof(outbuf)) {
>> perror("CHILD: write");
>> exit(1);
>> }
>>#ifdef USE_SHUTDOWN
>> shutdown(writefd, 2);
>>#endif
>>#ifdef USE_CLOSE
>> close(writefd);
>>#endif
>>
>> fprintf(stderr, "CHILD: exiting\n");
>> exit(0);
>> }
>>}
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Bug reporting: http://cygwin.com/bugs.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/