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 41b0eeddd6e9d29e94711e94ae300c56d9de4130..267c4fc2a5b6846f8ac48b67752c72ffb49be768 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -967,6 +967,32 @@ class EstablishmentManager { notifyActivity(); } + /** + * Called from UDPReceiver. + * Accelerate response to RelayResponse if we haven't sent it yet. + * + * @since 0.9.15 + */ + void receiveHolePunch(InetAddress from, int fromPort) { + RemoteHostId id = new RemoteHostId(from.getAddress(), fromPort); + OutboundEstablishState state = _outboundStates.get(id); + if (state != null) { + boolean sendNow = state.receiveHolePunch(); + if (sendNow) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Hole punch from " + state + ", sending SessionRequest now"); + notifyActivity(); + } else { + if (_log.shouldLog(Log.WARN)) + _log.warn("Hole punch from " + state + ", already sent SessionRequest"); + } + } else { + // HolePunch received before RelayResponse, and we didn't know the IP/port, or it changed + if (_log.shouldLog(Log.WARN)) + _log.warn("No state found for hole punch from " + from + " port " + fromPort); + } + } + /** * Are IP and port valid? This is only for checking the relay response. * Reject all IPv6, for now, even if we are configured for it. diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java index 39adc9b24b36f210e7a7081cb1374cc6dd6b2b46..ba4375dbdb8f8ec34623bd162a7c38df0a7b9d5c 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java @@ -99,6 +99,8 @@ class OutboundEstablishState { /** max delay including backoff */ private static final long MAX_DELAY = 15*1000; + private static final long WAIT_FOR_HOLE_PUNCH_DELAY = 500; + /** * @param claimedAddress an IP/port based RemoteHostId, or null if unknown * @param remoteHostId non-null, == claimedAddress if direct, or a hash-based one if indirect @@ -556,7 +558,7 @@ class OutboundEstablishState { public synchronized void introduced(byte bobIP[], int bobPort) { if (_currentState != OutboundState.OB_STATE_PENDING_INTRO) return; // we've already successfully been introduced, so don't overwrite old settings - _nextSend = _context.clock().now() + 500; // wait briefly for the hole punching + _nextSend = _context.clock().now() + WAIT_FOR_HOLE_PUNCH_DELAY; // wait briefly for the hole punching _currentState = OutboundState.OB_STATE_INTRODUCED; if (_claimedAddress != null && bobPort == _bobPort && DataHelper.eq(bobIP, _bobIP)) { // he's who he said he was @@ -570,6 +572,24 @@ class OutboundEstablishState { if (_log.shouldLog(Log.INFO)) _log.info("Introduced to " + _remoteHostId + ", now lets get on with establishing"); } + + /** + * Accelerate response to RelayResponse if we haven't sent it yet. + * + * @return true if we should send the SessionRequest now + * @since 0.9.15 + */ + synchronized boolean receiveHolePunch() { + if (_currentState != OutboundState.OB_STATE_INTRODUCED) + return false; + if (_requestSentCount > 0) + return false; + long now = _context.clock().now(); + if (_log.shouldLog(Log.WARN)) + _log.warn(toString() + " accelerating SessionRequest by " + (_nextSend - now) + " ms"); + _nextSend = now; + return true; + } /** how long have we been trying to establish this session? */ public long getLifetime() { return _context.clock().now() - _establishBegin; } 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 be5b97dcf830cd5d06c1da20dfe9627ab4d17ebe..65a7a81cbf5b95c4d87d89cee021a9b74f3d8dc8 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java @@ -1,6 +1,7 @@ package net.i2p.router.transport.udp; import java.io.IOException; +import java.net.DatagramPacket; import java.net.DatagramSocket; import java.util.Arrays; @@ -220,11 +221,12 @@ class UDPReceiver { // _socketChanged = false; //} UDPPacket packet = UDPPacket.acquire(_context, true); + DatagramPacket dpacket = packet.getPacket(); // Android ICS bug // http://code.google.com/p/android/issues/detail?id=24748 if (_isAndroid) - packet.getPacket().setLength(UDPPacket.MAX_PACKET_SIZE); + dpacket.setLength(UDPPacket.MAX_PACKET_SIZE); // block before we read... //if (_log.shouldLog(Log.DEBUG)) @@ -236,9 +238,9 @@ class UDPReceiver { //if (_log.shouldLog(Log.INFO)) // _log.info("Before blocking socket.receive on " + System.identityHashCode(packet)); //synchronized (Runner.this) { - _socket.receive(packet.getPacket()); + _socket.receive(dpacket); //} - int size = packet.getPacket().getLength(); + int size = dpacket.getLength(); if (_log.shouldLog(Log.INFO)) _log.info("After blocking socket.receive: packet is " + size + " bytes on " + System.identityHashCode(packet)); packet.resetBegin(); @@ -266,7 +268,8 @@ class UDPReceiver { _context.statManager().addRateData("udp.receiveHolePunch", 1); // nat hole punch packets are 0 bytes if (_log.shouldLog(Log.INFO)) - _log.info("Received a 0 byte udp packet from " + packet.getPacket().getAddress() + ":" + packet.getPacket().getPort()); + _log.info("Received a 0 byte udp packet from " + dpacket.getAddress() + ":" + dpacket.getPort()); + _transport.getEstablisher().receiveHolePunch(dpacket.getAddress(), dpacket.getPort()); packet.release(); } } catch (IOException ioe) {