IObjectExporter::ResolveOxid
[idempotent] error_status_t ResolveOxid
(
[in] handle_t hRpc,
[in] OXID *pOxid,
[in] unsigned short cRequestedProtseqs,
[in, ref, size_is(cRequestedProtseqs)]
unsigned short arRequestedProtseqs[],
[out, ref] MID *pmid,
[out, ref] STRINGARRAY **psaOxidBindings,
[out, ref] IPID *pipidRemUnknown
);
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 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.
If a ResolveOxid call is received for which the recipient Object Exporter is a middleman, the action required of the middleman depends on how the ordered list of requested protocol sequences (arRequestedProtseqs) relate to lists of protocol sequences previously known by the middleman to have been previously requested of the server. If the list of requested protocol sequences is a (perhaps non-proper) subset in order of a protocol sequence list previously requested of the server, then the corresponding cached string bindings may be returned immediately to the caller without actually communicating with the server. Otherwise, the actual psaRequestedProtseqs must be forwarded to the server, and the returned string bindings propagated back to the client. In such cases, it behooves the middleman to cache the returned string bindings for use in later calls.
In order to support the middleman case, Object Exporters are required to remember the OXID mapping information for remote OXIDs they have learned for some period of time beyond when they themselves have released all references to objects of this OXID. Let t be the full time-out period (ping period ´ number of pings to time-out) for some OID (any OID) for which this Object Exporters is a client and which resides in OXID. Then the Object Exporter must keep the binding information for OXID for at least an amount of time t following the release of a the local reference to any object in OXID.14.
Returned through pmid is an identifier that uniquely identifies the computer. Clients can use this to learn which OXIDs are collocated on the same computer, and thus which OIDs may be appropriately grouped together in ping sets (see ComplexPing). The computer identifier is guaranteed not to change so long as there are remote references to objects on the computer which remain valid. Thus, specifically, the computer ID may change as the computer reboots.
ResolveOxid also informs the caller of the IPID of the OXID object associated with this OXID.
hRpc | handle_t | An RPC binding handle used to make the request. |
pOxid | OXID* | The OXID for whom string bindings are requested. The OXID may or may not represent a process on the computer that receives the ResolveOxid call |
cRequestedProtseqs | unsigned short | The number of protocol sequences requested. |
arRequestedProtseqs | unsigned short[] | arRequestedProtseqs must be initialized with all the protocol IDs 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 Use Protseq section for more details. |
pmid | MID* | The computer identifier associated with OXID. |
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. |
S_OK | Success. The requested information was returned. |
RPC_E_INVALID_OBJECT | |
RPC_E_INVALID_OXID | This OXID is unknown to this Object Exporter, and thus no information was returned. |
RPC_E_SERVER_DIED | |
E_OUTOFMEMORY | |
E_UNEXPECTED | An unspecified error occurred. Some of the requested information may not be returned. |
Comments the object exporter ages string bindings and discards them, object references are transient things. They are not meant to be stored in files or otherwise kept persistently. The preferred method of storing persistent references will depend on the activation models available. On platforms that support them, monikers should be used for any persistent reference. In any case, well known object references can be constructed from well known string bindings, IPIDs and OIDs.
since object references are aged, it is the responsibility of each client to unmarshal them and begin pinging them in a timely fashion.
basic use of the ResolveOxid method is to translate an OXID to string bindings. Put another way, this method translates an opaque process and computer identifier to the information needed to reach that computer and process. There are four interesting cases: (i) looking up an OXID the first time an interface is unmarshaled on a computer, (ii) looking up an OXID between a pair of computers that already have connections, (iii) looking up an OXID from a middleman, (iv) and looking up string bindings with unresolved endpoints (lazy use protseq). Another interesting topic is garbage collection of stored string binding vectors.
Lookup Between Friends
OX C | Process D | OX E | Process F | Process G |
| Call F. | | | |
| | | Pass out ref to G. | |
| Receive out ref to G. | | | |
| Ask local OX to resolve OXID G. | | | |
Ask OX E to resolve OXID G. | | | | |
| | Look up G and return G's endpoints. | | |
Construct and cache string binding vector for G. | | | | |
Return results to D. | | | | |
| Ready to call G directly. | | | |
The case of a lookup between two computers that have already established communication is the easiest. In this scenario there are two computers, A and B. Process D already has an interface pointer to process F. Object exporter C already knows the string bindings for object exporter E and process F, but not process G. Object exporter E knows the string bindings for all the servers on its computer, for example, processes F and G. Process D calls process F and gets a reference to process G. Since process D has never seen the OXID for G before, it asks its local object exporter to resolve G. Process D also has to tell object exporter C where it got the reference from, in this case, process F. Object exporter C does not recognize the OXID G. However it does recognize the OXID F and knows the object exporter E is on the same computer as process F. So OX C calls ResolveOxid on OX E. OX E recognizes G and passes the string bindings back to OX C with the computer ID B. OX C caches this information so that if D ever gets a reference from G, it knows who to ask to resolve that reference.
My First Lookup
The previous example assumes that OX C already knows about OX E and process D is already talking to process F. Setting up the first connection between D and F (as well as C and E) is a tricky business known as activation. ORPC as described in this specification does not include activation models. Thus different vendors may have different activation models. However, there is one basic form of activation shared by all ORPCs. If two processes can communicate via DCE RPC, they can pass long standard object references. While this is not expected to be a common form of activation, it is a simple one that should certainly work across all ORPC implementations. Thus if D and E have established DCE RPC (or raw RPC) communication, they can bootstrap ORPC communication as follows.
OX C | Process D | OX E | Process F |
| | Register endpoints and OXID for F. | |
| Call F with raw RPC. | | |
| | | Pass an out ref to F. |
| | | Pass IID as additional parameter. |
| Tell C the OXID_INFO and MID for F. Include network address(es). | | |
Compute the string bindings for OX E from F. | | | |
Ask E to resolve F to get computer ID and endpoints for F. | | | |
| | Return endpoints and computer ID. | |
| Ready to call F via ORPC. | | |
This example points out that there has to be a local interface between processes and the local object exporter.
Middleman Lookup
The next case shows how lookup works between multiple computers. Suppose that E has a reference to G and G has a reference to I. Similarly, D knows about F and G, and F knows about H and I. What happens if G passes a reference to I over to E?
OX D | Process E | OX F | Process G | OX H | Process I |
| Call G. | | | | |
| | | Return a long reference to I. | | |
| Ask D to lookup I. | | | | |
Since it's a long ref to I call ResolveOxid on H. | | | | | |
| | | | Return endpoints to I. | |
Compute string bindings to I from endpoints and network addresses. | | | | | |
Return string bindings to E | | | | | |
| Ready to call I. | | | | |
Note that when process G returned a reference to I, it used he long form of the OBJREF which includes the protocol IDs and network addresses of the OXID resolver for process I (in this example, the addresses for OX H). This would results in OX D calling OX H directly, rather than needing to call OX F. The advantage of this is that if no references to process I needed by OX F, it could remove it from its OXID cache at any time, rather than keeping it around at least until OX D has had a chance to call it back to resolve OXID I.
Lazy Use Protseq
In a homogeneous network, all computers communicate via the same protocol sequence. In a heterogeneous network, computers 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 the lazy use protocol or it does not.
If the server is using the lazy use protseq protocol, the use of ResolveOxid is modified slightly. When the client OX calls the server OX, it passes the requested protseq vector. If none of the requested protseqs have endpoints allocated in the server, the server OX performs some local magic to get one allocated.
If the server does not implement the lazy use protseq protocol, then all protseqs are registered by the server and contain complete endpoints. However, if they are not, the endpoint mapper can be used to forward calls to the server. This requires that all server IIDs are registered in the endpoint mapper. It also allows a different lazy use protseq mechanism. The endpoint mapper can perform some local magic to force the server to allocate an endpoint. This is less efficient since no OXs ever learn the new endpoints.
The client will always pass in a vector of requested protseqs which the server can ignore if it does not implement the lazy use protseq protocol.
Aging String Bindings
Each object exporter must keep all the string bindings for references to remote computers as well as string bindings for all processes that are ORPC servers on its computers. However, unless the middleman marshaler always marshals proxy interfaces using the long form OBJREF, string bindings cannot be discarded as soon as remote references are. In the middleman example above, a process could pass out a reference to a remote object and immediately release any remaining references to that remote object. When the poor client called back to translate the OXID, the string bindings would be gone. To deal with that case, the object exporter must keep the string binding/OXID translation for one full time-out period (round up if the release occurs in the middle of a ping period) after the last local reference is released. A time-out period is the number of pings times the ping period.