Example #1
0
 public DBHistory(RouterContext context, String statGroup) {
   _context = context;
   _log = context.logManager().getLog(DBHistory.class);
   _statGroup = statGroup;
   _lastLookupReceived = -1;
   createRates(statGroup);
 }
Example #2
0
  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();
  }
Example #3
0
 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);
 }
Example #4
0
 /**
  * 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;
   }
 }
Example #6
0
 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
 }
Example #7
0
  /**
   * 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;
  }
Example #8
0
 /**
  * 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();
     }
 }
Example #9
0
  /**
   * @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());
 }
Example #12
0
 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);
 }
Example #13
0
 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 });
 }
Example #14
0
 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();
 }
Example #15
0
  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?
  }
Example #16
0
  /** @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;
  }
Example #17
0
 /** 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);
         }
       }
     }
   }
 }
Example #18
0
  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;
    //
  }
Example #19
0
 CreateRouterInfoJob(RouterContext ctx, Job next) {
   super(ctx);
   _next = next;
   _log = ctx.logManager().getLog(CreateRouterInfoJob.class);
 }
Example #20
0
  /**
   * @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);
      }
    }
  }
Example #21
0
 public Reseeder(RouterContext ctx) {
     _context = ctx;
     _log = ctx.logManager().getLog(Reseeder.class);
 }
Example #22
0
  /**
   * @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;
  }
Example #23
0
  /**
   * 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));
  }
Example #24
0
 public AdminListener(RouterContext context, int port) {
   _context = context;
   _log = context.logManager().getLog(AdminListener.class);
   _port = port;
   _running = false;
 }
Example #25
0
 public FloodfillMonitorJob(RouterContext context, FloodfillNetworkDatabaseFacade facade) {
   super(context);
   _facade = facade;
   _log = context.logManager().getLog(FloodfillMonitorJob.class);
 }
Example #26
0
  /**
   * 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;
  }
Example #27
0
  /**
   * 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;
  }
Example #28
0
 public UpdateHandler(RouterContext ctx) {
     _context = ctx;
     _log = ctx.logManager().getLog(UpdateHandler.class);
     _updateFile = (new File(ctx.getRouterDir(), SIGNED_UPDATE_FILE)).getAbsolutePath();
 }
Example #29
0
 public AdminManager(RouterContext context) {
   _context = context;
   _log = context.logManager().getLog(AdminManager.class);
 }