Chapter 7 Connection Management
This chapter describes how omniORB manages network connections.
7.1 Background
In CORBA, the ORB is the `middleware' that allows a client to invoke
an operation on an object without regard to its implementation or
location. In order to invoke an operation on an object, a client needs
to `bind' to the object by acquiring its object reference. Such a
reference may be obtained as the result of an operation on another
object (such as a naming service) or by conversion from a stringified
representation. If the object is in a different address space, the
binding process involves the ORB building a proxy object in the
client's address space. The ORB arranges for invocations on the proxy
object to be transparently mapped to equivalent invocations on the
implementation object.
For the sake of interoperability, CORBA mandates that all ORBs should
support IIOP as the means to communicate remote invocations over a
TCP/IP connection. IIOP is asymmetric with respect to the roles of the
parties at the two ends of a connection. At one end is the client
which can only initiate remote invocations. At the other end is the
server which can only receive remote invocations.
Notice that in CORBA, as in most distributed systems, remote bindings
are established implicitly without application intervention. This
provides the illusion that all objects are local, a property known as
`location transparency'. CORBA does not specify when such bindings
should be established or how they should be multiplexed over the
underlying network connections. Instead, ORBs are free to implement
implicit binding by a variety of means.
The rest of this chapter describes how omniORB manages network
connections and the programming interface to fine tune the management
policy.
7.2 The Model
omniORB is designed from the ground up to be fully multi-threaded. The
objective is to maximise the degree of concurrency and at the same
time eliminate any unnecessary thread overhead. Another objective is
to minimise the interference by the activities of other threads on the
progress of a remote invocation. In other words, thread `cross-talk'
should be minimised within the ORB. To achieve these objectives, the
degree of multiplexing at every level is kept to a minimum.
On the client side of a connection, the thread that invokes on a proxy
object drives the IIOP protocol directly and blocks on the connection
to receive the reply. On the server side, a dedicated thread blocks on
the connection. When it receives a request, it performs the up-call to
the object and sends the reply when the up-call returns. There is no
thread switching along the call chain.
With this design, there is at most one call in-flight at any time on a
connection. If there is only one connection, concurrent invocations to
the same remote address space would have to be serialised. To
eliminate this limitation, omniORB implements a dynamic
policy---multiple connections to the same remote address space are
created on demand and cached when there are concurrent invocations in
progress.
To be more precise, a network connection to another address space is
only established when a remote invocation is about to be made.
Therefore, there may be one or more object references in one address
space that refer to objects in a different address space but unless
the application invokes on these objects, no network connection is
made. The maximum number of connections opened to another address
space is 5 by default. This parameter can be changed by calling the
omniORB.maxTcpConnectionPerServer function before
calling ORB_init().
It is wasteful to leave a connection open when it has been left unused
for a considerable time. Too many idle connections could block out new
connections to a server when it runs out of spare communication
channels. For example, most Unix platforms have a limit on the number
of file handles a process can open. 64 is the usual default limit. The
value can be increased to a maximum of a thousand or more by changing
the `ulimit' in the shell.
7.3 Idle Connection Shutdown and Remote Call Timeout
Inside the ORB, a thread is dedicated to scan for idle connections.
The thread looks after both the outgoing connections and the incoming
connections.
When a connection is idle for a period of time, the connection is
shutdown. Similarly, if a remote call has not completed within a
defined period of time, the connection is shutdown and the ORB will
return COMM_FAILURE to the client.
How often the internal thread scans the connections is determined by
the value of the scan granularity. This value is defaulted to 5
seconds and can be changed using the command-line option
-ORBscanGranularity. Notice that this value determines the
precision the ORB is able to keep to the value of the idle connection
or remote call timeout.
How long the ORB will wait before it shuts down an idle connection is
determined by the idleConnectionPeriods. There are separate values for
incoming and outgoing connections. The default values are 180 and 120
seconds for incoming and outgoing connections respectively. These
values can be changed using the command-line options
-ORBinConScanPeriod and -ORBoutConScanPeriod.
Similarly, how long the ORB will wait for a remote call to complete is
determined by the parameter clientCallTimeOutPeriod for the client
side and the serverCallTimeOutPeroid for the server side. By default
calls will not timeout on either the client or server side.
The timeout can be changed with the
-ORBclientCallTimeOutPeriod and
-ORBserverCallTimeOutPeriod options. The scan can be disabled
completely by setting the scan granularity to 0.
7.4 Interoperability Considerations
The IIOP specification allows both the client and the server to
shutdown a connection unilaterally. When one end is about to shutdown
a connection, it should send a closeConnection message to the other
end. It should also make sure that the message will reach the other
end before it proceeds to shutdown the connection.
The client should distinguish between an orderly and an abnormal
connection shutdown. When a client receives a closeConnection message
before the connection is closed, the condition is an orderly shutdown.
If the message is not received, the condition is an abnormal shutdown.
In an abnormal shutdown, the ORB should raise a COMM_FAILURE
exception whereas in an orderly shutdown, the ORB should not
raise an exception and should try to re-establish a new connection
transparently.
omniORB implements these semantics completely. However, it is known
that some ORBs are not (yet) able to distinguish between an orderly
and an abnormal shutdown. Usually this is manifested as the client in
these ORBs seeing a COMM_FAILURE occasionally when connected
to an omniORB server. The work-around is either to catch the exception
in the application code and retry, or to turn off the idle connection
shutdown inside the omniORB server.
7.5 Connection Acceptance
omniORB provides the hook to implement a connection acceptance policy.
Inside the ORB runtime, a thread is dedicated to receive new
connections. When the thread is given the handle of a new connection
by the operating system, it calls the policy module to decide if the
connection can be accepted. If the answer is yes, the ORB will start
serving requests coming in from that connection. Otherwise, the
connection is shutdown immediately.
There can be a number of policy module implementations. The basic one
is a dummy module which just accepts every connection.
In addition, a host-based access control module is available on Unix
platforms. The module uses the IP address of the client to decide if
the connection can be accepted. The module is implemented using
tcp_wrappers 7.6. The access control policy can be defined as
rules in two access control files: hosts.allow and
hosts.deny. The syntax of the rules is described in the manual
page hosts_access(5) which can be found in
appendix A. The syntax defines a simple access
control language that is based on client (host name/address, user
name), and server (process name, host name/address) patterns. When
searching for a match on the server process name, the ORB uses the
value of omniORB::serverName. ORB_init() uses the argument
argv[0] to set the default value of this variable. This can be
overridden by the application with the -ORBserverName
<string> command line argument
The default location of the access control files is /etc. This
can be overridden by the extra options in omniORB.cfg. For
instance:
# omniORB configuration file - extra options
GATEKEEPER_ALLOWFILE /project/omni/var/hosts.allow
GATEKEEPER_DENYFILE /project/omni/var/hosts.deny
As each policy module is implemented as a separate library, the choice
of policy module is determined at program linkage time. For instance,
if the host-based access control module is in use:
% eg1 -ORBtraceLevel 2
omniORB gateKeeper is tcpwrapGK 1.0 - based on tcp_wrappers_7.6
I said,"Hello!". The Object said,"Hello!"
Whereas if the dummy module is in use:
% eg1 -ORBtraceLevel 2
omniORB gateKeeper is not installed. All incoming are accepted.
I said,"Hello!". The Object said,"Hello!"