[Search] [txt|pdf|bibtex] [Tracker] [Email] [Diff1] [Diff2] [Nits]

Versions: 00 01 02 03                                                   
Network Working Group                                        Nat Brown
INTERNET-DRAFT                                          Charlie Kindel
<draft-brown-dcom-v1-spec-01.txt>                Microsoft Corporation
Expires in six months                                   November, 1996


       Distributed Component Object Model Protocol -- DCOM/1.0


Status of this Memo

This document is an Internet-Draft. Internet-Drafts are working
documents of the Internet Engineering Task Force (IETF), its areas,
and its working groups. Note that other groups may also distribute
working documents as Internet-Drafts.

Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference material
or to cite them other than as "work in progress."

To learn the current status of any Internet-Draft, please check the
"1id-abstracts.txt" listing contained in the internet-drafts Shadow
Directories at <ftp://ftp.is.co.za/internet-drafts> (Africa),
<ftp://nic.nordu.net/internet-drafts> (Europe),
<ftp://munnari.oz.au/internet-drafts> (Pacific Rim),
<ftp://ds.internic.net/internet-drafts> (US East Coast), or
<ftp://ftp.isi.edu/internet-drafts> (US West Coast).

Distribution of this document is unlimited. Please send comments to
the authors at <mailto:oleidea@microsoft.com>. General discussions
about DCOM and its applications should take place on the DCOM mailing
list. To subscribe, send a piece of mail to
<mailto:DCOM@listserv.msn.com>. Leave the subject blank and in the
body of the message, first type "subscribe" for non-digest or "digest"
for digest version, followed by "DCOM", and finally by your name.
(example: "subscribe DCOM John Doe").

See <http://www.microsoft.com/workshop/RESOURCE/MAIL.HTM> for more
details.



Abstract

The Distributed Component Object Model protocol is an application-
level protocol for object-oriented remote procedure calls useful for
distributed, component-based systems of all types. It is a generic
protocol layered on the distributed computing environment (DCE) RPC
specification and facilitates the construction of task-specific
communication protocols through features such as: a platform neutral
argument/parameter marshaling format (NDR), the ability for objects to
support multiple interfaces with a safe, interface-level versioning
scheme suited to independent evolution by multiple parties, the
ability to make authenticated connections and to choose levels of
channel security, and a transport-neutral data representation for
references (including by-value) to objects.







Brown/Kindel                                                    page 1



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996


Table of Contents

     Status of this Memo...................................1

     Abstract..............................................1

     Table of Contents.....................................2

     1. Introduction.......................................3

          1.1 Purpose......................................3

     2. Overall Operation..................................4

          2.1 Object Calls.................................4
          2.2 OXIDs and Object Exporters...................5
          2.3 Marshaled Interface References...............5
          2.4 Reference Counting...........................6
          2.5 Pinging......................................7
          2.6 QueryInterface...............................9
          2.7 Causality ID.................................9

     3. Data Types and Structures..........................9

          3.1 DCE Packet Headers...........................9
          3.2 ORPC Base Definitions.......................10
          3.3 OBJREF......................................14
          3.4 STDOBJREF...................................15
          3.5 SORFLAGS....................................16
          3.6 ORPCINFOFLAGS...............................16
          3.7 ORPCTHIS....................................17
          3.8 ORPCTHAT....................................18
          3.9 HRESULTs....................................18
          3.10 Body Extensions............................19

     4. IRemUnknown interface.............................20

          4.1 IRemUnknown::RemQueryInterface..............21
          4.2 IRemUnknown::RemAddRef......................22
          4.3 IRemUnknown::RemRelease.....................23

     5. The OXID Resolver.................................24

          5.1 OXID Resolver Ports/Endpoints...............24
          5.2 The IOXIDResolver Interface.................25

     6. Security Considerations...........................33

     7. Acknowledgements..................................33

     8. References........................................33

     9. Author's Addresses................................34

















Brown/Kindel                                                    page 2



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

1. Introduction

The Distributed Component Object Model protocol (DCOM) is an
application-level protocol for object-oriented remote procedure calls
and is thus also called "Object RPC" or ORPC. The protocol consists of
a set of extensions, layered on the distributed computing environment
(DCE) RPC specification [CAE RPC], with which familiarity is assumed.
Familiarity is also assumed with the COM (Component Object Model)
specification [COM].

Object RPC specifies:

· How calls are made on an object

· How object references are represented, communicated, and maintained



1.1 Purpose

There is a natural tendency in a networked environment to create
entirely new application-level protocols as each new or seemingly
unique combination of client, user agent, and server requirement
arises.

While in many situations the definition of a new protocol is useful
and justifiable, there are numerous features which have eventually
been added to or required from each new protocol (or which become
layered above them) as they evolve and become used in broader
contexts.

A design goal of the DCOM protocol is the inherent support of standard
features required by any distributed application communication
protocol. In other words, to act as a framework to facilitate the
construction of task-specific communication paths between distributed
applications.


Data Marshaling

A common occurrence among user agents using the HTTP protocol today is
the use of complex, task-specific Query URL syntax and HTTP POSTs.
Also increasingly common is the POSTing and response with custom MIME
types to and from resources which interpret the format and reply in
same. While workable, there are drawbacks to this approach including
increased complexity and work to produce and consume each new (and
unique) format in the client and server, lessened ability to build
task-specific firewalls for administration and security purposes, and
in many cases definition of platform-centric formats.

DCOM utilizes the Network Data Representation (NDR) for arbitrary data
types supported by DCE RPC.


Security

DCOM leverages the authentication, authorization, and message
integrity capabilities of DCE RPC. An implementation may support any
level of DCE RPC security. Any connection or call can be made as
secure or as insecure as negotiated by the client and the server.


Safe Non-Coordinated Versioning of Interfaces

