Previous Contents Next

Chapter 6   The omniORB API

In this chapter, we introduce the omniORB API. The purpose of this API is to provide access points to omniORB specific functionality that is not covered by the CORBA specification. Obviously, if you use this API in your application, that part of your code is not going to be portable to run unchanged on other vendors' ORBs. To make it easier to identify omniORB dependent code, this API is defined under the name space `omniORB'1.

6.1   ORB initialisation options

CORBA::ORB_init() accepts the following standard command-line arguments:

-ORBid omniORB3 The identifier must be `omniORB3'.
-ORBInitRef <ObjectId>=<ObjectURI> See section 4.2.
-ORBDefaultInitRef <Default URI> See section 4.2.

and the following omniORB-specific arguments:

-ORBtraceLevel <level> See section 6.3.
-ORBtraceInvocations See section 6.3.
-ORBstrictIIOP See section 6.9.
-ORBtcAliasExpand <0 or 1> See section 9.2.
-ORBgiopMaxMsgSize <size in bytes> See section 6.5.
-ORBobjectTableSize <number of entries> See section 6.6.
-ORBserverName <string> See section 6.4.
-ORBno_bootstrap_agent See section 6.8.
-ORBdiiThrowsSysExceptions <0 or 1> See section 11.4.
-ORBabortOnInternalError <0 or 1> See section 6.11.
-ORBverifyObjectExistsAndType <0 or 1> See section 6.9.
-ORBinConScanPeriod <0--max integer> See section 8.3.
-ORBoutConScanPeriod <0--max integer> See section 8.3.
-ORBclientCallTimeOutPeriod <0--max integer> See section 8.3.
-ORBserverCallTimeOutPeriod <0--max integer> See section 8.3.
-ORBscanGranularity <0--max integer> See section 8.3.
-ORBlcdMode See section 6.9.
-ORBpoa_iiop_port <port no.> See section 6.2.
-ORBpoa_iiop_name_port <hostname[:port no.]> See section 6.2.
-ORBhelp Lists all ORB command line options.

and these two obsolete omniORB-specific arguments:

-ORBInitialHost <string> See section 6.8.
-ORBInitialPort <1--65535>] See section 6.8.

As defined in the CORBA specification, any command-line arguments understood by the ORB will be removed from argv when the initialisation functions return. Therefore, an application is not required to handle any command-line arguments it does not understand.

6.2   Hostname and port

Normally, omniORB lets the operating system pick which port number it should use to listen for IIOP calls. Alternatively, you can specify a particular port using -ORBpoa_iiop_port. If you specify -ORBpoa_iiop_port more than once, omniORB will listen on all the ports you specify.

By default, the ORB can work out the IP address of the host machine. This address is recorded in the object references of the local objects. However, when the host has multiple network interfaces and multiple IP addresses, it may be desirable for the application to control what address the ORB should use. This can be done by defining the environment variable OMNIORB_USEHOSTNAME to contain the preferred host name or IP address in dot-numeric form. Alternatively, the same can be achieved using the -ORBpoa_iiop_name_port option. You can optionally specify a port number too. Again, you can specify more than one host name by using -ORBpoa_iiop_name_port more than once.

6.3   Run-time Tracing and Diagnostic Messages

omniORB can output tracing and diagnostic messages to the standard error stream. To avoid conflicts between old-style iostream.h and new-style iostream, omniORB uses neither. Some or all of these messages can be turned on/off by setting the variable omniORB::traceLevel. The type definition of the variable is:

CORBA::ULong omniORB::traceLevel = 1; // The default value is 1
At the moment, the following trace levels are defined:

 
level 0 turn off all tracing and informational messages
level 1 informational messages only
level 2 the above plus configuration information
level 5 the above plus notifications when server threads are created or communication endpoints are shutdown
level 10--20 the above plus execution and exception traces
level 25 the above plus hex dumps of all data sent and received by the ORB via its network connections.

The variable can be changed by assignment inside your applications. It can also be changed by specifying the command-line option: -ORBtraceLevel <level>. For instance:

$ eg2_impl -ORBtraceLevel 5
New in omniORB 3, you can also trace operation invocations by setting omniORB::traceInvocations to true, or with the -ORBtraceInvocations command line argument.

6.4   Server Name

Applications can optionally specify a name to identify the server process. At the moment, this name is only used by the host-based access control module. See section 8.5 for details. The name is stored in the variable omniORB::serverName.

CORBA::String_var omniORB::serverName;
The variable can be changed by assignment inside your applications. It can also be changed by specifying the command-line option: -ORBserverName <string>.

6.5   GIOP Message Size

omniORB sets a limit on the GIOP message size that can be sent or received. The value can be obtained by calling:

size_t omniORB::MaxMessageSize();
and can be changed by:

void omniORB::MaxMessageSize(size_t newvalue);
or by the command-line option -ORBgiopMaxMsgSize. The exact value is somewhat arbitrary. The reason such a limit exists is to provide some way to protect the server side from resource exhaustion. Think about the case when the server receives a rogue GIOP(IIOP) request message that contains a sequence length field set to 231. With a reasonable message size limit, the server can reject this rogue message straight away.

6.6   Object table size

omniORB uses a hash table to store the mapping from object keys to servant objects. Normally, it dynamically re-sizes the hash table when it becomes too full or too empty. This is the most efficient trade-off between performance and memory usage. However, since all POA operations which add or remove objects from the table can (very occasionally) cause the object table to resize, the time spent in POA operations is much less predictable than if the table size was fixed.

To prevent omniORB from resizing its object table, set the variable omniORB::objectTableSize to the number of hash table entries you require before calling CORBA::ORB_init(). Alternatively, use the -ORBobjectTableSize argument. Note that omniORB uses an open hash table so you can have any number of objects active, no matter what size table you specify. If you have many more active objects than hash table entries, object look-up performance will become linear with the number of objects.

6.7   POA request holding timeout

POAs can be put into the holding state, which means that incoming requests are queued until the POA is set to a different state. Normally, queued requests are held for ever (or until the client times out as described in section 8.3). If you set omniORB::poaHoldRequestTimeout to a non-zero time in seconds, held requests will be cancelled after that time. When requests are cancelled in this way, the caller is sent a TRANSIENT exception.

6.8   Obsolete Initial Object Reference Bootstrapping

Starting from 2.6.0, but superseded by the Interoperable Naming Service in omniORB 3, a mechanism is available for the ORB runtime to obtain the initial object references to CORBA services. The bootstrap service is a special object with the object key `INIT' and the following interface2:

  // IDL
  module CORBA {
    interface InitialReferences {
      Object get(in ORB::ObjectId id);
      // returns the initial object reference of the service
      // identified by <id>. For example the id for the
      // Naming service is "NameService".

      ORB::ObjectIdList list();
      // returns the list of service ids that this agent knows
   };
 };
