propagate from branch 'i2p.i2p.unittests' (head 53586f73fb813f519cdb6a1f7b1b40efec2e35dc)

to branch 'i2p.i2p' (head 628a2c591ca44095e2f93acd026046d4512cf692)
This commit is contained in:
str4d
2015-12-08 05:27:03 +00:00
401 changed files with 36193 additions and 24628 deletions

View File

@@ -18,7 +18,7 @@ public class CoreVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = "0.9.22";
public final static String VERSION = "0.9.23";
/**
* For Vuze.

View File

@@ -84,6 +84,7 @@ public class I2PAppContext {
private RandomSource _random;
private KeyGenerator _keyGenerator;
protected KeyRing _keyRing; // overridden in RouterContext
@SuppressWarnings("deprecation")
private SimpleScheduler _simpleScheduler;
private SimpleTimer _simpleTimer;
private SimpleTimer2 _simpleTimer2;
@@ -532,7 +533,7 @@ public class I2PAppContext {
* @return set of Strings containing the names of defined system properties
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public Set<String> getPropertyNames() {
public Set<String> getPropertyNames() {
// clone to avoid ConcurrentModificationException
Set<String> names = new HashSet<String>((Set<String>) (Set) ((Properties) System.getProperties().clone()).keySet()); // TODO-Java6: s/keySet()/stringPropertyNames()/
if (_overrideProps != null)
@@ -940,6 +941,7 @@ public class I2PAppContext {
* @since 0.9 to replace static instance in the class
* @deprecated in 0.9.20, use simpleTimer2()
*/
@SuppressWarnings("deprecation")
public SimpleScheduler simpleScheduler() {
if (!_simpleSchedulerInitialized)
initializeSimpleScheduler();

View File

@@ -18,6 +18,7 @@ import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.PrivateKey;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.data.SigningPrivateKey;
/**
@@ -98,7 +99,7 @@ public interface I2PSession {
* objects that were sent along side the given keyUsed.
* @return success
*/
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set<SessionTag> tagsSent) throws I2PSessionException;
/**
* End-to-End Crypto is disabled, tags and keys are ignored.
@@ -106,7 +107,7 @@ public interface I2PSession {
* @param tagsSent UNUSED, IGNORED.
* @return success
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent) throws I2PSessionException;
/**
* End-to-End Crypto is disabled, tags and keys are ignored.
@@ -116,7 +117,7 @@ public interface I2PSession {
* @return success
* @since 0.7.1
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire) throws I2PSessionException;
/**
* See I2PSessionMuxedImpl for proto/port details.
@@ -133,7 +134,7 @@ public interface I2PSession {
* @return success
* @since 0.7.1
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent,
int proto, int fromPort, int toPort) throws I2PSessionException;
/**
@@ -152,7 +153,7 @@ public interface I2PSession {
* @return success
* @since 0.7.1
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
int proto, int fromPort, int toPort) throws I2PSessionException;
/**
@@ -171,7 +172,7 @@ public interface I2PSession {
* @return success
* @since 0.8.4
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
int proto, int fromPort, int toPort, int flags) throws I2PSessionException;
/**

View File

@@ -102,7 +102,7 @@ class I2CPMessageProducer {
if (_log.shouldLog(Log.DEBUG)) _log.debug("config signed");
msg.setSessionConfig(cfg);
if (_log.shouldLog(Log.DEBUG)) _log.debug("config loaded into message");
session.sendMessage(msg);
session.sendMessage_unchecked(msg);
if (_log.shouldLog(Log.DEBUG)) _log.debug("config message sent");
}
@@ -114,7 +114,7 @@ class I2CPMessageProducer {
if (session.isClosed()) return;
DestroySessionMessage dmsg = new DestroySessionMessage();
dmsg.setSessionId(session.getSessionId());
session.sendMessage(dmsg);
session.sendMessage_unchecked(dmsg);
// use DisconnectMessage only if we fail and drop connection...
// todo: update the code to fire off DisconnectMessage on socket error
//DisconnectMessage msg = new DisconnectMessage();
@@ -132,7 +132,7 @@ class I2CPMessageProducer {
* @param newKey unused - no end-to-end crypto
*/
public void sendMessage(I2PSessionImpl session, Destination dest, long nonce, byte[] payload, SessionTag tag,
SessionKey key, Set tags, SessionKey newKey, long expires) throws I2PSessionException {
SessionKey key, Set<SessionTag> tags, SessionKey newKey, long expires) throws I2PSessionException {
sendMessage(session, dest, nonce, payload, expires, 0);
}
@@ -371,7 +371,7 @@ class I2CPMessageProducer {
return;
}
msg.setSessionId(sid);
session.sendMessage(msg);
session.sendMessage_unchecked(msg);
}
/**

View File

@@ -209,8 +209,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
VersionComparator.comp(routerVersion, MIN_SUBSESSION_VERSION) >= 0);
synchronized (_stateLock) {
if (_state == State.OPENING) {
_state = State.GOTDATE;
_stateLock.notifyAll();
changeState(State.GOTDATE);
}
}
}
@@ -635,7 +634,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
auth.setProperty(PROP_USER, _options.getProperty(PROP_USER));
auth.setProperty(PROP_PW, _options.getProperty(PROP_PW));
}
sendMessage(new GetDateMessage(CoreVersion.VERSION, auth));
sendMessage_unchecked(new GetDateMessage(CoreVersion.VERSION, auth));
waitForDate();
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Before producer.connect()");
@@ -737,14 +736,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
* Report abuse with regards to the given messageId
*/
public void reportAbuse(int msgId, int severity) throws I2PSessionException {
synchronized (_stateLock) {
if (_state == State.CLOSED)
throw new I2PSessionException("Already closed");
if (_state == State.INIT)
throw new I2PSessionException("Not open, must call connect() first");
if (_state == State.OPENING) // not before GOTDATE
throw new I2PSessionException("Session not open yet");
}
verifyOpen();
_producer.reportAbuse(this, msgId, severity);
}
@@ -870,7 +862,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
if ((duration > 100) && _log.shouldLog(Log.INFO))
_log.info("Message availability notification for " + msgId.intValue() + " took "
+ duration + " to " + _sessionListener);
} catch (Exception e) {
} catch (RuntimeException e) {
_log.log(Log.CRIT, "Error notifying app of message availability", e);
}
} else {
@@ -1034,6 +1026,39 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
}
}
/**
* Throws I2PSessionException if uninitialized, closed or closing.
* Blocks if opening.
*
* @since 0.9.23
*/
protected void verifyOpen() throws I2PSessionException {
synchronized (_stateLock) {
while (true) {
switch (_state) {
case INIT:
throw new I2PSessionException("Not open, must call connect() first");
case OPENING: // fall thru
case GOTDATE:
try {
_stateLock.wait(5*1000);
continue;
} catch (InterruptedException ie) {
throw new I2PSessionException("Interrupted", ie);
}
case OPEN:
return;
case CLOSING: // fall thru
case CLOSED:
throw new I2PSessionException("Already closed");
}
}
}
}
/**
* Deliver an I2CP message to the router
* As of 0.9.3, may block for several seconds if the write queue to the router is full
@@ -1041,12 +1066,19 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
* @throws I2PSessionException if the message is malformed or there is an error writing it out
*/
void sendMessage(I2CPMessage message) throws I2PSessionException {
synchronized (_stateLock) {
if (_state == State.CLOSED)
throw new I2PSessionException("Already closed");
if (_state == State.INIT)
throw new I2PSessionException("Not open, must call connect() first");
}
verifyOpen();
sendMessage_unchecked(message);
}
/**
* Deliver an I2CP message to the router.
* Does NOT check state. Call only from connect() or other methods that need to
* send messages when not in OPEN state.
*
* @throws I2PSessionException if the message is malformed or there is an error writing it out
* @since 0.9.23
*/
void sendMessage_unchecked(I2CPMessage message) throws I2PSessionException {
if (_queue != null) {
// internal
try {
@@ -1055,11 +1087,13 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
} catch (InterruptedException ie) {
throw new I2PSessionException("Interrupted", ie);
}
} else if (_writer == null) {
// race here
throw new I2PSessionException("Already closed or not open");
} else {
_writer.addMessage(message);
ClientWriterRunner writer = _writer;
if (writer == null) {
throw new I2PSessionException("Already closed or not open");
} else {
writer.addMessage(message);
}
}
}
@@ -1441,11 +1475,11 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
SessionId id = _sessionId;
if (id == null)
id = new SessionId(65535);
sendMessage(new HostLookupMessage(id, h, nonce, maxWait));
sendMessage_unchecked(new HostLookupMessage(id, h, nonce, maxWait));
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Sending DestLookup for " + h);
sendMessage(new DestLookupMessage(h));
sendMessage_unchecked(new DestLookupMessage(h));
}
try {
synchronized (waiter) {
@@ -1533,7 +1567,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
SessionId id = _sessionId;
if (id == null)
id = new SessionId(65535);
sendMessage(new HostLookupMessage(id, name, nonce, maxWait));
sendMessage_unchecked(new HostLookupMessage(id, name, nonce, maxWait));
try {
synchronized (waiter) {
waiter.wait(maxWait);
@@ -1567,7 +1601,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
return null;
}
}
sendMessage(new GetBandwidthLimitsMessage());
sendMessage_unchecked(new GetBandwidthLimitsMessage());
try {
synchronized (_bwReceivedLock) {
_bwReceivedLock.wait(5*1000);

View File

@@ -29,6 +29,7 @@ import net.i2p.client.SendMessageStatusListener;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.data.i2cp.MessageId;
import net.i2p.data.i2cp.MessageStatusMessage;
import net.i2p.util.Log;
@@ -210,17 +211,17 @@ class I2PSessionImpl2 extends I2PSessionImpl {
throw new UnsupportedOperationException("Use MuxedImpl");
}
/** @throws UnsupportedOperationException always, use MuxedImpl */
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent,
int proto, int fromport, int toport) throws I2PSessionException {
throw new UnsupportedOperationException("Use MuxedImpl");
}
/** @throws UnsupportedOperationException always, use MuxedImpl */
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
int proto, int fromport, int toport) throws I2PSessionException {
throw new UnsupportedOperationException("Use MuxedImpl");
}
/** @throws UnsupportedOperationException always, use MuxedImpl */
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
int proto, int fromport, int toport, int flags) throws I2PSessionException {
throw new UnsupportedOperationException("Use MuxedImpl");
}
@@ -253,7 +254,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
* @param tagsSent unused - no end-to-end crypto
*/
@Override
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException {
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set<SessionTag> tagsSent) throws I2PSessionException {
return sendMessage(dest, payload, 0, payload.length, keyUsed, tagsSent, 0);
}
@@ -261,7 +262,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
* @param keyUsed unused - no end-to-end crypto
* @param tagsSent unused - no end-to-end crypto
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent)
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent)
throws I2PSessionException {
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0);
}
@@ -272,17 +273,10 @@ class I2PSessionImpl2 extends I2PSessionImpl {
* @param keyUsed unused - no end-to-end crypto
* @param tagsSent unused - no end-to-end crypto
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expires)
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expires)
throws I2PSessionException {
if (_log.shouldLog(Log.DEBUG)) _log.debug("sending message");
synchronized (_stateLock) {
if (_state == State.CLOSED)
throw new I2PSessionException("Already closed");
if (_state == State.INIT)
throw new I2PSessionException("Not open, must call connect() first");
if (_state == State.OPENING || _state == State.GOTDATE) // not before GOTDATE or session
throw new I2PSessionException("Session not open yet");
}
verifyOpen();
updateActivity();
// Sadly there is no way to send something completely uncompressed in a backward-compatible way,
@@ -339,7 +333,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
* @param keyUsed unused - no end-to-end crypto
* @param tagsSent unused - no end-to-end crypto
*/
protected boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires)
protected boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set<SessionTag> tagsSent, long expires)
throws I2PSessionException {
return sendBestEffort(dest, payload, expires, 0);
}

View File

