5.2.1 IOXIDResolver::ResolveOxid and IOXIDResolver::ResolveOxid2

Return the string bindings necessary to connect to a given OXID object.

On entry, arRequestedProtseqs contains the protocol sequences the client is willing to use to reach the server. These should be in decreasing order of protocol preference, with no duplicates permitted. Local protocols (such as "ncalrpc") are not permitted.

On exit, psaOxidBindings contains the string bindings that may be used to connect to the indicated OXID; if no such protocol bindings exist which match the requested protocol sequences, NULL may be returned. The returned string bindings are in decreasing order of preference of the server, with duplicate string bindings permitted (and not necessarily of the same preferential priority), though of course duplicates are of no utility. Local protocol sequences may not be present; however, protocol sequences that were not in the set of protocol sequences requested by the client may be. The string bindings returned need not contain endpoints; the endpoint mapper will be used as usual to obtain these dynamically.

Version 5.2 of the DCOM wire protocol introduces a new method called ResolveOXID2 which allows a client to determine the version of a server's COM implementation when it asks for OXID resolution. All clients must attempt to call this method to make sure that the major version of the server is one which they are capable of supporting. Clients who call this method and get an RPC_S_PROCNUM_OUT_OF_RANGE error can assume that the server supports version 5.1 of the DCOM wire protocol. If the method call does succeed, the client should compare pComVersion->MajorVersion with the major version(s) that the client supports. If the client does not explicitly support the major version returned by the server, it should disconnect.

The major version combined with the lower of the client's and server's minor versions should be inserted into the ORPCTHIS structure when issuing an ORPC to the server.

Please see the IDL section above for notes on the differences between the minor versions of the DCOM wire protocol.

Argument Type Description
HRpc Handle_t An RPC binding handle used to make the request.
Poxid OXID The OXID for whomstring bindings are requsted.
CRequestedProtseqs Unsigned short [] The number of protocol sequences with all the protocol id's the client is willing to use to reach the server. It cannot contain local protocol sequences. The object exporter must take care of local lookups privately. The protocol sequences are in order of preference or random order. No duplicates are allowed. See the Lazy Protocol Registration section for more details.
psaOxidBindings STRINGARRAY** The string bindings supported by this OXID, in preferential order. Note that these are Unicode strings.
pipidRemUnknown IPID* The IPID to the IRemUnknown interface the OXID object for this OXID.
pdwAuthnHint Unsigned long A value taken from the RPC_C_AUTHN constants. A hint to the caller as to the minimum authentication level which the server will accept.
pComVersion COMVERSION* [ResolveOxid2 Only] A structure containing the major and minor version of the COM implementation on the server

ReturnValue Meaning
S_OK Success. The requested information was returned.
RPC_S_PROCNUM_OUT_OF_RANGE RANGE The procedure number is out of range (i.e. the function is not implemented).
RPC_E_INVALID_OXID This OXID is unknown to this OXID Resolver, and thus no information was returned.
E_UNEXPECTED An unspecified error occurred. Some of the requested information may not be returned.

Object references are transient things. They are not meant to be stored in files or otherwise kept persistently.

Conversely, since object references are aged, it is the responsibility of each client to unmarshal them and begin pinging them in a timely fashion.

The basic use of the ResolveOxid method is to translate an OXID to string bindings. Put another way, this method translates an opaque process and machine identifier to the information needed to reach that machine and process. There are four interesting cases:

  1. Looking up an OXID the first time an interface is unmarshaled on a machine,

  2. Looking up an OXID between a pair of machines that already have connections,

  3. Looking up an OXID from a middleman, and

  4. Looking up string bindings with unresolved endpoints (lazy use protseq).

  5. Another interesting topic is garbage collection of stored string binding vectors.

5.2.1.2 Lookup Between Friends

Consider the case with two machines A and B. Machine A has a client process C and and OXID Resolver process D. Machine B has OXID Resolver process E and server process F.

Server process F, when it starts up, registers it's RPC string bindings with its local OXID Resolver process E, and creates an OBJREF to some object inside process F. At some future time client process C receives that OBJREF (Note: the mechanism used to acquire this OBJREF is not relevant to this discussion, it may have come through the object activation protocol (beyond the scope of this document) or as an [out] interface parameter in some other ORPC call, or through some other mechanism). The OBJREF contains the OXID for process F, and the string bindings for the Resolver process E on the server machine.

Client Process C asks its local OXID Resolver to resolve the OXID for F. It passes it the OXID and the string bindings for OXID Resolver E. If Resolver D has never seen the OXID before, it calls the OXID Resolver E to ask it to resolve the OXID. Resolver E looks up the OXID and returns the string bindings for server process F. Resolver D then caches this information for future use, and returns the string bindings to client process C. Client process C then binds to the string bindings and is now able to make ORPC calls directly to the server process F.

