From 082922de01b0ae5cc33320fd38410fbc4629a4d0 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Thu, 18 Sep 2014 13:32:27 +0000
Subject: [PATCH] NTCP: Return unused DH keypairs to the pool

---
 .../router/transport/ntcp/EstablishState.java | 54 ++++++++++++++++---
 .../router/transport/ntcp/EventPumper.java    |  4 +-
 .../router/transport/ntcp/NTCPConnection.java | 13 ++++-
 3 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
index a82782560e..facf890f9e 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
@@ -64,6 +64,7 @@ import net.i2p.util.SimpleByteCache;
 class EstablishState {
     
     public static final VerifiedEstablishState VERIFIED = new VerifiedEstablishState();
+    public static final FailedEstablishState FAILED = new FailedEstablishState();
     
     private final RouterContext _context;
     private final Log _log;
@@ -120,7 +121,7 @@ class EstablishState {
     private static final int HXY_SIZE = 32;  //Hash.HASH_LENGTH;
     private static final int HXY_TSB_PAD_SIZE = HXY_SIZE + 4 + 12;  // 48
 
-    private State _state;
+    protected State _state;
 
     private enum State {
         OB_INIT,
@@ -163,7 +164,6 @@ class EstablishState {
         _transport = null;
         _con = null;
         _e_hXY_tsB = null;
-        _state = State.VERIFIED;
     }
 
     public EstablishState(RouterContext ctx, NTCPTransport transport, NTCPConnection con) {
@@ -900,6 +900,15 @@ class EstablishState {
      */
     public synchronized byte[] getExtraBytes() { return _extra; }
 
+    /**
+     *  Release resources on timeout.
+     *  @param e may be null
+     *  @since 0.9.16
+     */
+    public synchronized void close(String reason, Exception e) {
+        fail(reason, e);
+    }
+
     /** Caller must synch. */
     private void fail(String reason) { fail(reason, null); }
 
@@ -919,7 +928,10 @@ class EstablishState {
         releaseBufs();
     }
 
-    /** Only call once. Caller must synch. */
+    /**
+     *  Only call once. Caller must synch.
+     *  @since 0.9.16
+     */
     private void releaseBufs() {
         // null or longer for OB
         if (_prevEncrypted != null && _prevEncrypted.length == AES_SIZE)
@@ -927,8 +939,12 @@ class EstablishState {
         SimpleByteCache.release(_curEncrypted);
         SimpleByteCache.release(_curDecrypted);
         SimpleByteCache.release(_hX_xor_bobIdentHash);
-        SimpleByteCache.release(_X);
-        SimpleByteCache.release(_Y);
+        if (_dh.getPeerPublicValue() == null)
+            _transport.returnUnused(_dh);
+        if (_con.isInbound())
+            SimpleByteCache.release(_X);
+        else
+            SimpleByteCache.release(_Y);
     }
 
     public synchronized String getError() { return _err; }
@@ -1024,12 +1040,36 @@ class EstablishState {
      *  @since 0.9.8
      */
     private static class VerifiedEstablishState extends EstablishState {
-        @Override public boolean isComplete() { return true; }
+
+        public VerifiedEstablishState() {
+            super();
+            _state = State.VERIFIED;
+        }
+
+        @Override public void prepareOutbound() {
+            Log log =RouterContext.getCurrentContext().logManager().getLog(VerifiedEstablishState.class);
+            log.warn("prepareOutbound() on verified state, doing nothing!");
+        }
+
+        @Override public String toString() { return "VerifiedEstablishState";}
+    }
+
+    /**
+     *  @since 0.9.16
+     */
+    private static class FailedEstablishState extends EstablishState {
+
+        public FailedEstablishState() {
+            super();
+            _state = State.CORRUPT;
+        }
+
         @Override public void prepareOutbound() {
             Log log =RouterContext.getCurrentContext().logManager().getLog(VerifiedEstablishState.class);
             log.warn("prepareOutbound() on verified state, doing nothing!");
         }
-        @Override public String toString() { return "VerfiedEstablishState";}
+
+        @Override public String toString() { return "FailedEstablishState";}
     }
 
     /** @deprecated unused */
diff --git a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
index 607234ae70..b6f539c962 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
@@ -532,14 +532,14 @@ class EventPumper implements Runnable {
                 con.outboundConnected();
                 _context.statManager().addRateData("ntcp.connectSuccessful", 1);
             } else {
-                con.close();
+                con.closeOnTimeout("connect failed", null);
                 _transport.markUnreachable(con.getRemotePeer().calculateHash());
                 _context.statManager().addRateData("ntcp.connectFailedTimeout", 1);
             }
         } catch (IOException ioe) {   // this is the usual failure path for a timeout or connect refused
             if (_log.shouldLog(Log.INFO))
                 _log.info("Failed outbound " + con, ioe);
-            con.close();
+            con.closeOnTimeout("connect failed", ioe);
             //_context.banlist().banlistRouter(con.getRemotePeer().calculateHash(), "Error connecting", NTCPTransport.STYLE);
             _transport.markUnreachable(con.getRemotePeer().calculateHash());
             _context.statManager().addRateData("ntcp.connectFailedTimeoutIOE", 1);
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
index acd5570e38..0e6ad83234 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
@@ -371,10 +371,21 @@ class NTCPConnection {
         }
     }
     
+    /**
+     *  Close and release EstablishState resources.
+     *  @param e may be null
+     *  @since 0.9.16
+     */
+    public void closeOnTimeout(String cause, Exception e) {
+        EstablishState es = _establishState;
+        close();
+        es.close(cause, e);
+    }
+
     private synchronized NTCPConnection locked_close(boolean allowRequeue) {
         if (_chan != null) try { _chan.close(); } catch (IOException ioe) { }
         if (_conKey != null) _conKey.cancel();
-        _establishState = EstablishState.VERIFIED;
+        _establishState = EstablishState.FAILED;
         NTCPConnection old = _transport.removeCon(this);
         _transport.getReader().connectionClosed(this);
         _transport.getWriter().connectionClosed(this);
-- 
GitLab