PageRenderTime 68ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/hadoop-common/src/java/org/apache/hadoop/net/NetUtils.java

https://bitbucket.org/hadoop/hadoop-0.21.0
Java | 463 lines | 198 code | 38 blank | 227 comment | 44 complexity | 03692c0e7f24fefd9aca59e9a8de6402 MD5 | raw file
Possible License(s): Apache-2.0
  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.classification.InterfaceAudience;
  37. import org.apache.hadoop.classification.InterfaceStability;
  38. import org.apache.hadoop.conf.Configuration;
  39. import org.apache.hadoop.fs.Path;
  40. import org.apache.hadoop.ipc.Server;
  41. import org.apache.hadoop.ipc.VersionedProtocol;
  42. import org.apache.hadoop.util.ReflectionUtils;
  43. @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
  44. @InterfaceStability.Unstable
  45. public class NetUtils {
  46. private static final Log LOG = LogFactory.getLog(NetUtils.class);
  47. private static Map<String, String> hostToResolved =
  48. new HashMap<String, String>();
  49. /**
  50. * Get the socket factory for the given class according to its
  51. * configuration parameter
  52. * <tt>hadoop.rpc.socket.factory.class.&lt;ClassName&gt;</tt>. When no
  53. * such parameter exists then fall back on the default socket factory as
  54. * configured by <tt>hadoop.rpc.socket.factory.class.default</tt>. If
  55. * this default socket factory is not configured, then fall back on the JVM
  56. * default socket factory.
  57. *
  58. * @param conf the configuration
  59. * @param clazz the class (usually a {@link VersionedProtocol})
  60. * @return a socket factory
  61. */
  62. public static SocketFactory getSocketFactory(Configuration conf,
  63. Class<?> clazz) {
  64. SocketFactory factory = null;
  65. String propValue =
  66. conf.get("hadoop.rpc.socket.factory.class." + clazz.getSimpleName());
  67. if ((propValue != null) && (propValue.length() > 0))
  68. factory = getSocketFactoryFromProperty(conf, propValue);
  69. if (factory == null)
  70. factory = getDefaultSocketFactory(conf);
  71. return factory;
  72. }
  73. /**
  74. * Get the default socket factory as specified by the configuration
  75. * parameter <tt>hadoop.rpc.socket.factory.default</tt>
  76. *
  77. * @param conf the configuration
  78. * @return the default socket factory as specified in the configuration or
  79. * the JVM default socket factory if the configuration does not
  80. * contain a default socket factory property.
  81. */
  82. public static SocketFactory getDefaultSocketFactory(Configuration conf) {
  83. String propValue = conf.get("hadoop.rpc.socket.factory.class.default");
  84. if ((propValue == null) || (propValue.length() == 0))
  85. return SocketFactory.getDefault();
  86. return getSocketFactoryFromProperty(conf, propValue);
  87. }
  88. /**
  89. * Get the socket factory corresponding to the given proxy URI. If the
  90. * given proxy URI corresponds to an absence of configuration parameter,
  91. * returns null. If the URI is malformed raises an exception.
  92. *
  93. * @param propValue the property which is the class name of the
  94. * SocketFactory to instantiate; assumed non null and non empty.
  95. * @return a socket factory as defined in the property value.
  96. */
  97. public static SocketFactory getSocketFactoryFromProperty(
  98. Configuration conf, String propValue) {
  99. try {
  100. Class<?> theClass = conf.getClassByName(propValue);
  101. return (SocketFactory) ReflectionUtils.newInstance(theClass, conf);
  102. } catch (ClassNotFoundException cnfe) {
  103. throw new RuntimeException("Socket Factory class not found: " + cnfe);
  104. }
  105. }
  106. /**
  107. * Util method to build socket addr from either:
  108. * <host>:<post>
  109. * <fs>://<host>:<port>/<path>
  110. */
  111. public static InetSocketAddress createSocketAddr(String target) {
  112. return createSocketAddr(target, -1);
  113. }
  114. /**
  115. * Util method to build socket addr from either:
  116. * <host>
  117. * <host>:<post>
  118. * <fs>://<host>:<port>/<path>
  119. */
  120. public static InetSocketAddress createSocketAddr(String target,
  121. int defaultPort) {
  122. if (target == null) {
  123. throw new IllegalArgumentException("Target address cannot be null.");
  124. }
  125. int colonIndex = target.indexOf(':');
  126. if (colonIndex < 0 && defaultPort == -1) {
  127. throw new RuntimeException("Not a host:port pair: " + target);
  128. }
  129. String hostname;
  130. int port = -1;
  131. if (!target.contains("/")) {
  132. if (colonIndex == -1) {
  133. hostname = target;
  134. } else {
  135. // must be the old style <host>:<port>
  136. hostname = target.substring(0, colonIndex);
  137. port = Integer.parseInt(target.substring(colonIndex + 1));
  138. }
  139. } else {
  140. // a new uri
  141. URI addr = new Path(target).toUri();
  142. hostname = addr.getHost();
  143. port = addr.getPort();
  144. }
  145. if (port == -1) {
  146. port = defaultPort;
  147. }
  148. if (getStaticResolution(hostname) != null) {
  149. hostname = getStaticResolution(hostname);
  150. }
  151. return new InetSocketAddress(hostname, port);
  152. }
  153. /**
  154. * Adds a static resolution for host. This can be used for setting up
  155. * hostnames with names that are fake to point to a well known host. For e.g.
  156. * in some testcases we require to have daemons with different hostnames
  157. * running on the same machine. In order to create connections to these
  158. * daemons, one can set up mappings from those hostnames to "localhost".
  159. * {@link NetUtils#getStaticResolution(String)} can be used to query for
  160. * the actual hostname.
  161. * @param host
  162. * @param resolvedName
  163. */
  164. public static void addStaticResolution(String host, String resolvedName) {
  165. synchronized (hostToResolved) {
  166. hostToResolved.put(host, resolvedName);
  167. }
  168. }
  169. /**
  170. * Retrieves the resolved name for the passed host. The resolved name must
  171. * have been set earlier using
  172. * {@link NetUtils#addStaticResolution(String, String)}
  173. * @param host
  174. * @return the resolution
  175. */
  176. public static String getStaticResolution(String host) {
  177. synchronized (hostToResolved) {
  178. return hostToResolved.get(host);
  179. }
  180. }
  181. /**
  182. * This is used to get all the resolutions that were added using
  183. * {@link NetUtils#addStaticResolution(String, String)}. The return
  184. * value is a List each element of which contains an array of String
  185. * of the form String[0]=hostname, String[1]=resolved-hostname
  186. * @return the list of resolutions
  187. */
  188. public static List <String[]> getAllStaticResolutions() {
  189. synchronized (hostToResolved) {
  190. Set <Entry <String, String>>entries = hostToResolved.entrySet();
  191. if (entries.size() == 0) {
  192. return null;
  193. }
  194. List <String[]> l = new ArrayList<String[]>(entries.size());
  195. for (Entry<String, String> e : entries) {
  196. l.add(new String[] {e.getKey(), e.getValue()});
  197. }
  198. return l;
  199. }
  200. }
  201. /**
  202. * Returns InetSocketAddress that a client can use to
  203. * connect to the server. Server.getListenerAddress() is not correct when
  204. * the server binds to "0.0.0.0". This returns "127.0.0.1:port" when
  205. * the getListenerAddress() returns "0.0.0.0:port".
  206. *
  207. * @param server
  208. * @return socket address that a client can use to connect to the server.
  209. */
  210. public static InetSocketAddress getConnectAddress(Server server) {
  211. InetSocketAddress addr = server.getListenerAddress();
  212. if (addr.getAddress().getHostAddress().equals("0.0.0.0")) {
  213. addr = new InetSocketAddress("127.0.0.1", addr.getPort());
  214. }
  215. return addr;
  216. }
  217. /**
  218. * Same as getInputStream(socket, socket.getSoTimeout()).<br><br>
  219. *
  220. * From documentation for {@link #getInputStream(Socket, long)}:<br>
  221. * Returns InputStream for the socket. If the socket has an associated
  222. * SocketChannel then it returns a
  223. * {@link SocketInputStream} with the given timeout. If the socket does not
  224. * have a channel, {@link Socket#getInputStream()} is returned. In the later
  225. * case, the timeout argument is ignored and the timeout set with
  226. * {@link Socket#setSoTimeout(int)} applies for reads.<br><br>
  227. *
  228. * Any socket created using socket factories returned by {@link #NetUtils},
  229. * must use this interface instead of {@link Socket#getInputStream()}.
  230. *
  231. * @see #getInputStream(Socket, long)
  232. *
  233. * @param socket
  234. * @return InputStream for reading from the socket.
  235. * @throws IOException
  236. */
  237. public static InputStream getInputStream(Socket socket)
  238. throws IOException {
  239. return getInputStream(socket, socket.getSoTimeout());
  240. }
  241. /**
  242. * Returns InputStream for the socket. If the socket has an associated
  243. * SocketChannel then it returns a
  244. * {@link SocketInputStream} with the given timeout. If the socket does not
  245. * have a channel, {@link Socket#getInputStream()} is returned. In the later
  246. * case, the timeout argument is ignored and the timeout set with
  247. * {@link Socket#setSoTimeout(int)} applies for reads.<br><br>
  248. *
  249. * Any socket created using socket factories returned by {@link #NetUtils},
  250. * must use this interface instead of {@link Socket#getInputStream()}.
  251. *
  252. * @see Socket#getChannel()
  253. *
  254. * @param socket
  255. * @param timeout timeout in milliseconds. This may not always apply. zero
  256. * for waiting as long as necessary.
  257. * @return InputStream for reading from the socket.
  258. * @throws IOException
  259. */
  260. public static InputStream getInputStream(Socket socket, long timeout)
  261. throws IOException {
  262. return (socket.getChannel() == null) ?
  263. socket.getInputStream() : new SocketInputStream(socket, timeout);
  264. }
  265. /**
  266. * Same as getOutputStream(socket, 0). Timeout of zero implies write will
  267. * wait until data is available.<br><br>
  268. *
  269. * From documentation for {@link #getOutputStream(Socket, long)} : <br>
  270. * Returns OutputStream for the socket. If the socket has an associated
  271. * SocketChannel then it returns a
  272. * {@link SocketOutputStream} with the given timeout. If the socket does not
  273. * have a channel, {@link Socket#getOutputStream()} is returned. In the later
  274. * case, the timeout argument is ignored and the write will wait until
  275. * data is available.<br><br>
  276. *
  277. * Any socket created using socket factories returned by {@link #NetUtils},
  278. * must use this interface instead of {@link Socket#getOutputStream()}.
  279. *
  280. * @see #getOutputStream(Socket, long)
  281. *
  282. * @param socket
  283. * @return OutputStream for writing to the socket.
  284. * @throws IOException
  285. */
  286. public static OutputStream getOutputStream(Socket socket)
  287. throws IOException {
  288. return getOutputStream(socket, 0);
  289. }
  290. /**
  291. * Returns OutputStream for the socket. If the socket has an associated
  292. * SocketChannel then it returns a
  293. * {@link SocketOutputStream} with the given timeout. If the socket does not
  294. * have a channel, {@link Socket#getOutputStream()} is returned. In the later
  295. * case, the timeout argument is ignored and the write will wait until
  296. * data is available.<br><br>
  297. *
  298. * Any socket created using socket factories returned by {@link #NetUtils},
  299. * must use this interface instead of {@link Socket#getOutputStream()}.
  300. *
  301. * @see Socket#getChannel()
  302. *
  303. * @param socket
  304. * @param timeout timeout in milliseconds. This may not always apply. zero
  305. * for waiting as long as necessary.
  306. * @return OutputStream for writing to the socket.
  307. * @throws IOException
  308. */
  309. public static OutputStream getOutputStream(Socket socket, long timeout)
  310. throws IOException {
  311. return (socket.getChannel() == null) ?
  312. socket.getOutputStream() : new SocketOutputStream(socket, timeout);
  313. }
  314. /**
  315. * This is a drop-in replacement for
  316. * {@link Socket#connect(SocketAddress, int)}.
  317. * In the case of normal sockets that don't have associated channels, this
  318. * just invokes <code>socket.connect(endpoint, timeout)</code>. If
  319. * <code>socket.getChannel()</code> returns a non-null channel,
  320. * connect is implemented using Hadoop's selectors. This is done mainly
  321. * to avoid Sun's connect implementation from creating thread-local
  322. * selectors, since Hadoop does not have control on when these are closed
  323. * and could end up taking all the available file descriptors.
  324. *
  325. * @see java.net.Socket#connect(java.net.SocketAddress, int)
  326. *
  327. * @param socket
  328. * @param endpoint
  329. * @param timeout - timeout in milliseconds
  330. */
  331. public static void connect(Socket socket,
  332. SocketAddress endpoint,
  333. int timeout) throws IOException {
  334. if (socket == null || endpoint == null || timeout < 0) {
  335. throw new IllegalArgumentException("Illegal argument for connect()");
  336. }
  337. SocketChannel ch = socket.getChannel();
  338. if (ch == null) {
  339. // let the default implementation handle it.
  340. socket.connect(endpoint, timeout);
  341. } else {
  342. SocketIOWithTimeout.connect(ch, endpoint, timeout);
  343. }
  344. // There is a very rare case allowed by the TCP specification, such that
  345. // if we are trying to connect to an endpoint on the local machine,
  346. // and we end up choosing an ephemeral port equal to the destination port,
  347. // we will actually end up getting connected to ourself (ie any data we
  348. // send just comes right back). This is only possible if the target
  349. // daemon is down, so we'll treat it like connection refused.
  350. if (socket.getLocalPort() == socket.getPort() &&
  351. socket.getLocalAddress().equals(socket.getInetAddress())) {
  352. LOG.info("Detected a loopback TCP socket, disconnecting it");
  353. socket.close();
  354. throw new ConnectException(
  355. "Localhost targeted connection resulted in a loopback. " +
  356. "No daemon is listening on the target port.");
  357. }
  358. }
  359. /**
  360. * Given a string representation of a host, return its ip address
  361. * in textual presentation.
  362. *
  363. * @param name a string representation of a host:
  364. * either a textual representation its IP address or its host name
  365. * @return its IP address in the string format
  366. */
  367. public static String normalizeHostName(String name) {
  368. if (Character.digit(name.charAt(0), 16) != -1) { // it is an IP
  369. return name;
  370. } else {
  371. try {
  372. InetAddress ipAddress = InetAddress.getByName(name);
  373. return ipAddress.getHostAddress();
  374. } catch (UnknownHostException e) {
  375. return name;
  376. }
  377. }
  378. }
  379. /**
  380. * Given a collection of string representation of hosts, return a list of
  381. * corresponding IP addresses in the textual representation.
  382. *
  383. * @param names a collection of string representations of hosts
  384. * @return a list of corresponding IP addresses in the string format
  385. * @see #normalizeHostName(String)
  386. */
  387. public static List<String> normalizeHostNames(Collection<String> names) {
  388. List<String> hostNames = new ArrayList<String>(names.size());
  389. for (String name : names) {
  390. hostNames.add(normalizeHostName(name));
  391. }
  392. return hostNames;
  393. }
  394. /**
  395. * Attempt to obtain the host name of a name specified by ip address.
  396. * Check that the node name is an ip addr and if so, attempt to determine
  397. * its host name. If the name is not an IP addr, or the actual name cannot
  398. * be determined, return null.
  399. *
  400. * @return Host name or null
  401. */
  402. private static final Pattern ipPattern = // Pattern for matching hostname to ip:port
  403. Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}:?\\d*");
  404. public static String getHostNameOfIP(String ip) {
  405. // If name is not an ip addr, don't bother looking it up
  406. if(!ipPattern.matcher(ip).matches())
  407. return null;
  408. String hostname = "";
  409. try {
  410. String n = ip.substring(0, ip.indexOf(':'));
  411. hostname = InetAddress.getByName(n).getHostName();
  412. } catch (UnknownHostException e) {
  413. return null;
  414. }
  415. return hostname;
  416. }
  417. /**
  418. * Return hostname without throwing exception.
  419. * @return hostname
  420. */
  421. public static String getHostname() {
  422. try {return "" + InetAddress.getLocalHost();}
  423. catch(UnknownHostException uhe) {return "" + uhe;}
  424. }
  425. }