The BXXP Framework
Finally, we get to the money shot: here's what we did.
We defined an application protocol framework called BXXP (the Blocks eXtensible eXchange Protocol). The reason it's a "framework" instead of an application protocol is that we provide all the mechanisms discussed earlier without actually specifying the kind of messages that get exchanged. So, when someone else needs an application protocol that requires connection-oriented, asynchronous request-response interactions, they can start with BXXP. It's then their responsibility to define the last 10% of the application protocol, the part that does, as we say, "the useful work".
So, what does BXXP look like?
Framing looks a lot like SMTP or HTTP: there's a command line that identifies the beginning of the frame, then there's a MIME object (headers and body). Unlike SMTP, BXXP uses octet-counting, but unlike HTTP, the command line is where you find the size of the payload.
Actually, the command line for BXXP has a lot of information, it tells you:
- whether this frame contains a request or response;
- whether there's more to the message than just what's in this frame (a continuation flag);
- how to distinguish the message contained in this frame from other messages (a serial number);
- where the payload occurs in the sliding window (a sequence number) and how many octets are in the payload of this frame; and,
- which part of the system should get the message (for requests) or whether this is a positive or negative response.
(The command line is textual and ends in a CR-LF pair, and the arguments are separated by a space.)
Since you need to know all this stuff to process a frame, we put it all in one easy to parse location. You could probably devise a more efficient encoding, but the command line is a very small part of the frame, so you wouldn't get much bounce from optimizing it. Further, because framing is at the heart of BXXP, the frame format has some self-consistency checks that catch the majority of programming errors.
Another trick is in the headers: because the command line contains all the framing information, the headers may contain minimal MIME information (such as Content-Type). Usually, however, the headers are empty. That's because the BXXP default payload is XML . (Actually, a "Content-Type: text/xml" with 8-bit encoding).
We chose XML as the default because it provides a simple mechanism for nested, textual representations. (Alas, the 822-style encoding doesn't easily support nesting.) By design, XML's nature isn't optimized for compact representations. That's okay because we're focusing on loosely-coupled systems and besides there are efficient XML parsers available.
We use 3-digit error codes.
In addition, the response message to a request is flagged as either positive or negative. This makes it easy to signal success or failure and allow the receiving peer some freedom in the amount of parsing it wants to do on failure.
Despite the lessons of SMTP and HTTP, there isn't a lot of field experience to rely on when designing the multiplexing features of BXXP. Here's what we did: frames are exchanged in the context of a "channel". Each channel has an associated "profile" that defines the syntax and semantics of the messages exchanged over a channel.
Channels provide both an extensibility mechanism for BXXP and the basis for multiplexing. Remember the last parameter in the command line of a BXXP frame? The "part of the system" that gets the message is identified by a channel number.
A profile is defined according to a "Profile Registration" template. The template defines how the profile is identified (using an XML DTD), what kind of messages get exchanged during channel creation, what kind of messages get sent in requests and responses, along with the syntax and semantics of those messages. When you create a channel, you identify a profile and provide some arguments. If the channel is successfully created, you get back a positive response; otherwise, you get back a negative response explaining why.
Perhaps the easiest way to see how channels provide an extensibility mechanism is to consider what happens when a connection is established. The BXXP peer that accepted the connection sends a greeting on channel zero identifying the profiles that it supports. (Channel 0 is used for channel management -- it's automatically created when a connection is opened.) If you want transport security, the very first thing you do is to create a channel that negotiates transport security, and, once the channel is created, you tell it to do its thing. Next, if you want to authenticate, you create a channel that performs user authentication, and, once the channel is created, you tell it to get busy. At this point, you create one or more channels for data exchange. This process is called "tuning"; once you've tuned the connection, you start using the data exchange channels to do "the useful work".
The first channel that's successfully started has a trick associated with it: when you ask to start the channel, you're allowed to specify a "service name" that goes with it. This allows a server with multiple configurations to select one based on the client's suggestion. (A useful analogy is HTTP 1.1's "Host:" header.) If the server accepts the "service name", then this configuration is used for the rest of the connection.
To allow parallelism, BXXP allows you to use multiple channels simultaneously. Each channel processes requests serially, but there are no constraints on the processing order for different channels. So, in a multi-threaded implementation, each channel maps to its own thread.
This is the most general case, of course. For one reason or another, an implementor may not be able to support this. So, BXXP allows for both positive and negative responses when a request is made. So, if you want the classic client-server model, the client program should simply reject any requests made by the server. This effectively throttles any asynchronous messages from the server.
Of course, we now need to provide a flow control mechanism and segmentation. For the former, we just took the mechanism used by TCP (sequence numbers and a sliding window) and used that. It's proven, and can be trivially implemented by a minimal implementation of BXXP. For the latter, we just put a "continuation" or "more to come" flag in the command line for the frame.
We use SASL. If you successfully authenticate using a channel, then there is a single user identity for each peer on that connection (i.e., authentication is per-connection, not per-channel). This design decision mandates that each connection correspond to a single user regardless of how many channels are open on that connection. One reason why this is important is that it allows service provisioning, such as quality of service (e.g., as in ) to be done on a per-user granularity.
We defined BXXP profiles for the most commonly used SASL mechanisms: OTP and Anonymous.
We use TLS. If you successfully complete a TLS negotiation using a channel, then all traffic on that connection is secured (i.e., confidentiality is per-connection, not per-channel, just like authentication).
We defined a BXXP profile that's used to start the TLS engine.
We purposefully excluded two things that are common to most application protocols: naming and authorization.
Naming was excluded from the framework because, outside of URIs , there isn't a commonly accepted framework for naming things. To our view, this remains a domain-specific problem for each application protocol. So, when an application protocol designer defines their own profile to do "the useful work", they'll have to deal with naming issues themselves. BXXP provides a mechanism for identifying profiles and binding them to channels. It's up to you to define the profile and use the channel.
Similarly, authorization was explicitly excluded from the framework. Every approach to authorization we've seen uses names to identify principals (i.e., targets and subjects), so if your framework doesn't include naming, it can't very well include authorization.
Of course, application protocols do have to deal with naming and authorization -- those are two of the issues addressed by the applications protocol designer when defining a profile for use with BXXP.
Next » Current Status
Copyright © 1999, 2000 media.org.