Annotation of 43BSD/contrib/xns/doc/courier.tbl.me, revision 1.1

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

unix.superglobalmegacorp.com

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