Coda File System

Next Previous Contents

3. The RP2Gen Stub Generator

3.1 Introduction

RP2GEN takes a description of a procedure call interface and generates stubs to use the RPC2 package, making the interface available on remote hosts. RP2GEN is designed to work with a number of different languages (C, FORTRAN 77, PASCAL), however, only the C interface is currently implemented.

RP2GEN also defines a set of external data representations for RPC types. These representations are defined at the end of this document in the section entitled External Data Representations. Any program wishing to communicate with a remote program using the RP2GEN semantics must obey these representation standards.

3.2 Usage

RP2GEN is invoked as follows:

rp2gen file

File is the file containing the description of the interface. Normally, these files have the extension .rpc2 . RPGen creates three files named: base .client.c; base .server.c; and base .h, where base is the name of the file without the extension and the pathname prefix. Thus:

rp2gen samoan.rpc2
would yield the files: samoan .client.c; samoan .server.c; and samoan .h.

A person wanting to provide a package remotely writes his package with a normal interface. The client programmer writes his code to make normal calls on the interface. Then the client program is linked with:

ld ... base.client.o /usr/andrew/lib/librpc2.a ...
and the server program with
ld ... base.server.o /usr/andrew/lib/librpc2.a ...

The server module provides a routine, the ExecuteRequest routine, that will decode the parameters of the request and make an appropriate call on the interface. (The routine is described below in the language interface sections.) The client module translates calls on the interface to messages that are sent via the RPC2 package. The .h file contains type definitions that RP2GEN generated from the type definitions in the input file, and definitions for the op-codes used by RP2GEN. This file, which is automatically included in the server and client files, may be included by any other module that needs access to these types.

3.3 Format of the Description File

In the syntax of a description file below, non-terminals are represented by italic names and literals are represented by bold strings.


file ::=
prefixes header_line default_timeout decl_or_proc_list
prefixes ::= empty | prefix | prefix prefix
prefix ::= Server Prefix string ; | Client Prefix string ;
header_line ::= Subsystem subsystem_name ;
subsystem_name ::= string
string ::= " zero_or_more_ascii_chars "
default_timeout ::= Timeout ( id_number ) ; | empty
decl_or_proc_list ::= decl_or_proc | decl_or_proc decl_or_proc_list
decl_or_proc ::= include | define | typedef | procedure_description
include ::= #include file_name
define ::= #define identifier number
typedef ::= typedef rpc2_type identifier array_spec ;
rpc2_type ::= type_name | rpc2_struct | rpc2_enum
type_name ::= RPC2_Integer | RPC2_Unsigned | RPC2_Byte | RPC2_String | RPC2_CountedBS | RPC2_BoundedBS | SE_Descriptor | RPC2_EncryptionKey | identifier
rpc2_struct ::= RPC2_Struct { field_list }
field_list ::= field | field field_list
field ::= type_name identifier_list ;
identifier_list ::= identifier | identifier , identifier_list
rpc2_enum ::= RPC2_Enum { enum_list }
enum_list ::= enum , enum_list | enum
enum ::= identifier = number
array_spec ::= empty | [ id_number ]
id_number ::= number | identifier
procedure_description ::= proc_name ( formal_list )
timeout_override new_connection ;
proc_name ::= identifier
formal_list ::= empty | formal_parameter | formal_parameter , formal_list
formal_parameter ::= usage type_name parameter_name
usage ::= IN | OUT | IN OUT
parameter_name ::= identifier
timeout_override ::= Timeout ( id_number ) | empty
new_connection ::= NEW_CONNECTION | empty
empty ::=

In addition to the syntax above, text enclosed in /* and */ is treated as a comment and ignored. Appearances of an include statement will be replaced by the contents of the specified file. All numbers are in decimal and may be preceded by a single hyphen: - , character. Identifiers follow C syntax except that the underline character: _ , may not begin an identifier. (Note that a particular language interface defines what identifiers may actually be used in various contexts.)

The following are reserved words in RP2GEN: server , client , prefix , subsystem , timeout , typedef , rpc2_struct , rpc2_enum , in and out . Case is ignored for reserved words, so that, for example, subsystem may be spelled as SubSystem if desired. Case is not ignored, however, for identifiers. Note that the predefined type names (RPC2_Integer , RPC2_Byte , etc.) are identifiers and must be written exactly as given above.

The prefixes may be used to cause the names of the procedures in the interface to be prefixed with a unique character string. The line:

