PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/h2/src/main/org/h2/util/NetUtils.java

http://h2database.googlecode.com/
Java | 281 lines | 177 code | 16 blank | 88 comment | 32 complexity | cc8067a2da8e40fb5deed05225284987 MD5 | raw file
  1. /*
  2. * Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License,
  3. * Version 1.0, and under the Eclipse Public License, Version 1.0
  4. * (http://h2database.com/html/license.html).
  5. * Initial Developer: H2 Group
  6. */
  7. package org.h2.util;
  8. import java.io.IOException;
  9. import java.net.BindException;
  10. import java.net.Inet6Address;
  11. import java.net.InetAddress;
  12. import java.net.InetSocketAddress;
  13. import java.net.ServerSocket;
  14. import java.net.Socket;
  15. import java.net.UnknownHostException;
  16. import org.h2.api.ErrorCode;
  17. import org.h2.engine.SysProperties;
  18. import org.h2.message.DbException;
  19. import org.h2.security.CipherFactory;
  20. /**
  21. * This utility class contains socket helper functions.
  22. */
  23. public class NetUtils {
  24. private static final int CACHE_MILLIS = 1000;
  25. private static InetAddress cachedBindAddress;
  26. private static String cachedLocalAddress;
  27. private static long cachedLocalAddressTime;
  28. private NetUtils() {
  29. // utility class
  30. }
  31. /**
  32. * Create a loopback socket (a socket that is connected to localhost) on
  33. * this port.
  34. *
  35. * @param port the port
  36. * @param ssl if SSL should be used
  37. * @return the socket
  38. */
  39. public static Socket createLoopbackSocket(int port, boolean ssl)
  40. throws IOException {
  41. InetAddress address = getBindAddress();
  42. if (address == null) {
  43. address = InetAddress.getLocalHost();
  44. }
  45. try {
  46. return createSocket(getHostAddress(address), port, ssl);
  47. } catch (IOException e) {
  48. try {
  49. return createSocket("localhost", port, ssl);
  50. } catch (IOException e2) {
  51. // throw the original exception
  52. throw e;
  53. }
  54. }
  55. }
  56. /**
  57. * Get the host address. This method adds '[' and ']' if required for
  58. * Inet6Address that contain a ':'.
  59. *
  60. * @param address the address
  61. * @return the host address
  62. */
  63. private static String getHostAddress(InetAddress address) {
  64. String host = address.getHostAddress();
  65. if (address instanceof Inet6Address) {
  66. if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
  67. host = "[" + host + "]";
  68. }
  69. }
  70. return host;
  71. }
  72. /**
  73. * Create a client socket that is connected to the given address and port.
  74. *
  75. * @param server to connect to (including an optional port)
  76. * @param defaultPort the default port (if not specified in the server
  77. * address)
  78. * @param ssl if SSL should be used
  79. * @return the socket
  80. */
  81. public static Socket createSocket(String server, int defaultPort,
  82. boolean ssl) throws IOException {
  83. int port = defaultPort;
  84. // IPv6: RFC 2732 format is '[a:b:c:d:e:f:g:h]' or
  85. // '[a:b:c:d:e:f:g:h]:port'
  86. // RFC 2396 format is 'a.b.c.d' or 'a.b.c.d:port' or 'hostname' or
  87. // 'hostname:port'
  88. int startIndex = server.startsWith("[") ? server.indexOf(']') : 0;
  89. int idx = server.indexOf(':', startIndex);
  90. if (idx >= 0) {
  91. port = Integer.decode(server.substring(idx + 1));
  92. server = server.substring(0, idx);
  93. }
  94. InetAddress address = InetAddress.getByName(server);
  95. return createSocket(address, port, ssl);
  96. }
  97. /**
  98. * Create a client socket that is connected to the given address and port.
  99. *
  100. * @param address the address to connect to
  101. * @param port the port
  102. * @param ssl if SSL should be used
  103. * @return the socket
  104. */
  105. public static Socket createSocket(InetAddress address, int port, boolean ssl)
  106. throws IOException {
  107. long start = System.currentTimeMillis();
  108. for (int i = 0;; i++) {
  109. try {
  110. if (ssl) {
  111. return CipherFactory.createSocket(address, port);
  112. }
  113. Socket socket = new Socket();
  114. socket.connect(new InetSocketAddress(address, port),
  115. SysProperties.SOCKET_CONNECT_TIMEOUT);
  116. return socket;
  117. } catch (IOException e) {
  118. if (System.currentTimeMillis() - start >=
  119. SysProperties.SOCKET_CONNECT_TIMEOUT) {
  120. // either it was a connect timeout,
  121. // or list of different exceptions
  122. throw e;
  123. }
  124. if (i >= SysProperties.SOCKET_CONNECT_RETRY) {
  125. throw e;
  126. }
  127. // wait a bit and retry
  128. try {
  129. // sleep at most 256 ms
  130. long sleep = Math.min(256, i * i);
  131. Thread.sleep(sleep);
  132. } catch (InterruptedException e2) {
  133. // ignore
  134. }
  135. }
  136. }
  137. }
  138. /**
  139. * Create a server socket. The system property h2.bindAddress is used if
  140. * set.
  141. *
  142. * @param port the port to listen on
  143. * @param ssl if SSL should be used
  144. * @return the server socket
  145. */
  146. public static ServerSocket createServerSocket(int port, boolean ssl) {
  147. try {
  148. return createServerSocketTry(port, ssl);
  149. } catch (Exception e) {
  150. // try again
  151. return createServerSocketTry(port, ssl);
  152. }
  153. }
  154. /**
  155. * Get the bind address if the system property h2.bindAddress is set, or
  156. * null if not.
  157. *
  158. * @return the bind address
  159. */
  160. private static InetAddress getBindAddress() throws UnknownHostException {
  161. String host = SysProperties.BIND_ADDRESS;
  162. if (host == null || host.length() == 0) {
  163. return null;
  164. }
  165. synchronized (NetUtils.class) {
  166. if (cachedBindAddress == null) {
  167. cachedBindAddress = InetAddress.getByName(host);
  168. }
  169. }
  170. return cachedBindAddress;
  171. }
  172. private static ServerSocket createServerSocketTry(int port, boolean ssl) {
  173. try {
  174. InetAddress bindAddress = getBindAddress();
  175. if (ssl) {
  176. return CipherFactory.createServerSocket(port, bindAddress);
  177. }
  178. if (bindAddress == null) {
  179. return new ServerSocket(port);
  180. }
  181. return new ServerSocket(port, 0, bindAddress);
  182. } catch (BindException be) {
  183. throw DbException.get(ErrorCode.EXCEPTION_OPENING_PORT_2,
  184. be, "" + port, be.toString());
  185. } catch (IOException e) {
  186. throw DbException.convertIOException(e, "port: " + port + " ssl: " + ssl);
  187. }
  188. }
  189. /**
  190. * Check if a socket is connected to a local address.
  191. *
  192. * @param socket the socket
  193. * @return true if it is
  194. */
  195. public static boolean isLocalAddress(Socket socket)
  196. throws UnknownHostException {
  197. InetAddress test = socket.getInetAddress();
  198. if (test.isLoopbackAddress()) {
  199. return true;
  200. }
  201. InetAddress localhost = InetAddress.getLocalHost();
  202. // localhost.getCanonicalHostName() is very very slow
  203. String host = localhost.getHostAddress();
  204. for (InetAddress addr : InetAddress.getAllByName(host)) {
  205. if (test.equals(addr)) {
  206. return true;
  207. }
  208. }
  209. return false;
  210. }
  211. /**
  212. * Close a server socket and ignore any exceptions.
  213. *
  214. * @param socket the socket
  215. * @return null
  216. */
  217. public static ServerSocket closeSilently(ServerSocket socket) {
  218. if (socket != null) {
  219. try {
  220. socket.close();
  221. } catch (IOException e) {
  222. // ignore
  223. }
  224. }
  225. return null;
  226. }
  227. /**
  228. * Get the local host address as a string.
  229. * For performance, the result is cached for one second.
  230. *
  231. * @return the local host address
  232. */
  233. public static synchronized String getLocalAddress() {
  234. long now = System.currentTimeMillis();
  235. if (cachedLocalAddress != null) {
  236. if (cachedLocalAddressTime + CACHE_MILLIS > now) {
  237. return cachedLocalAddress;
  238. }
  239. }
  240. InetAddress bind = null;
  241. boolean useLocalhost = false;
  242. try {
  243. bind = getBindAddress();
  244. if (bind == null) {
  245. useLocalhost = true;
  246. }
  247. } catch (UnknownHostException e) {
  248. // ignore
  249. }
  250. if (useLocalhost) {
  251. try {
  252. bind = InetAddress.getLocalHost();
  253. } catch (UnknownHostException e) {
  254. throw DbException.convert(e);
  255. }
  256. }
  257. String address = bind == null ? "localhost" : getHostAddress(bind);
  258. if (address.equals("127.0.0.1")) {
  259. address = "localhost";
  260. }
  261. cachedLocalAddress = address;
  262. cachedLocalAddressTime = now;
  263. return address;
  264. }
  265. }