forked from I2P_Developers/i2p.i2p
* 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
This commit is contained in:
@ -17,9 +17,9 @@ import net.i2p.crypto.ElGamalEngine;
|
|||||||
import net.i2p.crypto.HMAC256Generator;
|
import net.i2p.crypto.HMAC256Generator;
|
||||||
import net.i2p.crypto.HMACGenerator;
|
import net.i2p.crypto.HMACGenerator;
|
||||||
import net.i2p.crypto.KeyGenerator;
|
import net.i2p.crypto.KeyGenerator;
|
||||||
import net.i2p.crypto.PersistentSessionKeyManager;
|
|
||||||
import net.i2p.crypto.SHA256Generator;
|
import net.i2p.crypto.SHA256Generator;
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
|
import net.i2p.crypto.TransientSessionKeyManager;
|
||||||
import net.i2p.data.RoutingKeyGenerator;
|
import net.i2p.data.RoutingKeyGenerator;
|
||||||
import net.i2p.stat.StatManager;
|
import net.i2p.stat.StatManager;
|
||||||
import net.i2p.util.Clock;
|
import net.i2p.util.Clock;
|
||||||
@ -256,7 +256,8 @@ public class I2PAppContext {
|
|||||||
private void initializeSessionKeyManager() {
|
private void initializeSessionKeyManager() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (_sessionKeyManager == null)
|
if (_sessionKeyManager == null)
|
||||||
_sessionKeyManager = new PersistentSessionKeyManager(this);
|
//_sessionKeyManager = new PersistentSessionKeyManager(this);
|
||||||
|
_sessionKeyManager = new TransientSessionKeyManager(this);
|
||||||
_sessionKeyManagerInitialized = true;
|
_sessionKeyManagerInitialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,12 +58,19 @@ public class ElGamalAESEngine {
|
|||||||
new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
|
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
|
* Decrypt the message using the given private key. This works according to the
|
||||||
* ElGamal+AES algorithm in the data structure spec.
|
* 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 (data == null) {
|
||||||
if (_log.shouldLog(Log.ERROR)) _log.error("Null data being decrypted?");
|
if (_log.shouldLog(Log.ERROR)) _log.error("Null data being decrypted?");
|
||||||
return null;
|
return null;
|
||||||
@ -76,7 +83,7 @@ public class ElGamalAESEngine {
|
|||||||
byte tag[] = new byte[32];
|
byte tag[] = new byte[32];
|
||||||
System.arraycopy(data, 0, tag, 0, tag.length);
|
System.arraycopy(data, 0, tag, 0, tag.length);
|
||||||
SessionTag st = new SessionTag(tag);
|
SessionTag st = new SessionTag(tag);
|
||||||
SessionKey key = _context.sessionKeyManager().consumeTag(st);
|
SessionKey key = keyManager.consumeTag(st);
|
||||||
SessionKey foundKey = new SessionKey();
|
SessionKey foundKey = new SessionKey();
|
||||||
foundKey.setData(null);
|
foundKey.setData(null);
|
||||||
SessionKey usedKey = new SessionKey();
|
SessionKey usedKey = new SessionKey();
|
||||||
@ -124,11 +131,11 @@ public class ElGamalAESEngine {
|
|||||||
if (foundKey.getData() != null) {
|
if (foundKey.getData() != null) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Found key: " + foundKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
|
_log.debug("Found key: " + foundKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
|
||||||
_context.sessionKeyManager().tagsReceived(foundKey, foundTags);
|
keyManager.tagsReceived(foundKey, foundTags);
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Used key: " + usedKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
|
_log.debug("Used key: " + usedKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
|
||||||
_context.sessionKeyManager().tagsReceived(usedKey, foundTags);
|
keyManager.tagsReceived(usedKey, foundTags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return decrypted;
|
return decrypted;
|
||||||
|
@ -1,190 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -93,7 +93,7 @@ public class SessionKeyManager {
|
|||||||
* method after receiving an ack to a message delivering them)
|
* 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
|
* 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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,12 +33,12 @@ import net.i2p.util.SimpleTimer;
|
|||||||
* out to disk so this should not be considered secure in that sense.
|
* 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;
|
private Log _log;
|
||||||
/** Map allowing us to go from the targeted PublicKey to the OutboundSession used */
|
/** 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 */
|
/** Map allowing us to go from a SessionTag to the containing TagSet */
|
||||||
private Map _inboundTagSets;
|
private Map<SessionTag, TagSet> _inboundTagSets;
|
||||||
protected I2PAppContext _context;
|
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;
|
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
|
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);
|
super(context);
|
||||||
_log = context.logManager().getLog(TransientSessionKeyManager.class);
|
_log = context.logManager().getLog(TransientSessionKeyManager.class);
|
||||||
_context = context;
|
_context = context;
|
||||||
_outboundSessions = new HashMap(1024);
|
_outboundSessions = new HashMap(64);
|
||||||
_inboundTagSets = new HashMap(1024);
|
_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.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 });
|
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 */
|
/** TagSet */
|
||||||
protected Set getInboundTagSets() {
|
protected Set<TagSet> getInboundTagSets() {
|
||||||
synchronized (_inboundTagSets) {
|
synchronized (_inboundTagSets) {
|
||||||
return new HashSet(_inboundTagSets.values());
|
return new HashSet(_inboundTagSets.values());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** OutboundSession */
|
/** OutboundSession */
|
||||||
protected Set getOutboundSessions() {
|
protected Set<OutboundSession> getOutboundSessions() {
|
||||||
synchronized (_outboundSessions) {
|
synchronized (_outboundSessions) {
|
||||||
return new HashSet(_outboundSessions.values());
|
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))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Loading " + inboundTagSets.size() + " inbound tag sets, and "
|
_log.info("Loading " + inboundTagSets.size() + " inbound tag sets, and "
|
||||||
+ outboundSessions.size() + " outbound sessions");
|
+ outboundSessions.size() + " outbound sessions");
|
||||||
Map tagSets = new HashMap(inboundTagSets.size());
|
Map<SessionTag, TagSet> tagSets = new HashMap(inboundTagSets.size());
|
||||||
for (Iterator iter = inboundTagSets.iterator(); iter.hasNext();) {
|
for (Iterator<TagSet> iter = inboundTagSets.iterator(); iter.hasNext();) {
|
||||||
TagSet ts = (TagSet) iter.next();
|
TagSet ts = iter.next();
|
||||||
for (Iterator tsIter = ts.getTags().iterator(); tsIter.hasNext();) {
|
for (Iterator<SessionTag> tsIter = ts.getTags().iterator(); tsIter.hasNext();) {
|
||||||
SessionTag tag = (SessionTag) tsIter.next();
|
SessionTag tag = tsIter.next();
|
||||||
tagSets.put(tag, ts);
|
tagSets.put(tag, ts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,9 +118,9 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
_inboundTagSets.clear();
|
_inboundTagSets.clear();
|
||||||
_inboundTagSets.putAll(tagSets);
|
_inboundTagSets.putAll(tagSets);
|
||||||
}
|
}
|
||||||
Map sessions = new HashMap(outboundSessions.size());
|
Map<PublicKey, OutboundSession> sessions = new HashMap(outboundSessions.size());
|
||||||
for (Iterator iter = outboundSessions.iterator(); iter.hasNext();) {
|
for (Iterator<OutboundSession> iter = outboundSessions.iterator(); iter.hasNext();) {
|
||||||
OutboundSession sess = (OutboundSession) iter.next();
|
OutboundSession sess = iter.next();
|
||||||
sessions.put(sess.getTarget(), sess);
|
sessions.put(sess.getTarget(), sess);
|
||||||
}
|
}
|
||||||
synchronized (_outboundSessions) {
|
synchronized (_outboundSessions) {
|
||||||
@ -151,6 +155,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
* Associate a new session key with the specified target. Metrics to determine
|
* Associate a new session key with the specified target. Metrics to determine
|
||||||
* when to expire that key begin with this call.
|
* when to expire that key begin with this call.
|
||||||
*
|
*
|
||||||
|
* Unused except in tests?
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void createSession(PublicKey target, SessionKey key) {
|
public void createSession(PublicKey target, SessionKey key) {
|
||||||
@ -159,6 +164,18 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
addSession(sess);
|
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
|
* 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
|
* 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);
|
_log.debug("Tags delivered: " + sessionTags.size() + " for key: " + key.toBase64() + ": " + sessionTags);
|
||||||
}
|
}
|
||||||
OutboundSession sess = getSession(target);
|
OutboundSession sess = getSession(target);
|
||||||
if (sess == null) {
|
if (sess == null)
|
||||||
createSession(target, key);
|
sess = createAndReturnSession(target, key);
|
||||||
sess = getSession(target);
|
|
||||||
}
|
|
||||||
sess.setCurrentKey(key);
|
sess.setCurrentKey(key);
|
||||||
TagSet set = new TagSet(sessionTags, key, _context.clock().now());
|
TagSet set = new TagSet(sessionTags, key, _context.clock().now());
|
||||||
sess.addTags(set);
|
sess.addTags(set);
|
||||||
@ -257,13 +272,13 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void tagsReceived(SessionKey key, Set sessionTags) {
|
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) {
|
||||||
int overage = 0;
|
int overage = 0;
|
||||||
TagSet tagSet = new TagSet(sessionTags, key, _context.clock().now());
|
TagSet tagSet = new TagSet(sessionTags, key, _context.clock().now());
|
||||||
TagSet old = null;
|
TagSet old = null;
|
||||||
SessionTag dupTag = null;
|
SessionTag dupTag = null;
|
||||||
for (Iterator iter = sessionTags.iterator(); iter.hasNext();) {
|
for (Iterator<SessionTag> iter = sessionTags.iterator(); iter.hasNext();) {
|
||||||
SessionTag tag = (SessionTag) iter.next();
|
SessionTag tag = iter.next();
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Receiving tag " + tag + " for key " + key.toBase64() + " / " + key.toString() + ": tagSet: " + tagSet);
|
_log.debug("Receiving tag " + tag + " for key " + key.toBase64() + " / " + key.toString() + ": tagSet: " + tagSet);
|
||||||
synchronized (_inboundTagSets) {
|
synchronized (_inboundTagSets) {
|
||||||
@ -284,12 +299,12 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
if (old != null) {
|
if (old != null) {
|
||||||
// drop both old and tagSet tags
|
// drop both old and tagSet tags
|
||||||
synchronized (_inboundTagSets) {
|
synchronized (_inboundTagSets) {
|
||||||
for (Iterator iter = old.getTags().iterator(); iter.hasNext(); ) {
|
for (Iterator<SessionTag> iter = old.getTags().iterator(); iter.hasNext(); ) {
|
||||||
SessionTag tag = (SessionTag)iter.next();
|
SessionTag tag = iter.next();
|
||||||
_inboundTagSets.remove(tag);
|
_inboundTagSets.remove(tag);
|
||||||
}
|
}
|
||||||
for (Iterator iter = sessionTags.iterator(); iter.hasNext(); ) {
|
for (Iterator<SessionTag> iter = sessionTags.iterator(); iter.hasNext(); ) {
|
||||||
SessionTag tag = (SessionTag)iter.next();
|
SessionTag tag = iter.next();
|
||||||
_inboundTagSets.remove(tag);
|
_inboundTagSets.remove(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,10 +341,10 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
int tags = 0;
|
int tags = 0;
|
||||||
int toRemove = overage * 2;
|
int toRemove = overage * 2;
|
||||||
_log.log(Log.CRIT, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
|
_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) {
|
synchronized (_inboundTagSets) {
|
||||||
for (Iterator iter = _inboundTagSets.values().iterator(); iter.hasNext(); ) {
|
for (Iterator<TagSet> iter = _inboundTagSets.values().iterator(); iter.hasNext(); ) {
|
||||||
TagSet set = (TagSet)iter.next();
|
TagSet set = iter.next();
|
||||||
int size = set.getTags().size();
|
int size = set.getTags().size();
|
||||||
if (size > 1000)
|
if (size > 1000)
|
||||||
absurd++;
|
absurd++;
|
||||||
@ -345,8 +360,8 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < removed.size(); i++) {
|
for (int i = 0; i < removed.size(); i++) {
|
||||||
TagSet cur = (TagSet)removed.get(i);
|
TagSet cur = (TagSet)removed.get(i);
|
||||||
for (Iterator iter = cur.getTags().iterator(); iter.hasNext(); ) {
|
for (Iterator<SessionTag> iter = cur.getTags().iterator(); iter.hasNext(); ) {
|
||||||
SessionTag tag = (SessionTag)iter.next();
|
SessionTag tag = iter.next();
|
||||||
_inboundTagSets.remove(tag);
|
_inboundTagSets.remove(tag);
|
||||||
tags++;
|
tags++;
|
||||||
}
|
}
|
||||||
@ -429,9 +444,9 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
bufSummary = new StringBuffer(1024);
|
bufSummary = new StringBuffer(1024);
|
||||||
}
|
}
|
||||||
synchronized (_inboundTagSets) {
|
synchronized (_inboundTagSets) {
|
||||||
for (Iterator iter = _inboundTagSets.keySet().iterator(); iter.hasNext();) {
|
for (Iterator<SessionTag> iter = _inboundTagSets.keySet().iterator(); iter.hasNext();) {
|
||||||
SessionTag tag = (SessionTag) iter.next();
|
SessionTag tag = iter.next();
|
||||||
TagSet ts = (TagSet) _inboundTagSets.get(tag);
|
TagSet ts = _inboundTagSets.get(tag);
|
||||||
long age = now - ts.getDate();
|
long age = now - ts.getDate();
|
||||||
if (age > SESSION_LIFETIME_MAX_MS) {
|
if (age > SESSION_LIFETIME_MAX_MS) {
|
||||||
//if (ts.getDate() < now - 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 + "]");
|
//_log.warn("Expiring tags: [" + tagsToDrop + "]");
|
||||||
|
|
||||||
synchronized (_outboundSessions) {
|
synchronized (_outboundSessions) {
|
||||||
for (Iterator iter = _outboundSessions.keySet().iterator(); iter.hasNext();) {
|
for (Iterator<PublicKey> iter = _outboundSessions.keySet().iterator(); iter.hasNext();) {
|
||||||
PublicKey key = (PublicKey) iter.next();
|
PublicKey key = iter.next();
|
||||||
OutboundSession sess = (OutboundSession) _outboundSessions.get(key);
|
OutboundSession sess = _outboundSessions.get(key);
|
||||||
removed += sess.expireTags();
|
removed += sess.expireTags();
|
||||||
if (sess.availableTags() <= 0) {
|
if (sess.availableTags() <= 0) {
|
||||||
iter.remove();
|
iter.remove();
|
||||||
@ -472,22 +487,22 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
StringBuffer buf = new StringBuffer(1024);
|
StringBuffer buf = new StringBuffer(1024);
|
||||||
buf.append("<h2>Inbound sessions</h2>");
|
buf.append("<h2>Inbound sessions</h2>");
|
||||||
buf.append("<table border=\"1\">");
|
buf.append("<table border=\"1\">");
|
||||||
Set inbound = getInboundTagSets();
|
Set<TagSet> inbound = getInboundTagSets();
|
||||||
Map inboundSets = new HashMap(inbound.size());
|
Map<SessionKey, Set<TagSet>> inboundSets = new HashMap(inbound.size());
|
||||||
for (Iterator iter = inbound.iterator(); iter.hasNext();) {
|
for (Iterator<TagSet> iter = inbound.iterator(); iter.hasNext();) {
|
||||||
TagSet ts = (TagSet) iter.next();
|
TagSet ts = iter.next();
|
||||||
if (!inboundSets.containsKey(ts.getAssociatedKey())) inboundSets.put(ts.getAssociatedKey(), new HashSet());
|
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);
|
sets.add(ts);
|
||||||
}
|
}
|
||||||
for (Iterator iter = inboundSets.keySet().iterator(); iter.hasNext();) {
|
for (Iterator<SessionKey> iter = inboundSets.keySet().iterator(); iter.hasNext();) {
|
||||||
SessionKey skey = (SessionKey) iter.next();
|
SessionKey skey = iter.next();
|
||||||
Set sets = (Set) inboundSets.get(skey);
|
Set<TagSet> sets = inboundSets.get(skey);
|
||||||
buf.append("<tr><td><b>Session key</b>: ").append(skey.toBase64()).append("</td>");
|
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("<td><b># Sets:</b> ").append(sets.size()).append("</td></tr>");
|
||||||
buf.append("<tr><td colspan=\"2\"><ul>");
|
buf.append("<tr><td colspan=\"2\"><ul>");
|
||||||
for (Iterator siter = sets.iterator(); siter.hasNext();) {
|
for (Iterator<TagSet> siter = sets.iterator(); siter.hasNext();) {
|
||||||
TagSet ts = (TagSet) siter.next();
|
TagSet ts = siter.next();
|
||||||
buf.append("<li><b>Received on:</b> ").append(new Date(ts.getDate())).append(" with ")
|
buf.append("<li><b>Received on:</b> ").append(new Date(ts.getDate())).append(" with ")
|
||||||
.append(ts.getTags().size()).append(" tags remaining</li>");
|
.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("<h2><b>Outbound sessions</b></h2>");
|
||||||
|
|
||||||
buf.append("<table border=\"1\">");
|
buf.append("<table border=\"1\">");
|
||||||
Set outbound = getOutboundSessions();
|
Set<OutboundSession> outbound = getOutboundSessions();
|
||||||
for (Iterator iter = outbound.iterator(); iter.hasNext();) {
|
for (Iterator<OutboundSession> iter = outbound.iterator(); iter.hasNext();) {
|
||||||
OutboundSession sess = (OutboundSession) iter.next();
|
OutboundSession sess = iter.next();
|
||||||
buf.append("<tr><td><b>Target key:</b> ").append(sess.getTarget().toString()).append("<br />");
|
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>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>Last Used:</b> ").append(new Date(sess.getLastUsedDate())).append("<br />");
|
||||||
buf.append("<b># Sets:</b> ").append(sess.getTagSets().size()).append("</td></tr>");
|
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><b>Session key:</b> ").append(sess.getCurrentKey().toBase64()).append("</td></tr>");
|
||||||
buf.append("<tr><td><ul>");
|
buf.append("<tr><td><ul>");
|
||||||
for (Iterator siter = sess.getTagSets().iterator(); siter.hasNext();) {
|
for (Iterator<TagSet> siter = sess.getTagSets().iterator(); siter.hasNext();) {
|
||||||
TagSet ts = (TagSet) siter.next();
|
TagSet ts = siter.next();
|
||||||
buf.append("<li><b>Sent on:</b> ").append(new Date(ts.getDate())).append(" with ").append(
|
buf.append("<li><b>Sent on:</b> ").append(new Date(ts.getDate())).append(" with ").append(
|
||||||
ts.getTags()
|
ts.getTags()
|
||||||
.size())
|
.size())
|
||||||
@ -526,13 +541,13 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
private SessionKey _currentKey;
|
private SessionKey _currentKey;
|
||||||
private long _established;
|
private long _established;
|
||||||
private long _lastUsed;
|
private long _lastUsed;
|
||||||
private List _tagSets;
|
private List<TagSet> _tagSets;
|
||||||
|
|
||||||
public OutboundSession(PublicKey target) {
|
public OutboundSession(PublicKey target) {
|
||||||
this(target, null, _context.clock().now(), _context.clock().now(), new ArrayList());
|
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;
|
_target = target;
|
||||||
_currentKey = curKey;
|
_currentKey = curKey;
|
||||||
_established = established;
|
_established = established;
|
||||||
@ -541,7 +556,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** list of TagSet objects */
|
/** list of TagSet objects */
|
||||||
List getTagSets() {
|
List<TagSet> getTagSets() {
|
||||||
synchronized (_tagSets) {
|
synchronized (_tagSets) {
|
||||||
return new ArrayList(_tagSets);
|
return new ArrayList(_tagSets);
|
||||||
}
|
}
|
||||||
@ -560,7 +575,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
if (_currentKey != null) {
|
if (_currentKey != null) {
|
||||||
if (!_currentKey.equals(key)) {
|
if (!_currentKey.equals(key)) {
|
||||||
int dropped = 0;
|
int dropped = 0;
|
||||||
List sets = _tagSets;
|
List<TagSet> sets = _tagSets;
|
||||||
_tagSets = new ArrayList();
|
_tagSets = new ArrayList();
|
||||||
for (int i = 0; i < sets.size(); i++) {
|
for (int i = 0; i < sets.size(); i++) {
|
||||||
TagSet set = (TagSet) sets.get(i);
|
TagSet set = (TagSet) sets.get(i);
|
||||||
@ -642,8 +657,8 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
public long getLastExpirationDate() {
|
public long getLastExpirationDate() {
|
||||||
long last = 0;
|
long last = 0;
|
||||||
synchronized (_tagSets) {
|
synchronized (_tagSets) {
|
||||||
for (Iterator iter = _tagSets.iterator(); iter.hasNext();) {
|
for (Iterator<TagSet> iter = _tagSets.iterator(); iter.hasNext();) {
|
||||||
TagSet set = (TagSet) iter.next();
|
TagSet set = iter.next();
|
||||||
if ( (set.getDate() > last) && (set.getTags().size() > 0) )
|
if ( (set.getDate() > last) && (set.getTags().size() > 0) )
|
||||||
last = set.getDate();
|
last = set.getDate();
|
||||||
}
|
}
|
||||||
@ -663,12 +678,12 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class TagSet {
|
static class TagSet {
|
||||||
private Set _sessionTags;
|
private Set<SessionTag> _sessionTags;
|
||||||
private SessionKey _key;
|
private SessionKey _key;
|
||||||
private long _date;
|
private long _date;
|
||||||
private Exception _createdBy;
|
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 (key == null) throw new IllegalArgumentException("Missing key");
|
||||||
if (tags == null) throw new IllegalArgumentException("Missing tags");
|
if (tags == null) throw new IllegalArgumentException("Missing tags");
|
||||||
_sessionTags = tags;
|
_sessionTags = tags;
|
||||||
@ -692,7 +707,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** tags still available */
|
/** tags still available */
|
||||||
public Set getTags() {
|
public Set<SessionTag> getTags() {
|
||||||
return _sessionTags;
|
return _sessionTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ public class Router {
|
|||||||
private RouterInfo _routerInfo;
|
private RouterInfo _routerInfo;
|
||||||
private long _started;
|
private long _started;
|
||||||
private boolean _higherVersionSeen;
|
private boolean _higherVersionSeen;
|
||||||
private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
|
//private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
|
||||||
private boolean _killVMOnEnd;
|
private boolean _killVMOnEnd;
|
||||||
private boolean _isAlive;
|
private boolean _isAlive;
|
||||||
private int _gracefulExitCode;
|
private int _gracefulExitCode;
|
||||||
@ -144,7 +144,7 @@ public class Router {
|
|||||||
_higherVersionSeen = false;
|
_higherVersionSeen = false;
|
||||||
_log = _context.logManager().getLog(Router.class);
|
_log = _context.logManager().getLog(Router.class);
|
||||||
_log.info("New router created with config file " + _configFilename);
|
_log.info("New router created with config file " + _configFilename);
|
||||||
_sessionKeyPersistenceHelper = new SessionKeyPersistenceHelper(_context);
|
//_sessionKeyPersistenceHelper = new SessionKeyPersistenceHelper(_context);
|
||||||
_killVMOnEnd = true;
|
_killVMOnEnd = true;
|
||||||
_oomListener = new I2PThread.OOMEventListener() {
|
_oomListener = new I2PThread.OOMEventListener() {
|
||||||
public void outOfMemory(OutOfMemoryError oom) {
|
public void outOfMemory(OutOfMemoryError oom) {
|
||||||
@ -261,7 +261,7 @@ public class Router {
|
|||||||
SimpleScheduler.getInstance().addPeriodicEvent(new CoalesceStatsEvent(_context), 20*1000);
|
SimpleScheduler.getInstance().addPeriodicEvent(new CoalesceStatsEvent(_context), 20*1000);
|
||||||
_context.jobQueue().addJob(new UpdateRoutingKeyModifierJob(_context));
|
_context.jobQueue().addJob(new UpdateRoutingKeyModifierJob(_context));
|
||||||
warmupCrypto();
|
warmupCrypto();
|
||||||
_sessionKeyPersistenceHelper.startup();
|
//_sessionKeyPersistenceHelper.startup();
|
||||||
//_context.adminManager().startup();
|
//_context.adminManager().startup();
|
||||||
_context.blocklist().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.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.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 { _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);
|
RouterContext.listContexts().remove(_context);
|
||||||
dumpStats();
|
dumpStats();
|
||||||
finalShutdown(exitCode);
|
finalShutdown(exitCode);
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user