From 2dbe33e7698949700b6e62deb2afa1f0d1379d99 Mon Sep 17 00:00:00 2001 From: jrandom Date: Wed, 28 Jul 2004 00:08:15 +0000 Subject: [PATCH] * cleaned up the tunnelCreate reply timeout * reduced the number of tags passed when garlic routing a tunnelCreate * catch timeout on a tunnel message quicker * give a tunnel message a new messageId per hop * added some more infrastructure for per-hop tunnelId --- .../java/src/net/i2p/router/TunnelInfo.java | 12 +++++++++++ .../router/message/GarlicMessageBuilder.java | 11 ++++++---- .../message/HandleTunnelMessageJob.java | 21 ++++++++++++++++--- .../router/message/SendTunnelMessageJob.java | 9 +++++++- .../HandleTunnelCreateMessageJob.java | 10 ++++----- .../tunnelmanager/RequestTunnelJob.java | 2 +- 6 files changed, 51 insertions(+), 14 deletions(-) diff --git a/router/java/src/net/i2p/router/TunnelInfo.java b/router/java/src/net/i2p/router/TunnelInfo.java index 371e4fba3..a3b892193 100644 --- a/router/java/src/net/i2p/router/TunnelInfo.java +++ b/router/java/src/net/i2p/router/TunnelInfo.java @@ -40,6 +40,7 @@ public class TunnelInfo extends DataStructureImpl { private static Log _log; private TunnelId _id; private Hash _nextHop; + private TunnelId _nextHopId; private Hash _thisHop; private TunnelInfo _nextHopInfo; private TunnelConfigurationSessionKey _configurationKey; @@ -62,6 +63,7 @@ public class TunnelInfo extends DataStructureImpl { setTunnelId(null); setThisHop(null); setNextHop(null); + setNextHopId(null); setNextHopInfo(null); _configurationKey = null; _verificationKey = null; @@ -83,6 +85,9 @@ public class TunnelInfo extends DataStructureImpl { public Hash getNextHop() { return _nextHop; } public void setNextHop(Hash nextHopRouterIdentity) { _nextHop = nextHopRouterIdentity; } + public TunnelId getNextHopId() { return _nextHopId; } + public void setNextHopId(TunnelId id) { _nextHopId = id; } + public Hash getThisHop() { return _thisHop; } public void setThisHop(Hash thisHopRouterIdentity) { _thisHop = thisHopRouterIdentity; } @@ -197,6 +202,8 @@ public class TunnelInfo extends DataStructureImpl { if (includeNext.booleanValue()) { _nextHop = new Hash(); _nextHop.readBytes(in); + _nextHopId = new TunnelId(); + _nextHopId.readBytes(in); } else { _nextHop = null; } @@ -266,6 +273,7 @@ public class TunnelInfo extends DataStructureImpl { if (_nextHop != null) { DataHelper.writeBoolean(out, Boolean.TRUE); _nextHop.writeBytes(out); + _nextHopId.writeBytes(out); } else { DataHelper.writeBoolean(out, Boolean.FALSE); } @@ -321,6 +329,8 @@ public class TunnelInfo extends DataStructureImpl { buf.append("\n Destination: ").append(cur.getDestination().calculateHash().toBase64()); if (cur.getNextHop() != null) buf.append("\n Next: ").append(cur.getNextHop()); + if (cur.getNextHop() != null) + buf.append("\n NextId: ").append(cur.getNextHopId()); if (cur.getSettings() == null) buf.append("\n Expiration: ").append("none"); else @@ -338,6 +348,7 @@ public class TunnelInfo extends DataStructureImpl { rv = 7*rv + DataHelper.hashCode(_options); rv = 7*rv + DataHelper.hashCode(_destination); rv = 7*rv + DataHelper.hashCode(_nextHop); + rv = 7*rv + DataHelper.hashCode(_nextHopId); rv = 7*rv + DataHelper.hashCode(_thisHop); rv = 7*rv + DataHelper.hashCode(_id); rv = 7*rv + DataHelper.hashCode(_configurationKey); @@ -357,6 +368,7 @@ public class TunnelInfo extends DataStructureImpl { getIsReady() == info.getIsReady() && DataHelper.eq(getEncryptionKey(), info.getEncryptionKey()) && DataHelper.eq(getNextHop(), info.getNextHop()) && + DataHelper.eq(getNextHopId(), info.getNextHopId()) && DataHelper.eq(getNextHopInfo(), info.getNextHopInfo()) && DataHelper.eq(getSettings(), info.getSettings()) && DataHelper.eq(getSigningKey(), info.getSigningKey()) && diff --git a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java index be16c1a8e..3a2ee45c9 100644 --- a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java +++ b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java @@ -34,6 +34,9 @@ public class GarlicMessageBuilder { return buildMessage(ctx, config, new SessionKey(), new HashSet()); } public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set wrappedTags) { + return buildMessage(ctx, config, wrappedKey, wrappedTags, 20); + } + public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set wrappedTags, int numTagsToDeliver) { Log log = ctx.logManager().getLog(GarlicMessageBuilder.class); PublicKey key = config.getRecipientPublicKey(); if (key == null) { @@ -61,16 +64,16 @@ public class GarlicMessageBuilder { log.debug("Available tags for encryption to " + key + ": " + availTags); if (availTags < 10) { // arbitrary threshold - for (int i = 0; i < 20; i++) + for (int i = 0; i < numTagsToDeliver; i++) wrappedTags.add(new SessionTag(true)); if (log.shouldLog(Log.INFO)) - log.info("Less than 10 tags are available (" + availTags + "), so we're including 20 more"); + log.info("Less than 10 tags are available (" + availTags + "), so we're including more"); } else if (ctx.sessionKeyManager().getAvailableTimeLeft(key, curKey) < 30*1000) { // if we have > 10 tags, but they expire in under 30 seconds, we want more - for (int i = 0; i < 20; i++) + for (int i = 0; i < numTagsToDeliver; i++) wrappedTags.add(new SessionTag(true)); if (log.shouldLog(Log.INFO)) - log.info("Tags are almost expired, adding 20 new ones"); + log.info("Tags are almost expired, adding new ones"); } else { // always tack on at least one more - not necessary. //wrappedTags.add(new SessionTag(true)); diff --git a/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java b/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java index 30751ef36..8dbe74b79 100644 --- a/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java +++ b/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java @@ -198,9 +198,24 @@ public class HandleTunnelMessageJob extends JobImpl { getContext().statManager().addRateData("tunnel.relayMessageSize", _message.getData().length, 0); - SendMessageDirectJob j = new SendMessageDirectJob(getContext(), _message, + TunnelMessage msg = new TunnelMessage(getContext()); + msg.setData(_message.getData()); + msg.setEncryptedDeliveryInstructions(_message.getEncryptedDeliveryInstructions()); + msg.setTunnelId(info.getNextHopId()); + msg.setVerificationStructure(_message.getVerificationStructure()); + msg.setMessageExpiration(_message.getMessageExpiration()); + + int timeoutMs = (int)(_message.getMessageExpiration().getTime() - getContext().clock().now()); + if (timeoutMs < 1000) { + if (_log.shouldLog(Log.ERROR)) + _log.error("Message " + _message.getUniqueId() + " is valid and we would pass it on through tunnel " + + info.getTunnelId().getTunnelId() + ", but its too late (expired " + timeoutMs + "ms ago)"); + return; + } + + SendMessageDirectJob j = new SendMessageDirectJob(getContext(), msg, info.getNextHop(), - (int)(_message.getMessageExpiration().getTime() - getContext().clock().now()), + timeoutMs, FORWARD_PRIORITY); getContext().jobQueue().addJob(j); return; @@ -515,7 +530,7 @@ public class HandleTunnelMessageJob extends JobImpl { ReplyJob onReply = null; Hash targetRouter = null; TunnelId targetTunnelId = null; - SendTunnelMessageJob j = new SendTunnelMessageJob(ctx, _body, _info.getTunnelId(), targetRouter, targetTunnelId, onSuccess, onReply, onFailure, selector, timeout, FORWARD_PRIORITY); + SendTunnelMessageJob j = new SendTunnelMessageJob(ctx, _body, _info.getNextHopId(), targetRouter, targetTunnelId, onSuccess, onReply, onFailure, selector, timeout, FORWARD_PRIORITY); ctx.jobQueue().addJob(j); } else { if (_log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java b/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java index 0cac9a056..5a249f6e4 100644 --- a/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java +++ b/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java @@ -180,7 +180,14 @@ public class SendTunnelMessageJob extends JobImpl { _log.debug("Tunnel message created: " + msg + " out of encrypted message: " + _message); long now = getContext().clock().now(); - if (_expiration < now + 15*1000) { + if (_expiration < now) { + if (_log.shouldLog(Log.ERROR)) + _log.error("We are the gateway to " + info.getTunnelId().getTunnelId() + + " and the message " + msg.getUniqueId() + " is valid, but it has timed out (" + + (now - _expiration) + "ms ago)"); + if (_onFailure != null) + getContext().jobQueue().addJob(_onFailure); + }else if (_expiration < now + 15*1000) { if (_log.shouldLog(Log.WARN)) _log.warn("Adding a tunnel message that will expire shortly [" + new Date(_expiration) + "]", getAddedBy()); diff --git a/router/java/src/net/i2p/router/tunnelmanager/HandleTunnelCreateMessageJob.java b/router/java/src/net/i2p/router/tunnelmanager/HandleTunnelCreateMessageJob.java index ca7ee53e1..539fedd97 100644 --- a/router/java/src/net/i2p/router/tunnelmanager/HandleTunnelCreateMessageJob.java +++ b/router/java/src/net/i2p/router/tunnelmanager/HandleTunnelCreateMessageJob.java @@ -66,6 +66,7 @@ public class HandleTunnelCreateMessageJob extends JobImpl { info.setConfigurationKey(_message.getConfigurationKey()); info.setEncryptionKey(_message.getTunnelKey()); info.setNextHop(_message.getNextRouter()); + info.setNextHopId(_message.getNextTunnelId()); TunnelSettings settings = new TunnelSettings(getContext()); settings.setBytesPerMinuteAverage(_message.getMaxAvgBytesPerMin()); @@ -129,7 +130,6 @@ public class HandleTunnelCreateMessageJob extends JobImpl { } } - private static final long REPLY_TIMEOUT = 10*1000; private void sendReply(boolean ok) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Sending reply to a tunnel create of id " + _message.getTunnelId() @@ -149,7 +149,7 @@ public class HandleTunnelCreateMessageJob extends JobImpl { // since we don't actually check anything, this is a catch all msg.setStatus(TunnelCreateStatusMessage.STATUS_FAILED_OVERLOADED); } - msg.setMessageExpiration(new Date(getContext().clock().now()+60*1000)); + msg.setMessageExpiration(new Date(getContext().clock().now()+TIMEOUT)); // put that message into a garlic GarlicMessage reply = createReply(msg); @@ -161,7 +161,7 @@ public class HandleTunnelCreateMessageJob extends JobImpl { _message.getReplyTunnel(), (Job)null, (ReplyJob)null, (Job)null, (MessageSelector)null, - REPLY_TIMEOUT, PRIORITY); + TIMEOUT, PRIORITY); getContext().jobQueue().addJob(job); } @@ -189,7 +189,7 @@ public class HandleTunnelCreateMessageJob extends JobImpl { config.setCertificate(new Certificate(Certificate.CERTIFICATE_TYPE_NULL, null)); config.setDeliveryInstructions(instructions); config.setId(getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE)); - config.setExpiration(REPLY_TIMEOUT+getContext().clock().now()); + config.setExpiration(TIMEOUT+getContext().clock().now()); config.setRecipient(null); config.setRequestAck(false); @@ -211,7 +211,7 @@ public class HandleTunnelCreateMessageJob extends JobImpl { replyClove.setCertificate(new Certificate(Certificate.CERTIFICATE_TYPE_NULL, null)); replyClove.setDeliveryInstructions(instructions); - replyClove.setExpiration(REPLY_TIMEOUT+getContext().clock().now()); + replyClove.setExpiration(TIMEOUT+getContext().clock().now()); replyClove.setId(getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE)); replyClove.setPayload(body); replyClove.setRecipient(null); diff --git a/router/java/src/net/i2p/router/tunnelmanager/RequestTunnelJob.java b/router/java/src/net/i2p/router/tunnelmanager/RequestTunnelJob.java index c54643e1d..0f09fee55 100644 --- a/router/java/src/net/i2p/router/tunnelmanager/RequestTunnelJob.java +++ b/router/java/src/net/i2p/router/tunnelmanager/RequestTunnelJob.java @@ -422,7 +422,7 @@ public class RequestTunnelJob extends JobImpl { wrappedTo.setData(rcptKey.getData()); long start = getContext().clock().now(); - GarlicMessage message = GarlicMessageBuilder.buildMessage(getContext(), config, wrappedKey, wrappedTags); + GarlicMessage message = GarlicMessageBuilder.buildMessage(getContext(), config, wrappedKey, wrappedTags, 10); long end = getContext().clock().now(); if ( (end - start) > 1000) { if (_log.shouldLog(Log.WARN))