From df49c60c9671e4a28e636964d744c1f59fb6cb68 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Mon, 12 Jun 2000 15:00:15 +0000 Subject: Merged from 4.5.0-beta3a --- cpukit/librpc/src/rpc/svc.c | 491 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 491 insertions(+) (limited to 'cpukit/librpc/src/rpc/svc.c') diff --git a/cpukit/librpc/src/rpc/svc.c b/cpukit/librpc/src/rpc/svc.c index e69de29bb2..92832a589b 100644 --- a/cpukit/librpc/src/rpc/svc.c +++ b/cpukit/librpc/src/rpc/svc.c @@ -0,0 +1,491 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";*/ +/*static char *sccsid = "from: @(#)svc.c 2.4 88/08/11 4.0 RPCSRC";*/ +static char *rcsid = "$FreeBSD: src/lib/libc/rpc/svc.c,v 1.14 1999/08/28 00:00:48 peter Exp $"; +#endif + +/* + * svc.c, Server-side remote procedure call interface. + * + * There are two sets of procedures here. The xprt routines are + * for handling transport handles. The svc routines handle the + * list of service routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include +#include +#include +#include +#include + +#define xports ((SVCXPRT **)((struct rtems_rpc_task_variables *)rtems_rpc_task_variables)->svc_xports) +#define xportssize (((struct rtems_rpc_task_variables *)rtems_rpc_task_variables)->svc_xportssize) + +#define NULL_SVC ((struct svc_callout *)0) +#define RQCRED_SIZE 400 /* this size is excessive */ + +#define max(a, b) (a > b ? a : b) + +/* + * The services list + * Each entry represents a set of procedures (an rpc program). + * The dispatch routine takes request structs and runs the + * apropriate procedure. + */ +struct svc_callout { + struct svc_callout *sc_next; + u_long sc_prog; + u_long sc_vers; + void (*sc_dispatch)(); +}; +#define svc_head (struct svc_callout *)(((struct rtems_rpc_task_variables *)rtems_rpc_task_variables)->svc_svc_head) + +static struct svc_callout *svc_find(); + +/* *************** SVCXPRT related stuff **************** */ + +/* + * Activate a transport handle. + */ +void +xprt_register(xprt) + SVCXPRT *xprt; +{ + register int sock = xprt->xp_sock; + + if (sock + 1 > __svc_fdsetsize) { + int bytes = sizeof (fd_set); + fd_set *fds; + + fds = (fd_set *)malloc(bytes); + memset(fds, 0, bytes); + if (__svc_fdset) { + memcpy(fds, __svc_fdset, bytes); + free(__svc_fdset); + } + __svc_fdset = fds; + __svc_fdsetsize = bytes * NBBY; + } + + if (sock < FD_SETSIZE) + FD_SET(sock, &svc_fdset); + FD_SET(sock, __svc_fdset); + + if (xports == NULL || sock + 1 > xportssize) { + SVCXPRT **xp; + int size = FD_SETSIZE; + + if (sock + 1 > size) + size = sock + 1; + xp = (SVCXPRT **)mem_alloc(size * sizeof(SVCXPRT *)); + memset(xp, 0, size * sizeof(SVCXPRT *)); + if (xports) { + memcpy(xp, xports, xportssize * sizeof(SVCXPRT *)); + free(xports); + } + xportssize = size; + xports = xp; + } + xports[sock] = xprt; + svc_maxfd = max(svc_maxfd, sock); +} + +/* + * De-activate a transport handle. + */ +void +xprt_unregister(xprt) + SVCXPRT *xprt; +{ + register int sock = xprt->xp_sock; + + if (xports[sock] == xprt) { + xports[sock] = (SVCXPRT *)0; + if (sock < FD_SETSIZE) + FD_CLR(sock, &svc_fdset); + FD_CLR(sock, __svc_fdset); + if (sock == svc_maxfd) { + for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--) + if (xports[svc_maxfd]) + break; + } + /* + * XXX could use svc_maxfd as a hint to + * decrease the size of __svc_fdset + */ + } +} + + +/* ********************** CALLOUT list related stuff ************* */ + +/* + * Add a service program to the callout list. + * The dispatch routine will be called when a rpc request for this + * program number comes in. + */ +bool_t +svc_register(xprt, prog, vers, dispatch, protocol) + SVCXPRT *xprt; + u_long prog; + u_long vers; + void (*dispatch)(); + int protocol; +{ + struct svc_callout *prev; + register struct svc_callout *s; + + if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) { + if (s->sc_dispatch == dispatch) + goto pmap_it; /* he is registering another xptr */ + return (FALSE); + } + s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); + if (s == (struct svc_callout *)0) { + return (FALSE); + } + s->sc_prog = prog; + s->sc_vers = vers; + s->sc_dispatch = dispatch; + s->sc_next = svc_head; + svc_head = s; +pmap_it: + /* now register the information with the local binder service */ + if (protocol) { + return (pmap_set(prog, vers, protocol, xprt->xp_port)); + } + return (TRUE); +} + +/* + * Remove a service program from the callout list. + */ +void +svc_unregister(prog, vers) + u_long prog; + u_long vers; +{ + struct svc_callout *prev; + register struct svc_callout *s; + + if ((s = svc_find(prog, vers, &prev)) == NULL_SVC) + return; + if (prev == NULL_SVC) { + svc_head = s->sc_next; + } else { + prev->sc_next = s->sc_next; + } + s->sc_next = NULL_SVC; + mem_free((char *) s, (u_int) sizeof(struct svc_callout)); + /* now unregister the information with the local binder service */ + (void)pmap_unset(prog, vers); +} + +/* + * Search the callout list for a program number, return the callout + * struct. + */ +static struct svc_callout * +svc_find(prog, vers, prev) + u_long prog; + u_long vers; + struct svc_callout **prev; +{ + register struct svc_callout *s, *p; + + p = NULL_SVC; + for (s = svc_head; s != NULL_SVC; s = s->sc_next) { + if ((s->sc_prog == prog) && (s->sc_vers == vers)) + goto done; + p = s; + } +done: + *prev = p; + return (s); +} + +/* ******************* REPLY GENERATION ROUTINES ************ */ + +/* + * Send a reply to an rpc request + */ +bool_t +svc_sendreply(xprt, xdr_results, xdr_location) + register SVCXPRT *xprt; + xdrproc_t xdr_results; + caddr_t xdr_location; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SUCCESS; + rply.acpted_rply.ar_results.where = xdr_location; + rply.acpted_rply.ar_results.proc = xdr_results; + return (SVC_REPLY(xprt, &rply)); +} + +/* + * No procedure error reply + */ +void +svcerr_noproc(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROC_UNAVAIL; + SVC_REPLY(xprt, &rply); +} + +/* + * Can't decode args error reply + */ +void +svcerr_decode(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = GARBAGE_ARGS; + SVC_REPLY(xprt, &rply); +} + +/* + * Some system error + */ +void +svcerr_systemerr(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SYSTEM_ERR; + SVC_REPLY(xprt, &rply); +} + +/* + * Authentication error reply + */ +void +svcerr_auth(xprt, why) + SVCXPRT *xprt; + enum auth_stat why; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_DENIED; + rply.rjcted_rply.rj_stat = AUTH_ERROR; + rply.rjcted_rply.rj_why = why; + SVC_REPLY(xprt, &rply); +} + +/* + * Auth too weak error reply + */ +void +svcerr_weakauth(xprt) + SVCXPRT *xprt; +{ + + svcerr_auth(xprt, AUTH_TOOWEAK); +} + +/* + * Program unavailable error reply + */ +void +svcerr_noprog(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_UNAVAIL; + SVC_REPLY(xprt, &rply); +} + +/* + * Program version mismatch error reply + */ +void +svcerr_progvers(xprt, low_vers, high_vers) + register SVCXPRT *xprt; + u_long low_vers; + u_long high_vers; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_MISMATCH; + rply.acpted_rply.ar_vers.low = low_vers; + rply.acpted_rply.ar_vers.high = high_vers; + SVC_REPLY(xprt, &rply); +} + +/* ******************* SERVER INPUT STUFF ******************* */ + +/* + * Get server side input from some transport. + * + * Statement of authentication parameters management: + * This function owns and manages all authentication parameters, specifically + * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and + * the "cooked" credentials (rqst->rq_clntcred). + * However, this function does not know the structure of the cooked + * credentials, so it make the following assumptions: + * a) the structure is contiguous (no pointers), and + * b) the cred structure size does not exceed RQCRED_SIZE bytes. + * In all events, all three parameters are freed upon exit from this routine. + * The storage is trivially management on the call stack in user land, but + * is mallocated in kernel land. + */ + +void +svc_getreq(rdfds) + int rdfds; +{ + fd_set readfds; + + FD_ZERO(&readfds); + readfds.fds_bits[0] = rdfds; + svc_getreqset(&readfds); +} + +void +svc_getreqset(readfds) + fd_set *readfds; +{ + svc_getreqset2(readfds, FD_SETSIZE); +} + +void +svc_getreqset2(readfds, width) + fd_set *readfds; + int width; +{ + enum xprt_stat stat; + struct rpc_msg msg; + int prog_found; + u_long low_vers; + u_long high_vers; + struct svc_req r; + register SVCXPRT *xprt; + register int bit; + register int sock; + register fd_mask mask, *maskp; + char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; + msg.rm_call.cb_cred.oa_base = cred_area; + msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); + r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); + + + maskp = readfds->fds_bits; + for (sock = 0; sock < width; sock += NFDBITS) { + for (mask = *maskp++; (bit = ffs(mask)); mask ^= (1 << (bit - 1))) { + /* sock has input waiting */ + xprt = xports[sock + bit - 1]; + if (xprt == NULL) + /* But do we control sock? */ + continue; + /* now receive msgs from xprtprt (support batch calls) */ + do { + if (SVC_RECV(xprt, &msg)) { + + /* now find the exported program and call it */ + register struct svc_callout *s; + enum auth_stat why; + + r.rq_xprt = xprt; + r.rq_prog = msg.rm_call.cb_prog; + r.rq_vers = msg.rm_call.cb_vers; + r.rq_proc = msg.rm_call.cb_proc; + r.rq_cred = msg.rm_call.cb_cred; + /* first authenticate the message */ + if ((why= _authenticate(&r, &msg)) != AUTH_OK) { + svcerr_auth(xprt, why); + goto call_done; + } + /* now match message with a registered service*/ + prog_found = FALSE; + low_vers = (u_long) - 1; + high_vers = 0; + for (s = svc_head; s != NULL_SVC; s = s->sc_next) { + if (s->sc_prog == r.rq_prog) { + if (s->sc_vers == r.rq_vers) { + (*s->sc_dispatch)(&r, xprt); + goto call_done; + } /* found correct version */ + prog_found = TRUE; + if (s->sc_vers < low_vers) + low_vers = s->sc_vers; + if (s->sc_vers > high_vers) + high_vers = s->sc_vers; + } /* found correct program */ + } + /* + * if we got here, the program or version + * is not served ... + */ + if (prog_found) + svcerr_progvers(xprt, + low_vers, high_vers); + else + svcerr_noprog(xprt); + /* Fall through to ... */ + } + call_done: + if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ + SVC_DESTROY(xprt); + break; + } + } while (stat == XPRT_MOREREQS); + } + } +} -- cgit v1.2.3