|
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 headerThe 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 bodyThe blockbody consist of messageCount message one after one without any padding. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Messages | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Caching conceptTo 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 :
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. MessageHeaderThe message starts with a byte. The most significant bit decides, whether the message has a short or a longheader.
Request
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.
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.
ReplyIf 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.
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.
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. |