Go to the previous, next section.
ILU includes a number of internal interfaces that allow various functionality of the ILU kernel library to be replaced by user functionality.
malloc()
failures
in application-specific ways.
Every ILU address space uses either real threads, or some sort of event dispatching loop to simulate threads. ILU is thread-safe internally, and by default will continue to check its usage for even when event dispatching is used. Since many different thread systems and event dispatching loops exist, ILU provides interfaces to allow the user to describe the particular one that they're using to the ILU kernel. See section section Threads and Event Loops for more information on these topics. See `ILUSRC/runtime/kernel/iluxport.h' for documentation of the interfaces.
The ILU remote procedure call mechanism operates in layers.
Each
object reflects a particular mapping of the
abstract ILU RPC protocol onto a specific externally-defined RPC protocol.
(See section Protocols and Transports for a discussion of the abstract ILU protocol,
and how it is mapped to the ONC RPC protocol, and to the XNS Courier
protocol.)
ilu_Protocol
New RPC message protocols can be added to the ILU kernel
by writing a new
object, and calling the ILU kernel function ilu_Protocol
.
register it. The structure and
requirements of an ilu_RegisterProtocol()
object are defined in the file
`ILUSRC/runtime/kernel/iluprotocol.h'; the methods of the protocol
are considered to be `inside' the ILU kernel, and must therefore conform
to all ILU locking and error conventions. The locking conventions
are discussed in `ILUSRC/runtime/kernel/iluxport.h'; the error
conventions are documented in
ilu_Protocol
`ILUSRC/runtime/kernel/iluerror.h',
and pre-defined errors are documented in
`ILUSRC/runtime/kernel/iluerrs.h'.
Various examples of ILU protocols are available for study:
In general, ILU protocols form `messages' consisting of sequences of bytes, which are then passed to the ILU transport layer to be conveyed to another address space. The transport layer itself is composed of one or more ILU transport filters, each of which handles the message in turn. These filters are either communication filters, such as the filters which actually convey messages via TCP/IP or UDP/IP, or transformation filters, which alter the message and pass it to another transport filter, such as the ONC RPC record-marking filter, or the secure transport filter.
Each transport filter is either reliable or unreliable. All transformation filters are reliable; communication filters may or may not be reliable. A communication filter is reliable if it guarantees that any messages handed to it for transport will be reliably delivered to the other end of the communication connection. This in turn means that the communication mechanism used by the transport will take care of timeouts, retries, etc., internally, so that the ILU application need not worry about these itself. Unreliable communication filters are those which may require ILU participation in timeout and resending of messages to achieve reliable delivery.
Each filter is also either boundaried or non-boundaried. Boundaried filters are those which can comprehend and preserve message boundaries. Non-boundaried filters simply deal in chunks of bytes and have no way to recognize or preserve message boundaries. Various protocols and filters may have requirements as to whether the next filter below it in the communication stack is boundaried or non-boundaried.
New transport filters may be registered with the ILU kernel by
calling the kernel function
, described in
`ILU/runtime/kernel/iluxport.h', with the name of a new
transport filter and the address of a routine which returns an instance
of the new transport object type. Implementing a new transport
object type actually consists of implementing several related object types,
including ilu_RegisterTransport()
, ilu_TransportCreator
,
and ilu_TransportClass
. These object types are defined in the
file `ILUSRC/runtime/kernel/ilutransport.h'.
ilu_Mooring
As with protocols, the methods of the transport filter are considered to be `inside' the ILU kernel, and must therefore conform to all ILU locking and error conventions. The locking conventions are discussed in `ILUSRC/runtime/kernel/iluxport.h'; the error conventions are documented in `ILUSRC/runtime/kernel/iluerror.h', and pre-defined errors are documented in `ILUSRC/runtime/kernel/iluerrs.h'.
Examples of transformation filters may be found in `ILUSRC/runtime/kernel/sunrpcrm.c', which is a boundaried filter implementing ONC RPC's TCP/IP record marking scheme, and `ILUSRC/runtime/kernel/security.c', which is a non-boundaried filter implementing message integrity, sender authentication, and message privacy. Examples of communication filters may be found in `ILUSRC/runtime/kernel/newtcp.c', which is a non-boundaried reliable filter implementing data communication via TCP/IP, `ILUSRC/runtime/kernel/udp.c', which is a non-boundaried unreliable filter implementing data communication via UDP/IP, and `ILUSRC/runtime/kernel/inmem.c', which is a boundaried reliable filter implementing intra-address-space communication via memory buffers.
ILU true objects live in kernel servers, a kernel data structure that handles communication and other aspects of the object implementation. When an object reference is received from another address space, the kernel server is responsible for mapping this reference to an actual object. Normally, the kernel server simply consults an internal hash table for an object corresponding to a specified `instance handle'; however, an application may register an application-specific callback function to be used instead. This allows on-the-fly creation of objects, which is often vital when handling many objects. Actual in-memory representations of the objects can be garbage-collected, then dynamically re-incarnated when needed by a client.
The application registers this functionality by creating an implementation of
an
object, and passing that implementation as a parameter
to ilu_ObjectTable
when creating the kernel server. Typically,
ilu_CreateTrueServer
is called directly only by a language-specific runtime;
the actual application would work with object tables via whatever mechanism is
exported by the language-specific runtime. Check the documentation for your
particular language runtime for more information.
ilu_CreateTrueServer
ILU regards string binding handles generically as a way of encoding four pieces of information: the instance handle for an object, the server ID for an object, the most-specific type ID (MSTID) for an object, and communication information about how to communicate with that object, which we call contact-info. It further restricts them to conform to the URL syntax specified in the World Wide Web Consortium and IETF standard RFC 1738 (http://www.w3.org/pub/WWW/Addressing/rfc1738.txt). But this still allows ILU to support any number of URL schemes, which we define as some way of encoding these four pieces of information which conforms to the URL syntax rules.
The default URL scheme is called ilu:
, and encodes the information as
ilu:<server-id>/<instance-handle>;<MSTID>;<contact-info>
Most of these elements consist of US-ASCII strings with various additional constraints. The strings are encoded in what is called the SBH element encoded form: the set of alphanumeric characters plus the 4 characters DOLLAR (`$'), HYPHEN (`-'), PERIOD (`.'), and PLUS (`+') are represented by the character itself; other characters are escaped via the mechanism specified in RFC 1738: each is represented with 3 characters, a PERCENT (`%') character followed by two hexadecimal digits giving the US-ASCII character code for the escaped character.
The non-encoded form of the <server-id> and <instance-handle> strings may contain any character except for US-ASCII NUL.
The non-encoded form of the <MSTID> consists of the following
<type-id-scheme>:<type-id>
where the <type-id-scheme> consists of US-ASCII alphanumeric characters, and any constraints on <type-id> are specified by the <type-id-scheme>.
The <contact-info> is not encoded in the same way as the other fields. Rather, it consists of a series of communication info fields, separated by SEMICOLON (`;') characters. Each communications info field has the form
<protocol-info>@<transport-layer>[=<transport-layer>...]
where each of the <protocol-info> and <transport-layer> elements contain SBH element-encoded strings. The non-encoded form of these strings has an additional constraint: each must begin with the name or identifier for the protocol or transport layer it specifies, optionally followed by an UNDERSCORE (`_') character and any parameters for the protocol or transport. The name of the protocol or transport may not contain any UNDERSCORE (`_') characters. There are no additional ILU constraints on the formats used to represent parameters for the protocol or transport.
An application
can register a parser for one or more application-specific URL schemes
by calling the function
. It takes as an argument a function
which will accept a URL string, and return the four components required by ILU.
For instance, you might want to use a URL scheme for
the OMG CORBA ilu_RegisterSBHParser
IIOP
something like
iiop_1_0://<hostname>:<port>/<server-id>/<ih>
which can be considered to contain an instance handle of <ih>, a server ID of
<server-id>, an implicit object type of IDL:omg.org/CORBA/Object:1.0
,
and contact-info ofiiop_1_0_1@tcp_<hostname>_<port>
.
Or, you might want to use an HTTP
URL for an ILU object which
is exported via the HTTP
ILU protocol. Suppose that the normal ILU
string binding handle for the object was
ilu:tcp_1.2.3.4_20000//http_obj0;ilu:Ilu_Http_Type;http_1_0@tcp_1.2.3.4_20000
An alternate form which would be compatible with Web browsers would be
http://1.2.3.4:20000//http_obj0
with an implicit server ID of tcp_1.2.3.4_20000
, an implicit MSTID of
ilu:Ilu_Http_Type
, an instance handle of /http_obj0
,
and contact-info of http_1_0@tcp_1.2.3.4_20000
.
See the `ILUSRC/runtime/kernel/iluxport.h' for details on how
to use
.
ilu_RegisterSBHParser
As discussed in section Identities, application-specific identity types can be
registered with the ILU kernel for use with various authorization and
accounting schemes, and to support various forms of security in wire protocols
and transports. An application does this by creating a new value of type ilu_IdentityType
,
as specified in `ILUSRC/runtime/kernel/iluxport.h', and calling the
kernel function ilu_RegisterIdentityType
. After this is done, values of the new identity
types may be used. The major use for these identity types is to work together with
new application-specific RPC protocols and message transports (described above),
to implement various security and access policies for distributed systems.
Note that the mere act of registering a new identity type with the ILU
kernel will not cause values of that identity type to be automatically transmitted
in ILU calls. This will only happen if an appropriately designed transport
or protocol, which knows to do this, is also used. For experimental purposes, we
provide a switch will will cause the various flavors of Sun RPC
implemented for ILU
to automatically pass one specific identity type. To enable this, set the
environment variable ILU_SUNRPC_PREFERRED_IDENTITY
to the name of the identity
type to be passed automatically before running any of your ILU programs.
By default, the Sun RPC
protocols will automatically pass the UNIX
identification of the caller (the user id, group id, host IP address, and list of
groups to which the caller belongs). The identity type for this information is
called "SunRPCAuthUnixIdentity"
. To prevent its being passed automatically,
set the environment variable ILU_NO_SUNRPC_UNIX_AUTH
to any value before
running your ILU programs.
ILU uses a number of internal interfaces to allocate and free memory,
such as
, ilu_malloc()
, and ilu_free()
.
These functions wrap calls to the standard ilu_realloc()
, etc., in wrappers
that allow for better error handling. They are documented in
malloc()
`ILUSRC/runtime/kernel/iluxport.h'.
Applications can register callback functions to handle malloc
failures,
in two ways. The kernel function
allows registration
of routines which can be called to free up memory, to allow a ilu_AddFreer()
malloc
call
to succeed. The kernel functions
and
ilu_SetMemFaultAction()
allow applications to determine what action
should be taken if a ilu_SetMemFaultConsumer()
malloc
failure occurs.
ILU includes a comprehensive error-signalling system in the kernel library,
which is documented in `ILUSRC/runtime/kernel/iluerror.h'. In addition,
the kernel library contains many calls to
, which check that
various kernel invariants are maintained. When a runtime assertion fails,
the kernel may either call an application-specified failure handler, set
by a call to _ilu_Assert
, or take one of three
default actions, chosen by a call on ilu_SetAssertionFailureConsumer()
.
The three default actions are (1) to generate an illegal instruction trap,
and thus coredump; (2) to exit with some error code; and (3) to enter an endless
loop, calling ilu_SetAssertionFailureAction()
repeatedly. The third action is the default
action; the intent is to stop the program with all invalid data intact on the
stack, and network connections intact, so that a debugger may attach to the `live' process.
sleep()
The ILU kernel contains a large number of debugging print statements,
which document various things going on inside the kernel. The specific things
printed may be controlled by calling either
or
ilu_SetDebugLevel()
. The specific bits which can be specified
to ilu_SetDebugLevelViaString()
, or names which can be specified to
ilu_SetDebugLevel()
, are documented `ILUSRC/runtime/kernel/iludebug.h'.
ilu_SetDebugLevelViaString()
All debugging messages are displayed via calls to the kernel function
.
Normally, this routine simply calls ilu_DebugPrintf()
vfprintf (stderr, ...)
to actually output the messages.
However, this can be changed to call some
application-specific message output system by calling
,
documented in `ILUSRC/runtime/kernel/iluxport.h'. Two special values
are defined for, and accepted by, ilu_SetDebugMessageHandler()
; the value
ilu_SetDebugMessageHandler()
causes the debug system to revert to the
original output handler; the value ILU_DEFAULT_DEBUG_MESSAGE_HANDLER
causes the debug system to
simply discard any debugging messages.
ILU_NIL_DEBUG_MESSAGE_HANDLER
Debugging output can be directed to a file, by calling
with
a filename as an argument. The file will be created, and debugging messages will be written to it.
ilu_SendDebugOutputToFile()
Go to the previous, next section.