- From: Adam Bergkvist <adam.bergkvist@ericsson.com>
- Date: Tue, 24 Apr 2012 16:23:23 +0200
- To: Randell Jesup <randell-ietf@jesup.org>
- CC: "public-webrtc@w3.org" <public-webrtc@w3.org>, Michael Tuexen <tuexen@fh-muenster.de>, Randall Stewart <rrs@lakerest.net>, Salvatore Loreto <salvatore.loreto@ericsson.com>
On 2012-04-23 18:01, Randell Jesup wrote:
> In going over the details for the DataChannel minor protocol and how it
> works over SCTP, we realized we'll need a 3-way handshake instead of a
> 2-way. The reason is that an OPEN_RESPONSE sent ordered followed by a
> data message sent unordered would allow the data message to come in at
> the other end before the open response, and since we don't know the
> input-stream -> output-stream mapping until we get the OPEN_RESPONSE, we
> might not know what to do with it. So we plan to add an ACK message to
> the protocol to provide the 3-way handshake.
>
> We now have to decide what to do about the JS-level API; which to recap
> currently requires waiting for onopen on the opener's side, and allows
> the answerer to send() immediately on getting ondatachannel.
>
> We've figured out that we can allow send() before onopen (in either
> direction) by forcing data to be in-order until the 3-way handshake is
> complete. Obviously, if you're using in-order (reliable or unreliable)
> this doesn't matter. It does cause and data sent to be buffered in the
> stack(s) until it can be delivered, which typically would be no real
> problem unless the OPEN (or OPEN_RESPONSE) was lost and had to be
> re-transmitted.
>
> There are two really "simple and clean" solutions:
> 1) both sides wait for onopen()
> 2) neither side waits for onopen()
> Note that in #2 we'd still have onopen() for ease of porting WebSockets
> code to it DataChannels.
>
> We could also keep the current API (onopen at the opener, immediate on
> the receiver).
>
> #1 requires the application maintain state in a number of cases where it
> would not otherwise need to, or buffer within the app. I.e. an
> application that wants to send data on a channel not yet open must open
> it and somehow defer the sending until it's open. This can be
> encapsulated in JS functions:
>
> temp = peer.createDataChannel(..)
> temp.data_to_send = "I want to send just this";
> temp.onopen = function() {
> temp.send(temp.data_to_send);
> temp.close(); // don't wait for GC to close/reclaim stream!
> temp = null; // available for GC
> };
>
> Of course, not as straightforward as:
> temp = peer.createDataChannel(..)
> temp.send("I want to send just this");
> temp.close();
> temp = null;
>
> but not a lot worse. It's more complex if you might want to send more
> data to the channel and need to buffer all of it in the app (think a log
> channel) while waiting for it to open. Commonly the answerer will wait
> for incoming data before sending anything, but not in all cases.
>
> It seems to me that forcing in-order delivery until the handshake is
> complete is simpler for the user, and only rarely has any impact on the
> application. The exception might be if you wanted to dump a bunch of
> sends that were reliable and out-of-order immediately on creation of the
> channel - and I don't see it being a major issue there - and you can
> still wait on onopen if you want.
>
> Recap: #2 is slightly closer to how WebSockets works (though anything
> coded for WebSockets' onopen behavior would still work in #1), and #2
> avoids potential additional buffering in the stack if the
> OPEN/OPEN_RESPONSE is lost. (If it's not lost, there's really no extra
> buffering occurring, except maybe in the rare case where we need to
> increase the maximum number of simultaneous streams.)
>
> Opinions?
In approach #2, we move away from behaving like a WebSocket. More
precisely, a DataChannel could still be used instead of a WebSocket but
a WebSocket couldn't replace a DataChannel since a call to send() before
the "open" event would result in a InvalidStateError.
I've drawn some simple signaling diagrams below to help myself to
overview this. Let me know if they are over-simplified or perhaps even
wrong.
What we currently have with a 2-way handshake with comes with some problems.
2-way handshake
A -- OPEN -> B (datachannel@B)
A <- OPEN_RESP -- B (open@A)
Considering a 3-way handshake, approaches #1 and #2 would basically fire
the "open" events at the same time, but the difference would be that in
#1 it wouldn't be OK to call send() before the "open" event.
3-way handshake
A -- OPEN -> B (datachannel)@B)
A <- OPEN_RESP -- B (open@A)
A -- ACK -> B (open@B)
Couldn't we keep our current API behavior by delaying the "datachannel"
event on the B-side as described below? The order that the events are
trigger are reversed compared to the 2-way handshake above, but is that
a problem?
3-way handshake
A -- OPEN -> B
A <- OPEN_RESP -- B (open@A)
A -- ACK -> B (datachannel@B)
/Adam
Received on Tuesday, 24 April 2012 14:24:10 UTC