By default, all omniORB servers contain an instance of this object and are able to respond to remote invocations. To prevent the ORB from instantiating this object, the command-line option -ORBno_bootstrap_agent should be specified.

In particular, the Naming Service omniNames is able to respond to a query through this interface and return the object reference of its root context. In effect, the bootstrap agent provides a level of indirection. All omniORB clients still have to be supplied with the address of the bootstrap agent. However, the information is much easier to specify than a stringified IOR! Another advantage of this approach is that it is completely compatible with JavaIDL. This makes it possible for programs written for JavaIDL to share a Naming Service with omniORB.

The address of the bootstrap agent is given by the ORBInitialHost and ORBInitialPort parameter in the omniORB configuration file (section 1.2). The parameters can also be specified as command-line options (section 6.1). The parameter ORBInitialPort is optional. If it is not specified, port number 900 will be used.

During initialisation, the ORB reads the parameters in the omniORB configuration file. If the parameter NAMESERVICE is specified, the stringified IOR is used as the object reference of the root naming context. If the parameter is absent and the parameter ORBInitialHost is present, the ORB contacts the bootstrap agent at the address specified to obtain the root naming context when the application calls resolve_initial_references(). If neither is present, resolve_initial_references() returns a nil object reference. Finally, the command line argument -ORBInitialHost overrides any parameters in the configuration file. The ORB always contacts the bootstrap agent at the address specified to obtain the root naming context.

Now we are ready to describe a simple way to set up omniNames.

  1. Start omniNames for the first time on a machine (e.g. wobble):

    $ omniNames -start 1234

  2. Add to omniORB.cfg:

    ORBInitialHost wobble

    ORBInitialPort 1234

  3. All omniORB applications will now be able to contact omniNames.

    Alternatively, the command line options can be used, for example:

    $ eg3_impl -ORBInitialHost wobble -ORBInitialPort 1234 &

    $ eg3_clt -ORBInitialHost wobble -ORBInitialPort 1234

6.9   GIOP Lowest Common Denominator Mode