@@ -19,6 +19,7 @@ import net.i2p.client.SendMessageStatusListener;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.data.i2cp.MessagePayloadMessage;
import net.i2p.util.Log;
@@ -163,7 +164,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
*/
@Override
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
SessionKey keyUsed, Set tagsSent, long expires)
SessionKey keyUsed, Set<SessionTag> tagsSent, long expires)
throws I2PSessionException {
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, PROTO_UNSPECIFIED, PORT_UNSPECIFIED, PORT_UNSPECIFIED);
}
@@ -173,7 +174,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
* @param tagsSent unused - no end-to-end crypto
*/
@Override
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent,
int proto, int fromport, int toport) throws I2PSessionException {
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, proto, fromport, toport);
}
@@ -192,7 +193,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
*/
@Override
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
SessionKey keyUsed, Set tagsSent, long expires,
SessionKey keyUsed, Set<SessionTag> tagsSent, long expires,
int proto, int fromPort, int toPort)
throws I2PSessionException {
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, proto, fromPort, toPort, 0);
@@ -213,7 +214,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
*/
@Override
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
SessionKey keyUsed, Set tagsSent, long expires,
SessionKey keyUsed, Set<SessionTag> tagsSent, long expires,
int proto, int fromPort, int toPort, int flags)
throws I2PSessionException {
payload = prepPayload(payload, offset, size, proto, fromPort, toPort);
@@ -279,14 +280,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
* @since 0.9.14
*/
private byte[] prepPayload(byte[] payload, int offset, int size, int proto, int fromPort, int toPort) throws I2PSessionException {
synchronized (_stateLock) {
if (_state == State.CLOSED)
throw new I2PSessionException("Already closed");
if (_state == State.INIT)
throw new I2PSessionException("Not open, must call connect() first");
if (_state == State.OPENING || _state == State.GOTDATE) // not before GOTDATE or session
throw new I2PSessionException("Session not open yet");
}
verifyOpen();
updateActivity();
if (shouldCompress(size))
@@ -405,7 +399,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
try {
_demultiplexer.messageAvailable(I2PSessionMuxedImpl.this,
msg.id, msg.size, msg.proto, msg.fromPort, msg.toPort);
} catch (Exception e) {
} catch (RuntimeException e) {
_log.error("Error notifying app of message availability", e);
}
}

View File

@@ -122,11 +122,11 @@ public class I2PSimpleSession extends I2PSessionImpl2 {
Properties auth = new OrderedProperties();
auth.setProperty(PROP_USER, opts.getProperty(PROP_USER));
auth.setProperty(PROP_PW, opts.getProperty(PROP_PW));
sendMessage(new GetDateMessage(CoreVersion.VERSION, auth));
sendMessage_unchecked(new GetDateMessage(CoreVersion.VERSION, auth));
} else {
// we must now send a GetDate even in SimpleSession, or we won't know
// what version we are talking with and cannot use HostLookup
sendMessage(new GetDateMessage(CoreVersion.VERSION));
sendMessage_unchecked(new GetDateMessage(CoreVersion.VERSION));
}
waitForDate();
}

View File

