home *** CD-ROM | disk | FTP | other *** search
- // -*- c++ -*-
- /*
- Copyright (C) 1991 Peter Bersen
-
- This file is part of the rpc++ Library. This library is free
- software; you can redistribute it and/or modify it under the terms of
- the GNU Library General Public License as published by the Free
- Software Foundation; either version 2 of the License, or (at your
- option) any later version. This library is distributed in the hope
- that it will be useful, but WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the GNU Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Modified and partially rewritten March 1992 by Michael N. Lipp,
- mnl@dtro.e-technik.th-darmstadt.de. The original copyright terms and
- conditions apply without change to any modified or new parts.
- */
-
- static char _rpcpp_service_cc_[]
- = "service.cc,v 2.5 1993/01/20 15:00:14 mnl Exp";
-
- // service.cc,v
- // Revision 2.5 1993/01/20 15:00:14 mnl
- // Updated for gcc-2.3.3.
- //
- // Revision 2.4 1992/12/06 18:57:53 mnl
- // Fixed various bugs and added some Methods.
- //
- // Revision 2.3 1992/06/15 19:12:44 mnl
- // Fixed a few bugs, clarified interface.
- //
- // Revision 2.2 1992/06/13 14:27:02 mnl
- // Adapted to (patched) gcc-2.2. Fixed several bugs.
- //
- // Revision 2.1.1.1 1992/03/08 13:28:42 mnl
- // Initial mnl version.
- //
-
- #ifdef __GNUG__
- #pragma implementation
- #endif
-
- #include <assert.h>
- #include <stream.h>
- #include <memory.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <rpc/rpc.h>
- #include <rpc/svc.h>
- #include <rpc/pmap_clnt.h>
- #include "rpc++/service.h"
- #include "rpc++/request.h"
-
- extern "C" {
- extern int getdtablesize();
- }
-
- //
- // RpcRegistered -- help class
- //
-
- class RpcRegistered
- {
- public:
- RpcRequest request;
- AnyRpcCallback* callback;
-
- inline RpcRegistered (const RpcRequest& req, AnyRpcCallback* cb)
- : request (req), callback (cb) { }
- inline ~RpcRegistered ()
- { delete callback; }
- };
-
- //
- // RpcService
- //
-
- RpcService* RpcService::me = 0;
- // nopRequest is used as a dummy to mark reserved but not yet registered
- // service slots. Just in case it gets called, there is really a nop.
- static void nop () {}
- static RpcCallback nopCb (nop);
- RpcRegistered* RpcService::nopHandler
- = new RpcRegistered (RpcRequest (0, &Xdr::Xvoid), &nopCb);
-
- RpcService::RpcService (u_long pnum, u_long vnum)
- {
- init ();
- prog = pnum;
- vers = vnum;
- // find out if we have been started by inetd and set transp accoringly.
- sockaddr_in sa;
- int sasz = sizeof (sa);
- // if started by inetd, stdin is a socket
- standalone = (getsockname (0, (sockaddr*)&sa, &sasz) != 0);
- if (standalone)
- { // we are standalone
- (void) pmap_unset(prog, vers);
- xprt = svctcp_create(RPC_ANYSOCK, 0, 0);
- }
- else
- { // inetd is our parent
- xprt = svctcp_create(0, 0, 0);
- }
- if (xprt == NULL)
- {
- HandleError (cantCreateTCPService);
- return;
- }
- if (!svc_register(xprt, prog, vers, RpcServiceCallback,
- standalone ? IPPROTO_TCP : 0))
- {
- HandleError (cantRegisterService);
- return;
- }
- }
-
- RpcService::RpcService (u_long vnum)
- {
- init ();
- vers = vnum;
- prog = 0x40000000;
- xprt = svctcp_create(RPC_ANYSOCK, 0, 0);
- if (xprt == NULL)
- {
- HandleError (cantCreateTCPService);
- return;
- }
- while (! pmap_set (prog, vers, IPPROTO_TCP, xprt->xp_port))
- prog++;
- if (!svc_register(xprt, prog, vers, RpcServiceCallback, IPPROTO_TCP))
- {
- HandleError (cantRegisterService);
- return;
- }
- }
-
- void RpcService::init ()
- {
- errorState = noError;
- if (me)
- {
- HandleError (reconstructionAttempt);
- return;
- }
- me = this;
- handlers = 0;
- maxHandlerIndex = -1;
- inbuf = 0;
- inmax = 0;
- }
-
- RpcService::~RpcService ()
- {
- if (standalone)
- svc_unregister (prog, vers);
- for (int i = 0; i <= maxHandlerIndex; i++)
- if (handlers[i] != nopHandler)
- delete handlers[i];
- delete [] handlers;
- delete [] inbuf;
- me = 0;
- }
-
- void RpcService::HandleError ()
- {
- switch (errorState)
- {
- case reconstructionAttempt:
- cerr << "rpc++: Attempt to construct another instance of RpcService.\n";
- exit (1);
- case cantCreateTCPService:
- cerr << "rpc++: can't create tcp service.\n";
- exit(1);
- case cantRegisterService:
- cerr << form ("rpc++: can't register (%d, %d, tcp).", prog, vers);
- exit(1);
- case cantSendReply:
- cerr << "rpc++: can't reply to RPC call.\n";
- break;
- case invalidResult:
- cerr << "rpc++: registered routine has return NULL pointer.\n";
- abort ();
- case notRegistered:
- cerr << "rpc++: requested RPC routine not registered.\n";
- break;
- case cantGetArgs:
- cerr << "rpc++: can't get procedure arguments.\n";
- break;
- case cantFreeArgs:
- cerr << "rpc++: can't free XDR arguments.\n";
- break;
- }
- errorState = noError;
- }
-
- void RpcService::Register (const RpcRequest& req, const AnyRpcCallback& cb)
- {
- assert (req.Params () == -1 || cb.Params () == -1
- || req.Params () == cb.Params ());
- AnyRpcCallback* cbp = cb.CopyToHeap ();
- cbp->SetService (this);
- if (req.RequestNumber () > maxHandlerIndex)
- {
- RpcRegistered** reg = new RpcRegistered*[req.RequestNumber () + 10];
- memcpy (reg, handlers, (maxHandlerIndex + 1) * sizeof (RpcRegistered*));
- memset (®[maxHandlerIndex + 1], 0,
- (req.RequestNumber () + 10 - (maxHandlerIndex + 1))
- * sizeof (RpcRegistered*));
- delete handlers;
- handlers = reg;
- maxHandlerIndex = req.RequestNumber () + 10 - 1;
- }
- if (handlers[req.RequestNumber ()] != nopHandler)
- delete handlers[req.RequestNumber ()];
- handlers[req.RequestNumber ()] = new RpcRegistered (req, cbp);
- }
-
- void RpcService::Unregister (const RpcRequest& req)
- {
- if (req.RequestNumber () > maxHandlerIndex)
- return;
- if (handlers[req.RequestNumber ()] != nopHandler)
- delete handlers[req.RequestNumber ()];
- handlers[req.RequestNumber ()] = 0;
- }
-
- u_long RpcService::ReserveService ()
- {
- u_long svc = 0;
- for (int req = 1; req <= maxHandlerIndex; req++)
- {
- if (handlers[req] == 0)
- {
- svc = req;
- break;
- }
- }
- if (svc == 0)
- svc = maxHandlerIndex + 1;
- handlers[svc] = nopHandler;
- return svc;
- }
-
- void RpcService::Dispatch (svc_req* req, SVCXPRT* transp)
- {
- xprt = transp;
- if (req->rq_proc == NULLPROC)
- {
- if (! svc_sendreply (xprt, xdr_void, 0))
- {
- svcerr_systemerr (xprt);
- HandleError (cantSendReply);
- }
- return;
- }
- RpcRegistered* handler = ((req->rq_proc > maxHandlerIndex)
- ? 0
- : handlers[req->rq_proc]);
- if (! handler)
- {
- svcerr_noproc (xprt);
- HandleError (notRegistered);
- return;
- }
- rpcreq = &handler->request;
-
- int insz = rpcreq->ParamSize ();
- if (insz > inmax) // does in-data fit in available buffer?
- { // if not, increase buffer space
- delete [] inbuf;
- inbuf = new char[inmax = insz];
- }
- void* dataps[rpcreq->Params ()];
- void** dp = dataps;
- *dp = inbuf;
- for (XdrInfo** ip = rpcreq->InInfo(); *ip; ip++, dp++)
- dp[1] = (char*)dp[0] + (*ip)->Size ();
-
- memset (inbuf, 0, insz);
- XdrSeqInfo xsi = { rpcreq->InInfo (), dataps };
- if (!svc_getargs (xprt, Xdr::XdrParams, &xsi))
- {
- if (rpcreq->Type () == RpcRequest::normal) // errors can be reported
- svcerr_decode (xprt); // only if the client waits for a result
- HandleError (cantGetArgs);
- return;
- }
- haveReplied = FALSE;
- void* res = handler->callback->Do (dataps);
- if (! haveReplied)
- Reply (res);
- if (!svc_freeargs (xprt, Xdr::XdrParams, &xsi))
- HandleError (cantFreeArgs);
- xprt = 0;
- }
-
- void RpcService::Reply (void* res)
- {
- haveReplied = TRUE;
- if (rpcreq->Type () == RpcRequest::normal) // i.e., result expected
- {
- xdrproc_t outproc = rpcreq->OutInfo()->Proc ();
- if (outproc == (xdrproc_t)0)
- {
- cerr << "rpc++: RpcRequest has invalid xdrproc_t (0) in out-Info";
- abort ();
- }
- if (res == 0 && outproc != (xdrproc_t)xdr_void)
- {
- svcerr_systemerr (xprt);
- HandleError ();
- }
- else if (!svc_sendreply
- (xprt, rpcreq->OutInfo()->Proc (), (caddr_t)res))
- {
- svcerr_systemerr (xprt);
- HandleError (cantSendReply);
- }
- }
- }
-
- void RpcService::DoProvide (timeval* thisLong)
- {
- int dtbsz = getdtablesize();
- fd_set readfds;
-
- quitLoop = FALSE;
- while (! quitLoop)
- {
- readfds = svc_fdset;
- switch(select (dtbsz, &readfds, 0, 0, thisLong))
- {
- case -1:
- if (errno != EBADF)
- continue;
- cerr << "PRC++: select: " << sys_errlist[errno] << '\n';
- return;
- case 0:
- if (thisLong == 0)
- continue;
- return;
- default:
- svc_getreqset (&readfds);
- if (thisLong != 0)
- return;
- break;
- }
- }
- }
-
- const char* RpcService::CallerName ()
- {
- struct sockaddr_in *sa = Caller ();
- struct hostent* he = gethostbyaddr ((const char*)&sa->sin_addr,
- sizeof (sa->sin_addr),
- sa->sin_family);
- return he->h_name;
- }
-