use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class TransientDataStore method put.
/**
* @param data must be validated before here
* @return success
*/
public boolean put(Hash key, DatabaseEntry data) {
if (data == null)
return false;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Storing key " + key);
DatabaseEntry old = _data.putIfAbsent(key, data);
boolean rv = false;
if (data.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
// Don't do this here so we don't reset it at router startup;
// the StoreMessageJob calls this
// _context.profileManager().heardAbout(key);
RouterInfo ri = (RouterInfo) data;
if (old != null) {
RouterInfo ori = (RouterInfo) old;
if (ri.getPublished() < ori.getPublished()) {
if (_log.shouldLog(Log.INFO))
_log.info("Almost clobbered an old router! " + key + ": [old published on " + new Date(ori.getPublished()) + " new on " + new Date(ri.getPublished()) + ']');
} else if (ri.getPublished() == ori.getPublished()) {
if (_log.shouldLog(Log.INFO))
_log.info("Duplicate " + key);
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Updated the old router for " + key + ": [old published on " + new Date(ori.getPublished()) + " new on " + new Date(ri.getPublished()) + ']');
_data.put(key, data);
rv = true;
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("New router for " + key + ": published on " + new Date(ri.getPublished()));
rv = true;
}
} else if (data.getType() == DatabaseEntry.KEY_TYPE_LEASESET) {
LeaseSet ls = (LeaseSet) data;
if (old != null) {
LeaseSet ols = (LeaseSet) old;
if (ls.getEarliestLeaseDate() < ols.getEarliestLeaseDate()) {
if (_log.shouldLog(Log.INFO))
_log.info("Almost clobbered an old leaseSet! " + key + ": [old expires " + new Date(ols.getEarliestLeaseDate()) + " new on " + new Date(ls.getEarliestLeaseDate()) + ']');
} else if (ls.getEarliestLeaseDate() == ols.getEarliestLeaseDate()) {
if (_log.shouldLog(Log.INFO))
_log.info("Duplicate " + key);
} else {
if (_log.shouldLog(Log.INFO)) {
_log.info("Updated old leaseSet " + key + ": [old expires " + new Date(ols.getEarliestLeaseDate()) + " new on " + new Date(ls.getEarliestLeaseDate()) + ']');
if (_log.shouldLog(Log.DEBUG))
_log.debug("RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
}
_data.put(key, data);
rv = true;
}
} else {
if (_log.shouldLog(Log.INFO)) {
_log.info("New leaseset for " + key + ": expires " + new Date(ls.getEarliestLeaseDate()));
if (_log.shouldLog(Log.DEBUG))
_log.debug("RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
}
rv = true;
}
}
return rv;
}
use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class LocalClientMessageEventListener method startCreateSessionJob.
/**
* Immediately send a fake leaseset
*/
@Override
protected void startCreateSessionJob(SessionConfig config) {
long exp = _context.clock().now() + 10 * 60 * 1000;
LeaseSet ls = new LeaseSet();
Lease lease = new Lease();
lease.setGateway(Hash.FAKE_HASH);
TunnelId id = new TunnelId(1);
lease.setTunnelId(id);
Date date = new Date(exp);
lease.setEndDate(date);
ls.addLease(lease);
_runner.requestLeaseSet(config.getDestination().calculateHash(), ls, exp, null, null);
}
use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class RequestVariableLeaseSetMessageHandler method handleMessage.
@Override
public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Handle message " + message);
RequestVariableLeaseSetMessage msg = (RequestVariableLeaseSetMessage) message;
LeaseSet leaseSet = new LeaseSet();
for (int i = 0; i < msg.getEndpoints(); i++) {
leaseSet.addLease(msg.getEndpoint(i));
}
signLeaseSet(leaseSet, session);
}
use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class RequestLeaseSetJob method runJob.
public void runJob() {
if (_runner.isDead())
return;
LeaseSet requested = _requestState.getRequested();
long endTime = requested.getEarliestLeaseDate();
// Add a small number of ms (0 to MAX_FUDGE) that increases as we approach the expire time.
// Since the earliest date functions as a version number,
// this will force the floodfill to flood each new version;
// otherwise it won't if the earliest time hasn't changed.
long fudge = MAX_FUDGE - ((endTime - getContext().clock().now()) / (10 * 60 * 1000 / MAX_FUDGE));
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Adding fudge " + fudge);
endTime += fudge;
SessionId id = _runner.getSessionId(requested.getDestination().calculateHash());
if (id == null) {
_runner.failLeaseRequest(_requestState);
return;
}
I2CPMessage msg;
if (getContext().getProperty(PROP_VARIABLE, DFLT_VARIABLE) && (_runner instanceof QueuedClientConnectionRunner || RequestVariableLeaseSetMessage.isSupported(_runner.getClientVersion()))) {
// new style - leases will have individual expirations
RequestVariableLeaseSetMessage rmsg = new RequestVariableLeaseSetMessage();
rmsg.setSessionId(id);
for (int i = 0; i < requested.getLeaseCount(); i++) {
Lease lease = requested.getLease(i);
if (lease.getEndDate().getTime() < endTime) {
// don't modify old object, we don't know where it came from
Lease nl = new Lease();
nl.setGateway(lease.getGateway());
nl.setTunnelId(lease.getTunnelId());
nl.setEndDate(new Date(endTime));
lease = nl;
// if (_log.shouldLog(Log.INFO))
// _log.info("Adjusted end date to " + endTime + " for " + lease);
}
rmsg.addEndpoint(lease);
}
msg = rmsg;
} else {
// old style - all leases will have same expiration
RequestLeaseSetMessage rmsg = new RequestLeaseSetMessage();
Date end = new Date(endTime);
rmsg.setEndDate(end);
rmsg.setSessionId(id);
for (int i = 0; i < requested.getLeaseCount(); i++) {
Lease lease = requested.getLease(i);
rmsg.addEndpoint(lease.getGateway(), lease.getTunnelId());
}
msg = rmsg;
}
try {
// _runner.setLeaseRequest(state);
_runner.doSend(msg);
getContext().jobQueue().addJob(new CheckLeaseRequestStatus());
} catch (I2CPMessageException ime) {
getContext().statManager().addRateData("client.requestLeaseSetDropped", 1);
_log.error("Error sending I2CP message requesting the lease set", ime);
_requestState.setIsSuccessful(false);
if (_requestState.getOnFailed() != null)
RequestLeaseSetJob.this.getContext().jobQueue().addJob(_requestState.getOnFailed());
_runner.failLeaseRequest(_requestState);
// Don't disconnect, the tunnel will retry
// _runner.disconnectClient("I2CP error requesting leaseSet");
}
}
use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class OutboundClientMessageOneShotJob method send.
/**
* Send the message to the specified tunnel by creating a new garlic message containing
* the (already created) payload clove as well as a new delivery status message. This garlic
* message is sent out one of our tunnels, destined for the lease (tunnel+router) specified, and the delivery
* status message is targetting one of our free inbound tunnels as well. We use a new
* reply selector to keep an eye out for that delivery status message's token
*/
private void send() {
synchronized (this) {
if (_finished != Result.NONE) {
if (_log.shouldLog(Log.WARN))
_log.warn(OutboundClientMessageOneShotJob.this.getJobId() + ": SEND-AFTER-" + _finished);
return;
}
}
long now = getContext().clock().now();
if (now >= _overallExpiration) {
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED);
return;
}
_outTunnel = selectOutboundTunnel(_to);
if (_outTunnel == null) {
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Could not find any outbound tunnels to send the payload through... this might take a while");
getContext().statManager().addRateData("client.dispatchNoTunnels", now - _start);
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_NO_TUNNELS);
return;
}
// boolean wantACK = _wantACK || existingTags <= 30 || getContext().random().nextInt(100) < 5;
// what's the point of 5% random? possible improvements or replacements:
// DONE (getNextLease() is called before this): wantACK if we changed their inbound lease (getNextLease() sets _wantACK)
// DONE (selectOutboundTunnel() moved above here): wantACK if we changed our outbound tunnel (selectOutboundTunnel() sets _wantACK)
// DONE (added new cache): wantACK if we haven't in last 1m (requires a new static cache probably)
Long lastReplyRequestSent = _cache.lastReplyRequestCache.get(_hashPair);
boolean shouldRequestReply = lastReplyRequestSent == null || lastReplyRequestSent.longValue() < now - REPLY_REQUEST_INTERVAL;
int sendFlags = _clientMessage.getFlags();
// Per-message flag > 0 overrides per-session option
int tagsRequired = SendMessageOptions.getTagThreshold(sendFlags);
boolean wantACK = _wantACK || shouldRequestReply || GarlicMessageBuilder.needsTags(getContext(), _leaseSet.getEncryptionKey(), _from.calculateHash(), tagsRequired);
LeaseSet replyLeaseSet;
// Per-message flag == false overrides session option which is default true
String allow = _clientMessage.getSenderConfig().getOptions().getProperty(BUNDLE_REPLY_LEASESET);
boolean allowLeaseBundle = SendMessageOptions.getSendLeaseSet(sendFlags) && (allow == null || Boolean.parseBoolean(allow));
if (allowLeaseBundle) {
// If we want an ack, bundle a leaseSet...
// replyLeaseSet = getReplyLeaseSet(wantACK);
// Only when necessary. We don't need to force.
// ACKs find their own way back, they don't need a leaseset.
replyLeaseSet = getReplyLeaseSet(false);
// ... and vice versa (so we know he got it)
if (replyLeaseSet != null)
wantACK = true;
} else {
replyLeaseSet = null;
}
long token;
if (wantACK) {
_cache.lastReplyRequestCache.put(_hashPair, Long.valueOf(now));
token = getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE);
_inTunnel = selectInboundTunnel();
} else {
token = -1;
}
PayloadGarlicConfig clove = buildClove();
if (clove == null) {
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION);
return;
}
// if (_log.shouldLog(Log.DEBUG))
// _log.debug(getJobId() + ": Clove built to " + _toString);
PublicKey key = _leaseSet.getEncryptionKey();
SessionKey sessKey = new SessionKey();
Set<SessionTag> tags = new HashSet<SessionTag>();
// Per-message flag > 0 overrides per-session option
int tagsToSend = SendMessageOptions.getTagsToSend(sendFlags);
GarlicMessage msg = OutboundClientMessageJobHelper.createGarlicMessage(getContext(), token, _overallExpiration, key, clove, _from.calculateHash(), _to, _inTunnel, tagsToSend, tagsRequired, sessKey, tags, wantACK, replyLeaseSet);
if (msg == null) {
// we dont receive the reply? hmm...)
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Unable to create the garlic message (no tunnels left or too lagged) to " + _toString);
getContext().statManager().addRateData("client.dispatchNoTunnels", now - _start);
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_NO_TUNNELS);
return;
}
// if (_log.shouldLog(Log.DEBUG))
// _log.debug(getJobId() + ": send() - token expected " + token + " to " + _toString);
SendSuccessJob onReply = null;
SendTimeoutJob onFail = null;
ReplySelector selector = null;
if (wantACK) {
TagSetHandle tsh = null;
if (!tags.isEmpty()) {
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
if (skm != null)
tsh = skm.tagsDelivered(_leaseSet.getEncryptionKey(), sessKey, tags);
}
onReply = new SendSuccessJob(getContext(), sessKey, tsh);
onFail = new SendTimeoutJob(getContext(), sessKey, tsh);
long expiration = Math.max(_overallExpiration, _start + REPLY_TIMEOUT_MS_MIN);
selector = new ReplySelector(token, expiration);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Sending msg out " + _outTunnel.getSendTunnelId(0) + " to " + _toString + " at " + _lease.getTunnelId() + " on " + _lease.getGateway());
DispatchJob dispatchJob = new DispatchJob(getContext(), msg, selector, onReply, onFail);
// if (false) // dispatch may take 100+ms, so toss it in its own job
// getContext().jobQueue().addJob(dispatchJob);
// else
dispatchJob.runJob();
getContext().statManager().addRateData("client.dispatchPrepareTime", now - _start);
if (!wantACK)
getContext().statManager().addRateData("client.dispatchNoACK", 1);
}
Aggregations