@@ -100,7 +100,7 @@ class SubSession extends I2PSessionMuxedImpl {
public void connect() throws I2PSessionException {
synchronized(_stateLock) {
if (_state != State.OPEN) {
_state = State.OPENING;
changeState(State.OPENING);
}
}
boolean success = false;
@@ -121,7 +121,7 @@ class SubSession extends I2PSessionMuxedImpl {
if (_state != State.OPEN) {
Thread notifier = new I2PAppThread(_availabilityNotifier, "ClientNotifier " + getPrefix(), true);
notifier.start();
_state = State.OPEN;
changeState(State.OPEN);
}
}
success = true;
@@ -161,7 +161,20 @@ class SubSession extends I2PSessionMuxedImpl {
message.getType() != CreateSessionMessage.MESSAGE_TYPE &&
message.getType() != CreateLeaseSetMessage.MESSAGE_TYPE)
throw new I2PSessionException("Already closed");
_primary.sendMessage(message);
_primary.sendMessage_unchecked(message);
}
/**
* Deliver an I2CP message to the router.
* Does NOT check state. Call only from connect() or other methods that need to
* send messages when not in OPEN state.
*
* @throws I2PSessionException if the message is malformed or there is an error writing it out
* @since 0.9.23
*/
@Override
void sendMessage_unchecked(I2CPMessage message) throws I2PSessionException {
_primary.sendMessage_unchecked(message);
}
/**

View File

@@ -621,11 +621,33 @@ public class BlockfileNamingService extends DummyNamingService {
////////// Start NamingService API
/*
*
* Will strip a "www." prefix and retry if lookup fails
*
* @param hostname upper/lower case ok
* @param options If non-null and contains the key "list", lookup in
* that list only, otherwise all lists
*/
@Override
public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
Destination rv = lookup2(hostname, lookupOptions, storedOptions);
if (rv == null) {
// if hostname starts with "www.", strip and try again
// but not for www.i2p
hostname = hostname.toLowerCase(Locale.US);
if (hostname.startsWith("www.") && hostname.length() > 7) {
hostname = hostname.substring(4);
rv = lookup2(hostname, lookupOptions, storedOptions);
}
}
return rv;
}
/*
* @param options If non-null and contains the key "list", lookup in
* that list only, otherwise all lists
*/
private Destination lookup2(String hostname, Properties lookupOptions, Properties storedOptions) {
String listname = null;
if (lookupOptions != null)
listname = lookupOptions.getProperty("list");

View File

@@ -41,8 +41,8 @@ public class MetaNamingService extends DummyNamingService {
while (tok.hasMoreTokens()) {
try {
Class<?> cls = Class.forName(tok.nextToken());
Constructor<?> con = cls.getConstructor(new Class[] { I2PAppContext.class });
addNamingService((NamingService)con.newInstance(new Object[] { context }), false);
Constructor<?> con = cls.getConstructor(I2PAppContext.class);
addNamingService((NamingService)con.newInstance(), false);
} catch (Exception ex) {
}
}

View File

@@ -536,8 +536,8 @@ public abstract class NamingService {
String impl = context.getProperty(PROP_IMPL, DEFAULT_IMPL);
try {
Class<?> cls = Class.forName(impl);
Constructor<?> con = cls.getConstructor(new Class[] { I2PAppContext.class });
instance = (NamingService)con.newInstance(new Object[] { context });
Constructor<?> con = cls.getConstructor(I2PAppContext.class);
instance = (NamingService)con.newInstance(context);
} catch (Exception ex) {
Log log = context.logManager().getLog(NamingService.class);
// Blockfile may throw RuntimeException but HostsTxt won't

View File

@@ -77,6 +77,8 @@ public class SingleFileNamingService extends NamingService {
}
/**
* Will strip a "www." prefix and retry if lookup fails
*
* @param hostname case-sensitive; caller should convert to lower case
* @param lookupOptions ignored
* @param storedOptions ignored
@@ -85,9 +87,11 @@ public class SingleFileNamingService extends NamingService {
public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
try {
String key = getKey(hostname);
if (key == null && hostname.startsWith("www.") && hostname.length() > 7)
key = getKey(hostname.substring(4));
if (key != null)
return lookupBase64(key);
} catch (Exception ioe) {
} catch (IOException ioe) {
if (_file.exists())
_log.error("Error loading hosts file " + _file, ioe);
else if (_log.shouldLog(Log.WARN))
@@ -119,7 +123,7 @@ public class SingleFileNamingService extends NamingService {
return line.substring(0, split);
}
return null;
} catch (Exception ioe) {
} catch (IOException ioe) {
if (_file.exists())
_log.error("Error loading hosts file " + _file, ioe);
else if (_log.shouldLog(Log.WARN))

View File

@@ -1,11 +1,16 @@
package net.i2p.crypto;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Locale;
@@ -77,12 +82,40 @@ public class CertUtil {
* @return value or null if not found
*/
public static String getSubjectValue(X509Certificate cert, String type) {
X500Principal p = cert.getSubjectX500Principal();
return getValue(p, type);
}
/**
* Get a value out of the issuer distinguished name.
*
* Warning - unsupported in Android (no javax.naming), returns null.
*
* @param type e.g. "CN"
* @return value or null if not found
* @since 0.9.24
*/
public static String getIssuerValue(X509Certificate cert, String type) {
X500Principal p = cert.getIssuerX500Principal();
return getValue(p, type);
}
/**
* Get a value out of a X500Principal.
*
* Warning - unsupported in Android (no javax.naming), returns null.
*
* @param type e.g. "CN"
* @return value or null if not found
*/
private static String getValue(X500Principal p, String type) {
if (SystemVersion.isAndroid()) {
error("Don't call this in Android", new UnsupportedOperationException("I did it"));
return null;
}
if (p == null)
return null;
type = type.toUpperCase(Locale.US);
X500Principal p = cert.getSubjectX500Principal();
String subj = p.getName();
try {
LdapName name = new LdapName(subj);
@@ -106,4 +139,40 @@ public class CertUtil {
Log l = ctx.logManager().getLog(CertUtil.class);
l.log(level, msg, t);
}
/**
* Get the Java public key from a X.509 certificate file.
* Throws if the certificate is invalid (e.g. expired).
*
* @return non-null, throws on all errors including certificate invalid
* @since 0.9.24 moved from SU3File private method
*/
public static PublicKey loadKey(File kd) throws IOException, GeneralSecurityException {
return loadCert(kd).getPublicKey();
}
/**
* Get the certificate from a X.509 certificate file.
* Throws if the certificate is invalid (e.g. expired).
*
* @return non-null, throws on all errors including certificate invalid
* @since 0.9.24 adapted from SU3File private method
*/
public static X509Certificate loadCert(File kd) throws IOException, GeneralSecurityException {
InputStream fis = null;
try {
fis = new FileInputStream(kd);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
cert.checkValidity();
return cert;
} catch (IllegalArgumentException iae) {
// java 1.8.0_40-b10, openSUSE
// Exception in thread "main" java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit
// at java.util.Base64$Decoder.decode0(Base64.java:704)
throw new GeneralSecurityException("cert error", iae);
} finally {
try { if (fis != null) fis.close(); } catch (IOException foo) {}
}
}
}

View File

@@ -38,34 +38,12 @@ import net.i2p.util.SystemVersion;
*/
public class CryptixAESEngine extends AESEngine {
private final static CryptixRijndael_Algorithm _algo = new CryptixRijndael_Algorithm();
private final static boolean USE_FAKE_CRYPTO = false;
// keys are now cached in the SessionKey objects
//private CryptixAESKeyCache _cache;
/** see test results below */
private static final int MIN_SYSTEM_AES_LENGTH = 704;
private static final boolean USE_SYSTEM_AES;
static {
boolean systemOK = false;
if (hasAESNI()) {
try {
systemOK = Cipher.getMaxAllowedKeyLength("AES") >= 256;
} catch (GeneralSecurityException gse) {
// a NoSuchAlgorithmException
} catch (NoSuchMethodError nsme) {
// JamVM, gij
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key = new SecretKeySpec(new byte[32], "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
systemOK = true;
} catch (GeneralSecurityException gse) {
}
}
}
USE_SYSTEM_AES = systemOK;
//System.out.println("Using system AES? " + systemOK);
}
private static final boolean USE_SYSTEM_AES = hasAESNI() && CryptoCheck.isUnlimited();
/**
* Do we have AES-NI support in the processor and JVM?
@@ -124,12 +102,6 @@ public class CryptixAESEngine extends AESEngine {
if (length % 16 != 0)
throw new IllegalArgumentException("Only lengths mod 16 are supported here");
if (USE_FAKE_CRYPTO) {
_log.warn("AES Crypto disabled! Using trivial XOR");
System.arraycopy(payload, payloadIndex, out, outIndex, length);
return;
}
if (USE_SYSTEM_AES && length >= MIN_SYSTEM_AES_LENGTH) {
try {
SecretKeySpec key = new SecretKeySpec(sessionKey.getData(), "AES");
@@ -177,12 +149,6 @@ public class CryptixAESEngine extends AESEngine {
throw new IllegalArgumentException("out is too small (out.length=" + out.length
+ " outIndex=" + outIndex + " length=" + length);
if (USE_FAKE_CRYPTO) {
_log.warn("AES Crypto disabled! Using trivial XOR");
System.arraycopy(payload, payloadIndex, out, outIndex, length);
return ;
}
if (USE_SYSTEM_AES && length >= MIN_SYSTEM_AES_LENGTH) {
try {
SecretKeySpec key = new SecretKeySpec(sessionKey.getData(), "AES");

View File

@@ -0,0 +1,47 @@
package net.i2p.crypto;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/**
* Moved from CryptixAESEngine and net.i2p.router.tasks.CryptoChecker
*
* @since 0.9.23
*/
public class CryptoCheck {
private static final boolean _isUnlimited;
static {
boolean unlimited = false;
try {
unlimited = Cipher.getMaxAllowedKeyLength("AES") >= 256;
} catch (GeneralSecurityException gse) {
// a NoSuchAlgorithmException
} catch (NoSuchMethodError nsme) {
// JamVM, gij
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key = new SecretKeySpec(new byte[32], "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
unlimited = true;
} catch (GeneralSecurityException gse) {
}
}
_isUnlimited = unlimited;
}
private CryptoCheck() {}
/**
* Do we have unlimited crypto?
*/
public static boolean isUnlimited() {
return _isUnlimited;
}
public static void main(String args[]) {
System.out.println("Unlimited? " + isUnlimited());
}
}

View File

@@ -92,8 +92,8 @@ public class CryptoConstants {
if (ECConstants.isBCAvailable()) {
try {
Class<?> cls = Class.forName("org.bouncycastle.jce.spec.ElGamalParameterSpec");
Constructor<?> con = cls.getConstructor(new Class[] {BigInteger.class, BigInteger.class});
spec = (AlgorithmParameterSpec)con.newInstance(new Object[] {elgp, elgg});
Constructor<?> con = cls.getConstructor(BigInteger.class, BigInteger.class);
spec = (AlgorithmParameterSpec)con.newInstance(elgp, elgg);
//System.out.println("BC ElG spec loaded");
} catch (Exception e) {
//System.out.println("BC ElG spec failed");

View File

@@ -257,7 +257,7 @@ public class DSAEngine {
_log.warn("Took too long to verify the signature (" + diff + "ms)");
}
return ok;
} catch (Exception e) {
} catch (RuntimeException e) {
_log.log(Log.CRIT, "Error verifying the signature", e);
return false;
}

View File

@@ -35,6 +35,8 @@ class DirKeyRing implements KeyRing {
* and have a CN == keyName.
*
* CN check unsupported on Android.
*
* @return null if file doesn't exist, throws on all other errors
*/
public PublicKey getKey(String keyName, String scope, SigType type)
throws GeneralSecurityException, IOException {
@@ -47,26 +49,15 @@ class DirKeyRing implements KeyRing {
File kd = new File(sd, fileName + ".crt");
if (!kd.exists())
return null;
InputStream fis = null;
try {
fis = new FileInputStream(kd);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
cert.checkValidity();
if (!SystemVersion.isAndroid()) {
// getSubjectValue() unsupported on Android.
// Any cert problems will be caught in non-Android testing.
String cn = CertUtil.getSubjectValue(cert, "CN");
if (!keyName.equals(cn))
throw new GeneralSecurityException("CN mismatch: " + cn);
}
return cert.getPublicKey();
} catch (IllegalArgumentException iae) {
// java 1.8.0_40-b10, openSUSE
throw new GeneralSecurityException("Bad cert", iae);
} finally {
try { if (fis != null) fis.close(); } catch (IOException foo) {}
X509Certificate cert = CertUtil.loadCert(kd);
if (!SystemVersion.isAndroid()) {
// getSubjectValue() unsupported on Android.
// Any cert problems will be caught in non-Android testing.
String cn = CertUtil.getSubjectValue(cert, "CN");
if (!keyName.equals(cn))
throw new GeneralSecurityException("CN mismatch: " + cn);
}
return cert.getPublicKey();
}
/**

View File

@@ -3,6 +3,7 @@ package net.i2p.crypto;
import java.lang.reflect.Constructor;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.Provider;
import java.security.Security;
import java.security.spec.ECField;
@@ -42,8 +43,8 @@ class ECConstants {
if (Security.getProvider("BC") == null) {
try {
Class<?> cls = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
Constructor<?> con = cls.getConstructor(new Class[0]);
Provider bc = (Provider)con.newInstance(new Object[0]);
Constructor<?> con = cls.getConstructor();
Provider bc = (Provider)con.newInstance();
Security.addProvider(bc);
log("Added BC provider");
loaded = true;
@@ -278,7 +279,7 @@ class ECConstants {
AlgorithmParameters ap;
try {
ap = AlgorithmParameters.getInstance("EC");
} catch (Exception e) {
} catch (GeneralSecurityException e) {
if (BC_AVAILABLE) {
log("Named curve " + name + " is not available, trying BC", e);
ap = AlgorithmParameters.getInstance("EC", "BC");
@@ -292,7 +293,7 @@ class ECConstants {
ECParameterSpec rv = ap.getParameterSpec(ECParameterSpec.class);
log("Named curve " + name + " loaded");
return rv;
} catch (Exception e) {
} catch (GeneralSecurityException e) {
log("Named curve " + name + " is not available", e);
return null;
}

View File

@@ -327,12 +327,12 @@ public class ElGamalAESEngine {
//ByteArrayInputStream bais = new ByteArrayInputStream(decrypted);
int cur = 0;
long numTags = DataHelper.fromLong(decrypted, cur, 2);
if ((numTags < 0) || (numTags > MAX_TAGS_RECEIVED)) throw new Exception("Invalid number of session tags");
if ((numTags < 0) || (numTags > MAX_TAGS_RECEIVED)) throw new IllegalArgumentException("Invalid number of session tags");
if (numTags > 0) tags = new ArrayList<SessionTag>((int)numTags);
cur += 2;
//_log.debug("# tags: " + numTags);
if (numTags * SessionTag.BYTE_LENGTH > decrypted.length - 2) {
throw new Exception("# tags: " + numTags + " is too many for " + (decrypted.length - 2));
throw new IllegalArgumentException("# tags: " + numTags + " is too many for " + (decrypted.length - 2));
}
for (int i = 0; i < numTags; i++) {
byte tag[] = new byte[SessionTag.BYTE_LENGTH];
@@ -344,7 +344,7 @@ public class ElGamalAESEngine {
cur += 4;
//_log.debug("len: " + len);
if ((len < 0) || (len > decrypted.length - cur - Hash.HASH_LENGTH - 1))
throw new Exception("Invalid size of payload (" + len + ", remaining " + (decrypted.length-cur) +")");
throw new IllegalArgumentException("Invalid size of payload (" + len + ", remaining " + (decrypted.length-cur) +")");
//byte hashval[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(decrypted, cur, hashval, 0, Hash.HASH_LENGTH);
//readHash = new Hash();
@@ -379,8 +379,8 @@ public class ElGamalAESEngine {
return unencrData;
}
throw new Exception("Hash does not match");
} catch (Exception e) {
throw new RuntimeException("Hash does not match");
} catch (RuntimeException e) {
if (_log.shouldLog(Log.WARN)) _log.warn("Unable to decrypt AES block", e);
return null;
}

View File

@@ -108,7 +108,7 @@ public enum EncType {
return true;
try {
getParams();
} catch (Exception e) {
} catch (InvalidParameterSpecException e) {
return false;
}
return true;

View File

@@ -56,11 +56,9 @@ import net.i2p.util.RandomSource;
* @author jrandom
*/
public class KeyGenerator {
//private final Log _log;
private final I2PAppContext _context;
public KeyGenerator(I2PAppContext context) {
//_log = context.logManager().getLog(KeyGenerator.class);
_context = context;
}
@@ -85,7 +83,6 @@ public class KeyGenerator {
/**
* PBE the passphrase with the salt.
* Warning - SLOW
* Deprecated - Used by Syndie only.
*/
public SessionKey generateSessionKey(byte salt[], byte passphrase[]) {
byte salted[] = new byte[16+passphrase.length];
@@ -122,6 +119,7 @@ public class KeyGenerator {
/**
* @deprecated use getElGamalExponentSize() which allows override in the properties
*/
@Deprecated
public static final int PUBKEY_EXPONENT_SIZE = DEFAULT_USE_LONG_EXPONENT ?
PUBKEY_EXPONENT_SIZE_FULL :
PUBKEY_EXPONENT_SIZE_SHORT;
@@ -228,7 +226,7 @@ public class KeyGenerator {
}
/**
* Generic signature type, supports DSA and ECDSA
* Generic signature type, supports DSA, ECDSA, EdDSA
* @since 0.9.9
*/
public SimpleDataStructure[] generateSigningKeys(SigType type) throws GeneralSecurityException {
@@ -343,7 +341,7 @@ public class KeyGenerator {
public static void main(String args[]) {
try {
main2(args);
} catch (Exception e) {
} catch (RuntimeException e) {
e.printStackTrace();
}
}
@@ -381,7 +379,7 @@ public class KeyGenerator {
try {
System.out.println("Testing " + type);
testSig(type, runs);
} catch (Exception e) {
} catch (GeneralSecurityException e) {
System.out.println("error testing " + type);
e.printStackTrace();
}

View File

@@ -5,13 +5,13 @@ import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Locale;
@@ -31,11 +31,46 @@ import net.i2p.util.SystemVersion;
*/
public class KeyStoreUtil {
public static boolean _blacklistLogged;
public static final String DEFAULT_KEYSTORE_PASSWORD = "changeit";
private static final String DEFAULT_KEY_ALGORITHM = "RSA";
private static final int DEFAULT_KEY_SIZE = 2048;
private static final int DEFAULT_KEY_VALID_DAYS = 3652; // 10 years
/**
* No reports of some of these in a Java keystore but just to be safe...
* CNNIC ones are in Ubuntu keystore.
*/
private static final BigInteger[] BLACKLIST_SERIAL = new BigInteger[] {
// CNNIC https://googleonlinesecurity.blogspot.com/2015/03/maintaining-digital-certificate-security.html
new BigInteger("49:33:00:01".replace(":", ""), 16),
// CNNIC EV root https://bugzilla.mozilla.org/show_bug.cgi?id=607208
new BigInteger("48:9f:00:01".replace(":", ""), 16),
// Superfish http://blog.erratasec.com/2015/02/extracting-superfish-certificate.html
new BigInteger("d2:fc:13:87:a9:44:dc:e7".replace(":", ""), 16),
// eDellRoot https://www.reddit.com/r/technology/comments/3twmfv/dell_ships_laptops_with_rogue_root_ca_exactly/
new BigInteger("6b:c5:7b:95:18:93:aa:97:4b:62:4a:c0:88:fc:3b:b6".replace(":", ""), 16),
// DSDTestProvider https://blog.hboeck.de/archives/876-Superfish-2.0-Dangerous-Certificate-on-Dell-Laptops-breaks-encrypted-HTTPS-Connections.html
// serial number is actually negative; hex string as reported by certtool below
//new BigInteger("a4:4c:38:47:f8:ee:71:80:43:4d:b1:80:b9:a7:e9:62".replace(":", ""), 16)
new BigInteger("-5b:b3:c7:b8:07:11:8e:7f:bc:b2:4e:7f:46:58:16:9e".replace(":", ""), 16)
};
/**
* Corresponding issuer CN for the serial number.
* Must be same number of entries as BLACKLIST_SERIAL.
* See removeBlacklistedCerts() below for alternatives if we want
* to blacklist a cert without an issuer CN.
*/
private static final String[] BLACKLIST_ISSUER_CN = new String[] {
"CNNIC ROOT",
"China Internet Network Information Center EV Certificates Root",
"Superfish, Inc.",
"eDellRoot",
"DSDTestProvider"
};
/**
* Create a new KeyStore object, and load it from ksFile if it is
* non-null and it exists.
@@ -63,6 +98,8 @@ public class KeyStoreUtil {
if (ksFile != null && !exists) {
OutputStream fos = null;
try {
// must be initted
ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
fos = new SecureFileOutputStream(ksFile);
ks.store(fos, pwchars);
} finally {
@@ -98,7 +135,8 @@ public class KeyStoreUtil {
try {
ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
success = addCerts(new File(System.getProperty("java.home"), "etc/security/cacerts"), ks) > 0;
} catch (Exception e) {}
} catch (IOException e) {
} catch (GeneralSecurityException e) {}
} else {
success = loadCerts(new File(System.getProperty("java.home"), "etc/security/cacerts.bks"), ks);
}
@@ -109,11 +147,14 @@ public class KeyStoreUtil {
}
}
if (!success) {
if (success) {
removeBlacklistedCerts(ks);
} else {
try {
// must be initted
ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
} catch (Exception e) {}
} catch (IOException e) {
} catch (GeneralSecurityException e) {}
error("All key store loads failed, will only load local certificates", null);
}
return ks;
@@ -140,13 +181,15 @@ public class KeyStoreUtil {
try {
// not clear if null is allowed for password
ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
} catch (Exception foo) {}
} catch (IOException foo) {
} catch (GeneralSecurityException e) {}
return false;
} catch (IOException ioe) {
error("KeyStore load error, no default keys: " + file.getAbsolutePath(), ioe);
try {
ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
} catch (Exception foo) {}
} catch (IOException foo) {
} catch (GeneralSecurityException e) {}
return false;
} finally {
try { if (fis != null) fis.close(); } catch (IOException foo) {}
@@ -167,11 +210,66 @@ public class KeyStoreUtil {
for(Enumeration<String> e = ks.aliases(); e.hasMoreElements();) {
String alias = e.nextElement();
if (ks.isCertificateEntry(alias)) {
info("Found cert " + alias);
//info("Found cert " + alias);
count++;
}
}
} catch (Exception foo) {}
} catch (GeneralSecurityException e) {}
return count;
}
/**
* Remove all blacklisted X509 Certs in a key store.
* Match by serial number and issuer CN, which should uniquely identify a cert,
* if the CN is present. Should be faster than fingerprints.
*
* @return number successfully removed
* @since 0.9.24
*/
private static int removeBlacklistedCerts(KeyStore ks) {
// This matches on the CN in the issuer,
// and we can't do that on Android.
// We could just match the whole string, and we will have to
// if we want do it on Android or match a cert that has an issuer without a CN.
// Or, most certs that don't have a CN have an OU, that could be a fallback.
// Or do sha1hash(cert.getEncoded()) but that would be slower.
if (SystemVersion.isAndroid())
return 0;
int count = 0;
try {
for(Enumeration<String> e = ks.aliases(); e.hasMoreElements();) {
String alias = e.nextElement();
if (ks.isCertificateEntry(alias)) {
Certificate c = ks.getCertificate(alias);
if (c != null && (c instanceof X509Certificate)) {
X509Certificate xc = (X509Certificate) c;
BigInteger serial = xc.getSerialNumber();
for (int i = 0; i < BLACKLIST_SERIAL.length; i++) {
// debug:
//String xname = CertUtil.getIssuerValue(xc, "CN");
//info("Found \"" + xname + "\" s/n: " + serial.toString(16));
//if (xname == null)
// info("name is null, full issuer: " + xc.getIssuerX500Principal().getName());
if (BLACKLIST_SERIAL[i].equals(serial)) {
String name = CertUtil.getIssuerValue(xc, "CN");
if (BLACKLIST_ISSUER_CN[i].equals(name)) {
ks.deleteEntry(alias);
count++;
if (!_blacklistLogged) {
// should this be a logAlways?
warn("Ignoring blacklisted certificate \"" + alias +
"\" issued by: \"" + name +
"\" s/n: " + serial.toString(16), null);
}
}
}
}
}
}
}
} catch (GeneralSecurityException e) {}
if (count > 0)
_blacklistLogged = true;
return count;
}
@@ -198,7 +296,8 @@ public class KeyStoreUtil {
String alias = f.getName().toLowerCase(Locale.US);
if (alias.endsWith(".crt") || alias.endsWith(".pem") || alias.endsWith(".key") ||
alias.endsWith(".der") || alias.endsWith(".key") || alias.endsWith(".p7b") ||
alias.endsWith(".p7c") || alias.endsWith(".pfx") || alias.endsWith(".p12"))
alias.endsWith(".p7c") || alias.endsWith(".pfx") || alias.endsWith(".p12") ||
alias.endsWith(".cer"))
alias = alias.substring(0, alias.length() - 4);
boolean success = addCert(f, alias, ks);
if (success)
@@ -217,45 +316,32 @@ public class KeyStoreUtil {
* @since 0.8.2, moved from SSLEepGet in 0.9.9
*/
public static boolean addCert(File file, String alias, KeyStore ks) {
InputStream fis = null;
try {
fis = new FileInputStream(file);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
X509Certificate cert = CertUtil.loadCert(file);
info("Read X509 Certificate from " + file.getAbsolutePath() +
" Issuer: " + cert.getIssuerX500Principal() +
" Serial: " + cert.getSerialNumber().toString(16) +
"; Valid From: " + cert.getNotBefore() +
" To: " + cert.getNotAfter());
try {
cert.checkValidity();
} catch (CertificateExpiredException cee) {
String s = "Rejecting expired X509 Certificate: " + file.getAbsolutePath();
// Android often has old system certs
if (SystemVersion.isAndroid())
warn(s, cee);
else
error(s, cee);
return false;
} catch (CertificateNotYetValidException cnyve) {
error("Rejecting X509 Certificate not yet valid: " + file.getAbsolutePath(), cnyve);
return false;
}
ks.setCertificateEntry(alias, cert);
info("Now trusting X509 Certificate, Issuer: " + cert.getIssuerX500Principal());
} catch (CertificateExpiredException cee) {
String s = "Rejecting expired X509 Certificate: " + file.getAbsolutePath();
// Android often has old system certs
if (SystemVersion.isAndroid())
warn(s, cee);
else
error(s, cee);
return false;
} catch (CertificateNotYetValidException cnyve) {
error("Rejecting X509 Certificate not yet valid: " + file.getAbsolutePath(), cnyve);
return false;
} catch (GeneralSecurityException gse) {
error("Error reading X509 Certificate: " + file.getAbsolutePath(), gse);
return false;
} catch (IOException ioe) {
error("Error reading X509 Certificate: " + file.getAbsolutePath(), ioe);
return false;
} catch (IllegalArgumentException iae) {
// java 1.8.0_40-b10, openSUSE
// Exception in thread "main" java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit
// at java.util.Base64$Decoder.decode0(Base64.java:704)
error("Error reading X509 Certificate: " + file.getAbsolutePath(), iae);
return false;
} finally {
try { if (fis != null) fis.close(); } catch (IOException foo) {}
}
return true;
}
@@ -316,7 +402,10 @@ public class KeyStoreUtil {
error("Not overwriting key " + alias + ", already exists in " + ks, null);
return false;
}
} catch (Exception e) {
} catch (IOException e) {
error("Not overwriting key \"" + alias + "\", already exists in " + ks, e);
return false;
} catch (GeneralSecurityException e) {
error("Not overwriting key \"" + alias + "\", already exists in " + ks, e);
return false;
}
@@ -354,7 +443,10 @@ public class KeyStoreUtil {
success = getPrivateKey(ks, ksPW, alias, keyPW) != null;
if (!success)
error("Key gen failed to get private key", null);
} catch (Exception e) {
} catch (IOException e) {
error("Key gen failed to get private key", e);
success = false;
} catch (GeneralSecurityException e) {
error("Key gen failed to get private key", e);
success = false;
}
@@ -503,9 +595,9 @@ public class KeyStoreUtil {
/****
public static void main(String[] args) {
File ksf = (args.length > 0) ? new File(args[0]) : null;
try {
if (args.length > 0) {
File ksf = new File(args[0]);
if (ksf != null && !ksf.exists()) {
createKeyStore(ksf, DEFAULT_KEYSTORE_PASSWORD);
System.out.println("Created empty keystore " + ksf);
} else {
@@ -514,6 +606,17 @@ public class KeyStoreUtil {
System.out.println("Loaded system keystore");
int count = countCerts(ks);
System.out.println("Found " + count + " certs");
if (ksf != null && ksf.isDirectory()) {
count = addCerts(ksf, ks);
System.out.println("Found " + count + " certs in " + ksf);
if (count > 0) {
// rerun blacklist as a test
_blacklistLogged = false;
count = removeBlacklistedCerts(ks);
if (count > 0)
System.out.println("Found " + count + " blacklisted certs in " + ksf);
}
}
} else {
System.out.println("FAIL");
}

View File

@@ -15,8 +15,6 @@ import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
@@ -978,24 +976,12 @@ public class SU3File {
* @since 0.9.15
*/
private static PublicKey loadKey(File kd) throws IOException {
InputStream fis = null;
try {
fis = new FileInputStream(kd);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
cert.checkValidity();
return cert.getPublicKey();
return CertUtil.loadKey(kd);
} catch (GeneralSecurityException gse) {
IOException ioe = new IOException("cert error");
ioe.initCause(gse);
throw ioe;
} catch (IllegalArgumentException iae) {
// java 1.8.0_40-b10, openSUSE
IOException ioe = new IOException("cert error");
ioe.initCause(iae);
throw ioe;
} finally {
try { if (fis != null) fis.close(); } catch (IOException foo) {}
}
}
}

View File

@@ -1,5 +1,6 @@
package net.i2p.crypto;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
@@ -11,7 +12,9 @@ import java.util.Map;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.data.Hash;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SimpleDataStructure;
import net.i2p.util.SystemVersion;
/**
* Defines the properties for various signature types
@@ -193,11 +196,29 @@ public enum SigType {
return true;
try {
getParams();
if (getBaseAlgorithm() != SigAlgo.EdDSA)
Signature.getInstance(getAlgorithmName());
if (getBaseAlgorithm() != SigAlgo.EdDSA) {
Signature jsig = Signature.getInstance(getAlgorithmName());
if (getBaseAlgorithm() == SigAlgo.EC && SystemVersion.isGentoo() ) {
// Do a full keygen/sign test on Gentoo, because it lies. Keygen works but sigs fail.
// https://bugs.gentoo.org/show_bug.cgi?id=528338
// http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2497
// http://zzz.i2p/topics/1931
// Be sure nothing in the code paths below calls isAvailable()
// get an I2P keypair
SimpleDataStructure[] keys = KeyGenerator.getInstance().generateSigningKeys(this);
SigningPrivateKey privKey = (SigningPrivateKey) keys[1];
// convert privkey back to Java key and sign
jsig.initSign(SigUtil.toJavaECKey(privKey));
// use the pubkey as random data
jsig.update(keys[0].getData());
jsig.sign();
}
}
getDigestInstance();
getHashInstance();
} catch (Exception e) {
} catch (GeneralSecurityException e) {
return false;
} catch (RuntimeException e) {
return false;
}
return true;

View File

@@ -344,7 +344,11 @@ riCe6OlAEiNpcc6mMyIYYWFICbrDFTrDR3wXqwc/Jkcx6L5VVWoagpSzbo3yGhc=
System.out.println("\r\nPrivate key written to: " + privateKeyFile);
System.out.println("Public key written to: " + publicKeyFile);
System.out.println("\r\nPublic key: " + signingPublicKey.toBase64() + "\r\n");
} catch (Exception e) {
} catch (IOException e) {
System.err.println("Error writing keys:");
e.printStackTrace();
return false;
} catch (DataFormatException e) {
System.err.println("Error writing keys:");
e.printStackTrace();
return false;
@@ -758,7 +762,7 @@ riCe6OlAEiNpcc6mMyIYYWFICbrDFTrDR3wXqwc/Jkcx6L5VVWoagpSzbo3yGhc=
bytesToSignInputStream = new SequenceInputStream(versionHeaderInputStream, fileInputStream);
signature = _context.dsa().sign(bytesToSignInputStream, signingPrivateKey);
} catch (Exception e) {
} catch (IOException e) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error signing", e);

View File

@@ -722,7 +722,7 @@ public class GroupElement implements Serializable {
if (!this.repr.equals(ge.repr)) {
try {
ge = ge.toRep(this.repr);
} catch (Exception e) {
} catch (RuntimeException e) {
return false;
}
}

View File

@@ -16,7 +16,7 @@ import java.io.Serializable;
* maps, and the like.
*
*/
public class ByteArray implements Serializable, Comparable {
public class ByteArray implements Serializable, Comparable<ByteArray> {
private byte[] _data;
private int _valid;
private int _offset;
@@ -85,9 +85,8 @@ public class ByteArray implements Serializable, Comparable {
return (llen == rlen) && DataHelper.eq(lhs, loff, rhs, roff, llen);
}
public final int compareTo(Object obj) {
if (obj.getClass() != getClass()) throw new ClassCastException("invalid object: " + obj);
return DataHelper.compareTo(_data, ((ByteArray)obj).getData());
public final int compareTo(ByteArray ba) {
return DataHelper.compareTo(_data, ba.getData());
}
@Override

View File

@@ -215,7 +215,7 @@ public class Certificate extends DataStructureImpl {
throw new DataFormatException("Cert is too small [" + source.length + " off=" + offset + "]");
int cur = offset;
_type = (int)DataHelper.fromLong(source, cur, 1);
_type = source[cur] & 0xff;
cur++;
int length = (int)DataHelper.fromLong(source, cur, 2);
cur += 2;

View File

@@ -37,6 +37,8 @@ import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import net.i2p.I2PAppContext;
@@ -1615,11 +1617,11 @@ public class DataHelper {
* NOTE: formatDuration2() recommended in most cases for readability
*/
public static String formatSize(long bytes) {
double val = bytes;
float val = bytes;
int scale = 0;
while (val >= 1024) {
while (val >= 1024.0f) {
scale++;
val /= 1024;
val /= 1024.0f;
}
DecimalFormat fmt = new DecimalFormat("##0.00");
@@ -1693,7 +1695,7 @@ public class DataHelper {
if (unescaped == null) return null;
String escaped = unescaped;
for (int i = 0; i < escapeChars.length; i++) {
escaped = escaped.replaceAll(escapeChars[i], escapeCodes[i]);
escaped = escaped.replace(escapeChars[i], escapeCodes[i]);
}
return escaped;
}
@@ -1708,7 +1710,7 @@ public class DataHelper {
if (escaped == null) return null;
String unescaped = escaped;
for (int i = 0; i < escapeChars.length; i++) {
unescaped = unescaped.replaceAll(escapeCodes[i], escapeChars[i]);
unescaped = unescaped.replace(escapeCodes[i], escapeChars[i]);
}
return unescaped;
}
@@ -1888,4 +1890,38 @@ public class DataHelper {
}
return rv;
}
/**
* Same as s.split(regex) but caches the compiled pattern for speed.
* This saves about 10 microseconds (Bulldozer) on subsequent invocations.
*
* @param s non-null
* @param regex non-null
* @throws java.util.regex.PatternSyntaxException unchecked
* @since 0.9.24
*/
public static String[] split(String s, String regex) {
return split(s, regex, 0);
}
private static final ConcurrentHashMap<String, Pattern> patterns = new ConcurrentHashMap<String, Pattern>();
/**
* Same as s.split(regex, limit) but caches the compiled pattern for speed.
* This saves about 10 microseconds (Bulldozer) on subsequent invocations.
*
* @param s non-null
* @param regex non-null
* @param limit result threshold
* @throws java.util.regex.PatternSyntaxException unchecked
* @since 0.9.24
*/
public static String[] split(String s, String regex, int limit) {
Pattern p = patterns.get(regex);
if (p == null) {
p = Pattern.compile(regex);
patterns.putIfAbsent(regex, p);
}
return p.split(s, limit);
}
}

View File

@@ -9,6 +9,7 @@ import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
@@ -174,7 +175,10 @@ public class PrivateKeyFile {
pkf.write();
verifySignature(pkf.getDestination());
}
} catch (Exception e) {
} catch (I2PException e) {
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
@@ -358,7 +362,7 @@ public class PrivateKeyFile {
HashCash hc;
try {
hc = HashCash.mintCash(resource, effort);
} catch (Exception e) {
} catch (NoSuchAlgorithmException e) {
return null;
}
System.out.println("Generation took: " + DataHelper.formatDuration(System.currentTimeMillis() - begin));
@@ -391,7 +395,9 @@ public class PrivateKeyFile {
Destination d2;
try {
d2 = pkf2.getDestination();
} catch (Exception e) {
} catch (I2PException e) {
return null;
} catch (IOException e) {
return null;
}
if (d2 == null)
@@ -500,7 +506,7 @@ public class PrivateKeyFile {
long low = Long.MAX_VALUE;
try {
low = HashCash.estimateTime(hashEffort);
} catch (Exception e) {}
} catch (NoSuchAlgorithmException e) {}
// takes a lot longer than the estimate usually...
// maybe because the resource string is much longer than used in the estimate?
return "It is estimated that generating a HashCash Certificate with value " + hashEffort +

View File

@@ -46,7 +46,6 @@ import net.i2p.util.SystemVersion;
public class SDSCache<V extends SimpleDataStructure> {
//private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(SDSCache.class);
private static final Class[] conArg = new Class[] { byte[].class };
private static final double MIN_FACTOR = 0.20;
private static final double MAX_FACTOR = 5.0;
private static final double FACTOR;
@@ -74,7 +73,7 @@ public class SDSCache<V extends SimpleDataStructure> {
_cache = new LHMCache<Integer, WeakReference<V>>(size);
_datalen = len;
try {
_rvCon = rvClass.getConstructor(conArg);
_rvCon = rvClass.getConstructor(byte[].class);
} catch (NoSuchMethodException e) {
throw new RuntimeException("SDSCache init error", e);
}

View File

@@ -160,7 +160,7 @@ public class I2CPMessageReader {
public void run() {
try {
run2();
} catch (Exception e) {
} catch (RuntimeException e) {
_log.log(Log.CRIT, "Uncaught I2CP error", e);
_listener.readError(I2CPMessageReader.this, e);
cancelRunner();
@@ -193,7 +193,7 @@ public class I2CPMessageReader {
} catch (OutOfMemoryError oom) {
// ooms seen here... maybe log and keep going?
throw oom;
} catch (Exception e) {
} catch (RuntimeException e) {
_log.log(Log.CRIT, "Unhandled error reading I2CP stream", e);
_listener.disconnected(I2CPMessageReader.this);
cancelRunner();

View File

@@ -628,6 +628,7 @@ public class KBucketSet<T extends SimpleDataStructure> {
* @param data size <= SDS length, else throws IAE
* Can be 1 bigger if top byte is zero
*/
@SuppressWarnings("unchecked")
private T makeKey(byte[] data) {
int len = _us.length();
int dlen = data.length;

View File

@@ -145,7 +145,7 @@ public class BufferedStatLog implements StatLog {
if (_log.shouldLog(Log.DEBUG))
_log.debug("writing " + writeStart +"->"+ writeEnd);
writeEvents(writeStart, writeEnd);
} catch (Exception e) {
} catch (RuntimeException e) {
_log.error("error writing " + writeStart +"->"+ writeEnd, e);
}
}

View File

@@ -150,4 +150,16 @@ public class Frequency {
private final static long now() {
return System.currentTimeMillis();
}
/**
* Appends the data of this frequency to the specified StringBuilder
* @param dest to append data to
* @since 0.9.23
*/
synchronized void store(StringBuilder dest) {
dest.append("avgInterval:").append(_avgInterval).append(',');
dest.append("minAverageInterval").append(_minAverageInterval).append(',');
dest.append("lastEvent").append(_lastEvent).append(",");
dest.append("count").append(_count);
}
}

View File

@@ -1,5 +1,10 @@
package net.i2p.stat;
import java.io.IOException;
import java.io.OutputStream;
import net.i2p.data.DataHelper;
/** coordinate an event frequency over various periods */
public class FrequencyStat {
/** unique name of the statistic */
@@ -92,5 +97,34 @@ public class FrequencyStat {
if ((obj == null) || !(obj instanceof FrequencyStat)) return false;
return _statName.equals(((FrequencyStat)obj)._statName);
}
private final static String NL = System.getProperty("line.separator");
/**
* Serializes this FrequencyStat to the provided OutputStream
* @param out to write to
* @param prefix to prepend to the stat
* @throws IOException if something goes wrong
* @since 0.9.23
*/
public void store(OutputStream out, String prefix) throws IOException {
StringBuilder buf = new StringBuilder(1024);
buf.append(NL);
buf.append("################################################################################").append(NL);
buf.append("# Frequency: ").append(_groupName).append(": ").append(_statName).append(NL);
buf.append("# ").append(_description).append(NL);
buf.append("# ").append(NL).append(NL);
out.write(buf.toString().getBytes("UTF-8"));
buf.setLength(0);
for (Frequency r: _frequencies){
buf.append("#######").append(NL);
buf.append("# Period : ").append(DataHelper.formatDuration(r.getPeriod())).append(" for rate ")
.append(_groupName).append(" - ").append(_statName).append(NL);
buf.append(NL);
r.store(buf);
out.write(buf.toString().getBytes("UTF-8"));
buf.setLength(0);
}
}
}

View File

@@ -14,19 +14,19 @@ import net.i2p.data.DataHelper;
*/
public class Rate {
//private final static Log _log = new Log(Rate.class);
private double _currentTotalValue;
private float _currentTotalValue;
// was long, save space
private int _currentEventCount;
private long _currentTotalEventTime;
private double _lastTotalValue;
private int _currentTotalEventTime;
private float _lastTotalValue;
// was long, save space
private int _lastEventCount;
private long _lastTotalEventTime;
private double _extremeTotalValue;
private int _lastTotalEventTime;
private float _extremeTotalValue;
// was long, save space
private int _extremeEventCount;
private long _extremeTotalEventTime;
private double _lifetimeTotalValue;
private int _extremeTotalEventTime;
private float _lifetimeTotalValue;
private long _lifetimeEventCount;
private long _lifetimeTotalEventTime;
private RateSummaryListener _summaryListener;
@@ -227,10 +227,10 @@ public class Rate {
// ok ok, lets coalesce
// how much were we off by? (so that we can sample down the measured values)
double periodFactor = measuredPeriod / (double)_period;
float periodFactor = measuredPeriod / (float)_period;
_lastTotalValue = _currentTotalValue / periodFactor;
_lastEventCount = (int) (0.499999 + (_currentEventCount / periodFactor));
_lastTotalEventTime = (long) (_currentTotalEventTime / periodFactor);
_lastTotalEventTime = (int) (_currentTotalEventTime / periodFactor);
_lastCoalesceDate = now;
if (_currentEventCount == 0)
correctedTotalValue = 0;
@@ -244,7 +244,7 @@ public class Rate {
_extremeTotalEventTime = _lastTotalEventTime;
}
_currentTotalValue = 0.0D;
_currentTotalValue = 0.0f;
_currentEventCount = 0;
_currentTotalEventTime = 0;
}
@@ -505,16 +505,16 @@ public class Rate {
_period = PersistenceHelper.getInt(props, prefix, ".period");
_creationDate = PersistenceHelper.getLong(props, prefix, ".creationDate");
_lastCoalesceDate = PersistenceHelper.getLong(props, prefix, ".lastCoalesceDate");
_currentTotalValue = PersistenceHelper.getDouble(props, prefix, ".currentTotalValue");
_currentTotalValue = (float)PersistenceHelper.getDouble(props, prefix, ".currentTotalValue");
_currentEventCount = PersistenceHelper.getInt(props, prefix, ".currentEventCount");
_currentTotalEventTime = PersistenceHelper.getLong(props, prefix, ".currentTotalEventTime");
_lastTotalValue = PersistenceHelper.getDouble(props, prefix, ".lastTotalValue");
_currentTotalEventTime = (int)PersistenceHelper.getLong(props, prefix, ".currentTotalEventTime");
_lastTotalValue = (float)PersistenceHelper.getDouble(props, prefix, ".lastTotalValue");
_lastEventCount = PersistenceHelper.getInt(props, prefix, ".lastEventCount");
_lastTotalEventTime = PersistenceHelper.getLong(props, prefix, ".lastTotalEventTime");
_extremeTotalValue = PersistenceHelper.getDouble(props, prefix, ".extremeTotalValue");
_lastTotalEventTime = (int)PersistenceHelper.getLong(props, prefix, ".lastTotalEventTime");
_extremeTotalValue = (float)PersistenceHelper.getDouble(props, prefix, ".extremeTotalValue");
_extremeEventCount = PersistenceHelper.getInt(props, prefix, ".extremeEventCount");
_extremeTotalEventTime = PersistenceHelper.getLong(props, prefix, ".extremeTotalEventTime");
_lifetimeTotalValue = PersistenceHelper.getDouble(props, prefix, ".lifetimeTotalValue");
_extremeTotalEventTime = (int)PersistenceHelper.getLong(props, prefix, ".extremeTotalEventTime");
_lifetimeTotalValue = (float)PersistenceHelper.getDouble(props, prefix, ".lifetimeTotalValue");
_lifetimeEventCount = PersistenceHelper.getLong(props, prefix, ".lifetimeEventCount");
_lifetimeTotalEventTime = PersistenceHelper.getLong(props, prefix, ".lifetimeTotalEventTime");

View File

@@ -1,5 +1,7 @@
package net.i2p.stat;
import java.io.IOException;
import java.io.OutputStream;
import java.text.Collator;
import java.util.HashMap;
import java.util.HashSet;
@@ -247,4 +249,18 @@ public class StatManager {
public boolean ignoreStat(String statName) {
return _context.isRouterContext() && !_context.getBooleanProperty(PROP_STAT_FULL);
}
/**
* Serializes all Frequencies and Rates to the provided OutputStream
* @param out to write to
* @param prefix to use when serializing
* @throws IOException if something goes wrong
* @since 0.9.23
*/
public void store(OutputStream out, String prefix) throws IOException {
for (FrequencyStat fs : _frequencyStats.values())
fs.store(out, prefix);
for (RateStat rs : _rateStats.values())
rs.store(out,prefix);
}
}

View File

@@ -231,10 +231,10 @@ public abstract class Addresses {
I2PAppContext ctx = I2PAppContext.getCurrentContext();
if (ctx != null && ctx.isRouterContext()) {
long maxMemory = SystemVersion.getMaxMemory();
long min = 128;
long min = 256;
long max = 4096;
// 512 nominal for 128 MB
size = (int) Math.max(min, Math.min(max, 1 + (maxMemory / (256*1024))));
// 1024 nominal for 128 MB
size = (int) Math.max(min, Math.min(max, 1 + (maxMemory / (128*1024))));
} else {
size = 32;
}

View File

@@ -15,7 +15,8 @@ import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -24,6 +25,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import gnu.getopt.Getopt;
@@ -270,7 +273,7 @@ public class EepGet {
break;
} // switch
} // while
} catch (Exception e) {
} catch (RuntimeException e) {
e.printStackTrace();
error = true;
}
@@ -312,22 +315,52 @@ public class EepGet {
System.exit(1);
}
/**
* Parse URL for a viable filename.
*
* @param url a URL giving the location of an online resource
* @return a filename to save the resource as on local filesystem
*/
public static String suggestName(String url) {
int last = url.lastIndexOf('/');
if ((last < 0) || (url.lastIndexOf('#') > last))
last = url.lastIndexOf('#');
if ((last < 0) || (url.lastIndexOf('?') > last))
last = url.lastIndexOf('?');
if ((last < 0) || (url.lastIndexOf('=') > last))
last = url.lastIndexOf('=');
URI nameURL = null;
String name; // suggested name
String name = null;
if (last >= 0)
name = sanitize(url.substring(last+1));
if ( (name != null) && (name.length() > 0) )
return name;
else
return sanitize(url);
try {
nameURL = new URI(url);
} catch (URISyntaxException e) {
System.err.println("Please enter a properly formed URL.");
System.exit(1);
}
String path = nameURL.getRawPath(); // discard any URI queries
// if no file specified, eepget scrapes webpage - use domain as name
Pattern slashes = Pattern.compile("/+");
Matcher matcher = slashes.matcher(path);
// if empty path or just /'s - nameURL lets multiple /'s through
if (path.equals("") || matcher.matches()) {
name = sanitize(nameURL.getAuthority());
// if path specified
} else {
int last = path.lastIndexOf('/');
// if last / not at end of string, use following string as filename
if (last != path.length() - 1) {
name = sanitize(path.substring(last + 1));
// if there's a trailing / group look for previous / as trim point
} else {
int i = 1;
int slash;
while (true) {
slash = path.lastIndexOf('/', last - i);
if (slash != last - i) {
break;
}
i += 1;
}
name = sanitize(path.substring(slash + 1, path.length() - i));
}
}
return name;
}
@@ -690,24 +723,31 @@ public class EepGet {
if (_redirectLocation != null) {
// we also are here after a 407
//try {
try {
if (_redirectLocation.startsWith("http://")) {
_actualURL = _redirectLocation;
} else {
// the Location: field has been required to be an absolute URI at least since
// RFC 1945 (HTTP/1.0 1996), so it isn't clear what the point of this is.
// This oddly adds a ":" even if no port, but that seems to work.
URL url = new URL(_actualURL);
if (_redirectLocation.startsWith("/"))
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + _redirectLocation;
URI url = new URI(_actualURL);
String host = url.getHost();
if (host == null)
throw new MalformedURLException("Redirected to invalid URL");
int port = url.getPort();
if (port < 0)
port = 80;
if (_redirectLocation.startsWith("/"))
_actualURL = "http://" + host + ":" + port + _redirectLocation;
else
// this blows up completely on a redirect to https://, for example
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + "/" + _redirectLocation;
_actualURL = "http://" + host+ ":" + port + "/" + _redirectLocation;
}
// an MUE is an IOE
//} catch (MalformedURLException mue) {
// throw new IOException("Redirected from an invalid URL");
//}
} catch (URISyntaxException use) {
IOException ioe = new MalformedURLException("Redirected to invalid URL");
ioe.initCause(use);
throw ioe;
}
AuthState as = _authState;
if (_responseCode == 407) {
@@ -1099,7 +1139,7 @@ public class EepGet {
private int handleStatus(String line) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Status line: [" + line.trim() + "]");
String[] toks = line.split(" ", 3);
String[] toks = DataHelper.split(line, " ", 3);
if (toks.length < 2) {
if (_log.shouldLog(Log.WARN))
_log.warn("ERR: status "+ line);
@@ -1194,10 +1234,12 @@ public class EepGet {
if (_shouldProxy) {
_proxy = InternalSocket.getSocket(_proxyHost, _proxyPort);
} else {
//try {
URL url = new URL(_actualURL);
if ("http".equals(url.getProtocol())) {
try {
URI url = new URI(_actualURL);
if ("http".equals(url.getScheme())) {
String host = url.getHost();
if (host == null)
throw new MalformedURLException("URL is not supported:" + _actualURL);
String hostlc = host.toLowerCase(Locale.US);
if (hostlc.endsWith(".i2p"))
throw new UnknownHostException("I2P addresses must be proxied");
@@ -1216,10 +1258,11 @@ public class EepGet {
} else {
throw new MalformedURLException("URL is not supported:" + _actualURL);
}
// an MUE is an IOE
//} catch (MalformedURLException mue) {
// throw new IOException("Request URL is invalid");
//}
} catch (URISyntaxException use) {
IOException ioe = new MalformedURLException("Request URL is invalid");
ioe.initCause(use);
throw ioe;
}
}
_proxyIn = _proxy.getInputStream();
if (!(_proxy instanceof InternalSocket))
@@ -1241,13 +1284,20 @@ public class EepGet {
boolean post = false;
if ( (_postData != null) && (_postData.length() > 0) )
post = true;
URL url = new URL(_actualURL);
URI url;
try {
url = new URI(_actualURL);
} catch (URISyntaxException use) {
IOException ioe = new MalformedURLException("Bad URL");
ioe.initCause(use);
throw ioe;
}
String host = url.getHost();
if (host == null || host.length() <= 0)
throw new MalformedURLException("Bad URL, no host");
int port = url.getPort();
String path = url.getPath();
String query = url.getQuery();
String path = url.getRawPath();
String query = url.getRawQuery();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Requesting " + _actualURL);
// RFC 2616 sec 5.1.2 - full URL if proxied, absolute path only if not proxied
@@ -1470,7 +1520,7 @@ public class EepGet {
String key = null;
for (int i = 0; i < data.length; i++) {
switch (data[i]) {
case '\"':
case '"':
if (isQuoted) {
// keys never quoted
if (key != null) {

View File

@@ -6,7 +6,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import gnu.getopt.Getopt;
@@ -107,7 +109,7 @@ public class EepHead extends EepGet {
break;
} // switch
} // while
} catch (Exception e) {
} catch (RuntimeException e) {
e.printStackTrace();
error = true;
}
@@ -176,24 +178,31 @@ public class EepHead extends EepGet {
// Should we even follow redirects for HEAD?
if (_redirectLocation != null) {
//try {
try {
if (_redirectLocation.startsWith("http://")) {
_actualURL = _redirectLocation;
} else {
// the Location: field has been required to be an absolute URI at least since
// RFC 1945 (HTTP/1.0 1996), so it isn't clear what the point of this is.
// This oddly adds a ":" even if no port, but that seems to work.
URL url = new URL(_actualURL);
if (_redirectLocation.startsWith("/"))
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + _redirectLocation;
URI url = new URI(_actualURL);
String host = url.getHost();
if (host == null)
throw new MalformedURLException("Redirected to invalid URL");
int port = url.getPort();
if (port < 0)
port = 80;
if (_redirectLocation.startsWith("/"))
_actualURL = "http://" + host + ":" + port + _redirectLocation;
else
// this blows up completely on a redirect to https://, for example
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + "/" + _redirectLocation;
_actualURL = "http://" + host+ ":" + port + "/" + _redirectLocation;
}
// an MUE is an IOE
//} catch (MalformedURLException mue) {
// throw new IOException("Redirected from an invalid URL");
//}
} catch (URISyntaxException use) {
IOException ioe = new MalformedURLException("Redirected to invalid URL");
ioe.initCause(use);
throw ioe;
}
AuthState as = _authState;
if (_responseCode == 407) {
if (!_shouldProxy)
@@ -252,11 +261,20 @@ public class EepHead extends EepGet {
@Override
protected String getRequest() throws IOException {
StringBuilder buf = new StringBuilder(512);
URL url = new URL(_actualURL);
URI url;
try {
url = new URI(_actualURL);
} catch (URISyntaxException use) {
IOException ioe = new MalformedURLException("Bad URL");
ioe.initCause(use);
throw ioe;
}
String host = url.getHost();
if (host == null)
throw new MalformedURLException("Bad URL");
int port = url.getPort();
String path = url.getPath();
String query = url.getQuery();
String path = url.getRawPath();
String query = url.getRawQuery();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Requesting " + _actualURL);
// RFC 2616 sec 5.1.2 - full URL if proxied, absolute path only if not proxied

View File

@@ -300,9 +300,9 @@ public class FileUtil {
if (!_failedOracle) {
try {
Class<?> p200 = Class.forName("java.util.jar.Pack200", true, ClassLoader.getSystemClassLoader());
Method newUnpacker = p200.getMethod("newUnpacker", (Class[]) null);
Method newUnpacker = p200.getMethod("newUnpacker");
Object unpacker = newUnpacker.invoke(null,(Object[]) null);
Method unpack = unpacker.getClass().getMethod("unpack", new Class[] {InputStream.class, JarOutputStream.class});
Method unpack = unpacker.getClass().getMethod("unpack", InputStream.class, JarOutputStream.class);
// throws IOException
unpack.invoke(unpacker, new Object[] {in, out});
return;
@@ -321,9 +321,9 @@ public class FileUtil {
if (!_failedApache) {
try {
Class<?> p200 = Class.forName("org.apache.harmony.unpack200.Archive", true, ClassLoader.getSystemClassLoader());
Constructor<?> newUnpacker = p200.getConstructor(new Class[] {InputStream.class, JarOutputStream.class});
Object unpacker = newUnpacker.newInstance(new Object[] {in, out});
Method unpack = unpacker.getClass().getMethod("unpack", (Class[]) null);
Constructor<?> newUnpacker = p200.getConstructor(InputStream.class, JarOutputStream.class);
Object unpacker = newUnpacker.newInstance(in, out);
Method unpack = unpacker.getClass().getMethod("unpack");
// throws IOException or Pack200Exception
unpack.invoke(unpacker, (Object[]) null);
return;

View File

@@ -11,6 +11,7 @@ package net.i2p.util;
import gnu.crypto.prng.AsyncFortunaStandalone;
import java.io.IOException;
import java.security.SecureRandom;
import net.i2p.I2PAppContext;
@@ -266,7 +267,7 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
synchronized(_fortuna) {
_fortuna.addRandomBytes(data, offset, len);
}
} catch (Exception e) {
} catch (RuntimeException e) {
// AIOOBE seen, root cause unknown, ticket #1576
Log log = _context.logManager().getLog(FortunaRandomSource.class);
log.warn("feedEntropy()", e);
@@ -290,6 +291,6 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
rand.nextBytes(buf);
System.out.write(buf);
}
} catch (Exception e) { e.printStackTrace(); }
} catch (IOException e) { e.printStackTrace(); }
}
}

View File

@@ -14,10 +14,13 @@ import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Like I2PThread but with per-thread OOM listeners,
* Like {@link I2PThread} but with per-thread OOM listeners,
* rather than a static router-wide listener list,
* so that an OOM in an app won't call the router listener
* to shutdown the whole router.
*
* This is preferred for application use.
* See {@link I2PThread} for features.
*/
public class I2PAppThread extends I2PThread {
@@ -38,9 +41,17 @@ public class I2PAppThread extends I2PThread {
public I2PAppThread(Runnable r, String name) {
super(r, name);
}
public I2PAppThread(Runnable r, String name, boolean isDaemon) {
super(r, name, isDaemon);
}
/**
* @since 0.9.23
*/
public I2PAppThread(ThreadGroup group, Runnable r, String name) {
super(group, r, name);
}
@Override
protected void fireOOM(OutOfMemoryError oom) {

View File

@@ -83,6 +83,7 @@ import javax.net.ssl.TrustManagerFactory;
import net.i2p.I2PAppContext;
import net.i2p.crypto.KeyStoreUtil;
import net.i2p.data.DataHelper;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.util.PublicSuffixList;
@@ -204,7 +205,15 @@ public class I2PSSLSocketFactory {
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
// following is disabled because it is weak
// see e.g. https://bugzilla.mozilla.org/show_bug.cgi?id=1107787
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA"
// ??? "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"
//
// NOTE:
// If you add anything here, please also add to installer/resources/eepsite/jetty-ssl.xml
//
}));
/**
@@ -435,7 +444,7 @@ public class I2PSSLSocketFactory {
try {
if (line.charAt(0) == '#')
continue;
String[] s = line.split(",");
String[] s = DataHelper.split(line, ",");
String lc = s[0].toLowerCase(Locale.US);
tlds.add(lc);
i++;

View File

@@ -14,76 +14,63 @@ import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* In case its useful later...
* (e.g. w/ native programatic thread dumping, etc)
*
* As of 0.9.21, I2PThreads are initialized to NORM_PRIORITY
* (not the priority of the creating thread).
* Preferred over {@link Thread} for all router uses.
* For applications, {@link I2PAppThread} is preferred.
* <p>
* Provides the following features:
* <ul>
* <li>Logging to wrapper log on unexpected termination in {@link #run()}.
* <li>Notification of OOM to registered listener (the router),
* which will cause logging to the wrapper log and a router restart
* <li>Catching and logging "OOM" caused by thread limit in {@link #start()}
* with distinct message, and does not call the OOM listener.
* <li>As of 0.9.21, initialization to NORM_PRIORITY
* (not the priority of the creating thread).
* </ul>
*/
public class I2PThread extends Thread {
/**
* Non-static to avoid refs to old context in Android.
* Probably should just remove all the logging though.
* Logging removed, too much trouble with extra contexts
*/
//private volatile Log _log;
private static final Set<OOMEventListener> _listeners = new CopyOnWriteArraySet<OOMEventListener>();
//private String _name;
//private Exception _createdBy;
public I2PThread() {
super();
setPriority(NORM_PRIORITY);
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
// _createdBy = new Exception("Created by");
}
public I2PThread(String name) {
super(name);
setPriority(NORM_PRIORITY);
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
// _createdBy = new Exception("Created by");
}
public I2PThread(Runnable r) {
super(r);
setPriority(NORM_PRIORITY);
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
// _createdBy = new Exception("Created by");
}
public I2PThread(Runnable r, String name) {
super(r, name);
setPriority(NORM_PRIORITY);
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
// _createdBy = new Exception("Created by");
}
public I2PThread(Runnable r, String name, boolean isDaemon) {
super(r, name);
setDaemon(isDaemon);
setPriority(NORM_PRIORITY);
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
// _createdBy = new Exception("Created by");
}
public I2PThread(ThreadGroup g, Runnable r) {
super(g, r);
setPriority(NORM_PRIORITY);
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
// _createdBy = new Exception("Created by");
}
/****
private void log(int level, String msg) { log(level, msg, null); }
private void log(int level, String msg, Throwable t) {
// we cant assume log is created
if (_log == null) _log = new Log(I2PThread.class);
if (_log.shouldLog(level))
_log.log(level, msg, t);
/**
* @since 0.9.23
*/
public I2PThread(ThreadGroup group, Runnable r, String name) {
super(group, r, name);
setPriority(NORM_PRIORITY);
}
****/
/**
* Overridden to provide useful info to users on OOM, and to prevent
* shutting down the whole JVM for what is most likely not a heap issue.
@@ -103,25 +90,18 @@ public class I2PThread extends Thread {
System.out.println("Check ulimit -u, /etc/security/limits.conf, or /proc/sys/kernel/threads-max");
}
oom.printStackTrace();
if (!(SystemVersion.isWindows() || SystemVersion.isAndroid()))
throw new RuntimeException("Thread could not be started, " +
"Check ulimit -u, /etc/security/limits.conf, or /proc/sys/kernel/threads-max", oom);
throw new RuntimeException("Thread could not be started", oom);
}
}
@Override
public void run() {
//_name = Thread.currentThread().getName();
//log(Log.INFO, "New thread started" + (isDaemon() ? " (daemon): " : ": ") + _name, _createdBy);
try {
super.run();
} catch (Throwable t) {
/****
try {
log(Log.CRIT, "Thread terminated unexpectedly: " + getName(), t);
} catch (Throwable woof) {
System.err.println("Died within the OOM itself");
t.printStackTrace();
}
****/
if (t instanceof OutOfMemoryError) {
fireOOM((OutOfMemoryError)t);
} else {
@@ -129,18 +109,8 @@ public class I2PThread extends Thread {
t.printStackTrace();
}
}
// This creates a new I2PAppContext after it was deleted
// in Router.finalShutdown() via RouterContext.killGlobalContext()
//log(Log.INFO, "Thread finished normally: " + _name);
}
/****
protected void finalize() throws Throwable {
//log(Log.DEBUG, "Thread finalized: " + _name);
super.finalize();
}
****/
protected void fireOOM(OutOfMemoryError oom) {
for (OOMEventListener listener : _listeners)
listener.outOfMemory(oom);

View File

@@ -68,7 +68,7 @@ public class InternalSocket extends Socket {
}
@Override
public void close() {
public synchronized void close() {
try {
if (_is != null) {
_is.close();
@@ -84,7 +84,7 @@ public class InternalSocket extends Socket {
}
@Override
public boolean isClosed() {
public synchronized boolean isClosed() {
return _is == null || _os == null;
}

View File

@@ -22,7 +22,6 @@ import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
@@ -479,9 +478,7 @@ public class LogManager implements Flushable {
if (!format.equals(""))
fmt.applyPattern(format);
// the router sets the JVM time zone to UTC but saves the original here so we can get it
String systemTimeZone = _context.getProperty("i2p.systemTimeZone");
if (systemTimeZone != null)
fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone));
fmt.setTimeZone(SystemVersion.getSystemTimeZone(_context));
_dateFormatPattern = format;
_dateFormat = fmt;
return true;
@@ -763,7 +760,7 @@ public class LogManager implements Flushable {
private static final AtomicInteger __id = new AtomicInteger();
private class ShutdownHook extends Thread {
private class ShutdownHook extends I2PAppThread {
private final int _id;
public ShutdownHook() {
_id = __id.incrementAndGet();

View File

@@ -75,7 +75,7 @@ abstract class LogWriterBase implements Runnable {
if (_write && shouldReadConfig)
rereadConfig();
}
} catch (Exception e) {
} catch (RuntimeException e) {
System.err.println("Error writing the log: " + e);
e.printStackTrace();
}

View File

@@ -35,6 +35,7 @@ import freenet.support.CPUInformation.UnknownCPUException;
import net.i2p.I2PAppContext;
import net.i2p.crypto.CryptoConstants;
import net.i2p.data.DataHelper;
/**
* <p>BigInteger that takes advantage of the jbigi library for the modPow operation,
@@ -734,7 +735,7 @@ public class NativeBigInteger extends BigInteger {
in = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/cpuinfo"), "ISO-8859-1"), 4096);
String line = null;
while ( (line = in.readLine()) != null) {
String[] parts = line.split(":", 2);
String[] parts = DataHelper.split(line, ":", 2);
if (parts.length < 2)
continue;
String key = parts[0].trim().toLowerCase(Locale.US);

View File

@@ -6,7 +6,8 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
import gnu.getopt.Getopt;
@@ -106,7 +107,7 @@ public class PartialEepGet extends EepGet {
break;
} // switch
} // while
} catch (Exception e) {
} catch (RuntimeException e) {
e.printStackTrace();
error = true;
}
@@ -167,13 +168,20 @@ public class PartialEepGet extends EepGet {
@Override
protected String getRequest() throws IOException {
StringBuilder buf = new StringBuilder(2048);
URL url = new URL(_actualURL);
URI url;
try {
url = new URI(_actualURL);
} catch (URISyntaxException use) {
IOException ioe = new MalformedURLException("Bad URL");
ioe.initCause(use);
throw ioe;
}
String host = url.getHost();
if (host == null || host.length() <= 0)
throw new MalformedURLException("Bad URL, no host");
int port = url.getPort();
String path = url.getPath();
String query = url.getQuery();
String path = url.getRawPath();
String query = url.getRawQuery();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Requesting " + _actualURL);
// RFC 2616 sec 5.1.2 - full URL if proxied, absolute path only if not proxied

View File

@@ -99,6 +99,18 @@ public class PasswordManager {
String shash = _context.getProperty(pfx + PROP_SHASH);
if (shash == null)
return false;
return checkHash(shash, pw);
}
/**
* Check pw against b64 salt+hash, as generated by createHash()
*
* @param shash b64 string
* @param pw plain text non-null, already trimmed
* @return if pw verified
* @since 0.9.24
*/
public boolean checkHash(String shash, String pw) {
byte[] shashBytes = Base64.decode(shash);
if (shashBytes == null || shashBytes.length != SHASH_LENGTH)
return false;
@@ -110,6 +122,23 @@ public class PasswordManager {
return DataHelper.eq(hash, pwHash);
}
/**
* Create a salt+hash, to be saved and verified later by verifyHash().
*
* @param pw plain text non-null, already trimmed
* @return salted+hash b64 string
* @since 0.9.24
*/
public String createHash(String pw) {
byte[] salt = new byte[SALT_LENGTH];
_context.random().nextBytes(salt);
byte[] pwHash = _context.keyGenerator().generateSessionKey(salt, DataHelper.getUTF8(pw)).getData();
byte[] shashBytes = new byte[SHASH_LENGTH];
System.arraycopy(salt, 0, shashBytes, 0, SALT_LENGTH);
System.arraycopy(pwHash, 0, shashBytes, SALT_LENGTH, SessionKey.KEYSIZE_BYTES);
return Base64.encode(shashBytes);
}
/**
* Either plain or b64
*

View File

@@ -30,6 +30,10 @@ public class PortMapper {
public static final String SVC_SMTP = "SMTP";
public static final String SVC_POP = "POP3";
public static final String SVC_SAM = "SAM";
/** @since 0.9.24 */
public static final String SVC_SAM_UDP = "SAM-UDP";
/** @since 0.9.24 */
public static final String SVC_SAM_SSL = "SAM-SSL";
public static final String SVC_BOB = "BOB";
/** not necessary, already in config? */
public static final String SVC_I2CP = "I2CP";
@@ -111,7 +115,7 @@ public class PortMapper {
* @since 0.9.20
*/
public void renderStatusHTML(Writer out) throws IOException {
List<String> services = new ArrayList(_dir.keySet());
List<String> services = new ArrayList<String>(_dir.keySet());
out.write("<h2>Port Mapper</h2><table><tr><th>Service<th>Host<th>Port\n");
Collections.sort(services);
for (String s : services) {

View File

@@ -124,7 +124,7 @@ public class ResettableGZIPInputStream extends InflaterInputStream {
public long getTotalRead() {
try {
return inf.getBytesRead();
} catch (Exception e) {
} catch (RuntimeException e) {
return 0;
}
}
@@ -136,7 +136,7 @@ public class ResettableGZIPInputStream extends InflaterInputStream {
public long getTotalExpanded() {
try {
return inf.getBytesWritten();
} catch (Exception e) {
} catch (RuntimeException e) {
// possible NPE in some implementations
return 0;
}
@@ -149,7 +149,7 @@ public class ResettableGZIPInputStream extends InflaterInputStream {
public long getRemaining() {
try {
return inf.getRemaining();
} catch (Exception e) {
} catch (RuntimeException e) {
// possible NPE in some implementations
return 0;
}
@@ -162,7 +162,7 @@ public class ResettableGZIPInputStream extends InflaterInputStream {
public boolean getFinished() {
try {
return inf.finished();
} catch (Exception e) {
} catch (RuntimeException e) {
// possible NPE in some implementations
return true;
}

View File

@@ -46,7 +46,8 @@ import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
@@ -179,7 +180,7 @@ public class SSLEepGet extends EepGet {
break;
} // switch
} // while
} catch (Exception e) {
} catch (RuntimeException e) {
e.printStackTrace();
error = true;
}
@@ -369,7 +370,7 @@ public class SSLEepGet extends EepGet {
System.out.println(" Valid To: " + cert.getNotAfter());
try {
cert.checkValidity();
} catch (Exception e) {
} catch (GeneralSecurityException e) {
System.out.println(" WARNING: Certificate is not currently valid, it cannot be used");
}
CertUtil.saveCert(cert, new File(name));
@@ -553,12 +554,14 @@ public class SSLEepGet extends EepGet {
String req = getRequest();
//try {
URL url = new URL(_actualURL);
String host = null;
int port = 0;
if ("https".equals(url.getProtocol())) {
String host;
int port;
try {
URI url = new URI(_actualURL);
if ("https".equals(url.getScheme())) {
host = url.getHost();
if (host == null)
throw new MalformedURLException("Bad URL");
if (host.toLowerCase(Locale.US).endsWith(".i2p"))
throw new MalformedURLException("I2P addresses unsupported");
port = url.getPort();
@@ -589,10 +592,11 @@ public class SSLEepGet extends EepGet {
} else {
throw new MalformedURLException("Only https supported: " + _actualURL);
}
// an MUE is an IOE
//} catch (MalformedURLException mue) {
// throw new IOException("Request URL is invalid");
//}
} catch (URISyntaxException use) {
IOException ioe = new MalformedURLException("Redirected to invalid URL");
ioe.initCause(use);
throw ioe;
}
_proxyIn = _proxy.getInputStream();
_proxyOut = _proxy.getOutputStream();

View File

@@ -51,7 +51,7 @@ public class ShellCommand {
*
* @author hypercubus
*/
private class CommandThread extends Thread {
private class CommandThread extends I2PAppThread {
private final boolean consumeOutput;
private final Object shellCommand;
private final Result result;
@@ -84,7 +84,7 @@ public class ShellCommand {
*
* @author hypercubus
*/
private static class StreamConsumer extends Thread {
private static class StreamConsumer extends I2PAppThread {
private final BufferedReader bufferedReader;
public StreamConsumer(InputStream inputStream) {
@@ -115,7 +115,7 @@ public class ShellCommand {
*
* @author hypercubus
*/
private static class StreamReader extends Thread {
private static class StreamReader extends I2PAppThread {
private final BufferedReader bufferedReader;
public StreamReader(InputStream inputStream) {
@@ -149,7 +149,7 @@ public class ShellCommand {
*
* @author hypercubus
*/
private static class StreamWriter extends Thread {
private static class StreamWriter extends I2PAppThread {
private final BufferedWriter bufferedWriter;
public StreamWriter(OutputStream outputStream) {
@@ -439,7 +439,7 @@ public class ShellCommand {
System.out.println("ShellCommand waiting for \"" + name + '\"');
try {
process.waitFor();
} catch (Exception e) {
} catch (InterruptedException e) {
if (DEBUG) {
System.out.println("ShellCommand exception waiting for \"" + name + '\"');
e.printStackTrace();
@@ -457,7 +457,7 @@ public class ShellCommand {
if (process.exitValue() > 0)
return false;
}
} catch (Exception e) {
} catch (IOException e) {
// probably IOException, file not found from exec()
if (DEBUG) {
System.out.println("ShellCommand execute exception for \"" + name + '\"');

View File

@@ -118,11 +118,12 @@ public class SimpleTimer2 {
// (new Exception("OWCH! DAMN! Wrong ThreadGroup `" + name +"', `" + rv.getName() + "'")).printStackTrace();
// }
rv.setDaemon(true);
rv.setPriority(Thread.NORM_PRIORITY + 1);
return rv;
}
}
private ScheduledFuture schedule(TimedEvent t, long timeoutMs) {
private ScheduledFuture<?> schedule(TimedEvent t, long timeoutMs) {
return _executor.schedule(t, timeoutMs, TimeUnit.MILLISECONDS);
}
@@ -248,7 +249,7 @@ public class SimpleTimer2 {
private final SimpleTimer2 _pool;
private int _fuzz;
protected static final int DEFAULT_FUZZ = 3;
private ScheduledFuture _future; // _executor.remove() doesn't work so we have to use this
private ScheduledFuture<?> _future; // _executor.remove() doesn't work so we have to use this
// ... and I expect cancelling this way is more efficient
/** state of the current event. All access should be under lock. */
@@ -294,7 +295,7 @@ public class SimpleTimer2 {
if (timeoutMs <= 0) {
// streaming timers do call with timeoutMs == 0
if (timeoutMs < 0 && _log.shouldLog(Log.WARN))
_log.warn("Timeout <= 0: " + this + " timeout = " + timeoutMs + " state: " + _state);
_log.warn("Sched. timeout < 0: " + this + " timeout = " + timeoutMs + " state: " + _state);
timeoutMs = 1; // otherwise we may execute before _future is updated, which is fine
// except it triggers 'early execution' warning logging
}
@@ -336,6 +337,11 @@ public class SimpleTimer2 {
* two timeouts, else use the later
*/
public synchronized void reschedule(long timeoutMs, boolean useEarliestTime) {
if (timeoutMs <= 0) {
if (timeoutMs < 0 && _log.shouldWarn())
_log.warn("Resched. timeout < 0: " + this + " timeout = " + timeoutMs + " state: " + _state);
timeoutMs = 1;
}
final long now = System.currentTimeMillis();
long oldTimeout;
boolean scheduled = _state == TimedEventState.SCHEDULED;
@@ -348,6 +354,12 @@ public class SimpleTimer2 {
if ((oldTimeout - _fuzz > timeoutMs && useEarliestTime) ||
(oldTimeout + _fuzz < timeoutMs && !useEarliestTime)||
(!scheduled)) {
if (scheduled && oldTimeout <= 5) {
// don't reschedule to avoid race
if (_log.shouldWarn())
_log.warn("not rescheduling to " + timeoutMs + ", about to execute " + this + " in " + oldTimeout);
return;
}
if (scheduled && (now + timeoutMs) < _nextRun) {
if (_log.shouldLog(Log.INFO))
_log.info("Re-scheduling: " + this + " timeout = " + timeoutMs + " old timeout was " + oldTimeout + " state: " + _state);
@@ -381,10 +393,14 @@ public class SimpleTimer2 {
_cancelAfterRun = true;
return true;
case SCHEDULED:
boolean cancelled = _future.cancel(false);
// There's probably a race here, where it's cancelled after it's running
// The result (if rescheduled) is a dup on the queue, see tickets 1694, 1705
// Mitigated by close-to-execution check in reschedule()
boolean cancelled = _future.cancel(true);
if (cancelled)
_state = TimedEventState.CANCELLED;
else {} // log something as this could be serious, we remain RUNNING otherwise
else
_log.error("could not cancel " + this + " to run in " + (_nextRun - System.currentTimeMillis()), new Exception());
return cancelled;
}
return false;
@@ -406,6 +422,10 @@ public class SimpleTimer2 {
long before = System.currentTimeMillis();
long delay = 0;
synchronized(this) {
if (Thread.currentThread().isInterrupted()) {
_log.warn("I was interrupted in run, state "+_state+" event "+this);
return;
}
if (_rescheduleAfterRun)
throw new IllegalStateException(this + " rescheduleAfterRun cannot be true here");
@@ -415,13 +435,15 @@ public class SimpleTimer2 {
case IDLE: // fall through
case RUNNING:
throw new IllegalStateException(this + " not possible to be in " + _state);
case SCHEDULED: // proceed, switch to IDLE in case I need to reschedule
_state = TimedEventState.IDLE;
case SCHEDULED:
// proceed, will switch to IDLE to reschedule
}
// if I was rescheduled by the user, re-submit myself to the executor.
int difference = (int)(_nextRun - before); // careful with long uptimes
long difference = _nextRun - before; // careful with long uptimes
if (difference > _fuzz) {
// proceed, switch to IDLE to reschedule
_state = TimedEventState.IDLE;
schedule(difference);
return;
}
@@ -436,10 +458,12 @@ public class SimpleTimer2 {
else if (_log.shouldLog(Log.WARN))
_log.warn(_pool + " no _future " + this);
// This can be an incorrect warning especially after a schedule(0)
if (_log.shouldLog(Log.WARN) && delay > 100)
_log.warn(_pool + " early execution " + delay + ": " + this);
else if (_log.shouldLog(Log.WARN) && delay < -1000)
_log.warn(" late execution " + (0 - delay) + ": " + this + _pool.debug());
if (_log.shouldWarn()) {
if (delay > 100)
_log.warn(_pool + " early execution " + delay + ": " + this);
else if (delay < -1000)
_log.warn(" late execution " + (0 - delay) + ": " + this + _pool.debug());
}
try {
timeReached();
} catch (Throwable t) {

View File

@@ -5,6 +5,9 @@ package net.i2p.util;
*/
import java.lang.reflect.Field;
import java.util.TimeZone;
import net.i2p.I2PAppContext;
/**
* Methods to find out what system we are running on
@@ -18,6 +21,8 @@ public abstract class SystemVersion {
private static final boolean _isArm = System.getProperty("os.arch").startsWith("arm");
private static final boolean _isX86 = System.getProperty("os.arch").contains("86") ||
System.getProperty("os.arch").equals("amd64");
private static final boolean _isGentoo = System.getProperty("os.version").contains("gentoo") ||
System.getProperty("os.version").contains("hardened"); // Funtoo
private static final boolean _isAndroid;
private static final boolean _isApache;
private static final boolean _isGNU;
@@ -27,6 +32,7 @@ public abstract class SystemVersion {
private static final boolean _oneDotSix;
private static final boolean _oneDotSeven;
private static final boolean _oneDotEight;
private static final boolean _oneDotNine;
private static final int _androidSDK;
static {
@@ -62,10 +68,12 @@ public abstract class SystemVersion {
_oneDotSix = _androidSDK >= 9;
_oneDotSeven = _androidSDK >= 19;
_oneDotEight = false;
_oneDotNine = false;
} else {
_oneDotSix = VersionComparator.comp(System.getProperty("java.version"), "1.6") >= 0;
_oneDotSeven = _oneDotSix && VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
_oneDotEight = _oneDotSeven && VersionComparator.comp(System.getProperty("java.version"), "1.8") >= 0;
_oneDotNine = _oneDotEight && VersionComparator.comp(System.getProperty("java.version"), "1.9") >= 0;
}
}
@@ -95,6 +103,13 @@ public abstract class SystemVersion {
return _isGNU;
}
/**
* @since 0.9.23
*/
public static boolean isGentoo() {
return _isGentoo;
}
/**
* @since 0.9.8
*/
@@ -139,6 +154,15 @@ public abstract class SystemVersion {
return _oneDotEight;
}
/**
*
* @return true if Java 1.9 or higher, false for Android.
* @since 0.9.23
*/
public static boolean isJava9() {
return _oneDotNine;
}
/**
* This isn't always correct.
* http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit
@@ -181,4 +205,59 @@ public abstract class SystemVersion {
maxMemory = 96*1024*1024l;
return maxMemory;
}
/**
* The system's time zone, which is probably different from the
* JVM time zone, because Router changes the JVM default to GMT.
* It saves the old default in the context properties where we can get it.
* Use this to format a time in local time zone with DateFormat.setTimeZone().
*
* @return non-null
* @since 0.9.24
*/
public static TimeZone getSystemTimeZone() {
return getSystemTimeZone(I2PAppContext.getGlobalContext());
}
/**
* The system's time zone, which is probably different from the
* JVM time zone, because Router changes the JVM default to GMT.
* It saves the old default in the context properties where we can get it.
* Use this to format a time in local time zone with DateFormat.setTimeZone().
*
* @return non-null
* @since 0.9.24
*/
public static TimeZone getSystemTimeZone(I2PAppContext ctx) {
String systemTimeZone = ctx.getProperty("i2p.systemTimeZone");
if (systemTimeZone != null)
return TimeZone.getTimeZone(systemTimeZone);
return TimeZone.getDefault();
}
/**
* @since 0.9.24
*/
/****
public static void main(String[] args) {
System.out.println("64 bit : " + is64Bit());
System.out.println("Java 6 : " + isJava6());
System.out.println("Java 7 : " + isJava7());
System.out.println("Java 8 : " + isJava8());
System.out.println("Java 9 : " + isJava9());
System.out.println("Android : " + isAndroid());
if (isAndroid())
System.out.println(" Version: " + getAndroidVersion());
System.out.println("Apache : " + isApache());
System.out.println("ARM : " + isARM());
System.out.println("Mac : " + isMac());
System.out.println("Gentoo : " + isGentoo());
System.out.println("GNU : " + isGNU());
System.out.println("Windows : " + isWindows());
System.out.println("Wrapper : " + hasWrapper());
System.out.println("x86 : " + isX86());
System.out.println("Max mem : " + getMaxMemory());
}
****/
}

View File

@@ -65,7 +65,7 @@ public abstract class Translate {
* The {0} will be replaced by the parameter.
* Single quotes must be doubled, i.e. ' -> '' in the string.
* @param o parameter, not translated.
* To tranlslate parameter also, use _t("foo {0} bar", _t("baz"))
* To translate parameter also, use _t("foo {0} bar", _t("baz"))
* Do not double the single quotes in the parameter.
* Use autoboxing to call with ints, longs, floats, etc.
*/

View File

@@ -147,7 +147,7 @@ public class BlockFile implements Closeable {
bf.bfck(true);
bf.close();
raif.close();
} catch (Exception e) {
} catch (IOException e) {
e.printStackTrace();
}
}