propagate from branch 'i2p.i2p.zzz.i2cp' (head d4ac8162a4ba299ac912640f19076c3c90afdc67)

to branch 'i2p.i2p' (head adc5102c93383e01c74b87f04449dc9c307f6e75)
This commit is contained in:
zzz
2014-01-27 16:47:22 +00:00
24 changed files with 1298 additions and 195 deletions

View File

@@ -46,6 +46,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
@@ -57,6 +58,8 @@ import net.i2p.I2PException;
import net.i2p.client.I2PClient;
import net.i2p.client.I2PClientFactory;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.I2PSimpleClient;
import net.i2p.client.naming.NamingService;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
@@ -68,6 +71,7 @@ import net.i2p.i2ptunnel.streamr.StreamrConsumer;
import net.i2p.i2ptunnel.streamr.StreamrProducer;
import net.i2p.util.EventDispatcherImpl;
import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
/**
* An I2PTunnel tracks one or more I2PTunnelTasks and one or more I2PSessions.
@@ -87,9 +91,9 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
public boolean ownDest = false;
/** the I2CP port */
/** the I2CP port, non-null */
public String port = System.getProperty(I2PClient.PROP_TCP_PORT, "7654");
/** the I2CP host */
/** the I2CP host, non-null */
public String host = System.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
/** the listen-on host. Sadly the listen-on port does not have a field. */
public String listenHost = host;
@@ -168,7 +172,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
System.out.println("Enter 'help' for help.");
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.print("I2PTunnel>");
System.out.print("I2PTunnel> ");
String cmd = r.readLine();
if (cmd == null) break;
if (cmd.length() <= 0) continue;
@@ -293,6 +297,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
runPing(allargs, l);
} else if (cmdname.equals("owndest")) {
runOwnDest(args, l);
} else if (cmdname.equals("auth")) {
runAuth(args, l);
} else {
l.log("Unknown command [" + cmdname + "]");
}
@@ -308,27 +314,28 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
private static void runHelp(Logging l) {
l.log("Command list:");
// alphabetical please...
l.log("client <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
l.log("clientoptions[ key=value]*");
l.log("close [forced] <jobnumber>|all");
l.log("config <i2phost> <i2pport>");
l.log("connectclient <port> [<sharedClient>] [<proxy>]");
l.log("genkeys <privkeyfile> [<pubkeyfile>]");
l.log("gentextkeys");
l.log("httpbidirserver <host> <port> <proxyport> <spoofedhost> <privkeyfile>");
l.log("httpclient <port> [<sharedClient>] [<proxy>]");
l.log("httpserver <host> <port> <spoofedhost> <privkeyfile>");
l.log("ircclient <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
l.log("list");
l.log("listen_on <ip>");
l.log("lookup <name>");
l.log("owndest yes|no");
l.log("ping <args>");
l.log("quit");
l.log("read_timeout <msecs>");
l.log("run <commandfile>");
l.log("server <host> <port> <privkeyfile>");
l.log("textserver <host> <port> <privkey>");
l.log(" auth <username> <password>");
l.log(" client <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
l.log(" clientoptions [-acx] [key=value ]*");
l.log(" close [forced] <jobnumber>|all");
l.log(" config [-s] <i2phost> <i2pport>");
l.log(" connectclient <port> [<sharedClient>] [<proxy>]");
l.log(" genkeys <privkeyfile> [<pubkeyfile>]");
l.log(" gentextkeys");
l.log(" httpbidirserver <host> <port> <proxyport> <spoofedhost> <privkeyfile>");
l.log(" httpclient <port> [<sharedClient>] [<proxy>]");
l.log(" httpserver <host> <port> <spoofedhost> <privkeyfile>");
l.log(" ircclient <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
l.log(" list");
l.log(" listen_on <ip>");
l.log(" lookup <name>");
l.log(" owndest yes|no");
l.log(" ping <args>");
l.log(" quit");
l.log(" read_timeout <msecs>");
l.log(" run <commandfile>");
l.log(" server <host> <port> <privkeyfile>");
l.log(" textserver <host> <port> <privkey>");
}
/**
@@ -345,15 +352,43 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
* @param l logger to receive events and output
*/
public void runClientOptions(String args[], Logging l) {
_clientOptions.clear();
if (args != null) {
for (int i = 0; i < args.length; i++) {
if (args != null && args.length > 0) {
int i = 0;
if (args[0].equals("-a")) {
i++;
} else if (args[0].equals("-c")) {
_clientOptions.clear();
l.log("Client options cleared");
return;
} else if (args[0].equals("-x")) {
i++;
for ( ; i < args.length; i++) {
if (_clientOptions.remove(args[i]) != null)
l.log("Removed " + args[i]);
}
return;
} else {
_clientOptions.clear();
}
for ( ; i < args.length; i++) {
int index = args[i].indexOf('=');
if (index <= 0) continue;
String key = args[i].substring(0, index);
String val = args[i].substring(index+1);
_clientOptions.setProperty(key, val);
}
} else {
l.log("Usage:");
l.log(" clientoptions [key=value ]* // sets current options");
l.log(" clientoptions -a [key=value ]* // adds to current options");
l.log(" clientoptions -c // clears current options");
l.log(" clientoptions -x [key ]* // removes listed options");
l.log("Current options:");
Properties p = new OrderedProperties();
p.putAll(_clientOptions);
for (Map.Entry<Object, Object> e : p.entrySet()) {
l.log(" [" + e.getKey() + "] = [" + e.getValue() + ']');
}
}
notifyEvent("clientoptions_onResult", "ok");
}
@@ -1147,18 +1182,47 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
* @param l logger to receive events and output
*/
private void runConfig(String args[], Logging l) {
if (args.length == 2) {
host = args[0];
if (args.length >= 2) {
int i = 0;
if (args[0].equals("-s")) {
_clientOptions.setProperty("i2cp.SSL", "true");
i++;
} else {
_clientOptions.remove("i2cp.SSL");
}
host = args[i++];
listenHost = host;
port = args[1];
port = args[i];
notifyEvent("configResult", "ok");
} else {
l.log("config <i2phost> <i2pport>");
l.log("Usage:");
l.log(" config [-s] <i2phost> <i2pport>");
l.log(" sets the connection to the i2p router.");
l.log("Current setting:");
boolean ssl = Boolean.parseBoolean(_clientOptions.getProperty("i2cp.SSL"));
l.log(" " + host + ' ' + port + (ssl ? " SSL" : ""));
notifyEvent("configResult", "error");
}
}
/**
* Specify the i2cp username and password
*
* @param args {username, password}
* @param l logger to receive events and output
* @since 0.9.10
*/
private void runAuth(String args[], Logging l) {
if (args.length == 2) {
_clientOptions.setProperty("i2cp.username", args[0]);
_clientOptions.setProperty("i2cp.password", args[1]);
} else {
l.log("Usage:");
l.log(" auth <username> <password>");
l.log(" Sets the i2cp credentials");
}
}
/**
* Specify whether to use its own destination for each outgoing tunnel
* Deprecated - only used by CLI
@@ -1415,16 +1479,19 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
notifyEvent("lookupResult", "invalidUsage");
} else {
try {
Destination dest = destFromName(args[0]);
boolean ssl = Boolean.parseBoolean(_clientOptions.getProperty("i2cp.SSL"));
String user = _clientOptions.getProperty("i2cp.username");
String pw = _clientOptions.getProperty("i2cp.password");
Destination dest = destFromName(args[0], host, port, ssl, user, pw);
if (dest == null) {
l.log("Unknown host");
l.log("Unknown host: " + args[0]);
notifyEvent("lookupResult", "unkown host");
} else {
l.log(dest.toBase64());
notifyEvent("lookupResult", dest.toBase64());
}
} catch (DataFormatException dfe) {
l.log("Unknown or invalid host");
l.log("Unknown or invalid host: " + args[0]);
notifyEvent("lookupResult", "invalid host");
}
}
@@ -1441,20 +1508,19 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
*/
private void runPing(String allargs, Logging l) {
if (allargs.length() != 0) {
I2PTunnelTask task;
// pings always use the main destination
task = new I2Ping(allargs, l, false, this, this);
_clientOptions.setProperty(I2Ping.PROP_COMMAND, allargs);
I2PTunnelTask task = new I2Ping(l, ownDest, this, this);
addtask(task);
notifyEvent("pingTaskId", Integer.valueOf(task.getId()));
} else {
l.log("ping <opts> <dest>");
l.log("ping <opts> <b64dest|host>");
l.log("ping <opts> -h (pings all hosts in hosts.txt)");
l.log("ping <opts> -l <destlistfile> (pings a list of hosts in a file)");
l.log(" Options:\n" +
" -c (require 5 consecutive pings to report success)\n" +
" -m maxSimultaneousPings (default 10)\n" +
" -n numberOfPings (default 3)\n" +
" -t timeout (ms, default 5000)\n");
" -t timeout (ms, default 30000)\n");
l.log(" Tests communication with peers.\n");
notifyEvent("pingTaskId", Integer.valueOf(-1));
}
@@ -1599,6 +1665,19 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
* @deprecated Don't use i2ptunnel for lookup! Use I2PAppContext.getGlobalContext().namingService().lookup(name) from i2p.jar
*/
public static Destination destFromName(String name) throws DataFormatException {
return destFromName(name, null, null, false, null, null);
}
/**
* @param i2cpHost may be null
* @param i2cpPort may be null
* @param user may be null
* @param pw may be null
* @since 0.9.10
*/
private static Destination destFromName(String name, String i2cpHost,
String i2cpPort, boolean isSSL,
String user, String pw) throws DataFormatException {
if ((name == null) || (name.trim().length() <= 0)) throw new DataFormatException("Empty destination provided");
@@ -1642,8 +1721,46 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
}
} else {
// ask naming service
name = name.trim();
NamingService inst = ctx.namingService();
return inst.lookup(name);
boolean b32 = name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p");
Destination d = null;
if (ctx.isRouterContext() || !b32) {
// Local lookup.
// Even though we could do b32 outside router ctx here,
// we do it below instead so we can set the host and port,
// which we can't do with lookup()
d = inst.lookup(name);
if (d != null || ctx.isRouterContext() || name.length() >= 516)
return d;
}
// Outside router context only,
// try simple session to ask the router.
I2PClient client = new I2PSimpleClient();
Properties opts = new Properties();
if (i2cpHost != null)
opts.put(I2PClient.PROP_TCP_HOST, i2cpHost);
if (i2cpPort != null)
opts.put(I2PClient.PROP_TCP_PORT, i2cpPort);
opts.put("i2cp.SSL", Boolean.toString(isSSL));
if (user != null)
opts.put("i2cp.username", user);
if (pw != null)
opts.put("i2cp.password", pw);
I2PSession session = null;
try {
session = client.createSession(null, opts);
session.connect();
d = session.lookupDest(name);
} catch (I2PSessionException ise) {
if (log.shouldLog(Log.WARN))
log.warn("Lookup via router failed", ise);
} finally {
if (session != null) {
try { session.destroySession(); } catch (I2PSessionException ise) {}
}
}
return d;
}
}

View File

@@ -51,15 +51,18 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
protected final List<I2PSocket> mySockets = new ArrayList<I2PSocket>();
protected boolean _ownDest;
protected Destination dest = null;
protected Destination dest;
private int localPort;
private boolean listenerReady = false;
/**
* Protected for I2Ping since 0.9.10. Not for use outside package.
*/
protected boolean listenerReady;
protected ServerSocket ss;
private final Object startLock = new Object();
private boolean startRunning = false;
private boolean startRunning;
// private Object closeLock = new Object();
@@ -68,7 +71,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
private String privKeyFile;
// true if we are chained from a server.
private boolean chained = false;
private boolean chained;
/** how long to wait before dropping an idle thread */
private static final long HANDLER_KEEPALIVE_MS = 2*60*1000;
@@ -582,7 +585,11 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
return i2ps;
}
public final void run() {
/**
* Non-final since 0.9.10.
* Any overrides must set listenerReady = true.
*/
public void run() {
try {
InetAddress addr = getListenHost(l);
if (addr == null) {

View File

@@ -6,69 +6,70 @@ package net.i2p.i2ptunnel;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.data.Destination;
import net.i2p.util.EventDispatcher;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
public class I2Ping extends I2PTunnelTask implements Runnable {
private final static Log _log = new Log(I2Ping.class);
/**
* Warning - not necessarily a stable API.
* Used by I2PTunnel CLI only. Consider this sample code.
* Not for use outside this package.
*/
public class I2Ping extends I2PTunnelClientBase {
private int PING_COUNT = 3;
public static final String PROP_COMMAND = "command";
private static final int PING_COUNT = 3;
private static final int CPING_COUNT = 5;
private static final int PING_TIMEOUT = 5000;
private static final int PING_TIMEOUT = 30*1000;
private static final long PING_DISTANCE = 1000;
private int MAX_SIMUL_PINGS = 10; // not really final...
private boolean countPing = false;
private boolean reportTimes = true;
private I2PSocketManager sockMgr;
private Logging l;
private boolean finished = false;
private String command;
private long timeout = PING_TIMEOUT;
private volatile boolean finished;
private final Object simulLock = new Object();
private int simulPings = 0;
private long lastPingTime = 0;
private int simulPings;
private long lastPingTime;
private final Object lock = new Object(), slock = new Object();
//public I2Ping(String cmd, Logging l,
// boolean ownDest) {
// I2Ping(cmd, l, (EventDispatcher)null);
//}
public I2Ping(String cmd, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel) {
super("I2Ping [" + cmd + "]", notifyThis, tunnel);
this.l = l;
command = cmd;
synchronized (slock) {
if (ownDest) {
sockMgr = I2PTunnelClient.buildSocketManager(tunnel);
} else {
sockMgr = I2PTunnelClient.getSocketManager(tunnel);
}
/**
* tunnel.getOptions must contain "command".
* @throws IllegalArgumentException if it doesn't
*/
public I2Ping(Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel) {
super(-1, ownDest, l, notifyThis, "I2Ping", tunnel);
if (!tunnel.getClientOptions().containsKey(PROP_COMMAND)) {
// todo clean up
throw new IllegalArgumentException("Options does not contain " + PROP_COMMAND);
}
Thread t = new I2PAppThread(this);
t.setName("Client");
t.start();
open = true;
}
/**
* Overrides super. No client ServerSocket is created.
*/
@Override
public void run() {
// Notify constructor that port is ready
synchronized (this) {
listenerReady = true;
notify();
}
l.log("*** I2Ping results:");
try {
runCommand(command);
runCommand(getTunnel().getClientOptions().getProperty(PROP_COMMAND));
} catch (InterruptedException ex) {
l.log("*** Interrupted");
_log.error("Pinger interrupted", ex);
@@ -76,13 +77,15 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
_log.error("Pinger exception", ex);
}
l.log("*** Finished.");
synchronized (lock) {
finished = true;
}
finished = true;
close(false);
}
public void runCommand(String cmd) throws InterruptedException, IOException {
long timeout = PING_TIMEOUT;
int count = PING_COUNT;
boolean countPing = false;
boolean reportTimes = true;
while (true) {
if (cmd.startsWith("-t ")) { // timeout
cmd = cmd.substring(3);
@@ -92,6 +95,9 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
return;
} else {
timeout = Long.parseLong(cmd.substring(0, pos));
// convenience, convert msec to sec
if (timeout < 100)
timeout *= 1000;
cmd = cmd.substring(pos + 1);
}
} else if (cmd.startsWith("-m ")) { // max simultaneous pings
@@ -111,11 +117,12 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
l.log("Syntax error");
return;
} else {
PING_COUNT = Integer.parseInt(cmd.substring(0, pos));
count = Integer.parseInt(cmd.substring(0, pos));
cmd = cmd.substring(pos + 1);
}
} else if (cmd.startsWith("-c ")) { // "count" ping
countPing = true;
count = CPING_COUNT;
cmd = cmd.substring(3);
} else if (cmd.equals("-h")) { // ping all hosts
cmd = "-l hosts.txt";
@@ -131,7 +138,9 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
if (line.indexOf("=") != -1) { // maybe file is hosts.txt?
line = line.substring(0, line.indexOf("="));
}
pingHandlers.add(new PingHandler(line));
PingHandler ph = new PingHandler(line, count, timeout, countPing, reportTimes);
ph.start();
pingHandlers.add(ph);
if (++i > 1)
reportTimes = false;
}
@@ -140,28 +149,28 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
t.join();
return;
} else {
Thread t = new PingHandler(cmd);
Thread t = new PingHandler(cmd, count, timeout, countPing, reportTimes);
t.start();
t.join();
return;
}
}
}
@Override
public boolean close(boolean forced) {
if (!open) return true;
synchronized (lock) {
if (!forced && !finished) {
l.log("There are still pings running!");
return false;
}
l.log("Closing pinger " + toString());
l.log("Pinger closed.");
open = false;
return true;
super.close(forced);
if (!forced && !finished) {
l.log("There are still pings running!");
return false;
}
l.log("Closing pinger " + toString());
l.log("Pinger closed.");
return true;
}
public boolean ping(Destination dest) throws I2PException {
private boolean ping(Destination dest, long timeout) throws I2PException {
try {
synchronized (simulLock) {
while (simulPings >= MAX_SIMUL_PINGS) {
@@ -186,33 +195,48 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
}
}
public class PingHandler extends I2PAppThread {
private String destination;
/**
* Does nothing.
* @since 0.9.10
*/
protected void clientConnectionRun(Socket s) {}
public PingHandler(String dest) {
private class PingHandler extends I2PAppThread {
private final String destination;
private final int cnt;
private final long timeout;
private final boolean countPing;
private final boolean reportTimes;
/**
* As of 0.9.10, does NOT start itself.
* Caller must call start()
* @param dest b64 or b32 or host name
*/
public PingHandler(String dest, int count, long timeout, boolean countPings, boolean report) {
this.destination = dest;
cnt = count;
this.timeout = timeout;
countPing = countPings;
reportTimes = report;
setName("PingHandler for " + dest);
start();
}
@Override
public void run() {
try {
Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(destination);
Destination dest = lookup(destination);
if (dest == null) {
synchronized (lock) { // Logger is not thread safe
l.log("Unresolvable: " + destination + "");
}
l.log("Unresolvable: " + destination);
return;
}
int pass = 0;
int fail = 0;
long totalTime = 0;
int cnt = countPing ? CPING_COUNT : PING_COUNT;
StringBuilder pingResults = new StringBuilder(2 * cnt + destination.length() + 3);
for (int i = 0; i < cnt; i++) {
boolean sent;
sent = ping(dest);
sent = ping(dest, timeout);
if (countPing) {
if (!sent) {
pingResults.append(i).append(" ");
@@ -244,12 +268,35 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
pingResults.append("and ").append(fail).append(" lost for destination: ");
}
pingResults.append(" ").append(destination);
synchronized (lock) { // Logger is not thread safe
l.log(pingResults.toString());
}
l.log(pingResults.toString());
} catch (I2PException ex) {
_log.error("Error pinging " + destination, ex);
}
}
/**
* @param name b64 or b32 or host name
* @since 0.9.10
*/
private Destination lookup(String name) {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
boolean b32 = name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p");
if (ctx.isRouterContext() && !b32) {
// Local lookup.
// Even though we could do b32 outside router ctx here,
// we do it below instead so we can use the session,
// which we can't do with lookup()
Destination dest = ctx.namingService().lookup(name);
if (dest != null || ctx.isRouterContext() || name.length() >= 516)
return dest;
}
try {
I2PSession sess = sockMgr.getSession();
return sess.lookupDest(name);
} catch (I2PSessionException ise) {
_log.error("Error looking up " + name, ise);
return null;
}
}
}
}