From e2420151458b9e179a4e5db27621a7fd5a588b1f Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 4 Nov 2020 12:04:24 +0000 Subject: [PATCH] Util: Hook in ByteArrayStream Set accurate lengths for zero-copy --- .../client/streaming/I2PSocketManagerFactory.java | 10 +++++----- .../client/streaming/impl/I2PSocketManagerFull.java | 7 +++---- .../java/src/net/i2p/crypto/SelfSignedGenerator.java | 5 +++-- core/java/src/net/i2p/data/EncryptedLeaseSet.java | 3 ++- core/java/src/net/i2p/data/KeysAndCert.java | 6 ++++-- core/java/src/net/i2p/data/LeaseSet.java | 8 ++++---- core/java/src/net/i2p/data/LeaseSet2.java | 12 ++++++------ .../net/i2p/data/i2cp/BandwidthLimitsMessage.java | 4 ++-- .../net/i2p/data/i2cp/CreateLeaseSet2Message.java | 4 ++-- .../src/net/i2p/data/i2cp/CreateLeaseSetMessage.java | 4 ++-- .../java/src/net/i2p/data/i2cp/DestReplyMessage.java | 4 ++-- .../src/net/i2p/data/i2cp/DestroySessionMessage.java | 4 ++-- .../src/net/i2p/data/i2cp/DisconnectMessage.java | 7 +++++-- core/java/src/net/i2p/data/i2cp/GetDateMessage.java | 4 ++-- .../src/net/i2p/data/i2cp/HostLookupMessage.java | 4 ++-- .../java/src/net/i2p/data/i2cp/HostReplyMessage.java | 4 ++-- .../src/net/i2p/data/i2cp/ReportAbuseMessage.java | 8 ++++++-- .../net/i2p/data/i2cp/RequestLeaseSetMessage.java | 7 ++++--- .../data/i2cp/RequestVariableLeaseSetMessage.java | 7 ++++--- core/java/src/net/i2p/data/i2cp/SessionConfig.java | 5 +++-- .../src/net/i2p/data/i2cp/SessionStatusMessage.java | 4 ++-- core/java/src/net/i2p/data/i2cp/SetDateMessage.java | 4 ++-- core/java/src/net/i2p/util/ByteArrayStream.java | 3 +++ .../net/i2p/router/message/GarlicMessageBuilder.java | 8 ++++---- .../router/transport/ntcp/InboundEstablishState.java | 3 ++- 25 files changed, 78 insertions(+), 61 deletions(-) diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java index 26ee57c437..e071fe3972 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java @@ -1,7 +1,6 @@ package net.i2p.client.streaming; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; @@ -15,6 +14,7 @@ import net.i2p.client.I2PClientFactory; import net.i2p.client.I2PSession; import net.i2p.client.I2PSessionException; import net.i2p.crypto.SigType; +import net.i2p.util.ByteArrayStream; import net.i2p.util.Log; /** @@ -171,10 +171,10 @@ public class I2PSocketManagerFactory { public static I2PSocketManager createManager(String i2cpHost, int i2cpPort, Properties opts, IncomingConnectionFilter filter) { I2PClient client = I2PClientFactory.createClient(); - ByteArrayOutputStream keyStream = new ByteArrayOutputStream(1024); + ByteArrayStream keyStream = new ByteArrayStream(1024); try { client.createDestination(keyStream, getSigType(opts)); - ByteArrayInputStream in = new ByteArrayInputStream(keyStream.toByteArray()); + ByteArrayInputStream in = keyStream.asInputStream(); return createManager(in, i2cpHost, i2cpPort, opts, filter); } catch (IOException ioe) { getLog().error("Error creating the destination for socket manager", ioe); @@ -359,7 +359,7 @@ public class I2PSocketManagerFactory { throws I2PSessionException { if (myPrivateKeyStream == null) { I2PClient client = I2PClientFactory.createClient(); - ByteArrayOutputStream keyStream = new ByteArrayOutputStream(1024); + ByteArrayStream keyStream = new ByteArrayStream(1024); try { client.createDestination(keyStream, getSigType(opts)); } catch (I2PException e) { @@ -367,7 +367,7 @@ public class I2PSocketManagerFactory { } catch (IOException e) { throw new I2PSessionException("Error creating keys", e); } - myPrivateKeyStream = new ByteArrayInputStream(keyStream.toByteArray()); + myPrivateKeyStream = keyStream.asInputStream(); } return createManager(myPrivateKeyStream, i2cpHost, i2cpPort, opts, false, filter); } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java index 8ee0652fa3..d3df313949 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java @@ -1,7 +1,5 @@ package net.i2p.client.streaming.impl; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ConnectException; @@ -38,6 +36,7 @@ import net.i2p.data.Hash; import net.i2p.data.PrivateKey; import net.i2p.data.PublicKey; import net.i2p.data.SimpleDataStructure; +import net.i2p.util.ByteArrayStream; import net.i2p.util.ConvertToHash; import net.i2p.util.ConcurrentHashSet; import net.i2p.util.Log; @@ -275,7 +274,7 @@ public class I2PSocketManagerFull implements I2PSocketManager { // We don't actually need the same pubkey in the dest, just in the LS. // The dest one is unused. But this is how we find the LS keys // to reuse in RequestLeaseSetMessageHandler. - ByteArrayOutputStream keyStream = new ByteArrayOutputStream(1024); + ByteArrayStream keyStream = new ByteArrayStream(1024); try { SigType type = getSigType(opts); if (type != SigType.DSA_SHA1) { @@ -299,7 +298,7 @@ public class I2PSocketManagerFull implements I2PSocketManager { } catch (RuntimeException e) { throw new I2PSessionException("Error creating keys", e); } - privateKeyStream = new ByteArrayInputStream(keyStream.toByteArray()); + privateKeyStream = keyStream.asInputStream(); } I2PSession rv = _session.addSubsession(privateKeyStream, opts); boolean added = _subsessions.add(rv); diff --git a/core/java/src/net/i2p/crypto/SelfSignedGenerator.java b/core/java/src/net/i2p/crypto/SelfSignedGenerator.java index bd1a50713e..f80f5cb96b 100644 --- a/core/java/src/net/i2p/crypto/SelfSignedGenerator.java +++ b/core/java/src/net/i2p/crypto/SelfSignedGenerator.java @@ -40,6 +40,7 @@ import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; import net.i2p.data.SimpleDataStructure; import net.i2p.util.Addresses; +import net.i2p.util.ByteArrayStream; import net.i2p.util.HexDump; import net.i2p.util.RandomSource; import net.i2p.util.SecureFileOutputStream; @@ -904,11 +905,11 @@ public final class SelfSignedGenerator { * @throws IllegalArgumentException */ private static byte[] getEncodedOIDSeq(String oid) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(16); + byte[] b = getEncodedOID(oid); + ByteArrayStream baos = new ByteArrayStream(4 + b.length); baos.write(0x30); // len to be filled in later baos.write(0); - byte[] b = getEncodedOID(oid); baos.write(b, 0, b.length); // NULL baos.write(0x05); diff --git a/core/java/src/net/i2p/data/EncryptedLeaseSet.java b/core/java/src/net/i2p/data/EncryptedLeaseSet.java index d47356d99d..fe989607d0 100644 --- a/core/java/src/net/i2p/data/EncryptedLeaseSet.java +++ b/core/java/src/net/i2p/data/EncryptedLeaseSet.java @@ -19,6 +19,7 @@ import net.i2p.crypto.KeyPair; import net.i2p.crypto.SHA256Generator; import net.i2p.crypto.SigType; import net.i2p.crypto.x25519.X25519DH; +import net.i2p.util.ByteArrayStream; import net.i2p.util.Clock; import net.i2p.util.Log; @@ -853,7 +854,7 @@ public class EncryptedLeaseSet extends LeaseSet2 { _flags = saveFlags; SigningPrivateKey bkey = Blinding.blind(key, _alpha); int len = size(); - ByteArrayOutputStream out = new ByteArrayOutputStream(1 + len); + ByteArrayStream out = new ByteArrayStream(1 + len); try { // unlike LS1, sig covers type out.write(getType()); diff --git a/core/java/src/net/i2p/data/KeysAndCert.java b/core/java/src/net/i2p/data/KeysAndCert.java index d68880fde6..e4eba9dc63 100644 --- a/core/java/src/net/i2p/data/KeysAndCert.java +++ b/core/java/src/net/i2p/data/KeysAndCert.java @@ -9,7 +9,6 @@ package net.i2p.data; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -18,6 +17,7 @@ import java.util.Arrays; import net.i2p.crypto.EncType; import net.i2p.crypto.SHA256Generator; import net.i2p.crypto.SigType; +import net.i2p.util.ByteArrayStream; /** * KeysAndCert has a public key, a signing key, and a certificate. @@ -239,7 +239,9 @@ public class KeysAndCert extends DataStructureImpl { return __calculatedHash; byte identBytes[]; try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(400); + if (_certificate == null) + throw new IllegalStateException("KAC hash error"); + ByteArrayStream baos = new ByteArrayStream(384 + _certificate.size()); writeBytes(baos); identBytes = baos.toByteArray(); } catch (IOException ioe) { diff --git a/core/java/src/net/i2p/data/LeaseSet.java b/core/java/src/net/i2p/data/LeaseSet.java index 1d67c3f195..2a612a8d6d 100644 --- a/core/java/src/net/i2p/data/LeaseSet.java +++ b/core/java/src/net/i2p/data/LeaseSet.java @@ -10,7 +10,6 @@ package net.i2p.data; */ import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -22,6 +21,7 @@ import net.i2p.I2PAppContext; import net.i2p.crypto.DSAEngine; import net.i2p.crypto.EncType; import net.i2p.crypto.SigType; +import net.i2p.util.ByteArrayStream; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.RandomSource; @@ -335,7 +335,7 @@ public class LeaseSet extends DatabaseEntry { if ((_destination == null) || (_encryptionKey == null) || (_signingKey == null)) return null; int len = size(); - ByteArrayOutputStream out = new ByteArrayOutputStream(len); + ByteArrayStream out = new ByteArrayStream(len); try { _destination.writeBytes(out); _encryptionKey.writeBytes(out); @@ -497,7 +497,7 @@ public class LeaseSet extends DatabaseEntry { if (size < 1 || size > MAX_LEASES-1) throw new IllegalArgumentException("Bad number of leases for encryption"); int datalen = ((DATA_LEN * size / 16) + 1) * 16; - ByteArrayOutputStream baos = new ByteArrayOutputStream(datalen); + ByteArrayStream baos = new ByteArrayStream(datalen); for (int i = 0; i < size; i++) { _leases.get(i).getGateway().writeBytes(baos); _leases.get(i).getTunnelId().writeBytes(baos); @@ -545,7 +545,7 @@ public class LeaseSet extends DatabaseEntry { throw new DataFormatException("Bad number of leases decrypting " + _destination.toBase32() + " - is this destination encrypted?"); int datalen = DATA_LEN * size; - ByteArrayOutputStream baos = new ByteArrayOutputStream(datalen); + ByteArrayStream baos = new ByteArrayStream(datalen); for (int i = 0; i < size; i++) { _leases.get(i).getGateway().writeBytes(baos); _leases.get(i).getTunnelId().writeBytes(baos); diff --git a/core/java/src/net/i2p/data/LeaseSet2.java b/core/java/src/net/i2p/data/LeaseSet2.java index b1fc39a5cf..df523efad7 100644 --- a/core/java/src/net/i2p/data/LeaseSet2.java +++ b/core/java/src/net/i2p/data/LeaseSet2.java @@ -1,6 +1,5 @@ package net.i2p.data; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -16,6 +15,7 @@ import net.i2p.crypto.DSAEngine; import net.i2p.crypto.EncType; import net.i2p.crypto.SigAlgo; import net.i2p.crypto.SigType; +import net.i2p.util.ByteArrayStream; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.OrderedProperties; @@ -289,7 +289,7 @@ public class LeaseSet2 extends LeaseSet { * @return null on error */ public static Signature offlineSign(long expires, SigningPublicKey transientSPK, SigningPrivateKey priv) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(128); + ByteArrayStream baos = new ByteArrayStream(4 + 2 + transientSPK.length()); try { DataHelper.writeLong(baos, 4, expires / 1000); DataHelper.writeLong(baos, 2, transientSPK.getType().getCode()); @@ -314,7 +314,7 @@ public class LeaseSet2 extends LeaseSet { I2PAppContext ctx = I2PAppContext.getGlobalContext(); if (_transientExpires < ctx.clock().now()) return false; - ByteArrayOutputStream baos = new ByteArrayOutputStream(6 + _transientSigningPublicKey.length()); + ByteArrayStream baos = new ByteArrayStream(4 + 2 + _transientSigningPublicKey.length()); try { DataHelper.writeLong(baos, 4, _transientExpires / 1000); DataHelper.writeLong(baos, 2, _transientSigningPublicKey.getType().getCode()); @@ -387,7 +387,7 @@ public class LeaseSet2 extends LeaseSet { if (_destination == null) return null; int len = size(); - ByteArrayOutputStream out = new ByteArrayOutputStream(len); + ByteArrayStream out = new ByteArrayStream(len); try { writeBytesWithoutSig(out); } catch (IOException ioe) { @@ -605,7 +605,7 @@ public class LeaseSet2 extends LeaseSet { if (key == null) throw new DataFormatException("No signing key"); int len = size(); - ByteArrayOutputStream out = new ByteArrayOutputStream(1 + len); + ByteArrayStream out = new ByteArrayStream(1 + len); try { // unlike LS1, sig covers type out.write(getType()); @@ -647,7 +647,7 @@ public class LeaseSet2 extends LeaseSet { spk = getSigningPublicKey(); } int len = size(); - ByteArrayOutputStream out = new ByteArrayOutputStream(1 + len); + ByteArrayStream out = new ByteArrayStream(1 + len); try { // unlike LS1, sig covers type out.write(getType()); diff --git a/core/java/src/net/i2p/data/i2cp/BandwidthLimitsMessage.java b/core/java/src/net/i2p/data/i2cp/BandwidthLimitsMessage.java index cd0d0f6d3a..0d09dabd6f 100644 --- a/core/java/src/net/i2p/data/i2cp/BandwidthLimitsMessage.java +++ b/core/java/src/net/i2p/data/i2cp/BandwidthLimitsMessage.java @@ -5,12 +5,12 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; +import net.i2p.util.ByteArrayStream; /** * Tell the other side the limits @@ -63,7 +63,7 @@ public class BandwidthLimitsMessage extends I2CPMessageImpl { @Override protected byte[] doWriteMessage() throws I2CPMessageException, IOException { - ByteArrayOutputStream os = new ByteArrayOutputStream(64); + ByteArrayStream os = new ByteArrayStream(4 * LIMITS); try { for (int i = 0; i < LIMITS; i++) { DataHelper.writeLong(os, 4, data[i]); diff --git a/core/java/src/net/i2p/data/i2cp/CreateLeaseSet2Message.java b/core/java/src/net/i2p/data/i2cp/CreateLeaseSet2Message.java index 1cc64e67e1..e6918974a8 100644 --- a/core/java/src/net/i2p/data/i2cp/CreateLeaseSet2Message.java +++ b/core/java/src/net/i2p/data/i2cp/CreateLeaseSet2Message.java @@ -1,6 +1,5 @@ package net.i2p.data.i2cp; -import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -19,6 +18,7 @@ import net.i2p.data.LeaseSet2; import net.i2p.data.MetaLeaseSet; import net.i2p.data.PrivateKey; import net.i2p.data.PublicKey; +import net.i2p.util.ByteArrayStream; /** * Like CreateLeaseSetMessage, but supports both old @@ -174,7 +174,7 @@ public class CreateLeaseSet2Message extends CreateLeaseSetMessage { size += pk.length(); } } - ByteArrayOutputStream os = new ByteArrayOutputStream(size); + ByteArrayStream os = new ByteArrayStream(size); try { _sessionId.writeBytes(os); os.write(_leaseSet.getType()); diff --git a/core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java b/core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java index d7e8048cf3..bdd950456b 100644 --- a/core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java +++ b/core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java @@ -9,7 +9,6 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -17,6 +16,7 @@ import net.i2p.data.DataFormatException; import net.i2p.data.LeaseSet; import net.i2p.data.PrivateKey; import net.i2p.data.SigningPrivateKey; +import net.i2p.util.ByteArrayStream; /** * Defines the message a client sends to a router when authorizing @@ -105,7 +105,7 @@ public class CreateLeaseSetMessage extends I2CPMessageImpl { + _signingPrivateKey.length() + PrivateKey.KEYSIZE_BYTES + _leaseSet.size(); - ByteArrayOutputStream os = new ByteArrayOutputStream(size); + ByteArrayStream os = new ByteArrayStream(size); try { _sessionId.writeBytes(os); _signingPrivateKey.writeBytes(os); diff --git a/core/java/src/net/i2p/data/i2cp/DestReplyMessage.java b/core/java/src/net/i2p/data/i2cp/DestReplyMessage.java index d13cf658c9..639cddea48 100644 --- a/core/java/src/net/i2p/data/i2cp/DestReplyMessage.java +++ b/core/java/src/net/i2p/data/i2cp/DestReplyMessage.java @@ -6,13 +6,13 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.Destination; import net.i2p.data.Hash; +import net.i2p.util.ByteArrayStream; /** * Response to DestLookupMessage. @@ -76,7 +76,7 @@ public class DestReplyMessage extends I2CPMessageImpl { return new byte[0]; // null response allowed return _hash.getData(); } - ByteArrayOutputStream os = new ByteArrayOutputStream(_dest.size()); + ByteArrayStream os = new ByteArrayStream(_dest.size()); try { _dest.writeBytes(os); } catch (DataFormatException dfe) { diff --git a/core/java/src/net/i2p/data/i2cp/DestroySessionMessage.java b/core/java/src/net/i2p/data/i2cp/DestroySessionMessage.java index 67090011f6..3a17f77a3c 100644 --- a/core/java/src/net/i2p/data/i2cp/DestroySessionMessage.java +++ b/core/java/src/net/i2p/data/i2cp/DestroySessionMessage.java @@ -9,11 +9,11 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import net.i2p.data.DataFormatException; +import net.i2p.util.ByteArrayStream; /** * Defines the message a client sends to a router when destroying @@ -61,7 +61,7 @@ public class DestroySessionMessage extends I2CPMessageImpl { protected byte[] doWriteMessage() throws I2CPMessageException, IOException { if (_sessionId == null) throw new I2CPMessageException("Unable to write out the message as there is not enough data"); - ByteArrayOutputStream os = new ByteArrayOutputStream(64); + ByteArrayStream os = new ByteArrayStream(2); try { _sessionId.writeBytes(os); } catch (DataFormatException dfe) { diff --git a/core/java/src/net/i2p/data/i2cp/DisconnectMessage.java b/core/java/src/net/i2p/data/i2cp/DisconnectMessage.java index 2139cf21da..068954bd97 100644 --- a/core/java/src/net/i2p/data/i2cp/DisconnectMessage.java +++ b/core/java/src/net/i2p/data/i2cp/DisconnectMessage.java @@ -9,12 +9,12 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; +import net.i2p.util.ByteArrayStream; /** * Defines the message a client sends to a router when destroying @@ -48,7 +48,10 @@ public class DisconnectMessage extends I2CPMessageImpl { @Override protected byte[] doWriteMessage() throws I2CPMessageException, IOException { - ByteArrayOutputStream os = new ByteArrayOutputStream(64); + int len = 1; + if (_reason != null) + len += _reason.length(); + ByteArrayStream os = new ByteArrayStream(len); try { DataHelper.writeString(os, _reason); } catch (DataFormatException dfe) { diff --git a/core/java/src/net/i2p/data/i2cp/GetDateMessage.java b/core/java/src/net/i2p/data/i2cp/GetDateMessage.java index a65d626b65..9481d8e0b7 100644 --- a/core/java/src/net/i2p/data/i2cp/GetDateMessage.java +++ b/core/java/src/net/i2p/data/i2cp/GetDateMessage.java @@ -9,7 +9,6 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Map; @@ -17,6 +16,7 @@ import java.util.Properties; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; +import net.i2p.util.ByteArrayStream; import net.i2p.util.OrderedProperties; /** @@ -99,7 +99,7 @@ public class GetDateMessage extends I2CPMessageImpl { protected byte[] doWriteMessage() throws I2CPMessageException, IOException { if (_version == null) return new byte[0]; - ByteArrayOutputStream os = new ByteArrayOutputStream(_options != null ? 128 : 16); + ByteArrayStream os = new ByteArrayStream(_options != null ? 128 : (1 + 6)); try { DataHelper.writeString(os, _version); if (_options != null && !_options.isEmpty()) diff --git a/core/java/src/net/i2p/data/i2cp/HostLookupMessage.java b/core/java/src/net/i2p/data/i2cp/HostLookupMessage.java index 716f7e6e20..61f60df3e3 100644 --- a/core/java/src/net/i2p/data/i2cp/HostLookupMessage.java +++ b/core/java/src/net/i2p/data/i2cp/HostLookupMessage.java @@ -5,7 +5,6 @@ package net.i2p.data.i2cp; * with no warranty of any kind, either expressed or implied. */ -import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -13,6 +12,7 @@ import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Hash; +import net.i2p.util.ByteArrayStream; /** * Request the router look up the dest for a hash @@ -158,7 +158,7 @@ public class HostLookupMessage extends I2CPMessageImpl { } else { throw new I2CPMessageException("bad type"); } - ByteArrayOutputStream os = new ByteArrayOutputStream(len); + ByteArrayStream os = new ByteArrayStream(len); try { _sessionId.writeBytes(os); DataHelper.writeLong(os, 4, _reqID); diff --git a/core/java/src/net/i2p/data/i2cp/HostReplyMessage.java b/core/java/src/net/i2p/data/i2cp/HostReplyMessage.java index 415c4c6efa..59b799a4f4 100644 --- a/core/java/src/net/i2p/data/i2cp/HostReplyMessage.java +++ b/core/java/src/net/i2p/data/i2cp/HostReplyMessage.java @@ -6,7 +6,6 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -14,6 +13,7 @@ import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; +import net.i2p.util.ByteArrayStream; /** * Response to HostLookupMessage. Replaces DestReplyMessage. @@ -135,7 +135,7 @@ public class HostReplyMessage extends I2CPMessageImpl { throw new I2CPMessageException("Unable to write out the message as there is not enough data"); len += _dest.size(); } - ByteArrayOutputStream os = new ByteArrayOutputStream(len); + ByteArrayStream os = new ByteArrayStream(len); try { _sessionId.writeBytes(os); DataHelper.writeLong(os, 4, _reqID); diff --git a/core/java/src/net/i2p/data/i2cp/ReportAbuseMessage.java b/core/java/src/net/i2p/data/i2cp/ReportAbuseMessage.java index 4118ac322b..c4eb1f5c64 100644 --- a/core/java/src/net/i2p/data/i2cp/ReportAbuseMessage.java +++ b/core/java/src/net/i2p/data/i2cp/ReportAbuseMessage.java @@ -9,11 +9,11 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import net.i2p.data.DataFormatException; +import net.i2p.util.ByteArrayStream; /** * Defines the message a client sends to a router when asking the @@ -93,7 +93,11 @@ public class ReportAbuseMessage extends I2CPMessageImpl { protected byte[] doWriteMessage() throws I2CPMessageException, IOException { if ((_sessionId == null) || (_severity == null) || (_reason == null)) throw new I2CPMessageException("Not enough information to construct the message"); - ByteArrayOutputStream os = new ByteArrayOutputStream(32); + int len = 2 + 1 + 4 + 1; + String r = _reason.getReason(); + if (r != null) + len += r.length(); + ByteArrayStream os = new ByteArrayStream(len); try { _sessionId.writeBytes(os); _severity.writeBytes(os); diff --git a/core/java/src/net/i2p/data/i2cp/RequestLeaseSetMessage.java b/core/java/src/net/i2p/data/i2cp/RequestLeaseSetMessage.java index 8aca349f62..80a659893b 100644 --- a/core/java/src/net/i2p/data/i2cp/RequestLeaseSetMessage.java +++ b/core/java/src/net/i2p/data/i2cp/RequestLeaseSetMessage.java @@ -9,7 +9,6 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; @@ -21,6 +20,7 @@ import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.TunnelId; +import net.i2p.util.ByteArrayStream; /** * Defines the message a router sends to a client to request that @@ -38,7 +38,7 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl { private Date _end; public RequestLeaseSetMessage() { - _endpoints = new ArrayList(); + _endpoints = new ArrayList(6); } public SessionId getSessionId() { @@ -119,7 +119,8 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl { protected byte[] doWriteMessage() throws I2CPMessageException, IOException { if (_sessionId == null) throw new I2CPMessageException("Unable to write out the message as there is not enough data"); - ByteArrayOutputStream os = new ByteArrayOutputStream(256); + int len = 2 + 1 + (_endpoints.size() * (32 + 4)) + 8; + ByteArrayStream os = new ByteArrayStream(len); try { _sessionId.writeBytes(os); os.write((byte) _endpoints.size()); diff --git a/core/java/src/net/i2p/data/i2cp/RequestVariableLeaseSetMessage.java b/core/java/src/net/i2p/data/i2cp/RequestVariableLeaseSetMessage.java index beb3ad93b2..441fd6958f 100644 --- a/core/java/src/net/i2p/data/i2cp/RequestVariableLeaseSetMessage.java +++ b/core/java/src/net/i2p/data/i2cp/RequestVariableLeaseSetMessage.java @@ -9,7 +9,6 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -19,6 +18,7 @@ import java.util.List; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Lease; +import net.i2p.util.ByteArrayStream; import net.i2p.util.VersionComparator; /** @@ -38,7 +38,7 @@ public class RequestVariableLeaseSetMessage extends I2CPMessageImpl { private static final String MIN_VERSION = "0.9.7"; public RequestVariableLeaseSetMessage() { - _endpoints = new ArrayList(); + _endpoints = new ArrayList(6); } /** @@ -109,7 +109,8 @@ public class RequestVariableLeaseSetMessage extends I2CPMessageImpl { protected byte[] doWriteMessage() throws I2CPMessageException, IOException { if (_sessionId == null) throw new I2CPMessageException("No data"); - ByteArrayOutputStream os = new ByteArrayOutputStream(256); + int len = 2 + 1 + (_endpoints.size() * 44); + ByteArrayStream os = new ByteArrayStream(len); try { _sessionId.writeBytes(os); os.write((byte) _endpoints.size()); diff --git a/core/java/src/net/i2p/data/i2cp/SessionConfig.java b/core/java/src/net/i2p/data/i2cp/SessionConfig.java index 69072e9eba..a138e6aaaf 100644 --- a/core/java/src/net/i2p/data/i2cp/SessionConfig.java +++ b/core/java/src/net/i2p/data/i2cp/SessionConfig.java @@ -27,6 +27,7 @@ import net.i2p.data.Destination; import net.i2p.data.Signature; import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; +import net.i2p.util.ByteArrayStream; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.OrderedProperties; @@ -278,7 +279,7 @@ public class SessionConfig extends DataStructureImpl { Signature sig = getOfflineSignature(); if (sig == null) return false; - ByteArrayOutputStream baos = new ByteArrayOutputStream(128); + ByteArrayStream baos = new ByteArrayStream(6 + spk.length()); try { DataHelper.writeLong(baos, 4, expires / 1000); DataHelper.writeLong(baos, 2, spk.getType().getCode()); @@ -323,7 +324,7 @@ public class SessionConfig extends DataStructureImpl { if (_options == null) return null; if (_creationDate == null) return null; - ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream(512); try { //_log.debug("PubKey size for destination: " + _destination.getPublicKey().getData().length); //_log.debug("SigningKey size for destination: " + _destination.getSigningPublicKey().getData().length); diff --git a/core/java/src/net/i2p/data/i2cp/SessionStatusMessage.java b/core/java/src/net/i2p/data/i2cp/SessionStatusMessage.java index d01acdf4ff..9cb3977d38 100644 --- a/core/java/src/net/i2p/data/i2cp/SessionStatusMessage.java +++ b/core/java/src/net/i2p/data/i2cp/SessionStatusMessage.java @@ -9,13 +9,13 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; +import net.i2p.util.ByteArrayStream; /** * Defines the message a router sends to a client indicating the @@ -87,7 +87,7 @@ public class SessionStatusMessage extends I2CPMessageImpl { protected byte[] doWriteMessage() throws I2CPMessageException, IOException { if (_sessionId == null) throw new I2CPMessageException("Unable to write out the message as there is not enough data"); - ByteArrayOutputStream os = new ByteArrayOutputStream(64); + ByteArrayStream os = new ByteArrayStream(3); try { _sessionId.writeBytes(os); os.write((byte) _status); diff --git a/core/java/src/net/i2p/data/i2cp/SetDateMessage.java b/core/java/src/net/i2p/data/i2cp/SetDateMessage.java index 0fef292623..c585cd4a57 100644 --- a/core/java/src/net/i2p/data/i2cp/SetDateMessage.java +++ b/core/java/src/net/i2p/data/i2cp/SetDateMessage.java @@ -9,13 +9,13 @@ package net.i2p.data.i2cp; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Date; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; +import net.i2p.util.ByteArrayStream; import net.i2p.util.Clock; /** @@ -74,7 +74,7 @@ public class SetDateMessage extends I2CPMessageImpl { protected byte[] doWriteMessage() throws I2CPMessageException, IOException { if (_date == null) throw new I2CPMessageException("Unable to write out the message as there is not enough data"); - ByteArrayOutputStream os = new ByteArrayOutputStream(32); + ByteArrayStream os = new ByteArrayStream(8 + 1 + 6); try { DataHelper.writeDate(os, _date); if (_version != null) diff --git a/core/java/src/net/i2p/util/ByteArrayStream.java b/core/java/src/net/i2p/util/ByteArrayStream.java index 22192c5944..6fd3c1ffb0 100644 --- a/core/java/src/net/i2p/util/ByteArrayStream.java +++ b/core/java/src/net/i2p/util/ByteArrayStream.java @@ -18,6 +18,9 @@ public class ByteArrayStream extends ByteArrayOutputStream { super(); } + /** + * @param size if accurate, toByteArray() will be zero-copy + */ public ByteArrayStream(int size) { super(size); } diff --git a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java index 0535ff3767..0d3b61c19f 100644 --- a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java +++ b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java @@ -8,7 +8,6 @@ package net.i2p.router.message; * */ -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Date; import java.util.HashSet; @@ -37,6 +36,7 @@ import net.i2p.router.crypto.ratchet.MuxedSKM; import net.i2p.router.crypto.ratchet.RatchetSKM; import net.i2p.router.crypto.ratchet.RatchetSessionTag; import net.i2p.router.crypto.ratchet.ReplyCallback; +import net.i2p.util.ByteArrayStream; import net.i2p.util.Log; /** @@ -393,11 +393,11 @@ public class GarlicMessageBuilder { * @throws IllegalArgumentException on error */ private static byte[] buildCloveSet(RouterContext ctx, GarlicConfig config) { - ByteArrayOutputStream baos; + ByteArrayStream baos; try { if (config instanceof PayloadGarlicConfig) { byte clove[] = buildClove(ctx, (PayloadGarlicConfig)config); - baos = new ByteArrayOutputStream(clove.length + 16); + baos = new ByteArrayStream(1 + clove.length + 3 + 4 + 8); baos.write((byte) 1); baos.write(clove); } else { @@ -417,7 +417,7 @@ public class GarlicMessageBuilder { int len = 1; for (int i = 0; i < cloves.length; i++) len += cloves[i].length; - baos = new ByteArrayOutputStream(len + 16); + baos = new ByteArrayStream(1 + len + 3 + 4 + 8); baos.write((byte) cloves.length); for (int i = 0; i < cloves.length; i++) baos.write(cloves[i]); diff --git a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java index c391b4708b..88e1cd068c 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java @@ -33,6 +33,7 @@ import net.i2p.router.RouterContext; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.router.transport.crypto.DHSessionKeyBuilder; import static net.i2p.router.transport.ntcp.OutboundNTCP2State.*; +import net.i2p.util.ByteArrayStream; import net.i2p.util.ByteCache; import net.i2p.util.Log; import net.i2p.util.SimpleByteCache; @@ -456,7 +457,7 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa long rtt = now - _con.getCreated(); _peerSkew = (now - (tsA * 1000) - (rtt / 2) + 500) / 1000; - ByteArrayOutputStream baos = new ByteArrayOutputStream(768); + ByteArrayStream baos = new ByteArrayStream(256 + 256 + 32 + 4 + 4); baos.write(_X); baos.write(_Y); baos.write(_context.routerHash().getData());