Original text:
should be accessible through a unified set of API calls.  An application should be able to implement logic for its basic use of transport networking (establishing the transport, and sending and <del> receiving content) once, and expect that implementation to continue to function as the transports change. </del>  Any Transport Services API must expose the distilled minimal set of features offered by transport protocols I-D.ietf-taps-minset. using a specific protocol, and not when using others.  For example, if an application is using UDP, it may require control over the checksum or fragmentation behavior for UDP; if it used a protocol to <del> frame its content over a byte stream like TCP, it would not need these options.  In such cases, the API should expose the features in such a way that they take effect when a particular protocol is selected, but do not imply that only that protocol may be used if there are equivalent options. </del>  Other specialized features, however, may be strictly required by an application and thus constrain the set of protocols that can be used. For example, if an application requires encryption of its transport <del> content, only protocol stacks that include some transport security </del>  protocol are eligible to be used.  A Transport Services API must allow applications to define such requirements and constrain the system's options.  Since such options are not part of the core, if it is used to Listen() for incoming connections. Connection: A Connection object represents an active transport <del> protocol instance that can send and/or receive Content between a </del>  Local Endpoint and a Remote Endpoint.  It holds state pertaining to the underlying transport protocol instance and any ongoing data transfer.  This represents, for example, an active connection in a Initiate() is the primary action that an application can take to create a Connection to a remote endpoint, and prepare any required <del> local or remote state to be able to send and/or receive content. </del>  For some protocols, this may initiate a server-to-client style handshake; for other protocols, this may just establish local state; and for peer-to-peer protocols, this may begin the process 4.1.4. <del> Content: A Content object is a unit of data that can be </del>  represented as bytes that can be transferred between two endpoints <del> over a transport connection.  The bytes within a unit of Content are assumed to be ordered within the unit itself.  That is, if an </del>  application does not care about the order in which a peer receives two distinct spans of bytes, those spans of bytes are considered <del> independent units of Content.  Content may or may not be usable if incomplete or corrupted.  Boundaries of Content may or may not be understood or transmitted by transport protocols.  That is, what one application considers to be two units of Content sent on a stream-based transport may be treated as a single unit of Content by the application on the other side. Send() is the action to transmit Content over a Connection to a remote endpoint.  The interface to Send may include options specific to how this Content is to be sent.  Status of the Send operation may be delivered back to the application in an event events. </del>  Receive() is an action that indicates that the application is <del> ready to asynchronously accept Content over a Connection from a Remote Endpoint, while the Content itself will be delivered in an event events.  The interface to Receive may include options specific to the Content that is to be delivered to the application. </del>  4.1.5. Connection Ready: A Connection Ready event signals to an application that a given Connection is ready to send and/or <del> receive Content.  If the Connection relies on handshakes to </del>  establish state between peers, then it is assumed that these steps have been taken. Connection Finished: A Connection Finished event signals to an application that a given Connection is no longer usable for <del> sending or receiving Content.  This should deliver an error to the application that describes the nature of the termination. </del>  Connection Received: A Connection Received event signals to an application that a given Listener has passively received a Connection. <del> Content Received: A Content Received event delivers received content to the application, based on a Receive action.  This may include an error if the Receive action cannot be satisfied due to the Connection being closed. </del>  <del> Content Sent: A Content Sent event notifies the application of the status of its Send action.  This may be an error if the Content cannot be sent, or an indication that Content has been processed </del>  by the protocol stack. Path Properties Changed: A Path Properties Changed event notifies Protocol Instance: A Protocol Instance is a single instance of one protocol, including any state it has necessary to establish <del> connectivity or send and receive content. </del>  Protocol Stack: A Protocol Stack is a set of Protocol Instances (including relevant application, security, transport, or Internet protocols) that are used together to establish connectivity or <del> send and receive content.  A single stack may be simple (a single </del>  transport protocol instance over IP), or complex (multiple application protocol streams going through a single security and transport protocol, over IP; or, a multi-path transport protocol