In DCOM versioning of interfaces is done through identifiers which are
universally unique (UUID's). To version a published interface, a new


Brown/Kindel                                                    page 3



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

interface is defined with a different UUID to the updated
specification. Multiple parties can simultaneously introduce
"revisions" to interfaces by defining related but distinct interfaces
without fear of colliding with each other's version numbers and
without fear of breaking each other's down-level or up-level clients.

To date, the bulk of task-specific protocols (such as custom POSTs or
MIME types using HTTP) have little or no concept of versioning at all,
and simply "narrow" the incompatibility window by updating clients
(typically pages which are being downloaded anyway) and servers (CGI
scripts or other HTTP server infrastructure) simultaneously.



2. Overall Operation

The Object RPC protocol highly leverages the OSF DCE RPC network
protocol (see the reference [CAE RPC]). This leverage occurs at both
the specification level and the implementation level: the bulk of the
implementation effort involved in implementing the DCOM network
protocol is in fact that of implementing the DCE RPC network protocol
on which it is built.



2.1 Object Calls

An actual COM network remote procedure call (hereinafter referred to
as "an ORPC") is in fact a true DCE remote procedure call (herein
termed "a DCE RPC"), a "Request PDU" conforming to the specification
for such calls per [CAE RPC].

In an ORPC, the object ID field of the invocation header as specified
in [CAE RPC] contains an "IPID". An IPID is a 128-bit identifier known
as an interface pointer identifier which represents a particular
interface on a particular object in a particular server. As it is
passed in the object ID fields of a DCE RPC, the static type of an
IPID is in fact a UUID. However, IPIDs are scoped not globally but
rather only relative to the  server process  which originally
allocated them; IPIDs do not necessarily use the standard UUID
allocation algorithm, but rather may use a machine-specific algorithm
which can assist with dispatching.

In an ORPC, the interface ID field of the RPC header specifies the
IID, and arguments are found in the body, as usual. However, when
viewed from the DCE RPC perspective an additional first argument is
always present that is absent in the corresponding COM interface
specification. This argument is of type ORPCTHIS, which is described
in Section 3.7. It is placed first in the body of the Request PDU,
before the actual arguments of the ORPC.

It is specifically legal for an ORPC to attempt a call a method number
on a given interface which is beyond the number of methods believed by
the server to be in that interface. Such calls should cause a fault.

Similarly, in a reply to an ORPC (a DCE RPC "Response PDU"), when
viewed from the DCE RPC perspective, an additional first return value
is always present that is absent in the corresponding COM interface
specification. This argument is of type ORPCTHAT, which is described
in Section 3.8. It is placed first in the body of the Response PDU,
before the actual return values of the ORPC.



Brown/Kindel                                                    page 4



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

An ORPCTHAT may also be present in a "Fault PDU." In the
Connectionless (CL) Fault PDU, it is placed four bytes after the 32-
bit fault code which normally comprises the entire body of the PDU,
thus achieving eight byte alignment for the ORPCTHAT; the intervening
padding bytes are presently reserved and must be zero. The PDU body
length is of course set to encompass the entire body of the Fault PDU,
including the ORPCTHAT. In the Connection- Oriented (CO) Fault PDU,
the ORPCTHAT is placed in the standard location allocated for the
"stub data." In a Fault PDU of either form that results from an ORPC,
if an ORPCTHAT is not present then no other data may be substituted in
its here-specified location in the PDU.



2.2 OXIDs and Object Exporters

Although an IPID from a logical perspective semantically determines
the server, object and interface to which a particular call should be
directed, it does not by itself indicate the binding information
necessary to actually carry out an invocation.

The protocol represents this "how-to" communication information in a
64-bit value called an object exporter identifier, otherwise known as
an OXID. Conceptually, an OXID can be thought of as an implementation
scope for an object, which may be a whole machine, a given process, a
thread within that process, or other more esoteric implementation
scope, but the exact definition of such scopes has no bearing on the
protocol itself. Data structures in each Object Exporter keep track of
the IPIDs exported and imported by that Object Exporter.

A given machine at any moment may support several OXIDs; however there
is always a unique   OXID Resolver service per machine which
coordinates the management of all the OXIDs on the machine. The  OXID
Resolver typically (but not necessarily) resides at well-known ports
(or endpoints, depending on your terminology -- one per protocol, of
course) on the machine. It supports a DCE RPC interface known as
IOXIDResolver, described in Section 5.2.

An OXID is used to determine the RPC string bindings that allow calls
to reach their target IPID. Before making a call, the calling process
must translate an OXID into a set of bindings that the underlying RPC
implementation understands. It accomplishes this by maintaining a
cache of these mappings. When the destination application receives an
object reference, it checks to see if it recognizes the OXID. If it
does not, then it asks the OXID Resolver  which scopes the OXID
specified in the object reference  for the translation, and saves the
resulting set of string bindings in a local table that maps OXIDs to
string bindings.

Associated with each OXID (ie each Object Exporter) is COM object
termed an "OXID object." OXID objects implement (at least) the
IRemUnknown interface, a COM  interface through which remote
management of reference counts and requests for interfaces are
returned.



2.3 Marshaled Interface References

The DCOM protocol extends the Network Data Representation (NDR)
standard specified in [CAE RPC] by defining what can be thought of as
a new primitive data type that can be marshaled: that of an interface

Brown/Kindel                                                    page 5



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

reference to an object. This is the only extension to NDR made by the
DCOM protocol.

A marshaled interface reference is described by a type known as an
OBJREF, which is described in detail in Section 3.3. An OBJREF in
actuality has several variations:

NULL

This is a reference to no object.


STANDARD

A standard remote reference. Known as a STDOBJREF. A STDOBJREF
contains:

· An IPID, which uniquely specifies the interface and object.

· An object ID (OID), which uniquely specifies the identity of the
  object on which the IPID is found (scoped to the object exporter
  with which the object is associated).

· An OXID, which identifies the scope where the implementation of the
  object is active, and can be used to reach the interface pointer.

· A reference count, indicating the number of references to this IPID
  that are conveyed by this marshaling. This count, though typically
  a value of one, may in fact be zero, one, or more (see the next
  section).

· Some flags, explained later.


CUSTOM

Contains a class ID (CLSID) and class-specific information.

The Custom format gives an object control over the representation of
references to itself. For example, an immutable object might be passed
by value, in which case the class-specific information would contain
the object's immutable data.


HANDLER

A sub-case of the custom reference in which the class- specific
information is standardized.

For example, an object wishes to be represented in client address
spaces by a proxy object that caches state. In this case, the class-
specific information is just a standard reference to an interface
pointer that the handler (proxy object) will use to communicate with
the original object.

Interface references are always marshaled in little-endian byte order,
irrespective of the byte order prevailing in the remainder of the data
being marshaled.



2.4 Reference Counting

In the DCOM protocol, remote reference counting is conducted per
interface (per IPID).

The actual increment and decrement calls are carried out using
(respectively) the RemAddRef and RemRelease methods in a COM interface
known as IRemUnknown found on  the OXID object associated with each
OXID, the IPID of which is returned from the function


Brown/Kindel                                                    page 6



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

IOXIDResolver::ResolveOxid (section 5.2.1). In contrast to their
analogues in IUnknown, RemAddRef and RemRelease can in one call
increment or decrement the reference count of many different IPIDs by
an arbitrary amount; this allows for greater network efficiency. In
the interests of performance, client COM implementations typically do
not immediately translate each local AddRef and Release into a remote
RemAddRef and RemRelease. Rather, the actual remote release of all
interfaces on an object is typically deferred until all local
references to all interfaces on that object have been released.
Further, one actual remote reference count may be used to service many
local reference counts; that is, the client infrastructure may
multiplex zero or more local references to an interface into zero or
one remote references on the actual IPID.

To prevent a malicious application from calling RemRelease
incorrectly, an application may request secure references.  In that
case the application must call RemAddRef (and RemRelease later on)
securely and must request private references.  Private references are
stored by client identity so one client cannot release another
client’s references. DCOM requires that each client make a call to get
his own secure references, rather then receiving a secure reference
from someone who already has one.  This reduces the efficiency of
interface marshalling because the client must make a callback.



2.5 Pinging

The above reference counting scheme would be entirely adequate on its
own if clients never terminated abnormally, but in fact they do, and
the system needs to be robust in the face of clients terminating
abnormally 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 DCOM protocol, for
reasons of expense. The basic underlying technology used in virtually
all protocols for detecting remote abnormal termination 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 DCOM
protocol includes a pinging infrastructure to significantly reduce
network traffic by relying on the client  OXID Resolver implementation
to do local management of client liveness detection, and having the
actual pings be sent only on a machine by machine basis.

Pinging is carried out on a per-object (per OID), not a per- interface
(per-IPID) basis. Architecturally, at its server machine, 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 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 of local knowledge, though the timeliness with
which this is carried out, if at all, is implementation specific
detail of the server. 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 , then it knows a network partition healed. It can consider the


Brown/Kindel                                                    page 7



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

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 cPublicRefs 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, e.g., before CoUnmarshalInterface
returns) call to the object 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 to busy servers.



