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.
39 #define pmap_set __pmap_set
41 #define _authenticate _authenticate_internal
42 #define _rpc_dtablesize _rpc_dtablesize_internal
44 /* used by svc_[max_]pollfd */
45 #define __rpc_thread_svc_pollfd __rpc_thread_svc_pollfd_internal
46 #define __rpc_thread_svc_max_pollfd __rpc_thread_svc_max_pollfd_internal
48 /* used by svc_fdset */
49 #define __rpc_thread_svc_fdset __rpc_thread_svc_fdset_internal
57 #include "rpc_private.h"
59 #include <rpc/pmap_clnt.h>
62 #ifdef __UCLIBC_HAS_THREADS__
63 #define xports (*(SVCXPRT ***)&RPC_THREAD_VARIABLE(svc_xports_s))
65 static SVCXPRT **xports;
68 #define NULL_SVC ((struct svc_callout *)0)
69 #define RQCRED_SIZE 400 /* this size is excessive */
72 Each entry represents a set of procedures (an rpc program).
73 The dispatch routine takes request structs and runs the
74 appropriate procedure. */
76 struct svc_callout *sc_next;
79 void (*sc_dispatch) (struct svc_req *, SVCXPRT *);
81 #ifdef __UCLIBC_HAS_THREADS__
82 #define svc_head (*(struct svc_callout **)&RPC_THREAD_VARIABLE(svc_head_s))
84 static struct svc_callout *svc_head;
87 /* *************** SVCXPRT related stuff **************** */
89 /* Activate a transport handle. */
91 __xprt_register (SVCXPRT *xprt)
93 register int sock = xprt->xp_sock;
98 xports = (SVCXPRT **) malloc (_rpc_dtablesize () * sizeof (SVCXPRT *));
99 if (xports == NULL) /* DonĀ“t add handle */
103 if (sock < _rpc_dtablesize ())
106 if (sock < FD_SETSIZE)
107 FD_SET (sock, &svc_fdset);
109 /* Check if we have an empty slot */
110 for (i = 0; i < svc_max_pollfd; ++i)
111 if (svc_pollfd[i].fd == -1)
113 svc_pollfd[i].fd = sock;
114 svc_pollfd[i].events = (POLLIN | POLLPRI |
115 POLLRDNORM | POLLRDBAND);
120 svc_pollfd = realloc (svc_pollfd,
121 sizeof (struct pollfd) * svc_max_pollfd);
122 if (svc_pollfd == NULL) /* Out of memory */
125 svc_pollfd[svc_max_pollfd - 1].fd = sock;
126 svc_pollfd[svc_max_pollfd - 1].events = (POLLIN | POLLPRI |
127 POLLRDNORM | POLLRDBAND);
130 strong_alias(__xprt_register,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;
153 /* ********************** CALLOUT list related stuff ************* */
155 /* Search the callout list for a program number, return the callout
157 static struct svc_callout *
158 svc_find (rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev)
160 register struct svc_callout *s, *p;
163 for (s = svc_head; s != NULL_SVC; s = s->sc_next)
165 if ((s->sc_prog == prog) && (s->sc_vers == vers))
174 /* Add a service program to the callout list.
175 The dispatch routine will be called when a rpc request for this
176 program number comes in. */
178 svc_register (SVCXPRT * xprt, rpcprog_t prog, rpcvers_t vers,
179 void (*dispatch) (struct svc_req *, SVCXPRT *),
182 struct svc_callout *prev;
183 register struct svc_callout *s;
185 if ((s = svc_find (prog, vers, &prev)) != NULL_SVC)
187 if (s->sc_dispatch == dispatch)
188 goto pmap_it; /* he is registering another xptr */
191 s = (struct svc_callout *) mem_alloc (sizeof (struct svc_callout));
192 if (s == (struct svc_callout *) 0)
197 s->sc_dispatch = dispatch;
198 s->sc_next = svc_head;
202 /* now register the information with the local binder service */
204 return pmap_set (prog, vers, protocol, xprt->xp_port);
209 /* Remove a service program from the callout list. */
211 svc_unregister (rpcprog_t prog, rpcvers_t vers)
213 struct svc_callout *prev;
214 register struct svc_callout *s;
216 if ((s = svc_find (prog, vers, &prev)) == NULL_SVC)
219 if (prev == NULL_SVC)
220 svc_head = s->sc_next;
222 prev->sc_next = s->sc_next;
224 s->sc_next = NULL_SVC;
225 mem_free ((char *) s, (u_int) sizeof (struct svc_callout));
226 /* now unregister the information with the local binder service */
227 pmap_unset (prog, vers);
230 /* ******************* REPLY GENERATION ROUTINES ************ */
232 /* Send a reply to an rpc request */
233 bool_t attribute_hidden
234 __svc_sendreply (register SVCXPRT *xprt, xdrproc_t xdr_results,
235 caddr_t xdr_location)
239 rply.rm_direction = REPLY;
240 rply.rm_reply.rp_stat = MSG_ACCEPTED;
241 rply.acpted_rply.ar_verf = xprt->xp_verf;
242 rply.acpted_rply.ar_stat = SUCCESS;
243 rply.acpted_rply.ar_results.where = xdr_location;
244 rply.acpted_rply.ar_results.proc = xdr_results;
245 return SVC_REPLY (xprt, &rply);
247 strong_alias(__svc_sendreply,svc_sendreply)
249 /* No procedure error reply */
251 svcerr_noproc (register 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);
262 /* Can't decode args error reply */
264 svcerr_decode (register SVCXPRT *xprt)
268 rply.rm_direction = REPLY;
269 rply.rm_reply.rp_stat = MSG_ACCEPTED;
270 rply.acpted_rply.ar_verf = xprt->xp_verf;
271 rply.acpted_rply.ar_stat = GARBAGE_ARGS;
272 SVC_REPLY (xprt, &rply);
275 /* Some system error */
277 svcerr_systemerr (register SVCXPRT *xprt)
281 rply.rm_direction = REPLY;
282 rply.rm_reply.rp_stat = MSG_ACCEPTED;
283 rply.acpted_rply.ar_verf = xprt->xp_verf;
284 rply.acpted_rply.ar_stat = SYSTEM_ERR;
285 SVC_REPLY (xprt, &rply);
288 /* Authentication error reply */
289 void attribute_hidden
290 __svcerr_auth (SVCXPRT *xprt, enum auth_stat why)
294 rply.rm_direction = REPLY;
295 rply.rm_reply.rp_stat = MSG_DENIED;
296 rply.rjcted_rply.rj_stat = AUTH_ERROR;
297 rply.rjcted_rply.rj_why = why;
298 SVC_REPLY (xprt, &rply);
300 strong_alias(__svcerr_auth,svcerr_auth)
302 /* Auth too weak error reply */
304 svcerr_weakauth (SVCXPRT *xprt)
306 __svcerr_auth (xprt, AUTH_TOOWEAK);
309 /* Program unavailable error reply */
311 svcerr_noprog (register SVCXPRT *xprt)
315 rply.rm_direction = REPLY;
316 rply.rm_reply.rp_stat = MSG_ACCEPTED;
317 rply.acpted_rply.ar_verf = xprt->xp_verf;
318 rply.acpted_rply.ar_stat = PROG_UNAVAIL;
319 SVC_REPLY (xprt, &rply);
322 /* Program version mismatch error reply */
324 svcerr_progvers (register SVCXPRT *xprt, rpcvers_t low_vers,
329 rply.rm_direction = REPLY;
330 rply.rm_reply.rp_stat = MSG_ACCEPTED;
331 rply.acpted_rply.ar_verf = xprt->xp_verf;
332 rply.acpted_rply.ar_stat = PROG_MISMATCH;
333 rply.acpted_rply.ar_vers.low = low_vers;
334 rply.acpted_rply.ar_vers.high = high_vers;
335 SVC_REPLY (xprt, &rply);
338 /* ******************* SERVER INPUT STUFF ******************* */
341 * Get server side input from some transport.
343 * Statement of authentication parameters management:
344 * This function owns and manages all authentication parameters, specifically
345 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
346 * the "cooked" credentials (rqst->rq_clntcred).
347 * However, this function does not know the structure of the cooked
348 * credentials, so it make the following assumptions:
349 * a) the structure is contiguous (no pointers), and
350 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
351 * In all events, all three parameters are freed upon exit from this routine.
352 * The storage is trivially management on the call stack in user land, but
353 * is mallocated in kernel land.
357 svc_getreq (int rdfds)
362 readfds.fds_bits[0] = rdfds;
363 svc_getreqset (&readfds);
367 svc_getreqset (fd_set *readfds)
369 register u_int32_t mask;
370 register u_int32_t *maskp;
371 register int setsize;
375 setsize = _rpc_dtablesize ();
376 maskp = (u_int32_t *) readfds->fds_bits;
377 for (sock = 0; sock < setsize; sock += 32)
378 for (mask = *maskp++; (bit = ffs (mask)); mask ^= (1 << (bit - 1)))
379 svc_getreq_common (sock + bit - 1);
383 svc_getreq_poll (struct pollfd *pfdp, int pollretval)
386 register int fds_found;
388 for (i = fds_found = 0; i < svc_max_pollfd && fds_found < pollretval; ++i)
390 register struct pollfd *p = &pfdp[i];
392 if (p->fd != -1 && p->revents)
394 /* fd has input waiting */
397 if (p->revents & POLLNVAL)
398 xprt_unregister (xports[p->fd]);
400 svc_getreq_common (p->fd);
407 svc_getreq_common (const int fd)
411 register SVCXPRT *xprt;
412 char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
413 msg.rm_call.cb_cred.oa_base = cred_area;
414 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
417 /* Do we control fd? */
421 /* now receive msgs from xprtprt (support batch calls) */
424 if (SVC_RECV (xprt, &msg))
426 /* now find the exported program and call it */
427 struct svc_callout *s;
434 r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
436 r.rq_prog = msg.rm_call.cb_prog;
437 r.rq_vers = msg.rm_call.cb_vers;
438 r.rq_proc = msg.rm_call.cb_proc;
439 r.rq_cred = msg.rm_call.cb_cred;
441 /* first authenticate the message */
442 /* Check for null flavor and bypass these calls if possible */
444 if (msg.rm_call.cb_cred.oa_flavor == AUTH_NULL)
446 r.rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
447 r.rq_xprt->xp_verf.oa_length = 0;
449 else if ((why = _authenticate (&r, &msg)) != AUTH_OK)
451 __svcerr_auth (xprt, why);
455 /* now match message with a registered service */
460 for (s = svc_head; s != NULL_SVC; s = s->sc_next)
462 if (s->sc_prog == r.rq_prog)
464 if (s->sc_vers == r.rq_vers)
466 (*s->sc_dispatch) (&r, xprt);
469 /* found correct version */
471 if (s->sc_vers < low_vers)
472 low_vers = s->sc_vers;
473 if (s->sc_vers > high_vers)
474 high_vers = s->sc_vers;
476 /* found correct program */
478 /* if we got here, the program or version
481 svcerr_progvers (xprt, low_vers, high_vers);
483 svcerr_noprog (xprt);
484 /* Fall through to ... */
487 if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
493 while (stat == XPRT_MOREREQS);
496 #ifdef __UCLIBC_HAS_THREADS__
498 void attribute_hidden __rpc_thread_svc_cleanup (void)
500 struct svc_callout *svcp;
502 while ((svcp = svc_head) != NULL)
503 svc_unregister (svcp->sc_prog, svcp->sc_vers);
506 #endif /* __UCLIBC_HAS_THREADS__ */