OpenOffice Uno Remote Protocol 1.0
Specification

Abstract

This document specifies the Uno Remote Protocol V1.0 (urp). This protocol is used to transmit UNO calls via process-boundaries ( comparable to iiop in CORBA).

This protocol was primarily designed to minimize the amount of transferred data for a series of oneway calls. The protocol does not make any assumptions about how the data is transferred.

Messages and blocks


The largest transferred unit is an urp block. It consists of a block header and an arbitrary amount of messages.

A message may either be a request or a reply. It consists of a header and a body.

Blocks

Block header

The blockheader contains the size of the block beginning after the blockheader in bytes and the number of messages within the block.

long size;
long messageCount

0 == size and 0 == messageCount signals a CloseConnection message. The block body is empty. No further messages must be dispatched, the dispatcher thread should terminate.

Block body

The blockbody consist of messageCount message one after one without any padding.

Messages

Caching concept

To minimize transferred amount of data, urp has chosen caching. This means, urp is optimized for receptive calling on the same or recently used interfaces.

Each process owns two caching tables, one for sending and one for receiving. These caches are independent of each other, the sender always determines, what is in the cache. The cache sizes are bridge properties, which can be modified at runtime ( see below).

The following values are cached :

  • ThreadIdentifier (Tid)
  • ObjectIdentifier (Oid)
  • Types

The caching concept is the same for Tid, Oid and Type, below it is explained for oids only, but ThreadId and types are not different.

There exists a so called first-level-cache and second-level-cache.

1st level : This cache is not used for parameter marshaling, it is only used for transferring data about the object to call on. In case the Oid (of the object to call on) changed since the last call, the id is transfered (see below for the marshaling format of interfacereferences). If the oid did not change, no oid is transfered. This is signaled with flags in the MessageHeader.

2nd level : An oid is sent always bundled with a cache index. The receiver must store an association of cache index and oid ( in general in an array ). If the same oid needs to be sent again, only the cache index is sent. A cache index can be overwritten, if a different oid is sent with a previously used cache index. A cache index with the value 0xffff is an invalid index, it can be used to indicate, that the oid should not be cached. It is the senders responsibility to choose the strategy about how the cache is updated. A least-recently-used cache is probably a good choice for most applications.

MessageHeader

The message starts with a byte. The most significant bit decides, whether the message has a short or a longheader.

Bit
Name

value

1st byte

7

LONGHEADER


1

This byte contains a bitfield, that contains further information about the message (see Table bitfield description)

0

This message is a request with default flags. This implies, that the request is executed on the same interface and with the same threadid as the predecessor request.


If Bit 6 is not set, the MethodId can be found within the lower 6 bit of this byte.
If Bit 6 is set, the following byte contains the lower byte of the method id and the lower 6 bit of this byte contain the higher 6 bit of the method id.

The message header is finished after the method id.

Bit
Name

value

1st byte, bitfield description (bit7== 1)

6

REQUEST

1

This message is a request (see table request description).

0

This message is a reply (see table reply description ).

Request

Bit
Name

value

request description 1st byte (bit7==1, bit6 ==1)

5

NEWTYPE

1

The interfacetype of the stub, that shall be called on, changes. Therefor a new interfacetype is marshaled.

0

The interfacetype of the stub, that shall be called on, does not change

4

NEWOID

1

The object identfierof the stub, that shall be called on, changes. Therefor a new object identifier is marshaled.

0

The object identifier of the stub, that shall be called on, does not change

3

NEWTID

1

The thread, that shall be used to execute the request, changes. Therefor a new thread id is marshaled.

0

The request is executed in the same thread as before.

2

LONGMETHODID

1

The following method is is marshaled as an unsigned short. (This happens in general, when the method id is larger than 255 ).

0

The methodid is marshaled as an unsigned byte.

1

IGNORECACHE

1

Ignore all caching for this request and for the reply, that will be sent for this request. This means, that every oid, threadid or type, that is used in this request, must be sent complete with invalid cache ids (== 0xffff). Even the “1st level cache” (last ThreadID, last ObjectID and last Type) must remain unchanged.

Setting this bit implies, that bit 5, 4 and 3 are also set.

Note that if this request initiates another request, the new request will in general be marshaled by using and modifying the cache.

0

Caching takes place as usual.

0

MOREFLAGS

1

This byte is followed by another byte, that contains additional flags.

0

This byte is followed directly by the methodid in the format described by bit2.

