[REBOL] Re: tcp port open?
From: holger:rebol at: 18-Oct-2001 10:35
On Tue, Oct 09, 2001 at 12:48:49PM +0200, Maarten Koopmans wrote:
> copy returns none when there is no data
> query returns always true on an opened port regardless of the other side.
>
> So... question remains open.
It is a little complicated, unfortunately.
The problem is that TCP is full-duplex, but within the TCP protocol
both directions are logically separated, i.e. a TCP connection
really consists of two half-duplex pipes, each going in one direction.
Both pipes are always created at the same time, when the connection
is opened, but it is possible to close only one of them and keep the
other one open, leading to a "half-closed" connection.
At the TCP protocol level one side can only close its send pipe, not its
receive pipe. The connection is completely closed once both sides have
closed their send pipes. It is possible for a TCP connection to stay
in a half-closed state for an arbitrary amount of time. This is not an
error condition. It is not very common, but some protocols do make use
of it.
It is not possible to close only the receive pipe of a connection.
(The shutdown() function call in C allows that, but for TCP it is
basically a no-op, i.e. the other side is never informed about it, so
even in C closing the receive pipe has no real effect.) What this
means is that with TCP there is no way to tell the other side that
you are no longer willing to accept data.
*Usually* when one side recognizes that the peer has closed its
send pipe, the other side closes its send pipe as well, resulting
in a completely closed connection. This is not always the case though.
For instance with many of the trivial query protocols (daytime, auth
etc.) it is common for the client to send its request and immediately
close its send pipe. Then it waits on its receive pipe for the
server's response. The server only closes its send pipe after sending
its response, even if its receive pipe has been closed by the peer
before it gets a chance to respond.
In order to allow this functionality it is imperative that a server
does not automatically close its send pipe once its receive
pipe has been closed by the peer. Otherwise it would be unable to
respond to requests via a half-closed connection.
What this means for REBOL is:
You can detect whether your receive pipe has been closed by the
peer by performing a 'copy on the port, assuming the port is
in /no-wait mode. A none return means the other side has closed
its send pipe (your receive pipe), any other value means that
your receive pipe is still open.
A query on a port only tells you whether a port is connected at all,
not which pipes of the connection have which state. If the other side
closes its send pipe then you are still connected (because your
send pipe is still open), so query still returns true, and you can
still send data. Of course if the other side actually accepts that
data is a different matter. That depends on whether the other side
only closed its send pipe or whether it completely closed the
socket. There is no way for the local host to detect that, because
that information is not transmitted through TCP.
One exception though: Some, arguably broken, TCP/IP stacks (e.g.
Windows) return errors (RST) to the peer when they receive data for a
socket that has been closed by the program after the program
exits. Most other stacks simply acknowledge the data and throw it
away. For you that means when writing data to a TCP port, and the
receiver is "no longer there" then one of two things may happen:
either your data is silently accepted and ignored, or you may get
an error. Which one it is does not depend on your TCP/IP stack,
but on the peer's TCP/IP stack and how it handles program termination.
Checking whether your incoming side has been closed is NOT the right
way to determine whether the peer is "still there", because you may
get "false positives" on half-closed connections, as explained above.
(Unless, of course, you know that the protocol you are running across
the TCP channel is never supposed to use half-closed connections.
In that case that kind of check is safe.)
At the moment REBOL does not allow you to close only one pipe of a
connection. We plan to add that in one of the next versions, through
get/set-modes.
--
Holger Kruse
[holger--rebol--com]