If other client processes on machine A receive an OBJREF for process F, the OXID resolve can be handled completely by the Resolver process D on machine A. There is no need to contact Resolver process E on the server again.

If machine A gives an OBJREF for F to a client process on another machine G, then the Resolver process on G will repeat the same steps as Resolver process D did to resolve the OXID.

+============+============+  +===========+===========+
|       Machine A         |  |       Machine B       |
+============+============+  +===========+===========+
+============+============+  +===========+===========+
| Process  C | Resolver D |  | Resolver E| Process F |
+============+============+  +===========+===========+
|            |            |  |           | register  |
|            |            |  |           | endpoints |
|            |            |  |           | with local|
|            |            |  |           | Resolver E|
+------------+------------+  +-----------+-----------+
|            |            |  | cache F   |           |
|            |            |  | and it's  |           |
|            |            |  | endpoints |           |
|            |            |  |           |           |
+------------+------------+  +-----------+-----------+
| receive    |            |  |           |           |
| OBJREF     |            |  |           |           |
| to F       |            |  |           |           |
|            |            |  |           |           |
+------------+------------+  +-----------+-----------+
| ask local  |            |  |           |           |
| Resolver D |            |  |           |           |
| to resolve |            |  |           |           |
| F          |            |  |           |           |
+------------+------------+  +-----------+-----------+
|            | ask remote |  |           |           |
|            | Resolver   |  |           |           |
|            | E to       |  |           |           |
|            | resolve F  |  |           |           |
+------------+------------+  +-----------+-----------+
|            |            |  | lookup F  |           |
|            |            |  | and       |           |
|            |            |  | return    |           |
|            |            |  | endpoints |           |
+------------+------------+  +-----------+-----------+
|            | cache      |  |           |           |
|            | endpoints  |  |           |           |
|            | to F and   |  |           |           |
|            | return to C|  |           |           |
+------------+------------+  +-----------+-----------+
| bind to    |            |  |           |           |
| endpoint   |            |  |           |           |
| for F      |            |  |           |           |
|            |            |  |           |           |
+------------+------------+  +-----------+-----------+
| invoke     |            |  |           |           |
| method on  |            |  |           |           |
| F          |            |  |           |           |
|            |            |  |           |           |
+------------+------------+  +-----------+-----------+

5.2.1.4 Lazy Protocol Registration

In a homogeneous network, all machines communicate via the same protocol sequence. In a heterogeneous network, machines may support multiple protocol sequences. Since it is often expensive in resources to allocate endpoints (RpcServerUseProtseq) for all available protocol sequences, ORPC provides a mechanism where they may be allocated on demand. To implement this extension fully, there are some changes in the server. However, changes are optional. If not implemented, ORPC will still work correctly if less optimally in heterogeneous networks.

There are two cases: the server implements lazy protocol registration or it does not.

If the server is using lazy protocol registration, the implementation of ResolveOxid is modified slightly. When the client OXID Resolver calls the server OXID Resolver, it passes the requested protocol sequence vector. If none of the requested protocol sequences have endpoints allocated in the server, the server OXID Resolver allocates them according to its own endpoint allocation mechanisms.

If the server does not implement the lazy protocol registration, then all protocol sequences are registered by the server at server initialization time.

When registering protocol sequences, the server may register endpoints and the server's string bindings will contain the complete endpoints. However, if the server chooses not register endpoints when it registers protocol sequences the endpoint mapper process can be used to forward calls to the server. Using the endpoint mapper requires that all server IIDs be registered in the endpoint mapper. It also allows a different lazy protocol registration mechanism. The endpoint mapper can perform some local magic to force the server to register the protocol sequences.

The client will always pass in a vector of requested protocol sequences which the server can ignore if it does not implement lazy protocol registration.

5.2.2 IOXIDResolver::SimplePing

Pings provide a mechanism to garbage collect interfaces. If an interface has references but is not being pinged, it may be released. Conversely, if an interface has no references, it may be released even though it has recently been pinged. SimplePing just pings the contents of a set. The set must be created with ComplexPing (section 5.2.3).

Ping a set, previously created with IOXIDResolver::ComplexPing, of OIDs owned by this OXID Resolver. Note that neither IPIDs nor OIDs may be pinged, only explicitly created SETIDs.

Argument Type Description
hRpc handle_t An RPC binding handle used to make the request.
PSetId SETID* A SETID previously created with IOXIDResolver::ComplexPing on this same OXID Resolver.

ReturnValue Meaning
S_OK Success. The set was pinged.
RPC_E_INVALID_SET This SETID is unknown to this OXID Resolver, and thus the ping did not occur.
E_UNEXPECTED An unspecified error occurred. It is not known whether the ping was done or not.

5.2.3 IOXIDResolver::ComplexPing

