VisiBroker for C++ Developer’s Guide : VisiBroker Pluggable Transport Interface

VisiBroker Pluggable Transport Interface
VisiBroker for C++ provides a Pluggable Transport Interface, to support the use of transport protocols besides the ones inbuilt in the ORB for the transmission of CORBA invocations. The Interface supports the ‘plugging in’ of multiple transport protocols simultaneously, and is designed to provide a common interface that is suitable for use with a wide variety of transport types. The interface uses CORBA standard classes wherever possible, but is itself VisiBroker proprietary.
Pluggable Transport Interface Files
The VisiBroker Pluggable Transport Interface is delivered as a library and a supporting header file:
The header file vptrans.h can be found in the include directory
where bitmode is 64 on 64 bit platforms, “p” refers to the standard C++ version, and “version” refers to the version of VisiBroker. The APIs of the library are exposed through the vptrans.h header file.
Transport Layer Requirements
Any transport protocol plugged in to VisiBroker via the Pluggable Transport Interface will be used by the ORB to send and receive messages encoded using the standard GIOP protocol that is defined as part of the CORBA specification.
GIOP makes certain assumptions about the transport layer used to exchange these messages. The same assumptions have been used in the design of the Pluggable Transport Interface. Therefore, the user code that interfaces a specific transport to the ORB must ‘mask’ any differences between these requirements and the actual behavior of the transport.
The Pluggable Transport Interface assumes:
User-Provided Code Required for a Protocol Plugin
You must implement three main classes for each transport protocol that is to be plugged in to the ORB via the Pluggable Transport Interface:
1
2
3
Additionally, the Pluggable Transport Interface uses a “Factory” pattern to manage the instantiation each of these classes. Therefore three Factory classes must be provided, each creating instances of one of the above classes.
A transport protocol is initialized by instantiating the three Factory classes and registering them with the ORB via the Pluggable Protocol Interface. Calling a static function of the Pluggable Protocol Interface during the system initialization stage, before starting any CORBA server or client code, performs the registration.
Unique Profile ID Tag
Each plugged in transport is required to have a unique four-byte Profile ID tag, to distinguish it from other protocols. Profile ID tags are managed by the OMG. Micro Focus has a range of Profile ID tags registered with the OMG, and four of these tags are available for use by protocol plugins:
1
2
3
4
One of these tags should be used rather than a randomly chosen value, to avoid conflict with any third-party CORBA-based products.
Note, however, that there will still be the possibility of conflict, if the system that uses the protocol plugin is integrated with other systems based on VisiBroker for C++ that happen to contain a protocol plugin that choose the same Profile ID tag. This could occur either when different sub-systems, developed independently within the same organization, are integrated, or if the final system is required to interoperate with another CORBA-based system developed by another organization.
If either of the above scenarios is a serious possibility, a reserved number should be obtained from the OMG. See the OMG FAQ on CORBA tags, available at ftp://ftp.omg.org/pub/docs/ptc/99–02–01.txt, for details. The minimum number of tags required should be reserved, bearing in mind that a set of tags may normally only be reserved once per year. It is recommended that the numbers only be reserved as the developed system nears deployment.
Example Code
Two examples are provided in the examples/pluggable directory that illustrates how a plug-in transport could be implemented and how it could be used by a CORBA application. The example makes use of TCP/IP as transport to lay emphasis on the interface itself rather than to explain the intricacies of a transport layer.
Implementing a new transport
The following interfaces, exposed in the vptrans.h header file, need to be implemented.
VISPTransConnection and VISPTransConnectionFactory
This class represents a single connection between a server and a client. Whenever a program reads or writes to it, that data will be received or sent to one single peer endpoint on the remote side. When a client wants to send a request to a server, the ORB will look for a valid connection to that server and create one, if it does not exist, yet. The remote endpoint of the connection is setup using the given Profile of the server and communicating with the Listener (see “VISPTransListener and VISPTransListenerFactory”) on the server side. Besides general status information, this class also must either (a) provide a method to wait for data coming through the connection, that times out after a given number of seconds, or (b) use the ‘Pluggable Transport Bridge’ class to perform that function by signalling incoming data to the Bridge when it is available.
The Factory class is used to create instances of the plug-in connection and needs to be registered with a registrar using the static VISPTransRegistrar::addTransport API.
class _VBPTEXPORT VISPTransConnection {
public:
...
 
// send data to remote peer
virtual void write(CORBA::Boolean _isFirst, const char* _data, CORBA::ULong_offset,
CORBA::ULong _length, CORBA::ULongLong _timeout) = 0;
 
// read data sent from the connection from remote peer
virtual void read(CORBA::Boolean _isFirst,
char* _data, CORBA::ULong _offset,
CORBA::ULong _length,
CORBA::ULongLong _timeout) = 0;
 
// helpful for buffering transport to flush data immediately
virtual void flush() = 0;
 
// orderly close of the connection
virtual void close() = 0;
 
// communicate with remote peer listener to set up a new connection
virtual void connect(CORBA::ULongLong _timeout) = 0;
 
// should return unique Id (for this transport) for each connection instance
virtual CORBA::Long id() = 0;
 
// should return true if remote peer is still connected
virtual CORBA::Boolean isConnected() = 0;
 
// should return true if data is ready to be read
virtual CORBA::Boolean isDataAvailable() = 0;
 
// should return true if the transport can be used on reverse client-server
setup
virtual CORBA::Boolean no_callback() = 0;
 
// should return true if transport cannot wait for next message. This
makes the ORB
// use the bridge for timing out while waiting for next message
virtual CORBA::Boolean isBridgeSignalling() = 0;
 
// blocks till data arrives or timeout. Should return true if data is available
virtual CORBA::Boolean waitNextMessage(CORBA::ULong _timeout) = 0;
 
// Should return a copy of the profile describing the peer endpoint
virtual IOP::ProfileValue_ptr getPeerProfile() = 0;
 
// input peer profile telling the connection regarding its peer.
Used while connecting
virtual void setupProfile(const char* prefix, VISPTransProfileBase_ptr peer)
= 0;
 
};
 
