propagate from branch 'i2p.i2p' (head 4a63eba1606a8ba2448352876b4177d9e4c753a1)

to branch 'i2p.i2p.unittests' (head 051ea486db9f6f5a4327038827763f350369f932)
This commit is contained in:
str4d
2015-10-09 10:17:03 +00:00
395 changed files with 32801 additions and 26284 deletions

View File

@ -0,0 +1,31 @@
#**************************************************************************
#* MessagesBundle.properties -- English language error messages
#*
#* Copyright (c) 1998 by William King (wrking@eng.sun.com) and
#* Aaron M. Renn (arenn@urbanophile.com)
#*
#* This program is free software; you can redistribute it and/or modify
#* it under the terms of the GNU Library General Public License as published
#* by the Free Software Foundation; either version 2 of the License or
#* (at your option) any later version.
#*
#* This program is distributed in the hope that it will be useful, but
#* WITHOUT ANY WARRANTY; without even the implied warranty of
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#* GNU Library General Public License for more details.
#*
#* You should have received a copy of the GNU Library General Public License
#* along with this program; see the file COPYING.LIB. If not, write to
#* the Free Software Foundation Inc., 59 Temple Place - Suite 330,
#* Boston, MA 02111-1307 USA
#**************************************************************************/
getopt.ambigious={0}\: valitsin \u201d{1}\u201d ei ole yksiselitteinen
getopt.arguments1={0}\: valitsin ''--{1}'' ei salli argumenttia
getopt.arguments2={0}\: valitsin ''{1}{2}'' ei salli argumenttia
getopt.requires={0}\: valitsin ''{1}'' vaatii argumentin
getopt.unrecognized={0}\: tunnistamaton valitsin ''--{1}''
getopt.unrecognized2={0}\: tunnistamaton valitsin ''{1}{2}''
getopt.illegal={0}\: virheellinen valitsin -- {1}
getopt.invalid={0}\: virheellinen valitsin -- {1}
getopt.requires2={0}\: valitsin vaatii argumentin -- {1}
getopt.invalidValue=Virheellinen arvo {0} parametrille 'has_arg'

View File

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

View File

@ -96,7 +96,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
// established subsessions
private final ConcurrentHashMap<SessionId, SubSession> _subsessionMap;
private final Object _subsessionLock = new Object();
private static final String MIN_SUBSESSION_VERSION = "0.9.19";
private static final String MIN_SUBSESSION_VERSION = "0.9.21";
private volatile boolean _routerSupportsSubsessions;
/** hostname of router - will be null if in RouterContext */

View File

@ -501,6 +501,7 @@ public class KeyStoreUtil {
l.log(level, msg, t);
}
/****
public static void main(String[] args) {
try {
if (args.length > 0) {
@ -521,4 +522,5 @@ public class KeyStoreUtil {
e.printStackTrace();
}
}
****/
}

View File

