propagate from branch 'i2p.i2p' (head 5d56a7eb371dddb9336e596bda69f99c91294b05)

to branch 'i2p.i2p.str4d.ui' (head 3aeafcdb5c0ffbc9c77f574558f8438d3e81133e)
This commit is contained in:
str4d
2017-04-09 06:52:22 +00:00
212 changed files with 6356 additions and 1526 deletions

View File

@ -70,6 +70,7 @@ public class I2PSnarkUtil {
private boolean _areFilesPublic;
private List<String> _openTrackers;
private DHT _dht;
private long _startedTime;
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
@ -260,6 +261,8 @@ public class I2PSnarkUtil {
if (opts.getProperty(I2PClient.PROP_SIGTYPE) == null)
opts.setProperty(I2PClient.PROP_SIGTYPE, "EdDSA_SHA512_Ed25519");
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
if (_manager != null)
_startedTime = _context.clock().now();
_connecting = false;
}
if (_shouldUseDHT && _manager != null && _dht == null)
@ -295,6 +298,7 @@ public class I2PSnarkUtil {
_dht.stop();
_dht = null;
}
_startedTime = 0;
I2PSocketManager mgr = _manager;
// FIXME this can cause race NPEs elsewhere
_manager = null;
@ -310,6 +314,16 @@ public class I2PSnarkUtil {
_tmpDir.mkdirs();
}
/**
* When did we connect to the network?
* For RPC
* @return 0 if not connected
* @since 0.9.30
*/
public long getStartedTime() {
return _startedTime;
}
/** connect to the given destination */
I2PSocket connect(PeerID peer) throws IOException {
I2PSocketManager mgr = _manager;

View File

@ -89,6 +89,7 @@ public class Peer implements Comparable<Peer>
*/
//private static final long OPTION_AZMP = 0x1000000000000000l;
private long options;
private final boolean _isIncoming;
/**
* Outgoing connection.
@ -103,6 +104,7 @@ public class Peer implements Comparable<Peer>
this.infohash = infohash;
this.metainfo = metainfo;
_id = __id.incrementAndGet();
_isIncoming = false;
//_log.debug("Creating a new peer with " + peerID.toString(), new Exception("creating"));
}
@ -130,6 +132,16 @@ public class Peer implements Comparable<Peer>
_id = __id.incrementAndGet();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Creating a new peer " + peerID.toString(), new Exception("creating " + _id));
_isIncoming = true;
}
/**
* Is this an incoming connection?
* For RPC
* @since 0.9.30
*/
public boolean isIncoming() {
return _isIncoming;
}
/**

View File

@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.I2PAppContext;
import net.i2p.client.streaming.I2PServerSocket;
@ -237,8 +238,10 @@ public class Snark
private volatile boolean _autoStoppable;
// String indicating main activity
private volatile String activity = "Not started";
private final long savedUploaded;
private long savedUploaded;
private long _startedTime;
private static final AtomicInteger __RPCID = new AtomicInteger();
private final int _rpcID = __RPCID.incrementAndGet();
/**
* from main() via parseArguments() single torrent
@ -542,6 +545,7 @@ public class Snark
starting = true;
try {
x_startTorrent();
_startedTime = _util.getContext().clock().now();
} finally {
starting = false;
}
@ -633,16 +637,17 @@ public class Snark
if (st != null) {
// TODO: Cache the config-in-mem to compare vs config-on-disk
// (needed for auto-save to not double-save in some cases)
//boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
boolean changed = true;
if (changed && completeListener != null)
completeListener.updateStatus(this);
long nowUploaded = getUploaded();
boolean changed = storage.isChanged() || nowUploaded != savedUploaded;
try {
storage.close();
} catch (IOException ioe) {
System.out.println("Error closing " + torrent);
ioe.printStackTrace();
}
savedUploaded = nowUploaded;
if (changed && completeListener != null)
completeListener.updateStatus(this);
}
if (fast)
// HACK: See above if(!fast)
@ -1285,8 +1290,12 @@ public class Snark
allChecked = true;
checking = false;
if (storage.isChanged() && completeListener != null)
if (storage.isChanged() && completeListener != null) {
completeListener.updateStatus(this);
// this saved the status, so reset the variables
storage.clearChanged();
savedUploaded = getUploaded();
}
}
public void storageCompleted(Storage storage)
@ -1295,8 +1304,12 @@ public class Snark
_log.info("Completely received " + torrent);
//storage.close();
//System.out.println("Completely received: " + torrent);
if (completeListener != null)
if (completeListener != null) {
completeListener.torrentComplete(this);
// this saved the status, so reset the variables
savedUploaded = getUploaded();
storage.clearChanged();
}
}
public void setWantedPieces(Storage storage)
@ -1364,4 +1377,23 @@ public class Snark
long limit = 1024l * _util.getMaxUpBW();
return total > limit;
}
/**
* A unique ID for this torrent, useful for RPC
* @return positive value unless you wrap around
* @since 0.9.30
*/
public int getRPCID() {
return _rpcID;
}
/**
* When did we start this torrent
* For RPC
* @return 0 if not started before. Not cleared when stopped.
* @since 0.9.30
*/
public long getStartedTime() {
return _startedTime;
}
}

View File

@ -27,7 +27,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientApp;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import net.i2p.crypto.SHA1Hash;
import net.i2p.crypto.SigType;
import net.i2p.data.Base64;
@ -51,7 +53,7 @@ import org.klomp.snark.dht.KRPC;
/**
* Manage multiple snarks
*/
public class SnarkManager implements CompleteListener {
public class SnarkManager implements CompleteListener, ClientApp {
/**
* Map of (canonical) filename of the .torrent file to Snark instance.
@ -246,6 +248,13 @@ public class SnarkManager implements CompleteListener {
*/
public void start() {
_running = true;
if ("i2psnark".equals(_contextName)) {
// Register with the ClientAppManager so the rpc plugin can find us
// only if default instance
ClientAppManager cmgr = _context.clientAppManager();
if (cmgr != null)
cmgr.register(this);
}
_peerCoordinatorSet = new PeerCoordinatorSet();
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
@ -315,6 +324,12 @@ public class SnarkManager implements CompleteListener {
_connectionAcceptor.halt();
_idleChecker.cancel();
stopAllTorrents(true);
if ("i2psnark".equals(_contextName)) {
// only if default instance
ClientAppManager cmgr = _context.clientAppManager();
if (cmgr != null)
cmgr.unregister(this);
}
if (_log.shouldWarn())
_log.warn("Snark stop() end");
}
@ -322,6 +337,46 @@ public class SnarkManager implements CompleteListener {
/** @since 0.9.1 */
public boolean isStopping() { return _stopping; }
/**
* ClientApp method. Does nothing.
* Doesn't matter, we are only registering.
* @since 0.9.30
*/
public void startup() {}
/**
* ClientApp method. Does nothing.
* Doesn't matter, we are only registering.
* @since 0.9.30
*/
public void shutdown(String[] args) {}
/**
* ClientApp method.
* Doesn't matter, we are only registering.
* @return INITIALIZED always.
* @since 0.9.30
*/
public ClientAppState getState() {
return ClientAppState.INITIALIZED;
}
/**
* ClientApp method.
* @since 0.9.30
*/
public String getName() {
return "i2psnark";
}
/**
* ClientApp method.
* @since 0.9.30
*/
public String getDisplayName() {
return "i2psnark: " + _contextPath;
}
/** hook to I2PSnarkUtil for the servlet */
public I2PSnarkUtil util() { return _util; }
@ -440,6 +495,14 @@ public class SnarkManager implements CompleteListener {
return f;
}
/**
* For RPC
* @since 0.9.30
*/
public File getConfigDir() {
return _configDir;
}
/**
* Migrate the old flat config file to the new config dir
* containing the config file minus the per-torrent entries,
@ -1526,9 +1589,9 @@ public class SnarkManager implements CompleteListener {
* Called from servlet. This is only for the 'create torrent' form.
*
* @param metainfo the metainfo for the torrent
* @param bitfield the current completion status of the torrent
* @param bitfield the current completion status of the torrent, or null
* @param filename the absolute path to save the metainfo to, generally ending in ".torrent", which is also the name of the torrent
* Must be a filesystem-safe name.
* Must be a filesystem-safe name. If null, will generate a name from the metainfo.
* @param baseFile may be null, if so look in rootDataDir
* @throws RuntimeException via Snark.fatal()
* @return success
@ -1542,10 +1605,18 @@ public class SnarkManager implements CompleteListener {
if (snark != null) {
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
return false;
} else {
} else if (bitfield != null) {
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0, true); // no file priorities
}
// so addTorrent won't recheck
if (filename == null) {
File f = new File(getDataDir(), Storage.filterName(metainfo.getName()) + ".torrent");
if (f.exists()) {
addMessage(_t("Failed to copy torrent file to {0}", f.getAbsolutePath()));
_log.error("Torrent file already exists: " + f);
}
filename = f.getAbsolutePath();
}
try {
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
// hold the lock for a long time

View File

@ -305,6 +305,14 @@ public class Storage implements Closeable
return changed;
}
/**
* Clear the storage changed variable
* @since 0.9.30
*/
void clearChanged() {
changed = false;
}
/**
* File checking in progress.
* @since 0.9.3

View File

@ -106,11 +106,11 @@ class NodeInfo extends SimpleDataStructure {
if (parts.length != 4)
throw new DataFormatException("Bad format");
byte[] nid = Base64.decode(parts[0]);
if (nid == null)
if (nid == null || nid.length != NID.HASH_LENGTH)
throw new DataFormatException("Bad NID");
nID = new NID(nid);
byte[] h = Base64.decode(parts[1]);
if (h == null)
if (h == null || h.length != Hash.HASH_LENGTH)
throw new DataFormatException("Bad hash");
//hash = new Hash(h);
hash = Hash.create(h);

View File

@ -1803,6 +1803,8 @@ public class I2PSnarkServlet extends BasicServlet {
client = "Vuze" + getAzVersion(pid.getID());
else if ("CwsL".equals(ch))
client = "I2PSnarkXL";
else if ("LVhE".equals(ch))
client = "XD" + getAzVersion(pid.getID());
else if ("ZV".equals(ch.substring(2,4)) || "VUZP".equals(ch))
client = "Robert" + getRobtVersion(pid.getID());
else if (ch.startsWith("LV")) // LVCS 1.0.2?; LVRS 1.0.4