propagate from branch 'i2p.i2p.zzz.ipv6' (head 5c147c6e394fae03752dcf497923a90e3f2db529)

to branch 'i2p.i2p' (head 7af6987d5546664f76589afe0cbeeb780f4b5d58)
This commit is contained in:
zzz
2013-07-20 12:59:03 +00:00
230 changed files with 32173 additions and 109751 deletions

View File

@ -139,13 +139,18 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
long before = System.currentTimeMillis();
doFill(aBuff.buffer);
long after = System.currentTimeMillis();
boolean shouldWait = _fullBuffers.size() > 1;
_fullBuffers.offer(aBuff);
_context.statManager().addRateData("prng.bufferFillTime", after - before, 0);
Thread.yield();
long waitTime = (after-before)*5;
if (waitTime <= 0) // somehow postman saw waitTime show up as negative
waitTime = 50;
try { Thread.sleep(waitTime); } catch (InterruptedException ie) {}
if (shouldWait) {
Thread.yield();
long waitTime = (after-before)*5;
if (waitTime <= 0) // somehow postman saw waitTime show up as negative
waitTime = 50;
else if (waitTime > 5000)
waitTime = 5000;
try { Thread.sleep(waitTime); } catch (InterruptedException ie) {}
}
}
}

View File

@ -16,7 +16,7 @@ package net.i2p;
public class CoreVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = "0.9.6";
public final static String VERSION = "0.9.7";
public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION);

View File