2.5.1 Delta Pinging

Without any further refinements, ping messages could be quite hefty.
If machine A held 1024 remote object references (OIDs) on machine 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


Brown/Kindel                                                    page 8



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

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 RPC)
interface IOXIDResolver on the OXID Resolver: ComplexPing, and
SimplePing. ComplexPing is used by clients to group the set of OIDs
that they must ping into  sets known to the server. These entire sets
of OIDs can then be subsequently pinged with a single, short, call to
SimplePing.



2.6 QueryInterface

The IRemUnknown interface on the OXID object, in addition to servicing
reference counting as described above also services QueryInterface
calls for remote clients for IPIDs managed by that object exporter.
IRemUnknown::RemQueryInterface differs from IUnknown::QueryInterface
in much the same way as RemAddRef and RemRelease differ from AddRef
and Release, in that it is optimized for network access by being able
to retrieve many interfaces at once.



2.7 Causality ID

Each ORPC carries with it a UUID known as the causality id that
connects together the chain of ORPC calls that are causally related.
If an outgoing ORPC is made while servicing an incoming ORPC, the
outgoing call is to have the same causality id as the incoming call.
If an outgoing ORPC is made while not servicing an incoming ORPC, then
a new causality id is allocated for it.

Causality ids may in theory be reused as soon as it is certain that no
transitively outstanding call is still in progress which uses that
call. In practice, however, in the face of transitive calls and the
possibility of network failures in the middle of such call chains, it
is difficult to know for certain when this occurs. Thus,
pragmatically, causality ids are not reusable.

The causality id can be used by servers to understand when blocking or
deferring an incoming call (supported in some COM server programming
models) is very highly probable to cause a deadlock, and thus should
be avoided.

The causality id for maybe, idempotent, and broadcast calls must be
set to null (e.g., all zeros). If a server makes a ORPC call while
processing such a call, a new causality id must be generated as if it
were a top level call.



3. Data Types and Structures

This following several sections present the technical details of the
DCOM protocol.



3.1 DCE Packet Headers

Object RPC sits entirely on top of DCE RPC. The following list
describes the elements of ORPC that are specified above and beyond DCE
RPC.

Brown/Kindel                                                    page 9



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

· The object id field of the header must contain the IPID.

· The interface id of the RPC header must contain the IID, even
  though it is not needed given the IPID. This allows ORPC to sit on
  top of DCE RPC. An unmodified DCE RPC implementation will correctly
  dispatch based on IID and IPID. An optimized RPC need only dispatch
  based on IPID.

· An IPID uniquely identifies a particular interface on a particular
  object on a machine. The converse is not true; a particular
  interface on a particular object may be represented by multiple
  IPIDs. IPIDs are unique on their OXID. IPIDs may be reused, however
  reuse of IPIDs should be avoided.

· Datagram, maybe, and idempotent calls are all allowed in ORPC.

· Interface pointers may not be passed on maybe or idempotent calls.

· Datagram broadcasts are not allowed in ORPC.

· Faults are returned in the stub fault field of the DCE RPC fault
  packet. Any 32 bit value may be returned. Only
  RPC_E_VERSION_MISMATCH  is pre-specified:

· DCE RPC cancel is supported.

· All interface version numbers must be 0.0.



3.2 ORPC Base Definitions

There are several fundamental data types and structures on which the
COM network protocol is built. These types are shown here in standard
C header format.


////////////////////////////////////////////////////////////
// Basic Definitions
////////////////////////////////////////////////////////////
typedef unsiged long    HRESULT; // 32-bit integer: success/failure
typedef t_uuid          UUID;    // rename DCE-RPC type
typedef UUID            GUID;    // Globally Unique IDentifier
typedef unsigned hyper  ID;      // 64-bit integer
typedef ID              OXID;    // Object Exporter Identifier
typedef ID              OID;     // Object Identifer
typedef ID              SETID;   // Ping Set Identifier
typedef GUID            IPID;    // Interface Pointer Identifier
typedef GUID*           REFIPID;
typedef GUID            CID;     // Causality Identifier
#define CID_NULL        uuid_null; // All zeros

//////////////////////////////////////////////////////////////////
// ORPC Call Packet Format
//////////////////////////////////////////////////////////////////
const unsigned short COM_MAJOR_VERSION = 5;
const unsigned short COM_MINOR_VERSION = 1;

typedef struct tagCOMVERSION {
   unsigned short    MajorVersion;   // Major version number
   unsigned short    MinorVersion;   // Minor version number
} COMVERSION;

const unsigned long ORPCF_NULL      = 0;  // no additional info

Brown/Kindel                                                   page 10



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

                                          //  in packet
const unsigned long ORPCF_LOCAL     = 1;  // call is local to this
                                          //  machine
const unsigned long ORPCF_RESERVED1 = 2;  // reserved for local use
const unsigned long ORPCF_RESERVED2 = 4;  // reserved for local use
const unsigned long ORPCF_RESERVED3 = 8;  // reserved for local use
const unsigned long ORPCF_RESERVED4 = 16; // reserved for local use

// Extension to implicit parameters.
typedef struct tagORPC_EXTENT {
   GUID              id;         // Extension identifier
   unsigned long     size;       // Extension size
   byte              data[];     // [size_is((size+7)&~7)]
} ORPC_EXTENT;

// Array of extensions.
typedef struct tagORPC_EXTENT_ARRAY {
   unsigned long     size;       // Num extents.
   unsigned long     reserved;   // Must be zero.
   ORPC_EXTENT**     extent;     // [size_is((size+1)&~1), unique]
} ORPC_EXTENT_ARRAY;

// implicit 'this' pointer which is the first [in] parameter on
// every ORPC call.
typedef struct tagORPCTHIS {
   COMVERSION        version;    // COM version number
   unsigned long     flags;      // ORPCF flags for presence of
                                 //  other data
   unsigned long     reserved1;  // set to zero
   CID               cid;        // causality id of caller
   ORPC_EXTENT_ARRAY* extensions; // [unique] extensions
} ORPCTHIS;

// implicit 'that' pointer which is the first [out] parameter on
// every ORPC call.
typedef struct tagORPCTHAT {
   unsigned long     flags;      // ORPCF flags for presence
                                 //  of other data
   ORPC_EXTENT_ARRAY *extensions; // [unique] extensions
} ORPCTHAT;

 //////////////////////////////////////////////////////////////////
 // Marshaled COM Interface Wire Format
 //////////////////////////////////////////////////////////////////
