Subject: Re: Unidirectional streams PR

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Fri, 23 Jun 2017 23:00:23 -0700

> I think my and Igor’s e-mails illustrate that path; I can put a PR
together if desired.

I’d like that.

I’m concerned with the complexity of bidi+uni and I am not fond of bidi
alone either. It leaves a lot of room for error related to handling
unexpected transmissions on streams and how and when to open and close
streams. Uni-directional streams avoids these issues.

I also see the value in an API layer implementing a default BIDI layer on
top of uni-directional streams where a stream association is optional so
applications can build on that.

Thus, I would like to see a PR for uni+optional associated streams (option
3). But otherwise I prefer uni only (option 4). While 3) appears useful, an
application may have better context to provide associations, but if it
works out, it would be useful.

Note that bidi streams might offload some work for applications - but
the quic library needs to inform the app of events so an app would have to
handle abnormal cases such as early transmissions on a stream that is
expected to only be replied to after sending data. Therefore it might be
simpler to just manage uni-directional streams with fewer surprises even if
more explicit.

I have a separate use case for very light-weight uni-directional streams -
it’s relevant here to illustrate why you might want very small stream
headers - the point being - stream open and association should not require
a stream frame to be large by default - I don’t propose to include these
details for now, but just for illustration of what can be done:

A messaging application may send thousands upwards to 1 million messages
per second (if stream ID were 64 bit var length). Each packet might contain
30 messages of 50 bytes each without stream offset but with FIN bit and
clearly uni-directional. The stream ID can be delta encoded relative to
previous streams in same packet. If the application embeds an app specific
message receiver, the stream ID becomes a serial number. This effectively
implements partial reliability because a receiver could drop older messages
for the same app ID - e.g. game state or last sensor reading. The stream
length could also be allowed to be just 1 byte. This results in messages
that could have only 3 bytes of framing overhead per message on average:
<type-byte with flags: uni, fin, no-offset>, <var length signed stream ID
byte, delta to first in packet>, <var length packet length>{black box
payload including app specific stream receiver}. Note that 1 million
messages per second is perfectly possible on 10Gpbs but it would run out
of identifiers after 1 hour using 32-bit identifiers.

*From:* Mike Bishop

I think my and Igor’s e-mails illustrate that path; I can put a PR together
if desired.

*From:* Ian Sweet

ekr and I were chatting about the high level design options here.  There
are a lot of specific details to both PRs which may not be ideal, but no
matter what, the HTTP mapping(and future apps) are going to need both
bidirectional and unidirectional streams, so it's just a matter of where
that functionality is defined and implemented.

We came up with 4 options(I'm sure there are sub-options here, but bear
with me):

  1) Do nothing, let the application(ie: HTTP) create unidirectional
streams by closing one half of the bidi stream.

  2) Add unidirectional streams as an option to existing bidirectional
streams. (my PR is a proof of concept of that)

  3) Change the transport text to describe unidirectional streams and add a
mechanism in the transport doc to pair them into bidi streams.

  4) Replace bidirectional streams with unidirectional streams in the