class _VBPTEXPORT VISPTransConnectionFactory {
public:
...
 
// should return a new connection instance and return pointer to it
virtual VISPTransConnection_ptr create(const char* prefix) = 0;
 
};
VISPTransListener and VISPTransListenerFactory
This class is used on the server-side code to wait for incoming connections and requests from clients. New connections and requests on existing connections are signaled to the ORB via the Pluggable Transport Interface’s Bridge class (see “VISPTransBridge class”).
Instances of this class are created each time a Server Engine is created that includes Server Connection Managers (‘SCMs’) that specify the particular transport protocol. One instance is created per SCM instance that specifies the protocol.
When a request is received on an existing connection, the connection goes through a ‘Dispatch Cycle’. The Dispatch Cycle starts when the connection delivers data to the transport layer. In this initial state, the arrival of this data must be signalled to the ORB via the Bridge (see “VISPTransBridge class”) and then the Listener ignores the connection until the Dispatch process is completed (in the mean time, the connection is said to be in the ‘dispatch state’). The connection is returned to the initial state when the ORB makes a call to the Listener’s completedData() method. During the dispatch state the ORB will read directly from the connection until all requests are exhausted, avoiding any overhead incurred by the Bridge-Listener communication.
In most cases, the transport layer uses blocking calls that wait for new connections. In order to handle this situation, the Listener should be made a subclass of the class VISThread and start a separate thread of execution that can be blocked without holding up the whole ORB.
The factory instance as with the connection should return instances of the implemented plug-in listener and should be registered using VISPTransRegistrar::addTransportAPI.
class _VBPTEXPORT VISPTransListener {
public:
...
 
// Called by ORB to establish link to the bridge, so that listener-ORB
// communication can occur
virtual void setBridge(VISPTransBridge* up) = 0;
 
// Should return a profile describing the listener endpoint
virtual IOP::ProfileValue_ptr getListenerProfile() = 0;
 
// Called when the ORB has completed reading a request for the given id
// and wants the listener to once again signal via the bridge on any new requests.
virtual void completedData(CORBA::Long id) = 0;
 
// Should return true if connection with given id has data ready to be read
 
virtual CORBA::Boolean isDataAvailable(CORBA::Long id) = 0;
 
// Called when the listener needs to tear down the endpoint and close
all related
// active connections.
virtual void destroy() = 0;
};
 
class _VBPTEXPORT VISPTransListenerFactory {
public:
...
 
// Makes an new instance of the listener and should return pointer to it
virtual VISPTransListener_ptr create(const char* propPrefix) = 0;
 
};
VISPTransProfileBase and VISPTransProfileFactory
This class provides the functionality to convert between a transport-specific endpoint description and an IOP based IOR that can be exchanged with other CORBA implementations. It is also used during the process of binding a client to a server, by passing a ProfileValue to a ‘parsing’ function that has to return true or false, depending on whether an IOR usable for this transport was found inside of it.
An instance of this class is frequently passed to functions via a pointer to its base class type. In order to support safe runtime down casting with any C++ compiler, a _downcast function must be provided that can test if the cast is legal or not.
Additional classes
Two additional classes are provided by the Pluggable Transport Interface, that the user-provided transport plugin code will make calls to.
VISPTransBridge class
VISPTransBridge is a generic interface between the ORB and the transport plug-in to communicate various events. Some of the communications are:
Class _VBPTEXPORT VISPTransBridge {
public:
 
// Tell ORB about a new connection request passing the connection pointer
// Returns true if the ORB has accepted the connection, else false
virtual CORBA::Boolean addInput(VISPTransConnection_ptr con);
 
// Tell ORB of a new request on a connection. Typically this will start off the
// dispatch cycle
virtual void signalDataAvailable(CORBA::Long conId);
 
// Tell the ORB that the connection was closed by the remote peer.
virtual void closedByPeer(CORBA::Long conId)=0;
VISPTransRegistrar class
VISPTransRegistrar is the class that must be used to register a new transport with the ORB. The string given during registration is used as identifier of this transport and must be unique in the scope of that ORB. It will also be used in the prefix string of properties related to this transport.
class _VBPTEXPORT VISPTransRegistrar {
public:
// register the transport identifier string and the three factories used
to specific instances
// of this new transport
static void addTransport(const char* protocolName,
VISPTransConnectionFactory* connFac,
VISPTransListenerFactory* listFac,
VISPTransProfileFactory* profFac);
 
};