@ -80,12 +80,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
protected I2CPMessageReader _reader;
/** writer message queue */
protected ClientWriterRunner _writer;
/** where we pipe our messages */
protected /* FIXME final FIXME */OutputStream _out;
/**
* Used for internal connections to the router.
* If this is set, _socket, _writer, and _out will be null.
* If this is set, _socket and _writer will be null.
* @since 0.8.3
*/
protected I2CPMessageQueue _queue;
@ -94,7 +92,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
protected I2PSessionListener _sessionListener;
/** class that generates new messages */
protected I2CPMessageProducer _producer;
protected final I2CPMessageProducer _producer;
/** map of Long --> MessagePayloadMessage */
protected Map<Long, MessagePayloadMessage> _availableMessages;
@ -103,7 +101,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
protected final Object _bwReceivedLock = new Object();
protected volatile int[] _bwLimits;
protected I2PClientMessageHandlerMap _handlerMap;
protected final I2PClientMessageHandlerMap _handlerMap;
/** used to seperate things out so we can get rid of singletons */
protected final I2PAppContext _context;
@ -111,22 +109,24 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
/** monitor for waiting until a lease set has been granted */
private final Object _leaseSetWait = new Object();
/** whether the session connection has already been closed (or not yet opened) */
protected volatile boolean _closed;
/**
* @since 0.9.8
*/
protected enum State {
OPENING,
OPEN,
CLOSING,
CLOSED
}
/** whether the session connection is in the process of being closed */
protected volatile boolean _closing;
private State _state = State.CLOSED;
protected final Object _stateLock = new Object();
/** have we received the current date from the router yet? */
private volatile boolean _dateReceived;
/** lock that we wait upon, that the SetDateMessageHandler notifies */
private final Object _dateReceivedLock = new Object();
/** whether the session connection is in the process of being opened */
protected volatile boolean _opening;
/** monitor for waiting until opened */
private final Object _openingWait = new Object();
/**
* thread that we tell when new messages are available who then tells us
* to fetch them. The point of this is so that the fetch doesn't block the
@ -168,22 +168,24 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
public static final int LISTEN_PORT = 7654;
private static final int BUF_SIZE = 32*1024;
/**
* for extension by SimpleSession (no dest)
*/
protected I2PSessionImpl(I2PAppContext context, Properties options) {
this(context, options, false);
protected I2PSessionImpl(I2PAppContext context, Properties options,
I2PClientMessageHandlerMap handlerMap) {
this(context, options, handlerMap, false);
}
/**
* Basic setup of finals
* @since 0.9.7
*/
private I2PSessionImpl(I2PAppContext context, Properties options, boolean hasDest) {
private I2PSessionImpl(I2PAppContext context, Properties options,
I2PClientMessageHandlerMap handlerMap, boolean hasDest) {
_context = context;
_handlerMap = handlerMap;
_log = context.logManager().getLog(getClass());
_closed = true;
if (options == null)
options = (Properties) System.getProperties().clone();
_options = loadConfig(options);
@ -191,10 +193,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
_portNum = getPort();
_fastReceive = Boolean.parseBoolean(_options.getProperty(I2PClient.PROP_FAST_RECEIVE));
if (hasDest) {
_producer = new I2CPMessageProducer(context);
_availableMessages = new ConcurrentHashMap();
_myDestination = new Destination();
_privateKey = new PrivateKey();
_signingPrivateKey = new SigningPrivateKey();
} else {
_producer = null;
_availableMessages = null;
_myDestination = null;
_privateKey = null;
_signingPrivateKey = null;
@ -211,11 +217,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* @throws I2PSessionException if there is a problem loading the private keys or
*/
public I2PSessionImpl(I2PAppContext context, InputStream destKeyStream, Properties options) throws I2PSessionException {
this(context, options, true);
_handlerMap = new I2PClientMessageHandlerMap(context);
_producer = new I2CPMessageProducer(context);
this(context, options, new I2PClientMessageHandlerMap(context), true);
_availabilityNotifier = new AvailabilityNotifier();
_availableMessages = new ConcurrentHashMap();
try {
readDestination(destKeyStream);
} catch (DataFormatException dfe) {
@ -351,17 +354,13 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
return _leaseSet;
}
void setOpening(boolean ls) {
_opening = ls;
synchronized (_openingWait) {
_openingWait.notifyAll();
protected void changeState(State state) {
synchronized (_stateLock) {
_state = state;
_stateLock.notifyAll();
}
}
boolean getOpening() {
return _opening;
}
/**
* Load up the destKeyFile for our Destination, PrivateKey, and SigningPrivateKey
*
@ -378,12 +377,41 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* Connect to the router and establish a session. This call blocks until
* a session is granted.
*
* Should be threadsafe, other threads will block until complete.
* Disconnect / destroy from another thread may be called simultaneously and
* will (should?) interrupt the connect.
*
* @throws I2PSessionException if there is a configuration error or the router is
* not reachable
*/
public void connect() throws I2PSessionException {
setOpening(true);
_closed = false;
synchronized(_stateLock) {
boolean wasOpening = false;
boolean loop = true;
while (loop) {
switch (_state) {
case CLOSED:
if (wasOpening)
throw new I2PSessionException("connect by other thread failed");
loop = false;
break;
case OPENING:
wasOpening = true;
try {
_stateLock.wait(10*1000);
} catch (InterruptedException ie) {
throw new I2PSessionException("Interrupted", ie);
}
break;
case CLOSING:
throw new I2PSessionException("close in progress");
case OPEN:
return;
}
}
changeState(State.OPENING);
}
_availabilityNotifier.stopNotifying();
if ( (_options != null) &&
@ -392,32 +420,34 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
_log.error("I2CP guaranteed delivery mode has been removed, using best effort.");
}
boolean success = false;
long startConnect = _context.clock().now();
try {
// If we are in the router JVM, connect using the interal queue
if (_context.isRouterContext()) {
// _socket, _out, and _writer remain null
InternalClientManager mgr = _context.internalClientManager();
if (mgr == null)
throw new I2PSessionException("Router is not ready for connections");
// the following may throw an I2PSessionException
_queue = mgr.connect();
_reader = new QueuedI2CPMessageReader(_queue, this);
} else {
if (Boolean.parseBoolean(_options.getProperty(PROP_ENABLE_SSL)))
_socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
else
_socket = new Socket(_hostname, _portNum);
// _socket.setSoTimeout(1000000); // Uhmmm we could really-really use a real timeout, and handle it.
_out = _socket.getOutputStream();
_out.write(I2PClient.PROTOCOL_BYTE);
_out.flush();
_writer = new ClientWriterRunner(_out, this);
InputStream in = new BufferedInputStream(_socket.getInputStream(), BUF_SIZE);
_reader = new I2CPMessageReader(in, this);
// protect w/ closeSocket()
synchronized(_stateLock) {
// If we are in the router JVM, connect using the interal queue
if (_context.isRouterContext()) {
// _socket and _writer remain null
InternalClientManager mgr = _context.internalClientManager();
if (mgr == null)
throw new I2PSessionException("Router is not ready for connections");
// the following may throw an I2PSessionException
_queue = mgr.connect();
_reader = new QueuedI2CPMessageReader(_queue, this);
} else {
if (Boolean.parseBoolean(_options.getProperty(PROP_ENABLE_SSL)))
_socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
else
_socket = new Socket(_hostname, _portNum);
// _socket.setSoTimeout(1000000); // Uhmmm we could really-really use a real timeout, and handle it.
OutputStream out = _socket.getOutputStream();
out.write(I2PClient.PROTOCOL_BYTE);
out.flush();
_writer = new ClientWriterRunner(out, this);
InputStream in = new BufferedInputStream(_socket.getInputStream(), BUF_SIZE);
_reader = new I2CPMessageReader(in, this);
}
}
Thread notifier = new I2PAppThread(_availabilityNotifier, "ClientNotifier " + getPrefix(), true);
notifier.start();
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "before startReading");
_reader.startReading();
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Before getDate");
@ -426,55 +456,60 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
int waitcount = 0;
while (!_dateReceived) {
if (waitcount++ > 30) {
closeSocket();
throw new IOException("No handshake received from the router");
}
try {
synchronized (_dateReceivedLock) {
_dateReceivedLock.wait(1000);
}
} catch (InterruptedException ie) { // nop
synchronized (_dateReceivedLock) {
// InterruptedException caught below
_dateReceivedLock.wait(1000);
}
}
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "After received a SetDate response");
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Before producer.connect()");
_producer.connect(this);
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "After producer.connect()");
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "After producer.connect()");
// wait until we have created a lease set
waitcount = 0;
while (_leaseSet == null) {
if (waitcount++ > 5*60) {
throw new IOException("No tunnels built after waiting 5 minutes. Your network connection may be down, or there is severe network congestion.");
}
synchronized (_leaseSetWait) {
// InterruptedException caught below
_leaseSetWait.wait(1000);
}
}
if (_log.shouldLog(Log.INFO)) {
long connected = _context.clock().now();
_log.info(getPrefix() + "Lease set created with inbound tunnels after "
+ (connected - startConnect)
+ "ms - ready to participate in the network!");
}
Thread notifier = new I2PAppThread(_availabilityNotifier, "ClientNotifier " + getPrefix(), true);
notifier.start();
startIdleMonitor();
startVerifyUsage();
success = true;
} catch (InterruptedException ie) {
throw new I2PSessionException("Interrupted", ie);
} catch (UnknownHostException uhe) {
throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe);
} catch (IOException ioe) {
throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, ioe);
} finally {
if (success) {
changeState(State.OPEN);
} else {
_availabilityNotifier.stopNotifying();
synchronized(_stateLock) {
changeState(State.CLOSING);
try {
_producer.disconnect(this);
} catch (I2PSessionException ipe) {}
closeSocket();
throw new IOException("No tunnels built after waiting 5 minutes. Your network connection may be down, or there is severe network congestion.");
}
synchronized (_leaseSetWait) {
try {
_leaseSetWait.wait(1000);
} catch (InterruptedException ie) { // nop
}
}
}
long connected = _context.clock().now();
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix() + "Lease set created with inbound tunnels after "
+ (connected - startConnect)
+ "ms - ready to participate in the network!");
startIdleMonitor();
startVerifyUsage();
setOpening(false);
} catch (UnknownHostException uhe) {
_closed = true;
setOpening(false);
throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe);
} catch (IOException ioe) {
_closed = true;
setOpening(false);
throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, ioe);
}
}
@ -570,8 +605,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* Needs work.
*/
protected class AvailabilityNotifier implements Runnable {
private final List _pendingIds;
private final List _pendingSizes;
private final List<Long> _pendingIds;
private final List<Integer> _pendingSizes;
private volatile boolean _alive;
public AvailabilityNotifier() {
@ -606,8 +641,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
}
if (!_pendingIds.isEmpty()) {
msgId = (Long)_pendingIds.remove(0);
size = (Integer)_pendingSizes.remove(0);
msgId = _pendingIds.remove(0);
size = _pendingSizes.remove(0);
}
}
if ( (msgId != null) && (size != null) ) {
@ -695,8 +730,15 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
/** configure the listener */
public void setSessionListener(I2PSessionListener lsnr) { _sessionListener = lsnr; }
/** has the session been closed (or not yet connected)? */
public boolean isClosed() { return _closed; }
/**
* Has the session been closed (or not yet connected)?
* False when open and during transitions. Unsynchronized.
*/
public boolean isClosed() {
synchronized (_stateLock) {
return _state == State.CLOSED;
}
}
/**
* Deliver an I2CP message to the router
@ -713,7 +755,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
if (!_queue.offer(message, MAX_SEND_WAIT))
throw new I2PSessionException("Timed out waiting while write queue was full");
} catch (InterruptedException ie) {
throw new I2PSessionException("Interrupted while write queue was full", ie);
throw new I2PSessionException("Interrupted", ie);
}
} else if (_writer == null) {
throw new I2PSessionException("Already closed");
@ -756,21 +798,16 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
/**
* Tear down the session, and do NOT reconnect.
*
* Blocks if session has not been fully started.
* Will interrupt an open in progress.
*/
public void destroySession(boolean sendDisconnect) {
while (_opening) {
synchronized (_openingWait) {
try {
_openingWait.wait(1000);
} catch (InterruptedException ie) { // nop
}
}
synchronized(_stateLock) {
if (_state == State.CLOSING || _state == State.CLOSED)
return;
changeState(State.CLOSING);
}
if (_closed) return;
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "Destroy the session", new Exception("DestroySession()"));
_closing = true; // we use this to prevent a race
if (sendDisconnect && _producer != null) { // only null if overridden by I2PSimpleSession
try {
_producer.disconnect(this);
@ -783,19 +820,27 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
// SimpleSession does not initialize
if (_availabilityNotifier != null)
_availabilityNotifier.stopNotifying();
_closed = true;
_closing = false;
closeSocket();
if (_sessionListener != null) _sessionListener.disconnected(this);
}
/**
* Close the socket carefully
*
* Close the socket carefully.
*/
private void closeSocket() {
synchronized(_stateLock) {
changeState(State.CLOSING);
locked_closeSocket();
changeState(State.CLOSED);
}
}
/**
* Close the socket carefully.
* Caller must change state.
*/
private void locked_closeSocket() {
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "Closing the socket", new Exception("closeSocket"));
_closed = true;
if (_reader != null) {
_reader.stopReading();
_reader = null;
@ -830,8 +875,15 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
disconnect();
}
/**
* Will interrupt a connect in progress.
*/
protected void disconnect() {
if (_closed || _closing) return;
synchronized(_stateLock) {
if (_state == State.CLOSING || _state == State.CLOSED)
return;
changeState(State.CLOSING);
}
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Disconnect() called", new Exception("Disconnect"));
if (shouldReconnect()) {
if (reconnect()) {
@ -842,11 +894,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
if (_log.shouldLog(Log.ERROR))
_log.error(getPrefix() + "Disconned from the router, and not trying to reconnect further. I hope you're not hoping anything else will happen");
_log.error(getPrefix() + "Disconned from the router, and not trying to reconnect");
if (_sessionListener != null) _sessionListener.disconnected(this);
_closed = true;
closeSocket();
changeState(State.CLOSED);
}
private final static int MAX_RECONNECT_DELAY = 320*1000;
@ -865,7 +917,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
i++;
if ( (delay > MAX_RECONNECT_DELAY) || (delay <= 0) )
delay = MAX_RECONNECT_DELAY;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
return false;
}
try {
connect();
@ -970,7 +1026,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
if (rv != null)
return rv;
}
if (_closed)
if (isClosed())
return null;
LookupWaiter waiter = new LookupWaiter(h);
_pendingLookups.offer(waiter);
@ -980,7 +1036,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
synchronized (waiter) {
waiter.wait(maxWait);
}
} catch (InterruptedException ie) {}
} catch (InterruptedException ie) {
throw new I2PSessionException("Interrupted", ie);
}
} finally {
_pendingLookups.remove(waiter);
}
@ -996,14 +1054,16 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* @return null on failure
*/
public int[] bandwidthLimits() throws I2PSessionException {
if (_closed)
if (isClosed())
return null;
sendMessage(new GetBandwidthLimitsMessage());
try {
synchronized (_bwReceivedLock) {
_bwReceivedLock.wait(5*1000);
}
} catch (InterruptedException ie) {}
} catch (InterruptedException ie) {
throw new I2PSessionException("Interrupted", ie);
}
return _bwLimits;
}

