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
30 * svc.c, Server-side remote procedure call interface.
32 * There are two sets of procedures here. The xprt routines are
33 * for handling transport handles. The svc routines handle the
34 * list of service routines.
36 * Copyright (C) 1984, Sun Microsystems, Inc.
45 #include "rpc_private.h"
47 #include <rpc/pmap_clnt.h>
50 libc_hidden_proto(ffs)
51 libc_hidden_proto(pmap_set)
52 libc_hidden_proto(pmap_unset)
53 libc_hidden_proto(_authenticate)
54 libc_hidden_proto(_rpc_dtablesize)
55 /* used by svc_[max_]pollfd */
56 libc_hidden_proto(__rpc_thread_svc_pollfd)
57 libc_hidden_proto(__rpc_thread_svc_max_pollfd)
58 /* used by svc_fdset */
59 libc_hidden_proto(__rpc_thread_svc_fdset)
61 #ifdef __UCLIBC_HAS_THREADS__
62 #define xports (*(SVCXPRT ***)&RPC_THREAD_VARIABLE(svc_xports_s))
64 static SVCXPRT **xports;
67 #define NULL_SVC ((struct svc_callout *)0)
68 #define RQCRED_SIZE 400 /* this size is excessive */
71 Each entry represents a set of procedures (an rpc program).
72 The dispatch routine takes request structs and runs the
73 appropriate procedure. */
75 struct svc_callout *sc_next;
78 void (*sc_dispatch) (struct svc_req *, SVCXPRT *);
80 #ifdef __UCLIBC_HAS_THREADS__
81 #define svc_head (*(struct svc_callout **)&RPC_THREAD_VARIABLE(svc_head_s))
83 static struct svc_callout *svc_head;
86 /* *************** SVCXPRT related stuff **************** */
88 /* Activate a transport handle. */
90 xprt_register (SVCXPRT *xprt)
92 register int sock = xprt->xp_sock;
97 xports = (SVCXPRT **) malloc (_rpc_dtablesize () * sizeof (SVCXPRT *));
98 if (xports == NULL) /* DonĀ“t add handle */
102 if (sock < _rpc_dtablesize ())
105 if (sock < FD_SETSIZE)
106 FD_SET (sock, &svc_fdset);
108 /* Check if we have an empty slot */
109 for (i = 0; i < svc_max_pollfd; ++i)
110 if (svc_pollfd[i].fd == -1)
112 svc_pollfd[i].fd = sock;
113 svc_pollfd[i].events = (POLLIN | POLLPRI |
114 POLLRDNORM | POLLRDBAND);
119 svc_pollfd = realloc (svc_pollfd,
120 sizeof (struct pollfd) * svc_max_pollfd);
121 if (svc_pollfd == NULL) /* Out of memory */
124 svc_pollfd[svc_max_pollfd - 1].fd = sock;
125 svc_pollfd[svc_max_pollfd - 1].events = (POLLIN | POLLPRI |
126 POLLRDNORM | POLLRDBAND);
129 libc_hidden_proto(xprt_register)
130 libc_hidden_def(xprt_register)
132 /* De-activate a transport handle. */
134 xprt_unregister (SVCXPRT *xprt)
136 register int sock = xprt->xp_sock;
139 if ((sock < _rpc_dtablesize ()) && (xports[sock] == xprt))
141 xports[sock] = (SVCXPRT *) 0;
143 if (sock < FD_SETSIZE)
144 FD_CLR (sock, &svc_fdset);
146 for (i = 0; i < svc_max_pollfd; ++i)
147 if (svc_pollfd[i].fd == sock)
148 svc_pollfd[i].fd = -1;
151 libc_hidden_proto(xprt_unregister)
152 libc_hidden_def(xprt_unregister)
155 /* ********************** CALLOUT list related stuff ************* */
157 /* Search the callout list for a program number, return the callout
159 static struct svc_callout *
160 svc_find (rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev)
162 register struct svc_callout *s, *p;
165 for (s = svc_head; s != NULL_SVC; s = s->sc_next)
167 if ((s->sc_prog == prog) && (s->sc_vers == vers))
176 /* Add a service program to the callout list.
177 The dispatch routine will be called when a rpc request for this
178 program number comes in. */
180 svc_register (SVCXPRT * xprt, rpcprog_t prog, rpcvers_t vers,
181 void (*dispatch) (struct svc_req *, SVCXPRT *),
184 struct svc_callout *prev;
185 register struct svc_callout *s;
187 if ((s = svc_find (prog, vers, &prev)) != NULL_SVC)
189 if (s->sc_dispatch == dispatch)
190 goto pmap_it; /* he is registering another xptr */
193 s = (struct svc_callout *) mem_alloc (sizeof (struct svc_callout));
194 if (s == (struct svc_callout *) 0)
199 s->sc_dispatch = dispatch;
200 s->sc_next = svc_head;
204 /* now register the information with the local binder service */
206 return pmap_set (prog, vers, protocol, xprt->xp_port);
210 libc_hidden_proto(svc_register)
211 libc_hidden_def(svc_register)
213 /* Remove a service program from the callout list. */
215 svc_unregister (rpcprog_t prog, rpcvers_t vers)
217 struct svc_callout *prev;
218 register struct svc_callout *s;
220 if ((s = svc_find (prog, vers, &prev)) == NULL_SVC)
223 if (prev == NULL_SVC)
224 svc_head = s->sc_next;
226 prev->sc_next = s->sc_next;
228 s->sc_next = NULL_SVC;
229 mem_free ((char *) s, (u_int) sizeof (struct svc_callout));
230 /* now unregister the information with the local binder service */
231 pmap_unset (prog, vers);
233 libc_hidden_proto(svc_unregister)
234 libc_hidden_def(svc_unregister)
236 /* ******************* REPLY GENERATION ROUTINES ************ */
238 /* Send a reply to an rpc request */
240 svc_sendreply (register SVCXPRT *xprt, xdrproc_t xdr_results,
241 caddr_t xdr_location)
245 rply.rm_direction = REPLY;
246 rply.rm_reply.rp_stat = MSG_ACCEPTED;
247 rply.acpted_rply.ar_verf = xprt->xp_verf;
248 rply.acpted_rply.ar_stat = SUCCESS;
249 rply.acpted_rply.ar_results.where = xdr_location;
250 rply.acpted_rply.ar_results.proc = xdr_results;
251 return SVC_REPLY (xprt, &rply);
253 libc_hidden_proto(svc_sendreply)
254 libc_hidden_def(svc_sendreply)
256 /* No procedure error reply */
258 svcerr_noproc (register SVCXPRT *xprt)
262 rply.rm_direction = REPLY;
263 rply.rm_reply.rp_stat = MSG_ACCEPTED;
264 rply.acpted_rply.ar_verf = xprt->xp_verf;
265 rply.acpted_rply.ar_stat = PROC_UNAVAIL;
266 SVC_REPLY (xprt, &rply);
269 /* Can't decode args error reply */
271 svcerr_decode (register SVCXPRT *xprt)
275 rply.rm_direction = REPLY;
276 rply.rm_reply.rp_stat = MSG_ACCEPTED;
277 rply.acpted_rply.ar_verf = xprt->xp_verf;
278 rply.acpted_rply.ar_stat = GARBAGE_ARGS;
279 SVC_REPLY (xprt, &rply);
281 libc_hidden_proto(svcerr_decode)
282 libc_hidden_def(svcerr_decode)
284 /* Some system error */
286 svcerr_systemerr (register SVCXPRT *xprt)
290 rply.rm_direction = REPLY;
291 rply.rm_reply.rp_stat = MSG_ACCEPTED;
292 rply.acpted_rply.ar_verf = xprt->xp_verf;
293 rply.acpted_rply.ar_stat = SYSTEM_ERR;
294 SVC_REPLY (xprt, &rply);
297 /* Authentication error reply */
299 svcerr_auth (SVCXPRT *xprt, enum auth_stat why)
303 rply.rm_direction = REPLY;
304 rply.rm_reply.rp_stat = MSG_DENIED;
305 rply.rjcted_rply.rj_stat = AUTH_ERROR;
306 rply.rjcted_rply.rj_why = why;
307 SVC_REPLY (xprt, &rply);
309 libc_hidden_proto(svcerr_auth)
310 libc_hidden_def(svcerr_auth)
312 /* Auth too weak error reply */
314 svcerr_weakauth (SVCXPRT *xprt)
316 svcerr_auth (xprt, AUTH_TOOWEAK);
319 /* Program unavailable error reply */
321 svcerr_noprog (register 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);
331 libc_hidden_proto(svcerr_noprog)
332 libc_hidden_def(svcerr_noprog)
334 /* Program version mismatch error reply */
336 svcerr_progvers (register SVCXPRT *xprt, rpcvers_t low_vers,
341 rply.rm_direction = REPLY;
342 rply.rm_reply.rp_stat = MSG_ACCEPTED;
343 rply.acpted_rply.ar_verf = xprt->xp_verf;
344 rply.acpted_rply.ar_stat = PROG_MISMATCH;
345 rply.acpted_rply.ar_vers.low = low_vers;
346 rply.acpted_rply.ar_vers.high = high_vers;
347 SVC_REPLY (xprt, &rply);
349 libc_hidden_proto(svcerr_progvers)
350 libc_hidden_def(svcerr_progvers)
352 /* ******************* SERVER INPUT STUFF ******************* */
355 * Get server side input from some transport.
357 * Statement of authentication parameters management:
358 * This function owns and manages all authentication parameters, specifically
359 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
360 * the "cooked" credentials (rqst->rq_clntcred).
361 * However, this function does not know the structure of the cooked
362 * credentials, so it make the following assumptions:
363 * a) the structure is contiguous (no pointers), and
364 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
365 * In all events, all three parameters are freed upon exit from this routine.
366 * The storage is trivially management on the call stack in user land, but
367 * is mallocated in kernel land.
371 svc_getreq_common (const int fd)
375 register SVCXPRT *xprt;
376 char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
377 msg.rm_call.cb_cred.oa_base = cred_area;
378 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
381 /* Do we control fd? */
385 /* now receive msgs from xprtprt (support batch calls) */
388 if (SVC_RECV (xprt, &msg))
390 /* now find the exported program and call it */
391 struct svc_callout *s;
398 r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
400 r.rq_prog = msg.rm_call.cb_prog;
401 r.rq_vers = msg.rm_call.cb_vers;
402 r.rq_proc = msg.rm_call.cb_proc;
403 r.rq_cred = msg.rm_call.cb_cred;
405 /* first authenticate the message */
406 /* Check for null flavor and bypass these calls if possible */
408 if (msg.rm_call.cb_cred.oa_flavor == AUTH_NULL)
410 r.rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
411 r.rq_xprt->xp_verf.oa_length = 0;
413 else if ((why = _authenticate (&r, &msg)) != AUTH_OK)
415 svcerr_auth (xprt, why);
419 /* now match message with a registered service */
424 for (s = svc_head; s != NULL_SVC; s = s->sc_next)
426 if (s->sc_prog == r.rq_prog)
428 if (s->sc_vers == r.rq_vers)
430 (*s->sc_dispatch) (&r, xprt);
433 /* found correct version */
435 if (s->sc_vers < low_vers)
436 low_vers = s->sc_vers;
437 if (s->sc_vers > high_vers)
438 high_vers = s->sc_vers;
440 /* found correct program */
442 /* if we got here, the program or version
445 svcerr_progvers (xprt, low_vers, high_vers);
447 svcerr_noprog (xprt);
448 /* Fall through to ... */
451 if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
457 while (stat == XPRT_MOREREQS);
459 libc_hidden_proto(svc_getreq_common)
460 libc_hidden_def(svc_getreq_common)
463 svc_getreqset (fd_set *readfds)
465 register u_int32_t mask;
466 register u_int32_t *maskp;
467 register int setsize;
471 setsize = _rpc_dtablesize ();
472 maskp = (u_int32_t *) readfds->fds_bits;
473 for (sock = 0; sock < setsize; sock += 32)
474 for (mask = *maskp++; (bit = ffs (mask)); mask ^= (1 << (bit - 1)))
475 svc_getreq_common (sock + bit - 1);
477 libc_hidden_proto(svc_getreqset)
478 libc_hidden_def(svc_getreqset)
481 svc_getreq (int rdfds)
486 readfds.fds_bits[0] = rdfds;
487 svc_getreqset (&readfds);
489 libc_hidden_proto(svc_getreq)
490 libc_hidden_def(svc_getreq)
493 svc_getreq_poll (struct pollfd *pfdp, int pollretval)
496 register int fds_found;
498 for (i = fds_found = 0; i < svc_max_pollfd && fds_found < pollretval; ++i)
500 register struct pollfd *p = &pfdp[i];
502 if (p->fd != -1 && p->revents)
504 /* fd has input waiting */
507 if (p->revents & POLLNVAL)
508 xprt_unregister (xports[p->fd]);
510 svc_getreq_common (p->fd);
514 libc_hidden_proto(svc_getreq_poll)
515 libc_hidden_def(svc_getreq_poll)
517 #ifdef __UCLIBC_HAS_THREADS__
519 void attribute_hidden __rpc_thread_svc_cleanup (void)
521 struct svc_callout *svcp;
523 while ((svcp = svc_head) != NULL)
524 svc_unregister (svcp->sc_prog, svcp->sc_vers);
527 #endif /* __UCLIBC_HAS_THREADS__ */