00001 // Copyright (C) 2001, Compaq Computer Corporation 00002 // 00003 // This file is part of Vesta. 00004 // 00005 // Vesta is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU Lesser General Public 00007 // License as published by the Free Software Foundation; either 00008 // version 2.1 of the License, or (at your option) any later version. 00009 // 00010 // Vesta is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // Lesser General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU Lesser General Public 00016 // License along with Vesta; if not, write to the Free Software 00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 00019 // Last modified on Sun May 22 22:53:25 EDT 2005 by ken@xorian.net 00020 // modified on Fri Aug 14 15:32:04 PDT 1998 by mann 00021 // modified on Mon Jun 16 11:07:42 PDT 1997 by heydon 00022 // modified on Sun Aug 20 08:51:54 PDT 1995 by levin 00023 00024 // MultiSRPC -- a cache of SRPC connections to servers on various machines 00025 00026 // A "MultiSRPC" object is a cache of client SRPC connections to 00027 // potentially multiple servers that all export the same interface. 00028 // The object provides two functions, Start and End. A client calls 00029 // Start and specifies the desired host for the server; Start returns 00030 // a suitable SRPC object, either from its cache or newly created. 00031 // The client calls End to tell MultiSRPC that it is finished with an 00032 // SRPC connection, which is then placed in the cache for future use 00033 // by Start. 00034 00035 // Each MultiSRPC object represents a cache for a collection of 00036 // servers for the same interface. Here the term "interface" is used 00037 // somewhat loosely, since SRPC supports only a weak notion of 00038 // interface. SRPC allows its callers to specify a TCP port number 00039 // (or name for a port number) that is used to connect client and 00040 // server, but it is the responsibility of client and server code to 00041 // agree on such a number through other means. 00042 00043 // There are two common styles of assigning port numbers. In the 00044 // simpler case, a port number is associated with an abstract 00045 // "service" in advance of its deployment. This number is either 00046 // wired into the code of client and server, or is placed in some 00047 // external configuration database where it is looked up by using some 00048 // other piece of statically shared information. This technique works 00049 // well when the set of services can be enumerated in advance of 00050 // execution. 00051 00052 // A more complicated scheme is used when the service is, in effect, 00053 // an object, and the number of objects and/or their distribution 00054 // across service machines is not known statically. In this case, the 00055 // port number is assigned dynamically and communicated between client 00056 // and servers by means external to SRPC. This technique allows 00057 // multiple object servers to reside on the same host machine; they 00058 // simply use different port numbers. 00059 00060 // MultiSRPC supports both of these styles. An "interface" (port 00061 // number) can be specified at construction time, in which case all 00062 // cached connections held by the object use the same port number. 00063 // Alternatively, the interface need not be specified at construction 00064 // time, in which case the client must specify a port number on each 00065 // call to Start. 00066 00067 00068 #ifndef _MULTI_SRPC_H 00069 #define _MULTI_SRPC_H 00070 00071 #include <Basics.H> 00072 #include "SRPC.H" 00073 00074 class MultiSRPC { 00075 public: 00076 // Constructors 00077 MultiSRPC(const Text &interface = Text("")); 00078 /* Make a new, empty cache for connections to servers. If "interface" is 00079 non-empty, the servers all must export it. If "interface" is empty, 00080 the choice of interface is made at the time Start is called. */ 00081 00082 // Destructor 00083 ~MultiSRPC(); 00084 00085 typedef int ConnId; 00086 /* A connection identifier is ``valid'' iff it is non-negative. */ 00087 00088 // Request a new SRPC connection to a particular server 00089 ConnId Start(const Text &hostname, SRPC*& srpc) throw (SRPC::failure) 00090 { return Start(hostname, "", srpc); }; 00091 /* Return the valid identifier of a dedicated SRPC connection to a server 00092 for the interface named in the constructor running on the machine named 00093 "hostname", and set "srpc" to a pointer to the underlying connection. 00094 When done with the connection, either call "End" to make the connection 00095 available to other clients, or call "Discard" to cause the connection 00096 to be closed. 00097 00098 Throws "SRPC::failure" if the interface name specified in the 00099 constructor was empty or if "hostname" is an unknown host or if 00100 that host is not currently exporting the interface named in the 00101 constructor. */ 00102 00103 ConnId Start(const Text &hostname, const Text &interface, SRPC*& srpc) 00104 throw(SRPC::failure); 00105 /* Return the valid identifier of a dedicated SRPC connection to a server 00106 for the specified interface on the specified hostname, and set "srpc" 00107 to a pointer to the underlying connection. When done with the 00108 connection, either call "End" to make the connection available to other 00109 clients, or call "Discard" to cause the connection to be closed. 00110 00111 Throws "SRPC::failure" if the constructor specified a non-empty 00112 interface name or if "hostname" is an unknown host or if that 00113 host is not currently exporting the specified "interface". */ 00114 00115 // Finish using a connection 00116 void End(ConnId id) throw(); 00117 /* Make the connection "id" available to other clients. If "id" is invalid, 00118 this is a no-op. Otherwise, "id" must be a (valid) connection identifier 00119 returned by an invocation of the "Start" method above. */ 00120 00121 /* Usage Note: Since "End" is a no-op when "id" is an invalid connection 00122 identifier, no tests are required to handle the case where "Start" throws 00123 "SRPC::failure". Instead, clients can write code like this: 00124 00125 MultiSRPC::ConnId id = -1; 00126 try { 00127 SRPC *srpc; 00128 id = multi.Start(hostname, srpc); 00129 // use "srpc" connection here 00130 multi.End(id); 00131 } catch (SRPC::failure) { 00132 multi.End(id); 00133 // handle failure 00134 } 00135 */ 00136 00137 void Discard(ConnId id) throw(); 00138 /* Close the connection "id" and free the resources it consumed. Call this 00139 instead of End if you know the connection will not be useful to another 00140 client in the future. If "id" is invalid, this is a no-op. */ 00141 00142 void Purge(const Text &hostname, const Text &interface) throw(SRPC::failure); 00143 /* If there are any cached SRPC connections to the specified interface on 00144 the specified hostname that are not in use, close and discard them. */ 00145 00146 private: 00147 // the server interface 00148 Text intf; 00149 00150 // The connections are stored in a table indexed by server host name. 00151 // The entire table is protected by a mutex. 00152 Basics::mutex mu; 00153 00154 // For now, the table is a simple array of entries. If the "srpc" entry is 00155 // NULL, then a failure was detected on some previous SRPC connection that 00156 // used this entry in the table, so the entry is available for a new 00157 // connection. If the "interface" entry is Empty(), it is implicitly equal 00158 // to the value of "this->intf", which cannot be Empty(). 00159 struct Entry { 00160 Text hostname; 00161 Text interface; // empty iff intf is non-empty 00162 bool inUse; // connection in use? 00163 SRPC *srpc; // NULL means this entry is not used 00164 00165 // default constructor/destructor 00166 Entry() throw () : inUse(false), srpc((SRPC *)NULL) { /*SKIP*/ } 00167 ~Entry() throw (); 00168 }; 00169 typedef Entry *EntryPtr; 00170 00171 // The "tbl" is capable of holding "num" Entry's. The current entries are 00172 // "tbl[0]".."tbl[next-1]". All entries "tbl[next]".."tbl[num-1]" are NULL. 00173 int next, num; 00174 EntryPtr *tbl; 00175 }; 00176 00177 #endif // _MULTI_SRPC_H