OSF DCE SIG J. Harrow (DEC) Request For Comments: 2.0 June 1992 PROPOSED ENHANCEMENTS FOR DCE 1.1 IDL 1. INTRODUCTION This document proposes enhancements to the DCE 1.0 IDL language and compiler, to be supported in the DCE 1.1 release. 2. COMPLETE IDL ARRAY SUPPORT IDL support for arrays in DCE V1.0 was limited to: (a) Arrays with a lower bound of zero. (b) Arrays with conformance or varying dimensions only in the first (major) dimension. DCE 1.1 will remove these restrictions by supporting fully general arrays as described in the IDL functional specification. The following example includes declarations that were not supported in DCE 1.0 that will be allowed by DCE V1.1: (a) long c1[][4]; (b) long c2[][0..3]; /* Same array shape as c1 */ (c) long c3[0..*][4]; /* Same array shape as c1 */ (d) long c4[0..*][0..3]; /* Same array shape as c1 */ (e) float d1[1..10]; /* Equivalent to FORTRAN REAL D1(10) */ (f) float d2[*..10]; /* Lower bound is determined at run time */ (g) float d3[*..*]; /* Both bounds determined at run time */ 2.1. The Min_is Attribute The s are in one-to-one correspondence with the dimensions of the array, starting at the first. If there are fewer s than the array has dimensions then the missing s are assumed to be null. An will be non-null if and only if the lower bound of the corresponding dimension is determined at runtime. Not all s in a min_is clause may be null. Harrow Page 1 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 Below are examples of the syntax. Assume values of variables are as follows: long a = -10; long b = -20; long c = -30; long d = 15; long e = 25. (a) [min_is(a)] long g1[*..10]; /* g1[-10..10] */ (b) [min_is(a)] long g2[*..10][4]; /* g2[-10..10][0..3] */ (c) [min_is(a,b)] long g3[*..10][*..20]; /* g3[-10..10][-20..20] */ (d) [min_is(,b)] long g4[2][*..20]; /* g4[0..1][-20..20] */ (e) [min_is(a,,c)] long g5[*..7][2..9][*..8]; /* g5[-10..7][2..9][-30..8] */ (f) [min_is(a,b,)] long g6[*..10][*..20][3..8]; /* g6[-10..10][-20..20][3..8] */ (g) [max_is(,,e),min_is(a)] long g7[*..1][2..9][3..*]; /* g7[-10..1][2..9][3..25] */ (h) [min_is(a,,c),max_is(,d,e)] long g8[*..1][2..*][*..*]; /* g8[-10..1][2..15][-30..25] */ Implementation Note: As C does not directly support conformant arrays or arrays with non-zero lower bounds, the C representation of such an array is a pointer to the base type of the array. 2.2. Analysis of Implementation Tasks (a) Remove semantic checks that impose the DCE 1.0 restrictions. (b) Enhance header file generation for the fully general arrays. (c) Enhance stub generation to support the fully general arrays. 3. REFLECTION OF NODE DELETIONS FROM SERVER TO CLIENT The DCE 1.0 support for [ptr] pointers is not transparent in that if a manager routine releases storage via rpc_ss_free() for an input parameter, the corresponding free call does not occur in the client code. This additional transparency will be supported by DCE 1.1. It is enabled on a per-operation basis by specifying the [reflect_deletions] operation attribute. In the following example, if rpc_ss_free() is called with the value of parameter A in the manager code, the appropriate free() routine will be invoked in the Harrow Page 2 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 client stub with the value of parameter A in the client address space. [reflect_deletions] my_oper( [in,ptr] long int *A ); 3.1. Distinction of Node Deletion and Orphaning If, during an RPC call, application code uses the IDL-provided rpc_ss_free routine to free a node pointed to by a [ptr] pointer, the effect of that free will be duplicated on return to the caller by having the caller stub call the appropriate free routine. If the called application routine orphans a node by simply breaking the link to it instead of freeing it as described above, then the corresponding node will be orphaned at the caller. Note that this discussion applies only to nodes that are a part of the parameter either at the time of the call or at the time of the return. Nodes that are created by the callee and either deleted or orphaned before the return will not be reflected back to the caller in any way. Also, changes to orphaned nodes are not reflected back to the caller. 3.2. Analysis of Implementation Tasks (a) Add [reflect_deletions] attribute to IDL grammar. (b) Enhance server implementation of rpc_ss_free() routine to save list of node numbers that have been freed. (c) Modify server stub generation to transmit the conformant array of node numbers specifying the list of node numbers to be freed. (d) Modify client stub generation to receive the conformant array of node numbers, lookup the associated addresses and invoke the proper free routine. 4. NON-ENCAPSULATED UNIONS A union that is created without the use of the production is a non-encapsulated union. The discriminant of a non- encapsulated union is another parameter, if the union is a parameter, or another structure field if the union is a structure field. When the non-encapsulated union is being declared as a type, the production must be used. When a type that is a non-encapsulated type is used to declare a structure field or a parameter, the production must be used. When a non-encapsulated union is being declared directly as a structure field or a parameter, the production must be used. Harrow Page 3 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 Some examples of non-encapsulated unions: (a) typedef [switch_type(long)] union { [case (1,3)] float a_float; [case (2)] short b_short; [default]; /* An empty arm; nothing is shipped. */ } n_e_union_t; (b) typedef struct { long a; /* The discriminant for the union later in this struct. */ [switch_is(a)] n_e_union_t b; } a_struct; /* Note switch can follow union in operation */ (c) void op1 ( [in] handle_t h, [in, switch_is (s)] n_e_union_t u, [in] long s ); The n_e_union_t construct, above, gets turned into the following C union declaration in the generated header file. typedef union { float a_float; short b_short; } n_e_union_t; 4.1. Complete Union Syntax The syntax for a union definition is: (a) ::= union | (b) ::= union { } | union { } (c) ::= switch ( ) [ ] (d) ::= | | | Harrow Page 4 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 (e) ::= union { } | union { } (f) ::= (g) ::= [ ] ... (h) ::= [ ] ... (i) ::= [ ] ... | (j) ::= | (k) ::= case : (l) ::= <[> case ( [ , ] ... ) <]> (m) ::= default : (n) ::= <[> default <]> (o) ::= [ ] ; (p) ::= switch_type ( ) (q) ::= switch_is ( ) 4.2. Analysis of Implementation Tasks (a) IDL grammar (b) Semantic checks (c) Header file generation (d) Stub generation 5. UNIQUE ATTRIBUTE FOR POINTERS The [unique] attribute is the third and final pointer class to be supported by IDL. It provides a level of capability which can be efficiently implemented, and yet provides enough flexibility for the needs of many applications. Just as the current attributes [ref] and [ptr], it may be applied at the declaration site of a pointer in order to describe the required capabilities of the pointer. Harrow Page 5 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 5.1. Description of Unique Pointers A unique pointer is more flexible than a reference pointer, although it shares several important characteristics. The distinguishing characteristics of a unique pointer are: (a) A unique pointer may have the value NULL. (b) A unique pointer may change from NULL to non-NULL during a call. This results in allocating memory on return from the call, into which the result is stored. (c) A unique pointer may change from non-NULL to NULL during a call. This results in orphaning the pointee on return from the call. (d) If a unique pointer changes from one non-NULL value to another non-NULL value, the change is ignored. Unique pointers do not identify particular extents of memory. They simply identify an extent of memory suitable for storing the data. If it is important to know that a different memory location is storing the data for some reason, then one should use full pointers. A unique pointer has the following characteristics in common with reference pointers. (a) No storage pointed to by a unique pointer can be reached from any other name in the operation; i.e., the pointer does not cause any aliasing of data within the operation. (b) Data returned from the callee is written into the existing storage specified by the unique pointer if the pointer did not have the value NULL. 5.2. Analysis of Remaining Implementation Tasks (a) Modify stub generatation to handle [unique] pointers. (b) Regenerate stub support library routines for pointed-at types to include the newly add [unique] support. 6. USER-DEFINED EXCEPTIONS This extension to the IDL compiler will allow specification of a set of user-defined exceptions that may be generated by the server implementation of the interface. If an exception occurs during the execution of the server, it terminates the operation and the exception is propagated from server to client. Exceptions are declared via the exceptions interface attribute which has the following syntax: Harrow Page 6 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 :== exceptions ( [, ] ... ) Example of the exceptions attribute: [uuid(06255501-08af-11cb-8c4f-08002b13d56d), version(1.1), exceptions( exc_e_exquota, binop_e_aborted, binop_e_too_busy, binop_e_shutdown) ] interface binop { long binop_add( [in] long a, [in] long b ); } Since exceptions are associated with operation implementation, they are not imported into other interfaces via the import statement. 6.1. ACF Support for User-Defined Exceptions In order to make exceptions as transparent as possible, the default behavior is for IDL to define and initialize the exceptions under a once block in the generated stubs. If, however, the user wants to share exception names across multiple interfaces, or closely control their definition and initialization, they may use an ACF attribute to disable this automatic exception definition mechanism. (a) :== extern_exceptions [ ( [, ] ... ) ] (b) [extern_exceptions(exc_e_exquota)] interface binop {} If [extern_exceptions] is specified without a list of exceptions, no exceptions specified in the interface are defined or initialized. If a list of exceptions are present they represent the set of exceptions that are defined external to the interface and thus are not defined or initialized. All other exceptions listed in the [exceptions] attribute of the interface are defined and initialized. This attribute indicates that the specified exceptions are defined and initialized in some other external manner prior to making a call on the interface. They may be predefined exceptions (such as exc_e_exquota), provided by some other interface, or defined and initialized explicitly by the application itself. Harrow Page 7 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 6.2. NDR Representation of User-defined Exceptions The set of exceptions listed in the of an interface will be associated in order with unsigned integer values starting with one. These integer values provide the network representation of the exceptionsfor this interface. The NDR of a user-defined exception is a fault packet containing two idl_ulong_int values. The first being the fault nca_s_fault_user_defined from ncastat.idl followed by the integer value associated with the particular exception that occurred. 6.3. Design Tradeoffs The specified in the are the names of exceptions manipulated via the dce/exc_handling.h exception package. This is necessary to provide a consistent treatment of exceptions throughout DCE and allow for a portable implementation. The design outlined above allows specification of exceptions on a per-interface basis. If desired, exception specification could be allowed on a per-operation basis. This appears, however, to provide primarily a form of forced documentation, while providing little additional capability. Advantages of per-operation exceptions: (a) Provides explicit documentation of which operation may raise which exceptions. (b) If an operation raises an unexpected exception, the client will see rpc_x_unknown_remote_fault instead of the actual exception thus the application may handle all error cases without the use of a CATCH_ALL. Disadvantages of per-operation exceptions: (a) Requires repeated specification of shared exceptions on each operation. (b) Requires un/marshaling code to be generated per-operation. (c) If an operation raises an unexpected exception, the client will see rpc_x_unknown_remote_fault instead of the actual exception thus reducing the level of information available. Considering the concerns regarding stub size, and relatively small advantages provided by per-operation exceptions, this design chose declaration of exceptions on a per-interface basis. Harrow Page 8 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 6.4. Analysis of Implementation Tasks (a) Add [exceptions(...)] interface attribute to IDL grammar. (b) Add [extern_exceptions(...)] interface attribute to the ACF grammar. (c) Generate two mapping functions into the cstub and sstub. One for idl_ulong_int-to-exception and one from exception-to- idl_ulong_int. (d) Add a nca_s_fault_user_defined status to ncastat.idl that identifies a fault packet containing an exception integer value. (e) Generate a routine into the cstub and sstub to perform the EXC_INIT on each of the exceptions defined in the interface subject to the [extern_exceptions] attribute as described above. (f) Call the internal exception initialization routine for the interface within the stub once block. (g) Upon detecting an exception in the server stub, the exception- to-idl_ulong_int function is called and a fault packet containing nca_s_fault_user_defined followed by the idl_ulong_int representing the exception number. (h) The client stub should be extended to handle the nca_s_fault_user_defined specially by unmarshalling the exception number, calling the idl_ulong_int-to-exception function and then raising the indicated exception. 7. IDL ENCODING SERVICES (SUPPORT FOR PICKLING/PERSISTENT DATA STORAGE) This extension to the IDL stub compiler will enable instances of one or more data types to be encoded into and decoded from a byte stream format suitable for persistent storage. 7.1. IDL Syntax The presence of the interface attribute [encoding] indicates that this interface is intended to describe a set of operations used to encode and decode data specified as procedure arguments into/from a byte stream commonly referred to as a pickle. Harrow Page 9 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 7.2. IDL Semantics An [encoding] interface imposes restrictions upon the operations contained in the interface. Example restrictions include: (a) The [in] and [out] attributes are not significant. All parameters are considered to be [in,out] and are to be of a data type consistant with an [in,out] parameter (e.g. all parameters must be passed by reference). (b) An operation may not have a function result. (c) An operation may not have a [context_handle] argument. (d) An operation may not utilize [auto_handle] for binding. (e) An operation may not contain any pipe parameters. 7.3. User API For RPC calls the IDL data type handle_t is generated as an rpc_binding_handle_t. Since an [encoding] interface implements a method of storing and retrieving data, the handle_t type is generated as an idl_encoding_handle_t in the stub code. Similar to a pipe data structure, the idl_encoding_handle_t is a reference to a structure which provides the routines and state to manage the byte stream utilized as the encoding format. This provides flexibility to the application programmer in how the byte stream is allocated and managed. struct idl_encoding_struct_t { enum {encode,decode} operation; /* Select Encode/Decode */ idl_void_p_t state; /* For use by read/ write/allocate */ idl_ulong_int byte_count; /* Total bytes read/written */ void (* allocate)( /* Routine to provide encoding buffer */ struct idl_encoding_struct_t *h, /* [in,out] encoding handle */ idl_char *buf, /* [out] Address of buffer */ idl_ulong_int *size /* [in,out] Requested Size/Size of buffer */ ); void (* write)( /* Routine to provided encoded data to application */ struct idl_encoding_struct *h, /* [in,out] encoding handle */ Harrow Page 10 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 idl_char *buf, /* [in] Encoded data */ idl_ulong_int size /* [in] Size of encoded data */ ); void (* read)( struct idl_encoding_struct *h, /* [in,out] encoding handle */ idl_char *buf, /* [out] Data to be decoded */ idl_ulong_int *size /* [out] Size of buf */ ); } idl_encoding_struct_t; typedef struct idl_encoding_struct_t *idl_encoding_handle_t; The stubs check the operation field of the idl_encoding_struct_t to determine the operation to be performed. If the operation field has the value of encode then the supplied arguments are marshalled into a byte stream which is provided to the user in terms of the write() function provided in the handle. If the operation field has the value of decode, the stubs only do unmarshalling of the byte stream provided by calls to the read() function with the values returned via the operation arguments. 7.3.1. The allocate(state, buf, size) routine The allocate function is required to return the address of a buffer that is 8-byte aligned and a multiple of 8-bytes in length. This allows for optimized data manipulation in the generated stubs. The [in] size argument provides is the size requested by the stubs, the allocate routine may choose to return a buffer of a different size within the above constraints by indicating the size of the resulting buffer via the [out] size argument. 7.3.2. The read(state, buf, size) routine The read function is required to return the address of a buffer that is 8-byte aligned and a multiple of 8-bytes in length. This allows for optimized data manipulation in the generated stubs. 7.3.3. The write(state, buf, size) routine The write function is required to process the provided buffer that now contains the encoded byte stream. It will be called when the active buffer has been filled, or when the end of the encoding has been reached. Harrow Page 11 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 7.4. Information Routines void idl_encoding_inq_id( /*[in]*/ idl_encoding_t encoding, /* Address of encoded byte stream */ /*[out]*/ uuid_t *if_uuid, /* Interface uuid */ /*[out]*/ idl_ulong_int *if_op_num, /* Interface operation number */ /*[out]*/ error_status_t *st ); void idl_encoding_inq_header( /*[in]*/ idl_encoding_t encoding, /* Address of encoded byte stream */ /*[out]*/ uuid_t *if_uuid, /* Interface uuid */ /*[out]*/ idl_ulong_int *if_op_num, /* Interface operation number */ /*[out]*/ idl_ushort_int *if_minor_version, /* Interface version */ /*[out]*/ error_status_t *st ); void idl_encoding_set_header( /*[in,out]*/ idl_encoding_t encoding, /* Address of encoded byte stream */ /*[in]*/ idl_ulong_int encoding_version, /* Encoding version number */ /*[in]*/ idl_ulong_int data_length, /* Length of encoding (if available) */ /*[in]*/ uuid_t if_uuid, /* Interface uuid */ /*[in]*/ idl_ulong_int if_version, /* Interface version */ /*[in]*/ idl_ulong_int if_op_num, /* Operation number */ /*[in]*/ rpc_syntax_id_t encoding_syntax, /*[out]*/ error_status_t *st ); Harrow Page 12 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 7.5. Processing Description In order to support a wide variety of applications, the API of an encoding interface can be used in several ways. In the most general form, processing of the byte stream is done via routine. This allows for large, dynamically sized data, to be encoded/decoded incrementally. 7.5.1. Generalized encode operation In order to perform an encode operation, the application allocates and initializes an idl_encoding_struct_t. The following fields of the handle are relevant for a encode operation: (a) The operation field should be the value encode. (b) The state field should be initialized to an application- specific value as needed. (c) The allocate routine supplies an allocator which provides buffers into which the byte stream is written. (d) The write routine is used to communicate completed buffers back to the application for processing. (e) Upon invoking the stub routine, the allocate function supplied in the idl_encoding_struct_t will be called to obtain a buffer into which the byte stream will be written. If the size of all operation arguments can be determined at IDL compile time, then the requested size should be an approximation of the size of the resulting byte stream. In either case, the allocate routine may choose to provide either a larger or smaller buffer. The actual size of the buffer returned is indicated via the size argument to the allocate routine. The stub processes each argument encoding it into the buffer provided. After filling the buffer, or reaching the end of the byte stream, the stub calls the write routine. 7.5.2. Generalized decode operation In order to perform a decode operation, the application allocates and initializes an idl_encoding_struct_t. The following fields of the handle are relevant for a encode operation: (a) The operation field should be the value decode. (b) The state field should be initialized to an application- specific value as needed. (c) The read routine is used to request a portion of the byte stream be delivered to the stub for processing. Harrow Page 13 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 Upon invoking the stub routine, the read function supplied in the idl_encoding_struct_t will be called to obtain a buffer containing a portion of the byte stream. The read function will be called repeatedly until the entire byte stream has been obtained and the arguments decoded back into the operation arguments. 7.5.2.1. Example (a) scalars.idl: [encoding, uuid(689d24d8-45f0-11cb-825f-08002b107359)] interface scalars { void data_set1( handle_t h, long *a, long *b, double *c ); } (b) scalars.acf: interface scalars { data_set1([comm_status] st); } (c) scalars.c: #include #include "scalars.h" extern my_read(); main() { idl_ulong_int a,b; idl_long_float c; FILE *x = fopen("my_scalars.dat"); idl_encoding_struct_t my_data_h; error_status_t st; /* Decode file x, into values */ my_data_h.state = (idl_void_p_t)x; my_data_h.read = &my_read; my_data_h.operation = decode. data_set1(&my_data_h, &a, &b, &c, &st); if (st != error_status_ok) abort(); fclose(x); printf("My data: %d, %d, %f\n", a, b, c); } Harrow Page 14 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 7.5.3. Simplified encode/decode operations For applications that require less control over allocation and manipulation of the byte stream, an encoding interface supplies a default implementation of the allocate, read, and write functions. In order to utilize these default routines, the application allocates and initializes an idl_encoding_struct_t as follows: (a) The operation field should have the value encode or decode as desired. (b) The allocate, write and read routines should be set to NULL. (c) The state field is treated as an "idl_byte *". For a encode operation it is used to return the encoded byte stream. For a decode operation, the state field is used as input to provide the starting address of the memory resident byte stream. Under these circumstances the byte stream created by the encode operation is returned via the state field of the idl_encoding_struct_t. The current client memory management routines are used to allocate the resulting buffer. This is normally malloc/free (rpc_ss_allocate/rpc_ss_free from within a manager call) unless otherwise specified via rpc_ss_set_client_alloc_free() or rpc_ss_swap_client_alloc_free(). For a decode operation, the state field contains the starting address of the complete memory resident byte stream. Note that depending upon the size and complexity of data in the interface, utilizing this option will likely result in somewhat reduced performance as it may require an additional data copy in order to provide an contiguous buffer. 7.5.3.1. Example (a) scalars.idl: [encoding, uuid(689d24d8-45f0-11cb-825f-08002b107359)] interface scalars { void data_set1( handle_t h, long *a, long *b, double *c ); } (b) scalars.c: #include "scalars.h" main() { Harrow Page 15 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 idl_ulong_int a = 8, b = 22; idl_long_float c = 72.3; idl_encoding_struct_t my_data_h; /* Create byte stream encoding of my data */ my_data_h.operation = encode; my_data_h.allocate = NULL; my_data_h.write = NULL; data_set1(&my_data_h, &a, &b, &c); /* Display then free the encoded byte stream */ fwrite(my_data_h.state, my_data_h.byte_count, 1, stdout); free(my_data_h.state); } 7.6. Implementation Issues The encoding format of the byte stream will be an extended version of that used by DCE security. It will be enhanced to contain the interface version, and the operation number the pickle represents. Issues: (a) The idl_pkl_header_t contains the length of the encoding. Using the general encoding interface, the length field cannot be set until the entire data stream has been processed (or at least the length has been determined). The length field could support the value of zero denoting undetermined length. The API would then need to enable the size of an idl_encoding_t be supplied by the application. IDL doesn't actually need the size anyway because it knows how much data there must be. (b) Is the 24-bit limitation on a pickle size reasonable? 16777200 seems large, but no doubt some application would hit this limit as this will be a general use feature. Should we extend it to a 32-bit field? (c) Should we just remove the length field from the idl_pkl_header_t completely? Is it used by security? This would eliminate the previous two issues. (d) Should the allocate() routine be eliminated from the handle and just have the application process the data that appears as an argument to the write() routine? (e) The current header is in big endian encoding. If the header is extended for other reasons, it would make sense to call the integers in the header NDR encoded and include a byte which indicates their endianess. Harrow Page 16 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 7.6.1. Extensions to the idl_pkl_t security data type This section describes the idl_pkt_t data type. This is still in flux based upon resolution of the above issues. A pickle is the representation in a byte stream of a value whose type is specified in IDL. A pickle is divided into two parts: a "header" part followed by a "data" part. The header part contains four fields encoded according to the spec given below: an rpc_syntax_id_t specifying the encoding used in the pickle, the three drep field necessary to describe the data types used in the encoding, a uuid_t, interface version, and operation number specifying the interface of the value encoded in the pickle, an unsigned small (8 bit) pickle header version number (1 for this version), and a 32 bit unsigned integer giving the length in bytes of the data part of the pickle. The size of the header part of a pickle is TBD bytes. For applications that need to access the data part of a pickle the constant idl_pkl_data_offset is defined. The data part of a pickle is a byte stream that contains the encoding of the value per the encoding syntax specified in the header; this may include some info that is needed by the selected syntax and properly part of the pickled value (e.g. the NDR format label). Assuming that the info in a pickle header could be modeled by the following type: struct idl_pkl_header_t { unsigned8 version; /* pickle header version (now version=1) */ unsigned8 fill1; /* These 3 bytes could be used for data size if 16 meg is enough */ unsigned8 fill2; unsigned8 fill3; rpc_syntax_id_t syntax; /* encoding syntax used */ uuid_t if_uuid; /* id of interface */ unsigned32 if_version; /* version of interface */ unsigned32 op_num; /* operation number of encoding */ unsigned32 data_size; /* Size of data portion of byte stream (unless 16meg is enough) */ } idl_pkl_header_t; here is the layout of the pickle header (all integers are encoded n big-endian form): Harrow Page 17 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 name type offset(s) ---- ---- --------- version unsigned8 0 fill unsigned8 1,2,3 syntax.id.time_low unsigned32 4,5,6,7 syntax.id.time_mid unsigned16 8,9 syntax.id.time_hi_and_version unsigned16 10,11 syntax.id.clock_seq_hi_and_reserved unsigned8 12 syntax.id.clock_seq_low unsigned8 13 syntax.id.node[0] byte 14 syntax.id.node[1] byte 15 syntax.id.node[2] byte 16 syntax.id.node[3] byte 17 syntax.id.node[4] byte 18 syntax.id.node[5] byte 19 syntax.version unsigned32 20,21,22,23 if_uuid.id.time_low unsigned32 24,25,26,27 if_uuid.id.time_mid unsigned16 28,29 if_uuid.id.time_hi_and_version unsigned16 30,31 if_uuid.id.clock_seq_hi_and_reserved unsigned8 32 if_uuid.id.clock_seq_low unsigned8 33 if_uuid.id.node[0] byte 34 if_uuid.id.node[1] byte 35 if_uuid.id.node[2] byte 36 if_uuid.id.node[3] byte 37 if_uuid.id.node[4] byte 38 if_uuid.id.node[5] byte 39 if_version unsigned32 40,41,42,43 op_num unsigned32 44,45,46,47 data_size unsigned32 48,49,50,51 8. ENABLE REBINDING UNDER CUSTOMIZED/IMPLICIT BINDING This feature is an enhancement to the API for customized and implicit binding to allow attempts on multiple servers. Currently, the use of implicit or customized binding handles provide users with a way to build an RPC interface that appears to the caller as a local interface. They currently do not, however, support attempts on multiple servers due to their limited API. This feature is enabled by applying the [rebind] ACF attribute to either the customized handle or a customized implicit handle (i.e. an implicit handle whose type is not handle_t). Upon the failure of the RPC call utilizing either the customized or customized implicit binding method with the [rebind] attribute, a user-supplied rebind routine will be invoked to provide another handle on which to attempt the call. The rules under which a rebind are attempted due to an error are the same as those for the [auto_handle] binding method. The rebind routine for a handle with the [rebind] attribute has the following signature: Harrow Page 18 DCE-RFC 2.0 Proposed Enhancements for DCE 1.1 IDL June 1992 handle_t _rebind( /*[in]*/ instance, /* Customized handle */ /*[in]*/ handle_t h, /* Previous handle (from failing call) */ /*[in]*/ error_status_t st /* Status from failing call */ ); The application may indicate that rebinding is not possible by returning the value of NULL as the function result of the rebind routine. Note that the rebind routine has the responsibility for freeing the h argument, if necessary. The unbind routine is only called once per operation with the possibly NULL handle_t returned from the final call to the rebind routine. 8.1. Analysis of Implementation Tasks (a) Add [rebind] attribute to ACF grammar. (b) Generate rebind routine prototype into header file. (c) Adapt retry loop used to implement auto_handle, for retry of customized bindings. (d) Invoke the rebind routine, and retry call if a new handle is provided. AUTHOR'S ADDRESS Jerry Harrow Internet email: harrow@r2me2.enet.dec.com ZK02-1/Q18 Telephone: +1-603-881-2193 110 Spitbrook Rd. Nashua, NH 03062 USA Harrow Page 19