public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* data in socketpair() channel lost if writer closes or exits  without shutting down
@ 2001-07-13 11:14 Jonathan Kamens
  2001-07-13 17:21 ` Christopher Faylor
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Kamens @ 2001-07-13 11:14 UTC (permalink / raw)
  To: cygwin

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-13 11:14 data in socketpair() channel lost if writer closes or exits without shutting down Jonathan Kamens
@ 2001-07-13 17:21 ` Christopher Faylor
  2001-07-15 19:52   ` Jonathan Kamens
  2001-08-07 12:06   ` Christopher Faylor
  0 siblings, 2 replies; 13+ messages in thread
From: Christopher Faylor @ 2001-07-13 17:21 UTC (permalink / raw)
  To: cygwin

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/

-- 
cgf@cygnus.com                        Red Hat, Inc.
http://sources.redhat.com/            http://www.redhat.com/

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-13 17:21 ` Christopher Faylor
@ 2001-07-15 19:52   ` Jonathan Kamens
  2001-07-15 20:16     ` Christopher Faylor
  2001-07-16  0:53     ` Corinna Vinschen
  2001-08-07 12:06   ` Christopher Faylor
  1 sibling, 2 replies; 13+ messages in thread
From: Jonathan Kamens @ 2001-07-15 19:52 UTC (permalink / raw)
  To: cygwin; +Cc: cygwin

>  Date: Fri, 13 Jul 2001 20:21:46 -0400
>  From: Christopher Faylor <cgf@redhat.com>
>  
>  Thanks for the diagnosis.  Would you be willing to look at the
>  Cygwin socket code and suggest a fix?

OK, I looked at this for long enough to understand what's going wrong
and to understand theoretically how to fix it, but I'm hung up on some
of the Cygwin nuts and bolts.  Perhaps after I explain the problem,
someone can give me a couple of pointers for how to address it within
the Cygwin framework....

In yet another astounding piece of Windows brain-damage, the
*documented* behavior of the Winsock closesocket call is that any data
written to the socket that hasn't been read by the other end is lost,
and thus a client *must* call shutdown on a socket before closing it
to ensure that all data is transmitted to the other end.  The
reasoning behind implementing things this way escapes me.

My first thought after discovering this was that the obvious solution
is to call shutdown on the socket before calling closesocket in
fhandler_socket::close in fhandler_socket.cc.  Alas, we can't do this,
because a socket may be shared among multiple processes.  Although
each process has a different socket descriptor, the underlying socket
is shared among all of them, which means that as soon as any process
calls shutdown, the socket is unusable by all processes.  This is
clearly unacceptable when it's a common idiom, e.g., for a socketpair
to be created in a parent which then forks, and then the parent closes
one end of the socketpair while the child closes the other.

So, what I think needs to happen is that there needs to be some global
state, shared among all Cygwin processes, keeping track of sockets and
how many processes are using them.  Then, fhandler_socket::close can
check to see if all the processes but one have closed a socket, and
*only* then should it call shutdown on the socket before calling
closesocket on it.

Where I'm hung up is figuring out how to store that kind of global
state.  At first I thought it had something to do with "cygheap", but
upon further examination it looks to me like every cygwin process has
its own "cygheap"; perhaps I am confused about that.

If someone can suggest what I should look at to learn how to keep
global Cygwin state, I may be able to make more progress with this.

  jik

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-15 19:52   ` Jonathan Kamens
@ 2001-07-15 20:16     ` Christopher Faylor
  2001-07-15 20:41       ` Christopher Faylor
  2001-07-15 20:44       ` Jonathan Kamens
  2001-07-16  0:53     ` Corinna Vinschen
  1 sibling, 2 replies; 13+ messages in thread
From: Christopher Faylor @ 2001-07-15 20:16 UTC (permalink / raw)
  To: cygwin

