Package com.subgraph.orchid.circuits.path

Source Code of com.subgraph.orchid.circuits.path.CircuitNodeChooser

package com.subgraph.orchid.circuits.path;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import com.subgraph.orchid.ConsensusDocument;
import com.subgraph.orchid.Directory;
import com.subgraph.orchid.Router;
import com.subgraph.orchid.TorConfig;
import com.subgraph.orchid.crypto.TorRandom;

public class CircuitNodeChooser {
  private final static Logger logger = Logger.getLogger(CircuitNodeChooser.class.getName());
 
  public enum WeightRule { WEIGHT_FOR_DIR, WEIGHT_FOR_EXIT, WEIGHT_FOR_MID, WEIGHT_FOR_GUARD, NO_WEIGHTING};
  private final Directory directory;
  private final TorRandom random = new TorRandom();
 
  private final TorConfigNodeFilter configNodeFilter;

 
  public CircuitNodeChooser(TorConfig config, Directory directory) {
    this.directory = directory;
    this.configNodeFilter = new TorConfigNodeFilter(config);
  }
 
  /**
   *
   * @param candidates
   * @return The chosen exit router or 'null' if no suitable router is available
   */
  public Router chooseExitNode(List<Router> candidates) {
    final List<Router> filteredCandidates = configNodeFilter.filterExitCandidates(candidates);
    return chooseByBandwidth(filteredCandidates, WeightRule.WEIGHT_FOR_EXIT);
  }
 
  public Router chooseDirectory() {
    final RouterFilter filter = new RouterFilter() {
      public boolean filter(Router router) {
        return router.getDirectoryPort() != 0;
      }
    };
    final List<Router> candidates = getFilteredRouters(filter, false);
    final Router choice = chooseByBandwidth(candidates, WeightRule.WEIGHT_FOR_DIR);
    if(choice == null) {
      return directory.getRandomDirectoryAuthority();
    } else {
      return choice;
    }
  }

  /**
   *
   * @param rule
   * @param routerFilter
   * @return The chosen router or 'null' if no suitable router is available.
   */
  public Router chooseRandomNode(WeightRule rule, RouterFilter routerFilter) {
    final List<Router> candidates = getFilteredRouters(routerFilter, true);
    final Router choice = chooseByBandwidth(candidates, rule);
    if(choice == null) {
      // try again with more permissive flags
      return null;
    }
    return choice;
  }
 
  private List<Router> getFilteredRouters(RouterFilter rf, boolean needDescriptor) {
    final List<Router> routers = new ArrayList<Router>();
    for(Router r: getUsableRouters(needDescriptor)) {
      if(rf.filter(r)) {
        routers.add(r);
      }
    }
    return routers;
  }
 
  List<Router> getUsableRouters(boolean needDescriptor) {
    final List<Router> routers = new ArrayList<Router>();
    for(Router r: directory.getAllRouters()) {
      if(r.isRunning() &&
          r.isValid() &&
          !r.isHibernating() &&
          !(needDescriptor && r.getCurrentDescriptor() == null)) {
       
        routers.add(r);
      }
    }
   
    return routers;
  }

  private Router chooseByBandwidth(List<Router> candidates, WeightRule rule) {
    final Router choice = chooseNodeByBandwidthWeights(candidates, rule);
    if(choice != null) {
      return choice;
    } else {
      return chooseNodeByBandwidth(candidates, rule);
    }
  }
 
  private Router chooseNodeByBandwidthWeights(List<Router> candidates, WeightRule rule) {
    final ConsensusDocument consensus = directory.getCurrentConsensusDocument();
    if(consensus == null) {
      return null;
    }
    final BandwidthWeightedRouters bwr = computeWeightedBandwidths(candidates, consensus, rule);
    return bwr.chooseRandomRouterByWeight();
  }
 
 
  private BandwidthWeightedRouters computeWeightedBandwidths(List<Router> candidates, ConsensusDocument consensus, WeightRule rule) {
    final CircuitNodeChooserWeightParameters wp = CircuitNodeChooserWeightParameters.create(consensus, rule);
    if(!wp.isValid()) {
      logger.warning("Got invalid bandwidth weights. Falling back to old selection method");
      return null;
    }
    final BandwidthWeightedRouters weightedRouters = new BandwidthWeightedRouters();
    for(Router r: candidates) {
      double wbw = wp.calculateWeightedBandwidth(r);
      weightedRouters.addRouter(r, wbw);
    }
    return weightedRouters;
  }
 
  private Router chooseNodeByBandwidth(List<Router> routers, WeightRule rule) {
    final BandwidthWeightedRouters bwr = new BandwidthWeightedRouters();
    for(Router r: routers) {
      long bw = getRouterBandwidthBytes(r);
      if(bw == -1) {
        bwr.addRouterUnknown(r);
      } else {
        bwr.addRouter(r, bw);
      }
    }
    bwr.fixUnknownValues();
    if(bwr.isTotalBandwidthZero()) {
      if(routers.size() == 0) {
        return null;
      }
     
      final int idx = random.nextInt(routers.size());
      return routers.get(idx);
    }
   
    computeFinalWeights(bwr, rule);
    return bwr.chooseRandomRouterByWeight();
  }


  private final static double EPSILON = 0.1;
 
  private void computeFinalWeights(BandwidthWeightedRouters bwr, WeightRule rule) {
    final double exitWeight = calculateWeight(rule == WeightRule.WEIGHT_FOR_EXIT,
        bwr.getTotalExitBandwidth(), bwr.getTotalBandwidth());
    final double guardWeight = calculateWeight(rule == WeightRule.WEIGHT_FOR_GUARD,
        bwr.getTotalGuardBandwidth(), bwr.getTotalBandwidth());
   
    bwr.adjustWeights(exitWeight, guardWeight);
  }

  private double calculateWeight(boolean matchesRule, double totalByType, double total) {
    if(matchesRule || totalByType < EPSILON) {
      return 1.0;
    }
    final double result = 1.0 - (total / (3.0 * totalByType));
    if(result <= 0.0) {
      return 0.0;
    } else {
      return result;
    }
  }

  private long getRouterBandwidthBytes(Router r) {
    if(!r.hasBandwidth()) {
      return  -1;
    } else {
      return kbToBytes(r.getEstimatedBandwidth());
    }
  }

  private long kbToBytes(long bw) {
    return (bw > (Long.MAX_VALUE / 1000) ? Long.MAX_VALUE : bw * 1000);
  }
TOP

Related Classes of com.subgraph.orchid.circuits.path.CircuitNodeChooser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.