author | rriggs |
Fri, 07 Dec 2018 11:51:17 -0500 | |
changeset 52902 | e3398b2e1ab0 |
parent 47216 | 71c04702a3d5 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
14342
8435a30053c1
7197491: update copyright year to match last edit in jdk8 jdk repository
alanb
parents:
12040
diff
changeset
|
2 |
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
package sun.rmi.transport.tcp; |
|
26 |
||
27 |
import java.io.DataInput; |
|
28 |
import java.io.DataOutput; |
|
29 |
import java.io.IOException; |
|
30 |
import java.io.ObjectInput; |
|
31 |
import java.io.ObjectOutput; |
|
32 |
import java.net.InetAddress; |
|
33 |
import java.net.ServerSocket; |
|
34 |
import java.net.Socket; |
|
35 |
import java.rmi.ConnectIOException; |
|
36 |
import java.rmi.RemoteException; |
|
37 |
import java.rmi.server.RMIClientSocketFactory; |
|
38 |
import java.rmi.server.RMIServerSocketFactory; |
|
39 |
import java.rmi.server.RMISocketFactory; |
|
40 |
import java.security.AccessController; |
|
23333
b0af2c7c8c91
8035808: Eliminate dependency to GetPropertyAction and other sun.security.action convenient classes
mchung
parents:
14342
diff
changeset
|
41 |
import java.security.PrivilegedAction; |
2 | 42 |
import java.util.Collection; |
43 |
import java.util.HashMap; |
|
44 |
import java.util.HashSet; |
|
45 |
import java.util.LinkedList; |
|
46 |
import java.util.Map; |
|
47 |
import java.util.Set; |
|
48 |
import sun.rmi.runtime.Log; |
|
49 |
import sun.rmi.runtime.NewThreadAction; |
|
50 |
import sun.rmi.transport.Channel; |
|
51 |
import sun.rmi.transport.Endpoint; |
|
52 |
import sun.rmi.transport.Target; |
|
53 |
import sun.rmi.transport.Transport; |
|
54 |
||
55 |
/** |
|
56 |
* TCPEndpoint represents some communication endpoint for an address |
|
57 |
* space (VM). |
|
58 |
* |
|
59 |
* @author Ann Wollrath |
|
60 |
*/ |
|
61 |
public class TCPEndpoint implements Endpoint { |
|
62 |
/** IP address or host name */ |
|
63 |
private String host; |
|
64 |
/** port number */ |
|
65 |
private int port; |
|
66 |
/** custom client socket factory (null if not custom factory) */ |
|
67 |
private final RMIClientSocketFactory csf; |
|
68 |
/** custom server socket factory (null if not custom factory) */ |
|
69 |
private final RMIServerSocketFactory ssf; |
|
70 |
||
71 |
/** if local, the port number to listen on */ |
|
72 |
private int listenPort = -1; |
|
73 |
/** if local, the transport object associated with this endpoint */ |
|
74 |
private TCPTransport transport = null; |
|
75 |
||
76 |
/** the local host name */ |
|
77 |
private static String localHost; |
|
78 |
/** true if real local host name is known yet */ |
|
79 |
private static boolean localHostKnown; |
|
80 |
||
81 |
// this should be a *private* method since it is privileged |
|
82 |
private static int getInt(String name, int def) { |
|
23333
b0af2c7c8c91
8035808: Eliminate dependency to GetPropertyAction and other sun.security.action convenient classes
mchung
parents:
14342
diff
changeset
|
83 |
return AccessController.doPrivileged( |
b0af2c7c8c91
8035808: Eliminate dependency to GetPropertyAction and other sun.security.action convenient classes
mchung
parents:
14342
diff
changeset
|
84 |
(PrivilegedAction<Integer>) () -> Integer.getInteger(name, def)); |
2 | 85 |
} |
86 |
||
87 |
// this should be a *private* method since it is privileged |
|
88 |
private static boolean getBoolean(String name) { |
|
23333
b0af2c7c8c91
8035808: Eliminate dependency to GetPropertyAction and other sun.security.action convenient classes
mchung
parents:
14342
diff
changeset
|
89 |
return AccessController.doPrivileged( |
b0af2c7c8c91
8035808: Eliminate dependency to GetPropertyAction and other sun.security.action convenient classes
mchung
parents:
14342
diff
changeset
|
90 |
(PrivilegedAction<Boolean>) () -> Boolean.getBoolean(name)); |
2 | 91 |
} |
92 |
||
93 |
/** |
|
94 |
* Returns the value of the java.rmi.server.hostname property. |
|
95 |
*/ |
|
96 |
private static String getHostnameProperty() { |
|
97 |
return AccessController.doPrivileged( |
|
23333
b0af2c7c8c91
8035808: Eliminate dependency to GetPropertyAction and other sun.security.action convenient classes
mchung
parents:
14342
diff
changeset
|
98 |
(PrivilegedAction<String>) () -> System.getProperty("java.rmi.server.hostname")); |
2 | 99 |
} |
100 |
||
101 |
/** |
|
102 |
* Find host name of local machine. Property "java.rmi.server.hostname" |
|
103 |
* is used if set, so server administrator can compensate for the possible |
|
104 |
* inablility to get fully qualified host name from VM. |
|
105 |
*/ |
|
106 |
static { |
|
107 |
localHostKnown = true; |
|
108 |
localHost = getHostnameProperty(); |
|
109 |
||
110 |
// could try querying CGI program here? |
|
111 |
if (localHost == null) { |
|
112 |
try { |
|
113 |
InetAddress localAddr = InetAddress.getLocalHost(); |
|
114 |
byte[] raw = localAddr.getAddress(); |
|
115 |
if ((raw[0] == 127) && |
|
116 |
(raw[1] == 0) && |
|
117 |
(raw[2] == 0) && |
|
118 |
(raw[3] == 1)) { |
|
119 |
localHostKnown = false; |
|
120 |
} |
|
121 |
||
122 |
/* if the user wishes to use a fully qualified domain |
|
123 |
* name then attempt to find one. |
|
124 |
*/ |
|
125 |
if (getBoolean("java.rmi.server.useLocalHostName")) { |
|
126 |
localHost = FQDN.attemptFQDN(localAddr); |
|
127 |
} else { |
|
128 |
/* default to using ip addresses, names will |
|
129 |
* work across seperate domains. |
|
130 |
*/ |
|
131 |
localHost = localAddr.getHostAddress(); |
|
132 |
} |
|
133 |
} catch (Exception e) { |
|
134 |
localHostKnown = false; |
|
135 |
localHost = null; |
|
136 |
} |
|
137 |
} |
|
138 |
||
139 |
if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) { |
|
140 |
TCPTransport.tcpLog.log(Log.BRIEF, |
|
141 |
"localHostKnown = " + localHostKnown + |
|
142 |
", localHost = " + localHost); |
|
143 |
} |
|
144 |
} |
|
145 |
||
146 |
/** maps an endpoint key containing custom socket factories to |
|
147 |
* their own unique endpoint */ |
|
148 |
// TBD: should this be a weak hash table? |
|
149 |
private static final |
|
150 |
Map<TCPEndpoint,LinkedList<TCPEndpoint>> localEndpoints = |
|
12040
558b0e0d5910
7146763: Warnings cleanup in the sun.rmi and related packages
khazra
parents:
5506
diff
changeset
|
151 |
new HashMap<>(); |
2 | 152 |
|
153 |
/** |
|
154 |
* Create an endpoint for a specified host and port. |
|
155 |
* This should not be used by external classes to create endpoints |
|
156 |
* for servers in this VM; use getLocalEndpoint instead. |
|
157 |
*/ |
|
158 |
public TCPEndpoint(String host, int port) { |
|
159 |
this(host, port, null, null); |
|
160 |
} |
|
161 |
||
162 |
/** |
|
163 |
* Create a custom socket factory endpoint for a specified host and port. |
|
164 |
* This should not be used by external classes to create endpoints |
|
165 |
* for servers in this VM; use getLocalEndpoint instead. |
|
166 |
*/ |
|
167 |
public TCPEndpoint(String host, int port, RMIClientSocketFactory csf, |
|
168 |
RMIServerSocketFactory ssf) |
|
169 |
{ |
|
170 |
if (host == null) |
|
171 |
host = ""; |
|
172 |
this.host = host; |
|
173 |
this.port = port; |
|
174 |
this.csf = csf; |
|
175 |
this.ssf = ssf; |
|
176 |
} |
|
177 |
||
178 |
/** |
|
179 |
* Get an endpoint for the local address space on specified port. |
|
180 |
* If port number is 0, it returns shared default endpoint object |
|
181 |
* whose host name and port may or may not have been determined. |
|
182 |
*/ |
|
183 |
public static TCPEndpoint getLocalEndpoint(int port) { |
|
184 |
return getLocalEndpoint(port, null, null); |
|
185 |
} |
|
186 |
||
187 |
public static TCPEndpoint getLocalEndpoint(int port, |
|
188 |
RMIClientSocketFactory csf, |
|
189 |
RMIServerSocketFactory ssf) |
|
190 |
{ |
|
191 |
/* |
|
192 |
* Find mapping for an endpoint key to the list of local unique |
|
193 |
* endpoints for this client/server socket factory pair (perhaps |
|
194 |
* null) for the specific port. |
|
195 |
*/ |
|
196 |
TCPEndpoint ep = null; |
|
197 |
||
198 |
synchronized (localEndpoints) { |
|
199 |
TCPEndpoint endpointKey = new TCPEndpoint(null, port, csf, ssf); |
|
200 |
LinkedList<TCPEndpoint> epList = localEndpoints.get(endpointKey); |
|
201 |
String localHost = resampleLocalHost(); |
|
202 |
||
203 |
if (epList == null) { |
|
204 |
/* |
|
205 |
* Create new endpoint list. |
|
206 |
*/ |
|
207 |
ep = new TCPEndpoint(localHost, port, csf, ssf); |
|
208 |
epList = new LinkedList<TCPEndpoint>(); |
|
209 |
epList.add(ep); |
|
210 |
ep.listenPort = port; |
|
211 |
ep.transport = new TCPTransport(epList); |
|
212 |
localEndpoints.put(endpointKey, epList); |
|
213 |
||
214 |
if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) { |
|
215 |
TCPTransport.tcpLog.log(Log.BRIEF, |
|
216 |
"created local endpoint for socket factory " + ssf + |
|
217 |
" on port " + port); |
|
218 |
} |
|
219 |
} else { |
|
220 |
synchronized (epList) { |
|
221 |
ep = epList.getLast(); |
|
222 |
String lastHost = ep.host; |
|
223 |
int lastPort = ep.port; |
|
224 |
TCPTransport lastTransport = ep.transport; |
|
225 |
// assert (localHost == null ^ lastHost != null) |
|
226 |
if (localHost != null && !localHost.equals(lastHost)) { |
|
227 |
/* |
|
228 |
* Hostname has been updated; add updated endpoint |
|
229 |
* to list. |
|
230 |
*/ |
|
231 |
if (lastPort != 0) { |
|
232 |
/* |
|
233 |
* Remove outdated endpoints only if the |
|
234 |
* port has already been set on those endpoints. |
|
235 |
*/ |
|
236 |
epList.clear(); |
|
237 |
} |
|
238 |
ep = new TCPEndpoint(localHost, lastPort, csf, ssf); |
|
239 |
ep.listenPort = port; |
|
240 |
ep.transport = lastTransport; |
|
241 |
epList.add(ep); |
|
242 |
} |
|
243 |
} |
|
244 |
} |
|
245 |
} |
|
246 |
||
247 |
return ep; |
|
248 |
} |
|
249 |
||
250 |
/** |
|
251 |
* Resamples the local hostname and returns the possibly-updated |
|
252 |
* local hostname. |
|
253 |
*/ |
|
254 |
private static String resampleLocalHost() { |
|
255 |
||
256 |
String hostnameProperty = getHostnameProperty(); |
|
257 |
||
258 |
synchronized (localEndpoints) { |
|
259 |
// assert(localHostKnown ^ (localHost == null)) |
|
260 |
||
261 |
if (hostnameProperty != null) { |
|
262 |
if (!localHostKnown) { |
|
263 |
/* |
|
264 |
* If the local hostname is unknown, update ALL |
|
265 |
* existing endpoints with the new hostname. |
|
266 |
*/ |
|
267 |
setLocalHost(hostnameProperty); |
|
268 |
} else if (!hostnameProperty.equals(localHost)) { |
|
269 |
/* |
|
270 |
* Only update the localHost field for reference |
|
271 |
* in future endpoint creation. |
|
272 |
*/ |
|
273 |
localHost = hostnameProperty; |
|
274 |
||
275 |
if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) { |
|
276 |
TCPTransport.tcpLog.log(Log.BRIEF, |
|
277 |
"updated local hostname to: " + localHost); |
|
278 |
} |
|
279 |
} |
|
280 |
} |
|
281 |
return localHost; |
|
282 |
} |
|
283 |
} |
|
284 |
||
285 |
/** |
|
286 |
* Set the local host name, if currently unknown. |
|
287 |
*/ |
|
288 |
static void setLocalHost(String host) { |
|
289 |
// assert (host != null) |
|
290 |
||
291 |
synchronized (localEndpoints) { |
|
292 |
/* |
|
293 |
* If host is not known, change the host field of ALL |
|
294 |
* the local endpoints. |
|
295 |
*/ |
|
296 |
if (!localHostKnown) { |
|
297 |
localHost = host; |
|
298 |
localHostKnown = true; |
|
299 |
||
300 |
if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) { |
|
301 |
TCPTransport.tcpLog.log(Log.BRIEF, |
|
302 |
"local host set to " + host); |
|
303 |
} |
|
304 |
for (LinkedList<TCPEndpoint> epList : localEndpoints.values()) |
|
305 |
{ |
|
306 |
synchronized (epList) { |
|
307 |
for (TCPEndpoint ep : epList) { |
|
308 |
ep.host = host; |
|
309 |
} |
|
310 |
} |
|
311 |
} |
|
312 |
} |
|
313 |
} |
|
314 |
} |
|
315 |
||
316 |
/** |
|
317 |
* Set the port of the (shared) default endpoint object. |
|
318 |
* When first created, it contains port 0 because the transport |
|
319 |
* hasn't tried to listen to get assigned a port, or if listening |
|
320 |
* failed, a port hasn't been assigned from the server. |
|
321 |
*/ |
|
322 |
static void setDefaultPort(int port, RMIClientSocketFactory csf, |
|
323 |
RMIServerSocketFactory ssf) |
|
324 |
{ |
|
325 |
TCPEndpoint endpointKey = new TCPEndpoint(null, 0, csf, ssf); |
|
326 |
||
327 |
synchronized (localEndpoints) { |
|
328 |
LinkedList<TCPEndpoint> epList = localEndpoints.get(endpointKey); |
|
329 |
||
330 |
synchronized (epList) { |
|
331 |
int size = epList.size(); |
|
332 |
TCPEndpoint lastEp = epList.getLast(); |
|
333 |
||
334 |
for (TCPEndpoint ep : epList) { |
|
335 |
ep.port = port; |
|
336 |
} |
|
337 |
if (size > 1) { |
|
338 |
/* |
|
339 |
* Remove all but the last element of the list |
|
340 |
* (which contains the most recent hostname). |
|
341 |
*/ |
|
342 |
epList.clear(); |
|
343 |
epList.add(lastEp); |
|
344 |
} |
|
345 |
} |
|
346 |
||
347 |
/* |
|
348 |
* Allow future exports to use the actual bound port |
|
349 |
* explicitly (see 6269166). |
|
350 |
*/ |
|
351 |
TCPEndpoint newEndpointKey = new TCPEndpoint(null, port, csf, ssf); |
|
352 |
localEndpoints.put(newEndpointKey, epList); |
|
353 |
||
354 |
if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) { |
|
355 |
TCPTransport.tcpLog.log(Log.BRIEF, |
|
356 |
"default port for server socket factory " + ssf + |
|
357 |
" and client socket factory " + csf + |
|
358 |
" set to " + port); |
|
359 |
} |
|
360 |
} |
|
361 |
} |
|
362 |
||
363 |
/** |
|
364 |
* Returns transport for making connections to remote endpoints; |
|
365 |
* (here, the default transport at port 0 is used). |
|
366 |
*/ |
|
367 |
public Transport getOutboundTransport() { |
|
368 |
TCPEndpoint localEndpoint = getLocalEndpoint(0, null, null); |
|
369 |
return localEndpoint.transport; |
|
370 |
} |
|
371 |
||
372 |
/** |
|
373 |
* Returns the current list of known transports. |
|
374 |
* The returned list is an unshared collection of Transports, |
|
375 |
* including all transports which may have channels to remote |
|
376 |
* endpoints. |
|
377 |
*/ |
|
378 |
private static Collection<TCPTransport> allKnownTransports() { |
|
379 |
// Loop through local endpoints, getting the transport of each one. |
|
380 |
Set<TCPTransport> s; |
|
381 |
synchronized (localEndpoints) { |
|
382 |
// presize s to number of localEndpoints |
|
383 |
s = new HashSet<TCPTransport>(localEndpoints.size()); |
|
384 |
for (LinkedList<TCPEndpoint> epList : localEndpoints.values()) { |
|
385 |
/* |
|
386 |
* Each local endpoint has its transport added to s. |
|
387 |
* Note: the transport is the same for all endpoints |
|
388 |
* in the list, so it is okay to pick any one of them. |
|
389 |
*/ |
|
390 |
TCPEndpoint ep = epList.getFirst(); |
|
391 |
s.add(ep.transport); |
|
392 |
} |
|
393 |
} |
|
394 |
return s; |
|
395 |
} |
|
396 |
||
397 |
/** |
|
398 |
* Release idle outbound connections to reduce demand on I/O resources. |
|
399 |
* All transports are asked to release excess connections. |
|
400 |
*/ |
|
401 |
public static void shedConnectionCaches() { |
|
402 |
for (TCPTransport transport : allKnownTransports()) { |
|
403 |
transport.shedConnectionCaches(); |
|
404 |
} |
|
405 |
} |
|
406 |
||
407 |
/** |
|
408 |
* Export the object to accept incoming calls. |
|
409 |
*/ |
|
410 |
public void exportObject(Target target) throws RemoteException { |
|
411 |
transport.exportObject(target); |
|
412 |
} |
|
413 |
||
414 |
/** |
|
415 |
* Returns a channel for this (remote) endpoint. |
|
416 |
*/ |
|
417 |
public Channel getChannel() { |
|
418 |
return getOutboundTransport().getChannel(this); |
|
419 |
} |
|
420 |
||
421 |
/** |
|
422 |
* Returns address for endpoint |
|
423 |
*/ |
|
424 |
public String getHost() { |
|
425 |
return host; |
|
426 |
} |
|
427 |
||
428 |
/** |
|
429 |
* Returns the port for this endpoint. If this endpoint was |
|
430 |
* created as a server endpoint (using getLocalEndpoint) for a |
|
431 |
* default/anonymous port and its inbound transport has started |
|
432 |
* listening, this method returns (instead of zero) the actual |
|
433 |
* bound port suitable for passing to clients. |
|
434 |
**/ |
|
435 |
public int getPort() { |
|
436 |
return port; |
|
437 |
} |
|
438 |
||
439 |
/** |
|
440 |
* Returns the port that this endpoint's inbound transport listens |
|
441 |
* on, if this endpoint was created as a server endpoint (using |
|
442 |
* getLocalEndpoint). If this endpoint was created for the |
|
443 |
* default/anonymous port, then this method returns zero even if |
|
444 |
* the transport has started listening. |
|
445 |
**/ |
|
446 |
public int getListenPort() { |
|
447 |
return listenPort; |
|
448 |
} |
|
449 |
||
450 |
/** |
|
451 |
* Returns the transport for incoming connections to this |
|
452 |
* endpoint, if this endpoint was created as a server endpoint |
|
453 |
* (using getLocalEndpoint). |
|
454 |
**/ |
|
455 |
public Transport getInboundTransport() { |
|
456 |
return transport; |
|
457 |
} |
|
458 |
||
459 |
/** |
|
460 |
* Get the client socket factory associated with this endpoint. |
|
461 |
*/ |
|
462 |
public RMIClientSocketFactory getClientSocketFactory() { |
|
463 |
return csf; |
|
464 |
} |
|
465 |
||
466 |
/** |
|
467 |
* Get the server socket factory associated with this endpoint. |
|
468 |
*/ |
|
469 |
public RMIServerSocketFactory getServerSocketFactory() { |
|
470 |
return ssf; |
|
471 |
} |
|
472 |
||
473 |
/** |
|
474 |
* Return string representation for endpoint. |
|
475 |
*/ |
|
476 |
public String toString() { |
|
477 |
return "[" + host + ":" + port + |
|
478 |
(ssf != null ? "," + ssf : "") + |
|
479 |
(csf != null ? "," + csf : "") + |
|
480 |
"]"; |
|
481 |
} |
|
482 |
||
483 |
public int hashCode() { |
|
484 |
return port; |
|
485 |
} |
|
486 |
||
487 |
public boolean equals(Object obj) { |
|
488 |
if ((obj != null) && (obj instanceof TCPEndpoint)) { |
|
489 |
TCPEndpoint ep = (TCPEndpoint) obj; |
|
490 |
if (port != ep.port || !host.equals(ep.host)) |
|
491 |
return false; |
|
492 |
if (((csf == null) ^ (ep.csf == null)) || |
|
493 |
((ssf == null) ^ (ep.ssf == null))) |
|
494 |
return false; |
|
495 |
/* |
|
496 |
* Fix for 4254510: perform socket factory *class* equality check |
|
497 |
* before socket factory equality check to avoid passing |
|
498 |
* a potentially naughty socket factory to this endpoint's |
|
499 |
* {client,server} socket factory equals method. |
|
500 |
*/ |
|
501 |
if ((csf != null) && |
|
502 |
!(csf.getClass() == ep.csf.getClass() && csf.equals(ep.csf))) |
|
503 |
return false; |
|
504 |
if ((ssf != null) && |
|
505 |
!(ssf.getClass() == ep.ssf.getClass() && ssf.equals(ep.ssf))) |
|
506 |
return false; |
|
507 |
return true; |
|
508 |
} else { |
|
509 |
return false; |
|
510 |
} |
|
511 |
} |
|
512 |
||
513 |
/* codes for the self-describing formats of wire representation */ |
|
514 |
private static final int FORMAT_HOST_PORT = 0; |
|
515 |
private static final int FORMAT_HOST_PORT_FACTORY = 1; |
|
516 |
||
517 |
/** |
|
518 |
* Write endpoint to output stream. |
|
519 |
*/ |
|
520 |
public void write(ObjectOutput out) throws IOException { |
|
521 |
if (csf == null) { |
|
522 |
out.writeByte(FORMAT_HOST_PORT); |
|
523 |
out.writeUTF(host); |
|
524 |
out.writeInt(port); |
|
525 |
} else { |
|
526 |
out.writeByte(FORMAT_HOST_PORT_FACTORY); |
|
527 |
out.writeUTF(host); |
|
528 |
out.writeInt(port); |
|
529 |
out.writeObject(csf); |
|
530 |
} |
|
531 |
} |
|
532 |
||
533 |
/** |
|
534 |
* Get the endpoint from the input stream. |
|
535 |
* @param in the input stream |
|
536 |
* @exception IOException If id could not be read (due to stream failure) |
|
537 |
*/ |
|
538 |
public static TCPEndpoint read(ObjectInput in) |
|
539 |
throws IOException, ClassNotFoundException |
|
540 |
{ |
|
541 |
String host; |
|
542 |
int port; |
|
543 |
RMIClientSocketFactory csf = null; |
|
544 |
||
545 |
byte format = in.readByte(); |
|
546 |
switch (format) { |
|
547 |
case FORMAT_HOST_PORT: |
|
548 |
host = in.readUTF(); |
|
549 |
port = in.readInt(); |
|
550 |
break; |
|
551 |
||
552 |
case FORMAT_HOST_PORT_FACTORY: |
|
553 |
host = in.readUTF(); |
|
554 |
port = in.readInt(); |
|
555 |
csf = (RMIClientSocketFactory) in.readObject(); |
|
556 |
break; |
|
557 |
||
558 |
default: |
|
559 |
throw new IOException("invalid endpoint format"); |
|
560 |
} |
|
561 |
return new TCPEndpoint(host, port, csf, null); |
|
562 |
} |
|
563 |
||
564 |
/** |
|
565 |
* Write endpoint to output stream in older format used by |
|
566 |
* UnicastRef for JDK1.1 compatibility. |
|
567 |
*/ |
|
568 |
public void writeHostPortFormat(DataOutput out) throws IOException { |
|
569 |
if (csf != null) { |
|
570 |
throw new InternalError("TCPEndpoint.writeHostPortFormat: " + |
|
571 |
"called for endpoint with non-null socket factory"); |
|
572 |
} |
|
573 |
out.writeUTF(host); |
|
574 |
out.writeInt(port); |
|
575 |
} |
|
576 |
||
577 |
/** |
|
578 |
* Create a new endpoint from input stream data. |
|
579 |
* @param in the input stream |
|
580 |
*/ |
|
581 |
public static TCPEndpoint readHostPortFormat(DataInput in) |
|
582 |
throws IOException |
|
583 |
{ |
|
584 |
String host = in.readUTF(); |
|
585 |
int port = in.readInt(); |
|
586 |
return new TCPEndpoint(host, port); |
|
587 |
} |
|
588 |
||
589 |
private static RMISocketFactory chooseFactory() { |
|
590 |
RMISocketFactory sf = RMISocketFactory.getSocketFactory(); |
|
591 |
if (sf == null) { |
|
592 |
sf = TCPTransport.defaultSocketFactory; |
|
593 |
} |
|
594 |
return sf; |
|
595 |
} |
|
596 |
||
597 |
/** |
|
598 |
* Open and return new client socket connection to endpoint. |
|
599 |
*/ |
|
600 |
Socket newSocket() throws RemoteException { |
|
601 |
if (TCPTransport.tcpLog.isLoggable(Log.VERBOSE)) { |
|
602 |
TCPTransport.tcpLog.log(Log.VERBOSE, |
|
603 |
"opening socket to " + this); |
|
604 |
} |
|
605 |
||
606 |
Socket socket; |
|
607 |
||
608 |
try { |
|
609 |
RMIClientSocketFactory clientFactory = csf; |
|
610 |
if (clientFactory == null) { |
|
611 |
clientFactory = chooseFactory(); |
|
612 |
} |
|
613 |
socket = clientFactory.createSocket(host, port); |
|
614 |
||
615 |
} catch (java.net.UnknownHostException e) { |
|
616 |
throw new java.rmi.UnknownHostException( |
|
617 |
"Unknown host: " + host, e); |
|
618 |
} catch (java.net.ConnectException e) { |
|
619 |
throw new java.rmi.ConnectException( |
|
620 |
"Connection refused to host: " + host, e); |
|
621 |
} catch (IOException e) { |
|
622 |
// We might have simply run out of file descriptors |
|
623 |
try { |
|
624 |
TCPEndpoint.shedConnectionCaches(); |
|
625 |
// REMIND: should we retry createSocket? |
|
12040
558b0e0d5910
7146763: Warnings cleanup in the sun.rmi and related packages
khazra
parents:
5506
diff
changeset
|
626 |
} catch (OutOfMemoryError | Exception mem) { |
2 | 627 |
// don't quit if out of memory |
12040
558b0e0d5910
7146763: Warnings cleanup in the sun.rmi and related packages
khazra
parents:
5506
diff
changeset
|
628 |
// or shed fails non-catastrophically |
2 | 629 |
} |
630 |
||
631 |
throw new ConnectIOException("Exception creating connection to: " + |
|
632 |
host, e); |
|
633 |
} |
|
634 |
||
635 |
// set socket to disable Nagle's algorithm (always send immediately) |
|
636 |
// TBD: should this be left up to socket factory instead? |
|
637 |
try { |
|
638 |
socket.setTcpNoDelay(true); |
|
639 |
} catch (Exception e) { |
|
640 |
// if we fail to set this, ignore and proceed anyway |
|
641 |
} |
|
642 |
||
643 |
// fix 4187495: explicitly set SO_KEEPALIVE to prevent client hangs |
|
644 |
try { |
|
645 |
socket.setKeepAlive(true); |
|
646 |
} catch (Exception e) { |
|
647 |
// ignore and proceed |
|
648 |
} |
|
649 |
||
650 |
return socket; |
|
651 |
} |
|
652 |
||
653 |
/** |
|
654 |
* Return new server socket to listen for connections on this endpoint. |
|
655 |
*/ |
|
656 |
ServerSocket newServerSocket() throws IOException { |
|
657 |
if (TCPTransport.tcpLog.isLoggable(Log.VERBOSE)) { |
|
658 |
TCPTransport.tcpLog.log(Log.VERBOSE, |
|
659 |
"creating server socket on " + this); |
|
660 |
} |
|
661 |
||
662 |
RMIServerSocketFactory serverFactory = ssf; |
|
663 |
if (serverFactory == null) { |
|
664 |
serverFactory = chooseFactory(); |
|
665 |
} |
|
666 |
ServerSocket server = serverFactory.createServerSocket(listenPort); |
|
667 |
||
668 |
// if we listened on an anonymous port, set the default port |
|
669 |
// (for this socket factory) |
|
670 |
if (listenPort == 0) |
|
671 |
setDefaultPort(server.getLocalPort(), csf, ssf); |
|
672 |
||
673 |
return server; |
|
674 |
} |
|
675 |
||
676 |
/** |
|
677 |
* The class FQDN encapsulates a routine that makes a best effort |
|
678 |
* attempt to retrieve the fully qualified domain name of the local |
|
679 |
* host. |
|
680 |
* |
|
681 |
* @author Laird Dornin |
|
682 |
*/ |
|
683 |
private static class FQDN implements Runnable { |
|
684 |
||
685 |
/** |
|
686 |
* strings in which we can store discovered fqdn |
|
687 |
*/ |
|
688 |
private String reverseLookup; |
|
689 |
||
690 |
private String hostAddress; |
|
691 |
||
692 |
private FQDN(String hostAddress) { |
|
693 |
this.hostAddress = hostAddress; |
|
694 |
} |
|
695 |
||
696 |
/** |
|
697 |
* Do our best to obtain a fully qualified hostname for the local |
|
698 |
* host. Perform the following steps to get a localhostname: |
|
699 |
* |
|
700 |
* 1. InetAddress.getLocalHost().getHostName() - if contains |
|
701 |
* '.' use as FQDN |
|
702 |
* 2. if no '.' query name service for FQDN in a thread |
|
703 |
* Note: We query the name service for an FQDN by creating |
|
704 |
* an InetAddress via a stringified copy of the local ip |
|
705 |
* address; this creates an InetAddress with a null hostname. |
|
706 |
* Asking for the hostname of this InetAddress causes a name |
|
707 |
* service lookup. |
|
708 |
* |
|
709 |
* 3. if name service takes too long to return, use ip address |
|
710 |
* 4. if name service returns but response contains no '.' |
|
711 |
* default to ipaddress. |
|
712 |
*/ |
|
713 |
static String attemptFQDN(InetAddress localAddr) |
|
714 |
throws java.net.UnknownHostException |
|
715 |
{ |
|
716 |
||
717 |
String hostName = localAddr.getHostName(); |
|
718 |
||
719 |
if (hostName.indexOf('.') < 0 ) { |
|
720 |
||
721 |
String hostAddress = localAddr.getHostAddress(); |
|
722 |
FQDN f = new FQDN(hostAddress); |
|
723 |
||
724 |
int nameServiceTimeOut = |
|
725 |
TCPEndpoint.getInt("sun.rmi.transport.tcp.localHostNameTimeOut", |
|
726 |
10000); |
|
727 |
||
728 |
try { |
|
729 |
synchronized(f) { |
|
730 |
f.getFQDN(); |
|
731 |
||
732 |
/* wait to obtain an FQDN */ |
|
733 |
f.wait(nameServiceTimeOut); |
|
734 |
} |
|
735 |
} catch (InterruptedException e) { |
|
736 |
/* propagate the exception to the caller */ |
|
737 |
Thread.currentThread().interrupt(); |
|
738 |
} |
|
739 |
hostName = f.getHost(); |
|
740 |
||
52902
e3398b2e1ab0
8214971: Replace use of string.equals("") with isEmpty()
rriggs
parents:
47216
diff
changeset
|
741 |
if ((hostName == null) || (hostName.isEmpty()) |
2 | 742 |
|| (hostName.indexOf('.') < 0 )) { |
743 |
||
744 |
hostName = hostAddress; |
|
745 |
} |
|
746 |
} |
|
747 |
return hostName; |
|
748 |
} |
|
749 |
||
750 |
/** |
|
751 |
* Method that that will start a thread to wait to retrieve a |
|
752 |
* fully qualified domain name from a name service. The spawned |
|
753 |
* thread may never return but we have marked it as a daemon so the vm |
|
754 |
* will terminate appropriately. |
|
755 |
*/ |
|
756 |
private void getFQDN() { |
|
757 |
||
758 |
/* FQDN finder will run in RMI threadgroup. */ |
|
759 |
Thread t = AccessController.doPrivileged( |
|
760 |
new NewThreadAction(FQDN.this, "FQDN Finder", true)); |
|
761 |
t.start(); |
|
762 |
} |
|
763 |
||
764 |
private synchronized String getHost() { |
|
765 |
return reverseLookup; |
|
766 |
} |
|
767 |
||
768 |
/** |
|
769 |
* thread to query a name service for the fqdn of this host. |
|
770 |
*/ |
|
771 |
public void run() { |
|
772 |
||
773 |
String name = null; |
|
774 |
||
775 |
try { |
|
776 |
name = InetAddress.getByName(hostAddress).getHostName(); |
|
777 |
} catch (java.net.UnknownHostException e) { |
|
778 |
} finally { |
|
779 |
synchronized(this) { |
|
780 |
reverseLookup = name; |
|
781 |
this.notify(); |
|
782 |
} |
|
783 |
} |
|
784 |
} |
|
785 |
} |
|
786 |
} |