Annotation of 43BSDTahoe/new/xns/doc/courier.tbl.me, revision 1.1.1.1

1.1       root        1: \" $Header: courier.tbl.me,v 1.8 87/03/17 09:32:52 ed Exp $
                      2: \" $Header: courier.tbl.me,v 1.8 87/03/17 09:32:52 ed Exp $
                      3: \" $Log:       courier.tbl.me,v $
                      4: \" Revision 1.8  87/03/17  09:32:52  ed
                      5: \" Added -I switch to establish search path for DEPENDS UPON files.
                      6: \" 
                      7: \" Revision 1.7  86/11/22  07:12:05  jqj
                      8: \" small changes reflecting differences between 4.3bsd and 4.2 Maryland XNS.
                      9: \" 
                     10: \" Revision 1.6  86/05/12  09:02:43  jqj
                     11: \" minor revisions
                     12: \" 
                     13: \" Revision 1.5  85/03/26  06:30:58  jqj
                     14: \" Revised public alpha-test version, released 26 March 1985
                     15: \" 
                     16: \" Revision 1.4  85/03/11  16:46:01  jqj
                     17: \" Public alpha-test version, released 11 March 1985
                     18: \" 
                     19: .lg 0
                     20: .fo ''%''
                     21: .(l C
                     22: .ps +4
                     23: .b
                     24: XNS Courier under UNIX (4.3BSD)
                     25: .ps -4
                     26: .sp 2
                     27: .r
                     28: .he $ XNS Courier $ $Date: 87/03/17 09:32:52 $
                     29: J.Q. Johnson
                     30: Computer Science Department
                     31: Cornell University
                     32: 405 Upson Hall
                     33: Ithaca, NY  14853
                     34: .)l
                     35: .sh 1 "Introduction"
                     36: .pp
                     37: This document describes the implementation and use
                     38: of the Courier remote procedure call protocol for Berkeley UNIX
                     39: (version 4.3), with XNS.
                     40: .sp 1
                     41: .nf
                     42: .b
                     43: .(c
                     44: ********************************************************
                     45: Warning:  this document is a DRAFT design specification.
                     46: It has not yet been fully implemented, and the details of
                     47: the interface it specifies (particularly with respect to 
                     48: Courier servers) are subject to change.  Send design
                     49: comments to [email protected] or [email protected].
                     50: ********************************************************
                     51: .)c
                     52: .r
                     53: .fi
                     54: .sp 1
                     55: .uh "Changes since previous revision:"
                     56: .np
                     57: Added discussion of encapsulated protocols.
                     58: .np
                     59: Added discussion of Clearinghouse library calls for finding a connection,
                     60: and relationship of connections to outstanding RPCs.
                     61: .uh "Earlier changes:"
                     62: .np
                     63: Changed names of generated file names to include version number.
                     64: Added discussion on scope of names vs. DEPENDS UPON modules.
                     65: .np
                     66: Users must now link Courier program ``Foo'' with Foo1_support.o.
                     67: .np
                     68: Added some discussion of freeing dynamic storage via clear_Foo.
                     69: .np
                     70: Changed
                     71: .i CourierOpen()
                     72: to take ns_addr structure rather than a string host name.  Routines for
                     73: converting from name to address (using Clearinghouse) have not yet been
                     74: designed. 
                     75: .np
                     76: Changed ERROR discussion to indicate that an ERROR is mapped to a long
                     77: with value > 65535.
                     78: .np
                     79: Changed description of BDT to reflect use of 
                     80: .i BDTread()
                     81: and
                     82: .i BDTwrite() .
                     83: .np
                     84: Added SPPMAXDATA.
                     85: .np
                     86: Changed discussion of BulkData constants to indicate that things now
                     87: work correctly.
                     88: .sh 2 "General Description"
                     89: .pp
                     90: Courier is both a protocol and a specification language.
                     91: The protocol describes how remote procedures are invoked and
                     92: how parameters and results of various data types are transmitted.
                     93: The specification language, somewhat reminiscent of Mesa,
                     94: provides a simple way of defining the remote interfaces of distributed
                     95: programs.
                     96: .pp
                     97: This implementation is an attempt to allow UNIX C programmers to
                     98: construct distributed Courier programs to communicate with other
                     99: Courier implementations layered on XNS.  It thus requires kernel
                    100: support for XNS Sequenced Packet Protocol sockets.
                    101: .pp
                    102: The simplest form of distributed program using Courier
                    103: consists of three parts.
                    104: The first is the specification,
                    105: written in the Courier language.
                    106: The specification must declare all procedures of
                    107: the program that will be called remotely (the
                    108: .i "server procedures" ).
                    109: The next part is the implementation, in C, of the server procedures.
                    110: Finally, there is the client portion of the program, also in C, which calls
                    111: the server procedures.
                    112: Note that either the client or server portion of the program may be
                    113: omitted if the UNIX program is designed to act with a non-UNIX
                    114: partner; for example, a simple printing client under UNIX might send
                    115: files to a Xerox laser printer using the Printing protocol published
                    116: and supported by Xerox.
                    117: .sh 2 "Acknowledgements"
                    118: .pp
                    119: Contributors to the current implementation have included
                    120: JQ Johnson, the primary implementor of the current version of the
                    121: Courier compiler under UNIX,
                    122: Eric Cooper, the author of the original UNIX Courier/TCP compiler,
                    123: Jeff Mogul, the author of the exception signalling mechanism used
                    124: here to handle abort and reject messages,
                    125: James O'Toole, Chris Torek, and Mark Weiser,
                    126: the authors of the 4.2BSD version of UNIX kernel support for XNS,
                    127: Keith Sklower, the author of the present (4.3BSD) version of UNIX kernel support,
                    128: Lee Moore, and Bill Nesheim.
                    129: .pp
                    130: Some of the software is copyright 1984 by Eric Cooper, and is for
                    131: research use only; it may be freely distributed but may not be
                    132: sold as a commercial product.
                    133: .sh 2 "References"
                    134: .pp
                    135: This document assumes familiarity with the Courier language,
                    136: details of which may be found in
                    137: the Courier protocol definition,
                    138: .i "Courier: The Remote Procedure Call Protocol" ,
                    139: Xerox System Integration Standard 038112,
                    140: December 1981, and ``Appendix F, Bulk Data Transfer,'' Xerox System
                    141: Integration Standard 038112 Add. 1, October 1982.
                    142: However, for reference purposes, a grammar for the Courier language
                    143: may be found in the appendix to this document.
                    144: .pp
                    145: Users of Bulk Data Transfer will need to interact with SPP 
                    146: (Sequenced Packet Protocol)
                    147: streams, and may wish to see
                    148: .i "Internet Transport Protocols" ,
                    149: Xerox System Integration Standard 028112, December 1981.
                    150: .pp
                    151: Those interested in the workings of UNIX networking might consult
                    152: ``A 4.2bsd Interprocess Communications Primer,''
                    153: (DRAFT of March 11, 1983), by Samuel J. Leffler, Robert S. Fabry, and
                    154: William N. Joy, and the 
                    155: ``4.2BSD System Manual,''
                    156: (Revised July, 1983), by William Joy 
                    157: .i "et al" .
                    158: .pp
                    159: This document is also supplemented by various UNIX manual pages, notably
                    160: .i "xnscourier(3) " ,
                    161: and
                    162: .i "except(3)" .
                    163: .sh 2 "Software and Hardware Dependencies"
                    164: .pp
                    165: This package requires the following software to operate:
                    166: .(l
                    167: 4.3BSD (currently tested only for VAX and Gould versions)
                    168: PCC, 4.3BSD version (probably\-limited testing has been done with Tartan C)
                    169: .)l
                    170: .pp
                    171: To communicate with Xerox products you will need an Ethernet
                    172: interface.  Most of the existing example applications depend heavily on
                    173: the existence of a Xerox Clearinghouse somewhere on the local network.
                    174: .sh 1 "The Courier Specification Language"
                    175: .pp
                    176: The Courier specification language is documented (loosely) in the Xerox
                    177: ``Courier: The Remote Procedure Call Protocol.''  Our compiler
                    178: implements a large subset of the specification.  Note that the embedding
                    179: of Courier constructs in a message or bit stream is usually irrelevant to the
                    180: applications programmer, who need only be concerned with the semantics
                    181: of the Courier datatypes.  The courier compiler and runtimes translate
                    182: Courier datatypes into more easily managed C constructs and handle the
                    183: protocol of communication with the remote system.
                    184: .pp
                    185: This implementation places several restrictions on the specifications
                    186: it will accept:
                    187: .np
                    188: No forward references are permitted in the courier
                    189: specification.  The user must reorder type specifications so that all
                    190: types and constants are defined before they are used.
                    191: Special provisions are made for recursive type declarations of the form
                    192: typically found in Bulk Data ``StreamOf'' declarations; see the
                    193: discussion of BDT below for details.  General recursive declarations,
                    194: e.g. that of the Filing ``Filter,'' are not supported.
                    195: .np
                    196: The Courier specification is unclear as to lexical issues, 
                    197: name scope, and name overloading.
                    198: In the current compiler, names should contain only upper and lower case
                    199: letters or digits.  Also, all constants, types, and
                    200: enumeration tags within a module should have distinct names.  Enumeration
                    201: tag names are currently global; thus, different enumeration types, even
                    202: in different modules, may not have the same tags.
                    203: .np
                    204: Constants of type CHOICE are not fully supported.  In particular, they
                    205: are allowed only if the active arm of the choice is a nill record.
                    206: .np
                    207: Constants of type SEQUENCE are not supported.  Constants of type ARRAY
                    208: (which have the same syntax as SEQUENCE constants) are supported, but are
                    209: not rangechecked; ``Vect: ARRAY 10 OF INTEGER = {1,2,3}'' is accepted,
                    210: though illegal.
                    211: .np
                    212: This implementation supports DEPENDS UPON and
                    213: referenced types and constants.  However, the semantics of referenced
                    214: enumeration constants is unclear.  Also, this implementation
                    215: does not support recursive dependencies.
                    216: .lp
                    217: We think we've eliminated all other restrictions, but we're probably wrong.
                    218: .sh 2 "Predefined types"
                    219: .pp
                    220: The following typedefs correspond to predefined Courier types:
                    221: .(b
                    222: .TS
                    223: c c c
                    224: l l l.
                    225: Courier type   C typedef       Implemented (on VAX) as
                    226: 
                    227: BOOLEAN        Boolean char (0==TRUE, 1==FALSE)
                    228: CARDINAL       Cardinal        unsigned short
                    229: LONG CARDINAL  LongCardinal    unsigned long
                    230: INTEGER        Integer short
                    231: LONG INTEGER   LongInteger     long
                    232: STRING String  char*
                    233: UNSPECIFIED    Unspecified     unsigned short
                    234: LONG UNSPECIFIED       LongUnspecified unsigned long
                    235: .TE
                    236: .)b
                    237: Note that the representations of these types as seen by the applications
                    238: programmer are quite different from those sent over a Courier SPP connection.
                    239: For example, on the VAX a Cardinal's bytes are swapped before being
                    240: sent out in network byte order.  A UNIX String corresponds to a pointer to
                    241: a null-terminated array of characters while a Courier serialized STRING
                    242: contains a count directly followed by an array of characters.  Note
                    243: in particular that this implementation does
                    244: not support Courier STRINGs containing the ascii character NUL.
                    245: .sh 2 "Constructed types"
                    246: .pp
                    247: The Courier enumeration, array, and (non-null) record types
                    248: correspond to C enumerations, arrays, and structures respectively.
                    249: The Courier null record corresponds to an int.
                    250: .pp
                    251: The Courier sequence and choice types
                    252: pose some problems when they are mapped into C.
                    253: This is because an object of one of these types
                    254: must contain run-time information (the length of the sequence
                    255: or which choice is present)
                    256: that is implicit in Courier, but must be made explicit
                    257: in C.
                    258: Furthermore, the C programmer must bear the responsibility of keeping
                    259: this information consistent.
                    260: .pp
                    261: A sequence type is mapped into a structure consisting
                    262: of a Cardinal called
                    263: .i "length" ,
                    264: and a pointer to the sequence elements called
                    265: .i "sequence" .
                    266: The consistency requirement is that
                    267: .i "length"
                    268: indicate the number of elements in the array pointed to
                    269: by
                    270: .i "sequence" .
                    271: .pp
                    272: A choice type is mapped into a structure consisting
                    273: of an enumeration element called
                    274: .i "designator" ,
                    275: and a union of all the possible choices.
                    276: The designator is of the enumeration type defined
                    277: (implicitly or explicitly)
                    278: in the declaration of the choice type.
                    279: If this enumeration consists of elements
                    280: .i A ,
                    281: .i B ,
                    282: and
                    283: .i C ,
                    284: then the choices are accessible as
                    285: .i A_case ,
                    286: .i B_case ,
                    287: and
                    288: .i C_case .
                    289: The consistency requirement is that
                    290: .i "designator"
                    291: contain the enumeration value corresponding to
                    292: which choice currently occupies the union.
                    293: .sh 2 "Constants"
                    294: .pp
                    295: The Courier specification is silent on the precise representations of
                    296: numbers and strings.  In this implementation, numbers may be represented
                    297: as an optional minus sign followed by a
                    298: sequence of decimal digits or a sequence of octal digits followed
                    299: by ``B''.  A constant of type STRING 
                    300: is represented by a sequence of characters enclosed in
                    301: double quotation marks; it has the same restrictions as a C literal string (no
                    302: embedded newlines, use ``\e'' as a prefix character, etc.) except that double
                    303: double quotes are permitted to indicate quotations inside the string.
                    304: .sp 1
                    305: .nf
                    306: minInt: INTEGER = -2147483648;         -- or 20000000000B --
                    307: lastCard: CARDINAL = 177777B;          -- or 65535 --
                    308: quotedName: STRING = "my name is \"jqj""\en";
                    309: .fi
                    310: .sp 1
                    311: .pp
                    312: Although the Courier language allows constants of
                    313: any type to be declared,
                    314: it is difficult to define constants of constructed types
                    315: in C programs.
                    316: This implementation normally handles constants by creating
                    317: static variables initialized to the values of the (possibly structured)
                    318: constants.  The technique is not in general possible for structured 
                    319: constants of type CHOICE
                    320: since they are implemented as C ``unions'', so this implementation does not
                    321: support constants which contain a non-null CHOICE.  As a special case,
                    322: constants whose selected variant is a null record are allowed, e.g.
                    323: .sp 1
                    324:        myImmediate: BulkData.Immediate = immediate [];
                    325: .sp 1
                    326: .sh 2 "Procedures"
                    327: .pp
                    328: PROCEDURE constants correspond to C functions plus a numeric jump table
                    329: index used in serialization of procedure calls on the network.
                    330: Procedure declarations may include argument lists, result lists, and
                    331: error lists.  The argument list of the corresponding C function 
                    332: contains one parameter for each parameter specified in the declaration,
                    333: but is
                    334: expanded by the addition of 2 parameters (see below).  The result list
                    335: specifies a C structure to be returned by the C function containing the
                    336: results; for a procedure, Foo, this result list is of type FooResults.
                    337: Thus, a procedure declared
                    338: .sp 1
                    339:        Example: PROCEDURE [ ] RETURNS [ a: Foo, b: Baz ] = 0;
                    340: .sp 1
                    341: would be implemented by a C function with no arguments
                    342: returning a structure of type ExampleResults with definition
                    343: something like
                    344: .sp 1
                    345: .nf
                    346:        typedef struct {
                    347:                Foo a;
                    348:                Baz b;
                    349:        } ExampleResults
                    350: .fi
                    351: .sp 1
                    352: Note that Foo and Baz might be arbitrarily complex structures;
                    353: see ``Constructed Types'' above.
                    354: .pp
                    355: Importing a PROCEDURE from a DEPENDS UPON module imports only its jump
                    356: table index.
                    357: .sh 2 "ERROR constants"
                    358: .pp
                    359: An ERROR constant corresponds to a defined numeric value, and possibly
                    360: to a C structure describing its argument list.  For example,
                    361: .sp 1
                    362:        OtherError: ERROR [ errorstring: STRING ] = 1;
                    363: .sp 1
                    364: corresponds approximately to the C declarations:
                    365: .sp 1
                    366: .nf
                    367:        #define OtherError (1+ERROR_OFFSET)
                    368:        typedef struct {
                    369:                String errorstring;
                    370:        } OtherErrorArgs;
                    371: .fi
                    372: .sp 1
                    373: Note that ERROR values must be specified in the range 0 to 65535, but
                    374: that they produce a symbol which appears to the C programmer
                    375: with values of type int
                    376: in the range 65536 to 131171 (in some contexts, the user may wish to
                    377: treat C error values in the range 0 to 65535 as Unix error numbers).
                    378: The structure corresponding to the error
                    379: may be useful in creating and referencing error arguments
                    380: in C functions.
                    381: .sh 2 "Scope of Names"
                    382: .pp
                    383: Given a courier program beginning
                    384: .sp
                    385:        Example : PROGRAM 537 VERSION 1 =
                    386: .sp
                    387: types and constants declared in this program belong to the module ``Example1'';
                    388: Their full names have prefixed to them the program name and version number.
                    389: Given the declaration of ``minInt'' above, the XNS Courier compiler actually
                    390: produces a header file (here
                    391: .i Example1.h )
                    392: containing the C declaration:
                    393: .sp 1
                    394: .nf
                    395: static Integer Example1_minInt = {-2147483648};
                    396: .fi
                    397: .sp 1
                    398: .pp
                    399: This prefixing implies that a C programmer may refer to several different
                    400: remote Courier programs without risk of name collision.
                    401: For programmer convenience a second header file (here
                    402: .i Example1_defs.h )
                    403: is also created by the compiler containing macro definitions which widen
                    404: the scope to ``Example1'' and allow the programmer to refer to types and
                    405: constants without explicit qualification.  The programmer may include
                    406: whichever header file he prefers.
                    407: .pp
                    408: Note that types and constants obtained from a DEPENDS UPON inclusion must
                    409: be referenced using fully qualified form.  Note also that structure members,
                    410: procedure arguments, and enum tags are not currently qualified; beware
                    411: potential name conflicts!
                    412: .sh 1 "Running the Courier Compiler"
                    413: .pp
                    414: The specification file is expected to have the extension
                    415: .i ".cr" .
                    416: Consider the following skeletal Courier program definition:
                    417: .sp
                    418:        Example : PROGRAM 537 VERSION 1 = BEGIN ... END.
                    419: .sp
                    420: The name of this Courier program is ``Example''; it is version 1.
                    421: By convention, this specification would stored in the file
                    422: .i "Example1.cr" .
                    423: The ``537'' in this example is illustrative only;
                    424: the program number is uniquely allocated from the range of LongCardinals
                    425: by Xerox.  See Appendix B of the Courier standard for program number
                    426: assignment procedures.
                    427: .pp
                    428: The first step is to use the Courier compiler on the specification.
                    429: Assuming
                    430: .i "xnscourier"
                    431: is in your path (it is 
                    432: .i "/usr/new/xnscourier"
                    433: on the Berkeley distribution), type
                    434: .sp 1
                    435:        xnscourier Example1.cr
                    436: .sp 1
                    437: If there are no errors in compilation,
                    438: the following files will be produced:
                    439: .(b
                    440: .TS
                    441: c c
                    442: l l.
                    443: File   Contents
                    444: 
                    445: Example1_defs.h        scope widening macros (includes Example1.h)
                    446: Example1.h     definitions, typedefs, and constant declarations
                    447: Example1_support.c     routines to map between C and Courier
                    448: Example1_server.c      server main program and support routines
                    449: Example1_client.c      client routines to support applications calling Example
                    450: .TE
                    451: .)b
                    452: .pp
                    453: The header file
                    454: .i "Example1_defs.h"
                    455: should be included via
                    456: .sp
                    457:        #include ``Example1_defs.h''
                    458: .sp
                    459: in all user-written parts of the Courier program
                    460: (i.e., the implementations of the client program and server procedures.)
                    461: .pp
                    462: The 
                    463: .i "\fB-I\fIinclude-directory"
                    464: switch may be used on the command line of
                    465: .i xnscourier
                    466: to establish a search path for Courier specification files named in a
                    467: DEPENDS UPON clause. By default, the compiler looks first in the current
                    468: directory followed by the courier-description-file named in the 
                    469: .i /etc/Courierservices
                    470: file.
                    471: .sh 2 "Calling Remote Procedures \- Client Implementation"
                    472: .pp
                    473: A remote procedure appears to the C programmer to look almost like
                    474: a local procedure (although it typically makes use of resources not
                    475: available on the local machine or else runs many times slower
                    476: than would a local procedure).  A C client program (i.e. the caller
                    477: of a remote procedure) actually calls a stub function generated by
                    478: the courier compiler, which in turn executes the code necessary to
                    479: invoke the corresponding procedure on the remote machine.  
                    480: .pp
                    481: Before calling the remote procedure it is necessary to establish a
                    482: Courier SPP connection (in the process binding a local socket to
                    483: a remote machine).  This may be done by the calling the function
                    484: CourierOpen(), passing it as argument a structure identifying the remote
                    485: host.  This structure
                    486: is of type ``ns_addr''
                    487: as defined in the include file
                    488: .i "#include <netns/ns.h>" .
                    489: CourierOpen() returns an anonymous pointer
                    490: (of type CourierConnection*) to a structure containing
                    491: the socket to be used for this courier call, which should be passed
                    492: to each remote procedure to be executed on the particular remote host.
                    493: CourierOpen() returns NULL if there is a problem opening an SPP connection
                    494: to the host specified.
                    495: .pp
                    496: For low-level access to ns_addr structures,
                    497: the procedure getXNSaddr() is available, taking a string in the form
                    498: ``network#a1.a2.a3.a4.a5.a6#socket'' (where all numbers are hex) or 
                    499: ``networkhigh-networklow#d1-d2-d3-d4#socket'' (where all numbers are
                    500: 3-digit decimal numbers)
                    501: and returning a pointer to the
                    502: corresponding ns_addr structure.  This result may then be passed as the
                    503: argument to CourierOpen().
                    504: More normally, the user will have a string in the form of an NS address,
                    505: e.g. ``jqj:computer\ science:cornell-univ''.  This string can be
                    506: coerced into a Clearinghouse ObjectName, then used in a Clearinghouse-based
                    507: lookup to find the corresponding address:
                    508: .sp 1
                    509: .nf
                    510:        Clearinghouse2_ObjectName hobj, hdefault;
                    511:        struct ns_addr * host;
                    512:        char * string;
                    513: 
                    514:        CH_NameDefault(&hdefault);      /* get defaults */
                    515:        hobj = CH_StringToName(string, &hdefault);
                    516:        host = CH_LookupAddr(hobj, 0);  
                    517: .fi
                    518: .sp 1
                    519: .pp
                    520: The SPP connection may be reused by multiple RPCs destined for the same
                    521: host, even if the procedures are part of different remote programs.  However,
                    522: the SPP connection may not be reused while an RPC is outstanding; thus,
                    523: if you need to issue a Courier call during a BDT transfer, you will need
                    524: to obtain a second CourierConnection.
                    525: .pp
                    526: The client then calls the compiler-generated stub function to invoke
                    527: the remote procedure.  This stub
                    528: function takes at least 2 arguments:
                    529: .ip  (1)
                    530: The pointer returned from CourierOpen().
                    531: If the SPP connection does not
                    532: currently exist (i.e. has been closed by the server)
                    533: it is reopened for this call.
                    534: .ip (2)
                    535: A pointer to a user-supplied function which will be used if a Bulk Data
                    536: Transfer is required (see the section on BDT below); if this remote
                    537: procedure does not involve Bulk Data Transfer, then the function pointer
                    538: should be 0 or NULL.
                    539: .ip (3...)
                    540: One additional argument corresponding to each parameter in the Courier
                    541: language description of this procedure.
                    542: .pp
                    543: The remote procedure returns in one of 2 ways:  either it returns
                    544: normally, passing back a structure corresponding to the RETURNS parameters
                    545: specified in the procedure description, or it signals an error which
                    546: may be caught using the DURING ... HANDLER mechanism described in
                    547: .i except(1) .
                    548: .pp
                    549: A Courier procedure is allowed to return multiple results, a language feature
                    550: not easily mapped into C.  To provide this functionality, all UNIX
                    551: courier remote procedures actually return a structure
                    552: containing the procedure results.  Thus, for a procedure named
                    553: Foo, declared
                    554: .sp 1
                    555:        Foo: PROCEDURE [ ] RETURNS [str: STRING];
                    556: .sp 1
                    557: the C function Foo would return a structure of type FooResults, declared
                    558: .sp 1
                    559: .nf
                    560:        typedef struct {
                    561:                String str;
                    562:        } FooResults;
                    563: .fi
                    564: .fi
                    565: .pp
                    566: Instead of returning a value of type determined by the RESULTS clause
                    567: of a PROCEDURE declaration, a Courier remote procedure call may return
                    568: a reject message indicating the remote system's inability to even
                    569: attempt a remote operation, or an abort message raising a remote error,
                    570: i.e. reporting the operation's failure.  Reject and abort messages are
                    571: handled by a signalling mechanism  or if uncaught cause termination of
                    572: the client program.  For example, a client calling the remote procedure
                    573: defined by
                    574: .sp 1
                    575: .nf
                    576:        NoSuchFile: ERROR = 0;
                    577:        OtherError: ERROR [ errorstring: STRING ] = 1;
                    578:        Example: PROCEDURE [ ] REPORTS [ NoSuchFile, OtherError ];
                    579: .fi
                    580: .sp 1
                    581: might be coded as
                    582: .sp 1
                    583: .nf
                    584:        conn = CourierOpen(destaddr);
                    585:        DURING Example(conn,NULL)
                    586:        HANDLER switch(Exception.Code) {
                    587:        case REJECT_ERROR:
                    588:                fprintf(stderr,"Remote reject.\en");
                    589:                exit(1);
                    590:        case NoSuchFile:
                    591:                fprintf(stderr,"No such file\en");
                    592:                break;
                    593:        case OtherError:
                    594:                fprintf(stderr,"Remote error %s\en",
                    595:                        CourierErrArgs(OtherErrorArgs,errorstring) );
                    596:                break;
                    597:        case PROTOCOL_VIOLATION:
                    598:        case INTERNAL_ERROR:
                    599:                fprintf(stderr,"Local internal error %s\en",
                    600:                        Exception.Message);
                    601:                break;
                    602:        default:
                    603:                fprintf(stderr,"Unknown error, type %d\en",
                    604:                        Exception.Code);
                    605:        }       
                    606:        END_HANDLER
                    607: .fi
                    608: .sp 1
                    609: The error value, Exception.code, will be one of (1) ``REJECT_ERROR'',
                    610: which indicates a REJECT message from the remote server, (2) a program-defined
                    611: ERROR value (offset by ERROR_OFFSET), (3) or ``INTERNAL_ERROR'' 
                    612: or ``PROTOCOL_VIOLATION''
                    613: indicating
                    614: a serious internal error in the Unix courier implementation; in the third
                    615: case, a string is available as Exception.Message.
                    616: Both errors and rejections may have arguments, which can be accessed
                    617: within a handler as a struct pointed to by Exception.Message.  For
                    618: programmer convenience a macro, CourierErrArgs, is defined, taking
                    619: as arguments the typedef defining the current error's arguments 
                    620: and the name of the argument to be accessed; this macro may be used
                    621: only within an error handler.
                    622: For rejection messages, the type should be ``rejectionDetails,''
                    623: as defined on page 25 of the Courier spec.
                    624: .pp
                    625: When done with a particular remote connection, the client should call
                    626: CourierClose() with argument the pointer returned from CourierOpen()
                    627: to free the socket and cleanly close the connection.
                    628: .pp
                    629: The client program should be loaded with 
                    630: .i "Example1_client.o" ,
                    631: .i "Example1_support.o" ,
                    632: and -lcourier (the XNS Courier library)
                    633: to produce an executable program.
                    634: .sh 2 "Writing a Courier Server"
                    635: .pp
                    636: The Courier protocol specifies a standard for communicating
                    637: parameters and results which has been adhered to in this
                    638: implementation.
                    639: It also specifies an initial connection protocol
                    640: and a format for messages.
                    641: .pp
                    642: There is a single Courier Daemon per UNIX machine whose function
                    643: is to listen on a well-known XNS port for Courier interface activation
                    644: requests.
                    645: A request contains the number of the Courier program
                    646: whose server is to be activated, and its version number.  These two
                    647: numbers are used as a key in the file 
                    648: .i /etc/Courierservices
                    649: to identify
                    650: the executable file associated with the particular courier program.
                    651: .i /etc/Courierservices
                    652: consists of a sequence of lines of the form
                    653: .sp 1
                    654:        program-name  program-number  version  courier-description-file  server-binary-file
                    655: .sp 1
                    656: The daemon
                    657: either spawns the executable file
                    658: or replies with a reject message.  Note that each incoming remote procedure
                    659: call may be serviced by a separate UNIX process.
                    660: This implies that connection-oriented services (services which consist of a
                    661: sequence of related procedure calls) must be implemented by maintaining
                    662: the state of connections in a file.
                    663: .pp
                    664: The executable file containing the server for a particular remote
                    665: program consists of a main program generated by the courier compiler
                    666: which interprets CALL messages from the remote client and calls
                    667: one or more user-written functions to implement the
                    668: courier procedures.
                    669: .pp
                    670: Given a courier specification for the remote program Example containing
                    671: remote procedure Example,
                    672: the server functions (including the C function Example and any support
                    673: routines needed)
                    674: should be loaded with 
                    675: .i "Example1_server.o" ,
                    676: .i "Example1_support.o" ,
                    677: and -lcourier
                    678: to produce the server process that will be invoked whenever
                    679: an activation request arrives.
                    680: .pp
                    681: A server function receives an argument list similar to that passed by
                    682: a client to a remote procedure.  The first two arguments in the
                    683: parameter list should be ignored; each succeeding argument corresponds
                    684: to one parameter in the courier declaration.
                    685: .pp
                    686: To return from a server function you must return a structure containing
                    687: the results of the procedure.  If this structure contains pointers (e.g.
                    688: Strings) you should insure that the data pointed to is allocated
                    689: staticly or on the heap rather than on the stack.
                    690: You must not call exit(3) from within the server function; doing so will
                    691: cause the client (remote caller) to hang indefinitely waiting for a
                    692: reply.
                    693: .pp
                    694: To abort a server function, returning an error code, use the
                    695: ``raise(code, msg)''
                    696: library function, with arguments the error code and either NULL (if the
                    697: error takes no arguments) or a pointer to a structure containing the
                    698: arguments to the error.  Raise causes a longjump out of the function
                    699: directly to the handler, and thence to the remote procedure caller.
                    700: For example, to return the OtherError message defined above one might code
                    701: .sp 1
                    702: .nf
                    703:        OtherErrorArg randomerr;
                    704:        . . .
                    705:        randomerr.errorstring = sys_errlist[errno]);
                    706:        raise(OtherError,(char*) &randomerr);
                    707: .fi
                    708: .sp 1
                    709: .pp
                    710: When a server function returns to its main program caller the main()
                    711: sends the appropriate RETURN or ABORT message to the remote client,
                    712: and does an exit(0).  The server then holds the connection for up to 90 
                    713: seconds waiting for another Courier call to arrive on the same SPP
                    714: stream.
                    715: .sh 2 "Dynamic Allocation"
                    716: .pp
                    717: One additional 
                    718: .i caveat 
                    719: is necessary when using Courier remote procedure calls from C:  C does not
                    720: have garbage collection, so you should free any dynamically allocated storage
                    721: when you are done with it.  In general, top level Courier objects are
                    722: always allocated from the stack or statically; however, strings and sequences
                    723: within an object are generally allocated from the heap using malloc().
                    724: .pp
                    725: A client program which calls the remote procedure Foo defined above,
                    726: returning a STRING,
                    727: actually has returned to it a C struct containing a pointer to an array
                    728: of malloced characters.  When done with this string, the program may free
                    729: it by calling clear_FooResults() with argument the address of the
                    730: result returned by the call to Foo.  Thus:
                    731: .sp 1
                    732: .nf
                    733:        FooResults result;
                    734:        . . .
                    735:        result = Foo(conn,NULL);
                    736:        . . .
                    737:        printf("result was %s\n",result.str);
                    738:        clear_FooResults(&result);
                    739: .fi
                    740: .sp 1
                    741: .sh 1 "Using Bulk Data Transfer"
                    742: .pp
                    743: .sh 2 "Overview"
                    744: .pp
                    745: When a Courier program needs to transfer an arbitrary amount of
                    746: information as an argument or result of a Courier procedure, the
                    747: procedure is usually defined to have an argument of type ``BulkData.Sink''
                    748: or ``BulkData.Source'' (and a ``DEPENDS UPON BulkData''
                    749: is included in the program).
                    750: The argument is a ``source'' if it is information transferred from caller
                    751: to server (as though a procedure argument), a ``sink'' if it is
                    752: information transferred from server to caller (as though a procedure
                    753: result).  In this
                    754: implementation, a Courier procedure may have at most one such argument,
                    755: which must have the value null or immediate.
                    756: In a Courier call, the bulk data is transmitted in a special way,
                    757: multiplexed into the same data path as control messages
                    758: between the arguments and the results.
                    759: .pp
                    760: The BDT user should include in the 
                    761: .i ".cr"
                    762: file a ``DEPENDS UPON BulkData (0) VERSION 1'', then reference these
                    763: arguments as BulkData.Source and BulkData.Sink in PROCEDURE
                    764: declarations.
                    765: The declaration of a Courier PROCEDURE can then indicate a bulk
                    766: data transfer by including in its formal argument list a variable
                    767: of type BulkData.Source or BulkData.Sink
                    768: as appropriate.
                    769: The corresponding parameter to the C procedure will be of type
                    770: BulkData1_Descriptor.
                    771: .sh 2 "Coding a Client"
                    772: .pp
                    773: To use Bulk Data in a client program, the Courier definition of the
                    774: procedure must include one BulkData.Source or BulkData.Sink parameter.
                    775: As the actual argument to the call, the C client passes a constant,
                    776: either BulkData1_immediateSource, BulkData1_immediateSink, BulkData1_nullSource, 
                    777: or BulkData1_nullSink as appropriate.  The client
                    778: also specifies a pointer to a user-supplied function as the second
                    779: argument to the remote procedure.
                    780: Courier sets up the transaction, then calls the supplied function with
                    781: one argument, the pointer returned by CourierOpen() describing the
                    782: SPP socket on which to write (if a source argument) or read
                    783: (if a sink) the bulk data. 
                    784: .pp
                    785: To complete the transaction normally, the
                    786: function should send packets of SPP data terminated by
                    787: an end-of-message (if writing) or read up to but not beyond an
                    788: end-of-message (if reading), and should return normally to its caller.
                    789: To do so, it should call the procedures BDTread(), BDTwrite(), or 
                    790: BDTclosewrite()
                    791: as appropriate.  BDTread() and BDTwrite() take arguments analogous to read()
                    792: and write() except that instead of a file descriptor they accept the SPP
                    793: descriptor returned by CourierOpen(); their arguments are thus
                    794: (1) the pointer to the SPP data structure,
                    795: (2) a pointer to an array of characters (the IO buffer),
                    796: and (3) a count;
                    797: they return the number of characters actually read or written.
                    798: .pp
                    799: The UNIX program can finish a write transfer by calling BDTclosewrite() or
                    800: BDTabort(), each with the SPP descriptor as argument.
                    801: BDTclosewrite() produces an SPP end-of-message, while BDTabort() instructs
                    802: Courier to discard any buffered data and
                    803: send a Bulk Data Abort to abort the transaction.  A read transfer may also be
                    804: prematurely ended by calling BDTabort().
                    805: .sh 2 "Coding a Server"
                    806: .pp
                    807: Writing a server that uses BDT
                    808: is similar to writing the BDT function in a caller.
                    809: The server is passed a BulkData.Source or BulkData.Sink (the two are
                    810: indistinguishable at run time).
                    811: The server routine should check to make sure that the source or sink
                    812: is of type null or immediate (active and passive descriptors are not
                    813: supported in this implementation) by means of code such as:
                    814: .sp 1
                    815: .nf
                    816: Foo(bdtconnection,ignoredarg,..., s, ...)
                    817:        CourierConnection *bdtconnection;
                    818:        BulkData1_Sink s;
                    819:        . . .
                    820:        switch (s.designator) {
                    821:        case active:
                    822:        case passive:
                    823:                /* can't raise BulkData1_InvalidDescriptor, so */
                    824:                raise(someerror);
                    825:        case null:
                    826:                /* handle null transfer */
                    827:                break;
                    828:        case immediate:
                    829:                /* handle normal, i.e. immediate, transfer */
                    830:                break;
                    831:        }
                    832: .fi
                    833: .sp 1
                    834: Note that the BDT error InvalidDescriptor cannot be used unless the
                    835: procedure declaration explicitly notes that this is a valid REPORTS error
                    836: type.  Normally, each courier program defines its own error to be reported
                    837: on BDT problems.
                    838: .pp
                    839: Use the first argument to the server procedure as the handle on the
                    840: BDT connection.
                    841: As with a client BDTabort() may
                    842: be used to send abort messages.
                    843: .sh 2 "Sending Bulk Data"
                    844: .pp
                    845: Sending bulk data, either as client or server, is quite
                    846: straightforward.  Use the supplied procedure BDTwrite(), whose
                    847: semantics are similar to write().  BDTwrite() will return -1
                    848: if an error occurs or an abort from the listener is received; in this
                    849: case, the sender should immediately cease transmitting BDT data, and
                    850: should instead call BDTabort(). 
                    851: Typical code to send data on ``bdtconnection'',
                    852: in this case read from a buffered file open
                    853: as ``source,'' might appear as:
                    854: .sp 1
                    855: .nf
                    856:        CourierConnection *bdtconnection;
                    857:        FILE *source;
                    858:        int count;
                    859:        char buffer[SPPMAXDATA];
                    860:        ...
                    861:        while ( (count = fread(buffer,1,SPPMAXDATA,source)) > 0 &&
                    862:                BDTwrite(bdtconnection,buffer,count) >= 0 )
                    863:                ;
                    864:        if (count <= 0) /* succsfull transfer */
                    865:                BDTclosewrite(bdtconnection);
                    866:        else
                    867:                BDTabort(bdtconnection);
                    868: .fi
                    869: .sp 1
                    870: .pp
                    871: Each BDTwrite() transmits one packet after checking for an abort message
                    872: from the receiver.
                    873: A sender which gets an abort from a remote receiver must immediately
                    874: stop transferring data and instead must echo an abort via BDTabort()
                    875: to acknowledge the end of the transfer.
                    876: .pp
                    877: Also, for efficiency's
                    878: sake it is desirable to write packets as near as possible to the
                    879: nominal maximum length of an SPP packet; this suggests a buffer length of
                    880: 534 bytes.  For programmer convenience, the file
                    881: .i courier.h
                    882: defines the symbol SPPMAXDATA as 534.
                    883: .sh 2 "Receiving Bulk Data"
                    884: .pp
                    885: To make receiving bulk data simple, the routine BDTread() performs checks for
                    886: various conditions on receipt of each packet.  BDTread() will return the
                    887: count of the number of bytes actually read in each packet (skipping empty
                    888: packets), or 0 to indicate end of data.  If an error or BDT abort message
                    889: occurs, BDTread() will return -1; if this occurs, the receiver should 
                    890: immediately stop reading BDT data.
                    891: .pp
                    892: Typical code for receiving bulk data on the socket described by 
                    893: ``bdtconnection'' and
                    894: depositing it in the file opened for buffered ouput as ``destfile''
                    895: might be:
                    896: .sp 1
                    897: .nf
                    898:        CourierConnection *bdtconnection;       /* BDT source descriptor */
                    899:        FILE *destfile;                         /* output file */
                    900:        char sppdata[SPPMAXDATA];
                    901:        ...
                    902:                count = BDTread(bdtconnection, sppdata, SPPMAXDATA);
                    903:                while (count > 0) {     /* actually read data */
                    904:                        if (fwrite(sppdata, 1, count, destfile) == 0) {
                    905:                                        /* error while writing */
                    906:                                BDTabort(bdtconnection);
                    907:                                break;
                    908:                        }
                    909:                        count = BDTread(bdtconnection, sppdata, SPPMAXDATA);
                    910:                }
                    911:                if (count == 0) {
                    912:                        /* successful */
                    913:                        ...
                    914: .fi
                    915: .sp 1
                    916: .sh 2 "StreamOf declarations"
                    917: .pp
                    918: Frequently, data to be sent on a Bulk Data connection will be described
                    919: by a StreamOfSomething declaration in the courier specification.  For
                    920: example, in Clearinghouse several routines are documented as returning
                    921: a StreamOfObjectName; unfortunately, a StreamOf declaration is recursive,
                    922: and so is not immediately translatable into automatic packing and unpacking
                    923: routines which need to know in advance how much space to allocate for the
                    924: result.  As a kludge, we translate such types as if the recursive
                    925: part of the declaration were a null record.  
                    926: Consider:
                    927: .sp 1
                    928: .nf
                    929: StreamOfObjectName: TYPE = CHOICE OF {
                    930:        nextSegment (0) => RECORD [
                    931:                segment: SEQUENCE OF ObjectName,
                    932:                restOfStream: StreamOfObjectName ],
                    933:        lastSegment (1) => SEQUENCE OF ObjectName};
                    934: .fi
                    935: .sp 1
                    936: .lp
                    937: In the above declaration, the ``restOfStream is effectively ignored.
                    938: Given this declaration, the following routine may be passed to a
                    939: remote procedure as the Bulk Data actor.
                    940: .sp 1
                    941: .nf
                    942: #include "Clearinghouse_support.c"     /* get internalize_* routines */
                    943: #define MAXPACKS 5
                    944: 
                    945: GetData(conn)
                    946:        CourierConnection *conn;
                    947: {
                    948:        int count, i;
                    949:        Unspecified buffer[MAXWORDS*MAXPACKS], *bp, *bufend;
                    950:        StreamOfObjectName obnames;
                    951:        
                    952:        bufend = buffer;
                    953:        bp = buffer+MAXWORDS*(MAXPACKS-1);    /* end of available space */
                    954:        while (count = BDTread(conn, (char*)bufend, 
                    955:                                MAXWORDS*sizeof(Unspecified))
                    956:                ) {
                    957:                bufend += count/sizeof(Unspecified);
                    958:                if (bufend > bp) {
                    959:                        fprintf(stderr,"BDT read too big to fit\en");
                    960:                        BDTabort(conn);
                    961:                        /* should clear out stuff here if we knew how much */
                    962:                }
                    963:        }
                    964:        bp = buffer;
                    965:        while (bp < bufend) {
                    966:                bp += internalize_StreamOfObjectName(&obnames,bp);
                    967:                if (0 == (int) obnames.designator)
                    968:                   for (i = 0; i < obnames.nextSegment_case.segment.length; i++)
                    969:                        ProcessObjectName(
                    970:                                obnames.nextSegment_case.segment.sequence[i]);
                    971:                else {
                    972:                   for (i = 0; i < obnames.lastSegment_case.length; i++)
                    973:                        ProcessObjectName(
                    974:                                obnames.lastSegment_case.sequence[i]);
                    975:                   return;
                    976:                }
                    977:        }
                    978: }
                    979: .fi
                    980: .sp 1
                    981: .lp
                    982: Note that this code is very awkward, and that it requires that the whole
                    983: bulk data transfer be stored in memory before it is unpacked.  Stay
                    984: tuned; we intend to modify the compiler to make the handling of such
                    985: streams much easier, at the cost of incompatibility with the existing
                    986: scheme, of course!
                    987: .sh 2 "Encapsulated Protocols"
                    988: .pp
                    989: Some courier programs use what might be termed ``encapsulated protocols''
                    990: as a method of type punning to escape from the restrictions of the Courier
                    991: language.  For example, in Filing
                    992: .sp 1
                    993: .nf
                    994:        Attribute: RECORD [
                    995:                type: AttributeType, value: SEQUENCE OF UNSPECIFIED ];
                    996:        checksum: AttributeType = 0;
                    997:        Checksum: TYPE = CARDINAL;
                    998:        createdBy: AttributeType = 1;
                    999:        CreatedBy: TYPE = User;
                   1000: .fi
                   1001: .sp 1
                   1002: Depending on the value of the type subfield, the data in the value field
                   1003: is intended to be interpreted as either a CARDINAL or a User name.
                   1004: .pp
                   1005: Such encapsulation is in general bad design unless a very compelling
                   1006: need for it exists.  It is also awkward to support in a C program.  The
                   1007: best way to handle such types is to write functions to code and decode
                   1008: the encapsulated value using the low level packing and unpacking routines
                   1009: provided by the Courier compiler.  For example:
                   1010: .sp 1
                   1011: .nf
                   1012:        Filing4_User
                   1013:        AttrToUser(attr)
                   1014:                Filing4_Attribute *attr;
                   1015:        {
                   1016:                Unspecified buf[2049], *bp; /* space for biggest attribute */
                   1017:                Cardinal len;
                   1018:                Filing4_User retval;
                   1019: 
                   1020:                /* useful fact:   Item: TYPE = SEQUENCE OF UNSPECIFIED; */
                   1021:                externalize_Clearinghouse2_Item(&(attr->value), buf);
                   1022:                bp = buf;
                   1023:                bp += internalize_Cardinal(&len, bp);
                   1024:                bp += internalize_Filing4_User(&retval, bp);  
                   1025:                return(retval);
                   1026:        }
                   1027: 
                   1028:        UserToAttr(id, attr)
                   1029:                Filing4_User id;
                   1030:                Filing4_Attribute *attr;
                   1031:        {
                   1032:                Unspecified buf[2049], *bp;
                   1033:                Cardinal len;
                   1034: 
                   1035:                /* don't know length yet, so leave space for it */
                   1036:                bp = buf + sizeof_Cardinal(len);
                   1037:                len = externalize_Filing4_User(&id, bp);
                   1038:                (void) externalize_Cardinal(&len, buf);
                   1039:                internalize_Clearinghouse2_Item(&(attr->value), buf);
                   1040:                return;
                   1041:        }
                   1042: 
                   1043: .fi
                   1044: .sp 1
                   1045: Since the SEQUENCE OF UNSPECIFIED may have undergone arbitrary
                   1046: transformations
                   1047: during deserialization, translating it to a User record consists of first
                   1048: reserializing it into an array of char, then deserializing it using the
                   1049: low-level routine appropriate to the encapsulated type.  Translating to
                   1050: an encapsulated type is an almost precise inverse.
                   1051: .sh 1 "Example I:  Passwd.cr"
                   1052: .pp
                   1053: This section contains a Courier program which implements remote lookup in
                   1054: .i "/etc/passwd"
                   1055: (the UNIX database of user names, passwords, home directories, and so
                   1056: on).
                   1057: It does not utilize Bulk Data Transfer, but does illustrate most other
                   1058: features of this courier implementation.
                   1059: The applications programmer would first write 
                   1060: .i PasswordLookup.cr ,
                   1061: the description of the courier interface for the service, then might
                   1062: write
                   1063: .i PasswordLookup.c ,
                   1064: containing the routines needed to implement a server for this courier
                   1065: program, or might write
                   1066: .i lookup.c ,
                   1067: a typical client of this service.
                   1068: .bp
                   1069: .sh 2 "The specification (PasswordLookup.cr)"
                   1070: .sp 1
                   1071: .nf
                   1072: PasswordLookup : PROGRAM 754 VERSION 1 =
                   1073: 
                   1074: BEGIN
                   1075: 
                   1076:     -- This is a translation of the passwd structure in <pwd.h>
                   1077: 
                   1078:     Passwd : TYPE = RECORD [
                   1079:        pw_name, pw_passwd : STRING,
                   1080:        pw_uid, pw_gid, pw_quota : LONG CARDINAL,
                   1081:        pw_comment, pw_gecos, pw_dir, pw_shell : STRING
                   1082:     ];
                   1083: 
                   1084:     -- Remote Errors
                   1085: 
                   1086:     NoSuchUser : ERROR = 0;
                   1087:     OtherError : ERROR [ errorstring: STRING ] = 1;
                   1088: 
                   1089:     -- Remote entry points.
                   1090: 
                   1091:     LookupUid : PROCEDURE [ uid : CARDINAL ] RETURNS [ passwd : Passwd ]
                   1092:                    REPORTS [ NoSuchUser ]
                   1093:                    = 0;
                   1094: 
                   1095:     LookupUser : PROCEDURE [ user : STRING ]
                   1096:                    RETURNS [ passwd : Passwd, forward : STRING ]
                   1097:                    REPORTS [ NoSuchUser, OtherError ]
                   1098:                    = 1;
                   1099: 
                   1100: END.
                   1101: .fi
                   1102: .sp 2
                   1103: .sh 2 "PasswordLookup_defs.h"
                   1104: .sp 1
                   1105: .nf
                   1106: /*
                   1107:  * Declarations for Courier program PasswordLookup.
                   1108:  */
                   1109: #include <courier.h>
                   1110: #include <except.h>
                   1111: 
                   1112: typedef struct {
                   1113:        String pw_name;
                   1114:        String pw_passwd;
                   1115:        LongCardinal pw_uid;
                   1116:        LongCardinal pw_gid;
                   1117:        LongCardinal pw_quota;
                   1118:        String pw_comment;
                   1119:        String pw_gecos;
                   1120:        String pw_dir;
                   1121:        String pw_shell;
                   1122: } Passwd;
                   1123: 
                   1124: #define NoSuchUser 0
                   1125: 
                   1126: #define OtherError 1
                   1127: typedef struct {
                   1128:        String errorstring;
                   1129: } OtherErrorArg;
                   1130: 
                   1131: typedef struct {
                   1132:        Passwd passwd;
                   1133: } LookupUidResult;
                   1134: 
                   1135: typedef struct {
                   1136:        Passwd passwd;
                   1137:        String forward;
                   1138: } LookupUserResult;
                   1139: 
                   1140: extern LookupUidResult LookupUid();
                   1141: 
                   1142: extern LookupUserResult LookupUser();
                   1143: .fi
                   1144: .sp 2
                   1145: .sh 2 "Makefile"
                   1146: .sp 1
                   1147: .nf
                   1148: CFLAGS = -O
                   1149: USEROBJS = lookup.o PasswordLookup_client.o
                   1150: SRVROBJS = PasswordLookup.o PasswordLookup_server.o
                   1151: LIBS = -lcr
                   1152: DESTDIR = /usr/lib/courier
                   1153: 
                   1154: all:   lookup PasswordLookup
                   1155: 
                   1156: lookup:        $(USEROBJS)
                   1157:        cc -o lookup $(USEROBJS) $(LIBS)
                   1158: 
                   1159: PasswordLookup:        $(SRVROBJS)
                   1160:        cc -o PasswordLookup $(SRVROBJS) $(LIBS)
                   1161: 
                   1162: $(USEROBJS) $(SRVROBJS):       PasswordLookup_defs.h
                   1163: 
                   1164: PasswordLookup_defs.h \e
                   1165: PasswordLookup_server.c \e
                   1166: PasswordLookup_client.c:       PasswordLookup.cr
                   1167:        courier PasswordLookup.cr
                   1168: 
                   1169: install:       all
                   1170:        install -s PasswordLookup $(DESTDIR)
                   1171: 
                   1172: clean:
                   1173:        -rm -f *.o PasswordLookup_*.c PasswordLookup_defs.h
                   1174: .fi
                   1175: .bp
                   1176: .sh 2 "The server procedures (PasswordLookup.c)"
                   1177: .sp 1
                   1178: .nf
                   1179: #include <stdio.h>
                   1180: #include "PasswordLookup_defs.h"
                   1181: 
                   1182: extern Passwd *getpwnam(), *getpwuid();
                   1183: 
                   1184: LookupUidResult
                   1185: LookupUid(CourierConnection,CourierBDTProc,uid)
                   1186:        CourierConnection *CourierConnection, CourierBDTProc;
                   1187:        Cardinal uid;
                   1188: {
                   1189:        Passwd *pw;
                   1190: 
                   1191:        pw = getpwuid(uid);
                   1192:        if (pw == NULL)
                   1193:                raise(NoSuchUser,NULL);
                   1194:        else {
                   1195:                return (*(LookupUidResult*) &pw);
                   1196:        }
                   1197: }
                   1198: 
                   1199: LookupUserResult
                   1200: LookupUser(CourierConnection,CourierBDTProc,user)
                   1201:        CourierConnection *CourierConnection, CourierBDTProc;
                   1202:        String user;
                   1203: {
                   1204:        LookupUserResult result;
                   1205:        Passwd *pw;
                   1206:        FILE *fwdfd;
                   1207:        static char forward[100];
                   1208: 
                   1209:        pw = getpwnam(user);
                   1210:        if (pw == NULL)
                   1211:                raise (NoSuchUser,NULL);
                   1212:        else {
                   1213:                sprintf(forward,"%s/.forward",pw->pw_dir);
                   1214:                if ((fwdfd = fopen(forward,"r")) == NULL) {
                   1215:                        forward[0] = '\e0';
                   1216:                else {
                   1217:                        fgets(forward,100,fwdfd);
                   1218:                        fclose(fwdfd);
                   1219:                        if (strlen(forward) < 2) (
                   1220:                                static OtherErrorArg randomerr = {
                   1221:                                        "invalid forwarding file"};
                   1222:                                raise(OtherError,&randomerr));
                   1223:                }
                   1224:                result.password = *pw;
                   1225:                result.forward = forward;
                   1226:                return (result);
                   1227:        }
                   1228: }
                   1229: .fi
                   1230: .bp
                   1231: .sh 2 "The user program (lookup.c)"
                   1232: .sp 1
                   1233: .nf
                   1234: /*
                   1235:  * Sample program to access remote password lookup.
                   1236:  * Usage: lookup machine username
                   1237:  */
                   1238: #include <stdio.h>
                   1239: #include "PasswordLookup_defs.h"
                   1240: 
                   1241: main(argc, argv)
                   1242:        int argc;  char **argv;
                   1243: {
                   1244:        LookupUserResult result;
                   1245:        Passwd passwd;
                   1246:        CourierConnection *connection;
                   1247: 
                   1248:        if (argc < 3 || (destaddr = getXNSaddr(argv[1])) == NULL)) {
                   1249:                fprintf(stderr,"Usage:  %s machine file ...\en",argv[0]);
                   1250:                exit(1);
                   1251:        }
                   1252:        if ((connection = CourierOpen(destaddr)) == NULL) {
                   1253:                fprintf(stderr,"Can't open connection to %s\en",argv[1]);
                   1254:                exit(1);
                   1255:        }
                   1256:        DURING
                   1257:                result = LookupUser(connection,NULL,argv[2]);
                   1258:        HANDLER
                   1259:                switch(Exception.Code) {
                   1260:        case Courier_reject:
                   1261:                fprintf("Connection rejected, code = %d\en",
                   1262:                        CourierErrArgs(rejectionDetails,designator) );
                   1263:                exit(1);
                   1264:        case NoSuchUser:
                   1265:                printf("User %s unknown on %s.\en", argv[2], argv[1]);
                   1266:                exit(0);
                   1267:        case OtherError:
                   1268:                fprintf(stderr,"Remote error %s\en",
                   1269:                        CourierErrArgs(OtherErrorArg,errorstring) );
                   1270:                exit(1);
                   1271:        }
                   1272:        END_HANDLER;
                   1273: 
                   1274:        displaypwd(& result.passwd);
                   1275:        displayfwd(result.forward);
                   1276:        CourierClose(connection);
                   1277: }
                   1278: 
                   1279: displaypwd(p)
                   1280:        Passwd *p;
                   1281: {
                   1282:        printf("%s:%s:%d:%d:%s:%s:%s\en",
                   1283:                p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid,
                   1284:                p->pw_gecos, p->pw_dir, p->pw_shell);
                   1285: }
                   1286: 
                   1287: displayfwd(s)
                   1288:        String s;
                   1289: {
                   1290:        if (*s) printf("Mail forwarding to %s\en",s);
                   1291:        else    printf("Mail is not forwarded\en");
                   1292: }
                   1293: .fi
                   1294: .bp
                   1295: .sh 1 "Example II: PrintFile"
                   1296: .pp
                   1297: This example is a very simple application of Bulk Data Transfer.
                   1298: .sh 2 "PrintFile.cr"
                   1299: .sp 1
                   1300: .nf
                   1301: PrintFile: PROGRAM 756 VERSION 1 =
                   1302: BEGIN
                   1303: 
                   1304:     DEPENDS UPON BulkData (0) VERSION 1;
                   1305: 
                   1306:     -- Remote errors.
                   1307: 
                   1308:     CantPrint: ERROR = 0;
                   1309: 
                   1310:     -- Remote entry points.
                   1311: 
                   1312:     RPrint: PROCEDURE [ s: BulkData.Source ]
                   1313:                REPORTS [ CantPrint ];
                   1314: 
                   1315: END.
                   1316: .fi
                   1317: .sp 1
                   1318: .sh 2 "A typical client (remoteprint.c)"
                   1319: .lp
                   1320: .sp 1
                   1321: .nf
                   1322: /*
                   1323:  * Sample proram to print a file remotely using trivial remote print
                   1324:  * protocol.
                   1325:  * Usage:  remoteprint filename
                   1326:  *
                   1327:  */
                   1328: #include <stdio.h>
                   1329: #include <sys/types.h>
                   1330: #include <netns/ns.h>          /* for XNS addresses */
                   1331: #include "PrintFile_defs.h"
                   1332: 
                   1333: static FILE * source;  /* communicate from main to SendSource */
                   1334: 
                   1335: main(argc, argv)
                   1336:        int argc;
                   1337:        char *argv[];
                   1338: {
                   1339:        CourierConnection *connection;
                   1340:        struct ns_addr *destaddr;
                   1341: 
                   1342:        if (argc < 3 || (destaddr = getXNSaddr(argv[1])) == NULL)) {
                   1343:                fprintf(stderr,"Usage:  %s machine file ...\en",argv[0]);
                   1344:                exit(1);
                   1345:        }
                   1346:        if ((connection = CourierOpen(destaddr)) == NULL) {
                   1347:                fprintf(stderr,"Can't open connection to %s\en",argv[1]);
                   1348:                exit(1);
                   1349:        }
                   1350:        argv++;
                   1351:        while (argc-- > 2) {
                   1352:                argv++;
                   1353:                if (strcmp(argv[0],"-") == 0) source = stdin;
                   1354:                else source = fopen(argv[0],"r");
                   1355:                if (source == NULL)
                   1356:                        fprintf(stderr,"Can't open %s\en",argv[0]);
                   1357:                else DURING
                   1358:                        RPrint(connection,SendSource,immediateSource);
                   1359:                    HANDLER
                   1360:                        fprintf(stderr,"Call to RPrint failed.\en");
                   1361:                    END_HANDLER;
                   1362:                fclose(source);
                   1363:        }
                   1364:        CourierClose(connection);
                   1365: }
                   1366: 
                   1367: SendSource(bdtconnection)
                   1368: CourierConnection *bdtconnection;
                   1369: {
                   1370:        int count;
                   1371:        char buffer[SPPMAXDATA];
                   1372: 
                   1373:        while ( (count = fread(buffer,1,SPPMAXDATA,source)) > 0 &&
                   1374:                BDTwrite(bdtconnection,buffer,count) >= 0 )
                   1375:                ;
                   1376:        if (count <= 0)
                   1377:                BDTclosewrite(bdtconnection);   /* last packet with EOM set */
                   1378:        else
                   1379:                BDTabort(bdtconnection);
                   1380: }
                   1381: .fi
                   1382: .sp 2
                   1383: .sh 2 "Server (PrintFile.c)"
                   1384: .sp 1
                   1385: .nf
                   1386: #include <stdio.h>
                   1387: #include <sys/types.h>
                   1388: #include <netxns/ns.h>
                   1389: #include "PrintFile_defs.h"
                   1390: 
                   1391: RPrintResult
                   1392: Rprint(source,CourierBDTProc,s)
                   1393:        CourierConnection *source, CourierBDTProc;
                   1394:        BulkData1_Source s;
                   1395: {
                   1396:        FILE *printpipe;
                   1397:        char sppdata[SPPMAXDATA];
                   1398: 
                   1399:        switch (s.designator)
                   1400:        case active:
                   1401:        case passive:
                   1402:                raise(CantPrint);
                   1403:                /*NOTREACHED*/
                   1404:        case null:
                   1405:                system("print /dev/null");      /* print a null file */
                   1406:                return;
                   1407:        case immediate:
                   1408:                if ((printpipe = popen("print","w")) == NULL) {
                   1409:                        raise(CantPrint);
                   1410:                        /*NOTREACHED*/
                   1411:                }
                   1412:                count = BDTread(source, sppdata, SPPMAXDATA);
                   1413:                while (count > 0) {     /* actually read data */
                   1414:                        if (fwrite(sppdata, 1, count, printpipe) == 0) {
                   1415:                                BDTabort(source);
                   1416:                                break;
                   1417:                        }
                   1418:                        count = BDTread(source, sppdata, SPPMAXDATA);
                   1419:                }
                   1420:                if (pclose(printpipe) == 0 && count == 0)
                   1421:                        return;
                   1422:                else raise(CantPrint);
                   1423: }
                   1424: .fi
                   1425: .sh 1 "One Final Example"
                   1426: .pp
                   1427: Finally, we present a slightly 
                   1428: more useful example, a program to print an Interpress
                   1429: file on a Services-8 printer.  It depends on the standard Xerox Printing
                   1430: specification, program 4 version 3.  For an even better example, look
                   1431: at the printing client, xnsprint, provided with the XNS Courier distribution
                   1432: as
                   1433: .i "./examples/print/xnsprint.c" .
                   1434: .sp 2
                   1435: .nf
                   1436: #include <stdio.h>
                   1437: #include <sys/types.h>
                   1438: #include <netns/ns.h>
                   1439: #include "Printing_defs.h"
                   1440: #include <except.h>
                   1441: 
                   1442: static FILE *ipfile = NULL;
                   1443: 
                   1444: SendSource(bdtconnection)
                   1445: CourierConnection *bdtconnection;
                   1446: {
                   1447:        int count;
                   1448:        char buffer[SPPMAXDATA];
                   1449: 
                   1450:        while ( (count = fread(buffer,1,SPPMAXDATA,ipfile)) > 0 &&
                   1451:                BDTwrite(bdtconnection,buffer,count) >= 0 )
                   1452:                ;
                   1453:        if (count <= 0)
                   1454:                BDTclosewrite(bdtconnection);   /* last packet with EOM set */
                   1455:        else
                   1456:                BDTabort(bdtconnection);
                   1457: }
                   1458: 
                   1459: main(argc, argv)
                   1460:        int argc;
                   1461:        char *argv[];
                   1462: {
                   1463:        PrintResults result;
                   1464:        struct ns_addr *destaddr;
                   1465:        CourierConnection *conn;
                   1466:        extern struct ns_addr *getXNSaddr();
                   1467:        PrintAttributes attributes;
                   1468:        PrintOptions options;
                   1469: 
                   1470:        /* use Cornell print server, CornellS1 (slander) */
                   1471:        destaddr = getXNSaddr("2-273#2-852-159-207");
                   1472:        attributes.length = 0;
                   1473:        options.length = 0;
                   1474:        if (argc != 2 || ((ipfile = fopen(argv[1],"r")) == NULL)) {
                   1475:                fprintf(stderr,"Usage: %s file\en",argv[0]);
                   1476:                exit(1);
                   1477:        }
                   1478:        if ((conn = CourierOpen(destaddr)) == NULL) {
                   1479:                fprintf(stderr,"Can't open connection to %s\en",xnshost);
                   1480:                exit(1);
                   1481:        }
                   1482: 
                   1483:        DURING
                   1484:                result = Print(conn, SendSource, BulkData1_immediateSource,
                   1485:                                        attributes, options);
                   1486:        HANDLER {
                   1487:                switch (Exception.Code) {
                   1488:                case Busy:
                   1489:                        fprintf(stderr,"Busy\en");
                   1490:                        break;
                   1491:                case ConnectionError:
                   1492:                        fprintf(stderr,"Connection error, %d\en",
                   1493:                                CourierErrArgs(ConnectionErrorArgs,problem));
                   1494:                        break;
                   1495:                case InsufficientSpoolSpace:
                   1496:                case SpoolingQueueFull:
                   1497:                        fprintf(stderr,"Insufficient spool space\en");
                   1498:                        break;
                   1499:                case SpoolingDisabled:
                   1500:                        fprintf(stderr,"Spooling disabled\en");
                   1501:                        break;
                   1502:                case MasterTooLarge:
                   1503:                case TooManyClients:
                   1504:                case ServiceUnavailable:
                   1505:                case SystemError:
                   1506:                case InvalidPrintParameters:
                   1507:                case MediumUnavailable:
                   1508:                case TransferError:
                   1509:                        fprintf(stderr,"Some Printing error, number %d\en",
                   1510:                                Exception.code-ERROR_OFFSET);
                   1511:                        break;
                   1512:                case Undefined:
                   1513:                        fprintf(stderr,"Undefined error, number %d\en",
                   1514:                                CourierErrArgs(UndefinedArgs,problem));
                   1515:                        break;
                   1516:                case REJECT_ERROR:
                   1517:                        fprintf(stderr,"REJECT:  type = %d\en",
                   1518:                                CourierErrArgs(rejectionDetails, designator));
                   1519:                        break;
                   1520:                default:
                   1521:                        fprintf(stderr,"Some random error, code %d\en",
                   1522:                                Exception.Code);
                   1523:                        break;
                   1524:                }
                   1525:        exit(1);
                   1526:        } END_HANDLER;
                   1527: 
                   1528:        CourierClose(conn);
                   1529:        printf("Done.  Request ID %x %x %x %x %x\en",
                   1530:                result.printRequestID[0], result.printRequestID[1],
                   1531:                result.printRequestID[2], result.printRequestID[3],
                   1532:                result.printRequestID[4]);
                   1533: }
                   1534: .fi
                   1535: .bp
                   1536: .sh 1 "Final Notes"
                   1537: .pp
                   1538: The issues of authentication and protection are
                   1539: difficult.
                   1540: They are only touched upon in this implementation.
                   1541: Currently, each Courier program must perform any authentication
                   1542: (presumably using the Authentication protocol)
                   1543: if this is desired.  A few routines exist to allow cleints and servers
                   1544: to perform simple Authentication; no support for strong Authentication
                   1545: has yet been written.
                   1546: .pp
                   1547: This implementation is fairly inefficient, especially in
                   1548: the implementation of servers.  Courier calls require substantial
                   1549: extra copying of courier arguments and results.  More significantly,
                   1550: the requirement that each call spawn a unique process is very expensive
                   1551: in UNIX, and should be reconsidered.
                   1552: A sequence of RPCs on the same SPP stream that specifies the same program
                   1553: and version number uses the same process, but in all other cases a new
                   1554: process must be spawned for each individual RPC.
                   1555: .pp
                   1556: This implementation defines a number of reserved identifiers.
                   1557: .b ">>>should list them here<<<"
                   1558: .sh 1 "Appendix"
                   1559: .pp
                   1560: This appendix contains the grammar for the Courier language.
                   1561: It is similar to the YACC specification used
                   1562: by the Courier compiler.
                   1563: .sp
                   1564: .ps -2p
                   1565: .vs -2p
                   1566: .nf
                   1567: .TS
                   1568: l l l l l.
                   1569: %token identifier      number  string  
                   1570:        ARRAY   BEGIN   BOOLEAN CARDINAL
                   1571:        CHOICE  DEPENDS END     ERROR
                   1572:        FALSE   INTEGER LONG    OF
                   1573:        PROCEDURE       PROGRAM RECORD  REPORTS
                   1574:        RETURNS SEQUENCE        STRING  TRUE
                   1575:        TYPE    UNSPECIFIED     UPON    VERSION
                   1576: .TE
                   1577: %%
                   1578: 
                   1579: Program :
                   1580:                identifier ':' PROGRAM number VERSION number '='
                   1581:                BEGIN DependencyList DeclarationList END '.'
                   1582:        |
                   1583:                identifier ':' PROGRAM '='
                   1584:                BEGIN DependencyList DeclarationList END '.'
                   1585:        ;
                   1586: 
                   1587: DependencyList :
                   1588:                /* empty */
                   1589:        |       DEPENDS UPON ReferencedProgramList ';'
                   1590:        ;
                   1591: 
                   1592: ReferencedProgramList :
                   1593:                ReferencedProgram
                   1594:        |       ReferencedProgramList ',' ReferencedProgram
                   1595:        ;
                   1596: 
                   1597: ReferencedProgram :
                   1598:                identifier '(' number ')' VERSION number
                   1599:        ;
                   1600: 
                   1601: DeclarationList :
                   1602:                /* empty */
                   1603:        |       DeclarationList Declaration
                   1604:        ;
                   1605: 
                   1606: Declaration :
                   1607:                identifier ':' TYPE '=' Type ';'
                   1608:        |       identifier ':' Type '=' Constant ';'
                   1609:        ;
                   1610: 
                   1611: Type :
                   1612:                PredefinedType
                   1613:        |       ConstructedType
                   1614:        |       ReferencedType
                   1615:        ;
                   1616: 
                   1617: PredefinedType :
                   1618:                BOOLEAN
                   1619:        |       CARDINAL
                   1620:        |       LONG CARDINAL
                   1621:        |       INTEGER
                   1622:        |       LONG INTEGER
                   1623:        |       STRING
                   1624:        |       UNSPECIFIED
                   1625:        |       LONG UNSPECIFIED
                   1626:        ;
                   1627: 
                   1628: ConstructedType :
                   1629:                '{' CorrespondenceList '}'
                   1630:        |       ARRAY NumericValue OF Type
                   1631:        |       SEQUENCE MaximumNumber OF Type
                   1632:        |       RECORD '[' FieldList ']'
                   1633:        |       RECORD '[' ']'
                   1634:        |       CHOICE DesignatorType OF '{' CandidateList '}'
                   1635:        |       PROCEDURE ArgumentList ResultList ErrorList
                   1636:        |       ERROR ArgumentList
                   1637:        ;
                   1638: 
                   1639: ReferencedType :
                   1640:                identifier
                   1641:        |       identifier '.' identifier
                   1642:        ;
                   1643: 
                   1644: CorrespondenceList :
                   1645:                Correspondence
                   1646:        |       CorrespondenceList ',' Correspondence
                   1647:        ;
                   1648: 
                   1649: Correspondence :
                   1650:                identifier '(' NumericValue ')'
                   1651:        ;
                   1652: 
                   1653: MaximumNumber :
                   1654:                NumericValue
                   1655:        |       /* empty */
                   1656:        ;
                   1657: 
                   1658: NumericValue :
                   1659:                number
                   1660:        |       ReferencedConstant
                   1661:        ;
                   1662: 
                   1663: DesignatorType :
                   1664:                /* empty */
                   1665:        |       ReferencedType
                   1666:        ;
                   1667: 
                   1668: CandidateList :
                   1669:                Candidate
                   1670:        |       CandidateList ',' Candidate
                   1671:        ;
                   1672: 
                   1673: Candidate :
                   1674:                DesignatorList '=''>' Type
                   1675:        ;
                   1676: 
                   1677: DesignatorList :
                   1678:                Designator
                   1679:        |       DesignatorList ',' Designator
                   1680:        ;
                   1681: 
                   1682: Designator :
                   1683:                identifier
                   1684:        |       Correspondence
                   1685:        ;
                   1686: 
                   1687: ArgumentList :
                   1688:                /* empty */
                   1689:        |       '[' FieldList ']'
                   1690:        ;
                   1691: 
                   1692: ResultList :
                   1693:                /* empty */
                   1694:        |       RETURNS '[' FieldList ']'
                   1695:        ;
                   1696: 
                   1697: ErrorList :
                   1698:                /* empty */
                   1699:        |       REPORTS '[' NameList ']'
                   1700:        ;
                   1701: 
                   1702: FieldList :
                   1703:                Field
                   1704:        |       FieldList ',' Field
                   1705:        ;
                   1706: 
                   1707: Field :
                   1708:                NameList ':' Type
                   1709:        ;
                   1710: 
                   1711: Constant :
                   1712:                PredefinedConstant
                   1713:        |       ConstructedConstant
                   1714:        |       ReferencedConstant
                   1715:        ;
                   1716: 
                   1717: PredefinedConstant :
                   1718:                TRUE
                   1719:        |       FALSE
                   1720:        |       number
                   1721:        |       '-' number
                   1722:        |       '"' string '"'
                   1723:        ;
                   1724: 
                   1725: ConstructedConstant :
                   1726:                identifier
                   1727:        |       '[' ElementList ']'
                   1728:        |       '[' ComponentList ']'
                   1729:        |       '['']'
                   1730:        |       identifier Constant
                   1731:        |       number
                   1732:        ;
                   1733: 
                   1734: ReferencedConstant :
                   1735:                identifier
                   1736:        |       identifier '.' identifier
                   1737:        ;
                   1738: 
                   1739: ElementList :
                   1740:                Constant
                   1741:        |       ElementList ',' Constant
                   1742:        ;
                   1743: 
                   1744: ComponentList :
                   1745:                Component
                   1746:        |       ComponentList ',' Component
                   1747:        ;
                   1748: 
                   1749: Component :
                   1750:                NameList ':' Constant
                   1751:        ;
                   1752: 
                   1753: NameList :
                   1754:                identifier
                   1755:        |       NameList ',' identifier
                   1756:        ;
                   1757: .fi
                   1758: .vs
                   1759: .ps

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.