/**
   * Destroy the socket manager, freeing all the associated resources. This method will block until
   * all the managed sockets are closed.
   *
   * <p>CANNOT be restarted.
   */
  public void destroySocketManager() {
    if (!_isDestroyed.compareAndSet(false, true)) {
      // shouldn't happen, log a stack trace to find out why it happened
      _log.logCloseLoop("I2PSocketManager", getName());
      return;
    }
    _connectionManager.setAllowIncomingConnections(false);
    _connectionManager.shutdown();
    if (!_subsessions.isEmpty()) {
      for (I2PSession sess : _subsessions) {
        removeSubsession(sess);
      }
    }

    // should we destroy the _session too?
    // yes, since the old lib did (and SAM wants it to, and i dont know why not)
    if ((_session != null) && (!_session.isClosed())) {
      try {
        _session.destroySession();
      } catch (I2PSessionException ise) {
        _log.warn("Unable to destroy the session", ise);
      }
      PcapWriter pcap = null;
      synchronized (_pcapInitLock) {
        pcap = pcapWriter;
      }
      if (pcap != null) pcap.flush();
    }
  }
 /**
  * This updates ALL the session options (not just the bw) and tells the router
  *
  * @param limit KBps
  */
 public void setMaxUpBW(int limit) {
   _maxUpBW = limit;
   _opts.put(PROP_MAX_BW, Integer.toString(limit * (1024 * 6 / 5))); // add a little for overhead
   _configured = true;
   if (_manager != null) {
     I2PSession sess = _manager.getSession();
     if (sess != null) {
       Properties newProps = new Properties();
       newProps.putAll(_opts);
       sess.updateOptions(newProps);
     }
   }
 }
 /**
  * Remove the subsession
  *
  * @since 0.9.21
  */
 public void removeSubsession(I2PSession session) {
   _session.removeSubsession(session);
   boolean removed = _subsessions.remove(session);
   if (removed) {
     if (_log.shouldLog(Log.WARN)) _log.warn("Removeed subsession " + session);
   } else {
     if (_log.shouldLog(Log.WARN)) _log.warn("Subsession not found to remove " + session);
   }
 }