View File

@ -44,9 +44,12 @@ class I2PSessionImpl2 extends I2PSessionImpl {
/** Don't expect any MSMs from the router for outbound traffic @since 0.8.1 */
protected boolean _noEffort;
/** for extension */
protected I2PSessionImpl2(I2PAppContext context, Properties options) {
super(context, options);
/**
* for extension by SimpleSession (no dest)
*/
protected I2PSessionImpl2(I2PAppContext context, Properties options,
I2PClientMessageHandlerMap handlerMap) {
super(context, options, handlerMap);
}
/**

View File

@ -8,6 +8,7 @@ package net.i2p.client;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Properties;
@ -37,53 +38,57 @@ class I2PSimpleSession extends I2PSessionImpl2 {
* @throws I2PSessionException if there is a problem
*/
public I2PSimpleSession(I2PAppContext context, Properties options) throws I2PSessionException {
super(context, options);
_handlerMap = new SimpleMessageHandlerMap(context);
super(context, options, new SimpleMessageHandlerMap(context));
}
/**
* Connect to the router and establish a session. This call blocks until
* a session is granted.
*
* NOT threadsafe, do not call from multiple threads.
*
* @throws I2PSessionException if there is a configuration error or the router is
* not reachable
*/
@Override
public void connect() throws I2PSessionException {
_closed = false;
changeState(State.OPENING);
boolean success = false;
try {
// If we are in the router JVM, connect using the interal queue
if (_context.isRouterContext()) {
// _socket, _out, and _writer remain null
InternalClientManager mgr = _context.internalClientManager();
if (mgr == null)
throw new I2PSessionException("Router is not ready for connections");
// the following may throw an I2PSessionException
_queue = mgr.connect();
_reader = new QueuedI2CPMessageReader(_queue, this);
} else {
if (Boolean.parseBoolean(getOptions().getProperty(PROP_ENABLE_SSL)))
_socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
else
_socket = new Socket(_hostname, _portNum);
_out = _socket.getOutputStream();
_out.write(I2PClient.PROTOCOL_BYTE);
_out.flush();
_writer = new ClientWriterRunner(_out, this);
InputStream in = new BufferedInputStream(_socket.getInputStream(), BUF_SIZE);
_reader = new I2CPMessageReader(in, this);
// protect w/ closeSocket()
synchronized(_stateLock) {
// If we are in the router JVM, connect using the interal queue
if (_context.isRouterContext()) {
// _socket and _writer remain null
InternalClientManager mgr = _context.internalClientManager();
if (mgr == null)
throw new I2PSessionException("Router is not ready for connections");
// the following may throw an I2PSessionException
_queue = mgr.connect();
_reader = new QueuedI2CPMessageReader(_queue, this);
} else {
if (Boolean.parseBoolean(getOptions().getProperty(PROP_ENABLE_SSL)))
_socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
else
_socket = new Socket(_hostname, _portNum);
OutputStream out = _socket.getOutputStream();
out.write(I2PClient.PROTOCOL_BYTE);
out.flush();
_writer = new ClientWriterRunner(out, this);
InputStream in = new BufferedInputStream(_socket.getInputStream(), BUF_SIZE);
_reader = new I2CPMessageReader(in, this);
}
}
// we do not receive payload messages, so we do not need an AvailabilityNotifier
// ... or an Idle timer, or a VerifyUsage
_reader.startReading();
success = true;
} catch (UnknownHostException uhe) {
_closed = true;
throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe);
} catch (IOException ioe) {
_closed = true;
throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, ioe);
} finally {
changeState(success ? State.OPEN : State.CLOSED);
}
}

View File

@ -89,8 +89,19 @@ public class FileUtil {
/**
* As of release 0.7.12, any files inside the zip that have a .jar.pack or .war.pack suffix
* are transparently unpacked to a .jar or .war file using unpack200.
* Logs at WARN level to wrapper.log
*/
public static boolean extractZip(File zipfile, File targetDir) {
return extractZip(zipfile, targetDir, Log.WARN);
}
/**
* @param logLevel Log.WARN, etc.
* @return true if it was copied successfully
* @since 0.9.7
*/
public static boolean extractZip(File zipfile, File targetDir, int logLevel) {
int files = 0;
ZipFile zip = null;
try {
byte buf[] = new byte[16*1024];
@ -107,7 +118,8 @@ public class FileUtil {
if ( (parent != null) && (!parent.exists()) ) {
boolean parentsOk = parent.mkdirs();
if (!parentsOk) {
System.err.println("ERROR: Unable to create the parent dir for " + entry.getName() + ": [" + parent.getAbsolutePath() + "]");
if (logLevel <= Log.ERROR)
System.err.println("ERROR: Unable to create the parent dir for " + entry.getName() + ": [" + parent.getAbsolutePath() + "]");
return false;
}
}
@ -115,9 +127,10 @@ public class FileUtil {
if (!target.exists()) {
boolean created = target.mkdirs();
if (!created) {
System.err.println("ERROR: Unable to create the directory [" + entry.getName() + "]");
if (logLevel <= Log.ERROR)
System.err.println("ERROR: Unable to create the directory [" + entry.getName() + "]");
return false;
} else {
} else if (logLevel <= Log.INFO) {
System.err.println("INFO: Creating directory [" + entry.getName() + "]");
}
}
@ -131,28 +144,35 @@ public class FileUtil {
target = new File(targetDir, entry.getName().substring(0, entry.getName().length() - ".pack".length()));
jos = new JarOutputStream(new FileOutputStream(target));
unpack(in, jos);
System.err.println("INFO: File [" + entry.getName() + "] extracted and unpacked");
if (logLevel <= Log.INFO)
System.err.println("INFO: File [" + entry.getName() + "] extracted and unpacked");
} else {
fos = new FileOutputStream(target);
int read = 0;
while ( (read = in.read(buf)) != -1) {
fos.write(buf, 0, read);
}
System.err.println("INFO: File [" + entry.getName() + "] extracted");
if (logLevel <= Log.INFO)
System.err.println("INFO: File [" + entry.getName() + "] extracted");
}
files++;
} catch (IOException ioe) {
System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + ')');
if (ioe.getMessage() != null && ioe.getMessage().indexOf("CAFED00D") >= 0)
System.err.println("This may be caused by a packed library that requires Java 1.6, your Java version is: " +
System.getProperty("java.version"));
ioe.printStackTrace();
if (logLevel <= Log.ERROR) {
System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + ')');
if (ioe.getMessage() != null && ioe.getMessage().indexOf("CAFED00D") >= 0)
System.err.println("This may be caused by a packed library that requires Java 1.6, your Java version is: " +
System.getProperty("java.version"));
ioe.printStackTrace();
}
return false;
} catch (Exception e) {
// Oracle unpack() should throw an IOE but other problems can happen, e.g:
// java.lang.reflect.InvocationTargetException
// Caused by: java.util.zip.ZipException: duplicate entry: xxxxx
System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + ')');
e.printStackTrace();
if (logLevel <= Log.ERROR) {
System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + ')');
e.printStackTrace();
}
return false;
} finally {
try { if (in != null) in.close(); } catch (IOException ioe) {}
@ -163,13 +183,17 @@ public class FileUtil {
}
return true;
} catch (IOException ioe) {
System.err.println("ERROR: Unable to extract the zip file");
ioe.printStackTrace();
if (logLevel <= Log.ERROR) {
System.err.println("ERROR: Unable to extract the zip file");
ioe.printStackTrace();
}
return false;
} finally {
if (zip != null) {
try { zip.close(); } catch (IOException ioe) {}
}
if (files > 0 && logLevel <= Log.WARN)
System.err.println("INFO: " + files + " files extracted to " + targetDir);
}
}

