diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java index 0a950a1224fd32e91f45e513decf5a9b1a96c447..ae3cbb9127739aa0074c2675a6bd6025c9cf40d9 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder2.java @@ -728,8 +728,31 @@ class PacketBuilder2 { * @return ready to send packet, non-null */ public UDPPacket buildPeerTestToAlice(int code, Hash charlieHash, byte[] signedData, PeerState2 alice) { + return buildPeerTestToAlice(code, charlieHash, signedData, null, alice); + } + + /** + * Build a packet as Bob to Alice, with the response from Charlie, + * or a rejection by Bob. + * In-session, message 4. + * + * @param charlieHash fake hash (all zeros) if rejected by bob + * @param riBlock to include, may be null + * @return ready to send packet, non-null + * @since 0.9.57 + */ + public UDPPacket buildPeerTestToAlice(int code, Hash charlieHash, byte[] signedData, Block riBlock, PeerState2 alice) { Block block = new SSU2Payload.PeerTestBlock(4, code, charlieHash, signedData); - UDPPacket rv = buildPacket(Collections.<Fragment>emptyList(), Collections.singletonList(block), alice); + List<Block> blocks; + if (riBlock != null) { + // RouterInfo must be first + blocks = new ArrayList<Block>(2); + blocks.add(riBlock); + blocks.add(block); + } else { + blocks = Collections.singletonList(block); + } + UDPPacket rv = buildPacket(Collections.<Fragment>emptyList(), blocks, alice); rv.setMessageType(TYPE_TTA); return rv; } @@ -761,11 +784,21 @@ class PacketBuilder2 { * Build a packet as Bob to Charlie to help test Alice. * In-session, message 2. * + * @param riBlock to include, may be null * @return ready to send packet, non-null */ - public UDPPacket buildPeerTestToCharlie(Hash aliceHash, byte[] signedData, PeerState2 charlie) { + public UDPPacket buildPeerTestToCharlie(Hash aliceHash, byte[] signedData, Block riBlock, PeerState2 charlie) { Block block = new SSU2Payload.PeerTestBlock(2, 0, aliceHash, signedData); - UDPPacket rv = buildPacket(Collections.<Fragment>emptyList(), Collections.singletonList(block), charlie); + List<Block> blocks; + if (riBlock != null) { + // RouterInfo must be first + blocks = new ArrayList<Block>(2); + blocks.add(riBlock); + blocks.add(block); + } else { + blocks = Collections.singletonList(block); + } + UDPPacket rv = buildPacket(Collections.<Fragment>emptyList(), blocks, charlie); rv.setMessageType(TYPE_TBC); return rv; } 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 4d5acfb95534c90c44340b05a17bbca4b3444326..b9aab6fdb60ed359a5c60a409ead6d60ad9500da 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java @@ -1193,16 +1193,8 @@ class PeerTestManager { // send alice RI to charlie if (_log.shouldDebug()) _log.debug("Send Alice RI and msg 2 to charlie on " + state); - // TODO see if Alide RI will compress enough to fit in the peer test packet - DatabaseStoreMessage dbsm = new DatabaseStoreMessage(_context); - dbsm.setEntry(aliceRI); - dbsm.setMessageExpiration(now + 10*1000); - _transport.send(dbsm, charlie); // forward to charlie, don't bother to validate signed data - UDPPacket packet = _packetBuilder2.buildPeerTestToCharlie(alice, data, (PeerState2) charlie); - // delay because dbsm is queued, we want it to get there first - new DelaySend(packet, 100); - charlie.setLastSendTime(now); + sendRIandPT(aliceRI, -1, alice, data, (PeerState2) charlie, now); break; } @@ -1328,15 +1320,7 @@ class PeerTestManager { _log.info("Charlie response " + status + " picked a new one " + charlie + " on " + state); state.setCharlie(charlie.getRemoteIPAddress(), charlie.getRemotePort(), charlie.getRemotePeer()); state.setLastSendTime(now); - // TODO see if Alice RI will compress enough to fit in the peer test packet - DatabaseStoreMessage dbsm = new DatabaseStoreMessage(_context); - dbsm.setEntry(aliceRI); - dbsm.setMessageExpiration(now + 10*1000); - _transport.send(dbsm, charlie); - UDPPacket packet = _packetBuilder2.buildPeerTestToCharlie(alice, state.getTestData(), (PeerState2) charlie); - // delay because dbsm is queued, we want it to get there first - new DelaySend(packet, 100); - charlie.setLastSendTime(now); + sendRIandPT(aliceRI, -1, alice, state.getTestData(), (PeerState2) charlie, now); break; } } @@ -1353,11 +1337,6 @@ class PeerTestManager { // Alice would need it to verify sig, but not worth the bandwidth if (_log.shouldDebug()) _log.debug("Send Charlie RI to alice on " + state); - // TODO see if Charlie RI will compress enough to fit in the peer test packet - DatabaseStoreMessage dbsm = new DatabaseStoreMessage(_context); - dbsm.setEntry(charlieRI); - dbsm.setMessageExpiration(now + 10*1000); - _transport.send(dbsm, alice); if (true) { // Debug - validate signed data // we forward it to alice even on failure @@ -1377,13 +1356,7 @@ class PeerTestManager { // FIXME this will probably get there before the RI if (_log.shouldDebug()) _log.debug("Send msg 4 status " + status + " to alice on " + state); - UDPPacket packet = _packetBuilder2.buildPeerTestToAlice(status, charlie, data, alice); - // delay because dbsm is queued, we want it to get there first - if (charlieRI != null) - new DelaySend(packet, 100); - else - _transport.send(packet); - alice.setLastSendTime(now); + sendRIandPT(charlieRI, status, charlie, data, alice, now); // overwrite alice-signed test data with charlie-signed data in case we need to retransmit state.setStatus(status); state.setSendAliceTime(now); @@ -2126,6 +2099,67 @@ class PeerTestManager { } } + /** + * Send RI and Peer Test. SSU2 only. We are Bob. + * + * Msg 2 Bob to Charlie with Alice's RI + * Msg 4 Bob to Alice with Charlie's RI + * + * @param ri may be null, but hopefully not + * @param status -1 for msg 2, nonnegative for msg 4 + * @param hash alice for msg 2, charlie for msg 4 + * @param data signed peer test data + * @param to charlie for msg 2, alice for msg 4 + * @since 0.9.57 + */ + private void sendRIandPT(RouterInfo ri, int status, Hash hash, byte[] data, PeerState2 to, long now) { + boolean delay = false; + SSU2Payload.RIBlock riblock = null; + if (ri != null) { + // See if the RI will compress enough to fit in the peer test packet, + // as this makes everything go smoother and faster. + // Overhead total is 183 via IPv4, 203 via IPv6 (w/ IPv4 addr in data) + // Overhead total is 195 via IPv4, 215 via IPv6 (w/ IPv6 addr in data) + int avail = to.getMTU() - + ((to.isIPv6() ? PacketBuilder2.MIN_IPV6_DATA_PACKET_OVERHEAD : PacketBuilder2.MIN_DATA_PACKET_OVERHEAD) + + SSU2Payload.BLOCK_HEADER_SIZE + // peer test block header + 3 + // peer test block msgnum/code/flag + Hash.HASH_LENGTH + // peer test block hash + data.length + // peer test block signed data + SSU2Payload.BLOCK_HEADER_SIZE + // RI block header + 2 // RI block flag/frag bytes + ); + byte[] info = ri.toByteArray(); + byte[] gzipped = DataHelper.compress(info, 0, info.length, DataHelper.MAX_COMPRESSION); + if (_log.shouldDebug()) + _log.debug("RI: " + info.length + " bytes uncompressed, " + gzipped.length + + " compressed, MTU " + to.getMTU() + ", available " + avail); + boolean gzip = gzipped.length < info.length; + if (gzip) + info = gzipped; + if (info.length <= avail) { + riblock = new SSU2Payload.RIBlock(info, 0, info.length, false, gzip, 0, 1); + } else { + DatabaseStoreMessage dbsm = new DatabaseStoreMessage(_context); + dbsm.setEntry(ri); + dbsm.setMessageExpiration(now + 10*1000); + _transport.send(dbsm, to); + delay = true; + } + } + UDPPacket packet; + if (status < 0) + packet = _packetBuilder2.buildPeerTestToCharlie(hash, data, riblock, to); + else + packet = _packetBuilder2.buildPeerTestToAlice(status, hash, data, riblock, to); + // delay because dbsm is queued, we want it to get there first + if (delay) + new DelaySend(packet, 100); + else + _transport.send(packet); + to.setLastSendTime(now); + } + /** * Simple fix for RI getting there before PeerTest. * SSU2 only. We are Bob, for delaying msg sent after RI to Alice or Charlie.