/* * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. * * The Sun Project JXTA(TM) Software License * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowledgment: "This product includes software * developed by Sun Microsystems, Inc. for JXTA(TM) technology." * Alternately, this acknowledgment may appear in the software itself, if * and wherever such third-party acknowledgments normally appear. * * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must * not be used to endorse or promote products derived from this software * without prior written permission. For written permission, please contact * Project JXTA at http://www.jxta.org. * * 5. Products derived from this software may not be called "JXTA", nor may * "JXTA" appear in their name, without prior written permission of Sun. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * JXTA is a registered trademark of Sun Microsystems, Inc. in the United * States and other countries. * * Please see the license information page at : * <http://www.jxta.org/project/www/license.html> for instructions on use of * the license in source files. * * ==================================================================== * * This software consists of voluntary contributions made by many individuals * on behalf of Project JXTA. For more information on Project JXTA, please see * http://www.jxta.org. * * This license is based on the BSD license adopted by the Apache Foundation. */ package net.jxta.impl.peergroup; import net.jxta.document.AdvertisementFactory; import net.jxta.document.MimeMediaType; import net.jxta.document.StructuredDocumentFactory; import net.jxta.document.StructuredDocumentUtils; import net.jxta.document.XMLDocument; import net.jxta.document.XMLElement; import net.jxta.exception.ConfiguratorException; import net.jxta.impl.endpoint.IPUtils; import net.jxta.impl.protocol.HTTPAdv; import net.jxta.impl.protocol.PSEConfigAdv; import net.jxta.impl.protocol.PlatformConfig; import net.jxta.impl.protocol.RdvConfigAdv; import net.jxta.impl.protocol.RelayConfigAdv; import net.jxta.impl.protocol.TCPAdv; import net.jxta.logging.Logging; import net.jxta.peergroup.PeerGroup; import net.jxta.protocol.TransportAdvertisement; import java.net.InetAddress; import java.net.URI; import java.util.Enumeration; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; /** * A simple platform configurator. This implementation provides reasonable * automatic configuration for edge peers on the JXTA public network. * <p/> * This implementation will read default values from several Java system * properties as appropriate: * <p/> * jxta.peer.name -- The peer name to use. * jxta.http.port -- The http port to use. * jxta.tcp.port -- The tcp port to use. * * @see net.jxta.peergroup.Configurator */ public class AutomaticConfigurator extends NullConfigurator { /** * Log4J logger */ private final static transient Logger LOG = Logger.getLogger(AutomaticConfigurator.class.getName()); /** * Configures the platform using the specified directory. * @param jxtaHome store home URI * @throws net.jxta.exception.ConfiguratorException if a configuration error occurs */ public AutomaticConfigurator(URI jxtaHome) throws ConfiguratorException { super(jxtaHome); } /** * {@inheritDoc} */ @Override public PlatformConfig getPlatformConfig() throws ConfiguratorException { super.getPlatformConfig(); boolean reconf; try { reconf = buildPlatformConfig(); } catch (RuntimeException serious) { if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { LOG.log(Level.SEVERE, "Trouble while fixing PlatformConfig. Hope for the best.", serious); } reconf = true; } // See if we need a reconf if (reconf) { throw new IncompleteConfigurationException("Damaged platform configuration."); } // Save the updated config. save(); return advertisement; } /** * Makes sure a PlatformConfig is present and if not, creates one. * <p/> * Performs some checking of PlatformConfig values and will fix some * minor configuration problems automatically. * * @return If <tt>true</tt> then manual reconfiguration (of some form) is required. */ private boolean buildPlatformConfig() { boolean reconf = false; if (advertisement == null) { if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("New PlatformConfig Advertisement"); } advertisement = (PlatformConfig) AdvertisementFactory.newAdvertisement(PlatformConfig.getAdvertisementType()); advertisement.setDescription("Platform Config Advertisement created by : " + AutomaticConfigurator.class.getName()); } // Set the peer name String peerName = advertisement.getName(); if ((null == peerName) || (0 == peerName.trim().length())) { String jpn = System.getProperty("jxta.peer.name", ""); if (0 != jpn.trim().length()) { advertisement.setName(jpn); } } // Check the HTTP Message Transport parameters. XMLDocument http = (XMLDocument) advertisement.getServiceParam(PeerGroup.httpProtoClassID); HTTPAdv httpAdv = null; boolean httpEnabled = true; if (http != null) { try { httpEnabled = advertisement.isSvcEnabled(PeerGroup.httpProtoClassID); XMLElement param = null; Enumeration httpChilds = http.getChildren(TransportAdvertisement.getAdvertisementType()); // get the HTTPAdv from TransportAdv if (httpChilds.hasMoreElements()) { param = (XMLElement) httpChilds.nextElement(); } if (null != param) { httpAdv = (HTTPAdv) AdvertisementFactory.newAdvertisement(param); if (httpEnabled) { // check if the interface address is still valid. String intf = httpAdv.getInterfaceAddress(); if ((null != intf) && !isValidInetAddress(intf)) { reconf = true; if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("Reconfig requested - invalid interface address"); } } } } } catch (RuntimeException advTrouble) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "HTTP advertisement corrupted", advTrouble); } httpAdv = null; } } if (httpAdv == null) { if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("HTTP advertisement missing, making a new one."); } int port = 0; // get the port from a property String httpPort = System.getProperty("jxta.http.port"); if (httpPort != null) { try { int propertyPort = Integer.parseInt(httpPort); if ((propertyPort < 65536) && (propertyPort >= 0)) { port = propertyPort; } else { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.warning("Property \'jxta.http.port\' is not a valid port number : " + propertyPort); } } } catch (NumberFormatException ignored) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.warning("Property \'jxta.http.port\' was not an integer : " + http); } } } httpAdv = (HTTPAdv) AdvertisementFactory.newAdvertisement(HTTPAdv.getAdvertisementType()); httpAdv.setProtocol("http"); httpAdv.setPort(port); httpAdv.setServerEnabled(false); } // Create new param docs that contain the updated adv http = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); XMLDocument httAdvDoc = (XMLDocument) httpAdv.getDocument(MimeMediaType.XMLUTF8); StructuredDocumentUtils.copyElements(http, http, httAdvDoc); if (!httpEnabled) { http.appendChild(http.createElement("isOff")); } advertisement.putServiceParam(PeerGroup.httpProtoClassID, http); // Check the TCP Message Transport parameters. XMLDocument tcp = (XMLDocument) advertisement.getServiceParam(PeerGroup.tcpProtoClassID); TCPAdv tcpAdv = null; boolean tcpEnabled = true; if (tcp != null) { try { tcpEnabled = advertisement.isSvcEnabled(PeerGroup.tcpProtoClassID); XMLElement param = null; Enumeration tcpChilds = tcp.getChildren(TransportAdvertisement.getAdvertisementType()); // get the TransportAdv if (tcpChilds.hasMoreElements()) { param = (XMLElement) tcpChilds.nextElement(); } if (null != param) { tcpAdv = (TCPAdv) AdvertisementFactory.newAdvertisement(param); if (tcpEnabled) { String intf = tcpAdv.getInterfaceAddress(); if ((null != intf) && !isValidInetAddress(intf)) { reconf = true; if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("Reconfig requested - invalid interface address"); } } } } } catch (RuntimeException advTrouble) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "TCP advertisement corrupted", advTrouble); } tcpAdv = null; } } if (tcpAdv == null) { if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("TCP advertisement missing, making a new one."); } int port = 0; // get the port from a property String tcpPort = System.getProperty("jxta.tcp.port"); if (tcpPort != null) { try { int propertyPort = Integer.parseInt(tcpPort); if ((propertyPort < 65536) && (propertyPort >= 0)) { port = propertyPort; } else { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.warning("Property \'jxta.tcp.port\' is not a valid port number : " + propertyPort); } } } catch (NumberFormatException ignored) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.warning("Property \'jxta.tcp.port\' was not an integer : " + tcpPort); } } } tcpAdv = (TCPAdv) AdvertisementFactory.newAdvertisement(TCPAdv.getAdvertisementType()); tcpAdv.setProtocol("tcp"); tcpAdv.setPort(port); tcpAdv.setMulticastAddr("224.0.1.85"); tcpAdv.setMulticastPort(1234); tcpAdv.setMulticastSize(16384); tcpAdv.setMulticastState(true); } tcp = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); StructuredDocumentUtils.copyElements(tcp, tcp, (XMLDocument) tcpAdv.getDocument(MimeMediaType.XMLUTF8)); if (!tcpEnabled) { tcp.appendChild(tcp.createElement("isOff")); } advertisement.putServiceParam(PeerGroup.tcpProtoClassID, tcp); // Check the relay config RelayConfigAdv relayConfig = null; try { XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.relayProtoClassID); if (param != null) { // XXX 20041027 backwards compatibility param.addAttribute("type", RelayConfigAdv.getAdvertisementType()); relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(param); } } catch (Exception failure) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "Problem reading relay configuration", failure); } } if (null == relayConfig) { if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("Relay Config advertisement missing, making a new one."); } // restore default values. relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(RelayConfigAdv.getAdvertisementType()); // Enable relay if any transport doesn't support incoming. if (!tcpAdv.isServerEnabled() || !httpAdv.isServerEnabled()) { relayConfig.setClientEnabled(true); } } /* if( (0 == relayConfig.getSeedingURIs().length) && (0 == relayConfig.getSeedRelays().length) && !relayConfig.isServerEnabled() ) { // add the default relay seeding peer. relayConfig.addSeedingURI( "http://rdv.jxtahosts.net/cgi-bin/relays.cgi?3" ); } */ XMLDocument relayDoc = (XMLDocument) relayConfig.getDocument(MimeMediaType.XMLUTF8); advertisement.putServiceParam(PeerGroup.relayProtoClassID, relayDoc); // Check Rendezvous Configuration RdvConfigAdv rdvAdv = null; try { XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.rendezvousClassID); if (param != null) { // XXX 20041027 backwards compatibility param.addAttribute("type", RdvConfigAdv.getAdvertisementType()); rdvAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(param); } } catch (Exception failure) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "Problem reading rendezvous configuration", failure); } } if (null == rdvAdv) { if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("Rdv Config advertisement missing, making a new one."); } // restore default values. rdvAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType()); } /* if( (0 == rdvAdv.getSeedingURIs().length) && (0 == rdvAdv.getSeedRendezvous().length) && (RdvConfigAdv.RendezVousConfiguration.RENDEZVOUS != rdvAdv.getConfiguration()) && (RdvConfigAdv.RendezVousConfiguration.AD_HOC != rdvAdv.getConfiguration()) && !relayConfig.isClientEnabled() ) { // add the default rendezvous seeding peer if we don't know of any rendezvous, aren't a rendezvous ourselves, aren't in ad-hoc mode or using a relay. rdvAdv.addSeedingURI( "http://rdv.jxtahosts.net/cgi-bin/rendezvous.cgi?3" ); } */ XMLDocument rdvDoc = (XMLDocument) rdvAdv.getDocument(MimeMediaType.XMLUTF8); advertisement.putServiceParam(PeerGroup.rendezvousClassID, rdvDoc); // if no proxy param section, disable it. XMLDocument proxy = (XMLDocument) advertisement.getServiceParam(PeerGroup.proxyClassID); if (null == proxy) { if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("Proxy config advertisement missing, making a new one."); } proxy = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); proxy.appendChild(proxy.createElement("isOff")); advertisement.putServiceParam(PeerGroup.proxyClassID, proxy); } // Check the PSE Configuration PSEConfigAdv pseConfig = null; try { XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.membershipClassID); if (param != null) { // XXX 20041027 backwards compatibility param.addAttribute("type", PSEConfigAdv.getAdvertisementType()); pseConfig = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(param); } } catch (Exception failure) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "Problem reading pse configuration", failure); } } if (null == pseConfig) { if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { LOG.config("PSE Config advertisement missing, making a new one."); } // restore default values. pseConfig = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(PSEConfigAdv.getAdvertisementType()); XMLDocument pseDoc = (XMLDocument) pseConfig.getDocument(MimeMediaType.XMLUTF8); advertisement.putServiceParam(PeerGroup.membershipClassID, pseDoc); } // If we did not modify anything of importance or see anything wrong, // leave the adv alone. return reconf; } private boolean isValidInetAddress(String address) { boolean found = false; boolean loopback; InetAddress[] ias; try { ias = InetAddress.getAllByName(address); } catch (java.net.UnknownHostException notfound) { return false; } for (Iterator la = IPUtils.getAllLocalAddresses().iterator(); la.hasNext() && !found;) { for (InetAddress ia1 : ias) { found |= ia1.equals(la.next()); } } loopback = true; for (InetAddress ia1 : ias) { loopback &= ia1.isLoopbackAddress(); } return found || loopback; } }