Pinging

The above reference counting scheme would be entirely adequate on its own if clients never crashed, but in fact they do, and the system needs to be robust in the face of clients crashing when they hold remote references. In a DCE RPC, one typically addresses this issue through the use of context handles. Context handles are not used, however, by the COM network protocol, for reasons of expense. The basic underlying technology used in virtually all protocols for detecting remote crashes is that of periodic pings. Naive use of RPC context handles would result in per-object per-client process pings being sent to the server. The COM network protocol architects its pinging infrastructure to reduce network traffic by relying on the client Object Exporter implementation to do local management of client liveness detection, and having the actual pings be sent only on a computer-to-computer basis.

Pinging is carried out on a per-object (per OID), not a per-interface (per IPID) basis. Architecturally, at its server computer, each exported object (each exported OID) has associated with it a pingPeriod time value and a numPingsToTimeOut count which together (through their product) determine the overall amount of time known as the "ping period" that must elapse without receiving a ping on that OID or an invocation on one of its IPIDs before all the remote references to IPIDs associated with that OID can be considered to have expired. Once expiration has occurred, the interfaces behind the IPIDs can as would be expected be reclaimed solely on the basis local knowledge, though the timeliness with which this is carried out, if at all, is an implementation specific. If the server COM infrastructure defers such garbage collection in this situation (perhaps because it has local references keeping the interface pointer alive) and it later hears a ping or receives a remote call, then it knows a network partition healed. It can consider the extant remote references to be reactivated and can continue remote operations.

When interface pointers are conveyed from one client to another, such as being passed as either [in] or [out] parameters to a call, the interface pointer is marshaled in one client and unmarshaled in the other. In order to successfully unmarshal the interface, the destination client must obtain at least one reference count on the interface. This is usually accomplished by passing in the marshaled interface STDOBJREF a cRefs of (at least) one; the destination client then takes ownership of that many (more) reference counts to the indicated IPID, and the source client then owns that many fewer reference counts on the IPID. It is legal, however, for zero reference counts to be passed in the STDOBJREF; here, the destination client must (if it does not already have access to that IPID and thus have a non-zero reference count for it) before it successfully unmarshals the interface reference (concretely, such as, before CoUnmarshalInterface returns) call to the object's exporter using IRemUnknown::RemAddRef to obtain a reference count for it.

If the destination client is in fact the object's server, then special processing is required by the destination client. The remote reference counts being passed to it should, in effect, be "taken out of circulation," as what where heretofore remote references are being converted into local references. Thus, the reference counts present in the STDOBJREF are in fact decremented from the remote reference count for the IPID in question.

Some objects have a usage model such that they do not need to be pinged at all; such objects are indicated by the presence of a flag in a STDOBJREF to an interface on the object. Objects which are not pinged in fact need not be reference counted either, though it is legal (but pointless) for a client to reference count the IPIDs of such objects.

For all other objects, assuming a non-zero ping period, it is the responsibility of the holder of an interface reference on some object to ensure that pings reach the server frequently enough to prevent expiration of the object. The frequency used by a client depends on the ping period, the reliability of the channel between the client and the server, and the probability of failure (no pings getting through and possible premature garbage-collection) that the client is willing to tolerate. The ping packet and / or its reply may both request changes to the ping period. Through this mechanism, network traffic may be reduced in the face of slow links busy servers.

Delta Pinging

Without any further refinements, ping messages could be quite hefty. If computer A held 1024 remote objects (OIDs) on computer B, then it would send 16K-byte ping messages. This would be annoying if the set of remote objects was relatively stable and the ping messages were the same from ping to ping.

The delta mechanism reduces the size of ping messages. It uses a ping-set interface that allows the pinging of a single set to replace the pinging of multiple OIDs.

Instead of pinging each OID, the client defines a set. Each ping contains only the set ID and the list of additions and subtractions to the set. Objects that come and go within one ping period are removed from the set without ever having been added.

The pinging protocol is carried out using two methods in the (DCE) interface IObjectExporter on the Object Exporter: ComplexPing, and SimplePing. ComplexPing is used to by clients to group the set of OIDs that they must ping into UUID-tagged sets known to the server. These entire sets of OIDs can then be subsequently pinged with a single, short, call to SimplePing.