source: rtems/c/src/librpc/src/rpc/PSD.doc/rpc.prog.ms @ df49c60

4.104.114.84.95
Last change on this file since df49c60 was df49c60, checked in by Joel Sherrill <joel.sherrill@…>, on 06/12/00 at 15:00:15

Merged from 4.5.0-beta3a

  • Property mode set to 100644
File size: 67.2 KB
Line 
1.\"
2.\" Must use -- tbl and pic -- with this one
3.\"
4.\" @(#)rpc.prog.ms     2.3 88/08/11 4.0 RPCSRC
5.de BT
6.if \\n%=1 .tl ''- % -''
7..
8.IX "Network Programming" "" "" "" PAGE MAJOR
9.nr OF 0
10.ND
11.\" prevent excess underlining in nroff
12.if n .fp 2 R
13.OH 'Remote Procedure Call Programming Guide''Page %'
14.EH 'Page %''Remote Procedure Call Programming Guide'
15.SH
16\&Remote Procedure Call Programming Guide
17.nr OF 1
18.IX "RPC Programming Guide"
19.LP
20This document assumes a working knowledge of network theory.  It is
21intended for programmers who wish to write network applications using
22remote procedure calls (explained below), and who want to understand
23the RPC mechanisms usually hidden by the
24.I rpcgen(1)
25protocol compiler.
26.I rpcgen
27is described in detail in the previous chapter, the
28.I "\fBrpcgen\fP \fIProgramming Guide\fP".
29.SH
30Note:
31.I
32.IX rpcgen "" \fIrpcgen\fP
33Before attempting to write a network application, or to convert an
34existing non-network application to run over the network, you may want to
35understand the material in this chapter.  However, for most applications,
36you can circumvent the need to cope with the details presented here by using
37.I rpcgen .
38The
39.I "Generating XDR Routines"
40section of that chapter contains the complete source for a working RPC
41service\(ema remote directory listing service which uses
42.I rpcgen
43to generate XDR routines as well as client and server stubs.
44.LP
45.LP
46What are remote procedure calls?  Simply put, they are the high-level
47communications paradigm used in the operating system.
48RPC presumes the existence of
49low-level networking mechanisms (such as TCP/IP and UDP/IP), and upon them
50it implements a logical client to server communications system designed
51specifically for the support of network applications.  With RPC, the client
52makes a procedure call to send a data packet to the server.  When the
53packet arrives, the server calls a dispatch routine, performs whatever
54service is requested, sends back the reply, and the procedure call returns
55to the client.
56.NH 0
57\&Layers of RPC
58.IX "layers of RPC"
59.IX "RPC" "layers"
60.LP
61The RPC interface can be seen as being divided into three layers.\**
62.FS
63For a complete specification of the routines in the remote procedure
64call Library, see the
65.I rpc(3N)
66manual page.
67.FE
68.LP
69.I "The Highest Layer:"
70.IX RPC "The Highest Layer"
71The highest layer is totally transparent to the operating system,
72machine and network upon which is is run.  It's probably best to
73think of this level as a way of
74.I using
75RPC, rather than as
76a \fIpart of\fP RPC proper.  Programmers who write RPC routines
77should (almost) always make this layer available to others by way
78of a simple C front end that entirely hides the networking.
79.LP
80To illustrate, at this level a program can simply make a call to
81.I rnusers (),
82a C routine which returns the number of users on a remote machine.
83The user is not explicitly aware of using RPC \(em they simply
84call a procedure, just as they would call
85.I malloc() .
86.LP
87.I "The Middle Layer:"
88.IX RPC "The Middle Layer"
89The middle layer is really \*QRPC proper.\*U  Here, the user doesn't
90need to consider details about sockets, the UNIX system, or other low-level
91implementation mechanisms.  They simply make remote procedure calls
92to routines on other machines.  The selling point here is simplicity. 
93It's this layer that allows RPC to pass the \*Qhello world\*U test \(em
94simple things should be simple.  The middle-layer routines are used
95for most applications.
96.LP
97RPC calls are made with the system routines
98.I registerrpc()
99.I callrpc()
100and
101.I svc_run ().
102The first two of these are the most fundamental:
103.I registerrpc()
104obtains a unique system-wide procedure-identification number, and
105.I callrpc()
106actually executes a remote procedure call.  At the middle level, a
107call to
108.I rnusers()
109is implemented by way of these two routines.
110.LP
111The middle layer is unfortunately rarely used in serious programming
112due to its inflexibility (simplicity).  It does not allow timeout
113specifications or the choice of transport.  It allows no UNIX
114process control or flexibility in case of errors.  It doesn't support
115multiple kinds of call authentication.  The programmer rarely needs
116all these kinds of control, but one or two of them is often necessary.
117.LP
118.I "The Lowest Layer:"
119.IX RPC "The Lowest Layer"
120The lowest layer does allow these details to be controlled by the
121programmer, and for that reason it is often necessary.  Programs
122written at this level are also most efficient, but this is rarely a
123real issue \(em since RPC clients and servers rarely generate
124heavy network loads.
125.LP
126Although this document only discusses the interface to C,
127remote procedure calls can be made from any language.
128Even though this document discusses RPC
129when it is used to communicate
130between processes on different machines,
131it works just as well for communication
132between different processes on the same machine.
133.br
134.KS
135.NH 2
136\&The RPC Paradigm
137.IX RPC paradigm
138.LP
139Here is a diagram of the RPC paradigm:
140.LP
141\fBFigure 1-1\fI Network Communication with the Remote Reocedure Call\fR
142.LP
143.PS
144L1: arrow down 1i "client " rjust "program " rjust
145L2: line right 1.5i "\fIcallrpc\fP" "function"
146move up 1.5i; line dotted down 6i; move up 4.5i
147arrow right 1i
148L3: arrow down 1i "invoke " rjust "service " rjust
149L4: arrow right 1.5i "call" "service"
150L5: arrow down 1i " service" ljust " executes" ljust
151L6: arrow left 1.5i "\fIreturn\fP" "answer"
152L7: arrow down 1i "request " rjust "completed " rjust
153L8: line left 1i
154arrow left 1.5i "\fIreturn\fP" "reply"
155L9: arrow down 1i "program " rjust "continues " rjust
156line dashed down from L2 to L9
157line dashed down from L4 to L7
158line dashed up 1i from L3 "service " rjust "daemon " rjust
159arrow dashed down 1i from L8
160move right 1i from L3
161box invis "Machine B"
162move left 1.2i from L2; move down
163box invis "Machine A"
164.PE
165.KE
166.KS
167.NH 1
168\&Higher Layers of RPC
169.NH 2
170\&Highest Layer
171.IX "highest layer of RPC"
172.IX RPC "highest layer"
173.LP
174Imagine you're writing a program that needs to know
175how many users are logged into a remote machine.
176You can do this by calling the RPC library routine
177.I rnusers()
178as illustrated below:
179.ie t .DS
180.el .DS L
181.ft CW
182#include <stdio.h>
183
184main(argc, argv)
185        int argc;
186        char **argv;
187{
188        int num;
189
190        if (argc != 2) {
191                fprintf(stderr, "usage: rnusers hostname\en");
192                exit(1);
193        }
194        if ((num = rnusers(argv[1])) < 0) {
195                fprintf(stderr, "error: rnusers\en");
196                exit(-1);
197        }
198        printf("%d users on %s\en", num, argv[1]);
199        exit(0);
200}
201.DE
202.KE
203RPC library routines such as
204.I rnusers()
205are in the RPC services library
206.I librpcsvc.a
207Thus, the program above should be compiled with
208.DS
209.ft CW
210% cc \fIprogram.c -lrpcsvc\fP
211.DE
212.I rnusers (),
213like the other RPC library routines, is documented in section 3R
214of the
215.I "System Interface Manual for the Sun Workstation" ,
216the same section which documents the standard Sun RPC services. 
217.IX "RPC Services"
218See the
219.I intro(3R)
220manual page for an explanation of the documentation strategy
221for these services and their RPC protocols.
222.LP
223Here are some of the RPC service library routines available to the
224C programmer:
225.LP
226\fBTable 3-3\fI RPC Service Library Routines\RP
227.TS
228box tab (&) ;
229cfI cfI
230lfL l .
231Routine&Description
232_
233.sp.5
234rnusers&Return number of users on remote machine
235rusers&Return information about users on remote machine
236havedisk&Determine if remote machine has disk
237rstats&Get performance data from remote kernel
238rwall&Write to specified remote machines
239yppasswd&Update user password in Yellow Pages
240.TE
241.LP
242Other RPC services \(em for example
243.I ether()
244.I mount
245.I rquota()
246and
247.I spray
248\(em are not available to the C programmer as library routines.
249They do, however,
250have RPC program numbers so they can be invoked with
251.I callrpc()
252which will be discussed in the next section.  Most of them also
253have compilable
254.I rpcgen(1)
255protocol description files.  (The
256.I rpcgen
257protocol compiler radically simplifies the process of developing
258network applications. 
259See the \fBrpcgen\fI Programming Guide\fR
260for detailed information about
261.I rpcgen
262and
263.I rpcgen
264protocol description files).
265.KS
266.NH 2
267\&Intermediate Layer
268.IX "intermediate layer of RPC"
269.IX "RPC" "intermediate layer"
270.LP
271The simplest interface, which explicitly makes RPC calls, uses the
272functions
273.I callrpc()
274and
275.I registerrpc()
276Using this method, the number of remote users can be gotten as follows:
277.ie t .DS
278.el .DS L
279#include <stdio.h>
280#include <rpc/rpc.h>
281#include <utmp.h>
282#include <rpcsvc/rusers.h>
283
284main(argc, argv)
285        int argc;
286        char **argv;
287{
288        unsigned long nusers;
289        int stat;
290
291        if (argc != 2) {
292                fprintf(stderr, "usage: nusers hostname\en");
293                exit(-1);
294        }
295        if (stat = callrpc(argv[1],
296          RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
297          xdr_void, 0, xdr_u_long, &nusers) != 0) {
298                clnt_perrno(stat);
299                exit(1);
300        }
301        printf("%d users on %s\en", nusers, argv[1]);
302        exit(0);
303}
304.DE
305.KE
306Each RPC procedure is uniquely defined by a program number,
307version number, and procedure number.  The program number
308specifies a group of related remote procedures, each of
309which has a different procedure number.  Each program also
310has a version number, so when a minor change is made to a
311remote service (adding a new procedure, for example), a new
312program number doesn't have to be assigned.  When you want
313to call a procedure to find the number of remote users, you
314look up the appropriate program, version and procedure numbers
315in a manual, just as you look up the name of a memory allocator
316when you want to allocate memory.
317.LP
318The simplest way of making remote procedure calls is with the the RPC
319library routine
320.I callrpc()
321It has eight parameters.  The first is the name of the remote server
322machine.  The next three parameters are the program, version, and procedure
323numbers\(emtogether they identify the procedure to be called.
324The fifth and sixth parameters are an XDR filter and an argument to
325be encoded and passed to the remote procedure. 
326The final two parameters are a filter for decoding the results
327returned by the remote procedure and a pointer to the place where
328the procedure's results are to be stored.  Multiple arguments and
329results are handled by embedding them in structures.  If
330.I callrpc()
331completes successfully, it returns zero; else it returns a nonzero
332value.  The return codes (of type
333.IX "enum clnt_stat (in RPC programming)" "" "\fIenum clnt_stat\fP (in RPC programming)"
334cast into an integer) are found in
335.I <rpc/clnt.h> .
336.LP
337Since data types may be represented differently on different machines,
338.I callrpc()
339needs both the type of the RPC argument, as well as
340a pointer to the argument itself (and similarly for the result).  For
341.I RUSERSPROC_NUM ,
342the return value is an
343.I "unsigned long"
344so
345.I callrpc()
346has
347.I xdr_u_long()
348as its first return parameter, which says
349that the result is of type
350.I "unsigned long"
351and
352.I &nusers
353as its second return parameter,
354which is a pointer to where the long result will be placed.  Since
355.I RUSERSPROC_NUM
356takes no argument, the argument parameter of
357.I callrpc()
358is
359.I xdr_void ().
360.LP
361After trying several times to deliver a message, if
362.I callrpc()
363gets no answer, it returns with an error code.
364The delivery mechanism is UDP,
365which stands for User Datagram Protocol.
366Methods for adjusting the number of retries
367or for using a different protocol require you to use the lower
368layer of the RPC library, discussed later in this document.
369The remote server procedure
370corresponding to the above might look like this:
371.ie t .DS
372.el .DS L
373.ft CW
374.ft CW
375char *
376nuser(indata)
377        char *indata;
378{
379        unsigned long nusers;
380
381.ft I
382        /*
383         * Code here to compute the number of users
384         * and place result in variable \fInusers\fP.
385         */
386.ft CW
387        return((char *)&nusers);
388}
389.DE
390.LP
391It takes one argument, which is a pointer to the input
392of the remote procedure call (ignored in our example),
393and it returns a pointer to the result.
394In the current version of C,
395character pointers are the generic pointers,
396so both the input argument and the return value are cast to
397.I "char *" .
398.LP
399Normally, a server registers all of the RPC calls it plans
400to handle, and then goes into an infinite loop waiting to service requests.
401In this example, there is only a single procedure
402to register, so the main body of the server would look like this:
403.ie t .DS
404.el .DS L
405.ft CW
406#include <stdio.h>
407#include <rpc/rpc.h>
408#include <utmp.h>
409#include <rpcsvc/rusers.h>
410
411char *nuser();
412
413main()
414{
415        registerrpc(RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
416                nuser, xdr_void, xdr_u_long);
417        svc_run();              /* \fINever returns\fP */
418        fprintf(stderr, "Error: svc_run returned!\en");
419        exit(1);
420}
421.DE
422.LP
423The
424.I registerrpc()
425routine registers a C procedure as corresponding to a
426given RPC procedure number.  The first three parameters,
427.I RUSERPROG ,
428.I RUSERSVERS ,
429and
430.I RUSERSPROC_NUM
431are the program, version, and procedure numbers
432of the remote procedure to be registered;
433.I nuser()
434is the name of the local procedure that implements the remote
435procedure; and
436.I xdr_void()
437and
438.I xdr_u_long()
439are the XDR filters for the remote procedure's arguments and
440results, respectively.  (Multiple arguments or multiple results
441are passed as structures).
442.LP
443Only the UDP transport mechanism can use
444.I registerrpc()
445thus, it is always safe in conjunction with calls generated by
446.I callrpc() .
447.SH
448.IX "UDP 8K warning"
449Warning: the UDP transport mechanism can only deal with
450arguments and results less than 8K bytes in length.
451.LP
452.LP
453After registering the local procedure, the server program's
454main procedure calls
455.I svc_run (),
456the RPC library's remote procedure dispatcher.  It is this
457function that calls the remote procedures in response to RPC
458call messages.  Note that the dispatcher takes care of decoding
459remote procedure arguments and encoding results, using the XDR
460filters specified when the remote procedure was registered.
461.NH 2
462\&Assigning Program Numbers
463.IX "program number assignment"
464.IX "assigning program numbers"
465.LP
466Program numbers are assigned in groups of
467.I 0x20000000
468according to the following chart:
469.DS
470.ft CW
471       0x0 - 0x1fffffff \fRDefined by Sun\fP
4720x20000000 - 0x3fffffff \fRDefined by user\fP
4730x40000000 - 0x5fffffff \fRTransient\fP
4740x60000000 - 0x7fffffff \fRReserved\fP
4750x80000000 - 0x9fffffff \fRReserved\fP
4760xa0000000 - 0xbfffffff \fRReserved\fP
4770xc0000000 - 0xdfffffff \fRReserved\fP
4780xe0000000 - 0xffffffff \fRReserved\fP
479.ft R
480.DE
481Sun Microsystems administers the first group of numbers, which
482should be identical for all Sun customers.  If a customer
483develops an application that might be of general interest, that
484application should be given an assigned number in the first
485range.  The second group of numbers is reserved for specific
486customer applications.  This range is intended primarily for
487debugging new programs.  The third group is reserved for
488applications that generate program numbers dynamically.  The
489final groups are reserved for future use, and should not be
490used.
491.LP
492To register a protocol specification, send a request by network
493mail to
494.I rpc@sun
495or write to:
496.DS
497RPC Administrator
498Sun Microsystems
4992550 Garcia Ave.
500Mountain View, CA 94043
501.DE
502Please include a compilable
503.I rpcgen
504\*Q.x\*U file describing your protocol.
505You will be given a unique program number in return.
506.IX RPC administration
507.IX administration "of RPC"
508.LP
509The RPC program numbers and protocol specifications
510of standard Sun RPC services can be
511found in the include files in
512.I "/usr/include/rpcsvc" .
513These services, however, constitute only a small subset
514of those which have been registered.  The complete list of
515registered programs, as of the time when this manual was
516printed, is:
517.LP
518\fBTable 3-2\fI RPC Registered Programs\fR
519.TS H
520box tab (&) ;
521lfBI lfBI lfBI
522lfL lfL lfI .
523RPC Number&Program&Description
524_
525.TH
526.sp.5
527100000&PMAPPROG&portmapper
528100001&RSTATPROG&remote stats           
529100002&RUSERSPROG&remote users           
530100003&NFSPROG&nfs                     
531100004&YPPROG&Yellow Pages           
532100005&MOUNTPROG&mount demon             
533100006&DBXPROG&remote dbx             
534100007&YPBINDPROG&yp binder               
535100008&WALLPROG&shutdown msg           
536100009&YPPASSWDPROG&yppasswd server         
537100010&ETHERSTATPROG&ether stats             
538100011&RQUOTAPROG&disk quotas             
539100012&SPRAYPROG&spray packets           
540100013&IBM3270PROG&3270 mapper             
541100014&IBMRJEPROG&RJE mapper             
542100015&SELNSVCPROG&selection service       
543100016&RDATABASEPROG&remote database access 
544100017&REXECPROG&remote execution       
545100018&ALICEPROG&Alice Office Automation
546100019&SCHEDPROG&scheduling service     
547100020&LOCKPROG&local lock manager     
548100021&NETLOCKPROG&network lock manager   
549100022&X25PROG&x.25 inr protocol       
550100023&STATMON1PROG&status monitor 1       
551100024&STATMON2PROG&status monitor 2       
552100025&SELNLIBPROG&selection library       
553100026&BOOTPARAMPROG&boot parameters service
554100027&MAZEPROG&mazewars game           
555100028&YPUPDATEPROG&yp update               
556100029&KEYSERVEPROG&key server             
557100030&SECURECMDPROG&secure login           
558100031&NETFWDIPROG&nfs net forwarder init       
559100032&NETFWDTPROG&nfs net forwarder trans     
560100033&SUNLINKMAP_PROG&sunlink MAP             
561100034&NETMONPROG&network monitor               
562100035&DBASEPROG&lightweight database   
563100036&PWDAUTHPROG&password authorization       
564100037&TFSPROG&translucent file svc     
565100038&NSEPROG&nse server               
566100039&NSE_ACTIVATE_PROG&nse activate daemon   
567.sp .2i
568150001&PCNFSDPROG&pc passwd authorization
569.sp .2i
570200000&PYRAMIDLOCKINGPROG&Pyramid-locking         
571200001&PYRAMIDSYS5&Pyramid-sys5           
572200002&CADDS_IMAGE&CV cadds_image               
573.sp .2i
574300001&ADT_RFLOCKPROG&ADT file locking 
575.TE
576.NH 2
577\&Passing Arbitrary Data Types
578.IX "arbitrary data types"
579.LP
580In the previous example, the RPC call passes a single
581.I "unsigned long"
582RPC can handle arbitrary data structures, regardless of
583different machines' byte orders or structure layout conventions,
584by always converting them to a network standard called
585.I "External Data Representation"
586(XDR) before
587sending them over the wire.
588The process of converting from a particular machine representation
589to XDR format is called
590.I serializing ,
591and the reverse process is called
592.I deserializing .
593The type field parameters of
594.I callrpc()
595and
596.I registerrpc()
597can be a built-in procedure like
598.I xdr_u_long()
599in the previous example, or a user supplied one.
600XDR has these built-in type routines:
601.IX RPC "built-in routines"
602.DS
603.ft CW
604xdr_int()      xdr_u_int()      xdr_enum()
605xdr_long()     xdr_u_long()     xdr_bool()
606xdr_short()    xdr_u_short()    xdr_wrapstring()
607xdr_char()     xdr_u_char()
608.DE
609Note that the routine
610.I xdr_string()
611exists, but cannot be used with
612.I callrpc()
613and
614.I registerrpc (),
615which only pass two parameters to their XDR routines.
616.I xdr_wrapstring()
617has only two parameters, and is thus OK.  It calls
618.I xdr_string ().
619.LP
620As an example of a user-defined type routine,
621if you wanted to send the structure
622.DS
623.ft CW
624struct simple {
625        int a;
626        short b;
627} simple;
628.DE
629then you would call
630.I callrpc()
631as
632.DS
633.ft CW
634callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
635        xdr_simple, &simple ...);
636.DE
637where
638.I xdr_simple()
639is written as:
640.ie t .DS
641.el .DS L
642.ft CW
643#include <rpc/rpc.h>
644
645xdr_simple(xdrsp, simplep)
646        XDR *xdrsp;
647        struct simple *simplep;
648{
649        if (!xdr_int(xdrsp, &simplep->a))
650                return (0);
651        if (!xdr_short(xdrsp, &simplep->b))
652                return (0);
653        return (1);
654}
655.DE
656.LP
657An XDR routine returns nonzero (true in the sense of C) if it
658completes successfully, and zero otherwise.
659A complete description of XDR is in the
660.I "XDR Protocol Specification"
661section of this manual, only few implementation examples are
662given here.
663.LP
664In addition to the built-in primitives,
665there are also the prefabricated building blocks:
666.DS
667.ft CW
668xdr_array()       xdr_bytes()     xdr_reference()
669xdr_vector()      xdr_union()     xdr_pointer()
670xdr_string()      xdr_opaque()
671.DE
672To send a variable array of integers,
673you might package them up as a structure like this
674.DS
675.ft CW
676struct varintarr {
677        int *data;
678        int arrlnth;
679} arr;
680.DE
681and make an RPC call such as
682.DS
683.ft CW
684callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
685        xdr_varintarr, &arr...);
686.DE
687with
688.I xdr_varintarr()
689defined as:
690.ie t .DS
691.el .DS L
692.ft CW
693xdr_varintarr(xdrsp, arrp)
694        XDR *xdrsp;
695        struct varintarr *arrp;
696{
697        return (xdr_array(xdrsp, &arrp->data, &arrp->arrlnth,
698                MAXLEN, sizeof(int), xdr_int));
699}
700.DE
701This routine takes as parameters the XDR handle,
702a pointer to the array, a pointer to the size of the array,
703the maximum allowable array size,
704the size of each array element,
705and an XDR routine for handling each array element.
706.KS
707.LP
708If the size of the array is known in advance, one can use
709.I xdr_vector (),
710which serializes fixed-length arrays.
711.ie t .DS
712.el .DS L
713.ft CW
714int intarr[SIZE];
715
716xdr_intarr(xdrsp, intarr)
717        XDR *xdrsp;
718        int intarr[];
719{
720        int i;
721
722        return (xdr_vector(xdrsp, intarr, SIZE, sizeof(int),
723                xdr_int));
724}
725.DE
726.KE
727.LP
728XDR always converts quantities to 4-byte multiples when serializing.
729Thus, if either of the examples above involved characters
730instead of integers, each character would occupy 32 bits.
731That is the reason for the XDR routine
732.I xdr_bytes()
733which is like
734.I xdr_array()
735except that it packs characters;
736.I xdr_bytes()
737has four parameters, similar to the first four parameters of
738.I xdr_array ().
739For null-terminated strings, there is also the
740.I xdr_string()
741routine, which is the same as
742.I xdr_bytes()
743without the length parameter.
744On serializing it gets the string length from
745.I strlen (),
746and on deserializing it creates a null-terminated string.
747.LP
748Here is a final example that calls the previously written
749.I xdr_simple()
750as well as the built-in functions
751.I xdr_string()
752and
753.I xdr_reference (),
754which chases pointers:
755.ie t .DS
756.el .DS L
757.ft CW
758struct finalexample {
759        char *string;
760        struct simple *simplep;
761} finalexample;
762
763xdr_finalexample(xdrsp, finalp)
764        XDR *xdrsp;
765        struct finalexample *finalp;
766{
767
768        if (!xdr_string(xdrsp, &finalp->string, MAXSTRLEN))
769                return (0);
770        if (!xdr_reference(xdrsp, &finalp->simplep,
771          sizeof(struct simple), xdr_simple);
772                return (0);
773        return (1);
774}
775.DE
776Note that we could as easily call
777.I xdr_simple()
778here instead of
779.I xdr_reference ().
780.NH 1
781\&Lowest Layer of RPC
782.IX "lowest layer of RPC"
783.IX "RPC" "lowest layer"
784.LP
785In the examples given so far,
786RPC takes care of many details automatically for you.
787In this section, we'll show you how you can change the defaults
788by using lower layers of the RPC library.
789It is assumed that you are familiar with sockets
790and the system calls for dealing with them.
791.LP
792There are several occasions when you may need to use lower layers of
793RPC.  First, you may need to use TCP, since the higher layer uses UDP,
794which restricts RPC calls to 8K bytes of data.  Using TCP permits calls
795to send long streams of data. 
796For an example, see the
797.I TCP
798section below.  Second, you may want to allocate and free memory
799while serializing or deserializing with XDR routines. 
800There is no call at the higher level to let
801you free memory explicitly. 
802For more explanation, see the
803.I "Memory Allocation with XDR"
804section below. 
805Third, you may need to perform authentication
806on either the client or server side, by supplying
807credentials or verifying them.
808See the explanation in the
809.I Authentication
810section below.
811.NH 2
812\&More on the Server Side
813.IX RPC "server side"
814.LP
815The server for the
816.I nusers()
817program shown below does the same thing as the one using
818.I registerrpc()
819above, but is written using a lower layer of the RPC package:
820.ie t .DS
821.el .DS L
822.ft CW
823#include <stdio.h>
824#include <rpc/rpc.h>
825#include <utmp.h>
826#include <rpcsvc/rusers.h>
827
828main()
829{
830        SVCXPRT *transp;
831        int nuser();
832
833        transp = svcudp_create(RPC_ANYSOCK);
834        if (transp == NULL){
835                fprintf(stderr, "can't create an RPC server\en");
836                exit(1);
837        }
838        pmap_unset(RUSERSPROG, RUSERSVERS);
839        if (!svc_register(transp, RUSERSPROG, RUSERSVERS,
840                          nuser, IPPROTO_UDP)) {
841                fprintf(stderr, "can't register RUSER service\en");
842                exit(1);
843        }
844        svc_run();  /* \fINever returns\fP */
845        fprintf(stderr, "should never reach this point\en");
846}
847
848nuser(rqstp, transp)
849        struct svc_req *rqstp;
850        SVCXPRT *transp;
851{
852        unsigned long nusers;
853
854        switch (rqstp->rq_proc) {
855        case NULLPROC:
856                if (!svc_sendreply(transp, xdr_void, 0))
857                        fprintf(stderr, "can't reply to RPC call\en");
858                return;
859        case RUSERSPROC_NUM:
860.ft I
861                /*
862                 * Code here to compute the number of users
863                 * and assign it to the variable \fInusers\fP
864                 */
865.ft CW
866                if (!svc_sendreply(transp, xdr_u_long, &nusers))
867                        fprintf(stderr, "can't reply to RPC call\en");
868                return;
869        default:
870                svcerr_noproc(transp);
871                return;
872        }
873}
874.DE
875.LP
876First, the server gets a transport handle, which is used
877for receiving and replying to RPC messages.
878.I registerrpc()
879uses
880.I svcudp_create()
881to get a UDP handle.
882If you require a more reliable protocol, call
883.I svctcp_create()
884instead.
885If the argument to
886.I svcudp_create()
887is
888.I RPC_ANYSOCK
889the RPC library creates a socket
890on which to receive and reply to RPC calls.  Otherwise,
891.I svcudp_create()
892expects its argument to be a valid socket number.
893If you specify your own socket, it can be bound or unbound.
894If it is bound to a port by the user, the port numbers of
895.I svcudp_create()
896and
897.I clnttcp_create()
898(the low-level client routine) must match.
899.LP
900If the user specifies the
901.I RPC_ANYSOCK
902argument, the RPC library routines will open sockets.
903Otherwise they will expect the user to do so.  The routines
904.I svcudp_create()
905and
906.I clntudp_create()
907will cause the RPC library routines to
908.I bind()
909their socket if it is not bound already.
910.LP
911A service may choose to register its port number with the
912local portmapper service.  This is done is done by specifying
913a non-zero protocol number in
914.I svc_register ().
915Incidently, a client can discover the server's port number by
916consulting the portmapper on their server's machine.  This can
917be done automatically by specifying a zero port number in
918.I clntudp_create()
919or
920.I clnttcp_create ().
921.LP
922After creating an
923.I SVCXPRT ,
924the next step is to call
925.I pmap_unset()
926so that if the
927.I nusers()
928server crashed earlier,
929any previous trace of it is erased before restarting.
930More precisely,
931.I pmap_unset()
932erases the entry for
933.I RUSERSPROG
934from the port mapper's tables.
935.LP
936Finally, we associate the program number for
937.I nusers()
938with the procedure
939.I nuser ().
940The final argument to
941.I svc_register()
942is normally the protocol being used,
943which, in this case, is
944.I IPPROTO_UDP
945Notice that unlike
946.I registerrpc (),
947there are no XDR routines involved
948in the registration process.
949Also, registration is done on the program,
950rather than procedure, level.
951.LP
952The user routine
953.I nuser()
954must call and dispatch the appropriate XDR routines
955based on the procedure number.
956Note that
957two things are handled by
958.I nuser()
959that
960.I registerrpc()
961handles automatically.
962The first is that procedure
963.I NULLPROC
964(currently zero) returns with no results.
965This can be used as a simple test
966for detecting if a remote program is running.
967Second, there is a check for invalid procedure numbers.
968If one is detected,
969.I svcerr_noproc()
970is called to handle the error.
971.KS
972.LP
973The user service routine serializes the results and returns
974them to the RPC caller via
975.I svc_sendreply()
976Its first parameter is the
977.I SVCXPRT
978handle, the second is the XDR routine,
979and the third is a pointer to the data to be returned.
980Not illustrated above is how a server
981handles an RPC program that receives data.
982As an example, we can add a procedure
983.I RUSERSPROC_BOOL
984which has an argument
985.I nusers (),
986and returns
987.I TRUE
988or
989.I FALSE
990depending on whether there are nusers logged on.
991It would look like this:
992.ie t .DS
993.el .DS L
994.ft CW
995case RUSERSPROC_BOOL: {
996        int bool;
997        unsigned nuserquery;
998
999        if (!svc_getargs(transp, xdr_u_int, &nuserquery) {
1000                svcerr_decode(transp);
1001                return;
1002        }
1003.ft I
1004        /*
1005         * Code to set \fInusers\fP = number of users
1006         */
1007.ft CW
1008        if (nuserquery == nusers)
1009                bool = TRUE;
1010        else
1011                bool = FALSE;
1012        if (!svc_sendreply(transp, xdr_bool, &bool)) {
1013                 fprintf(stderr, "can't reply to RPC call\en");
1014                 return (1);
1015        }
1016        return;
1017}
1018.DE
1019.KE
1020.LP
1021The relevant routine is
1022.I svc_getargs()
1023which takes an
1024.I SVCXPRT
1025handle, the XDR routine,
1026and a pointer to where the input is to be placed as arguments.
1027.NH 2
1028\&Memory Allocation with XDR
1029.IX "memory allocation with XDR"
1030.IX XDR "memory allocation"
1031.LP
1032XDR routines not only do input and output,
1033they also do memory allocation.
1034This is why the second parameter of
1035.I xdr_array()
1036is a pointer to an array, rather than the array itself.
1037If it is
1038.I NULL ,
1039then
1040.I xdr_array()
1041allocates space for the array and returns a pointer to it,
1042putting the size of the array in the third argument.
1043As an example, consider the following XDR routine
1044.I xdr_chararr1()
1045which deals with a fixed array of bytes with length
1046.I SIZE .
1047.ie t .DS
1048.el .DS L
1049.ft CW
1050xdr_chararr1(xdrsp, chararr)
1051        XDR *xdrsp;
1052        char chararr[];
1053{
1054        char *p;
1055        int len;
1056
1057        p = chararr;
1058        len = SIZE;
1059        return (xdr_bytes(xdrsp, &p, &len, SIZE));
1060}
1061.DE
1062If space has already been allocated in
1063.I chararr ,
1064it can be called from a server like this:
1065.ie t .DS
1066.el .DS L
1067.ft CW
1068char chararr[SIZE];
1069
1070svc_getargs(transp, xdr_chararr1, chararr);
1071.DE
1072If you want XDR to do the allocation,
1073you would have to rewrite this routine in the following way:
1074.ie t .DS
1075.el .DS L
1076.ft CW
1077xdr_chararr2(xdrsp, chararrp)
1078        XDR *xdrsp;
1079        char **chararrp;
1080{
1081        int len;
1082
1083        len = SIZE;
1084        return (xdr_bytes(xdrsp, charrarrp, &len, SIZE));
1085}
1086.DE
1087Then the RPC call might look like this:
1088.ie t .DS
1089.el .DS L
1090.ft CW
1091char *arrptr;
1092
1093arrptr = NULL;
1094svc_getargs(transp, xdr_chararr2, &arrptr);
1095.ft I
1096/*
1097 * Use the result here
1098 */
1099.ft CW
1100svc_freeargs(transp, xdr_chararr2, &arrptr);
1101.DE
1102Note that, after being used, the character array can be freed with
1103.I svc_freeargs()
1104.I svc_freeargs()
1105will not attempt to free any memory if the variable indicating it
1106is NULL.  For example, in the the routine
1107.I xdr_finalexample (),
1108given earlier, if
1109.I finalp->string
1110was NULL, then it would not be freed.  The same is true for
1111.I finalp->simplep .
1112.LP
1113To summarize, each XDR routine is responsible
1114for serializing, deserializing, and freeing memory.
1115When an XDR routine is called from
1116.I callrpc()
1117the serializing part is used.
1118When called from
1119.I svc_getargs()
1120the deserializer is used.
1121And when called from
1122.I svc_freeargs()
1123the memory deallocator is used.  When building simple examples like those
1124in this section, a user doesn't have to worry
1125about the three modes. 
1126See the
1127.I "External Data Representation: Sun Technical Notes"
1128for examples of more sophisticated XDR routines that determine
1129which of the three modes they are in and adjust their behavior accordingly.
1130.KS
1131.NH 2
1132\&The Calling Side
1133.IX RPC "calling side"
1134.LP
1135When you use
1136.I callrpc()
1137you have no control over the RPC delivery
1138mechanism or the socket used to transport the data.
1139To illustrate the layer of RPC that lets you adjust these
1140parameters, consider the following code to call the
1141.I nusers
1142service:
1143.ie t .DS
1144.el .DS L
1145.ft CW
1146.vs 11
1147#include <stdio.h>
1148#include <rpc/rpc.h>
1149#include <utmp.h>
1150#include <rpcsvc/rusers.h>
1151#include <sys/socket.h>
1152#include <sys/time.h>
1153#include <netdb.h>
1154
1155main(argc, argv)
1156        int argc;
1157        char **argv;
1158{
1159        struct hostent *hp;
1160        struct timeval pertry_timeout, total_timeout;
1161        struct sockaddr_in server_addr;
1162        int sock = RPC_ANYSOCK;
1163        register CLIENT *client;
1164        enum clnt_stat clnt_stat;
1165        unsigned long nusers;
1166
1167        if (argc != 2) {
1168                fprintf(stderr, "usage: nusers hostname\en");
1169                exit(-1);
1170        }
1171        if ((hp = gethostbyname(argv[1])) == NULL) {
1172                fprintf(stderr, "can't get addr for %s\en",argv[1]);
1173                exit(-1);
1174        }
1175        pertry_timeout.tv_sec = 3;
1176        pertry_timeout.tv_usec = 0;
1177        bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
1178                hp->h_length);
1179        server_addr.sin_family = AF_INET;
1180        server_addr.sin_port =  0;
1181        if ((client = clntudp_create(&server_addr, RUSERSPROG,
1182          RUSERSVERS, pertry_timeout, &sock)) == NULL) {
1183                clnt_pcreateerror("clntudp_create");
1184                exit(-1);
1185        }
1186        total_timeout.tv_sec = 20;
1187        total_timeout.tv_usec = 0;
1188        clnt_stat = clnt_call(client, RUSERSPROC_NUM, xdr_void,
1189                0, xdr_u_long, &nusers, total_timeout);
1190        if (clnt_stat != RPC_SUCCESS) {
1191                clnt_perror(client, "rpc");
1192                exit(-1);
1193        }
1194        clnt_destroy(client);
1195        close(sock);
1196        exit(0);
1197}
1198.vs
1199.DE
1200.KE
1201The low-level version of
1202.I callrpc()
1203is
1204.I clnt_call()
1205which takes a
1206.I CLIENT
1207pointer rather than a host name.  The parameters to
1208.I clnt_call()
1209are a
1210.I CLIENT
1211pointer, the procedure number,
1212the XDR routine for serializing the argument,
1213a pointer to the argument,
1214the XDR routine for deserializing the return value,
1215a pointer to where the return value will be placed,
1216and the time in seconds to wait for a reply.
1217.LP
1218The
1219.I CLIENT
1220pointer is encoded with the transport mechanism.
1221.I callrpc()
1222uses UDP, thus it calls
1223.I clntudp_create()
1224to get a
1225.I CLIENT
1226pointer.  To get TCP (Transmission Control Protocol), you would use
1227.I clnttcp_create() .
1228.LP
1229The parameters to
1230.I clntudp_create()
1231are the server address, the program number, the version number,
1232a timeout value (between tries), and a pointer to a socket.
1233The final argument to
1234.I clnt_call()
1235is the total time to wait for a response.
1236Thus, the number of tries is the
1237.I clnt_call()
1238timeout divided by the
1239.I clntudp_create()
1240timeout.
1241.LP
1242Note that the
1243.I clnt_destroy()
1244call
1245always deallocates the space associated with the
1246.I CLIENT
1247handle.  It closes the socket associated with the
1248.I CLIENT
1249handle, however, only if the RPC library opened it.  It the
1250socket was opened by the user, it stays open.  This makes it
1251possible, in cases where there are multiple client handles
1252using the same socket, to destroy one handle without closing
1253the socket that other handles are using.
1254.LP
1255To make a stream connection, the call to
1256.I clntudp_create()
1257is replaced with a call to
1258.I clnttcp_create() .
1259.DS
1260.ft CW
1261clnttcp_create(&server_addr, prognum, versnum, &sock,
1262               inputsize, outputsize);
1263.DE
1264There is no timeout argument; instead, the receive and send buffer
1265sizes must be specified.  When the
1266.I clnttcp_create()
1267call is made, a TCP connection is established.
1268All RPC calls using that
1269.I CLIENT
1270handle would use this connection.
1271The server side of an RPC call using TCP has
1272.I svcudp_create()
1273replaced by
1274.I svctcp_create() .
1275.DS
1276.ft CW
1277transp = svctcp_create(RPC_ANYSOCK, 0, 0);
1278.DE
1279The last two arguments to
1280.I svctcp_create()
1281are send and receive sizes respectively.  If `0' is specified for
1282either of these, the system chooses a reasonable default.
1283.KS
1284.NH 1
1285\&Other RPC Features
1286.IX "RPC" "miscellaneous features"
1287.IX "miscellaneous RPC features"
1288.LP
1289This section discusses some other aspects of RPC
1290that are occasionally useful.
1291.NH 2
1292\&Select on the Server Side
1293.IX RPC select() RPC \fIselect()\fP
1294.IX select() "" \fIselect()\fP "on the server side"
1295.LP
1296Suppose a process is processing RPC requests
1297while performing some other activity.
1298If the other activity involves periodically updating a data structure,
1299the process can set an alarm signal before calling
1300.I svc_run()
1301But if the other activity
1302involves waiting on a a file descriptor, the
1303.I svc_run()
1304call won't work.
1305The code for
1306.I svc_run()
1307is as follows:
1308.ie t .DS
1309.el .DS L
1310.ft CW
1311.vs 11
1312void
1313svc_run()
1314{
1315        fd_set readfds;
1316        int dtbsz = getdtablesize();
1317
1318        for (;;) {
1319                readfds = svc_fds;
1320                switch (select(dtbsz, &readfds, NULL,NULL,NULL)) {
1321
1322                case -1:
1323                        if (errno == EINTR)
1324                                continue;
1325                        perror("select");
1326                        return;
1327                case 0:
1328                        break;
1329                default:
1330                        svc_getreqset(&readfds);
1331                }
1332        }
1333}
1334.vs
1335.DE
1336.KE
1337.LP
1338You can bypass
1339.I svc_run()
1340and call
1341.I svc_getreqset()
1342yourself.
1343All you need to know are the file descriptors
1344of the socket(s) associated with the programs you are waiting on.
1345Thus you can have your own
1346.I select()
1347.IX select() "" \fIselect()\fP
1348that waits on both the RPC socket,
1349and your own descriptors.  Note that
1350.I svc_fds()
1351is a bit mask of all the file descriptors that RPC is using for
1352services.  It can change everytime that
1353.I any
1354RPC library routine is called, because descriptors are constantly
1355being opened and closed, for example for TCP connections.
1356.NH 2
1357\&Broadcast RPC
1358.IX "broadcast RPC"
1359.IX RPC "broadcast"
1360.LP
1361The
1362.I portmapper
1363is a daemon that converts RPC program numbers
1364into DARPA protocol port numbers; see the
1365.I portmap
1366man page.  You can't do broadcast RPC without the portmapper.
1367Here are the main differences between
1368broadcast RPC and normal RPC calls:
1369.IP  1.
1370Normal RPC expects one answer, whereas
1371broadcast RPC expects many answers
1372(one or more answer from each responding machine).
1373.IP  2.
1374Broadcast RPC can only be supported by packet-oriented (connectionless)
1375transport protocols like UPD/IP.
1376.IP  3.
1377The implementation of broadcast RPC
1378treats all unsuccessful responses as garbage by filtering them out.
1379Thus, if there is a version mismatch between the
1380broadcaster and a remote service,
1381the user of broadcast RPC never knows.
1382.IP  4.
1383All broadcast messages are sent to the portmap port.
1384Thus, only services that register themselves with their portmapper
1385are accessible via the broadcast RPC mechanism.
1386.IP  5.
1387Broadcast requests are limited in size to the MTU (Maximum Transfer
1388Unit) of the local network.  For Ethernet, the MTU is 1500 bytes.
1389.KS
1390.NH 3
1391\&Broadcast RPC Synopsis
1392.IX "broadcast RPC" synopsis
1393.IX "RPC" "broadcast synopsis"
1394.ie t .DS
1395.el .DS L
1396.ft CW
1397#include <rpc/pmap_clnt.h>
1398        . . .
1399enum clnt_stat  clnt_stat;
1400        . . .
1401clnt_stat = clnt_broadcast(prognum, versnum, procnum,
1402  inproc, in, outproc, out, eachresult)
1403        u_long    prognum;        /* \fIprogram number\fP */
1404        u_long    versnum;        /* \fIversion number\fP */
1405        u_long    procnum;        /* \fIprocedure number\fP */
1406        xdrproc_t inproc;         /* \fIxdr routine for args\fP */
1407        caddr_t   in;             /* \fIpointer to args\fP */
1408        xdrproc_t outproc;        /* \fIxdr routine for results\fP */
1409        caddr_t   out;            /* \fIpointer to results\fP */
1410        bool_t    (*eachresult)();/* \fIcall with each result gotten\fP */
1411.DE
1412.KE
1413The procedure
1414.I eachresult()
1415is called each time a valid result is obtained.
1416It returns a boolean that indicates
1417whether or not the user wants more responses.
1418.ie t .DS
1419.el .DS L
1420.ft CW
1421bool_t done;
1422        . . .
1423done = eachresult(resultsp, raddr)
1424        caddr_t resultsp;
1425        struct sockaddr_in *raddr; /* \fIAddr of responding machine\fP */
1426.DE
1427If
1428.I done
1429is
1430.I TRUE ,
1431then broadcasting stops and
1432.I clnt_broadcast()
1433returns successfully.
1434Otherwise, the routine waits for another response.
1435The request is rebroadcast
1436after a few seconds of waiting.
1437If no responses come back,
1438the routine returns with
1439.I RPC_TIMEDOUT .
1440.NH 2
1441\&Batching
1442.IX "batching"
1443.IX RPC "batching"
1444.LP
1445The RPC architecture is designed so that clients send a call message,
1446and wait for servers to reply that the call succeeded.
1447This implies that clients do not compute
1448while servers are processing a call.
1449This is inefficient if the client does not want or need
1450an acknowledgement for every message sent.
1451It is possible for clients to continue computing
1452while waiting for a response,
1453using RPC batch facilities.
1454.LP
1455RPC messages can be placed in a \*Qpipeline\*U of calls
1456to a desired server; this is called batching.
1457Batching assumes that:
14581) each RPC call in the pipeline requires no response from the server,
1459and the server does not send a response message; and
14602) the pipeline of calls is transported on a reliable
1461byte stream transport such as TCP/IP.
1462Since the server does not respond to every call,
1463the client can generate new calls in parallel
1464with the server executing previous calls.
1465Furthermore, the TCP/IP implementation can buffer up
1466many call messages, and send them to the server in one
1467.I write()
1468system call.  This overlapped execution
1469greatly decreases the interprocess communication overhead of
1470the client and server processes,
1471and the total elapsed time of a series of calls.
1472.LP
1473Since the batched calls are buffered,
1474the client should eventually do a nonbatched call
1475in order to flush the pipeline.
1476.LP
1477A contrived example of batching follows.
1478Assume a string rendering service (like a window system)
1479has two similar calls: one renders a string and returns void results,
1480while the other renders a string and remains silent.
1481The service (using the TCP/IP transport) may look like:
1482.ie t .DS
1483.el .DS L
1484.ft CW
1485#include <stdio.h>
1486#include <rpc/rpc.h>
1487#include <suntool/windows.h>
1488
1489void windowdispatch();
1490
1491main()
1492{
1493        SVCXPRT *transp;
1494
1495        transp = svctcp_create(RPC_ANYSOCK, 0, 0);
1496        if (transp == NULL){
1497                fprintf(stderr, "can't create an RPC server\en");
1498                exit(1);
1499        }
1500        pmap_unset(WINDOWPROG, WINDOWVERS);
1501        if (!svc_register(transp, WINDOWPROG, WINDOWVERS,
1502          windowdispatch, IPPROTO_TCP)) {
1503                fprintf(stderr, "can't register WINDOW service\en");
1504                exit(1);
1505        }
1506        svc_run();  /* \fINever returns\fP */
1507        fprintf(stderr, "should never reach this point\en");
1508}
1509
1510void
1511windowdispatch(rqstp, transp)
1512        struct svc_req *rqstp;
1513        SVCXPRT *transp;
1514{
1515        char *s = NULL;
1516
1517        switch (rqstp->rq_proc) {
1518        case NULLPROC:
1519                if (!svc_sendreply(transp, xdr_void, 0))
1520                        fprintf(stderr, "can't reply to RPC call\en");
1521                return;
1522        case RENDERSTRING:
1523                if (!svc_getargs(transp, xdr_wrapstring, &s)) {
1524                        fprintf(stderr, "can't decode arguments\en");
1525.ft I
1526                        /*
1527                         * Tell caller he screwed up
1528                         */
1529.ft CW
1530                        svcerr_decode(transp);
1531                        break;
1532                }
1533.ft I
1534                /*
1535                 * Code here to render the string \fIs\fP
1536                 */
1537.ft CW
1538                if (!svc_sendreply(transp, xdr_void, NULL))
1539                        fprintf(stderr, "can't reply to RPC call\en");
1540                break;
1541        case RENDERSTRING_BATCHED:
1542                if (!svc_getargs(transp, xdr_wrapstring, &s)) {
1543                        fprintf(stderr, "can't decode arguments\en");
1544.ft I
1545                        /*
1546                         * We are silent in the face of protocol errors
1547                         */
1548.ft CW
1549                        break;
1550                }
1551.ft I
1552                /*
1553                 * Code here to render string s, but send no reply!
1554                 */
1555.ft CW
1556                break;
1557        default:
1558                svcerr_noproc(transp);
1559                return;
1560        }
1561.ft I
1562        /*
1563         * Now free string allocated while decoding arguments
1564         */
1565.ft CW
1566        svc_freeargs(transp, xdr_wrapstring, &s);
1567}
1568.DE
1569Of course the service could have one procedure
1570that takes the string and a boolean
1571to indicate whether or not the procedure should respond.
1572.LP
1573In order for a client to take advantage of batching,
1574the client must perform RPC calls on a TCP-based transport
1575and the actual calls must have the following attributes:
15761) the result's XDR routine must be zero
1577.I NULL ),
1578and 2) the RPC call's timeout must be zero.
1579.KS
1580.LP
1581Here is an example of a client that uses batching to render a
1582bunch of strings; the batching is flushed when the client gets
1583a null string (EOF):
1584.ie t .DS
1585.el .DS L
1586.ft CW
1587.vs 11
1588#include <stdio.h>
1589#include <rpc/rpc.h>
1590#include <sys/socket.h>
1591#include <sys/time.h>
1592#include <netdb.h>
1593#include <suntool/windows.h>
1594
1595main(argc, argv)
1596        int argc;
1597        char **argv;
1598{
1599        struct hostent *hp;
1600        struct timeval pertry_timeout, total_timeout;
1601        struct sockaddr_in server_addr;
1602        int sock = RPC_ANYSOCK;
1603        register CLIENT *client;
1604        enum clnt_stat clnt_stat;
1605        char buf[1000], *s = buf;
1606
1607        if ((client = clnttcp_create(&server_addr,
1608          WINDOWPROG, WINDOWVERS, &sock, 0, 0)) == NULL) {
1609                perror("clnttcp_create");
1610                exit(-1);
1611        }
1612        total_timeout.tv_sec = 0;
1613        total_timeout.tv_usec = 0;
1614        while (scanf("%s", s) != EOF) {
1615                clnt_stat = clnt_call(client, RENDERSTRING_BATCHED,
1616                        xdr_wrapstring, &s, NULL, NULL, total_timeout);
1617                if (clnt_stat != RPC_SUCCESS) {
1618                        clnt_perror(client, "batched rpc");
1619                        exit(-1);
1620                }
1621        }
1622
1623        /* \fINow flush the pipeline\fP */
1624
1625        total_timeout.tv_sec = 20;
1626        clnt_stat = clnt_call(client, NULLPROC, xdr_void, NULL,
1627                xdr_void, NULL, total_timeout);
1628        if (clnt_stat != RPC_SUCCESS) {
1629                clnt_perror(client, "rpc");
1630                exit(-1);
1631        }
1632        clnt_destroy(client);
1633        exit(0);
1634}
1635.vs
1636.DE
1637.KE
1638Since the server sends no message,
1639the clients cannot be notified of any of the failures that may occur.
1640Therefore, clients are on their own when it comes to handling errors.
1641.LP
1642The above example was completed to render
1643all of the (2000) lines in the file
1644.I /etc/termcap .
1645The rendering service did nothing but throw the lines away.
1646The example was run in the following four configurations:
16471) machine to itself, regular RPC;
16482) machine to itself, batched RPC;
16493) machine to another, regular RPC; and
16504) machine to another, batched RPC.
1651The results are as follows:
16521) 50 seconds;
16532) 16 seconds;
16543) 52 seconds;
16554) 10 seconds.
1656Running
1657.I fscanf()
1658on
1659.I /etc/termcap
1660only requires six seconds.
1661These timings show the advantage of protocols
1662that allow for overlapped execution,
1663though these protocols are often hard to design.
1664.NH 2
1665\&Authentication
1666.IX "authentication"
1667.IX "RPC" "authentication"
1668.LP
1669In the examples presented so far,
1670the caller never identified itself to the server,
1671and the server never required an ID from the caller.
1672Clearly, some network services, such as a network filesystem,
1673require stronger security than what has been presented so far.
1674.LP
1675In reality, every RPC call is authenticated by
1676the RPC package on the server, and similarly,
1677the RPC client package generates and sends authentication parameters.
1678Just as different transports (TCP/IP or UDP/IP)
1679can be used when creating RPC clients and servers,
1680different forms of authentication can be associated with RPC clients;
1681the default authentication type used as a default is type
1682.I none .
1683.LP
1684The authentication subsystem of the RPC package is open ended.
1685That is, numerous types of authentication are easy to support.
1686.NH 3
1687\&UNIX Authentication
1688.IX "UNIX Authentication"
1689.IP "\fIThe Client Side\fP"
1690.LP
1691When a caller creates a new RPC client handle as in:
1692.DS
1693.ft CW
1694clnt = clntudp_create(address, prognum, versnum,
1695                      wait, sockp)
1696.DE
1697the appropriate transport instance defaults
1698the associate authentication handle to be
1699.DS
1700.ft CW
1701clnt->cl_auth = authnone_create();
1702.DE
1703The RPC client can choose to use
1704.I UNIX
1705style authentication by setting
1706.I clnt\->cl_auth
1707after creating the RPC client handle:
1708.DS
1709.ft CW
1710clnt->cl_auth = authunix_create_default();
1711.DE
1712This causes each RPC call associated with
1713.I clnt
1714to carry with it the following authentication credentials structure:
1715.ie t .DS
1716.el .DS L
1717.ft I
1718/*
1719 * UNIX style credentials.
1720 */
1721.ft CW
1722struct authunix_parms {
1723    u_long  aup_time;       /* \fIcredentials creation time\fP */
1724    char    *aup_machname;  /* \fIhost name where client is\fP */
1725    int     aup_uid;        /* \fIclient's UNIX effective uid\fP */
1726    int     aup_gid;        /* \fIclient's current group id\fP */
1727    u_int   aup_len;        /* \fIelement length of aup_gids\fP */
1728    int     *aup_gids;      /* \fIarray of groups user is in\fP */
1729};
1730.DE
1731These fields are set by
1732.I authunix_create_default()
1733by invoking the appropriate system calls.
1734Since the RPC user created this new style of authentication,
1735the user is responsible for destroying it with:
1736.DS
1737.ft CW
1738auth_destroy(clnt->cl_auth);
1739.DE
1740This should be done in all cases, to conserve memory.
1741.sp
1742.IP "\fIThe Server Side\fP"
1743.LP
1744Service implementors have a harder time dealing with authentication issues
1745since the RPC package passes the service dispatch routine a request
1746that has an arbitrary authentication style associated with it.
1747Consider the fields of a request handle passed to a service dispatch routine:
1748.ie t .DS
1749.el .DS L
1750.ft I
1751/*
1752 * An RPC Service request
1753 */
1754.ft CW
1755struct svc_req {
1756    u_long    rq_prog;          /* \fIservice program number\fP */
1757    u_long    rq_vers;          /* \fIservice protocol vers num\fP */
1758    u_long    rq_proc;          /* \fIdesired procedure number\fP */
1759    struct opaque_auth rq_cred; /* \fIraw credentials from wire\fP */
1760    caddr_t   rq_clntcred;  /* \fIcredentials (read only)\fP */
1761};
1762.DE
1763The
1764.I rq_cred
1765is mostly opaque, except for one field of interest:
1766the style or flavor of authentication credentials:
1767.ie t .DS
1768.el .DS L
1769.ft I
1770/*
1771 * Authentication info.  Mostly opaque to the programmer.
1772 */
1773.ft CW
1774struct opaque_auth {
1775    enum_t  oa_flavor;  /* \fIstyle of credentials\fP */
1776    caddr_t oa_base;    /* \fIaddress of more auth stuff\fP */
1777    u_int   oa_length;  /* \fInot to exceed \fIMAX_AUTH_BYTES */
1778};
1779.DE
1780.IX RPC guarantees
1781The RPC package guarantees the following
1782to the service dispatch routine:
1783.IP  1.
1784That the request's
1785.I rq_cred
1786is well formed.  Thus the service implementor may inspect the request's
1787.I rq_cred.oa_flavor
1788to determine which style of authentication the caller used.
1789The service implementor may also wish to inspect the other fields of
1790.I rq_cred
1791if the style is not one of the styles supported by the RPC package.
1792.IP  2.
1793That the request's
1794.I rq_clntcred
1795field is either
1796.I NULL
1797or points to a well formed structure
1798that corresponds to a supported style of authentication credentials.
1799Remember that only
1800.I unix
1801style is currently supported, so (currently)
1802.I rq_clntcred
1803could be cast to a pointer to an
1804.I authunix_parms
1805structure.  If
1806.I rq_clntcred
1807is
1808.I NULL ,
1809the service implementor may wish to inspect the other (opaque) fields of
1810.I rq_cred
1811in case the service knows about a new type of authentication
1812that the RPC package does not know about.
1813.LP
1814Our remote users service example can be extended so that
1815it computes results for all users except UID 16:
1816.ie t .DS
1817.el .DS L
1818.ft CW
1819.vs 11
1820nuser(rqstp, transp)
1821        struct svc_req *rqstp;
1822        SVCXPRT *transp;
1823{
1824        struct authunix_parms *unix_cred;
1825        int uid;
1826        unsigned long nusers;
1827
1828.ft I
1829        /*
1830         * we don't care about authentication for null proc
1831         */
1832.ft CW
1833        if (rqstp->rq_proc == NULLPROC) {
1834                if (!svc_sendreply(transp, xdr_void, 0)) {
1835                        fprintf(stderr, "can't reply to RPC call\en");
1836                        return (1);
1837                 }
1838                 return;
1839        }
1840.ft I
1841        /*
1842         * now get the uid
1843         */
1844.ft CW
1845        switch (rqstp->rq_cred.oa_flavor) {
1846        case AUTH_UNIX:
1847                unix_cred =
1848                        (struct authunix_parms *)rqstp->rq_clntcred;
1849                uid = unix_cred->aup_uid;
1850                break;
1851        case AUTH_NULL:
1852        default:
1853                svcerr_weakauth(transp);
1854                return;
1855        }
1856        switch (rqstp->rq_proc) {
1857        case RUSERSPROC_NUM:
1858.ft I
1859                /*
1860                 * make sure caller is allowed to call this proc
1861                 */
1862.ft CW
1863                if (uid == 16) {
1864                        svcerr_systemerr(transp);
1865                        return;
1866                }
1867.ft I
1868                /*
1869                 * Code here to compute the number of users
1870                 * and assign it to the variable \fInusers\fP
1871                 */
1872.ft CW
1873                if (!svc_sendreply(transp, xdr_u_long, &nusers)) {
1874                        fprintf(stderr, "can't reply to RPC call\en");
1875                        return (1);
1876                }
1877                return;
1878        default:
1879                svcerr_noproc(transp);
1880                return;
1881        }
1882}
1883.vs
1884.DE
1885A few things should be noted here.
1886First, it is customary not to check
1887the authentication parameters associated with the
1888.I NULLPROC
1889(procedure number zero).
1890Second, if the authentication parameter's type is not suitable
1891for your service, you should call
1892.I svcerr_weakauth() .
1893And finally, the service protocol itself should return status
1894for access denied; in the case of our example, the protocol
1895does not have such a status, so we call the service primitive
1896.I svcerr_systemerr()
1897instead.
1898.LP
1899The last point underscores the relation between
1900the RPC authentication package and the services;
1901RPC deals only with
1902.I authentication
1903and not with individual services'
1904.I "access control" .
1905The services themselves must implement their own access control policies
1906and reflect these policies as return statuses in their protocols.
1907.NH 2
1908\&DES Authentication
1909.IX RPC DES
1910.IX RPC authentication
1911.LP
1912UNIX authentication is quite easy to defeat.  Instead of using
1913.I authunix_create_default (),
1914one can call
1915.I authunix_create()
1916and then modify the RPC authentication handle it returns by filling in
1917whatever user ID and hostname they wish the server to think they have.
1918DES authentication is thus recommended for people who want more security
1919than UNIX authentication offers.
1920.LP
1921The details of the DES authentication protocol are complicated and
1922are not explained here. 
1923See
1924.I "Remote Procedure Calls: Protocol Specification"
1925for the details.
1926.LP
1927In  order for  DES authentication   to  work, the
1928.I keyserv(8c)
1929daemon must be running  on both  the  server  and client machines.  The
1930users on  these machines  need  public  keys  assigned by  the network
1931administrator in  the
1932.I publickey(5)
1933database.  And,  they  need to have decrypted  their  secret keys
1934using  their  login   password.  This automatically happens when one
1935logs in using
1936.I login(1) ,
1937or can be done manually using
1938.I keylogin(1) .
1939The
1940.I "Network Services"
1941chapter
1942./" XXX
1943explains more how to setup secure networking.
1944.sp
1945.IP "\fIClient Side\fP"
1946.LP
1947If a client wishes to use DES authentication, it must set its
1948authentication handle appropriately.  Here is an example:
1949.DS
1950cl->cl_auth =
1951        authdes_create(servername, 60, &server_addr, NULL);
1952.DE
1953The first argument is the network name or \*Qnetname\*U of the owner of
1954the server process.  Typically, server processes are root processes
1955and their netname can be derived using the following call:
1956.DS
1957char servername[MAXNETNAMELEN];
1958
1959host2netname(servername, rhostname, NULL);
1960.DE
1961Here,
1962.I rhostname
1963is the hostname of the machine the server process is running on.
1964.I host2netname()
1965fills in
1966.I servername
1967to contain this root process's netname.  If the
1968server process was run by a regular user, one could use the call
1969.I user2netname()
1970instead.  Here is an example for a server process with the same user
1971ID as the client:
1972.DS
1973char servername[MAXNETNAMELEN];
1974
1975user2netname(servername, getuid(), NULL);
1976.DE
1977The last argument to both of these calls,
1978.I user2netname()
1979and
1980.I host2netname (),
1981is the name of the naming domain where the server is located.  The
1982.I NULL
1983used here means \*Quse the local domain name.\*U
1984.LP
1985The second argument to
1986.I authdes_create()
1987is a lifetime for the credential.  Here it is set to sixty
1988seconds.  What that means is that the credential will expire 60
1989seconds from now.  If some mischievous user tries to reuse the
1990credential, the server RPC subsystem will recognize that it has
1991expired and not grant any requests.  If the same mischievous user
1992tries to reuse the credential within the sixty second lifetime,
1993he will still be rejected because the server RPC subsystem
1994remembers which credentials it has already seen in the near past,
1995and will not grant requests to duplicates.
1996.LP
1997The third argument to
1998.I authdes_create()
1999is the address of the host to synchronize with.  In order for DES
2000authentication to work, the server and client must agree upon the
2001time.  Here we pass the address of the server itself, so the
2002client and server will both be using the same time: the server's
2003time.  The argument can be
2004.I NULL ,
2005which means \*Qdon't bother synchronizing.\*U You should only do this
2006if you are sure the client and server are already synchronized.
2007.LP
2008The final argument to
2009.I authdes_create()
2010is the address of a DES encryption key to use for encrypting
2011timestamps and data.  If this argument is
2012.I NULL ,
2013as it is in this example, a random key will be chosen.  The client
2014may find out the encryption key being used by consulting the
2015.I ah_key
2016field of the authentication handle.
2017.sp
2018.IP "\fIServer Side\fP"
2019.LP
2020The server side is a lot simpler than the client side.  Here is the
2021previous example rewritten to use
2022.I AUTH_DES
2023instead of
2024.I AUTH_UNIX :
2025.ie t .DS
2026.el .DS L
2027.ft CW
2028.vs 11
2029#include <sys/time.h>
2030#include <rpc/auth_des.h>
2031        . . .
2032        . . .
2033nuser(rqstp, transp)
2034        struct svc_req *rqstp;
2035        SVCXPRT *transp;
2036{
2037        struct authdes_cred *des_cred;
2038        int uid;
2039        int gid;
2040        int gidlen;
2041        int gidlist[10];
2042.ft I
2043        /*
2044         * we don't care about authentication for null proc
2045         */
2046.ft CW
2047
2048        if (rqstp->rq_proc == NULLPROC) {
2049                /* \fIsame as before\fP */
2050        }
2051
2052.ft I
2053        /*
2054         * now get the uid
2055         */
2056.ft CW
2057        switch (rqstp->rq_cred.oa_flavor) {
2058        case AUTH_DES:
2059                des_cred =
2060                        (struct authdes_cred *) rqstp->rq_clntcred;
2061                if (! netname2user(des_cred->adc_fullname.name,
2062                        &uid, &gid, &gidlen, gidlist))
2063                {
2064                        fprintf(stderr, "unknown user: %s\n",
2065                                des_cred->adc_fullname.name);
2066                        svcerr_systemerr(transp);
2067                        return;
2068                }
2069                break;
2070        case AUTH_NULL:
2071        default:
2072                svcerr_weakauth(transp);
2073                return;
2074        }
2075
2076.ft I
2077        /*
2078         * The rest is the same as before
2079         */     
2080.ft CW
2081.vs
2082.DE
2083Note the use of the routine
2084.I netname2user (),
2085the inverse of
2086.I user2netname ():
2087it takes a network ID and converts to a unix ID.
2088.I netname2user ()
2089also supplies the group IDs which we don't use in this example,
2090but which may be useful to other UNIX programs.
2091.NH 2
2092\&Using Inetd
2093.IX inetd "" "using \fIinetd\fP"
2094.LP
2095An RPC server can be started from
2096.I inetd
2097The only difference from the usual code is that the service
2098creation routine should be called in the following form:
2099.ie t .DS
2100.el .DS L
2101.ft CW
2102transp = svcudp_create(0);     /* \fIFor UDP\fP */
2103transp = svctcp_create(0,0,0); /* \fIFor listener TCP sockets\fP */
2104transp = svcfd_create(0,0,0);  /* \fIFor connected TCP sockets\fP */
2105.DE
2106since
2107.I inet
2108passes a socket as file descriptor 0.
2109Also,
2110.I svc_register()
2111should be called as
2112.ie t .DS
2113.el .DS L
2114.ft CW
2115svc_register(transp, PROGNUM, VERSNUM, service, 0);
2116.DE
2117with the final flag as 0,
2118since the program would already be registered by
2119.I inetd
2120Remember that if you want to exit
2121from the server process and return control to
2122.I inet
2123you need to explicitly exit, since
2124.I svc_run()
2125never returns.
2126.LP
2127The format of entries in
2128.I /etc/inetd.conf
2129for RPC services is in one of the following two forms:
2130.ie t .DS
2131.el .DS L
2132.ft CW
2133p_name/version dgram  rpc/udp wait/nowait user server args
2134p_name/version stream rpc/tcp wait/nowait user server args
2135.DE
2136where
2137.I p_name
2138is the symbolic name of the program as it appears in
2139.I rpc(5) ,
2140.I server
2141is the program implementing the server,
2142and
2143.I program
2144and
2145.I version
2146are the program and version numbers of the service.
2147For more information, see
2148.I inetd.conf(5) .
2149.LP
2150If the same program handles multiple versions,
2151then the version number can be a range,
2152as in this example:
2153.ie t .DS
2154.el .DS L
2155.ft CW
2156rstatd/1-2 dgram rpc/udp wait root /usr/etc/rpc.rstatd
2157.DE
2158.NH 1
2159\&More Examples
2160.sp 1
2161.NH 2
2162\&Versions
2163.IX "versions"
2164.IX "RPC" "versions"
2165.LP
2166By convention, the first version number of program
2167.I PROG
2168is
2169.I PROGVERS_ORIG
2170and the most recent version is
2171.I PROGVERS
2172Suppose there is a new version of the
2173.I user
2174program that returns an
2175.I "unsigned short"
2176rather than a
2177.I long .
2178If we name this version
2179.I RUSERSVERS_SHORT
2180then a server that wants to support both versions
2181would do a double register.
2182.ie t .DS
2183.el .DS L
2184.ft CW
2185if (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG,
2186  nuser, IPPROTO_TCP)) {
2187        fprintf(stderr, "can't register RUSER service\en");
2188        exit(1);
2189}
2190if (!svc_register(transp, RUSERSPROG, RUSERSVERS_SHORT,
2191  nuser, IPPROTO_TCP)) {
2192        fprintf(stderr, "can't register RUSER service\en");
2193        exit(1);
2194}
2195.DE
2196Both versions can be handled by the same C procedure:
2197.ie t .DS
2198.el .DS L
2199.ft CW
2200.vs 11
2201nuser(rqstp, transp)
2202        struct svc_req *rqstp;
2203        SVCXPRT *transp;
2204{
2205        unsigned long nusers;
2206        unsigned short nusers2;
2207
2208        switch (rqstp->rq_proc) {
2209        case NULLPROC:
2210                if (!svc_sendreply(transp, xdr_void, 0)) {
2211                        fprintf(stderr, "can't reply to RPC call\en");
2212            return (1);
2213                }
2214                return;
2215        case RUSERSPROC_NUM:
2216.ft I
2217                /*
2218         * Code here to compute the number of users
2219         * and assign it to the variable \fInusers\fP
2220                 */
2221.ft CW
2222                nusers2 = nusers;
2223                switch (rqstp->rq_vers) {
2224                case RUSERSVERS_ORIG:
2225            if (!svc_sendreply(transp, xdr_u_long,
2226                    &nusers)) {
2227                fprintf(stderr,"can't reply to RPC call\en");
2228                        }
2229                        break;
2230                case RUSERSVERS_SHORT:
2231            if (!svc_sendreply(transp, xdr_u_short,
2232                    &nusers2)) {
2233                fprintf(stderr,"can't reply to RPC call\en");
2234                        }
2235                        break;
2236                }
2237        default:
2238                svcerr_noproc(transp);
2239                return;
2240        }
2241}
2242.vs
2243.DE
2244.KS
2245.NH 2
2246\&TCP
2247.IX "TCP"
2248.LP
2249Here is an example that is essentially
2250.I rcp.
2251The initiator of the RPC
2252.I snd
2253call takes its standard input and sends it to the server
2254.I rcv
2255which prints it on standard output.
2256The RPC call uses TCP.
2257This also illustrates an XDR procedure that behaves differently
2258on serialization than on deserialization.
2259.ie t .DS
2260.el .DS L
2261.vs 11
2262.ft I
2263/*
2264 * The xdr routine:
2265 *              on decode, read from wire, write onto fp
2266 *              on encode, read from fp, write onto wire
2267 */
2268.ft CW
2269#include <stdio.h>
2270#include <rpc/rpc.h>
2271
2272xdr_rcp(xdrs, fp)
2273        XDR *xdrs;
2274        FILE *fp;
2275{
2276        unsigned long size;
2277        char buf[BUFSIZ], *p;
2278
2279        if (xdrs->x_op == XDR_FREE)/* nothing to free */
2280                return 1;
2281        while (1) {
2282                if (xdrs->x_op == XDR_ENCODE) {
2283                        if ((size = fread(buf, sizeof(char), BUFSIZ,
2284                          fp)) == 0 && ferror(fp)) {
2285                                fprintf(stderr, "can't fread\en");
2286                                return (1);
2287                        }
2288                }
2289                p = buf;
2290                if (!xdr_bytes(xdrs, &p, &size, BUFSIZ))
2291                        return 0;
2292                if (size == 0)
2293                        return 1;
2294                if (xdrs->x_op == XDR_DECODE) {
2295                        if (fwrite(buf, sizeof(char), size,
2296                          fp) != size) {
2297                                fprintf(stderr, "can't fwrite\en");
2298                                return (1);
2299                        }
2300                }
2301        }
2302}
2303.vs
2304.DE
2305.KE
2306.ie t .DS
2307.el .DS L
2308.vs 11
2309.ft I
2310/*
2311 * The sender routines
2312 */
2313.ft CW
2314#include <stdio.h>
2315#include <netdb.h>
2316#include <rpc/rpc.h>
2317#include <sys/socket.h>
2318#include <sys/time.h>
2319
2320main(argc, argv)
2321        int argc;
2322        char **argv;
2323{
2324        int xdr_rcp();
2325        int err;
2326
2327        if (argc < 2) {
2328                fprintf(stderr, "usage: %s servername\en", argv[0]);
2329                exit(-1);
2330        }
2331        if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC,
2332          RCPVERS, xdr_rcp, stdin, xdr_void, 0) != 0)) {
2333                clnt_perrno(err);
2334                fprintf(stderr, "can't make RPC call\en");
2335                exit(1);
2336        }
2337        exit(0);
2338}
2339
2340callrpctcp(host, prognum, procnum, versnum,
2341           inproc, in, outproc, out)
2342        char *host, *in, *out;
2343        xdrproc_t inproc, outproc;
2344{
2345        struct sockaddr_in server_addr;
2346        int socket = RPC_ANYSOCK;
2347        enum clnt_stat clnt_stat;
2348        struct hostent *hp;
2349        register CLIENT *client;
2350        struct timeval total_timeout;
2351
2352        if ((hp = gethostbyname(host)) == NULL) {
2353                fprintf(stderr, "can't get addr for '%s'\en", host);
2354                return (-1);
2355        }
2356        bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
2357                hp->h_length);
2358        server_addr.sin_family = AF_INET;
2359        server_addr.sin_port =  0;
2360        if ((client = clnttcp_create(&server_addr, prognum,
2361          versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) {
2362                perror("rpctcp_create");
2363                return (-1);
2364        }
2365        total_timeout.tv_sec = 20;
2366        total_timeout.tv_usec = 0;
2367        clnt_stat = clnt_call(client, procnum,
2368                inproc, in, outproc, out, total_timeout);
2369        clnt_destroy(client);
2370        return (int)clnt_stat;
2371}
2372.vs
2373.DE
2374.ie t .DS
2375.el .DS L
2376.vs 11
2377.ft I
2378/*
2379 * The receiving routines
2380 */
2381.ft CW
2382#include <stdio.h>
2383#include <rpc/rpc.h>
2384
2385main()
2386{
2387        register SVCXPRT *transp;
2388     int rcp_service(), xdr_rcp();
2389
2390        if ((transp = svctcp_create(RPC_ANYSOCK,
2391          BUFSIZ, BUFSIZ)) == NULL) {
2392                fprintf("svctcp_create: error\en");
2393                exit(1);
2394        }
2395        pmap_unset(RCPPROG, RCPVERS);
2396        if (!svc_register(transp,
2397          RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) {
2398                fprintf(stderr, "svc_register: error\en");
2399                exit(1);
2400        }
2401        svc_run();  /* \fInever returns\fP */
2402        fprintf(stderr, "svc_run should never return\en");
2403}
2404
2405rcp_service(rqstp, transp)
2406        register struct svc_req *rqstp;
2407        register SVCXPRT *transp;
2408{
2409        switch (rqstp->rq_proc) {
2410        case NULLPROC:
2411                if (svc_sendreply(transp, xdr_void, 0) == 0) {
2412                        fprintf(stderr, "err: rcp_service");
2413                        return (1);
2414                }
2415                return;
2416        case RCPPROC_FP:
2417                if (!svc_getargs(transp, xdr_rcp, stdout)) {
2418                        svcerr_decode(transp);
2419                        return;
2420                }
2421                if (!svc_sendreply(transp, xdr_void, 0)) {
2422                        fprintf(stderr, "can't reply\en");
2423                        return;
2424                }
2425                return (0);
2426        default:
2427                svcerr_noproc(transp);
2428                return;
2429        }
2430}
2431.vs
2432.DE
2433.NH 2
2434\&Callback Procedures
2435.IX RPC "callback procedures"
2436.LP
2437Occasionally, it is useful to have a server become a client,
2438and make an RPC call back to the process which is its client.
2439An example is remote debugging,
2440where the client is a window system program,
2441and the server is a debugger running on the remote machine.
2442Most of the time,
2443the user clicks a mouse button at the debugging window,
2444which converts this to a debugger command,
2445and then makes an RPC call to the server
2446(where the debugger is actually running),
2447telling it to execute that command.
2448However, when the debugger hits a breakpoint, the roles are reversed,
2449and the debugger wants to make an rpc call to the window program,
2450so that it can inform the user that a breakpoint has been reached.
2451.LP
2452In order to do an RPC callback,
2453you need a program number to make the RPC call on.
2454Since this will be a dynamically generated program number,
2455it should be in the transient range,
2456.I "0x40000000 - 0x5fffffff" .
2457The routine
2458.I gettransient()
2459returns a valid program number in the transient range,
2460and registers it with the portmapper.
2461It only talks to the portmapper running on the same machine as the
2462.I gettransient()
2463routine itself.  The call to
2464.I pmap_set()
2465is a test and set operation,
2466in that it indivisibly tests whether a program number
2467has already been registered,
2468and if it has not, then reserves it.  On return, the
2469.I sockp
2470argument will contain a socket that can be used
2471as the argument to an
2472.I svcudp_create()
2473or
2474.I svctcp_create()
2475call.
2476.ie t .DS
2477.el .DS L
2478.ft CW
2479.vs 11
2480#include <stdio.h>
2481#include <rpc/rpc.h>
2482#include <sys/socket.h>
2483
2484gettransient(proto, vers, sockp)
2485        int proto, vers, *sockp;
2486{
2487        static int prognum = 0x40000000;
2488        int s, len, socktype;
2489        struct sockaddr_in addr;
2490
2491        switch(proto) {
2492                case IPPROTO_UDP:
2493                        socktype = SOCK_DGRAM;
2494                        break;
2495                case IPPROTO_TCP:
2496                        socktype = SOCK_STREAM;
2497                        break;
2498                default:
2499                        fprintf(stderr, "unknown protocol type\en");
2500                        return 0;
2501        }
2502        if (*sockp == RPC_ANYSOCK) {
2503                if ((s = socket(AF_INET, socktype, 0)) < 0) {
2504                        perror("socket");
2505                        return (0);
2506                }
2507                *sockp = s;
2508        }
2509        else
2510                s = *sockp;
2511        addr.sin_addr.s_addr = 0;
2512        addr.sin_family = AF_INET;
2513        addr.sin_port = 0;
2514        len = sizeof(addr);
2515.ft I
2516        /*
2517         * may be already bound, so don't check for error
2518         */
2519.ft CW
2520        bind(s, &addr, len);
2521        if (getsockname(s, &addr, &len)< 0) {
2522                perror("getsockname");
2523                return (0);
2524        }
2525        while (!pmap_set(prognum++, vers, proto,
2526                ntohs(addr.sin_port))) continue;
2527        return (prognum-1);
2528}
2529.vs
2530.DE
2531.SH
2532Note:
2533.I
2534The call to
2535.I ntohs()
2536is necessary to ensure that the port number in
2537.I "addr.sin_port" ,
2538which is in
2539.I network
2540byte order, is passed in
2541.I host
2542byte order (as
2543.I pmap_set()
2544expects).  See the
2545.I byteorder(3N)
2546man page for more details on the conversion of network
2547addresses from network to host byte order.
2548.KS
2549.LP
2550The following pair of programs illustrate how to use the
2551.I gettransient()
2552routine.
2553The client makes an RPC call to the server,
2554passing it a transient program number.
2555Then the client waits around to receive a callback
2556from the server at that program number.
2557The server registers the program
2558.I EXAMPLEPROG
2559so that it can receive the RPC call
2560informing it of the callback program number.
2561Then at some random time (on receiving an
2562.I ALRM
2563signal in this example), it sends a callback RPC call,
2564using the program number it received earlier.
2565.ie t .DS
2566.el .DS L
2567.vs 11
2568.ft I
2569/*
2570 * client
2571 */
2572.ft CW
2573#include <stdio.h>
2574#include <rpc/rpc.h>
2575
2576int callback();
2577char hostname[256];
2578
2579main()
2580{
2581        int x, ans, s;
2582        SVCXPRT *xprt;
2583
2584        gethostname(hostname, sizeof(hostname));
2585        s = RPC_ANYSOCK;
2586        x = gettransient(IPPROTO_UDP, 1, &s);
2587        fprintf(stderr, "client gets prognum %d\en", x);
2588        if ((xprt = svcudp_create(s)) == NULL) {
2589          fprintf(stderr, "rpc_server: svcudp_create\en");
2590                exit(1);
2591        }
2592.ft I
2593        /* protocol is 0 - gettransient does registering
2594         */
2595.ft CW
2596        (void)svc_register(xprt, x, 1, callback, 0);
2597        ans = callrpc(hostname, EXAMPLEPROG, EXAMPLEVERS,
2598                EXAMPLEPROC_CALLBACK, xdr_int, &x, xdr_void, 0);
2599        if ((enum clnt_stat) ans != RPC_SUCCESS) {
2600                fprintf(stderr, "call: ");
2601                clnt_perrno(ans);
2602                fprintf(stderr, "\en");
2603        }
2604        svc_run();
2605        fprintf(stderr, "Error: svc_run shouldn't return\en");
2606}
2607
2608callback(rqstp, transp)
2609        register struct svc_req *rqstp;
2610        register SVCXPRT *transp;
2611{
2612        switch (rqstp->rq_proc) {
2613                case 0:
2614                        if (!svc_sendreply(transp, xdr_void, 0)) {
2615                                fprintf(stderr, "err: exampleprog\en");
2616                                return (1);
2617                        }
2618                        return (0);
2619                case 1:
2620                        if (!svc_getargs(transp, xdr_void, 0)) {
2621                                svcerr_decode(transp);
2622                                return (1);
2623                        }
2624                        fprintf(stderr, "client got callback\en");
2625                        if (!svc_sendreply(transp, xdr_void, 0)) {
2626                                fprintf(stderr, "err: exampleprog");
2627                                return (1);
2628                        }
2629        }
2630}
2631.vs
2632.DE
2633.KE
2634.ie t .DS
2635.el .DS L
2636.vs 11
2637.ft I
2638/*
2639 * server
2640 */
2641.ft CW
2642#include <stdio.h>
2643#include <rpc/rpc.h>
2644#include <sys/signal.h>
2645
2646char *getnewprog();
2647char hostname[256];
2648int docallback();
2649int pnum;               /* \fIprogram number for callback routine\fP */
2650
2651main()
2652{
2653        gethostname(hostname, sizeof(hostname));
2654        registerrpc(EXAMPLEPROG, EXAMPLEVERS,
2655          EXAMPLEPROC_CALLBACK, getnewprog, xdr_int, xdr_void);
2656        fprintf(stderr, "server going into svc_run\en");
2657        signal(SIGALRM, docallback);
2658        alarm(10);
2659        svc_run();
2660        fprintf(stderr, "Error: svc_run shouldn't return\en");
2661}
2662
2663char *
2664getnewprog(pnump)
2665        char *pnump;
2666{
2667        pnum = *(int *)pnump;
2668        return NULL;
2669}
2670
2671docallback()
2672{
2673        int ans;
2674
2675        ans = callrpc(hostname, pnum, 1, 1, xdr_void, 0,
2676                xdr_void, 0);
2677        if (ans != 0) {
2678                fprintf(stderr, "server: ");
2679                clnt_perrno(ans);
2680                fprintf(stderr, "\en");
2681        }
2682}
2683.vs
2684.DE
Note: See TracBrowser for help on using the repository browser.