AbstractThis document specifies the UNO Remote Protocol version 1.0 (URP). This protocol is used to transmit UNO calls across process boundaries (comparable to IIOP in CORBA). This protocol was primarily designed to minimize the amount of transferred data for a series of one-way calls. The protocol does not make any assumptions about how the data is transferred. Basic Data RepresentationData is transferred as sequences of 8-bit bytes. Data is neither aligned nor padded. Multi-byte entities are transferred in network byte order (most significant byte first). Entities like “a 32-bit signed integer” or “a 16-bit unsigned integer” are represented in the obvious way. There is one special kind of entity that appears at various places in this
specification: A compressed number, which denotes a 32-bit unsigned
integer, is represented as either one byte or five bytes. If the first byte
equals Blocks and MessagesThe largest transferred unit is a block. It consists of a fixed-size block header, followed by zero or more messages:
A message may either be a request or a reply. It consists of a header and a body. Block HeaderThe block header consists of two 32-bit unsigned integers. The first integer specifies the size of the block in bytes, not counting the eight bytes of the block header. The second integer specifies the number of messages within the block. If both integers (the size and the message count) are zero, the block
constitutes a MessagesCaching ConceptTo minimize the amount of transferred data, URP uses caching. This means that URP is optimized for repetitive calls on the same or recently used UNO interfaces. The following three different kinds of entities are cached:
The caching used is the same for each of the three different kinds; below, it is explained for OIDs only, but TIDs and types are no different. There are two different caching mechanisms, a first-level cache and a second-level cache. First-Level CacheFor each of the two directions of an URP bridge, there is a last OID item (actually, there are individual last OID, last TID, and last type items). The two items for the different directions are completely independent of one another. The contents of a last OID item is affected exclusively by the sending side, as detailed below. (Both sides of an URP bridge will have a private copy of a last OID item, where these two copies will always be in sync. But that can be considered an implementation detail.) Initially, the last OID item is empty. The header of a request message specifies the OID of the object on which to make a call (correspondingly, it also specifies the TID of the thread from which to make the call, and the interface type on which to make the call). The header contains a flag that specifies whether to use the contents of the last OID item (in which case the last OID item must not be empty), or whether the header contains a new OID (which is then stored in the last OID item, overwriting any old contents). Second-Level CacheFor each of the two directions of an URP bridge, there is a cache table (actually, there are three individual cache tables for OIDs, TIDs, and types). The two cache tables for the different directions are completely independent of one another. The contents of a cache table is affected exclusively by the sending side, as detailed below. (Both sides of an URP bridge will have a private copy of a cache table, where these two copies will always be in sync. But that can be considered an implementation detail.) Initially, each cache table is empty. The caching mechanism uses cache indices, 16-bit unsigned integers. Let K ∈ [0 … 216 − 2] be the current cache table size. An OID can be transferred in either of two ways:
ObjectsObject Life CycleSee UNO Object Life Cycle Model for an explanation of the object life cycle concept and related terms. An URP bridge has to ensure that an object that has been transferred over the bridge can reliably be detected as done, once the object has transitioned to that state. The following describes the current mechanism to achieve this, but note that it is broken (see below). In the following, the notion of an object o together with an interface type t implemented by o is used, written as the tuple 〈o, t〉. Each side of an URP bridge maintains a reference count (a non-negative integer) for each tuple 〈o, t〉 that it has sent over the bridge (either as the target of a method call in a request message, or as the value of an interface type among the data of a request or reply message). Also, at any point in time, each side of an URP bridge considers a given tuple 〈o, t〉 as either bridged in or not. A tuple 〈o, t〉 is considered bridged in at one side of a bridge if and only if the corresponding reference count is positive at the other side of the bridge. A tuple 〈o, t〉 can only be used as the target of a method call in a request message while it is bridged in at the sending side. Each reference count starts out at zero. When sending the tuple 〈o, t〉 (as the value of an interface type among the data of a request or reply message), the sending side increments its reference count for 〈o, t〉, unless it considers as bridged in any tuple 〈o, t′〉, where t′ is a subtype of t (including t itself). If the same tuple appears multiple times in the data of a message, the corresponding reference count is incremented multiple times. For every tuple 〈o, t〉 that is bridged
in at one side of an URP bridge, that side has to eventually send a
When a tuple 〈o, t〉 becomes no longer bridged in at one side of an URP bridge, that side may no longer use that tuple (in particular, send it as the value of an interface type among the data of a message), unless it still has another reference of type t to o. An object o cannot become done as long as any side of any URP bridge has a positive reference count for any tuple 〈o, t〉, with arbitrary t. The optimization rule (to not increment the reference count for
〈o, t〉 when
〈o, t〉 itself or some subtype tuple
〈o, t′〉 is considered as bridged in)
is broken, as it leads to race conditions: Suppose there are three
environments, A, B, and C; each two
environments are connected via an URP bridge. Environment A has
a local UNO object o, and it has sent o to both
B and C. Both B and C
have a proxy for o (each of the two proxies forwarding to
environment A). Once this setup is established, we only
consider the bridge between B and C. Also, we can
ignore any interface types (just assume o only implements
For the bridge between B and C, initially both B and C have a reference count of 0 for the object o, and neither of them considers o to be bridged in. Assume B sends object o to C.
Lets call this Send1. The optimization rule does not
apply: B increments its reference count for o
to 1 as soon as it sends the message Send1 at
time t1, and C considers o to
be bridged in as soon as it receives the message at time
t2 > t1. (When C does
no longer need the o offered by B, it will send
back a Assume C sends object o to B (lets call this Send2) at about the same time as Send1 happens. C sends the message Send2 at time t3. There are two cases to consider:
But when B receives Send2, it cannot tell
which of the two cases occurred. Thus, B does not know whether to
send back a [TODO: This needs to be fixed.] Object IdentifiersEach UNO object is assigned a globally unique object identifier (OID), which is a non-empty ASCII string. How OIDs are assigned to UNO objects, and how it is ensured that they are globally unique is outside the scope of this document. Within URP, OIDs are used for four purposes:
ThreadsSee UNO Execution Model for a general description of threads in UNO, and for related terminology. Each UNO thread is assigned a globally unique thread identifier (TID), which is a non-empty byte sequence. How TIDs are assigned to UNO threads, and how it is ensured that they are globally unique is outside the scope of this document. (Note that global uniqueness is only required for the TIDs of active threads—an active thread may have the same TID as a done thread, i.e., TIDs may be recycled.) Generally, URP represents normal UNO interface method invocations as
synchronous calls, and one-way UNO interface method invocations as asynchronous
calls. This can be overridden with a To satisfy the requirements of the UNO execution model, each side of an URP bridge implementation must adhere to certain rules:
In language bindings that map (conceptual) UNO threads to “real” process threads, it may be useful to share this mapping across all URP bridges within one process (even across different language bindings): Assume that a synchronous request message with a given TID is sent out over some bridge. The process thread corresponding to the given TID will be blocked until a corresponding reply message is received back over that bridge. Further assume that within this time span a synchronous request message with the same TID is received over some other bridge. It is desirable, then, that this message is executed in the blocked process thread (temporarily unblocking it), so that it can share critical resources (e.g., mutices, thread local storage) with the blocked method execution. Function IDsThe function ID corresponding to a given interface type member function is defined to be the function index the member function maps to (see UNO Type System). It is an error for a function index that is used as a function ID to be outside the range [0 … 216 − 1]. Special MessagesApart from normal messages (that represent calls of methods on UNO objects), there are various kinds of special messages. The
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Bit name | Value | Description |
|---|---|---|
7 LONGHEADER |
1 | The first byte contains flags with further information about the message. |
| 0 | The message is a short request message with default flags. | |
| … | … | |
For a long message header, the second most significant bit of the first flag byte specifies whether the message is a request or a reply:
| Bit name | Value | Description |
|---|---|---|
7 LONGHEADER | 1 | |
6 REQUEST |
1 | The message is a request. |
| 0 | The message is a reply. | |
| … | … | |
A short request message encodes the function ID in the flag bytes (a short request message can only be used if the function ID is in the range [0 … 214 − 1]; otherwise, a regular request message must be used). It implicitly uses the first-level caching mechanism for types, OIDs, and TIDs. Its header consists of the one or two flag bytes only:
| Bit name | Value | Description |
|---|---|---|
7 LONGHEADER | 0 | |
6 FUNCTIONID14 |
1 | The message header consists of two flag bytes. The lower order 6 bits of the first byte contain the higher order bits of the function ID, and the 8 bits of the second byte contain the lower order bits of the function ID. |
| 0 | The message header consists of only one flag byte. The lower order 6 bits of the byte contain the function ID. | |
| … | … | |
Request Messages
A request message represents the call of a method m of an
interface type t at an object o (with a given
OID); the call is made from some UNO thread h (with a given
TID). The method m has a fixed sequence of parameters
〈x1 t1, …,
xk tk〉, k ≥ 0, where each xi
designates the parameter as either in, out, or
in-out, and each ti is a non-void,
non-exception type. If the method m is not defined as a one-way
method (or if a MUSTREPLY flag requires a reply nonetheless), the
request message will be followed by a reply message with the same TID, sent in
the opposite direction.
| Bit name | Value | Description |
|---|---|---|
7 LONGHEADER | 1 | |
6 REQUEST | 1 | |
5 NEWTYPE |
1 | The interface type t of the method call is given explicitly, as part of the message header. |
| 0 | The interface type t of the method call is given implicitly, using the first-level caching mechanism for types. | |
4 NEWOID |
1 | The OID of the method call is given explicitly, as part of the message header. |
| 0 | The OID of the method call is given implicitly, using the first-level caching mechanism for OIDs. | |
3 NEWTID |
1 | The TID of the method call is given explicitly, as part of the message header. |
| 0 | The TID of the method call is given implicitly, using the first-level caching mechanism for TIDs. | |
2 FUNCTIONID16 |
1 | The function ID is represented as a 16-bit unsigned integer. |
| 0 | The function ID is represented as an 8-bit unsigned integer. | |
1 IGNORECACHE |
1 | Do not update the last type, OID, and TID items of the
first-level cache for this request and any corresponding reply.
(Typically, when this bit is set, bits 3–5 will also be set,
i.e., the type, OID, and TID of the method call will be given
explicitly, as part of the message header, and will furthermore only
use the second-level cache index 0xFFFF; also, all
types, OIDs, or TIDs represented within the data of the messages
will typically be given explicitly, not taken from the second-level
cache, and will only use the second-level cache index
0xFFFF.) |
| 0 | Caching is used as defined. | |
0 MOREFLAGS |
1 | This byte is followed by a second flag byte. |
| 0 | This byte is the only flag byte. |
If a second flag byte follows, it specifies whether or not a reply is sent
back (flag MUSTREPLY), and whether the call is executed
synchronously or asynchronously (flag SYNCHRONOUS), overriding any
one-way definition of the method m. If no second flag byte
follows, the settings of the flags MUSTREPLY and
SYNCHRONOUS is specified by the definition of m: if
m is defined as a one-way method, both MUSTREPLY and
SYNCHRONOUS are implicitly set to 0; if m is
defined as a normal (not one-way) method, both MUSTREPLY and
SYNCHRONOUS are implicitly set to 1. It is an error if
MUSTREPLY and SYNCHRONOUS are not set either both
to 0 or both to 1.
It seems to be a historic mistake that there are two redundant bits,
MUSTREPLY and SYNCHRONOUS, that must always have the
same value.
| Bit name | Value | Description |
|---|---|---|
7 MUSTREPLY |
1 | A reply must be sent back. |
| 0 | No reply must be sent back. (For a method that would originally be synchronous, setting this bit to 1 means that information about the return value, the output values of out and in-out parameters, and thrown exceptions is effectively lost.) | |
6 SYNCHRONOUS |
1 | Execute the call synchronously. |
| 0 | Execute the call asynchronously. | |
| 0–5 reserved | 0 | When sending, these bits must be set to 0; when receiving, the values of these bits should be ignored. |
The flag bytes are followed by the function ID, either a 16-bit or an 8-bit unsigned integer.
If the NEWTYPE flag is set, then the interface
type t follows, represented as a value of type
TYPE.
If the NEWOID flag is set, then the OID follows. For its
representation, the second-level caching mechanism for OIDs is used. An
OID d is a non-empty ASCII string, and hence also a non-empty
Unicode string. The OID is represented as the representation of a Unicode
string d′ of type STRING, followed by a cache
index. If d′ is the empty string, the OID is taken from the
OID cache table. Otherwise, d = d′ is the OID.
Conversely, it is an error if the Unicode string d′ is not
also an ASCII string that is a valid OID. (This also implies that no valid OID
may be the empty ASCII string.)
If the NEWTID flag is set, then the TID follows. For its
representation, the second-level caching mechanism for TIDs is used. A
TID d, which is a non-empty byte sequence, is represented as the
representation of a sequence d′ of component type
BYTE, followed by a cache index. If d′ is the
empty sequence, the TID is taken from the TID cache table. Otherwise,
d = d′ is the TID.
The message header is finished then. The message body contains the input values of any in and in-out parameters from 〈x1 t1, …, xk tk〉, in that order. Each relevant value vi is represented as a value of type ti, for 1 ≤ i ≤ k.
Reply Messages
Each reply message corresponds to a request message. It represents the data (return value and output values of any out and in-out parameters, or any thrown exception) returned from the call represented by the corresponding request message. Apart from the fixed sequence of parameters 〈x1 t1, …, xk tk〉, k ≥ 0, the method m has a return value type t0 (which must be a non-exception type), and a set of exception specifications {e1, …, el}, l ≥ 0 (where each ei must be an exception type).
A reply message header has only one flag byte:
| Bit name | Value | Description |
|---|---|---|
7 LONGHEADER | 1 | |
6 REQUEST | 0 | |
5 EXCEPTION |
1 | The call terminated abnormally, by throwing an exception. |
| 0 | The call terminated normally. | |
| 4 reserved | 0 | When sending, this bit must be set to 0; when receiving, the value of this bit should be ignored. |
3 NEWTID |
1 | The TID of the method call is given explicitly, as part of the message header. |
| 0 | The TID of the method call is given implicitly, using the first-level caching mechanism for TIDs. | |
| 0–2 reserved | 0 | When sending, these bits must be set to 0; when receiving, the values of these bits should be ignored. |
If the NEWTID flag is set, the flag byte is followed by the TID,
as described for request messages above. The message header is finished
then.
If the EXCEPTION flag is set, the message body contains the
thrown exception, represented as a value
〈t′, v′〉 of type
ANY. The type t′ must be an exception type
that matches the set of exception specifications {e1,
…, el}.
If the EXCEPTION flag is not set, the message body contains the
return value v0, represented as a value of
type t0, followed by the output values of any out and
in-out parameters from
〈x1 t1,
…,
xk tk〉, in that order. Each relevant
value vi is represented as a value of
type ti, for 1 ≤ i ≤
k.
UNO Data Representation
See UNO Type System for a description of the UNO type system and related terms. Assume that v is a value of type t. The following specifies the representation of v of type t′, where t′ is determined by context, and will always be the same as t, except for struct, exception, and interface types.
Basic Types
A value of a basic type t is represented as zero or more bytes, in the obvious way:
| Type | Bytes |
|---|---|
VOID | 0 |
BOOLEAN | 1 |
BYTE | 1 |
SHORT | 2 |
UNSIGNED SHORT | 2 |
LONG | 4 |
UNSIGNED LONG | 4 |
HYPER | 8 |
UNSIGNED HYPER | 8 |
FLOAT | 4 |
DOUBLE | 8 |
CHAR | 2 |
STRING
A string is first converted into a sequence of bytes, using UTF-8. Let k ≥ 0 be the length of that sequence. The string is represented as the compressed number k, followed by the UTF-8–converted bytes. It is an error if k ≥ 232. Conversely, it is an error if the bytes do not form a valid UTF-8 encoding.
TYPE
A type is represented as one or more bytes. The seven lower order bits of
the first byte (b & 0x7F) specify the
type class (see also the enum type com.sun.star.uno.TypeClass):
| Type | b &
0x7F |
|---|---|
VOID | 0 |
BOOLEAN | 2 |
BYTE | 3 |
SHORT | 4 |
UNSIGNED SHORT | 5 |
LONG | 6 |
UNSIGNED LONG | 7 |
HYPER | 8 |
UNSIGNED HYPER | 9 |
FLOAT | 10 |
DOUBLE | 11 |
CHAR | 1 |
STRING | 12 |
TYPE | 13 |
ANY | 14 |
| sequence types | 20 |
| enum types | 15 |
| struct types | 17 |
| exception types | 19 |
| interface types | 22 |
It is an error if the seven lower order bits have a value not listed
above. The higher order bit of the first byte (b &
0x80) is a cache flag.
For a simple type, only the first byte is needed. The cache flag must be set to 0.
For a complex type, the second-level caching mechanism for types is used.
The first byte is followed by a cache index. If the cache flag is zero, the
type is taken from the type cache table. If the cache flag is one, the name of
the type follows, represented as a value of type STRING.
The decision to represent complex types by both type class and name leads to some redundancy. For sequence types, for example, a better approach would be to represent a sequence type as the type class byte 20 followed by the encoding of the component type.
ANY
Let v =
〈t1, v1〉 be a value
of type ANY. It is represented as the representation of
t1 of type TYPE, followed by the
representation of v1 of
type t1.
Sequence Types
Let v = (v1, …, vk), k ≥ 0, be a value of the sequence type with component type tc. It is represented as the compressed number k, followed by the representations of v1, …, vk of type tc, in that order. It is an error if k ≥ 232.
Enum Types
Let v = n, n ∈ [−231 … 231 − 1], be a value of an enum type. It is represented as the 32-bit signed integer n. Conversely, it is an error if a 32-bit signed integer n shall represent a value of some enum type, and that enum type does not contain a member with numeric value n.
Struct and Exception Types
Let v = 〈v1, …, vk〉 be a value of the struct or exception type t = 〈t1, …, tk〉, k ≥ 0 (where the ti include any members inherited from a possible parent type). Assume that v is to be represented as a value of type t′, where t′ = 〈t1, … tl〉, 0 ≤ l ≤ k, is a supertype of t. The value v is first converted into a value v′ = 〈v1, …, vl〉 of type t′, by slicing it. The value v′ is then represented as the combination of the representation of vi of type ti, for i from 1 to l.
Interface Types
Let v be a reference of interface type t, either
the null reference or a reference to a UNO object o with
OID d. Assume that v is to be represented as a value
of type t′, where t′ is a supertype
of t (but note that this type t′ is
irrelevant for the representation of v). If v is the
null reference, it is represented as the representation of the empty
STRING, followed by the special cache index 0xFFFF.
Otherwise, it is represented as the representation of the OID d,
as described for request messages above.
Protocol Properties
Properties may be used to customize bridge-internal settings. Special messages are used to change protocol properties (see Messages for Accessing and Manipulating Protocol Properties).
| Name | Type | Description |
|---|---|---|
CurrentContext |
ANY |
Changing this property (to an arbitrary
ANY value) enables a mode in which the UNO current
context is passed across URP.An implementation of an URP bridge may fail to change this property (i.e., raise a com::sun::star::bridge::InvalidProtocolChangeException
exception in response to a commitChange message). Each
implementation of an URP bridge should try to change this property
as soon as the bridge is established. (Early bridge
implementations failed to pass the current context across the
bridge, and that needed to be changed in a compatible
way.)When the current context mode is enabled, the message body of every non-special request message is prefixed by the UNO current context (in the respective thread) as a value of type com::sun::star::uno::XCurrentContext. |
|
Authors: Jörg Budischewski, Stephan Bergmann, Kai Sommerfeld (last modification $Date: 2006/11/08 16:48:26 $). Copyright 2001 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303 USA. |


