[rtcweb] Data Channel Negotiation

Martin Thomson <martin.thomson@gmail.com> Thu, 07 February 2013 11:22 UTC

Return-Path: <martin.thomson@gmail.com>
X-Original-To: rtcweb@ietfa.amsl.com
Delivered-To: rtcweb@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id B488121F85E8 for <rtcweb@ietfa.amsl.com>; Thu, 7 Feb 2013 03:22:33 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -3.1
X-Spam-Level:
X-Spam-Status: No, score=-3.1 tagged_above=-999 required=5 tests=[AWL=-0.500, BAYES_00=-2.599, NO_RELAYS=-0.001]
Received: from mail.ietf.org ([64.170.98.30]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id DUc5BwTiTBkq for <rtcweb@ietfa.amsl.com>; Thu, 7 Feb 2013 03:22:32 -0800 (PST)
Received: from mail-we0-x22e.google.com (mail-we0-x22e.google.com [IPv6:2a00:1450:400c:c03::22e]) by ietfa.amsl.com (Postfix) with ESMTP id 4821E21F85CB for <rtcweb@ietf.org>; Thu, 7 Feb 2013 03:22:31 -0800 (PST)
Received: by mail-we0-f174.google.com with SMTP id r6so1966893wey.33 for <rtcweb@ietf.org>; Thu, 07 Feb 2013 03:22:30 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:x-received:date:message-id:subject:from:to :content-type; bh=MZSrzZHUg151/Xd07il8lWNfvzWfeJ3IM+5tyuGY8fI=; b=LSN/h3ACOZbfzw2VJqQulWzogZFxkPUIE4hXDOOViAOfJTVH2S+KyzZKN651vdWD9q s9T2DiRrKc8T4vLXV0xmKGXVwbCN0vpPn19RIWvvbhD9l90lqWmvqD0+8CHbE1CYnHnw tA2WuixRijA9l/dAmFUtHXYdW9y2SGzaYWGuL32BZJZEAPtClP2lHpqpw4B5SEuryUAv ght82xkP1bnrzlCt5/ZiC69gOItHWWnAMXBhisdMRfaqksm2+qY45kdxOx7VHtFzMu5o iRg06tdx1LuT3QJ9sOPAWnnZGU4DEYWjtBjNJykQRkreqESM0coyvlWFj6Vsq3ynDwaJ ezug==
MIME-Version: 1.0
X-Received: by 10.180.90.147 with SMTP id bw19mr10977688wib.28.1360236135701; Thu, 07 Feb 2013 03:22:15 -0800 (PST)
Received: by 10.194.5.135 with HTTP; Thu, 7 Feb 2013 03:22:15 -0800 (PST)
Date: Thu, 07 Feb 2013 06:22:15 -0500
Message-ID: <CABkgnnWUpMSBLioSD2+p82vGszX9R0Q4WFfME5j-DuK+B7KVJw@mail.gmail.com>
From: Martin Thomson <martin.thomson@gmail.com>
To: "rtcweb@ietf.org" <rtcweb@ietf.org>, Randell Jesup <randell-ietf@jesup.org>
Content-Type: text/plain; charset="UTF-8"
Subject: [rtcweb] Data Channel Negotiation
X-BeenThere: rtcweb@ietf.org
X-Mailman-Version: 2.1.12
Precedence: list
List-Id: Real-Time Communication in WEB-browsers working group list <rtcweb.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/rtcweb>, <mailto:rtcweb-request@ietf.org?subject=unsubscribe>
List-Archive: <http://www.ietf.org/mail-archive/web/rtcweb>
List-Post: <mailto:rtcweb@ietf.org>
List-Help: <mailto:rtcweb-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/rtcweb>, <mailto:rtcweb-request@ietf.org?subject=subscribe>
X-List-Received-Date: Thu, 07 Feb 2013 11:22:35 -0000

We're a fickle lot.  It seems that decisions can be unmade very easily.

In any case, I promised a concrete proposal.  Here it is.  Beware:
long post ahead.

This proposal is progressive, I think that the best option would be to
take all of it, but we could choose to not adopt the later parts.
I'll start with the basics.

==Layer 1

Negotiate all new data channels with SDP offer/answer.

As I understand it, the 1.5 round trip cost for in-band channel
creation was to prevent glare.  (Randell hinted that there might have
been something else that was SCTP-specific, but this appears to reduce
to a straightforward glare situation.)  Doing the negotiation in SDP
lets us use the glare mitigation mechanisms we have built into SDP, so
we save 0.5 round trips for every new channel.

This allows us to ditch the in-band signaling protocol almost entirely
(see Option B below).

Creating a new data channel triggers the onnegotiationneeded event.

==Layer 2

Zero round trip channel establishment

The only reason that we have for negotiation of each channel is to
provide a consistent set of characteristics for each channel.  The
peer that creates a channel decides the values for label,
retransmission count (0, n, infinite), and subprotocol.  If you don't
care about these values being consistent between peers, or you have
another means of ensuring consistency, you don't need to negotiate new
channels at all.

Here, we permit the use of additional channels immediately after
creation, without negotiation.  This has several advantages...and
ramifications.  And no real drawbacks.

Firstly, the arrival of a packet on a stream that is not negotiated
will require the creation of a data channel.  The properties of this
data channel will be largely unknown. The browser can possibly detect
that the channel is unreliable if the packet doesn't request
acknowledgement, but that's something I'm not 100% clear on for
partially reliable messages.  As a result, the browser will be
required to leave these properties undefined or generate default
values for them.

It's perfectly OK to have default or undefined values for label,
reliability and subprotocol as long as you let the application set new
values.  This allows for another advantage: applications can, if they
choose, set the reliability on a per-packet basis, consistent with all
other SCTP APIs, but setting the property before sending each packet.
This keeps the simplicity of the API design, ensures websocket
compatibility for those that need it, but it exposes more SCTP
capabilities to those that desire those features.

This does have consequences for negotiation: Values for label,
reliability and subprotocol need to be declarative in SDP, not
negotiated.  Both peers would be required to signal the values that
they are using for each stream.  This would allow for the fact that
peers could set different values for the same stream number, based on
whatever values are set on their data channel object.  In the general
case, it allows one peer to declare the use of a particular stream and
the other peer to not advertise anything on the matching stream.

This also makes the 'onopen' event useless for all but the first
channel.  It should fire immediately for any channel that is created
when the association is already active.

Receipt of a message on a channel that has not already been created
locally causes the following events, one after the other:
ondatachannel, onopen, onmessage.

In order to maintain the symmetrical usage pattern, and the
websockets-compatible usage pattern, we would then require several
things:
1. The browser MUST, by default, negotiate streams with values that
match any in an offer if it does not already have a data channel for
that stream number.  The browser MUST also create the corresponding
data channels.
2. Applications that require perfect channel symmetry need to
negotiate before using streams.
3. Applications that care about having their use of the API be
interchangeable with websockets need to wait for the 'onopen' event
before sending anything, lest they get errors when switching to
websockets.

On that last point: We could require that channels reject attempts to
send() prior to the onopen event being processed, but that is
unnecessarily mean.  Calling createDataChannel() followed immediately
by send() should be OK as long as the association is active.  Just
because you haven't processed the 'onopen', doesn't mean that you
should be prevented from using a perfectly usable channel.  Of course,
waiting for onopen would be safest in the general case, and many
applications would naturally do this, but I see no reason to constrain
usage patterns unnecessarily.

===Option A

Removing the in-band protocol makes the negotiation of the protocol
that layers on top of SCTP less crucial ... it makes negotiation of
the upper-layer protocol less crucial.  In the WebRTC case, we
probably don't need to negotiate 'webrtc-datachannel', we could even
let the application decide the value for that label.

Personally, I don't think that we need to surface API to enable
changing protocols.  However, it would be completely harmless in this
configuration for an application to change the protocol label to
something else by editing SDP, so that they could interoperate with a
peer that expected another protocol.  That would enable CLUE usage, or
BFCP, or whatever, as long as you can find someone who talks SCTP over
DTLS over UDP.

===Option B

The one remnant of the in-band protocol that remains is the parts that
apply to the data payloads.  The in-band protocol is required to
provide two features:
1. the ability to distinguish between textual data and binary data
2. the ability to send messages of arbitrary length

I am sorely tempted to suggest that the first feature can instead be
part of channel configuration, such that it is negotiated (with a
default of binary).  This would mean that negotiation is needed if you
want to use text and you can't handle the conversion of binary to
text.  (Sadly, this isn't made easy and the top answer at
stackoverflow doesn't work for UTF-8:
http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers)

For the second, draft-jesup-rtcweb-data-protocol indicates that 2Gb is
the limit, but my reading of RFC 4920 indicates that there is no limit
to message size.  I'm far from expert in this area, but is it possible
that this is an implementation limitation rather than a protocol one?
Either way, I'm tempted to suggest that fragmentation can be pushed to
the application.

This would allow for direct access to SCTP, rather than an
encapsulated layer.  This is good for several reasons.  Firstly, we
don't need to specify a protocol at all.  We avoid all the arguments
about what byte goes where.  More importantly, it leaves the SCTP
clean, allowing WebRTC applications to use SCTP without ornamentation.

===Option C

If you care about reconciling the values for label, reliability, and
subprotocol, it might be necessary to surface the values declared by
your peer in the API.  You can get this information from the SDP, but
if you don't like the idea of SDP spelunking you have two choices:
provide an 'on(re)negotiated' event that carries the values declared
by the remote peer; or, provide read-only accessors for these.

I'm not certain that reconciliation of these values is important.
Applications can even build their own mechanisms if it is.  If we must
build more mechanisms, then I tend to favor the 'on(re)negotiated'
event.