MIDDL to C language mapping



next up previous
Next: Action of the Up: MSRPC2 User Manual Previous: Introduction

MIDDL to C language mapping

Primitive Types

Primitive MIDDL types are output by the MSRPC2 stub compiler as their IDL name in mixed case, prefixed by the string MSRPC. They are then mapped to system C datatypes by a file called MSRPCMachineTypes.h. The current definitions are nothing mysterious; the file reads:

typedef u_int32      MSRPCBoolean;
typedef u_int16      MSRPCShortCardinal;
typedef u_int32      MSRPCCardinal;
typedef u_int64      MSRPCLongCardinal;
typedef int16        MSRPCShortInteger;
typedef int32        MSRPCInteger;
typedef int64        MSRPCLongInteger;
typedef float32      MSRPCReal;
typedef float64      MSRPCLongReal;
typedef char        *MSRPCString;
typedef u_char       MSRPCOctet;
typedef char         MSRPCChar;
-where u_int32, etc. are defined elsewhere in a machine-dependent file.

Interface References

The basic interface reference type is defined in the base types interface (see below). An interface reference is defined in MIDDL as:

MSRPCInterfaceRef : TYPE = RECORD [
        id      : MSRPCInterfaceID,
        attrs   : MSRPCAttributes,
        hint    : MSRPCAddressHint
];
-which maps to a C definition of:
typedef struct MSRPCInterfaceRef MSRPCInterfaceRef ;
struct MSRPCInterfaceRef {
    MSRPCInterfaceID id ;
    MSRPCAttributes attrs ;
    MSRPCAddressHint hint ;
} ;
  1. The id is supposed to be an identifier for the interface that is unique in time in space. It is intended to be checked at bind time to allow a client to be sure that it is talking to the interface it thinks it is. It can be regarded as ``the Truth''.
  2. The attrs field contains information about which endian the server uses for data, and whether to perform an end-to-end check on the interface id at bind time.
  3. The address hint is a discriminated union with a member for every protocol supported by MSRPC, including the local (same protection domain) optimisation. Its members are protocol specific addresses, with possible additional information such as Quality of Service hints.
Any interface reference should be regarded as nothing more than a hint as to how to bind to a service. If a bind fails it may be that the interface is still extant and even accessible, but other means may be required in order to find it, such as an additional Trader operation.

It is useful to examine the MSRPCBaseTypes interface definition and the files it includes, since they contain a fair number of useful types for representing protocol-specific addresses and may also change as new protocols are added.

Constructed Types

The 7 MIDDL type constructors map in a fairly natural way onto (slightly less safe) C types as follows. They are described by examples, many taken from the base types interface.

Aliases

MSNLQosSpec : TYPE = STRING;
-maps to:
typedef MSRPCString MSNLQosSpec ;

Arrays

MSRPC2InterfaceID : TYPE = ARRAY 8 OF OCTET;
-maps to:
typedef MSRPC2Octet MSRPC2InterfaceID[8];

Enumerations

MSRPCEndian     : TYPE = { Big, Little };
-maps to:
typedef enum {
    Big ,
    Little ,
} MSRPCEndian ;
Note that all enumeration types are guaranteed to start at 0. This is important for mapping of the power set type, described below.

Sequences

Crawl : TYPE = SEQUENCE OF Bar ;
-maps to:
typedef struct Crawl Crawl;
struct Crawl {
        MSRPCCardinal len;
        Bar          *data;
};

Sequence and strings are the only variable-length data types in MSRPC2. This has implications for unmarshalling, since the user cannot easily allocate space for them in advance as she can for other data types. MSRPC2 provides a facility for the user to control memory allocation for storage of unmarshalled sequences and strings, described later.

Records

MSRPCAttributes : TYPE = RECORD [
        endian  : MSRPCEndian,
        check   : BOOLEAN
];
-maps to:
typedef struct MSRPCAttributes MSRPCAttributes ;
struct MSRPCAttributes {
    MSRPCEndian endian ;
    MSRPCBoolean check ;
} ;

Choices

MSRPCProtocol : TYPE = { MSRPC_PROTO_MSNL,
                         MSRPC_PROTO_TCP,
                         MSRPC_PROTO_SDOM };

MSRPCAddressHint : TYPE = CHOICE MSRPCProtocol OF {
        MSRPC_PROTO_MSNL        =>      MSNLAddressHint,
        MSRPC_PROTO_TCP         =>      TCPAddressHint,
        MSRPC_PROTO_SDOM        =>      SDomAddressHint };
-maps to:
typedef enum {
    MSRPC_PROTO_MSNL ,
    MSRPC_PROTO_TCP ,
    MSRPC_PROTO_SDOM ,
} MSRPCProtocol ;