View File

@ -262,27 +262,23 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
}
}
/*****
/**
* Outputs to stdout for dieharder:
* <code>
* java -cp build/i2p.jar net.i2p.util.FortunaRandomSource | dieharder -a -g 200
* </code>
*/
public static void main(String args[]) {
try {
RandomSource rand = I2PAppContext.getGlobalContext().random();
if (true) {
for (int i = 0; i < 1000; i++)
if (rand.nextFloat() < 0)
throw new RuntimeException("negative!");
System.out.println("All positive");
return;
java.util.Properties props = new java.util.Properties();
props.setProperty("prng.buffers", "12");
I2PAppContext ctx = new I2PAppContext(props);
RandomSource rand = ctx.random();
byte[] buf = new byte[65536];
while (true) {
rand.nextBytes(buf);
System.out.write(buf);
}
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
java.util.zip.GZIPOutputStream gos = new java.util.zip.GZIPOutputStream(baos);
for (int i = 0; i < 1024*1024; i++) {
int c = rand.nextInt(256);
gos.write((byte)c);
}
gos.finish();
byte compressed[] = baos.toByteArray();
System.out.println("Compressed size of 1MB: " + compressed.length);
} catch (Exception e) { e.printStackTrace(); }
}
*****/
}

View File

@ -87,6 +87,7 @@ public class SimpleTimer2 {
/**
* Stops the SimpleTimer.
* Subsequent executions should not throw a RejectedExecutionException.
* Cannot be restarted.
*/
public void stop() {
_executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());

View File

@ -1,6 +1,7 @@
package net.i2p.util;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
@ -64,43 +65,33 @@ public abstract class Translate {
* Use autoboxing to call with ints, longs, floats, etc.
*/
public static String getString(String s, Object o, I2PAppContext ctx, String bun) {
String lang = getLanguage(ctx);
if (lang.equals(TEST_LANG))
return TEST_STRING + '(' + o + ')' + TEST_STRING;
String x = getString(s, ctx, bun);
Object[] oArray = new Object[1];
oArray[0] = o;
try {
MessageFormat fmt = new MessageFormat(x, new Locale(lang));
return fmt.format(oArray, new StringBuffer(), null).toString();
} catch (IllegalArgumentException iae) {
System.err.println("Bad format: orig: \"" + s +
"\" trans: \"" + x +
"\" param: \"" + o +
"\" lang: " + lang);
return "FIXME: " + x + ' ' + o;
}
return getString(s, ctx, bun, o);
}
/** for {0} and {1} */
public static String getString(String s, Object o, Object o2, I2PAppContext ctx, String bun) {
return getString(s, ctx, bun, o, o2);
}
/**
* Varargs
* @param oArray parameters
* @since 0.9.8
*/
public static String getString(String s, I2PAppContext ctx, String bun, Object... oArray) {
String lang = getLanguage(ctx);
if (lang.equals(TEST_LANG))
return TEST_STRING + '(' + o + ',' + o2 + ')' + TEST_STRING;
return TEST_STRING + Arrays.toString(oArray) + TEST_STRING;
String x = getString(s, ctx, bun);
Object[] oArray = new Object[2];
oArray[0] = o;
oArray[1] = o2;
try {
MessageFormat fmt = new MessageFormat(x, new Locale(lang));
return fmt.format(oArray, new StringBuffer(), null).toString();
} catch (IllegalArgumentException iae) {
System.err.println("Bad format: orig: \"" + s +
"\" trans: \"" + x +
"\" param1: \"" + o +
"\" param2: \"" + o2 +
"\" lang: " + lang);
return "FIXME: " + x + ' ' + o + ',' + o2;
"\" params: " + Arrays.toString(oArray) +
" lang: " + lang);
return "FIXME: " + x + ' ' + Arrays.toString(oArray);
}
}

View File

@ -0,0 +1,449 @@
package net.i2p.util;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilterReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.i2p.I2PAppContext;
/**
* Translate.
*
* Strings are tagged with _("translateme")
* or _("translate {0} me", "foo")
*
* Max two parameters.
* String and parameters must be double-quoted (no ngettext, no tagged parameters).
* Escape quotes inside quote with \".
* Commas and spaces between args are optional.
* Entire tag (from '_' to ')') must be on one line.
* Multiple tags allowed on one line.
*
* Also will extract strings to a dummy java file for postprocessing by xgettext - see main().
*
* @since 0.9.8
*/
public class TranslateReader extends FilterReader {
/** all states may transition to START */
private enum S {
START,
/** next state LPAREN */
UNDER,
/** next state QUOTE */
LPAREN,
/** next state LPAREN or BACK */
QUOTE,
/** next state QUOTE */
BACK
}
private final String _bundle;
private final I2PAppContext _ctx;
/** parse in progress */
private final StringBuilder _inBuf;
/** parsed and translated */
private final StringBuilder _outBuf;
/** pending string or parameter for translation */
private final StringBuilder _argBuf;
/** parsed string and parameters */
private final List<String> _args;
private S _state = S.START;
private TagHook _hook;
private static final int MAX_ARGS = 9;
/**
* @param bundle may be null for tagging only
* @param in UTF-8
*/
public TranslateReader(I2PAppContext ctx, String bundle, InputStream in) throws IOException {
super(new BufferedReader(new InputStreamReader(in, "UTF-8")));
_ctx = ctx;
_bundle = bundle;
_args = new ArrayList(4);
_inBuf = new StringBuilder(64);
_outBuf = new StringBuilder(64);
_argBuf = new StringBuilder(64);
}
@Override
public int read() throws IOException {
int rv = popit();
if (rv > 0)
return rv;
return parse();
}
private int parse() throws IOException {
while (true) {
int c = in.read();
if (c >= 0)
pushit((char) c);
//System.err.println("State: " + _state + " char: '" + ((char)c) + "'");
switch (c) {
case -1:
case '\r':
case '\n':
return flushit();
case '_':
switch (_state) {
case START:
_state = S.UNDER;
break;
case BACK:
_state = S.QUOTE;
// fall thru
case QUOTE:
_argBuf.append((char) c);
break;
default:
return flushit();
}
break;
case '(':
switch (_state) {
case UNDER:
_args.clear();
_state = S.LPAREN;
break;
case BACK:
_state = S.QUOTE;
// fall thru
case QUOTE:
_argBuf.append((char) c);
break;
default:
return flushit();
}
break;
case '"':
switch (_state) {
case LPAREN:
// got an opening quote for a parameter
if (_args.size() >= MAX_ARGS)
return flushit();
_argBuf.setLength(0);
_state = S.QUOTE;
break;
case BACK:
_argBuf.append((char) c);
_state = S.QUOTE;
break;
case QUOTE:
// got a closing quote for a parameter
_args.add(_argBuf.toString());
_state = S.LPAREN;
break;
default:
return flushit();
}
break;
case '\\':
switch (_state) {
case QUOTE:
_state = S.BACK;
break;
case BACK:
_argBuf.append((char) c);
_state = S.QUOTE;
break;
default:
return flushit();
}
break;
case ' ':
case '\t':
case ',':
switch (_state) {
case BACK:
_state = S.QUOTE;
// fall thru
case QUOTE:
_argBuf.append((char) c);
break;
case LPAREN:
// ignore whitespace and commas between args
break;
default:
return flushit();
}
break;
case ')':
switch (_state) {
case BACK:
_state = S.QUOTE;
// fall thru
case QUOTE:
_argBuf.append((char) c);
break;
case LPAREN:
// Finally, we have something to translate!
translate();
return popit();
default:
return flushit();
}
break;
default:
switch (_state) {
case BACK:
_state = S.QUOTE;
// fall thru
case QUOTE:
_argBuf.append((char) c);
break;
default:
return flushit();
}
break;
}
}
}
@Override
public int read(char cbuf[], int off, int len) throws IOException {
for (int i = 0; i < len; i++) {
int c = read();
if (c < 0) {
if (i == 0)
return -1;
return i;
}
cbuf[off + i] = (char) c;
}
return len;
}
@Override
public long skip(long n) throws IOException {
for (long i = 0; i < n; i++) {
int c = read();
if (c < 0) {
if (i == 0)
return -1;
return i;
}
}
return n;
}
@Override
public boolean ready() throws IOException {
return _outBuf.length() > 0 || _inBuf.length() > 0 ||in.ready();
}
@Override
public void close() throws IOException {
_inBuf.setLength(0);
_outBuf.setLength(0);
_state = S.START;
in.close();
}
@Override
public void mark(int readLimit) {}
@Override
public void reset() throws IOException {
throw new IOException();
}
@Override
public boolean markSupported() {
return false;
}
/**
* put in the pending parse buf
*/
private void pushit(char c) {
_inBuf.append(c);
}
/**
* flush _inBuf to _outBuf,
* reset state,
* and return next char or -1
*/
private int flushit() {
_state = S.START;
if (_inBuf.length() > 0) {
_outBuf.append(_inBuf);
_inBuf.setLength(0);
}
return popit();
}
/**
* return next char from _outBuf or -1
*/
private int popit() {
if (_outBuf.length() > 0) {
int rv = _outBuf.charAt(0) & 0xffff;
_outBuf.deleteCharAt(0);
return rv;
}
return -1;
}
/**
* clear _inBuf, translate _args to _outBuf,
* reset state
*/
private void translate() {
//System.err.println("Translating: " + _args.toString());
int argCount = _args.size();
if (argCount <= 0 || argCount > MAX_ARGS) {
flushit();
return;
}
_state = S.START;
_inBuf.setLength(0);
if (_hook != null) {
_hook.tag(_args);
return;
}
String tx = null;
if (argCount == 1)
tx = Translate.getString(_args.get(0), _ctx, _bundle);
else
tx = Translate.getString(_args.get(0), _ctx, _bundle, _args.subList(1, _args.size()).toArray());
_outBuf.append(tx);
}
private interface TagHook extends Closeable {
public void tag(List<String> args);
}
private static class Tagger implements TagHook {
private final PrintStream _out;
private final String _name;
private int _count;
public Tagger(String file) throws IOException {
_name = file;
_out = new PrintStream(file, "UTF-8");
_out.println("// Automatically generated, do not edit");
_out.println("package dummy;");
_out.println("class Dummy {");
_out.println(" void dummy() {");
}
public void tag(List<String> args) {
if (args.size() <= 0)
return;
_out.print("\t_(");
for (int i = 0; i < args.size(); i++) {
if (i > 0)
_out.print(", ");
_out.print('"');
_out.print(args.get(i).replace("\"", "\\\""));
_out.print('"');
}
_out.println(");");
_count++;
}
public void close() throws IOException {
_out.println(" }");
_out.println("}");
if (_out.checkError())
throw new IOException();
_out.close();
System.out.println(_count + " strings written to " + _name);
}
}
public static void main(String[] args) {
try {
if (args.length >= 2 && args[0].equals("test"))
test(args[1]);
else if (args.length >= 2 && args[0].equals("tag"))
tag(args);
else
System.err.println("Usage:\n" +
"\ttest file (output to stdout)\n" +
"\ttag file (output to file.java)\n" +
"\ttag dir outfile\n" +
"\ttag file1 [file2...] outfile");
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
private static void test(String file) throws IOException {
TranslateReader r = new TranslateReader(I2PAppContext.getGlobalContext(),
"net.i2p.router.web.messages",
new FileInputStream(file));
int c;
while ((c = r.read()) >= 0) {
System.out.print((char)c);
}
System.out.flush();
}
/** @param files ignore 0 */
private static void tag(String[] files) throws IOException {
char[] buf = new char[256];
String outfile;
List<String> filelist;
if (files.length == 2) {
outfile = files[1] + ".java";
filelist = Collections.singletonList(files[1]);
} else if (files.length == 3 && (new File(files[1])).isDirectory()) {
outfile = files[2];
File dir = new File(files[1]);
File[] listing = dir.listFiles();
if (listing == null)
throw new IOException();
filelist = new ArrayList(listing.length);
for (int i = 0; i < listing.length; i++) {
File f = listing[i];
if (!f.isDirectory())
filelist.add(f.getAbsolutePath());
}
} else {
outfile = files[files.length - 1];
filelist = Arrays.asList(files).subList(1, files.length - 1);
}
TagHook tagger = null;
try {
tagger = new Tagger(outfile);
for (String file : filelist) {
TranslateReader r = null;
try {
r = new TranslateReader(I2PAppContext.getGlobalContext(),
null,
new FileInputStream(file));
r._hook = tagger;
while (r.read(buf, 0, buf.length) >= 0) {
// throw away output
}
} finally {
if (r != null) r.close();
}
}
} finally {
if (tagger != null) tagger.close();
}
}
}