Reviewer comments:
Option for addressing : replace Content in the architecture with Message (where appropriate); use more general concepts like data in the background/design explanation, use Message in the concepts section, and refer to a Message's content when we need to talk about the bytes specifically in this Message.
I am not hugely sold on the definition of /Content: A Content object/. I struggled in NEAT with the best word, and we eventually decided on /data block/. That's not perfect, but it at least keeps away from the notion of content delivery networks, and various other uses of the word "Content". Can we please reconsider this?
Sure, we can reconsider. Data Block is one option; we could also just do Data, but then the singular chunk is more awkward. Some test phrases: "a given Connection is ready to send and/or receive Content" "a given Connection is ready to send and/or receive Data Blocks" "a given Connection is ready to send and/or receive Data" Yeah, I don't like making this seem like a Content Delivery Network, but when this does get applied to protocols like QUIC and HTTP/2 as a transport, then there are instances in which this is the Content portion of the Header/Content divide. Any other votes from the group?
&lt;whispers> message
I mean, message works nicely—other than the fact that it's a bit awkward when describing incomplete message content.
Hard to come up with a good term for this one. In the test phrases above I think Data works quite well, but I am not sure it will in all situations.
I suggested "data block" or "data", but I really would not have questioned "message".
With our Socket Intents work, we started at "object" and finally came to "message". A message can easily be spread across several PUDs for transmission. If re-assembly fails, we end up with partial messages.
One comment on the relationship between Message and Content: if we do Message as the main architecture concept (which I'm fine with to be clear), I can imagine that implementations or APIs can still refer to the "content of the message" as opposed to metadata about the message—for example, when I receive a UDP packet as a Message, the content is the interior payload of the datagram, but my metadata includes the ECN flags received on the packet. Does that sound good?
Foe me trhat would be fine ((... we could people thinking about the content of messages, or content messages, etc - but at least we don't have "content of content" etc ;-) ))
does this for Architecture; we still need to make this change in API (and make sure it carries forward into Implementation as necessary)
Yes, needed for API as well. I already modified Implementation for this.
NAME as you're updating the API document with Message, make sure to make it clear that a single Send() or Receive() does not need to correspond in all cases to a complete Message, and that the Message's content is passed or delivered, along with an indication of whether this Message is now complete. I'm referencing this in the implementation for TCP and protocols with very long frames, so it needs to be reflected cleanly in the API too.
NAME ACK. Not having to make the distinction was one of the nice things about "Content", but we should be explicit about partials in the API anyway.
my current proposal for -00 is to acknowledge it both on send and receive, and to punt on the details as implementation-specific.
The details of what "complete" means for a Message is certainly implementation-determined; as long as there's a flag in the Send() call, and in the Message Received callback, that's fine.
So did changing the name from Content to Message now change the semantic of things? I thought we were using the AFra-Bytestream concept from minset with the Framer as a convenience, but I do not understand how it maps to the partial messages?
I hope not. I think it's fine (and good!) for the send call to have a flag, and for the receive call to have a flag - so an app CAN be informed about a complete message arriving, when the receiving transport system knows that it is indeed complete. However, the transport system doesn't automatically guarantee to the sender that the receiver will be informed about the end of the message that the sender signifies with the flag. In other words: I had an issue with text in the postsockets document that talked about messages, which indicated a guarantee that these messages will be transferred as such. I don't have an issue with flags in send and receive that MAY work (but are not guaranteed to always work).
The flag for a Message being complete is purely local to an implementation: If you use TCP, or some long frames, you can send Message data and not be complete; and you'll only send a FIN, or whatever end-of-frame marker you have when you send data with the complete flag. If the frame needs length-value, it will wait until you mark complete. If you use UDP, if you don't mark your Message as complete, the implementation would pend up data for the Message and wait til its complete before sending the datagram out.If you use TCP, or some long frames, when you receive, the complete flag indicates whether or not this was a FIN or the end of your frame. Since the Message could be gigabytes long, you can't just wait to deliver all at once sometimes. For UDP, Messages will be complete when received by default, but I can request to only receive two bytes at a time or something, and get delivered little chunks until the datagram is completely read.
But how do I send multiple messages over a TCP connection, this is the part I do not understand also from the implementation draft. I do not know what is underneath, so I send a bunch of messages on a connection and if it is TCP is gets sent as a stream of bytes and if it is SCTP it gets sent as a sequence of messages? Or I am only allowed to send one message over a TCP connection?
You can't send multiple Messages on a TCP stream without using a framing protocol on top of TCP; you can, of course, send multiple pieces of Message content, and mark the final one as the Message being complete. There is only one sensible Message per direction in TCP.
As things are now, the application can't know that there is only TCP, and the transport system doesn't know whether a framing protocol is used. So, when a message is complete, the sender must be allowed to say that it's complete, whenever it wants. As you said this is local, and that shouldn't be a problem. When there is a framing protocol, there is no need for the transport system to convey "end of message" via TCP, so there is no problem if this is ignored. I find the logic of "one message = one TCP connection" disturbing. If I send 50 short messages, do I risk getting connections permanently opened and torn down because my "end of message" becomes a FIN? That doesn't sound like a good idea and it doesn't make much sense to me (e.g., it wrecks congestion control).
No, you should not be sending 50 short messages on a single connection. That would cause a lot of havoc on the connection. This really isn't a problem if we're looking at falling back between equivalent protocols. The protocols that will make sense to an application need to have equivalent contracts if they aren't rewriting any code. So, I can use the same code for TCP or TLS over TCP or a QUIC Stream etc, since those all look the same. But if I'm writing discrete messages that are very short on a connection, I need a protocol that supports that—my use case here is IKE sending short messages either over UDP or over Length-Value frames on TCP (RFC8229). HTTP messages over TLS or QUIC or whatever also are equivalent.
I don't see why 50 short messages on a single connection would cause a problem. It really shouldn't! What if I'm writing a game that only needs one connection and sends many small updates over it? So if you implement IKE over the transport system, IKE is understood (can be parsed) from the receiver side data stream, even if you hand it over as individual data blocks - you don't need to tell the receiver-side IKE instance where its message ends. Where's the problem? I don't understand what this has to do with "end of message = FIN" and why anyone would need that. It doesn't make sense to me and sounds like unnecessary trouble.
50 short messages is fine, if the protocol knows what a message is. And you could have a degenerate "framer" over TCP which doesn't add any bytes to indicate length or framing and just puts the Message content down in bytes—essentially, ignore any completion markers. But it should also be possible to communicate over a stream or long message: "I was writing a long gigabyte message, and now I'm done".
Hm. Sure. And if an app wants to make absolutely sure this "URL gigabyte message, and now I'm done" information reaches the other end, it can always use Close.
Yeah, that works for TCP, but say I have a framing protocol on top of TCP—HTTP for example, and I'm doing pipelining of messages. I can still have mega-byte or giga-byte long messages that I send in multiple chunks on this Connection, and the completion bit tells the protocol when the HTTP request is done, and we need to start the headers for the next one.
Sure! No problem in this case either
... but there is text along these lines that doesn't sound right to me in the implementation draft, section 5.1.1. This: The effect of the application sending a Message is determined by the top-level protocol in the established Protocol Stack. That is, if the top-level protocol provides an abstraction of framed messages over a connection, the application will be able to send multiple Messages on that connection, even if the framing protocol is built on a byte-stream protocol like TCP. URL as if the top-level protocol is inside the transport system and that top-level protocol must provide framed messages, or else multiple messages can not be sent over a byte-stream protocol like TCP. However: it's nice if there is a framing protocol like HTTP or whatever on top of your internal stack, but it should also be possible to send multiple messages just over TCP. This shouldn't be a problem as long as my receiver-side application can detect where messages begin and end.
I think that what you're describing is the "degenerate framing protocol" that I referred to earlier—yes, we can let something just write on the stream, but either: You have actual boundaries that can be detected, in which case we call this a framing protocol (may be very very simple) You don't have any on-the-wire detectable boundaries, in which case you can have a degenerate framer that just lays down the content of the Message without boundaries. You can do this, but it's a bit silly. Or you can just treat the stream as one big message if you want.
When you say "can be detected, in which case we call this a framing protocol", can that be outside the transport system or not? My complaint is about the text sounding as if the framing protocol must be inside the transport system. With what I call an "Application-Framed Bytestream", a sender-side application simply hands over messages, and as long as the receiver-side application (all outside the transport system!) is able to detect them, these messages can go over e.g. SCTP, where they can arrive out-of-order, or TCP, where they will arrive in-order, without requiring any special intervention - it's always the same receive call. You may receive your messages in parts but they are in-order "inside" (of course) and you (the receiver-side app) can detect where they end.
NAME By "can be detected", I meant "is represented in the on-the-wire format such that both the local and remote endpoints are explicitly communicating this message boundary", like HTTP or SCTP. If you just lay the bytes out in TCP without any other encoding, you're doing Message boundaries that only make sense to one end (which can be okay, but is a bit degenerate).
NAME perhaps we're finally on the same page: yes I mean a case where only one end (the sender side) of the transport system knowing about the message boundaries in case of TCP, but the application on top knows the boundaries, on both the sender and receiver side. The point of my presentations and text about the "Application-Framed Bytestream" was that this is enough: you can do everything you want with this, you don't actually need anything else. And it makes ideas like informing the receiver app about partial message reception unnecessary. The idea is that the receiver only accepts data blocks until it sees a message boundary that it knows about - then it has a complete message.
lgtm

Revised text:
should be accessible through a unified set of API calls.  An application should be able to implement logic for its basic use of transport networking (establishing the transport, and sending and  <ins> receiving data) once, and expect that implementation to continue to function as the transports change. </ins> Any Transport Services API must expose the distilled minimal set of features offered by transport protocols I-D.ietf-taps-minset. using a specific protocol, and not when using others.  For example, if an application is using UDP, it may require control over the checksum or fragmentation behavior for UDP; if it used a protocol to  <ins> frame its data over a byte stream like TCP, it would not need these options.  In such cases, the API should expose the features in such a way that they take effect when a particular protocol is selected, but do not imply that only that protocol may be used if there are equivalent options. </ins> Other specialized features, however, may be strictly required by an application and thus constrain the set of protocols that can be used. For example, if an application requires encryption of its transport  <ins> data, only protocol stacks that include some transport security </ins> protocol are eligible to be used.  A Transport Services API must allow applications to define such requirements and constrain the system's options.  Since such options are not part of the core, if it is used to Listen() for incoming connections. Connection: A Connection object represents an active transport  <ins> protocol instance that can send and/or receive Messages between a </ins> Local Endpoint and a Remote Endpoint.  It holds state pertaining to the underlying transport protocol instance and any ongoing data transfer.  This represents, for example, an active connection in a Initiate() is the primary action that an application can take to create a Connection to a remote endpoint, and prepare any required  <ins> local or remote state to be able to send and/or receive Messages. </ins> For some protocols, this may initiate a server-to-client style handshake; for other protocols, this may just establish local state; and for peer-to-peer protocols, this may begin the process 4.1.4.  <ins> Message: A Message object is a unit of data that can be </ins> represented as bytes that can be transferred between two endpoints  <ins> over a transport connection.  The bytes within a Message are assumed to be ordered within the unit itself.  That is, if an </ins> application does not care about the order in which a peer receives two distinct spans of bytes, those spans of bytes are considered  <ins> independent Messages.  Messages may or may not be usable if incomplete or corrupted.  Boundaries of a Message may or may not be understood or transmitted by transport protocols.  That is, what one application considers to be two Messages sent on a stream-based transport may be treated as a single Message by the application on the other side. Send() is the action to transmit a Message or partial Message over a Connection to a Remote Endpoint.  The interface to Send may include options specific to how the Message's content is to be sent.  Status of the Send operation may be delivered back to the application in an event events. </ins> Receive() is an action that indicates that the application is  <ins> ready to asynchronously accept a Message over a Connection from a Remote Endpoint, while the Message content itself will be delivered in an event events.  The interface to Receive may include options specific to the Message that is to be delivered to the application. </ins> 4.1.5. Connection Ready: A Connection Ready event signals to an application that a given Connection is ready to send and/or  <ins> receive Messages.  If the Connection relies on handshakes to </ins> establish state between peers, then it is assumed that these steps have been taken. Connection Finished: A Connection Finished event signals to an application that a given Connection is no longer usable for  <ins> sending or receiving Messages.  This should deliver an error to the application that describes the nature of the termination. </ins> Connection Received: A Connection Received event signals to an application that a given Listener has passively received a Connection.  <ins> Message Received: A Message Received event delivers received Message content to the application, based on a Receive action. This may include an error if the Receive action cannot be satisfied due to the Connection being closed. </ins>  <ins> Message Sent: A Message Sent event notifies the application of the status of its Send action.  This may be an error if the Message cannot be sent, or an indication that Message has been processed </ins> by the protocol stack. Path Properties Changed: A Path Properties Changed event notifies Protocol Instance: A Protocol Instance is a single instance of one protocol, including any state it has necessary to establish  <ins> connectivity or send and receive Messages. </ins> Protocol Stack: A Protocol Stack is a set of Protocol Instances (including relevant application, security, transport, or Internet protocols) that are used together to establish connectivity or  <ins> send and receive Messages.  A single stack may be simple (a single </ins> transport protocol instance over IP), or complex (multiple application protocol streams going through a single security and transport protocol, over IP; or, a multi-path transport protocol