Package com.subgraph.orchid.circuits.guards

Source Code of com.subgraph.orchid.circuits.guards.Bridges$DescriptorDownloader

package com.subgraph.orchid.circuits.guards;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;

import com.subgraph.orchid.BridgeRouter;
import com.subgraph.orchid.DirectoryDownloader;
import com.subgraph.orchid.Router;
import com.subgraph.orchid.RouterDescriptor;
import com.subgraph.orchid.TorConfig;
import com.subgraph.orchid.config.TorConfigBridgeLine;
import com.subgraph.orchid.crypto.TorRandom;
import com.subgraph.orchid.directory.downloader.DirectoryRequestFailedException;

public class Bridges {
  private static final Logger logger = Logger.getLogger(Bridges.class.getName());
 
  private class DescriptorDownloader implements Runnable {

    private final BridgeRouterImpl target;
   
    DescriptorDownloader(BridgeRouterImpl target) {
      this.target = target;
    }
 
    public void run() {
      try {
        downloadDescriptor();
      } finally {
        decrementOutstandingTasks();
      }
    }
   
    private void downloadDescriptor() {
      logger.fine("Downloading descriptor for bridge: "+ target);
      try {
        final RouterDescriptor descriptor = directoryDownloader.downloadBridgeDescriptor(target);
        if(descriptor != null) {
          logger.fine("Descriptor received for bridge "+ target +". Adding to list of usable bridges");
          target.setDescriptor(descriptor);
          synchronized(lock) {
            bridgeRouters.add(target);
            lock.notifyAll();
          }
        }
      } catch (DirectoryRequestFailedException e) {
        logger.warning("Failed to download descriptor for bridge: "+ e.getMessage());
      }
    }
   
    private void decrementOutstandingTasks() {
      if(outstandingDownloadTasks.decrementAndGet() == 0) {
        logger.fine("Initial descriptor fetch complete");
        synchronized(lock) {
          bridgesInitialized = true;
          lock.notifyAll();
        }
      }
    }
  }

  private final TorConfig config;
  private final DirectoryDownloader directoryDownloader;
 
  private final Set<BridgeRouterImpl> bridgeRouters;
  private final TorRandom random;
  private final Object lock;
 
  /** Initialization started */
  private boolean bridgesInitializing;
  /** Initialization completed */
  private boolean bridgesInitialized;

  private AtomicInteger outstandingDownloadTasks;
 
  Bridges(TorConfig config, DirectoryDownloader directoryDownloader) {
    this.config = config;
    this.directoryDownloader = directoryDownloader;
    this.bridgeRouters = new HashSet<BridgeRouterImpl>();
    this.random = new TorRandom();
    this.lock = new Object();
    this.outstandingDownloadTasks = new AtomicInteger();
  }

  BridgeRouter chooseRandomBridge(Set<Router> excluded) throws InterruptedException {
   
    synchronized(lock) {
      if(!bridgesInitialized && !bridgesInitializing) {
        initializeBridges();
      }
      while(!bridgesInitialized && !hasCandidates(excluded)) {
        lock.wait();
      }
      final List<BridgeRouter> candidates = getCandidates(excluded);
      if(candidates.isEmpty()) {
        logger.warning("Bridges enabled but no usable bridges configured");
        return null;
      }
      return candidates.get(random.nextInt(candidates.size()));
    }
  }

  private boolean hasCandidates(Set<Router> excluded) {
    return !(getCandidates(excluded).isEmpty());
  }
 
  private List<BridgeRouter> getCandidates(Set<Router> excluded) {
    if(bridgeRouters.isEmpty()) {
      return Collections.emptyList();
    }
    final List<BridgeRouter> candidates = new ArrayList<BridgeRouter>(bridgeRouters.size());
    for(BridgeRouter br: bridgeRouters) {
      if(!excluded.contains(br)) {
        candidates.add(br);
      }
    }
    return candidates;
  }

  private void initializeBridges() {
    logger.fine("Initializing bridges...");
    synchronized(lock) {
      if(bridgesInitializing || bridgesInitialized) {
        return;
      }
      if(directoryDownloader == null) {
        throw new IllegalStateException("Cannot download bridge descriptors because DirectoryDownload instance not initialized");
      }
      bridgesInitializing = true;
      startAllDownloadTasks();
    }
  }
 
  private List<Runnable> createDownloadTasks() {
    final List<Runnable> tasks = new ArrayList<Runnable>();
    for(TorConfigBridgeLine line: config.getBridges()) {
      tasks.add(new DescriptorDownloader(createBridgeFromLine(line)));
    }
    return tasks;
  }
 
  private void startAllDownloadTasks() {
    final List<Runnable> tasks = createDownloadTasks();
    outstandingDownloadTasks.set(tasks.size());
    for(Runnable r: tasks) {
      final Thread thread = new Thread(r);
      thread.start();
    }
  }
 
  private BridgeRouterImpl createBridgeFromLine(TorConfigBridgeLine line) {
    final BridgeRouterImpl bridge = new BridgeRouterImpl(line.getAddress(), line.getPort());
    if(line.getFingerprint() != null) {
      bridge.setIdentity(line.getFingerprint());
    }
    return bridge;
  }
}
TOP

Related Classes of com.subgraph.orchid.circuits.guards.Bridges$DescriptorDownloader

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.