Sometimes, to cope with bugs in another ORB, it is necessary to disable various GIOP and IIOP features in order to achieve interoperability. If the command line option -ORBlcdMode is present or the function omniORB::enableLcdMode() is called, the ORB enters the so-called `lowest common denominator mode'. It bends over backwards to cope with bugs in the ORB at the other end. This is purely a transitional measure. The long term solution is to report the bugs to the other vendors and ask them to fix them expediently.

In some (sloppy) IIOP implementations, the message size value in the IIOP header can be larger than the actual body size, i.e. there is garbage at the end. As the spec does not say the message size must match the body size exactly, this is not a clear violation of the spec. omniORB's default policy is to expect incoming messages to be formatted properly. Any messages that have garbage at the end will be rejected.

-ORBlcdMode and omniORB::enableLcdMode() set omniORB to silently skip the unread part of such invalid messages. Alternatively, you can just change this policy with the -ORBstrictIIOP 0 command line, or by setting omniORB::strictIIOP to zero. The problem with doing this is that the header message size may actually be garbage, caused by a bug in the sender's code. The receiving thread may block forever as it tries to read more data from the connection. In this case the sender won't send any more as it thinks it has marshalled in all the data.

By default, omniORB uses the GIOP LOCATE_REQUEST message to verify the existence of an object prior to the first invocation. If another vendor's ORB is known not to be able to handle this GIOP message, set the variable omniORB::verifyObjectExistsAndType to 0 to disable this feature, and hence achieve interoperability. The command line option -ORBverifyObjectExistsAndType has the same effect.

6.10   GIOP Requesting Principal field

In versions 1.0 and 1.1 of the GIOP specification, request messages contain a `principal' field which was intended to identify the client. The meaning of the principal field was never specified, and its use is now deprecated. The field is not present in GIOP 1.2. omniORB normally uses the string `nobody' in the principal field. However, some systems (e.g. the GNOME desktop environment) use the principal field as an authentication mechanism, so omniORB allows you to configure the principal by setting the OMNIORB_PRINCIPAL environment variable.

6.11   Trapping omniORB Internal Errors

class fatalException {
public:
    const char *file() const;
    int line() const;
    const char *errmsg() const;
};
When omniORB detects an internal problem that is most likely to be caused by a bug in the runtime, it raises the exception omniORB::fatalException. When this exception is raised, it is not sensible to proceed with any operation that involves the ORB's runtime. It is best to exit the program immediately. The exception structure carried by omniORB::fatalException contains the exact location (the file name and the line number) where the exception is raised. You are strongly encouraged to file a bug report and point out the location.

It may help to cause a core-dump and look at the stack trace to locate where the exception was thrown. This can be done by setting the variable omniORB::abortOnInternalError to 1. The variable can also be set via the command line option -ORBabortOnInternalError.



6.12   System Exception Handlers

By default, all system exceptions which are raised during an operation invocation, with the exception of CORBA::TRANSIENT, are propagated to the application code. Some applications may prefer to trap these exceptions within the proxy objects so that the application logic does not have to deal with the error condition. For example, when a CORBA::COMM_FAILURE is received, an application may just want to retry the invocation until it finally succeeds. This approach is useful for objects that are persistent and their operations are idempotent.

omniORB provides a set of functions to install exception handlers. Once they are installed, proxy objects will call these handlers when the associated system exceptions are raised by the ORB runtime. Handlers can be installed for CORBA::TRANSIENT, CORBA::COMM_FAILURE and CORBA::SystemException. This last handler covers all system exceptions other than the two covered by the first two handlers. An exception handler can be installed for individual proxy objects, or it can be installed for all proxy objects in the address space.

6.12.1   CORBA::TRANSIENT handlers

When a CORBA::TRANSIENT exception is raised by the ORB runtime, the default behaviour of the proxy objects is to retry indefinitely until the operation succeeds. Successive retries will be delayed progressively by multiples of omniORB::defaultTransientRetryDelayIncrement. The delay will be limited to the maximum specified by omniORB::defaultTransientRetryDelayMaximum. The unit of both values are in seconds.

The ORB runtime will raise CORBA::TRANSIENT under the following conditions:

  1. When a cached network connection is broken while an operation invocation is in progress. The ORB will try to open a new connection at the next invocation.

  2. When the proxy object has been redirected by a location forward message by the remote object to a new location and the object at the new location cannot be contacted. In addition to the CORBA::TRANSIENT exception, the proxy object also resets its internal state so that the next invocation will be directed at the original location of the remote object.

  3. When the remote object reports CORBA::TRANSIENT.
Applications can override the default behaviour by installing their own exception handler. The API to do so is summarised below:

