Subject: [rtcweb] Data Channels Proposal: Now in Internet Draft Form

From: Martin Thomson <[email-masked]>
Date: Mon, 18 Feb 2013 09:51:39 -0800

I think that we're actually at the point where the involved parties
each understand each other's positions.  Now comes the time to provide
everyone else with a coherent proposal that they can evaluate.

http://tools.ietf.org/html/draft-thomson-rtcweb-data-00

This is intended as an alternative to the mechanisms in
draft-ietf-rtcweb-data-channel.  It is also intended to render
draft-jesup-rtcweb-data-protocol unnecessary.  That is, of course, as
long as it meets with the approval of the working group.

---

From: Randell Jesup <[email-masked]>
Date: Tue, 19 Feb 2013 01:21:18 -0500

> long as it meets with the approval of the working group.

Thanks for suggesting something concrete.  It really helps in helping 
get to the heart of the arguments.  I'd love to see one from the people 
who advocated pure-SDP in the room.  (or even an argument in favor of 
their position).

Ok, differences as I see them from draft-ietf-rtcweb-data-channel/etc, 
and comments:

*tl;dr:***I believe this actually ends up with more total complexity, 
especially in terms of the API presented to users/JS code, with little 
or no practical win in usecases or reduction in total code.   It feels 
at times like it's optimizing for some unspoken legacy SCTP application, 
or that it's a general preference to using it like raw SCTP and all else 
(negotiation, etc) is merely to satisfy (mostly) the W3's requirements.  
("If you care about consistency...")

*1. Requirements:*
Differences:
Your draft attempts to make virtually all feasible SCTP features visible 
to the application.  The current draft does not, and provides a limited 
set of features that are static per-channel.

Comments:
"The ability to use as many SCTP features as possible" - your draft 
certainly attempts to provide that, but that was generally rejected as a 
requirement in the past.  Exposing those features (even if they exist in 
SCTP) has a cost, both in API complexity and in testing. If I make 
per-packet markings visible, I need to build tests for all those fun 
edge cases.  One (of several) arguments was that if you need a different 
set of per-packet features, you can use a channel with different 
characteristics.  The actual use-cases for per-packet marking seem 
unlikely to be widely needed given access to multiple channels.  Another 
was that the more complexity exposed, the more complex the mental model 
and understanding of the underlying network protocol characteristics 
needed by the JS programmer.

If this is to be a requirement, it should be tied to some likely usecase 
we've defined or we expect this to be used for.  Are you adding new 
usecases?  If so, please disclose them, as no existing usecase requires 
what you've added here I believe.

*2. Overview:*
Differences:
Your draft ties Channels in a 1-1 mapping to specific stream numbers 
which are exposed.  The current draft ties them to pairs of streams 
(hidden), which may or may not be identical in number.

Your draft gives 3 ways channels can be created, basically telling it "I 
want you to make an offer including it", "I got an offer including it", 
and by messages "just arriving" on unused channels. The current draft 
(assuming 0 RTT setup) has two ways: createDataChannel() on one end, and 
onDataChannel on the other.

Your draft has ways where race conditions can cause channel creation 
failure, or if the other side rejects, etc.  The current draft only 
really can fail due to the association failing or a failure to increase 
the number of streams.

Comments:
It's a bit misleading to state the properties aren't per-message, since 
later you say you can change them per-message.  This is largely 
therefore an optimization to reduce typing/verbiage.  This does as you 
say enable you to use common code for websockets and this.

There are some significant missing pieces to the SDP negotiation part, 
at least at the W3 layer (which I realize this draft isn't, but we need 
to consider it in our design).  Unlike media, we don't have good ways to 
extract the datachannels offered/etc; the best I can think of would be 
to create all the datachannels offered on setRemoteDescription and fire 
events for them, and in response to the event if you want to reject it 
close() the stream before createAnswer.  But this is tricky, since all 
the onXXXX's are async and so when do you call createAnswer?  This seems 
an unspecified and thorny bit of JS API to define.  Doable, sure, but 
considerable complexity and increased async-ness for minimal gain (IMO).