typedef enum tagMSHLFLAGS {
   MSHLFLAGS_NORMAL        = 0,
   MSHLFLAGS_TABLESTRONG   = 1,
   MSHLFLAGS_TABLEWEAK     = 2,
} MSHLFLAGS;

// Tower IDs for common protocols
const unsigned short NCADG_IP_UDP   = 0x08;
const unsigned short NCACN_IP_TCP   = 0x07;
const unsigned short NCADG_IPX      = 0x0E;
const unsigned short NCACN_SPX      = 0x0C;
const unsigned short NCACN_NB_NB    = 0x12;
const unsigned short NCACN_NB_IPX   = 0x0D;

Brown/Kindel                                                   page 11



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

const unsigned short NCACN_DNET_NSP = 0x04;
const unsigned short NCALRPC        = 0x10;

// This is the return type for arrays of string bindings or protseqs
// used by many ORPC interfaces.

typedef struct tagSTRINGBINDING {
   unsigned short    wTowerId;      // Cannot be zero.
   unsigned short    aNetworkAddr;  // Zero terminated.
} STRINGBINDING;

// this value (invalid in DCE RPC) indicates to use default authz
const unsigned short COM_C_AUTHZ_NONE = 0xffff;

typedef struct tagSECURITYBINDING {
   unsigned short    wAuthnSvc;     // Must not be zero
   unsigned short    wAuthzSvc;     // Must not be zero
   unsigned short    aPrincName;    // NULL terminated
} SECURITYBINDING;

// DUALSTRINGARRAYS are the return type for arrays of network
// addresses, arrays of endpoints and arrays of both used in
// many ORPC interfaces
typedef struct tagDUALSTRINGARRAY {
   unsigned short    wNumEntries;      // # of entries in array
   unsigned short    wSecurityOffset;  // Offset of security info

   // The array contains two parts, a set of STRINGBINDINGs
   // and a set of SECURITYBINDINGs.  Each set is terminated by an
   // extra zero.  The shortest array contains four zeros.
   unsigned short    aStringArray[];   // [size_is(wNumEntries)]
} DUALSTRINGARRAY;

// arbitrary value to help ensure validity
const unsigned long OBJREF_SIGNATURE = 0x574f454d;

const unsigned long OBJREF_STANDARD = 0x1;
const unsigned long OBJREF_HANDLER  = 0x2;
const unsigned long OBJREF_CUSTOM   = 0x4;

// Flag values for a STDOBJREF (standard part of an OBJREF).
// SORF_OXRES1 - SORF_OXRES8 are reserved for the object exporters
// use only, object importers must ignore them and must not enforce
// MBZ.
const unsigned long SORF_NULL    = 0x0000;   // convenient for init
const unsigned long SORF_OXRES1  = 0x0001;   // reserved by exporter
const unsigned long SORF_OXRES2  = 0x0020;   // reserved by exporter
const unsigned long SORF_OXRES3  = 0x0040;   // reserved by exporter
const unsigned long SORF_OXRES4  = 0x0080;   // reserved by exporter
const unsigned long SORF_OXRES5  = 0x0100;   // reserved by exporter
const unsigned long SORF_OXRES6  = 0x0200;   // reserved by exporter
const unsigned long SORF_OXRES7  = 0x0400;   // reserved by exporter
const unsigned long SORF_OXRES8  = 0x0800;   // reserved by exporter
const unsigned long SORF_NOPING  = 0x1000;   // Pinging not required

typedef struct tagSTDOBJREF {
   unsigned long  flags;            // SORF_ flags (see above)

Brown/Kindel                                                   page 12



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

   unsigned long  cPublicRefs;      // count of references passed
   OXID           oxid;             // oxid of server with this oid
   OID            oid;              // oid of object with this ipid
   IPID           ipid;             // ipid of Interface
} STDOBJREF;

// although this structure is conformant, it is always marshaled
// in little-endian byte-order.
typedef struct tagOBJREF {
   unsigned long  signature;        // must be OBJREF_SIGNATURE
   unsigned long  flags;            // OBJREF flags (see above)
   GUID           iid;              // interface identifier

   union {        // [switch_is(flags), switch_type(unsigned long)]
      struct {    // [case(OBJREF_STANDARD)]
         STDOBJREF         std;        // standard objref
         DUALSTRINGARRAY   saResAddr;  // resolver address
      } u_standard;

      struct {    // [case(OBJREF_HANDLER)]
         STDOBJREF         std;        // standard objref
         CLSID             clsid;      // Clsid of handler code
         DUALSTRINGARRAY   saResAddr;  // resolver address
      } u_handler;

      struct {    // [case(OBJREF_CUSTOM)]
         CLSID           clsid;        // Clsid of unmarshaling code
         unsigned long   cbExtension;  // size of extension data
         unsigned long   size;         // size of data that follows
         byte            *pData;       // extension +
                                       // class specific data
                                       // [size_is(size), ref]
      } u_custom;
   } u_objref;
} OBJREF;

// wire representation of a marshalled interface pointer,
// always the little-endian form of an OBJREF
typedef struct tagMInterfacePointer {
   ULONG             ulCntData;        // size of data
   byte              abData[];         // [size_is(ulCntData)] data
} MInterfacePointer, *PMInterfacePointer;

// OXID Resolver information associated with each OXID.
typedef struct tagOXID_INFO {
   DWORD             dwTid;            // thread id of object exporter
   DWORD             dwPid;            // process id of obj exporter
   IPID              ipidRemUnknown;   // IRemUnknown IPID for object
exporter
    DWORD            dwAuthnHint;
    DUALSTRINGARRAY  *psa;             // protocol and security info
} OXID_INFO;

//////////////////////////////////////////////////////////////////




Brown/Kindel                                                   page 13



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

3.3 OBJREF

An OBJREF is the data type used to represent an actual marshaled
object reference. An OBJREF can either be empty or assume one of three
variations, depending on the degree to which the object being
marshaled uses the hook architecture (IMarshal, etc.) in the
marshaling infrastructure. The OBJREF structure is a union consisting
of a switch flag followed by the appropriate data.



3.3.1 OBJREF_STANDARD

Contains one interface of an object marshaled in standard form.
Contains a standard reference, along with a set of protocol sequences
and network addresses that can be used to bind to an OXID resolver
that is able to resolve the OXID in the STDOBJREF. This is useful when
marshaling a proxy to give to another machine (a.k.a. the "middleman"
case). The marshaling machine specifies the saResAddr for the OXID
Resolver on the server machine, eliminating the need for the
unmarshaler  to call the marshaler (middleman) back to get this
information. Further, the marshaler does not need to keep the OXID in
its cache beyond the lifetime of its own references in order to
satisfy requests from parties that it just gave the OBJREF to.


Member      Type           Semantic

signature   unsigned long  must be OBJREF_SIGNATURE

flags       unsigned long  OBJREF flags (section 3.5)

GUID        iid            Interface identifier

std         STDOBJREF      A standard object reference used to
                            connect to the source object (Section
                            3.4).

SaResAddr   STRINGARRAY    The resolver address.



3.3.2 OBJREF_HANDLER

