Beispiel #1
0
  void disconnect() {
    PeerState s = state;
    if (s != null) {
      // try to save partial piece
      if (this.deregister) {
        PeerListener p = s.listener;
        if (p != null) {
          List<PartialPiece> pcs = s.returnPartialPieces();
          if (!pcs.isEmpty()) p.savePartialPieces(this, pcs);
          // now covered by savePartialPieces
          // p.markUnrequested(this);
        }
      }
      state = null;

      PeerConnectionIn in = s.in;
      if (in != null) in.disconnect();
      PeerConnectionOut out = s.out;
      if (out != null) out.disconnect();
      PeerListener pl = s.listener;
      if (pl != null) pl.disconnected(this);
    }
    I2PSocket csock = sock;
    sock = null;
    if ((csock != null) && (!csock.isClosed())) {
      try {
        csock.close();
      } catch (IOException ioe) {
        _log.warn("Error disconnecting " + toString(), ioe);
      }
    }
  }
  /**
   * Act as a SOCKS 5 client to connect to an outproxy
   *
   * @return open socket or throws error
   * @since 0.8.2
   */
  private I2PSocket outproxyConnect(I2PSOCKSTunnel tun, String proxy)
      throws IOException, SOCKSException, DataFormatException, I2PException {
    Properties overrides = new Properties();
    overrides.setProperty("option.i2p.streaming.connectDelay", "1000");
    I2PSocketOptions proxyOpts = tun.buildOptions(overrides);
    Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(proxy);
    if (dest == null) throw new SOCKSException("Outproxy not found");
    I2PSocket destSock =
        tun.createI2PSocket(
            I2PAppContext.getGlobalContext().namingService().lookup(proxy), proxyOpts);
    try {
      DataOutputStream out = new DataOutputStream(destSock.getOutputStream());
      boolean authAvail =
          Boolean.parseBoolean(props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH));
      String configUser = null;
      String configPW = null;
      if (authAvail) {
        configUser = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER_PREFIX + proxy);
        configPW = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW_PREFIX + proxy);
        if (configUser == null || configPW == null) {
          configUser = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER);
          configPW = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW);
          if (configUser == null || configPW == null) authAvail = false;
        }
      }

      // send the init
      out.writeByte(SOCKS_VERSION_5);
      if (authAvail) {
        out.writeByte(2);
        out.writeByte(Method.NO_AUTH_REQUIRED);
        out.writeByte(Method.USERNAME_PASSWORD);
      } else {
        out.writeByte(1);
        out.writeByte(Method.NO_AUTH_REQUIRED);
      }
      out.flush();

      // read init reply
      DataInputStream in = new DataInputStream(destSock.getInputStream());
      // is this right or should we not try to do 5-to-4 conversion?
      int hisVersion = in.readByte();
      if (hisVersion != SOCKS_VERSION_5 /* && addrtype == AddressType.DOMAINNAME */)
        throw new SOCKSException("SOCKS Outproxy is not Version 5");
      // else if (hisVersion != 4)
      //    throw new SOCKSException("Unsupported SOCKS Outproxy Version");

      int method = in.readByte();
      if (method == Method.NO_AUTH_REQUIRED) {
        // good
      } else if (method == Method.USERNAME_PASSWORD) {
        if (authAvail) {
          // send the auth
          out.writeByte(AUTH_VERSION);
          byte[] user = configUser.getBytes("UTF-8");
          byte[] pw = configPW.getBytes("UTF-8");
          out.writeByte(user.length);
          out.write(user);
          out.writeByte(pw.length);
          out.write(pw);
          out.flush();
          // read the auth reply
          if (in.readByte() != AUTH_VERSION)
            throw new SOCKSException("Bad auth version from outproxy");
          if (in.readByte() != AUTH_SUCCESS)
            throw new SOCKSException("Outproxy authorization failure");
        } else {
          throw new SOCKSException(
              "Outproxy requires authorization, please configure username/password");
        }
      } else {
        throw new SOCKSException("Outproxy authorization failure");
      }

      // send the connect command
      out.writeByte(SOCKS_VERSION_5);
      out.writeByte(Command.CONNECT);
      out.writeByte(0); // reserved
      out.writeByte(addressType);
      if (addressType == AddressType.IPV4) {
        out.write(InetAddress.getByName(connHostName).getAddress());
      } else if (addressType == AddressType.DOMAINNAME) {
        byte[] d = connHostName.getBytes("ISO-8859-1");
        out.writeByte(d.length);
        out.write(d);
      } else {
        // shouldn't happen
        throw new SOCKSException("Unknown address type for outproxy?");
      }
      out.writeShort(connPort);
      out.flush();

      // read the connect reply
      hisVersion = in.readByte();
      if (hisVersion != SOCKS_VERSION_5)
        throw new SOCKSException("Outproxy response is not Version 5");
      int reply = in.readByte();
      in.readByte(); // reserved
      int type = in.readByte();
      int count = 0;
      if (type == AddressType.IPV4) {
        count = 4;
      } else if (type == AddressType.DOMAINNAME) {
        count = in.readUnsignedByte();
      } else if (type == AddressType.IPV6) {
        count = 16;
      } else {
        throw new SOCKSException("Unsupported address type in outproxy response");
      }
      byte[] addr = new byte[count];
      in.readFully(addr); // address
      in.readUnsignedShort(); // port
      if (reply != Reply.SUCCEEDED)
        throw new SOCKSException("Outproxy rejected request, response = " + reply);
      // throw away the address in the response
      // todo pass the response through?
    } catch (IOException e) {
      try {
        destSock.close();
      } catch (IOException ioe) {
      }
      throw e;
    } catch (SOCKSException e) {
      try {
        destSock.close();
      } catch (IOException ioe) {
      }
      throw e;
    }
    // that's it, caller will send confirmation to our client
    return destSock;
  }