On Sun, Jul 15, 2001 at 10:52:20PM -0400, Jonathan Kamens wrote:
>>  Date: Fri, 13 Jul 2001 20:21:46 -0400
>>  From: Christopher Faylor <cgf@redhat.com>
>>  
>>  Thanks for the diagnosis.  Would you be willing to look at the
>>  Cygwin socket code and suggest a fix?
>
>OK, I looked at this for long enough to understand what's going wrong
>and to understand theoretically how to fix it, but I'm hung up on some
>of the Cygwin nuts and bolts.  Perhaps after I explain the problem,
>someone can give me a couple of pointers for how to address it within
>the Cygwin framework....
>
>In yet another astounding piece of Windows brain-damage, the
>*documented* behavior of the Winsock closesocket call is that any data
>written to the socket that hasn't been read by the other end is lost,
>and thus a client *must* call shutdown on a socket before closing it
>to ensure that all data is transmitted to the other end.  The
>reasoning behind implementing things this way escapes me.
>
>My first thought after discovering this was that the obvious solution
>is to call shutdown on the socket before calling closesocket in
>fhandler_socket::close in fhandler_socket.cc.  Alas, we can't do this,
>because a socket may be shared among multiple processes.  Although
>each process has a different socket descriptor, the underlying socket
>is shared among all of them, which means that as soon as any process
>calls shutdown, the socket is unusable by all processes.  This is
>clearly unacceptable when it's a common idiom, e.g., for a socketpair
>to be created in a parent which then forks, and then the parent closes
>one end of the socketpair while the child closes the other.
>
>So, what I think needs to happen is that there needs to be some global
>state, shared among all Cygwin processes, keeping track of sockets and
>how many processes are using them.  Then, fhandler_socket::close can
>check to see if all the processes but one have closed a socket, and
>*only* then should it call shutdown on the socket before calling
>closesocket on it.
>
>Where I'm hung up is figuring out how to store that kind of global
>state.  At first I thought it had something to do with "cygheap", but
>upon further examination it looks to me like every cygwin process has
>its own "cygheap"; perhaps I am confused about that.
>
>If someone can suggest what I should look at to learn how to keep
>global Cygwin state, I may be able to make more progress with this.

Each cygwin process inherits a copy of cygheap.  The cygheap is
not strictly shared between processes.  It is just inherited from
its parent.

We don't have any mechanism for sharing file handle (or actually device)
state between processes.  Corinna and I have talked about this for some
time, though.  If we had something like this, I could fix some other
problems with the handling pipes, too.

cgf

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-15 20:16     ` Christopher Faylor
@ 2001-07-15 20:41       ` Christopher Faylor
  2001-07-15 20:44       ` Jonathan Kamens
  1 sibling, 0 replies; 13+ messages in thread
From: Christopher Faylor @ 2001-07-15 20:41 UTC (permalink / raw)
  To: cygwin

Btw, thanks much for looking into this, Jonathan.  I am
glad that we know what the problem is even if we don't
know how to fix it currently.

cgf

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-15 20:16     ` Christopher Faylor
  2001-07-15 20:41       ` Christopher Faylor
@ 2001-07-15 20:44       ` Jonathan Kamens
  1 sibling, 0 replies; 13+ messages in thread
From: Jonathan Kamens @ 2001-07-15 20:44 UTC (permalink / raw)
  To: cygwin

>  Date: Sun, 15 Jul 2001 23:15:52 -0400
>  From: Christopher Faylor <cgf@redhat.com>
>  
>  We don't have any mechanism for sharing file handle (or actually device)
>  state between processes.

Absent such a mechanism, I can't think of any way to fix this bug (or
perhaps I should say, to work around this Windows bug :-).

  jik

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-15 19:52   ` Jonathan Kamens
  2001-07-15 20:16     ` Christopher Faylor
@ 2001-07-16  0:53     ` Corinna Vinschen
  2001-07-16 11:00       ` Jonathan Kamens
  1 sibling, 1 reply; 13+ messages in thread
From: Corinna Vinschen @ 2001-07-16  0:53 UTC (permalink / raw)
  To: cygwin

On Sun, Jul 15, 2001 at 10:52:20PM -0400, Jonathan Kamens wrote:
> >  Date: Fri, 13 Jul 2001 20:21:46 -0400
> >  From: Christopher Faylor <cgf@redhat.com>
> >  
> >  Thanks for the diagnosis.  Would you be willing to look at the
> >  Cygwin socket code and suggest a fix?
> 
> In yet another astounding piece of Windows brain-damage, the
> *documented* behavior of the Winsock closesocket call is that any data
> written to the socket that hasn't been read by the other end is lost,
> and thus a client *must* call shutdown on a socket before closing it
> to ensure that all data is transmitted to the other end.  The

Thanks for figuring that out. I would be very interested in this
piece of documentation. Could you give me a pointer?

The problem is, from what I read so far (which is basically the MSDN)
the default behaviour on closing a socket is to perform a graceful
shutdown with immediate return of the `closesocket' function (linger
"off"). I just have that page "Graceful Shutdown, Linger Options, and
Socket Closure" inside of MSDN, that's all.

Since Microsoft at least claims that linger "off" is a valid and
settable state, shouldn't we try a very simple solution first?
We could change the Cygwin internal `socket' function so that
we don't rely on the linger setting but set linger "off" explicitely
after the socket() call. We could even set it explicitely in
a WSADuplicateSocket/WSASocket action on fork.