class omniORB {
public:
  
typedef CORBA::Boolean (*transientExceptionHandler_t)(void* cookie,
                                                CORBA::ULong n_retries,
                                                const CORBA::TRANSIENT& ex);

static void installTransientExceptionHandler(void* cookie,
                                             transientExceptionHandler_t fn);

static void installTransientExceptionHandler(CORBA::Object_ptr obj,
                                             void* cookie,
                                             transientExceptionHandler_t fn);
  
static CORBA::ULong defaultTransientRetryDelayIncrement;
static CORBA::ULong defaultTransientRetryDelayMaximum;
}
The overloaded function installTransientExceptionHandler() can be used to install the exception handlers for CORBA::TRANSIENT. Two forms are available: the first form installs an exception handler for all object references except for those which have an exception handler installed by the second form, which takes an additional argument to identify the target object reference. The argument cookie is an opaque pointer which will be passed on by the ORB when it calls the exception handler.

An exception handler will be called by proxy objects with three arguments. The cookie is the opaque pointer registered by installTransientExceptionHandler(). The argument n_retries is the number of times the proxy has called this handler for the same invocation. The argument ex is the value of the exception caught. The exception handler is expected to do whatever is appropriate and returns a boolean value. If the return value is TRUE(1), the proxy object retries the operation. If the return value is FALSE(0), the CORBA::TRANSIENT exception is propagated into the application code.

The following sample code installs a simple exception handler for all objects and for a specific object:

CORBA::Boolean my_transient_handler1 (void* cookie,
                                      CORBA::ULong retries,
                                      const CORBA::TRANSIENT& ex)
{
   cerr << "transient handler 1 called." << endl;
   return 1;           // retry immediately.
}
 
CORBA::Boolean my_transient_handler2 (void* cookie,
                                      CORBA::ULong retries,
                                      const CORBA::TRANSIENT& ex)
{
   cerr << "transient handler 2 called." << endl;
   return 1;           // retry immediately.
}


static Echo_ptr myobj;

void installhandlers()
{
   omniORB::installTransientExceptionHandler(0,my_transient_handler1);
   // All proxy objects will call my_transient_handler1 from now on.

   omniORB::installTransientExceptionHandler(myobj,0,my_transient_handler2);
   // The proxy object of myobj will call my_transient_handler2 from now on.
}

6.12.2   CORBA::COMM_FAILURE

When the ORB runtime fails to establish a network connection to the remote object and none of the conditions listed above for raising a CORBA::TRANSIENT is applicable, it raises a CORBA::COMM_FAILURE exception.

The default behaviour of the proxy objects is to propagate this exception to the application. Applications can override the default behaviour by installing their own exception handlers. The API to do so is summarised below:

class omniORB {
public:

typedef CORBA::Boolean (*commFailureExceptionHandler_t)(void* cookie,
                                                CORBA::ULong n_retries,
                                                const CORBA::COMM_FAILURE& ex);

static void installCommFailureExceptionHandler(void* cookie,
                                             commFailureExceptionHandler_t fn);

static void installCommFailureExceptionHandler(CORBA::Object_ptr obj,
                                             void* cookie,
                                             commFailureExceptionHandler_t
                                             fn);
}
The functions are equivalent to their counterparts for CORBA::TRANSIENT.

6.12.3   CORBA::SystemException

To report an error condition, the ORB runtime may raise other system exceptions. If the exception is neither CORBA::TRANISENT nor CORBA::COMM_FAILURE, the default behaviour of the proxy objects is to propagate this exception to the application. Applications can override the default behaviour by installing their own exception handlers. The API to do so is summarised below:

class omniORB {
public:

typedef CORBA::Boolean (*systemExceptionHandler_t)(void* cookie,
                                            CORBA::ULong n_retries,
                                            const CORBA::SystemException& ex);

static void installSystemExceptionHandler(void* cookie,
                                          systemExceptionHandler_t fn);

static void installSystemExceptionHandler(CORBA::Object_ptr obj,
                                          void* cookie,
                                          systemExceptionHandler_t fn);
}
The functions are equivalent to their counterparts for CORBA::TRANSIENT.

6.13   Location forwarding

Any CORBA operation invocation can return a LOCATION_FORWARD message to the caller, indicating that it should retry the invocation on a new object reference. The standard allows ServantManagers to trigger LOCATION_FORWARDs by raising the PortableServer::ForwardRequest exception, but it does not provide a similar mechanism for normal servants. omniORB provides the omniORB::LOCATION_FORWARD exception for this purpose. It can be thrown by any operation implementation.

class LOCATION_FORWARD {
public:
  LOCATION_FORWARD(CORBA::Object_ptr objref);
};
The exception object consumes the object reference it is passed.


1
omniORB is a class name if the C++ compiler does not support the namespace keyword.
2
This interface was first defined by Sun's NEO and is in used in Sun's JavaIDL.

Previous Contents Next