- 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