![]() | Documentation - Protocol Design |
Now that you've seen the high-level
picture, you are ready to understand how the system magically builds
protocol trees. The algorithm we use will pick (usually) the fastest
possible route. It supports building any protocol on top of any other
protocol as long as the capabilities of the underlying channel are correct.
Before you get hit with the entire design document, it is good to
understand some basic terms specific to Chorus.
A Channel is an object which can transfer or receive raw
chunks of binary data. A tcp stream, a udp association, an email inbox, a
modem, and a tunneled http connection through ssh and socks are all
examples of a Channels. All implementations of a Channel are derived from
the
ChannelI class.
Every Channel has Capabilities which describe whether it
is reliable, boundary-preserving, when reads/writes can happen, etc.
These Capabilities take the form of a set of tokens. The tokens are
nominally pointers to strings, but they are distinguished by pointer value
to prevent possible namespace clashes. New Capabilities may be added
as needed to express requirements (more on this later).
The
Capabilities class
should not need to be extended. It is a concrete class.
To establish a Channel, we need an entity which is watching for new
connections and an entity which is interested in connecting. The entities
locate each other via an Address. Unlike addresses that most
programmers are familiar with, our addresses specify a protocol tree. Each
node in the tree contains parameters for that protocol. The (named)
children of the node are used in building underlying mechanisms. The leaves
of the tree's parameters include the more familiar address information.
The
Address class
should not need to be extended. It is a concrete class.
The object which accepts connections is called an Outlet. An
outlet differs from the standard concept of a port (which most programmers
are familiar with) in one critical way: it does not have a permanent
Address. Everytime a person wishes to connect (plug-in) to the Outlet,
they must obtain a fresh Address from the address() method. This method may
perform network related operations. All implementations of an Outlet are
derived from the
OutletI class.
Some times it is necessary to be able to open multiple Channels to an
Outlet via a single Address. This is acheived with a Plug.
When connecting to an Outlet one has two options: create a Plug or create a
Channel. Sometimes an Address is unsuitable for creating a Plug. In this
case you will get a null pointer and you may reuse the address to build a
Channel. If you do get a Plug, you may call it's connect() method to
repeatedly manufacture Channels to the same Outlet. All implementations of
a Plug are derived from the
PlugI class.
An objects which constructs appropriate Channels, Outlets, or Plugs is
called a Protocol. A Protocol need not appear as the protocol
name mentioned in the Address it operates on. For example, an http proxy
would be implemented as HttpProxyProtocol and would match Addresses with
'http/transport/tcp'. When a Protocol is asked to construct an object, it
is given an Address and an AcceptableI callback. If it can construct an
acceptable object, it will try to do so and may throw
Failed exceptions.
If it is unable, it returns a null pointer indicating that the Address was
not consumed and that the Address could not be used to by this Protocol to
produce an acceptable object. All implementations of a Protocol are derived
from the
Protocol class.
Finally, there is a Registry singleton which all Protocols are
registered in and can be used to build an Outlet, Plug, or Channel from an
Address and an AcceptableI callback. It tries all possible combinations of
Protocols and selects the first to connect (for Plugs and Channels) or
combines all possibilities (for Outlets). Protocols generally use the
Registry to construct their subtransports. The high-level interface uses it
to create the underlying mechanism. The
Registry interface
is not to be extended as it represents a singleton.
Now, let's look at the overall picture:
![]() |