PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

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

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