/*******************************************************************************
* Copyright (c) 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.orion.internal.server.hosting;
import java.net.*;
import java.util.*;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.orion.server.core.LogHelper;
/**
* Stores the list of host names that may be allocated to hosted sites.The server administrator can control
* the host name configuration by setting a configuration property for the Orion server.<p>
*
* The property's value is a comma-separated list where each entry describes either a domain name
* (which may include wildcards), or an IP address. Each entry in the list becomes the name of a
* virtual host that a site can be served on. Wildcard domains can be used to serve many different
* virtual hosts as subdomains of the wildcard domain.
*
* Examples:
* <dl>
* <dt><code>site.myorion.net</code></dt>
* <dd>Makes 1 host name, <code>site.myorion.net</code>, available for allocation as a virtual host name.</dd>
*
* <dt><code>127.0.0.2,127.0.0.3</code></dt>
* <dd>Makes the 2 IP addresses available as virtual host names. Since they happen to be loopback addresses,
* any hosted site assigned to them will not be accessible by remote users.</dd>
*
* <dt><code>*.myorion.net</code></dt>
* <dd>Makes all of <code>*.myorion.net</code> available for allocation. Sites will be given subdomains,
* for example <code>site1.myorion.net</code>, <code>site2.myorion.net</code>, etc.</dd>
*
* <dt><code>foo.myorion.net,*.myorion.net</code></dt>
* <dd>The domains will be allocated in the order provided: first <code>foo.myorion.net</code>, then
* subdomains of <code>myorion.net</code>.</dd>
* </dl>
*/
public class SiteHostingConfig {
private static final int DEFAULT_HOST_COUNT = 16;
private List<String> hosts;
private SiteHostingConfig(List<String> hosts) {
this.hosts = hosts;
}
/**
* @return An unmodifiable view of all hosts in the configuration, in the same order as the
* user provided them, and not checked for duplicate entries.
*/
public List<String> getHosts() {
return Collections.unmodifiableList(hosts);
}
/**
* @param hostInfo String containing the user-supplied site configuration info.
* @return A hosting configuration parsed from <code>hostInfo</code>. If <code>vhostInfo</code>
* is <code>null</code>, returns a default configuration.
*/
public static SiteHostingConfig getSiteHostingConfig(String hostInfo) {
return hostInfo == null ? getDefault() : fromString(hostInfo);
}
/**
* Parses a SiteHostingConfig from the <code>hostInfo</code> string.
*/
private static SiteHostingConfig fromString(String hostInfo) {
List<String> hosts = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(hostInfo, ", "); //$NON-NLS-1$
if (!st.hasMoreTokens()) {
LogHelper.log(new Status(IStatus.ERROR, HostingActivator.PI_SERVER_HOSTING, "Empty hosting configuration", null));
}
for (; st.hasMoreTokens();) {
String token = st.nextToken();
hosts.add(token);
}
return new SiteHostingConfig(hosts);
}
/**
* @return A default SiteHostingConfig based on the platform and network setup. If possible,
* the config will include some IP addresses that point to the loopback device.
*/
private static SiteHostingConfig getDefault() {
List<String> aliases = new ArrayList<String>();
// TODO: this guessing is fragile and only useful for self-hosting. Is it really useful?
if (System.getProperty("os.name").startsWith("Mac OS X")) { //$NON-NLS-1$ //$NON-NLS-2$
// In OS X, although all 127.x.x.x addresses report isLoopback() == true, only 127.0.0.1
// actually routes to localhost. So we can't do much here.
} else {
InetAddress loopbackIp = getLoopbackAddress();
try {
// Allocate some more loopback IPs
byte[] address = loopbackIp.getAddress();
byte lastByte = address[address.length - 1];
for (int i = 0, b = lastByte + 1; i < DEFAULT_HOST_COUNT && b <= 0xff; i++, b++) {
byte[] derivedAddress = address.clone();
derivedAddress[address.length - 1] = (byte) b;
aliases.add(InetAddress.getByAddress(derivedAddress).getHostAddress());
}
} catch (UnknownHostException e) {
// Should not happen
LogHelper.log(new Status(IStatus.ERROR, HostingActivator.PI_SERVER_HOSTING, e.getMessage(), e));
}
}
return new SiteHostingConfig(aliases);
}
/**
* @return The IPv4 loopback device, or null if it couldn't be determined.
*/
private static InetAddress getLoopbackAddress() {
try {
for (NetworkInterface interfaze : Collections.list(NetworkInterface.getNetworkInterfaces())) {
if (interfaze.isLoopback()) {
for (InetAddress address : Collections.list(interfaze.getInetAddresses())) {
if (address instanceof Inet4Address) {
return address;
}
}
}
}
} catch (SocketException e) {
LogHelper.log(new Status(IStatus.ERROR, HostingActivator.PI_SERVER_HOSTING, e.getMessage(), e));
}
return null;
}
}