1 |
/* |
/* |
2 |
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. |
Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
41 |
import java.rmi.server.RMIServerSocketFactory; |
import java.rmi.server.RMIServerSocketFactory; |
42 |
import java.rmi.server.RMIClientSocketFactory; |
import java.rmi.server.RMIClientSocketFactory; |
43 |
import java.rmi.RemoteException; |
import java.rmi.RemoteException; |
|
import gnu.java.rmi.server.UnicastConnection; |
|
|
import java.util.Hashtable; |
|
|
import java.net.Socket; |
|
|
import java.net.ServerSocket; |
|
44 |
import java.io.IOException; |
import java.io.IOException; |
45 |
import java.io.ObjectOutput; |
import java.io.ObjectOutput; |
46 |
import java.io.ObjectInput; |
import java.io.ObjectInput; |
47 |
|
import java.io.DataInputStream; |
48 |
import java.lang.Thread; |
import java.lang.Thread; |
49 |
import java.lang.Runnable; |
import java.lang.Runnable; |
50 |
import java.net.InetAddress; |
import java.net.InetAddress; |
51 |
|
import java.net.Socket; |
52 |
|
import java.net.ServerSocket; |
53 |
import java.net.UnknownHostException; |
import java.net.UnknownHostException; |
54 |
|
|
55 |
|
import java.util.ArrayList; |
56 |
|
import java.util.ConcurrentModificationException; |
57 |
|
import java.util.Enumeration; |
58 |
|
import java.util.Hashtable; |
59 |
|
import java.util.Iterator; |
60 |
|
|
61 |
|
import gnu.java.rmi.server.UnicastConnection; |
62 |
|
|
63 |
public class UnicastConnectionManager |
public class UnicastConnectionManager |
64 |
implements Runnable, ProtocolConstants { |
implements Runnable, ProtocolConstants { |
65 |
|
|
67 |
// use different maps for server/client type UnicastConnectionManager |
// use different maps for server/client type UnicastConnectionManager |
68 |
private static Hashtable servers = new Hashtable(); |
private static Hashtable servers = new Hashtable(); |
69 |
private static Hashtable clients = new Hashtable(); |
private static Hashtable clients = new Hashtable(); |
70 |
|
private ArrayList connections; //client connection pool |
71 |
|
|
72 |
// make serverThread volatile for poll |
// make serverThread volatile for poll |
73 |
private volatile Thread serverThread; |
private volatile Thread serverThread; |
74 |
private ServerSocket ssock; |
private ServerSocket ssock; |
75 |
String serverName; |
String serverName; |
76 |
int serverPort; |
int serverPort; |
77 |
|
|
78 |
|
static private Thread scavenger; |
79 |
|
|
80 |
|
// If client and server are in the same VM, serverobj represents server |
81 |
|
Object serverobj; |
82 |
|
|
83 |
|
private static RMISocketFactory defaultSocketFactory = RMISocketFactory.getSocketFactory(); |
84 |
private RMIServerSocketFactory serverFactory; |
private RMIServerSocketFactory serverFactory; |
85 |
private RMIClientSocketFactory clientFactory; |
private RMIClientSocketFactory clientFactory; |
86 |
|
|
87 |
|
// The following is for debug |
88 |
|
private static int ncsock = 0; //count of client socket |
89 |
|
private static int nssock = 0; //count of server socket |
90 |
|
private static int ncmanager = 0; //count of client manager |
91 |
|
private static int nsmanager = 0; //count of server manager |
92 |
|
|
93 |
|
private static final boolean debug = false; |
94 |
|
|
95 |
|
private static final Object GLOBAL_LOCK = new Object(); |
96 |
|
|
97 |
static { |
static { |
98 |
try { |
try { |
99 |
//Use host address instead of host name to avoid name resolving issues |
//Use host address instead of host name to avoid name resolving issues |
103 |
catch (UnknownHostException _) { |
catch (UnknownHostException _) { |
104 |
localhost = "localhost"; |
localhost = "localhost"; |
105 |
} |
} |
106 |
|
|
107 |
|
|
108 |
|
} |
109 |
|
|
110 |
|
//Only one scavenger thread running globally |
111 |
|
private static void startScavenger(){ |
112 |
|
scavenger = new Thread(new Runnable(){ |
113 |
|
public void run(){ |
114 |
|
if (debug) System.out.println("************* start scavenger."); |
115 |
|
boolean liveon = true; |
116 |
|
while (liveon){ |
117 |
|
// Sleep for the expire timeout |
118 |
|
try{ |
119 |
|
Thread.sleep(UnicastConnection.CONNECTION_TIMEOUT); |
120 |
|
}catch(InterruptedException _ie){ |
121 |
|
break; |
122 |
|
} |
123 |
|
liveon = false; |
124 |
|
// Scavenge all clients' connections that're expired |
125 |
|
Iterator iter = clients.values().iterator(); |
126 |
|
long l = System.currentTimeMillis(); |
127 |
|
try{ |
128 |
|
while(iter.hasNext()){ |
129 |
|
UnicastConnectionManager man = (UnicastConnectionManager)iter.next(); |
130 |
|
ArrayList conns = man.connections; |
131 |
|
synchronized(conns) { // is the lock a little coarser? |
132 |
|
for (int last = conns.size() - 1; |
133 |
|
last >= 0; |
134 |
|
--last) |
135 |
|
{ |
136 |
|
UnicastConnection conn = (UnicastConnection)conns.get(last); |
137 |
|
if (UnicastConnection.isExpired(conn, l)){ |
138 |
|
conns.remove(last); |
139 |
|
conn.disconnect(); |
140 |
|
conn = null; |
141 |
|
}else |
142 |
|
liveon = true; //there're still live connections |
143 |
|
} |
144 |
|
} |
145 |
|
} |
146 |
|
}catch(ConcurrentModificationException cme) { |
147 |
|
// handle it lazily |
148 |
|
liveon = true; |
149 |
|
} |
150 |
|
} |
151 |
|
scavenger = null; |
152 |
|
if (debug) System.out.println("************* exit scavenger."); |
153 |
|
} |
154 |
|
}); |
155 |
|
scavenger.start(); |
156 |
} |
} |
157 |
|
|
158 |
|
/** |
159 |
|
* Client UnicastConnectionManager constructor |
160 |
|
*/ |
161 |
private UnicastConnectionManager(String host, int port, RMIClientSocketFactory csf) { |
private UnicastConnectionManager(String host, int port, RMIClientSocketFactory csf) { |
162 |
ssock = null; |
ssock = null; |
163 |
serverName = host; |
serverName = host; |
164 |
serverPort = port; |
serverPort = port; |
165 |
serverFactory = null; |
serverFactory = null; |
166 |
clientFactory = csf; |
clientFactory = csf; |
167 |
|
connections = new ArrayList(); |
168 |
} |
} |
169 |
|
|
170 |
|
/** |
171 |
|
* Server UnicastConnectionManager constructor |
172 |
|
*/ |
173 |
private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) { |
private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) { |
174 |
try { |
try { |
175 |
ssock = ssf.createServerSocket(port); |
ssock = ssf.createServerSocket(port); |
197 |
public static synchronized UnicastConnectionManager getInstance(String host, int port, RMIClientSocketFactory csf) { |
public static synchronized UnicastConnectionManager getInstance(String host, int port, RMIClientSocketFactory csf) { |
198 |
//System.out.println("getInstance: " + host + "," + port + "," + csf); |
//System.out.println("getInstance: " + host + "," + port + "," + csf); |
199 |
if (csf == null) { |
if (csf == null) { |
200 |
csf = RMISocketFactory.getSocketFactory(); |
csf = defaultSocketFactory; |
201 |
} |
} |
202 |
// change host name to host address to avoid name resolving issues |
// change host name to host address to avoid name resolving issues |
203 |
try{ |
try{ |
208 |
UnicastConnectionManager man = (UnicastConnectionManager)clients.get(key); |
UnicastConnectionManager man = (UnicastConnectionManager)clients.get(key); |
209 |
if (man == null) { |
if (man == null) { |
210 |
man = new UnicastConnectionManager(host, port, csf); |
man = new UnicastConnectionManager(host, port, csf); |
211 |
|
if (debug) { |
212 |
|
ncmanager++; |
213 |
|
System.out.println("\n\n ====== " + ncmanager + " client managers.\n\n"); |
214 |
|
} |
215 |
clients.put(key, man); |
clients.put(key, man); |
216 |
|
|
217 |
|
// Detect if client and server are in the same VM, i.e., their keys are equal |
218 |
|
UnicastConnectionManager svrman = (UnicastConnectionManager)servers.get(key); |
219 |
|
if(svrman != null){ // server and client are in the same VM |
220 |
|
man.serverobj = svrman.serverobj; |
221 |
|
} |
222 |
} |
} |
223 |
return (man); |
return (man); |
224 |
} |
} |
230 |
public static synchronized UnicastConnectionManager getInstance(int port, RMIServerSocketFactory ssf) { |
public static synchronized UnicastConnectionManager getInstance(int port, RMIServerSocketFactory ssf) { |
231 |
//System.out.println("getInstance: " + port + "," + ssf); |
//System.out.println("getInstance: " + port + "," + ssf); |
232 |
if (ssf == null) { |
if (ssf == null) { |
233 |
ssf = RMISocketFactory.getSocketFactory(); |
ssf = defaultSocketFactory; |
234 |
} |
} |
235 |
TripleKey key = new TripleKey(localhost, port, ssf); |
TripleKey key = new TripleKey(localhost, port, ssf); |
236 |
UnicastConnectionManager man = (UnicastConnectionManager)servers.get(key); |
UnicastConnectionManager man = (UnicastConnectionManager)servers.get(key); |
237 |
if (man == null) { |
if (man == null) { |
238 |
man = new UnicastConnectionManager(port, ssf); |
man = new UnicastConnectionManager(port, ssf); |
239 |
|
if (debug) { |
240 |
|
nsmanager++; |
241 |
|
System.out.println("\n\n ****** " + nsmanager + " server managers.\n\n"); |
242 |
|
} |
243 |
// The provided port might not be the set port. |
// The provided port might not be the set port. |
244 |
key.port = man.serverPort; |
key.port = man.serverPort; |
245 |
servers.put(key, man); |
servers.put(key, man); |
264 |
*/ |
*/ |
265 |
private UnicastConnection getServerConnection() throws IOException { |
private UnicastConnection getServerConnection() throws IOException { |
266 |
Socket sock = ssock.accept(); |
Socket sock = ssock.accept(); |
267 |
|
sock.setTcpNoDelay(true); //?? |
268 |
UnicastConnection conn = new UnicastConnection(this, sock); |
UnicastConnection conn = new UnicastConnection(this, sock); |
269 |
conn.acceptConnection(); |
conn.acceptConnection(); |
270 |
//System.out.println("Server connection " + conn); |
if (debug){ |
271 |
|
nssock++; |
272 |
|
System.out.println("\n\n ****** " + nssock + " server socks.\n\n"); |
273 |
|
} |
274 |
|
//System.out.println("Server connection " + sock); |
275 |
return (conn); |
return (conn); |
276 |
} |
} |
277 |
|
|
279 |
* Make a conection from this client to the server. |
* Make a conection from this client to the server. |
280 |
*/ |
*/ |
281 |
private UnicastConnection getClientConnection() throws IOException { |
private UnicastConnection getClientConnection() throws IOException { |
282 |
|
ArrayList conns = connections; |
283 |
|
UnicastConnection conn; |
284 |
|
|
285 |
|
synchronized(conns) { |
286 |
|
int nconn = conns.size() - 1; |
287 |
|
|
288 |
|
// if there're free connections in connection pool |
289 |
|
if(nconn >= 0) { |
290 |
|
conn = (UnicastConnection)conns.get(nconn); |
291 |
|
//Should we check if conn is alive using Ping?? |
292 |
|
conns.remove(nconn); |
293 |
|
|
294 |
|
// Check if the connection is already expired |
295 |
|
long l = System.currentTimeMillis(); |
296 |
|
if (!UnicastConnection.isExpired(conn, l)){ |
297 |
|
return conn; |
298 |
|
}else { |
299 |
|
conn.disconnect(); |
300 |
|
conn = null; |
301 |
|
} |
302 |
|
} |
303 |
|
} |
304 |
|
|
305 |
Socket sock = clientFactory.createSocket(serverName, serverPort); |
Socket sock = clientFactory.createSocket(serverName, serverPort); |
306 |
UnicastConnection conn = new UnicastConnection(this, sock); |
conn = new UnicastConnection(this, sock); |
307 |
conn.makeConnection(DEFAULT_PROTOCOL); |
conn.makeConnection(DEFAULT_PROTOCOL); |
308 |
//System.out.println("Client connection " + conn); |
|
309 |
|
if (debug) { |
310 |
|
ncsock++; |
311 |
|
System.out.println("\n\n ====== " + ncsock + " client socks.\n\n"); |
312 |
|
} |
313 |
|
|
314 |
return (conn); |
return (conn); |
315 |
} |
} |
316 |
|
|
320 |
*/ |
*/ |
321 |
public void discardConnection(UnicastConnection conn) { |
public void discardConnection(UnicastConnection conn) { |
322 |
//System.out.println("Discarding connection " + conn); |
//System.out.println("Discarding connection " + conn); |
323 |
|
//conn.disconnect(); |
324 |
|
if (ssock != null) //server connection |
325 |
conn.disconnect(); |
conn.disconnect(); |
326 |
|
else { |
327 |
|
// To client connection, we'd like to return back to pool |
328 |
|
UnicastConnection.resetTime(conn); |
329 |
|
//Ensure there're only one scavenger globally |
330 |
|
synchronized(GLOBAL_LOCK) { |
331 |
|
connections.add(conn); //borrow this lock to garantee thread safety |
332 |
|
if (scavenger == null) |
333 |
|
startScavenger(); |
334 |
|
} |
335 |
|
} |
336 |
} |
} |
337 |
|
|
338 |
/** |
/** |
345 |
return; |
return; |
346 |
} |
} |
347 |
serverThread = new Thread(this); |
serverThread = new Thread(this); |
348 |
|
// The following is not necessary when java.lang.Thread's constructor do this. |
349 |
|
// serverThread.setContextClassLoader(Thread.currentThread().getContextClassLoader()); |
350 |
} |
} |
351 |
serverThread.start(); |
serverThread.start(); |
352 |
} |
} |
374 |
//System.out.println("Waiting for connection on " + serverPort); |
//System.out.println("Waiting for connection on " + serverPort); |
375 |
UnicastConnection conn = getServerConnection(); |
UnicastConnection conn = getServerConnection(); |
376 |
// use a thread pool to improve performance |
// use a thread pool to improve performance |
377 |
// (new Thread(conn)).start(); |
//ConnectionRunnerPool.dispatchConnection(conn); |
378 |
ConnectionRunnerPool.dispatchConnection(conn); |
(new Thread(conn)).start(); |
379 |
} |
} |
380 |
catch (Exception e) { |
catch (Exception e) { |
381 |
// e.printStackTrace(); |
e.printStackTrace(); |
382 |
} |
} |
383 |
} |
} |
384 |
} |
} |
397 |
static UnicastConnectionManager read(ObjectInput in) throws IOException { |
static UnicastConnectionManager read(ObjectInput in) throws IOException { |
398 |
String host = in.readUTF(); |
String host = in.readUTF(); |
399 |
int port = in.readInt(); |
int port = in.readInt(); |
400 |
RMIClientSocketFactory csf = ((RMIObjectInputStream)in).manager.clientFactory; |
//RMIClientSocketFactory csf = ((RMIObjectInputStream)in).manager.clientFactory; |
401 |
return (getInstance(host, port, csf)); |
//return (getInstance(host, port, csf)); |
402 |
|
return (getInstance(host, port, null)); |
403 |
} |
} |
404 |
|
|
405 |
} |
} |
432 |
TripleKey other = (TripleKey)obj; |
TripleKey other = (TripleKey)obj; |
433 |
if (this.host.equals(other.host) && |
if (this.host.equals(other.host) && |
434 |
this.other == other.other && |
this.other == other.other && |
435 |
(this.port == other.port || this.port == 0 || other.port == 0)) { |
(this.port == other.port /* || this.port == 0 || other.port == 0*/)) { |
436 |
return (true); |
return (true); |
437 |
} |
} |
438 |
} |
} |