diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index 75a276aa0..3a557c5a1 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -118,8 +118,8 @@ public class I2PTunnel implements Logging, EventDispatcher { _tunnelId = ++__tunnelId; _log = _context.logManager().getLog(I2PTunnel.class); _event = new EventDispatcherImpl(); - Properties p = new Properties(); - p.putAll(System.getProperties()); + // as of 0.8.4, include context properties + Properties p = _context.getProperties(); _clientOptions = p; _sessions = new ArrayList(1); diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/ByteCollector.java b/apps/ministreaming/java/src/net/i2p/client/streaming/ByteCollector.java index 39249b449..38d96ddb7 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/ByteCollector.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/ByteCollector.java @@ -4,6 +4,7 @@ package net.i2p.client.streaming; * Like a StringBuffer, but for bytes. This class is not internally synchronized, * so care should be taken when using in a multithreaded environment. * + * @deprecated Only used by deprecated I2PSocketImpl */ class ByteCollector { byte[] contents; @@ -294,4 +295,4 @@ class ByteCollector { size = 0; return bb; } -} \ No newline at end of file +} diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java index 02bef1a0a..1651d40d2 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java @@ -4,9 +4,12 @@ */ package net.i2p.client.streaming; +import java.io.IOException; import java.io.InterruptedIOException; import java.net.ConnectException; import java.net.NoRouteToHostException; +import java.net.ServerSocket; +import java.net.Socket; import java.util.Properties; import java.util.Set; @@ -84,7 +87,7 @@ public interface I2PSocketManager { * * @return a set of currently connected I2PSockets */ - public Set listSockets(); + public Set listSockets(); /** * Ping the specified peer, returning true if they replied to the ping within @@ -107,4 +110,25 @@ public interface I2PSocketManager { public static interface DisconnectListener { public void sessionDisconnected(); } + + /** + * Like getServerSocket but returns a real ServerSocket for easier porting of apps. + * @since 0.8.4 + */ + public ServerSocket getStandardServerSocket() throws IOException; + + /** + * Like connect() but returns a real Socket, and throws only IOE, + * for easier porting of apps. + * @since 0.8.4 + */ + public Socket connectToSocket(Destination peer) throws IOException; + + /** + * Like connect() but returns a real Socket, and throws only IOE, + * for easier porting of apps. + * @param timeout ms if > 0, forces blocking (disables connectDelay) + * @since 0.8.4 + */ + public Socket connectToSocket(Destination peer, int timeout) throws IOException; } diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerImpl.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerImpl.java index fb2589b52..e0a5b022f 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerImpl.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerImpl.java @@ -10,6 +10,8 @@ import java.io.InterruptedIOException; import java.io.UnsupportedEncodingException; import java.net.ConnectException; import java.net.NoRouteToHostException; +import java.net.ServerSocket; +import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -461,6 +463,14 @@ class I2PSocketManagerImpl implements I2PSocketManager, I2PSessionListener { return _serverSocket; } + /** + * @throws UnsupportedOperationException + * @since 0.8.4 + */ + public ServerSocket getStandardServerSocket() { + throw new UnsupportedOperationException(); + } + /** * Create a new connected socket (block until the socket is created) * @@ -601,6 +611,22 @@ class I2PSocketManagerImpl implements I2PSocketManager, I2PSessionListener { return connect(peer, null); } + /** + * @throws UnsupportedOperationException + * @since 0.8.4 + */ + public Socket connectToSocket(Destination peer) { + throw new UnsupportedOperationException(); + } + + /** + * @throws UnsupportedOperationException + * @since 0.8.4 + */ + public Socket connectToSocket(Destination peer, int timeout) { + throw new UnsupportedOperationException(); + } + /** * Destroy the socket manager, freeing all the associated resources. This * method will block untill all the managed sockets are closed. @@ -660,7 +686,7 @@ class I2PSocketManagerImpl implements I2PSocketManager, I2PSessionListener { * Retrieve a set of currently connected I2PSockets, either initiated locally or remotely. * */ - public Set listSockets() { + public Set listSockets() { Set sockets = new HashSet(8); synchronized (lock) { sockets.addAll(_inSockets.values()); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java index 9388d06d2..6dd3aa987 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java @@ -100,7 +100,7 @@ public class ConfigNetHelper extends HelperBase { } public String getTcpAutoIPChecked(int mode) { - boolean enabled = TransportManager.enableNTCP(_context); + boolean enabled = TransportManager.isNTCPEnabled(_context); String hostname = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME); boolean specified = hostname != null && hostname.length() > 0; String auto = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "false"); diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java index 69ace81a2..10ff38856 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java @@ -40,7 +40,7 @@ class ConnectionManager { private int _maxConcurrentStreams; private ConnectionOptions _defaultOptions; private volatile int _numWaiting; - private long SoTimeout; + private long _soTimeout; private ConnThrottler _minuteThrottler; private ConnThrottler _hourThrottler; private ConnThrottler _dayThrottler; @@ -64,7 +64,7 @@ class ConnectionManager { _allowIncoming = false; _numWaiting = 0; /** Socket timeout for accept() */ - SoTimeout = -1; + _soTimeout = -1; _context.statManager().createRateStat("stream.con.lifetimeMessagesSent", "How many messages do we send on a stream?", "Stream", new long[] { 60*60*1000, 24*60*60*1000 }); _context.statManager().createRateStat("stream.con.lifetimeMessagesReceived", "How many messages do we receive on a stream?", "Stream", new long[] { 60*60*1000, 24*60*60*1000 }); @@ -97,16 +97,16 @@ class ConnectionManager { * Set the socket accept() timeout. * @param x */ - public void MsetSoTimeout(long x) { - SoTimeout = x; + public void setSoTimeout(long x) { + _soTimeout = x; } /** * Get the socket accept() timeout. * @return accept timeout in ms. */ - public long MgetSoTimeout() { - return SoTimeout; + public long getSoTimeout() { + return _soTimeout; } public void setAllowIncomingConnections(boolean allow) { diff --git a/apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java b/apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java index acb58fe15..71e1dd3ac 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java @@ -26,11 +26,11 @@ class I2PServerSocketFull implements I2PServerSocket { } public long getSoTimeout() { - return _socketManager.getConnectionManager().MgetSoTimeout(); + return _socketManager.getConnectionManager().getSoTimeout(); } public void setSoTimeout(long x) { - _socketManager.getConnectionManager().MsetSoTimeout(x); + _socketManager.getConnectionManager().setSoTimeout(x); } /** * Close the connection. diff --git a/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketFull.java b/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketFull.java index dfcfacfa1..f8dbe74ea 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketFull.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketFull.java @@ -46,6 +46,10 @@ class I2PSocketFull implements I2PSocket { Connection getConnection() { return _connection; } + /** + * Warning, may return null instead of throwing IOE, + * which is not what the interface says. + */ public InputStream getInputStream() { Connection c = _connection; if (c != null) @@ -62,6 +66,10 @@ class I2PSocketFull implements I2PSocket { return null; } + /** + * Warning, may return null instead of throwing IOE, + * which is not what the interface says. + */ public OutputStream getOutputStream() throws IOException { Connection c = _connection; if (c != null) diff --git a/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java b/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java index 03abafdda..573354e89 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java @@ -1,6 +1,9 @@ package net.i2p.client.streaming; +import java.io.IOException; import java.net.NoRouteToHostException; +import java.net.ServerSocket; +import java.net.Socket; import java.net.SocketTimeoutException; import java.util.HashSet; import java.util.Iterator; @@ -30,6 +33,7 @@ public class I2PSocketManagerFull implements I2PSocketManager { private Log _log; private I2PSession _session; private I2PServerSocketFull _serverSocket; + private StandardServerSocket _realServerSocket; private ConnectionOptions _defaultOptions; private long _acceptTimeout; private String _name; @@ -44,8 +48,6 @@ public class I2PSocketManagerFull implements I2PSocketManager { private static final long ACCEPT_TIMEOUT_DEFAULT = 5*1000; public I2PSocketManagerFull() { - _context = null; - _session = null; } /** @@ -120,7 +122,7 @@ public class I2PSocketManagerFull implements I2PSocketManager { */ public I2PSocket receiveSocket() throws I2PException, SocketTimeoutException { verifySession(); - Connection con = _connectionManager.getConnectionHandler().accept(_connectionManager.MgetSoTimeout()); + Connection con = _connectionManager.getConnectionHandler().accept(_connectionManager.getSoTimeout()); if(_log.shouldLog(Log.DEBUG)) { _log.debug("receiveSocket() called: " + con); } @@ -129,7 +131,7 @@ public class I2PSocketManagerFull implements I2PSocketManager { con.setSocket(sock); return sock; } else { - if(_connectionManager.MgetSoTimeout() == -1) { + if(_connectionManager.getSoTimeout() == -1) { return null; } throw new SocketTimeoutException("I2PSocket timed out"); @@ -171,6 +173,17 @@ public class I2PSocketManagerFull implements I2PSocketManager { return _serverSocket; } + /** + * Like getServerSocket but returns a real ServerSocket for easier porting of apps. + * @since 0.8.4 + */ + public synchronized ServerSocket getStandardServerSocket() throws IOException { + if (_realServerSocket == null) + _realServerSocket = new StandardServerSocket(_serverSocket); + _connectionManager.setAllowIncomingConnections(true); + return _realServerSocket; + } + private void verifySession() throws I2PException { if (!_connectionManager.getSession().isClosed()) return; @@ -185,7 +198,7 @@ public class I2PSocketManagerFull implements I2PSocketManager { * 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 + * @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 @@ -235,6 +248,45 @@ public class I2PSocketManagerFull implements I2PSocketManager { return connect(peer, _defaultOptions); } + /** + * Like connect() but returns a real Socket, and throws only IOE, + * for easier porting of apps. + * @since 0.8.4 + */ + public Socket connectToSocket(Destination peer) throws IOException { + return connectToSocket(peer, _defaultOptions); + } + + /** + * Like connect() but returns a real Socket, and throws only IOE, + * for easier porting of apps. + * @param timeout ms if > 0, forces blocking (disables connectDelay) + * @since 0.8.4 + */ + public Socket connectToSocket(Destination peer, int timeout) throws IOException { + ConnectionOptions opts = new ConnectionOptions(_defaultOptions); + opts.setConnectTimeout(timeout); + if (timeout > 0) + opts.setConnectDelay(-1); + return connectToSocket(peer, opts); + } + + /** + * Like connect() but returns a real Socket, and throws only IOE, + * for easier porting of apps. + * @param options may be null + * @since 0.8.4 + */ + private Socket connectToSocket(Destination peer, I2PSocketOptions options) throws IOException { + try { + I2PSocket sock = connect(peer, options); + return new StandardSocket(sock); + } catch (I2PException i2pe) { + // fixme in 1.6 change to cause + throw new IOException(i2pe.toString()); + } + } + /** * Destroy the socket manager, freeing all the associated resources. This * method will block untill all the managed sockets are closed. @@ -259,11 +311,10 @@ public class I2PSocketManagerFull implements I2PSocketManager { * * @return set of currently connected I2PSockets */ - public Set listSockets() { - Set connections = _connectionManager.listConnections(); - Set rv = new HashSet(connections.size()); - for (Iterator iter = connections.iterator(); iter.hasNext(); ) { - Connection con = (Connection)iter.next(); + public Set listSockets() { + Set connections = _connectionManager.listConnections(); + Set rv = new HashSet(connections.size()); + for (Connection con : connections) { if (con.getSocket() != null) rv.add(con.getSocket()); } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/StandardServerSocket.java b/apps/streaming/java/src/net/i2p/client/streaming/StandardServerSocket.java new file mode 100644 index 000000000..937973afe --- /dev/null +++ b/apps/streaming/java/src/net/i2p/client/streaming/StandardServerSocket.java @@ -0,0 +1,168 @@ +package net.i2p.client.streaming; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.channels.ServerSocketChannel; + +import net.i2p.I2PException; + +/** + * Bridge to I2PServerSocket. + * + * This extends ServerSocket to make porting apps easier. + * accept() returns a real Socket (a StandardSocket). + * accept() throws IOExceptions like ServerSockets do, rather than returning + * null or throwing I2PExceptions. + * + * StandardServerSockets are always bound. + * You may not create an unbound StandardServerSocket. + * Create this through the SocketManager. + * + * @since 0.8.4 + */ +class StandardServerSocket extends ServerSocket { + private final I2PServerSocketFull _socket; + + /** + * Doesn't really throw IOE but super() does + */ + StandardServerSocket(I2PServerSocketFull socket) throws IOException { + _socket = socket; + } + + public Socket accept() throws IOException { + try { + I2PSocket sock = _socket.accept(); + if (sock == null) + throw new IOException("No socket"); + return new StandardSocket(sock); + } catch (I2PException i2pe) { + // fixme in 1.6 change to cause + throw new IOException(i2pe.toString()); + } + } + + /** + * @throws UnsupportedOperationException always + */ + @Override + public void bind(SocketAddress endpoint) { + throw new UnsupportedOperationException(); + } + + /** + * @throws UnsupportedOperationException always + */ + @Override + public void bind(SocketAddress endpoint, int backlog) { + throw new UnsupportedOperationException(); + } + + @Override + public void close() throws IOException { + if (isClosed()) + throw new IOException("Already closed"); + _socket.close(); + } + + /** + * @return null always + */ + @Override + public ServerSocketChannel getChannel() { + return null; + } + + /** + * @return null always + */ + @Override + public InetAddress getInetAddress() { + return null; + } + + /** + * @return -1 always + */ + @Override + public int getLocalPort() { + return -1; + } + + /** + * @return null always + */ + @Override + public SocketAddress getLocalSocketAddress() { + return null; + } + + @Override + public int getReceiveBufferSize() { + ConnectionOptions opts = (ConnectionOptions) ((I2PSocketManagerFull)_socket.getManager()).getDefaultOptions(); + if (opts == null) + return 64*1024; + return opts.getInboundBufferSize(); + } + + /** + * @return false always + */ + @Override + public boolean getReuseAddress() { + return false; + } + + @Override + public int getSoTimeout() { + return (int) _socket.getSoTimeout(); + } + + /** + * @return true always + */ + @Override + public boolean isBound() { + return true; + } + + @Override + public boolean isClosed() { + return ((I2PSocketManagerFull)_socket.getManager()).getConnectionManager().getAllowIncomingConnections(); + } + + /** + * Does nothing. + */ + @Override + public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { + } + + /** + * Does nothing. + */ + @Override + public void setReceiveBufferSize(int size) { + } + + /** + * Does nothing. + */ + @Override + public void setReuseAddress(boolean on) { + } + + @Override + public void setSoTimeout(int timeout) throws SocketException { + _socket.setSoTimeout(timeout); + } + + @Override + public String toString() { + return _socket.toString(); + } +} diff --git a/apps/streaming/java/src/net/i2p/client/streaming/StandardSocket.java b/apps/streaming/java/src/net/i2p/client/streaming/StandardSocket.java new file mode 100644 index 000000000..3c743d7eb --- /dev/null +++ b/apps/streaming/java/src/net/i2p/client/streaming/StandardSocket.java @@ -0,0 +1,338 @@ +package net.i2p.client.streaming; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.channels.SocketChannel; + +import net.i2p.I2PException; + +/** + * Bridge to I2PSocket. + * + * This extends Socket to make porting apps easier. + * Methods throw IOExceptions like Sockets do, rather than returning + * null for some methods. + * + * StandardSockets are always bound, and always start out connected + * (unless connectDelay is > 0). + * You may not create an unbound StandardSocket. + * Create this through the SocketManager. + * + * @since 0.8.4 + */ +class StandardSocket extends Socket { + private final I2PSocket _socket; + + StandardSocket(I2PSocket socket) { + _socket = socket; + } + + /** + * @throws UnsupportedOperationException always + */ + @Override + public void bind(SocketAddress bindpoint) { + throw new UnsupportedOperationException(); + } + + @Override + public void close() throws IOException { + if (_socket.isClosed()) + throw new IOException("Already closed"); + _socket.close(); + } + + /** + * @throws UnsupportedOperationException always + */ + @Override + public void connect(SocketAddress endpoint) { + throw new UnsupportedOperationException(); + } + + /** + * @throws UnsupportedOperationException always + */ + @Override + public void connect(SocketAddress endpoint, int timeout) { + throw new UnsupportedOperationException(); + } + + /** + * @return null always + */ + @Override + public SocketChannel getChannel() { + return null; + } + + /** + * @return null always + */ + @Override + public InetAddress getInetAddress() { + return null; + } + + @Override + public InputStream getInputStream() throws IOException { + InputStream rv = _socket.getInputStream(); + if (rv != null) + return rv; + throw new IOException("No stream"); + } + + @Override + public boolean getKeepAlive() { + ConnectionOptions opts = (ConnectionOptions) _socket.getOptions(); + if (opts == null) + return false; + return opts.getInactivityAction() == ConnectionOptions.INACTIVITY_ACTION_SEND; + } + + /** + * @return null always + */ + @Override + public InetAddress getLocalAddress() { + return null; + } + + /** + * @return -1 always + */ + @Override + public int getLocalPort() { + return -1; + } + + /** + * @return null always + */ + @Override + public SocketAddress getLocalSocketAddress() { + return null; + } + + /** + * @return false always + */ + @Override + public boolean getOOBInline() { + return false; + } + + @Override + public OutputStream getOutputStream() throws IOException { + OutputStream rv = _socket.getOutputStream(); + if (rv != null) + return rv; + throw new IOException("Mo stream"); + } + + /** + * @return 0 always + */ + @Override + public int getPort() { + return 0; + } + + @Override + public int getReceiveBufferSize() { + ConnectionOptions opts = (ConnectionOptions) _socket.getOptions(); + if (opts == null) + return 64*1024; + return opts.getInboundBufferSize(); + } + + /** + * @throws UnsupportedOperationException always + */ + @Override + public SocketAddress getRemoteSocketAddress() { + throw new UnsupportedOperationException(); + } + + /** + * @return false always + */ + @Override + public boolean getReuseAddress() { + return false; + } + + @Override + public int getSendBufferSize() { + ConnectionOptions opts = (ConnectionOptions) _socket.getOptions(); + if (opts == null) + return 64*1024; + return opts.getInboundBufferSize(); + } + + @Override + public int getSoLinger() { + I2PSocketOptions opts = _socket.getOptions(); + if (opts == null) + return -1; + return -1; // fixme really? + } + + @Override + public int getSoTimeout() { + I2PSocketOptions opts = _socket.getOptions(); + if (opts == null) + return 0; + return (int) opts.getReadTimeout(); + } + + /** + * @return false always + */ + @Override + public boolean getTcpNoDelay() { + // No option yet. See ConnectionDataReceiver + return false; + } + + /** + * @return 0 always + */ + @Override + public int getTrafficClass() { + return 0; + } + + /** + * @return true always + */ + @Override + public boolean isBound() { + return true; + } + + @Override + public boolean isClosed() { + return _socket.isClosed(); + } + + @Override + public boolean isConnected() { + return !_socket.isClosed(); + } + + @Override + public boolean isInputShutdown() { + return _socket.isClosed(); + } + + @Override + public boolean isOutputShutdown() { + return _socket.isClosed(); + } + + /** + * @throws UnsupportedOperationException always + */ + @Override + public void sendUrgentData(int data) { + throw new UnsupportedOperationException(); + } + + @Override + public void setKeepAlive(boolean on) { + ConnectionOptions opts = (ConnectionOptions) _socket.getOptions(); + if (opts == null) + return; + if (on) + opts.setInactivityAction(ConnectionOptions.INACTIVITY_ACTION_SEND); + else + opts.setInactivityAction(ConnectionOptions.INACTIVITY_ACTION_NOOP); // DISCONNECT? + } + + /** + * @throws UnsupportedOperationException if on is true + */ + @Override + public void setOOBInline(boolean on) { + if (on) + throw new UnsupportedOperationException(); + } + + /** + * Does nothing. + */ + @Override + public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { + } + + /** + * Does nothing. + */ + @Override + public void setReceiveBufferSize(int size) { + } + + /** + * Does nothing. + */ + @Override + public void setReuseAddress(boolean on) { + } + + /** + * Does nothing. + */ + @Override + public void setSendBufferSize(int size) { + } + + /** + * Does nothing. + */ + @Override + public void setSoLinger(boolean on, int linger) { + } + + @Override + public void setSoTimeout(int timeout) throws SocketException { + I2PSocketOptions opts = _socket.getOptions(); + if (opts == null) + throw new SocketException("No options"); + opts.setReadTimeout(timeout); + } + + /** + * Does nothing. + */ + @Override + public void setTcpNoDelay(boolean on) { + } + + /** + * Does nothing. + */ + @Override + public void setTrafficClass(int tc) { + } + + @Override + public void shutdownInput() throws IOException { + close(); + } + + @Override + public void shutdownOutput() throws IOException { + close(); + } + + @Override + public String toString() { + return _socket.toString(); + } +} diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index e6df37e6f..e5ec21c75 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -63,7 +63,7 @@ import net.i2p.util.SecureDirectory; */ public class I2PAppContext { /** the context that components without explicit root are bound */ - protected static I2PAppContext _globalAppContext; + protected static volatile I2PAppContext _globalAppContext; private Properties _overrideProps; @@ -117,7 +117,8 @@ public class I2PAppContext { * */ public static I2PAppContext getGlobalContext() { - // skip the global lock + // skip the global lock - _gAC must be volatile + // http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html I2PAppContext rv = _globalAppContext; if (rv != null) return rv; @@ -474,6 +475,9 @@ public class I2PAppContext { * provided during the context construction, as well as the ones included in * System.getProperties. * + * WARNING - not overridden in RouterContext, doesn't contain router config settings, + * use getProperties() instead. + * * @return set of Strings containing the names of defined system properties */ public Set getPropertyNames() { @@ -483,6 +487,21 @@ public class I2PAppContext { return names; } + /** + * Access the configuration attributes of this context, listing the properties + * provided during the context construction, as well as the ones included in + * System.getProperties. + * + * @return new Properties with system and context properties + * @since 0.8.4 + */ + public Properties getProperties() { + Properties rv = new Properties(); + rv.putAll(System.getProperties()); + rv.putAll(_overrideProps); + return rv; + } + /** * The statistics component with which we can track various events * over time. diff --git a/core/java/src/net/i2p/client/I2CPMessageProducer.java b/core/java/src/net/i2p/client/I2CPMessageProducer.java index 0fa35d8cf..f9840c5c3 100644 --- a/core/java/src/net/i2p/client/I2CPMessageProducer.java +++ b/core/java/src/net/i2p/client/I2CPMessageProducer.java @@ -12,6 +12,8 @@ package net.i2p.client; import java.util.Date; import java.util.Properties; import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; import net.i2p.I2PAppContext; import net.i2p.data.DataFormatException; @@ -41,22 +43,51 @@ import net.i2p.util.Log; * @author jrandom */ class I2CPMessageProducer { - private final static Log _log = new Log(I2CPMessageProducer.class); + private final Log _log; private final I2PAppContext _context; - private int _sendBps; - private long _sendPeriodBytes; - private long _sendPeriodBeginTime; + private int _maxBytesPerSecond; + private volatile int _sendPeriodBytes; + private volatile long _sendPeriodBeginTime; + private final ReentrantLock _lock; + private static final String PROP_MAX_BW = "i2cp.outboundBytesPerSecond"; + /** see ConnectionOptions in streaming - MTU + streaming overhead + gzip overhead */ + private static final int TYP_SIZE = 1730 + 28 + 23; + private static final int MIN_RATE = 2 * TYP_SIZE; public I2CPMessageProducer(I2PAppContext context) { _context = context; - context.statManager().createRateStat("client.sendBpsRaw", "How fast we pump out I2CP data messages", "ClientMessages", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 }); + _log = context.logManager().getLog(I2CPMessageProducer.class); + _lock = new ReentrantLock(true); + context.statManager().createRateStat("client.sendThrottled", "Times waited for bandwidth", "ClientMessages", new long[] { 60*1000 }); + context.statManager().createRateStat("client.sendDropped", "Length of msg dropped waiting for bandwidth", "ClientMessages", new long[] { 60*1000 }); } + /** + * Update the bandwidth setting + * @since 0.8.4 + */ + public void updateBandwidth(I2PSessionImpl session) { + String max = session.getOptions().getProperty(PROP_MAX_BW); + if (max != null) { + try { + int iMax = Integer.parseInt(max); + if (iMax > 0) + // round up to next higher TYP_SIZE for efficiency, then add some fudge for small messages + _maxBytesPerSecond = 256 + Math.max(MIN_RATE, TYP_SIZE * ((iMax + TYP_SIZE - 1) / TYP_SIZE)); + else + _maxBytesPerSecond = 0; + } catch (NumberFormatException nfe) {} + } + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Setting " + _maxBytesPerSecond + " BPS max"); + } + /** * Send all the messages that a client needs to send to a router to establish * a new session. */ public void connect(I2PSessionImpl session) throws I2PSessionException { + updateBandwidth(session); CreateSessionMessage msg = new CreateSessionMessage(); SessionConfig cfg = new SessionConfig(session.getMyDestination()); cfg.setOptions(session.getOptions()); @@ -99,6 +130,9 @@ class I2CPMessageProducer { */ public void sendMessage(I2PSessionImpl session, Destination dest, long nonce, byte[] payload, SessionTag tag, SessionKey key, Set tags, SessionKey newKey, long expires) throws I2PSessionException { + if (!updateBps(payload.length, expires)) + // drop the message... send fail notification? + return; SendMessageMessage msg; if (expires > 0) { msg = new SendMessageExpiresMessage(); @@ -111,20 +145,108 @@ class I2CPMessageProducer { Payload data = createPayload(dest, payload, tag, key, tags, newKey); msg.setPayload(data); session.sendMessage(msg); - updateBps(payload.length); } - private void updateBps(int len) { - long now = _context.clock().now(); - float period = ((float)now-_sendPeriodBeginTime)/1000f; - if (period >= 1f) { - // first term decays on slow transmission - _sendBps = (int)(((float)0.9f * (float)_sendBps) + ((float)0.1f*((float)_sendPeriodBytes)/period)); - _sendPeriodBytes = len; - _sendPeriodBeginTime = now; - _context.statManager().addRateData("client.sendBpsRaw", _sendBps, 0); - } else { - _sendPeriodBytes += len; + /** + * Super-simple bandwidth throttler. + * We only calculate on a one-second basis, so large messages + * (compared to the one-second limit) may exceed the limits. + * Tuned for streaming, may not work well for large datagrams. + * + * This does poorly with low rate limits since it doesn't credit + * bandwidth across two periods. So the limit is rounded up, + * and the min limit is set to 2x the typ size, above. + * + * Blocking so this could be very bad for retransmissions, + * as it could clog StreamingTimer. + * Waits are somewhat "fair" using ReentrantLock. + * While out-of-order transmission is acceptable, fairness + * reduces the chance of starvation. ReentrantLock does not + * guarantee in-order execution due to thread priority issues, + * so out-of-order may still occur. But shouldn't happen within + * the same thread anyway... Also note that small messages may + * go ahead of large ones that are waiting for the next window. + * Also, threads waiting a second time go to the back of the line. + * + * Since this is at the I2CP layer, it includes streaming overhead, + * streaming acks and retransmissions, + * gzip overhead (or "underhead" for compression), + * repliable datagram overhead, etc. + * However, it does not, of course, include the substantial overhead + * imposed by the router for the leaseset, tags, encryption, + * and fixed-size tunnel messages. + * + * @param expires if > 0, an expiration date + * @return true if we should send the message, false to drop it + */ + private boolean updateBps(int len, long expires) { + if (_maxBytesPerSecond <= 0) + return true; + //synchronized(this) { + _lock.lock(); + try { + int waitCount = 0; + while (true) { + long now = _context.clock().now(); + if (waitCount > 0 && expires > 0 && expires < now) { + // just say no to bufferbloat... drop the message right here + _context.statManager().addRateData("client.sendDropped", len, 0); + if (_log.shouldLog(Log.WARN)) + _log.warn("Dropping " + len + " byte msg expired in queue"); + return false; + } + + long period = now - _sendPeriodBeginTime; + if (period >= 2000) { + // start new period, always let it through no matter how big + _sendPeriodBytes = len; + _sendPeriodBeginTime = now; + if (_log.shouldLog(Log.DEBUG)) + _log.debug("New period after idle, " + len + " bytes"); + return true; + } + + if (period >= 1000) { + // start new period + // Allow burst within 2 sec, only advance window by 1 sec, and + // every other second give credit for unused bytes in previous period + if (_sendPeriodBytes > 0 && ((_sendPeriodBeginTime / 1000) & 0x01) == 0) + _sendPeriodBytes += len - _maxBytesPerSecond; + else + _sendPeriodBytes = len; + _sendPeriodBeginTime += 1000; + if (_log.shouldLog(Log.DEBUG)) + _log.debug("New period, " + len + " bytes"); + return true; + } + + if (_sendPeriodBytes + len <= _maxBytesPerSecond) { + // still bytes available in this period + _sendPeriodBytes += len; + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Sending " + len + ", Elapsed " + period + "ms, total " + _sendPeriodBytes + " bytes"); + return true; + } + + if (waitCount >= 2) { + // just say no to bufferbloat... drop the message right here + _context.statManager().addRateData("client.sendDropped", len, 0); + if (_log.shouldLog(Log.WARN)) + _log.warn("Dropping " + len + " byte msg after waiting " + waitCount + " times"); + return false; + } + + // wait until next period + _context.statManager().addRateData("client.sendThrottled", ++waitCount, 0); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Throttled " + len + " bytes, wait #" + waitCount + ' ' + (1000 - period) + "ms" /*, new Exception()*/); + try { + //this.wait(1000 - period); + _lock.newCondition().await(1000 - period, TimeUnit.MILLISECONDS); + } catch (InterruptedException ie) {} + } + } finally { + _lock.unlock(); } } diff --git a/core/java/src/net/i2p/client/I2PSession.java b/core/java/src/net/i2p/client/I2PSession.java index cd20cfc2d..27138b884 100644 --- a/core/java/src/net/i2p/client/I2PSession.java +++ b/core/java/src/net/i2p/client/I2PSession.java @@ -9,6 +9,7 @@ package net.i2p.client; * */ +import java.util.Properties; import java.util.Set; import net.i2p.data.Destination; @@ -151,6 +152,13 @@ public interface I2PSession { */ public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException; + /** + * Does not remove properties previously present but missing from this options parameter. + * @param options non-null + * @since 0.8.4 + */ + public void updateOptions(Properties options); + /** * Get the current bandwidth limits. Blocking. */ diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index 8b4389e47..b904b121d 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -221,20 +221,32 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa } } + /** save some memory, don't pass along the pointless properties */ private Properties filter(Properties options) { Properties rv = new Properties(); for (Iterator iter = options.keySet().iterator(); iter.hasNext();) { String key = (String) iter.next(); - String val = options.getProperty(key); - if (key.startsWith("java") || - key.startsWith("user") || - key.startsWith("os") || - key.startsWith("sun") || - key.startsWith("file") || - key.startsWith("line") || - key.startsWith("wrapper")) { + if (key.startsWith("java.") || + key.startsWith("user.") || + key.startsWith("os.") || + key.startsWith("sun.") || + key.startsWith("file.") || + key.equals("line.separator") || + key.equals("path.separator") || + key.equals("prng.buffers") || + key.equals("router.trustedUpdateKeys") || + key.startsWith("router.update") || + key.startsWith("routerconsole.") || + key.startsWith("time.") || + key.startsWith("stat.") || + key.startsWith("gnu.") || // gnu JVM + key.startsWith("net.i2p.router.web.") || // console nonces + key.startsWith("wrapper.")) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Skipping property: " + key); - } else if ((key.length() > 255) || (val.length() > 255)) { + continue; + } + String val = options.getProperty(key); + if ((key.length() > 255) || (val.length() > 255)) { if (_log.shouldLog(Log.WARN)) _log.warn(getPrefix() + "Not passing on property [" + key @@ -247,6 +259,18 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa return rv; } + /** + * Update the tunnel and bandwidth settings + * @since 0.8.4 + */ + public void updateOptions(Properties options) { + _options.putAll(filter(options)); + _producer.updateBandwidth(this); + try { + _producer.updateTunnels(this, 0); + } catch (I2PSessionException ise) {} + } + void setLeaseSet(LeaseSet ls) { _leaseSet = ls; if (ls != null) { @@ -397,7 +421,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa * */ public byte[] receiveMessage(int msgId) throws I2PSessionException { - MessagePayloadMessage msg = _availableMessages.remove(new Long(msgId)); + MessagePayloadMessage msg = _availableMessages.remove(Long.valueOf(msgId)); if (msg == null) { _log.error("Receive message " + msgId + " had no matches"); return null; @@ -444,7 +468,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa * Recieve a payload message and let the app know its available */ public void addNewMessage(MessagePayloadMessage msg) { - Long mid = new Long(msg.getMessageId()); + Long mid = Long.valueOf(msg.getMessageId()); _availableMessages.put(mid, msg); long id = msg.getMessageId(); byte data[] = msg.getPayload().getUnencryptedData(); @@ -494,7 +518,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa public void available(long msgId, int size) { synchronized (AvailabilityNotifier.this) { - _pendingIds.add(new Long(msgId)); + _pendingIds.add(Long.valueOf(msgId)); _pendingSizes.add(Integer.valueOf(size)); AvailabilityNotifier.this.notifyAll(); } diff --git a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java index 342b05d26..c8ddaf77b 100644 --- a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java @@ -191,7 +191,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession { */ @Override public void addNewMessage(MessagePayloadMessage msg) { - Long mid = new Long(msg.getMessageId()); + Long mid = Long.valueOf(msg.getMessageId()); _availableMessages.put(mid, msg); long id = msg.getMessageId(); byte data[] = msg.getPayload().getUnencryptedData(); diff --git a/core/java/src/net/i2p/client/I2PSimpleSession.java b/core/java/src/net/i2p/client/I2PSimpleSession.java index e984b6d30..e108fc008 100644 --- a/core/java/src/net/i2p/client/I2PSimpleSession.java +++ b/core/java/src/net/i2p/client/I2PSimpleSession.java @@ -98,10 +98,17 @@ class I2PSimpleSession extends I2PSessionImpl2 { } } + /** + * Ignore, does nothing + * @since 0.8.4 + */ + @Override + public void updateOptions(Properties options) {} + /** * Only map message handlers that we will use */ - class SimpleMessageHandlerMap extends I2PClientMessageHandlerMap { + private static class SimpleMessageHandlerMap extends I2PClientMessageHandlerMap { public SimpleMessageHandlerMap(I2PAppContext context) { int highest = Math.max(DestReplyMessage.MESSAGE_TYPE, BandwidthLimitsMessage.MESSAGE_TYPE); _handlers = new I2CPMessageHandler[highest+1]; diff --git a/core/java/src/net/i2p/crypto/CryptixAESEngine.java b/core/java/src/net/i2p/crypto/CryptixAESEngine.java index ea2338003..350821e35 100644 --- a/core/java/src/net/i2p/crypto/CryptixAESEngine.java +++ b/core/java/src/net/i2p/crypto/CryptixAESEngine.java @@ -149,7 +149,7 @@ public class CryptixAESEngine extends AESEngine { @Override public final void decryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte rv[], int outIndex) { if ( (payload == null) || (rv == null) ) - throw new IllegalArgumentException("null block args [payload=" + payload + " rv="+rv); + throw new IllegalArgumentException("null block args"); if (payload.length - inIndex > rv.length - outIndex) throw new IllegalArgumentException("bad block args [payload.len=" + payload.length + " inIndex=" + inIndex + " rv.len=" + rv.length diff --git a/core/java/src/net/i2p/data/Base32.java b/core/java/src/net/i2p/data/Base32.java index 3071e0bc0..cbcb93515 100644 --- a/core/java/src/net/i2p/data/Base32.java +++ b/core/java/src/net/i2p/data/Base32.java @@ -72,13 +72,13 @@ public class Base32 { } private static void runApp(String args[]) { + if ("encodestring".equalsIgnoreCase(args[0])) { + System.out.println(encode(args[1].getBytes())); + return; + } + InputStream in = System.in; + OutputStream out = System.out; try { - if ("encodestring".equalsIgnoreCase(args[0])) { - System.out.println(encode(args[1].getBytes())); - return; - } - InputStream in = System.in; - OutputStream out = System.out; if (args.length >= 3) { out = new FileOutputStream(args[2]); } @@ -95,6 +95,9 @@ public class Base32 { } } catch (IOException ioe) { ioe.printStackTrace(System.err); + } finally { + try { in.close(); } catch (IOException e) {} + try { out.close(); } catch (IOException e) {} } } diff --git a/core/java/src/net/i2p/data/Base64.java b/core/java/src/net/i2p/data/Base64.java index fe730af6b..52d59002d 100644 --- a/core/java/src/net/i2p/data/Base64.java +++ b/core/java/src/net/i2p/data/Base64.java @@ -178,13 +178,13 @@ public class Base64 { } private static void runApp(String args[]) { + if ("encodestring".equalsIgnoreCase(args[0])) { + System.out.println(encode(args[1].getBytes())); + return; + } + InputStream in = System.in; + OutputStream out = System.out; try { - if ("encodestring".equalsIgnoreCase(args[0])) { - System.out.println(encode(args[1].getBytes())); - return; - } - InputStream in = System.in; - OutputStream out = System.out; if (args.length >= 3) { out = new FileOutputStream(args[2]); } @@ -201,6 +201,9 @@ public class Base64 { } } catch (IOException ioe) { ioe.printStackTrace(System.err); + } finally { + try { in.close(); } catch (IOException e) {} + try { out.close(); } catch (IOException e) {} } } diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index bd6bf260d..33264edf2 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -844,7 +844,7 @@ public class DataHelper { */ public final static void xor(byte lhs[], int startLeft, byte rhs[], int startRight, byte out[], int startOut, int len) { if ( (lhs == null) || (rhs == null) || (out == null) ) - throw new NullPointerException("Invalid params to xor (" + lhs + ", " + rhs + ", " + out + ")"); + throw new NullPointerException("Null params to xor"); if (lhs.length < startLeft + len) throw new IllegalArgumentException("Left hand side is too short"); if (rhs.length < startRight + len) diff --git a/core/java/src/net/i2p/data/PrivateKeyFile.java b/core/java/src/net/i2p/data/PrivateKeyFile.java index 0c752f9d6..4f4af3cf9 100644 --- a/core/java/src/net/i2p/data/PrivateKeyFile.java +++ b/core/java/src/net/i2p/data/PrivateKeyFile.java @@ -133,9 +133,15 @@ public class PrivateKeyFile { */ public Destination createIfAbsent() throws I2PException, IOException, DataFormatException { if(!this.file.exists()) { - FileOutputStream out = new FileOutputStream(this.file); - this.client.createDestination(out); - out.close(); + FileOutputStream out = null; + try { + out = new FileOutputStream(this.file); + this.client.createDestination(out); + } finally { + if (out != null) { + try { out.close(); } catch (IOException ioe) {} + } + } } return getDestination(); } @@ -243,29 +249,36 @@ public class PrivateKeyFile { public I2PSession open() throws I2PSessionException, IOException { return this.open(new Properties()); } + public I2PSession open(Properties opts) throws I2PSessionException, IOException { - // open input file - FileInputStream in = new FileInputStream(this.file); - - // create sesssion - I2PSession s = this.client.createSession(in, opts); - - // close file - in.close(); - - return s; + FileInputStream in = null; + try { + in = new FileInputStream(this.file); + I2PSession s = this.client.createSession(in, opts); + return s; + } finally { + if (in != null) { + try { in.close(); } catch (IOException ioe) {} + } + } } /** * Copied from I2PClientImpl.createDestination() */ public void write() throws IOException, DataFormatException { - FileOutputStream out = new FileOutputStream(this.file); - this.dest.writeBytes(out); - this.privKey.writeBytes(out); - this.signingPrivKey.writeBytes(out); - out.flush(); - out.close(); + FileOutputStream out = null; + try { + out = new FileOutputStream(this.file); + this.dest.writeBytes(out); + this.privKey.writeBytes(out); + this.signingPrivKey.writeBytes(out); + out.flush(); + } finally { + if (out != null) { + try { out.close(); } catch (IOException ioe) {} + } + } } @Override @@ -377,7 +390,8 @@ public class PrivateKeyFile { } } } - } catch (Exception ioe) { + } catch (DataFormatException dfe) { + } catch (IOException ioe) { } // not found, continue to the next file } diff --git a/core/java/src/net/i2p/data/i2cp/DestReplyMessage.java b/core/java/src/net/i2p/data/i2cp/DestReplyMessage.java index 788fb36a0..f4d44a3ae 100644 --- a/core/java/src/net/i2p/data/i2cp/DestReplyMessage.java +++ b/core/java/src/net/i2p/data/i2cp/DestReplyMessage.java @@ -74,10 +74,11 @@ public class DestReplyMessage extends I2CPMessageImpl { } protected byte[] doWriteMessage() throws I2CPMessageException, IOException { - if (_dest == null && _hash == null) - return new byte[0]; // null response allowed - if (_dest == null && _hash != null) + if (_dest == null) { + if (_hash == null) + return new byte[0]; // null response allowed return _hash.getData(); + } ByteArrayOutputStream os = new ByteArrayOutputStream(_dest.size()); try { _dest.writeBytes(os); diff --git a/core/java/src/net/i2p/stat/FrequencyStat.java b/core/java/src/net/i2p/stat/FrequencyStat.java index dfa7bcfe6..d18a469db 100644 --- a/core/java/src/net/i2p/stat/FrequencyStat.java +++ b/core/java/src/net/i2p/stat/FrequencyStat.java @@ -89,7 +89,7 @@ public class FrequencyStat { /** @since 0.8.2 */ @Override public boolean equals(Object obj) { - if ((obj == null) || (obj.getClass() != FrequencyStat.class)) return false; + if ((obj == null) || !(obj instanceof FrequencyStat)) return false; return _statName.equals(((FrequencyStat)obj)._statName); } diff --git a/core/java/src/net/i2p/stat/Rate.java b/core/java/src/net/i2p/stat/Rate.java index fd0fae49f..8473d58eb 100644 --- a/core/java/src/net/i2p/stat/Rate.java +++ b/core/java/src/net/i2p/stat/Rate.java @@ -473,7 +473,7 @@ public class Rate { @Override public boolean equals(Object obj) { - if ((obj == null) || (obj.getClass() != Rate.class)) return false; + if ((obj == null) || !(obj instanceof Rate)) return false; if (obj == this) return true; Rate r = (Rate) obj; return _period == r.getPeriod() && _creationDate == r.getCreationDate() && diff --git a/core/java/src/net/i2p/stat/RateStat.java b/core/java/src/net/i2p/stat/RateStat.java index 79ddec519..fded9b019 100644 --- a/core/java/src/net/i2p/stat/RateStat.java +++ b/core/java/src/net/i2p/stat/RateStat.java @@ -108,7 +108,7 @@ public class RateStat { @Override public boolean equals(Object obj) { - if ((obj == null) || (obj.getClass() != RateStat.class)) return false; + if ((obj == null) || !(obj instanceof RateStat)) return false; RateStat rs = (RateStat) obj; if (DataHelper.eq(getGroupName(), rs.getGroupName()) && DataHelper.eq(getDescription(), rs.getDescription()) && DataHelper.eq(getName(), rs.getName())) { diff --git a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java index 0a2ee498b..b0a4cfc6d 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java @@ -12,6 +12,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import net.i2p.I2PAppContext; +import net.i2p.data.DatabaseEntry; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Hash; @@ -28,59 +29,39 @@ import net.i2p.data.TunnelId; public class DatabaseStoreMessage extends I2NPMessageImpl { public final static int MESSAGE_TYPE = 1; private Hash _key; - private int _type; - private LeaseSet _leaseSet; - private RouterInfo _info; - private byte[] _leaseSetCache; - private byte[] _routerInfoCache; + private DatabaseEntry _dbEntry; + private byte[] _byteCache; private long _replyToken; private TunnelId _replyTunnel; private Hash _replyGateway; - public final static int KEY_TYPE_ROUTERINFO = 0; - public final static int KEY_TYPE_LEASESET = 1; - public DatabaseStoreMessage(I2PAppContext context) { super(context); - setValueType(-1); } /** * Defines the key in the network database being stored * */ - public Hash getKey() { return _key; } - public void setKey(Hash key) { _key = key; } - - /** - * Defines the router info value in the network database being stored - * - */ - public RouterInfo getRouterInfo() { return _info; } - public void setRouterInfo(RouterInfo routerInfo) { - _info = routerInfo; - if (_info != null) - setValueType(KEY_TYPE_ROUTERINFO); + public Hash getKey() { + if (_key != null) + return _key; // receive + if (_dbEntry != null) + return _dbEntry.getHash(); // create + return null; } /** - * Defines the lease set value in the network database being stored - * + * Defines the entry in the network database being stored */ - public LeaseSet getLeaseSet() { return _leaseSet; } - public void setLeaseSet(LeaseSet leaseSet) { - _leaseSet = leaseSet; - if (_leaseSet != null) - setValueType(KEY_TYPE_LEASESET); - } - + public DatabaseEntry getEntry() { return _dbEntry; } + /** - * Defines type of key being stored in the network database - - * either KEY_TYPE_ROUTERINFO or KEY_TYPE_LEASESET - * + * This also sets the key */ - public int getValueType() { return _type; } - public void setValueType(int type) { _type = type; } + public void setEntry(DatabaseEntry entry) { + _dbEntry = entry; + } /** * If a reply is desired, this token specifies the message ID that should @@ -90,6 +71,7 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { * @return positive reply token ID, or 0 if no reply is necessary. */ public long getReplyToken() { return _replyToken; } + /** * Update the reply token. * @@ -113,13 +95,10 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); int curIndex = offset; - //byte keyData[] = new byte[Hash.HASH_LENGTH]; - //System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH); _key = Hash.create(data, curIndex); curIndex += Hash.HASH_LENGTH; - //_key = new Hash(keyData); - _type = (int)DataHelper.fromLong(data, curIndex, 1); + type = (int)DataHelper.fromLong(data, curIndex, 1); curIndex++; _replyToken = DataHelper.fromLong(data, curIndex, 4); @@ -131,39 +110,38 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { _replyTunnel = new TunnelId(tunnel); curIndex += 4; - //byte gw[] = new byte[Hash.HASH_LENGTH]; - //System.arraycopy(data, curIndex, gw, 0, Hash.HASH_LENGTH); _replyGateway = Hash.create(data, curIndex); curIndex += Hash.HASH_LENGTH; - //_replyGateway = new Hash(gw); } else { _replyTunnel = null; _replyGateway = null; } - if (_type == KEY_TYPE_LEASESET) { - _leaseSet = new LeaseSet(); + if (type == DatabaseEntry.KEY_TYPE_LEASESET) { + _dbEntry = new LeaseSet(); try { - _leaseSet.readBytes(new ByteArrayInputStream(data, curIndex, data.length-curIndex)); + _dbEntry.readBytes(new ByteArrayInputStream(data, curIndex, data.length-curIndex)); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error reading the leaseSet", dfe); } - } else if (_type == KEY_TYPE_ROUTERINFO) { - _info = new RouterInfo(); + } else if (type == DatabaseEntry.KEY_TYPE_ROUTERINFO) { + _dbEntry = new RouterInfo(); int compressedSize = (int)DataHelper.fromLong(data, curIndex, 2); curIndex += 2; try { byte decompressed[] = DataHelper.decompress(data, curIndex, compressedSize); - _info.readBytes(new ByteArrayInputStream(decompressed)); + _dbEntry.readBytes(new ByteArrayInputStream(decompressed)); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error reading the routerInfo", dfe); } catch (IOException ioe) { throw new I2NPMessageException("Compressed routerInfo was corrupt", ioe); } } else { - throw new I2NPMessageException("Invalid type of key read from the structure - " + _type); + throw new I2NPMessageException("Invalid type of key read from the structure - " + type); } + //if (!key.equals(_dbEntry.getHash())) + // throw new I2NPMessageException("Hash mismatch in DSM"); } @@ -172,28 +150,28 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { int len = Hash.HASH_LENGTH + 1 + 4; // key+type+replyToken if (_replyToken > 0) len += 4 + Hash.HASH_LENGTH; // replyTunnel+replyGateway - if (_type == KEY_TYPE_LEASESET) { - _leaseSetCache = _leaseSet.toByteArray(); - len += _leaseSetCache.length; - } else if (_type == KEY_TYPE_ROUTERINFO) { - byte uncompressed[] = _info.toByteArray(); - byte compressed[] = DataHelper.compress(uncompressed); - _routerInfoCache = compressed; - len += compressed.length + 2; + if (_dbEntry.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { + _byteCache = _dbEntry.toByteArray(); + } else if (_dbEntry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { + byte uncompressed[] = _dbEntry.toByteArray(); + _byteCache = DataHelper.compress(uncompressed); + len += 2; } + len += _byteCache.length; return len; } + /** write the message body to the output array, starting at the given index */ protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException { - if (_key == null) throw new I2NPMessageException("Invalid key"); - if ( (_type != KEY_TYPE_LEASESET) && (_type != KEY_TYPE_ROUTERINFO) ) throw new I2NPMessageException("Invalid key type"); - if ( (_type == KEY_TYPE_LEASESET) && (_leaseSet == null) ) throw new I2NPMessageException("Missing lease set"); - if ( (_type == KEY_TYPE_ROUTERINFO) && (_info == null) ) throw new I2NPMessageException("Missing router info"); + if (_dbEntry == null) throw new I2NPMessageException("Missing entry"); + int type = _dbEntry.getType(); + if (type != DatabaseEntry.KEY_TYPE_LEASESET && type != DatabaseEntry.KEY_TYPE_ROUTERINFO) + throw new I2NPMessageException("Invalid key type"); - System.arraycopy(_key.getData(), 0, out, curIndex, Hash.HASH_LENGTH); + // Use the hash of the DatabaseEntry + System.arraycopy(getKey().getData(), 0, out, curIndex, Hash.HASH_LENGTH); curIndex += Hash.HASH_LENGTH; - byte type[] = DataHelper.toLong(1, _type); - out[curIndex++] = type[0]; + out[curIndex++] = (byte) type; byte tok[] = DataHelper.toLong(4, _replyToken); System.arraycopy(tok, 0, out, curIndex, 4); curIndex += 4; @@ -209,17 +187,14 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { curIndex += Hash.HASH_LENGTH; } - if (_type == KEY_TYPE_LEASESET) { - // initialized in calculateWrittenLength - System.arraycopy(_leaseSetCache, 0, out, curIndex, _leaseSetCache.length); - curIndex += _leaseSetCache.length; - } else if (_type == KEY_TYPE_ROUTERINFO) { - byte len[] = DataHelper.toLong(2, _routerInfoCache.length); + // _byteCache initialized in calculateWrittenLength + if (type == DatabaseEntry.KEY_TYPE_ROUTERINFO) { + byte len[] = DataHelper.toLong(2, _byteCache.length); out[curIndex++] = len[0]; out[curIndex++] = len[1]; - System.arraycopy(_routerInfoCache, 0, out, curIndex, _routerInfoCache.length); - curIndex += _routerInfoCache.length; } + System.arraycopy(_byteCache, 0, out, curIndex, _byteCache.length); + curIndex += _byteCache.length; return curIndex; } @@ -228,9 +203,7 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { @Override public int hashCode() { return DataHelper.hashCode(getKey()) + - DataHelper.hashCode(getLeaseSet()) + - DataHelper.hashCode(getRouterInfo()) + - getValueType() + + DataHelper.hashCode(_dbEntry) + (int)getReplyToken() + DataHelper.hashCode(getReplyTunnel()) + DataHelper.hashCode(getReplyGateway()); @@ -241,9 +214,7 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { if ( (object != null) && (object instanceof DatabaseStoreMessage) ) { DatabaseStoreMessage msg = (DatabaseStoreMessage)object; return DataHelper.eq(getKey(),msg.getKey()) && - DataHelper.eq(getLeaseSet(),msg.getLeaseSet()) && - DataHelper.eq(getRouterInfo(),msg.getRouterInfo()) && - _type == msg.getValueType() && + DataHelper.eq(_dbEntry,msg.getEntry()) && getReplyToken() == msg.getReplyToken() && DataHelper.eq(getReplyTunnel(), msg.getReplyTunnel()) && DataHelper.eq(getReplyGateway(), msg.getReplyGateway()); @@ -259,9 +230,7 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { buf.append("\n\tExpiration: ").append(getMessageExpiration()); buf.append("\n\tUnique ID: ").append(getUniqueId()); buf.append("\n\tKey: ").append(getKey()); - buf.append("\n\tValue Type: ").append(getValueType()); - buf.append("\n\tRouter Info: ").append(getRouterInfo()); - buf.append("\n\tLease Set: ").append(getLeaseSet()); + buf.append("\n\tEntry: ").append(_dbEntry); buf.append("\n\tReply token: ").append(getReplyToken()); buf.append("\n\tReply tunnel: ").append(getReplyTunnel()); buf.append("\n\tReply gateway: ").append(getReplyGateway()); diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index 6b4ab71f4..021bbf6c1 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -116,7 +116,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM if (!eq) throw new I2NPMessageException("Hash does not match for " + getClass().getName()); - long start = _context.clock().now(); + //long start = _context.clock().now(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); readMessage(buffer, 0, size, type); @@ -159,7 +159,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM if (!eq) throw new I2NPMessageException("Hash does not match for " + getClass().getName()); - long start = _context.clock().now(); + //long start = _context.clock().now(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); readMessage(data, cur, size, type); @@ -215,7 +215,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM } public int toByteArray(byte buffer[]) { - long start = _context.clock().now(); + //long start = _context.clock().now(); int prefixLen = 1 // type + 4 // uniqueId diff --git a/router/java/src/net/i2p/data/i2np/TunnelDataMessage.java b/router/java/src/net/i2p/data/i2np/TunnelDataMessage.java index 1ac01d0a6..ef4930594 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelDataMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelDataMessage.java @@ -160,7 +160,7 @@ public class TunnelDataMessage extends I2NPMessageImpl { /** write the message body to the output array, starting at the given index */ protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException { if ( (_tunnelId <= 0) || (_data == null) ) - throw new I2NPMessageException("Not enough data to write out (id=" + _tunnelId + " data=" + _data + ")"); + throw new I2NPMessageException("Not enough data to write out (id=" + _tunnelId + ")"); if (_data.length <= 0) throw new I2NPMessageException("Not enough data to write out (data.length=" + _data.length + ")"); diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java index d401f1532..634eafd19 100644 --- a/router/java/src/net/i2p/router/Blocklist.java +++ b/router/java/src/net/i2p/router/Blocklist.java @@ -59,7 +59,7 @@ import net.i2p.util.Log; * */ public class Blocklist { - private Log _log; + private final Log _log; private RouterContext _context; private long _blocklist[]; private int _blocklistSize; @@ -72,15 +72,11 @@ public class Blocklist { public Blocklist(RouterContext context) { _context = context; _log = context.logManager().getLog(Blocklist.class); - _blocklist = null; - _blocklistSize = 0; - _wrapSave = null; } + /** only for testing with main() */ public Blocklist() { _log = new Log(Blocklist.class); - _blocklist = null; - _blocklistSize = 0; } static final String PROP_BLOCKLIST_ENABLED = "router.blocklist.enable"; diff --git a/router/java/src/net/i2p/router/DummyNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/DummyNetworkDatabaseFacade.java index 6031cf630..0f06f507c 100644 --- a/router/java/src/net/i2p/router/DummyNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/DummyNetworkDatabaseFacade.java @@ -16,6 +16,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -36,6 +37,7 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade { _routers.put(info.getIdentity().getHash(), info); } + public DatabaseEntry lookupLocally(Hash key) { return null; } public void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) {} public LeaseSet lookupLeaseSetLocally(Hash key) { return null; } public void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) { diff --git a/router/java/src/net/i2p/router/InNetMessagePool.java b/router/java/src/net/i2p/router/InNetMessagePool.java index 47b799da5..4e6846b46 100644 --- a/router/java/src/net/i2p/router/InNetMessagePool.java +++ b/router/java/src/net/i2p/router/InNetMessagePool.java @@ -30,15 +30,17 @@ import net.i2p.util.Log; * */ public class InNetMessagePool implements Service { - private Log _log; - private RouterContext _context; - private HandlerJobBuilder _handlerJobBuilders[]; + private final Log _log; + private final RouterContext _context; + private final HandlerJobBuilder _handlerJobBuilders[]; + /** following 5 unused unless DISPATCH_DIRECT == false */ private final List _pendingDataMessages; private final List _pendingDataMessagesFrom; private final List _pendingGatewayMessages; private SharedShortCircuitDataJob _shortCircuitDataJob; private SharedShortCircuitGatewayJob _shortCircuitGatewayJob; + private boolean _alive; private boolean _dispatchThreaded; diff --git a/router/java/src/net/i2p/router/JobQueue.java b/router/java/src/net/i2p/router/JobQueue.java index f56b25f9e..60bfeec7e 100644 --- a/router/java/src/net/i2p/router/JobQueue.java +++ b/router/java/src/net/i2p/router/JobQueue.java @@ -34,22 +34,22 @@ import net.i2p.util.Log; * */ public class JobQueue { - private Log _log; - private RouterContext _context; + private final Log _log; + private final RouterContext _context; /** Integer (runnerId) to JobQueueRunner for created runners */ private final Map _queueRunners; /** a counter to identify a job runner */ private volatile static int _runnerId = 0; /** list of jobs that are ready to run ASAP */ - private BlockingQueue _readyJobs; + private final BlockingQueue _readyJobs; /** list of jobs that are scheduled for running in the future */ - private List _timedJobs; + private final List _timedJobs; /** job name to JobStat for that job */ private final Map _jobStats; /** how many job queue runners can go concurrently */ private int _maxRunners = 1; - private QueuePumper _pumper; + private final QueuePumper _pumper; /** will we allow the # job runners to grow beyond 1? */ private boolean _allowParallelOperation; /** have we been killed or are we alive? */ diff --git a/router/java/src/net/i2p/router/JobQueueRunner.java b/router/java/src/net/i2p/router/JobQueueRunner.java index ca0ee3f1b..e9b0d08fb 100644 --- a/router/java/src/net/i2p/router/JobQueueRunner.java +++ b/router/java/src/net/i2p/router/JobQueueRunner.java @@ -4,10 +4,10 @@ import net.i2p.util.Log; /** a do run run run a do run run */ class JobQueueRunner implements Runnable { - private Log _log; - private RouterContext _context; + private final Log _log; + private final RouterContext _context; private boolean _keepRunning; - private int _id; + private final int _id; private long _numJobs; private Job _currentJob; private Job _lastJob; @@ -19,9 +19,6 @@ class JobQueueRunner implements Runnable { _context = context; _id = id; _keepRunning = true; - _numJobs = 0; - _currentJob = null; - _lastJob = null; _log = _context.logManager().getLog(JobQueueRunner.class); _context.statManager().createRateStat("jobQueue.jobRun", "How long jobs take", "JobQueue", new long[] { 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("jobQueue.jobRunSlow", "How long jobs that take over a second take", "JobQueue", new long[] { 60*60*1000l, 24*60*60*1000l }); diff --git a/router/java/src/net/i2p/router/JobStats.java b/router/java/src/net/i2p/router/JobStats.java index 19362cff3..f9cfdc9cc 100644 --- a/router/java/src/net/i2p/router/JobStats.java +++ b/router/java/src/net/i2p/router/JobStats.java @@ -4,7 +4,7 @@ import net.i2p.data.DataHelper; /** glorified struct to contain basic job stats */ class JobStats { - private String _job; + private final String _job; private volatile long _numRuns; private volatile long _totalTime; private volatile long _maxTime; diff --git a/router/java/src/net/i2p/router/JobTiming.java b/router/java/src/net/i2p/router/JobTiming.java index d979074a6..fd410f131 100644 --- a/router/java/src/net/i2p/router/JobTiming.java +++ b/router/java/src/net/i2p/router/JobTiming.java @@ -18,7 +18,7 @@ public class JobTiming implements Clock.ClockUpdateListener { private long _start; private long _actualStart; private long _actualEnd; - private RouterContext _context; + private final RouterContext _context; public JobTiming(RouterContext context) { _context = context; diff --git a/router/java/src/net/i2p/router/KeyManager.java b/router/java/src/net/i2p/router/KeyManager.java index fd0e85a9e..0e0b4e5d6 100644 --- a/router/java/src/net/i2p/router/KeyManager.java +++ b/router/java/src/net/i2p/router/KeyManager.java @@ -12,9 +12,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import net.i2p.data.DataFormatException; @@ -37,14 +35,14 @@ import net.i2p.util.SecureFileOutputStream; * */ public class KeyManager { - private Log _log; - private RouterContext _context; + private final Log _log; + private final RouterContext _context; private PrivateKey _privateKey; private PublicKey _publicKey; private SigningPrivateKey _signingPrivateKey; private SigningPublicKey _signingPublicKey; private final Map _leaseSetKeys; // Destination --> LeaseSetKeys - private SynchronizeKeysJob _synchronizeJob; + private final SynchronizeKeysJob _synchronizeJob; public final static String PROP_KEYDIR = "router.keyBackupDir"; public final static String DEFAULT_KEYDIR = "keyBackup"; @@ -61,10 +59,6 @@ public class KeyManager { _context = context; _log = _context.logManager().getLog(KeyManager.class); _synchronizeJob = new SynchronizeKeysJob(); - setPrivateKey(null); - setPublicKey(null); - setSigningPrivateKey(null); - setSigningPublicKey(null); _leaseSetKeys = new ConcurrentHashMap(); } @@ -132,12 +126,6 @@ public class KeyManager { return _leaseSetKeys.get(dest); } - public Set getAllKeys() { - HashSet keys = new HashSet(); - keys.addAll(_leaseSetKeys.values()); - return keys; - } - private class SynchronizeKeysJob extends JobImpl { public SynchronizeKeysJob() { super(KeyManager.this._context); diff --git a/router/java/src/net/i2p/router/MessageValidator.java b/router/java/src/net/i2p/router/MessageValidator.java index b673702a1..b61916612 100644 --- a/router/java/src/net/i2p/router/MessageValidator.java +++ b/router/java/src/net/i2p/router/MessageValidator.java @@ -13,14 +13,13 @@ import net.i2p.util.Log; * */ public class MessageValidator { - private Log _log; - private RouterContext _context; + private final Log _log; + private final RouterContext _context; private DecayingBloomFilter _filter; public MessageValidator(RouterContext context) { _log = context.logManager().getLog(MessageValidator.class); - _filter = null; _context = context; context.statManager().createRateStat("router.duplicateMessageId", "Note that a duplicate messageId was received", "Router", new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); diff --git a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java index 50b9d5364..741f94953 100644 --- a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java @@ -13,6 +13,7 @@ import java.io.Writer; import java.util.Collections; import java.util.Set; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -32,6 +33,11 @@ public abstract class NetworkDatabaseFacade implements Service { */ public abstract Set findNearestRouters(Hash key, int maxNumRouters, Set peersToIgnore); + /** + * @return RouterInfo, LeaseSet, or null + * @since 0.8.3 + */ + public abstract DatabaseEntry lookupLocally(Hash key); public abstract void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs); public abstract LeaseSet lookupLeaseSetLocally(Hash key); public abstract void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs); diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java index cb3c63662..7fa3c4607 100644 --- a/router/java/src/net/i2p/router/RouterContext.java +++ b/router/java/src/net/i2p/router/RouterContext.java @@ -351,6 +351,18 @@ public class RouterContext extends I2PAppContext { return super.getProperty(propName, defaultVal); } + /** + * @return new Properties with system and context properties + * @since 0.8.4 + */ + @Override + public Properties getProperties() { + Properties rv = super.getProperties(); + if (_router != null) + rv.putAll(_router.getConfigMap()); + return rv; + } + /** * The context's synchronized clock, which is kept context specific only to * enable simulators to play with clock skew among different instances. diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java index d3d3129af..4297f7eb5 100644 --- a/router/java/src/net/i2p/router/RouterThrottleImpl.java +++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java @@ -12,12 +12,12 @@ import net.i2p.util.Log; * */ class RouterThrottleImpl implements RouterThrottle { - private RouterContext _context; - private Log _log; + private final RouterContext _context; + private final Log _log; private String _tunnelStatus; /** - * arbitrary hard limit of 10 seconds - if its taking this long to get + * arbitrary hard limit - if it's taking this long to get * to a job, we're congested. * */ diff --git a/router/java/src/net/i2p/router/RouterWatchdog.java b/router/java/src/net/i2p/router/RouterWatchdog.java index 14dc01c1e..482f3b3ed 100644 --- a/router/java/src/net/i2p/router/RouterWatchdog.java +++ b/router/java/src/net/i2p/router/RouterWatchdog.java @@ -12,8 +12,8 @@ import net.i2p.util.Log; * */ class RouterWatchdog implements Runnable { - private Log _log; - private RouterContext _context; + private final Log _log; + private final RouterContext _context; private int _consecutiveErrors; private static final long MAX_JOB_RUN_LAG = 60*1000; diff --git a/router/java/src/net/i2p/router/Shitlist.java b/router/java/src/net/i2p/router/Shitlist.java index f675d1056..55b778ad1 100644 --- a/router/java/src/net/i2p/router/Shitlist.java +++ b/router/java/src/net/i2p/router/Shitlist.java @@ -10,13 +10,13 @@ package net.i2p.router; import java.io.IOException; import java.io.Writer; -import java.util.concurrent.ConcurrentHashMap; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import net.i2p.data.DataHelper; import net.i2p.data.Hash; @@ -31,9 +31,9 @@ import net.i2p.util.Log; * shitlist. */ public class Shitlist { - private Log _log; - private RouterContext _context; - private Map _entries; + private final Log _log; + private final RouterContext _context; + private final Map _entries; public static class Entry { /** when it should expire, per the i2p clock */ diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java b/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java index 9025fd22b..0ba55213e 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java @@ -227,9 +227,8 @@ class OutboundClientMessageJobHelper { clove.setExpiration(expiration); clove.setId(ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE)); DatabaseStoreMessage msg = new DatabaseStoreMessage(ctx); - msg.setLeaseSet(replyLeaseSet); + msg.setEntry(replyLeaseSet); msg.setMessageExpiration(expiration); - msg.setKey(replyLeaseSet.getDestination().calculateHash()); clove.setPayload(msg); clove.setRecipientPublicKey(null); clove.setRequestAck(false); diff --git a/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java b/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java index ce907ae71..8cdc87e6f 100644 --- a/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java @@ -12,7 +12,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import net.i2p.data.DataStructure; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterIdentity; @@ -227,20 +227,19 @@ public class HandleDatabaseLookupMessageJob extends JobImpl { return routerHashSet.contains(getContext().routerHash()); } - private void sendData(Hash key, DataStructure data, Hash toPeer, TunnelId replyTunnel) { + private void sendData(Hash key, DatabaseEntry data, Hash toPeer, TunnelId replyTunnel) { + if (!key.equals(data.getHash())) { + _log.error("Hash mismatch HDLMJ"); + return; + } if (_log.shouldLog(Log.DEBUG)) _log.debug("Sending data matching key " + key.toBase64() + " to peer " + toPeer.toBase64() + " tunnel " + replyTunnel); DatabaseStoreMessage msg = new DatabaseStoreMessage(getContext()); - msg.setKey(key); - if (data instanceof LeaseSet) { - msg.setLeaseSet((LeaseSet)data); - msg.setValueType(DatabaseStoreMessage.KEY_TYPE_LEASESET); + if (data.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { getContext().statManager().addRateData("netDb.lookupsMatchedLeaseSet", 1, 0); - } else if (data instanceof RouterInfo) { - msg.setRouterInfo((RouterInfo)data); - msg.setValueType(DatabaseStoreMessage.KEY_TYPE_ROUTERINFO); } + msg.setEntry(data); getContext().statManager().addRateData("netDb.lookupsMatched", 1, 0); getContext().statManager().addRateData("netDb.lookupsHandled", 1, 0); sendMessage(msg, toPeer, replyTunnel); diff --git a/router/java/src/net/i2p/router/networkdb/HandleDatabaseStoreMessageJob.java b/router/java/src/net/i2p/router/networkdb/HandleDatabaseStoreMessageJob.java index a61f947a5..183d1da04 100644 --- a/router/java/src/net/i2p/router/networkdb/HandleDatabaseStoreMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/HandleDatabaseStoreMessageJob.java @@ -10,9 +10,11 @@ package net.i2p.router.networkdb; import java.util.Date; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterIdentity; +import net.i2p.data.RouterInfo; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.DeliveryStatusMessage; import net.i2p.router.JobImpl; @@ -59,16 +61,17 @@ public class HandleDatabaseStoreMessageJob extends JobImpl { String invalidMessage = null; boolean wasNew = false; - if (_message.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) { + DatabaseEntry entry = _message.getEntry(); + if (entry.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { getContext().statManager().addRateData("netDb.storeLeaseSetHandled", 1, 0); try { - LeaseSet ls = _message.getLeaseSet(); + LeaseSet ls = (LeaseSet) entry; // mark it as something we received, so we'll answer queries // for it. this flag does NOT get set on entries that we // receive in response to our own lookups. ls.setReceivedAsPublished(true); - LeaseSet match = getContext().netDb().store(_message.getKey(), _message.getLeaseSet()); + LeaseSet match = getContext().netDb().store(_message.getKey(), ls); if (match == null) { wasNew = true; } else { @@ -78,13 +81,14 @@ public class HandleDatabaseStoreMessageJob extends JobImpl { } catch (IllegalArgumentException iae) { invalidMessage = iae.getMessage(); } - } else if (_message.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) { + } else if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { + RouterInfo ri = (RouterInfo) entry; getContext().statManager().addRateData("netDb.storeRouterInfoHandled", 1, 0); if (_log.shouldLog(Log.INFO)) _log.info("Handling dbStore of router " + _message.getKey() + " with publishDate of " - + new Date(_message.getRouterInfo().getPublished())); + + new Date(ri.getPublished())); try { - Object match = getContext().netDb().store(_message.getKey(), _message.getRouterInfo()); + Object match = getContext().netDb().store(_message.getKey(), ri); wasNew = (null == match); getContext().profileManager().heardAbout(_message.getKey()); } catch (IllegalArgumentException iae) { @@ -92,7 +96,7 @@ public class HandleDatabaseStoreMessageJob extends JobImpl { } } else { if (_log.shouldLog(Log.ERROR)) - _log.error("Invalid DatabaseStoreMessage data type - " + _message.getValueType() + _log.error("Invalid DatabaseStoreMessage data type - " + entry.getType() + ": " + _message); } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/DataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/DataStore.java index b4b55f3f8..ab064e2b0 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/DataStore.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/DataStore.java @@ -8,21 +8,27 @@ package net.i2p.router.networkdb.kademlia; * */ +import java.util.Collection; +import java.util.Map; import java.util.Set; -import net.i2p.data.DataStructure; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; public interface DataStore { public boolean isInitialized(); public boolean isKnown(Hash key); - public DataStructure get(Hash key); - public DataStructure get(Hash key, boolean persist); - public boolean put(Hash key, DataStructure data); - public boolean put(Hash key, DataStructure data, boolean persist); - public DataStructure remove(Hash key); - public DataStructure remove(Hash key, boolean persist); + public DatabaseEntry get(Hash key); + public DatabaseEntry get(Hash key, boolean persist); + public boolean put(Hash key, DatabaseEntry data); + public boolean put(Hash key, DatabaseEntry data, boolean persist); + public DatabaseEntry remove(Hash key); + public DatabaseEntry remove(Hash key, boolean persist); public Set getKeys(); + /** @since 0.8.3 */ + public Collection getEntries(); + /** @since 0.8.3 */ + public Set> getMapEntries(); public void stop(); public void restart(); public void rescan(); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/ExpireLeasesJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/ExpireLeasesJob.java index 7d4be1336..59d8fc429 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/ExpireLeasesJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/ExpireLeasesJob.java @@ -12,6 +12,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.router.JobImpl; @@ -61,8 +62,8 @@ class ExpireLeasesJob extends JobImpl { Set toExpire = new HashSet(128); for (Iterator iter = keys.iterator(); iter.hasNext(); ) { Hash key = (Hash)iter.next(); - Object obj = _facade.getDataStore().get(key); - if (obj instanceof LeaseSet) { + DatabaseEntry obj = _facade.getDataStore().get(key); + if (obj.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { LeaseSet ls = (LeaseSet)obj; if (!ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) toExpire.add(key); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java index 20572667e..34b0e4e2b 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java @@ -1,5 +1,8 @@ package net.i2p.router.networkdb.kademlia; +import net.i2p.data.DatabaseEntry; +import net.i2p.data.LeaseSet; +import net.i2p.data.RouterInfo; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.I2NPMessage; @@ -61,14 +64,15 @@ class FloodOnlyLookupMatchJob extends JobImpl implements ReplyJob { // We do it here first to make sure it is in the DB before // runJob() and search.success() is called??? // Should we just pass the DataStructure directly back to somebody? - if (dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) { + if (dsm.getEntry().getType() == DatabaseEntry.KEY_TYPE_LEASESET) { // Since HFDSMJ wants to setReceivedAsPublished(), we have to // set a flag saying this was really the result of a query, // so don't do that. - dsm.getLeaseSet().setReceivedAsReply(); - getContext().netDb().store(dsm.getKey(), dsm.getLeaseSet()); + LeaseSet ls = (LeaseSet) dsm.getEntry(); + ls.setReceivedAsReply(); + getContext().netDb().store(dsm.getKey(), ls); } else { - getContext().netDb().store(dsm.getKey(), dsm.getRouterInfo()); + getContext().netDb().store(dsm.getKey(), (RouterInfo) dsm.getEntry()); } } catch (IllegalArgumentException iae) { if (_log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodSearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodSearchJob.java index bfa5c59ea..1cecc2074 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodSearchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodSearchJob.java @@ -182,8 +182,7 @@ public class FloodSearchJob extends JobImpl { _search = job; } public void runJob() { - if ( (getContext().netDb().lookupLeaseSetLocally(_search.getKey()) != null) || - (getContext().netDb().lookupRouterInfoLocally(_search.getKey()) != null) ) { + if (getContext().netDb().lookupLocally(_search.getKey()) != null) { _search.success(); } else { int remaining = _search.getLookupsRemaining(); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java index 540173ed6..5ba670135 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java @@ -7,8 +7,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import net.i2p.data.DatabaseEntry; import net.i2p.data.DataFormatException; -import net.i2p.data.DataStructure; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -93,11 +93,11 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad } @Override - public void sendStore(Hash key, DataStructure ds, Job onSuccess, Job onFailure, long sendTimeout, Set toIgnore) { + public void sendStore(Hash key, DatabaseEntry ds, Job onSuccess, Job onFailure, long sendTimeout, Set toIgnore) { // if we are a part of the floodfill netDb, don't send out our own leaseSets as part // of the flooding - instead, send them to a random floodfill peer so *they* can flood 'em out. // perhaps statistically adjust this so we are the source every 1/N times... or something. - if (floodfillEnabled() && (ds instanceof RouterInfo)) { + if (floodfillEnabled() && (ds.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO)) { flood(ds); if (onSuccess != null) _context.jobQueue().addJob(onSuccess); @@ -129,12 +129,8 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad * We do this to implement Kademlia within the floodfills, i.e. * we flood to those closest to the key. */ - public void flood(DataStructure ds) { - Hash key; - if (ds instanceof LeaseSet) - key = ((LeaseSet)ds).getDestination().calculateHash(); - else - key = ((RouterInfo)ds).getIdentity().calculateHash(); + public void flood(DatabaseEntry ds) { + Hash key = ds.getHash(); Hash rkey = _context.routingKeyGenerator().getRoutingKey(key); FloodfillPeerSelector sel = (FloodfillPeerSelector)getPeerSelector(); List peers = sel.selectFloodfillParticipants(rkey, MAX_TO_FLOOD, getKBuckets()); @@ -151,12 +147,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad if (peer.equals(_context.routerHash())) continue; DatabaseStoreMessage msg = new DatabaseStoreMessage(_context); - if (ds instanceof LeaseSet) { - msg.setLeaseSet((LeaseSet)ds); - } else { - msg.setRouterInfo((RouterInfo)ds); - } - msg.setKey(key); + msg.setEntry(ds); msg.setReplyGateway(null); msg.setReplyToken(0); msg.setReplyTunnel(null); @@ -242,13 +233,9 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad List rv = new ArrayList(); DataStore ds = getDataStore(); if (ds != null) { - Set keys = ds.getKeys(); - if (keys != null) { - for (Iterator iter = keys.iterator(); iter.hasNext(); ) { - Object o = ds.get((Hash)iter.next()); - if (o instanceof RouterInfo) - rv.add((RouterInfo)o); - } + for (DatabaseEntry o : ds.getEntries()) { + if (o.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) + rv.add((RouterInfo)o); } } return rv; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java index 14969df83..babd35dd2 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java @@ -12,7 +12,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; -import net.i2p.data.DataStructure; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -30,7 +30,7 @@ class FloodfillStoreJob extends StoreJob { * Send a data structure to the floodfills * */ - public FloodfillStoreJob(RouterContext context, FloodfillNetworkDatabaseFacade facade, Hash key, DataStructure data, Job onSuccess, Job onFailure, long timeoutMs) { + public FloodfillStoreJob(RouterContext context, FloodfillNetworkDatabaseFacade facade, Hash key, DatabaseEntry data, Job onSuccess, Job onFailure, long timeoutMs) { this(context, facade, key, data, onSuccess, onFailure, timeoutMs, null); } @@ -38,7 +38,7 @@ class FloodfillStoreJob extends StoreJob { * @param toSkip set of peer hashes of people we dont want to send the data to (e.g. we * already know they have it). This can be null. */ - public FloodfillStoreJob(RouterContext context, FloodfillNetworkDatabaseFacade facade, Hash key, DataStructure data, Job onSuccess, Job onFailure, long timeoutMs, Set toSkip) { + public FloodfillStoreJob(RouterContext context, FloodfillNetworkDatabaseFacade facade, Hash key, DatabaseEntry data, Job onSuccess, Job onFailure, long timeoutMs, Set toSkip) { super(context, facade, key, data, onSuccess, onFailure, timeoutMs, toSkip); _facade = facade; } @@ -63,15 +63,12 @@ class FloodfillStoreJob extends StoreJob { } // Get the time stamp from the data we sent, so the Verify job can meke sure that // it finds something stamped with that time or newer. - long published = 0; - DataStructure data = _state.getData(); - boolean isRouterInfo = data instanceof RouterInfo; + DatabaseEntry data = _state.getData(); + boolean isRouterInfo = data.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO; + long published = data.getDate(); if (isRouterInfo) { - published = ((RouterInfo) data).getPublished(); // Temporarily disable return; - } else if (data instanceof LeaseSet) { - published = ((LeaseSet) data).getEarliestLeaseDate(); } // we should always have exactly one successful entry Hash sentTo = null; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java index fa944f384..c7dca1271 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java @@ -4,7 +4,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import net.i2p.data.DataStructure; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.RouterInfo; import net.i2p.data.i2np.DatabaseLookupMessage; @@ -201,10 +201,7 @@ public class FloodfillVerifyStoreJob extends JobImpl { // Verify it's as recent as the one we sent boolean success = false; DatabaseStoreMessage dsm = (DatabaseStoreMessage)_message; - if (_isRouterInfo && dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) - success = dsm.getRouterInfo().getPublished() >= _published; - else if ((!_isRouterInfo) && dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) - success = dsm.getLeaseSet().getEarliestLeaseDate() >= _published; + success = dsm.getEntry().getDate() >= _published; if (success) { // store ok, w00t! getContext().profileManager().dbLookupSuccessful(_target, delay); @@ -218,7 +215,7 @@ public class FloodfillVerifyStoreJob extends JobImpl { if (_log.shouldLog(Log.WARN)) _log.warn("Verify failed (older) for " + _key); if (_log.shouldLog(Log.INFO)) - _log.info("Rcvd older lease: " + dsm.getLeaseSet()); + _log.info("Rcvd older lease: " + dsm.getEntry()); } else if (_message instanceof DatabaseSearchReplyMessage) { // assume 0 old, all new, 0 invalid, 0 dup getContext().profileManager().dbLookupReply(_target, 0, @@ -245,11 +242,7 @@ public class FloodfillVerifyStoreJob extends JobImpl { * So at least we'll try THREE ffs round-robin if things continue to fail... */ private void resend() { - DataStructure ds; - if (_isRouterInfo) - ds = _facade.lookupRouterInfoLocally(_key); - else - ds = _facade.lookupLeaseSetLocally(_key); + DatabaseEntry ds = _facade.lookupLocally(_key); if (ds != null) { Set toSkip = new HashSet(2); if (_sentTo != null) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java index 4e3c9c30c..1409ecc2a 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java @@ -57,9 +57,7 @@ public class HandleFloodfillDatabaseLookupMessageJob extends HandleDatabaseLooku // that would increment the netDb.lookupsHandled and netDb.lookupsMatched stats DatabaseStoreMessage msg = new DatabaseStoreMessage(getContext()); RouterInfo me = getContext().router().getRouterInfo(); - msg.setKey(me.getIdentity().getHash()); - msg.setRouterInfo(me); - msg.setValueType(DatabaseStoreMessage.KEY_TYPE_ROUTERINFO); + msg.setEntry(me); sendMessage(msg, toPeer, replyTunnel); } } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java index ea53c1566..a546ad7a2 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java @@ -11,6 +11,7 @@ package net.i2p.router.networkdb.kademlia; import java.util.Date; import java.util.Set; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterIdentity; @@ -55,7 +56,8 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { boolean wasNew = false; RouterInfo prevNetDb = null; Hash key = _message.getKey(); - if (_message.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) { + DatabaseEntry entry = _message.getEntry(); + if (entry.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { getContext().statManager().addRateData("netDb.storeLeaseSetHandled", 1, 0); if (_log.shouldLog(Log.INFO)) _log.info("Handling dbStore of leaseset " + _message); @@ -75,7 +77,7 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { throw new IllegalArgumentException("Peer attempted to store local leaseSet: " + key.toBase64().substring(0, 4)); } - LeaseSet ls = _message.getLeaseSet(); + LeaseSet ls = (LeaseSet) entry; //boolean oldrar = ls.getReceivedAsReply(); //boolean oldrap = ls.getReceivedAsPublished(); // If this was received as a response to a query, @@ -91,10 +93,10 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { //boolean rap = ls.getReceivedAsPublished(); //if (_log.shouldLog(Log.INFO)) // _log.info("oldrap? " + oldrap + " oldrar? " + oldrar + " newrap? " + rap); - LeaseSet match = getContext().netDb().store(key, _message.getLeaseSet()); + LeaseSet match = getContext().netDb().store(key, ls); if (match == null) { wasNew = true; - } else if (match.getEarliestLeaseDate() < _message.getLeaseSet().getEarliestLeaseDate()) { + } else if (match.getEarliestLeaseDate() < ls.getEarliestLeaseDate()) { wasNew = true; // If it is in our keyspace and we are talking to it @@ -117,11 +119,12 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { } catch (IllegalArgumentException iae) { invalidMessage = iae.getMessage(); } - } else if (_message.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) { + } else if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { + RouterInfo ri = (RouterInfo) entry; getContext().statManager().addRateData("netDb.storeRouterInfoHandled", 1, 0); if (_log.shouldLog(Log.INFO)) _log.info("Handling dbStore of router " + key + " with publishDate of " - + new Date(_message.getRouterInfo().getPublished())); + + new Date(ri.getPublished())); try { // Never store our RouterInfo received from somebody else. // This generally happens from a FloodfillVerifyStoreJob. @@ -132,8 +135,8 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { // throw rather than return, so that we send the ack below (prevent easy attack) throw new IllegalArgumentException("Peer attempted to store our RouterInfo"); } - prevNetDb = getContext().netDb().store(key, _message.getRouterInfo()); - wasNew = ((null == prevNetDb) || (prevNetDb.getPublished() < _message.getRouterInfo().getPublished())); + prevNetDb = getContext().netDb().store(key, ri); + wasNew = ((null == prevNetDb) || (prevNetDb.getPublished() < ri.getPublished())); // Check new routerinfo address against blocklist if (wasNew) { if (prevNetDb == null) { @@ -143,7 +146,7 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { _log.warn("Blocklisting new peer " + key); } else { Set oldAddr = prevNetDb.getAddresses(); - Set newAddr = _message.getRouterInfo().getAddresses(); + Set newAddr = ri.getAddresses(); if (newAddr != null && (!newAddr.equals(oldAddr)) && (!getContext().shitlist().isShitlistedForever(key)) && getContext().blocklist().isBlocklisted(key) && @@ -157,7 +160,7 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { } } else { if (_log.shouldLog(Log.ERROR)) - _log.error("Invalid DatabaseStoreMessage data type - " + _message.getValueType() + _log.error("Invalid DatabaseStoreMessage data type - " + entry.getType() + ": " + _message); } @@ -198,12 +201,9 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { return; } long floodBegin = System.currentTimeMillis(); - if (_message.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) - _facade.flood(_message.getLeaseSet()); + _facade.flood(_message.getEntry()); // ERR: see comment in HandleDatabaseLookupMessageJob regarding hidden mode //else if (!_message.getRouterInfo().isHidden()) - else - _facade.flood(_message.getRouterInfo()); long floodEnd = System.currentTimeMillis(); getContext().statManager().addRateData("netDb.storeFloodNew", floodEnd-floodBegin, 0); } else { diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java index 0ae718104..ffcb8efd4 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java @@ -24,8 +24,8 @@ import java.util.Properties; import java.util.Set; import java.util.TreeSet; +import net.i2p.data.DatabaseEntry; import net.i2p.data.DataHelper; -import net.i2p.data.DataStructure; import net.i2p.data.Destination; import net.i2p.data.Hash; import net.i2p.data.Lease; @@ -235,11 +235,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { public void startup() { _log.info("Starting up the kademlia network database"); RouterInfo ri = _context.router().getRouterInfo(); - String dbDir = _context.router().getConfigSetting(PROP_DB_DIR); - if (dbDir == null) { - _log.info("No DB dir specified [" + PROP_DB_DIR + "], using [" + DEFAULT_DB_DIR + "]"); - dbDir = DEFAULT_DB_DIR; - } + String dbDir = _context.getProperty(PROP_DB_DIR, DEFAULT_DB_DIR); String enforce = _context.getProperty(PROP_ENFORCE_NETID); if (enforce != null) _enforceNetId = Boolean.valueOf(enforce).booleanValue(); @@ -247,7 +243,11 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { _enforceNetId = DEFAULT_ENFORCE_NETID; _kb = new KBucketSet(_context, ri.getIdentity().getHash()); - _ds = new PersistentDataStore(_context, dbDir, this); + try { + _ds = new PersistentDataStore(_context, dbDir, this); + } catch (IOException ioe) { + throw new RuntimeException("Unable to initialize netdb storage", ioe); + } //_ds = new TransientDataStore(); // _exploreKeys = new HashSet(64); _dbDir = dbDir; @@ -350,21 +350,11 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { /** get the hashes for all known routers */ public Set getAllRouters() { if (!_initialized) return Collections.EMPTY_SET; - Set keys = _ds.getKeys(); - Set rv = new HashSet(keys.size()); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("getAllRouters(): # keys in the datastore: " + keys.size()); - for (Hash key : keys) { - DataStructure ds = _ds.get(key); - if (ds == null) { - if (_log.shouldLog(Log.INFO)) - _log.info("Selected hash " + key.toBase64() + " is not stored locally"); - } else if ( !(ds instanceof RouterInfo) ) { - // leaseSet - } else { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("getAllRouters(): key is router: " + key.toBase64()); - rv.add(key); + Set> entries = _ds.getMapEntries(); + Set rv = new HashSet(entries.size()); + for (Map.Entry entry : entries) { + if (entry.getValue().getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { + rv.add(entry.getKey()); } } return rv; @@ -383,8 +373,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { public int size() { return _count; } public void add(Hash entry) { if (_ds == null) return; - Object o = _ds.get(entry); - if (o instanceof RouterInfo) + DatabaseEntry o = _ds.get(entry); + if (o != null && o.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) _count++; } } @@ -400,12 +390,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { public int getKnownLeaseSets() { if (_ds == null) return 0; //return _ds.countLeaseSets(); - Set keys = _ds.getKeys(); int rv = 0; - for (Hash key : keys) { - DataStructure ds = _ds.get(key); - if (ds != null && - ds instanceof LeaseSet && + for (DatabaseEntry ds : _ds.getEntries()) { + if (ds.getType() == DatabaseEntry.KEY_TYPE_LEASESET && ((LeaseSet)ds).getReceivedAsPublished()) rv++; } @@ -418,8 +405,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { public int size() { return _count; } public void add(Hash entry) { if (_ds == null) return; - Object o = _ds.get(entry); - if (o instanceof LeaseSet) + DatabaseEntry o = _ds.get(entry); + if (o != null && o.getType() == DatabaseEntry.KEY_TYPE_LEASESET) _count++; } } @@ -434,6 +421,32 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { return _kb.size(); } + /** + * @return RouterInfo, LeaseSet, or null, validated + * @since 0.8.3 + */ + public DatabaseEntry lookupLocally(Hash key) { + if (!_initialized) + return null; + DatabaseEntry rv = _ds.get(key); + if (rv == null) + return null; + if (rv.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { + LeaseSet ls = (LeaseSet)rv; + if (ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) + return rv; + else + fail(key); + } else if (rv.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { + try { + if (validate(key, (RouterInfo)rv) == null) + return rv; + } catch (IllegalArgumentException iae) {} + fail(key); + } + return null; + } + public void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) { if (!_initialized) return; LeaseSet ls = lookupLeaseSetLocally(key); @@ -453,9 +466,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { public LeaseSet lookupLeaseSetLocally(Hash key) { if (!_initialized) return null; - if (_ds.isKnown(key)) { - DataStructure ds = _ds.get(key); - if (ds instanceof LeaseSet) { + DatabaseEntry ds = _ds.get(key); + if (ds != null) { + if (ds.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { LeaseSet ls = (LeaseSet)ds; if (ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) { return ls; @@ -489,9 +502,9 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { public RouterInfo lookupRouterInfoLocally(Hash key) { if (!_initialized) return null; - DataStructure ds = _ds.get(key); + DatabaseEntry ds = _ds.get(key); if (ds != null) { - if (ds instanceof RouterInfo) { + if (ds.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { // more aggressive than perhaps is necessary, but makes sure we // drop old references that we had accepted on startup (since // startup allows some lax rules). @@ -610,6 +623,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { * Determine whether this leaseSet will be accepted as valid and current * given what we know now. * + * TODO this is called several times, only check the key and signature once + * * @return reason why the entry is not valid, or null if it is valid */ String validate(Hash key, LeaseSet leaseSet) { @@ -692,6 +707,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { * Determine whether this routerInfo will be accepted as valid and current * given what we know now. * + * TODO this is called several times, only check the key and signature once */ String validate(Hash key, RouterInfo routerInfo) throws IllegalArgumentException { long now = _context.clock().now(); @@ -807,30 +823,26 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { public void fail(Hash dbEntry) { if (!_initialized) return; - boolean isRouterInfo = false; - Object o = _ds.get(dbEntry); - if (o instanceof RouterInfo) - isRouterInfo = true; - - if (isRouterInfo) { - lookupBeforeDropping(dbEntry, (RouterInfo)o); - return; - } else { - // we always drop leaseSets that are failed [timed out], - // regardless of how many routers we have. this is called on a lease if - // it has expired *or* its tunnels are failing and we want to see if there - // are any updates - if (_log.shouldLog(Log.INFO)) - _log.info("Dropping a lease: " + dbEntry); - } - + DatabaseEntry o = _ds.get(dbEntry); if (o == null) { + // if we dont know the key, lets make sure it isn't a now-dead peer _kb.remove(dbEntry); _context.peerManager().removeCapabilities(dbEntry); - // if we dont know the key, lets make sure it isn't a now-dead peer + return; } - - _ds.remove(dbEntry, isRouterInfo); + + if (o.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { + lookupBeforeDropping(dbEntry, (RouterInfo)o); + return; + } + + // we always drop leaseSets that are failed [timed out], + // regardless of how many routers we have. this is called on a lease if + // it has expired *or* its tunnels are failing and we want to see if there + // are any updates + if (_log.shouldLog(Log.INFO)) + _log.info("Dropping a lease: " + dbEntry); + _ds.remove(dbEntry, false); } /** don't use directly - see F.N.D.F. override */ @@ -852,7 +864,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { public void unpublish(LeaseSet localLeaseSet) { if (!_initialized) return; Hash h = localLeaseSet.getDestination().calculateHash(); - DataStructure data = _ds.remove(h); + DatabaseEntry data = _ds.remove(h); if (data == null) { if (_log.shouldLog(Log.WARN)) @@ -906,8 +918,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { Set keys = getDataStore().getKeys(); for (Iterator iter = keys.iterator(); iter.hasNext(); ) { Hash key = (Hash)iter.next(); - Object o = getDataStore().get(key); - if (o instanceof LeaseSet) + DatabaseEntry o = getDataStore().get(key); + if (o.getType() == DatabaseEntry.KEY_TYPE_LEASESET) leases.add(o); } return leases; @@ -920,8 +932,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { Set keys = getDataStore().getKeys(); for (Iterator iter = keys.iterator(); iter.hasNext(); ) { Hash key = (Hash)iter.next(); - Object o = getDataStore().get(key); - if (o instanceof RouterInfo) + DatabaseEntry o = getDataStore().get(key); + if (o.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) routers.add(o); } return routers; @@ -953,7 +965,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { } /** unused (overridden in FNDF) */ - public void sendStore(Hash key, DataStructure ds, Job onSuccess, Job onFailure, long sendTimeout, Set toIgnore) { + public void sendStore(Hash key, DatabaseEntry ds, Job onSuccess, Job onFailure, long sendTimeout, Set toIgnore) { if ( (ds == null) || (key == null) ) { if (onFailure != null) _context.jobQueue().addJob(onFailure); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java index 429489cf0..ad938e7ed 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java @@ -19,8 +19,8 @@ import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import net.i2p.data.Base64; +import net.i2p.data.DatabaseEntry; import net.i2p.data.DataFormatException; -import net.i2p.data.DataStructure; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -39,19 +39,22 @@ import net.i2p.util.SecureFileOutputStream; * */ class PersistentDataStore extends TransientDataStore { - private Log _log; - private String _dbDir; - private KademliaNetworkDatabaseFacade _facade; - private Writer _writer; - private ReadJob _readJob; + private final Log _log; + private final File _dbDir; + private final KademliaNetworkDatabaseFacade _facade; + private final Writer _writer; + private final ReadJob _readJob; private boolean _initialized; private final static int READ_DELAY = 60*1000; - public PersistentDataStore(RouterContext ctx, String dbDir, KademliaNetworkDatabaseFacade facade) { + /** + * @param dbDir relative path + */ + public PersistentDataStore(RouterContext ctx, String dbDir, KademliaNetworkDatabaseFacade facade) throws IOException { super(ctx); _log = ctx.logManager().getLog(PersistentDataStore.class); - _dbDir = dbDir; + _dbDir = getDbDir(dbDir); _facade = facade; _readJob = new ReadJob(); _context.jobQueue().addJob(_readJob); @@ -79,7 +82,6 @@ class PersistentDataStore extends TransientDataStore { @Override public void restart() { super.restart(); - _dbDir = _facade.getDbDir(); } @Override @@ -89,7 +91,7 @@ class PersistentDataStore extends TransientDataStore { } @Override - public DataStructure get(Hash key) { + public DatabaseEntry get(Hash key) { return get(key, true); } @@ -98,8 +100,8 @@ class PersistentDataStore extends TransientDataStore { * @param persist if false, call super only, don't access disk */ @Override - public DataStructure get(Hash key, boolean persist) { - DataStructure rv = super.get(key); + public DatabaseEntry get(Hash key, boolean persist) { + DatabaseEntry rv = super.get(key); /***** if (rv != null || !persist) return rv; @@ -114,7 +116,7 @@ class PersistentDataStore extends TransientDataStore { } @Override - public DataStructure remove(Hash key) { + public DatabaseEntry remove(Hash key) { return remove(key, true); } @@ -122,7 +124,7 @@ class PersistentDataStore extends TransientDataStore { * @param persist if false, call super only, don't access disk */ @Override - public DataStructure remove(Hash key, boolean persist) { + public DatabaseEntry remove(Hash key, boolean persist) { if (persist) { _writer.remove(key); _context.jobQueue().addJob(new RemoveJob(key)); @@ -131,7 +133,7 @@ class PersistentDataStore extends TransientDataStore { } @Override - public boolean put(Hash key, DataStructure data) { + public boolean put(Hash key, DatabaseEntry data) { return put(key, data, true); } @@ -140,11 +142,11 @@ class PersistentDataStore extends TransientDataStore { * @return success */ @Override - public boolean put(Hash key, DataStructure data, boolean persist) { + public boolean put(Hash key, DatabaseEntry data, boolean persist) { if ( (data == null) || (key == null) ) return false; boolean rv = super.put(key, data); // Don't bother writing LeaseSets to disk - if (rv && persist && data instanceof RouterInfo) + if (rv && persist && data.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) _writer.queue(key, data); return rv; } @@ -160,8 +162,7 @@ class PersistentDataStore extends TransientDataStore { if (_log.shouldLog(Log.INFO)) _log.info("Removing key " + _key /* , getAddedBy() */); try { - File dbDir = getDbDir(); - removeFile(_key, dbDir); + removeFile(_key, _dbDir); } catch (IOException ioe) { _log.error("Error removing key " + _key, ioe); } @@ -180,10 +181,10 @@ class PersistentDataStore extends TransientDataStore { * We store a reference to the data here too, * rather than simply pull it from super.get(), because * we will soon have to implement a scheme for keeping only - * a subset of all DataStructures in memory and keeping the rest on disk. + * a subset of all DatabaseEntrys in memory and keeping the rest on disk. */ private class Writer implements Runnable { - private final Map_keys; + private final Map_keys; private final Object _waitLock; private volatile boolean _quit; @@ -192,7 +193,7 @@ class PersistentDataStore extends TransientDataStore { _waitLock = new Object(); } - public void queue(Hash key, DataStructure data) { + public void queue(Hash key, DatabaseEntry data) { int pending = _keys.size(); boolean exists = (null != _keys.put(key, data)); if (exists) @@ -201,7 +202,7 @@ class PersistentDataStore extends TransientDataStore { } /** check to see if it's in the write queue */ - public DataStructure get(Hash key) { + public DatabaseEntry get(Hash key) { return _keys.get(key); } @@ -212,16 +213,16 @@ class PersistentDataStore extends TransientDataStore { public void run() { _quit = false; Hash key = null; - DataStructure data = null; + DatabaseEntry data = null; int count = 0; int lastCount = 0; long startTime = 0; while (true) { // get a new iterator every time to get a random entry without // having concurrency issues or copying to a List or Array - Iterator> iter = _keys.entrySet().iterator(); + Iterator> iter = _keys.entrySet().iterator(); try { - Map.Entry entry = iter.next(); + Map.Entry entry = iter.next(); key = entry.getKey(); data = entry.getValue(); iter.remove(); @@ -236,7 +237,10 @@ class PersistentDataStore extends TransientDataStore { if (key != null) { if (data != null) { - write(key, data); + // synch with the reader job + synchronized (_dbDir) { + write(key, data); + } data = null; } key = null; @@ -271,23 +275,22 @@ class PersistentDataStore extends TransientDataStore { } } - private void write(Hash key, DataStructure data) { + private void write(Hash key, DatabaseEntry data) { if (_log.shouldLog(Log.INFO)) _log.info("Writing key " + key); FileOutputStream fos = null; File dbFile = null; try { String filename = null; - File dbDir = getDbDir(); - if (data instanceof LeaseSet) + if (data.getType() == DatabaseEntry.KEY_TYPE_LEASESET) filename = getLeaseSetName(key); - else if (data instanceof RouterInfo) + else if (data.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) filename = getRouterInfoName(key); else throw new IOException("We don't know how to write objects of type " + data.getClass().getName()); - dbFile = new File(dbDir, filename); + dbFile = new File(_dbDir, filename); long dataPublishDate = getPublishDate(data); if (dbFile.lastModified() < dataPublishDate) { // our filesystem is out of date, lets replace it @@ -313,27 +316,33 @@ class PersistentDataStore extends TransientDataStore { if (fos != null) try { fos.close(); } catch (IOException ioe) {} } } - private long getPublishDate(DataStructure data) { - if (data instanceof RouterInfo) { - return ((RouterInfo)data).getPublished(); - } else if (data instanceof LeaseSet) { - return ((LeaseSet)data).getEarliestLeaseDate(); - } else { - return -1; - } + private long getPublishDate(DatabaseEntry data) { + return data.getDate(); } /** This is only for manual reseeding? Why bother every 60 sec??? */ private class ReadJob extends JobImpl { private boolean _alreadyWarned; + private long _lastModified; + public ReadJob() { super(PersistentDataStore.this._context); _alreadyWarned = false; } + public String getName() { return "DB Read Job"; } + public void runJob() { - _log.info("Rereading new files"); - readFiles(); + // check directory mod time to save a lot of object churn in scanning all the file names + long lastMod = _dbDir.lastModified(); + if (lastMod > _lastModified) { + _lastModified = lastMod; + _log.info("Rereading new files"); + // synch with the writer job + synchronized (_dbDir) { + readFiles(); + } + } requeue(READ_DELAY); } @@ -343,9 +352,8 @@ class PersistentDataStore extends TransientDataStore { private void readFiles() { int routerCount = 0; - try { - File dbDir = getDbDir(); - File routerInfoFiles[] = dbDir.listFiles(RouterInfoFilter.getInstance()); + + File routerInfoFiles[] = _dbDir.listFiles(RouterInfoFilter.getInstance()); if (routerInfoFiles != null) { routerCount += routerInfoFiles.length; if (routerInfoFiles.length > 5) @@ -360,9 +368,6 @@ class PersistentDataStore extends TransientDataStore { } } } - } catch (IOException ioe) { - _log.error("Error reading files in the db dir", ioe); - } if (!_alreadyWarned) { ReseedChecker.checkReseed(_context, routerCount); @@ -384,9 +389,9 @@ class PersistentDataStore extends TransientDataStore { private boolean shouldRead() { // persist = false to call only super.get() - DataStructure data = get(_key, false); + DatabaseEntry data = get(_key, false); if (data == null) return true; - if (data instanceof RouterInfo) { + if (data.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { long knownDate = ((RouterInfo)data).getPublished(); long fileDate = _routerFile.lastModified(); if (fileDate > knownDate) @@ -442,8 +447,8 @@ class PersistentDataStore extends TransientDataStore { } - private File getDbDir() throws IOException { - File f = new SecureDirectory(_context.getRouterDir(), _dbDir); + private File getDbDir(String dbDir) throws IOException { + File f = new SecureDirectory(_context.getRouterDir(), dbDir); if (!f.exists()) { boolean created = f.mkdirs(); if (!created) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java index 9400a17f6..09f150db0 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java @@ -14,8 +14,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import net.i2p.data.DatabaseEntry; import net.i2p.data.DataHelper; -import net.i2p.data.DataStructure; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -293,12 +293,12 @@ class SearchJob extends JobImpl { attempted.addAll(closestHashes); for (Iterator iter = closestHashes.iterator(); iter.hasNext(); ) { Hash peer = (Hash)iter.next(); - DataStructure ds = _facade.getDataStore().get(peer); + DatabaseEntry ds = _facade.getDataStore().get(peer); if (ds == null) { if (_log.shouldLog(Log.INFO)) _log.info("Next closest peer " + peer + " was only recently referred to us, sending a search for them"); getContext().netDb().lookupRouterInfo(peer, null, null, _timeoutMs); - } else if (!(ds instanceof RouterInfo)) { + } else if (!(ds.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO)) { if (_log.shouldLog(Log.WARN)) _log.warn(getJobId() + ": Error selecting closest hash that wasnt a router! " + peer + " : " + ds.getClass().getName()); @@ -635,7 +635,7 @@ class SearchJob extends JobImpl { * */ private void resend() { - DataStructure ds = _facade.lookupLeaseSetLocally(_state.getTarget()); + DatabaseEntry ds = _facade.lookupLeaseSetLocally(_state.getTarget()); if (ds == null) { if (SHOULD_RESEND_ROUTERINFO) { ds = _facade.lookupRouterInfoLocally(_state.getTarget()); @@ -665,8 +665,7 @@ class SearchJob extends JobImpl { */ private boolean resend(RouterInfo toPeer, LeaseSet ls) { DatabaseStoreMessage msg = new DatabaseStoreMessage(getContext()); - msg.setKey(ls.getDestination().calculateHash()); - msg.setLeaseSet(ls); + msg.setEntry(ls); msg.setMessageExpiration(getContext().clock().now() + RESEND_TIMEOUT); TunnelInfo outTunnel = getContext().tunnelManager().selectOutboundTunnel(); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java index b5a824472..22602b497 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java @@ -2,7 +2,9 @@ package net.i2p.router.networkdb.kademlia; import java.util.Date; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; +import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; @@ -78,22 +80,23 @@ class SearchUpdateReplyFoundJob extends JobImpl implements ReplyJob { long timeToReply = _state.dataFound(_peer); DatabaseStoreMessage msg = (DatabaseStoreMessage)message; - if (msg.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) { + DatabaseEntry entry = msg.getEntry(); + if (entry.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { try { - _facade.store(msg.getKey(), msg.getLeaseSet()); + _facade.store(msg.getKey(), (LeaseSet) entry); getContext().profileManager().dbLookupSuccessful(_peer, timeToReply); } catch (IllegalArgumentException iae) { if (_log.shouldLog(Log.ERROR)) _log.warn("Peer " + _peer + " sent us an invalid leaseSet: " + iae.getMessage()); getContext().profileManager().dbLookupReply(_peer, 0, 0, 1, 0, timeToReply); } - } else if (msg.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) { + } else if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { if (_log.shouldLog(Log.INFO)) _log.info(getJobId() + ": dbStore received on search containing router " + msg.getKey() + " with publishDate of " - + new Date(msg.getRouterInfo().getPublished())); + + new Date(entry.getDate())); try { - _facade.store(msg.getKey(), msg.getRouterInfo()); + _facade.store(msg.getKey(), (RouterInfo) entry); getContext().profileManager().dbLookupSuccessful(_peer, timeToReply); } catch (IllegalArgumentException iae) { if (_log.shouldLog(Log.ERROR)) @@ -102,7 +105,7 @@ class SearchUpdateReplyFoundJob extends JobImpl implements ReplyJob { } } else { if (_log.shouldLog(Log.ERROR)) - _log.error(getJobId() + ": Unknown db store type?!@ " + msg.getValueType()); + _log.error(getJobId() + ": Unknown db store type?!@ " + entry.getType()); } } else if (message instanceof DatabaseSearchReplyMessage) { _job.replyFound((DatabaseSearchReplyMessage)message, _peer); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java index ad8217c6a..47a3e17d6 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java @@ -13,7 +13,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import net.i2p.data.DataStructure; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -61,7 +61,7 @@ class StoreJob extends JobImpl { * */ public StoreJob(RouterContext context, KademliaNetworkDatabaseFacade facade, Hash key, - DataStructure data, Job onSuccess, Job onFailure, long timeoutMs) { + DatabaseEntry data, Job onSuccess, Job onFailure, long timeoutMs) { this(context, facade, key, data, onSuccess, onFailure, timeoutMs, null); } @@ -70,7 +70,7 @@ class StoreJob extends JobImpl { * already know they have it). This can be null. */ public StoreJob(RouterContext context, KademliaNetworkDatabaseFacade facade, Hash key, - DataStructure data, Job onSuccess, Job onFailure, long timeoutMs, Set toSkip) { + DatabaseEntry data, Job onSuccess, Job onFailure, long timeoutMs, Set toSkip) { super(context); _log = context.logManager().getLog(StoreJob.class); _facade = facade; @@ -167,8 +167,8 @@ class StoreJob extends JobImpl { _log.info(getJobId() + ": Continue sending key " + _state.getTarget() + " after " + _state.getAttempted().size() + " tries to " + closestHashes); for (Iterator iter = closestHashes.iterator(); iter.hasNext(); ) { Hash peer = iter.next(); - DataStructure ds = _facade.getDataStore().get(peer); - if ( (ds == null) || !(ds instanceof RouterInfo) ) { + DatabaseEntry ds = _facade.getDataStore().get(peer); + if ( (ds == null) || !(ds.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) ) { if (_log.shouldLog(Log.INFO)) _log.info(getJobId() + ": Error selecting closest hash that wasnt a router! " + peer + " : " + ds); _state.addSkipped(peer); @@ -255,16 +255,19 @@ class StoreJob extends JobImpl { * */ private void sendStore(RouterInfo router, int responseTime) { + if (!_state.getTarget().equals(_state.getData().getHash())) { + _log.error("Hash mismatch StoreJob"); + return; + } DatabaseStoreMessage msg = new DatabaseStoreMessage(getContext()); - msg.setKey(_state.getTarget()); - if (_state.getData() instanceof RouterInfo) { - msg.setRouterInfo((RouterInfo)_state.getData()); + if (_state.getData().getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { if (responseTime > MAX_DIRECT_EXPIRATION) responseTime = MAX_DIRECT_EXPIRATION; - } else if (_state.getData() instanceof LeaseSet) - msg.setLeaseSet((LeaseSet)_state.getData()); - else + } else if (_state.getData().getType() == DatabaseEntry.KEY_TYPE_LEASESET) { + } else { throw new IllegalArgumentException("Storing an unknown data type! " + _state.getData()); + } + msg.setEntry(_state.getData()); msg.setMessageExpiration(getContext().clock().now() + _timeoutMs); if (router.getIdentity().equals(getContext().router().getRouterInfo().getIdentity())) { @@ -286,7 +289,7 @@ class StoreJob extends JobImpl { * */ private void sendStore(DatabaseStoreMessage msg, RouterInfo peer, long expiration) { - if (msg.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) { + if (msg.getEntry().getType() == DatabaseEntry.KEY_TYPE_LEASESET) { getContext().statManager().addRateData("netDb.storeLeaseSetSent", 1, 0); // if it is an encrypted leaseset... if (getContext().keyRing().get(msg.getKey()) != null) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java index eb131fdfc..4737a4707 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java @@ -9,7 +9,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import net.i2p.data.DataStructure; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.router.RouterContext; @@ -19,7 +19,7 @@ import net.i2p.router.RouterContext; class StoreState { private RouterContext _context; private Hash _key; - private DataStructure _data; + private DatabaseEntry _data; private final HashSet _pendingPeers; private Map _pendingPeerTimes; private Map _pendingMessages; @@ -31,10 +31,10 @@ class StoreState { private volatile long _completed; private volatile long _started; - public StoreState(RouterContext ctx, Hash key, DataStructure data) { + public StoreState(RouterContext ctx, Hash key, DatabaseEntry data) { this(ctx, key, data, null); } - public StoreState(RouterContext ctx, Hash key, DataStructure data, Set toSkip) { + public StoreState(RouterContext ctx, Hash key, DatabaseEntry data, Set toSkip) { _context = ctx; _key = key; _data = data; @@ -54,7 +54,7 @@ class StoreState { } public Hash getTarget() { return _key; } - public DataStructure getData() { return _data; } + public DatabaseEntry getData() { return _data; } public Set getPending() { synchronized (_pendingPeers) { return (Set)_pendingPeers.clone(); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java index d5e10738c..59156321e 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java @@ -8,14 +8,15 @@ package net.i2p.router.networkdb.kademlia; * */ +import java.util.Collection; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import net.i2p.data.DatabaseEntry; import net.i2p.data.DataHelper; -import net.i2p.data.DataStructure; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; @@ -24,7 +25,7 @@ import net.i2p.util.Log; class TransientDataStore implements DataStore { private Log _log; - private ConcurrentHashMap _data; + private ConcurrentHashMap _data; protected RouterContext _context; public TransientDataStore(RouterContext ctx) { @@ -51,12 +52,28 @@ class TransientDataStore implements DataStore { return new HashSet(_data.keySet()); } + /** + * @return not a copy + * @since 0.8.3 + */ + public Collection getEntries() { + return _data.values(); + } + + /** + * @return not a copy + * @since 0.8.3 + */ + public Set> getMapEntries() { + return _data.entrySet(); + } + /** for PersistentDataStore only - don't use here @throws IAE always */ - public DataStructure get(Hash key, boolean persist) { + public DatabaseEntry get(Hash key, boolean persist) { throw new IllegalArgumentException("no"); } - public DataStructure get(Hash key) { + public DatabaseEntry get(Hash key) { return _data.get(key); } @@ -66,15 +83,15 @@ class TransientDataStore implements DataStore { public int countLeaseSets() { int count = 0; - for (DataStructure d : _data.values()) { - if (d instanceof LeaseSet) + for (DatabaseEntry d : _data.values()) { + if (d.getType() == DatabaseEntry.KEY_TYPE_LEASESET) count++; } return count; } /** for PersistentDataStore only - don't use here @throws IAE always */ - public boolean put(Hash key, DataStructure data, boolean persist) { + public boolean put(Hash key, DatabaseEntry data, boolean persist) { throw new IllegalArgumentException("no"); } @@ -82,14 +99,14 @@ class TransientDataStore implements DataStore { * @param data must be validated before here * @return success */ - public boolean put(Hash key, DataStructure data) { + public boolean put(Hash key, DatabaseEntry data) { if (data == null) return false; if (_log.shouldLog(Log.DEBUG)) _log.debug("Storing key " + key); - DataStructure old = null; + DatabaseEntry old = null; old = _data.putIfAbsent(key, data); boolean rv = false; - if (data instanceof RouterInfo) { + if (data.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { // Don't do this here so we don't reset it at router startup; // the StoreMessageJob calls this //_context.profileManager().heardAbout(key); @@ -113,7 +130,7 @@ class TransientDataStore implements DataStore { _log.info("New router for " + key + ": published on " + new Date(ri.getPublished())); rv = true; } - } else if (data instanceof LeaseSet) { + } else if (data.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { LeaseSet ls = (LeaseSet)data; if (old != null) { LeaseSet ols = (LeaseSet)old; @@ -158,9 +175,9 @@ class TransientDataStore implements DataStore { public String toString() { StringBuilder buf = new StringBuilder(); buf.append("Transient DataStore: ").append(_data.size()).append("\nKeys: "); - for (Map.Entry e : _data.entrySet()) { + for (Map.Entry e : _data.entrySet()) { Hash key = e.getKey(); - DataStructure dp = e.getValue(); + DatabaseEntry dp = e.getValue(); buf.append("\n\t*Key: ").append(key.toString()).append("\n\tContent: ").append(dp.toString()); } buf.append("\n"); @@ -168,11 +185,11 @@ class TransientDataStore implements DataStore { } /** for PersistentDataStore only - don't use here */ - public DataStructure remove(Hash key, boolean persist) { + public DatabaseEntry remove(Hash key, boolean persist) { throw new IllegalArgumentException("no"); } - public DataStructure remove(Hash key) { + public DatabaseEntry remove(Hash key) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Removing key " + key.toBase64()); return _data.remove(key); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/XORComparator.java b/router/java/src/net/i2p/router/networkdb/kademlia/XORComparator.java index 3c2b9d2d2..71dbefc6e 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/XORComparator.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/XORComparator.java @@ -9,7 +9,7 @@ import net.i2p.data.Hash; * Help sort Hashes in relation to a base key using the XOR metric * */ -class XORComparator implements Comparator { +class XORComparator implements Comparator { private Hash _base; /** * @param target key to compare distances with @@ -17,15 +17,11 @@ class XORComparator implements Comparator { public XORComparator(Hash target) { _base = target; } - public int compare(Object lhs, Object rhs) { + public int compare(Hash lhs, Hash rhs) { if (lhs == null) throw new NullPointerException("LHS is null"); if (rhs == null) throw new NullPointerException("RHS is null"); - if ( (lhs instanceof Hash) && (rhs instanceof Hash) ) { - byte lhsDelta[] = DataHelper.xor(((Hash)lhs).getData(), _base.getData()); - byte rhsDelta[] = DataHelper.xor(((Hash)rhs).getData(), _base.getData()); - return DataHelper.compareTo(lhsDelta, rhsDelta); - } else { - throw new ClassCastException(lhs.getClass().getName() + " / " + rhs.getClass().getName()); - } + byte lhsDelta[] = DataHelper.xor(lhs.getData(), _base.getData()); + byte rhsDelta[] = DataHelper.xor(rhs.getData(), _base.getData()); + return DataHelper.compareTo(lhsDelta, rhsDelta); } } diff --git a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java index 4f225ec97..b2b6671c8 100644 --- a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java +++ b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java @@ -3,6 +3,7 @@ package net.i2p.router.networkdb.reseed; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -278,7 +279,7 @@ public class Reseeder { if (fetched % 60 == 0) System.out.println(); } - } catch (Exception e) { + } catch (IOException e) { errors++; } } @@ -298,20 +299,20 @@ public class Reseeder { } /* Since we don't return a value, we should always throw an exception if something fails. */ - private void fetchSeed(String seedURL, String peer) throws Exception { + private void fetchSeed(String seedURL, String peer) throws IOException { URL url = new URL(seedURL + (seedURL.endsWith("/") ? "" : "/") + "routerInfo-" + peer + ".dat"); byte data[] = readURL(url); if (data == null) { // Logging deprecated here since attemptFailed() provides better info _log.debug("Failed fetching seed: " + url.toString()); - throw new Exception ("Failed fetching seed."); + throw new IOException("Failed fetching seed."); } //System.out.println("read: " + (data != null ? data.length : -1)); writeSeed(peer, data); } - private byte[] readURL(URL url) throws Exception { + private byte[] readURL(URL url) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024); EepGet get; @@ -338,15 +339,21 @@ public class Reseeder { return null; } - private void writeSeed(String name, byte data[]) throws Exception { + private void writeSeed(String name, byte data[]) throws IOException { String dirName = "netDb"; // _context.getProperty("router.networkDatabase.dbDir", "netDb"); File netDbDir = new SecureDirectory(_context.getRouterDir(), dirName); if (!netDbDir.exists()) { boolean ok = netDbDir.mkdirs(); } - FileOutputStream fos = new SecureFileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat")); - fos.write(data); - fos.close(); + FileOutputStream fos = null; + try { + fos = new SecureFileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat")); + fos.write(data); + } finally { + try { + if (fos != null) fos.close(); + } catch (IOException ioe) {} + } } } diff --git a/router/java/src/net/i2p/router/peermanager/PeerProfile.java b/router/java/src/net/i2p/router/peermanager/PeerProfile.java index 6f7fe54bb..a2665004b 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerProfile.java +++ b/router/java/src/net/i2p/router/peermanager/PeerProfile.java @@ -484,14 +484,17 @@ public class PeerProfile { @Override public int hashCode() { return (_peer == null ? 0 : _peer.hashCode()); } + @Override public boolean equals(Object obj) { - if (obj == null) return false; - if (obj.getClass() != PeerProfile.class) return false; - if (_peer == null) return false; + if (obj == null || + (!(obj instanceof PeerProfile)) || + _peer == null) + return false; PeerProfile prof = (PeerProfile)obj; return _peer.equals(prof.getPeer()); } + @Override public String toString() { return "Profile: " + getPeer().toBase64(); } diff --git a/router/java/src/net/i2p/router/peermanager/PeerTestJob.java b/router/java/src/net/i2p/router/peermanager/PeerTestJob.java index 11e8cacb8..1d5fe3a84 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerTestJob.java +++ b/router/java/src/net/i2p/router/peermanager/PeerTestJob.java @@ -178,8 +178,7 @@ public class PeerTestJob extends JobImpl { */ private DatabaseStoreMessage buildMessage(RouterInfo peer, TunnelId replyTunnel, Hash replyGateway, long nonce, long expiration) { DatabaseStoreMessage msg = new DatabaseStoreMessage(getContext()); - msg.setKey(peer.getIdentity().getHash()); - msg.setRouterInfo(peer); + msg.setEntry(peer); msg.setReplyGateway(replyGateway); msg.setReplyTunnel(replyTunnel); msg.setReplyToken(nonce); diff --git a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java index e012fab49..592c1f267 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java +++ b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java @@ -1,9 +1,11 @@ package net.i2p.router.peermanager; +import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FilenameFilter; +import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.util.HashSet; @@ -270,11 +272,12 @@ class ProfilePersistenceHelper { } private void loadProps(Properties props, File file) { + InputStream fin = null; try { - FileInputStream fin = new FileInputStream(file); + fin = new BufferedInputStream(new FileInputStream(file), 1); + fin.mark(1); int c = fin.read(); - fin.close(); - fin = new FileInputStream(file); // ghetto mark+reset + fin.reset(); if (c == '#') { // uncompressed if (_log.shouldLog(Log.INFO)) @@ -289,6 +292,10 @@ class ProfilePersistenceHelper { } catch (IOException ioe) { if (_log.shouldLog(Log.WARN)) _log.warn("Error loading properties from " + file.getName(), ioe); + } finally { + try { + if (fin != null) fin.close(); + } catch (IOException e) {} } } diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java index 094f526c7..8a90adc37 100644 --- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java +++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java @@ -215,7 +215,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade { * This should really be moved to ntcp/NTCPTransport.java, why is it here? */ public static RouterAddress createNTCPAddress(RouterContext ctx) { - if (!TransportManager.enableNTCP(ctx)) return null; + if (!TransportManager.isNTCPEnabled(ctx)) return null; String name = ctx.router().getConfigSetting(PROP_I2NP_NTCP_HOSTNAME); String port = ctx.router().getConfigSetting(PROP_I2NP_NTCP_PORT); /* diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java index 7ac7d05b2..fef585022 100644 --- a/router/java/src/net/i2p/router/transport/TransportImpl.java +++ b/router/java/src/net/i2p/router/transport/TransportImpl.java @@ -512,7 +512,7 @@ public abstract class TransportImpl implements Transport { public void markUnreachable(Hash peer) { long now = _context.clock().now(); synchronized (_unreachableEntries) { - _unreachableEntries.put(peer, new Long(now)); + _unreachableEntries.put(peer, Long.valueOf(now)); } markWasUnreachable(peer, true); } diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index a682840b1..a0a7db519 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -46,10 +46,10 @@ public class TransportManager implements TransportEventListener { private RouterContext _context; private UPnPManager _upnpManager; + /** default true */ public final static String PROP_ENABLE_UDP = "i2np.udp.enable"; + /** default true */ public final static String PROP_ENABLE_NTCP = "i2np.ntcp.enable"; - public final static String DEFAULT_ENABLE_NTCP = "true"; - public final static String DEFAULT_ENABLE_UDP = "true"; /** default true */ public final static String PROP_ENABLE_UPNP = "i2np.upnp.enable"; @@ -80,37 +80,33 @@ public class TransportManager implements TransportEventListener { } private void configTransports() { - String enableUDP = _context.router().getConfigSetting(PROP_ENABLE_UDP); - if (enableUDP == null) - enableUDP = DEFAULT_ENABLE_UDP; - if ("true".equalsIgnoreCase(enableUDP)) { + boolean enableUDP = _context.getBooleanPropertyDefaultTrue(PROP_ENABLE_UDP); + if (enableUDP) { UDPTransport udp = new UDPTransport(_context); addTransport(udp); initializeAddress(udp); } - if (enableNTCP(_context)) + if (isNTCPEnabled(_context)) addTransport(new NTCPTransport(_context)); if (_transports.isEmpty()) _log.log(Log.CRIT, "No transports are enabled"); } - public static boolean enableNTCP(RouterContext ctx) { - String enableNTCP = ctx.router().getConfigSetting(PROP_ENABLE_NTCP); - if (enableNTCP == null) - enableNTCP = DEFAULT_ENABLE_NTCP; - return "true".equalsIgnoreCase(enableNTCP); + public static boolean isNTCPEnabled(RouterContext ctx) { + return ctx.getBooleanPropertyDefaultTrue(PROP_ENABLE_NTCP); } - private static void initializeAddress(Transport t) { + private void initializeAddress(Transport t) { String ips = Addresses.getAnyAddress(); if (ips == null) return; - InetAddress ia = null; + InetAddress ia; try { ia = InetAddress.getByName(ips); - } catch (UnknownHostException e) {return;} - if (ia == null) + } catch (UnknownHostException e) { + _log.error("UDP failed to bind to local address", e); return; + } byte[] ip = ia.getAddress(); t.externalAddressReceived(Transport.SOURCE_INTERFACE, ip, 0); } diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java index d13a51cec..c2ccf03f1 100644 --- a/router/java/src/net/i2p/router/transport/UPnP.java +++ b/router/java/src/net/i2p/router/transport/UPnP.java @@ -554,7 +554,10 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis return retval; } - /** non-blocking */ + /** + * non-blocking + * @param ports non-null + */ public void onChangePublicPorts(Set ports, ForwardPortCallback cb) { Set portsToDumpNow = null; Set portsToForwardNow = null; @@ -568,7 +571,7 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis portsToForward = ports; portsToForwardNow = ports; portsToDumpNow = null; - } else if(ports == null || ports.isEmpty()) { + } else if(ports.isEmpty()) { portsToDumpNow = portsToForward; portsToForward = ports; portsToForwardNow = null; diff --git a/router/java/src/net/i2p/router/transport/UPnPManager.java b/router/java/src/net/i2p/router/transport/UPnPManager.java index 7996a4556..fbd0d7db2 100644 --- a/router/java/src/net/i2p/router/transport/UPnPManager.java +++ b/router/java/src/net/i2p/router/transport/UPnPManager.java @@ -87,8 +87,9 @@ public class UPnPManager { if (!_isRunning) return; Set forwards = new HashSet(ports.size()); - for (String style : ports.keySet()) { - int port = ports.get(style).intValue(); + for (Map.Entry entry : ports.entrySet()) { + String style = entry.getKey(); + int port = entry.getValue().intValue(); int protocol = -1; if ("SSU".equals(style)) protocol = ForwardPort.PROTOCOL_UDP_IPV4; @@ -136,8 +137,9 @@ public class UPnPManager { _log.debug("No external address returned"); } - for (ForwardPort fp : statuses.keySet()) { - ForwardPortStatus fps = statuses.get(fp); + for (Map.Entry entry : statuses.entrySet()) { + ForwardPort fp = entry.getKey(); + ForwardPortStatus fps = entry.getValue(); if (_log.shouldLog(Log.DEBUG)) _log.debug(fp.name + " " + fp.protocol + " " + fp.portNumber + " status: " + fps.status + " reason: " + fps.reasonString + " ext port: " + fps.externalPort); 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 8de07fe6e..d6109c640 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java +++ b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java @@ -69,7 +69,7 @@ import net.i2p.util.Log; * NOTE: Check info is unused. * */ -public class EstablishState { +class EstablishState { private RouterContext _context; private Log _log; 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 29592bf52..eeeef56c1 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java +++ b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java @@ -26,7 +26,7 @@ import net.i2p.util.Log; /** * */ -public class EventPumper implements Runnable { +class EventPumper implements Runnable { private RouterContext _context; private Log _log; private volatile boolean _alive; 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 3fb4c6b37..a24b3d972 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java @@ -53,9 +53,9 @@ import net.i2p.util.Log; * * */ -public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { - private RouterContext _context; - private Log _log; +class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { + private final RouterContext _context; + private final Log _log; private SocketChannel _chan; private SelectionKey _conKey; /** list of ByteBuffer containing data we have read and are ready to process, oldest first */ @@ -71,7 +71,7 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { private long _establishedOn; private EstablishState _establishState; private NTCPTransport _transport; - private boolean _isInbound; + private final boolean _isInbound; private boolean _closed; private NTCPAddress _remAddr; private RouterIdentity _remotePeer; @@ -87,17 +87,17 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { private byte _curReadBlock[]; /** next byte to which data should be placed in the _curReadBlock */ private int _curReadBlockIndex; - private byte _decryptBlockBuf[]; + private final byte _decryptBlockBuf[]; /** last AES block of the encrypted I2NP message (to serve as the next block's IV) */ private byte _prevReadBlock[]; private byte _prevWriteEnd[]; /** current partially read I2NP message */ - private ReadState _curReadState; + private final ReadState _curReadState; private long _messagesRead; private long _messagesWritten; private long _lastSendTime; private long _lastReceiveTime; - private long _created; + private final long _created; private long _nextMetaTime; /** unencrypted outbound metadata buffer */ private final byte _meta[] = new byte[16]; @@ -127,28 +127,21 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { _context = ctx; _log = ctx.logManager().getLog(getClass()); _created = System.currentTimeMillis(); - _lastSendTime = _created; - _lastReceiveTime = _created; _transport = transport; _chan = chan; _readBufs = new LinkedBlockingQueue(); _writeBufs = new LinkedBlockingQueue(); _bwRequests = new ConcurrentHashSet(2); _outbound = new LinkedBlockingQueue(); - _established = false; _isInbound = true; - _closed = false; _decryptBlockBuf = new byte[16]; - _curReadBlock = new byte[16]; - _prevReadBlock = new byte[16]; _curReadState = new ReadState(); _establishState = new EstablishState(ctx, transport, this); _conKey = key; _conKey.attach(this); - _sendingMeta = false; - _consecutiveBacklog = 0; - transport.establishing(this); + initialize(); } + /** * Create an outbound unconnected NTCP connection * @@ -157,26 +150,25 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { _context = ctx; _log = ctx.logManager().getLog(getClass()); _created = System.currentTimeMillis(); - _lastSendTime = _created; - _lastReceiveTime = _created; _transport = transport; + _remotePeer = remotePeer; _remAddr = remAddr; _readBufs = new LinkedBlockingQueue(); _writeBufs = new LinkedBlockingQueue(); _bwRequests = new ConcurrentHashSet(2); _outbound = new LinkedBlockingQueue(); - _established = false; _isInbound = false; - _closed = false; _decryptBlockBuf = new byte[16]; + _curReadState = new ReadState(); + initialize(); + } + + private void initialize() { + _lastSendTime = _created; + _lastReceiveTime = _created; _curReadBlock = new byte[16]; _prevReadBlock = new byte[16]; - _curReadState = new ReadState(); - _remotePeer = remotePeer; - _sendingMeta = false; - _consecutiveBacklog = 0; - //_establishState = new EstablishState(ctx, transport, this); - transport.establishing(this); + _transport.establishing(this); } public SocketChannel getChannel() { return _chan; } @@ -207,13 +199,18 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { _nextMetaTime = System.currentTimeMillis() + _context.random().nextInt(META_FREQUENCY); _nextInfoTime = System.currentTimeMillis() + (INFO_FREQUENCY / 2) + _context.random().nextInt(INFO_FREQUENCY); } + + /** @return seconds */ public long getClockSkew() { return _clockSkew; } + + /** @return milliseconds */ public long getUptime() { if (!_established) return getTimeSinceCreated(); else return System.currentTimeMillis()-_establishedOn; } + public long getMessagesSent() { return _messagesWritten; } public long getMessagesReceived() { return _messagesRead; } public long getOutboundQueueSize() { @@ -222,9 +219,16 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { queued++; return queued; } + + /** @return milliseconds */ public long getTimeSinceSend() { return System.currentTimeMillis()-_lastSendTime; } + + /** @return milliseconds */ public long getTimeSinceReceive() { return System.currentTimeMillis()-_lastReceiveTime; } + + /** @return milliseconds */ public long getTimeSinceCreated() { return System.currentTimeMillis()-_created; } + public int getConsecutiveBacklog() { return _consecutiveBacklog; } public boolean isClosed() { return _closed; } @@ -344,8 +348,7 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { OutNetMessage infoMsg = new OutNetMessage(_context); infoMsg.setExpiration(_context.clock().now()+10*1000); DatabaseStoreMessage dsm = new DatabaseStoreMessage(_context); - dsm.setKey(_context.routerHash()); - dsm.setRouterInfo(_context.router().getRouterInfo()); + dsm.setEntry(_context.router().getRouterInfo()); infoMsg.setMessage(dsm); infoMsg.setPriority(100); RouterInfo target = _context.netDb().lookupRouterInfoLocally(_remotePeer.calculateHash()); @@ -625,26 +628,26 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { } msg.beginTransmission(); - long begin = System.currentTimeMillis(); + //long begin = System.currentTimeMillis(); PrepBuffer buf = (PrepBuffer)msg.releasePreparationBuffer(); if (buf == null) throw new RuntimeException("buf is null for " + msg); _context.aes().encrypt(buf.unencrypted, 0, buf.encrypted, 0, _sessionKey, _prevWriteEnd, 0, buf.unencryptedLength); System.arraycopy(buf.encrypted, buf.encrypted.length-16, _prevWriteEnd, 0, _prevWriteEnd.length); - long encryptedTime = System.currentTimeMillis(); + //long encryptedTime = System.currentTimeMillis(); //if (_log.shouldLog(Log.DEBUG)) // _log.debug("Encrypting " + msg + " [" + System.identityHashCode(msg) + "] crc=" + crc.getValue() + "\nas: " // + Base64.encode(encrypted, 0, 16) + "...\ndecrypted: " // + Base64.encode(unencrypted, 0, 16) + "..." + "\nIV=" + Base64.encode(_prevWriteEnd, 0, 16)); _transport.getPumper().wantsWrite(this, buf.encrypted); - long wantsTime = System.currentTimeMillis(); + //long wantsTime = System.currentTimeMillis(); releaseBuf(buf); - long releaseTime = System.currentTimeMillis(); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("prepared outbound " + System.identityHashCode(msg) - + " encrypted=" + (encryptedTime-begin) - + " wantsWrite=" + (wantsTime-encryptedTime) - + " releaseBuf=" + (releaseTime-wantsTime)); + //long releaseTime = System.currentTimeMillis(); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("prepared outbound " + System.identityHashCode(msg) + // + " encrypted=" + (encryptedTime-begin) + // + " wantsWrite=" + (wantsTime-encryptedTime) + // + " releaseBuf=" + (releaseTime-wantsTime)); // for every 6-12 hours that we are connected to a peer, send them // our updated netDb info (they may not accept it and instead query @@ -667,9 +670,9 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { //if (!_isInbound && !_established) // return; msg.beginPrepare(); - long begin = System.currentTimeMillis(); + //long begin = System.currentTimeMillis(); PrepBuffer buf = acquireBuf(); - long alloc = System.currentTimeMillis(); + //long alloc = System.currentTimeMillis(); I2NPMessage m = msg.getMessage(); buf.baseLength = m.toByteArray(buf.base); @@ -689,7 +692,7 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { _context.random().nextBytes(buf.pad); // maybe more than necessary, but its only the prng System.arraycopy(buf.pad, 0, buf.unencrypted, 2+sz, buf.padLength); - long serialized = System.currentTimeMillis(); + //long serialized = System.currentTimeMillis(); buf.crc.update(buf.unencrypted, 0, buf.unencryptedLength-4); long val = buf.crc.getValue(); @@ -700,11 +703,11 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { DataHelper.toLong(buf.unencrypted, buf.unencryptedLength-4, 4, val); buf.encrypted = new byte[buf.unencryptedLength]; - long crced = System.currentTimeMillis(); + //long crced = System.currentTimeMillis(); msg.prepared(buf); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Buffered prepare took " + (crced-begin) + ", alloc=" + (alloc-begin) - + " serialize=" + (serialized-alloc) + " crc=" + (crced-serialized)); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Buffered prepare took " + (crced-begin) + ", alloc=" + (alloc-begin) + // + " serialize=" + (serialized-alloc) + " crc=" + (crced-serialized)); } private static final int MIN_PREP_BUFS = 5; @@ -828,14 +831,16 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { * contents have been fully allocated */ public void queuedRecv(ByteBuffer buf, FIFOBandwidthLimiter.Request req) { - addRequest(req); req.attach(buf); req.setCompleteListener(this); + addRequest(req); } + + /** ditto for writes */ public void queuedWrite(ByteBuffer buf, FIFOBandwidthLimiter.Request req) { - addRequest(req); req.attach(buf); req.setCompleteListener(this); + addRequest(req); } /** @@ -1083,15 +1088,6 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener { // enqueueInfoMessage(); // this often? } - @Override - public int hashCode() { return System.identityHashCode(this); } - @Override - public boolean equals(Object obj) { - if(obj == null) return false; - if(obj.getClass() != NTCPConnection.class) return false; - return obj == this; - } - private static final int MAX_HANDLERS = 4; private final static LinkedBlockingQueue _i2npHandlers = new LinkedBlockingQueue(MAX_HANDLERS); diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java index 374c7a5ba..24b86fd5b 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java @@ -23,7 +23,7 @@ import net.i2p.util.Log; * * @author zzz */ -public class NTCPSendFinisher { +class NTCPSendFinisher { private static final int MIN_THREADS = 1; private static final int MAX_THREADS = 4; private final I2PAppContext _context; @@ -31,7 +31,11 @@ public class NTCPSendFinisher { private final Log _log; private static int _count; private ThreadPoolExecutor _executor; - private static int _threads; + private static final int THREADS; + static { + long maxMemory = Runtime.getRuntime().maxMemory(); + THREADS = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024)))); + } public NTCPSendFinisher(I2PAppContext context, NTCPTransport transport) { _context = context; @@ -42,9 +46,7 @@ public class NTCPSendFinisher { public void start() { _count = 0; - long maxMemory = Runtime.getRuntime().maxMemory(); - _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024)))); - _executor = new CustomThreadPoolExecutor(_threads); + _executor = new CustomThreadPoolExecutor(THREADS); } public void stop() { @@ -73,7 +75,7 @@ public class NTCPSendFinisher { private static class CustomThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) { Thread rv = Executors.defaultThreadFactory().newThread(r); - rv.setName("NTCPSendFinisher " + (++_count) + '/' + _threads); + rv.setName("NTCPSendFinisher " + (++_count) + '/' + THREADS); rv.setDaemon(true); return rv; } diff --git a/router/java/src/net/i2p/router/transport/udp/ACKSender.java b/router/java/src/net/i2p/router/transport/udp/ACKSender.java index d6035766d..33fd401df 100644 --- a/router/java/src/net/i2p/router/transport/udp/ACKSender.java +++ b/router/java/src/net/i2p/router/transport/udp/ACKSender.java @@ -2,6 +2,7 @@ package net.i2p.router.transport.udp; import java.util.HashSet; import java.util.List; +import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -120,7 +121,7 @@ class ACKSender implements Runnable { try { // bulk operations may throw an exception _peersToACK.addAll(notYet); - } catch (Exception e) {} + } catch (NoSuchElementException nsee) {} notYet.clear(); break; } else { diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java index d19f929c2..24e0efe87 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -577,8 +577,7 @@ class EstablishmentManager { (isInbound ? " inbound con from " + peer : "outbound con to " + peer)); DatabaseStoreMessage m = new DatabaseStoreMessage(_context); - m.setKey(_context.routerHash()); - m.setRouterInfo(_context.router().getRouterInfo()); + m.setEntry(_context.router().getRouterInfo()); m.setMessageExpiration(_context.clock().now() + 10*1000); _transport.send(m, peer); } @@ -642,7 +641,7 @@ class EstablishmentManager { private void handlePendingIntro(OutboundEstablishState state) { long nonce = _context.random().nextLong(MAX_NONCE); while (true) { - OutboundEstablishState old = _liveIntroductions.putIfAbsent(new Long(nonce), state); + OutboundEstablishState old = _liveIntroductions.putIfAbsent(Long.valueOf(nonce), state); if (old != null) { nonce = _context.random().nextLong(MAX_NONCE); } else { @@ -670,7 +669,7 @@ class EstablishmentManager { } public void timeReached() { // remove only if value equal to state - boolean removed = _liveIntroductions.remove(new Long(_nonce), _state); + boolean removed = _liveIntroductions.remove(Long.valueOf(_nonce), _state); if (removed) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Send intro for " + _state.getRemoteHostId().toString() + " timed out"); @@ -682,7 +681,7 @@ class EstablishmentManager { void receiveRelayResponse(RemoteHostId bob, UDPPacketReader reader) { long nonce = reader.getRelayResponseReader().readNonce(); - OutboundEstablishState state = _liveIntroductions.remove(new Long(nonce)); + OutboundEstablishState state = _liveIntroductions.remove(Long.valueOf(nonce)); if (state == null) return; // already established diff --git a/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java index bc0ddc5f5..f685c9e78 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java @@ -100,7 +100,7 @@ class InboundMessageFragments /*implements UDPTransport.PartialACKSource */{ for (int i = 0; i < fragments; i++) { long mid = data.readMessageId(i); - Long messageId = new Long(mid); + Long messageId = Long.valueOf(mid); if (_recentlyCompletedMessages.isKnown(mid)) { _context.statManager().addRateData("udp.ignoreRecentDuplicate", 1, 0); diff --git a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java index 326c43f15..b39f44de9 100644 --- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java +++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java @@ -53,7 +53,7 @@ class IntroductionManager { _log.debug("Adding peer " + peer.getRemoteHostId() + ", weRelayToThemAs " + peer.getWeRelayToThemAs() + ", theyRelayToUsAs " + peer.getTheyRelayToUsAs()); if (peer.getWeRelayToThemAs() > 0) - _outbound.put(new Long(peer.getWeRelayToThemAs()), peer); + _outbound.put(Long.valueOf(peer.getWeRelayToThemAs()), peer); if (peer.getTheyRelayToUsAs() > 0) { _inbound.add(peer); } @@ -65,14 +65,14 @@ class IntroductionManager { _log.debug("removing peer " + peer.getRemoteHostId() + ", weRelayToThemAs " + peer.getWeRelayToThemAs() + ", theyRelayToUsAs " + peer.getTheyRelayToUsAs()); if (peer.getWeRelayToThemAs() > 0) - _outbound.remove(new Long(peer.getWeRelayToThemAs())); + _outbound.remove(Long.valueOf(peer.getWeRelayToThemAs())); if (peer.getTheyRelayToUsAs() > 0) { _inbound.remove(peer); } } public PeerState get(long id) { - return _outbound.get(new Long(id)); + return _outbound.get(Long.valueOf(id)); } /** diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index 98daaecf9..cc43c4b2e 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -661,7 +661,6 @@ class PacketBuilder { */ public UDPPacket buildSessionDestroyPacket(PeerState peer) { UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_SESSION_DESTROY << 4)); - byte data[] = packet.getPacket().getData(); int off = HEADER_SIZE; StringBuilder msg = null; diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java index 2c0138228..230c1b792 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java @@ -20,14 +20,14 @@ import net.i2p.util.Log; * */ class PacketHandler { - private RouterContext _context; - private Log _log; - private UDPTransport _transport; - private UDPEndpoint _endpoint; - private EstablishmentManager _establisher; - private InboundMessageFragments _inbound; - private PeerTestManager _testManager; - private IntroductionManager _introManager; + private final RouterContext _context; + private final Log _log; + private final UDPTransport _transport; + private final UDPEndpoint _endpoint; + private final EstablishmentManager _establisher; + private final InboundMessageFragments _inbound; + private final PeerTestManager _testManager; + private final IntroductionManager _introManager; private boolean _keepReading; private final Handler[] _handlers; @@ -337,6 +337,9 @@ class PacketHandler { _state = 30; } + /** + * @param state non-null + */ private void receivePacket(UDPPacketReader reader, UDPPacket packet, InboundEstablishState state) { receivePacket(reader, packet, state, true); } @@ -345,11 +348,12 @@ class PacketHandler { * Inbound establishing conn * Decrypt and validate the packet then call handlePacket() * + * @param state non-null * @param allowFallback if it isn't valid for this establishment state, try as a non-establishment packet */ private void receivePacket(UDPPacketReader reader, UDPPacket packet, InboundEstablishState state, boolean allowFallback) { _state = 31; - if ( (state != null) && (_log.shouldLog(Log.DEBUG)) ) { + if (_log.shouldLog(Log.DEBUG)) { StringBuilder buf = new StringBuilder(128); buf.append("Attempting to receive a packet on a known inbound state: "); buf.append(state); @@ -388,10 +392,12 @@ class PacketHandler { /** * Outbound establishing conn * Decrypt and validate the packet then call handlePacket() + * + * @param state non-null */ private void receivePacket(UDPPacketReader reader, UDPPacket packet, OutboundEstablishState state) { _state = 35; - if ( (state != null) && (_log.shouldLog(Log.DEBUG)) ) { + if (_log.shouldLog(Log.DEBUG)) { StringBuilder buf = new StringBuilder(128); buf.append("Attempting to receive a packet on a known outbound state: "); buf.append(state); diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java index a3211a5a6..46b1e4666 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java @@ -153,7 +153,7 @@ class PeerTestManager { _log.debug("Running test with bob = " + bobIP + ":" + bobPort + " " + test.getNonce()); while (_recentTests.size() > 16) _recentTests.poll(); - _recentTests.offer(new Long(test.getNonce())); + _recentTests.offer(Long.valueOf(test.getNonce())); sendTestToBob(); @@ -432,7 +432,7 @@ class PeerTestManager { testInfo.readIP(testIP, 0); } - PeerTestState state = _activeTests.get(new Long(nonce)); + PeerTestState state = _activeTests.get(Long.valueOf(nonce)); if (state == null) { if ( (testIP == null) || (testPort <= 0) ) { @@ -441,7 +441,7 @@ class PeerTestManager { _log.debug("test IP/port are blank coming from " + from + ", assuming we are Bob and they are alice"); receiveFromAliceAsBob(from, testInfo, nonce, null); } else { - if (_recentTests.contains(new Long(nonce))) { + if (_recentTests.contains(Long.valueOf(nonce))) { // ignore the packet, as its a holdover from a recently completed locally // initiated test } else { @@ -536,7 +536,7 @@ class PeerTestManager { _log.debug("Receive from bob (" + from + ") as charlie, sending back to bob and sending to alice @ " + aliceIP + ":" + alicePort); if (isNew) { - _activeTests.put(new Long(nonce), state); + _activeTests.put(Long.valueOf(nonce), state); SimpleScheduler.getInstance().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME); } @@ -615,7 +615,7 @@ class PeerTestManager { } if (isNew) { - _activeTests.put(new Long(nonce), state); + _activeTests.put(Long.valueOf(nonce), state); SimpleScheduler.getInstance().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME); } @@ -691,7 +691,7 @@ class PeerTestManager { _nonce = nonce; } public void timeReached() { - _activeTests.remove(new Long(_nonce)); + _activeTests.remove(Long.valueOf(_nonce)); } } } diff --git a/router/java/src/net/i2p/router/transport/udp/RemoteHostId.java b/router/java/src/net/i2p/router/transport/udp/RemoteHostId.java index 510d712a0..837a50268 100644 --- a/router/java/src/net/i2p/router/transport/udp/RemoteHostId.java +++ b/router/java/src/net/i2p/router/transport/udp/RemoteHostId.java @@ -28,21 +28,15 @@ final class RemoteHostId { @Override public int hashCode() { - int rv = 0; - for (int i = 0; _ip != null && i < _ip.length; i++) - rv += _ip[i] << i; - for (int i = 0; _peerHash != null && i < _peerHash.length; i++) - rv += _peerHash[i] << i; - rv += _port; - return rv; + return DataHelper.hashCode(_ip) ^ DataHelper.hashCode(_peerHash) ^ _port; } @Override public boolean equals(Object obj) { if (obj == null) - throw new NullPointerException("obj is null"); + return false; if (!(obj instanceof RemoteHostId)) - throw new ClassCastException("obj is a " + obj.getClass().getName()); + return false; RemoteHostId id = (RemoteHostId)obj; return (_port == id.getPort()) && DataHelper.eq(_ip, id.getIP()) && DataHelper.eq(_peerHash, id.getPeerHash()); } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java index 0a1937db1..ded71f8a2 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java @@ -20,16 +20,16 @@ import net.i2p.util.SimpleTimer; * */ class UDPReceiver { - private RouterContext _context; - private Log _log; + private final RouterContext _context; + private final Log _log; private DatagramSocket _socket; private String _name; private final BlockingQueue _inboundQueue; private boolean _keepRunning; - private Runner _runner; - private UDPTransport _transport; + private final Runner _runner; + private final UDPTransport _transport; private static int __id; - private int _id; + private final int _id; private static final int TYPE_POISON = -99999; public UDPReceiver(RouterContext ctx, UDPTransport transport, DatagramSocket socket, String name) { @@ -179,8 +179,7 @@ class UDPReceiver { msg.append(queueSize); msg.append(" queued for "); msg.append(headPeriod); - if (_transport != null) - msg.append(" packet handlers: ").append(_transport.getPacketHandlerStatus()); + msg.append(" packet handlers: ").append(_transport.getPacketHandlerStatus()); _log.warn(msg.toString()); } return queueSize; diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index b55d845ad..9aac88523 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -18,6 +18,7 @@ import java.util.TreeSet; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; +import net.i2p.data.DatabaseEntry; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.RouterAddress; @@ -773,8 +774,11 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority public void messageReceived(I2NPMessage inMsg, RouterIdentity remoteIdent, Hash remoteIdentHash, long msToReceive, int bytesReceived) { if (inMsg.getType() == DatabaseStoreMessage.MESSAGE_TYPE) { DatabaseStoreMessage dsm = (DatabaseStoreMessage)inMsg; - if ( (dsm.getRouterInfo() != null) && - (dsm.getRouterInfo().getNetworkId() != Router.NETWORK_ID) ) { + DatabaseEntry entry = dsm.getEntry(); + if (entry == null) + return; + if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO && + ((RouterInfo) entry).getNetworkId() != Router.NETWORK_ID) { // this is pre-0.6.1.10, so it isn't going to happen any more /* @@ -792,7 +796,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority + " because they are in the wrong net"); } */ - Hash peerHash = dsm.getRouterInfo().getIdentity().calculateHash(); + Hash peerHash = entry.getHash(); PeerState peer = getPeerState(peerHash); if (peer != null) { RemoteHostId remote = peer.getRemoteHostId(); @@ -801,14 +805,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority SimpleScheduler.getInstance().addEvent(new RemoveDropList(remote), DROPLIST_PERIOD); } markUnreachable(peerHash); - _context.shitlist().shitlistRouter(peerHash, "Part of the wrong network, version = " + dsm.getRouterInfo().getOption("router.version")); + _context.shitlist().shitlistRouter(peerHash, "Part of the wrong network, version = " + ((RouterInfo) entry).getOption("router.version")); //_context.shitlist().shitlistRouter(peerHash, "Part of the wrong network", STYLE); dropPeer(peerHash, false, "wrong network"); if (_log.shouldLog(Log.WARN)) - _log.warn("Dropping the peer " + peerHash.toBase64() + " because they are in the wrong net: " + dsm.getRouterInfo()); + _log.warn("Dropping the peer " + peerHash.toBase64() + " because they are in the wrong net: " + entry); return; } else { - if (dsm.getRouterInfo() != null) { + if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) { if (_log.shouldLog(Log.INFO)) _log.info("Received an RI from the same net"); } else { @@ -1633,7 +1637,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final IdleInComparator _instance = new IdleInComparator(); public static final IdleInComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = r.getLastReceiveTime() - l.getLastReceiveTime(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1645,7 +1649,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final IdleOutComparator _instance = new IdleOutComparator(); public static final IdleOutComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = r.getLastSendTime() - l.getLastSendTime(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1657,7 +1661,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final RateInComparator _instance = new RateInComparator(); public static final RateInComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getReceiveBps() - r.getReceiveBps(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1669,7 +1673,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final RateOutComparator _instance = new RateOutComparator(); public static final RateOutComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getSendBps() - r.getSendBps(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1681,7 +1685,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final UptimeComparator _instance = new UptimeComparator(); public static final UptimeComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = r.getKeyEstablishedTime() - l.getKeyEstablishedTime(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1693,7 +1697,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final SkewComparator _instance = new SkewComparator(); public static final SkewComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = Math.abs(l.getClockSkew()) - Math.abs(r.getClockSkew()); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1705,7 +1709,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final CwndComparator _instance = new CwndComparator(); public static final CwndComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getSendWindowBytes() - r.getSendWindowBytes(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1717,7 +1721,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final SsthreshComparator _instance = new SsthreshComparator(); public static final SsthreshComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getSlowStartThreshold() - r.getSlowStartThreshold(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1729,7 +1733,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final RTTComparator _instance = new RTTComparator(); public static final RTTComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getRTT() - r.getRTT(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1741,7 +1745,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final DevComparator _instance = new DevComparator(); public static final DevComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getRTTDeviation() - r.getRTTDeviation(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1753,7 +1757,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final RTOComparator _instance = new RTOComparator(); public static final RTOComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getRTO() - r.getRTO(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1765,7 +1769,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final MTUComparator _instance = new MTUComparator(); public static final MTUComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getMTU() - r.getMTU(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1777,7 +1781,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final SendCountComparator _instance = new SendCountComparator(); public static final SendCountComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getPacketsTransmitted() - r.getPacketsTransmitted(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1789,7 +1793,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final RecvCountComparator _instance = new RecvCountComparator(); public static final RecvCountComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getPacketsReceived() - r.getPacketsReceived(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1801,7 +1805,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final ResendComparator _instance = new ResendComparator(); public static final ResendComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getPacketsRetransmitted() - r.getPacketsRetransmitted(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1813,7 +1817,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private static final DupComparator _instance = new DupComparator(); public static final DupComparator instance() { return _instance; } @Override - protected int compare(PeerState l, PeerState r) { + public int compare(PeerState l, PeerState r) { long rv = l.getPacketsReceivedDuplicate() - r.getPacketsReceivedDuplicate(); if (rv == 0) // fallback on alpha return super.compare(l, r); @@ -1822,17 +1826,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } - private static class PeerComparator implements Comparator { - public int compare(Object lhs, Object rhs) { - if ( (lhs == null) || (rhs == null) || !(lhs instanceof PeerState) || !(rhs instanceof PeerState)) - throw new IllegalArgumentException("rhs = " + rhs + " lhs = " + lhs); - return compare((PeerState)lhs, (PeerState)rhs); - } - protected int compare(PeerState l, PeerState r) { - // base64 retains binary ordering - return l.getRemotePeer().toBase64().compareTo(r.getRemotePeer().toBase64()); + private static class PeerComparator implements Comparator { + public int compare(PeerState l, PeerState r) { + return DataHelper.compareTo(l.getRemotePeer().getData(), r.getRemotePeer().getData()); } } + private static class InverseComparator implements Comparator { private Comparator _comp; public InverseComparator(Comparator comp) { _comp = comp; } diff --git a/router/java/src/net/i2p/router/tunnel/BuildMessageGenerator.java b/router/java/src/net/i2p/router/tunnel/BuildMessageGenerator.java index da169db75..179066989 100644 --- a/router/java/src/net/i2p/router/tunnel/BuildMessageGenerator.java +++ b/router/java/src/net/i2p/router/tunnel/BuildMessageGenerator.java @@ -21,9 +21,6 @@ import net.i2p.util.Log; * */ public class BuildMessageGenerator { - // cached, rather than creating lots of temporary Integer objects whenever we build a tunnel - public static final Integer ORDER[] = new Integer[TunnelBuildMessage.MAX_RECORD_COUNT]; - static { for (int i = 0; i < ORDER.length; i++) ORDER[i] = Integer.valueOf(i); } /** return null if it is unable to find a router's public key (etc) */ /**** diff --git a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java index 7948c5387..f4b6062f5 100644 --- a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java +++ b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java @@ -360,10 +360,10 @@ public class FragmentHandler { FragmentedMessage msg = null; if (fragmented) { synchronized (_fragmentedMessages) { - msg = _fragmentedMessages.get(new Long(messageId)); + msg = _fragmentedMessages.get(Long.valueOf(messageId)); if (msg == null) { msg = new FragmentedMessage(_context); - _fragmentedMessages.put(new Long(messageId), msg); + _fragmentedMessages.put(Long.valueOf(messageId), msg); } } } else { @@ -377,7 +377,7 @@ public class FragmentHandler { if (!ok) return -1; if (msg.isComplete()) { synchronized (_fragmentedMessages) { - _fragmentedMessages.remove(new Long(messageId)); + _fragmentedMessages.remove(Long.valueOf(messageId)); } if (msg.getExpireEvent() != null) SimpleTimer.getInstance().removeEvent(msg.getExpireEvent()); @@ -432,10 +432,10 @@ public class FragmentHandler { FragmentedMessage msg = null; synchronized (_fragmentedMessages) { - msg = _fragmentedMessages.get(new Long(messageId)); + msg = _fragmentedMessages.get(Long.valueOf(messageId)); if (msg == null) { msg = new FragmentedMessage(_context); - _fragmentedMessages.put(new Long(messageId), msg); + _fragmentedMessages.put(Long.valueOf(messageId), msg); } } @@ -446,7 +446,7 @@ public class FragmentHandler { if (msg.isComplete()) { synchronized (_fragmentedMessages) { - _fragmentedMessages.remove(new Long(messageId)); + _fragmentedMessages.remove(Long.valueOf(messageId)); } if (msg.getExpireEvent() != null) SimpleTimer.getInstance().removeEvent(msg.getExpireEvent()); @@ -529,7 +529,7 @@ public class FragmentHandler { public void timeReached() { boolean removed = false; synchronized (_fragmentedMessages) { - removed = (null != _fragmentedMessages.remove(new Long(_msg.getMessageId()))); + removed = (null != _fragmentedMessages.remove(Long.valueOf(_msg.getMessageId()))); } synchronized (_msg) { if (removed && !_msg.getReleased()) { diff --git a/router/java/src/net/i2p/router/tunnel/HopConfig.java b/router/java/src/net/i2p/router/tunnel/HopConfig.java index 532bdfe20..3ac96bf28 100644 --- a/router/java/src/net/i2p/router/tunnel/HopConfig.java +++ b/router/java/src/net/i2p/router/tunnel/HopConfig.java @@ -73,7 +73,7 @@ public class HopConfig { } public void setSendTunnelId(byte id[]) { _sendTunnelId = id; } - private TunnelId getTunnel(byte id[]) { + private static TunnelId getTunnel(byte id[]) { if (id == null) return null; else diff --git a/router/java/src/net/i2p/router/tunnel/HopProcessor.java b/router/java/src/net/i2p/router/tunnel/HopProcessor.java index 205339d7f..eac1f71da 100644 --- a/router/java/src/net/i2p/router/tunnel/HopProcessor.java +++ b/router/java/src/net/i2p/router/tunnel/HopProcessor.java @@ -77,7 +77,7 @@ public class HopProcessor { boolean okIV = _validator.receiveIV(orig, offset, orig, offset + IV_LENGTH); if (!okIV) { if (_log.shouldLog(Log.WARN)) - _log.warn("Invalid IV received on tunnel " + _config.getReceiveTunnelId()); + _log.warn("Invalid IV received on tunnel " + _config.getReceiveTunnel()); return false; } diff --git a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java index fcdb77ea9..82fdc47c6 100644 --- a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java +++ b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java @@ -1,8 +1,10 @@ package net.i2p.router.tunnel; +import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.Payload; +import net.i2p.data.RouterInfo; import net.i2p.data.TunnelId; import net.i2p.data.i2np.DataMessage; import net.i2p.data.i2np.DatabaseSearchReplyMessage; @@ -71,7 +73,7 @@ public class InboundMessageDistributor implements GarlicMessageReceiver.CloveRec msg = newMsg; } else if ( (_client != null) && (msg.getType() == DatabaseStoreMessage.MESSAGE_TYPE) && - (((DatabaseStoreMessage)msg).getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO)) { + (((DatabaseStoreMessage)msg).getEntry().getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO)) { // FVSJ may result in an unsolicited RI store if the peer went non-ff. // Maybe we can figure out a way to handle this safely, so we don't ask him again. // For now, just hope we eventually find out through other means. @@ -165,7 +167,7 @@ public class InboundMessageDistributor implements GarlicMessageReceiver.CloveRec // unnecessarily DatabaseStoreMessage dsm = (DatabaseStoreMessage)data; try { - if (dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) { + if (dsm.getEntry().getType() == DatabaseEntry.KEY_TYPE_LEASESET) { // If it was stored to us before, don't undo the // receivedAsPublished flag so we will continue to respond to requests // for the leaseset. That is, we don't want this to change the @@ -173,10 +175,11 @@ public class InboundMessageDistributor implements GarlicMessageReceiver.CloveRec // When the keyspace rotates at midnight, and this leaseset moves out // of our keyspace, maybe we shouldn't do this? // Should we do this whether ff or not? - LeaseSet old = _context.netDb().store(dsm.getKey(), dsm.getLeaseSet()); + LeaseSet ls = (LeaseSet) dsm.getEntry(); + LeaseSet old = _context.netDb().store(dsm.getKey(), ls); if (old != null && old.getReceivedAsPublished() /** && ((FloodfillNetworkDatabaseFacade)_context.netDb()).floodfillEnabled() **/ ) - dsm.getLeaseSet().setReceivedAsPublished(true); + ls.setReceivedAsPublished(true); if (_log.shouldLog(Log.INFO)) _log.info("Storing LS for: " + dsm.getKey() + " sent to: " + _client); } else { @@ -189,7 +192,7 @@ public class InboundMessageDistributor implements GarlicMessageReceiver.CloveRec _log.error("Dropped dangerous message down a tunnel for " + _client.toBase64() + ": " + dsm, new Exception("cause")); return; } - _context.netDb().store(dsm.getKey(), dsm.getRouterInfo()); + _context.netDb().store(dsm.getKey(), (RouterInfo) dsm.getEntry()); } } catch (IllegalArgumentException iae) { if (_log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java b/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java index c9b28b856..6c85895c6 100644 --- a/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java +++ b/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java @@ -52,92 +52,11 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor { * NOTE: Unused here, see BatchedPreprocessor override, super is not called. */ public boolean preprocessQueue(List pending, TunnelGateway.Sender sender, TunnelGateway.Receiver rec) { - if (true) throw new IllegalArgumentException("unused, right?"); - long begin = System.currentTimeMillis(); - StringBuilder buf = null; - if (_log.shouldLog(Log.DEBUG)) { - buf = new StringBuilder(256); - buf.append("Trivial preprocessing of ").append(pending.size()).append(" "); - } - while (!pending.isEmpty()) { - TunnelGateway.Pending msg = pending.remove(0); - long beforePreproc = System.currentTimeMillis(); - byte preprocessed[][] = preprocess(msg); - long afterPreproc = System.currentTimeMillis(); - if (buf != null) - buf.append("preprocessed into " + preprocessed.length + " fragments after " + (afterPreproc-beforePreproc) + ". "); - for (int i = 0; i < preprocessed.length; i++) { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Preprocessed: fragment " + i + "/" + (preprocessed.length-1) + " in " - + msg.getMessageId() + ": " - + " send through " + sender + " receive with " + rec); - //Base64.encode(preprocessed[i])); - long beforeSend = System.currentTimeMillis(); - long id = sender.sendPreprocessed(preprocessed[i], rec); - long afterSend = System.currentTimeMillis(); - if (buf != null) - buf.append("send of " + msg.getMessageId() + " took " + (afterSend-beforeSend) + ". "); - msg.addMessageId(id); - } - notePreprocessing(msg.getMessageId(), msg.getFragmentNumber(), preprocessed.length, msg.getMessageIds(), null); - if (preprocessed.length != msg.getFragmentNumber() + 1) { - throw new RuntimeException("wtf, preprocessed " + msg.getMessageId() + " into " - + msg.getFragmentNumber() + "/" + preprocessed.length + " fragments, size = " - + msg.getData().length); - } - if (buf != null) - buf.append("all fragments sent after " + (System.currentTimeMillis()-afterPreproc) + ". "); - } - if (buf != null) { - buf.append("queue preprocessed after " + (System.currentTimeMillis()-begin) + "."); - _log.debug(buf.toString()); - } - return false; + throw new IllegalArgumentException("unused, right?"); } protected void notePreprocessing(long messageId, int numFragments, int totalLength, List messageIds, String msg) {} - /* - * @deprecated unused except by above - */ - private byte[][] preprocess(TunnelGateway.Pending msg) { - List fragments = new ArrayList(1); - - while (msg.getOffset() < msg.getData().length) { - fragments.add(preprocessFragment(msg)); - //if (_log.shouldLog(Log.DEBUG)) - // _log.debug("\n\nafter preprocessing fragment\n\n"); - } - - byte rv[][] = new byte[fragments.size()][]; - for (int i = 0; i < fragments.size(); i++) - rv[i] = fragments.get(i); - return rv; - } - - /** - * Preprocess the next available fragment off the given one in phases: - * First, write it out as { instructions + payload + random IV }, calculate the - * SHA256 of that, then move the instructions + payload to the end - * of the target, setting IV as the beginning. Then add the necessary random pad - * bytes after the IV, followed by the first 4 bytes of that SHA256, lining up - * exactly to meet the beginning of the instructions. (i hope) - * - * @deprecated unused except by above - */ - private byte[] preprocessFragment(TunnelGateway.Pending msg) { - byte target[] = _dataCache.acquire().getData(); - - int offset = 0; - if (msg.getOffset() <= 0) - offset = writeFirstFragment(msg, target, offset); - else - offset = writeSubsequentFragment(msg, target, offset); - - preprocess(target, offset); - return target; - } - /** * Wrap the preprocessed fragments with the necessary padding / checksums * to act as a tunnel message. diff --git a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java index c8424d853..d736e338d 100644 --- a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java +++ b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java @@ -623,7 +623,7 @@ public class TunnelDispatcher implements Service { // drop in proportion to size w.r.t. a standard 1024-byte message // this is a little expensive but we want to adjust the curve between 0 and 1 // Most messages are 1024, only at the OBEP do we see other sizes - if (len != 1024d) + if ((int)len != 1024) pctDrop = (float) Math.pow(pctDrop, 1024d / len); float rand = _context.random().nextFloat(); boolean reject = rand <= pctDrop; diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java index 8b08b6ec8..19505c0c7 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java @@ -294,7 +294,9 @@ class BuildExecutor implements Runnable { if (!_repoll) { if (_log.shouldLog(Log.DEBUG)) _log.debug("No tunnel to build with (allowed=" + allowed + ", wanted=" + wanted.size() + ", pending=" + pendingRemaining + "), wait for a while"); - _currentlyBuilding.wait(1*1000+_context.random().nextInt(1*1000)); + try { + _currentlyBuilding.wait(1*1000+_context.random().nextInt(1*1000)); + } catch (InterruptedException ie) {} } } } else { @@ -369,7 +371,7 @@ class BuildExecutor implements Runnable { wanted.clear(); pools.clear(); - } catch (Exception e) { + } catch (RuntimeException e) { if (_log.shouldLog(Log.CRIT)) _log.log(Log.CRIT, "B0rked in the tunnel builder", e); } @@ -459,7 +461,7 @@ class BuildExecutor implements Runnable { for (int i = 0; i < 32; i++) _recentBuildIds.remove(0); } - _recentBuildIds.add(new Long(id)); + _recentBuildIds.add(Long.valueOf(id)); } } } @@ -483,7 +485,7 @@ class BuildExecutor implements Runnable { public boolean wasRecentlyBuilding(long replyId) { synchronized (_recentBuildIds) { - return _recentBuildIds.contains(new Long(replyId)); + return _recentBuildIds.contains(Long.valueOf(replyId)); } } diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java index 7a79f927c..0ccb53fbd 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java @@ -25,9 +25,9 @@ import net.i2p.util.VersionComparator; * */ class BuildRequestor { - private static final List ORDER = new ArrayList(BuildMessageGenerator.ORDER.length); + private static final List ORDER = new ArrayList(TunnelBuildMessage.MAX_RECORD_COUNT); static { - for (int i = 0; i < BuildMessageGenerator.ORDER.length; i++) + for (int i = 0; i < TunnelBuildMessage.MAX_RECORD_COUNT; i++) ORDER.add(Integer.valueOf(i)); } private static final int PRIORITY = 500; diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java index e6f3e599e..03fa5bd71 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java @@ -464,9 +464,9 @@ public class TunnelPool { * but we use latest expiration first, since we need to sort them by that anyway. * */ - class LeaseComparator implements Comparator { - public int compare(Object l, Object r) { - return ((Lease)r).getEndDate().compareTo(((Lease)l).getEndDate()); + private static class LeaseComparator implements Comparator { + public int compare(Lease l, Lease r) { + return r.getEndDate().compareTo(l.getEndDate()); } }