OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [librpc/] [src/] [rpc/] [PSD.doc/] [rpc.prog.ms] - Blame information for rev 607

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
.\"
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
20
This document assumes a working knowledge of network theory.  It is
21
intended for programmers who wish to write network applications using
22
remote procedure calls (explained below), and who want to understand
23
the RPC mechanisms usually hidden by the
24
.I rpcgen(1)
25
protocol compiler.
26
.I rpcgen
27
is described in detail in the previous chapter, the
28
.I "\fBrpcgen\fP \fIProgramming Guide\fP".
29
.SH
30
Note:
31
.I
32
.IX rpcgen "" \fIrpcgen\fP
33
Before attempting to write a network application, or to convert an
34
existing non-network application to run over the network, you may want to
35
understand the material in this chapter.  However, for most applications,
36
you can circumvent the need to cope with the details presented here by using
37
.I rpcgen .
38
The
39
.I "Generating XDR Routines"
40
section of that chapter contains the complete source for a working RPC
41
service\(ema remote directory listing service which uses
42
.I rpcgen
43
to generate XDR routines as well as client and server stubs.
44
.LP
45
.LP
46
What are remote procedure calls?  Simply put, they are the high-level
47
communications paradigm used in the operating system.
48
RPC presumes the existence of
49
low-level networking mechanisms (such as TCP/IP and UDP/IP), and upon them
50
it implements a logical client to server communications system designed
51
specifically for the support of network applications.  With RPC, the client
52
makes a procedure call to send a data packet to the server.  When the
53
packet arrives, the server calls a dispatch routine, performs whatever
54
service is requested, sends back the reply, and the procedure call returns
55
to the client.
56
.NH 0
57
\&Layers of RPC
58
.IX "layers of RPC"
59
.IX "RPC" "layers"
60
.LP
61
The RPC interface can be seen as being divided into three layers.\**
62
.FS
63
For a complete specification of the routines in the remote procedure
64
call Library, see the
65
.I rpc(3N)
66
manual page.
67
.FE
68
.LP
69
.I "The Highest Layer:"
70
.IX RPC "The Highest Layer"
71
The highest layer is totally transparent to the operating system,
72
machine and network upon which is is run.  It's probably best to
73
think of this level as a way of
74
.I using
75
RPC, rather than as
76
a \fIpart of\fP RPC proper.  Programmers who write RPC routines
77
should (almost) always make this layer available to others by way
78
of a simple C front end that entirely hides the networking.
79
.LP
80
To illustrate, at this level a program can simply make a call to
81
.I rnusers (),
82
a C routine which returns the number of users on a remote machine.
83
The user is not explicitly aware of using RPC \(em they simply
84
call a procedure, just as they would call
85
.I malloc() .
86
.LP
87
.I "The Middle Layer:"
88
.IX RPC "The Middle Layer"
89
The middle layer is really \*QRPC proper.\*U  Here, the user doesn't
90
need to consider details about sockets, the UNIX system, or other low-level
91
implementation mechanisms.  They simply make remote procedure calls
92
to routines on other machines.  The selling point here is simplicity.
93
It's this layer that allows RPC to pass the \*Qhello world\*U test \(em
94
simple things should be simple.  The middle-layer routines are used
95
for most applications.
96
.LP
97
RPC calls are made with the system routines
98
.I registerrpc()
99
.I callrpc()
100
and
101
.I svc_run ().
102
The first two of these are the most fundamental:
103
.I registerrpc()
104
obtains a unique system-wide procedure-identification number, and
105
.I callrpc()
106
actually executes a remote procedure call.  At the middle level, a
107
call to
108
.I rnusers()
109
is implemented by way of these two routines.
110
.LP
111
The middle layer is unfortunately rarely used in serious programming
112
due to its inflexibility (simplicity).  It does not allow timeout
113
specifications or the choice of transport.  It allows no UNIX
114
process control or flexibility in case of errors.  It doesn't support
115
multiple kinds of call authentication.  The programmer rarely needs
116
all 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"
120
The lowest layer does allow these details to be controlled by the
121
programmer, and for that reason it is often necessary.  Programs
122
written at this level are also most efficient, but this is rarely a
123
real issue \(em since RPC clients and servers rarely generate
124
heavy network loads.
125
.LP
126
Although this document only discusses the interface to C,
127
remote procedure calls can be made from any language.
128
Even though this document discusses RPC
129
when it is used to communicate
130
between processes on different machines,
131
it works just as well for communication
132
between different processes on the same machine.
133
.br
134
.KS
135
.NH 2
136
\&The RPC Paradigm
137
.IX RPC paradigm
138
.LP
139
Here 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
144
L1: arrow down 1i "client " rjust "program " rjust
145
L2: line right 1.5i "\fIcallrpc\fP" "function"
146
move up 1.5i; line dotted down 6i; move up 4.5i
147
arrow right 1i
148
L3: arrow down 1i "invoke " rjust "service " rjust
149
L4: arrow right 1.5i "call" "service"
150
L5: arrow down 1i " service" ljust " executes" ljust
151
L6: arrow left 1.5i "\fIreturn\fP" "answer"
152
L7: arrow down 1i "request " rjust "completed " rjust
153
L8: line left 1i
154
arrow left 1.5i "\fIreturn\fP" "reply"
155
L9: arrow down 1i "program " rjust "continues " rjust
156
line dashed down from L2 to L9
157
line dashed down from L4 to L7
158
line dashed up 1i from L3 "service " rjust "daemon " rjust
159
arrow dashed down 1i from L8
160
move right 1i from L3
161
box invis "Machine B"
162
move left 1.2i from L2; move down
163
box 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
174
Imagine you're writing a program that needs to know
175
how many users are logged into a remote machine.
176
You can do this by calling the RPC library routine
177
.I rnusers()
178
as illustrated below:
179
.ie t .DS
180
.el .DS L
181
.ft CW
182
#include 
183
 
184
main(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
203
RPC library routines such as
204
.I rnusers()
205
are in the RPC services library
206
.I librpcsvc.a
207
Thus, the program above should be compiled with
208
.DS
209
.ft CW
210
% cc \fIprogram.c -lrpcsvc\fP
211
.DE
212
.I rnusers (),
213
like the other RPC library routines, is documented in section 3R
214
of the
215
.I "System Interface Manual for the Sun Workstation" ,
216
the same section which documents the standard Sun RPC services.
217
.IX "RPC Services"
218
See the
219
.I intro(3R)
220
manual page for an explanation of the documentation strategy
221
for these services and their RPC protocols.
222
.LP
223
Here are some of the RPC service library routines available to the
224
C programmer:
225
.LP
226
\fBTable 3-3\fI RPC Service Library Routines\RP
227
.TS
228
box tab (&) ;
229
cfI cfI
230
lfL l .
231
Routine&Description
232
_
233
.sp.5
234
rnusers&Return number of users on remote machine
235
rusers&Return information about users on remote machine
236
havedisk&Determine if remote machine has disk
237
rstats&Get performance data from remote kernel
238
rwall&Write to specified remote machines
239
yppasswd&Update user password in Yellow Pages
240
.TE
241
.LP
242
Other RPC services \(em for example
243
.I ether()
244
.I mount
245
.I rquota()
246
and
247
.I spray
248
\(em are not available to the C programmer as library routines.
249
They do, however,
250
have RPC program numbers so they can be invoked with
251
.I callrpc()
252
which will be discussed in the next section.  Most of them also
253
have compilable
254
.I rpcgen(1)
255
protocol description files.  (The
256
.I rpcgen
257
protocol compiler radically simplifies the process of developing
258
network applications.
259
See the \fBrpcgen\fI Programming Guide\fR
260
for detailed information about
261
.I rpcgen
262
and
263
.I rpcgen
264
protocol description files).
265
.KS
266
.NH 2
267
\&Intermediate Layer
268
.IX "intermediate layer of RPC"
269
.IX "RPC" "intermediate layer"
270
.LP
271
The simplest interface, which explicitly makes RPC calls, uses the
272
functions
273
.I callrpc()
274
and
275
.I registerrpc()
276
Using this method, the number of remote users can be gotten as follows:
277
.ie t .DS
278
.el .DS L
279
#include 
280
#include 
281
#include 
282
#include 
283
 
284
main(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
306
Each RPC procedure is uniquely defined by a program number,
307
version number, and procedure number.  The program number
308
specifies a group of related remote procedures, each of
309
which has a different procedure number.  Each program also
310
has a version number, so when a minor change is made to a
311
remote service (adding a new procedure, for example), a new
312
program number doesn't have to be assigned.  When you want
313
to call a procedure to find the number of remote users, you
314
look up the appropriate program, version and procedure numbers
315
in a manual, just as you look up the name of a memory allocator
316
when you want to allocate memory.
317
.LP
318
The simplest way of making remote procedure calls is with the the RPC
319
library routine
320
.I callrpc()
321
It has eight parameters.  The first is the name of the remote server
322
machine.  The next three parameters are the program, version, and procedure
323
numbers\(emtogether they identify the procedure to be called.
324
The fifth and sixth parameters are an XDR filter and an argument to
325
be encoded and passed to the remote procedure.
326
The final two parameters are a filter for decoding the results
327
returned by the remote procedure and a pointer to the place where
328
the procedure's results are to be stored.  Multiple arguments and
329
results are handled by embedding them in structures.  If
330
.I callrpc()
331
completes successfully, it returns zero; else it returns a nonzero
332
value.  The return codes (of type
333
.IX "enum clnt_stat (in RPC programming)" "" "\fIenum clnt_stat\fP (in RPC programming)"
334
cast into an integer) are found in
335
.I  .
336
.LP
337
Since data types may be represented differently on different machines,
338
.I callrpc()
339
needs both the type of the RPC argument, as well as
340
a pointer to the argument itself (and similarly for the result).  For
341
.I RUSERSPROC_NUM ,
342
the return value is an
343
.I "unsigned long"
344
so
345
.I callrpc()
346
has
347
.I xdr_u_long()
348
as its first return parameter, which says
349
that the result is of type
350
.I "unsigned long"
351
and
352
.I &nusers
353
as its second return parameter,
354
which is a pointer to where the long result will be placed.  Since
355
.I RUSERSPROC_NUM
356
takes no argument, the argument parameter of
357
.I callrpc()
358
is
359
.I xdr_void ().
360
.LP
361
After trying several times to deliver a message, if
362
.I callrpc()
363
gets no answer, it returns with an error code.
364
The delivery mechanism is UDP,
365
which stands for User Datagram Protocol.
366
Methods for adjusting the number of retries
367
or for using a different protocol require you to use the lower
368
layer of the RPC library, discussed later in this document.
369
The remote server procedure
370
corresponding to the above might look like this:
371
.ie t .DS
372
.el .DS L
373
.ft CW
374
.ft CW
375
char *
376
nuser(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
391
It takes one argument, which is a pointer to the input
392
of the remote procedure call (ignored in our example),
393
and it returns a pointer to the result.
394
In the current version of C,
395
character pointers are the generic pointers,
396
so both the input argument and the return value are cast to
397
.I "char *" .
398
.LP
399
Normally, a server registers all of the RPC calls it plans
400
to handle, and then goes into an infinite loop waiting to service requests.
401
In this example, there is only a single procedure
402
to 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 
407
#include 
408
#include 
409
#include 
410
 
411
char *nuser();
412
 
413
main()
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
423
The
424
.I registerrpc()
425
routine registers a C procedure as corresponding to a
426
given RPC procedure number.  The first three parameters,
427
.I RUSERPROG ,
428
.I RUSERSVERS ,
429
and
430
.I RUSERSPROC_NUM
431
are the program, version, and procedure numbers
432
of the remote procedure to be registered;
433
.I nuser()
434
is the name of the local procedure that implements the remote
435
procedure; and
436
.I xdr_void()
437
and
438
.I xdr_u_long()
439
are the XDR filters for the remote procedure's arguments and
440
results, respectively.  (Multiple arguments or multiple results
441
are passed as structures).
442
.LP
443
Only the UDP transport mechanism can use
444
.I registerrpc()
445
thus, it is always safe in conjunction with calls generated by
446
.I callrpc() .
447
.SH
448
.IX "UDP 8K warning"
449
Warning: the UDP transport mechanism can only deal with
450
arguments and results less than 8K bytes in length.
451
.LP
452
.LP
453
After registering the local procedure, the server program's
454
main procedure calls
455
.I svc_run (),
456
the RPC library's remote procedure dispatcher.  It is this
457
function that calls the remote procedures in response to RPC
458
call messages.  Note that the dispatcher takes care of decoding
459
remote procedure arguments and encoding results, using the XDR
460
filters 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
466
Program numbers are assigned in groups of
467
.I 0x20000000
468
according to the following chart:
469
.DS
470
.ft CW
471
       0x0 - 0x1fffffff \fRDefined by Sun\fP
472
0x20000000 - 0x3fffffff \fRDefined by user\fP
473
0x40000000 - 0x5fffffff \fRTransient\fP
474
0x60000000 - 0x7fffffff \fRReserved\fP
475
0x80000000 - 0x9fffffff \fRReserved\fP
476
0xa0000000 - 0xbfffffff \fRReserved\fP
477
0xc0000000 - 0xdfffffff \fRReserved\fP
478
0xe0000000 - 0xffffffff \fRReserved\fP
479
.ft R
480
.DE
481
Sun Microsystems administers the first group of numbers, which
482
should be identical for all Sun customers.  If a customer
483
develops an application that might be of general interest, that
484
application should be given an assigned number in the first
485
range.  The second group of numbers is reserved for specific
486
customer applications.  This range is intended primarily for
487
debugging new programs.  The third group is reserved for
488
applications that generate program numbers dynamically.  The
489
final groups are reserved for future use, and should not be
490
used.
491
.LP
492
To register a protocol specification, send a request by network
493
mail to
494
.I rpc@sun
495
or write to:
496
.DS
497
RPC Administrator
498
Sun Microsystems
499
2550 Garcia Ave.
500
Mountain View, CA 94043
501
.DE
502
Please include a compilable
503
.I rpcgen
504
\*Q.x\*U file describing your protocol.
505
You will be given a unique program number in return.
506
.IX RPC administration
507
.IX administration "of RPC"
508
.LP
509
The RPC program numbers and protocol specifications
510
of standard Sun RPC services can be
511
found in the include files in
512
.I "/usr/include/rpcsvc" .
513
These services, however, constitute only a small subset
514
of those which have been registered.  The complete list of
515
registered programs, as of the time when this manual was
516
printed, is:
517
.LP
518
\fBTable 3-2\fI RPC Registered Programs\fR
519
.TS H
520
box tab (&) ;
521
lfBI lfBI lfBI
522
lfL lfL lfI .
523
RPC Number&Program&Description
524
_
525
.TH
526
.sp.5
527
100000&PMAPPROG&portmapper
528
100001&RSTATPROG&remote stats
529
100002&RUSERSPROG&remote users
530
100003&NFSPROG&nfs
531
100004&YPPROG&Yellow Pages
532
100005&MOUNTPROG&mount demon
533
100006&DBXPROG&remote dbx
534
100007&YPBINDPROG&yp binder
535
100008&WALLPROG&shutdown msg
536
100009&YPPASSWDPROG&yppasswd server
537
100010ÐERSTATPROGðer stats
538
100011&RQUOTAPROG&disk quotas
539
100012&SPRAYPROG&spray packets
540
100013&IBM3270PROG&3270 mapper
541
100014&IBMRJEPROG&RJE mapper
542
100015&SELNSVCPROG&selection service
543
100016&RDATABASEPROG&remote database access
544
100017&REXECPROG&remote execution
545
100018&ALICEPROG&Alice Office Automation
546
100019&SCHEDPROG&scheduling service
547
100020&LOCKPROG&local lock manager
548
100021&NETLOCKPROG&network lock manager
549
100022&X25PROG&x.25 inr protocol
550
100023&STATMON1PROG&status monitor 1
551
100024&STATMON2PROG&status monitor 2
552
100025&SELNLIBPROG&selection library
553
100026&BOOTPARAMPROG&boot parameters service
554
100027&MAZEPROG&mazewars game
555
100028&YPUPDATEPROG&yp update
556
100029&KEYSERVEPROG&key server
557
100030&SECURECMDPROG&secure login
558
100031&NETFWDIPROG&nfs net forwarder init
559
100032&NETFWDTPROG&nfs net forwarder trans
560
100033&SUNLINKMAP_PROG&sunlink MAP
561
100034&NETMONPROG&network monitor
562
100035&DBASEPROG&lightweight database
563
100036&PWDAUTHPROG&password authorization
564
100037&TFSPROG&translucent file svc
565
100038&NSEPROG&nse server
566
100039&NSE_ACTIVATE_PROG&nse activate daemon
567
.sp .2i
568
150001&PCNFSDPROG&pc passwd authorization
569
.sp .2i
570
200000&PYRAMIDLOCKINGPROG&Pyramid-locking
571
200001&PYRAMIDSYS5&Pyramid-sys5
572
200002&CADDS_IMAGE&CV cadds_image
573
.sp .2i
574
300001&ADT_RFLOCKPROG&ADT file locking
575
.TE
576
.NH 2
577
\&Passing Arbitrary Data Types
578
.IX "arbitrary data types"
579
.LP
580
In the previous example, the RPC call passes a single
581
.I "unsigned long"
582
RPC can handle arbitrary data structures, regardless of
583
different machines' byte orders or structure layout conventions,
584
by always converting them to a network standard called
585
.I "External Data Representation"
586
(XDR) before
587
sending them over the wire.
588
The process of converting from a particular machine representation
589
to XDR format is called
590
.I serializing ,
591
and the reverse process is called
592
.I deserializing .
593
The type field parameters of
594
.I callrpc()
595
and
596
.I registerrpc()
597
can be a built-in procedure like
598
.I xdr_u_long()
599
in the previous example, or a user supplied one.
600
XDR has these built-in type routines:
601
.IX RPC "built-in routines"
602
.DS
603
.ft CW
604
xdr_int()      xdr_u_int()      xdr_enum()
605
xdr_long()     xdr_u_long()     xdr_bool()
606
xdr_short()    xdr_u_short()    xdr_wrapstring()
607
xdr_char()     xdr_u_char()
608
.DE
609
Note that the routine
610
.I xdr_string()
611
exists, but cannot be used with
612
.I callrpc()
613
and
614
.I registerrpc (),
615
which only pass two parameters to their XDR routines.
616
.I xdr_wrapstring()
617
has only two parameters, and is thus OK.  It calls
618
.I xdr_string ().
619
.LP
620
As an example of a user-defined type routine,
621
if you wanted to send the structure
622
.DS
623
.ft CW
624
struct simple {
625
        int a;
626
        short b;
627
} simple;
628
.DE
629
then you would call
630
.I callrpc()
631
as
632
.DS
633
.ft CW
634
callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
635
        xdr_simple, &simple ...);
636
.DE
637
where
638
.I xdr_simple()
639
is written as:
640
.ie t .DS
641
.el .DS L
642
.ft CW
643
#include 
644
 
645
xdr_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
657
An XDR routine returns nonzero (true in the sense of C) if it
658
completes successfully, and zero otherwise.
659
A complete description of XDR is in the
660
.I "XDR Protocol Specification"
661
section of this manual, only few implementation examples are
662
given here.
663
.LP
664
In addition to the built-in primitives,
665
there are also the prefabricated building blocks:
666
.DS
667
.ft CW
668
xdr_array()       xdr_bytes()     xdr_reference()
669
xdr_vector()      xdr_union()     xdr_pointer()
670
xdr_string()      xdr_opaque()
671
.DE
672
To send a variable array of integers,
673
you might package them up as a structure like this
674
.DS
675
.ft CW
676
struct varintarr {
677
        int *data;
678
        int arrlnth;
679
} arr;
680
.DE
681
and make an RPC call such as
682
.DS
683
.ft CW
684
callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
685
        xdr_varintarr, &arr...);
686
.DE
687
with
688
.I xdr_varintarr()
689
defined as:
690
.ie t .DS
691
.el .DS L
692
.ft CW
693
xdr_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
701
This routine takes as parameters the XDR handle,
702
a pointer to the array, a pointer to the size of the array,
703
the maximum allowable array size,
704
the size of each array element,
705
and an XDR routine for handling each array element.
706
.KS
707
.LP
708
If the size of the array is known in advance, one can use
709
.I xdr_vector (),
710
which serializes fixed-length arrays.
711
.ie t .DS
712
.el .DS L
713
.ft CW
714
int intarr[SIZE];
715
 
716
xdr_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
728
XDR always converts quantities to 4-byte multiples when serializing.
729
Thus, if either of the examples above involved characters
730
instead of integers, each character would occupy 32 bits.
731
That is the reason for the XDR routine
732
.I xdr_bytes()
733
which is like
734
.I xdr_array()
735
except that it packs characters;
736
.I xdr_bytes()
737
has four parameters, similar to the first four parameters of
738
.I xdr_array ().
739
For null-terminated strings, there is also the
740
.I xdr_string()
741
routine, which is the same as
742
.I xdr_bytes()
743
without the length parameter.
744
On serializing it gets the string length from
745
.I strlen (),
746
and on deserializing it creates a null-terminated string.
747
.LP
748
Here is a final example that calls the previously written
749
.I xdr_simple()
750
as well as the built-in functions
751
.I xdr_string()
752
and
753
.I xdr_reference (),
754
which chases pointers:
755
.ie t .DS
756
.el .DS L
757
.ft CW
758
struct finalexample {
759
        char *string;
760
        struct simple *simplep;
761
} finalexample;
762
 
763
xdr_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
776
Note that we could as easily call
777
.I xdr_simple()
778
here 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
785
In the examples given so far,
786
RPC takes care of many details automatically for you.
787
In this section, we'll show you how you can change the defaults
788
by using lower layers of the RPC library.
789
It is assumed that you are familiar with sockets
790
and the system calls for dealing with them.
791
.LP
792
There are several occasions when you may need to use lower layers of
793
RPC.  First, you may need to use TCP, since the higher layer uses UDP,
794
which restricts RPC calls to 8K bytes of data.  Using TCP permits calls
795
to send long streams of data.
796
For an example, see the
797
.I TCP
798
section below.  Second, you may want to allocate and free memory
799
while serializing or deserializing with XDR routines.
800
There is no call at the higher level to let
801
you free memory explicitly.
802
For more explanation, see the
803
.I "Memory Allocation with XDR"
804
section below.
805
Third, you may need to perform authentication
806
on either the client or server side, by supplying
807
credentials or verifying them.
808
See the explanation in the
809
.I Authentication
810
section below.
811
.NH 2
812
\&More on the Server Side
813
.IX RPC "server side"
814
.LP
815
The server for the
816
.I nusers()
817
program shown below does the same thing as the one using
818
.I registerrpc()
819
above, but is written using a lower layer of the RPC package:
820
.ie t .DS
821
.el .DS L
822
.ft CW
823
#include 
824
#include 
825
#include 
826
#include 
827
 
828
main()
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
 
848
nuser(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
876
First, the server gets a transport handle, which is used
877
for receiving and replying to RPC messages.
878
.I registerrpc()
879
uses
880
.I svcudp_create()
881
to get a UDP handle.
882
If you require a more reliable protocol, call
883
.I svctcp_create()
884
instead.
885
If the argument to
886
.I svcudp_create()
887
is
888
.I RPC_ANYSOCK
889
the RPC library creates a socket
890
on which to receive and reply to RPC calls.  Otherwise,
891
.I svcudp_create()
892
expects its argument to be a valid socket number.
893
If you specify your own socket, it can be bound or unbound.
894
If it is bound to a port by the user, the port numbers of
895
.I svcudp_create()
896
and
897
.I clnttcp_create()
898
(the low-level client routine) must match.
899
.LP
900
If the user specifies the
901
.I RPC_ANYSOCK
902
argument, the RPC library routines will open sockets.
903
Otherwise they will expect the user to do so.  The routines
904
.I svcudp_create()
905
and
906
.I clntudp_create()
907
will cause the RPC library routines to
908
.I bind()
909
their socket if it is not bound already.
910
.LP
911
A service may choose to register its port number with the
912
local portmapper service.  This is done is done by specifying
913
a non-zero protocol number in
914
.I svc_register ().
915
Incidently, a client can discover the server's port number by
916
consulting the portmapper on their server's machine.  This can
917
be done automatically by specifying a zero port number in
918
.I clntudp_create()
919
or
920
.I clnttcp_create ().
921
.LP
922
After creating an
923
.I SVCXPRT ,
924
the next step is to call
925
.I pmap_unset()
926
so that if the
927
.I nusers()
928
server crashed earlier,
929
any previous trace of it is erased before restarting.
930
More precisely,
931
.I pmap_unset()
932
erases the entry for
933
.I RUSERSPROG
934
from the port mapper's tables.
935
.LP
936
Finally, we associate the program number for
937
.I nusers()
938
with the procedure
939
.I nuser ().
940
The final argument to
941
.I svc_register()
942
is normally the protocol being used,
943
which, in this case, is
944
.I IPPROTO_UDP
945
Notice that unlike
946
.I registerrpc (),
947
there are no XDR routines involved
948
in the registration process.
949
Also, registration is done on the program,
950
rather than procedure, level.
951
.LP
952
The user routine
953
.I nuser()
954
must call and dispatch the appropriate XDR routines
955
based on the procedure number.
956
Note that
957
two things are handled by
958
.I nuser()
959
that
960
.I registerrpc()
961
handles automatically.
962
The first is that procedure
963
.I NULLPROC
964
(currently zero) returns with no results.
965
This can be used as a simple test
966
for detecting if a remote program is running.
967
Second, there is a check for invalid procedure numbers.
968
If one is detected,
969
.I svcerr_noproc()
970
is called to handle the error.
971
.KS
972
.LP
973
The user service routine serializes the results and returns
974
them to the RPC caller via
975
.I svc_sendreply()
976
Its first parameter is the
977
.I SVCXPRT
978
handle, the second is the XDR routine,
979
and the third is a pointer to the data to be returned.
980
Not illustrated above is how a server
981
handles an RPC program that receives data.
982
As an example, we can add a procedure
983
.I RUSERSPROC_BOOL
984
which has an argument
985
.I nusers (),
986
and returns
987
.I TRUE
988
or
989
.I FALSE
990
depending on whether there are nusers logged on.
991
It would look like this:
992
.ie t .DS
993
.el .DS L
994
.ft CW
995
case 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
1021
The relevant routine is
1022
.I svc_getargs()
1023
which takes an
1024
.I SVCXPRT
1025
handle, the XDR routine,
1026
and 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
1032
XDR routines not only do input and output,
1033
they also do memory allocation.
1034
This is why the second parameter of
1035
.I xdr_array()
1036
is a pointer to an array, rather than the array itself.
1037
If it is
1038
.I NULL ,
1039
then
1040
.I xdr_array()
1041
allocates space for the array and returns a pointer to it,
1042
putting the size of the array in the third argument.
1043
As an example, consider the following XDR routine
1044
.I xdr_chararr1()
1045
which deals with a fixed array of bytes with length
1046
.I SIZE .
1047
.ie t .DS
1048
.el .DS L
1049
.ft CW
1050
xdr_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
1062
If space has already been allocated in
1063
.I chararr ,
1064
it can be called from a server like this:
1065
.ie t .DS
1066
.el .DS L
1067
.ft CW
1068
char chararr[SIZE];
1069
 
1070
svc_getargs(transp, xdr_chararr1, chararr);
1071
.DE
1072
If you want XDR to do the allocation,
1073
you would have to rewrite this routine in the following way:
1074
.ie t .DS
1075
.el .DS L
1076
.ft CW
1077
xdr_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
1087
Then the RPC call might look like this:
1088
.ie t .DS
1089
.el .DS L
1090
.ft CW
1091
char *arrptr;
1092
 
1093
arrptr = NULL;
1094
svc_getargs(transp, xdr_chararr2, &arrptr);
1095
.ft I
1096
/*
1097
 * Use the result here
1098
 */
1099
.ft CW
1100
svc_freeargs(transp, xdr_chararr2, &arrptr);
1101
.DE
1102
Note that, after being used, the character array can be freed with
1103
.I svc_freeargs()
1104
.I svc_freeargs()
1105
will not attempt to free any memory if the variable indicating it
1106
is NULL.  For example, in the the routine
1107
.I xdr_finalexample (),
1108
given earlier, if
1109
.I finalp->string
1110
was NULL, then it would not be freed.  The same is true for
1111
.I finalp->simplep .
1112
.LP
1113
To summarize, each XDR routine is responsible
1114
for serializing, deserializing, and freeing memory.
1115
When an XDR routine is called from
1116
.I callrpc()
1117
the serializing part is used.
1118
When called from
1119
.I svc_getargs()
1120
the deserializer is used.
1121
And when called from
1122
.I svc_freeargs()
1123
the memory deallocator is used.  When building simple examples like those
1124
in this section, a user doesn't have to worry
1125
about the three modes.
1126
See the
1127
.I "External Data Representation: Sun Technical Notes"
1128
for examples of more sophisticated XDR routines that determine
1129
which 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
1135
When you use
1136
.I callrpc()
1137
you have no control over the RPC delivery
1138
mechanism or the socket used to transport the data.
1139
To illustrate the layer of RPC that lets you adjust these
1140
parameters, consider the following code to call the
1141
.I nusers
1142
service:
1143
.ie t .DS
1144
.el .DS L
1145
.ft CW
1146
.vs 11
1147
#include 
1148
#include 
1149
#include 
1150
#include 
1151
#include 
1152
#include 
1153
#include 
1154
 
1155
main(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
1201
The low-level version of
1202
.I callrpc()
1203
is
1204
.I clnt_call()
1205
which takes a
1206
.I CLIENT
1207
pointer rather than a host name.  The parameters to
1208
.I clnt_call()
1209
are a
1210
.I CLIENT
1211
pointer, the procedure number,
1212
the XDR routine for serializing the argument,
1213
a pointer to the argument,
1214
the XDR routine for deserializing the return value,
1215
a pointer to where the return value will be placed,
1216
and the time in seconds to wait for a reply.
1217
.LP
1218
The
1219
.I CLIENT
1220
pointer is encoded with the transport mechanism.
1221
.I callrpc()
1222
uses UDP, thus it calls
1223
.I clntudp_create()
1224
to get a
1225
.I CLIENT
1226
pointer.  To get TCP (Transmission Control Protocol), you would use
1227
.I clnttcp_create() .
1228
.LP
1229
The parameters to
1230
.I clntudp_create()
1231
are the server address, the program number, the version number,
1232
a timeout value (between tries), and a pointer to a socket.
1233
The final argument to
1234
.I clnt_call()
1235
is the total time to wait for a response.
1236
Thus, the number of tries is the
1237
.I clnt_call()
1238
timeout divided by the
1239
.I clntudp_create()
1240
timeout.
1241
.LP
1242
Note that the
1243
.I clnt_destroy()
1244
call
1245
always deallocates the space associated with the
1246
.I CLIENT
1247
handle.  It closes the socket associated with the
1248
.I CLIENT
1249
handle, however, only if the RPC library opened it.  It the
1250
socket was opened by the user, it stays open.  This makes it
1251
possible, in cases where there are multiple client handles
1252
using the same socket, to destroy one handle without closing
1253
the socket that other handles are using.
1254
.LP
1255
To make a stream connection, the call to
1256
.I clntudp_create()
1257
is replaced with a call to
1258
.I clnttcp_create() .
1259
.DS
1260
.ft CW
1261
clnttcp_create(&server_addr, prognum, versnum, &sock,
1262
               inputsize, outputsize);
1263
.DE
1264
There is no timeout argument; instead, the receive and send buffer
1265
sizes must be specified.  When the
1266
.I clnttcp_create()
1267
call is made, a TCP connection is established.
1268
All RPC calls using that
1269
.I CLIENT
1270
handle would use this connection.
1271
The server side of an RPC call using TCP has
1272
.I svcudp_create()
1273
replaced by
1274
.I svctcp_create() .
1275
.DS
1276
.ft CW
1277
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
1278
.DE
1279
The last two arguments to
1280
.I svctcp_create()
1281
are send and receive sizes respectively.  If `0' is specified for
1282
either 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
1289
This section discusses some other aspects of RPC
1290
that 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
1296
Suppose a process is processing RPC requests
1297
while performing some other activity.
1298
If the other activity involves periodically updating a data structure,
1299
the process can set an alarm signal before calling
1300
.I svc_run()
1301
But if the other activity
1302
involves waiting on a a file descriptor, the
1303
.I svc_run()
1304
call won't work.
1305
The code for
1306
.I svc_run()
1307
is as follows:
1308
.ie t .DS
1309
.el .DS L
1310
.ft CW
1311
.vs 11
1312
void
1313
svc_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
1338
You can bypass
1339
.I svc_run()
1340
and call
1341
.I svc_getreqset()
1342
yourself.
1343
All you need to know are the file descriptors
1344
of the socket(s) associated with the programs you are waiting on.
1345
Thus you can have your own
1346
.I select()
1347
.IX select() "" \fIselect()\fP
1348
that waits on both the RPC socket,
1349
and your own descriptors.  Note that
1350
.I svc_fds()
1351
is a bit mask of all the file descriptors that RPC is using for
1352
services.  It can change everytime that
1353
.I any
1354
RPC library routine is called, because descriptors are constantly
1355
being opened and closed, for example for TCP connections.
1356
.NH 2
1357
\&Broadcast RPC
1358
.IX "broadcast RPC"
1359
.IX RPC "broadcast"
1360
.LP
1361
The
1362
.I portmapper
1363
is a daemon that converts RPC program numbers
1364
into DARPA protocol port numbers; see the
1365
.I portmap
1366
man page.  You can't do broadcast RPC without the portmapper.
1367
Here are the main differences between
1368
broadcast RPC and normal RPC calls:
1369
.IP  1.
1370
Normal RPC expects one answer, whereas
1371
broadcast RPC expects many answers
1372
(one or more answer from each responding machine).
1373
.IP  2.
1374
Broadcast RPC can only be supported by packet-oriented (connectionless)
1375
transport protocols like UPD/IP.
1376
.IP  3.
1377
The implementation of broadcast RPC
1378
treats all unsuccessful responses as garbage by filtering them out.
1379
Thus, if there is a version mismatch between the
1380
broadcaster and a remote service,
1381
the user of broadcast RPC never knows.
1382
.IP  4.
1383
All broadcast messages are sent to the portmap port.
1384
Thus, only services that register themselves with their portmapper
1385
are accessible via the broadcast RPC mechanism.
1386
.IP  5.
1387
Broadcast requests are limited in size to the MTU (Maximum Transfer
1388
Unit) 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 
1398
        . . .
1399
enum clnt_stat  clnt_stat;
1400
        . . .
1401
clnt_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
1413
The procedure
1414
.I eachresult()
1415
is called each time a valid result is obtained.
1416
It returns a boolean that indicates
1417
whether or not the user wants more responses.
1418
.ie t .DS
1419
.el .DS L
1420
.ft CW
1421
bool_t done;
1422
        . . .
1423
done = eachresult(resultsp, raddr)
1424
        caddr_t resultsp;
1425
        struct sockaddr_in *raddr; /* \fIAddr of responding machine\fP */
1426
.DE
1427
If
1428
.I done
1429
is
1430
.I TRUE ,
1431
then broadcasting stops and
1432
.I clnt_broadcast()
1433
returns successfully.
1434
Otherwise, the routine waits for another response.
1435
The request is rebroadcast
1436
after a few seconds of waiting.
1437
If no responses come back,
1438
the routine returns with
1439
.I RPC_TIMEDOUT .
1440
.NH 2
1441
\&Batching
1442
.IX "batching"
1443
.IX RPC "batching"
1444
.LP
1445
The RPC architecture is designed so that clients send a call message,
1446
and wait for servers to reply that the call succeeded.
1447
This implies that clients do not compute
1448
while servers are processing a call.
1449
This is inefficient if the client does not want or need
1450
an acknowledgement for every message sent.
1451
It is possible for clients to continue computing
1452
while waiting for a response,
1453
using RPC batch facilities.
1454
.LP
1455
RPC messages can be placed in a \*Qpipeline\*U of calls
1456
to a desired server; this is called batching.
1457
Batching assumes that:
1458
1) each RPC call in the pipeline requires no response from the server,
1459
and the server does not send a response message; and
1460
2) the pipeline of calls is transported on a reliable
1461
byte stream transport such as TCP/IP.
1462
Since the server does not respond to every call,
1463
the client can generate new calls in parallel
1464
with the server executing previous calls.
1465
Furthermore, the TCP/IP implementation can buffer up
1466
many call messages, and send them to the server in one
1467
.I write()
1468
system call.  This overlapped execution
1469
greatly decreases the interprocess communication overhead of
1470
the client and server processes,
1471
and the total elapsed time of a series of calls.
1472
.LP
1473
Since the batched calls are buffered,
1474
the client should eventually do a nonbatched call
1475
in order to flush the pipeline.
1476
.LP
1477
A contrived example of batching follows.
1478
Assume a string rendering service (like a window system)
1479
has two similar calls: one renders a string and returns void results,
1480
while the other renders a string and remains silent.
1481
The service (using the TCP/IP transport) may look like:
1482
.ie t .DS
1483
.el .DS L
1484
.ft CW
1485
#include 
1486
#include 
1487
#include 
1488
 
1489
void windowdispatch();
1490
 
1491
main()
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
 
1510
void
1511
windowdispatch(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
1569
Of course the service could have one procedure
1570
that takes the string and a boolean
1571
to indicate whether or not the procedure should respond.
1572
.LP
1573
In order for a client to take advantage of batching,
1574
the client must perform RPC calls on a TCP-based transport
1575
and the actual calls must have the following attributes:
1576
1) the result's XDR routine must be zero
1577
.I NULL ),
1578
and 2) the RPC call's timeout must be zero.
1579
.KS
1580
.LP
1581
Here is an example of a client that uses batching to render a
1582
bunch of strings; the batching is flushed when the client gets
1583
a null string (EOF):
1584
.ie t .DS
1585
.el .DS L
1586
.ft CW
1587
.vs 11
1588
#include 
1589
#include 
1590
#include 
1591
#include 
1592
#include 
1593
#include 
1594
 
1595
main(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
1638
Since the server sends no message,
1639
the clients cannot be notified of any of the failures that may occur.
1640
Therefore, clients are on their own when it comes to handling errors.
1641
.LP
1642
The above example was completed to render
1643
all of the (2000) lines in the file
1644
.I /etc/termcap .
1645
The rendering service did nothing but throw the lines away.
1646
The example was run in the following four configurations:
1647
1) machine to itself, regular RPC;
1648
2) machine to itself, batched RPC;
1649
3) machine to another, regular RPC; and
1650
4) machine to another, batched RPC.
1651
The results are as follows:
1652
1) 50 seconds;
1653
2) 16 seconds;
1654
3) 52 seconds;
1655
4) 10 seconds.
1656
Running
1657
.I fscanf()
1658
on
1659
.I /etc/termcap
1660
only requires six seconds.
1661
These timings show the advantage of protocols
1662
that allow for overlapped execution,
1663
though these protocols are often hard to design.
1664
.NH 2
1665
\&Authentication
1666
.IX "authentication"
1667
.IX "RPC" "authentication"
1668
.LP
1669
In the examples presented so far,
1670
the caller never identified itself to the server,
1671
and the server never required an ID from the caller.
1672
Clearly, some network services, such as a network filesystem,
1673
require stronger security than what has been presented so far.
1674
.LP
1675
In reality, every RPC call is authenticated by
1676
the RPC package on the server, and similarly,
1677
the RPC client package generates and sends authentication parameters.
1678
Just as different transports (TCP/IP or UDP/IP)
1679
can be used when creating RPC clients and servers,
1680
different forms of authentication can be associated with RPC clients;
1681
the default authentication type used as a default is type
1682
.I none .
1683
.LP
1684
The authentication subsystem of the RPC package is open ended.
1685
That 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
1691
When a caller creates a new RPC client handle as in:
1692
.DS
1693
.ft CW
1694
clnt = clntudp_create(address, prognum, versnum,
1695
                      wait, sockp)
1696
.DE
1697
the appropriate transport instance defaults
1698
the associate authentication handle to be
1699
.DS
1700
.ft CW
1701
clnt->cl_auth = authnone_create();
1702
.DE
1703
The RPC client can choose to use
1704
.I UNIX
1705
style authentication by setting
1706
.I clnt\->cl_auth
1707
after creating the RPC client handle:
1708
.DS
1709
.ft CW
1710
clnt->cl_auth = authunix_create_default();
1711
.DE
1712
This causes each RPC call associated with
1713
.I clnt
1714
to 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
1722
struct 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
1731
These fields are set by
1732
.I authunix_create_default()
1733
by invoking the appropriate system calls.
1734
Since the RPC user created this new style of authentication,
1735
the user is responsible for destroying it with:
1736
.DS
1737
.ft CW
1738
auth_destroy(clnt->cl_auth);
1739
.DE
1740
This should be done in all cases, to conserve memory.
1741
.sp
1742
.IP "\fIThe Server Side\fP"
1743
.LP
1744
Service implementors have a harder time dealing with authentication issues
1745
since the RPC package passes the service dispatch routine a request
1746
that has an arbitrary authentication style associated with it.
1747
Consider 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
1755
struct 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
1763
The
1764
.I rq_cred
1765
is mostly opaque, except for one field of interest:
1766
the 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
1774
struct 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
1781
The RPC package guarantees the following
1782
to the service dispatch routine:
1783
.IP  1.
1784
That the request's
1785
.I rq_cred
1786
is well formed.  Thus the service implementor may inspect the request's
1787
.I rq_cred.oa_flavor
1788
to determine which style of authentication the caller used.
1789
The service implementor may also wish to inspect the other fields of
1790
.I rq_cred
1791
if the style is not one of the styles supported by the RPC package.
1792
.IP  2.
1793
That the request's
1794
.I rq_clntcred
1795
field is either
1796
.I NULL
1797
or points to a well formed structure
1798
that corresponds to a supported style of authentication credentials.
1799
Remember that only
1800
.I unix
1801
style is currently supported, so (currently)
1802
.I rq_clntcred
1803
could be cast to a pointer to an
1804
.I authunix_parms
1805
structure.  If
1806
.I rq_clntcred
1807
is
1808
.I NULL ,
1809
the service implementor may wish to inspect the other (opaque) fields of
1810
.I rq_cred
1811
in case the service knows about a new type of authentication
1812
that the RPC package does not know about.
1813
.LP
1814
Our remote users service example can be extended so that
1815
it computes results for all users except UID 16:
1816
.ie t .DS
1817
.el .DS L
1818
.ft CW
1819
.vs 11
1820
nuser(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
1885
A few things should be noted here.
1886
First, it is customary not to check
1887
the authentication parameters associated with the
1888
.I NULLPROC
1889
(procedure number zero).
1890
Second, if the authentication parameter's type is not suitable
1891
for your service, you should call
1892
.I svcerr_weakauth() .
1893
And finally, the service protocol itself should return status
1894
for access denied; in the case of our example, the protocol
1895
does not have such a status, so we call the service primitive
1896
.I svcerr_systemerr()
1897
instead.
1898
.LP
1899
The last point underscores the relation between
1900
the RPC authentication package and the services;
1901
RPC deals only with
1902
.I authentication
1903
and not with individual services'
1904
.I "access control" .
1905
The services themselves must implement their own access control policies
1906
and 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
1912
UNIX authentication is quite easy to defeat.  Instead of using
1913
.I authunix_create_default (),
1914
one can call
1915
.I authunix_create()
1916
and then modify the RPC authentication handle it returns by filling in
1917
whatever user ID and hostname they wish the server to think they have.
1918
DES authentication is thus recommended for people who want more security
1919
than UNIX authentication offers.
1920
.LP
1921
The details of the DES authentication protocol are complicated and
1922
are not explained here.
1923
See
1924
.I "Remote Procedure Calls: Protocol Specification"
1925
for the details.
1926
.LP
1927
In  order for  DES authentication   to  work, the
1928
.I keyserv(8c)
1929
daemon must be running  on both  the  server  and client machines.  The
1930
users on  these machines  need  public  keys  assigned by  the network
1931
administrator in  the
1932
.I publickey(5)
1933
database.  And,  they  need to have decrypted  their  secret keys
1934
using  their  login   password.  This automatically happens when one
1935
logs in using
1936
.I login(1) ,
1937
or can be done manually using
1938
.I keylogin(1) .
1939
The
1940
.I "Network Services"
1941
chapter
1942
./" XXX
1943
explains more how to setup secure networking.
1944
.sp
1945
.IP "\fIClient Side\fP"
1946
.LP
1947
If a client wishes to use DES authentication, it must set its
1948
authentication handle appropriately.  Here is an example:
1949
.DS
1950
cl->cl_auth =
1951
        authdes_create(servername, 60, &server_addr, NULL);
1952
.DE
1953
The first argument is the network name or \*Qnetname\*U of the owner of
1954
the server process.  Typically, server processes are root processes
1955
and their netname can be derived using the following call:
1956
.DS
1957
char servername[MAXNETNAMELEN];
1958
 
1959
host2netname(servername, rhostname, NULL);
1960
.DE
1961
Here,
1962
.I rhostname
1963
is the hostname of the machine the server process is running on.
1964
.I host2netname()
1965
fills in
1966
.I servername
1967
to contain this root process's netname.  If the
1968
server process was run by a regular user, one could use the call
1969
.I user2netname()
1970
instead.  Here is an example for a server process with the same user
1971
ID as the client:
1972
.DS
1973
char servername[MAXNETNAMELEN];
1974
 
1975
user2netname(servername, getuid(), NULL);
1976
.DE
1977
The last argument to both of these calls,
1978
.I user2netname()
1979
and
1980
.I host2netname (),
1981
is the name of the naming domain where the server is located.  The
1982
.I NULL
1983
used here means \*Quse the local domain name.\*U
1984
.LP
1985
The second argument to
1986
.I authdes_create()
1987
is a lifetime for the credential.  Here it is set to sixty
1988
seconds.  What that means is that the credential will expire 60
1989
seconds from now.  If some mischievous user tries to reuse the
1990
credential, the server RPC subsystem will recognize that it has
1991
expired and not grant any requests.  If the same mischievous user
1992
tries to reuse the credential within the sixty second lifetime,
1993
he will still be rejected because the server RPC subsystem
1994
remembers which credentials it has already seen in the near past,
1995
and will not grant requests to duplicates.
1996
.LP
1997
The third argument to
1998
.I authdes_create()
1999
is the address of the host to synchronize with.  In order for DES
2000
authentication to work, the server and client must agree upon the
2001
time.  Here we pass the address of the server itself, so the
2002
client and server will both be using the same time: the server's
2003
time.  The argument can be
2004
.I NULL ,
2005
which means \*Qdon't bother synchronizing.\*U You should only do this
2006
if you are sure the client and server are already synchronized.
2007
.LP
2008
The final argument to
2009
.I authdes_create()
2010
is the address of a DES encryption key to use for encrypting
2011
timestamps and data.  If this argument is
2012
.I NULL ,
2013
as it is in this example, a random key will be chosen.  The client
2014
may find out the encryption key being used by consulting the
2015
.I ah_key
2016
field of the authentication handle.
2017
.sp
2018
.IP "\fIServer Side\fP"
2019
.LP
2020
The server side is a lot simpler than the client side.  Here is the
2021
previous example rewritten to use
2022
.I AUTH_DES
2023
instead of
2024
.I AUTH_UNIX :
2025
.ie t .DS
2026
.el .DS L
2027
.ft CW
2028
.vs 11
2029
#include 
2030
#include 
2031
        . . .
2032
        . . .
2033
nuser(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
2083
Note the use of the routine
2084
.I netname2user (),
2085
the inverse of
2086
.I user2netname ():
2087
it takes a network ID and converts to a unix ID.
2088
.I netname2user ()
2089
also supplies the group IDs which we don't use in this example,
2090
but which may be useful to other UNIX programs.
2091
.NH 2
2092
\&Using Inetd
2093
.IX inetd "" "using \fIinetd\fP"
2094
.LP
2095
An RPC server can be started from
2096
.I inetd
2097
The only difference from the usual code is that the service
2098
creation routine should be called in the following form:
2099
.ie t .DS
2100
.el .DS L
2101
.ft CW
2102
transp = svcudp_create(0);     /* \fIFor UDP\fP */
2103
transp = svctcp_create(0,0,0); /* \fIFor listener TCP sockets\fP */
2104
transp = svcfd_create(0,0,0);  /* \fIFor connected TCP sockets\fP */
2105
.DE
2106
since
2107
.I inet
2108
passes a socket as file descriptor 0.
2109
Also,
2110
.I svc_register()
2111
should be called as
2112
.ie t .DS
2113
.el .DS L
2114
.ft CW
2115
svc_register(transp, PROGNUM, VERSNUM, service, 0);
2116
.DE
2117
with the final flag as 0,
2118
since the program would already be registered by
2119
.I inetd
2120
Remember that if you want to exit
2121
from the server process and return control to
2122
.I inet
2123
you need to explicitly exit, since
2124
.I svc_run()
2125
never returns.
2126
.LP
2127
The format of entries in
2128
.I /etc/inetd.conf
2129
for RPC services is in one of the following two forms:
2130
.ie t .DS
2131
.el .DS L
2132
.ft CW
2133
p_name/version dgram  rpc/udp wait/nowait user server args
2134
p_name/version stream rpc/tcp wait/nowait user server args
2135
.DE
2136
where
2137
.I p_name
2138
is the symbolic name of the program as it appears in
2139
.I rpc(5) ,
2140
.I server
2141
is the program implementing the server,
2142
and
2143
.I program
2144
and
2145
.I version
2146
are the program and version numbers of the service.
2147
For more information, see
2148
.I inetd.conf(5) .
2149
.LP
2150
If the same program handles multiple versions,
2151
then the version number can be a range,
2152
as in this example:
2153
.ie t .DS
2154
.el .DS L
2155
.ft CW
2156
rstatd/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
2166
By convention, the first version number of program
2167
.I PROG
2168
is
2169
.I PROGVERS_ORIG
2170
and the most recent version is
2171
.I PROGVERS
2172
Suppose there is a new version of the
2173
.I user
2174
program that returns an
2175
.I "unsigned short"
2176
rather than a
2177
.I long .
2178
If we name this version
2179
.I RUSERSVERS_SHORT
2180
then a server that wants to support both versions
2181
would do a double register.
2182
.ie t .DS
2183
.el .DS L
2184
.ft CW
2185
if (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG,
2186
  nuser, IPPROTO_TCP)) {
2187
        fprintf(stderr, "can't register RUSER service\en");
2188
        exit(1);
2189
}
2190
if (!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
2196
Both versions can be handled by the same C procedure:
2197
.ie t .DS
2198
.el .DS L
2199
.ft CW
2200
.vs 11
2201
nuser(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
2249
Here is an example that is essentially
2250
.I rcp.
2251
The initiator of the RPC
2252
.I snd
2253
call takes its standard input and sends it to the server
2254
.I rcv
2255
which prints it on standard output.
2256
The RPC call uses TCP.
2257
This also illustrates an XDR procedure that behaves differently
2258
on 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 
2270
#include 
2271
 
2272
xdr_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 
2315
#include 
2316
#include 
2317
#include 
2318
#include 
2319
 
2320
main(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
 
2340
callrpctcp(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 
2383
#include 
2384
 
2385
main()
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
 
2405
rcp_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
2437
Occasionally, it is useful to have a server become a client,
2438
and make an RPC call back to the process which is its client.
2439
An example is remote debugging,
2440
where the client is a window system program,
2441
and the server is a debugger running on the remote machine.
2442
Most of the time,
2443
the user clicks a mouse button at the debugging window,
2444
which converts this to a debugger command,
2445
and then makes an RPC call to the server
2446
(where the debugger is actually running),
2447
telling it to execute that command.
2448
However, when the debugger hits a breakpoint, the roles are reversed,
2449
and the debugger wants to make an rpc call to the window program,
2450
so that it can inform the user that a breakpoint has been reached.
2451
.LP
2452
In order to do an RPC callback,
2453
you need a program number to make the RPC call on.
2454
Since this will be a dynamically generated program number,
2455
it should be in the transient range,
2456
.I "0x40000000 - 0x5fffffff" .
2457
The routine
2458
.I gettransient()
2459
returns a valid program number in the transient range,
2460
and registers it with the portmapper.
2461
It only talks to the portmapper running on the same machine as the
2462
.I gettransient()
2463
routine itself.  The call to
2464
.I pmap_set()
2465
is a test and set operation,
2466
in that it indivisibly tests whether a program number
2467
has already been registered,
2468
and if it has not, then reserves it.  On return, the
2469
.I sockp
2470
argument will contain a socket that can be used
2471
as the argument to an
2472
.I svcudp_create()
2473
or
2474
.I svctcp_create()
2475
call.
2476
.ie t .DS
2477
.el .DS L
2478
.ft CW
2479
.vs 11
2480
#include 
2481
#include 
2482
#include 
2483
 
2484
gettransient(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
2532
Note:
2533
.I
2534
The call to
2535
.I ntohs()
2536
is necessary to ensure that the port number in
2537
.I "addr.sin_port" ,
2538
which is in
2539
.I network
2540
byte order, is passed in
2541
.I host
2542
byte order (as
2543
.I pmap_set()
2544
expects).  See the
2545
.I byteorder(3N)
2546
man page for more details on the conversion of network
2547
addresses from network to host byte order.
2548
.KS
2549
.LP
2550
The following pair of programs illustrate how to use the
2551
.I gettransient()
2552
routine.
2553
The client makes an RPC call to the server,
2554
passing it a transient program number.
2555
Then the client waits around to receive a callback
2556
from the server at that program number.
2557
The server registers the program
2558
.I EXAMPLEPROG
2559
so that it can receive the RPC call
2560
informing it of the callback program number.
2561
Then at some random time (on receiving an
2562
.I ALRM
2563
signal in this example), it sends a callback RPC call,
2564
using 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 
2574
#include 
2575
 
2576
int callback();
2577
char hostname[256];
2578
 
2579
main()
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
 
2608
callback(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 
2643
#include 
2644
#include 
2645
 
2646
char *getnewprog();
2647
char hostname[256];
2648
int docallback();
2649
int pnum;               /* \fIprogram number for callback routine\fP */
2650
 
2651
main()
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
 
2663
char *
2664
getnewprog(pnump)
2665
        char *pnump;
2666
{
2667
        pnum = *(int *)pnump;
2668
        return NULL;
2669
}
2670
 
2671
docallback()
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.