Annotation of 43BSD/contrib/sunrpc/doc/rpc.prog, revision 1.1.1.1

1.1       root        1: .OH 'RPC Programming''Page \\\\n(PN'
                      2: .EH 'Page \\\\n(PN''RPC Programming'
                      3: .OF 'Sun Microsystems''Release 2.0'
                      4: .EF 'Release 2.0''Sun Microsystems'
                      5: .RP
                      6: .rm DY
                      7: .TL
                      8: .ps 20
                      9: Remote Procedure Call
                     10: .sp.5
                     11: Programming Guide
                     12: .
                     13: .H 1 "Introduction"
                     14: .LP
                     15: Programs that communicate over a network
                     16: need a paradigm for communication.
                     17: A low-level mechanism might 
                     18: send a signal on the arrival of incoming packets,
                     19: causing a network signal handler to execute.
                     20: A high-level mechanism would be the Ada 
                     21: .L rendezvous .
                     22: The method used at Sun is the
                     23: Remote Procedure Call (RPC) paradigm,
                     24: in which a client communicates with a server.
                     25: In this process,
                     26: the client first calls a procedure to send a data packet to the server.
                     27: When the packet arrives, the server calls a dispatch routine,  
                     28: performs whatever service is requested, sends back the reply,
                     29: and the procedure call returns to the client.
                     30: .LP
                     31: The RPC interface is divided into three layers.
                     32: The highest layer is totally transparent to the programmer.
                     33: To illustrate,
                     34: at this level a program can contain a call to
                     35: .L rnusers() ,
                     36: which returns the number of users on a remote machine.
                     37: You don't have to be aware that RPC is being used,
                     38: since you simply make the call in a program,
                     39: just as you would call
                     40: .L malloc() .
                     41: .LP
                     42: At the middle layer, the routines
                     43: .L registerrpc()
                     44: and
                     45: .L callrpc()
                     46: are used to make RPC calls:
                     47: .L registerrpc()
                     48: obtains a unique system-wide number, while
                     49: .L callrpc()
                     50: executes a remote procedure call.
                     51: The 
                     52: .L rnusers()
                     53: call is implemented using these two routines
                     54: The middle-layer routines are designed for most common applications,
                     55: and shield the user from knowing about sockets.
                     56: .LP
                     57: The lowest layer is used for more sophisticated applications,
                     58: which may want to alter the defaults of the routines.
                     59: At this layer, you can explicitly manipulate
                     60: sockets used for transmitting RPC messages.
                     61: This level should be avoided if possible.
                     62: .LP
                     63: Section 2 of this manual illustrates use of the highest two layers
                     64: while Section 3 presents the low-level interface.
                     65: Section 4 of the manual discusses miscellaneous topics.
                     66: The final section summarizes 
                     67: all the entry points into the RPC system.
                     68: .LP
                     69: Although this document only discusses the interface to C,
                     70: remote procedure calls can be made from any language.
                     71: Even though this document discusses RPC
                     72: when it is used to communicate
                     73: between processes on different machines,
                     74: it works just as well for communication
                     75: between different processes on the same machine.
                     76: .bp
                     77: .
                     78: .H 1 "Introductory Examples"
                     79: .H 2 "Highest Layer"
                     80: .LP
                     81: Imagine you're writing a program that needs to know
                     82: how many users are logged into a remote machine.
                     83: You can do this by calling the library routine
                     84: .L rnusers() ,
                     85: as illustrated below:
                     86: .LS
                     87: #include <stdio.h>
                     88: .sp.5
                     89: main(argc, argv)
                     90:        int argc;
                     91:        char **argv;
                     92: {
                     93:        unsigned num;
                     94: .sp.5
                     95:        if (argc < 2) {
                     96:                fprintf(stderr, "usage: rnusers hostname\en");
                     97:                exit(1);
                     98:        }
                     99:        if ((num = rnusers(argv[1])) < 0) {
                    100:                fprintf(stderr, "error: rnusers\en");
                    101:                exit(-1);
                    102:        }
                    103:        printf("%d users on %s\en", num, argv[1]);
                    104:        exit(0);
                    105: }
                    106: .LE
                    107: RPC library routines such as
                    108: .L rnusers()
                    109: are included in the C library
                    110: .L libc.a .
                    111: Thus, the program above could be compiled with
                    112: .LS
                    113: % cc \fIprogram.c\fP
                    114: .LE
                    115: Some other library routines are
                    116: .L rstat()
                    117: to gather remote performance statistics, and
                    118: .L ypmatch()
                    119: to glean information from the yellow pages (YP).
                    120: The YP library routines are documented on the manual page
                    121: .I ypclnt (3N).
                    122: .bp
                    123: .
                    124: .H 2 "Intermediate Layer"
                    125: .LP
                    126: The simplest interface, which explicitly makes RPC
                    127: calls, uses the functions
                    128: .L callrpc()
                    129: and
                    130: .L registerrpc() .
                    131: Using this method, another way to get the number of remote users is:
                    132: .LS
                    133: #include <stdio.h>
                    134: #include <rpcsvc/rusers.h>
                    135: .sp.5
                    136: main(argc, argv)
                    137:        int argc;
                    138:        char **argv;
                    139: {
                    140:        unsigned long nusers;
                    141: .sp.5
                    142:        if (argc < 2) {
                    143:                fprintf(stderr, "usage: nusers hostname\en");
                    144:                exit(-1);
                    145:        }
                    146:        if (callrpc(argv[1], RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
                    147:            xdr_void, 0, xdr_u_long, &nusers) != 0) {
                    148:                fprintf(stderr, "error: callrpc\en");
                    149:                exit(1);
                    150:        }
                    151:        printf("number of users on %s is %d\en", argv[1], nusers);
                    152:        exit(0);
                    153: }
                    154: .LE
                    155: A program number, version number, and procedure number
                    156: defines each RPC procedure.
                    157: The program number defines a group
                    158: of related remote procedures, each of which has a different
                    159: procedure number.
                    160: Each program also has a version number,
                    161: so when a minor change is made to a remote service
                    162: (adding a new procedure, for example),
                    163: a new program number doesn't have to be assigned.
                    164: When you want to call a procedure to
                    165: find the number of remote users, you look up the appropriate
                    166: program, version and procedure numbers
                    167: in a manual, similar to when you look up the name of memory
                    168: allocator when you want to allocate memory.
                    169: .LP
                    170: The simplest routine in the RPC library
                    171: used to make remote procedure calls is
                    172: .L callrpc() .
                    173: It has eight parameters.
                    174: The first is the name of the remote machine.
                    175: The next three parameters
                    176: are the program, version, and procedure numbers.
                    177: The following two parameters
                    178: define the argument of the RPC call, and the final two parameters
                    179: are for the return value of the call. 
                    180: If it completes successfully,
                    181: .L callrpc()
                    182: returns zero, but nonzero otherwise.
                    183: The exact meaning of the return codes is found in
                    184: .L <rpc/clnt.h> ,
                    185: and is in fact an
                    186: .L "enum clnt_stat"
                    187: cast into an integer.
                    188: .LP
                    189: Since data types may be represented differently on different machines,
                    190: .L callrpc()
                    191: needs both the type of the RPC argument, as well as
                    192: a pointer to the argument itself (and similarly for the result).
                    193: For RUSERSPROC_NUM, the return value is an
                    194: .L "unsigned long" ,
                    195: so 
                    196: .L callrpc()
                    197: has
                    198: .L xdr_u_long
                    199: as its first return parameter, which says 
                    200: that the result is of type
                    201: .L "unsigned long",
                    202: and
                    203: .L &nusers 
                    204: as its second return parameter,
                    205: which is a pointer to where the long result will be placed.
                    206: Since RUSERSPROC_NUM takes no argument, the argument parameter of
                    207: .L callrpc()
                    208: is
                    209: .L xdr_void .
                    210: .LP
                    211: After trying several times to deliver a message, if
                    212: .L callrpc()
                    213: gets no answer, it returns with an error code.
                    214: The delivery mechanism is UDP,
                    215: which stands for User Datagram Protocol.
                    216: Methods for adjusting the number of retries
                    217: or for using a different protocol require you to use the lower
                    218: layer of the RPC library, discussed later in this document.
                    219: The remote server procedure
                    220: corresponding to the above might look like this:
                    221: .LS
                    222: char *
                    223: nuser(indata)
                    224:        char *indata;
                    225: {
                    226:        static int nusers;
                    227: .sp.5
                    228:        /*
                    229:         * code here to compute the number of users
                    230:         * and place result in variable nusers
                    231:         */
                    232:        return ((char *)&nusers);
                    233: }
                    234: .LE
                    235: .LP
                    236: It takes one argument, which is a pointer to the input
                    237: of the remote procedure call (ignored in our example),
                    238: and it returns a pointer to the result.
                    239: In the current version of C,
                    240: character pointers are the generic pointers,
                    241: so both the input argument and the return value are cast to
                    242: .L "char *" .
                    243: .LP
                    244: Normally, a server registers all of the RPC calls it plans
                    245: to handle, and then goes into an infinite loop waiting to service requests.
                    246: In this example, there is only a single procedure
                    247: to register, so the main body of the server would look like this:
                    248: .LS
                    249: #include <stdio.h>
                    250: #include <rpcsvc/rusers.h>
                    251: .sp.5
                    252: char *nuser();
                    253: .sp.5
                    254: main()
                    255: {
                    256:        registerrpc(RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM, nuser,
                    257:            xdr_void, xdr_u_long);
                    258:        svc_run();              /* never returns */
                    259:        fprintf(stderr, "Error: svc_run returned!\en");
                    260:        exit(1);
                    261: }
                    262: .LE
                    263: .LP
                    264: The
                    265: .L registerrpc()
                    266: routine establishes what C procedure
                    267: corresponds to each RPC procedure number.
                    268: The first three parameters,
                    269: RUSERPROG, RUSERSVERS, and RUSERSPROC_NUM
                    270: are the program, version, and procedure numbers
                    271: of the remote procedure to be registered;
                    272: .L nuser
                    273: is the name of the C procedure implementing it;
                    274: and 
                    275: .L xdr_void
                    276: and
                    277: .L xdr_u_long
                    278: are the types of the input to and output from the procedure.
                    279: .LP
                    280: Only the UDP transport mechanism can use
                    281: .L registerrpc() ;
                    282: thus, it is always safe in conjunction with calls generated by 
                    283: .L callrpc() .
                    284: .LP
                    285: Warning: the UDP transport mechanism can only deal with
                    286: arguments and results less than 8K bytes in length.
                    287: .
                    288: .H 2 "Assigning Program Numbers"
                    289: .LP
                    290: Program numbers are assigned in groups of 0x20000000 (536870912)
                    291: according to the following chart:
                    292: .LS
                    293:        0 - 1fffffff    defined by sun
                    294: 20000000 - 3fffffff    defined by user
                    295: 40000000 - 5fffffff    transient
                    296: 60000000 - 7fffffff    reserved
                    297: 80000000 - 9fffffff    reserved
                    298: a0000000 - bfffffff    reserved
                    299: c0000000 - dfffffff    reserved
                    300: e0000000 - ffffffff    reserved
                    301: .LE
                    302: Sun Microsystems administers the first group of numbers,
                    303: which should be identical for all Sun customers.
                    304: If a customer develops an application that might be of general
                    305: interest, that application should be given an assigned number
                    306: in the first range.
                    307: The second group of numbers is reserved for specific customer
                    308: applications.
                    309: This range is intended primarily for debugging new programs.
                    310: The third group is reserved for applications that
                    311: generate program numbers dynamically.
                    312: The final groups
                    313: are reserved for future use, and should not be used.
                    314: .LP
                    315: The exact registration process for Sun defined numbers is yet
                    316: to be established.
                    317: .
                    318: .H 2 "Passing Arbitrary Data Types"
                    319: .LP
                    320: In the previous example, the RPC call passes a single
                    321: .L "unsigned long."
                    322: RPC can handle arbitrary data structures, regardless of
                    323: different machines' byte orders or structure layout conventions,
                    324: by always converting them to a network standard called 
                    325: .I "eXternal Data Representation"
                    326: (XDR) before
                    327: sending them over the wire.
                    328: The process of converting from a particular machine representation
                    329: to XDR format is called
                    330: .I serializing ,
                    331: and the reverse process is called
                    332: .I deserializing .
                    333: The type field parameters of 
                    334: .L callrpc()
                    335: and
                    336: .L registerrpc()
                    337: can be a built-in procedure like
                    338: .L xdr_u_long()
                    339: in the previous example, or a user supplied one.
                    340: XDR has these built-in type routines:
                    341: .LS
                    342: xdr_int()      xdr_u_int()      xdr_enum()
                    343: xdr_long()     xdr_u_long()     xdr_bool()  
                    344: xdr_short()    xdr_u_short()    xdr_string()
                    345: .LE
                    346: As an example of a user-defined type routine,
                    347: if you wanted to send the structure
                    348: .LS
                    349: struct simple {
                    350:        int a;
                    351:        short b;
                    352: } simple;
                    353: .LE
                    354: then you would call
                    355: .L callrpc
                    356: as
                    357: .LS
                    358: callrpc(hostname, PROGNUM, VERSNUM, PROCNUM, xdr_simple, &simple ...);
                    359: .LE
                    360: where
                    361: .L xdr_simple()
                    362: is written as:
                    363: .LS
                    364: #include <rpc/rpc.h>
                    365: .sp.5
                    366: xdr_simple(xdrsp, simplep)
                    367:        XDR *xdrsp;
                    368:        struct simple *simplep;
                    369: {
                    370:        if (!xdr_int(xdrsp, &simplep->a))
                    371:                return (0);
                    372:        if (!xdr_short(xdrsp, &simplep->b))
                    373:                return (0);
                    374:        return (1);
                    375: }
                    376: .LE
                    377: .LP
                    378: An XDR routine returns nonzero (true in the sense of C)
                    379: if it completes successfully, and zero otherwise.
                    380: A complete description of XDR is in the 
                    381: .I "XDR Protocol Specification" ,
                    382: so this section only gives a few examples of XDR implementation.
                    383: .LP
                    384: In addition to the built-in primitives,
                    385: there are also the prefabricated building blocks:
                    386: .LS
                    387: xdr_array()       xdr_bytes()
                    388: xdr_reference()   xdr_union()
                    389: .LE
                    390: To send a variable array of integers,
                    391: you might package them up as a structure like this
                    392: .LS
                    393: struct varintarr {
                    394:        int *data;
                    395:        int arrlnth;
                    396: } arr;
                    397: .LE
                    398: and make an RPC call such as
                    399: .LS
                    400: callrpc(hostname, PROGNUM, VERSNUM, PROCNUM, xdr_varintarr, &arr...);
                    401: .LE
                    402: with
                    403: .L xdr_varintarr()
                    404: defined as:
                    405: .LS
                    406: xdr_varintarr(xdrsp, varintarr)
                    407:        XDR *xdrsp;
                    408:        struct varintarr *arrp;
                    409: {
                    410:        xdr_array(xdrsp, &arrp->data, &arrp->arrlnth, MAXLEN,
                    411:                sizeof(int), xdr_int);
                    412: }
                    413: .LE
                    414: This routine takes as parameters the XDR handle,
                    415: a pointer to the array, a pointer to the size of the array,
                    416: the maximum allowable array size,
                    417: the size of each array element,
                    418: and an XDR routine for handling each array element.
                    419: .LP
                    420: If the size of the array is known in advance, then
                    421: the following could also be used to send 
                    422: out an array of length SIZE:
                    423: .LS
                    424: int intarr[SIZE];
                    425: .sp.5
                    426: xdr_intarr(xdrsp, intarr)
                    427:        XDR *xdrsp;
                    428:        int intarr[];
                    429: {
                    430:        int i;
                    431: .sp.5
                    432:        for (i = 0; i < SIZE; i++) {
                    433:                if (!xdr_int(xdrsp, &intarr[i]))
                    434:                        return (0);
                    435:        }
                    436:        return (1);
                    437: }
                    438: .LE
                    439: .LP
                    440: XDR always converts quantities to 4-byte multiples when deserializing.
                    441: Thus, if either of the examples above involved characters
                    442: instead of integers, each character would occupy 32 bits.
                    443: That is the reason for the XDR routine
                    444: .L xdr_bytes() ,
                    445: which is like
                    446: .L xdr_array()
                    447: except that it packs characters.
                    448: It has four parameters,
                    449: the same as the first four parameters of
                    450: .L xdr_array() .
                    451: For null-terminated strings, there is also the
                    452: .L xdr_string()
                    453: routine, which is the same as
                    454: .L xdr_bytes()
                    455: without the length parameter.
                    456: On serializing it gets the string length from 
                    457: .L strlen() ,
                    458: and on deserializing it creates a null-terminated string.
                    459: .LP
                    460: Here is a final example that calls the previously written
                    461: .L xdr_simple()
                    462: as well as the built-in functions
                    463: .L xdr_string()
                    464: and
                    465: .L xdr_reference() ,
                    466: which chases pointers:
                    467: .LS
                    468: struct finalexample {
                    469:        char *string;
                    470:        struct simple *simplep;
                    471: } finalexample;
                    472: .LE
                    473: .LS
                    474: xdr_finalexample(xdrsp, finalp)
                    475:        XDR *xdrsp;
                    476:        struct finalexample *finalp;
                    477: {
                    478:        int i;
                    479: .sp.5
                    480:        if (!xdr_string(xdrsp, &finalp->string, MAXSTRLEN))
                    481:                return (0);
                    482:        if (!xdr_reference(xdrsp, &finalp->simplep,
                    483:            sizeof(struct simple), xdr_simple);
                    484:                return (0);
                    485:        return (1);
                    486: }
                    487: .LE
                    488: .bp
                    489: .
                    490: .H 1 "Lower Layers of RPC"
                    491: .LP
                    492: In the examples given so far,
                    493: RPC takes care of many details automatically for you.
                    494: In this section, we'll show you how you can change the defaults
                    495: by using lower layers of the RPC library.
                    496: It is assumed that you are familiar with sockets
                    497: and the system calls for dealing with them.
                    498: If not, consult
                    499: .I "The IPC Tutorial" .
                    500: .H 2 "More on the Server Side"
                    501: .LP
                    502: There are a number of assumptions built into 
                    503: .L registerrpc() .
                    504: One is that you are using the UDP datagram protocol.
                    505: Another is that
                    506: you don't want to do anything unusual while deserializing,
                    507: since the deserialization process happens automatically
                    508: before the user's server routine is called.
                    509: The server for the
                    510: .L nusers
                    511: program shown below
                    512: is written using a lower layer of the RPC package,
                    513: which does not make these assumptions.
                    514: .LS
                    515: #include <stdio.h>
                    516: #include <rpc/rpc.h>
                    517: #include <rpcsvc/rusers.h>
                    518: .sp.5
                    519: int nuser();
                    520: .sp.5
                    521: main()
                    522: {
                    523:        SVCXPRT *transp;
                    524: .sp.5
                    525:        transp = svcudp_create(RPC_ANYSOCK);
                    526:        if (transp == NULL){
                    527:                fprintf(stderr, "couldn't create an RPC server\en");
                    528:                exit(1);
                    529:        }
                    530:        pmap_unset(RUSERSPROG, RUSERSVERS);
                    531:        if (!svc_register(transp, RUSERSPROG, RUSERSVERS, nuser,
                    532:            IPPROTO_UDP)) {
                    533:                fprintf(stderr, "couldn't register RUSER service\en");
                    534:                exit(1);
                    535:        }
                    536:        svc_run();  /* never returns */
                    537:        fprintf(stderr, "should never reach this point\en");
                    538: }
                    539: .LE
                    540: .LS
                    541: nuser(rqstp, tranp)
                    542:        struct svc_req *rqstp;
                    543:        SVCXPRT *transp;
                    544: {
                    545:        unsigned long nusers;
                    546: .sp.5
                    547:        switch (rqstp->rq_proc) {
                    548:        case NULLPROC:
                    549:                if (!svc_sendreply(transp, xdr_void, 0)) {
                    550:                        fprintf(stderr, "couldn't reply to RPC call\en");
                    551:                        exit(1);
                    552:                }
                    553:                return;
                    554:        case RUSERSPROC_NUM:
                    555:                /*
                    556:                 * code here to compute the number of users
                    557:                 * and put in variable nusers
                    558:                 */
                    559:                if (!svc_sendreply(transp, xdr_u_long, &nusers) {
                    560:                        fprintf(stderr, "couldn't reply to RPC call\en");
                    561:                        exit(1);
                    562:                }
                    563:                return;
                    564:        default: 
                    565:                svcerr_noproc(transp);
                    566:                return;
                    567:        }
                    568: }
                    569: .LE
                    570: .LP
                    571: First, the server gets a transport handle, which is used
                    572: for sending out RPC messages.
                    573: .L registerrpc()
                    574: uses
                    575: .L svcudp_create()
                    576: to get a UDP handle.
                    577: If you require a reliable protocol, call
                    578: .L svctcp_create()
                    579: instead.
                    580: If the argument to
                    581: .L svcudp_create()
                    582: is RPC_ANYSOCK,
                    583: the RPC library creates a socket
                    584: on which to send out RPC calls.
                    585: Otherwise, 
                    586: .L svcudp_create()
                    587: expects its argument to be a valid socket number.
                    588: If you specify your own socket, it can be bound or unbound.
                    589: If it is bound to a port by the user, the port numbers of
                    590: .L svcudp_create()
                    591: and
                    592: .L clntudp_create()
                    593: (the low-level client routine) must match.
                    594: .LP
                    595: When the user specifies RPC_ANYSOCK for a socket 
                    596: or gives an unbound socket, the system determines
                    597: port numbers in the following way:
                    598: when a server starts up,
                    599: it advertises to a port mapper demon on its local machine,
                    600: which picks a port number for the RPC procedure
                    601: if the socket specified to
                    602: .L svcudp_create()
                    603: isn't already bound.
                    604: When the
                    605: .L clntudp_create()
                    606: call is made with an unbound socket,
                    607: the system queries the port mapper on
                    608: the machine to which the call is being made,
                    609: and gets the appropriate port number.
                    610: If the port mapper is not running
                    611: or has no port corresponding to the RPC call,
                    612: the RPC call fails.
                    613: Users can make RPC calls
                    614: to the port mapper themselves.
                    615: The appropriate procedure
                    616: numbers are in the include file
                    617: .L <rpc/pmap_prot.h> .
                    618: .LP
                    619: After creating an SVCXPRT, the next step is to call
                    620: .L pmap_unset()
                    621: so that if the
                    622: .L nusers
                    623: server crashed earlier,
                    624: any previous trace of it is erased before restarting.
                    625: More precisely,
                    626: .L pmap_unset()
                    627: erases the entry for RUSERS from the port mapper's tables.
                    628: .LP
                    629: Finally, we associate the program number for
                    630: .L nusers
                    631: with the procedure 
                    632: .L nuser() .
                    633: The final argument to
                    634: .L svc_register()
                    635: is normally the protocol being used,
                    636: which, in this case, is IPPROTO_UDP.
                    637: Notice that unlike
                    638: .L registerrpc() ,
                    639: there are no XDR routines involved
                    640: in the registration process.
                    641: Also, registration is done on the program,
                    642: rather than procedure, level.
                    643: .LP
                    644: The user routine 
                    645: .L nuser()
                    646: must call and dispatch the appropriate XDR routines
                    647: based on the procedure number.
                    648: Note that 
                    649: two things are handled by 
                    650: .L nuser()
                    651: that
                    652: .L registerrpc()
                    653: handles automatically. 
                    654: The first is that procedure NULLPROC
                    655: (currently zero) returns with no arguments.
                    656: This can be used as a simple test
                    657: for detecting if a remote program is running.
                    658: Second, there is a check for invalid procedure numbers.
                    659: If one is detected,
                    660: .L svcerr_noproc()
                    661: is called to handle the error.
                    662: .LP
                    663: The user service routine serializes the results and returns
                    664: them to the RPC caller via 
                    665: .L svc_sendreply() .
                    666: Its first parameter is the SVCXPRT handle,
                    667: the second is the XDR routine,
                    668: and the third is a pointer to the data to be returned.
                    669: Not illustrated above is how a server
                    670: handles an RPC program that passes data.
                    671: As an example, we can add a procedure RUSERSPROC_BOOL,
                    672: which has an argument
                    673: .L nusers ,
                    674: and returns TRUE or FALSE depending on
                    675: whether there are nusers logged on.
                    676: It would look like this:
                    677: .LS
                    678: case RUSERSPROC_BOOL: {
                    679:        int bool;
                    680:        unsigned nuserquery;
                    681: .sp.5
                    682:        if (!svc_getargs(transp, xdr_u_int, &nuserquery) {
                    683:                svcerr_decode(transp);
                    684:                return;
                    685:        }
                    686:        /*
                    687:         * code to set nusers = number of users
                    688:         */
                    689:        if (nuserquery == nusers)
                    690:                bool = TRUE;
                    691:        else
                    692:                bool = FALSE;
                    693:        if (!svc_sendreply(transp, xdr_bool, &bool){
                    694:                 fprintf(stderr, "couldn't reply to RPC call\en");
                    695:                 exit(1);
                    696:        }
                    697:        return;
                    698: }
                    699: .LE
                    700: .LP
                    701: The relevant routine is
                    702: .L svc_getargs() ,
                    703: which takes an SVCXPRT handle, the XDR routine,
                    704: and a pointer to where the input is to be placed as arguments.
                    705: .H 2 "Memory Allocation with XDR"
                    706: .LP
                    707: XDR routines not only do input and output,
                    708: they also do memory allocation.
                    709: This is why the second parameter of
                    710: .L xdr_array()
                    711: is a pointer to an array, rather than the array itself.
                    712: If it is NULL, then
                    713: .L xdr_array()
                    714: allocates space for the array and returns a pointer to it, 
                    715: putting the size of the array in the third argument.
                    716: As an example, consider the following XDR routine
                    717: .L xdr_chararr1() ,
                    718: which deals with a fixed array of bytes with length SIZE:
                    719: .LS
                    720: xdr_chararr1(xdrsp, chararr)
                    721:        XDR *xdrsp;
                    722:        char chararr[];
                    723: {
                    724:        char *p;
                    725:        int len;
                    726: .sp.5
                    727:        p = chararr;
                    728:        len = SIZE;
                    729:        return (xdr_bytes(xdrsp, &p, &len, SIZE));
                    730: }
                    731: .LE
                    732: It might be called from a server like this,
                    733: .LS
                    734: char chararr[SIZE];
                    735: .sp.5
                    736: svc_getargs(transp, xdr_chararr1, chararr);
                    737: .LE
                    738: where
                    739: .L chararr
                    740: has already allocated space.
                    741: If you want XDR to do the allocation,
                    742: you would have to rewrite this routine in the following way:
                    743: .LS
                    744: xdr_chararr2(xdrsp, chararrp)
                    745:        XDR *xdrsp;
                    746:        char **chararrp;
                    747: {
                    748:        int len;
                    749: .sp.5
                    750:        len = SIZE;
                    751:        return (xdr_bytes(xdrsp, charrarrp, &len, SIZE));
                    752: }
                    753: .LE
                    754: Then the RPC call might look like this:
                    755: .LS
                    756: char *arrptr;
                    757: .sp.5
                    758: arrptr = NULL;
                    759: svc_getargs(transp, xdr_chararr2, &arrptr);
                    760: /* 
                    761:  * use the result here
                    762:  */
                    763: svc_freeargs(xdrsp, xdr_chararr2, &arrptr);
                    764: .LE
                    765: After using the character array, it can be freed with
                    766: .L svc_freeargs() .
                    767: In the routine
                    768: .L xdr_finalexample()
                    769: given earlier, if
                    770: .L finalp->string
                    771: was NULL in the call
                    772: .LS
                    773: svc_getargs(transp, xdr_finalexample, &finalp);
                    774: .LE
                    775: then
                    776: .LS
                    777: svc_freeargs(xdrsp, xdr_finalexample, &finalp);
                    778: .LE
                    779: frees the array allocated to hold
                    780: .L finalp->string ;
                    781: otherwise, it frees nothing.
                    782: The same is true for
                    783: .L finalp->simplep .
                    784: .LP
                    785: To summarize, each XDR routine is responsible
                    786: for serializing, deserializing, and allocating memory.
                    787: When an XDR routine is called from
                    788: .L callrpc() ,
                    789: the serializing part is used.
                    790: When called from
                    791: .L svc_getargs() ,
                    792: the deserializer is used.
                    793: And when called from
                    794: .L svc_freeargs() ,
                    795: the memory deallocator is used.
                    796: When building simple examples like those in this section,
                    797: a user doesn't have to worry about the three modes.
                    798: The XDR reference manual has examples of more
                    799: sophisticated XDR routines that 
                    800: determine which of the three modes they are in
                    801: to function correctly.
                    802: .
                    803: .H 2 "The Calling Side"
                    804: .LP
                    805: When you use
                    806: .L callrpc,
                    807: you have no control over the RPC delivery
                    808: mechanism or the socket used to transport the data.
                    809: To illustrate the layer of RPC that lets you adjust these
                    810: parameters, consider the following code to call the
                    811: .L nusers
                    812: service:
                    813: .LS
                    814: #include <stdio.h>
                    815: #include <rpc/rpc.h>
                    816: #include <rpcsvc/rusers.h>
                    817: #include <sys/socket.h>
                    818: #include <sys/time.h>
                    819: #include <netdb.h>
                    820: .sp.5
                    821: main(argc, argv)
                    822:        int argc;
                    823:        char **argv;
                    824: {
                    825:        struct hostent *hp;
                    826:        struct timeval pertry_timeout, total_timeout;
                    827:        struct sockaddr_in server_addr;
                    828:        int addrlen, sock = RPC_ANYSOCK;
                    829:        register CLIENT *client;
                    830:        enum clnt_stat clnt_stat;
                    831:        unsigned long nusers;
                    832: .sp.5
                    833:        if (argc < 2) {
                    834:                fprintf(stderr, "usage: nusers hostname\en");
                    835:                exit(-1);
                    836:        }
                    837:        if ((hp = gethostbyname(argv[1])) == NULL) {
                    838:                fprintf(stderr, "cannot get addr for '%s'\en", argv[1]);
                    839:                exit(-1);
                    840:        }
                    841:        pertry_timeout.tv_sec = 3;
                    842:        pertry_timeout.tv_usec = 0;
                    843:        addrlen = sizeof(struct sockaddr_in);
                    844:        bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, hp->h_length);
                    845:        server_addr.sin_family = AF_INET;
                    846:        server_addr.sin_port =  0;
                    847:        if ((client = clntudp_create(&server_addr, RUSERSPROG,
                    848:            RUSERSVERS, pertry_timeout, &sock)) == NULL) {
                    849:                perror("clntudp_create");
                    850:                exit(-1);
                    851:        }
                    852:        total_timeout.tv_sec = 20;
                    853:        total_timeout.tv_usec = 0;
                    854:        clnt_stat = clnt_call(client, RUSERSPROC_NUM, xdr_void, 0,
                    855:            xdr_u_long, &nusers, total_timeout);
                    856:        if (clnt_stat != RPC_SUCCESS) {
                    857:                clnt_perror(client, "rpc");
                    858:                exit(-1);
                    859:        }
                    860:        clnt_destroy(client);
                    861: }
                    862: .LE
                    863: The low-level version of 
                    864: .L callrpc()
                    865: is
                    866: .L clnt_call() ,
                    867: which takes a CLIENT pointer rather than a host name.
                    868: The parameters to 
                    869: .L clnt_call()
                    870: are a CLIENT pointer, the procedure number,
                    871: the XDR routine for serializing the argument,
                    872: a pointer to the argument,
                    873: the XDR routine for deserializing the return value,
                    874: a pointer to where the return value will be placed,
                    875: and the time in seconds to wait for a reply.
                    876: .LP
                    877: The CLIENT pointer is encoded with  
                    878: the transport mechanism.
                    879: .L callrpc()
                    880: uses UDP, thus it calls
                    881: .L clntudp_create()
                    882: to get a CLIENT pointer.
                    883: To get TCP (Transport Control Protocol), you would use
                    884: .L clnttcp_create() .
                    885: .LP
                    886: The parameters to
                    887: .L clntudp_create()
                    888: are the server address, the length of the server address,
                    889: the program number, the version number,
                    890: a timeout value (between tries), and a pointer to a socket.
                    891: The final argument to
                    892: .L clnt_call()
                    893: is the total time to wait for a response.
                    894: Thus, the number of tries is the
                    895: .L clnt_call()
                    896: timeout divided by the
                    897: .L clntudp_create()
                    898: timeout.
                    899: .LP
                    900: There is one thing to note when using the
                    901: .L clnt_destroy()
                    902: call.
                    903: It deallocates any space associated with the CLIENT handle,
                    904: but it does not close the socket associated with it,
                    905: which was passed as an argument to
                    906: .L clntudp_create() .
                    907: The reason is that if 
                    908: there are multiple client handles using the same socket,
                    909: then it is possible to close one handle
                    910: without destroying the socket that other handles
                    911: are using.
                    912: .LP
                    913: To make a stream connection, the call to
                    914: .L clntudp_create()
                    915: is replaced with a call to 
                    916: .L clnttcp_create(). 
                    917: .LS
                    918: clnttcp_create(&server_addr, prognum, versnum, &socket, inputsize,
                    919:        outputsize);
                    920: .LE
                    921: There is no timeout argument; instead, the receive and send buffer
                    922: sizes must be specified.  When the
                    923: .L clnttcp_create()
                    924: call is made, a TCP connection is established.
                    925: All RPC calls using that CLIENT handle would use this connection.
                    926: The server side of an RPC call using TCP has 
                    927: .L svcudp_create()
                    928: replaced by
                    929: .L svctcp_create() .
                    930: .bp
                    931: .
                    932: .H 1 "Other RPC Features"
                    933: .LP
                    934: This section discusses some other aspects of RPC
                    935: that are occasionally useful.
                    936: .
                    937: .H 2 "Select on the Server Side"
                    938: .LP
                    939: Suppose a process is processing RPC requests
                    940: while performing some other activity.
                    941: If the other activity involves periodically updating a data structure,
                    942: the process can set an alarm signal before calling
                    943: .L svc_run() .
                    944: But if the other activity
                    945: involves waiting on a a file descriptor, the
                    946: .L svc_run()
                    947: call won't work.
                    948: The code for
                    949: .L svc_run()
                    950: is as follows:
                    951: .LS
                    952: void
                    953: svc_run()
                    954: {
                    955:        int readfds;
                    956: .sp.5
                    957:        for (;;) {
                    958:                readfds = svc_fds;
                    959:                switch (select(32, &readfds, NULL, NULL, NULL)) {
                    960: .sp.5
                    961:                case -1:
                    962:                        if (errno == EINTR)
                    963:                                continue;
                    964:                        perror("rstat: select");
                    965:                        return;
                    966:                case 0:
                    967:                        break;
                    968:                default:
                    969:                        svc_getreq(readfds);
                    970:                }
                    971:        }
                    972: }
                    973: .LE
                    974: .LP
                    975: You can bypass
                    976: .L svc_run() 
                    977: and call
                    978: .L svc_getreq()
                    979: yourself.
                    980: All you need to know are the file descriptors
                    981: of the socket(s) associated with the programs you are waiting on.
                    982: Thus you can have your own
                    983: .L select()
                    984: that waits on both the RPC socket,
                    985: and your own descriptors.
                    986: .
                    987: .H 2 "Broadcast RPC"
                    988: .LP
                    989: The
                    990: .L pmap
                    991: and RPC protocols implement broadcast RPC.
                    992: Here are the main differences between broadcast RPC
                    993: and normal RPC calls:
                    994: .IP 1)
                    995: Normal RPC expects one answer, whereas
                    996: broadcast RPC expects many answers
                    997: (one or more answer from each responding machine).
                    998: .IP 2)
                    999: Broadcast RPC can only be supported by packet-oriented (connectionless)
                   1000: transport protocols like UPD/IP.
                   1001: .IP 3)
                   1002: The implementation of broadcast RPC
                   1003: treats all unsuccessful responses as garbage by filtering them out.
                   1004: Thus, if there is a version mismatch between the
                   1005: broadcaster and a remote service,
                   1006: the user of broadcast RPC never knows.
                   1007: .IP 4)
                   1008: All broadcast messages are sent to the portmap port.
                   1009: Thus, only services that register themselves with their portmapper
                   1010: are accessible via the broadcast RPC mechanism.
                   1011: .
                   1012: .H 3 "Broadcast RPC Synopsis"
                   1013: .LP
                   1014: .LS
                   1015: #include <rpc/pmap_clnt.h>
                   1016: .sp.5
                   1017: enum clnt_stat clnt_stat;
                   1018: .sp.5
                   1019: clnt_stat =
                   1020: clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
                   1021: u_long         prog;           /* program number */
                   1022: u_long         vers;           /* version number */
                   1023: u_long         proc;           /* procedure number */
                   1024: xdrproc_t      xargs;          /* xdr routine for args */
                   1025: caddr_t                argsp;          /* pointer to args */
                   1026: xdrproc_t      xresults;       /* xdr routine for results */
                   1027: caddr_t                resultsp;       /* pointer to results */
                   1028: bool_t (*eachresult)();                /* call with each result obtained */
                   1029: .LE
                   1030: The procedure
                   1031: .L eachresult()
                   1032: is called each time a valid result is obtained.
                   1033: It returns a boolean that indicates
                   1034: whether or not the client wants more responses.
                   1035: .LS
                   1036: bool_t                 done;
                   1037: .sp.5
                   1038: done =
                   1039: eachresult(resultsp, raddr)
                   1040: caddr_t                        resultsp;
                   1041: struct sockaddr_in     *raddr;   /* address of machine that sent response */
                   1042: .LE
                   1043: If
                   1044: .L done
                   1045: is TRUE, then broadcasting stops and
                   1046: .L clnt_broadcast()
                   1047: returns successfully.
                   1048: Otherwise, the routine waits for another response.
                   1049: The request is rebroadcast
                   1050: after a few seconds of waiting.
                   1051: If no responses come back,
                   1052: the routine returns with RPC_TIMEDOUT.
                   1053: To interpret 
                   1054: .L clnt_stat
                   1055: errors, feed the error code to
                   1056: .L clnt_perrno() .
                   1057: .
                   1058: .H 2 "Batching"
                   1059: .LP
                   1060: The RPC architecture is designed so that clients send a call message,
                   1061: and wait for servers to reply that the call succeeded.
                   1062: This implies that clients do not compute
                   1063: while servers are processing a call.
                   1064: This is inefficient if the client does not want or need
                   1065: an acknowledgement for every message sent.
                   1066: It is possible for clients to continue computing
                   1067: while waiting for a response,
                   1068: using RPC batch facilities.
                   1069: .LP
                   1070: RPC messages can be placed in a ``pipeline'' of calls
                   1071: to a desired server; this is called batching.
                   1072: Batching assumes that:
                   1073: 1) each RPC call in the pipeline requires no response from the server,
                   1074: and the server does not send a response message; and
                   1075: 2) the pipeline of calls is transported on a reliable
                   1076: byte stream transport such as TCP/IP.
                   1077: Since the server does not respond to every call,
                   1078: the client can generate new calls in parallel
                   1079: with the server executing previous calls.
                   1080: Furthermore, the TCP/IP implementation can buffer up
                   1081: many call messages, and send them to the server in one
                   1082: .L write
                   1083: system call.  This overlapped execution
                   1084: greatly decreases the interprocess communication overhead of
                   1085: the client and server processes,
                   1086: and the total elapsed time of a series of calls.
                   1087: .LP
                   1088: Since the batched calls are buffered,
                   1089: the client should eventually do a legitimate call
                   1090: in order to flush the pipeline.
                   1091: .LP
                   1092: A contrived example of batching follows.
                   1093: Assume a string rendering service (like a window system)
                   1094: has two similar calls: one renders a string and returns void results,
                   1095: while the other renders a string and remains silent.
                   1096: The service (using the TCP/IP transport) may look like:
                   1097: .LS
                   1098: #include <stdio.h>
                   1099: #include <rpc/rpc.h>
                   1100: #include <rpcsvc/windows.h>
                   1101: .sp.5
                   1102: void windowdispatch();
                   1103: .sp.5
                   1104: main()
                   1105: {
                   1106:        SVCXPRT *transp;
                   1107: .sp.5
                   1108:        transp = svctcp_create(RPC_ANYSOCK, 0, 0);
                   1109:        if (transp == NULL){
                   1110:                fprintf(stderr, "couldn't create an RPC server\en");
                   1111:                exit(1);
                   1112:        }
                   1113:        pmap_unset(WINDOWPROG, WINDOWVERS);
                   1114:        if (!svc_register(transp, WINDOWPROG, WINDOWVERS, windowdispatch,
                   1115:            IPPROTO_TCP)) {
                   1116:                fprintf(stderr, "couldn't register WINDOW service\en");
                   1117:                exit(1);
                   1118:        }
                   1119:        svc_run();  /* never returns */
                   1120:        fprintf(stderr, "should never reach this point\en");
                   1121: }
                   1122: .LE
                   1123: .LS no
                   1124: void
                   1125: windowdispatch(rqstp, transp)
                   1126:        struct svc_req *rqstp;
                   1127:        SVCXPRT *transp;
                   1128: {
                   1129:        char *s = NULL;
                   1130: .sp.5
                   1131:        switch (rqstp->rq_proc) {
                   1132:        case NULLPROC:
                   1133:                if (!svc_sendreply(transp, xdr_void, 0)) {
                   1134:                        fprintf(stderr, "couldn't reply to RPC call\en");
                   1135:                        exit(1);
                   1136:                }
                   1137:                return;
                   1138:        case RENDERSTRING:
                   1139:                if (!svc_getargs(transp, xdr_wrapstring, &s)) {
                   1140:                        fprintf(stderr, "couldn't decode arguments\en");
                   1141:                        svcerr_decode(transp); /* tell caller he screwed up */
                   1142:                        break;
                   1143:                }
                   1144:                /*
                   1145:                 * call here to to render the string s
                   1146:                 */
                   1147:                if (!svc_sendreply(transp, xdr_void, NULL)) {
                   1148:                        fprintf(stderr, "couldn't reply to RPC call\en");
                   1149:                        exit(1);
                   1150:                }
                   1151:                break;
                   1152:        case RENDERSTRING_BATCHED:
                   1153:                if (!svc_getargs(transp, xdr_wrapstring, &s)) {
                   1154:                        fprintf(stderr, "couldn't decode arguments\en");
                   1155:                        /*
                   1156:                         * we are silent in the face of protocol errors
                   1157:                         */
                   1158:                        break;
                   1159:                }
                   1160:                /*
                   1161:                 * call here to to render the string s,
                   1162:                 * but sends no reply!
                   1163:                 */
                   1164:                break;
                   1165:        default:
                   1166:                svcerr_noproc(transp);
                   1167:                return;
                   1168:        }
                   1169:        /*
                   1170:         * now free string allocated while decoding arguments
                   1171:         */
                   1172:        svc_freeargs(transp, xdr_wrapstring, &s);
                   1173: }
                   1174: .LE
                   1175: Of course the service could have one procedure
                   1176: that takes the string and a boolean
                   1177: to indicate whether or not the procedure should respond.
                   1178: .LP
                   1179: In order for a client to take advantage of batching,
                   1180: the client must perform RPC calls on a TCP-based transport
                   1181: and the actual calls must have the following attributes:
                   1182: 1) the result's XDR routine must be zero (NULL), and
                   1183: 2) the RPC call's timeout must be zero.
                   1184: .LP
                   1185: Here is an example of a client that uses batching
                   1186: to render a bunch of strings;
                   1187: the batching is flushed when the client gets a null string:
                   1188: .LS
                   1189: #include <stdio.h>
                   1190: #include <rpc/rpc.h>
                   1191: #include <rpcsvc/windows.h>
                   1192: #include <sys/socket.h>
                   1193: #include <sys/time.h>
                   1194: #include <netdb.h>
                   1195: .sp.5
                   1196: main(argc, argv)
                   1197:        int argc;
                   1198:        char **argv;
                   1199: {
                   1200:        struct hostent *hp;
                   1201:        struct timeval pertry_timeout, total_timeout;
                   1202:        struct sockaddr_in server_addr;
                   1203:        int addrlen, sock = RPC_ANYSOCK;
                   1204:        register CLIENT *client;
                   1205:        enum clnt_stat clnt_stat;
                   1206:        char buf[1000];
                   1207:        char *s = buf;
                   1208: .sp.5 
                   1209:        /*
                   1210:         * initial as in example 3.3
                   1211:         */
                   1212:        if ((client = clnttcp_create(&server_addr, WINDOWPROG,
                   1213:            WINDOWVERS, &sock, 0, 0)) == NULL) {
                   1214:                perror("clnttcp_create");
                   1215:                exit(-1);
                   1216:        }
                   1217:        total_timeout.tv_sec = 0;
                   1218:        total_timeout.tv_usec = 0;
                   1219:        while (scanf("%s", s) != EOF) {
                   1220:                clnt_stat = clnt_call(client, RENDERSTRING_BATCHED,
                   1221:                    xdr_wrapstring, &s, NULL, NULL, total_timeout);
                   1222:                if (clnt_stat != RPC_SUCCESS) {
                   1223:                        clnt_perror(client, "batched rpc");
                   1224:                        exit(-1);
                   1225:                }
                   1226:        }
                   1227:        /*
                   1228:         * now flush the pipeline
                   1229:         */
                   1230:        total_timeout.tv_sec = 20;
                   1231:        clnt_stat = clnt_call(client, NULLPROC,
                   1232:            xdr_void, NULL, xdr_void, NULL, total_timeout);
                   1233:        if (clnt_stat != RPC_SUCCESS) {
                   1234:                clnt_perror(client, "rpc");
                   1235:                exit(-1);
                   1236:        }
                   1237:        
                   1238:        clnt_destroy(client);
                   1239: }
                   1240: .LE
                   1241: Since the server sends no message,
                   1242: the clients cannot be notified of any of the failures that may occur.
                   1243: Therefore, clients are on their own when it comes to handling errors.
                   1244: .LP
                   1245: The above example was completed to render
                   1246: all of the (2000) lines in the file
                   1247: .I /etc/termcap .
                   1248: The rendering service did nothing but to throw the lines away.
                   1249: The example was run in the following four configurations:
                   1250: 1) machine to itself, regular RPC;
                   1251: 2) machine to itself, batched RPC;
                   1252: 3) machine to another, regular RPC; and
                   1253: 4) machine to another, batched RPC.
                   1254: The results are as follows:
                   1255: 1) 50 seconds;
                   1256: 2) 16 seconds;
                   1257: 3) 52 seconds;
                   1258: 4) 10 seconds.
                   1259: Running
                   1260: .L fscanf()
                   1261: on
                   1262: .I /etc/termcap
                   1263: only requires six seconds.
                   1264: These timings show the advantage of protocols
                   1265: that allow for overlapped execution,
                   1266: though these protocols are often hard to design.
                   1267: .
                   1268: .H 2 "Authentication"
                   1269: .LP
                   1270: In the examples presented so far,
                   1271: the caller never identified itself to the server,
                   1272: and the server never required an ID from the caller.
                   1273: Clearly, some network services, such as a network filesystem,
                   1274: require stronger security than what has been presented so far.
                   1275: .LP
                   1276: In reality, every RPC call is authenticated by
                   1277: the RPC package on the server, and similarly,
                   1278: the RPC client package generates and sends authentication parameters.
                   1279: Just as different transports (TCP/IP or UDP/IP)
                   1280: can be used when creating RPC clients and servers,
                   1281: different forms of authentication can be associated with RPC clients;
                   1282: the default authentication type used as a default is type
                   1283: .I none .
                   1284: .LP
                   1285: The authentication subsystem of the RPC package is open ended.
                   1286: That is, numerous types of authentication are easy to support.
                   1287: However, this section deals only with
                   1288: .I unix
                   1289: type authentication, which besides
                   1290: .I none
                   1291: is the only supported type.
                   1292: .
                   1293: .H 3 "The Client Side"
                   1294: .LP
                   1295: When a caller creates a new RPC client handle as in:
                   1296: .LS
                   1297: clnt = clntudp_create(address, prognum, versnum, wait, sockp)
                   1298: .LE
                   1299: the appropriate transport instance defaults
                   1300: the associate authentication handle to be
                   1301: .LS
                   1302: clnt->cl_auth = authnone_create();
                   1303: .LE
                   1304: The RPC client can choose to use
                   1305: .I unix
                   1306: style authentication by setting
                   1307: .L clnt->cl_auth
                   1308: after creating the RPC client handle:
                   1309: .LS
                   1310: clnt->cl_auth = authunix_create_default();
                   1311: .LE
                   1312: This causes each RPC call associated with
                   1313: .L clnt
                   1314: to carry with it the following authentication credentials structure:
                   1315: .LS
                   1316: /*
                   1317:  * Unix style credentials.
                   1318:  */
                   1319: struct authunix_parms {
                   1320:        u_long  aup_time;       /* credentials creation time */
                   1321:        char    *aup_machname;  /* host name of where the client is calling */
                   1322:        int     aup_uid;        /* client's UNIX effective uid */
                   1323:        int     aup_gid;        /* client's current UNIX group id */
                   1324:        u_int   aup_len;        /* the element length of aup_gids array */
                   1325:        int     *aup_gids;      /* array of 4.2 groups to which user belongs */
                   1326: };
                   1327: .LE
                   1328: These fields are set by
                   1329: .L authunix_create_default()
                   1330: by invoking the appropriate system calls.
                   1331: .LP
                   1332: Since the RPC user created this new style of authentication,
                   1333: he is responsible for destroying it with:
                   1334: .LS
                   1335: auth_destroy(clnt->cl_auth);
                   1336: .LE
                   1337: .
                   1338: .H 3 "The Server Side"
                   1339: .LP
                   1340: Service implementors have a harder time dealing with authentication issues
                   1341: since the RPC package passes the service dispatch routine a request
                   1342: that has an arbitrary authentication style associated with it.
                   1343: Consider the fields of a request handle passed to a service dispatch routine:
                   1344: .LS
                   1345: /*
                   1346:  * An RPC Service request
                   1347:  */
                   1348: struct svc_req {
                   1349:        u_long          rq_prog;        /* service program number */
                   1350:        u_long          rq_vers;        /* service protocol version number*/
                   1351:        u_long          rq_proc;        /* the desired procedure number*/
                   1352:        struct opaque_auth rq_cred;     /* raw credentials from the ``wire'' */
                   1353:        caddr_t         rq_clntcred;    /* read only, cooked credentials */
                   1354: };
                   1355: .LE
                   1356: The
                   1357: .L rq_cred
                   1358: is mostly opaque, except for one field of interest:
                   1359: the style of authentication credentials:
                   1360: .LS
                   1361: /*
                   1362:  * Authentication info.  Mostly opaque to the programmer.
                   1363:  */
                   1364: struct opaque_auth {
                   1365:        enum_t  oa_flavor;      /* style of credentials */
                   1366:        caddr_t oa_base;        /* address of more auth stuff */
                   1367:        u_int   oa_length;      /* not to exceed MAX_AUTH_BYTES */
                   1368: };
                   1369: .LE
                   1370: The RPC package guarantees the following
                   1371: to the service dispatch routine:
                   1372: .IP 1)
                   1373: That the request's
                   1374: .L rq_cred
                   1375: is well formed.  Thus the service implementor may inspect the request's
                   1376: .L rq_cred.oa_flavor
                   1377: to determine which style of authentication the caller used.
                   1378: The service implementor may also wish to inspect the other fields of
                   1379: .L rq_cred
                   1380: if the style is not one of the styles supported by the RPC package.
                   1381: .IP 2)
                   1382: That the request's
                   1383: .L rq_clntcred
                   1384: field is either NULL or points to a well formed structure
                   1385: that corresponds to a supported style of authentication credentials.
                   1386: Remember that only
                   1387: .I unix
                   1388: style is currently supported, so (currently)
                   1389: .L rq_clntcred
                   1390: could be cast to a pointer to an
                   1391: .L authunix_parms
                   1392: structure.  If
                   1393: .L rq_clntcred
                   1394: is NULL, the service implementor may wish to inspect
                   1395: the other (opaque) fileds of
                   1396: .L rq_cred
                   1397: in case the service knows about a new type of authentication
                   1398: that the RPC package does not know about.
                   1399: .LP
                   1400: Our remote users service example can be extended so that
                   1401: it computes results for all users except UID 16:
                   1402: .LS
                   1403: nuser(rqstp, tranp)
                   1404:        struct svc_req *rqstp;
                   1405:        SVCXPRT *transp;
                   1406: {
                   1407:        struct authunix_parms *unix_cred;
                   1408:        int uid;
                   1409:        unsigned long nusers;
                   1410: .sp.5
                   1411:        /*
                   1412:         * we don't care about authentication for the null procedure
                   1413:         */
                   1414:        if (rqstp->rq_proc == NULLPROC) {
                   1415:                if (!svc_sendreply(transp, xdr_void, 0)) {
                   1416:                        fprintf(stderr, "couldn't reply to RPC call\en");
                   1417:                        exit(1);
                   1418:                 }
                   1419:                 return;
                   1420:        }
                   1421:        /*
                   1422:         * now get the uid
                   1423:         */
                   1424:        switch (rqstp->rq_cred.oa_flavor) {
                   1425:        case AUTH_UNIX:
                   1426:                unix_cred = (struct authunix_parms *) rqstp->rq_clntcred;
                   1427:                uid = unix_cred->aup_uid;
                   1428:                break;
                   1429:        case AUTH_NULL:
                   1430:        default:
                   1431:                svcerr_weakauth(transp);
                   1432:                return;
                   1433:        }
                   1434:        switch (rqstp->rq_proc) {
                   1435:        case RUSERSPROC_NUM:
                   1436:                /*
                   1437:                 * make sure the caller is allow to call this procedure.
                   1438:                 */
                   1439:                if (uid == 16) {
                   1440:                        svcerr_systemerr(transp);
                   1441:                        return;
                   1442:                }
                   1443:                /*
                   1444:                 * code here to compute the number of users
                   1445:                 * and put in variable nusers
                   1446:                 */
                   1447:                if (!svc_sendreply(transp, xdr_u_long, &nusers) {
                   1448:                        fprintf(stderr, "couldn't reply to RPC call\en");
                   1449:                        exit(1);
                   1450:                }
                   1451:                return;
                   1452:        default:
                   1453:                svcerr_noproc(transp);
                   1454:                return;
                   1455:        }
                   1456: }
                   1457: .LE
                   1458: A few things should be noted here.
                   1459: First, it is customary not to check the authentication parameters
                   1460: associated with the NULLPROC (procedure number zero).
                   1461: Second, if the authentication parameter's type is not suitable
                   1462: for your service, you should call
                   1463: .L svcerr_weakauth() .
                   1464: And finally, the service protocol itself should return status
                   1465: for access denied; in the case of our example, the protocol
                   1466: does not have such a status, so we call the service primitive
                   1467: .L svcerr_systemerr()
                   1468: instead.
                   1469: .LP
                   1470: The last point underscores the relation between
                   1471: the RPC authentication package and the services;
                   1472: RPC deals only with authentication and not with
                   1473: individual services' access control.
                   1474: The services themselves must implement their own access control policies
                   1475: and reflect these policies as return statuses in their protocols.
                   1476: .
                   1477: .H 2 "Using Inetd"
                   1478: .LP
                   1479: An RPC server can be started from
                   1480: .L inetd .
                   1481: The only difference
                   1482: from the usual code is that
                   1483: .L svcudp_create()
                   1484: should be called as
                   1485: .LS
                   1486: transp = svcudp_create(0);
                   1487: .LE
                   1488: since
                   1489: .L inet
                   1490: passes a socket as file descriptor 0.
                   1491: Also,
                   1492: .L svc_register()
                   1493: should be called as
                   1494: .LS
                   1495: svc_register(PROGNUM, VERSNUM, service, transp, 0);
                   1496: .LE
                   1497: with the final flag as 0,
                   1498: since the program would already be registered by
                   1499: .L inetd .
                   1500: Remember that if you want to exit
                   1501: from the server process and return control to
                   1502: .L inet ,
                   1503: you need to explicitly exit, since
                   1504: .L svc_run()
                   1505: never returns.
                   1506: .LP
                   1507: The format of entries in /etc/servers for RPC services is
                   1508: .LS
                   1509: rpc udp \fIserver \0program \0version\fP
                   1510: .LE
                   1511: where 
                   1512: .I server
                   1513: is the C code implementing the server,
                   1514: and 
                   1515: .I program
                   1516: and
                   1517: .I version
                   1518: are the program and version numbers of the service.
                   1519: The key word 
                   1520: .L udp
                   1521: can be replaced by 
                   1522: .L tcp
                   1523: for TCP-based RPC services.
                   1524: .LP
                   1525: If the same program handles multiple versions,
                   1526: then the version number can be a range,
                   1527: as in this example:
                   1528: .LS
                   1529: rpc udp /usr/etc/rstatd 100001 1-2
                   1530: .LE
                   1531: .bp
                   1532: .
                   1533: .H 1 "More Examples"
                   1534: .H 2 "Versions"
                   1535: .LP
                   1536: By convention, the first version number of program FOO is 
                   1537: FOOVERS_ORIG and the most recent version is FOOVERS.
                   1538: Suppose there is a new version of the 
                   1539: .L user
                   1540: program that returns an
                   1541: .L "unsigned short"
                   1542: rather than a
                   1543: .L long .
                   1544: If we name this version
                   1545: RUSERSVERS_SHORT, then
                   1546: a server that wants to support both versions
                   1547: would do a double register.
                   1548: .LS
                   1549: .sp.5
                   1550: if (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG, nuser,
                   1551:     IPPROTO_TCP)) {
                   1552:        fprintf(stderr, "couldn't register RUSER service\en");
                   1553:        exit(1);
                   1554: }
                   1555: if (!svc_register(transp, RUSERSPROG, RUSERSVERS_SHORT, nuser,
                   1556:     IPPROTO_TCP)) {
                   1557:        fprintf(stderr, "couldn't register RUSER service\en");
                   1558:        exit(1);
                   1559: }
                   1560: .LE
                   1561: .bp
                   1562: Both versions can be handled by the same C procedure:
                   1563: .LS 0
                   1564: nuser(rqstp, tranp)
                   1565:        struct svc_req *rqstp;
                   1566:        SVCXPRT *transp;
                   1567: {
                   1568:        unsigned long nusers;
                   1569:        unsigned short nusers2
                   1570: .sp.5
                   1571:        switch (rqstp->rq_proc) {
                   1572:        case NULLPROC:
                   1573:                if (!svc_sendreply(transp, xdr_void, 0)) {
                   1574:                        fprintf(stderr, "couldn't reply to RPC call\en");
                   1575:                        exit(1);
                   1576:                }
                   1577:                return;
                   1578:        case RUSERSPROC_NUM:
                   1579:                /*
                   1580:                 * code here to compute the number of users
                   1581:                 * and put in variable nusers
                   1582:                 */
                   1583:                nusers2 = nusers;
                   1584:                if (rqstp->rq_vers == RUSERSVERS_ORIG)
                   1585:                        if (!svc_sendreply(transp, xdr_u_long, &nusers) {
                   1586:                                fprintf(stderr, "couldn't reply to RPC call\en");
                   1587:                                exit(1);
                   1588:                        }
                   1589:                else
                   1590:                        if (!svc_sendreply(transp, xdr_u_short, &nusers2) {
                   1591:                                fprintf(stderr, "couldn't reply to RPC call\en");
                   1592:                                exit(1);
                   1593:                return;
                   1594:        default: 
                   1595:                svcerr_noproc(transp);
                   1596:                return;
                   1597:        }
                   1598: }
                   1599: .LE
                   1600: .H 2 "TCP"
                   1601: .LP
                   1602: Here is an example that is essentially  
                   1603: .L rcp .
                   1604: The initiator of the RPC 
                   1605: .L snd()
                   1606: call takes its standard input and sends it to the server 
                   1607: .L rcv() ,
                   1608: which prints it on standard output.
                   1609: The RPC call uses TCP.
                   1610: This also illustrates an XDR procedure that behaves differently
                   1611: on serialization than on deserialization.
                   1612: .LS 0
                   1613: /* 
                   1614:  * The xdr routine:
                   1615:  *
                   1616:  * on decode, read from wire, write onto fp
                   1617:  * on encode, read from fp, write onto wire
                   1618:  */
                   1619: #include <stdio.h>
                   1620: #include <rpc/rpc.h>
                   1621: .sp.5
                   1622: xdr_rcp(xdrs, fp)
                   1623:        XDR *xdrs;
                   1624:        FILE *fp;
                   1625: {
                   1626:        unsigned long size;
                   1627:        char buf[MAXCHUNK], *p;
                   1628: .sp.5
                   1629:        if (xdrs->x_op == XDR_FREE)/* nothing to free */
                   1630:                return 1;
                   1631:        while (1) {
                   1632:                if (xdrs->x_op == XDR_ENCODE) {
                   1633:                        if ((size = fread (buf, sizeof(char), MAXCHUNK, fp))
                   1634:                            == 0 && ferror(fp)) {
                   1635:                                fprintf(stderr, "couldn't fread\en");
                   1636:                                exit(1);
                   1637:                        }
                   1638:                }
                   1639:                p = buf;
                   1640:                if (!xdr_bytes(xdrs, &p, &size, MAXCHUNK))
                   1641:                        return 0;
                   1642:                if (size == 0)
                   1643:                        return 1;
                   1644:                if (xdrs->x_op == XDR_DECODE) {
                   1645:                        if (fwrite(buf, sizeof(char), size, fp) != size) {
                   1646:                                fprintf(stderr, "couldn't fwrite\en");
                   1647:                                exit(1);
                   1648:                        }
                   1649:                }
                   1650:        }
                   1651: }
                   1652: .LE
                   1653: .LS 0
                   1654: /*
                   1655:  * The sender routines
                   1656:  */
                   1657: #include <stdio.h>
                   1658: #include <netdb.h>
                   1659: #include <rpc/rpc.h>
                   1660: #include <sys/socket.h>
                   1661: #include <sys/time.h>
                   1662: .sp.5
                   1663: main(argc, argv)
                   1664:        int argc;
                   1665:        char **argv;
                   1666: {
                   1667:        int err;
                   1668: .sp.5
                   1669:        if (argc < 2) {
                   1670:                fprintf(stderr, "usage: %s server-name\en", argv[0]);
                   1671:                exit(-1);
                   1672:        }
                   1673:        if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC_FP, RCPVERS,
                   1674:            xdr_rcp, stdin, xdr_void, 0) != 0)) {
                   1675:                clnt_perrno(err);
                   1676:                fprintf(stderr, " couldn't make RPC call\en");
                   1677:                exit(1);
                   1678:        }
                   1679: }
                   1680: .sp.5
                   1681: callrpctcp(host, prognum, procnum, versnum, inproc, in, outproc, out)
                   1682:        char *host, *in, *out;
                   1683:        xdrproc_t inproc, outproc;
                   1684: {
                   1685:        struct sockaddr_in server_addr;
                   1686:        int socket = RPC_ANYSOCK;
                   1687:        enum clnt_stat clnt_stat;
                   1688:        struct hostent *hp;
                   1689:        register CLIENT *client;
                   1690:        struct timeval total_timeout;
                   1691: .sp.5
                   1692:        if ((hp = gethostbyname(host)) == NULL) {
                   1693:                fprintf(stderr, "cannot get addr for '%s'\en", host);
                   1694:                exit(-1);
                   1695:        }
                   1696:        bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, hp->h_length);
                   1697:        server_addr.sin_family = AF_INET;
                   1698:        server_addr.sin_port =  0;
                   1699:        if ((client = clnttcp_create(&server_addr, prognum,
                   1700:            versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) {
                   1701:                perror("rpctcp_create");
                   1702:                exit(-1);
                   1703:        }
                   1704:        total_timeout.tv_sec = 20;
                   1705:        total_timeout.tv_usec = 0;
                   1706:        clnt_stat = clnt_call(client, procnum, inproc, in, outproc, out, total_timeout);
                   1707:        clnt_destroy(client)
                   1708:        return (int)clnt_stat;
                   1709: }
                   1710: .LE
                   1711: .LS 0
                   1712: /*
                   1713:  * The receiving routines
                   1714:  */
                   1715: #include <stdio.h>
                   1716: #include <rpc/rpc.h>
                   1717: .sp.5
                   1718: main()
                   1719: {
                   1720:        register SVCXPRT *transp;
                   1721: .sp.5
                   1722:        if ((transp = svctcp_create(RPC_ANYSOCK, 1024, 1024)) == NULL) {
                   1723:                fprintf("svctcp_create: error\en");
                   1724:                exit(1);
                   1725:        }
                   1726:        pmap_unset(RCPPROG, RCPVERS);
                   1727:        if (!svc_register(transp, RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) {
                   1728:                fprintf(stderr, "svc_register: error\en");
                   1729:                exit(1);
                   1730:        }
                   1731:        svc_run();  /* never returns */
                   1732:        fprintf(stderr, "svc_run should never return\en");
                   1733: }
                   1734: .sp.5
                   1735: rcp_service(rqstp, transp)
                   1736:        register struct svc_req *rqstp;
                   1737:        register SVCXPRT *transp;
                   1738: {
                   1739:        switch (rqstp->rq_proc) {
                   1740:        case NULLPROC:
                   1741:                if (svc_sendreply(transp, xdr_void, 0) == 0) {
                   1742:                        fprintf(stderr, "err: rcp_service");
                   1743:                        exit(1);
                   1744:                }
                   1745:                return;
                   1746:        case RCPPROC_FP:
                   1747:                if (!svc_getargs(transp, xdr_rcp, stdout)) {
                   1748:                        svcerr_decode(transp);
                   1749:                        return;
                   1750:                }
                   1751:                if (!svc_sendreply(transp, xdr_void, 0)) {
                   1752:                        fprintf(stderr, "can't reply\en");
                   1753:                        return;
                   1754:                }
                   1755:                exit(0);
                   1756:        default: 
                   1757:                svcerr_noproc(transp);
                   1758:                return;
                   1759:        }
                   1760: }
                   1761: .LE
                   1762: .H 2 "Callback Procedures"
                   1763: .LP
                   1764: Occasionally, it is useful to have a server become a client,
                   1765: and make an RPC call back the process which is its client.
                   1766: An example is remote debugging,
                   1767: where the client is a window system program,
                   1768: and the server is a debugger running on the remote machine.
                   1769: Most of the time,
                   1770: the user clicks a mouse button at the debugging window,
                   1771: which converts this to a debugger command,
                   1772: and then makes an RPC call to the server
                   1773: (where the debugger is actually running),
                   1774: telling it to execute that command.
                   1775: However, when the debugger hits a breakpoint, the roles are reversed,
                   1776: and the debugger wants to make an rpc call to the window program,
                   1777: so that it can inform the user that a breakpoint has been reached.
                   1778: .LP
                   1779: In order to do an RPC callback,
                   1780: you need a program number to make the RPC call on.
                   1781: Since this will be a dynamically generated program number,
                   1782: it should be in the transient range, 0x40000000 - 0x5fffffff.
                   1783: The routine
                   1784: .L gettransient()
                   1785: returns a valid program number in the transient range,
                   1786: and registers it with the portmapper.
                   1787: It only talks to the portmapper running on the same machine as the
                   1788: .L gettransient()
                   1789: routine itself.
                   1790: The call to
                   1791: .L pmap_set()
                   1792: is a test and set operation,
                   1793: in that it indivisibly tests whether a program number
                   1794: has already been registered,
                   1795: and if it has not, then reserves it.
                   1796: On return, the
                   1797: .L sockp
                   1798: argument will contain a socket that can be used
                   1799: as the argument to an
                   1800: .L svcudp_create()
                   1801: or
                   1802: .L svctcp_create()
                   1803: call.
                   1804: .LS
                   1805: #include <stdio.h>
                   1806: #include <rpc/rpc.h>
                   1807: #include <sys/socket.h>
                   1808: .sp.5
                   1809: gettransient(proto, vers, sockp)
                   1810:        int *sockp;
                   1811: {
                   1812:        static int prognum = 0x40000000;
                   1813:        int s, len, socktype;
                   1814:        struct sockaddr_in addr;
                   1815: .sp.5
                   1816:        switch(proto) {
                   1817:                case IPPROTO_UDP:
                   1818:                        socktype = SOCK_DGRAM;
                   1819:                        break;
                   1820:                case IPPROTO_TCP:
                   1821:                        socktype = SOCK_STREAM;
                   1822:                        break;
                   1823:                default:
                   1824:                        fprintf(stderr, "unknown protocol type\en");
                   1825:                        return 0;
                   1826:        }
                   1827:        if (*sockp == RPC_ANYSOCK) {
                   1828:                if ((s = socket(AF_INET, socktype, 0)) < 0) {
                   1829:                        perror("socket");
                   1830:                        return (0);
                   1831:                }
                   1832:                *sockp = s;
                   1833:        }
                   1834:        else
                   1835:                s = *sockp;
                   1836:        addr.sin_addr.s_addr = 0;
                   1837:        addr.sin_family = AF_INET;
                   1838:        addr.sin_port = 0;
                   1839:        len = sizeof(addr);
                   1840:        /*
                   1841:         * may be already bound, so don't check for err
                   1842:         */
                   1843:        bind(s, &addr, len);
                   1844:        if (getsockname(s, &addr, &len)< 0) {
                   1845:                perror("getsockname");
                   1846:                return (0);
                   1847:        }
                   1848:        while (pmap_set(prognum++, vers, proto, addr.sin_port) == 0)
                   1849:                continue;
                   1850:        return (prognum-1);
                   1851: }
                   1852: .LE
                   1853: The following pair of programs illustrate how to use the
                   1854: .L gettransient()
                   1855: routine.
                   1856: The client makes an RPC call to the server,
                   1857: passing it a transient program number.
                   1858: Then the client waits around to receive a callback
                   1859: from the server at that program number.
                   1860: The server registers the program EXAMPELPROG,
                   1861: so that it can receive the RPC call
                   1862: informing it of the callback program number.
                   1863: Then at some random time (on receiving an ALRM signal in this example),
                   1864: it sends a callback RPC call,
                   1865: using the program number it received earlier.
                   1866: .LS
                   1867: /*
                   1868:  * client
                   1869:  */
                   1870: #include <stdio.h>
                   1871: #include <rpc/rpc.h>
                   1872: .sp.5
                   1873: int callback();
                   1874: char hostname[256];
                   1875: .sp.5
                   1876: main(argc, argv)
                   1877:        char **argv;
                   1878: {
                   1879:        int x, ans, s;
                   1880:        SVCXPRT *xprt;
                   1881: .sp.5
                   1882:        gethostname(hostname, sizeof(hostname));
                   1883:        s = RPC_ANYSOCK;
                   1884:        x = gettransient(IPPROTO_UDP, 1, &s);
                   1885:        fprintf(stderr, "client gets prognum %d\en", x);
                   1886: 
                   1887:        if ((xprt = svcudp_create(s)) == NULL) {
                   1888:            fprintf(stderr, "rpc_server: svcudp_create\en");
                   1889:            exit(1);
                   1890:        }
                   1891:        (void)svc_register(xprt, x, 1, callback, 0);
                   1892: 
                   1893:        ans = callrpc(hostname, EXAMPLEPROG, EXAMPLEPROC_CALLBACK,
                   1894:            EXAMPLEVERS, xdr_int, &x, xdr_void, 0);
                   1895:        if (ans != 0) {
                   1896:                fprintf(stderr, "call: ");
                   1897:                clnt_perrno(ans);
                   1898:                fprintf(stderr, "\en");
                   1899:        }
                   1900:        svc_run();
                   1901:        fprintf(stderr, "Error: svc_run shouldn't have returned\en");
                   1902: }
                   1903: .LE
                   1904: .LS
                   1905: callback(rqstp, transp)
                   1906:        register struct svc_req *rqstp;
                   1907:        register SVCXPRT *transp;
                   1908: {
                   1909:        switch (rqstp->rq_proc) {
                   1910:                case 0:
                   1911:                        if (svc_sendreply(transp, xdr_void, 0)  == FALSE) {
                   1912:                                fprintf(stderr, "err: rusersd\en");
                   1913:                                exit(1);
                   1914:                            }
                   1915:                        exit(0);
                   1916:                case 1:
                   1917:                        if (!svc_getargs(transp, xdr_void, 0)) {
                   1918:                                svcerr_decode(transp);
                   1919:                                exit(1);
                   1920:                        }
                   1921:                        fprintf(stderr, "client got callback\en");
                   1922:                        if (svc_sendreply(transp, xdr_void, 0)  == FALSE) {
                   1923:                                fprintf(stderr, "err: rusersd");
                   1924:                                exit(1);
                   1925:                        }
                   1926:        }
                   1927: }
                   1928: .LE
                   1929: .LS
                   1930: /*
                   1931:  * server
                   1932:  */
                   1933: #include <stdio.h>
                   1934: #include <rpc/rpc.h>
                   1935: #include <sys/signal.h>
                   1936: .sp.5
                   1937: char *getnewprog();
                   1938: char hostname[256];
                   1939: int docallback();
                   1940: int pnum;              /*program number for callback routine */ 
                   1941: .sp.5
                   1942: main(argc, argv)
                   1943:        char **argv;
                   1944: {
                   1945:        gethostname(hostname, sizeof(hostname));
                   1946:        registerrpc(EXAMPLEPROG, EXAMPLEPROC_CALLBACK, EXAMPLEVERS,
                   1947:            getnewprog, xdr_int, xdr_void);
                   1948:        fprintf(stderr, "server going into svc_run\en");
                   1949:        alarm(10);
                   1950:        signal(SIGALRM, docallback);
                   1951:        svc_run();
                   1952:        fprintf(stderr, "Error: svc_run shouldn't have returned\en");
                   1953: }
                   1954: .sp.5
                   1955: char *
                   1956: getnewprog(pnump)
                   1957:        char *pnump;
                   1958: {
                   1959:        pnum = *(int *)pnump;
                   1960:        return NULL;
                   1961: }
                   1962: .sp.5
                   1963: docallback()
                   1964: {
                   1965:        int ans;
                   1966: .sp.5
                   1967:        ans = callrpc(hostname, pnum, 1, 1, xdr_void, 0, xdr_void, 0);
                   1968:        if (ans != 0) {
                   1969:                fprintf(stderr, "server: ");
                   1970:                clnt_perrno(ans);
                   1971:                fprintf(stderr, "\en");
                   1972:        }
                   1973: }
                   1974: .LE

unix.superglobalmegacorp.com

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