Comments?

Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Developer                                mailto:cygwin@cygwin.com
Red Hat, Inc.

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-16  0:53     ` Corinna Vinschen
@ 2001-07-16 11:00       ` Jonathan Kamens
  2001-07-16 12:55         ` Corinna Vinschen
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Kamens @ 2001-07-16 11:00 UTC (permalink / raw)
  To: cygwin

>  Date: Mon, 16 Jul 2001 09:52:58 +0200
>  From: Corinna Vinschen <cygwin@cygwin.com>
>  
>  Thanks for figuring that out. I would be very interested in this
>  piece of documentation. Could you give me a pointer?

The MSDN page documenting the "closesocket" function says, "Note: To
assure that all data is sent and received on a connection, an
application should call shutdown before calling closesocket."

I believe you're right that the default SO_DONTLINGER behavior will do
the right thing *if the process that called closesocket() stays
running until all the data has been received by the other end of the
connection*.  The problem is that much of the time, a process closes
its sockets when it's cleaning up and about to exit, i.e., it doesn't
hang around afterwards for long enough for the data to be received at
the other end.

The reason why things are different if the process exits is because
Winsock runs in user space.  Windows can't leave something around
finishing up with data transmission after the process exits.  On Unix,
on the other hand, sockets are handled in the kernel, and the kernel
will happily maintain that state and finish transmitting the data even
after the process which sent it is gone.

When I was investigating this, I should have paid more attention to
SO_LINGER and SO_DONTLINGER.  I suppose that another potential fix to
this problem, independent of calling shutdown as I previously
suggested, is to set the SO_LINGER option with a nonzero timeout, to
give the other end time to read the data before closesocket returns.
Of course, there are obvious problems with this -- the program calling
close will hang while closesocket is waiting for the data to finish
transmitting, and there's no way to pick a timeout which is (a) not
too large and (b) guaranteed to always allow data to finish being
transmitted when there's someone at the other end to receive it.

Perhaps as a compromise we could set SO_LINGER on all new sockets with
a short timeout, say a few seconds, to give data time to flush.

Or, slightly more complex but slightly more correct, keep track of
whether or not a socket was at some point shared between multiple
processes (either as a result of a fork or as a result of sending a
file descriptor between processes (does Cygwin support that?)).  When
a socket is first shared, we can set SO_LINGER as I described above.
Then, when a socket is closed, check if it was ever shared and call
shutdown if it wasn't.

>  The problem is, from what I read so far (which is basically the MSDN)
>  the default behaviour on closing a socket is to perform a graceful
>  shutdown with immediate return of the `closesocket' function (linger
>  "off"). I just have that page "Graceful Shutdown, Linger Options, and
>  Socket Closure" inside of MSDN, that's all.

Amusingly enough, the link to that page on the "closesocket" page is
invalid.

  jik

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-16 11:00       ` Jonathan Kamens
@ 2001-07-16 12:55         ` Corinna Vinschen
  2001-07-16 19:00           ` Christopher Faylor
  0 siblings, 1 reply; 13+ messages in thread
From: Corinna Vinschen @ 2001-07-16 12:55 UTC (permalink / raw)
  To: cygwin

On Mon, Jul 16, 2001 at 02:00:10PM -0400, Jonathan Kamens wrote:
> The reason why things are different if the process exits is because
> Winsock runs in user space.  Windows can't leave something around
> finishing up with data transmission after the process exits.  On Unix,
> on the other hand, sockets are handled in the kernel, and the kernel
> will happily maintain that state and finish transmitting the data even
> after the process which sent it is gone.

AFAICS, that's the most important observation. I never thought about
that.

> Perhaps as a compromise we could set SO_LINGER on all new sockets with
> a short timeout, say a few seconds, to give data time to flush.

No, that's incorrect. Excerpt from W. Richard Stevens, "UNIX Network
Programming Vol. 1, Network APIs: Sockets and XTI", 2nd Edition, p. 187:

	If l_onoff is nonzero and l_linger is 0, TCP aborts the
	connection when it is closed [...]. That is, TCP discards
	any data still remaining [...]. This avoids TCP's TIME_WAIT
	state, but in doing so leaves open the possibility of
	another incarnation of this connection being created within
	2MSL seconds and having old duplicate segments from the just
	terminated connection being incorrectly delivered to the new
	incarnation [...].

> Or, slightly more complex but slightly more correct, keep track of
> whether or not a socket was at some point shared between multiple
> processes (either as a result of a fork or as a result of sending a
> file descriptor between processes (does Cygwin support that?)).  When
> a socket is first shared, we can set SO_LINGER as I described above.
> Then, when a socket is closed, check if it was ever shared and call
> shutdown if it wasn't.

Since Cygwin has currently no "device layer" (though planned for the
future) we have no sharing of data between duplicated and inherited
file descriptors, unfortunately.

> >   I just have that page "Graceful Shutdown, Linger Options, and
> >  Socket Closure" inside of MSDN, that's all.
> 
> Amusingly enough, the link to that page on the "closesocket" page is
> invalid.

http://msdn.microsoft.com/library/en-us/winsock/hh/winsock/ovrvw3_3she.asp

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Developer                                mailto:cygwin@cygwin.com
Red Hat, Inc.

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-16 12:55         ` Corinna Vinschen
@ 2001-07-16 19:00           ` Christopher Faylor
  2001-07-17  1:30             ` Corinna Vinschen
  0 siblings, 1 reply; 13+ messages in thread
