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

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

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