|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.