I seriously dislike "it may fail if the other side used the channel".  
Why create such error paths and ways to break your app when there's no 
need to?  Is this needed for interfacing with some sort of legacy system?

*3. (In)consistent Properties*
Differences:
Your draft allows non-SDP-negotiated channels to have inconsistent 
properties.  The current draft does not.

Comments:
You could say properties are irrelevant since you can change them for 
each message; therefore they only matter if they're set and then the 
channel exposed to code that simply takes the properties for granted.

This means that to emulate a WebSockets channel, you'd need to (likely) 
negotiate it in SDP (especially given the label and protocol fields).

I don't see how apparently raw SS7 intererop is involved here.  Is this 
a new usecase?

How is this better for the application than the current draft (assuming 
0 RTT setup)?

*3.1 Negotiation*
Differences:
In your draft, properties can be offer/answer negotiated.  In the 
current draft, all properties are declarative; there is no negotiation 
over the properties.

Comments:
If you actually want to offer/answer over the properties you need to 
define all the O/A semantics, and then how to surface those to the app.  
This adds a lot of edge and error cases to deal with unless you define 
that no actual negotiation occurs.  You can punt and say all that is the 
apps business, but then you're back a "bad days" case having the app 
parse SDP, etc.

What are we gaining in practice here?  What usecase will use actual 
negotiation here, or is it just a way to implement consistent 
declarative properties?  (And there are still edge/error cases to deal 
with and at least ignore).

The current draft keeps things simple since there's no penalty really 
for setting up a channel you're not interested in - if you don't want 
it, just call "newchannel.close()".

*3.2 Dealing with Mismatched Properties*
Differences:
N/A (in the current draft this can't happen)

Comments:
There's a bunch here to deal with and describe what happens if the app 
uses a stream before or during negotiation/etc.  None of this is 
relevant in the current draft (and the API user doesn't have to 
understand all this).
*
**4. Available Data Channel Properties*
Differences:
Your draft specs a full set of possible SCTP properties and makes all 
but streamId mutable at any time.  The current draft has a much smaller 
set of properties (label, protocol, reliable, ordered, readystate, 
bufferedamount, binarytype). Only binarytype is mutable.  The only ones 
added vs WebSockets are reliable and ordered.

*5. SDP Format*
Differences:
Like what I proposed for the "1.5 RTT init SDP shortcut" in Boston, you 
have to specify each channel and all the properties.  The current draft 
(using the 0-RTT proposal) only needs to specify the protocol and 
protocol-level options like default number of streams.

Comments:
If this is O/A, it has a similar set of issues to m-lines, though they 
can go away since they have a stream number attached.  But you have to 
include all active ones in each O/A exchange.    What happens if you 
mutated the properties on one side in order to do packet-by-packet 
option selection.  Does that mirror into SDP?  Does the other side then 
change?  Since changing them on one side doesn't generate a 
negotiation-needed, if you echo the changes you could get surprised when 
negotiations happen for other reasons.  If it's purely declarative and 
doesn't track changes, it's more doable, but what happens if one side 
removes a channel in the O/A?  And can the answerer in the initial 
exchange add channels?  If so, what does the offerer do; is this real 
negotiation? Does this trigger negotiation-needed?

The current draft's SDP (minus the per-channel stuff not needed with 
0-RTT) is very simple.