From: Christopher Faylor @ 2001-07-16 19:00 UTC (permalink / raw)
  To: cygwin

On Mon, Jul 16, 2001 at 09:54:05PM +0200, Corinna Vinschen wrote:
>On Mon, Jul 16, 2001 at 02:00:10PM -0400, Jonathan Kamens wrote:
>> Or, slightly more complex but slightly more correct, keep track of
>> whether or not a socket was at some point shared between multiple
>> processes (either as a result of a fork or as a result of sending a
>> file descriptor between processes (does Cygwin support that?)).  When
>> a socket is first shared, we can set SO_LINGER as I described above.
>> Then, when a socket is closed, check if it was ever shared and call
>> shutdown if it wasn't.
>
>Since Cygwin has currently no "device layer" (though planned for the
>future) we have no sharing of data between duplicated and inherited
>file descriptors, unfortunately.

I wonder if we could kludge something into the delete-on-close queue
for now...

cgf

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-16 19:00           ` Christopher Faylor
@ 2001-07-17  1:30             ` Corinna Vinschen
  0 siblings, 0 replies; 13+ messages in thread
From: Corinna Vinschen @ 2001-07-17  1:30 UTC (permalink / raw)
  To: cygwin

On Mon, Jul 16, 2001 at 10:00:33PM -0400, Christopher Faylor wrote:
> On Mon, Jul 16, 2001 at 09:54:05PM +0200, Corinna Vinschen wrote:
> >On Mon, Jul 16, 2001 at 02:00:10PM -0400, Jonathan Kamens wrote:
> >> Or, slightly more complex but slightly more correct, keep track of
> >> whether or not a socket was at some point shared between multiple
> >> processes (either as a result of a fork or as a result of sending a
> >> file descriptor between processes (does Cygwin support that?)).  When
> >> a socket is first shared, we can set SO_LINGER as I described above.
> >> Then, when a socket is closed, check if it was ever shared and call
> >> shutdown if it wasn't.
> >
> >Since Cygwin has currently no "device layer" (though planned for the
> >future) we have no sharing of data between duplicated and inherited
> >file descriptors, unfortunately.
> 
> I wonder if we could kludge something into the delete-on-close queue
> for now...

Hmm, probably...

Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Developer                                mailto:cygwin@cygwin.com
Red Hat, Inc.

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-07-13 17:21 ` Christopher Faylor
  2001-07-15 19:52   ` Jonathan Kamens
@ 2001-08-07 12:06   ` Christopher Faylor
  2001-08-08  0:03     ` Corinna Vinschen
  1 sibling, 1 reply; 13+ messages in thread
From: Christopher Faylor @ 2001-08-07 12:06 UTC (permalink / raw)
  To: cygwin

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: data in socketpair() channel lost if writer closes or exits without shutting down
  2001-08-07 12:06   ` Christopher Faylor
@ 2001-08-08  0:03     ` Corinna Vinschen
  0 siblings, 0 replies; 13+ messages in thread
From: Corinna Vinschen @ 2001-08-08  0:03 UTC (permalink / raw)
  To: cygwin

On Tue, Aug 07, 2001 at 03:06:03PM -0400, Christopher Faylor wrote:
> I'm getting ready to make a new release.  Was there ever any movement
> on a fix for this?

No, I'm afraid.

Corinna

> 
> 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/

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Developer                                mailto:cygwin@cygwin.com
Red Hat, Inc.

--
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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2001-08-08  0:03 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-07-13 11:14 data in socketpair() channel lost if writer closes or exits without shutting down Jonathan Kamens
2001-07-13 17:21 ` Christopher Faylor
2001-07-15 19:52   ` Jonathan Kamens
2001-07-15 20:16     ` Christopher Faylor
2001-07-15 20:41       ` Christopher Faylor
2001-07-15 20:44       ` Jonathan Kamens
2001-07-16  0:53     ` Corinna Vinschen
2001-07-16 11:00       ` Jonathan Kamens
2001-07-16 12:55         ` Corinna Vinschen
2001-07-16 19:00           ` Christopher Faylor
2001-07-17  1:30             ` Corinna Vinschen
2001-08-07 12:06   ` Christopher Faylor
2001-08-08  0:03     ` Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).