home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / rpc3.9 / part03 / svc.c < prev   
Encoding:
C/C++ Source or Header  |  1988-02-27  |  10.9 KB  |  474 lines

  1. /* @(#)svc.c    1.4 87/11/16 3.9 RPCSRC */
  2. /*
  3.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  4.  * unrestricted use provided that this legend is included on all tape
  5.  * media and as a part of the software program in whole or part.  Users
  6.  * may copy or modify Sun RPC without charge, but are not authorized
  7.  * to license or distribute it to anyone else except as part of a product or
  8.  * program developed by the user.
  9.  * 
  10.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  11.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  12.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  13.  * 
  14.  * Sun RPC is provided with no support and without any obligation on the
  15.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  16.  * modification or enhancement.
  17.  * 
  18.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  19.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  20.  * OR ANY PART THEREOF.
  21.  * 
  22.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  23.  * or profits or other special, indirect and consequential damages, even if
  24.  * Sun has been advised of the possibility of such damages.
  25.  * 
  26.  * Sun Microsystems, Inc.
  27.  * 2550 Garcia Avenue
  28.  * Mountain View, California  94043
  29.  */
  30. #if !defined(lint) && defined(SCCSIDS)
  31. static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro";
  32. #endif
  33.  
  34. /*
  35.  * svc.c, Server-side remote procedure call interface.
  36.  *
  37.  * There are two sets of procedures here.  The xprt routines are
  38.  * for handling transport handles.  The svc routines handle the
  39.  * list of service routines.
  40.  *
  41.  * Copyright (C) 1984, Sun Microsystems, Inc.
  42.  */
  43.  
  44. #include <sys/errno.h>
  45. #include <sys/time.h>
  46. #include <rpc/rpc.h>
  47. #include <rpc/pmap_clnt.h>
  48.  
  49. extern int errno;
  50.  
  51. #ifdef FD_SETSIZE
  52. static SVCXPRT **xports;
  53. #else
  54. #define NOFILE 32
  55.  
  56. static SVCXPRT *xports[NOFILE];
  57. #endif /* def FD_SETSIZE */
  58.  
  59. #define NULL_SVC ((struct svc_callout *)0)
  60. #define    RQCRED_SIZE    400        /* this size is excessive */
  61.  
  62. /*
  63.  * The services list
  64.  * Each entry represents a set of procedures (an rpc program).
  65.  * The dispatch routine takes request structs and runs the
  66.  * apropriate procedure.
  67.  */
  68. static struct svc_callout {
  69.     struct svc_callout *sc_next;
  70.     u_long            sc_prog;
  71.     u_long            sc_vers;
  72.     void            (*sc_dispatch)();
  73. } *svc_head;
  74.  
  75. static struct svc_callout *svc_find();
  76.  
  77. /* ***************  SVCXPRT related stuff **************** */
  78.  
  79. /*
  80.  * Activate a transport handle.
  81.  */
  82. void
  83. xprt_register(xprt)
  84.     SVCXPRT *xprt;
  85. {
  86.     register int sock = xprt->xp_sock;
  87.  
  88. #ifdef FD_SETSIZE
  89.     if (xports == NULL) {
  90.         xports = (SVCXPRT **)
  91.             mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
  92.     }
  93.     if (sock < _rpc_dtablesize()) {
  94.         xports[sock] = xprt;
  95.         FD_SET(sock, &svc_fdset);
  96.     }
  97. #else
  98.     if (sock < NOFILE) {
  99.         xports[sock] = xprt;
  100.         svc_fds |= (1 << sock);
  101.     }
  102. #endif /* def FD_SETSIZE */
  103.  
  104. }
  105.  
  106. /*
  107.  * De-activate a transport handle. 
  108.  */
  109. void
  110. xprt_unregister(xprt) 
  111.     SVCXPRT *xprt;
  112.     register int sock = xprt->xp_sock;
  113.  
  114. #ifdef FD_SETSIZE
  115.     if ((sock < _rpc_dtablesize()) && (xports[sock] == xprt)) {
  116.         xports[sock] = (SVCXPRT *)0;
  117.         FD_CLR(sock, &svc_fdset);
  118.     }
  119. #else
  120.     if ((sock < NOFILE) && (xports[sock] == xprt)) {
  121.         xports[sock] = (SVCXPRT *)0;
  122.         svc_fds &= ~(1 << sock);
  123.     }
  124. #endif /* def FD_SETSIZE */
  125. }
  126.  
  127.  
  128. /* ********************** CALLOUT list related stuff ************* */
  129.  
  130. /*
  131.  * Add a service program to the callout list.
  132.  * The dispatch routine will be called when a rpc request for this
  133.  * program number comes in.
  134.  */
  135. bool_t
  136. svc_register(xprt, prog, vers, dispatch, protocol)
  137.     SVCXPRT *xprt;
  138.     u_long prog;
  139.     u_long vers;
  140.     void (*dispatch)();
  141.     int protocol;
  142. {
  143.     struct svc_callout *prev;
  144.     register struct svc_callout *s;
  145.  
  146.     if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) {
  147.         if (s->sc_dispatch == dispatch)
  148.             goto pmap_it;  /* he is registering another xptr */
  149.         return (FALSE);
  150.     }
  151.     s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
  152.     if (s == (struct svc_callout *)0) {
  153.         return (FALSE);
  154.     }
  155.     s->sc_prog = prog;
  156.     s->sc_vers = vers;
  157.     s->sc_dispatch = dispatch;
  158.     s->sc_next = svc_head;
  159.     svc_head = s;
  160. pmap_it:
  161.     /* now register the information with the local binder service */
  162.     if (protocol) {
  163.         return (pmap_set(prog, vers, protocol, xprt->xp_port));
  164.     }
  165.     return (TRUE);
  166. }
  167.  
  168. /*
  169.  * Remove a service program from the callout list.
  170.  */
  171. void
  172. svc_unregister(prog, vers)
  173.     u_long prog;
  174.     u_long vers;
  175. {
  176.     struct svc_callout *prev;
  177.     register struct svc_callout *s;
  178.  
  179.     if ((s = svc_find(prog, vers, &prev)) == NULL_SVC)
  180.         return;
  181.     if (prev == NULL_SVC) {
  182.         svc_head = s->sc_next;
  183.     } else {
  184.         prev->sc_next = s->sc_next;
  185.     }
  186.     s->sc_next = NULL_SVC;
  187.     mem_free((char *) s, (u_int) sizeof(struct svc_callout));
  188.     /* now unregister the information with the local binder service */
  189.     (void)pmap_unset(prog, vers);
  190. }
  191.  
  192. /*
  193.  * Search the callout list for a program number, return the callout
  194.  * struct.
  195.  */
  196. static struct svc_callout *
  197. svc_find(prog, vers, prev)
  198.     u_long prog;
  199.     u_long vers;
  200.     struct svc_callout **prev;
  201. {
  202.     register struct svc_callout *s, *p;
  203.  
  204.     p = NULL_SVC;
  205.     for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
  206.         if ((s->sc_prog == prog) && (s->sc_vers == vers))
  207.             goto done;
  208.         p = s;
  209.     }
  210. done:
  211.     *prev = p;
  212.     return (s);
  213. }
  214.  
  215. /* ******************* REPLY GENERATION ROUTINES  ************ */
  216.  
  217. /*
  218.  * Send a reply to an rpc request
  219.  */
  220. bool_t
  221. svc_sendreply(xprt, xdr_results, xdr_location)
  222.     register SVCXPRT *xprt;
  223.     xdrproc_t xdr_results;
  224.     caddr_t xdr_location;
  225. {
  226.     struct rpc_msg rply; 
  227.  
  228.     rply.rm_direction = REPLY;  
  229.     rply.rm_reply.rp_stat = MSG_ACCEPTED; 
  230.     rply.acpted_rply.ar_verf = xprt->xp_verf; 
  231.     rply.acpted_rply.ar_stat = SUCCESS;
  232.     rply.acpted_rply.ar_results.where = xdr_location;
  233.     rply.acpted_rply.ar_results.proc = xdr_results;
  234.     return (SVC_REPLY(xprt, &rply)); 
  235. }
  236.  
  237. /*
  238.  * No procedure error reply
  239.  */
  240. void
  241. svcerr_noproc(xprt)
  242.     register SVCXPRT *xprt;
  243. {
  244.     struct rpc_msg rply;
  245.  
  246.     rply.rm_direction = REPLY;
  247.     rply.rm_reply.rp_stat = MSG_ACCEPTED;
  248.     rply.acpted_rply.ar_verf = xprt->xp_verf;
  249.     rply.acpted_rply.ar_stat = PROC_UNAVAIL;
  250.     SVC_REPLY(xprt, &rply);
  251. }
  252.  
  253. /*
  254.  * Can't decode args error reply
  255.  */
  256. void
  257. svcerr_decode(xprt)
  258.     register SVCXPRT *xprt;
  259. {
  260.     struct rpc_msg rply; 
  261.  
  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 = GARBAGE_ARGS;
  266.     SVC_REPLY(xprt, &rply); 
  267. }
  268.  
  269. /*
  270.  * Some system error
  271.  */
  272. void
  273. svcerr_systemerr(xprt)
  274.     register SVCXPRT *xprt;
  275. {
  276.     struct rpc_msg rply; 
  277.  
  278.     rply.rm_direction = REPLY; 
  279.     rply.rm_reply.rp_stat = MSG_ACCEPTED; 
  280.     rply.acpted_rply.ar_verf = xprt->xp_verf;
  281.     rply.acpted_rply.ar_stat = SYSTEM_ERR;
  282.     SVC_REPLY(xprt, &rply); 
  283. }
  284.  
  285. /*
  286.  * Authentication error reply
  287.  */
  288. void
  289. svcerr_auth(xprt, why)
  290.     SVCXPRT *xprt;
  291.     enum auth_stat why;
  292. {
  293.     struct rpc_msg rply;
  294.  
  295.     rply.rm_direction = REPLY;
  296.     rply.rm_reply.rp_stat = MSG_DENIED;
  297.     rply.rjcted_rply.rj_stat = AUTH_ERROR;
  298.     rply.rjcted_rply.rj_why = why;
  299.     SVC_REPLY(xprt, &rply);
  300. }
  301.  
  302. /*
  303.  * Auth too weak error reply
  304.  */
  305. void
  306. svcerr_weakauth(xprt)
  307.     SVCXPRT *xprt;
  308. {
  309.  
  310.     svcerr_auth(xprt, AUTH_TOOWEAK);
  311. }
  312.  
  313. /*
  314.  * Program unavailable error reply
  315.  */
  316. void 
  317. svcerr_noprog(xprt)
  318.     register SVCXPRT *xprt;
  319. {
  320.     struct rpc_msg rply;  
  321.  
  322.     rply.rm_direction = REPLY;   
  323.     rply.rm_reply.rp_stat = MSG_ACCEPTED;  
  324.     rply.acpted_rply.ar_verf = xprt->xp_verf;  
  325.     rply.acpted_rply.ar_stat = PROG_UNAVAIL;
  326.     SVC_REPLY(xprt, &rply);
  327. }
  328.  
  329. /*
  330.  * Program version mismatch error reply
  331.  */
  332. void  
  333. svcerr_progvers(xprt, low_vers, high_vers)
  334.     register SVCXPRT *xprt; 
  335.     u_long low_vers;
  336.     u_long high_vers;
  337. {
  338.     struct rpc_msg rply;
  339.  
  340.     rply.rm_direction = REPLY;
  341.     rply.rm_reply.rp_stat = MSG_ACCEPTED;
  342.     rply.acpted_rply.ar_verf = xprt->xp_verf;
  343.     rply.acpted_rply.ar_stat = PROG_MISMATCH;
  344.     rply.acpted_rply.ar_vers.low = low_vers;
  345.     rply.acpted_rply.ar_vers.high = high_vers;
  346.     SVC_REPLY(xprt, &rply);
  347. }
  348.  
  349. /* ******************* SERVER INPUT STUFF ******************* */
  350.  
  351. /*
  352.  * Get server side input from some transport.
  353.  *
  354.  * Statement of authentication parameters management:
  355.  * This function owns and manages all authentication parameters, specifically
  356.  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
  357.  * the "cooked" credentials (rqst->rq_clntcred).
  358.  * However, this function does not know the structure of the cooked
  359.  * credentials, so it make the following assumptions: 
  360.  *   a) the structure is contiguous (no pointers), and
  361.  *   b) the cred structure size does not exceed RQCRED_SIZE bytes. 
  362.  * In all events, all three parameters are freed upon exit from this routine.
  363.  * The storage is trivially management on the call stack in user land, but
  364.  * is mallocated in kernel land.
  365.  */
  366.  
  367. void
  368. svc_getreq(rdfds)
  369.     int rdfds;
  370. {
  371. #ifdef FD_SETSIZE
  372.     fd_set readfds;
  373.  
  374.     FD_ZERO(&readfds);
  375.     readfds.fds_bits[0] = rdfds;
  376.     svc_getreqset(&readfds);
  377. #else
  378.     int readfds = rdfds & svc_fds;
  379.  
  380.     svc_getreqset(&readfds);
  381. #endif /* def FD_SETSIZE */
  382. }
  383.  
  384. void
  385. svc_getreqset(readfds)
  386. #ifdef FD_SETSIZE
  387.     fd_set *readfds;
  388. {
  389. #else
  390.     int *readfds;
  391. {
  392.     int readfds_local = *readfds;
  393. #endif /* def FD_SETSIZE */
  394.     register enum xprt_stat stat;
  395.     struct rpc_msg msg;
  396.     int prog_found;
  397.     int
  398.     u_long low_vers;
  399.     u_long high_vers;
  400.     struct svc_req r;
  401.     register int sock;
  402.     register SVCXPRT *xprt;
  403.     char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
  404.     msg.rm_call.cb_cred.oa_base = cred_area;
  405.     msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
  406.     r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
  407.  
  408.     
  409. #ifdef FD_SETSIZE
  410.     for (sock = 0; sock < FD_SETSIZE; sock++) {
  411.         if (FD_ISSET(sock, readfds) && FD_ISSET(sock, &svc_fdset)) {
  412. #else
  413.     for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) {
  414.         if ((readfds_local & 1) != 0) {
  415. #endif /* def FD_SETSIZE */
  416.         /* sock has input waiting */
  417.         xprt = xports[sock];
  418.         /* now receive msgs from xprtprt (support batch calls) */
  419.         do {
  420.             if (SVC_RECV(xprt, &msg)) {
  421.  
  422.                 /* now find the exported program and call it */
  423.                 register struct svc_callout *s;
  424.                 enum auth_stat why;
  425.  
  426.                 r.rq_xprt = xprt;
  427.                 r.rq_prog = msg.rm_call.cb_prog;
  428.                 r.rq_vers = msg.rm_call.cb_vers;
  429.                 r.rq_proc = msg.rm_call.cb_proc;
  430.                 r.rq_cred = msg.rm_call.cb_cred;
  431.                 /* first authenticate the message */
  432.                 if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
  433.                     svcerr_auth(xprt, why);
  434.                     goto call_done;
  435.                 }
  436.                 /* now match message with a registered service*/
  437.                 prog_found = FALSE;
  438.                 low_vers = 0 - 1;
  439.                 high_vers = 0;
  440.                 for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
  441.                     if (s->sc_prog == r.rq_prog) {
  442.                         if (s->sc_vers == r.rq_vers) {
  443.                             (*s->sc_dispatch)(&r, xprt);
  444.                             goto call_done;
  445.                         }  /* found correct version */
  446.                         prog_found = TRUE;
  447.                         if (s->sc_vers < low_vers)
  448.                             low_vers = s->sc_vers;
  449.                         if (s->sc_vers > high_vers)
  450.                             high_vers = s->sc_vers;
  451.                     }   /* found correct program */
  452.                 }
  453.                 /*
  454.                  * if we got here, the program or version
  455.                  * is not served ...
  456.                  */
  457.                 if (prog_found)
  458.                     svcerr_progvers(xprt,
  459.                     low_vers, high_vers);
  460.                 else
  461.                      svcerr_noprog(xprt);
  462.                 /* Fall through to ... */
  463.             }
  464.         call_done:
  465.             if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
  466.                 SVC_DESTROY(xprt);
  467.                 break;
  468.             }
  469.         } while (stat == XPRT_MOREREQS);
  470.         }
  471.     }
  472. }
  473.