Server Prefix "test";

will cause the server file to assume that the name of the server interface procedure name is test_ name . Likewise, the statement:

Client Prefix "real";

affects the client interface. This feature is useful in case it is necessary to link the client and server interfaces together. Without this feature, name conflicts would occur.

The header_line defines the name of this subsystem. The subsystem name is used in generating a unique for the execute request routine.

The default_timeout is used in both the server and client stubs. Both are specified in seconds. Zero is interpreted as an infinite timeout value. The value specifies the timeout value used on RPC2_MakeRPC () and RPC2_SendResponse () calls in the client and server stubs respectively. The timeout parameter may be overriden for individual procedures by specifying a timeout_override . Note that the timeouts apply to each individual Unix blocking system call, not to the entire RPC2 procedure.

The new_connection is used to designate at most one server procedure that will be called when the subsystem receives the initial RPC2 connection. The new connection procedure must have 4 arguments in the following order with the following usages and types:


(IN RPC2_Integer: SideEffectType,
 IN RPC2_Integer: SecurityLevel,
 IN RPC2_Integer: EncryptionType,
 IN RPC2_CountedBS: ClientIdent,

where SideEffectType, SecurityLevel, EncryptionType, and ClientIdent have the values that were specified on the clients call to RPC2_Bind. Note that RP2Gen will automatically perform an RPC2_Enable call at the end of this routine. If no new connection procedure is specified, then the call to the execute request routine with the initial connection request will return RPC2_FAIL.

The usage tells whether the data for the parameter is to be copied in, copied out, or copied in both directions. The usage and type_name specifications together tell how the programmer should declare the parameters in the server code.

Example 1: Common Definitions for Coda File System


/*
 * Include file common to callback.rpc2, vice.rpc2 and res.rpc2
 */

typedef RPC2_Unsigned   VolumeId;
typedef VolumeId               VolId;
typedef RPC2_;Unsigned  VnodeId;
typedef RPC2_;Unsigned  Unique;

typedef RPC2_Struct 
        {
        VolumeId        Volume;
        VnodeId         Vnode;
        Unique          Unique;
        } ViceFid;

typedef RPC2_Struct
        {
        RPC2_Unsigned   Host;
        RPC2_Unsigned   Uniquifier;
        } ViceStoreId;

typedef RPC2_Struct
        {
        RPC2_Integer    Site0;
        RPC2_Integer    Site1;
        RPC2_Integer    Site2;
        RPC2_Integer    Site3;
        RPC2_Integer    Site4;
        RPC2_Integer    Site5;
        RPC2_Integer    Site6;
        RPC2_Integer    Site7;
        } ViceVersionArray;

typedef RPC2_Struct
        {
        ViceVersionArray        Versions;
        ViceStoreId     StoreId;
        RPC2_Unsigned   Flags;
        } ViceVersionVector;

typedef RPC2_Unsigned   UserId;
typedef RPC2_Unsigned   FileVersion;
typedef RPC2_Unsigned   Date;
typedef RPC2_Integer    Rights;

typedef RPC2_Enum 
        { 
        Invalid = 0,
        File = 1, 
        Directory = 2, 
        SymbolicLink = 3 
        } ViceDataType;

typedef RPC2_Enum
        {
        NoCallBack = 0,
        CallBackSet = 1,
        BidFidReleased = 3
        } CallBackStatus;


typedef RPC2_Struct
        {
        RPC2_Unsigned   InterfaceVersion;
        ViceDataType    VnodeType;
        RPC2_Integer    LinkCount;
        RPC2_Unsigned   Length;
        FileVersion     DataVersion;
        ViceVersionVector       VV;
        Date            Date;
        UserId          Author;
        UserId          Owner;
        CallBackStatus  CallBack;
        Rights          MyAccess;
        Rights          AnyAccess;
        RPC2_Unsigned   Mode;
        VnodeId         vparent;
        Unique          uparent;
        } ViceStatus;

Example 2: The Coda Resolution Subsystem Interface


/* res.rpc2 
 * Defines the resolution subsystem interface
 * 
 * Created Puneet Kumar, June 1990
 */
server prefix "RS";
client prefix "Res";

Subsystem "resolution";

#define RESPORTAL       1361
#define RESOLUTIONSUBSYSID 5893

/* 
Return codes from the servers on resolution subsystem
*/
#define RES_FAILURE     -512
#define RES_SUCCESS     0
#define RES_TIMEDOUT    -513
#define RES_NOTRUNT     -514
#define RES_BADOPLIST   -515

#include "vcrcommon.rpc2"

typedef RPC2_Struct
        {
        RPC2_Integer    status;
        RPC2_Unsigned   Author;
        RPC2_Unsigned   Owner;
        RPC2_Unsigned   Date;
        RPC2_Unsigned   Mode;
        } ResStatus;

typedef RPC2_Struct
        {
        RPC2_Integer            LogSize;
        ViceVersionVector       VV;
        } ResVolParm;

typedef RPC2_Enum
        {
        FetchStatus = 0,
        FetchSData = 1
        } ResFetchType;

typedef RPC2_Enum
        {
        ResStoreStatus = 0,
        ResStoreData = 1
        } ResStoreType;

COP2     (IN ViceStoreId StoreId,
                 IN ViceVersionVector UpdateSet);

NewConnection (IN RPC2_Integer SideEffectType,
                 IN RPC2_Integer SecurityLevel,
                 IN RPC2_Integer EncryptionType,
                 IN RPC2_CountedBS ClientIdent)
                 NEW_CONNECTION;

ForceFile    (IN ViceFid Fid,
                 IN ResStoreType Request,
                 IN RPC2_Integer Length,
                 IN ViceVersionVector VV,
                 IN ResStatus Status,
                 IN OUT SE_Descriptor BD);

LockAndFetch (IN ViceFid Fid, 
                 IN ResFetchType Request, 
                 OUT ViceVersionVector VV,
                 OUT RPC2_Integer logsize);

UnlockVol    (IN VolumeId Vid);

MarkInc      (IN ViceFid Fid);

FetchFile (IN ViceFid Fid, 
                 IN RPC2_Unsigned PrimaryHost,
                 OUT ResStatus Status,
                 IN OUT SE_Descriptor BD);

ForceDirVV (IN ViceFid Fid,
                 IN ViceVersionVector VV);

DoForceDirOps (IN ViceFid Fid,
                 IN ViceStatus status,
                 IN OUT RPC2_CountedBS AccessList,
                 OUT RPC2_Integer rstatus,
                 IN OUT SE_Descriptor sed);

GetForceDirOps  (IN ViceFid Fid,
                 OUT ViceStatus status, 
                 IN OUT RPC2_CountedBS AccessList,
                 IN OUT SE_Descriptor sed);

FetchLog (IN ViceFid Fid,
                 OUT RPC2_Integer logsize,
                 IN OUT SE_Descriptor sed);

DirResPhase2 (IN ViceFid Fid,
                 IN ViceStoreId logid,
                 OUT ViceStatus status,
                 IN RPC2_BoundedBS pbinc);

DirResPhase1 (IN ViceFid Fid, 
                 IN RPC2_Integer size,
                 IN OUT ViceStatus status,
                 IN OUT RPC2_BoundedBS piggyinc,
                 IN OUT SE_Descriptor sed);

DirResPhase3 (IN ViceFid Fid,
                 IN ViceVersionVector UpdateSet,
                 IN OUT SE_Descriptor sed);

3.4 Command Line Parameters

In addition, several command line flags are available to modify the behavior of rp2gen :

-c file

Specify the name of the client .c file.

-s file

Specify the name of the server .c file.

-h file

Specify the name of the header file.

-m file

Specify the name of the MultiRPC stub file.

-I path

Additional path to look for included files.

-e,-neterrors

Translate system-specfic error codes to caller's system-specfic codes.

-cplusplus

Generate C++ compatible code in .cc files.

3.5 The C Interface

This section describes the C interface generated by RP2GEN. The following table shows the relationship between RP2GEN parameter declarations and the corrseponding C parameter declarations.

RP2Gen representation of parameters

RPC2 Type
in out in out >
RPC2_Integer long long * long *
RPC2_Unsigned unsigned long unsigned long * unsigned long *
RPC2_Byte unsigned char unsigned char * unsigned char *
RPC2_String unsigned char * unsigned char * unsigned char *
RPC2_CountedBS RPC2_CountedBS * RPC2_CountedBS * RPC2_CountedBS *
RPC2_BoundedBS RPC2_BoundedBS * RPC2_BoundedBS * RPC2_BoundedBS *
RPC2_EncryptionKey RPC2_EncryptionKey RPC2_EncryptionKey * RPC2_EncryptionKey *
SE(Descriptor) illegal illegal
SE(Descriptor) *
RPC2_Enum name name name * name *
RPC2_Struct name name * name * name *
RPC2_Byte name[... name name name

In all cases it is the caller's responsibility to allocate storage for all parameters. This means that for IN and IN OUT parameters of a non-fixed type, it is the callee's responsibility to ensure that the value to be copied back to the caller does not exceed the storage allocated by the callee.

The caller must call an RPC2 procedure with an initial implicit argument of type RPC2_Handle that indicates the destination address(es) of the target process(es). The callee must declare the C routine that corresponds to an RPC2 procedure with an initial implicit argument of type RPC2_Handle. Upon invocation, this argument will be bound to the address of a handle that indicates the address of the caller.

RP2GEN also generates a routine that serves to decode an RPC2 request. The name of this routine is " subsystem_name_ExecuteRequest ", and it is invoked as follows:

int subsystem_name_ExecuteRequest (cid, Request, bd) RPC2_Handle cid; RPC2_PacketBuffer *Request; SE_Descriptor *bd;

This routine will unmarshall the arguments and call the appropriate interface routine. The return value from this routine will be the return value from the interface routine.

The client program is responsible for actually making the connection with the server and must pass the connection id as an additional parameter (the first) on each call to the interface.

3.6 External Data Representations

This section defines the external data representation used by RP2GEN, that is, the representation that is sent out over the wire. Each item sent over on the wire is required to be a multiple of 4 (8-bit) bytes. (Items are padded as necessary to achieve this constraint.) The bytes of an item are numbered 0 through n -1 (where n mod 4 = 0). The bytes are read and written such that byte m always precedes byte m +1.

RPC2_Integer

An RPC2_Integer is a 32-bit item that encodes an integer represented in twos complement notation. The most significant byte of the integer is 0, and the least significant byte is 3.

RPC2_Unsigned

An RPC2_Unsigned is a 32-bit item that encodes an unsigned integer. The most significant byte of the integer is 0, the least significant byte is 3.

RPC2_Byte

An RPC2_Byte is transmitted as a single byte followed by three padding bytes.

RPC2_String

An RPC2_String is a C-style null-terminated character string. It is sent as an RPC2_Integer indicating the number of characters to follow, not counting the null byte, which is, however, sent. This is followed by bytes representing the characters (padded to a multiple of 4), where the first character (i.e., farthest from the null byte) is byte 0. An RPC2_String of length 0 is representing by sending an RPC2_Integer with value 0, followed by a 0 byte and three padding bytes.

RPC2_CountedBS

An RPC2_CountedBS is used to represent a byte string of arbitrary length. The byte string is not terminated by a null byte. An RPC2_CountedBS is sent as an RPC2_Integer representing the number of bytes, followed by the bytes themselves (padded to a multiple of 4 . The byte with the lowest address is sent as byte 0.

RPC2_BoundedBS

An RPC2_BoundedBS is intended to allow you to remotely play the game that C programmers play: allocate a large buffer, fill in some bytes, then call a procedure that takes this buffer as a parameter and replaces its contents by a possibly longer sequence of bytes. An RPC2_BoundedBS is transmitted as two RPC2_Integer s representing the maximum and current lengths of the byte strings. This is followed by the bytes representing the contents of the buffer (padded to a multiple of 4). The byte with the lowest address is byte 0.

RPC2_EncryptionKey

An RPC2_EncryptionKey is used to transmit an encryption key (surprise!). A key is sent as a sequence of RPC2_KEYSIZE bytes, padded to a multiple of 4. Element 0 of the array is byte 0.

SE(Descriptor)

Objects of type @SE(Descriptor) are never transmitted.

RPC2_Struct

An RPC2_Struct is transmitted as a sequence of items representing its fields. The fields are sent in textual order of declaration (i.e., from left to right and top to bottom). Each field is sent using, recursively, its RPC2 representation.

RPC2_Enum

An RPC2_Enum has the same representation has an RPC2_Integer , and the underlying integer used by the compiler is transmitted as the value of an RPC2_Enum. (Note that in C, this underlying value may be specified by the user. This is recommended practice.)

Array

The total number of bytes transmitted for an array must be a multiple of 4. However, the number of bytes sent for each element depends on the type of the element.

Currently, only arrays of RPC2_Byte are defined. The elements of such an array are each sent as a single byte (no padding), with array element, n-1, preceding element, n .


Next Previous Contents