2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
25 * Sun Microsystems, Inc.
27 * Mountain View, California 94043
29 * @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro
30 * @(#)svc.c 2.4 88/08/11 4.0 RPCSRC
31 * $FreeBSD: src/lib/libc/rpc/svc.c,v 1.14.2.1 2001/03/05 10:50:36 obrien Exp $
32 * $DragonFly: src/lib/libc/rpc/svc.c,v 1.4 2005/11/13 12:27:04 swildner Exp $
36 * svc.c, Server-side remote procedure call interface.
38 * There are two sets of procedures here. The xprt routines are
39 * for handling transport handles. The svc routines handle the
40 * list of service routines.
42 * Copyright (C) 1984, Sun Microsystems, Inc.
48 #include <rpc/pmap_clnt.h>
50 static SVCXPRT
**xports
;
51 static int xportssize
;
53 #define NULL_SVC ((struct svc_callout *)0)
54 #define RQCRED_SIZE 400 /* this size is excessive */
56 #define max(a, b) (a > b ? a : b)
60 * Each entry represents a set of procedures (an rpc program).
61 * The dispatch routine takes request structs and runs the
62 * apropriate procedure.
64 static struct svc_callout
{
65 struct svc_callout
*sc_next
;
68 void (*sc_dispatch
)();
71 static struct svc_callout
*svc_find();
73 int __svc_fdsetsize
= 0;
74 fd_set
*__svc_fdset
= NULL
;
76 /* *************** SVCXPRT related stuff **************** */
79 * Activate a transport handle.
82 xprt_register(SVCXPRT
*xprt
)
84 int sock
= xprt
->xp_sock
;
86 if (sock
+ 1 > __svc_fdsetsize
) {
87 int bytes
= howmany(sock
+ 1, NFDBITS
) * sizeof(fd_mask
);
90 fds
= (fd_set
*)malloc(bytes
);
91 memset(fds
, 0, bytes
);
93 memcpy(fds
, __svc_fdset
, howmany(__svc_fdsetsize
,
94 NFDBITS
) * sizeof(fd_mask
));
98 __svc_fdsetsize
= howmany(sock
+1, NFDBITS
) * NFDBITS
;
101 if (sock
< FD_SETSIZE
)
102 FD_SET(sock
, &svc_fdset
);
103 FD_SET(sock
, __svc_fdset
);
105 if (xports
== NULL
|| sock
+ 1 > xportssize
) {
107 int size
= FD_SETSIZE
;
111 xp
= (SVCXPRT
**)mem_alloc(size
* sizeof(SVCXPRT
*));
112 memset(xp
, 0, size
* sizeof(SVCXPRT
*));
114 memcpy(xp
, xports
, xportssize
* sizeof(SVCXPRT
*));
121 svc_maxfd
= max(svc_maxfd
, sock
);
125 * De-activate a transport handle.
128 xprt_unregister(SVCXPRT
*xprt
)
130 int sock
= xprt
->xp_sock
;
132 if (xports
[sock
] == xprt
) {
133 xports
[sock
] = (SVCXPRT
*)0;
134 if (sock
< FD_SETSIZE
)
135 FD_CLR(sock
, &svc_fdset
);
136 FD_CLR(sock
, __svc_fdset
);
137 if (sock
== svc_maxfd
) {
138 for (svc_maxfd
--; svc_maxfd
>= 0; svc_maxfd
--)
139 if (xports
[svc_maxfd
])
143 * XXX could use svc_maxfd as a hint to
144 * decrease the size of __svc_fdset
150 /* ********************** CALLOUT list related stuff ************* */
153 * Add a service program to the callout list.
154 * The dispatch routine will be called when a rpc request for this
155 * program number comes in.
158 svc_register(SVCXPRT
*xprt
, u_long prog
, u_long vers
, void (*dispatch
)(),
161 struct svc_callout
*prev
;
162 struct svc_callout
*s
;
164 if ((s
= svc_find(prog
, vers
, &prev
)) != NULL_SVC
) {
165 if (s
->sc_dispatch
== dispatch
)
166 goto pmap_it
; /* he is registering another xptr */
169 s
= (struct svc_callout
*)mem_alloc(sizeof(struct svc_callout
));
170 if (s
== (struct svc_callout
*)0) {
175 s
->sc_dispatch
= dispatch
;
176 s
->sc_next
= svc_head
;
179 /* now register the information with the local binder service */
181 return (pmap_set(prog
, vers
, protocol
, xprt
->xp_port
));
187 * Remove a service program from the callout list.
190 svc_unregister(u_long prog
, u_long vers
)
192 struct svc_callout
*prev
;
193 struct svc_callout
*s
;
195 if ((s
= svc_find(prog
, vers
, &prev
)) == NULL_SVC
)
197 if (prev
== NULL_SVC
) {
198 svc_head
= s
->sc_next
;
200 prev
->sc_next
= s
->sc_next
;
202 s
->sc_next
= NULL_SVC
;
203 mem_free((char *) s
, (u_int
) sizeof(struct svc_callout
));
204 /* now unregister the information with the local binder service */
205 pmap_unset(prog
, vers
);
209 * Search the callout list for a program number, return the callout
212 static struct svc_callout
*
213 svc_find(u_long prog
, u_long vers
, struct svc_callout
**prev
)
215 struct svc_callout
*s
, *p
;
218 for (s
= svc_head
; s
!= NULL_SVC
; s
= s
->sc_next
) {
219 if ((s
->sc_prog
== prog
) && (s
->sc_vers
== vers
))
228 /* ******************* REPLY GENERATION ROUTINES ************ */
231 * Send a reply to an rpc request
234 svc_sendreply(SVCXPRT
*xprt
, xdrproc_t xdr_results
, caddr_t xdr_location
)
238 rply
.rm_direction
= REPLY
;
239 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
240 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
241 rply
.acpted_rply
.ar_stat
= SUCCESS
;
242 rply
.acpted_rply
.ar_results
.where
= xdr_location
;
243 rply
.acpted_rply
.ar_results
.proc
= xdr_results
;
244 return (SVC_REPLY(xprt
, &rply
));
248 * No procedure error reply
251 svcerr_noproc(SVCXPRT
*xprt
)
255 rply
.rm_direction
= REPLY
;
256 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
257 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
258 rply
.acpted_rply
.ar_stat
= PROC_UNAVAIL
;
259 SVC_REPLY(xprt
, &rply
);
263 * Can't decode args error reply
266 svcerr_decode(SVCXPRT
*xprt
)
270 rply
.rm_direction
= REPLY
;
271 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
272 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
273 rply
.acpted_rply
.ar_stat
= GARBAGE_ARGS
;
274 SVC_REPLY(xprt
, &rply
);
281 svcerr_systemerr(SVCXPRT
*xprt
)
285 rply
.rm_direction
= REPLY
;
286 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
287 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
288 rply
.acpted_rply
.ar_stat
= SYSTEM_ERR
;
289 SVC_REPLY(xprt
, &rply
);
293 * Authentication error reply
296 svcerr_auth(SVCXPRT
*xprt
, enum auth_stat why
)
300 rply
.rm_direction
= REPLY
;
301 rply
.rm_reply
.rp_stat
= MSG_DENIED
;
302 rply
.rjcted_rply
.rj_stat
= AUTH_ERROR
;
303 rply
.rjcted_rply
.rj_why
= why
;
304 SVC_REPLY(xprt
, &rply
);
308 * Auth too weak error reply
311 svcerr_weakauth(SVCXPRT
*xprt
)
314 svcerr_auth(xprt
, AUTH_TOOWEAK
);
318 * Program unavailable error reply
321 svcerr_noprog(SVCXPRT
*xprt
)
325 rply
.rm_direction
= REPLY
;
326 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
327 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
328 rply
.acpted_rply
.ar_stat
= PROG_UNAVAIL
;
329 SVC_REPLY(xprt
, &rply
);
333 * Program version mismatch error reply
336 svcerr_progvers(SVCXPRT
*xprt
, u_long low_vers
, u_long high_vers
)
340 rply
.rm_direction
= REPLY
;
341 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
342 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
343 rply
.acpted_rply
.ar_stat
= PROG_MISMATCH
;
344 rply
.acpted_rply
.ar_vers
.low
= low_vers
;
345 rply
.acpted_rply
.ar_vers
.high
= high_vers
;
346 SVC_REPLY(xprt
, &rply
);
349 /* ******************* SERVER INPUT STUFF ******************* */
352 * Get server side input from some transport.
354 * Statement of authentication parameters management:
355 * This function owns and manages all authentication parameters, specifically
356 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
357 * the "cooked" credentials (rqst->rq_clntcred).
358 * However, this function does not know the structure of the cooked
359 * credentials, so it make the following assumptions:
360 * a) the structure is contiguous (no pointers), and
361 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
362 * In all events, all three parameters are freed upon exit from this routine.
363 * The storage is trivially management on the call stack in user land, but
364 * is mallocated in kernel land.
368 svc_getreq(int rdfds
)
373 readfds
.fds_bits
[0] = rdfds
;
374 svc_getreqset(&readfds
);
378 svc_getreqset(fd_set
*readfds
)
380 svc_getreqset2(readfds
, FD_SETSIZE
);
384 svc_getreqset2(fd_set
*readfds
, int width
)
395 fd_mask mask
, *maskp
;
396 char cred_area
[2*MAX_AUTH_BYTES
+ RQCRED_SIZE
];
397 msg
.rm_call
.cb_cred
.oa_base
= cred_area
;
398 msg
.rm_call
.cb_verf
.oa_base
= &(cred_area
[MAX_AUTH_BYTES
]);
399 r
.rq_clntcred
= &(cred_area
[2*MAX_AUTH_BYTES
]);
402 maskp
= readfds
->fds_bits
;
403 for (sock
= 0; sock
< width
; sock
+= NFDBITS
) {
404 for (mask
= *maskp
++; (bit
= ffs(mask
)); mask
^= (1 << (bit
- 1))) {
405 /* sock has input waiting */
406 xprt
= xports
[sock
+ bit
- 1];
408 /* But do we control sock? */
410 /* now receive msgs from xprtprt (support batch calls) */
412 if (SVC_RECV(xprt
, &msg
)) {
414 /* now find the exported program and call it */
415 struct svc_callout
*s
;
419 r
.rq_prog
= msg
.rm_call
.cb_prog
;
420 r
.rq_vers
= msg
.rm_call
.cb_vers
;
421 r
.rq_proc
= msg
.rm_call
.cb_proc
;
422 r
.rq_cred
= msg
.rm_call
.cb_cred
;
423 /* first authenticate the message */
424 if ((why
= _authenticate(&r
, &msg
)) != AUTH_OK
) {
425 svcerr_auth(xprt
, why
);
428 /* now match message with a registered service*/
430 low_vers
= (u_long
) - 1;
432 for (s
= svc_head
; s
!= NULL_SVC
; s
= s
->sc_next
) {
433 if (s
->sc_prog
== r
.rq_prog
) {
434 if (s
->sc_vers
== r
.rq_vers
) {
435 (*s
->sc_dispatch
)(&r
, xprt
);
437 } /* found correct version */
439 if (s
->sc_vers
< low_vers
)
440 low_vers
= s
->sc_vers
;
441 if (s
->sc_vers
> high_vers
)
442 high_vers
= s
->sc_vers
;
443 } /* found correct program */
446 * if we got here, the program or version
450 svcerr_progvers(xprt
,
451 low_vers
, high_vers
);
454 /* Fall through to ... */
457 if ((stat
= SVC_STAT(xprt
)) == XPRT_DIED
){
461 } while (stat
== XPRT_MOREREQS
);