diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java index f0520d46f..8e55073f4 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java @@ -117,6 +117,9 @@ public class I2PSocketException extends SocketException { case MessageStatusMessage.STATUS_SEND_FAILURE_META_LEASESET: return "Meta lease set"; + case MessageStatusMessage.STATUS_SEND_FAILURE_LOOPBACK: + return "local loopback denied, set i2cp.disableLoopback=true to test sending to yourself through tunnels"; + case SendMessageStatusListener.STATUS_CANCELLED: return _x("Local destination shutdown"); diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/PacketQueue.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/PacketQueue.java index 14d980ea9..dcbdb300b 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/PacketQueue.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/PacketQueue.java @@ -324,6 +324,7 @@ class PacketQueue implements SendMessageStatusListener, Closeable { case MessageStatusMessage.STATUS_SEND_FAILURE_DESTINATION: case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET: case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED_LEASESET: + case MessageStatusMessage.STATUS_SEND_FAILURE_LOOPBACK: case SendMessageStatusListener.STATUS_CANCELLED: if (con.getHighestAckedThrough() >= 0) { // a retxed SYN succeeded before the first SYN failed diff --git a/core/java/src/net/i2p/client/impl/MessageState.java b/core/java/src/net/i2p/client/impl/MessageState.java index e60f080c8..478d69391 100644 --- a/core/java/src/net/i2p/client/impl/MessageState.java +++ b/core/java/src/net/i2p/client/impl/MessageState.java @@ -157,6 +157,7 @@ class MessageState { case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED_LEASESET: case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET: case MessageStatusMessage.STATUS_SEND_FAILURE_META_LEASESET: + case MessageStatusMessage.STATUS_SEND_FAILURE_LOOPBACK: case SendMessageStatusListener.STATUS_CANCELLED: // does not trump success if (_state != State.SUCCESS) diff --git a/core/java/src/net/i2p/data/i2cp/MessageStatusMessage.java b/core/java/src/net/i2p/data/i2cp/MessageStatusMessage.java index 72ee546d5..2cd87d14c 100644 --- a/core/java/src/net/i2p/data/i2cp/MessageStatusMessage.java +++ b/core/java/src/net/i2p/data/i2cp/MessageStatusMessage.java @@ -189,6 +189,13 @@ public class MessageStatusMessage extends I2CPMessageImpl { */ public final static int STATUS_SEND_FAILURE_META_LEASESET = 22; + /** + * Message was attempted to be sent to the same Destination. + * This is a guaranteed failure. + * @since 0.9.62 + */ + public final static int STATUS_SEND_FAILURE_LOOPBACK = 23; + // NOTE: // Add any new status codes to handlers in: // net.i2p.client.impl.MessageState diff --git a/router/java/src/net/i2p/router/client/ClientConnectionRunner.java b/router/java/src/net/i2p/router/client/ClientConnectionRunner.java index 9c0cdd078..98a87516b 100644 --- a/router/java/src/net/i2p/router/client/ClientConnectionRunner.java +++ b/router/java/src/net/i2p/router/client/ClientConnectionRunner.java @@ -806,7 +806,7 @@ class ClientConnectionRunner { // the following blocks as described above Destination fromDest = getDestination(message.getSessionId()); if (fromDest != null) - _manager.distributeMessage(fromDest, dest, payload, + _manager.distributeMessage(this, fromDest, dest, payload, id, message.getNonce(), expiration, flags); // else log error? //long timeToDistribute = _context.clock().now() - beforeDistribute; diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java index d991b7538..8aad9e14f 100644 --- a/router/java/src/net/i2p/router/client/ClientManager.java +++ b/router/java/src/net/i2p/router/client/ClientManager.java @@ -451,11 +451,13 @@ class ClientManager { /** * Distribute message to a local or remote destination. + * + * @param sender non-null * @param msgId the router's ID for this message * @param messageNonce the client's ID for this message * @param flags ignored for local */ - void distributeMessage(Destination fromDest, Destination toDest, Payload payload, + void distributeMessage(ClientConnectionRunner sender, Destination fromDest, Destination toDest, Payload payload, MessageId msgId, long messageNonce, long expiration, int flags) { ClientConnectionRunner runner; if (_ctx.getBooleanProperty(PROP_DISABLE_LOOPBACK)) { @@ -467,22 +469,19 @@ class ClientManager { if (runner != null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Message " + msgId + " is targeting a local destination. distribute it as such"); - ClientConnectionRunner sender = getRunner(fromDest); - if (sender == null) { - // sender went away - return; + if (runner != sender) { + // run this inline so we don't clog up the job queue + Job j = new DistributeLocal(toDest, runner, sender, fromDest, payload, msgId, messageNonce); + //_ctx.jobQueue().addJob(j); + j.runJob(); + } else { + if (_log.shouldWarn()) + _log.warn("Loopback attempt from client " + fromDest.getHash()); + int rc = MessageStatusMessage.STATUS_SEND_FAILURE_LOOPBACK; + sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, rc); } - // run this inline so we don't clog up the job queue - Job j = new DistributeLocal(toDest, runner, sender, fromDest, payload, msgId, messageNonce); - //_ctx.jobQueue().addJob(j); - j.runJob(); } else if (!_metaDests.isEmpty() && _metaDests.contains(toDest)) { // meta dests don't have runners but are local, and you can't send to them - ClientConnectionRunner sender = getRunner(fromDest); - if (sender == null) { - // sender went away - return; - } int rc = MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET; sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, rc); } else { diff --git a/router/java/test/junit/net/i2p/router/client/LocalClientManager.java b/router/java/test/junit/net/i2p/router/client/LocalClientManager.java index e8fbd8f22..f4df6139d 100644 --- a/router/java/test/junit/net/i2p/router/client/LocalClientManager.java +++ b/router/java/test/junit/net/i2p/router/client/LocalClientManager.java @@ -56,19 +56,16 @@ class LocalClientManager extends ClientManager { * @param flags ignored for local */ @Override - void distributeMessage(Destination fromDest, Destination toDest, Payload payload, + void distributeMessage(ClientConnectionRunner sender, Destination fromDest, Destination toDest, Payload payload, MessageId msgId, long messageNonce, long expiration, int flags) { // check if there is a runner for it - ClientConnectionRunner sender = getRunner(fromDest); ClientConnectionRunner runner = getRunner(toDest); if (runner != null) { if (dropX1000 > 0) { if (100 * 1000 * _ctx.random().nextFloat() < dropX1000) { System.out.println("Message " + msgId + " DROPPED randomly"); - if (sender != null) { - // pretend success - sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, MessageStatusMessage.STATUS_SEND_GUARANTEED_SUCCESS); - } + // pretend success + sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, MessageStatusMessage.STATUS_SEND_GUARANTEED_SUCCESS); } } if (latency > 0 || jitter > 0) { @@ -83,15 +80,12 @@ class LocalClientManager extends ClientManager { } } boolean ok = runner.receiveMessage(toDest, fromDest, payload); - if (sender != null) { - int rc = ok ? MessageStatusMessage.STATUS_SEND_SUCCESS_LOCAL : MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL; - sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, rc); - } + int rc = ok ? MessageStatusMessage.STATUS_SEND_SUCCESS_LOCAL : MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL; + sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, rc); } else { // remote. ignore. System.out.println("Message " + msgId + " is targeting a REMOTE destination - DROPPED"); - if (sender != null) - sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, MessageStatusMessage.STATUS_SEND_GUARANTEED_FAILURE); + sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, MessageStatusMessage.STATUS_SEND_GUARANTEED_FAILURE); } } @@ -113,10 +107,8 @@ class LocalClientManager extends ClientManager { public void timeReached() { boolean ok = r.receiveMessage(td, fd, pl); - if (s != null) { - int rc = ok ? MessageStatusMessage.STATUS_SEND_SUCCESS_LOCAL : MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL; - s.updateMessageDeliveryStatus(fd, id, nonce, rc); - } + int rc = ok ? MessageStatusMessage.STATUS_SEND_SUCCESS_LOCAL : MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL; + s.updateMessageDeliveryStatus(fd, id, nonce, rc); } }