To be an effective platform for performance-sensitive real-time and embedded applications, off-the-shelf CORBA middleware must preserve the communication-layer quality of service (QoS) properties of applications end-to-end. However, the standard CORBA GIOP/IIOP interoperability protocols are not well suited for applications that cannot tolerate the message footprint size, latency, and jitter associated with general-purpose messaging and transport protocols. Fortunately, the CORBA specification defines the notion of "Environmentally-Specific Inter-ORB Protocols" (ESIOPs) that can be used to integrate non-GIOP/IIOP protocols beneath an ORB.
To allow end-users and developers to take advantage of ESIOP capabilities, it is useful for an ORB to support a pluggable protocols framework that allows custom messaging and transport protocols to be configured flexibly and used transparently by applications. This document explains how to develop pluggable protocols using TAO's pluggable protocols framework. Here are some links that describe TAO's pluggable protocols framework, though not how to implement one:
http://www.cs.wustl.edu/~schmidt/PDF/PfHSN.pdf
http://www.cs.wustl.edu/~schmidt/PDF/pluggable_protocols.pdf
There are several basic implementation details that should be followed when implementing pluggable protocols for TAO. This section describes them.
It is possible to implement a pluggable protocol for TAO without using any ACE components, or using existing pluggable protocols as a reference, but that is certainly more difficult than taking advantage of the code reuse offered by using existing ACE and TAO models and implementations.
TAO takes advantage of the many useful encapsulations provided by ACE.
These include ACE's IPC_SAP
classes, Event Handlers
and the operation dispatching features provided by the Reactor
.
However, in order to use these encapsulations some requirements must be
satisfied.
To be able to successfully use the ACE components listed above, the underlying protocol used in the pluggable protocol for TAO should support the following features and characteristics:
HANDLE
).select
system call,
or on Win32 platforms, the WaitForMultipleObjects
call on
the handles that refer to the open sessions/connections. This
ability is required in order to use the ACE_Select_Reactor
or the ACE_WFMO_Reactor
concrete Reactor
implementations.
Some underlying transports do not provide any such ability.
However, it may sometimes be possible to separate data delivery
from notification. For example, TAO's shared memory transport
transports data through shared memory, but since it is not possible
to use select
on shared memory another mechanism must be
used for notification. One way to do this is to use a local IPC
connection strictly for notification purposes. Whenever, data is
sent through shared memory, a byte of data could be written to the
local IPC connection. That local IPC connection would be used to
notify the receiving process that data is available for reading in
shared memory. Since local IPC can be multiplexed using the
select
system call, the ACE_Select_Reactor
can be
used to handle operation dispatching for the shared memory
pluggable protocol.
HANDLE
s to hidden windows or the use of a window message pump
then the underlying pluggable protocol may be difficult or pointless
to implement as a pluggable protocol.One of the easiest ways to implement a pluggable protocol for TAO is to do the following:
IPC_SAP
wrappers around the underlying
protocol implementation. For example, ACE wraps the socket API
to create an ACE_INET_Addr
, ACE_SOCK_Acceptor
,
ACE_SOCK_Connector
and ACE_SOCK_Stream
.
IPC_SAP
wrappers for other implementations, such as OSI
transport protocol layer 4, aka TP4, should be implemented
similarly. A TP4 implementation could have an ACE_TP4_Addr
,
ACE_TP4_Acceptor
, ACE_TP4_Connector
and an
ACE_TP4_Stream
. Any new implementation should retain the
interface provided by the base IPC_SAP
classes in ACE.IPC_SAP
components have been
implemented, creating the necessary TAO pluggable protocol components
should be fairly easy. In fact, much of the code can be ``cut and
pasted'' from existing TAO pluggable protocol implementations.
For example, TAO's UIOP pluggable protocol was, for the most part,
based entirely on the IIOP pluggable protocol code found in TAO's
``tao/IIOP_*'' source files. The only things that had to be
changed for UIOP were the protocol prefix, address format and URL
style IOR format. Each of these pluggable protocol characteristics is
documented later in this documentation.The next section goes into detail about TAO's pluggable protocol framework components and their public interfaces. It is our goal that no changes to ACE or TAO should be necessary to implement a pluggable protocol. Naturally, as with all frameworks, it's only possible to achieve this goal if (1) all possible use-cases are understood in advance or (2) the framework is generalized when confronted with new use-cases that weren't handled before. Therefore, we describe the conditions that must currently hold in order to develop and integrate a pluggable protocol for TAO.
In order for a pluggable protocol to be usable by TAO
without making any modifications to TAO itself,
it must be implemented to provide the functionality dictated by TAO's
pluggable protocols framework interface. This functionality is
implemented within several components, namely the Acceptor
,
Connector
, Connection Handler
, Protocol
Factory
, Profile
and Transport
. This section
describes each of them.
A server can accept connections at one or more endpoints, potentially using the same protocol for all endpoints. The set of protocols that an ORB uses to play the client role need not match the set of protocols used for the server role. Moreover, the ORB can even be a ``pure client,'' i.e., a client that only makes requests, in which case it can use several protocols to make requests, but receive no requests from other clients.
The server must generate an IOR that includes all possible inter-ORB and transport-protocol-specific profiles for which the object can be accessed. As with the client, it should be possible to add new protocols without changing the ORB.
We use the Acceptor pattern [ 1] to accept the connections. As with the Connector pattern, an Acceptor decouples the connection establishment from the processing performed on that connection. However, in the Acceptor pattern, the connection is accepted passively, rather than being initiated actively.
Figure 1 illustrates how TAO's pluggable
protocols framework leverages the design . The concrete ACE
Service Handler
created by the ACE Acceptor
is responsible for implementing
the External Polymorphism pattern [2] and
encapsulating itself behind the Transport
interface
defined in our pluggable protocols framework.
We use the Adapter pattern to leverage the ACE
implementation of the Acceptors. This pattern also permits a seamless
integration with the lower levels of the ORB. In the Acceptor pattern,
the Acceptor
object is a factory that creates Service
Handler
s. Service Handler
s are responsible for performing
I/O with their connected peers. In TAO's pluggable protocol
framework, the Transport
objects are Service Handlers
implemented as abstract classes. This design shields the ORB from
variations in the Acceptor
s, Connector
s, and
Service Handler
s for each particular protocol.
When a connection is established, the concrete Acceptor
creates the appropriate Connection Handler
and IOP objects. The
Connection Handler
also creates a Transport
object that
functions as a bridge. As with the Connector
, the
Acceptor
also acts as a bridge object, hiding the transport- and
strategy-specific details of the acceptor.
TAO's Acceptor
interface, shown below.
All Acceptor
implementations must inherit from the
TAO_Acceptor
abstract base class.
A description of each of the methods that must be implemented follows:
Acceptor
implementation, nothing else is really done in
the constructor. For example, the TAO_IIOP_Acceptor
constructor implementation is:
Note that initializing the TAO_Acceptor
base class with
a tag value is required. Additional information about tags
is available in the tags section
of this document. In this case,
TAO_TAG_IIOP_PROFILE
is defined to be the OMG assigned tag
for the CORBA IIOP protocol. Until a tag that uniquely identifies
the protocol is assigned, a tag value that isn't used by any
other protocol can be used in the meantime.
open
open
method initializes the acceptor, i.e. sets the
protocol version to use (if supported), parses any
protocol-specific options (if any) and creates the endpoint passed
to it.
The address specified by using the
-ORBEndpoint
ORB option is passed directly to this method.
If more than one address is specified within a given
-ORBEndpoint
option then each address is passed one by one
to this method by the pluggable protocols framework. For example,
the following -ORBEndpoint
command line option:
will cause the following open
method invocations to
occur:
Extracting individual addresses from an -ORBEndpoint
option is handled by TAO's pluggable protocols framework. It is
up to the pluggable protocol to handle the address passed to this
method.
open_default
-ORBEndpoint
options such as the following
are used:
In this case, an IIOP endpoint will be created on the local
host. The port will be chosen by the IIOP pluggable protocol.
open_default
will invoked in the following manner:
open_default (orbcore, 0)
close
close
method is self-explanatory. It simply shuts
down any open endpoints, and recovers resources as necessary. This
method is automatically invoked by the pluggable protocols framework
when the ORB associated with that endpoint is shut down.create_mprofile
create_mprofile
method creates a protocol-specific
Profile
object and gives ownership of that profile to the
TAO_MProfile
object, basically a container that holds
multiple profiles, passed to it. The code for this method is
typically ``boilerplate,'' i.e. it can be based almost
entirely on TAO's existing pluggable protocol implementations
of create_profile
. Here is how it is implemented in
TAO's IIOP acceptor:
}
Most of the code that is common to all pluggable protocols will be factored out of this method in the near future.
is_collocated
is_collocated
method checks if the Profile
has the same endpoint as the Acceptor
. Assuming ACE is
used as the underlying layer between the operating system calls and
a pluggable protocol, this code is also ``boilerplate.''
TAO's IIOP implementation does the following:
endpoint_count
endpoint_count
returns the number of endpoints the
Acceptor
is listening on. This is used for determining how
many Profiles
will be generated for this Acceptor
.
Currently, all of TAO's pluggable protocols simply return
1
.When a client references an object, the ORB must obtain the corresponding profile list, which is derived from the IOR and a profile ordering policy, and transparently establish a connection to the server.
There can be one or more combinations of inter-ORB and transport
protocols available in an ORB. For a given profile, the ORB must verify
the presence of the associated IOP and transport protocol, if available.
It must then locate the applicable Connector
and delegate it to
establish the connection.
We use the Connector pattern [1] to actively establish a connection to a remote object. This pattern decouples the connection establishment from the processing performed after the connection is successful.
As before, the Connector Registry
, shown above
in Figure 2, is used to locate the right
Connector
for the current profile. The
actual profile selected for use will depend on the set of Policies active
at the time of connection establishment. However, once a profile is
selected, the connector registry matches the profile type, represented by
a well known tag, with an instance of a concrete Connector
.
Connector
s are adapters for the ACE
implementation of the Connector pattern. Thus, they are typically
lightweight objects that simply delegate to a corresponding ACE
component.
Figure 3 shows the base classes and their relations for IIOP.
This figure shows an explicit co-variance between the Profile
and the Connector
s for each protocol. In general, a
Connector
must downcast the Profile
to its specific
type. This downcast is safe because profile creation is limited to the
Connector
and Acceptor
registries. In both cases, the
profile is created with a matching tag. The tag is used by the Connector
Registry to choose the Connector
that can handle each profile.
As shown in the same figure, the Connector Registry manipulates only
the base classes. Therefore, new protocols can be added without requiring
any modification to the existing pluggable protocols framework. When a
connection is successfully established, the Profile
is passed a
pointer to the particular IOP object and to the Transport
objects that were created.
TAO's Connector
interface, shown below.
All Connector
implementations must inherit from the
TAO_Connector
abstract base class.
A description of each of the methods that must be implemented follows:
Acceptor
constructor, the
TAO_Connector
base class should be initialized with the
tag associated with the pluggable protocol in question. Here is
TAO's IIOP pluggable protocol Connector
constructor:
open
open
method simply opens the underlying connector.
This is typically an ACE_Strategy_Connector
template
instance. For example, TAO's IIOP pluggable protocol uses an
Connector
, this method should also register the
Connection Handler
with an ACE_Reactor
.
close
close
simply closes the underlying Connector
bridge and the concrete Connector
.connect
connect
method actively establishes a connection to
the endpoint encoded within the IOR in use. It should first verify
that the tag contained within Profile
passed to it matches
the tag associated with the pluggable protocol. If the tags do not
match then an attempt use a Profile
for another pluggable
protocol was made.
The Transport
object must also be set in this method.
This is generally done by using the transport
method found
within the Connection Handler
being used.
preconnect
preconnect
method is invoked when the
-ORBPreconnect
ORB option is used. It causes a blocking
connection to be made to the specified address. Multiple
connections can be made to the same endpoint. For example, the
following -ORBPreconnect
option will cause two IIOP
blocking connections to be made to the specified host and port:
Much of the preconnect parsing code in TAO's current
preconnect
implementations will be factored out into a
common method. Pluggable protocols will still be responsible for
parsing addresses, just like the open
method in
Acceptor
s (not Connector
s).
check_prefix
check_prefix
checks that the protocol prefix in a URL
style IOR or preconnect endpoint is valid for use with a given
pluggable protocol. For example, the check_prefix
implementation in TAO's IIOP pluggable protocol looks like the
following:
It checks that the protocol prefix in a URL style IOR (e.g.
corbaloc:iiop:foo.bar.com:1234/...
) or preconnect endpoint
matches the one(s) supported by the IIOP pluggable protocol, in
this case ``iiop
'' and
``iioploc
.'' If no match occurs then return an
error condition (-1
). Note that the protocol prefix
``iiop
'' is only there for backward compatibility.
It may be removed in future TAO releases.
This method is important for TAO's implementation of the CORBA Interoperable Naming Service.
object_key_delimiter
the object key delimiter is `/
.' However, this
character is not suitable for all pluggable protocols, such as
TAO's UIOP pluggable protocol, because addresses within a URL
style IOR may contain that very same character. A typical TAO UIOP
URL style IOR may look something like:
In this case, the object key delimiter is a vertical bar
`|
' because using the same object key delimiter that
IIOP uses `/
' would cause the point where the UIOP
rendezvous point ``/tmp/foobar
'' ends and where
the object key ``some_other_object_key
'' begins to
be ambiguous. For instance, if an IIOP object key delimiter was
used in a UIOP URL style IOR as follows:
it then becomes impossible to tell if the rendezous point is
``/tmp
'' or ``/tmp/foobar
,'' and
similarly for the object key, hence the need for an object key
delimiter other than `/
.'
In general, this method simply returns a static variable in the
associated Profile
that contains the object key delimiter
appropriate for the given pluggable protocol.
create_profile
make_profile
make_profile
is another method that can essentially be
``cut and pasted'' from existing TAO pluggable protocols.
It is simply a Profile
factory. The Profile
it
creates is initialized with an object reference of the form:
or
where ``N.n
'' are the major and minor protocol
versions, respectively, and the `/
' is the
protocol-specific object key delimiter.
TAO Profile
objects encapsulate all of the methods and
members necessary to create and parse a protocol-specific IOR, in
addition to representing object address and location information. TAO
Profile
s are based on CORBA IOR definitions.
All protocol-specific Profile
implementations should inherit
from the TAO_Profile
abstract base class.
Its interface follows. Only the methods that must be implemented are
shown:
TAO's existing pluggable protocols have a static member containing the object key delimiter specific to the given pluggable protocol, in addition to a static protocol prefix accessor method that simply returns a pointer to a static string containing the protocol prefix specific to the pluggable protocol. Note that both of these members will always remain constant so there is no problem in making them static.
Theses static member are:
object_key_delimiter
prefix
The IIOP prefix
method is:
Note that it not strictly necessary to implement equivalent versions of these static members. TAO's implementation just happens to use them. However, pluggable protocol implementations that are based on TAO's pluggable protocols may need them.
Common to all concrete Profile
implementations are a set of
methods that must be implemented. A description of each of these
methods:
Profile
classes. While
pluggable protocols are not strictly required to implement analogs to
all of the constructors in existing TAO pluggable protocols, it is
generally a good idea to do so. All of the constructors should
initialize the TAO_Profile
abstract base class with the tag
associated with the pluggable protocol. The object key should also be
set during Profile
construction.parse_string
parse_string
initialize a Profile
object using
the provided string. The string passed to this method has the
format:
or
where the address
and the object key delimiter
`/
' are pluggable protocol specific. The
parse_string
method must be able to extract the protocol
version (even if it isn't used), the address and the object key
from the provided string. It is generally a good idea to use the
parse_string
methods in TAO's existing pluggable
protocols as a reference when implementing this method.
to_string
Profile
object. Most of this
code is also ``boilerplate.'' However, the address part of
the URL style IOR, returned by this method should be specific to
the pluggable protocol. For example, the address in the following
IIOP URL style IOR:
is ``foo.bar.com:1234
.'' Much of the in
TAO's existing pluggable protocols may also be factored out
because that code is common to all pluggable protocols. The URL
style IOR created by this method should be usable by TAO's Interoperable
Naming Service via the
-ORBInitRef
ORB option.
decode
Profile
object, by extracting
(decoding all object reference information found within the
CDR stream. Care must be taken to extract the information in the
correct order. Use existing TAO pluggable protocol decode
implementations as a reference.
The decode
method performs the inverse operation of the
encode
method.
encode
Profile
object in to the provided
output CDR stream. Care must be taken to insert the information in
the correct order. Use existing TAO pluggable protocol
encode
implementations as a reference.
The encode
method performs the inverse operation of the
decode
method.
_key
_key
method constructs a TAO_ObjectKey
object
that is a copy of the object key found within the
Profile
object, and returns a pointer to the newly create
TAO_ObjectKey
object. Note that the caller owns the
memory allocated by this method. TAO's IIOP _key
implementation is:
is_equivalent
is_equivalent
method implements the CORBA specified
method of the same name. It should return true if this profile is
equivalent to the profile to which it is being compared. Two profiles
are equivalent if and only if their tag, version, address and
object key are the same.hash
hash
method implements the CORBA specified method of
the same name. It is expected to return 32 bit unsigned
integer
(CORBA::ULong
) that uniquely identifies the
CORBA object referenced by the Profile
object. This method
accepts an argument that specifies the largest value the hash can
be.
Any algorithm deemed suitable to provide the required
functionality may be used. The ACE
class in the ACE
library provides implementations of several hash algorithms.
addr_to_string
addr_to_string
returns a string representation of the
address. It should return -1
if the supplied buffer is too
small. The stringified address should have the same form that the
address in the URL style IOR has. This method should be
reentrant.reset_hint
reset_hint
method resets the pointer to a
successfully used Connection Handler
. If no pointer to such a
Connection Handler
, i.e. a hint is provided by the
pluggable protocol then this method may be implemented as a
``no-op.'' A pluggable protcol that does not provide a cached
Connection Handler
will not be able to take advantage of
improved Connector
table look up times.TAO's uses the ACE's Service Configurator implementation [3] to dynamically load pluggable protocol
factories. A
Protocol_Factory
is responsible for creating the
Acceptor
and Connector
for the given pluggable
protocol. TAO iterates through the list of loaded Protocol
Factories
and invokes a factory operation that creates the desired
object: an Acceptor
on the server-side, and a Connector
on the client-side.
All Protocol_Factory
implementations should be derived from
the TAO_Protocol_Factory
abstract base class defined in
<Protocol_Factory.h
>
. The TAO_Protocol_Factory
interface is shown below:
Each of the important methods to be implemented are described below:
init
init
method is invoked immediately after the pluggable
protocol factory is loaded. The Service Configurator
passes Protocol Factory
options specified in a Service
Configurator
configuration file (e.g. svc.conf
) to
this method. The passing convention is essentially the same as
command line argc
/argv
argument passing
convention. The only difference lies in the fact that the option
parsing should begin at argv[0]
instead of
argv[1]
. This differs from the standard command line
passing convention where argv[0]
is the name of the
program currently being run. In any case, the init
method
allows protocol-specific options to be implemented. Once passed to
this method, the pluggable protocol can use them to, for example,
enable or disable certain features or flags within the Protocol
Factory
. Other pluggable protocol components can then use
these flags or features as necessary.
A typical Service Configurator
file line that loads a
pluggable protocol dynamically, and passes arguments to the
init
method would look like:
In the above example, the arguments ``-Foo
''
and ``Bar
'' would be passed as argv[0]
and argv[1]
, respectively, to the Protocol_Factory
init
method.
match_prefix
prefix
prefix
method simply returns a pointer to the static
string containing the protocol prefix used by the pluggable
protocol.options_delimiter
options_delimiter
method is similar to the
object_key_delimiter
method found in the
Connector
. However, it used to delimit where an endpoint
ends and where its options begin. For example, the following
-ORBEndpoint
option specifies a endpoint-specific
priority:
To get around ambiguities in endpoints that can have a
`/
' character in them, the options_delimiter
method can be used to determine what character to be used. For
example, TAO's UIOP pluggable protocol implementation defines
the following:
An endpoint option for the UIOP pluggable protocol can look like the following:
Notice that the `|
' character is used to mark where
the rendezvous point ends and where the endpoint-specific options
begin.
options_delimiter
is a server-side related method. It
is of no use to the client-side.
make_acceptor
make_acceptor
method is a factory method that returns
a pointer to a dynamically allocated Acceptor
specific to
the pluggable protocol to which the Protocol_Factory
object belongs. TAO's UIOP pluggable protocol implementation
defines this method as follows:
make_connector
make_connector
method is a factory method that returns
a pointer to a dynamically allocated Connector
specific to
the pluggable protocol to which the Protocol_Factory
object belongs. TAO's UIOP pluggable protocol implementation
defines this method as follows:
requires_explicit_endpoint
-ORBEndpoint
option. For example, local IPC
(aka UNIX domain sockets) is unable to remove the rendesvouz point if
the server crashes. For those protocols, it is better to create the
endpoint only if the user requests one. This method is queried by TAO
before creating a default acceptor during ORB initialization. If it
returns 1
then no default endpoint should be created. Service Object
s, such as the Protocol_Factory
, must be
declared in a certain way. ACE's Service Configurator implementation
provides two macros to ensure that the required additional declarations
are made to make an object have to the correct interface. The two macros
are ACE_STATIC_SVC_DECLARE
and ACE_FACTORY_DECLARE
.
Typical usage of these declaration macros is demonstrated by TAO's
UIOP pluggable protocol implementation:
also required. These are provided by ``DEFINE
''
counterparts of the above two declaration macros. An example of how to
use them follows:
Notice that the macro arguments above have corresponding Service
Configurator
configuration file entries:
It is desirable to provide for alternative mappings between different ORB messaging protocols and ORB transport adaptors. For example, a single ORB messaging protocol such as GIOP can be mapped to any reliable, connection-oriented transport protocol, such as TCP or TP4. Alternatively, a single transport protocol can be the basis for alternative instantiations of ORB messaging protocols, e.g., different versions of GIOP differing in the number and types of messages, as well as in the format of those messages.
An ORB messaging protocol imposes requirements on any underlying
network transport protocols. For instance, the transport requirements
assumed by GIOP, see Section , require the underlying network transport protocol to
support a reliable, connection-oriented byte-stream. These requirements
are fulfilled by TCP thus leading to the direct mapping of GIOP onto this
transport protocol. However, alternative network transport protocols such
as ATM with AAL5 encapsulation may be more appropriate in some
environments. In this case, the messaging implementation will have to
provide the missing semantics, such as reliability, in order to use
GIOP.
The ORB Messaging protocol implementations must be independent of the adaptation layer needed for transports that do not satisfy all their requirements. Otherwise, the same messaging protocol may be re-implemented needlessly for each transport, which is time-consuming, error-prone, and time/space inefficient. Likewise, for those transports that can support multiple ORB Messaging protocols, it must be possible to isolate them from the details of the ORB messaging implementation. Care must be taken, however, because not all ORB Messaging protocols can be used with all transport protocols, i.e., some mechanism is needed to ensure only semantically compatible protocols are configured [4].
Use the Layers architecture pattern [5], which decomposes the system into groups of components, each one at a different level of abstraction. 1 For the client, the ORB uses a particular ORB messaging protocol to send a request. This ORB messaging protocol delegates part of the work to the transport adapter component that completes the message and sends it to the server. If the low-level transport in use, e.g., ATM, UDP, TCP/IP, etc., does not satisfy the requirements of the ORB messaging protocol, the ORB transport adapter component can implement them.
In the server, the transport adapter component receives data from the underlying communication infrastructure, such as sockets or shared memory, and it passes the message up to the ORB messaging layer. As with the client, this layer can be very lightweight if the requirements imposed by the ORB messaging layer are satisfied by the underlying network transport protocol. Otherwise, it must implement those missing requirements by building them into the concrete transport adapter component.
As shown in Figure 4, TAO implements the
messaging protocol and the transport protocol
in separate components. The client ORB uses the current profile to find
the right transport and ORB messaging implementations. The creation and
initialization of these classes is controlled by the
Connector
, with each
Connector
instance handling a particular ORB messaging/transport
tuple.
Figure 5 illustrates how the server's
implementation uses the same transport classes, but with a different
relationship. In particular, the transport class calls back the messaging
class when data is received from the IPC mechanism. As with the client,
a factory, in this case the Acceptor
, creates and initializes these objects.
A Transport
implements external polymorphism
[ 2] over the Client_Connection_Handler
and the Service_Connection_Handler
objects described in the
Connection_Handler
section of this
document. A Connection_Handler
is simply a template instantiation of
ACE_Svc_Handler<>
, but they don't do much work. They
just delegate on the Transport
classes. This somewhat strange
design is easy to understand once it is realized that not all
ACE_Svc_Handler<>
classes are type compatible (except in
their most basic ACE_Event_Handler
form) so they must be wrapped
using the TAO_Transport
class.
All TAO pluggable protocol Transport
classes must inherit
from the TAO_Transport
abstract base class.
TAO_Transport
interface is shown below. Again, only the
methods that should be implemented for a given pluggable protocol are
shown:
Each method is described below:
Transport
object should also initialize the TAO_Transport
base class
with the tag corresponding to the pluggable protocol.close_connection
Connection Handler
's close
method is invoked my this method.idle
Connection Handler
.handle
Reactor
.event_handler
Event Handler
used by
the Reactor
.send
send
writes data to the connection established in the
underlying transport, such as a TCP connection in the IIOP
pluggable protocol. Three versions of this method must be
implemented. Two of them write data contained within an
ACE_Message_Block
and the remaining simply sends the data
within a buffer of a given length.
When implementing this method, it is important to be aware of
the correct underlying send
or write
operation to
use. Some of TAO's existing pluggable protocols use the
send
calls provided by the operating system because no
further processing of the data being sent is necessary. However,
other protocols may process perform additional operations on the
data being sent, in which case the send
operation provided
by the underlying protocol implementation should be used instead of
the raw operating system send
call.
recv
recv
operation reads a given number of bytes into a
supplied buffer. Unlike the send
method, there is only one
version of the recv
operation. The same caveat of ensuring
that the appropriate recv
or read
operation is used
also applies to this method.start_request
start_request
implementations should essentially be the same in all pluggable
protocol implementations. The only thing that should differ is the
type of Profile
being used. Note that this method is only
useful for clients.start_locate
start_locate
implementations should essentially be the same
in all pluggable protocol implementations. The only thing that should
differ is the type of Profile
being used. Note that this
method is only useful for clients. Note that this method is only
useful for clients.send_request
send
, allows the
transport (and wait strategy) to take appropiate action. This method
is closely tied to TAO's GIOP implementation.
send_request
implementations should essentially be the same
in all pluggable protocol implementations. The only thing that should
differ is the type of Profile
being used. Note that this
method is only useful for clients.handle_client_input
handle_client_input
reads and handles the reply from the
server. It returns zero when there is Short Read
on the
connection, returns 1
when the full reply is read and
handled, and returns -1
on errors. Note that this method is
only useful for clients.register_handler
Connection Handler
with the
Reactor
. It will be called by the Wait Strategy
if
the Reactor
is used for that strategy. This code should
essentially be ``boilerplate'' code. It shouldn't differ
much between pluggable protocol implementations if the same ACE event
handling and dispatching components are used. Note that this method
may be deprecated in the future.There other methods in the TAO_Transport
that can be overridden.
However, the default implementations should be more than satisfactory for
most pluggable protocols.
TAO's existing pluggable protocols implement client-side and
server-side specific Transport
s. For the most part, they can be
used as references for other pluggable protocols.
A Connection_Handler
is simply a template instantiation of
ACE_Svc_Handler<>
[1],
a service handler. ACE_Svc_Handler
s provide a
well-defined interface that Acceptor
and Connector
pattern factories use as their target. Service handlers perform
application-specific processing and communicate via the connection
established by the Connector
and Acceptor
components.
Typically, TAO Connection_Handler
s will subclass
ACE_Svc_Handler
and do all the interesting work in the subclass.
TAO pluggable transport protocol Connection_Handler
s should be
derived from the ACE_Svc_Handler
class declared in <
Svc_Handler.h
>.
TAO's existing pluggable transport protocol implementations define
three classes, a base class derived from an ACE_Svc_Handler
specific to that protocol, and a client-side and a server-side class
derived from that base class. Generally, it is a good idea to base new
Connection_Handler
implementations on TAO's existing ones.
It is necessary to have a very good understanding of some of the patterns upon which the ACE framework is built. These are the REACTOR, ACCEPTOR, CONNECTOR, FACTORY, STRATEGY, and SERVICE CONFIGURATOR PATTERN. Papers which can be helpful include:
Reactor ( PDF )
Reactor1-93 ( PDF )
Reactor2-93 ( PDF )
reactor-rules ( PDF )
reactor-siemens ( PDF )
Svc-Conf ( PDF )
Acc-Con ( PDF )
These are all readily available from the TAO and ACE website.
My starting point for understanding how to add a pluggable protocol to the TAO ORB came from mailing list entry from Carlos O'Ryan. One can find it in the archives of the comp.soft-sys.ace newsgroup. It is dated 1999/06/02 RE: [ace-users] TAO: ATM pluggable protocol. I will repeat the section of that email that was particularly useful to me. (In the email, he is responding to someone who had inquired about adding the ATM protocol).
Basically, you need to look at the following files:
IIOP_Profile.{h,i,cpp}
IIOP_Connector.{h,i,cpp}
IIOP_Acceptor.{h,i,cpp}
IIOP_Factory.{h,i,cpp}
IIOP_Transport.{h,i,cpp}
Connect.{h,i,cpp} [probably will be renamed IIOP_Connect VSN]The profile class handles the addressing format for your transport. It would basically be a wrapper around the ACE_ATM_Addr() class. The Connector and Acceptor classes are simply wrappers around ACE_Acceptor<ACE_ATM_ACCEPTOR> and ACE_Connector<ACE_ATM_ACCEPTOR>, again no big deal (I think). The factory is even simpler.
Things get really interesting in the Transport and Connect classes. Transport just implements external polymorphism over the Client_Connection_Handler and the Service_Connection_Handler objects defined in the Connect.{h,i,cpp}, those are simply ACE_Svc_Handler<ACE_ATM_Stream>, but they don't do much work, they just delegate on the Transport classes. This somewhat strange design is easy to understand once you realize that all the ACE_Svc_Handler<> classes are not type compatible (except in their most basic ACE_Event_Handler form). So they must be wrapped using the TAO_Transport class.
Make sure to review Pluggable Protocols in the Release Information for the ACE ORB (TAO).
Helpful mailing list entries are listed below. The following is from Ossama Othman.
The stock TAO distribution has support for two transport protocols, TCP/IP and local namespace sockets (aka Unix Domain sockets). However, TAO's pluggable protocols framework allows users to add support for additional transport protocols. All you'd really have to do is implement a SCRAMNet pluggable transport protocol with the interface TAO's pluggable protocol framework provides and you'd be able to use SCRAMNet with TAO just as easily as the IIOP (GIOP over TCP/IP) and UIOP (GIOP over Unix domains sockets) protocols.The idea is to implement GIOP messaging over a SCRAMNet transport. If you model your implementation on TAO's IIOP and UIOP implementations then it should be fairly straightforward to create a SCRAMNet pluggable protocol for TAO. The hard part is implementing the equivalent ACE classes for SCRAMNet.
. . .
It's actually not that bad. The easiest way to add a pluggable protocol to TAO, IMO, is to base your pluggable protocol on existing ones. As long as you have the same interface for your protocol as the existing ones then it is fairly easy to create your TAO pluggable protocol. However, in order to do that you have to create ACE_SCRAMNet_{Acceptor, Connector, Stream, Addr} implementations, for example, since TAO's existing pluggable protocols use those interfaces.
As long as you use the same interface for your protocol as the interface for ace/ACE_SOCK* and tao/IIOP* then you shouldn't have much of a problem.
This also assumes that you're implementation can satisfy the conditions stated earlier in this document.
Note also that the TAO files pluggable.* are important to review and
understand as they contain the abstract classes that form the common
inteface for TAO's pluggable protocol framework.
Getting a full understanding on how IIOP was implemented (GIOP over
TCP/IP) and also seeing how provisions were made to add UIOP, was very
helpful to adding my own protocol. In understanding IIOP, I needed to
review the section of the OMG CORBA spec on GIOP, IIOP and Object
references and see how this would apply to my protocol.
In my case, I added a transport layer that uses SCRAMNet (from Systran
Corp) replicated shared memory hardware. This is actual physical memory
cards located on two different machines. When a change is made to one
memory then that change appears very quickly (very low latency here) in
the other memory. I decided that I would implement GIOP over SCRAMNet as
this seemed to be the simplest. With SCRAMNet, one could implement this
transport layer for the TAO ORB in a few different ways, GIOP over
SCRAMNet, Environment-specific inter-ORB protocol (ESIOP) or using
collocation (since it is shared replicated memory). I have not done the
latter two, only GIOP over SCRAMNet just to get a proof of concept
working.
For a graphical representation of the extensions for the new SCRAMNet
classes I have may a skeletal Rose diagram showing (at this point) the
inheritance relationships of the new and existing classes. See (TBD) ftp
site for this Rose diagram.
The new classes created were.
TAO_SCRAMNet_Profile
TAO_SCRAMNet_Acceptor
TAO_SCRAMNet_Connector
TAO_SCRAMNet_TransportTAO_SCRAMNet_Server_TransportTAO_SCRAMNet_Protocol_Factory (Derived from TAO_Protocol Factory in Protocol_Factory.h)
TAO_SCRAMNet_Client_Transport
TAO_SCRAMNet_Handler_BaseTAO_SCRAMNet_Client_Connection_Handler
TAO_SCRAMNet_Server_Connection_Handler
ACE_SCRAMNet_Addr
ACE_SCRAMNet_Acceptor
ACE_SCRAMNet_Connector
ACE_SCRAMNet_Stream
I closely followed the way that IIOP and UIOP were defined and
implemented in the definition and implementation of the SCRAMNet classes.
Following the existing protocol implementation was the largest source of
help for me. Being able to step through the operation of the ORB for the
IIOP protocol and then transposing that over to my protocol made the
process relatively painless and quite the learning experience.
I am using TAO under Phar Lap's Embedded Tool Suite Real-Time
Operating System which is an RTOS which supports a subset of the Win32
API and Winsock 1.1. Because of the new SCRAMNet transport hardware I
needed to change the ORBs core reactor to a WFMO_Reactor. Any instance of
the TAO ORB can only have one reactor type or it won't work. In my
case I am using an ORB in one thread that uses the WFMO_Reactor and the
SCRAMNet transport, and an ORB in another thread that uses a Select
Reactor and the IIOP protocol. I won't go into much of the SCRAMNet
specific stuff as I assume most people are interested in adding a
pluggable protocol in general.
RE: IORs
I found that I needed to have a full understanding of what the exact
contents of a TAO-created IOR were as I needed to be able to understand
how to decode the location information that was now written in the IOR
with the SCRAMNet specific information. Decoding of the preconnect and
endpoint info is important. The endpoint info both in the command line
arguments and in the IOR are different for the each protocol and so your
implemention of the new classes has to parse this information
correctly.
In order to create the ORB with the Win32 Reactor at the core as well
as the SCRAMNet protocol factory loaded and initialize I needed to use
the svc.conf file with the the following options
-ORBReactorType wfmo
-ORBProtocolFactory SCRAMNet_Factory
Beyond the above, I just traced through the operation of the IIOP protocol in action to see exactly where I needed to just graft on the new ACE_SCRAMNet classes, the TAO_SCRAMNet classes and their associated implementations for send and recv so that the SCRAMNet hardware was used as the transport and not the ethernet hardware.
This section covers additional information not necessarily related to TAO's pluggable protocol framework but may still be of interest to pluggable protocol and ORB developers, nevertheless.
Tags are used to uniquely identify certain parts of an ORB, including the following:
For information about tags and tag allocation see:
http://www.omg.org/cgi-bin/doc?ptc/99-02-01
Information about tags used in TAO is available here.
Once a TAO pluggable protocol is implemented, the ORB is told to load
it by adding entries to a Service Configurator
configuration
file (e.g. svc.conf
for that protocol. A typical
svc.conf
file could contain entries such as the following:
These entries would cause a pluggable protocol called ``FOOIOP''
to be loaded into the ORB. By default the IIOP and UIOP (if supported)
pluggable protocols are loaded into TAO if no such entries are provided.
Explicitly specifying which protocols to load in this way prevents any
pluggable protocols from being loaded by default. The
-ORBProtocolFactory
ORB option causes the specified protocol
factory to be loaded into the ORB. Multiple pluggable protocols can be
loaded simply by adding more Service Configurator
configuration
file entries. For example, the following entries would cause the
TAO's IIOP and the fictional FOOIOP pluggable protocols to be loaded:
In this case, TAO's UIOP pluggable protocol would not be
loaded. Service Configurator
configuration file names are not
limited to the name svc.conf
. The ORB can be told to
use a configuration file other than svc.conf
by
using the -ORBSvcConf
ORB option.
Note that the FOOIOP protocol resides in a library other than the TAO
library, called libTAO_FOO.so
on UNIX platforms, and
TAO_FOO.dll
on Win32 platforms. This ability to
dynamically load pluggable protocols in libraries that are completely
separate libraries from the TAO library truly makes TAO's pluggable
protocol framework ``pluggable.'' Make sure the directory your
pluggable protocol library is located in is also in your library search
path, typically LD_LIBRARY_PATH
on UNIX systems and/or the
``/etc/ld.so.conf
'' file on some UNIX systems. Remember
to run ldconfig
if you modify
``/etc/ld.so.conf
.''
Creating an endpoint specific to a given pluggable protocol is simply
a matter of using TAO's
-ORBEndpoint
ORB option. This is detailed in the documentation
for the open
and
open_default
methods
in the Acceptor
section of this
document. Once an endpoint is created, the client uses the IOR that
points to the object on that endpoint tomake requests on that object.
All ORB options are described here.