home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD2.bin / bbs / comm / amitcp-sdk-4.0.lha / AmiTCP-SDK / src / rpclib / svc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-30  |  10.7 KB  |  482 lines

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