Side note: the syntax won't work as the SCTP/DTLS spec allows for 
multiple associations; people like Cullen and others have argued for 
that being allowed for the generic case of SCTP over DTLS (the SCTP SDP 
spec isn't *just* for DataChannels in WebRTC).  But it could be reworked 
into a syntax that would work closer the what I presented.

-- 
Randell Jesup
[email-masked]

---

From: Martin Thomson <[email-masked]>
Date: Tue, 19 Feb 2013 11:43:37 -0800

On 18 February 2013 22:21, Randell Jesup <[email-masked]> wrote:
> especially in terms of the API presented to users/JS code, with little or no
> practical win in usecases or reduction in total code.   It feels at times
> like it's optimizing for some unspoken legacy SCTP application, or that it's
> a general preference to using it like raw SCTP and all else (negotiation,
> etc) is merely to satisfy (mostly) the W3's requirements.  ("If you care
> about consistency...")

I'm sensitive to the (potential) need for CLUE to use these channels.
An in-band protocol makes that difficult.

It does make M3UA implementation possible, as opposed to impossible.
But yes, I'm fairly sure that the set of people who care about that
sort of thing is very small, if not zero.  The legacy cases are for
amusement value only.

> per-packet markings visible, I need to build tests for all those fun edge
> cases.

Like sending packets with different properties?  Doesn't sound
especially hard.  It might even make some test cases easier to write.

Sure, an implementation now likely has to track more state on a
per-message basis, rather than referencing a channel-global, but
that's really very minor.

> *2. Overview:*
> Differences:
> Your draft ties Channels in a 1-1 mapping to specific stream numbers which
> are exposed.  The current draft ties them to pairs of streams (hidden),
> which may or may not be identical in number.

Your draft does expose stream numbers in SDP.  Neither proposal
requires that application be aware of the numbers.

> failure, or if the other side rejects, etc.  The current draft only really
> can fail due to the association failing or a failure to increase the number
> of streams.

That's a false comparison.  Stream adds can always fail in either
proposal - there aren't an unlimited number of streams.  Either could
raise the stream limit.  jesup-rtcweb-data-protocol assumes that this
is always possible, which is not the case.

This proposal doesn't permit rejecting of new channels, so I don't
know how you inferred that.  You can close immediately, which should
suffice.

The real race condition is a glare case where both sides add the
"same" stream. For this proposal, that's based on stream number; for
your proposal, it's based on label.  I didn't see how
jesup-rtcweb-data-protocol proposes to resolve the glare caused when
two open requests pass in flight for the same label, but this proposal
only cares if you are performing offer/answer negotiation and that
glare problem is already solved.

> There are some significant missing pieces to the SDP negotiation part, at
> least at the W3 layer (which I realize this draft isn't, but we need to
> consider it in our design).  Unlike media, we don't have good ways to
> extract the datachannels offered/etc; the best I can think of would be to
> create all the datachannels offered on setRemoteDescription and fire events
> for them, and in response to the event if you want to reject it close() the
> stream before createAnswer.  But this is tricky, since all the onXXXX's are
> async and so when do you call createAnswer?  This seems an unspecified and
> thorny bit of JS API to define.  Doable, sure, but considerable complexity
> and increased async-ness for minimal gain (IMO).

I see, if you wanted to reject a channel, how would you do it?  That's
a problem in either proposal.  This is potentially far worse for your
proposal.  I suspect that the only real option would be to
setRemoteDescription(), which could populate pc.dataChannels[]
immediately (and prior to firing the ondatachannel events).  Then you
could investigate and close in a synchronous fashion.

I always imagined that this would happen for media as well, noting
that streams might be slightly more challenging than something that
has all the properties present in the SDP.

> I seriously dislike "it may fail if the other side used the channel".  Why
> create such error paths and ways to break your app when there's no need to?
> Is this needed for interfacing with some sort of legacy system?

I think that you misread this one.  If I create channel 3 and then try
to create another channel 3, then that should fail.  I assume that you
don't permit two channels with the same label in your proposal either.

> negotiate it in SDP (especially given the label and protocol fields).

It doesn't matter how you create the channel.  You can emulate
WebSockets in a number of ways (I believe that the default values for
channels produce WebSockets-compatible properties.  If you want to
signal "protocol" (label isn't a WebSockets concept), then yes, a
round trip is needed.  You could run an offer/answer round, or your
own application-specific signaling.  That round trip could be after
creating the channel, depending on your application needs.

> I don't see how apparently raw SS7 intererop is involved here.  Is this a
> new usecase?

See above.  These little jokes keep me from going (more) batty.

> How is this better for the application than the current draft (assuming 0
> RTT setup)?

I don't think that the assumption is valid, so I'm not sure the
question is either.

> *3.1 Negotiation*
> Differences:
> In your draft, properties can be offer/answer negotiated.  In the current
> draft, all properties are declarative; there is no negotiation over the
> properties.

You don't have negotiation, sure.  I think that you just have
unresolved glare scenarios.

> Comments:
> If you actually want to offer/answer over the properties you need to define
> all the O/A semantics, and then how to surface those to the app.  This adds
> a lot of edge and error cases to deal with unless you define that no actual
> negotiation occurs.  You can punt and say all that is the apps business, but
> then you're back a "bad days" case having the app parse SDP, etc.

Given that the SDP is declarative, I don't see how this is
substantively different from your proposal.  The 1.5RTT one.

> negotiation here, or is it just a way to implement consistent declarative
> properties?  (And there are still edge/error cases to deal with and at least
> ignore).

In practice, we are providing a service for applications that care
about property consistency.  This says, "Here, you need to do
offer/answer anyway.  As long as you are doing O/A, we can use that to
ensure that your data channels match up nicely."

> The current draft keeps things simple since there's no penalty really for
> setting up a channel you're not interested in - if you don't want it, just
> call "newchannel.close()".

I don't see how that is different, or relevant.

> Your draft specs a full set of possible SCTP properties and makes all but
> streamId mutable at any time.  The current draft has a much smaller set of
> properties (label, protocol, reliable, ordered, readystate, bufferedamount,
> binarytype). Only binarytype is mutable.  The only ones added vs WebSockets
> are reliable and ordered.

... and label.  That's new too.

I'm ok with having less flexibility with respect to reliability.  I
was only being complete for the first pass.

> *5. SDP Format*
> Differences:
> Like what I proposed for the "1.5 RTT init SDP shortcut" in Boston, you have
> to specify each channel and all the properties.  The current draft (using
> the 0-RTT proposal) only needs to specify the protocol and protocol-level
> options like default number of streams.

Yes, that's clearly the biggest difference between this and your 0-RTT
in-band proposal: where these extra bits are passed.

> Comments:
> If this is O/A, it has a similar set of issues to m-lines, though they can
> go away since they have a stream number attached.  But you have to include
> all active ones in each O/A exchange.

That's a good thing.  I believe in clear expressiveness over saving
bytes.  gzip exists so that we don't have to make bad compromises in
these trade-offs.

> What happens if you mutated the
> properties on one side in order to do packet-by-packet option selection.
> Does that mirror into SDP?  Does the other side then change?

Good question.  I didn't put that in the draft in part because it's
API-stuff, in part because I forgot.

The current values for properties should appear in the SDP when it is
generated.  If the answerer doesn't have that channel, it is required
to create one with matching properties.  This is the entirety of the
negotiation that goes on.  If the answer already has a channel, it
doesn't change that local channel properties.  The answer includes the
properties that the answer has for the channel.  The offerer might
learn of channels from an answer, and consequently should pass a new
channel object with matching properties to the app.

> Since changing
> them on one side doesn't generate a negotiation-needed, if you echo the
> changes you could get surprised when negotiations happen for other reasons.

Changing properties doesn't trigger the need for negotiation, sure,
but creating the channel does.  I can't imagine any scenario where the
outcome of changes is surprising.

> If it's purely declarative and doesn't track changes, it's more doable, but
> what happens if one side removes a channel in the O/A?

Removal/rejection was something I didn't add.  On purpose.  Close the
channel if you don't want it.

> And can the answerer
> in the initial exchange add channels?  If so, what does the offerer do; is
> this real negotiation? Does this trigger negotiation-needed?

Yes.  The offerer is expected to create a matching channel and pass it
to the app.

No, this is not "real" negotiation.  That's because negotiation of the
sort that is performed when selecting codecs is not required.

> Side note: the syntax won't work as the SCTP/DTLS spec allows for multiple
> associations; people like Cullen and others have argued for that being
> allowed for the generic case of SCTP over DTLS (the SCTP SDP spec isn't
> *just* for DataChannels in WebRTC).  But it could be reworked into a syntax
> that would work closer the what I presented.

That's unfortunate.  I did make an explicit note about this
assumption.  BTW, my preferred solve is:

a=sctp-port:5000

...with all the negative consequences that implies.

---

From: Michael Tuexen <[email-masked]>
Date: Tue, 19 Feb 2013 22:38:04 +0100

> It does make M3UA implementation possible, as opposed to impossible.
Martin,

I don't understand why you are referring here (and in you ID) to
M3UA being transferred over an RTCWeb Datachannel. Are you envisioning
running an STP in a browser?

Best regards
Michael
> _______________________________________________
> rtcweb mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/rtcweb
>

---

From: Randell Jesup <[email-masked]>
Date: Wed, 20 Feb 2013 00:28:35 -0500

tl;dr: (though this post *is* shorter):

Speaking to a larger point: What use-case(s) or what advantage does this 
get which is not provided by the current draft?  What's the practical 
advantage of changing?  Is the current draft problematic to implement, 
or is the new proposal significantly easier to implement?  (BTW, I'll 
note the current draft does support 0-RTT with no changes).  Can the 
current draft be modified to address these issues?  How much does this 
affect the complexity of the interface and API for JS users?  For 
example, why do you believe there's a need at the application level for 
per-packet mutation of the channel properties, given one has a large 
number of channels available?  What's the use-case?

tl;dr of tl;dr: You're suggesting a change late in the process, please 
give a focused answer to "why?"

Thanks!

> An in-band protocol makes that difficult.

My understanding is that they were interested in using our DataChannels 
protocol.  They can run other protocols on other associations on the 
same DTLS link if they want.  I've heard no indications that the current 
draft would cause a problem for them.

> sort of thing is very small, if not zero.  The legacy cases are for

Ok, good.

> especially hard.  It might even make some test cases easier to write.

The test space is combinatorially larger, since there are issues like 
out-of-order before/after in-order to test, reliable before/after/mixed 
with partial/no reliability, etc.

However, one can ignore this and assume the SCTP stack works, and 
usually you'll be right.

> requires that application be aware of the numbers.

No, the 0-RTT proposal never puts anything in SDP except association 
startup options.  The SDP acceleration isn't needed if 
createDataChannel() is 0-RTT.  That's why 0-RTT is a very simple solution.

> is always possible, which is not the case.

They can fail due to no streams, and if so the onError callback (JS) is 
fired for the channel, and it's moved into the "closed" state. Not a 
problem, and per the quote above "or a failure to increase the number of 
streams".  If that's not in the draft, it will be.

> know how you inferred that.  You can close immediately, which should

Ok, but if it's negotiated in SDP, what if the SDP answer doesn't have 
your channel?  Seems like rejection to me (and an app could edit the SDP 
to do so).

> glare problem is already solved.

Long ago it was agreed on the list to drop label-glare resolution 
entirely.  If both sides create a channel name "foo", then both sides 
have 2 channels named "foo" and it's up to the application to deal with it.

> could investigate and close in a synchronous fashion.

Actually, and I think I mentioned this in the room in Boston and again 
on the list since a couple of times, if you want to reject just call 
close() on the stream after it's created.  From what you say, your 
proposal for SDP is similar: declarative; close() to reject after the 
fact (since close doesn't go through O/A!)  If you use SDP to represent 
channels, you have to handle effective rejection even if it's officially 
declarative.

> don't permit two channels with the same label in your proposal either.

Actually the current draft does allow duplicate names, per above. Read 
section 6; you'll see there's no mention of processing on the labels on 
either side.

-- 
Randell Jesup
[email-masked]