transport doc and make transports implement bidi streams if they need them.
(Martin's PR is an example of this)

---

From: Christian Huitema <[email-masked]>
Date: Sat, 24 Jun 2017 12:15:03 -0700

Nice discussion. Seeing this design by many PR, I am afraid we will meet
an old friend: https://en.wikipedia.org/wiki/Camel.

-- 
Christian Huitema

---

From: Ranjeeth Kumar Dasineni <[email-masked]>
Date: Tue, 27 Jun 2017 14:31:38 -0700

This thread has gone quiet. So, I am voicing my concerns about Martin's
proposal here to reiterate the importance of deployment experience, making
things no simpler than necessary and to generally evoke a sense of urgency.
Personal opinions, of course!!

1. We are the underplaying the importance of deployment experience. I am
afraid that IETF-QUIC, after these changes, diverges quite far from the
deployed G-QUIC. Far enough, to throw serious doubt on all assumptions
about performance and deployability. It becomes effectively a brand new
protocol designed not based on running code but what seems to be an obvious
simplification of one layer, at the cost of complexity at another layer.
Leaving the benefits of simplification aside, I am wary of standardizing
things that have not been deployed anywhere. H2 push and priorities should
serve as a lesson here where one could clearly articulate the benefits when
designing them and yet it was extremely hard to realize those benefits in
practice. Here, I have a hard time even articulating the benefits of a
simple transport layer, speaking of which ...

2. We are overplaying the simplicity of design. Even if we deem deployment
experience not a concern, if every application layer protocol that needs
support for bidirectional streams has to implement some correlators and
such above, that's a net negative in terms of complexity. Arguably, it's
far simpler for an application to simulate/enforce unidirectionality when
it needs. Not to mention there does not seem a deployed application or an
immediate candidate that needs it. H2 Push is a special pony which is yet
to be deployed widely and something that I would treat as an exception, not
norm. Even with H2, where implementation of application level correlators
seems simple enough, it raises the questions on ease of deployment (if
proxies will get this right), debuggability (examining a single request +
response is now harder) and the impact of bug (more prone to sending
critical data to the wrong destination). The demonstrated success of G-QUIC
and the first likely role for IETF-QUIC is as an approximately drop-in
replacement for H2. I would like the focus to be on succeeding there first
before attempting to build an overly generic transport protocol. Which
leads me to ...

3. QUIC is not the last transport that will be built. Not to speak of
future versions of QUIC itself. Part of the allure of moving transport to
user space, to me, is the ability to iterate faster. The success of H2 and
the wide interest in QUIC convinces me that protocols will evolve at a much
faster rate going forward. And that there will be enough time and
opportunities to experiment as more applications use QUIC and evolve a
different set of needs. Such experiments and implementation experience
should drive the changes, I believe. Having said that, some ideas in the PR
(like the explicit type field in stream header and the push id) are not
really tied to unidirectionality and I would like to see them absorbed into
IETF-QUIC anyway.

This is my first mail to the working group. My biggest motivation was to
reiterate on the sense of urgency. Pardon me if I flouted any rules in the
process.

Cheers,
Ranjeeth

---

From: Dmitri Tikhonov <[email-masked]>
Date: Wed, 28 Jun 2017 08:42:21 -0400

On Tue, Jun 27, 2017 at 02:31:38PM -0700, Ranjeeth Kumar Dasineni wrote:
> such above, that's a net negative in terms of complexity.

This is an important point: we want QUIC adoption to be made easy.
A program that speaks HTTP today should be able to use an existing QUIC
library without having to emulate bidirectional streams in order to fit
it into HTTP usage pattern.  Forcing every one of these programs to do
this is certainly a hurdle.

  - Dmitri.

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Wed, 28 Jun 2017 09:41:34 -0400

In reply to Ranjeeth

It is not only a matter of simplicity for the sake of simplicity:

- A complex transport layer might end up being poorly implemented leading
to reduced interoperability and ultimately adoption. This complexity is not
only in implementation but also in understanding the exact semantics of
stream lifetime. Even if the spec is sufficiently clear, it will still be
open to misinterpretations.

- Bi-directional state may have to be maintained longer and with more
overhead than with uni-directional streams, especially under loss,
potentially leading to poor performance and poor resource utilisation
because the transport layer has insufficient information.

- The extra complexity at the application layer may be overstated - it is
significantly simpler to manage a map that associates to two streams than
it is to maintain bi-directional state at the transport layer. It is even
possible to implicitly link streams with same identifiers, e.g. in a RPC
scenario. That said, I do see a potential benefit of a wrapper that
implements the common bi-directional case.

- Complexity at the application layer may be duplicated, but implementation
errors are also isolated to that application. Specifically for HTTP I would
assume that QUIC transport and QUIC HTTP implementers would be large the
same for a long time to come, so I would not expect the tradeoff here to be
particularly concerning.

- Unix pipes are traditionally constructed as a pair of uni-directional
file descriptors and that is a reasonably proven model. C’s standard
library stdin, stdout and stderr is an example of an asymmetric model with
implicit linkage between uni-directional file descriptors.

- There are lots of use cases for non-HTTP like connectivity - Kafka high
volume message queuing for example. The industry trend appears to move
towards asynchronous processing and messaging. It depends on whether you
look at QUIC as a TCP + TLS replacement, or as a HTTPS / REST RPC
replacement.

- Uni-directional streams may currently be unproven in the wild, but a
proposal is needed before an implementation can be made and testet. I agree
that it is easy to design into wrong assumptions without real world testing.

- There will hopefully not be a large number of successors to QUIC -
perhaps some purpose specific variants, e.g. for embedded use. Widespread
adaptation and compatibility is very necessary so it makes sense to have
QUIC being sufficiently simple and expressive to achieve this goal. A
polymorf QUIC will not achieve that goal. On the other hand, a solid QUIC
foundation can be used for a large number of application protocols.

- Finally, it may turn out that uni-directional streams just is a bad idea
- I doubt it, but I do believe real world tests are needed.

Kind Regards,
Mikkel Fahnøe Jørgensen

On 28 June 2017 at 14.42.36, Dmitri Tikhonov ([email-masked])
wrote:

- Dmitri.

---

From: Jo Kulik <[email-masked]>
Date: Wed, 28 Jun 2017 10:09:00 -0400

I'd like to pop back up to a comment Igor made last week, because I find it
helpful in thinking about the design space:

I think of three layers of abstraction:
>
> 1.       QUIC Wire Protocol (the thing described by the QUIC Transport
> RFC)
> 2.       QUIC Library API (a library exposing some useful abstractions --
> such as blocking/non-blocking unidirectional streams and bidirectional
> “sockets” -- and implementing them using QUIC Wire Protocol)
> 3.       Application (something that uses QUIC Library APIs)

I think there is some argument to be made that Martin's original proposal
did not take into account how we would achieve (2) for bi-directional
streams.  (I don't think it strictly said "thou shalt not do (2)" either,
but that is up to interpretation.)

Several people have argued that we do not want every application to have to
re-implement bi-directional streams (3) for every application, and this is
not how g-quic (our largest deployment) works right now.  These arguments
make sense to me, but YMMV.

Just because the particular *mechanism* that is being proposed has some
issues, however, doesn't scream out to me, at least, that we should abandon
this particular *design goal*.  The goal being a transport protocol that
can elegantly fit with a uni/bi stream model.  Now, if we conclude that
there can never be an elegant model that achieves this goal, then so be
it.  But I also feel like we haven't reached that point in the discussion
yet.  (At the very least, this discussion has been fruitful to me in terms
of mapping the design space and elucidating requirements).

One of the reasons I still think this design goal is under consideration is
that Ian and Igor/Mike have been talking about alternate solutions which
have a similar flavor.  During the recent "quiet"ness on the thread,
personally, I've been waiting to hear more from them.

On Wed, Jun 28, 2017 at 9:41 AM, Mikkel Fahnøe Jørgensen <[email-masked]

> - Complexity at the application layer may be duplicated, but
> implementation errors are also isolated to that application. Specifically
> for HTTP I would assume that QUIC transport and QUIC HTTP implementers
> would be large the same for a long time to come, so I would not expect the
> tradeoff here to be particularly concerning.
>

---

From: "Swindells, Thomas (Nokia - GB/Cambridge, UK)" <[email-masked]>
Date: Wed, 28 Jun 2017 14:56:17 +0000

I agree that looking at the layers of abstraction is useful. In principle having the wire protocol just have constructs for unidirectional streams does not in itself limit creating bi-directional communication flows, supported at either the library or application layer.

However, there need to be a standard way of doing bi-directional communication for migrating applications implemented using a socket style api. It needs to be easy to move an existing application from TCP to QUIC. This move may be attractive in many situations as QUIC gives improved security and may allow greater throughput due to the more modern (and customizable) congestion control algorithms compared to the OS TCP stack.

For migrating standard socket api applications I don’t think it would be appropriate to leave the work to the application to do correlation, at least the library should be providing this service using the wire protocol as appropriate. Clearly we want a client written with one library to be able to communicate successfully with a server written using a different library. This needs some form of standardization of the signalling. This could either be a building block overlay on top of QUIC, or implemented at the wire protocol level.

In terms of patterns I think the following may be some of the most common patterns (with potential to be provided at the library and or wire protocol level).
I/O pattern  : Example
1/0   : An input only flow, perhaps a data logger like syslog with no confirmation/feedback
0/1  : an output only flow, perhaps a topic message bus service with no confirmation/feedback
1/1 : standard TCP applications with a single flow per connection
1/* : single input, many output, modelling STDIN/STDOUT+STDERR
(1/1)* : multiplexed pairs of flows – supporting multiple sockets muxed onto a single QUIC connection

Obviously, an application would always have the option to combine any single direction flows with application level correlators to construct more complex flows if desired.

At the moment my gut says the 1/1 use-case is common enough that the wire protocol should provide a standard mechanism to support it as a standard overlay would probably end up being treated as part of the wire format anyway.

Perhaps streams should be explicitly created with a CREATE_STREAM frame which would be capable of defining multiple related streams?
There is the option of whether only (1/1) pairs can be created this way, or (1/n) combinations could be supported (with an application defined way to identify the use of each of the output streams). A step further may be that there is a transport parameter that defines whether the server is allowed to create additional streams, or if stream creation is purely client driven (like TCP). I don’t know if either of these would simplify how to handle stream accounting, and in particular only creating a flow when all parties have sufficient allowances left.

Thomas

From: QUIC [mailto:[email-masked]] On Behalf Of Jo Kulik
Sent: 28 June 2017 15:09
To: Mikkel Fahnøe Jørgensen <[email-masked]>
Cc: QUIC WG <[email-masked]>; Dmitri Tikhonov <[email-masked]>
Subject: Re: Unidirectional streams PR

I'd like to pop back up to a comment Igor made last week, because I find it helpful in thinking about the design space:

1.       QUIC Wire Protocol (the thing described by the QUIC Transport RFC)
2.       QUIC Library API (a library exposing some useful abstractions -- such as blocking/non-blocking unidirectional streams and bidirectional “sockets” -- and implementing them using QUIC Wire Protocol)
3.       Application (something that uses QUIC Library APIs)
I think there is some argument to be made that Martin's original proposal did not take into account how we would achieve (2) for bi-directional streams.  (I don't think it strictly said "thou shalt not do (2)" either, but that is up to interpretation.)

Several people have argued that we do not want every application to have to re-implement bi-directional streams (3) for every application, and this is not how g-quic (our largest deployment) works right now.  These arguments make sense to me, but YMMV.

Just because the particular *mechanism* that is being proposed has some issues, however, doesn't scream out to me, at least, that we should abandon this particular *design goal*.  The goal being a transport protocol that can elegantly fit with a uni/bi stream model.  Now, if we conclude that there can never be an elegant model that achieves this goal, then so be it.  But I also feel like we haven't reached that point in the discussion yet.  (At the very least, this discussion has been fruitful to me in terms of mapping the design space and elucidating requirements).

One of the reasons I still think this design goal is under consideration is that Ian and Igor/Mike have been talking about alternate solutions which have a similar flavor.  During the recent "quiet"ness on the thread, personally, I've been waiting to hear more from them.

On Wed, Jun 28, 2017 at 9:41 AM, Mikkel Fahnøe Jørgensen <[email-masked]<mailto:[email-masked]>> wrote:
In reply to Ranjeeth

- A complex transport layer might end up being poorly implemented leading to reduced interoperability and ultimately adoption. This complexity is not only in implementation but also in understanding the exact semantics of stream lifetime. Even if the spec is sufficiently clear, it will still be open to misinterpretations.

- Bi-directional state may have to be maintained longer and with more overhead than with uni-directional streams, especially under loss, potentially leading to poor performance and poor resource utilisation because the transport layer has insufficient information.

- The extra complexity at the application layer may be overstated - it is significantly simpler to manage a map that associates to two streams than it is to maintain bi-directional state at the transport layer. It is even possible to implicitly link streams with same identifiers, e.g. in a RPC scenario. That said, I do see a potential benefit of a wrapper that implements the common bi-directional case.

- Complexity at the application layer may be duplicated, but implementation errors are also isolated to that application. Specifically for HTTP I would assume that QUIC transport and QUIC HTTP implementers would be large the same for a long time to come, so I would not expect the tradeoff here to be particularly concerning.

- Unix pipes are traditionally constructed as a pair of uni-directional file descriptors and that is a reasonably proven model. C’s standard library stdin, stdout and stderr is an example of an asymmetric model with implicit linkage between uni-directional file descriptors.

- There are lots of use cases for non-HTTP like connectivity - Kafka high volume message queuing for example. The industry trend appears to move towards asynchronous processing and messaging. It depends on whether you look at QUIC as a TCP + TLS replacement, or as a HTTPS / REST RPC replacement.

- Uni-directional streams may currently be unproven in the wild, but a proposal is needed before an implementation can be made and testet. I agree that it is easy to design into wrong assumptions without real world testing.

- There will hopefully not be a large number of successors to QUIC - perhaps some purpose specific variants, e.g. for embedded use. Widespread adaptation and compatibility is very necessary so it makes sense to have QUIC being sufficiently simple and expressive to achieve this goal. A polymorf QUIC will not achieve that goal. On the other hand, a solid QUIC foundation can be used for a large number of application protocols.

- Finally, it may turn out that uni-directional streams just is a bad idea - I doubt it, but I do believe real world tests are needed.

Kind Regards,
Mikkel Fahnøe Jørgensen

On 28 June 2017 at 14.42.36, Dmitri Tikhonov ([email-masked]<mailto:[email-masked]>) wrote:

- Dmitri.

---

From: Mike Bishop <[email-masked]>
Date: Wed, 28 Jun 2017 22:26:37 +0000

As promised, a PR for adding “associated streams” is at https://github.com/quicwg/base-drafts/pull/672.  This very deliberately builds on top of MT’s PR – it’s adding a primitive which can be used to construct various abstractions atop unidirectional streams, but the lifecycle is still fundamentally unidirectional.

Copying my notes here for list discussion purposes.
Major changes
Leveraging @igorlord<https://github.com/igorlord>'s insight that OO=00 only occurs on the first STREAM frame of a stream, I used that as the trigger for a Stream Properties byte. Two bits of that byte describe the directionality of the stream:

  *   Unidirectional (no response expected)
  *   Initial bidirectional (one response expected)
  *   Initial multi-response (one or more responses expected; needs a better name)
  *   Response
If the type is Response, there's an Associated Stream ID field, length given by two more bits following the same pattern as the SS bits in the STREAM frame ID.
Personal Opinion
On the plus side, these stream types seem to cover the abstractions I can envision for most applications. You can unilaterally send something (unidirectional), do request/response (bidirectional), or pub/sub (single subscription stream, series of update streams).
I don't care for the fact that I still need the stream type header in HTTP after putting this in the transport. That will be ameliorated if we go back to one stream per request, since all unidirectional streams will be push streams. (As a side-note, I considered using the multiple-response option in the HTTP mapping, but then I need a stream header again to indicate which is the response and which the pushes.)
I particularly don't like that you now have to look at the frame type header to find out whether a field exists which tells you the length of something else in the header. I'd like to simplify that. I went with this model over a CREATE_STREAM frame because of @mikkelfj<https://github.com/mikkelfj>'s use-case of very small messages -- this adds only one byte to the first frame on a stream in one direction and 2-5 bytes to the first frame of response streams. A separate frame type would be somewhat larger, but could be cleaner in that respect.

From: QUIC [mailto:[email-masked]] On Behalf Of Swindells, Thomas (Nokia - GB/Cambridge, UK)
Sent: Wednesday, June 28, 2017 7:56 AM
To: Jo Kulik <[email-masked]>; Mikkel Fahnøe Jørgensen <[email-masked]>
Cc: QUIC WG <[email-masked]>; Dmitri Tikhonov <[email-masked]>
Subject: RE: Unidirectional streams PR

Thomas

From: QUIC [mailto:[email-masked]] On Behalf Of Jo Kulik
Sent: 28 June 2017 15:09
To: Mikkel Fahnøe Jørgensen <[email-masked]<mailto:[email-masked]>>
Cc: QUIC WG <[email-masked]<mailto:[email-masked]>>; Dmitri Tikhonov <[email-masked]<mailto:[email-masked]>>
Subject: Re: Unidirectional streams PR

Kind Regards,
Mikkel Fahnøe Jørgensen

- Dmitri.

---

From: Martin Thomson <[email-masked]>
Date: Wed, 28 Jun 2017 16:28:28 -0700

There is probably a simpler approach here, take a bit (as Ian did) and
say that if that bit is set, then the stream is in response to another
and the stream ID of the stream to which this is responding follows
immediately after the stream ID of the stream itself.  You could then
include that only at the start of the stream, or in multiple frames
(or as we decide).

The problem with this, as with several of the other issues we're
discussing, is that unless what the transport provides is a perfect
fit for application semantics, you end up building those semantics
into the application anyway.  HTTP certainly can't survive without its
own association semantics for pushes.  That suggests to me that having
bidirectional semantics in the transport creates more duplication than
otherwise.  Hence my proposal.

On 28 June 2017 at 15:26, Mike Bishop <[email-masked]> wrote:
> As promised, a PR for adding “associated streams” is at
> https://github.com/quicwg/base-drafts/pull/672.  This very deliberately
> builds on top of MT’s PR – it’s adding a primitive which can be used to
> construct various abstractions atop unidirectional streams, but the
> lifecycle is still fundamentally unidirectional.
>
>
>
> Leveraging @igorlord's insight that OO=00 only occurs on the first STREAM
> frame of a stream, I used that as the trigger for a Stream Properties byte.
> Two bits of that byte describe the directionality of the stream:
>
> Unidirectional (no response expected)
> Initial bidirectional (one response expected)
> Initial multi-response (one or more responses expected; needs a better name)
> Response
>
> If the type is Response, there's an Associated Stream ID field, length given
> by two more bits following the same pattern as the SS bits in the STREAM
> frame ID.
>
> Personal Opinion
>
> On the plus side, these stream types seem to cover the abstractions I can
> envision for most applications. You can unilaterally send something
> (unidirectional), do request/response (bidirectional), or pub/sub (single
> subscription stream, series of update streams).
>
> I don't care for the fact that I still need the stream type header in HTTP
> after putting this in the transport. That will be ameliorated if we go back
> to one stream per request, since all unidirectional streams will be push
> streams. (As a side-note, I considered using the multiple-response option in
> the HTTP mapping, but then I need a stream header again to indicate which is
> the response and which the pushes.)
>
> I particularly don't like that you now have to look at the frame type header
> to find out whether a field exists which tells you the length of something
> else in the header. I'd like to simplify that. I went with this model over a
> CREATE_STREAM frame because of @mikkelfj's use-case of very small messages
> -- this adds only one byte to the first frame on a stream in one direction
> and 2-5 bytes to the first frame of response streams. A separate frame type
> would be somewhat larger, but could be cleaner in that respect.
>
>
>
>
>
> I agree that looking at the layers of abstraction is useful. In principle
> having the wire protocol just have constructs for unidirectional streams
> does not in itself limit creating bi-directional communication flows,
> supported at either the library or application layer.
>
>
>
> However, there need to be a standard way of doing bi-directional
> communication for migrating applications implemented using a socket style
> api. It needs to be easy to move an existing application from TCP to QUIC.
> This move may be attractive in many situations as QUIC gives improved
> security and may allow greater throughput due to the more modern (and
> customizable) congestion control algorithms compared to the OS TCP stack.
>
>
>
> For migrating standard socket api applications I don’t think it would be
> appropriate to leave the work to the application to do correlation, at least
> the library should be providing this service using the wire protocol as
> appropriate. Clearly we want a client written with one library to be able to
> communicate successfully with a server written using a different library.
> This needs some form of standardization of the signalling. This could either
> be a building block overlay on top of QUIC, or implemented at the wire
> protocol level.
>
>
>
> In terms of patterns I think the following may be some of the most common
> patterns (with potential to be provided at the library and or wire protocol
> level).
>
> I/O pattern  : Example
>
> Obviously, an application would always have the option to combine any single
> direction flows with application level correlators to construct more complex
> flows if desired.
>
>
>
> At the moment my gut says the 1/1 use-case is common enough that the wire
> protocol should provide a standard mechanism to support it as a standard
> overlay would probably end up being treated as part of the wire format
> anyway.
>
>
>
> Perhaps streams should be explicitly created with a CREATE_STREAM frame
> which would be capable of defining multiple related streams?
>
> There is the option of whether only (1/1) pairs can be created this way, or
> (1/n) combinations could be supported (with an application defined way to
> identify the use of each of the output streams). A step further may be that
> there is a transport parameter that defines whether the server is allowed to
> create additional streams, or if stream creation is purely client driven
> (like TCP). I don’t know if either of these would simplify how to handle
> stream accounting, and in particular only creating a flow when all parties
> have sufficient allowances left.
>
>
>
> Thomas
>
>
>
> this particular *design goal*.  The goal being a transport protocol that can
> elegantly fit with a uni/bi stream model.  Now, if we conclude that there
> can never be an elegant model that achieves this goal, then so be it.  But I
> also feel like we haven't reached that point in the discussion yet.  (At the
> very least, this discussion has been fruitful to me in terms of mapping the
> design space and elucidating requirements).
>
>
>
> On Wed, Jun 28, 2017 at 9:41 AM, Mikkel Fahnøe Jørgensen
> <[email-masked]> wrote:
>
> In reply to Ranjeeth
>
>
>
> - A complex transport layer might end up being poorly implemented leading to
> reduced interoperability and ultimately adoption. This complexity is not
> significantly simpler to manage a map that associates to two streams than it
> is to maintain bi-directional state at the transport layer. It is even
> - Unix pipes are traditionally constructed as a pair of uni-directional file
> descriptors and that is a reasonably proven model. C’s standard library
> stdin, stdout and stderr is an example of an asymmetric model with implicit
> linkage between uni-directional file descriptors.
>
>
>
> - There will hopefully not be a large number of successors to QUIC - perhaps
> some purpose specific variants, e.g. for embedded use. Widespread adaptation
> and compatibility is very necessary so it makes sense to have QUIC being
> sufficiently simple and expressive to achieve this goal. A polymorf QUIC
> will not achieve that goal. On the other hand, a solid QUIC foundation can
> be used for a large number of application protocols.
>
>
>
> - Finally, it may turn out that uni-directional streams just is a bad idea -
> I doubt it, but I do believe real world tests are needed.
>
>
>
> Kind Regards,
>
> Mikkel Fahnøe Jørgensen
>
>
>

---

From: "Lubashev, Igor" <[email-masked]>
Date: Thu, 29 Jun 2017 00:14:32 +0000

> unless what the transport provides is a perfect fit for application semantics, you end up building those semantics into the application anyway.

I agree with this. We should avoid adding complexity into transport for rare use cases, since it goes against KISS principle.

On the other hand, adding support for a by far the most common use case makes a lot of sense.  This helps apps avoid screwing up implementing that common case and lets us optimize that common case in the lower layer. BiDi streams are such common cases. Uni streams are likely to be the second-most-common cases (hence you offered this PR to optimize them).

The Associated Streams proposal offers extra semantic flexibility at a cost of some semantic complexity (someone would need to verify that the associated stream numbers make sense -- api? apps?) and a few extra bytes.

I'd like to wait to see Ian's revised proposal.  The initial proposal offered to do only one thing -- offer a choice of uni/bi-directional streams -- but it did it in a very simple way, which is nice.

- Igor

-----Original Message-----
From: Martin Thomson [mailto:[email-masked]] 
Sent: Wednesday, June 28, 2017 7:28 PM
To: Mike Bishop <[email-masked]>
Cc: Swindells, Thomas (Nokia - GB/Cambridge, UK) <[email-masked]>; QUIC WG <[email-masked]>; Mikkel Fahnøe Jørgensen <[email-masked]>; Dmitri Tikhonov <[email-masked]>; Jo Kulik <[email-masked]>
Subject: Re: Unidirectional streams PR

There is probably a simpler approach here, take a bit (as Ian did) and say that if that bit is set, then the stream is in response to another and the stream ID of the stream to which this is responding follows immediately after the stream ID of the stream itself.  You could then include that only at the start of the stream, or in multiple frames (or as we decide).

The problem with this, as with several of the other issues we're discussing, is that unless what the transport provides is a perfect fit for application semantics, you end up building those semantics into the application anyway.  HTTP certainly can't survive without its own association semantics for pushes.  That suggests to me that having bidirectional semantics in the transport creates more duplication than otherwise.  Hence my proposal.

On 28 June 2017 at 15:26, Mike Bishop <[email-masked]> wrote:
> https://github.com/quicwg/base-drafts/pull/672.  This very 
> deliberately builds on top of MT’s PR – it’s adding a primitive which 
> can be used to construct various abstractions atop unidirectional 
> streams, but the lifecycle is still fundamentally unidirectional.
>
>
>
> Leveraging @igorlord's insight that OO=00 only occurs on the first 
> STREAM frame of a stream, I used that as the trigger for a Stream Properties byte.
> Initial bidirectional (one response expected) Initial multi-response 
> (one or more responses expected; needs a better name) Response
>
> If the type is Response, there's an Associated Stream ID field, length 
> given by two more bits following the same pattern as the SS bits in 
> the STREAM frame ID.
>
> Personal Opinion
>
> On the plus side, these stream types seem to cover the abstractions I 
> can envision for most applications. You can unilaterally send 
> something (unidirectional), do request/response (bidirectional), or 
> pub/sub (single subscription stream, series of update streams).
>
> I don't care for the fact that I still need the stream type header in 
> HTTP after putting this in the transport. That will be ameliorated if 
> we go back to one stream per request, since all unidirectional streams 
> will be push streams. (As a side-note, I considered using the 
> multiple-response option in the HTTP mapping, but then I need a stream 
> header again to indicate which is the response and which the pushes.)
>
> I particularly don't like that you now have to look at the frame type 
> header to find out whether a field exists which tells you the length 
> of something else in the header. I'd like to simplify that. I went 
> with this model over a CREATE_STREAM frame because of @mikkelfj's 
> use-case of very small messages
> -- this adds only one byte to the first frame on a stream in one 
> direction and 2-5 bytes to the first frame of response streams. A 
> separate frame type would be somewhat larger, but could be cleaner in that respect.
>
>
>
>
>
> I agree that looking at the layers of abstraction is useful. In 
> principle having the wire protocol just have constructs for 
> unidirectional streams does not in itself limit creating 
> bi-directional communication flows, supported at either the library or application layer.
>
>
>
> communication for migrating applications implemented using a socket 
> style api. It needs to be easy to move an existing application from TCP to QUIC.
> For migrating standard socket api applications I don’t think it would 
> be appropriate to leave the work to the application to do correlation, 
> at least the library should be providing this service using the wire 
> protocol as appropriate. Clearly we want a client written with one 
> library to be able to communicate successfully with a server written using a different library.
> This needs some form of standardization of the signalling. This could 
> either be a building block overlay on top of QUIC, or implemented at 
> the wire protocol level.
>
>
>
> In terms of patterns I think the following may be some of the most 
> common patterns (with potential to be provided at the library and or 
> wire protocol level).
>
> I/O pattern  : Example
>
> Obviously, an application would always have the option to combine any 
> single direction flows with application level correlators to construct 
> more complex flows if desired.
>
>
>
> At the moment my gut says the 1/1 use-case is common enough that the 
> wire protocol should provide a standard mechanism to support it as a 
> standard overlay would probably end up being treated as part of the 
> wire format anyway.
>
>
>
> Perhaps streams should be explicitly created with a CREATE_STREAM 
> frame which would be capable of defining multiple related streams?
>
> (1/n) combinations could be supported (with an application defined way 
> to identify the use of each of the output streams). A step further may 
> be that there is a transport parameter that defines whether the server 
> is allowed to create additional streams, or if stream creation is 
> purely client driven (like TCP). I don’t know if either of these would 
> simplify how to handle stream accounting, and in particular only 
> creating a flow when all parties have sufficient allowances left.
>
>
>
> Thomas
>
>
>
> I'd like to pop back up to a comment Igor made last week, because I 
> find it helpful in thinking about the design space:
>
>
>
> I think there is some argument to be made that Martin's original 
> proposal did not take into account how we would achieve (2) for 
> bi-directional streams.  (I don't think it strictly said "thou shalt 
> not do (2)" either, but that is up to interpretation.)
>
>
>
> Several people have argued that we do not want every application to 
> have to re-implement bi-directional streams (3) for every application, 
> and this is not how g-quic (our largest deployment) works right now.  
> These arguments make sense to me, but YMMV.
>
>
>
> Just because the particular *mechanism* that is being proposed has 
> some issues, however, doesn't scream out to me, at least, that we 
> should abandon this particular *design goal*.  The goal being a 
> transport protocol that can elegantly fit with a uni/bi stream model.  
> Now, if we conclude that there can never be an elegant model that 
> achieves this goal, then so be it.  But I also feel like we haven't 
> reached that point in the discussion yet.  (At the very least, this 
> discussion has been fruitful to me in terms of mapping the design space and elucidating requirements).
>
>
>
> One of the reasons I still think this design goal is under 
> consideration is that Ian and Igor/Mike have been talking about 
> alternate solutions which have a similar flavor.  During the recent 
> "quiet"ness on the thread, personally, I've been waiting to hear more from them.
>
>
>
> - A complex transport layer might end up being poorly implemented 
> leading to reduced interoperability and ultimately adoption. This 
> complexity is not only in implementation but also in understanding the 
> exact semantics of stream lifetime. Even if the spec is sufficiently 
> clear, it will still be open to misinterpretations.
>
>
>
> - The extra complexity at the application layer may be overstated - it 
> is significantly simpler to manage a map that associates to two 
> streams than it is to maintain bi-directional state at the transport 
> layer. It is even possible to implicitly link streams with same 
> identifiers, e.g. in a RPC scenario. That said, I do see a potential 
> benefit of a wrapper that implements the common bi-directional case.
>
>
>
> implementation errors are also isolated to that application. 
> Specifically for HTTP I would assume that QUIC transport and QUIC HTTP 
> implementers would be large the same for a long time to come, so I 
> would not expect the tradeoff here to be particularly concerning.
>
>
>
> - Unix pipes are traditionally constructed as a pair of 
> uni-directional file descriptors and that is a reasonably proven 
> model. C’s standard library stdin, stdout and stderr is an example of 
> an asymmetric model with implicit linkage between uni-directional file descriptors.
>
>
>
> - There are lots of use cases for non-HTTP like connectivity - Kafka 
> high volume message queuing for example. The industry trend appears to 
> move towards asynchronous processing and messaging. It depends on 
> whether you look at QUIC as a TCP + TLS replacement, or as a HTTPS / 
> REST RPC replacement.
>
>
>
> proposal is needed before an implementation can be made and testet. I 
> agree that it is easy to design into wrong assumptions without real world testing.
>
>
>
> perhaps some purpose specific variants, e.g. for embedded use. 
> Widespread adaptation and compatibility is very necessary so it makes 
> sense to have QUIC being sufficiently simple and expressive to achieve 
> this goal. A polymorf QUIC will not achieve that goal. On the other 
> hand, a solid QUIC foundation can be used for a large number of application protocols.
>
>
>
> - Finally, it may turn out that uni-directional streams just is a bad 
> idea - I doubt it, but I do believe real world tests are needed.
>
>
>
> Kind Regards,
>
> Mikkel Fahnøe Jørgensen
>
>
>
>> 2. We are overplaying the simplicity of design. Even if we deem 
>> deployment experience not a concern, if every application layer 
>> protocol that needs support for bidirectional streams has to 
>> implement some correlators and such above, that's a net negative in terms of complexity.
>
> A program that speaks HTTP today should be able to use an existing 
> QUIC library without having to emulate bidirectional streams in order 
> to fit it into HTTP usage pattern. Forcing every one of these programs 
> to do this is certainly a hurdle.
>
> - Dmitri.
>
>

---

From: Ian Swett <[email-masked]>
Date: Wed, 28 Jun 2017 21:23:13 -0400

I updated my PR(#656 <https://github.com/quicwg/base-drafts/pull/656>)
today, sorry for the delay.  I attempted to address the issues identified
with text.  Some may prefer more tweaks to the state diagram, which are
also possible, so I'm open to suggestions.

In the meantime, I've been considering other alternatives, including
variations on Mike's direction and a variation of the "Do Nothing" option
which involved the application signaling to the transport that streams of a
certain sort(ie: server to client for server push) were unidirectional, as
GQUIC does today.  Overall, I think the approach I've outlined does a good
job of iterating on existing deployment experience and adding explicit
signaling for unidirectional streams instead of implicit signaling at the
application layer.  There are pros and cons to both explicit and implicit
signaling, but I think explicit signaling is more complete and less prone
to application error.

Thanks, Ian

On Wed, Jun 28, 2017 at 8:14 PM, Lubashev, Igor <[email-masked]> wrote:

> > unless what the transport provides is a perfect fit for application
> semantics, you end up building those semantics into the application anyway.
>
> I agree with this. We should avoid adding complexity into transport for
> rare use cases, since it goes against KISS principle.
>
> On the other hand, adding support for a by far the most common use case
> makes a lot of sense.  This helps apps avoid screwing up implementing that
> common case and lets us optimize that common case in the lower layer. BiDi
> streams are such common cases. Uni streams are likely to be the
> second-most-common cases (hence you offered this PR to optimize them).
>
>
> The Associated Streams proposal offers extra semantic flexibility at a
> cost of some semantic complexity (someone would need to verify that the
> associated stream numbers make sense -- api? apps?) and a few extra bytes.
>
> I'd like to wait to see Ian's revised proposal.  The initial proposal
> offered to do only one thing -- offer a choice of uni/bi-directional
> streams -- but it did it in a very simple way, which is nice.
>
> - Igor
>
>
> Cc: Swindells, Thomas (Nokia - GB/Cambridge, UK) <
> [email-masked]>; QUIC WG <[email-masked]>; Mikkel Fahnøe
> Jørgensen <[email-masked]>; Dmitri Tikhonov <
> [email-masked]>; Jo Kulik <[email-masked]>
> There is probably a simpler approach here, take a bit (as Ian did) and say
> that if that bit is set, then the stream is in response to another and the
> stream ID of the stream to which this is responding follows immediately
> after the stream ID of the stream itself.  You could then include that only
> at the start of the stream, or in multiple frames (or as we decide).
>
> discussing, is that unless what the transport provides is a perfect fit for
> application semantics, you end up building those semantics into the
> application anyway.  HTTP certainly can't survive without its own
> association semantics for pushes.  That suggests to me that having

---

From: Christian Huitema <[email-masked]>
Date: Thu, 29 Jun 2017 09:34:58 -0700

On 6/28/2017 6:23 PM, Ian Swett wrote:

> today, sorry for the delay.  I attempted to address the issues
> identified with text.  Some may prefer more tweaks to the state
> diagram, which are also possible, so I'm open to suggestions.
>
> variations on Mike's direction and a variation of the "Do Nothing"
> option which involved the application signaling to the transport that
> streams of a certain sort(ie: server to client for server push) were
> unidirectional, as GQUIC does today.  Overall, I think the approach
> I've outlined does a good job of iterating on existing deployment
> experience and adding explicit signaling for unidirectional streams
> instead of implicit signaling at the application layer.  There are
> pros and cons to both explicit and implicit signaling, but I think
> explicit signaling is more complete and less prone to application error.
>

I understand how to handle concurrent stream limits with plain
bidirectional streams or with plain unidirectional streams, but things
are not so clear when we start mixing models by adding a unidirectional
option to bidirectional or vice versa. In the clean models, we can count
the number of streams initiated by one entity and not yet closed. But in
the mixed models, what do we count, exactly?

For example, let's suppose that in an unidirectional stream model, the
client creates a stream that also "implies" a stream creation in the
other direction. Does this implied stream count against the server limit
or the client limit?

Or vice versa. Suppose that in a bidirectional stream model the client
creates a stream that is declared as actually unidirectional. And
suppose that this stream is immediately closed -- a stream frame with
both the FIN bit and the PR 656 UNI bit set. This stream counts against
the client's number of concurrent streams, but it is immediately closed
by both parties. Does it count as zero?
-- 

Christian Huitema

---

From: Mike Bishop <[email-masked]>
Date: Thu, 29 Jun 2017 16:57:27 +0000

Moot point – there is no concurrent stream limit in the protocol.  There is only a maximum stream ID, and how your implementation decides what maximum stream ID to issue to the peer allows you to choose any resolution to these questions you like.

Now, in the unidirectional or mixed designs, you do have the corner case where a client can send a request, but not give the server enough Stream IDs to respond.  (Don’t do that.)  More realistically, the server can have a limited number of Stream IDs and spend them on pushes instead of actual responses.

From: QUIC [mailto:[email-masked]] On Behalf Of Christian Huitema
Sent: Thursday, June 29, 2017 9:35 AM
To: [email-masked]
Subject: Re: Unidirectional streams PR

On 6/28/2017 6:23 PM, Ian Swett wrote:
I updated my PR(#656<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fquicwg%2Fbase-drafts%2Fpull%2F656&data=02%7C01%7Cmichael.bishop%40microsoft.com%7C50b7c91a6bf441d6674d08d4bf0cd498%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636343509210959657&sdata=zdHHgc1IfzdwEWFQCPIk%2B7iufCR1jzJ9eHtqXx9Bak0%3D&reserved=0>) today, sorry for the delay.  I attempted to address the issues identified with text.  Some may prefer more tweaks to the state diagram, which are also possible, so I'm open to suggestions.

In the meantime, I've been considering other alternatives, including variations on Mike's direction and a variation of the "Do Nothing" option which involved the application signaling to the transport that streams of a certain sort(ie: server to client for server push) were unidirectional, as GQUIC does today.  Overall, I think the approach I've outlined does a good job of iterating on existing deployment experience and adding explicit signaling for unidirectional streams instead of implicit signaling at the application layer.  There are pros and cons to both explicit and implicit signaling, but I think explicit signaling is more complete and less prone to application error.

I understand how to handle concurrent stream limits with plain bidirectional streams or with plain unidirectional streams, but things are not so clear when we start mixing models by adding a unidirectional option to bidirectional or vice versa. In the clean models, we can count the number of streams initiated by one entity and not yet closed. But in the mixed models, what do we count, exactly?

For example, let's suppose that in an unidirectional stream model, the client creates a stream that also "implies" a stream creation in the other direction. Does this implied stream count against the server limit or the client limit?

Or vice versa. Suppose that in a bidirectional stream model the client creates a stream that is declared as actually unidirectional. And suppose that this stream is immediately closed -- a stream frame with both the FIN bit and the PR 656 UNI bit set. This stream counts against the client's number of concurrent streams, but it is immediately closed by both parties. Does it count as zero?
--

Christian Huitema

---

From: Christian Huitema <[email-masked]>
Date: Thu, 29 Jun 2017 11:40:36 -0700

On 6/29/2017 9:57 AM, Mike Bishop wrote:
>
> Moot point – there is no concurrent stream limit in the protocol. 
> There is only a maximum stream ID, and how your implementation decides
> what maximum stream ID to issue to the peer allows you to choose any
> resolution to these questions you like.
>
OK, my bad.

> Now, in the unidirectional or mixed designs, you do have the corner
> case where a client can send a request, but not give the server enough
> Stream IDs to respond.  (Don’t do that.)  More realistically, the
> server can have a limited number of Stream IDs and spend them on
> pushes instead of actual responses
>

I am looking at the "mixed" scenario, in which the client would open an
unidirectional stream with an associated "stream N" in the other
direction. Will we say that doing so automatically pushes the server's
maximum stream ID to some value greater than N?

-- 
Christian Huitema

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Thu, 29 Jun 2017 15:02:09 -0400

On 29 June 2017 at 20.40.50, Christian Huitema ([email-masked]) wrote:

I am looking at the "mixed" scenario, in which the client would open an
unidirectional stream with an associated "stream N" in the other direction.
Will we say that doing so automatically pushes the server's maximum stream
ID to some value greater than N?

I believe the streams need to operate independently: having endpoint A open
a unidirectional stream A/N that can be responded to by endpoint B
necessarily requires that B has granted A a limit of at least the value
A/N. If the stream A/N permits association by one or more streams B/M
initiated by B, each of those streams necessarily must be at or below the
limit granted by A but only once those streams are in fact opened. Endpoint
A might never grant sufficient streams to enable B to respond. The
identifiers B/M chosen by B are unknown to A.

Note that there is a problem with enforcing how many streams that can be
associated with A/N because A/N might be closed and gone. Keeping state is
problematic. On the other hand it is trivial to reject associations with
streams that have not yet been opened, especially if streams are opened in
strict order. Implicit opening of lower valued streams will not work, and
is not needed.

---

From: Subodh Iyengar <[email-masked]>
Date: Fri, 30 Jun 2017 23:14:02 +0000

I've read through both approaches and commented on both PR with concrete issues. I would like to voice some high level thoughts as well.

I believe the purpose of the unidirectional streams exercise is two-fold: maybe reduce complexity of transport, enable applications to have easier mappings.

I have implemented the stream state machine specified in the current draft and I have to stress this very much that no matter what state diagram we specify in the draft, the implementation of the state machine will not match 1:1, there are always hidden states. One such concrete example is when you reset a stream you might want to discard any incoming data vs if you're in half closed you would want to process and buffer it. This creates a new hidden state which is not captured in the state machine.

To me personally, the initial draw for pure unidirectionality (@Martin's proposal) was to reduce the number of states in the transport to make the transport easier to implement and not so much the easier mappings of applications. We're chartered to work on HTTP/2 first and that's my primary interest as well. It seems though that in HTTP/2 the vast majority of transactions are actually bidirectional, and it only needs unidirectional support for pushes. I think unidirectional streams doesn't add new functionality to HTTP/2.

However after looking at the proposals and the feedback, as a transport implementor I'm rethinking my initial draw towards purely unidirectional streams such that I might as well take up the burden to implement bi-directionality once so that the apps can be simpler.

That being said we need some concept of unidirectionality in the transport to support the push use case for HTTP/2. It is kind of awkward right now that we need to send a FIN from the client to close a push stream.

I'm not in favor of #656 because it adds more complexity to the state machine, however I'm more of a fan of @Ian's do nothing + app dictates a manual transition, since that allows us to keep the same state machine flow and let the app get undirectionality by explicitly having the app transition the stream state machine as needed. There are some cool things in @Martin's proposal that I would actually like to see back in the HTTP mapping with bidi streams like stream headers for pushed streams, however I'd rather prefer the do nothing + manually transition states with application coordination.

Subodh
________________________________
From: QUIC <[email-masked]> on behalf of Mikkel Fahnøe Jørgensen <[email-masked]>
Sent: Thursday, June 29, 2017 12:02:09 PM
To: [email-masked]; Christian Huitema; Mike Bishop
Subject: Re: Unidirectional streams PR

On 29 June 2017 at 20.40.50, Christian Huitema ([email-masked]<mailto:[email-masked]>) wrote:

I am looking at the "mixed" scenario, in which the client would open an unidirectional stream with an associated "stream N" in the other direction. Will we say that doing so automatically pushes the server's maximum stream ID to some value greater than N?

I believe the streams need to operate independently: having endpoint A open a unidirectional stream A/N that can be responded to by endpoint B necessarily requires that B has granted A a limit of at least the value A/N. If the stream A/N permits association by one or more streams B/M initiated by B, each of those streams necessarily must be at or below the limit granted by A but only once those streams are in fact opened. Endpoint A might never grant sufficient streams to enable B to respond. The identifiers B/M chosen by B are unknown to A.

Note that there is a problem with enforcing how many streams that can be associated with A/N because A/N might be closed and gone. Keeping state is problematic. On the other hand it is trivial to reject associations with streams that have not yet been opened, especially if streams are opened in strict order. Implicit opening of lower valued streams will not work, and is not needed.

---

From: "Lubashev, Igor" <[email-masked]>
Date: Fri, 30 Jun 2017 23:54:43 +0000

I am worried about silent (app-directed) stream closing. This it a layering violation, since it introduces transport-layer semantics (stream state transition) that are not signaled on the wire.

Such silent stream closing would make it hard (impossible?) to write a generic QUIC proxy, for example. A generic proxy must be able to know when a stream is closed, so it can release resources. In fact, the proxy would provide a better experience, if it could also know stream priorities and other possible stream attributes explicitly.

 (The proxy may be a good idea, if you have limited devices attached to your low latency/high quality network, which is connected to the rest of the Net over high latency/low quality links. You’d deploy such a proxy, so it can maintain deep buffers, needed for communication over high latency/low quality links.)

As for Ian's Uni-bit proposal, the state machine is no more complicated than in the original spec. (You would probably want to add a Uni bit to RST_STREAM frame to keep stream directionality unambiguous at all times.)

- Igor

-----Original Message-----
From: Subodh Iyengar [[email-masked]]
Received: Friday, 30 Jun 2017, 7:14PM
To: Mikkel Fahnøe Jørgensen [[email-masked]]; [email-masked] [[email-masked]]; Christian Huitema [[email-masked]]; Mike Bishop [[email-masked]]
Subject: Re: Unidirectional streams PR

Subodh

---

From: Subodh Iyengar <[email-masked]>
Date: Sat, 1 Jul 2017 00:08:27 +0000

> I am worried about silent (app-directed) stream closing. This it a layering violation, since it introduces transport-layer semantics (stream state transition) that are not signaled on the wire.

Why is it a layer violation, apps change state of the transport all the time :) The way it would happen is that the transport would expose an API like closeWithoutFin() and close() which basically decide whether or not a stream is unidirectional.

app directed closing doesn't prevent a generic quic proxy from sending a FIN if it wants. The FIN will be completely consistent with the state machine. I see app directed closing as more of an optimization to not sending some extra bytes when not needed.

> As for Ian's Uni-bit proposal, the state machine is no more complicated than in the original spec. (You would probably want to add a Uni bit to RST_STREAM frame to keep stream directionality unambi…

See my comments on the PR. I suggested the same RST uni bit as well as there is another state transition that is missing as well, so I think it's definitely a change. Plus it makes it such that we cannot open lower streams which I think is undesirable.

Subodh

________________________________
From: Lubashev, Igor <[email-masked]>
Sent: Friday, June 30, 2017 4:54:43 PM
To: [email-masked]; [email-masked]; [email-masked]; Subodh Iyengar; [email-masked]
Subject: RE: Unidirectional streams PR

- Igor

-----Original Message-----
From: Subodh Iyengar [[email-masked]]
Received: Friday, 30 Jun 2017, 7:14PM
To: Mikkel Fahnøe Jørgensen [[email-masked]]; [email-masked] [[email-masked]]; Christian Huitema [[email-masked]]; Mike Bishop [[email-masked]]
Subject: Re: Unidirectional streams PR

Subodh

---

From: "Lubashev, Igor" <[email-masked]>
Date: Sat, 1 Jul 2017 00:39:50 +0000

> Why is it a layer violation, apps change state of the transport all the time

The key is the lack of explicit on-the-wire signaling of stream state transition. Without such a signal, a generic proxy that is not aware of your application internals is not able to know when to send the FIN (and get rid of its state). It has to keep the stream half-closed, ready for an endpoint to start sending data over that stream at any moment, till the end of the connection.

> PR

Thanks. I will take a look. (Three places for discussions: the list, issues, PRs...)

-----Original Message-----
From: Subodh Iyengar [[email-masked]]
Received: Friday, 30 Jun 2017, 8:08PM
To: Lubashev, Igor [[email-masked]]; [email-masked] [[email-masked]]; [email-masked] [[email-masked]]; [email-masked] [[email-masked]]; [email-masked] [[email-masked]]
Subject: Re: Unidirectional streams PR

Subodh

- Igor

-----Original Message-----
From: Subodh Iyengar [[email-masked]]
Received: Friday, 30 Jun 2017, 7:14PM
To: Mikkel Fahnøe Jørgensen [[email-masked]]; [email-masked] [[email-masked]]; Christian Huitema [[email-masked]]; Mike Bishop [[email-masked]]
Subject: Re: Unidirectional streams PR

Subodh