home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / mnl-rpc++-2.3.1 / part01 / service.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-24  |  9.0 KB  |  366 lines

  1. // -*- c++ -*-
  2. /* 
  3. Copyright (C) 1991 Peter Bersen
  4.  
  5. This file is part of the rpc++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  
  17. Modified and partially rewritten March 1992 by Michael N. Lipp,
  18. mnl@dtro.e-technik.th-darmstadt.de. The original copyright terms and
  19. conditions apply without change to any modified or new parts.
  20. */
  21.  
  22. static char _rpcpp_service_cc_[]
  23. = "service.cc,v 2.5 1993/01/20 15:00:14 mnl Exp";
  24.  
  25. // service.cc,v
  26. // Revision 2.5  1993/01/20  15:00:14  mnl
  27. // Updated for gcc-2.3.3.
  28. //
  29. // Revision 2.4  1992/12/06  18:57:53  mnl
  30. // Fixed various bugs and added some Methods.
  31. //
  32. // Revision 2.3  1992/06/15  19:12:44  mnl
  33. // Fixed a few bugs, clarified interface.
  34. //
  35. // Revision 2.2  1992/06/13  14:27:02  mnl
  36. // Adapted to (patched) gcc-2.2. Fixed several bugs.
  37. //
  38. // Revision 2.1.1.1  1992/03/08  13:28:42  mnl
  39. // Initial mnl version.
  40. //
  41.  
  42. #ifdef __GNUG__
  43. #pragma implementation
  44. #endif
  45.  
  46. #include <assert.h>
  47. #include <stream.h>
  48. #include <memory.h>
  49. #include <errno.h>
  50. #include <stdlib.h>
  51. #include <sys/types.h>
  52. #include <sys/socket.h>
  53. #include <netdb.h>
  54. #include <rpc/rpc.h>
  55. #include <rpc/svc.h>
  56. #include <rpc/pmap_clnt.h>
  57. #include "rpc++/service.h"
  58. #include "rpc++/request.h"
  59.  
  60. extern "C" {
  61.   extern int getdtablesize();
  62. }
  63.  
  64. //
  65. // RpcRegistered -- help class
  66. //
  67.  
  68. class RpcRegistered
  69. {
  70. public:
  71.   RpcRequest request;
  72.   AnyRpcCallback* callback;
  73.  
  74.   inline RpcRegistered (const RpcRequest& req, AnyRpcCallback* cb)
  75.     : request (req), callback (cb) { }
  76.   inline ~RpcRegistered ()
  77.     { delete callback; }
  78. };
  79.  
  80. //
  81. // RpcService
  82. //
  83.  
  84. RpcService* RpcService::me = 0;
  85. // nopRequest is used as a dummy to mark reserved but not yet registered
  86. // service slots. Just in case it gets called, there is really a nop.
  87. static void nop () {}
  88. static RpcCallback nopCb (nop);
  89. RpcRegistered* RpcService::nopHandler
  90.  = new RpcRegistered (RpcRequest (0, &Xdr::Xvoid), &nopCb);
  91.  
  92. RpcService::RpcService (u_long pnum, u_long vnum)
  93. {
  94.   init ();
  95.   prog = pnum;
  96.   vers = vnum;
  97.   // find out if we have been started by inetd and set transp accoringly.
  98.   sockaddr_in sa;
  99.   int sasz = sizeof (sa);
  100.   // if started by inetd, stdin is a socket
  101.   standalone = (getsockname (0, (sockaddr*)&sa, &sasz) != 0);
  102.   if (standalone)
  103.     { // we are standalone
  104.       (void) pmap_unset(prog, vers);
  105.       xprt = svctcp_create(RPC_ANYSOCK, 0, 0);
  106.     }
  107.   else
  108.     { // inetd is our parent
  109.       xprt = svctcp_create(0, 0, 0);
  110.     }
  111.   if (xprt == NULL)
  112.     {
  113.       HandleError (cantCreateTCPService);
  114.       return;
  115.     }
  116.   if (!svc_register(xprt, prog, vers, RpcServiceCallback,
  117.             standalone ? IPPROTO_TCP : 0))
  118.     {
  119.       HandleError (cantRegisterService);
  120.       return;
  121.     }
  122. }
  123.  
  124. RpcService::RpcService (u_long vnum)
  125. {
  126.   init ();
  127.   vers = vnum;
  128.   prog = 0x40000000;
  129.   xprt = svctcp_create(RPC_ANYSOCK, 0, 0);
  130.   if (xprt == NULL)
  131.     {
  132.       HandleError (cantCreateTCPService);
  133.       return;
  134.     }
  135.   while (! pmap_set (prog, vers, IPPROTO_TCP, xprt->xp_port))
  136.     prog++;
  137.   if (!svc_register(xprt, prog, vers, RpcServiceCallback, IPPROTO_TCP))
  138.     {
  139.       HandleError (cantRegisterService);
  140.       return;
  141.     }
  142. }
  143.  
  144. void RpcService::init ()
  145. {
  146.   errorState = noError;
  147.   if (me)
  148.     {
  149.       HandleError (reconstructionAttempt);
  150.       return;
  151.     }
  152.   me = this;
  153.   handlers = 0;
  154.   maxHandlerIndex = -1;
  155.   inbuf = 0;
  156.   inmax = 0;
  157. }
  158.  
  159. RpcService::~RpcService ()
  160. {
  161.   if (standalone)
  162.     svc_unregister (prog, vers);
  163.   for (int i = 0; i <= maxHandlerIndex; i++)
  164.     if (handlers[i] != nopHandler)
  165.       delete handlers[i];
  166.   delete [] handlers;
  167.   delete [] inbuf;
  168.   me = 0;
  169. }
  170.  
  171. void RpcService::HandleError ()
  172. {
  173.   switch (errorState)
  174.     {
  175.     case reconstructionAttempt:
  176.       cerr << "rpc++: Attempt to construct another instance of RpcService.\n";
  177.       exit (1);
  178.     case cantCreateTCPService:
  179.       cerr << "rpc++: can't create tcp service.\n";
  180.       exit(1);
  181.     case cantRegisterService:
  182.       cerr << form ("rpc++: can't register (%d, %d, tcp).", prog, vers);
  183.       exit(1);
  184.     case cantSendReply:
  185.       cerr << "rpc++: can't reply to RPC call.\n";
  186.       break;
  187.     case invalidResult:
  188.       cerr << "rpc++: registered routine has return NULL pointer.\n";
  189.       abort ();
  190.     case notRegistered:
  191.       cerr << "rpc++: requested RPC routine not registered.\n";
  192.       break;
  193.     case cantGetArgs:
  194.       cerr << "rpc++: can't get procedure arguments.\n";
  195.       break;
  196.     case cantFreeArgs:
  197.       cerr << "rpc++: can't free XDR arguments.\n";
  198.       break;
  199.     }
  200.   errorState = noError;
  201. }
  202.  
  203. void RpcService::Register (const RpcRequest& req, const AnyRpcCallback& cb)
  204. {
  205.   assert (req.Params () == -1 || cb.Params () == -1
  206.       || req.Params () == cb.Params ());
  207.   AnyRpcCallback* cbp = cb.CopyToHeap ();
  208.   cbp->SetService (this);
  209.   if (req.RequestNumber () > maxHandlerIndex)
  210.     {
  211.       RpcRegistered** reg = new RpcRegistered*[req.RequestNumber () + 10];
  212.       memcpy (reg, handlers, (maxHandlerIndex + 1) * sizeof (RpcRegistered*));
  213.       memset (®[maxHandlerIndex + 1], 0,
  214.           (req.RequestNumber () + 10 - (maxHandlerIndex + 1))
  215.           * sizeof (RpcRegistered*));
  216.       delete handlers;
  217.       handlers = reg;
  218.       maxHandlerIndex = req.RequestNumber () + 10 - 1;
  219.     }
  220.   if (handlers[req.RequestNumber ()] != nopHandler)
  221.     delete handlers[req.RequestNumber ()];
  222.   handlers[req.RequestNumber ()] = new RpcRegistered (req, cbp);
  223. }
  224.  
  225. void RpcService::Unregister (const RpcRequest& req)
  226. {
  227.   if (req.RequestNumber () > maxHandlerIndex)
  228.     return;
  229.   if (handlers[req.RequestNumber ()] != nopHandler)
  230.     delete handlers[req.RequestNumber ()];
  231.   handlers[req.RequestNumber ()] = 0;
  232. }
  233.  
  234. u_long RpcService::ReserveService ()
  235. {
  236.   u_long svc = 0;
  237.   for (int req = 1; req <= maxHandlerIndex; req++)
  238.     {
  239.       if (handlers[req] == 0)
  240.     {
  241.       svc = req;
  242.       break;
  243.     }
  244.     }
  245.   if (svc == 0)
  246.     svc = maxHandlerIndex + 1;
  247.   handlers[svc] = nopHandler;
  248.   return svc;
  249. }
  250.  
  251. void RpcService::Dispatch (svc_req* req, SVCXPRT* transp)
  252. {
  253.   xprt = transp;
  254.   if (req->rq_proc == NULLPROC)
  255.     {
  256.       if (! svc_sendreply (xprt, xdr_void, 0))
  257.     {
  258.       svcerr_systemerr (xprt);
  259.       HandleError (cantSendReply);
  260.     }
  261.       return;
  262.     }
  263.   RpcRegistered* handler = ((req->rq_proc > maxHandlerIndex)
  264.                 ? 0
  265.                 : handlers[req->rq_proc]);
  266.   if (! handler)
  267.     {
  268.       svcerr_noproc (xprt);
  269.       HandleError (notRegistered);
  270.       return;
  271.     }
  272.   rpcreq = &handler->request;
  273.  
  274.   int insz = rpcreq->ParamSize ();
  275.   if (insz > inmax) // does in-data fit in available buffer?
  276.     { // if not, increase buffer space
  277.       delete [] inbuf;
  278.       inbuf = new char[inmax = insz];
  279.     }
  280.   void* dataps[rpcreq->Params ()];
  281.   void** dp = dataps;
  282.   *dp = inbuf;
  283.   for (XdrInfo** ip = rpcreq->InInfo(); *ip; ip++, dp++)
  284.     dp[1] = (char*)dp[0] + (*ip)->Size ();
  285.  
  286.   memset (inbuf, 0, insz);
  287.   XdrSeqInfo xsi = { rpcreq->InInfo (), dataps };
  288.   if (!svc_getargs (xprt, Xdr::XdrParams, &xsi))
  289.     {
  290.       if (rpcreq->Type () == RpcRequest::normal) // errors can be reported
  291.     svcerr_decode (xprt);   // only if the client waits for a result
  292.       HandleError (cantGetArgs);
  293.       return;
  294.     }
  295.   haveReplied = FALSE;
  296.   void* res = handler->callback->Do (dataps);
  297.   if (! haveReplied)
  298.     Reply (res);
  299.   if (!svc_freeargs (xprt, Xdr::XdrParams, &xsi))
  300.     HandleError (cantFreeArgs);
  301.   xprt = 0;
  302. }
  303.  
  304. void RpcService::Reply (void* res)
  305. {
  306.   haveReplied = TRUE;
  307.   if (rpcreq->Type () == RpcRequest::normal) // i.e., result expected
  308.     {
  309.       xdrproc_t outproc = rpcreq->OutInfo()->Proc ();
  310.       if (outproc == (xdrproc_t)0)
  311.     {
  312.       cerr << "rpc++: RpcRequest has invalid xdrproc_t (0) in out-Info";
  313.       abort ();
  314.     }
  315.       if (res == 0 && outproc != (xdrproc_t)xdr_void)
  316.     {
  317.       svcerr_systemerr (xprt);
  318.       HandleError ();
  319.     }
  320.       else if (!svc_sendreply
  321.            (xprt, rpcreq->OutInfo()->Proc (), (caddr_t)res))
  322.     {
  323.       svcerr_systemerr (xprt);
  324.       HandleError (cantSendReply);
  325.     }
  326.     }
  327. }
  328.  
  329. void RpcService::DoProvide (timeval* thisLong)
  330. {
  331.   int dtbsz = getdtablesize();
  332.   fd_set readfds;
  333.  
  334.   quitLoop = FALSE;
  335.   while (! quitLoop)
  336.     {
  337.       readfds = svc_fdset;
  338.       switch(select (dtbsz, &readfds, 0, 0, thisLong))
  339.     {
  340.     case -1:
  341.       if (errno != EBADF)
  342.         continue;
  343.       cerr << "PRC++: select: " << sys_errlist[errno] << '\n';
  344.       return;
  345.     case 0:
  346.       if (thisLong == 0)
  347.         continue;
  348.       return;
  349.     default:
  350.       svc_getreqset (&readfds);
  351.       if (thisLong != 0)
  352.         return;
  353.       break;
  354.     }
  355.     }
  356. }
  357.  
  358. const char* RpcService::CallerName ()
  359. {
  360.   struct sockaddr_in *sa = Caller ();
  361.   struct hostent* he = gethostbyaddr ((const char*)&sa->sin_addr,
  362.                       sizeof (sa->sin_addr),
  363.                       sa->sin_family);
  364.   return he->h_name;
  365. }
  366.