public DBHistory(RouterContext context, String statGroup) { _context = context; _log = context.logManager().getLog(DBHistory.class); _statGroup = statGroup; _lastLookupReceived = -1; createRates(statGroup); }
public JobQueue(RouterContext context) { _context = context; _log = context.logManager().getLog(JobQueue.class); _context .statManager() .createRateStat( "jobQueue.readyJobs", "How many ready and waiting jobs there are?", "JobQueue", new long[] {60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); _context .statManager() .createRateStat( "jobQueue.droppedJobs", "How many jobs do we drop due to insane overload?", "JobQueue", new long[] {60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); // following are for JobQueueRunner _context .statManager() .createRateStat( "jobQueue.jobRun", "How long jobs take", "JobQueue", new long[] {60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); _context .statManager() .createRateStat( "jobQueue.jobRunSlow", "How long jobs that take over a second take", "JobQueue", new long[] {60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); _context .statManager() .createRequiredRateStat( "jobQueue.jobLag", "Job run delay (ms)", "JobQueue", new long[] {60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); _context .statManager() .createRateStat( "jobQueue.jobWait", "How long does a job sit on the job queue?", "JobQueue", new long[] {60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); // _context.statManager().createRateStat("jobQueue.jobRunnerInactive", "How long are runners // inactive?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); _alive = true; _readyJobs = new LinkedBlockingQueue(); _timedJobs = new TreeSet(new JobComparator()); _jobLock = new Object(); _queueRunners = new ConcurrentHashMap(RUNNERS); _jobStats = new ConcurrentHashMap(); _pumper = new QueuePumper(); I2PThread pumperThread = new I2PThread(_pumper, "Job Queue Pumper", true); // pumperThread.setPriority(I2PThread.NORM_PRIORITY+1); pumperThread.start(); }
public UDPReceiver( RouterContext ctx, UDPTransport transport, DatagramSocket socket, String name) { _context = ctx; _log = ctx.logManager().getLog(UDPReceiver.class); _name = name; _socket = socket; _transport = transport; _handler = transport.getPacketHandler(); if (_handler == null) throw new IllegalStateException(); _runner = new Runner(); // _context.statManager().createRateStat("udp.receivePacketSize", "How large packets received // are", "udp", UDPTransport.RATES); // _context.statManager().createRateStat("udp.receiveRemaining", "How many packets are left // sitting on the receiver's queue", "udp", UDPTransport.RATES); // _context.statManager().createRateStat("udp.droppedInbound", "How many packet are queued up // but not yet received when we drop", "udp", UDPTransport.RATES); _context .statManager() .createRateStat( "udp.receiveHolePunch", "How often we receive a NAT hole punch", "udp", UDPTransport.RATES); _context .statManager() .createRateStat( "udp.ignorePacketFromDroplist", "Packet lifetime for those dropped on the drop list", "udp", UDPTransport.RATES); }
/** * Deferred deletion of plugins that we failed to delete before. * * @since 0.9.13 */ private static void deferredDeletePlugins(RouterContext ctx) { Log log = ctx.logManager().getLog(PluginStarter.class); boolean changed = false; Properties props = pluginProperties(); for (Iterator<Map.Entry<Object, Object>> iter = props.entrySet().iterator(); iter.hasNext(); ) { Map.Entry<Object, Object> e = iter.next(); String name = (String) e.getKey(); if (name.startsWith(PREFIX) && name.endsWith(ENABLED)) { // deferred deletion of a plugin if (e.getValue().equals(DELETED)) { String app = name.substring(PREFIX.length(), name.lastIndexOf(ENABLED)); // shouldn't happen, this is run early if (isPluginRunning(app, ctx)) continue; File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + app); boolean deleted = FileUtil.rmdir(pluginDir, false); if (deleted) { log.logAlways(Log.WARN, "Deferred deletion of " + pluginDir + " successful"); iter.remove(); changed = true; } else { if (log.shouldLog(Log.WARN)) log.warn("Deferred deletion of " + pluginDir + " failed"); } } } } if (changed) storePluginProperties(props); }
/** * @param claimedAddress an IP/port based RemoteHostId, or null if unknown * @param remoteHostId non-null, == claimedAddress if direct, or a hash-based one if indirect * @param addr non-null */ public OutboundEstablishState( RouterContext ctx, RemoteHostId claimedAddress, RemoteHostId remoteHostId, RouterIdentity remotePeer, SessionKey introKey, UDPAddress addr, DHSessionKeyBuilder.Factory dh) { _context = ctx; _log = ctx.logManager().getLog(OutboundEstablishState.class); if (claimedAddress != null) { _bobIP = claimedAddress.getIP(); _bobPort = claimedAddress.getPort(); } else { // _bobIP = null; _bobPort = -1; } _claimedAddress = claimedAddress; _remoteHostId = remoteHostId; _remotePeer = remotePeer; _introKey = introKey; _queuedMessages = new LinkedBlockingQueue<OutNetMessage>(); _establishBegin = ctx.clock().now(); _remoteAddress = addr; _introductionNonce = -1; _keyFactory = dh; if (addr.getIntroducerCount() > 0) { if (_log.shouldLog(Log.DEBUG)) _log.debug( "new outbound establish to " + remotePeer.calculateHash() + ", with address: " + addr); _currentState = OutboundState.OB_STATE_PENDING_INTRO; } else { _currentState = OutboundState.OB_STATE_UNKNOWN; } }
public OutboundReceiver(RouterContext ctx, TunnelCreatorConfig cfg) { _context = ctx; _log = ctx.logManager().getLog(OutboundReceiver.class); _config = cfg; _nextHopCache = _context.netDb().lookupRouterInfoLocally(_config.getPeer(1)); // all createRateStat() in TunnelDispatcher }
/** * Returns <code>true</code> if one or more client threads are running in a given plugin. * * @param pluginName * @return true if running */ private static boolean isClientThreadRunning(String pluginName, RouterContext ctx) { ThreadGroup group = pluginThreadGroups.get(pluginName); if (group == null) return false; boolean rv = group.activeCount() > 0; // Plugins start before the eepsite, and will create the static Timer thread // in RolloverFileOutputStream, which never stops. Don't count it. if (rv) { Log log = ctx.logManager().getLog(PluginStarter.class); Thread[] activeThreads = new Thread[128]; int count = group.enumerate(activeThreads); boolean notRollover = false; for (int i = 0; i < count; i++) { if (activeThreads[i] != null) { String name = activeThreads[i].getName(); if (!"org.eclipse.jetty.util.RolloverFileOutputStream".equals(name)) notRollover = true; if (log.shouldLog(Log.DEBUG)) log.debug( "Found " + activeThreads[i].getState() + " thread for " + pluginName + ": " + name); } } rv = notRollover; } return rv; }
/** * Configure this bean to query a particular router context * * @param contextId beginning few characters of the routerHash, or null to pick * the first one we come across. */ public void setContextId(String contextId) { try { _context = ContextHelper.getContext(contextId); _log = _context.logManager().getLog(UpdateHandler.class); } catch (Throwable t) { t.printStackTrace(); } }
/** * @return true on success * @throws just about anything, caller would be wise to catch Throwable */ public static boolean stopPlugin(RouterContext ctx, String appName) throws Exception { Log log = ctx.logManager().getLog(PluginStarter.class); File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName); if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) { log.error("Cannot stop nonexistent plugin: " + appName); return false; } // stop things in clients.config File clientConfig = new File(pluginDir, "clients.config"); if (clientConfig.exists()) { Properties props = new Properties(); DataHelper.loadProps(props, clientConfig); List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig); runClientApps(ctx, pluginDir, clients, "stop"); } // stop console webapps in console/webapps // ContextHandlerCollection server = WebAppStarter.getConsoleServer(); // if (server != null) { /* File consoleDir = new File(pluginDir, "console"); Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath()); File webappDir = new File(consoleDir, "webapps"); String fileNames[] = webappDir.list(RouterConsoleRunner.WarFilenameFilter.instance()); if (fileNames != null) { for (int i = 0; i < fileNames.length; i++) { String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war")); if (Arrays.asList(STANDARD_WEBAPPS).contains(warName)) { continue; } WebAppStarter.stopWebApp(server, warName); } } */ if (pluginWars.containsKey(appName)) { Iterator<String> wars = pluginWars.get(appName).iterator(); while (wars.hasNext()) { String warName = wars.next(); WebAppStarter.stopWebApp(warName); } pluginWars.get(appName).clear(); } // } // remove summary bar link Properties props = pluginProperties(ctx, appName); String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx)); if (name == null) name = ConfigClientsHelper.stripHTML(props, "consoleLinkName"); if (name != null && name.length() > 0) NavHelper.unregisterApp(name); if (log.shouldLog(Log.WARN)) log.warn("Stopping plugin: " + appName); return true; }
public ProfilePersistenceHelper(RouterContext ctx) { _context = ctx; _log = ctx.logManager().getLog(ProfilePersistenceHelper.class); String dir = _context.getProperty(PROP_PEER_PROFILE_DIR, DEFAULT_PEER_PROFILE_DIR); _profileDir = new SecureDirectory(_context.getRouterDir(), dir); if (!_profileDir.exists()) _profileDir.mkdirs(); for (int j = 0; j < B64.length(); j++) { File subdir = new SecureDirectory(_profileDir, DIR_PREFIX + B64.charAt(j)); if (!subdir.exists()) subdir.mkdir(); } }
/** Create a new runner against the given socket */ public ClientConnectionRunner(RouterContext context, ClientManager manager, Socket socket) { _context = context; _log = _context.logManager().getLog(ClientConnectionRunner.class); _manager = manager; _socket = socket; // unused for fastReceive _messages = new ConcurrentHashMap(); _alreadyProcessed = new ArrayList(); _acceptedPending = new ConcurrentHashSet(); _messageId = new AtomicInteger(_context.random().nextInt()); }
public MessageHistory(RouterContext context) { _context = context; _log = context.logManager().getLog(getClass()); _fmt = new SimpleDateFormat("yy/MM/dd.HH:mm:ss.SSS"); _fmt.setTimeZone(TimeZone.getTimeZone("GMT")); _unwrittenEntries = new LinkedBlockingQueue(); _reinitializeJob = new ReinitializeJob(); _writeJob = new WriteJob(); _firstPass = true; // _submitMessageHistoryJob = new SubmitMessageHistoryJob(_context); initialize(true); }
public OutNetMessage(RouterContext context) { _context = context; _log = context.logManager().getLog(OutNetMessage.class); _priority = -1; _expiration = -1; // _createdBy = new Exception("Created by"); _created = context.clock().now(); if (_log.shouldLog(Log.INFO)) timestamp("Created"); // _context.messageStateMonitor().outboundMessageAdded(); // _context.statManager().createRateStat("outNetMessage.timeToDiscard", // "How long until we discard an outbound msg?", // "OutNetMessage", new long[] { 5*60*1000, 30*60*1000, // 60*60*1000 }); }
public UPnPManager(RouterContext context, TransportManager manager) { _context = context; _manager = manager; _log = _context.logManager().getLog(UPnPManager.class); // UPnP wants to bind to IPv6 link local interfaces by default, but what UPnP router // is going to want to talk IPv6 anyway? Just make it easy and force IPv4 only org.cybergarage.upnp.UPnP.setEnable(org.cybergarage.upnp.UPnP.USE_ONLY_IPV4_ADDR); // set up logging in the UPnP package Debug.initialize(context); _upnp = new UPnP(context); _upnp.setHTTPPort(_context.getProperty(PROP_HTTP_PORT, DEFAULT_HTTP_PORT)); _upnp.setSSDPPort(_context.getProperty(PROP_SSDP_PORT, DEFAULT_SSDP_PORT)); _upnpCallback = new UPnPCallback(); _rescanner = new Rescanner(); }
private static void buildZeroHop( RouterContext ctx, TunnelPool pool, PooledTunnelCreatorConfig cfg, BuildExecutor exec) { Log log = ctx.logManager().getLog(BuildRequestor.class); if (log.shouldLog(Log.DEBUG)) log.debug("Build zero hop tunnel " + cfg); exec.buildComplete(cfg, pool); if (cfg.isInbound()) ctx.tunnelDispatcher().joinInbound(cfg); else ctx.tunnelDispatcher().joinOutbound(cfg); pool.addTunnel(cfg); exec.buildSuccessful(cfg); ExpireJob expireJob = new ExpireJob(ctx, cfg, pool); cfg.setExpireJob(expireJob); ctx.jobQueue().addJob(expireJob); // can it get much easier? }
/** @return true on success - caller should call stopPlugin() first */ static boolean deletePlugin(RouterContext ctx, String appName) throws Exception { Log log = ctx.logManager().getLog(PluginStarter.class); File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName); if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) { log.error("Cannot delete nonexistent plugin: " + appName); return false; } // uninstall things in clients.config File clientConfig = new File(pluginDir, "clients.config"); if (clientConfig.exists()) { Properties props = new Properties(); DataHelper.loadProps(props, clientConfig); List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig); runClientApps(ctx, pluginDir, clients, "uninstall"); } // unregister themes, and switch to default if we are unregistering the current theme File dir = new File(pluginDir, "console/themes"); File[] tfiles = dir.listFiles(); if (tfiles != null) { String current = ctx.getProperty(CSSHelper.PROP_THEME_NAME); Map<String, String> changes = new HashMap<String, String>(); List<String> removes = new ArrayList<String>(); for (int i = 0; i < tfiles.length; i++) { String name = tfiles[i].getName(); if (tfiles[i].isDirectory() && (!Arrays.asList(STANDARD_THEMES).contains(tfiles[i]))) { removes.add(ConfigUIHelper.PROP_THEME_PFX + name); if (name.equals(current)) changes.put(CSSHelper.PROP_THEME_NAME, CSSHelper.DEFAULT_THEME); } } ctx.router().saveConfig(changes, removes); } boolean deleted = FileUtil.rmdir(pluginDir, false); Properties props = pluginProperties(); for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) { String name = (String) iter.next(); if (name.startsWith(PREFIX + appName + '.')) iter.remove(); } if (!deleted) { // This happens on Windows when there are plugin jars in classpath // Mark it as deleted, we will try again after restart log.logAlways(Log.WARN, "Deletion of " + pluginDir + " failed, will try again at restart"); props.setProperty(PREFIX + appName + ENABLED, DELETED); } storePluginProperties(props); return true; }
/** this shouldn't throw anything */ static void startPlugins(RouterContext ctx) { Log log = ctx.logManager().getLog(PluginStarter.class); Properties props = pluginProperties(); for (Map.Entry<Object, Object> e : props.entrySet()) { String name = (String) e.getKey(); if (name.startsWith(PREFIX) && name.endsWith(ENABLED)) { if (Boolean.parseBoolean((String) e.getValue())) { String app = name.substring(PREFIX.length(), name.lastIndexOf(ENABLED)); // plugins could have been started after update if (isPluginRunning(app, ctx)) continue; try { if (!startPlugin(ctx, app)) log.error("Failed to start plugin: " + app); } catch (Throwable t) { log.error("Failed to start plugin: " + app, t); } } } } }
public static boolean isPluginRunning(String pluginName, RouterContext ctx) { Log log = ctx.logManager().getLog(PluginStarter.class); boolean isJobRunning = false; Collection<SimpleTimer2.TimedEvent> pending = _pendingPluginClients.get(pluginName); if (pending != null && !pending.isEmpty()) { // TODO have a pending indication too isJobRunning = true; } boolean isWarRunning = false; if (pluginWars.containsKey(pluginName)) { Iterator<String> it = pluginWars.get(pluginName).iterator(); while (it.hasNext() && !isWarRunning) { String warName = it.next(); if (WebAppStarter.isWebAppRunning(warName)) { isWarRunning = true; } } } boolean isClientThreadRunning = isClientThreadRunning(pluginName, ctx); if (log.shouldLog(Log.DEBUG)) log.debug( "plugin name = <" + pluginName + ">; threads running? " + isClientThreadRunning + "; webapp running? " + isWarRunning + "; jobs running? " + isJobRunning); return isClientThreadRunning || isWarRunning || isJobRunning; // // if (log.shouldLog(Log.DEBUG)) // log.debug("plugin name = <" + pluginName + ">; threads running? " + // isClientThreadRunning(pluginName) + "; webapp running? " + // WebAppStarter.isWebAppRunning(pluginName) + "; jobs running? " + isJobRunning); // return isClientThreadRunning(pluginName) || WebAppStarter.isWebAppRunning(pluginName) || // isJobRunning; // }
CreateRouterInfoJob(RouterContext ctx, Job next) { super(ctx); _next = next; _log = ctx.logManager().getLog(CreateRouterInfoJob.class); }
/** * @param action "start" or "stop" or "uninstall" * @throws just about anything if an app has a delay less than zero, caller would be wise to catch * Throwable If no apps have a delay less than zero, it shouldn't throw anything */ private static void runClientApps( RouterContext ctx, File pluginDir, List<ClientAppConfig> apps, String action) throws Exception { Log log = ctx.logManager().getLog(PluginStarter.class); // initialize pluginThreadGroup and _pendingPluginClients String pluginName = pluginDir.getName(); if (!pluginThreadGroups.containsKey(pluginName)) pluginThreadGroups.put(pluginName, new ThreadGroup(pluginName)); ThreadGroup pluginThreadGroup = pluginThreadGroups.get(pluginName); if (action.equals("start")) _pendingPluginClients.put(pluginName, new ConcurrentHashSet<SimpleTimer2.TimedEvent>()); for (ClientAppConfig app : apps) { // If the client is a running ClientApp that we want to stop, // bypass all the logic below. if (action.equals("stop")) { String[] argVal = LoadClientAppsJob.parseArgs(app.args); // We must do all the substitution just as when started, so the // argument array comparison in getClientApp() works. // Do this after parsing so we don't need to worry about quoting for (int i = 0; i < argVal.length; i++) { if (argVal[i].indexOf("$") >= 0) { argVal[i] = argVal[i].replace("$I2P", ctx.getBaseDir().getAbsolutePath()); argVal[i] = argVal[i].replace("$CONFIG", ctx.getConfigDir().getAbsolutePath()); argVal[i] = argVal[i].replace("$PLUGIN", pluginDir.getAbsolutePath()); } } ClientApp ca = ctx.routerAppManager().getClientApp(app.className, argVal); if (ca != null) { // even if (ca.getState() != ClientAppState.RUNNING), we do this, we don't want to fall // thru try { ca.shutdown(LoadClientAppsJob.parseArgs(app.stopargs)); } catch (Throwable t) { throw new Exception(t); } continue; } } if (action.equals("start") && app.disabled) continue; String argVal[]; if (action.equals("start")) { // start argVal = LoadClientAppsJob.parseArgs(app.args); } else { String args; if (action.equals("stop")) args = app.stopargs; else if (action.equals("uninstall")) args = app.uninstallargs; else throw new IllegalArgumentException("bad action"); // args must be present if (args == null || args.length() <= 0) continue; argVal = LoadClientAppsJob.parseArgs(args); } // do this after parsing so we don't need to worry about quoting for (int i = 0; i < argVal.length; i++) { if (argVal[i].indexOf("$") >= 0) { argVal[i] = argVal[i].replace("$I2P", ctx.getBaseDir().getAbsolutePath()); argVal[i] = argVal[i].replace("$CONFIG", ctx.getConfigDir().getAbsolutePath()); argVal[i] = argVal[i].replace("$PLUGIN", pluginDir.getAbsolutePath()); } } ClassLoader cl = null; if (app.classpath != null) { String cp = app.classpath; if (cp.indexOf("$") >= 0) { cp = cp.replace("$I2P", ctx.getBaseDir().getAbsolutePath()); cp = cp.replace("$CONFIG", ctx.getConfigDir().getAbsolutePath()); cp = cp.replace("$PLUGIN", pluginDir.getAbsolutePath()); } // Old way - add for the whole JVM // addToClasspath(cp, app.clientName, log); // New way - add only for this client // We cache the ClassLoader we start the client with, so // we can reuse it for stopping and uninstalling. // If we don't, the client won't be able to find its // static members. String clCacheKey = pluginName + app.className + app.args; if (!action.equals("start")) cl = _clCache.get(clCacheKey); if (cl == null) { URL[] urls = classpathToURLArray(cp, app.clientName, log); if (urls != null) { cl = new URLClassLoader(urls, ClassLoader.getSystemClassLoader()); if (action.equals("start")) _clCache.put(clCacheKey, cl); } } } if (app.delay < 0 && action.equals("start")) { // this will throw exceptions LoadClientAppsJob.runClientInline(app.className, app.clientName, argVal, log, cl); } else if (app.delay == 0 || !action.equals("start")) { // quick check, will throw ClassNotFoundException on error LoadClientAppsJob.testClient(app.className, cl); // run this guy now LoadClientAppsJob.runClient( app.className, app.clientName, argVal, ctx, log, pluginThreadGroup, cl); } else { // If there is some delay, there may be a really good reason for it. // Loading a class would be one of them! // So we do a quick check first, If it bombs out, we delay and try again. // If it bombs after that, then we throw the ClassNotFoundException. try { // quick check LoadClientAppsJob.testClient(app.className, cl); } catch (ClassNotFoundException ex) { // Try again 1 or 2 seconds later. // This should be enough time. Although it is a lousy hack // it should work for most cases. // Perhaps it may be even better to delay a percentage // if > 1, and reduce the delay time. // Under normal circumstances there will be no delay at all. try { if (app.delay > 1) { Thread.sleep(2000); } else { Thread.sleep(1000); } } catch (InterruptedException ie) { } // quick check, will throw ClassNotFoundException on error LoadClientAppsJob.testClient(app.className, cl); } // wait before firing it up SimpleTimer2.TimedEvent evt = new TrackedDelayedClient( pluginName, ctx.simpleTimer2(), ctx, app.className, app.clientName, argVal, pluginThreadGroup, cl); evt.schedule(app.delay); } } }
public Reseeder(RouterContext ctx) { _context = ctx; _log = ctx.logManager().getLog(Reseeder.class); }
/** * @return true on success * @throws just about anything, caller would be wise to catch Throwable */ public static boolean startPlugin(RouterContext ctx, String appName) throws Exception { Log log = ctx.logManager().getLog(PluginStarter.class); File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName); String iconfile = null; if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) { log.error("Cannot start nonexistent plugin: " + appName); disablePlugin(appName); return false; } // Do we need to extract an update? File pluginUpdate = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName + "/app.xpi2p.zip"); if (pluginUpdate.exists()) { // Compare the start time of the router with the plugin. if (ctx.router().getWhenStarted() > pluginUpdate.lastModified()) { if (!FileUtil.extractZip(pluginUpdate, pluginDir)) { pluginUpdate.delete(); String foo = "Plugin '" + appName + "' failed to update! File '" + pluginUpdate + "' deleted. You may need to remove and install the plugin again."; log.error(foo); disablePlugin(appName); throw new Exception(foo); } else { pluginUpdate.delete(); // Need to always log this, and log.logAlways() did not work for me. System.err.println("INFO: Plugin updated: " + appName); } } // silently fail to update, because we have not restarted. } Properties props = pluginProperties(ctx, appName); String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version"); if (minVersion != null && VersionComparator.comp(CoreVersion.VERSION, minVersion) < 0) { String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher"; log.error(foo); disablePlugin(appName); throw new Exception(foo); } minVersion = ConfigClientsHelper.stripHTML(props, "min-java-version"); if (minVersion != null && VersionComparator.comp(System.getProperty("java.version"), minVersion) < 0) { String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher"; log.error(foo); disablePlugin(appName); throw new Exception(foo); } String jVersion = LogsHelper.jettyVersion(); minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version"); if (minVersion != null && VersionComparator.comp(minVersion, jVersion) > 0) { String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher"; log.error(foo); disablePlugin(appName); throw new Exception(foo); } String maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version"); if (maxVersion != null && VersionComparator.comp(maxVersion, jVersion) < 0) { String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower"; log.error(foo); disablePlugin(appName); throw new Exception(foo); } if (log.shouldLog(Log.INFO)) log.info("Starting plugin: " + appName); // register themes File dir = new File(pluginDir, "console/themes"); File[] tfiles = dir.listFiles(); if (tfiles != null) { for (int i = 0; i < tfiles.length; i++) { String name = tfiles[i].getName(); if (tfiles[i].isDirectory() && (!Arrays.asList(STANDARD_THEMES).contains(tfiles[i]))) ctx.router() .setConfigSetting(ConfigUIHelper.PROP_THEME_PFX + name, tfiles[i].getAbsolutePath()); // we don't need to save } } // load and start things in clients.config File clientConfig = new File(pluginDir, "clients.config"); if (clientConfig.exists()) { Properties cprops = new Properties(); DataHelper.loadProps(cprops, clientConfig); List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig); runClientApps(ctx, pluginDir, clients, "start"); } // start console webapps in console/webapps ContextHandlerCollection server = WebAppStarter.getConsoleServer(); if (server != null) { File consoleDir = new File(pluginDir, "console"); Properties wprops = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath()); File webappDir = new File(consoleDir, "webapps"); String fileNames[] = webappDir.list(RouterConsoleRunner.WarFilenameFilter.instance()); if (fileNames != null) { if (!pluginWars.containsKey(appName)) pluginWars.put(appName, new ConcurrentHashSet<String>()); for (int i = 0; i < fileNames.length; i++) { try { String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war")); // log.error("Found webapp: " + warName); // check for duplicates in $I2P if (Arrays.asList(STANDARD_WEBAPPS).contains(warName)) { log.error("Skipping duplicate webapp " + warName + " in plugin " + appName); continue; } String enabled = wprops.getProperty(RouterConsoleRunner.PREFIX + warName + ENABLED); if (!"false".equals(enabled)) { if (log.shouldLog(Log.INFO)) log.info("Starting webapp: " + warName); String path = new File(webappDir, fileNames[i]).getCanonicalPath(); WebAppStarter.startWebApp(ctx, server, warName, path); pluginWars.get(appName).add(warName); } } catch (IOException ioe) { log.error("Error resolving '" + fileNames[i] + "' in '" + webappDir, ioe); } } // Check for iconfile in plugin.properties String icfile = ConfigClientsHelper.stripHTML(props, "console-icon"); if (icfile != null && !icfile.contains("..")) { StringBuilder buf = new StringBuilder(32); buf.append('/').append(appName); if (!icfile.startsWith("/")) buf.append('/'); buf.append(icfile); iconfile = buf.toString(); } } } else { log.error("No console web server to start plugins?"); } // add translation jars in console/locale // These will not override existing resource bundles since we are adding them // later in the classpath. File localeDir = new File(pluginDir, "console/locale"); if (localeDir.exists() && localeDir.isDirectory()) { File[] files = localeDir.listFiles(); if (files != null) { boolean added = false; for (int i = 0; i < files.length; i++) { File f = files[i]; if (f.getName().endsWith(".jar")) { try { addPath(f.toURI().toURL()); log.error("INFO: Adding translation plugin to classpath: " + f); added = true; } catch (Exception e) { log.error("Plugin " + appName + " bad classpath element: " + f, e); } } } if (added) Translate.clearCache(); } } // add summary bar link String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx)); if (name == null) name = ConfigClientsHelper.stripHTML(props, "consoleLinkName"); String url = ConfigClientsHelper.stripHTML(props, "consoleLinkURL"); if (name != null && url != null && name.length() > 0 && url.length() > 0) { String tip = ConfigClientsHelper.stripHTML(props, "consoleLinkTooltip_" + Messages.getLanguage(ctx)); if (tip == null) tip = ConfigClientsHelper.stripHTML(props, "consoleLinkTooltip"); NavHelper.registerApp(name, url, tip, iconfile); } return true; }
/** * inline * * @since 0.8.13 */ private static void updateAll(RouterContext ctx, boolean delay) { List<String> plugins = getPlugins(); Map<String, String> toUpdate = new HashMap<String, String>(); for (String appName : plugins) { Properties props = pluginProperties(ctx, appName); String url = props.getProperty("updateURL"); if (url != null) toUpdate.put(appName, url); } if (toUpdate.isEmpty()) return; ConsoleUpdateManager mgr = UpdateHandler.updateManager(ctx); if (mgr == null) return; if (mgr.isUpdateInProgress()) return; if (delay) { // wait for proxy mgr.update(TYPE_DUMMY, 3 * 60 * 1000); mgr.notifyProgress(null, Messages.getString("Checking for plugin updates", ctx)); int loop = 0; do { try { Thread.sleep(5 * 1000); } catch (InterruptedException ie) { } if (loop++ > 40) break; } while (mgr.isUpdateInProgress(TYPE_DUMMY)); } String proxyHost = ctx.getProperty( ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); int proxyPort = ConfigUpdateHandler.proxyPort(ctx); if (proxyPort == ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT && proxyHost.equals(ConfigUpdateHandler.DEFAULT_PROXY_HOST) && ctx.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) < 0) { mgr.notifyComplete( null, Messages.getString("Plugin update check failed", ctx) + " - " + Messages.getString("HTTP client proxy tunnel must be running", ctx)); return; } Log log = ctx.logManager().getLog(PluginStarter.class); int updated = 0; for (Map.Entry<String, String> entry : toUpdate.entrySet()) { String appName = entry.getKey(); if (log.shouldLog(Log.WARN)) log.warn("Checking for update plugin: " + appName); // blocking if (mgr.checkAvailable(PLUGIN, appName, 60 * 1000) == null) { if (log.shouldLog(Log.WARN)) log.warn("No update available for plugin: " + appName); continue; } if (log.shouldLog(Log.WARN)) log.warn("Updating plugin: " + appName); // non-blocking mgr.update(PLUGIN, appName, 30 * 60 * 1000); int loop = 0; do { // only wait for 4 minutes, then we will // keep going try { Thread.sleep(5 * 1000); } catch (InterruptedException ie) { } if (loop++ > 48) break; } while (mgr.isUpdateInProgress(PLUGIN, appName)); if (mgr.getUpdateAvailable(PLUGIN, appName) != null) updated++; } if (updated > 0) mgr.notifyComplete(null, ngettext("1 plugin updated", "{0} plugins updated", updated, ctx)); else mgr.notifyComplete(null, Messages.getString("Plugin update check complete", ctx)); }
public AdminListener(RouterContext context, int port) { _context = context; _log = context.logManager().getLog(AdminListener.class); _port = port; _running = false; }
public FloodfillMonitorJob(RouterContext context, FloodfillNetworkDatabaseFacade facade) { super(context); _facade = facade; _log = context.logManager().getLog(FloodfillMonitorJob.class); }
/** * Send out a build request message. * * @param cfg ReplyMessageId must be set * @return success */ public static boolean request( RouterContext ctx, TunnelPool pool, PooledTunnelCreatorConfig cfg, BuildExecutor exec) { // new style crypto fills in all the blanks, while the old style waits for replies to fill in // the next hop, etc prepare(ctx, cfg); if (cfg.getLength() <= 1) { buildZeroHop(ctx, pool, cfg, exec); return true; } Log log = ctx.logManager().getLog(BuildRequestor.class); cfg.setTunnelPool(pool); TunnelInfo pairedTunnel = null; Hash farEnd = cfg.getFarEnd(); TunnelManagerFacade mgr = ctx.tunnelManager(); boolean isInbound = pool.getSettings().isInbound(); if (pool.getSettings().isExploratory() || !usePairedTunnels(ctx)) { if (isInbound) pairedTunnel = mgr.selectOutboundExploratoryTunnel(farEnd); else pairedTunnel = mgr.selectInboundExploratoryTunnel(farEnd); } else { // building a client tunnel if (isInbound) pairedTunnel = mgr.selectOutboundTunnel(pool.getSettings().getDestination(), farEnd); else pairedTunnel = mgr.selectInboundTunnel(pool.getSettings().getDestination(), farEnd); if (pairedTunnel == null) { if (isInbound) { // random more reliable than closest ?? // pairedTunnel = mgr.selectOutboundExploratoryTunnel(farEnd); pairedTunnel = mgr.selectOutboundTunnel(); if (pairedTunnel != null && pairedTunnel.getLength() <= 1 && mgr.getOutboundSettings().getLength() > 0 && mgr.getOutboundSettings().getLength() + mgr.getOutboundSettings().getLengthVariance() > 0) { // don't build using a zero-hop expl., // as it is both very bad for anonomyity, // and it takes a build slot away from exploratory pairedTunnel = null; } } else { // random more reliable than closest ?? // pairedTunnel = mgr.selectInboundExploratoryTunnel(farEnd); pairedTunnel = mgr.selectInboundTunnel(); if (pairedTunnel != null && pairedTunnel.getLength() <= 1 && mgr.getInboundSettings().getLength() > 0 && mgr.getInboundSettings().getLength() + mgr.getInboundSettings().getLengthVariance() > 0) { // ditto pairedTunnel = null; } } if (pairedTunnel != null && log.shouldLog(Log.INFO)) log.info("Couldn't find a paired tunnel for " + cfg + ", using exploratory tunnel"); } } if (pairedTunnel == null) { if (log.shouldLog(Log.WARN)) log.warn("Tunnel build failed, as we couldn't find a paired tunnel for " + cfg); exec.buildComplete(cfg, pool); // Not even an exploratory tunnel? We are in big trouble. // Let's not spin through here too fast. // But don't let a client tunnel waiting for exploratories slow things down too much, // as there may be other tunnel pools who can build int ms = pool.getSettings().isExploratory() ? 250 : 25; try { Thread.sleep(ms); } catch (InterruptedException ie) { } return false; } // long beforeCreate = System.currentTimeMillis(); TunnelBuildMessage msg = createTunnelBuildMessage(ctx, pool, cfg, pairedTunnel, exec); // long createTime = System.currentTimeMillis()-beforeCreate; if (msg == null) { if (log.shouldLog(Log.WARN)) log.warn("Tunnel build failed, as we couldn't create the tunnel build message for " + cfg); exec.buildComplete(cfg, pool); return false; } // cfg.setPairedTunnel(pairedTunnel); // long beforeDispatch = System.currentTimeMillis(); if (cfg.isInbound()) { if (log.shouldLog(Log.INFO)) log.info( "Sending the tunnel build request " + msg.getUniqueId() + " out the tunnel " + pairedTunnel + " to " + cfg.getPeer(0) + " for " + cfg + " waiting for the reply of " + cfg.getReplyMessageId()); // send it out a tunnel targetting the first hop // TODO - would be nice to have a TunnelBuildFirstHopFailJob queued if the // pairedTunnel is zero-hop, but no way to do that? ctx.tunnelDispatcher().dispatchOutbound(msg, pairedTunnel.getSendTunnelId(0), cfg.getPeer(0)); } else { if (log.shouldLog(Log.INFO)) log.info( "Sending the tunnel build request directly to " + cfg.getPeer(1) + " for " + cfg + " waiting for the reply of " + cfg.getReplyMessageId() + " with msgId=" + msg.getUniqueId()); // send it directly to the first hop // Add some fuzz to the TBM expiration to make it harder to guess how many hops // or placement in the tunnel msg.setMessageExpiration( ctx.clock().now() + BUILD_MSG_TIMEOUT + ctx.random().nextLong(20 * 1000)); // We set the OutNetMessage expiration much shorter, so that the // TunnelBuildFirstHopFailJob fires before the 13s build expiration. RouterInfo peer = ctx.netDb().lookupRouterInfoLocally(cfg.getPeer(1)); if (peer == null) { if (log.shouldLog(Log.WARN)) log.warn("Could not find the next hop to send the outbound request to: " + cfg); exec.buildComplete(cfg, pool); return false; } OutNetMessage outMsg = new OutNetMessage(ctx, msg, ctx.clock().now() + FIRST_HOP_TIMEOUT, PRIORITY, peer); outMsg.setOnFailedSendJob(new TunnelBuildFirstHopFailJob(ctx, pool, cfg, exec)); ctx.outNetMessagePool().add(outMsg); } // if (log.shouldLog(Log.DEBUG)) // log.debug("Tunnel build message " + msg.getUniqueId() + " created in " + createTime // + "ms and dispatched in " + (System.currentTimeMillis()-beforeDispatch)); return true; }
/** * If the tunnel is short enough, and everybody in the tunnel, and the OBEP or IBGW for the paired * tunnel, all support the new variable-sized tunnel build message, then use that, otherwise the * old 8-entry version. * * @return null on error */ private static TunnelBuildMessage createTunnelBuildMessage( RouterContext ctx, TunnelPool pool, PooledTunnelCreatorConfig cfg, TunnelInfo pairedTunnel, BuildExecutor exec) { Log log = ctx.logManager().getLog(BuildRequestor.class); long replyTunnel = 0; Hash replyRouter = null; boolean useVariable = SEND_VARIABLE && cfg.getLength() <= MEDIUM_RECORDS; if (cfg.isInbound()) { // replyTunnel = 0; // as above replyRouter = ctx.routerHash(); if (useVariable) { // check the reply OBEP and all the tunnel peers except ourselves if (!supportsVariable(ctx, pairedTunnel.getPeer(pairedTunnel.getLength() - 1))) { useVariable = false; } else { for (int i = 0; i < cfg.getLength() - 1; i++) { if (!supportsVariable(ctx, cfg.getPeer(i))) { useVariable = false; break; } } } } } else { replyTunnel = pairedTunnel.getReceiveTunnelId(0).getTunnelId(); replyRouter = pairedTunnel.getPeer(0); if (useVariable) { // check the reply IBGW and all the tunnel peers except ourselves if (!supportsVariable(ctx, replyRouter)) { useVariable = false; } else { for (int i = 1; i < cfg.getLength() - 1; i++) { if (!supportsVariable(ctx, cfg.getPeer(i))) { useVariable = false; break; } } } } } // populate and encrypt the message TunnelBuildMessage msg; List<Integer> order; if (useVariable) { if (cfg.getLength() <= SHORT_RECORDS) { msg = new VariableTunnelBuildMessage(ctx, SHORT_RECORDS); order = new ArrayList<Integer>(SHORT_ORDER); } else { msg = new VariableTunnelBuildMessage(ctx, MEDIUM_RECORDS); order = new ArrayList<Integer>(MEDIUM_ORDER); } } else { msg = new TunnelBuildMessage(ctx); order = new ArrayList<Integer>(ORDER); } // This is in BuildExecutor.buildTunnel() now // long replyMessageId = ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE); // cfg.setReplyMessageId(replyMessageId); Collections.shuffle(order, ctx.random()); // randomized placement within the message cfg.setReplyOrder(order); if (log.shouldLog(Log.DEBUG)) log.debug("Build order: " + order + " for " + cfg); for (int i = 0; i < msg.getRecordCount(); i++) { int hop = order.get(i).intValue(); PublicKey key = null; if (BuildMessageGenerator.isBlank(cfg, hop)) { // erm, blank } else { Hash peer = cfg.getPeer(hop); RouterInfo peerInfo = ctx.netDb().lookupRouterInfoLocally(peer); if (peerInfo == null) { if (log.shouldLog(Log.WARN)) log.warn( "Peer selected for hop " + i + "/" + hop + " was not found locally: " + peer + " for " + cfg); return null; } else { key = peerInfo.getIdentity().getPublicKey(); } } if (log.shouldLog(Log.DEBUG)) log.debug(cfg.getReplyMessageId() + ": record " + i + "/" + hop + " has key " + key); BuildMessageGenerator.createRecord(i, hop, msg, cfg, replyRouter, replyTunnel, ctx, key); } BuildMessageGenerator.layeredEncrypt(ctx, msg, cfg, order); return msg; }
public UpdateHandler(RouterContext ctx) { _context = ctx; _log = ctx.logManager().getLog(UpdateHandler.class); _updateFile = (new File(ctx.getRouterDir(), SIGNED_UPDATE_FILE)).getAbsolutePath(); }
public AdminManager(RouterContext context) { _context = context; _log = context.logManager().getLog(AdminManager.class); }