Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!think.com!paperboy!hsdndev!cmcl2!adm!lhc!lhc!warsaw From: warsaw@nlm.nih.gov (Barry A. Warsaw) Newsgroups: comp.lang.c++ Subject: Re: Sun C++ 2.0 and RPC: Urg! (update) Message-ID: Date: 23 May 91 16:57:41 GMT References: <260@wimpy.nms.gdc.portal.com> Sender: usenet@nlm.nih.gov (usenet news poster) Reply-To: warsaw@nlm.nih.gov Organization: Century Computing, Inc. Lines: 109 In-Reply-To: bergquis@nms.gdc.portal.com's message of 20 May 91 16:30:45 GMT >>>>> "Brett" == Brett Bergquist writes: Brett> I to have been trying to get Sun C++ 2.0 to work with RPC. Brett> I found the same faults in the header files that you did. Brett> I took a different approach by compiling the _svc.c, Brett> _xdr.c, and _clnt.c using the C compiler. Somewhere in the Brett> manual for C++, it mentioned that you probably want to Brett> compile these files with the C compile so that you do not Brett> get a lot of warnings. Well, after a bit of hacking (at patching the Sun C++ 2.0 header files), I've finally got a couple of classes implementing RPC. I took the files generated by rpcgen (not rpcgen++) as a template and wrapped it all up into a `server' and `client' class. One limitation is that I only implemented tcp since that's what I'm using, but there's nothing to prevent you from extending/modifying the class internals. Below are the public interfaces to the two classes. You'll still need rpcgen to create the _xdr.c file and the .h file if you don't do it by hand (which really is almost as easy, except there's more to maintain when the protocol changes). If you're interested in more details send email. `server' usage requires you to derive your own class from server and make member functions of this class take two char*& arguments. These member functions will be the callback associated with RPC procedure numbers. The two char*& arguments can be cast to pointers to the appropriate data type within the callback function. Allocation and de-allocation of memory, serializing and deserializing XDR streams, etc, are all handled internally, as well as registration with portmapper and other bookkeeping. `client' usage more straightforward. You just give it a server hostname to connect to and then remotely execute procedures. You give rexec the size of the receiving data type (out) so that it is zeroed out before the deserialized data is placed there. -Barry NAME: Barry A. Warsaw USMAIL: National Library of Medicine TELE: (301) 496-1936 Lister Hill National Center for INET: warsaw@nlm.nih.gov Biomedical Communications UUCP: uunet!nlm.nih.gov!warsaw Information Technology Branch 8600 Rockville Pike Bldg. 38A, Rm. 7s722 Bethesda, Md. 20894 ==================== server class ==================== typedef void (server::*rpc_handler)( char*& in, char*& out ); class server { public: // it is an error to instantiate more than 1 instance of the // server class. Note that there is no destructor for this // class since (due to the nature of the run method), it will // never be destroyed until the entire process dies. server( u_long prognum, u_long versnum ); // register an RPC procedure with the appropriate callback // function which can handle this procedure call. void regproc( u_long procedure, rpc_handler callback, xdrproc_t in_converter, int indata_size, xdrproc_t out_converter, int outdata_size ); // once all callbacks are registered, the application can call // the run method below to start up the RPC server. it is an // error for run() to ever return so if a callback is used to // terminate the server, it should call exit() inline void run( void ); // returns non-zero if the application was started up by the // inet daemon inline int inetd_p( void ); protected: // this function actually does the dispatching to the member // function that can handle the remote procedure call. it is // not directly called by the RPC level code. virtual void dispatch( svc_req* request, SVCXPRT* transp ); }; ==================== client class interface ==================== static timeval _DEFAULT_CLIENT_TIMEOUT = { 25, 0 }; class client { public: inline client( string server, u_long prognum, u_long versnum, timeval timeout = _DEFAULT_CLIENT_TIMEOUT ); inline ~client( void ); // execute remote procedure on server, returns zero on // success, non-zero on failure. inline int rexec( u_long procedure, xdrproc_t in_converter, char*& in, xdrproc_t out_converter, char*& out, int sizeof_outdata ); // get and set the timeout value inline void timeout( timeval& new_timeout ); inline timeval timeout( void ); };