A marshaling of an object that wishes to use handler marshaling. For
example, an object wishes to be represented in client address spaces
by a proxy object that caches state. In this case, the class- specific
information is just a standard reference to an interface pointer that
the handler (proxy object) will use to communicate with the original
object. See the IStdMarshalInfo interface.


Member      Type           Semantic

signature   unsigned long  must be OBJREF_SIGNATURE

flags       unsigned long  OBJREF flags (section 3.5)

GUID        iid            Interface identifier

std         STDOBJREF      A standard object reference used to
                            connect to the source object (Section
                            3.4).

clsid       CLSID          The CLSID of handler to create in the
                            destination client.

SaResAddr   STRINGARRAY    The resolver address.


Brown/Kindel                                                   page 14



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996



3.3.3 OBJREF_CUSTOM

A marshaling of an object which supports custom marshaling. The Custom
format gives an object control over the representation of references
to itself. For example, an immutable object might be passed by value,
in which case the class-specific information would contain the
object's immutable data. See the IMarshal interface.


Member      Type           Semantic

signature   unsigned long  must be OBJREF_SIGNATURE

flags       unsigned long  OBJREF flags (section 3.5)

GUID        iid            Interface identifier

clsid       CLSID          The CLSID of the object to create in the
                            destination client.

cbExtension unsigned long  The size of the extension data.

size        unsigned long  The size of the marshaled data provided
                            by the source object, plus the size of
                            the extension data, and passed in pData.

pData       byte*          The data bytes that should be passed to
                            IMarshal::UnmarshalInterface on a new
                            instance of class clsid in order to
                            initialize it and complete the unmarshal
                            process (class specific data).

                            The first cbExtension bytes are the
                            reserved for future extensions to the
                            protocol, and should not be passed into
                            the custom unmarshaler.
                            CoUnmarshalInterface should skip the
                            extension data, and the data starting at
                            pData+cbExtension should be given to the
                            custom unmarshaler.



3.4 STDOBJREF

An instance of a STDOBJREF represents a COM interface pointer that has
been marshaled using the standard COM network protocol.

The members and semantics of the STDOBJREF structure are as follows:


Member       Semantic

flags        Flag values taken from the enumeration SORFFLAGS. These
             are described in Section 3.5.

cPublicRefs  The number of reference counts on ipid that are being
             transferred in this marshaling.

oxid         The OXID of the server that owns this OID.

oid          The OID of the object to which ipid corresponds.

ipid         The IPID of the interface being marshaled.





Brown/Kindel                                                   page 15



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

3.5 SORFLAGS

The various SORFLAGS values have the following meanings. The
SORF_OXRESxxx bit flags are reserved for the object exporter's use
only, and must be ignored by object importers. They need not be passed
through when marshaling an interface proxy.


Flag         Value   Meaning

SORF_NULL    0       Convenient for initialization.

SORF_OXRES1  1       Reserved for exporter.

SORF_OXRES2  32      Reserved for exporter.

SORF_OXRES3  64      Reserved for exporter.

SORF_OXRES4  128     Reserved for exporter.

SORF_OXRES5  256     Reserved for exporter.

SORF_OXRES6  512     Reserved for exporter.

SORF_OXRES7  1024    Reserved for exporter.

SORF_OXRES8  2048    Reserved for exporter.

SORF_NOPING  4096    This OID does not require pinging. Further, all
                     interfaces on this OID, including this IPID,
                     need not be reference counted. Pinging and
                     reference counting on this object and its
                     interfaces are still permitted, however, though
                     such action is pointless.



3.6 ORPCINFOFLAGS

The various ORPCINFOFLAGS have the following meanings.


Flag             Meaning

ORPCF_NULL       (Not a real flag. Merely a defined constant
                 indicating the absence of any flag values.)

ORPCF_LOCAL      The destination of this call is on the same machine
                 on which it originates. This value is never to be
                 specified in calls which are not in fact local.

ORPCF_RESERVED1  If ORPCF_LOCAL is set, then reserved for local use;
                 otherwise, reserved for future use.

ORPCF_RESERVED2  If ORPCF_LOCAL is set, then reserved for local use;
                 otherwise, reserved for future use.

ORPCF_RESERVED3  If ORPCF_LOCAL is set, then reserved for local use;
                 otherwise, reserved for future use.

ORPCF_RESERVED4  If ORPCF_LOCAL is set, then reserved for local use;
                 otherwise, reserved for future use.


Implementations may use the local and reserved flags to indicate any
extra information needed for local calls. Note that if the ORPCF_LOCAL
bit is not set and any of the other bits are set then the receiver
should return a fault.





Brown/Kindel                                                   page 16



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

3.7 ORPCTHIS

In every Request PDU that is an ORPC, the body (CL case) or the stub
data (CO case) which normally contains the marshaled arguments in fact
begins with an instance of the ORPCTHIS structure. The marshaled
arguments of the COM interface invocation follow the ORPCTHIS; thus,
viewed at the DCE RPC perspective, the call has an additional first
argument. The ORPCTHIS is padded with zero-bytes if necessary to
achieve an overall size that is a multiple of eight bytes; thus, the
remaining arguments are as a whole eight byte aligned.

As in regular calls, the causality id must be propagated. If A calls
ComputePi on B, B calls Release on C (which gets converted to
RemRelease), and C calls Add on A, A will see the same causality id
that it called B with.


Member      Type               Semantic

version     COMVERSION         The version number of the COM
                                protocol used to make this particular
                                ORPC. The initial value will be 5.1.
                                Each packet contains the sender's
                                major and minor ORPC version numbers.
                                The client's and server's major
                                versions must be equal. Backward
                                compatible changes in the protocol
                                are indicated by higher minor version
                                numbers. Therefore, a server's minor
                                version must be greater than or equal
                                to the client's. However, if the
                                server's minor version exceeds the
                                client's minor version, it must
                                return the client's minor version and
                                restrict its use of the protocol to
                                the minor version specified by the
                                client. A protocol version mismatch
                                causes the RPC_E_VERSION_MISMATCH
                                ORPC fault to be returned.

flags       unsigned long      Flag values taken from the
                                enumeration ORPCINFOFLAGS (section
                                3.6). Reserved unsigned long Must be
                                set to zero.

reserved1   unsigned long      Set to zero.

cid         CID                The causality id of this ORPC.

extensions  ORPC_EXTENT_ARRAY* The body extensions, if any, passed
                                with this call. Body extensions are
                                GUID-tagged blobs of data which are
                                marshaled as an array of bytes.
                                Extensions are always marshaled with
                                initial eight byte alignment. Body
                                extensions which are presently
                                defined are described in Section
                                3.10.


The cid field contains the causality id. Each time a client makes a
unique call, a new causality id is generated. If a server makes a call


Brown/Kindel                                                   page 17



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

while processing a request from a client, the new call must have the
same causality id as the call currently being processed. This allows
simple servers to avoid working on more then one thing at a time (for
example A calls B calls A again, meanwhile C tries to call A with a
new causality id). It tells the server that he is being called because
he asked someone to do something for him. There are several
interesting exceptions.

The causality id for maybe and idempotent calls must be set to
CID_NULL. If a server makes a ORPC call while processing such a call,
a new causality id must be generated.