typedef struct MSRPCAddressHint MSRPCAddressHint ;
struct MSRPCAddressHint {
    MSRPCProtocol d ;
    union {
        MSNLAddressHint MSRPC_PROTO_MSNL ;
        TCPAddressHint  MSRPC_PROTO_TCP ;
        SDomAddressHint MSRPC_PROTO_SDOM ;
    } u ;
} ;

Power Sets

Bar : TYPE = SET OF Beers ;
-maps to:
typedef set_t Bar ;
-which is a generic type to represent sets. Since a set_t is actually an unsigned integer, to get information about a set type you can use the enumeration value and a shift operator to mask bits. This works because enumeration values start at 0 and is the intended mechanism for manipulating set types (indeed, set types were introduced into MIDDL as an abstraction of bitmasks).

There is currently a restriction on the maximum cardinality of a set type of 32 elements (for obvious reasons). This may be increased to 64 in the near future (for equally obvious reasons).

InterfaceRefs

Typed interface references are currently treated as type aliases.

Subtyping of Interfaces

There is no inheritance in MSRPC2.

If a MIDDL interface imports datatypes by means of the NEEDS or IS COMPATIBLE WITH directives, there is no duplication of type definitions in the C files. It remains sufficient, however, to only include the type and marshalling header files from the interface one is interested in, as this will include all the type files it needs. All header files output by the stub compiler have C preprocessor directives to ensure that they are only parsed once.

Operations and exceptions, on the other hand, are always defined from scratch for a given interface. It would in theory be possible to re-use stub routines from supertype interfaces (as the Modula-3 Network Objects implementation over ANSA does), but doing this in C would blow away what little type safety the bindings system gives you, and the stubs are very small anyway. Of course, the user level method functions can be re-used trivially.

Every interface in MSRPC2 is implicitly compatible with (in the MIDDL sense) an interface called MSRPCBaseTypes. This interface defines the engineering failure exception and the MSRPCInterfaceRef type, along with all the protocol-specific information it contains in the address hint.

Interrogations and Announcements

Operations in MIDDL are mapped onto function pointers which are members of binding structures (see bindings below). A new C type is defined for each MIDDL operation, which is a pointer to a C function returning a boolean value. Under ANSI C, these function pointers are prototyped and should take as parameters a pointer to the binding being used, followed by the parameters of the operation, followed by the results the operation returned passed by reference.

Any parameters of type RECORD, ARRAY or CHOICE (or types which are aliases to these types) are passed by reference for efficiency. Note, when used as arguments, SEQUENCES are passed by value, as they map to C structures which are more efficiently passed in this way.

Suppose a MIDDL interface called Beer defined an operation like:

BuyRound : INTERROGATION OPERATION [ num : INTEGER; order : Bar ]
              RETURNS [ pints : CARDINAL ]
              RAISES WrongOrder, TimeCalled ;
Then the stub compiler would output a type definition:
typedef (bool_t)(*Beer_BuyRound) _((
        Beer_Binding  *self,
        MSRPCInteger   num,
        Bar            order,
        MSRPCCardinal *pints ));
-and a Beer_Binding structure would contain a member called ops.BuyRound of this type.

This happens on both client and server sides, so a client would call an instance of this function type and the server would implement one. Indeed, in the case of a local (same domain) binding, the client would directly call the server routine.

Exceptions

Exceptions in MIDDL are mapped onto C functions in the server, and to an exception structure in the client. The server calls the exception routine which results in the arguments to the exception being unmarshalled into an exception structure in the client. These can then be accessed by an in-line exception handler, as described in a later section.

Thus if the Beer interface defined an exception:

WrongOrder : EXCEPTION [ who : CARDINAL ;
                         msg : STRING ] ;
-the stub compiler would output a type definition for the server of:
typedef (bool_t)(*Beer_WrongOrder) _((
        Beer_Binding   *self,
        MSRPCCardinal   who,
        MSRPCString     msg ));
-and a Beer_Binding structure would contain a member called excs.BuyRound of this type. The binding exception structure structure would also contain a union of all possible exception results, for this example this would include
struct Beer_Binding 
{ ...
   struct { ...
           union {
                   struct {
                            MSRPCCardinal who;
                            MSRPCString   msg; 
                          } WrongOrder;
                   ...
                 } u;
          } excs;
};

The binding structure also contains two fields used to signal which of the exceptions occurred (if any). In the present implementation this consists of a pointer to a table of exceptions names, and a pointer to the entry signifying the exception that occured. For gcc this allows exception name matching to be done by pointer comparison, for ansi-c compilers, string comparison is used between exception names.

The interface called MSRPCBaseTypes defines an exception:

InternalError : EXCEPTION [ status : CARDINAL ;
                            err_no : INTEGER ];
This exception is used for signalling what ANSA call ``engineering failures'': internal errors in the MSRPC2 infrastructure and the like. It is implicitly the first operation of any kind defined in an interface.



next up previous
Next: Action of the Up: MSRPC2 User Manual Previous: Introduction



Simon Crosby and Richard Hayton