PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/server/src/main/java/org/jboss/as/server/services/net/NetworkInterfaceService.java

https://github.com/tomathome/jboss-as
Java | 267 lines | 193 code | 23 blank | 51 comment | 41 complexity | 570e8fddf57ae20b644ce3c26f365128 MD5 | raw file
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2010, Red Hat Inc., and individual contributors as indicated
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.jboss.as.server.services.net;
  23. import java.net.Inet4Address;
  24. import java.net.Inet6Address;
  25. import java.net.InetAddress;
  26. import java.net.NetworkInterface;
  27. import java.net.SocketException;
  28. import java.net.UnknownHostException;
  29. import java.util.ArrayList;
  30. import java.util.Collection;
  31. import java.util.Collections;
  32. import java.util.Enumeration;
  33. import java.util.HashSet;
  34. import java.util.Set;
  35. import org.jboss.as.controller.interfaces.InterfaceCriteria;
  36. import org.jboss.as.controller.interfaces.ParsedInterfaceCriteria;
  37. import org.jboss.as.network.NetworkInterfaceBinding;
  38. import org.jboss.logging.Logger;
  39. import org.jboss.msc.service.Service;
  40. import org.jboss.msc.service.ServiceName;
  41. import org.jboss.msc.service.StartContext;
  42. import org.jboss.msc.service.StartException;
  43. import org.jboss.msc.service.StopContext;
  44. /**
  45. * Service resolving the {@code NetworkInterfaceBinding} based on the configured interfaces in the domain model.
  46. *
  47. * @author Emanuel Muckenhuber Scott stark (sstark@redhat.com) (C) 2011 Red Hat Inc.
  48. */
  49. public class NetworkInterfaceService implements Service<NetworkInterfaceBinding> {
  50. private static Logger log = Logger.getLogger("org.jboss.as.server.net");
  51. /** The service base name. */
  52. public static final ServiceName JBOSS_NETWORK_INTERFACE = ServiceName.JBOSS.append("network");
  53. private static final boolean preferIPv4Stack = Boolean.getBoolean("java.net.preferIPv4Stack");
  54. private static final boolean preferIPv6Stack = Boolean.getBoolean("java.net.preferIPv6Addresses");
  55. private static final String IPV4_ANYLOCAL = "0.0.0.0";
  56. private static final String IPV6_ANYLOCAL = "::";
  57. /** The interface binding. */
  58. private NetworkInterfaceBinding interfaceBinding;
  59. private final String name;
  60. private final boolean anyLocalV4;
  61. private final boolean anyLocalV6;
  62. private final boolean anyLocal;
  63. private final InterfaceCriteria criteria;
  64. public static Service<NetworkInterfaceBinding> create(String name, ParsedInterfaceCriteria criteria) {
  65. return new NetworkInterfaceService(name, criteria.isAnyLocalV4(), criteria.isAnyLocalV6(), criteria.isAnyLocal(),
  66. new OverallInterfaceCriteria(criteria.getCriteria()));
  67. }
  68. public NetworkInterfaceService(final String name, final boolean anyLocalV4, final boolean anyLocalV6,
  69. final boolean anyLocal, final InterfaceCriteria criteria) {
  70. this.name = name;
  71. this.anyLocalV4 = anyLocalV4;
  72. this.anyLocalV6 = anyLocalV6;
  73. this.anyLocal = anyLocal;
  74. this.criteria = criteria;
  75. }
  76. public synchronized void start(StartContext arg0) throws StartException {
  77. log.debug("Starting NetworkInterfaceService\n");
  78. try {
  79. this.interfaceBinding = createBinding(name, anyLocalV4, anyLocalV6, anyLocal, criteria);
  80. } catch (Exception e) {
  81. throw new StartException(e);
  82. }
  83. if (this.interfaceBinding == null) {
  84. throw new StartException("failed to resolve interface " + name);
  85. }
  86. log.debugf("NetworkInterfaceService matched interface binding: %s\n", interfaceBinding);
  87. }
  88. public static NetworkInterfaceBinding createBinding(String name, ParsedInterfaceCriteria criteria) throws SocketException,
  89. UnknownHostException {
  90. return createBinding(name, criteria.isAnyLocalV4(), criteria.isAnyLocalV6(), criteria.isAnyLocal(),
  91. new OverallInterfaceCriteria(criteria.getCriteria()));
  92. }
  93. static NetworkInterfaceBinding createBinding(final String name, final boolean anyLocalV4, final boolean anyLocalV6,
  94. final boolean anyLocal, final InterfaceCriteria criteria) throws SocketException, UnknownHostException {
  95. if (anyLocalV4) {
  96. return getNetworkInterfaceBinding(IPV4_ANYLOCAL);
  97. } else if (anyLocalV6) {
  98. return getNetworkInterfaceBinding(IPV6_ANYLOCAL);
  99. } else if (anyLocal) {
  100. return getNetworkInterfaceBinding(preferIPv4Stack ? IPV4_ANYLOCAL : IPV6_ANYLOCAL);
  101. } else {
  102. return resolveInterface(criteria);
  103. }
  104. }
  105. public synchronized void stop(StopContext arg0) {
  106. this.interfaceBinding = null;
  107. }
  108. public synchronized NetworkInterfaceBinding getValue() throws IllegalStateException {
  109. final NetworkInterfaceBinding binding = this.interfaceBinding;
  110. if (binding == null) {
  111. throw new IllegalStateException();
  112. }
  113. return binding;
  114. }
  115. static NetworkInterfaceBinding resolveInterface(final InterfaceCriteria criteria) throws SocketException {
  116. NetworkInterfaceBinding result = null;
  117. final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
  118. log.tracef("resolveInterface, checking criteria: %s\n", criteria);
  119. while (result == null && networkInterfaces.hasMoreElements()) {
  120. final NetworkInterface networkInterface = networkInterfaces.nextElement();
  121. result = resolveInterface(criteria, networkInterface);
  122. if (result == null) {
  123. final Enumeration<NetworkInterface> subInterfaces = networkInterface.getSubInterfaces();
  124. while (result == null && subInterfaces.hasMoreElements()) {
  125. final NetworkInterface subInterface = subInterfaces.nextElement();
  126. result = resolveInterface(criteria, subInterface);
  127. }
  128. }
  129. }
  130. return result;
  131. }
  132. private static NetworkInterfaceBinding resolveInterface(final InterfaceCriteria criteria,
  133. final NetworkInterface networkInterface) throws SocketException {
  134. log.tracef("resolveInterface, checking NetworkInterface: %s\n", toString(networkInterface));
  135. final Enumeration<InetAddress> interfaceAddresses = networkInterface.getInetAddresses();
  136. while (interfaceAddresses.hasMoreElements()) {
  137. final InetAddress address = interfaceAddresses.nextElement();
  138. if (preferIPv4Stack && !preferIPv6Stack && !(address instanceof Inet4Address)) {
  139. continue;
  140. } else if (preferIPv6Stack && !preferIPv4Stack && !(address instanceof Inet6Address)) {
  141. continue;
  142. }
  143. log.tracef("Checking interface(name=%s,address=%s), criteria=%s\n", networkInterface.getName(), address, criteria);
  144. InetAddress bindAddress = criteria.isAcceptable(networkInterface, address);
  145. if (bindAddress != null) {
  146. log.tracef("Criteria provided bind address: %s\n", bindAddress);
  147. return new NetworkInterfaceBinding(Collections.singleton(networkInterface), bindAddress);
  148. }
  149. }
  150. return null;
  151. }
  152. static NetworkInterfaceBinding getNetworkInterfaceBinding(final String addr) throws UnknownHostException, SocketException {
  153. final InetAddress address = InetAddress.getByName(addr);
  154. final Collection<NetworkInterface> interfaces = new ArrayList<NetworkInterface>();
  155. final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
  156. while (networkInterfaces.hasMoreElements()) {
  157. interfaces.add(networkInterfaces.nextElement());
  158. }
  159. return new NetworkInterfaceBinding(interfaces, address);
  160. }
  161. /** Overall interface criteria. */
  162. static final class OverallInterfaceCriteria implements InterfaceCriteria {
  163. private static final long serialVersionUID = -5417786897309925997L;
  164. private final Set<InterfaceCriteria> interfaceCriteria;
  165. public OverallInterfaceCriteria(Set<InterfaceCriteria> criteria) {
  166. interfaceCriteria = criteria;
  167. }
  168. /**
  169. * Loop through associated criteria and build a unique address as follows: 1. Iterate through all criteria, returning
  170. * null if any criteria return a null result from
  171. * {@linkplain #isAcceptable(java.net.NetworkInterface, java.net.InetAddress)}. 2. Collect the accepted addressed into a
  172. * Set. 3. If the set contains a single address, this is returned as the criteria match. 4. If there are more than 2
  173. * addresses, log a warning and return null to indicate no match was agreed on. 5. If there are 2 addresses, remove the
  174. * input address and if the resulting set has only one address, return it as the criteria match. Otherwise, log a
  175. * warning indicating 2 unique criteria addresses were seen and return null to indicate no match was agreed on.
  176. *
  177. * @return the unique address determined by the all criteria, null if no such address was found
  178. * @throws SocketException
  179. */
  180. @Override
  181. public InetAddress isAcceptable(NetworkInterface networkInterface, InetAddress address) throws SocketException {
  182. // Build up a set of unique addresses from the criteria
  183. HashSet<InetAddress> addresses = new HashSet<InetAddress>();
  184. for (InterfaceCriteria criteria : interfaceCriteria) {
  185. InetAddress bindAddress = criteria.isAcceptable(networkInterface, address);
  186. if (bindAddress == null) {
  187. log.debugf("Criteria(%s) failed to accept input\n", criteria);
  188. return null;
  189. }
  190. log.tracef("%s accepted input, provided bind address: %s", criteria, bindAddress);
  191. addresses.add(bindAddress);
  192. }
  193. log.debugf("Candidate accepted addresses are: %s\n", addresses);
  194. // Determine which address to return
  195. InetAddress bindAddress = null;
  196. if (addresses.size() > 0) {
  197. log.tracef("Determining unique address from among: %s\n", addresses.toString());
  198. if (addresses.size() == 1)
  199. bindAddress = addresses.iterator().next();
  200. else {
  201. // Remove the input address and see if non-unique addresses exist
  202. if (addresses.size() > 2)
  203. log.warnf("More than two unique criteria addresses were seen: %s\n", addresses.toString());
  204. else {
  205. log.warnf("Checking two unique criteria addresses were seen: %s\n", addresses.toString());
  206. addresses.remove(address);
  207. if (addresses.size() == 1)
  208. bindAddress = addresses.iterator().next();
  209. else
  210. log.warnf("Two unique criteria addresses were seen: %s\n", addresses.toString());
  211. }
  212. }
  213. }
  214. return bindAddress;
  215. }
  216. public String toString() {
  217. StringBuilder sb = new StringBuilder("OverallInterfaceCriteria(");
  218. for (InterfaceCriteria criteria : interfaceCriteria) {
  219. sb.append(criteria.toString());
  220. sb.append(",");
  221. }
  222. sb.setLength(sb.length() - 1);
  223. sb.append(")");
  224. return sb.toString();
  225. }
  226. }
  227. /**
  228. * A little toString utility for NetworkInterface since its version seems to add the hardware address and this corrupts
  229. * logging output.
  230. *
  231. * @param iface The interface to convert to string format.
  232. * @return toString for NetworkInterface
  233. */
  234. static String toString(NetworkInterface iface) {
  235. StringBuilder sb = new StringBuilder("NetworkInterface(");
  236. sb.append("name:");
  237. sb.append(iface.getName());
  238. sb.append("(");
  239. sb.append(iface.getDisplayName());
  240. sb.append("), addresses:");
  241. sb.append(iface.getInterfaceAddresses());
  242. return sb.toString();
  243. }
  244. }