PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Core/org/objectweb/proactive/core/util/ProActiveInet.java

https://bitbucket.org/lp/programming-multiactivities
Java | 421 lines | 269 code | 71 blank | 81 comment | 60 complexity | 566fd05e3eddc1e8da652ffe01e400f8 MD5 | raw file
  1. /*
  2. * ################################################################
  3. *
  4. * ProActive Parallel Suite(TM): The Java(TM) library for
  5. * Parallel, Distributed, Multi-Core Computing for
  6. * Enterprise Grids & Clouds
  7. *
  8. * Copyright (C) 1997-2012 INRIA/University of
  9. * Nice-Sophia Antipolis/ActiveEon
  10. * Contact: proactive@ow2.org or contact@activeeon.com
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Affero General Public License
  14. * as published by the Free Software Foundation; version 3 of
  15. * the License.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Affero General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public License
  23. * along with this library; if not, write to the Free Software
  24. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  25. * USA
  26. *
  27. * If needed, contact us to obtain a release under GPL Version 2 or 3
  28. * or a different license than the AGPL.
  29. *
  30. * Initial developer(s): The ProActive Team
  31. * http://proactive.inria.fr/team_members.htm
  32. * Contributor(s):
  33. *
  34. * ################################################################
  35. * $$PROACTIVE_INITIAL_DEV$$
  36. */
  37. package org.objectweb.proactive.core.util;
  38. import java.net.Inet6Address;
  39. import java.net.InetAddress;
  40. import java.net.NetworkInterface;
  41. import java.net.SocketException;
  42. import java.net.UnknownHostException;
  43. import java.util.Enumeration;
  44. import java.util.LinkedList;
  45. import java.util.List;
  46. import org.apache.log4j.Logger;
  47. import org.objectweb.proactive.core.config.CentralPAPropertyRepository;
  48. import org.objectweb.proactive.core.util.log.Loggers;
  49. import org.objectweb.proactive.core.util.log.ProActiveLogger;
  50. /** Provide the local InetAddress to be used by ProActive
  51. *
  52. * Expected behavior of this class is described in the ProActive manual, chapter "ProActive basic configuration"
  53. */
  54. public class ProActiveInet {
  55. static private Logger logger = ProActiveLogger.getLogger(Loggers.CONFIGURATION_NETWORK);
  56. final static private ProActiveInet instance = new ProActiveInet();
  57. final private InetAddress electedAddress;
  58. static public ProActiveInet getInstance() {
  59. return instance;
  60. }
  61. private ProActiveInet() {
  62. electedAddress = electAnAddress();
  63. if (electedAddress == null) {
  64. logger.error("No local Inet Address found. Exiting");
  65. }
  66. }
  67. /**
  68. * Returns the inet address used by the local ProActive Runtime
  69. *
  70. * @return
  71. */
  72. public InetAddress getInetAddress() {
  73. if (electedAddress == null) {
  74. throw new IllegalStateException("No suitable IP address found");
  75. }
  76. return electedAddress;
  77. }
  78. public List<String> listAllInetAddress() {
  79. LinkedList<String> ret = new LinkedList<String>();
  80. Enumeration<NetworkInterface> nis;
  81. try {
  82. nis = NetworkInterface.getNetworkInterfaces();
  83. while (nis.hasMoreElements()) {
  84. NetworkInterface ni = nis.nextElement();
  85. StringBuilder sb = new StringBuilder();
  86. sb.append(ni.getName());
  87. sb.append("\t");
  88. sb.append("MAC n/a");
  89. sb.append("\t");
  90. Enumeration<InetAddress> ias = ni.getInetAddresses();
  91. while (ias.hasMoreElements()) {
  92. InetAddress ia = ias.nextElement();
  93. sb.append(ia.getHostAddress());
  94. sb.append(" ");
  95. }
  96. ret.add(sb.toString());
  97. }
  98. } catch (SocketException e) {
  99. logger.info("Failed to find a suitable InetAddress", e);
  100. }
  101. return ret;
  102. }
  103. /**
  104. * Returns the host name of the local ProActive inet address
  105. *
  106. * If {@link CentralPAPropertyRepository.PA_USE_IP_ADDRESS} is set then the IP address is
  107. * returned instead of an FQDN
  108. *
  109. * @return
  110. * @see PAProperties
  111. */
  112. public String getHostname() {
  113. return URIBuilder.getHostNameorIP(getInetAddress());
  114. }
  115. private InetAddress electAnAddress() {
  116. InetAddress ia = null;
  117. if (defaultBehavior()) {
  118. logger.debug("Using default algorithm to elected an IP address");
  119. ia = getDefaultInterface();
  120. } else {
  121. // Follow the user defined rules
  122. if (CentralPAPropertyRepository.PA_HOSTNAME.isSet()) {
  123. logger.debug(CentralPAPropertyRepository.PA_HOSTNAME.getName() +
  124. " defined. Using getByName() to elected an IP address");
  125. // return the result of getByName
  126. try {
  127. ia = InetAddress.getByName(CentralPAPropertyRepository.PA_HOSTNAME.getValue());
  128. } catch (UnknownHostException e) {
  129. logger.info(CentralPAPropertyRepository.PA_HOSTNAME.getName() +
  130. " is set, but no IP address is bound to this hostname");
  131. }
  132. } else {
  133. logger
  134. .debug("At least one proactive.net.* property defined. Using the matching algorithm to elect an IP address");
  135. // Use the filter algorithm
  136. if (ia == null) {
  137. List<InetAddress> l;
  138. l = getAllInetAddresses();
  139. l = filterByNetmask(l);
  140. l = filterLoopback(l);
  141. l = filterPrivate(l);
  142. for (InetAddress addr : l) {
  143. if (CentralPAPropertyRepository.PA_NET_DISABLE_IPv6.isTrue() &&
  144. addr instanceof Inet6Address) {
  145. continue;
  146. }
  147. ia = addr;
  148. break;
  149. }
  150. }
  151. }
  152. }
  153. return ia;
  154. }
  155. /**
  156. * Elects the default {@link InetAddress}.
  157. *
  158. * A first match algorithm is used:
  159. * <ol>
  160. * <li>Public IP address</li>
  161. * <li>Private IP address</li>
  162. * <li>loopback address</li>
  163. * </ol>
  164. *
  165. * IPv6 address can enabled/disabled with the
  166. * {@link PAProperties#PA_NET_DISABLE_IPv6} property.
  167. */
  168. private InetAddress getDefaultInterface() {
  169. List<InetAddress> ias = getAllInetAddresses();
  170. // Search for a public IPv4 address
  171. for (InetAddress ia : ias) {
  172. if (ia.isLoopbackAddress())
  173. continue;
  174. if (ia.isSiteLocalAddress())
  175. continue;
  176. if (CentralPAPropertyRepository.PA_NET_DISABLE_IPv6.isTrue() && ia instanceof Inet6Address)
  177. continue;
  178. return ia;
  179. }
  180. // Search for a private IPv4 address
  181. for (InetAddress ia : ias) {
  182. if (ia.isLoopbackAddress())
  183. continue;
  184. if (CentralPAPropertyRepository.PA_NET_DISABLE_IPv6.isTrue() && ia instanceof Inet6Address)
  185. continue;
  186. return ia;
  187. }
  188. // Search for a loopback address
  189. for (InetAddress ia : ias) {
  190. if (CentralPAPropertyRepository.PA_NET_DISABLE_IPv6.isTrue() && ia instanceof Inet6Address)
  191. continue;
  192. return ia;
  193. }
  194. return null;
  195. }
  196. /**
  197. * Returns true if a property that can affect interface binding is set.
  198. * False otherwise
  199. */
  200. private boolean defaultBehavior() {
  201. if (CentralPAPropertyRepository.PA_HOSTNAME.isSet())
  202. return false;
  203. if (CentralPAPropertyRepository.PA_NET_NOLOOPBACK.isSet())
  204. return false;
  205. if (CentralPAPropertyRepository.PA_NET_NOPRIVATE.isSet())
  206. return false;
  207. if (CentralPAPropertyRepository.PA_NET_NETMASK.isSet())
  208. return false;
  209. if (CentralPAPropertyRepository.PA_NET_INTERFACE.isSet())
  210. return false;
  211. return true;
  212. }
  213. private List<InetAddress> getAllInetAddresses() {
  214. LinkedList<InetAddress> ret = new LinkedList<InetAddress>();
  215. String intf = CentralPAPropertyRepository.PA_NET_INTERFACE.getValue();
  216. Enumeration<NetworkInterface> nis;
  217. try {
  218. nis = NetworkInterface.getNetworkInterfaces();
  219. while (nis.hasMoreElements()) {
  220. NetworkInterface ni = nis.nextElement();
  221. if (intf != null && !ni.getName().equals(intf)) {
  222. // Skip this interface
  223. continue;
  224. }
  225. Enumeration<InetAddress> ias = ni.getInetAddresses();
  226. while (ias.hasMoreElements()) {
  227. InetAddress ia = ias.nextElement();
  228. ret.add(ia);
  229. }
  230. }
  231. } catch (SocketException e) {
  232. logger.info("Failed to find a suitable InetAddress", e);
  233. }
  234. return ret;
  235. }
  236. private List<InetAddress> filterPrivate(List<InetAddress> l) {
  237. if (!CentralPAPropertyRepository.PA_NET_NOPRIVATE.isSet() ||
  238. !CentralPAPropertyRepository.PA_NET_NOPRIVATE.isTrue()) {
  239. // All InetAddress match
  240. return new LinkedList<InetAddress>(l);
  241. }
  242. List<InetAddress> ret = new LinkedList<InetAddress>();
  243. for (InetAddress ia : l) {
  244. if (!ia.isSiteLocalAddress()) {
  245. ret.add(ia);
  246. } else {
  247. logger.debug("Discarded " + ia + " because of the no private criteria");
  248. }
  249. }
  250. return ret;
  251. }
  252. private List<InetAddress> filterLoopback(List<InetAddress> l) {
  253. if (!CentralPAPropertyRepository.PA_NET_NOLOOPBACK.isSet() ||
  254. !CentralPAPropertyRepository.PA_NET_NOLOOPBACK.isTrue()) {
  255. // All InetAddress match
  256. return new LinkedList<InetAddress>(l);
  257. }
  258. List<InetAddress> ret = new LinkedList<InetAddress>();
  259. for (InetAddress ia : l) {
  260. if (!ia.isLoopbackAddress()) {
  261. ret.add(ia);
  262. } else {
  263. logger.debug("Discarded " + ia + " because of the no loopback criteria");
  264. }
  265. }
  266. return ret;
  267. }
  268. private List<InetAddress> filterByNetmask(List<InetAddress> l) {
  269. if (!CentralPAPropertyRepository.PA_NET_NETMASK.isSet()) {
  270. // All InetAddress match
  271. return new LinkedList<InetAddress>(l);
  272. }
  273. IPMatcher matcher;
  274. try {
  275. matcher = new IPMatcher(CentralPAPropertyRepository.PA_NET_NETMASK.getValue());
  276. } catch (Throwable e) {
  277. logger.fatal("Invalid format for property " +
  278. CentralPAPropertyRepository.PA_NET_NETMASK.getName() + ". Must be xxx.xxx.xxx.xxx/xx");
  279. return new LinkedList<InetAddress>();
  280. }
  281. List<InetAddress> ret = new LinkedList<InetAddress>();
  282. for (InetAddress ia : l) {
  283. if (!(ia instanceof Inet6Address)) {
  284. if (matcher.match(ia)) {
  285. ret.add(ia);
  286. } else {
  287. logger.debug("Discarded " + ia +
  288. " because of netmask criteria is not compatible with IPv6");
  289. }
  290. } else {
  291. logger.debug("Discarded " + ia + " because of the netmask criteria");
  292. }
  293. }
  294. return ret;
  295. }
  296. static private class IPMatcher {
  297. final private int networkPortion;
  298. final private int mask;
  299. public IPMatcher(String str) throws Throwable {
  300. String[] array = str.split("/");
  301. if (array.length != 2)
  302. throw new IllegalArgumentException("Invalid string, xxx.xxx.xxx.xxx/xx expected");
  303. int ip = stringToInt(array[0]);
  304. int significantBits = Integer.parseInt(array[1]);
  305. this.mask = computeMask(ip, significantBits);
  306. this.networkPortion = ip & this.mask;
  307. }
  308. private int computeMask(int ip, int mask) {
  309. int shift = Integer.SIZE - mask;
  310. return (~0 >> shift) << shift;
  311. }
  312. public boolean match(String ip) throws Exception {
  313. return match(stringToInt(ip));
  314. }
  315. public boolean match(InetAddress ia) {
  316. try {
  317. return match(stringToInt(ia.getHostAddress()));
  318. } catch (Exception e) {
  319. ProActiveLogger.logImpossibleException(logger, e);
  320. return false;
  321. }
  322. }
  323. public boolean match(int ip) throws Exception {
  324. return (ip & mask) == networkPortion;
  325. }
  326. private static String getBits(int value) {
  327. int displayMask = 1 << 31;
  328. StringBuffer buf = new StringBuffer(35);
  329. for (int c = 1; c <= 32; c++) {
  330. buf.append((value & displayMask) == 0 ? '0' : '1');
  331. value <<= 1;
  332. if (c % 8 == 0)
  333. buf.append(' ');
  334. }
  335. return buf.toString();
  336. }
  337. private int stringToInt(String ip) throws Exception {
  338. String[] parts = ip.split("\\.");
  339. int tmp = 0;
  340. for (int i = 0; i < parts.length; i++) {
  341. int parsedInt = Integer.parseInt(parts[i]);
  342. if (parsedInt > 255 || parsedInt < 0) {
  343. throw new Exception("An octet must be a number between 0 and 255.");
  344. }
  345. tmp |= parsedInt << ((3 - i) * 8);
  346. }
  347. return tmp;
  348. }
  349. }
  350. }