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 * $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $
32 * $FreeBSD: src/lib/libc/rpc/svc.c,v 1.24 2006/02/27 22:10:59 deischen Exp $
33 * $DragonFly: src/lib/libc/rpc/svc.c,v 1.4 2005/11/13 12:27:04 swildner Exp $
37 * svc.c, Server-side remote procedure call interface.
39 * There are two sets of procedures here. The xprt routines are
40 * for handling transport handles. The svc routines handle the
41 * list of service routines.
43 * Copyright (C) 1984, Sun Microsystems, Inc.
46 #include "namespace.h"
47 #include "reentrant.h"
48 #include <sys/types.h>
57 #include <rpc/pmap_clnt.h>
59 #include "un-namespace.h"
64 #define RQCRED_SIZE 400 /* this size is excessive */
66 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
67 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
69 #define max(a, b) (a > b ? a : b)
73 * Each entry represents a set of procedures (an rpc program).
74 * The dispatch routine takes request structs and runs the
75 * apropriate procedure.
77 static struct svc_callout
{
78 struct svc_callout
*sc_next
;
82 void (*sc_dispatch
)(struct svc_req
*, SVCXPRT
*);
85 static struct svc_callout
*svc_find(rpcprog_t
, rpcvers_t
,
86 struct svc_callout
**, char *);
87 static void __xprt_do_unregister (SVCXPRT
*xprt
, bool_t dolock
);
89 /* *************** SVCXPRT related stuff **************** */
92 * Activate a transport handle.
95 xprt_register(SVCXPRT
*xprt
)
103 rwlock_wrlock(&svc_fd_lock
);
104 if (__svc_xports
== NULL
) {
105 __svc_xports
= (SVCXPRT
**)
106 mem_alloc(FD_SETSIZE
* sizeof(SVCXPRT
*));
107 if (__svc_xports
== NULL
)
109 memset(__svc_xports
, '\0', FD_SETSIZE
* sizeof(SVCXPRT
*));
111 if (sock
< FD_SETSIZE
) {
112 __svc_xports
[sock
] = xprt
;
113 FD_SET(sock
, &svc_fdset
);
114 svc_maxfd
= max(svc_maxfd
, sock
);
116 rwlock_unlock(&svc_fd_lock
);
120 xprt_unregister(SVCXPRT
*xprt
)
122 __xprt_do_unregister(xprt
, TRUE
);
126 __xprt_unregister_unlocked(SVCXPRT
*xprt
)
128 __xprt_do_unregister(xprt
, FALSE
);
132 * De-activate a transport handle.
135 __xprt_do_unregister(SVCXPRT
*xprt
, bool_t dolock
)
139 assert(xprt
!= NULL
);
144 rwlock_wrlock(&svc_fd_lock
);
145 if ((sock
< FD_SETSIZE
) && (__svc_xports
[sock
] == xprt
)) {
146 __svc_xports
[sock
] = NULL
;
147 FD_CLR(sock
, &svc_fdset
);
148 if (sock
>= svc_maxfd
) {
149 for (svc_maxfd
--; svc_maxfd
>=0; svc_maxfd
--)
150 if (__svc_xports
[svc_maxfd
])
155 rwlock_unlock(&svc_fd_lock
);
159 * Add a service program to the callout list.
160 * The dispatch routine will be called when a rpc request for this
161 * program number comes in.
164 svc_reg(SVCXPRT
*xprt
, const rpcprog_t prog
, const rpcvers_t vers
,
165 void (*dispatch
)(struct svc_req
*, SVCXPRT
*),
166 const struct netconfig
*nconf
)
169 struct svc_callout
*prev
;
170 struct svc_callout
*s
;
171 struct netconfig
*tnconf
;
175 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
177 if (xprt
->xp_netid
) {
178 netid
= strdup(xprt
->xp_netid
);
180 } else if (nconf
&& nconf
->nc_netid
) {
181 netid
= strdup(nconf
->nc_netid
);
183 } else if ((tnconf
= __rpcgettp(xprt
->xp_fd
)) != NULL
) {
184 netid
= strdup(tnconf
->nc_netid
);
186 freenetconfigent(tnconf
);
187 } /* must have been created with svc_raw_create */
188 if ((netid
== NULL
) && (flag
== 1)) {
192 rwlock_wrlock(&svc_lock
);
193 if ((s
= svc_find(prog
, vers
, &prev
, netid
)) != NULL
) {
196 if (s
->sc_dispatch
== dispatch
)
197 goto rpcb_it
; /* he is registering another xptr */
198 rwlock_unlock(&svc_lock
);
201 s
= mem_alloc(sizeof (struct svc_callout
));
205 rwlock_unlock(&svc_lock
);
211 s
->sc_dispatch
= dispatch
;
213 s
->sc_next
= svc_head
;
216 if ((xprt
->xp_netid
== NULL
) && (flag
== 1) && netid
)
217 ((SVCXPRT
*) xprt
)->xp_netid
= strdup(netid
);
220 rwlock_unlock(&svc_lock
);
221 /* now register the information with the local binder service */
223 /*LINTED const castaway*/
224 dummy
= rpcb_set(prog
, vers
, (struct netconfig
*) nconf
,
225 &((SVCXPRT
*) xprt
)->xp_ltaddr
);
232 * Remove a service program from the callout list.
235 svc_unreg(const rpcprog_t prog
, const rpcvers_t vers
)
237 struct svc_callout
*prev
;
238 struct svc_callout
*s
;
240 /* unregister the information anyway */
241 rpcb_unset(prog
, vers
, NULL
);
242 rwlock_wrlock(&svc_lock
);
243 while ((s
= svc_find(prog
, vers
, &prev
, NULL
)) != NULL
) {
245 svc_head
= s
->sc_next
;
247 prev
->sc_next
= s
->sc_next
;
251 mem_free(s
->sc_netid
, sizeof (s
->sc_netid
) + 1);
252 mem_free(s
, sizeof (struct svc_callout
));
254 rwlock_unlock(&svc_lock
);
257 /* ********************** CALLOUT list related stuff ************* */
261 * Add a service program to the callout list.
262 * The dispatch routine will be called when a rpc request for this
263 * program number comes in.
266 svc_register(SVCXPRT
*xprt
, u_long prog
, u_long vers
,
267 void (*dispatch
)(struct svc_req
*, SVCXPRT
*), int protocol
)
269 struct svc_callout
*prev
;
270 struct svc_callout
*s
;
272 assert(xprt
!= NULL
);
273 assert(dispatch
!= NULL
);
275 if ((s
= svc_find((rpcprog_t
)prog
, (rpcvers_t
)vers
, &prev
, NULL
)) !=
277 if (s
->sc_dispatch
== dispatch
)
278 goto pmap_it
; /* he is registering another xptr */
281 s
= mem_alloc(sizeof(struct svc_callout
));
285 s
->sc_prog
= (rpcprog_t
)prog
;
286 s
->sc_vers
= (rpcvers_t
)vers
;
287 s
->sc_dispatch
= dispatch
;
288 s
->sc_next
= svc_head
;
291 /* now register the information with the local binder service */
293 return (pmap_set(prog
, vers
, protocol
, xprt
->xp_port
));
299 * Remove a service program from the callout list.
302 svc_unregister(u_long prog
, u_long vers
)
304 struct svc_callout
*prev
;
305 struct svc_callout
*s
;
307 if ((s
= svc_find((rpcprog_t
)prog
, (rpcvers_t
)vers
, &prev
, NULL
)) ==
311 svc_head
= s
->sc_next
;
313 prev
->sc_next
= s
->sc_next
;
316 mem_free(s
, sizeof(struct svc_callout
));
317 /* now unregister the information with the local binder service */
318 pmap_unset(prog
, vers
);
323 * Search the callout list for a program number, return the callout
326 static struct svc_callout
*
327 svc_find(rpcprog_t prog
, rpcvers_t vers
, struct svc_callout
**prev
, char *netid
)
329 struct svc_callout
*s
, *p
;
331 assert(prev
!= NULL
);
334 for (s
= svc_head
; s
!= NULL
; s
= s
->sc_next
) {
335 if (((s
->sc_prog
== prog
) && (s
->sc_vers
== vers
)) &&
336 ((netid
== NULL
) || (s
->sc_netid
== NULL
) ||
337 (strcmp(netid
, s
->sc_netid
) == 0)))
345 /* ******************* REPLY GENERATION ROUTINES ************ */
348 * Send a reply to an rpc request
351 svc_sendreply(SVCXPRT
*xprt
, xdrproc_t xdr_results
, void *xdr_location
)
355 assert(xprt
!= NULL
);
357 rply
.rm_direction
= REPLY
;
358 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
359 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
360 rply
.acpted_rply
.ar_stat
= SUCCESS
;
361 rply
.acpted_rply
.ar_results
.where
= xdr_location
;
362 rply
.acpted_rply
.ar_results
.proc
= xdr_results
;
363 return (SVC_REPLY(xprt
, &rply
));
367 * No procedure error reply
370 svcerr_noproc(SVCXPRT
*xprt
)
374 assert(xprt
!= NULL
);
376 rply
.rm_direction
= REPLY
;
377 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
378 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
379 rply
.acpted_rply
.ar_stat
= PROC_UNAVAIL
;
380 SVC_REPLY(xprt
, &rply
);
384 * Can't decode args error reply
387 svcerr_decode(SVCXPRT
*xprt
)
391 assert(xprt
!= NULL
);
393 rply
.rm_direction
= REPLY
;
394 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
395 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
396 rply
.acpted_rply
.ar_stat
= GARBAGE_ARGS
;
397 SVC_REPLY(xprt
, &rply
);
404 svcerr_systemerr(SVCXPRT
*xprt
)
408 assert(xprt
!= NULL
);
410 rply
.rm_direction
= REPLY
;
411 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
412 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
413 rply
.acpted_rply
.ar_stat
= SYSTEM_ERR
;
414 SVC_REPLY(xprt
, &rply
);
418 * Authentication error reply
421 svcerr_auth(SVCXPRT
*xprt
, enum auth_stat why
)
425 assert(xprt
!= NULL
);
427 rply
.rm_direction
= REPLY
;
428 rply
.rm_reply
.rp_stat
= MSG_DENIED
;
429 rply
.rjcted_rply
.rj_stat
= AUTH_ERROR
;
430 rply
.rjcted_rply
.rj_why
= why
;
431 SVC_REPLY(xprt
, &rply
);
435 * Auth too weak error reply
438 svcerr_weakauth(SVCXPRT
*xprt
)
441 assert(xprt
!= NULL
);
443 svcerr_auth(xprt
, AUTH_TOOWEAK
);
447 * Program unavailable error reply
450 svcerr_noprog(SVCXPRT
*xprt
)
454 assert(xprt
!= NULL
);
456 rply
.rm_direction
= REPLY
;
457 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
458 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
459 rply
.acpted_rply
.ar_stat
= PROG_UNAVAIL
;
460 SVC_REPLY(xprt
, &rply
);
464 * Program version mismatch error reply
467 svcerr_progvers(SVCXPRT
*xprt
, rpcvers_t low_vers
, rpcvers_t high_vers
)
471 assert(xprt
!= NULL
);
473 rply
.rm_direction
= REPLY
;
474 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
475 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
476 rply
.acpted_rply
.ar_stat
= PROG_MISMATCH
;
477 rply
.acpted_rply
.ar_vers
.low
= (u_int32_t
)low_vers
;
478 rply
.acpted_rply
.ar_vers
.high
= (u_int32_t
)high_vers
;
479 SVC_REPLY(xprt
, &rply
);
482 /* ******************* SERVER INPUT STUFF ******************* */
485 * Get server side input from some transport.
487 * Statement of authentication parameters management:
488 * This function owns and manages all authentication parameters, specifically
489 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
490 * the "cooked" credentials (rqst->rq_clntcred).
491 * However, this function does not know the structure of the cooked
492 * credentials, so it make the following assumptions:
493 * a) the structure is contiguous (no pointers), and
494 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
495 * In all events, all three parameters are freed upon exit from this routine.
496 * The storage is trivially management on the call stack in user land, but
497 * is mallocated in kernel land.
501 svc_getreq(int rdfds
)
506 readfds
.fds_bits
[0] = rdfds
;
507 svc_getreqset(&readfds
);
511 svc_getreqset(fd_set
*readfds
)
514 fd_mask mask
, *maskp
;
517 assert(readfds
!= NULL
);
519 maskp
= readfds
->fds_bits
;
520 for (sock
= 0; sock
< FD_SETSIZE
; sock
+= NFDBITS
) {
521 for (mask
= *maskp
++; (bit
= ffs(mask
)) != 0;
522 mask
^= (1 << (bit
- 1))) {
523 /* sock has input waiting */
525 svc_getreq_common(fd
);
531 svc_getreq_common(int fd
)
540 char cred_area
[2*MAX_AUTH_BYTES
+ RQCRED_SIZE
];
542 msg
.rm_call
.cb_cred
.oa_base
= cred_area
;
543 msg
.rm_call
.cb_verf
.oa_base
= &(cred_area
[MAX_AUTH_BYTES
]);
544 r
.rq_clntcred
= &(cred_area
[2*MAX_AUTH_BYTES
]);
546 rwlock_rdlock(&svc_fd_lock
);
547 xprt
= __svc_xports
[fd
];
548 rwlock_unlock(&svc_fd_lock
);
550 /* But do we control sock? */
552 /* now receive msgs from xprtprt (support batch calls) */
554 if (SVC_RECV(xprt
, &msg
)) {
556 /* now find the exported program and call it */
557 struct svc_callout
*s
;
561 r
.rq_prog
= msg
.rm_call
.cb_prog
;
562 r
.rq_vers
= msg
.rm_call
.cb_vers
;
563 r
.rq_proc
= msg
.rm_call
.cb_proc
;
564 r
.rq_cred
= msg
.rm_call
.cb_cred
;
565 /* first authenticate the message */
566 if ((why
= _authenticate(&r
, &msg
)) != AUTH_OK
) {
567 svcerr_auth(xprt
, why
);
570 /* now match message with a registered service*/
572 low_vers
= (rpcvers_t
) -1L;
573 high_vers
= (rpcvers_t
) 0L;
574 for (s
= svc_head
; s
!= NULL
; s
= s
->sc_next
) {
575 if (s
->sc_prog
== r
.rq_prog
) {
576 if (s
->sc_vers
== r
.rq_vers
) {
577 (*s
->sc_dispatch
)(&r
, xprt
);
579 } /* found correct version */
581 if (s
->sc_vers
< low_vers
)
582 low_vers
= s
->sc_vers
;
583 if (s
->sc_vers
> high_vers
)
584 high_vers
= s
->sc_vers
;
585 } /* found correct program */
588 * if we got here, the program or version
592 svcerr_progvers(xprt
, low_vers
, high_vers
);
595 /* Fall through to ... */
598 * Check if the xprt has been disconnected in a
599 * recursive call in the service dispatch routine.
602 rwlock_rdlock(&svc_fd_lock
);
603 if (xprt
!= __svc_xports
[fd
]) {
604 rwlock_unlock(&svc_fd_lock
);
607 rwlock_unlock(&svc_fd_lock
);
609 if ((stat
= SVC_STAT(xprt
)) == XPRT_DIED
){
613 } while (stat
== XPRT_MOREREQS
);
618 svc_getreq_poll(struct pollfd
*pfdp
, int pollretval
)
623 for (i
= fds_found
= 0; fds_found
< pollretval
; i
++) {
624 struct pollfd
*p
= &pfdp
[i
];
627 /* fd has input waiting */
630 * We assume that this function is only called
631 * via someone _select()ing from svc_fdset or
632 * _poll()ing from svc_pollset[]. Thus it's safe
633 * to handle the POLLNVAL event by simply turning
634 * the corresponding bit off in svc_fdset. The
635 * svc_pollset[] array is derived from svc_fdset
636 * and so will also be updated eventually.
638 * XXX Should we do an xprt_unregister() instead?
640 if (p
->revents
& POLLNVAL
) {
641 rwlock_wrlock(&svc_fd_lock
);
642 FD_CLR(p
->fd
, &svc_fdset
);
643 rwlock_unlock(&svc_fd_lock
);
645 svc_getreq_common(p
->fd
);
651 rpc_control(int what
, void *arg
)
656 case RPC_SVC_CONNMAXREC_SET
:
662 case RPC_SVC_CONNMAXREC_GET
:
663 *(int *)arg
= __svc_maxrec
;