I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit e65c2e27 authored by zzz's avatar zzz
Browse files

* Session Keys:

      - Don't instantiate unused SessionKeyPersistenceHelper
      - Use TransientSessionKeyManager instead of PersistentSessionKeyManager
      - Add generics to TransientSessionKeyManager to help understand it
      - Change initial session map size to 64 (was 1024)
      - Prepare for per-destination SessionKeyManagers in ElGamalAESEngine
parent b43338bd
No related branches found
No related tags found
No related merge requests found
......@@ -17,9 +17,9 @@ import net.i2p.crypto.ElGamalEngine;
import net.i2p.crypto.HMAC256Generator;
import net.i2p.crypto.HMACGenerator;
import net.i2p.crypto.KeyGenerator;
import net.i2p.crypto.PersistentSessionKeyManager;
import net.i2p.crypto.SHA256Generator;
import net.i2p.crypto.SessionKeyManager;
import net.i2p.crypto.TransientSessionKeyManager;
import net.i2p.data.RoutingKeyGenerator;
import net.i2p.stat.StatManager;
import net.i2p.util.Clock;
......@@ -256,7 +256,8 @@ public class I2PAppContext {
private void initializeSessionKeyManager() {
synchronized (this) {
if (_sessionKeyManager == null)
_sessionKeyManager = new PersistentSessionKeyManager(this);
//_sessionKeyManager = new PersistentSessionKeyManager(this);
_sessionKeyManager = new TransientSessionKeyManager(this);
_sessionKeyManagerInitialized = true;
}
}
......
......@@ -58,12 +58,19 @@ public class ElGamalAESEngine {
new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
}
/**
* Decrypt the message using the given private key using tags from the given key manager.
*/
public byte[] decrypt(byte data[], PrivateKey targetPrivateKey) throws DataFormatException {
return decrypt(data, targetPrivateKey, _context.sessionKeyManager());
}
/**
* Decrypt the message using the given private key. This works according to the
* ElGamal+AES algorithm in the data structure spec.
*
*/
public byte[] decrypt(byte data[], PrivateKey targetPrivateKey) throws DataFormatException {
public byte[] decrypt(byte data[], PrivateKey targetPrivateKey, SessionKeyManager keyManager) throws DataFormatException {
if (data == null) {
if (_log.shouldLog(Log.ERROR)) _log.error("Null data being decrypted?");
return null;
......@@ -76,7 +83,7 @@ public class ElGamalAESEngine {
byte tag[] = new byte[32];
System.arraycopy(data, 0, tag, 0, tag.length);
SessionTag st = new SessionTag(tag);
SessionKey key = _context.sessionKeyManager().consumeTag(st);
SessionKey key = keyManager.consumeTag(st);
SessionKey foundKey = new SessionKey();
foundKey.setData(null);
SessionKey usedKey = new SessionKey();
......@@ -124,11 +131,11 @@ public class ElGamalAESEngine {
if (foundKey.getData() != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Found key: " + foundKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
_context.sessionKeyManager().tagsReceived(foundKey, foundTags);
keyManager.tagsReceived(foundKey, foundTags);
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Used key: " + usedKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
_context.sessionKeyManager().tagsReceived(usedKey, foundTags);
keyManager.tagsReceived(usedKey, foundTags);
}
}
return decrypted;
......
package net.i2p.crypto;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.util.Log;
/**
* Expose the functionality to allow people to write out and read in the
* session key and session tag information via streams. This implementation
* does not write anywhere except where its told.
*
*/
public class PersistentSessionKeyManager extends TransientSessionKeyManager {
private Log _log;
private Object _yk = YKGenerator.class;
/**
* The session key manager should only be constructed and accessed through the
* application context. This constructor should only be used by the
* appropriate application context itself.
*
*/
public PersistentSessionKeyManager(I2PAppContext context) {
super(context);
_log = context.logManager().getLog(PersistentSessionKeyManager.class);
}
private PersistentSessionKeyManager() {
this(null);
}
/**
* Write the session key data to the given stream
*
*/
public void saveState(OutputStream out) throws IOException, DataFormatException {
if (true) return;
Set tagSets = getInboundTagSets();
Set sessions = getOutboundSessions();
if (_log.shouldLog(Log.INFO))
_log.info("Saving state with " + tagSets.size() + " inbound tagSets and "
+ sessions.size() + " outbound sessions");
DataHelper.writeLong(out, 4, tagSets.size());
for (Iterator iter = tagSets.iterator(); iter.hasNext();) {
TagSet ts = (TagSet) iter.next();
writeTagSet(out, ts);
}
DataHelper.writeLong(out, 4, sessions.size());
for (Iterator iter = sessions.iterator(); iter.hasNext();) {
OutboundSession sess = (OutboundSession) iter.next();
writeOutboundSession(out, sess);
}
}
/**
* Load the session key data from the given stream
*
*/
public void loadState(InputStream in) throws IOException, DataFormatException {
int inboundSets = (int) DataHelper.readLong(in, 4);
Set tagSets = new HashSet(inboundSets);
for (int i = 0; i < inboundSets; i++) {
TagSet ts = readTagSet(in);
tagSets.add(ts);
}
int outboundSessions = (int) DataHelper.readLong(in, 4);
Set sessions = new HashSet(outboundSessions);
for (int i = 0; i < outboundSessions; i++) {
OutboundSession sess = readOutboundSession(in);
sessions.add(sess);
}
if (_log.shouldLog(Log.INFO))
_log.info("Loading state with " + tagSets.size() + " inbound tagSets and "
+ sessions.size() + " outbound sessions");
setData(tagSets, sessions);
}
private void writeOutboundSession(OutputStream out, OutboundSession sess) throws IOException, DataFormatException {
sess.getTarget().writeBytes(out);
sess.getCurrentKey().writeBytes(out);
DataHelper.writeDate(out, new Date(sess.getEstablishedDate()));
DataHelper.writeDate(out, new Date(sess.getLastUsedDate()));
List sets = sess.getTagSets();
DataHelper.writeLong(out, 2, sets.size());
for (Iterator iter = sets.iterator(); iter.hasNext();) {
TagSet set = (TagSet) iter.next();
writeTagSet(out, set);
}
}
private void writeTagSet(OutputStream out, TagSet ts) throws IOException, DataFormatException {
ts.getAssociatedKey().writeBytes(out);
DataHelper.writeDate(out, new Date(ts.getDate()));
DataHelper.writeLong(out, 2, ts.getTags().size());
for (Iterator iter = ts.getTags().iterator(); iter.hasNext();) {
SessionTag tag = (SessionTag) iter.next();
out.write(tag.getData());
}
}
private OutboundSession readOutboundSession(InputStream in) throws IOException, DataFormatException {
PublicKey key = new PublicKey();
key.readBytes(in);
SessionKey skey = new SessionKey();
skey.readBytes(in);
Date established = DataHelper.readDate(in);
Date lastUsed = DataHelper.readDate(in);
int tagSets = (int) DataHelper.readLong(in, 2);
ArrayList sets = new ArrayList(tagSets);
for (int i = 0; i < tagSets; i++) {
TagSet ts = readTagSet(in);
sets.add(ts);
}
return new OutboundSession(key, skey, established.getTime(), lastUsed.getTime(), sets);
}
private TagSet readTagSet(InputStream in) throws IOException, DataFormatException {
SessionKey key = new SessionKey();
key.readBytes(in);
Date date = DataHelper.readDate(in);
int numTags = (int) DataHelper.readLong(in, 2);
Set tags = new HashSet(numTags);
for (int i = 0; i < numTags; i++) {
SessionTag tag = new SessionTag();
byte val[] = new byte[SessionTag.BYTE_LENGTH];
int read = DataHelper.read(in, val);
if (read != SessionTag.BYTE_LENGTH)
throw new IOException("Unable to fully read a session tag [" + read + " not " + SessionTag.BYTE_LENGTH
+ ")");
tag.setData(val);
tags.add(tag);
}
TagSet ts = new TagSet(tags, key, _context.clock().now());
ts.setDate(date.getTime());
return ts;
}
public static void main(String args[]) {
I2PAppContext ctx = new I2PAppContext();
Log log = ctx.logManager().getLog(PersistentSessionKeyManager.class);
PersistentSessionKeyManager mgr = (PersistentSessionKeyManager)ctx.sessionKeyManager();
try {
mgr.loadState(new FileInputStream("sessionKeys.dat"));
String state = mgr.renderStatusHTML();
FileOutputStream fos = new FileOutputStream("sessionKeysBeforeExpire.html");
fos.write(state.getBytes());
fos.close();
int expired = mgr.aggressiveExpire();
log.error("Expired: " + expired);
String stateAfter = mgr.renderStatusHTML();
FileOutputStream fos2 = new FileOutputStream("sessionKeysAfterExpire.html");
fos2.write(stateAfter.getBytes());
fos2.close();
} catch (Throwable t) {
log.error("Error loading/storing sessionKeys", t);
}
try {
Thread.sleep(3000);
} catch (Throwable t) { // nop
}
}
}
\ No newline at end of file
......@@ -93,7 +93,7 @@ public class SessionKeyManager {
* method after receiving an ack to a message delivering them)
*
*/
public void tagsDelivered(PublicKey target, SessionKey key, Set sessionTags) { // nop
public void tagsDelivered(PublicKey target, SessionKey key, Set<SessionTag> sessionTags) { // nop
}
/**
......@@ -109,7 +109,7 @@ public class SessionKeyManager {
* Accept the given tags and associate them with the given key for decryption
*
*/
public void tagsReceived(SessionKey key, Set sessionTags) { // nop
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) { // nop
}
/**
......@@ -130,4 +130,4 @@ public class SessionKeyManager {
*/
public void shutdown() { // nop
}
}
\ No newline at end of file
}
......@@ -33,12 +33,12 @@ import net.i2p.util.SimpleTimer;
* out to disk so this should not be considered secure in that sense.
*
*/
class TransientSessionKeyManager extends SessionKeyManager {
public class TransientSessionKeyManager extends SessionKeyManager {
private Log _log;
/** Map allowing us to go from the targeted PublicKey to the OutboundSession used */
private Map _outboundSessions;
private Map<PublicKey, OutboundSession> _outboundSessions;
/** Map allowing us to go from a SessionTag to the containing TagSet */
private Map _inboundTagSets;
private Map<SessionTag, TagSet> _inboundTagSets;
protected I2PAppContext _context;
/**
......@@ -55,6 +55,10 @@ class TransientSessionKeyManager extends SessionKeyManager {
*
*/
public final static long SESSION_LIFETIME_MAX_MS = SESSION_TAG_DURATION_MS + 5 * 60 * 1000;
/**
* a few MB? how about 16MB!
* This is the max size of _inboundTagSets.
*/
public final static int MAX_INBOUND_SESSION_TAGS = 500 * 1000; // this will consume at most a few MB
/**
......@@ -67,7 +71,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
super(context);
_log = context.logManager().getLog(TransientSessionKeyManager.class);
_context = context;
_outboundSessions = new HashMap(1024);
_outboundSessions = new HashMap(64);
_inboundTagSets = new HashMap(1024);
context.statManager().createRateStat("crypto.sessionTagsExpired", "How many tags/sessions are expired?", "Encryption", new long[] { 10*60*1000, 60*60*1000, 3*60*60*1000 });
context.statManager().createRateStat("crypto.sessionTagsRemaining", "How many tags/sessions are remaining after a cleanup?", "Encryption", new long[] { 10*60*1000, 60*60*1000, 3*60*60*1000 });
......@@ -85,28 +89,28 @@ class TransientSessionKeyManager extends SessionKeyManager {
}
/** TagSet */
protected Set getInboundTagSets() {
protected Set<TagSet> getInboundTagSets() {
synchronized (_inboundTagSets) {
return new HashSet(_inboundTagSets.values());
}
}
/** OutboundSession */
protected Set getOutboundSessions() {
protected Set<OutboundSession> getOutboundSessions() {
synchronized (_outboundSessions) {
return new HashSet(_outboundSessions.values());
}
}
protected void setData(Set inboundTagSets, Set outboundSessions) {
protected void setData(Set<TagSet> inboundTagSets, Set<OutboundSession> outboundSessions) {
if (_log.shouldLog(Log.INFO))
_log.info("Loading " + inboundTagSets.size() + " inbound tag sets, and "
+ outboundSessions.size() + " outbound sessions");
Map tagSets = new HashMap(inboundTagSets.size());
for (Iterator iter = inboundTagSets.iterator(); iter.hasNext();) {
TagSet ts = (TagSet) iter.next();
for (Iterator tsIter = ts.getTags().iterator(); tsIter.hasNext();) {
SessionTag tag = (SessionTag) tsIter.next();
Map<SessionTag, TagSet> tagSets = new HashMap(inboundTagSets.size());
for (Iterator<TagSet> iter = inboundTagSets.iterator(); iter.hasNext();) {
TagSet ts = iter.next();
for (Iterator<SessionTag> tsIter = ts.getTags().iterator(); tsIter.hasNext();) {
SessionTag tag = tsIter.next();
tagSets.put(tag, ts);
}
}
......@@ -114,9 +118,9 @@ class TransientSessionKeyManager extends SessionKeyManager {
_inboundTagSets.clear();
_inboundTagSets.putAll(tagSets);
}
Map sessions = new HashMap(outboundSessions.size());
for (Iterator iter = outboundSessions.iterator(); iter.hasNext();) {
OutboundSession sess = (OutboundSession) iter.next();
Map<PublicKey, OutboundSession> sessions = new HashMap(outboundSessions.size());
for (Iterator<OutboundSession> iter = outboundSessions.iterator(); iter.hasNext();) {
OutboundSession sess = iter.next();
sessions.put(sess.getTarget(), sess);
}
synchronized (_outboundSessions) {
......@@ -151,6 +155,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
* Associate a new session key with the specified target. Metrics to determine
* when to expire that key begin with this call.
*
* Unused except in tests?
*/
@Override
public void createSession(PublicKey target, SessionKey key) {
......@@ -159,6 +164,18 @@ class TransientSessionKeyManager extends SessionKeyManager {
addSession(sess);
}
/**
* Same as above but for internal use, returns OutboundSession so we don't have
* to do a subsequent getSession()
*
*/
private OutboundSession createAndReturnSession(PublicKey target, SessionKey key) {
OutboundSession sess = new OutboundSession(target);
sess.setCurrentKey(key);
addSession(sess);
return sess;
}
/**
* Retrieve the next available session tag for identifying the use of the given
* key when communicating with the target. If this returns null, no tags are
......@@ -232,10 +249,8 @@ class TransientSessionKeyManager extends SessionKeyManager {
_log.debug("Tags delivered: " + sessionTags.size() + " for key: " + key.toBase64() + ": " + sessionTags);
}
OutboundSession sess = getSession(target);
if (sess == null) {
createSession(target, key);
sess = getSession(target);
}
if (sess == null)
sess = createAndReturnSession(target, key);
sess.setCurrentKey(key);
TagSet set = new TagSet(sessionTags, key, _context.clock().now());
sess.addTags(set);
......@@ -257,13 +272,13 @@ class TransientSessionKeyManager extends SessionKeyManager {
*
*/
@Override
public void tagsReceived(SessionKey key, Set sessionTags) {
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) {
int overage = 0;
TagSet tagSet = new TagSet(sessionTags, key, _context.clock().now());
TagSet old = null;
SessionTag dupTag = null;
for (Iterator iter = sessionTags.iterator(); iter.hasNext();) {
SessionTag tag = (SessionTag) iter.next();
for (Iterator<SessionTag> iter = sessionTags.iterator(); iter.hasNext();) {
SessionTag tag = iter.next();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Receiving tag " + tag + " for key " + key.toBase64() + " / " + key.toString() + ": tagSet: " + tagSet);
synchronized (_inboundTagSets) {
......@@ -284,12 +299,12 @@ class TransientSessionKeyManager extends SessionKeyManager {
if (old != null) {
// drop both old and tagSet tags
synchronized (_inboundTagSets) {
for (Iterator iter = old.getTags().iterator(); iter.hasNext(); ) {
SessionTag tag = (SessionTag)iter.next();
for (Iterator<SessionTag> iter = old.getTags().iterator(); iter.hasNext(); ) {
SessionTag tag = iter.next();
_inboundTagSets.remove(tag);
}
for (Iterator iter = sessionTags.iterator(); iter.hasNext(); ) {
SessionTag tag = (SessionTag)iter.next();
for (Iterator<SessionTag> iter = sessionTags.iterator(); iter.hasNext(); ) {
SessionTag tag = iter.next();
_inboundTagSets.remove(tag);
}
}
......@@ -326,10 +341,10 @@ class TransientSessionKeyManager extends SessionKeyManager {
int tags = 0;
int toRemove = overage * 2;
_log.log(Log.CRIT, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
List removed = new ArrayList(toRemove);
List<TagSet> removed = new ArrayList(toRemove);
synchronized (_inboundTagSets) {
for (Iterator iter = _inboundTagSets.values().iterator(); iter.hasNext(); ) {
TagSet set = (TagSet)iter.next();
for (Iterator<TagSet> iter = _inboundTagSets.values().iterator(); iter.hasNext(); ) {
TagSet set = iter.next();
int size = set.getTags().size();
if (size > 1000)
absurd++;
......@@ -345,8 +360,8 @@ class TransientSessionKeyManager extends SessionKeyManager {
}
for (int i = 0; i < removed.size(); i++) {
TagSet cur = (TagSet)removed.get(i);
for (Iterator iter = cur.getTags().iterator(); iter.hasNext(); ) {
SessionTag tag = (SessionTag)iter.next();
for (Iterator<SessionTag> iter = cur.getTags().iterator(); iter.hasNext(); ) {
SessionTag tag = iter.next();
_inboundTagSets.remove(tag);
tags++;
}
......@@ -429,9 +444,9 @@ class TransientSessionKeyManager extends SessionKeyManager {
bufSummary = new StringBuffer(1024);
}
synchronized (_inboundTagSets) {
for (Iterator iter = _inboundTagSets.keySet().iterator(); iter.hasNext();) {
SessionTag tag = (SessionTag) iter.next();
TagSet ts = (TagSet) _inboundTagSets.get(tag);
for (Iterator<SessionTag> iter = _inboundTagSets.keySet().iterator(); iter.hasNext();) {
SessionTag tag = iter.next();
TagSet ts = _inboundTagSets.get(tag);
long age = now - ts.getDate();
if (age > SESSION_LIFETIME_MAX_MS) {
//if (ts.getDate() < now - SESSION_LIFETIME_MAX_MS) {
......@@ -455,9 +470,9 @@ class TransientSessionKeyManager extends SessionKeyManager {
//_log.warn("Expiring tags: [" + tagsToDrop + "]");
synchronized (_outboundSessions) {
for (Iterator iter = _outboundSessions.keySet().iterator(); iter.hasNext();) {
PublicKey key = (PublicKey) iter.next();
OutboundSession sess = (OutboundSession) _outboundSessions.get(key);
for (Iterator<PublicKey> iter = _outboundSessions.keySet().iterator(); iter.hasNext();) {
PublicKey key = iter.next();
OutboundSession sess = _outboundSessions.get(key);
removed += sess.expireTags();
if (sess.availableTags() <= 0) {
iter.remove();
......@@ -472,22 +487,22 @@ class TransientSessionKeyManager extends SessionKeyManager {
StringBuffer buf = new StringBuffer(1024);
buf.append("<h2>Inbound sessions</h2>");
buf.append("<table border=\"1\">");
Set inbound = getInboundTagSets();
Map inboundSets = new HashMap(inbound.size());
for (Iterator iter = inbound.iterator(); iter.hasNext();) {
TagSet ts = (TagSet) iter.next();
Set<TagSet> inbound = getInboundTagSets();
Map<SessionKey, Set<TagSet>> inboundSets = new HashMap(inbound.size());
for (Iterator<TagSet> iter = inbound.iterator(); iter.hasNext();) {
TagSet ts = iter.next();
if (!inboundSets.containsKey(ts.getAssociatedKey())) inboundSets.put(ts.getAssociatedKey(), new HashSet());
Set sets = (Set) inboundSets.get(ts.getAssociatedKey());
Set<TagSet> sets = inboundSets.get(ts.getAssociatedKey());
sets.add(ts);
}
for (Iterator iter = inboundSets.keySet().iterator(); iter.hasNext();) {
SessionKey skey = (SessionKey) iter.next();
Set sets = (Set) inboundSets.get(skey);
for (Iterator<SessionKey> iter = inboundSets.keySet().iterator(); iter.hasNext();) {
SessionKey skey = iter.next();
Set<TagSet> sets = inboundSets.get(skey);
buf.append("<tr><td><b>Session key</b>: ").append(skey.toBase64()).append("</td>");
buf.append("<td><b># Sets:</b> ").append(sets.size()).append("</td></tr>");
buf.append("<tr><td colspan=\"2\"><ul>");
for (Iterator siter = sets.iterator(); siter.hasNext();) {
TagSet ts = (TagSet) siter.next();
for (Iterator<TagSet> siter = sets.iterator(); siter.hasNext();) {
TagSet ts = siter.next();
buf.append("<li><b>Received on:</b> ").append(new Date(ts.getDate())).append(" with ")
.append(ts.getTags().size()).append(" tags remaining</li>");
}
......@@ -498,17 +513,17 @@ class TransientSessionKeyManager extends SessionKeyManager {
buf.append("<h2><b>Outbound sessions</b></h2>");
buf.append("<table border=\"1\">");
Set outbound = getOutboundSessions();
for (Iterator iter = outbound.iterator(); iter.hasNext();) {
OutboundSession sess = (OutboundSession) iter.next();
Set<OutboundSession> outbound = getOutboundSessions();
for (Iterator<OutboundSession> iter = outbound.iterator(); iter.hasNext();) {
OutboundSession sess = iter.next();
buf.append("<tr><td><b>Target key:</b> ").append(sess.getTarget().toString()).append("<br />");
buf.append("<b>Established:</b> ").append(new Date(sess.getEstablishedDate())).append("<br />");
buf.append("<b>Last Used:</b> ").append(new Date(sess.getLastUsedDate())).append("<br />");
buf.append("<b># Sets:</b> ").append(sess.getTagSets().size()).append("</td></tr>");
buf.append("<tr><td><b>Session key:</b> ").append(sess.getCurrentKey().toBase64()).append("</td></tr>");
buf.append("<tr><td><ul>");
for (Iterator siter = sess.getTagSets().iterator(); siter.hasNext();) {
TagSet ts = (TagSet) siter.next();
for (Iterator<TagSet> siter = sess.getTagSets().iterator(); siter.hasNext();) {
TagSet ts = siter.next();
buf.append("<li><b>Sent on:</b> ").append(new Date(ts.getDate())).append(" with ").append(
ts.getTags()
.size())
......@@ -526,13 +541,13 @@ class TransientSessionKeyManager extends SessionKeyManager {
private SessionKey _currentKey;
private long _established;
private long _lastUsed;
private List _tagSets;
private List<TagSet> _tagSets;
public OutboundSession(PublicKey target) {
this(target, null, _context.clock().now(), _context.clock().now(), new ArrayList());
}
OutboundSession(PublicKey target, SessionKey curKey, long established, long lastUsed, List tagSets) {
OutboundSession(PublicKey target, SessionKey curKey, long established, long lastUsed, List<TagSet> tagSets) {
_target = target;
_currentKey = curKey;
_established = established;
......@@ -541,7 +556,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
}
/** list of TagSet objects */
List getTagSets() {
List<TagSet> getTagSets() {
synchronized (_tagSets) {
return new ArrayList(_tagSets);
}
......@@ -560,7 +575,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
if (_currentKey != null) {
if (!_currentKey.equals(key)) {
int dropped = 0;
List sets = _tagSets;
List<TagSet> sets = _tagSets;
_tagSets = new ArrayList();
for (int i = 0; i < sets.size(); i++) {
TagSet set = (TagSet) sets.get(i);
......@@ -642,8 +657,8 @@ class TransientSessionKeyManager extends SessionKeyManager {
public long getLastExpirationDate() {
long last = 0;
synchronized (_tagSets) {
for (Iterator iter = _tagSets.iterator(); iter.hasNext();) {
TagSet set = (TagSet) iter.next();
for (Iterator<TagSet> iter = _tagSets.iterator(); iter.hasNext();) {
TagSet set = iter.next();
if ( (set.getDate() > last) && (set.getTags().size() > 0) )
last = set.getDate();
}
......@@ -663,12 +678,12 @@ class TransientSessionKeyManager extends SessionKeyManager {
}
static class TagSet {
private Set _sessionTags;
private Set<SessionTag> _sessionTags;
private SessionKey _key;
private long _date;
private Exception _createdBy;
public TagSet(Set tags, SessionKey key, long date) {
public TagSet(Set<SessionTag> tags, SessionKey key, long date) {
if (key == null) throw new IllegalArgumentException("Missing key");
if (tags == null) throw new IllegalArgumentException("Missing tags");
_sessionTags = tags;
......@@ -692,7 +707,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
}
/** tags still available */
public Set getTags() {
public Set<SessionTag> getTags() {
return _sessionTags;
}
......
......@@ -57,7 +57,7 @@ public class Router {
private RouterInfo _routerInfo;
private long _started;
private boolean _higherVersionSeen;
private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
//private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
private boolean _killVMOnEnd;
private boolean _isAlive;
private int _gracefulExitCode;
......@@ -144,7 +144,7 @@ public class Router {
_higherVersionSeen = false;
_log = _context.logManager().getLog(Router.class);
_log.info("New router created with config file " + _configFilename);
_sessionKeyPersistenceHelper = new SessionKeyPersistenceHelper(_context);
//_sessionKeyPersistenceHelper = new SessionKeyPersistenceHelper(_context);
_killVMOnEnd = true;
_oomListener = new I2PThread.OOMEventListener() {
public void outOfMemory(OutOfMemoryError oom) {
......@@ -261,7 +261,7 @@ public class Router {
SimpleScheduler.getInstance().addPeriodicEvent(new CoalesceStatsEvent(_context), 20*1000);
_context.jobQueue().addJob(new UpdateRoutingKeyModifierJob(_context));
warmupCrypto();
_sessionKeyPersistenceHelper.startup();
//_sessionKeyPersistenceHelper.startup();
//_context.adminManager().startup();
_context.blocklist().startup();
......@@ -813,7 +813,7 @@ public class Router {
try { _context.messageRegistry().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message registry", t); }
try { _context.messageValidator().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message validator", t); }
try { _context.inNetMessagePool().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the inbound net pool", t); }
try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
//try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
RouterContext.listContexts().remove(_context);
dumpStats();
finalShutdown(exitCode);
......
package net.i2p.router;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Writer;
import net.i2p.crypto.PersistentSessionKeyManager;
import net.i2p.crypto.SessionKeyManager;
import net.i2p.util.Log;
/**
* Centralize the sessionKeyManager persistence (rather than leave it to a private
* job in the startup job)
*
*/
public class SessionKeyPersistenceHelper implements Service {
private Log _log;
private RouterContext _context;
private SessionKeyWriterJob _writerJob;
private final static long PERSIST_DELAY = 3*60*1000;
private final static String PROP_SESSION_KEY_FILE = "router.sessionKeys.location";
private final static String DEFAULT_SESSION_KEY_FILE = "sessionKeys.dat";
public SessionKeyPersistenceHelper(RouterContext context) {
_context = context;
_log = _context.logManager().getLog(SessionKeyPersistenceHelper.class);
_writerJob = new SessionKeyWriterJob();
}
public void shutdown() {
writeState();
}
public void restart() {
writeState();
startup();
}
private String getKeyFile() {
String val = _context.router().getConfigSetting(PROP_SESSION_KEY_FILE);
if (val == null)
val = DEFAULT_SESSION_KEY_FILE;
return val;
}
public void startup() {
SessionKeyManager mgr = _context.sessionKeyManager();
if (mgr instanceof PersistentSessionKeyManager) {
PersistentSessionKeyManager manager = (PersistentSessionKeyManager)mgr;
File f = new File(getKeyFile());
if (f.exists()) {
FileInputStream fin = null;
try {
fin = new FileInputStream(f);
manager.loadState(fin);
int expired = manager.aggressiveExpire();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Session keys loaded [not error] with " + expired
+ " sets immediately expired");
} catch (Throwable t) {
_log.error("Error reading in session key data", t);
} finally {
if (fin != null) try { fin.close(); } catch (IOException ioe) {}
}
}
_context.jobQueue().addJob(_writerJob);
}
}
private void writeState() {
if (true) return;
Object o = _context.sessionKeyManager();
if (!(o instanceof PersistentSessionKeyManager)) {
_log.error("Unable to persist the session key state - manager is " + o.getClass().getName());
return;
}
PersistentSessionKeyManager mgr = (PersistentSessionKeyManager)o;
// only need for synchronization is during shutdown()
synchronized (mgr) {
FileOutputStream fos = null;
try {
int expired = mgr.aggressiveExpire();
if (expired > 0) {
_log.info("Agressive expired " + expired + " tag sets");
}
fos = new FileOutputStream(getKeyFile());
mgr.saveState(fos);
fos.flush();
_log.debug("Session keys written");
} catch (Throwable t) {
_log.debug("Error writing session key state", t);
} finally {
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
}
}
}
public void renderStatusHTML(Writer out) { }
private class SessionKeyWriterJob extends JobImpl {
public SessionKeyWriterJob() {
super(SessionKeyPersistenceHelper.this._context);
getTiming().setStartAfter(PERSIST_DELAY);
}
public String getName() { return "Write Session Keys"; }
public void runJob() {
writeState();
requeue(PERSIST_DELAY);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment