Uno/Remote/Specifications/Uno Remote Protocol

From Apache OpenOffice Wiki
Jump to: navigation, search

RPC is a convenient but flawed accident of historySteve Vinoski

Abstract

This 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 Representation

Data 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 0xFF, the following four bytes represent an integer in the range [0 … 232 − 1]. If the first (and only) byte is less than 0xFF, it represents an integer in the range [0 … 254]. Integers in the range [0 … 254] can thus be represented as either one byte or five bytes; both forms are valid, but the shorter form is preferred.

Blocks and Messages

The largest transferred unit is a block. It consists of a fixed-size block header, followed by one or more messages:

Block header:
 size
 message count
Message 1
 …
Message k

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

Block Header

The 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.

The given size must match the actual size exactly (that is, there must not be any excess bytes after the last message in the block). The message count must not be zero.

Messages

Caching Concept

To 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:

  • Object identifiers (OIDs)
  • Thread identifiers (TIDs)
  • Types

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 Cache

For 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 Cache

For 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. The cache table size is K = 256. (Historically, the cache table size was intended to be dynamically changeable, hence the use of 16-bit qunatities.) An OID can be transferred in either of two ways:

  • As an OID together with a cache index. The OID is entered into the cache table at the given index. The cache index must be in the range [0 … K − 1]. (If the cache table already contains an entry for the given index, the old entry is overwritten.) As a special case, if the cache index equals 0xFFFF, the OID is not entered into the cache table.
  • As only a cache index. The cache index must be in the range [0 … K − 1], and the cache table must contain an entry for that index. The transferred OID is the cache table entry at the given index.

Objects

Object Life Cycle

See 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 〈ot〉. Each side of an URP bridge maintains a reference count (a non-negative integer) for each tuple 〈ot〉 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 〈ot〉 as either bridged in or not. A tuple 〈ot〉 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 〈ot〉 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 〈ot〉 (as the value of an interface type among the data of a request or reply message), the sending side increments its reference count for 〈ot〉, unless it considers as bridged in any tuple 〈ot′〉, 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 〈ot〉 that is bridged in at one side of an URP bridge, that side has to eventually send a release message for 〈ot〉 to the other side. Each release message causes the receiving side to decrement its corresponding reference count by one. It is an error to send a release message for a tuple while it is not bridged in at the sending side.

When a tuple 〈ot〉 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 〈ot〉, with arbitrary t.

The optimization rule (to not increment the reference count for 〈ot〉 when 〈ot〉 itself or some subtype tuple 〈ot′〉 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 com.sun.star.uno.XInterface).

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 notapply: 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 release message to B, which will in turn drop its reference count for o back to 0.)

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:

  1. If t3 < t2 (Send1 has not yet reached C), the optimization rule will not apply, and C increments its reference count for o to 1.
  2. If t3 > t2 (Send1 has already reached C, and C considers o to be bridged in), the optimization rule does apply, and C does not increment its reference count for o (which stays at 0).

But when B receives Send2, it cannot tell which of the two cases occurred. Thus, B does not know whether to send back a release message to C.

[TODO: This needs to be fixed.]

Object Identifiers

Each 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:

  • To identify the object that is the target of a method call in a request message.
  • To identify an object for which a reference to that object is the value of an interface type among the data of a request or reply message.
  • As initial object identifiers in queryInterface messages to request initial objects, see The queryInterface Message.
  • The special OID UrpProtocolProperties is used to identify certain special messages; see Protocol Property Messages.

Threads

See 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 MUSTREPLY flag: On the one hand, one-way UNO interface method invocations can be forced to use synchronous instead of asynchronous calls; doing so is in accordance with the specification of the UNO execution model. On the other hand, normal UNO interface method invocations can be forced to use asynchronous instead of synchronous calls (with a MUSTREPLY flag set to 0); doing so violates the specification of the UNO execution model, and should thus be avoided.

To satisfy the requirements of the UNO execution model, each side of an URP bridge implementation must adhere to certain rules:

  • When sending a synchronous request message with the TID of a UNO thread h, the sending side will not execute any computation steps in thread h (especially, it will not send any further request or reply messages with the given TID), until it receives back the corresponding reply message.
  • When sending an asynchronous request message with the TID of a UNO thread h, the sending side simply continues to execute computation steps in thread h. It does not wait for any reply message.
  • For each TID, the receiving side maintains a queue of pending request messages received with that TID. Upon receiving a synchronous or asynchronous request messages with a given TID, the receiving side enqueues it at the end of the corresponding queue.
  • Whenever a synchronous request message becomes the first entry in a queue for a given TID (of some UNO thread h), the receiving side starts to sequentially execute the computation steps corresponding to the requested UNO interface method, in thread h. It uses the TID of thread h for all request messages sent while executing these computation steps. When it is finished with the computation steps, it sends back a reply message (with the given TID), and the synchronous request message is removed from the head of the queue.
  • Whenever an asynchronous request message becomes the first entry in a queue for a given TID (of some UNO thread h), the receiving side starts to sequentially execute the computation steps corresponding to the requested UNO interface method, in a new (previously immaterial) thread h′. It uses the TID of thread h′ for all request messages sent while executing these computation steps. When it is finished with the computation steps, thread h′ transitions from active to done, and the asynchronous request message is removed from the head of the queue.

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 IDs

The 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 Messages

Apart from normal messages (that represent calls of methods on UNO objects), there are various kinds of special messages.

The queryInterface Message

This message is used to query a UNO object o for a supported interface type t. It is a request message corresponding to a UNO IDL interface method of the form any queryInterface([in] type). It uses function ID 0 (which is otherwise reserved). The passed in type must be an interface type. The corresponding reply message contains a value 〈t′, v′〉 of type ANY. If o does implement the requested type t, t′ must equal t, and v must be a non-null reference of type t to o. Otherwise, t′ must be VOID.

There is a special sort of queryInterface messages that request initial objects. Bridges often face a bootstrapping problem, in that neither side of a bridge knows the OID of an object available at the other side, and neither side can send meaningful request messages. To solve this problem, each side of a bridge can define a well-known set of initial object identifiers, which can be used by the other side of the bridge to obtain references to those initial objects. This is done with special queryInterface messages, where the target OID is the initial object identifier (instead of a real OID), and the requested interface type is com.sun.star.uno.XInterface. The method call interface type of the request message itself must also be com.sun.star.uno.XInterface. Using an initial object identifier instead of an OID is only valid in such a special queryInterface call; the corresponding reply message will return an ANY containing an object reference with the real OID of the requested initial object (or it will return a VOID ANY). How to distinguish a normal queryInterface message (with a real OID) from such a special queryInterface message (with an initial object identifier instead of an OID) is left unspecified.

It is unfortunate that initial object identifiers and OIDs share a single name space.

The release Message

This message is used to control reference counts associated with objects, see Object Life Cycle. It is a request message corresponding to a UNO IDL interface method of the form [oneway] void release(). It uses function ID 2 (which is otherwise reserved). (Even though this is a one-way method, a MUSTREPLY flag may require a corresponding reply message, just as with any other one-way method.)

Protocol Property Messages

Properties may be used to customize bridge-internal settings for application-dependent requirements (see Protocol Properties). Properties can be accessed by sending special request messages containing the special OID UrpProtocolProperties and the interface type com.sun.star.bridge.XProtocolProperties.

This implies that the OID UrpProtocolProperties is reserved by URP (but only as a real OID, not necessarily as an initial object identifier). The interface type com.sun.star.bridge.XProtocolProperties is only used as a—meaningless—tag here; whether or not there is a type of that name (be it an interface type or any other kind of type) is irrelevant.

It is unfortunate that the special OID UrpProtocolProperties shares a single name space with normal OIDs, and that these special messages use the interface type com.sun.star.bridge.XProtocolProperties as a tag.

Exchanging requestChange and commitChange messages must adhere to a special protocol. For this protocol, each side of the bridge is in one of a number of states at any point in time: initial, requested(n), reply−1, reply0, reply1, commit, committed, or wait. Initially, each side of the bridge is in state initial. Each side of the bridge transitions as follows:

  • In state initial, it can send a requestChange request with a given random number n, and transition to state requested(n).
  • In state initial, it can receive a requestChange request. It must send back a corresponding reply with return value 1, and transition to state wait.
  • In state requested(n), it can receive a reply corresponding to its requestChange request, with return value 1. It must transition to state commit.
  • In state requested(n), it can receive a requestChange request with a random number n′. It must behave as follows:
    • If n < n′, it sends back a reply with return value 1, and transitions to state reply0.
    • If n = n′, it sends back a reply with return value −1, and transitions to state reply−1.
    • If n > n′, it sends back a reply with return value 0, and transitions to state reply1.
  • In state reply−1, it will receive a reply corresponding to its requestChange request, with return value −1. It must transition to state initial.
  • In state reply0, it will receive a reply corresponding to its requestChange request, with return value 0. It must transition to state wait.
  • In state reply1, it will receive a reply corresponding to its requestChange request, with return value 1. It must transition to state commit.
  • In state commit, it must send a commitChange request, and transition to state committed.
  • In state committed, it will receive a reply corresponding to its commitChange request. It must transition to state initial.
  • After sending the commitChange request in state commit, this side of the bridge must not send any messages, until it has received the corresponding reply in state committed. (This implies that the sent commitChange request must be the last message in a block.)
  • In state wait, it will receive a commitChange request. It must send back a corresponding reply, and transition to state initial.

Any behaviour of one side of a bridge that does not conform to this protocol is an error. What other messages, besides requestChange and commitChange requests and replies, are sent at what times is not controlled by this protocol (except for the limitation to not send any messages while a commitChange is in transit).

This protocol can lead to livelock if both sides of a bridge continuously send requestChange messages with identical random numbers.

The requestChange Message

This message is used to initiate a change of protocol properties. It is a request message corresponding to a UNO IDL interface method of the form

long requestChange([in] long randomNumber);

The function ID to use for this message is 4.

The parameter randomNumber is used in case both sides of the bridge send a requestChange message at the same time. The general idea is that the side that supplies the larger number is allowed to proceed with a commitChange message.

The corresponding reply message contains a LONG. Possible values are 1, 0, and −1; it is an error if any other value is returned. The general idea is that 1 indicates that the receiver can proceed and send a commitChange message, 0 indicates that the other side supplied a larger random number, and −1 indicates that both sides supplied the same random number.

The commitChange Message

This message is used to commit changes of protocol properties. It is a request message corresponding to a UNO IDL interface method of the form

void commitChange([in] sequence< com::sun::star::bridge::ProtocolProperty > newValues)
 raises (com::sun::star::bridge::InvalidProtocolChangeException);

The function ID to use for this message is 5.

The sequence newValues may only contain defined properties, and only those properties that are contained in newValues will be changed. The corresponding reply message will signal an InvalidProtocolChangeException if the other side of the bridge fails to change at least one of the properties, for whatever reason. In that case, no properties are changed at all. To try to change properties again, a new requestChange message must be send.

On either side of the bridge, the new property values take effect immediately after the (successful) reply to commitChange has been sent or received, respectively. Thus, the reply message itself must still be sent using the old property values.

Message Headers

Each message starts with one or two flag bytes. The most significant bit of the first flag byte specifies whether the message has a long or a short header:

First byte of any message header
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:

First byte of long message header
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:

First byte of short (request) message header
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.

First byte of (long) request message header
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 reserved 0 When sending, this bit must be set to 0; when receiving, the value of this bit should be ignored.
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.

Possible second byte of (long) request message header
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 ≤ ik.

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:

First byte of reply message header
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 ≤ ik.

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 (values of type BOOLEAN are represented as numeric values 0 denoting false and 1 denoting true; it is an error to use any other numeric values):

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 = 〈t1v1〉 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 ≤ lk, 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 Protocol Property Messages).

The protocol properties defined for URP 1.0
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 request message that is not a special release or protocol property message is prefixed by the UNO current context (in the respective thread) as a value of type com::sun::star::uno::XCurrentContext. (It appears to be a historic mistake that the special queryInterface messages are not also exempted.)
Personal tools