Package com.subgraph.orchid.circuits

Source Code of com.subgraph.orchid.circuits.StreamImpl

package com.subgraph.orchid.circuits;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;

import com.subgraph.orchid.Circuit;
import com.subgraph.orchid.CircuitNode;
import com.subgraph.orchid.RelayCell;
import com.subgraph.orchid.Stream;
import com.subgraph.orchid.StreamConnectFailedException;
import com.subgraph.orchid.TorException;
import com.subgraph.orchid.circuits.cells.RelayCellImpl;
import com.subgraph.orchid.dashboard.DashboardRenderable;
import com.subgraph.orchid.dashboard.DashboardRenderer;

public class StreamImpl implements Stream, DashboardRenderable {
  private final static Logger logger = Logger.getLogger(StreamImpl.class.getName());

  private final static int STREAMWINDOW_START = 500;
  private final static int STREAMWINDOW_INCREMENT = 50;
  private final static int STREAMWINDOW_MAX_UNFLUSHED = 10;
 
  private final CircuitImpl circuit;
 
  private final int streamId;
  private final boolean autoclose;
 
  private final CircuitNode targetNode;
  private final TorInputStream inputStream;
  private final TorOutputStream outputStream;
 
  private boolean isClosed;
  private boolean relayEndReceived;
  private int relayEndReason;
  private boolean relayConnectedReceived;
  private final Object waitConnectLock = new Object();
  private final Object windowLock = new Object();
  private int packageWindow;
  private int deliverWindow;

  private String streamTarget = "";
 
  StreamImpl(CircuitImpl circuit, CircuitNode targetNode, int streamId, boolean autoclose) {
    this.circuit = circuit;
    this.targetNode = targetNode;
    this.streamId = streamId;
    this.autoclose = autoclose;
    this.inputStream = new TorInputStream(this);
    this.outputStream = new TorOutputStream(this);
    packageWindow = STREAMWINDOW_START;
    deliverWindow = STREAMWINDOW_START;
  }

  void addInputCell(RelayCell cell) {
    if(isClosed)
      return;
    if(cell.getRelayCommand() == RelayCell.RELAY_END) {
      synchronized(waitConnectLock) {
        relayEndReason = cell.getByte();
        relayEndReceived = true;
        inputStream.addEndCell(cell);
        waitConnectLock.notifyAll();
      }
    } else if(cell.getRelayCommand() == RelayCell.RELAY_CONNECTED) {
      synchronized(waitConnectLock) {
        relayConnectedReceived = true;
        waitConnectLock.notifyAll();
      }
    } else if(cell.getRelayCommand() == RelayCell.RELAY_SENDME) {
      synchronized(windowLock) {
        packageWindow += STREAMWINDOW_INCREMENT;
        windowLock.notifyAll();
      }
    }
    else {
      inputStream.addInputCell(cell);
      synchronized(windowLock) {
        deliverWindow--;
        if(deliverWindow < 0)
          throw new TorException("Stream has negative delivery window");
      }
      considerSendingSendme();
    }
  }

  private void considerSendingSendme() {
    synchronized(windowLock) {
      if(deliverWindow > (STREAMWINDOW_START - STREAMWINDOW_INCREMENT))
        return;

      if(inputStream.unflushedCellCount() >= STREAMWINDOW_MAX_UNFLUSHED)
        return;

      final RelayCell sendme = circuit.createRelayCell(RelayCell.RELAY_SENDME, streamId, targetNode);
      circuit.sendRelayCell(sendme);
      deliverWindow += STREAMWINDOW_INCREMENT;
    }
  }

  public int getStreamId() {
    return streamId;
  }

  public Circuit getCircuit() {
    return circuit;
  }

  public CircuitNode getTargetNode() {
    return targetNode;
  }

  public void close() {
    if(isClosed)
      return;
   
    logger.fine("Closing stream "+ this);
   
    isClosed = true;
    inputStream.close();
    outputStream.close();
    circuit.removeStream(this);
    if(autoclose) {
      circuit.markForClose();
    }
   
    if(!relayEndReceived) {
      final RelayCell cell = new RelayCellImpl(circuit.getFinalCircuitNode(), circuit.getCircuitId(), streamId, RelayCell.RELAY_END);
      cell.putByte(RelayCell.REASON_DONE);
      circuit.sendRelayCellToFinalNode(cell);
    }
  }

  public void openDirectory(long timeout) throws InterruptedException, TimeoutException, StreamConnectFailedException {
    streamTarget = "[Directory]";
    final RelayCell cell = new RelayCellImpl(circuit.getFinalCircuitNode(), circuit.getCircuitId(), streamId, RelayCell.RELAY_BEGIN_DIR);
    circuit.sendRelayCellToFinalNode(cell);
    waitForRelayConnected(timeout);
  }

  void openExit(String target, int port, long timeout) throws InterruptedException, TimeoutException, StreamConnectFailedException {
    streamTarget = target + ":"+ port;
    final RelayCell cell = new RelayCellImpl(circuit.getFinalCircuitNode(), circuit.getCircuitId(), streamId, RelayCell.RELAY_BEGIN);
    cell.putString(target + ":"+ port);
    circuit.sendRelayCellToFinalNode(cell);
    waitForRelayConnected(timeout);
  }
 
  private void waitForRelayConnected(long timeout) throws InterruptedException, TimeoutException, StreamConnectFailedException {
    final long start = System.currentTimeMillis();
    long elapsed = 0;
    synchronized(waitConnectLock) {
      while(!relayConnectedReceived) {

        if(relayEndReceived) {
          throw new StreamConnectFailedException(relayEndReason);
        }

        if(elapsed >= timeout) {
          throw new TimeoutException();
        }

        waitConnectLock.wait(timeout - elapsed);
       
        elapsed = System.currentTimeMillis() - start;
      }
    }
  }

  public InputStream getInputStream() {
    return inputStream;
  }

  public OutputStream getOutputStream() {
    return outputStream;
  }

  public void waitForSendWindowAndDecrement() {
    waitForSendWindow(true);
  }

  public void waitForSendWindow() {
    waitForSendWindow(false);
  }

  public void waitForSendWindow(boolean decrement) {
    synchronized(windowLock) {
      while(packageWindow == 0) {
        try {
          windowLock.wait();
        } catch (InterruptedException e) {
          throw new TorException("Thread interrupted while waiting for stream package window");
        }
      }
      if(decrement)
        packageWindow--;
    }
    targetNode.waitForSendWindow();
  }

  public String toString() {
    return "[Stream stream_id="+ streamId + " circuit="+ circuit +" target="+ streamTarget +"]";
  }

  public void dashboardRender(DashboardRenderer renderer, PrintWriter writer, int flags) throws IOException {
    writer.print("     ");
    writer.print("[Stream stream_id="+ streamId + " cid="+ circuit.getCircuitId());
    if(relayConnectedReceived) {
      writer.print(" sent="+outputStream.getBytesSent() + " recv="+ inputStream.getBytesReceived());
    } else {
      writer.print(" (waiting connect)");
    }
    writer.print(" target="+ streamTarget);
    writer.println("]");
  }
}
TOP

Related Classes of com.subgraph.orchid.circuits.StreamImpl

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.