In the face of network failures, the same causality id may end up in
use by two independent processes at the same time. If A calls B calls
C calls D and C fails, both B and D can independently, simultaneously
make calls to E with the same causality id.

The extensions field contains extensions to the channel header,
described in Section 3.10. Note that in order to force the ORPCTHIS
header to be 8 byte aligned an even number of extensions must be
present and the size of the extension data must be a multiple of 8.



3.8 ORPCTHAT

In every Response PDU that is an ORPC, the body (CL case) or the stub
data (CO case) which normally contains the marshaled output parameters
in fact begins with an instance of the ORPCTHAT structure. The
marshaled output parameters of the COM interface invocation follow the
ORPCTHAT; thus, viewed at the DCE RPC perspective, the call has an
additional output parameters. The ORPCTHAT is padded with zero-bytes
if necessary to achieve an overall size that is a multiple of eight
bytes; thus, the remaining output parameters as a whole are eight byte
aligned.


Member      Type                Semantic

flags       unsigned long       Flag values taken from the
                                 enumeration ORPCINFOFLAGS (section
                                 3.6).

extensions  ORPC_EXTENT_ARRAY*  The body extensions, if any,
                                 returned by this call. See Section
                                 3.10 for a general description of
                                 body extensions as well as a
                                 description of existing well-known
                                 extensions.



3.9 HRESULTs

HRESULTs are the 32-bit return value from all ORPC methods. The
following is a partial list of already defined HRESULTs.


S_OK                   Success. (0x00000000)

E_OUTOFMEMORY          Insufficient memory to complete the call.
                       (0x80000002)

E_INVALIDARG           One or more arguments are invalid.


Brown/Kindel                                                   page 18



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

                       (0x80000003)

E_NOINTERFACE          No such interface supported (0x80000004)

E_ACCESSDENIED         A secured operation has failed due to
                       (0x80070005) inadequate security privileges.

E_UNEXPECTED           Unknown, but relatively catastrophic
                       (0x8000FFFF) error.

RPC_E_INVALID_OXID     The object exporter was not found.
                       (0x80070776)

RPC_E_INVALID_OID      The object specified was not found or
                       (0x80070777) recognized.

RPC_E_INVALID_SET      The object exporter set specified was
                       (0x80070778) not found.

RPC_E_INVALID_OBJECT   The requested object does not exist


Further details TBS.



3.10 Body Extensions

Body Extensions are UUID-tagged blocks of data which are useful for
conveying additional, typically out-of-band, information on incoming
invocations (within ORPCTHIS, Section 3.7) and in replies (within
ORPCTHAT, Section 3.8).

Any implementations of the DCOM protocol may define its own extensions
with their own UUIDs. Implementations should skip over extensions
which they do not recognize or do not wish to support.

Body Extensions are marshaled as an array of bytes with initial eight
byte alignment. The following sections describe several existing body
extensions.



3.10.1 Debugging Extension

{f1f19680-4d2a-11ce-a66a-0020af6e72f4}

This extension aids in debugging ORPC. In particular it is designed to
allow single stepping over an ORPC call into the server and out of the
server into the client.

Further details TBS.



3.10.2 Extended Error Extension

{f1f19681-4d2a-11ce-a66a-0020af6e72f4}

The extended error information body extension conveys extended error
information concerning the original root cause of a error back to a
caller so that the caller can deal with it. This extension is only
semantically useful in Response and Fault PDUs.

It is intended that this error information is suitable for displaying
information to a human being who is the user; this information is not
intended to be the basis for logic decisions in a piece of client
code, for doing so couples the client code to the implementation of
the server. Rather, client code should act semantically only on the
information returned through the interface that it invokes.


Brown/Kindel                                                   page 19



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

Further details TBS.



4. IRemUnknown interface

The IRemUnknown interface is used by remote clients for manipulating
reference counts on the IPIDs that they hold and for obtaining
additional interfaces on the objects on which those IPIDs are found.

References are kept per interface rather then per object.

This interface is implemented by the COM "OXID object" associated with
each OXID ( ie each Object Exporter). The IPID for the IRemUnknown
interface on this object is returned from IOXIDResolver::ResolveOxid;
see Section 5.2.1. An OXID object need never be pinged; its interfaces
(this IPID included) need never be reference counted. IRemUnknown is
specified as follows:


//  The remote version of IUnknown.  This interface exists on every
//  OXID (whether an OXID represents either a thread or a process is
//  implementation specific).  It is used by clients to query for new
//  interfaces, get additional references (for marshaling), and
release
//  outstanding references.
//  This interface is passed along during OXID resolution.
//
[
   object,
   uuid(00000131-0000-0000-C000-000000000046)
]
interface IRemUnknown : IUnknown
{
    typedef struct tagREMQIRESULT
    {
       HRESULT      hResult;            // result of call
       STDOBJREF    std;                // data for returned interface
    } REMQIRESULT;

    HRESULT RemQueryInterface
    (
        [in] REFIPID        ripid,      // interface to QI on
        [in] unsigned long  cRefs,      // count of AddRefs requested
        [in] unsigned short cIids,      // count of IIDs that follow
        [in, size_is(cIids)]
        IID*                iids,       // IIDs to QI for
        [out, size_is(,cIids)]
        REMQIRESULT**       ppQIResults // results returned
    );

    typedef struct tagREMINTERFACEREF
    {
        IPID           ipid;           // ipid to AddRef/Release
        unsigned long  cPublicRefs;
        unsigned long  cPrivateRefs;
    } REMINTERFACEREF;

    HRESULT RemAddRef
    (

Brown/Kindel                                                   page 20



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

        [in] unsigned short    cInterfaceRefs,
        [in, size_is(cInterfaceRefs)]
        REMINTERFACEREF        InterfaceRefs[],
        [out, size_is(cInterfaceRefs)]
        HRESULT*               pResults
    );

    HRESULT RemRelease
    (
        [in] unsigned short    cInterfaceRefs,
        [in, size_is(cInterfaceRefs)]
        REMINTERFACEREF        InterfaceRefs[]
    );
}



4.1 IRemUnknown::RemQueryInterface

QueryInterface for and return the result thereof for zero or more
interfaces from the interface behind the IPID ipid. ipid must
designate an interface derived from IUnknown (recall that all remoted
interfaces must derive from IUnknown). The QueryInterface calls on the
object that are used to service this request are conducted on the
IUnknown interface of the object.

Argument     Type           Semantic

ripid        REFIPID        The interface on an object from whom
                             more interfaces are desired.

CRefs        unsigned long  The number of references sought on each
                             of the returned IIDs.

CIids        unsigned short The number of interfaces being
                             requested.

iids         IID*           The list of IIDs that name the
                             interfaces sought on this object.

ppQIResults  REMQIRESULT**  The place at which the array of the
                             results of the various QueryInterface
                             calls are returned.


ReturnValue           Meaning

S_OK                  Success. An attempt was made to retrieve each
                      of the requested interfaces from the indicated
                      object; that is, QueryInterface was actually
                      invoked for each IID. QueryInterface returned
                      S_OK for every IID specified.

S_FALSE               Success. An attempt was made to retrieve each
                      of the requested interfaces from the indicated
                      object; that is, QueryInterface was actually
                      invoked for each IID. QueryInterface returned a
                      failure code for at least one of the IIDs
                      specified.

