PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/core/org/apache/hadoop/net/NetUtils.java

https://github.com/johnsonchengwu/hadoop-common
Java | 488 lines | 221 code | 37 blank | 230 comment | 56 complexity | d4b03ec0d77f443d8fbac5a8b89f25a0 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.apache.hadoop.net;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.OutputStream;
  22. import java.net.InetAddress;
  23. import java.net.InetSocketAddress;
  24. import java.net.Socket;
  25. import java.net.SocketAddress;
  26. import java.net.URI;
  27. import java.net.UnknownHostException;
  28. import java.net.ConnectException;
  29. import java.nio.channels.SocketChannel;
  30. import java.util.Map.Entry;
  31. import java.util.regex.Pattern;
  32. import java.util.*;
  33. import javax.net.SocketFactory;
  34. import org.apache.commons.logging.Log;
  35. import org.apache.commons.logging.LogFactory;
  36. import org.apache.hadoop.conf.Configuration;
  37. import org.apache.hadoop.fs.Path;
  38. import org.apache.hadoop.ipc.Server;
  39. import org.apache.hadoop.ipc.VersionedProtocol;
  40. import org.apache.hadoop.util.ReflectionUtils;
  41. public class NetUtils {
  42. private static final Log LOG = LogFactory.getLog(NetUtils.class);
  43. private static Map<String, String> hostToResolved =
  44. new HashMap<String, String>();
  45. /**
  46. * Get the socket factory for the given class according to its
  47. * configuration parameter
  48. * <tt>hadoop.rpc.socket.factory.class.&lt;ClassName&gt;</tt>. When no
  49. * such parameter exists then fall back on the default socket factory as
  50. * configured by <tt>hadoop.rpc.socket.factory.class.default</tt>. If
  51. * this default socket factory is not configured, then fall back on the JVM
  52. * default socket factory.
  53. *
  54. * @param conf the configuration
  55. * @param clazz the class (usually a {@link VersionedProtocol})
  56. * @return a socket factory
  57. */
  58. public static SocketFactory getSocketFactory(Configuration conf,
  59. Class<?> clazz) {
  60. SocketFactory factory = null;
  61. String propValue =
  62. conf.get("hadoop.rpc.socket.factory.class." + clazz.getSimpleName());
  63. if ((propValue != null) && (propValue.length() > 0))
  64. factory = getSocketFactoryFromProperty(conf, propValue);
  65. if (factory == null)
  66. factory = getDefaultSocketFactory(conf);
  67. return factory;
  68. }
  69. /**
  70. * Get the default socket factory as specified by the configuration
  71. * parameter <tt>hadoop.rpc.socket.factory.default</tt>
  72. *
  73. * @param conf the configuration
  74. * @return the default socket factory as specified in the configuration or
  75. * the JVM default socket factory if the configuration does not
  76. * contain a default socket factory property.
  77. */
  78. public static SocketFactory getDefaultSocketFactory(Configuration conf) {
  79. String propValue = conf.get("hadoop.rpc.socket.factory.class.default");
  80. if ((propValue == null) || (propValue.length() == 0))
  81. return SocketFactory.getDefault();
  82. return getSocketFactoryFromProperty(conf, propValue);
  83. }
  84. /**
  85. * Get the socket factory corresponding to the given proxy URI. If the
  86. * given proxy URI corresponds to an absence of configuration parameter,
  87. * returns null. If the URI is malformed raises an exception.
  88. *
  89. * @param propValue the property which is the class name of the
  90. * SocketFactory to instantiate; assumed non null and non empty.
  91. * @return a socket factory as defined in the property value.
  92. */
  93. public static SocketFactory getSocketFactoryFromProperty(
  94. Configuration conf, String propValue) {
  95. try {
  96. Class<?> theClass = conf.getClassByName(propValue);
  97. return (SocketFactory) ReflectionUtils.newInstance(theClass, conf);
  98. } catch (ClassNotFoundException cnfe) {
  99. throw new RuntimeException("Socket Factory class not found: " + cnfe);
  100. }
  101. }
  102. /**
  103. * Util method to build socket addr from either:
  104. * <host>:<post>
  105. * <fs>://<host>:<port>/<path>
  106. */
  107. public static InetSocketAddress createSocketAddr(String target) {
  108. return createSocketAddr(target, -1);
  109. }
  110. /**
  111. * Util method to build socket addr from either:
  112. * <host>
  113. * <host>:<post>
  114. * <fs>://<host>:<port>/<path>
  115. */
  116. public static InetSocketAddress createSocketAddr(String target,
  117. int defaultPort) {
  118. int colonIndex = target.indexOf(':');
  119. if (colonIndex < 0 && defaultPort == -1) {
  120. throw new RuntimeException("Not a host:port pair: " + target);
  121. }
  122. String hostname;
  123. int port = -1;
  124. if (!target.contains("/")) {
  125. if (colonIndex == -1) {
  126. hostname = target;
  127. } else {
  128. // must be the old style <host>:<port>
  129. hostname = target.substring(0, colonIndex);
  130. port = Integer.parseInt(target.substring(colonIndex + 1));
  131. }
  132. } else {
  133. // a new uri
  134. URI addr = new Path(target).toUri();
  135. hostname = addr.getHost();
  136. port = addr.getPort();
  137. }
  138. if (port == -1) {
  139. port = defaultPort;
  140. }
  141. if (getStaticResolution(hostname) != null) {
  142. hostname = getStaticResolution(hostname);
  143. }
  144. return new InetSocketAddress(hostname, port);
  145. }
  146. /**
  147. * Handle the transition from pairs of attributes specifying a host and port
  148. * to a single colon separated one.
  149. * @param conf the configuration to check
  150. * @param oldBindAddressName the old address attribute name
  151. * @param oldPortName the old port attribute name
  152. * @param newBindAddressName the new combined name
  153. * @return the complete address from the configuration
  154. */
  155. @Deprecated
  156. public static String getServerAddress(Configuration conf,
  157. String oldBindAddressName,
  158. String oldPortName,
  159. String newBindAddressName) {
  160. String oldAddr = conf.get(oldBindAddressName);
  161. String oldPort = conf.get(oldPortName);
  162. String newAddrPort = conf.get(newBindAddressName);
  163. if (oldAddr == null && oldPort == null && newAddrPort != null) {
  164. return newAddrPort;
  165. }
  166. if (newAddrPort == null) {
  167. throw new IllegalArgumentException("No value for " + newBindAddressName);
  168. }
  169. String[] newAddrPortParts = newAddrPort.split(":",2);
  170. if (newAddrPortParts.length != 2) {
  171. throw new IllegalArgumentException("Invalid address/port: " +
  172. newAddrPort);
  173. }
  174. if (oldAddr == null) {
  175. oldAddr = newAddrPortParts[0];
  176. } else {
  177. LOG.warn("Configuration parameter " + oldBindAddressName +
  178. " is deprecated. Use " + newBindAddressName + " instead.");
  179. }
  180. if (oldPort == null) {
  181. oldPort = newAddrPortParts[1];
  182. } else {
  183. LOG.warn("Configuration parameter " + oldPortName +
  184. " is deprecated. Use " + newBindAddressName + " instead.");
  185. }
  186. return oldAddr + ":" + oldPort;
  187. }
  188. /**
  189. * Adds a static resolution for host. This can be used for setting up
  190. * hostnames with names that are fake to point to a well known host. For e.g.
  191. * in some testcases we require to have daemons with different hostnames
  192. * running on the same machine. In order to create connections to these
  193. * daemons, one can set up mappings from those hostnames to "localhost".
  194. * {@link NetUtils#getStaticResolution(String)} can be used to query for
  195. * the actual hostname.
  196. * @param host
  197. * @param resolvedName
  198. */
  199. public static void addStaticResolution(String host, String resolvedName) {
  200. synchronized (hostToResolved) {
  201. hostToResolved.put(host, resolvedName);
  202. }
  203. }
  204. /**
  205. * Retrieves the resolved name for the passed host. The resolved name must
  206. * have been set earlier using
  207. * {@link NetUtils#addStaticResolution(String, String)}
  208. * @param host
  209. * @return the resolution
  210. */
  211. public static String getStaticResolution(String host) {
  212. synchronized (hostToResolved) {
  213. return hostToResolved.get(host);
  214. }
  215. }
  216. /**
  217. * This is used to get all the resolutions that were added using
  218. * {@link NetUtils#addStaticResolution(String, String)}. The return
  219. * value is a List each element of which contains an array of String
  220. * of the form String[0]=hostname, String[1]=resolved-hostname
  221. * @return the list of resolutions
  222. */
  223. public static List <String[]> getAllStaticResolutions() {
  224. synchronized (hostToResolved) {
  225. Set <Entry <String, String>>entries = hostToResolved.entrySet();
  226. if (entries.size() == 0) {
  227. return null;
  228. }
  229. List <String[]> l = new ArrayList<String[]>(entries.size());
  230. for (Entry<String, String> e : entries) {
  231. l.add(new String[] {e.getKey(), e.getValue()});
  232. }
  233. return l;
  234. }
  235. }
  236. /**
  237. * Returns InetSocketAddress that a client can use to
  238. * connect to the server. Server.getListenerAddress() is not correct when
  239. * the server binds to "0.0.0.0". This returns "127.0.0.1:port" when
  240. * the getListenerAddress() returns "0.0.0.0:port".
  241. *
  242. * @param server
  243. * @return socket address that a client can use to connect to the server.
  244. */
  245. public static InetSocketAddress getConnectAddress(Server server) {
  246. InetSocketAddress addr = server.getListenerAddress();
  247. if (addr.getAddress().getHostAddress().equals("0.0.0.0")) {
  248. addr = new InetSocketAddress("127.0.0.1", addr.getPort());
  249. }
  250. return addr;
  251. }
  252. /**
  253. * Same as getInputStream(socket, socket.getSoTimeout()).<br><br>
  254. *
  255. * From documentation for {@link #getInputStream(Socket, long)}:<br>
  256. * Returns InputStream for the socket. If the socket has an associated
  257. * SocketChannel then it returns a
  258. * {@link SocketInputStream} with the given timeout. If the socket does not
  259. * have a channel, {@link Socket#getInputStream()} is returned. In the later
  260. * case, the timeout argument is ignored and the timeout set with
  261. * {@link Socket#setSoTimeout(int)} applies for reads.<br><br>
  262. *
  263. * Any socket created using socket factories returned by {@link #NetUtils},
  264. * must use this interface instead of {@link Socket#getInputStream()}.
  265. *
  266. * @see #getInputStream(Socket, long)
  267. *
  268. * @param socket
  269. * @return InputStream for reading from the socket.
  270. * @throws IOException
  271. */
  272. public static InputStream getInputStream(Socket socket)
  273. throws IOException {
  274. return getInputStream(socket, socket.getSoTimeout());
  275. }
  276. /**
  277. * Returns InputStream for the socket. If the socket has an associated
  278. * SocketChannel then it returns a
  279. * {@link SocketInputStream} with the given timeout. If the socket does not
  280. * have a channel, {@link Socket#getInputStream()} is returned. In the later
  281. * case, the timeout argument is ignored and the timeout set with
  282. * {@link Socket#setSoTimeout(int)} applies for reads.<br><br>
  283. *
  284. * Any socket created using socket factories returned by {@link #NetUtils},
  285. * must use this interface instead of {@link Socket#getInputStream()}.
  286. *
  287. * @see Socket#getChannel()
  288. *
  289. * @param socket
  290. * @param timeout timeout in milliseconds. This may not always apply. zero
  291. * for waiting as long as necessary.
  292. * @return InputStream for reading from the socket.
  293. * @throws IOException
  294. */
  295. public static InputStream getInputStream(Socket socket, long timeout)
  296. throws IOException {
  297. return (socket.getChannel() == null) ?
  298. socket.getInputStream() : new SocketInputStream(socket, timeout);
  299. }
  300. /**
  301. * Same as getOutputStream(socket, 0). Timeout of zero implies write will
  302. * wait until data is available.<br><br>
  303. *
  304. * From documentation for {@link #getOutputStream(Socket, long)} : <br>
  305. * Returns OutputStream for the socket. If the socket has an associated
  306. * SocketChannel then it returns a
  307. * {@link SocketOutputStream} with the given timeout. If the socket does not
  308. * have a channel, {@link Socket#getOutputStream()} is returned. In the later
  309. * case, the timeout argument is ignored and the write will wait until
  310. * data is available.<br><br>
  311. *
  312. * Any socket created using socket factories returned by {@link #NetUtils},
  313. * must use this interface instead of {@link Socket#getOutputStream()}.
  314. *
  315. * @see #getOutputStream(Socket, long)
  316. *
  317. * @param socket
  318. * @return OutputStream for writing to the socket.
  319. * @throws IOException
  320. */
  321. public static OutputStream getOutputStream(Socket socket)
  322. throws IOException {
  323. return getOutputStream(socket, 0);
  324. }
  325. /**
  326. * Returns OutputStream for the socket. If the socket has an associated
  327. * SocketChannel then it returns a
  328. * {@link SocketOutputStream} with the given timeout. If the socket does not
  329. * have a channel, {@link Socket#getOutputStream()} is returned. In the later
  330. * case, the timeout argument is ignored and the write will wait until
  331. * data is available.<br><br>
  332. *
  333. * Any socket created using socket factories returned by {@link #NetUtils},
  334. * must use this interface instead of {@link Socket#getOutputStream()}.
  335. *
  336. * @see Socket#getChannel()
  337. *
  338. * @param socket
  339. * @param timeout timeout in milliseconds. This may not always apply. zero
  340. * for waiting as long as necessary.
  341. * @return OutputStream for writing to the socket.
  342. * @throws IOException
  343. */
  344. public static OutputStream getOutputStream(Socket socket, long timeout)
  345. throws IOException {
  346. return (socket.getChannel() == null) ?
  347. socket.getOutputStream() : new SocketOutputStream(socket, timeout);
  348. }
  349. /**
  350. * This is a drop-in replacement for
  351. * {@link Socket#connect(SocketAddress, int)}.
  352. * In the case of normal sockets that don't have associated channels, this
  353. * just invokes <code>socket.connect(endpoint, timeout)</code>. If
  354. * <code>socket.getChannel()</code> returns a non-null channel,
  355. * connect is implemented using Hadoop's selectors. This is done mainly
  356. * to avoid Sun's connect implementation from creating thread-local
  357. * selectors, since Hadoop does not have control on when these are closed
  358. * and could end up taking all the available file descriptors.
  359. *
  360. * @see java.net.Socket#connect(java.net.SocketAddress, int)
  361. *
  362. * @param socket
  363. * @param endpoint
  364. * @param timeout - timeout in milliseconds
  365. */
  366. public static void connect(Socket socket,
  367. SocketAddress endpoint,
  368. int timeout) throws IOException {
  369. if (socket == null || endpoint == null || timeout < 0) {
  370. throw new IllegalArgumentException("Illegal argument for connect()");
  371. }
  372. try {
  373. SocketChannel ch = socket.getChannel();
  374. if (ch == null) {
  375. // let the default implementation handle it.
  376. socket.connect(endpoint, timeout);
  377. } else {
  378. SocketIOWithTimeout.connect(ch, endpoint, timeout);
  379. }
  380. } catch (ConnectException e) {
  381. throw (ConnectException) new ConnectException(
  382. e + " connecting to " + endpoint).initCause(e);
  383. }
  384. }
  385. /**
  386. * Given a string representation of a host, return its ip address
  387. * in textual presentation.
  388. *
  389. * @param name a string representation of a host:
  390. * either a textual representation its IP address or its host name
  391. * @return its IP address in the string format
  392. */
  393. public static String normalizeHostName(String name) {
  394. if (Character.digit(name.charAt(0), 16) != -1) { // it is an IP
  395. return name;
  396. } else {
  397. try {
  398. InetAddress ipAddress = InetAddress.getByName(name);
  399. return ipAddress.getHostAddress();
  400. } catch (UnknownHostException e) {
  401. return name;
  402. }
  403. }
  404. }
  405. /**
  406. * Given a collection of string representation of hosts, return a list of
  407. * corresponding IP addresses in the textual representation.
  408. *
  409. * @param names a collection of string representations of hosts
  410. * @return a list of corresponding IP addresses in the string format
  411. * @see #normalizeHostName(String)
  412. */
  413. public static List<String> normalizeHostNames(Collection<String> names) {
  414. List<String> hostNames = new ArrayList<String>(names.size());
  415. for (String name : names) {
  416. hostNames.add(normalizeHostName(name));
  417. }
  418. return hostNames;
  419. }
  420. /**
  421. * Attempt to obtain the host name of a name specified by ip address.
  422. * Check that the node name is an ip addr and if so, attempt to determine
  423. * its host name. If the name is not an IP addr, or the actual name cannot
  424. * be determined, return null.
  425. *
  426. * @return Host name or null
  427. */
  428. private static final Pattern ipPattern = // Pattern for matching hostname to ip:port
  429. Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:?\\d*");
  430. public static String getHostNameOfIP(String ip) {
  431. // If name is not an ip addr, don't bother looking it up
  432. if(!ipPattern.matcher(ip).matches())
  433. return null;
  434. String hostname = "";
  435. try {
  436. String n = ip.substring(0, ip.indexOf(':'));
  437. hostname = InetAddress.getByName(n).getHostName();
  438. } catch (UnknownHostException e) {
  439. return null;
  440. }
  441. return hostname;
  442. }
  443. /**
  444. * Return hostname without throwing exception.
  445. * @return hostname
  446. */
  447. public static String getHostname() {
  448. try {return "" + InetAddress.getLocalHost();}
  449. catch(UnknownHostException uhe) {return "" + uhe;}
  450. }
  451. }