Ping a ping set. Optionally, add and/or remove some OIDs from the set. Optionally, adjust some ping timing parameters associated with the set. After a set is defined, a SimplePing will mark the entire contents of the set as ctive. After a set is defined, SimplePing should be used to ping the set. ComplexPing need only be used to adjust the contents of the set (or to adjust the time-out).

Ping set ids (SETIDs) are allocated unilaterally by the server OXID Resolver. The client OXID Resolver then communicates with the server OXID Resolver to add (and later remove) OIDs from the ping set..

Each OID owned by a server OXID Resolver may be placed in zero or more ping sets by the various clients of the OID. The client owner of each such set will set a ping period and a ping time-out count for the set, thus determining an overall time-out period for the set as the product of these two values. The time-out period is implicitly applied to each OID contained in the set and to future OIDs that might add be added to it. The server OXID Resolver is responsible for ensuring that an OID that it owns does not expire until at least a period of time t has elapsed without that OID being pinged, where t is the maximum time-out period over all the sets which presently contain the given OID, or, if OID is not presently in any such sets but was previously, t is the time-out period for the last set from which OID was removed at the instant that that removal was done; otherwise, OID has never been in a set, and t is a default value (ping period equals 120 seconds, ping time-out count equals three (3), t equals 360 seconds, or six (6) minutes).

Clients are responsible for pinging servers often enough to ensure that they do not expire given the possibility of network delays, lost packets, and so on. If a client only requires access to a given object for what it would consider less than a time-out period for the object (that is, it receives and release the object in that period of time), then unless it is certain it has not itself passed the object to another client, it must be sure to nevertheless ping the object (a ComplexPing that both adds and removes the OID will suffice). This ensures that an object will not expire as it is passed through a chain of calls from one client to another.

An OID is said to be pinged when a set into which it was previously added and presently still resides is pinged with either a SimplePing or a ComplexPing, or when it is newly added to a set with ComplexPing. Note that these rules imply that a ComplexPing that removes an OID from a set still counts as a ping on that OID. In addition to pinging the set SETID, this call sets the time-out period of the set as the product of a newly-specified ping period and a newly-specified "ping count to expiration;" these values take effect immediately. Ping periods are specified in tenths of a second, yielding a maximum allowable ping period of about 1 hr 50 min.

Adjustment of the time-out period of the set is considered to happen before the addition of any new OIDs to the set, which is in turn considered to happen before the removal of any OIDs from the set. Thus, an OID that is added and removed in a single call no longer resides in the set, but is considered to have been pinged, and will have as its time-out at least the time-out period specified in that ComplexPing call.

On exit, the server may request that the client adjust the time-out period; that is, ask it to specify a different time-out period in subsequent calls to ComplexPing. This capability can be used to reduce traffic in busy servers or over slow links. The server indicates its desire through the values it returns through the variables pReqSetPingPeriod and pReqSetNumPingsToTimeOut. If the server seeks no change, it simply returns the corresponding values passed by the client; if it wishes a longer time-out period, it indicates larger values for one or both of these variables; if it wishes a smaller period, it indicates smaller values. When indicating a larger value, the server must start immediately acting on that larger value by adjusting the time-out period of the set. However, when indicating a smaller value, it must consider its request as purely advice to the client, and not take any action: if the client wishes to oblige, it will do so in a subsequent call to ComplexPing by specifying an appropriate time-out period.

Argument Type Description
HRpc Handle_t An RPC binding handle used to make the request
PSetID SETID The SETID being manipulated. SequenceNum unsigned short The sequence number allows the object exporter to detect duplicate packets. Since the call is idempotent, it is possible for duplicates to get executed and for calls to arrive out of order when one ping is delayed.
cAddToSet Unsigned short The size of the array AddToSet.
DelFromSet Unsigned short The size of the array DelFromSet.
AddToSet OID[] The list of OIDs which are to be added to this set. Adding an OID to a set in which it already exists is permitted; such an action, as would be expected, is considered to ping the OID.
DelFromSe OID[] The list of OIDs which are to be removed from this set. Removal counts as a ping. An OID removed from a set will expire after the number of ping periods has expired without any pings (not the number of ping periods - 1). If an id is added and removed from a set in the same ComplexPing, the id is considered to have been deleted.
PpingBackoffFactor Unsigned short Acts as a hint (only) from the server to the client in order to reduce ping traffic. Clients are requested to not ping more often than (1<<*pPingBackoffFactor)* (BasePingInterval=120) seconds, and the number of pings until timeout remains unchanged at the default of 3. Clients may choose to assume that this parameter is always zero.

ReturnValue Meaning
S_OK Success. The set was pinged, etc.
RPC_E_INVALID_OID Indicates that some OID was not recognized. There is no recovery action for this error, it is informational only.
E_ACCESSDENIED Access is denied.
E_OUTOFMEMORY There was not enough memory to service the call. The caller may retry adding OIDs to the set on the next ping.
E_UNEXPECTED An unspecified error occurred. It is not known whether the ping or any of the other actions were done or not