E_NOINTERFACE         QueryInterface returned a failure code for
                      every IID specifed.

E_INVALIDARG          One or more arguments (likely ipid) were
                      invalid. No result values are returned.


Brown/Kindel                                                   page 21



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

E_UNEXPECTED          An unspecified error occurred.

E_OUTOFMEMORY         Insufficient memory to complete the call.

RPC_E_INVALID_OBJECT  The requested object does not exist. No result
                      values are returned.



4.1.1 REMQIRESULT

The REMQIRESULT structure contains the following members:


Member     Type         Semantic

hResult    HRESULT      The result code from the QueryInterface call
                        made for the requested IID.

std        STDOBJREF    The data for the returned interface. Note
                        that if hResult indicates failure then the
                        contents of STDOBJREF are undefined.



4.2 IRemUnknown::RemAddRef

Obtain and grant ownership to the caller of one or more reference
counts on one or more IPIDs managed by the corresponding OXID.


Argument       Type            Semantic

cInterfaceRefs unsigned short  The size of the rgRefs array.

InterfaceRefs  REMINTERFACEREF An array of REMINTERFACEREFs, cRefs
               []              large. Each IPID indicates an
                                interface managed by this OXID on
                                whom more reference counts are
                                sought. The corresponding reference
                                count (cInterfaceRefs), which may
                                not be zero (and thus is one or
                                more), indicates the number of
                                reference counts sought on that
                                IPID.

PResults       HRESULT*        An array of HRESULTs cInterfaceRefs
                                large, each containing the result of
                                attempting an AddRef on the ipid in
                                the corresponding REMINTERFACREF.


Return Value   Meaning

S_OK           Success. An attempt was made to retrieve each of the
               requested interface references.

E_INVALIDARG   One or more of the IPIDs indicated were not in fact
               managed by this OXID, or one or more of the requested
               reference counts was zero. None of the requested
               reference counts have been granted to the caller; the
               call is a no-op.

E_UNEXPECTED   An unspecified error occurred. It is unknown whether
               any or all of the requested reference counts have
               been granted.

CO_E_OBJNOTREG Object is not registered.


Brown/Kindel                                                   page 22



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996


A useful optimization is for a caller to RemAddRef more than needed.

When a process receives an out marshaled interface, it receives one
reference count. If the process wishes to pass that interface as an
out parameter, it must get another reference to pass along. Instead,
the process (or middleman) should get a large number of references.
Then if the interface is passed out multiple times, no new remote
calls are needed to gain additional references.

A marshaler may optionally specify more than one reference in the
STDOBJREF when marshaling an interface. This allows the middle man
case to pre-fill its cache of references without making an extra
RemAddRef call. The number of references passed is always specified in
the STDOBJREF field.

If cPrivateRefs is not zero for all IPIDs, the call to RemAddRef must
be made securely.  DCOM on the server remembers the name of the client
and the authentication and authorization service used to make to
RemAddRef call.



4.2.1 REMINTERFACEREF

Member      Type           Semantic

IPID        ipid           ipid to AddRef/Release.

unsigned    cPublicRefs    Number of public references granted .
long

unsigned    cPrivateRefs   Number  of  private  references  granted.
long                       Private references belong only to this
                           client and can not be passed to other
                           clients when marshaling the proxy. If a
                           client has only private references and
                           wishes to pass the proxy to some other
                           client, it must first obtain some public
                           references via IRemUnknown::RemAddRef and
                           then pass one or more of those references
                           in the STDOBJREF cPublicRefs field of the
                           marshaled interface.


4.3 IRemUnknown::RemRelease

Release ownership of one or more reference counts on one or more IPIDs
managed by the corresponding OXID.

If cPrivateRefs is not zero for all IPIDs, the call to RemRelease must
be made securely.  For each IPID, DCOM maintains a table of reference
counts indexed by the client identity (name, authn svc, authz svc).
All public references are stored in one entry.  Any call to RemRelease
can release public references.  Private references can only be
released by the client that added them.


Argument    Type              Semantic

cRefs       unsigned short    The size of the rgRefs array.

rgRefs      REMINTERFACEREF[] An array of REMINTERFACEREFs, cRefs
                              large. Each IPID indicates an
                              interface managed by this OXID on whom
                              more reference counts are being

Brown/Kindel                                                   page 23



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

                              returned. The corresponding reference
                              count, which may not be zero (and thus
                              is one or more), indicates the number
                              of reference counts returned on that
                              IPID.


Return Value Meaning

S_OK         Success. An attempt was made to release each of the
             requested interface references.

E_INVALIDARG One or more of the IPIDs indicated were not in fact
             managed by this OXID, or one or more of the requested
             reference counts was zero. None of the offered
             reference counts have been accepted by the server; the
             call is a no-op.

E_UNEXPECTED An unspecified error occurred. It is unknown whether
             any or all of the offered reference counts have been
             accepted.


5. The OXID Resolver

Each machine that supports the COM network protocol supports a one-
per-machine service known as the machine's `OXID Resolver.'
Communication with an  OXID Resolver is via a DCE RPC, not an ORPC.

The  OXID Resolver performs several services:

· It caches and returns to clients when asked the string bindings
  necessary to connect to OXIDs of exported objects for which this
  machine is either itself a client or is the server. Note that it
  typically returns only to client processes on the same machine as
  itself, the OXIDs for which it is a client.

· It receives pings from remote client machines to keep its own
  objects alive.

· May do lazy protocol registration in the servers which it scopes.

These services are carried out through an RPC interface (not a COM
interface) known as IOXIDResolver. An  OXID Resolver may be asked for
the information required to connect to one of two different kinds of
OXIDs, either the OXIDs associated with its own objects, or the OXIDs
associated with objects for which it is itself  a client  The second
case occurs when two or more client processes on the same machine ask
their local OXID Resolver to resolve a given OXID. The client OXID
Resolver in this case can cache the OXID information an return it to
local clients without having to contact the server’s OXID Resolver
again.



5.1 OXID Resolver Ports/Endpoints

The  OXID Resolver  resides at different endpoints (ports) depending
on the transport being used. The OXID Resolver optimally resides at
the same endpoints as the DCE RPC Endpoint Mapper (EPM). To
accommodate systems where DCOM will coexist with existing DCE RPC
installations (i.e., where an EPM and presumably a complete DCE RPC
runtime already exists), the DCOM implementation on that system will
register its interfaces with the DCE EPM and all DCOM implementations
must be able to fall back if they make DCOM-specific calls on the DCE
EPM endpoint which fail.

Brown/Kindel                                                   page 24



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996


Protocol String     Description                            Endpoint
Name(s)

ncadg_ip_udp, ip    CL over UDP/IP                         135

ncacn_ip_tcp        CO over TCP/IP                         135

ncadg_ipx           CL over IPX                            TBD

ncacn_spx           CO over SPX                            TBD

ncacn_nb_nb         CO over NetBIOS over NetBEUI           TBD

ncacn_nb_tcp        CO over NetBIOS over TCP/IP            135

ncacn_np            CO over Named Pipes                    TBD