If bit MOREFLAGS is set, there follows a 2nd byte as bitfield. In case MOREFLAGS is not set, the values default to method declaration in IDL. (If the call is declared synchronous, bit MUSTREPLY and bit SYNCHRONOUS would be both set to 1. If the call is declared asynchronous, both bits would be set to 0.

So the second byte must only be sent, if the default should be changed.

Bit
Name

value

request description 2nd Byte (1st byte bit MOREFLAGS == 1)

7

MUSTREPLY

1

A reply for this request MUST be sent after the request finishes.

Note : This is independent of the method declaration in IDL. This should allow the application programmer to customize calls on demand.

0

A reply for this request MUST NOT be sent.

Note : This is independent of the method declaration in IDL. This should allow the application programmer to customize calls on demand

6

SYNCHRONOUS

1

Execute the thread using the synchronous threadID ( Enque the request in your threadpool as sync).

Note : This is independent of the method declaration in IDL. This should allow the application programmer to customize calls on demand

0

Execute the thread using the asynchron threadID (Enque the request as a asynchron thread).

Note : This is independent of the method declaration in IDL. This should allow the application programmer to customize calls on demand

The initial byte or bytes is/are followed by the methodid in the format specified by LONGMETHOID of the 1st byte.

The methodId is the index of the method as the interface appears in IDL-description (save attributes). It is an index over all methods including superinterfaces. All attributes always appear before normal methods. A read-only attribute counts as one method, a readwrite attribute counts as two methods.

The methodId must be smaller than 0x4000 ( == 16384 ).

If signaled by the flags, the message header is followed by the new oid, new type and new ThreadId.

The oid is marshaled as interfacereference ( see below ).

The type of the interface is marshaled as Type (see below).

The threadid is marshaled as the following struct :

struct ThreadId
{
   sequence< byte > full;
   unsigned short cache;
};

After the message header, all in parameters are marshaled as they appear in the method signature.


Reply

Bit

value

reply description 1st Byte (bit6==1)

5

EXCEPTION

1

The request has thrown an exception.

0

The request has returned normally.

3

NEWTID

1

The thread, that has executed the request, is different from the last one that sent a request or a reply. Therefor a new thread id is marshaled.

0

The thread, that has executed the request is the same, that has sent a reply or a request before. Therefor the threadid is not changed.

If signaled by the NEWTID-flag, the message header is followed by a new threadId (format see above).

In case the EXCEPTION flag is set, an any, that contains the exception, follows. Otherwise, the return value and all out-parameters are marshaled.

Value marshaling

This chapter describes, how a value of an arbitrary datatype is marshaled.

Compressed numbers

Compressed numbers are transported the following way :

If the first byte == 0xff, the following 4 byte contain the number.

If the first byte < 0xff, it contains the number.

Primitive types

All primitive marshaling is done using network byte order, this means most significant byte is marshaled first. Data is not aligned to minimize package size.

Datatype

Marshaled length

byte

1

boolean

1

short,unsigned short

2

long, unsigned long,float

4

char (Unicode char)

2

hyper, unsigned hyper, double

8

void

0


enum

The enum value is marshaled as enum value as specified in idl. The enum value is marshaled as long

Constructed types

struct

Structs are marshaled element by element. The elements are in the same order as specified in IDL.

exception

Exception are marshaled the same way as structs are.

sequence

The number of elements is marshaled followed by all elements. The number of elements n is marshaled compressed.

strings

Strings are transported in the UTF-8 format. The length of the UTF-8 strings is marshaled followed by the utf-8 string without the 0 termination byte. The length is marshaled compressed.

Interface references

Only the Object-Identifier (OID) must be marshaled. The type of the reference is known from the context.

The oid is marshaled using the following struct.

struct InterfaceReference
{
	sequence < byte > full;
	unsigned short cache;
};

If the byte sequence is empty, the cache is valid and the cache value must uniquely identify a reference, that was mapped before.

If the byte sequence is not empty, it contains the complete object id. In this case, the member “cache” contains the cacheid, which will be used the next time, the same reference needs to be marshaled. If cached == 0xffff, the id is not cached at all.

Typedefs

Typedef marshaling is delegated to the original type.

Type

Types are introduced by a byte. It contains the type class( byte & 0x7f ). If this is a simple type (string,type,any,or numbers), the type is marshaled complete.

If the type is not simple, the byte is followed by an unsigned short, which contains the cache entry. If the cache entry == 0xffff, the following type must not be cached (This may be necessary when e.g. a message must not use the cache).

If (byte & 0x80) is zero, the type can be retrieved from the cache using the unsigned short and type marshaling is completed.

If (byte & 0x80) is not zero, the cache value is followed by the name of the type as ascii-string. The type must be inserted in the cache with the given cache entry.

Any

Any is marshaled as type followed by the value.


Protocol properties

Properties may be used to customize bridge internal settings for application dependent requirements.

Properties can be accessed using uno-calls to a special bridge internal object. One can access the object using the oid “UrpProtocolProperties”. Calls to the object can be delivered directly without having a proxy on it. No release on the object is necessary. The Object supports the com.sun.star.bridge.XProtocolProperties interface (see below).

There may exists read and read/write properties. Read properties only inform about the status of the bridge, they cannot be modified from remote.

Every read/write property has a default value. The bridge MUST be initialized with the stated default values.

Note that each implementation of the UNO protocol MUST be able to work with the default values.

Below you find the supported properties for URP V1.0.

The properties may modify the complete binary format of the protocol. This can be done, because there is an exactly defined timespan, when both sides of the bridge change the properties. This is a little nasty to implement, but offers best flexibility.

Name

access

Type

Default value

Description

BridgeId

read

sequence< byte>

-

An id, that uniquely identifies one bridge within the process ( e.g. the bridge pointer). This value can be used to generate unique oneway threadids.

TypeCacheSize

read write

long

256

The number of available slots for caching types.

OidCacheSize

read write

long

256

The number of available slots for caching object identifiers.

TidCacheSize

read write

long

256

The number of available slots for caching Thread identifier.

SupportedVersions

read

string

-

A comma seperated list of version numbers, that are supported.

Version

read write

string

“1.0”

The version of the protocol, that is used.

FlushBlockSize

read write

long

4096

If the marshaled amount of data for a sequence of oneway calls exceed FlushBlockSize, the calls are sent immeadiatly

OnewayTimeoutMUSEC

read write

long

10000

The timeout that is used for sending oneway calls (in µs).

ClearCache

read write

boolean

0

The whole cache (including “1st level cache”) is invalidated when this property is commited with 1 value.

SupportsMustReply

read

boolean

-

States, if the remote counterpart supports the MUSTREPLY flag, so that calls also send a reply, that are declared as oneway.

SupportsSynchronous

read

boolean

-

States, if the remote counterpart supports the synchronous flags, so that an synchronous call can be executed using the asynchronous threadID.

SupportsMultipleSynchronous

read

boolean

-

States, if the remote counterpart supports the feature, that multiple synchronous calls can be sent without waiting for the reply.

Negotiate

read

boolean

0

When this property is set during bridge startup, the bridge does not negotiate with the remote counterpart for properties. Instead all requested properties are set blindly. This requires, that the remote counterpart is started with the same set of properties.

ForceSynchronous

read write

boolean

0

All oneway calls must be executed synchronous. If a oneway declared method is called, the flags MUSTREPLY and SYNCHRONOUS must be set to override the default declared in IDL.

Tabelle 1URP Properties V1.0



IDL-Declaration of ::com::sun::star::bridge::XProtocolProperties

/******
 * INTERNAL INTERFACE, DO NOT USE IT ELSEWHERE
 * Bridge internal interface, that allows to change protocol settings
 * of the remote counter part. In general, this interface is implemented by the
 * bridge itself. It must not be called from outside the bridge.
 *****/
[ uik(A7EF98B1-8D82-11d4-9F1B0050-04D7755D), ident( "XProtocolProperties", 1.0 ) ]
interface XProtocolProperties : com::sun::star::uno::XInterface
{
	/***
	 * Called to get a list of bridge internal properties.
	 * Which properties can be retrieved, is protocol
	 * dependend. The properties MUST NOT change between a
	 * requestChange and a commit change call.
	 ***/
	sequence< ProtocolProperty > getProperties( );

	/****
	 * Called to initiate a protocol change. This method
	 * should always be called in the scope  of the local
	 * bridge setting object, because the remote counter part
	 * may do such a call
	 * at the same time (typically at startup time).
	 *
	 * @param nRandomNumber In case both processes call
	 *                      requestChange at the same time,
	 *                      the caller with the higher
	 *                      nRandomNumber is allowed to call
	 *                      commitChange.
	 * @returns 1, if the caller may ( and MUST !!!) call
	 *             commitChange.
	 *          0, if the caller is not allowed to call
	 *             commitChange. This can only happen, if the
	 *             other bridge has called requestChange at
	 *             the same time and nRandomNumber is smaller
	 *             than the other bridge's nRandomNumber. The
	 *             remote counterpart is supposed to call
	 *             commitChange within a small time span. Please
	 *             call requestChange() after the remote
	 *             counterpart has called commitChange().
	 *          -1 if the nRandomNumber is of the same value as
	 *             the previously sent requestChange (sent by the
	 *             remote counterpart). This is a draw :o).
	 *             Generate a new random number and try again.
	 ****/
	long requestChange( [in] long nRandomNumber );

	/****
	 * Called to commit a protocol change. It is only allowed to
	 * call commitChange, if requestChange has been called
	 * previously and the return value was true.
	 * The new properties are valid after the reply of
	 * commitChange has been received. Note, that this is
	 * difficult for the callee, because it must marshal the reply
	 * with the old settings.
	 * All properties not mentioned in the list are unchanged.
	 * Note that the bridge must be blocked for other threads,
	 * before commitChange is sent and unblocked
	 * after the reply has been received. This blocks the bridge.
	 * 
	 * @raises InvalidProtocolChangeException
	 *              when the remote counterpart could not change
	 *              at least one of the properties. No property
	 *              has been changed. requestChange must be called
	 *              again to initiate a new change of the protocol.
	 ****/
	void commitChange( [in] sequence< ProtocolProperty > newValues )
		raises ( com::sun::star::bridge::InvalidProtocolChangeException );
};

Author: Jörg Budischewski ($Date: 2001/08/09 13:37:54 $)
Copyright 2001 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303 USA.