@ -540,9 +540,10 @@ public class SU3File {
String ctype = null;
String ftype = null;
String kfile = null;
String kspass = KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD;
boolean error = false;
boolean shouldVerify = true;
Getopt g = new Getopt("SU3File", args, "t:c:f:k:x");
Getopt g = new Getopt("SU3File", args, "t:c:f:k:xp:");
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
@ -566,6 +567,10 @@ public class SU3File {
shouldVerify = false;
break;
case 'p':
kspass = g.getOptarg();
break;
case '?':
case ':':
default:
@ -586,16 +591,16 @@ public class SU3File {
Properties props = new Properties();
props.setProperty("prng.bufferSize", "16384");
new I2PAppContext(props);
ok = signCLI(stype, ctype, ftype, a.get(0), a.get(1), a.get(2), a.get(3), a.get(4), "");
ok = signCLI(stype, ctype, ftype, a.get(0), a.get(1), a.get(2), a.get(3), a.get(4), "", kspass);
} else if ("bulksign".equals(cmd)) {
Properties props = new Properties();
props.setProperty("prng.bufferSize", "16384");
new I2PAppContext(props);
ok = bulkSignCLI(stype, ctype, a.get(0), a.get(1), a.get(2), a.get(3));
ok = bulkSignCLI(stype, ctype, a.get(0), a.get(1), a.get(2), a.get(3), kspass);
} else if ("verifysig".equals(cmd)) {
ok = verifySigCLI(a.get(0), kfile);
} else if ("keygen".equals(cmd)) {
ok = genKeysCLI(stype, a.get(0), a.get(1), a.get(2));
ok = genKeysCLI(stype, a.get(0), a.get(1), a.get(2), kspass);
} else if ("extract".equals(cmd)) {
ok = extractCLI(a.get(0), a.get(1), shouldVerify, kfile);
} else {
@ -611,12 +616,13 @@ public class SU3File {
}
private static final void showUsageCLI() {
System.err.println("Usage: SU3File keygen [-t type|code] publicKeyFile keystore.ks you@mail.i2p");
System.err.println(" SU3File sign [-t type|code] [-c type|code] [-f type|code] inputFile.zip signedFile.su3 keystore.ks version you@mail.i2p");
System.err.println(" SU3File bulksign [-t type|code] [-c type|code] directory keystore.ks version you@mail.i2p");
System.err.println(" SU3File showversion signedFile.su3");
System.err.println(" SU3File verifysig [-k file.crt] signedFile.su3 ## -k use this pubkey cert for verification");
System.err.println(" SU3File extract [-x] [-k file.crt] signedFile.su3 outFile ## -x don't check sig");
System.err.println("Usage: SU3File keygen [-t type|code] [-p keystorepw] publicKeyFile keystore.ks you@mail.i2p\n" +
" SU3File sign [-t type|code] [-c type|code] [-f type|code] [-p keystorepw] inputFile.zip signedFile.su3 keystore.ks version you@mail.i2p\n" +
" SU3File bulksign [-t type|code] [-c type|code] [-p keystorepw] directory keystore.ks version you@mail.i2p\n" +
" SU3File showversion signedFile.su3\n" +
" SU3File verifysig [-k file.crt] signedFile.su3 ## -k use this pubkey cert for verification\n" +
" SU3File extract [-x] [-k file.crt] signedFile.su3 outFile ## -x don't check sig");
System.err.println("Default keystore password: \"" + KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD + '"');
System.err.println(dumpTypes());
}
@ -714,7 +720,7 @@ public class SU3File {
* @since 0.9.9
*/
private static final boolean bulkSignCLI(String stype, String ctype, String dir,
String privateKeyFile, String version, String signerName) {
String privateKeyFile, String version, String signerName, String kspass) {
File d = new File(dir);
if (!d.isDirectory()) {
System.out.println("Directory does not exist: " + d);
@ -749,7 +755,8 @@ public class SU3File {
if (!inputFile.endsWith(".zip"))
continue;
String signedFile = inputFile.substring(0, inputFile.length() - 4) + ".su3";
boolean rv = signCLI(stype, ctype, null, inputFile, signedFile, privateKeyFile, version, signerName, keypw);
boolean rv = signCLI(stype, ctype, null, inputFile, signedFile,
privateKeyFile, version, signerName, keypw, kspass);
if (!rv)
return false;
success++;
@ -764,7 +771,7 @@ public class SU3File {
* @since 0.9.9
*/
private static final boolean signCLI(String stype, String ctype, String ftype, String inputFile, String signedFile,
String privateKeyFile, String version, String signerName, String keypw) {
String privateKeyFile, String version, String signerName, String keypw, String kspass) {
SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : SigType.parseSigType(stype);
if (type == null) {
System.out.println("Signature type " + stype + " is not supported");
@ -799,7 +806,7 @@ public class SU3File {
System.out.println("Warning: File type " + ftype + " is undefined");
}
}
return signCLI(type, ct, ft, inputFile, signedFile, privateKeyFile, version, signerName, keypw);
return signCLI(type, ct, ft, inputFile, signedFile, privateKeyFile, version, signerName, keypw, kspass);
}
/**
@ -807,7 +814,7 @@ public class SU3File {
* @since 0.9.9
*/
private static final boolean signCLI(SigType type, ContentType ctype, int ftype, String inputFile, String signedFile,
String privateKeyFile, String version, String signerName, String keypw) {
String privateKeyFile, String version, String signerName, String keypw, String kspass) {
try {
while (keypw.length() < 6) {
System.out.print("Enter password for key \"" + signerName + "\": ");
@ -821,7 +828,7 @@ public class SU3File {
System.out.println("Key password must be at least 6 characters");
}
File pkfile = new File(privateKeyFile);
PrivateKey pk = KeyStoreUtil.getPrivateKey(pkfile,KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, signerName, keypw);
PrivateKey pk = KeyStoreUtil.getPrivateKey(pkfile, kspass, signerName, keypw);
if (pk == null) {
System.out.println("Private key for " + signerName + " not found in keystore " + privateKeyFile);
return false;
@ -895,13 +902,14 @@ public class SU3File {
* @return success
* @since 0.9.9
*/
private static final boolean genKeysCLI(String stype, String publicKeyFile, String privateKeyFile, String alias) {
private static final boolean genKeysCLI(String stype, String publicKeyFile, String privateKeyFile,
String alias, String kspass) {
SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : SigType.parseSigType(stype);
if (type == null) {
System.out.println("Signature type " + stype + " is not supported");
return false;
}
return genKeysCLI(type, publicKeyFile, privateKeyFile, alias);
return genKeysCLI(type, publicKeyFile, privateKeyFile, alias, kspass);
}
/**
@ -909,7 +917,8 @@ public class SU3File {
* @return success
* @since 0.9.9
*/
private static final boolean genKeysCLI(SigType type, String publicKeyFile, String privateKeyFile, String alias) {
private static final boolean genKeysCLI(SigType type, String publicKeyFile, String privateKeyFile,
String alias, String kspass) {
File pubFile = new File(publicKeyFile);
if (pubFile.exists()) {
System.out.println("Error: Not overwriting file " + publicKeyFile);
@ -947,7 +956,7 @@ public class SU3File {
if (keylen == 528)
keylen = 521;
}
boolean success = KeyStoreUtil.createKeys(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias,
boolean success = KeyStoreUtil.createKeys(ksFile, kspass, alias,
alias, "I2P", 3652, type.getBaseAlgorithm().getName(),
keylen, keypw);
if (!success) {

View File

@ -47,16 +47,17 @@ public class Certificate extends DataStructureImpl {
public final static int CERTIFICATE_TYPE_KEY = 5;
/**
* If null cert, return immutable static instance, else create new
* If null, P256 key, or Ed25519 key cert, return immutable static instance, else create new
* @throws DataFormatException if not enough bytes
* @since 0.8.3
*/
public static Certificate create(byte[] data, int off) throws DataFormatException {
int type;
byte[] payload;
int length;
try {
type = data[off] & 0xff;
int length = (int) DataHelper.fromLong(data, off + 1, 2);
length = (int) DataHelper.fromLong(data, off + 1, 2);
if (type == 0 && length == 0)
return NULL_CERT;
// from here down roughly the same as readBytes() below
@ -68,6 +69,12 @@ public class Certificate extends DataStructureImpl {
throw new DataFormatException("not enough bytes", aioobe);
}
if (type == CERTIFICATE_TYPE_KEY) {
if (length == 4) {
if (Arrays.equals(payload, KeyCertificate.Ed25519_PAYLOAD))
return KeyCertificate.ELG_Ed25519_CERT;
if (Arrays.equals(payload, KeyCertificate.ECDSA256_PAYLOAD))
return KeyCertificate.ELG_ECDSA256_CERT;
}
try {
return new KeyCertificate(payload);
} catch (DataFormatException dfe) {
@ -78,7 +85,7 @@ public class Certificate extends DataStructureImpl {
}
/**
* If null cert, return immutable static instance, else create new
* If null, P256 key, or Ed25519 key cert, return immutable static instance, else create new
* @since 0.8.3
*/
public static Certificate create(InputStream in) throws DataFormatException, IOException {
@ -93,8 +100,15 @@ public class Certificate extends DataStructureImpl {
int read = DataHelper.read(in, payload);
if (read != length)
throw new DataFormatException("Not enough bytes for the payload (read: " + read + " length: " + length + ')');
if (type == CERTIFICATE_TYPE_KEY)
if (type == CERTIFICATE_TYPE_KEY) {
if (length == 4) {
if (Arrays.equals(payload, KeyCertificate.Ed25519_PAYLOAD))
return KeyCertificate.ELG_Ed25519_CERT;
if (Arrays.equals(payload, KeyCertificate.ECDSA256_PAYLOAD))
return KeyCertificate.ELG_ECDSA256_CERT;
}
return new KeyCertificate(payload);
}
return new Certificate(type, payload);
}

View File

@ -1546,7 +1546,7 @@ public class DataHelper {
// years
t = ngettext("1 year", "{0} years", (int) (ms / (365L * 24 * 60 * 60 * 1000)));
} else {
return _("n/a");
return _t("n/a");
}
// Replace minus sign to work around
// bug in Chrome (and IE?), line breaks at the minus sign
@ -1593,7 +1593,7 @@ public class DataHelper {
// years
t = ngettext("1 year", "{0} years", (int) (ms / (365L * 24 * 60 * 60 * 1000)));
} else {
return _("n/a");
return _t("n/a");
}
if (ms < 0)
t = t.replace("-", "&minus;");
@ -1602,7 +1602,7 @@ public class DataHelper {
private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
private static String _(String key) {
private static String _t(String key) {
return Translate.getString(key, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
}

View File

@ -17,15 +17,41 @@ public class KeyCertificate extends Certificate {
public static final int HEADER_LENGTH = 4;
/** @since 0.9.22 pkg private for Certificate.create() */
static final byte[] Ed25519_PAYLOAD = new byte[] {
0, (byte) (SigType.EdDSA_SHA512_Ed25519.getCode()), 0, 0
};
/** @since 0.9.22 pkg private for Certificate.create() */
static final byte[] ECDSA256_PAYLOAD = new byte[] {
0, (byte) (SigType.ECDSA_SHA256_P256.getCode()), 0, 0
};
/**
* An immutable ElG/ECDSA-P256 certificate.
*/
public static final KeyCertificate ELG_ECDSA256_CERT;
/**
* An immutable ElG/Ed25519 certificate.
* @since 0.9.22
*/
public static final KeyCertificate ELG_Ed25519_CERT;
static {
KeyCertificate kc;
try {
kc = new ECDSA256Cert();
} catch (DataFormatException dfe) {
kc = null; // won't happen
throw new RuntimeException(dfe); // won't happen
}
ELG_ECDSA256_CERT = kc;
try {
kc = new Ed25519Cert();
} catch (DataFormatException dfe) {
throw new RuntimeException(dfe); // won't happen
}
ELG_Ed25519_CERT = kc;
}
/**
@ -185,19 +211,17 @@ public class KeyCertificate extends Certificate {
/**
* An immutable ElG/ECDSA-256 certificate.
* @since 0.8.3
*/
private static final class ECDSA256Cert extends KeyCertificate {
private static final byte[] ECDSA256_DATA = new byte[] {
CERTIFICATE_TYPE_KEY, 0, HEADER_LENGTH, 0, (byte) (SigType.ECDSA_SHA256_P256.getCode()), 0, 0
};
private static final int ECDSA256_LENGTH = ECDSA256_DATA.length;
private static final byte[] ECDSA256_PAYLOAD = new byte[] {
0, (byte) (SigType.ECDSA_SHA256_P256.getCode()), 0, 0
};
private final int _hashcode;
public ECDSA256Cert() throws DataFormatException {
super(ECDSA256_PAYLOAD);
_hashcode = super.hashCode();
}
/** @throws RuntimeException always */
@ -246,7 +270,75 @@ public class KeyCertificate extends Certificate {
/** Overridden for efficiency */
@Override
public int hashCode() {
return 1234567;
return _hashcode;
}
}
/**
* An immutable ElG/Ed25519 certificate.
* @since 0.9.22
*/
private static final class Ed25519Cert extends KeyCertificate {
private static final byte[] ED_DATA = new byte[] { CERTIFICATE_TYPE_KEY,
0, HEADER_LENGTH,
0, (byte) SigType.EdDSA_SHA512_Ed25519.getCode(),
0, 0
};
private static final int ED_LENGTH = ED_DATA.length;
private final int _hashcode;
public Ed25519Cert() throws DataFormatException {
super(Ed25519_PAYLOAD);
_hashcode = super.hashCode();
}
/** @throws RuntimeException always */
@Override
public void setCertificateType(int type) {
throw new RuntimeException("Data already set");
}
/** @throws RuntimeException always */
@Override
public void setPayload(byte[] payload) {
throw new RuntimeException("Data already set");
}
/** @throws RuntimeException always */
@Override
public void readBytes(InputStream in) throws DataFormatException, IOException {
throw new RuntimeException("Data already set");
}
/** Overridden for efficiency */
@Override
public void writeBytes(OutputStream out) throws IOException {
out.write(ED_DATA);
}
/** Overridden for efficiency */
@Override
public int writeBytes(byte target[], int offset) {
System.arraycopy(ED_DATA, 0, target, offset, ED_LENGTH);
return ED_LENGTH;
}
/** @throws RuntimeException always */
@Override
public int readBytes(byte source[], int offset) throws DataFormatException {
throw new RuntimeException("Data already set");
}
/** Overridden for efficiency */
@Override
public int size() {
return ED_LENGTH;
}
/** Overridden for efficiency */
@Override
public int hashCode() {
return _hashcode;
}
}
}

View File

@ -1,5 +1,7 @@
package net.i2p.internal;
import java.io.Closeable;
import net.i2p.data.i2cp.I2CPMessage;
/**
@ -15,7 +17,7 @@ import net.i2p.data.i2cp.I2CPMessage;
* @author zzz
* @since 0.8.3
*/
public abstract class I2CPMessageQueue {
public abstract class I2CPMessageQueue implements Closeable {
/**
* Send a message, nonblocking.

View File

@ -178,6 +178,7 @@ public interface UpdateManager {
* @since 0.9.21
*/
public boolean isUpdateInProgress(UpdateType type, String id);
/**
* Non-blocking. Does not check.
* Fails if check or update already in progress.
@ -225,6 +226,7 @@ public interface UpdateManager {
/**
* The status on any update current or last finished.
* @return status or ""
* @since 0.9.21
*/
public String getStatus();

View File

@ -15,6 +15,8 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.http.conn.util.InetAddressUtils;
import net.i2p.I2PAppContext;
/**
@ -260,12 +262,9 @@ public abstract class Addresses {
}
if (rv == null) {
try {
boolean isIPv4 = host.replaceAll("[0-9\\.]", "").length() == 0;
if (isIPv4 && host.replaceAll("[0-9]", "").length() != 3)
return null;
rv = InetAddress.getByName(host).getAddress();
if (isIPv4 ||
host.replaceAll("[0-9a-fA-F:]", "").length() == 0) {
if (InetAddressUtils.isIPv4Address(host) ||
InetAddressUtils.isIPv6Address(host)) {
synchronized (_IPAddress) {
_IPAddress.put(host, rv);
}

View File

@ -755,6 +755,8 @@ public class EepGet {
Thread pusher = null;
_decompressException = null;
if (_isGzippedResponse) {
if (_log.shouldInfo())
_log.info("Gzipped response, starting decompressor");
PipedInputStream pi = BigPipedInputStream.getInstance();
PipedOutputStream po = new PipedOutputStream(pi);
pusher = new I2PAppThread(new Gunzipper(pi, _out), "EepGet Decompressor");
@ -1096,7 +1098,7 @@ public class EepGet {
*/
private int handleStatus(String line) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Status line: [" + line + "]");
_log.debug("Status line: [" + line.trim() + "]");
String[] toks = line.split(" ", 3);
if (toks.length < 2) {
if (_log.shouldLog(Log.WARN))
@ -1160,17 +1162,13 @@ public class EepGet {
lookahead[1] = lookahead[2];
lookahead[2] = (byte)cur;
}
private static boolean isEndOfHeaders(byte lookahead[]) {
byte first = lookahead[0];
byte second = lookahead[1];
byte third = lookahead[2];
return (isNL(second) && isNL(third)) || // \n\n
(isNL(first) && isNL(third)); // \n\r\n
return lookahead[2] == NL &&
(lookahead[0] == NL || lookahead[1] == NL); // \n\n or \n\r\n
}
/** we ignore any potential \r, since we trim it on write anyway */
private static final byte NL = '\n';
private static boolean isNL(byte b) { return (b == NL); }
/**
* @param timeout may be null
@ -1315,7 +1313,8 @@ public class EepGet {
buf.append("Content-length: ").append(_postData.length()).append("\r\n");
// This will be replaced if we are going through I2PTunnelHTTPClient
buf.append("Accept-Encoding: ");
if ((!_shouldProxy) &&
// as of 0.9.23, the proxy passes the Accept-Encoding header through
if ( /* (!_shouldProxy) && */
// This is kindof a hack, but if we are downloading a gzip file
// we don't want to transparently gunzip it and save it as a .gz file.
(!path.endsWith(".gz")) && (!path.endsWith(".tgz")))

View File

@ -284,7 +284,7 @@ public class I2PSSLSocketFactory {
host.equals("localhost") ||
host.equals("127.0.0.1") ||
host.equals("::1") ||
host.equals("0:0:0:0:0:0:0::1")) {
host.equals("0:0:0:0:0:0:0:1")) {
if (log.shouldWarn())
log.warn("Skipping hostname validation for " + host);
return;

View File

@ -10,6 +10,7 @@ package net.i2p.util;
*/
import java.io.File;
import java.io.Flushable;
import java.io.IOException;
import java.text.DateFormat;
import java.text.DecimalFormat;
@ -37,7 +38,7 @@ import net.i2p.data.DataHelper;
* writes them where appropriate.
*
*/
public class LogManager {
public class LogManager implements Flushable {
public final static String CONFIG_LOCATION_PROP = "loggerConfigLocation";
public final static String FILENAME_OVERRIDE_PROP = "loggerFilenameOverride";
public final static String CONFIG_LOCATION_DEFAULT = "logger.config";

View File

@ -67,10 +67,12 @@ abstract class LogWriterBase implements Runnable {
public void run() {
_write = true;
// don't bother on Android
final boolean shouldReadConfig = !SystemVersion.isAndroid();
try {
while (_write) {
flushRecords();
if (_write)
if (_write && shouldReadConfig)
rereadConfig();
}
} catch (Exception e) {
@ -145,7 +147,7 @@ abstract class LogWriterBase implements Runnable {
private String dupMessage(int dupCount, LogRecord lastRecord, boolean reverse) {
String arrows = reverse ? "&darr;&darr;&darr;" : "^^^";
return LogRecordFormatter.getWhen(_manager, lastRecord) + ' ' + arrows + ' ' +
_(dupCount, "1 similar message omitted", "{0} similar messages omitted") + ' ' + arrows + '\n';
_t(dupCount, "1 similar message omitted", "{0} similar messages omitted") + ' ' + arrows + '\n';
}
private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
@ -154,7 +156,7 @@ abstract class LogWriterBase implements Runnable {
* gettext
* @since 0.9.3
*/
private String _(int a, String b, String c) {
private String _t(int a, String b, String c) {
return Translate.getString(a, b, c, _manager.getContext(), BUNDLE_NAME);
}

View File

@ -33,6 +33,8 @@ public class PortMapper {
public static final String SVC_BOB = "BOB";
/** not necessary, already in config? */
public static final String SVC_I2CP = "I2CP";
/** @since 0.9.23 */
public static final String SVC_I2CP_SSL = "I2CP-SSL";
/**
* @param context unused for now

View File

@ -6,6 +6,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.I2PAppContext;
@ -38,7 +39,7 @@ public class SimpleTimer2 {
private static final int MAX_THREADS = 4;
private final ScheduledThreadPoolExecutor _executor;
private final String _name;
private volatile int _count;
private final AtomicInteger _count = new AtomicInteger();
private final int _threads;
/**
@ -102,7 +103,7 @@ public class SimpleTimer2 {
super.afterExecute(r, t);
if (t != null) { // shoudn't happen, caught in RunnableEvent.run()
Log log = I2PAppContext.getGlobalContext().logManager().getLog(SimpleTimer2.class);
log.log(Log.CRIT, "wtf, event borked: " + r, t);
log.log(Log.CRIT, "event borked: " + r, t);
}
}
}
@ -110,7 +111,7 @@ public class SimpleTimer2 {
private class CustomThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread rv = Executors.defaultThreadFactory().newThread(r);
rv.setName(_name + ' ' + (++_count) + '/' + _threads);
rv.setName(_name + ' ' + _count.incrementAndGet() + '/' + _threads);
// Uncomment this to test threadgrouping, but we should be all safe now that the constructor preallocates!
// String name = rv.getThreadGroup().getName();
// if(!name.equals("main")) {
@ -164,7 +165,8 @@ public class SimpleTimer2 {
* New code should use SimpleTimer2.TimedEvent.
*
* @since 0.9.20
* @param timeoutMs run first and subsequent iterations of this event every timeoutMs ms
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms, 5000 minimum
* @throws IllegalArgumentException if timeoutMs less than 5000
*/
public void addPeriodicEvent(final SimpleTimer.TimedEvent event, final long timeoutMs) {
addPeriodicEvent(event, timeoutMs, timeoutMs);
@ -183,7 +185,8 @@ public class SimpleTimer2 {
*
* @since 0.9.20
* @param delay run the first iteration of this event after delay ms
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms, 5000 minimum
* @throws IllegalArgumentException if timeoutMs less than 5000
*/
public void addPeriodicEvent(final SimpleTimer.TimedEvent event, final long delay, final long timeoutMs) {
@ -254,6 +257,8 @@ public class SimpleTimer2 {
private long _nextRun;
/** whether this was scheduled during RUNNING state. LOCKING: this */
private boolean _rescheduleAfterRun;
/** whether this was cancelled during RUNNING state. LOCKING: this */
private boolean _cancelAfterRun;
/** must call schedule() later */
public TimedEvent(SimpleTimer2 pool) {
@ -286,12 +291,17 @@ public class SimpleTimer2 {
public synchronized void schedule(long timeoutMs) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Scheduling: " + this + " timeout = " + timeoutMs + " state: " + _state);
if (timeoutMs <= 0 && _log.shouldLog(Log.WARN))
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);
timeoutMs = 1; // otherwise we may execute before _future is updated, which is fine
// except it triggers 'early execution' warning logging
}
// always set absolute time of execution
_nextRun = timeoutMs + System.currentTimeMillis();
_cancelAfterRun = false;
switch(_state) {
case RUNNING:
@ -352,11 +362,13 @@ public class SimpleTimer2 {
* @param timeoutMs
*/
public synchronized void forceReschedule(long timeoutMs) {
cancel();
// don't cancel while running!
if (_state == TimedEventState.SCHEDULED)
cancel();
schedule(timeoutMs);
}
/** returns true if cancelled */
/** @return true if cancelled */
public synchronized boolean cancel() {
// always clear
_rescheduleAfterRun = false;
@ -365,7 +377,9 @@ public class SimpleTimer2 {
case CANCELLED: // fall through
case IDLE:
break; // my preference is to throw IllegalState here, but let it be.
case RUNNING: // fall through
case RUNNING:
_cancelAfterRun = true;
return true;
case SCHEDULED:
boolean cancelled = _future.cancel(false);
if (cancelled)
@ -378,20 +392,29 @@ public class SimpleTimer2 {
}
public void run() {
try {
run2();
} catch (RuntimeException re) {
_log.error("timer error", re);
throw re;
}
}
private void run2() {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Running: " + this);
long before = System.currentTimeMillis();
long delay = 0;
synchronized(this) {
if (_rescheduleAfterRun)
throw new IllegalStateException("rescheduleAfterRun cannot be true here");
throw new IllegalStateException(this + " rescheduleAfterRun cannot be true here");
switch(_state) {
case CANCELLED:
return; // goodbye
case IDLE: // fall through
case RUNNING:
throw new IllegalStateException("not possible to be in " + _state);
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;
}
@ -411,12 +434,12 @@ public class SimpleTimer2 {
if (_future != null)
delay = _future.getDelay(TimeUnit.MILLISECONDS);
else if (_log.shouldLog(Log.WARN))
_log.warn(_pool + " wtf, no _future " + this);
_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 + " wtf, early execution " + delay + ": " + this);
_log.warn(_pool + " early execution " + delay + ": " + this);
else if (_log.shouldLog(Log.WARN) && delay < -1000)
_log.warn(" wtf, late execution " + (0 - delay) + ": " + this + _pool.debug());
_log.warn(" late execution " + (0 - delay) + ": " + this + _pool.debug());
try {
timeReached();
} catch (Throwable t) {
@ -426,22 +449,27 @@ public class SimpleTimer2 {
switch(_state) {
case SCHEDULED: // fall through
case IDLE:
throw new IllegalStateException("can't be " + _state);
throw new IllegalStateException(this + " can't be " + _state);
case CANCELLED:
break; // nothing
case RUNNING:
_state = TimedEventState.IDLE;
// do we need to reschedule?
if (_rescheduleAfterRun) {
_rescheduleAfterRun = false;
schedule(_nextRun - System.currentTimeMillis());
if (_cancelAfterRun) {
_cancelAfterRun = false;
_state = TimedEventState.CANCELLED;
} else {
_state = TimedEventState.IDLE;
// do we need to reschedule?
if (_rescheduleAfterRun) {
_rescheduleAfterRun = false;
schedule(_nextRun - System.currentTimeMillis());
}
}
}
}
}
long time = System.currentTimeMillis() - before;
if (time > 500 && _log.shouldLog(Log.WARN))
_log.warn(_pool + " wtf, event execution took " + time + ": " + this);
_log.warn(_pool + " event execution took " + time + ": " + this);
if (_log.shouldLog(Log.INFO)) {
// this call is slow - iterates through a HashMap -
// would be better to have a local AtomicLong if we care
@ -470,6 +498,7 @@ public class SimpleTimer2 {
return _executor.getCompletedTaskCount();
}
/** warning - slow */
private String debug() {
_executor.purge(); // Remove cancelled tasks from the queue so we get a good queue size stat
return
@ -490,10 +519,13 @@ public class SimpleTimer2 {
* Schedule periodic event
*
* @param delay run the first iteration of this event after delay ms
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms, 5000 minimum
* @throws IllegalArgumentException if timeoutMs less than 5000
*/
public PeriodicTimedEvent(SimpleTimer2 pool, long delay, long timeoutMs) {
super(pool, delay);
if (timeoutMs < 5000)
throw new IllegalArgumentException("timeout minimum 5000");
_timeoutMs = timeoutMs;
}

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 _("foo {0} bar", _("baz"))
* To tranlslate 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

@ -351,7 +351,7 @@ public class TranslateReader extends FilterReader {
public void tag(List<String> args) {
if (args.size() <= 0)
return;
_out.print("\t_(");
_out.print("\t_t(");
for (int i = 0; i < args.size(); i++) {
if (i > 0)
_out.print(", ");
@ -373,6 +373,9 @@ public class TranslateReader extends FilterReader {
}
}
/**
* Do not comment out, used to extract tags as a part of the build process.
*/
public static void main(String[] args) {
try {
if (args.length >= 2 && args[0].equals("test"))

View File

@ -28,9 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.metanotion.io;
import java.io.Closeable;
import java.io.IOException;
public interface RandomAccessInterface {
public interface RandomAccessInterface extends Closeable {
public long getFilePointer() throws IOException;
public long length() throws IOException;
public int read() throws IOException;

View File

@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.metanotion.io.block;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
@ -64,7 +65,7 @@ import net.i2p.util.Log;
* Pages are 1 KB and are numbered starting from 1.
* e.g. the Metaindex skiplist is at offset 1024 bytes
*/
public class BlockFile {
public class BlockFile implements Closeable {
public static final int PAGESIZE = 1024;
public static final long OFFSET_MOUNTED = 20;
public final Log log = I2PAppContext.getGlobalContext().logManager().getLog(BlockFile.class);

View File

@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.metanotion.io.block.index;
import java.io.Closeable;
import java.io.IOException;
import java.util.HashMap;
@ -50,7 +51,7 @@ import net.i2p.util.Log;
*
* Always fits on one page.
*/
public class BSkipList extends SkipList {
public class BSkipList extends SkipList implements Closeable {
private static final long MAGIC = 0x536b69704c697374l; // "SkipList"
public int firstSpanPage = 0;
public int firstLevelPage = 0;

View File

@ -28,12 +28,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.metanotion.util.skiplist;
import java.io.Flushable;
import net.metanotion.io.block.BlockFile;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
public class SkipLevels {
public class SkipLevels implements Flushable {
/** We can't have more than 2**32 pages */
public static final int MAX_SIZE = 32;

View File

@ -28,13 +28,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.metanotion.util.skiplist;
import java.io.Flushable;
import java.util.Random;
import net.i2p.util.RandomSource;
//import net.metanotion.io.block.BlockFile;
public class SkipList {
public class SkipList implements Flushable {
/** the probability of each next higher level */
protected static final int P = 2;
private static final int MIN_SLOTS = 4;

View File

@ -28,9 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.metanotion.util.skiplist;
import java.io.Flushable;
//import net.metanotion.io.block.BlockFile;
public class SkipSpan {
public class SkipSpan implements Flushable {
/** This is actually limited by BlockFile.spanSize which is much smaller */
public static final int MAX_SIZE = 256;