ncacn_dnet_nsp      CO over DECNet Network Services 96
                    Protocol (DECNet Phase IV)

ncacn_osi_dna       CO over Open Systems 69
                    Interconnection (DECNet Phase V)

ncadg_dds, dds      CL over Domain Datagram Service        12

ncahttp             Hybrid over HTTP (TBS)                 80


5.2 The IOXIDResolver Interface

IOXIDResolver (in earlier DCOM documentation this interface was named
IObjectExporter) is defined as follows:


[
    uuid(99fcfec4-5260-101b-bbcb-00aa0021347a),
    pointer_default(unique)
]
interface IOXIDResolver
{
    // Method to get the protocol sequences, string bindings
    // and machine id for an object server given its OXID.
    [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] DUALSTRINGARRAY **ppdsaOxidBindings,
    [out, ref] IPID            *pipidRemUnknown,
    [out, ref] DWORD           *pAuthnHint
    );

    // Simple ping is used to ping a Set. Client machines use this
    // to inform the object exporter that it is still using the
    // members of the set.
    // Returns S_TRUE if the SetId is known by the object exporter,
    // S_FALSE if not.
    [idempotent] error_status_t SimplePing
    (
    [in]  handle_t  hRpc,
    [in]  SETID    *pSetId  // Must not be zero
    );



Brown/Kindel                                                   page 25



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

    // Complex ping is used to create sets of OIDs to ping. The
    // whole set can subsequently be pinged using SimplePing,
    // thus reducing network traffic.
    [idempotent] error_status_t ComplexPing
    (
    [in]       handle_t        hRpc,
    [in, out]  SETID          *pSetId,  // In of 0 on first
                                        // call for new set.
    [in]       unsigned short  SequenceNum,
    [in]       unsigned short  cAddToSet,
    [in]       unsigned short  cDelFromSet,
    [in, unique, size_is(cAddToSet)]   OID AddToSet[],
                 // add these OIDs to the set
    [in, unique, size_is(cDelFromSet)] OID DelFromSet[],
                 // remove these OIDs from the set
    [out]      unsigned short *pPingBackoffFactor
                 // 2^factor = multipler
    );

    // In some cases the client maybe unsure that a particular
    // binding will reach the server.  (For example, when the oxid
    // bindings have more then one TCP/IP binding)  This call
    // can be used to validate the binding
    // from the client.
    [idempotent] error_status_t ServerAlive
    (
    [in]       handle_t        hRpc
    );
}

5.2.1 IOXIDResolver::ResolveOxid

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.


Argument              Type           Description

hRpc                  handle_t       An RPC binding handle used to
                                     make the request.

pOxid                 OXID*          The OXID for whom string
                                     bindings are requested.


Brown/Kindel                                                   page 26



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

cRequestedProtseqs    unsigned       The number of protocol sequences
                      short          requested.

arRequestedProtseqs   unsigned       arRequestedProtseqs must be
                      short[]        initialized 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       A value taken from the
                      long*          RPC_C_AUTHN constants. A hint to
                                     the caller as to the minimum
                                     authentication level which the
                                     server will accept.



Return Value         Meaning

S_OK                 Success. The requested information was
                     returned.

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



Brown/Kindel                                                   page 27



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

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

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 OXID
Resolver process C and client 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 it’s local OXID Resolver process E, and creates an
OBJREF to some object inside process F. At some future time client
process D 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 D asks it’s 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 |           |

Brown/Kindel                                                   page 28



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

|            |            |  |           |           |

+------------+------------+  +-----------+-----------+

| receive    |            |  |           |           |

| OBJREF     |            |  |           |           |

| to F       |            |  |           |           |

|            |            |  |           |           |

+------------+------------+  +-----------+-----------+

| ask local  |            |  |           |           |

| Resolver C |            |  |           |           |

| to resolve |            |  |           |           |

| F          |            |  |           |           |

+------------+------------+  +-----------+-----------+

|            | ask remote |  |           |           |

|            | Resolver   |  |           |           |

|            | E to       |  |           |           |

|            | resolve F  |  |           |           |

+------------+------------+  +-----------+-----------+

|            |            |  | lookup F  |           |

|            |            |  | and       |           |

|            |            |  | return    |           |

|            |            |  | endpoints |           |

+------------+------------+  +-----------+-----------+

|            | cache      |  |           |           |

|            | endpoints  |  |           |           |

|            | to F and   |  |           |           |

|            | return to D|  |           |           |

+------------+------------+  +-----------+-----------+

| 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


Brown/Kindel                                                   page 29



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

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.


Return Value       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.




Brown/Kindel                                                   page 30



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

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

Brown/Kindel                                                   page 31



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

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   The size of the array AddToSet.
                    short

cDelFromSet         unsigned   The size of the array DelFromSet.
                    short

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.

DelFromSet          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   Acts as a hint (only) from the server
                    short*     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


Brown/Kindel                                                   page 32



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

                                this parameter is always zero.



Return Value       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.



6. Security Considerations

In general, like any generic data transfer protocol, DCOM cannot
regulate the content of the data that is transferred, nor is there any
a priori method of determining the sensitivity of any particular piece
of information within the context of any given ORPC.

Specifically, however, DCOM entirely leverages the security
infrastructure defined by DCE RPC, which allows for various forms of
authentication, authorization, and message integrity.

Further details TBS.



7. Acknowledgements

As previously noted, the DCOM protocol highly leverages the DCE RPC
Specification [CAE RPC], and we again acknowledge its usefulness to
this specification.

The DCOM protocol itself is the combined effort of a large number of
people. The following individuals in particular were critical to the
definitions which appear in this specification.

    Bob Atkinson                Deborah Black

    Vibhas Chandorkar           Richard Draves

    Mario Goertzel              Rick Hill

    Gregory Jensenworth         David Kays

    Paul Leach                  Alex Mitchell

    Kevin Ross                  Mark Ryland

    Bharat Shah                 Tony Williams




8. References

[CAE RPC] CAE Specification, X/Open DCE: Remote Procedure Call, X/Open
     Company Limited, Reading, Berkshire, UK (xopen.co.uk), 1994.
     X/Open Document Number C309. ISBN 1-85912-041-5. (also available


Brown/Kindel                                                   page 33



Internet Draft    <draft-brown-dcom-v1-spec-01.txt>    November, 1996

     online through from the OSF at
     <http://www.osf.org/mall/dce/free_dce.htm> after registration)

[COM] The Component Object Model Specification, Version 0.99,
     November, 1996, Microsoft Corporation. (also available online
     from Microsoft at
     <http://www.microsoft.com/oledev/olecom/title.htm>. Note that
     this reference is circular because this document (the DCOM wire
     protocol specification) is the same chapter 15 of the COM
     Specification.



9. Author's Addresses

Nat Brown One Microsoft Way Redmond, WA 98052-6399, U.S.A. Fax: +1
     (206) 936 7329 Email: <mailto:natbro@microsoft.com>

Charlie Kindel One Microsoft Way Redmond, WA 98052-6399, U.S.A. Fax:
     +1 (206) 936 7329 Email: <mailto:ckindel@microsoft.com>









































Brown/Kindel                                                   page 34