Example #4
0
 /**
  * @param name b64 or b32 or host name
  * @since 0.9.11
  */
 private Destination lookup(String name) {
   I2PAppContext ctx = I2PAppContext.getGlobalContext();
   boolean b32 = name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p");
   if (ctx.isRouterContext() && !b32) {
     // Local lookup.
     // Even though we could do b32 outside router ctx here,
     // we do it below instead so we can use the session,
     // which we can't do with lookup()
     Destination dest = ctx.namingService().lookup(name);
     if (dest != null || ctx.isRouterContext() || name.length() >= 516) return dest;
   }
   try {
     I2PSession sess = sockMgr.getSession();
     return sess.lookupDest(name);
   } catch (I2PSessionException ise) {
     _log.error("Error looking up " + name, ise);
     return null;
   }
 }
  /**
   * Create a new connected socket. Blocks until the socket is created, unless the connectDelay
   * option (i2p.streaming.connectDelay) is set and greater than zero. If so this will return
   * immediately, and the client may quickly write initial data to the socket and this data will be
   * bundled in the SYN packet.
   *
   * @param peer Destination to connect to
   * @param options I2P socket options to be used for connecting, may be null
   * @return I2PSocket if successful
   * @throws NoRouteToHostException if the peer is not found or not reachable
   * @throws I2PException if there is some other I2P-related problem
   */
  public I2PSocket connect(Destination peer, I2PSocketOptions options)
      throws I2PException, NoRouteToHostException {
    if (options == null) options = _defaultOptions;
    ConnectionOptions opts = null;
    if (options instanceof ConnectionOptions)
      opts = new ConnectionOptions((ConnectionOptions) options);
    else opts = new ConnectionOptions(options);

    if (_log.shouldLog(Log.INFO))
      _log.info(
          "Connecting to "
              + peer.calculateHash().toBase64().substring(0, 6)
              + " with options: "
              + opts);
    // pick the subsession here
    I2PSession session = _session;
    if (!_subsessions.isEmpty()) {
      updateUserDsaList();
      Hash h = peer.calculateHash();
      if (_dsaOnly.contains(h) || (!_userDsaOnly.isEmpty() && _userDsaOnly.contains(h))) {
        // FIXME just taking the first one for now
        for (I2PSession sess : _subsessions) {
          if (sess.getMyDestination().getSigType() == SigType.DSA_SHA1) {
            session = sess;
            break;
          }
        }
      }
    }
    verifySession(session);
    // the following blocks unless connect delay > 0
    Connection con = _connectionManager.connect(peer, opts, session);
    if (con == null)
      throw new TooManyStreamsException("Too many streams, max " + _defaultOptions.getMaxConns());
    I2PSocketFull socket = new I2PSocketFull(con, _context);
    con.setSocket(socket);
    if (con.getConnectionError() != null) {
      con.disconnect(false);
      throw new NoRouteToHostException(con.getConnectionError());
    }
    return socket;
  }
 /** Base64 Hash or Hash.i2p or name.i2p using naming service */
 Destination getDestination(String ip) {
   if (ip == null) return null;
   if (ip.endsWith(".i2p")) {
     if (ip.length() < 520) { // key + ".i2p"
       if (_manager != null && ip.length() == BASE32_HASH_LENGTH + 8 && ip.endsWith(".b32.i2p")) {
         // Use existing I2PSession for b32 lookups if we have it
         // This is much more efficient than using the naming service
         I2PSession sess = _manager.getSession();
         if (sess != null) {
           byte[] b = Base32.decode(ip.substring(0, BASE32_HASH_LENGTH));
           if (b != null) {
             // Hash h = new Hash(b);
             Hash h = Hash.create(b);
             if (_log.shouldLog(Log.INFO)) _log.info("Using existing session for lookup of " + ip);
             try {
               return sess.lookupDest(h, 15 * 1000);
             } catch (I2PSessionException ise) {
             }
           }
         }
       }
       if (_log.shouldLog(Log.INFO)) _log.info("Using naming service for lookup of " + ip);
       return _context.namingService().lookup(ip);
     }
     if (_log.shouldLog(Log.INFO)) _log.info("Creating Destination for " + ip);
     try {
       return new Destination(ip.substring(0, ip.length() - 4)); // sans .i2p
     } catch (DataFormatException dfe) {
       return null;
     }
   } else {
     if (_log.shouldLog(Log.INFO)) _log.info("Creating Destination for " + ip);
     try {
       return new Destination(ip);
     } catch (DataFormatException dfe) {
       return null;
     }
   }
 }
 /**
  * Instruct the client that the given session has received a message with size # of bytes.
  *
  * @param session session to notify
  * @param msgId message number available
  * @param size size of the message
  */
 public void messageAvailable(
     I2PSession session, int msgId, long size, int proto, int fromPort, int toPort) {
   byte data[] = null;
   try {
     data = session.receiveMessage(msgId);
   } catch (I2PSessionException ise) {
     _context.statManager().addRateData("stream.packetReceiveFailure", 1);
     if (_log.shouldLog(Log.WARN)) _log.warn("Error receiving the message", ise);
     return;
   }
   if (data == null) return;
   Packet packet = new Packet();
   try {
     packet.readPacket(data, 0, data.length);
     packet.setRemotePort(fromPort);
     packet.setLocalPort(toPort);
     _manager.getPacketHandler().receivePacket(packet);
   } catch (IllegalArgumentException iae) {
     _context.statManager().addRateData("stream.packetReceiveFailure", 1);
     if (_log.shouldLog(Log.WARN)) _log.warn("Received an invalid packet", iae);
   }
 }
 /**
  * @return a new subsession, non-null
  * @param privateKeyStream null for transient, if non-null must have same encryption keys as
  *     primary session and different signing keys
  * @param opts subsession options if any, may be null
  * @since 0.9.21
  */
 public I2PSession addSubsession(InputStream privateKeyStream, Properties opts)
     throws I2PSessionException {
   if (privateKeyStream == null) {
     // We don't actually need the same pubkey in the dest, just in the LS.
     // The dest one is unused. But this is how we find the LS keys
     // to reuse in RequestLeaseSetMessageHandler.
     ByteArrayOutputStream keyStream = new ByteArrayOutputStream(1024);
     try {
       SigType type = getSigType(opts);
       if (type != SigType.DSA_SHA1) {
         // hassle, have to set up the padding and cert, see I2PClientImpl
         throw new I2PSessionException("type " + type + " unsupported");
       }
       PublicKey pub = _session.getMyDestination().getPublicKey();
       PrivateKey priv = _session.getDecryptionKey();
       SimpleDataStructure[] keys = _context.keyGenerator().generateSigningKeys(type);
       pub.writeBytes(keyStream);
       keys[0].writeBytes(keyStream); // signing pub
       Certificate.NULL_CERT.writeBytes(keyStream);
       priv.writeBytes(keyStream);
       keys[1].writeBytes(keyStream); // signing priv
     } catch (Exception e) {
       throw new I2PSessionException("Error creating keys", e);
     }
     privateKeyStream = new ByteArrayInputStream(keyStream.toByteArray());
   }
   I2PSession rv = _session.addSubsession(privateKeyStream, opts);
   boolean added = _subsessions.add(rv);
   if (!added) {
     // shouldn't happen
     _session.removeSubsession(rv);
     throw new I2PSessionException("dup");
   }
   ConnectionOptions defaultOptions = new ConnectionOptions(opts);
   int protocol =
       defaultOptions.getEnforceProtocol() ? I2PSession.PROTO_STREAMING : I2PSession.PROTO_ANY;
   rv.addMuxedSessionListener(
       _connectionManager.getMessageHandler(), protocol, defaultOptions.getLocalPort());
   if (_log.shouldLog(Log.WARN)) _log.warn("Added subsession " + rv);
   return rv;
 }
 /**
  * @return dest or null
  * @since 0.8.4
  */
 Destination getMyDestination() {
   if (_manager == null) return null;
   I2PSession sess = _manager.getSession();
   if (sess != null) return sess.getMyDestination();
   return null;
 }
 /** @since 0.9.21 */
 private void verifySession(I2PSession session) throws I2PException {
   if (_isDestroyed.get()) throw new I2PException("Session was closed");
   if (!session.isClosed()) return;
   session.connect();
 }
 /**
  * @return a list of subsessions, non-null, does not include the primary session
  * @since 0.9.21
  */
 public List<I2PSession> getSubsessions() {
   return _session.getSubsessions();
 }
Example #12
0
 @Override
 public String getPublicDestinationInfo() {
   I2PSession ses = manager.getSession();
   return ses.getMyDestination().toBase64();
 }