package edu.washington.cs.oneswarm.ui.gwt; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.Principal; import java.util.logging.Logger; import org.gudy.azureus2.core3.config.COConfigurationManager; import org.gudy.azureus2.core3.config.ParameterListener; import org.gudy.azureus2.core3.util.Constants; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.SystemProperties; import org.gudy.azureus2.plugins.Plugin; import org.gudy.azureus2.plugins.PluginException; import org.gudy.azureus2.plugins.PluginInterface; import org.mortbay.jetty.Connector; import org.mortbay.jetty.Handler; import org.mortbay.jetty.NCSARequestLog; import org.mortbay.jetty.Request; import org.mortbay.jetty.Response; import org.mortbay.jetty.Server; import org.mortbay.jetty.handler.ContextHandlerCollection; import org.mortbay.jetty.handler.HandlerCollection; import org.mortbay.jetty.handler.RequestLogHandler; import org.mortbay.jetty.nio.SelectChannelConnector; import org.mortbay.jetty.security.Constraint; import org.mortbay.jetty.security.ConstraintMapping; import org.mortbay.jetty.security.Credential; import org.mortbay.jetty.security.HashUserRealm; import org.mortbay.jetty.security.SecurityHandler; import org.mortbay.jetty.servlet.Context; import org.mortbay.jetty.servlet.FilterHolder; import org.mortbay.servlet.GzipFilter; import org.mortbay.thread.BoundedThreadPool; import org.mortbay.thread.QueuedThreadPool; import edu.washington.cs.oneswarm.HealthChecker; import edu.washington.cs.oneswarm.f2f.ExperimentalHarnessManager; import edu.washington.cs.oneswarm.f2f.multisource.Sha1HashManager; import edu.washington.cs.oneswarm.f2f.multisource.Sha1HashManager.Sha1CalcListener; import edu.washington.cs.oneswarm.f2f.multisource.Sha1HashManager.Sha1HashJobListener; import edu.washington.cs.oneswarm.f2f.multisource.Sha1HashManager.Sha1Result; import edu.washington.cs.oneswarm.ui.gwt.rpc.BackendTask; import edu.washington.cs.oneswarm.ui.gwt.rpc.OneSwarmConstants; import edu.washington.cs.oneswarm.ui.gwt.server.BackendTaskManager; import edu.washington.cs.oneswarm.ui.gwt.server.BackendTaskManager.CancellationListener; import edu.washington.cs.oneswarm.ui.gwt.server.community.CommunityServerManager; import edu.washington.cs.oneswarm.ui.gwt.server.handlers.MultiHandler; public class OsgwtuiMain implements Plugin { public static final String LOCALHOST = "127.0.0.1"; private Server authenticatedServer; private CoreInterface coreInterface; private PluginInterface pluginInterface; private RemoteAccessForward remoteAccessForward = null; private Server server; private synchronized void disableRemoteAccess() { if (remoteAccessForward != null) { System.out.println("disabling remote accesss"); try { authenticatedServer.stop(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } remoteAccessForward.stop(); remoteAccessForward = null; } coreInterface.setRemoteAccess(remoteAccessForward); } private static Logger logger = Logger.getLogger(OsgwtuiMain.class.getName()); private synchronized void enableRemoteAccess() throws Exception { if (remoteAccessForward == null) { logger.fine("enabling remote access"); Connector connector = new SelectChannelConnector(); connector.setHost(LOCALHOST); connector.setPort(Constants.LOCAL_WEB_SERVER_PORT_AUTH); authenticatedServer = new Server(); authenticatedServer.addConnector(connector); // sets the thread pool (just so it is deamon=true) QueuedThreadPool threadPool = new QueuedThreadPool(); threadPool.setMinThreads(5); // threadPool.setMaxThreads(10); threadPool.setName("Auth Jetty thread pool"); threadPool.setDaemon(true); authenticatedServer.setThreadPool(threadPool); Constraint constraint = new Constraint(); constraint.setName(Constraint.__BASIC_AUTH); constraint.setRoles(new String[] { "remote_user" }); constraint.setAuthenticate(true); ConstraintMapping cm = new ConstraintMapping(); cm.setConstraint(constraint); cm.setPathSpec("/*"); SecurityHandler securityHandler = new SecurityHandler(); securityHandler.setUserRealm(new ExtraSaltHashUserRealm(RemoteAccessConfig .usesMD5Sha1Password(), "OneSwarm Remote", RemoteAccessConfig.REMOTE_ACCESS_FILE.getCanonicalPath())); securityHandler.setConstraintMappings(new ConstraintMapping[] { cm }); ContextHandlerCollection contexts = new ContextHandlerCollection(); authenticatedServer.setHandler(contexts); Context root = new Context(contexts, "/", Context.NO_SESSIONS); root.addFilter(new FilterHolder(new GzipFilter()), "/*", Handler.ALL); MultiHandler mh = new MultiHandler(coreInterface, true); if (System.getProperty("com.sun.management.jmxremote") != null) { RequestLogHandler requestLogHandler = new RequestLogHandler(); NCSARequestLog requestLog = new NCSARequestLog( "/tmp/jetty-yyyy_mm_dd.remoterequest.log"); requestLog.setRetainDays(1); requestLog.setAppend(false); requestLog.setExtended(true); requestLog.setLogTimeZone("GMT"); requestLogHandler.setRequestLog(requestLog); HandlerCollection handlers = new HandlerCollection(); handlers.setHandlers(new Handler[] { mh, requestLogHandler }); root.setHandler(handlers); } else { root.setHandler(mh); } root.addHandler(securityHandler); // make sure that the class loader can find all classes in the // osgwtui // plugin dir... root.setClassLoader(pluginInterface.getPluginClassLoader()); authenticatedServer.start(); remoteAccessForward = new RemoteAccessForward(); remoteAccessForward.start(); logger.fine("remote access enabled"); } coreInterface.setRemoteAccess(remoteAccessForward); } public CoreInterface getCoreInterface() { return coreInterface; } @Override public void initialize(PluginInterface pluginInterface) throws PluginException { this.coreInterface = new CoreInterface(pluginInterface); // make sure to unload in case of shutdown this.pluginInterface = pluginInterface; logger.fine("oneswarm ui plugin loaded"); Connector connector = new SelectChannelConnector(); connector.setHost(LOCALHOST); connector.setPort(Constants.LOCAL_WEB_SERVER_PORT); server = new Server(); /** * If we're running with jconsole support, start the MBean server */ if (System.getProperty("com.sun.management.jmxremote") != null) { connector.setStatsOn(true); logger.info("Starting managemenat bean"); // MBeanServer mBeanServer = // ManagementFactory.getPlatformMBeanServer(); // MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer); // server.getContainer().addEventListener(mBeanContainer); // mBeanContainer.start(); } checkAutoStartRegistry(); server.addConnector(connector); // sets the thread pool (just so it is deamon=true) BoundedThreadPool threadPool = new BoundedThreadPool(); threadPool.setMinThreads(5); // threadPool.setMaxThreads(10); threadPool.setName("Jetty thread pool"); threadPool.setDaemon(true); server.setThreadPool(threadPool); ContextHandlerCollection contexts = new ContextHandlerCollection(); server.setHandler(contexts); Context root = new Context(contexts, "/", Context.NO_SESSIONS); MultiHandler mh = new MultiHandler(coreInterface, false); if (System.getProperty("com.sun.management.jmxremote") != null) { RequestLogHandler requestLogHandler = new RequestLogHandler(); NCSARequestLog requestLog = new NCSARequestLog("/tmp/jetty-yyyy_mm_dd.request.log"); requestLog.setRetainDays(1); requestLog.setAppend(false); requestLog.setExtended(true); requestLog.setLogTimeZone("GMT"); requestLogHandler.setRequestLog(requestLog); HandlerCollection handlers = new HandlerCollection(); handlers.setHandlers(new Handler[] { mh, requestLogHandler }); root.setHandler(handlers); } else { root.setHandler(mh); } // make sure that the class loader can find all classes in the osgwtui // plugin dir... root.setClassLoader(pluginInterface.getPluginClassLoader()); root.setVirtualHosts(new String[] { LOCALHOST }); try { server.start(); if (isRemoteAccessAllowed()) { enableRemoteAccess(); } installRemoteAccessPropertyListener(); // Thread.sleep(10000); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } // Maybe initialize Experimental code for tests. ExperimentalHarnessManager ehm = ExperimentalHarnessManager.get(); ehm.setCore(coreInterface); if (ExperimentalHarnessManager.isEnabled()) { ehm.start(); } // make sure community server refreshes whether we load the web UI or // not. CommunityServerManager.get(); /* * add the listener to the sha1 hasher manager */ Sha1HashManager.getInstance().addJobListener(new Sha1HashJobListener() { @Override public Sha1CalcListener jobAdded(String name) { final int taskID = BackendTaskManager.get().createTask("Hashing: " + name, new CancellationListener() { @Override public void cancelled(int inID) { Sha1HashManager.getInstance().stop(); } }); final BackendTask task = BackendTaskManager.get().getTask(taskID); task.setSummary("Calculating SHA1 and ED2K hashes of " + name); return new Sha1CalcListener() { @Override public void progress(double fraction) { int percent = (int) Math.round(100 * fraction); task.setProgress(percent + "%"); } @Override public void errorOccured(Throwable cause) { BackendTaskManager.get().removeTask(taskID); } @Override public void completed(Sha1Result result) { BackendTaskManager.get().removeTask(taskID); } }; } }); /** * Start health checking */ HealthChecker health = new HealthChecker(); health.start(); } private void checkAutoStartRegistry() { if (Constants.isWindows) { try { /* * else, not first start sync up the setting with what is in the * windows registry */ int handle = RegUtil .RegOpenKey(RegUtil.HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", RegUtil.KEY_ALL_ACCESS)[RegUtil.NATIVE_HANDLE]; byte[] value = RegUtil.RegQueryValueEx(handle, "OneSwarm"); RegUtil.RegCloseKey(handle); if (value != null) { COConfigurationManager.setParameter("autostart", true); } else { COConfigurationManager.setParameter("autostart", false); } } catch (Exception e) { e.printStackTrace(); } // create config listener COConfigurationManager.addAndFireParameterListener("autostart", new ParameterListener() { @Override public void parameterChanged(String parameterName) { try { int handle = RegUtil.RegOpenKey(RegUtil.HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", RegUtil.KEY_ALL_ACCESS)[RegUtil.NATIVE_HANDLE]; byte[] value = RegUtil.RegQueryValueEx(handle, "OneSwarm"); boolean registryValue = value != null; if (registryValue != COConfigurationManager .getBooleanParameter("autostart")) { if (COConfigurationManager.getBooleanParameter("autostart")) { // install the registry key RegUtil.RegSetValueEx(handle, "OneSwarm", "\"" + SystemProperties.getApplicationPath() + "OneSwarm.exe\" --autostart"); } else { // remove the registry key RegUtil.RegDeleteValue(handle, "OneSwarm"); } } RegUtil.RegCloseKey(handle); } catch (Exception e) { e.printStackTrace(); } } }); } } private void installRemoteAccessPropertyListener() { COConfigurationManager.addParameterListener(OneSwarmConstants.REMOTE_ACCESS_PROPERTIES_KEY, new ParameterListener() { @Override public void parameterChanged(String parameterName) { disableRemoteAccess(); if (isRemoteAccessAllowed()) { try { enableRemoteAccess(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { disableRemoteAccess(); } } }); } private boolean isRemoteAccessAllowed() { return COConfigurationManager .getBooleanParameter(OneSwarmConstants.REMOTE_ACCESS_PROPERTIES_KEY); } public void shutdown() { logger.fine("Shutting down"); try { server.stop(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } coreInterface.shutdown(); } private static class ExtraSaltHashUserRealm extends HashUserRealm { private final boolean useSha1; public ExtraSaltHashUserRealm(boolean useSha1, String realm, String authFile) throws IOException { super(realm, authFile); this.useSha1 = useSha1; } @Override public Principal authenticate(String username, Object credentials, Request request) { try { if (useSha1) { String sha1SaltAndPassword = RemoteAccessConfig .getSaltedPassword((String) credentials); logger.finest("got authentication request: user=" + username + " salt_sha1=" + sha1SaltAndPassword); Principal principal = super .authenticate(username, sha1SaltAndPassword, request); return principal; } else { return super.authenticate(username, credentials, request); } } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } @Override public void setSingleSignOn(Request request, Response response, Principal principal, Credential credential) { Debug.out("set single sign-on called"); super.setSingleSignOn(request, response, principal, credential); } @Override public Credential getSingleSignOn(Request request, Response response) { Debug.out("getSingleSignOn"); return super.getSingleSignOn(request, response); } } }