Bring in a transport-independent RPC (TI-RPC).
[dragonfly.git] / lib / libc / rpc / svc.c
blob2a321bb311959b14a4bc05c9401bdb2d9c09f68f
1 /*
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.
26 * 2550 Garcia Avenue
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>
49 #include <sys/poll.h>
50 #include <assert.h>
51 #include <errno.h>
52 #include <stdlib.h>
53 #include <string.h>
55 #include <rpc/rpc.h>
56 #ifdef PORTMAP
57 #include <rpc/pmap_clnt.h>
58 #endif /* PORTMAP */
59 #include "un-namespace.h"
61 #include "rpc_com.h"
62 #include "mt_misc.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)
72 * The services list
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;
79 rpcprog_t sc_prog;
80 rpcvers_t sc_vers;
81 char *sc_netid;
82 void (*sc_dispatch)(struct svc_req *, SVCXPRT *);
83 } *svc_head;
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.
94 void
95 xprt_register(SVCXPRT *xprt)
97 int sock;
99 assert(xprt != NULL);
101 sock = xprt->xp_fd;
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)
108 return;
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);
119 void
120 xprt_unregister(SVCXPRT *xprt)
122 __xprt_do_unregister(xprt, TRUE);
125 void
126 __xprt_unregister_unlocked(SVCXPRT *xprt)
128 __xprt_do_unregister(xprt, FALSE);
132 * De-activate a transport handle.
134 static void
135 __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock)
137 int sock;
139 assert(xprt != NULL);
141 sock = xprt->xp_fd;
143 if (dolock)
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])
151 break;
154 if (dolock)
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.
163 bool_t
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)
168 bool_t dummy;
169 struct svc_callout *prev;
170 struct svc_callout *s;
171 struct netconfig *tnconf;
172 char *netid = NULL;
173 int flag = 0;
175 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
177 if (xprt->xp_netid) {
178 netid = strdup(xprt->xp_netid);
179 flag = 1;
180 } else if (nconf && nconf->nc_netid) {
181 netid = strdup(nconf->nc_netid);
182 flag = 1;
183 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
184 netid = strdup(tnconf->nc_netid);
185 flag = 1;
186 freenetconfigent(tnconf);
187 } /* must have been created with svc_raw_create */
188 if ((netid == NULL) && (flag == 1)) {
189 return (FALSE);
192 rwlock_wrlock(&svc_lock);
193 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
194 if (netid)
195 free(netid);
196 if (s->sc_dispatch == dispatch)
197 goto rpcb_it; /* he is registering another xptr */
198 rwlock_unlock(&svc_lock);
199 return (FALSE);
201 s = mem_alloc(sizeof (struct svc_callout));
202 if (s == NULL) {
203 if (netid)
204 free(netid);
205 rwlock_unlock(&svc_lock);
206 return (FALSE);
209 s->sc_prog = prog;
210 s->sc_vers = vers;
211 s->sc_dispatch = dispatch;
212 s->sc_netid = netid;
213 s->sc_next = svc_head;
214 svc_head = s;
216 if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
217 ((SVCXPRT *) xprt)->xp_netid = strdup(netid);
219 rpcb_it:
220 rwlock_unlock(&svc_lock);
221 /* now register the information with the local binder service */
222 if (nconf) {
223 /*LINTED const castaway*/
224 dummy = rpcb_set(prog, vers, (struct netconfig *) nconf,
225 &((SVCXPRT *) xprt)->xp_ltaddr);
226 return (dummy);
228 return (TRUE);
232 * Remove a service program from the callout list.
234 void
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) {
244 if (prev == NULL) {
245 svc_head = s->sc_next;
246 } else {
247 prev->sc_next = s->sc_next;
249 s->sc_next = NULL;
250 if (s->sc_netid)
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 ************* */
259 #ifdef PORTMAP
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.
265 bool_t
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)) !=
276 NULL) {
277 if (s->sc_dispatch == dispatch)
278 goto pmap_it; /* he is registering another xptr */
279 return (FALSE);
281 s = mem_alloc(sizeof(struct svc_callout));
282 if (s == NULL) {
283 return (FALSE);
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;
289 svc_head = s;
290 pmap_it:
291 /* now register the information with the local binder service */
292 if (protocol) {
293 return (pmap_set(prog, vers, protocol, xprt->xp_port));
295 return (TRUE);
299 * Remove a service program from the callout list.
301 void
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)) ==
308 NULL)
309 return;
310 if (prev == NULL) {
311 svc_head = s->sc_next;
312 } else {
313 prev->sc_next = s->sc_next;
315 s->sc_next = NULL;
316 mem_free(s, sizeof(struct svc_callout));
317 /* now unregister the information with the local binder service */
318 pmap_unset(prog, vers);
320 #endif /* PORTMAP */
323 * Search the callout list for a program number, return the callout
324 * struct.
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);
333 p = 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)))
338 break;
339 p = s;
341 *prev = p;
342 return (s);
345 /* ******************* REPLY GENERATION ROUTINES ************ */
348 * Send a reply to an rpc request
350 bool_t
351 svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, void *xdr_location)
353 struct rpc_msg rply;
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
369 void
370 svcerr_noproc(SVCXPRT *xprt)
372 struct rpc_msg rply;
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
386 void
387 svcerr_decode(SVCXPRT *xprt)
389 struct rpc_msg rply;
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);
401 * Some system error
403 void
404 svcerr_systemerr(SVCXPRT *xprt)
406 struct rpc_msg rply;
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
420 void
421 svcerr_auth(SVCXPRT *xprt, enum auth_stat why)
423 struct rpc_msg rply;
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
437 void
438 svcerr_weakauth(SVCXPRT *xprt)
441 assert(xprt != NULL);
443 svcerr_auth(xprt, AUTH_TOOWEAK);
447 * Program unavailable error reply
449 void
450 svcerr_noprog(SVCXPRT *xprt)
452 struct rpc_msg rply;
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
466 void
467 svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers)
469 struct rpc_msg rply;
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.
500 void
501 svc_getreq(int rdfds)
503 fd_set readfds;
505 FD_ZERO(&readfds);
506 readfds.fds_bits[0] = rdfds;
507 svc_getreqset(&readfds);
510 void
511 svc_getreqset(fd_set *readfds)
513 int bit, fd;
514 fd_mask mask, *maskp;
515 int sock;
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 */
524 fd = sock + bit - 1;
525 svc_getreq_common(fd);
530 void
531 svc_getreq_common(int fd)
533 SVCXPRT *xprt;
534 struct svc_req r;
535 struct rpc_msg msg;
536 int prog_found;
537 rpcvers_t low_vers;
538 rpcvers_t high_vers;
539 enum xprt_stat stat;
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);
549 if (xprt == NULL)
550 /* But do we control sock? */
551 return;
552 /* now receive msgs from xprtprt (support batch calls) */
553 do {
554 if (SVC_RECV(xprt, &msg)) {
556 /* now find the exported program and call it */
557 struct svc_callout *s;
558 enum auth_stat why;
560 r.rq_xprt = xprt;
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);
568 goto call_done;
570 /* now match message with a registered service*/
571 prog_found = FALSE;
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);
578 goto call_done;
579 } /* found correct version */
580 prog_found = TRUE;
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
589 * is not served ...
591 if (prog_found)
592 svcerr_progvers(xprt, low_vers, high_vers);
593 else
594 svcerr_noprog(xprt);
595 /* Fall through to ... */
598 * Check if the xprt has been disconnected in a
599 * recursive call in the service dispatch routine.
600 * If so, then break.
602 rwlock_rdlock(&svc_fd_lock);
603 if (xprt != __svc_xports[fd]) {
604 rwlock_unlock(&svc_fd_lock);
605 break;
607 rwlock_unlock(&svc_fd_lock);
608 call_done:
609 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
610 SVC_DESTROY(xprt);
611 break;
613 } while (stat == XPRT_MOREREQS);
617 void
618 svc_getreq_poll(struct pollfd *pfdp, int pollretval)
620 int i;
621 int fds_found;
623 for (i = fds_found = 0; fds_found < pollretval; i++) {
624 struct pollfd *p = &pfdp[i];
626 if (p->revents) {
627 /* fd has input waiting */
628 fds_found++;
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);
644 } else
645 svc_getreq_common(p->fd);
650 bool_t
651 rpc_control(int what, void *arg)
653 int val;
655 switch (what) {
656 case RPC_SVC_CONNMAXREC_SET:
657 val = *(int *)arg;
658 if (val <= 0)
659 return FALSE;
660 __svc_maxrec = val;
661 return TRUE;
662 case RPC_SVC_CONNMAXREC_GET:
663 *(int *)arg = __svc_maxrec;
664 return TRUE;
665 default:
666 break;
668 return FALSE;