Back to index

glibc  2.9
svc.c
Go to the documentation of this file.
00001 /*
00002  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
00003  * unrestricted use provided that this legend is included on all tape
00004  * media and as a part of the software program in whole or part.  Users
00005  * may copy or modify Sun RPC without charge, but are not authorized
00006  * to license or distribute it to anyone else except as part of a product or
00007  * program developed by the user.
00008  *
00009  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
00010  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
00011  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
00012  *
00013  * Sun RPC is provided with no support and without any obligation on the
00014  * part of Sun Microsystems, Inc. to assist in its use, correction,
00015  * modification or enhancement.
00016  *
00017  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
00018  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
00019  * OR ANY PART THEREOF.
00020  *
00021  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
00022  * or profits or other special, indirect and consequential damages, even if
00023  * Sun has been advised of the possibility of such damages.
00024  *
00025  * Sun Microsystems, Inc.
00026  * 2550 Garcia Avenue
00027  * Mountain View, California  94043
00028  */
00029 /*
00030  * svc.c, Server-side remote procedure call interface.
00031  *
00032  * There are two sets of procedures here.  The xprt routines are
00033  * for handling transport handles.  The svc routines handle the
00034  * list of service routines.
00035  *
00036  * Copyright (C) 1984, Sun Microsystems, Inc.
00037  */
00038 
00039 #include <errno.h>
00040 #include <unistd.h>
00041 #include <rpc/rpc.h>
00042 #include <rpc/svc.h>
00043 #include <rpc/pmap_clnt.h>
00044 #include <sys/poll.h>
00045 
00046 #ifdef _RPC_THREAD_SAFE_
00047 #define xports RPC_THREAD_VARIABLE(svc_xports_s)
00048 #else
00049 static SVCXPRT **xports;
00050 #endif
00051 
00052 #define NULL_SVC ((struct svc_callout *)0)
00053 #define       RQCRED_SIZE   400    /* this size is excessive */
00054 
00055 /* The services list
00056    Each entry represents a set of procedures (an rpc program).
00057    The dispatch routine takes request structs and runs the
00058    appropriate procedure. */
00059 struct svc_callout {
00060   struct svc_callout *sc_next;
00061   rpcprog_t sc_prog;
00062   rpcvers_t sc_vers;
00063   void (*sc_dispatch) (struct svc_req *, SVCXPRT *);
00064   bool_t sc_mapped;
00065 };
00066 #ifdef _RPC_THREAD_SAFE_
00067 #define svc_head RPC_THREAD_VARIABLE(svc_head_s)
00068 #else
00069 static struct svc_callout *svc_head;
00070 #endif
00071 
00072 /* ***************  SVCXPRT related stuff **************** */
00073 
00074 /* Activate a transport handle. */
00075 void
00076 xprt_register (SVCXPRT *xprt)
00077 {
00078   register int sock = xprt->xp_sock;
00079   register int i;
00080 
00081   if (xports == NULL)
00082     {
00083       xports = (SVCXPRT **) malloc (_rpc_dtablesize () * sizeof (SVCXPRT *));
00084       if (xports == NULL) /* Donīt add handle */
00085        return;
00086     }
00087 
00088   if (sock < _rpc_dtablesize ())
00089     {
00090       struct pollfd *new_svc_pollfd;
00091 
00092       xports[sock] = xprt;
00093       if (sock < FD_SETSIZE)
00094        FD_SET (sock, &svc_fdset);
00095 
00096       /* Check if we have an empty slot */
00097       for (i = 0; i < svc_max_pollfd; ++i)
00098        if (svc_pollfd[i].fd == -1)
00099          {
00100            svc_pollfd[i].fd = sock;
00101            svc_pollfd[i].events = (POLLIN | POLLPRI |
00102                                 POLLRDNORM | POLLRDBAND);
00103            return;
00104          }
00105 
00106       new_svc_pollfd = (struct pollfd *) realloc (svc_pollfd,
00107                                             sizeof (struct pollfd)
00108                                             * (svc_max_pollfd + 1));
00109       if (new_svc_pollfd == NULL) /* Out of memory */
00110        return;
00111       svc_pollfd = new_svc_pollfd;
00112       ++svc_max_pollfd;
00113 
00114       svc_pollfd[svc_max_pollfd - 1].fd = sock;
00115       svc_pollfd[svc_max_pollfd - 1].events = (POLLIN | POLLPRI |
00116                                           POLLRDNORM | POLLRDBAND);
00117     }
00118 }
00119 libc_hidden_def (xprt_register)
00120 
00121 /* De-activate a transport handle. */
00122 void
00123 xprt_unregister (SVCXPRT *xprt)
00124 {
00125   register int sock = xprt->xp_sock;
00126   register int i;
00127 
00128   if ((sock < _rpc_dtablesize ()) && (xports[sock] == xprt))
00129     {
00130       xports[sock] = (SVCXPRT *) 0;
00131 
00132       if (sock < FD_SETSIZE)
00133        FD_CLR (sock, &svc_fdset);
00134 
00135       for (i = 0; i < svc_max_pollfd; ++i)
00136        if (svc_pollfd[i].fd == sock)
00137          svc_pollfd[i].fd = -1;
00138     }
00139 }
00140 libc_hidden_def (xprt_unregister)
00141 
00142 
00143 /* ********************** CALLOUT list related stuff ************* */
00144 
00145 /* Search the callout list for a program number, return the callout
00146    struct. */
00147 static struct svc_callout *
00148 svc_find (rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev)
00149 {
00150   register struct svc_callout *s, *p;
00151 
00152   p = NULL_SVC;
00153   for (s = svc_head; s != NULL_SVC; s = s->sc_next)
00154     {
00155       if ((s->sc_prog == prog) && (s->sc_vers == vers))
00156        goto done;
00157       p = s;
00158     }
00159 done:
00160   *prev = p;
00161   return s;
00162 }
00163 
00164 
00165 static bool_t
00166 svc_is_mapped (rpcprog_t prog, rpcvers_t vers)
00167 {
00168   struct svc_callout *prev;
00169   register struct svc_callout *s;
00170   s = svc_find (prog, vers, &prev);
00171   return s!= NULL_SVC && s->sc_mapped;
00172 }
00173 
00174 
00175 /* Add a service program to the callout list.
00176    The dispatch routine will be called when a rpc request for this
00177    program number comes in. */
00178 bool_t
00179 svc_register (SVCXPRT * xprt, rpcprog_t prog, rpcvers_t vers,
00180              void (*dispatch) (struct svc_req *, SVCXPRT *),
00181              rpcproc_t protocol)
00182 {
00183   struct svc_callout *prev;
00184   register struct svc_callout *s;
00185 
00186   if ((s = svc_find (prog, vers, &prev)) != NULL_SVC)
00187     {
00188       if (s->sc_dispatch == dispatch)
00189        goto pmap_it;        /* he is registering another xptr */
00190       return FALSE;
00191     }
00192   s = (struct svc_callout *) mem_alloc (sizeof (struct svc_callout));
00193   if (s == (struct svc_callout *) 0)
00194     return FALSE;
00195 
00196   s->sc_prog = prog;
00197   s->sc_vers = vers;
00198   s->sc_dispatch = dispatch;
00199   s->sc_next = svc_head;
00200   s->sc_mapped = FALSE;
00201   svc_head = s;
00202 
00203 pmap_it:
00204   /* now register the information with the local binder service */
00205   if (protocol)
00206     {
00207       if (! pmap_set (prog, vers, protocol, xprt->xp_port))
00208        return FALSE;
00209 
00210       s->sc_mapped = TRUE;
00211     }
00212 
00213   return TRUE;
00214 }
00215 libc_hidden_def (svc_register)
00216 
00217 /* Remove a service program from the callout list. */
00218 void
00219 svc_unregister (rpcprog_t prog, rpcvers_t vers)
00220 {
00221   struct svc_callout *prev;
00222   register struct svc_callout *s;
00223 
00224   if ((s = svc_find (prog, vers, &prev)) == NULL_SVC)
00225     return;
00226 
00227   if (prev == NULL_SVC)
00228     svc_head = s->sc_next;
00229   else
00230     prev->sc_next = s->sc_next;
00231 
00232   s->sc_next = NULL_SVC;
00233   mem_free ((char *) s, (u_int) sizeof (struct svc_callout));
00234   /* now unregister the information with the local binder service */
00235   if (! svc_is_mapped (prog, vers))
00236     pmap_unset (prog, vers);
00237 }
00238 libc_hidden_def (svc_unregister)
00239 
00240 /* ******************* REPLY GENERATION ROUTINES  ************ */
00241 
00242 /* Send a reply to an rpc request */
00243 bool_t
00244 svc_sendreply (register SVCXPRT *xprt, xdrproc_t xdr_results,
00245               caddr_t xdr_location)
00246 {
00247   struct rpc_msg rply;
00248 
00249   rply.rm_direction = REPLY;
00250   rply.rm_reply.rp_stat = MSG_ACCEPTED;
00251   rply.acpted_rply.ar_verf = xprt->xp_verf;
00252   rply.acpted_rply.ar_stat = SUCCESS;
00253   rply.acpted_rply.ar_results.where = xdr_location;
00254   rply.acpted_rply.ar_results.proc = xdr_results;
00255   return SVC_REPLY (xprt, &rply);
00256 }
00257 INTDEF (svc_sendreply)
00258 
00259 /* No procedure error reply */
00260 void
00261 svcerr_noproc (register SVCXPRT *xprt)
00262 {
00263   struct rpc_msg rply;
00264 
00265   rply.rm_direction = REPLY;
00266   rply.rm_reply.rp_stat = MSG_ACCEPTED;
00267   rply.acpted_rply.ar_verf = xprt->xp_verf;
00268   rply.acpted_rply.ar_stat = PROC_UNAVAIL;
00269   SVC_REPLY (xprt, &rply);
00270 }
00271 
00272 /* Can't decode args error reply */
00273 void
00274 svcerr_decode (register SVCXPRT *xprt)
00275 {
00276   struct rpc_msg rply;
00277 
00278   rply.rm_direction = REPLY;
00279   rply.rm_reply.rp_stat = MSG_ACCEPTED;
00280   rply.acpted_rply.ar_verf = xprt->xp_verf;
00281   rply.acpted_rply.ar_stat = GARBAGE_ARGS;
00282   SVC_REPLY (xprt, &rply);
00283 }
00284 INTDEF (svcerr_decode)
00285 
00286 /* Some system error */
00287 void
00288 svcerr_systemerr (register SVCXPRT *xprt)
00289 {
00290   struct rpc_msg rply;
00291 
00292   rply.rm_direction = REPLY;
00293   rply.rm_reply.rp_stat = MSG_ACCEPTED;
00294   rply.acpted_rply.ar_verf = xprt->xp_verf;
00295   rply.acpted_rply.ar_stat = SYSTEM_ERR;
00296   SVC_REPLY (xprt, &rply);
00297 }
00298 
00299 /* Authentication error reply */
00300 void
00301 svcerr_auth (SVCXPRT *xprt, enum auth_stat why)
00302 {
00303   struct rpc_msg rply;
00304 
00305   rply.rm_direction = REPLY;
00306   rply.rm_reply.rp_stat = MSG_DENIED;
00307   rply.rjcted_rply.rj_stat = AUTH_ERROR;
00308   rply.rjcted_rply.rj_why = why;
00309   SVC_REPLY (xprt, &rply);
00310 }
00311 libc_hidden_def (svcerr_auth)
00312 
00313 /* Auth too weak error reply */
00314 void
00315 svcerr_weakauth (SVCXPRT *xprt)
00316 {
00317   svcerr_auth (xprt, AUTH_TOOWEAK);
00318 }
00319 
00320 /* Program unavailable error reply */
00321 void
00322 svcerr_noprog (register SVCXPRT *xprt)
00323 {
00324   struct rpc_msg rply;
00325 
00326   rply.rm_direction = REPLY;
00327   rply.rm_reply.rp_stat = MSG_ACCEPTED;
00328   rply.acpted_rply.ar_verf = xprt->xp_verf;
00329   rply.acpted_rply.ar_stat = PROG_UNAVAIL;
00330   SVC_REPLY (xprt, &rply);
00331 }
00332 libc_hidden_def (svcerr_noprog)
00333 
00334 /* Program version mismatch error reply */
00335 void
00336 svcerr_progvers (register SVCXPRT *xprt, rpcvers_t low_vers,
00337                rpcvers_t high_vers)
00338 {
00339   struct rpc_msg rply;
00340 
00341   rply.rm_direction = REPLY;
00342   rply.rm_reply.rp_stat = MSG_ACCEPTED;
00343   rply.acpted_rply.ar_verf = xprt->xp_verf;
00344   rply.acpted_rply.ar_stat = PROG_MISMATCH;
00345   rply.acpted_rply.ar_vers.low = low_vers;
00346   rply.acpted_rply.ar_vers.high = high_vers;
00347   SVC_REPLY (xprt, &rply);
00348 }
00349 libc_hidden_def (svcerr_progvers)
00350 
00351 /* ******************* SERVER INPUT STUFF ******************* */
00352 
00353 /*
00354  * Get server side input from some transport.
00355  *
00356  * Statement of authentication parameters management:
00357  * This function owns and manages all authentication parameters, specifically
00358  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
00359  * the "cooked" credentials (rqst->rq_clntcred).
00360  * However, this function does not know the structure of the cooked
00361  * credentials, so it make the following assumptions:
00362  *   a) the structure is contiguous (no pointers), and
00363  *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
00364  * In all events, all three parameters are freed upon exit from this routine.
00365  * The storage is trivially management on the call stack in user land, but
00366  * is mallocated in kernel land.
00367  */
00368 
00369 void
00370 svc_getreq (int rdfds)
00371 {
00372   fd_set readfds;
00373 
00374   FD_ZERO (&readfds);
00375   readfds.fds_bits[0] = rdfds;
00376   INTUSE(svc_getreqset) (&readfds);
00377 }
00378 INTDEF (svc_getreq)
00379 
00380 void
00381 svc_getreqset (fd_set *readfds)
00382 {
00383   register fd_mask mask;
00384   register fd_mask *maskp;
00385   register int setsize;
00386   register int sock;
00387   register int bit;
00388 
00389   setsize = _rpc_dtablesize ();
00390   if (setsize > FD_SETSIZE)
00391     setsize = FD_SETSIZE;
00392   maskp = readfds->fds_bits;
00393   for (sock = 0; sock < setsize; sock += NFDBITS)
00394     for (mask = *maskp++; (bit = ffsl (mask)); mask ^= (1L << (bit - 1)))
00395       INTUSE(svc_getreq_common) (sock + bit - 1);
00396 }
00397 INTDEF (svc_getreqset)
00398 
00399 void
00400 svc_getreq_poll (struct pollfd *pfdp, int pollretval)
00401 {
00402   if (pollretval == 0)
00403     return;
00404 
00405   register int fds_found;
00406   for (int i = fds_found = 0; i < svc_max_pollfd; ++i)
00407     {
00408       register struct pollfd *p = &pfdp[i];
00409 
00410       if (p->fd != -1 && p->revents)
00411        {
00412          /* fd has input waiting */
00413          if (p->revents & POLLNVAL)
00414            xprt_unregister (xports[p->fd]);
00415          else
00416            INTUSE(svc_getreq_common) (p->fd);
00417 
00418          if (++fds_found >= pollretval)
00419            break;
00420        }
00421     }
00422 }
00423 INTDEF (svc_getreq_poll)
00424 
00425 
00426 void
00427 svc_getreq_common (const int fd)
00428 {
00429   enum xprt_stat stat;
00430   struct rpc_msg msg;
00431   register SVCXPRT *xprt;
00432   char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
00433   msg.rm_call.cb_cred.oa_base = cred_area;
00434   msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
00435 
00436   xprt = xports[fd];
00437   /* Do we control fd? */
00438   if (xprt == NULL)
00439      return;
00440 
00441   /* now receive msgs from xprtprt (support batch calls) */
00442   do
00443     {
00444       if (SVC_RECV (xprt, &msg))
00445        {
00446          /* now find the exported program and call it */
00447          struct svc_callout *s;
00448          struct svc_req r;
00449          enum auth_stat why;
00450          rpcvers_t low_vers;
00451          rpcvers_t high_vers;
00452          int prog_found;
00453 
00454          r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
00455          r.rq_xprt = xprt;
00456          r.rq_prog = msg.rm_call.cb_prog;
00457          r.rq_vers = msg.rm_call.cb_vers;
00458          r.rq_proc = msg.rm_call.cb_proc;
00459          r.rq_cred = msg.rm_call.cb_cred;
00460 
00461          /* first authenticate the message */
00462          /* Check for null flavor and bypass these calls if possible */
00463 
00464          if (msg.rm_call.cb_cred.oa_flavor == AUTH_NULL)
00465            {
00466              r.rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
00467              r.rq_xprt->xp_verf.oa_length = 0;
00468            }
00469          else if ((why = INTUSE(_authenticate) (&r, &msg)) != AUTH_OK)
00470            {
00471              svcerr_auth (xprt, why);
00472              goto call_done;
00473            }
00474 
00475          /* now match message with a registered service */
00476          prog_found = FALSE;
00477          low_vers = 0 - 1;
00478          high_vers = 0;
00479 
00480          for (s = svc_head; s != NULL_SVC; s = s->sc_next)
00481            {
00482              if (s->sc_prog == r.rq_prog)
00483               {
00484                 if (s->sc_vers == r.rq_vers)
00485                   {
00486                     (*s->sc_dispatch) (&r, xprt);
00487                     goto call_done;
00488                   }
00489                 /* found correct version */
00490                 prog_found = TRUE;
00491                 if (s->sc_vers < low_vers)
00492                   low_vers = s->sc_vers;
00493                 if (s->sc_vers > high_vers)
00494                   high_vers = s->sc_vers;
00495               }
00496              /* found correct program */
00497            }
00498          /* if we got here, the program or version
00499             is not served ... */
00500          if (prog_found)
00501            svcerr_progvers (xprt, low_vers, high_vers);
00502          else
00503            svcerr_noprog (xprt);
00504          /* Fall through to ... */
00505        }
00506     call_done:
00507       if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
00508        {
00509          SVC_DESTROY (xprt);
00510          break;
00511        }
00512     }
00513   while (stat == XPRT_MOREREQS);
00514 }
00515 INTDEF (svc_getreq_common)
00516 
00517 #ifdef _RPC_THREAD_SAFE_
00518 
00519 void
00520 __rpc_thread_svc_cleanup (void)
00521 {
00522   struct svc_callout *svcp;
00523 
00524   while ((svcp = svc_head) != NULL)
00525     svc_unregister (svcp->sc_prog, svcp->sc_vers);
00526 }
00527 
00528 #endif /* _RPC_THREAD_SAFE_ */