forked from I2P_Developers/i2p.i2p
* I2PTunnel standard and IRC clients:
- Allow host:port targets; set defaults in i2ptunnel.config (ticket #1066) - Don't fail start if hostname is unresolvable; retry at connect time (ticket #946) - Output IRC message on connect fail - Update target list on-the-fly when configuration changes
This commit is contained in:
@@ -4,24 +4,35 @@
|
|||||||
package net.i2p.i2ptunnel;
|
package net.i2p.i2ptunnel;
|
||||||
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import net.i2p.client.streaming.I2PSocket;
|
import net.i2p.client.streaming.I2PSocket;
|
||||||
|
import net.i2p.client.streaming.I2PSocketAddress;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.util.EventDispatcher;
|
import net.i2p.util.EventDispatcher;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
public class I2PTunnelClient extends I2PTunnelClientBase {
|
public class I2PTunnelClient extends I2PTunnelClientBase {
|
||||||
|
|
||||||
/** list of Destination objects that we point at */
|
/**
|
||||||
|
* list of Destination objects that we point at
|
||||||
|
* @deprecated why protected? Is anybody using out-of-tree? Protected from the beginning (2004)
|
||||||
|
*/
|
||||||
protected List<Destination> dests;
|
protected List<Destination> dests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* replacement for dests
|
||||||
|
*/
|
||||||
|
private final List<I2PSocketAddress> _addrs;
|
||||||
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1
|
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1
|
||||||
protected long readTimeout = DEFAULT_READ_TIMEOUT;
|
protected long readTimeout = DEFAULT_READ_TIMEOUT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param destinations comma delimited list of peers we target
|
* @param destinations peers we target, comma- or space-separated. Since 0.9.9, each dest may be appended with :port
|
||||||
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
||||||
* valid config to contact the router
|
* valid config to contact the router
|
||||||
*/
|
*/
|
||||||
@@ -32,30 +43,21 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
|
|||||||
"Standard client on " + tunnel.listenHost + ':' + localPort,
|
"Standard client on " + tunnel.listenHost + ':' + localPort,
|
||||||
tunnel, pkf);
|
tunnel, pkf);
|
||||||
|
|
||||||
|
_addrs = new ArrayList(1);
|
||||||
if (waitEventValue("openBaseClientResult").equals("error")) {
|
if (waitEventValue("openBaseClientResult").equals("error")) {
|
||||||
notifyEvent("openClientResult", "error");
|
notifyEvent("openClientResult", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringTokenizer tok = new StringTokenizer(destinations, ", ");
|
|
||||||
dests = new ArrayList(1);
|
dests = new ArrayList(1);
|
||||||
while (tok.hasMoreTokens()) {
|
buildAddresses(destinations);
|
||||||
String destination = tok.nextToken();
|
|
||||||
Destination destN = _context.namingService().lookup(destination);
|
|
||||||
if (destN == null)
|
|
||||||
l.log("Could not resolve " + destination);
|
|
||||||
else
|
|
||||||
dests.add(destN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dests.isEmpty()) {
|
if (_addrs.isEmpty()) {
|
||||||
l.log("No valid target destinations found");
|
l.log("No valid target destinations found");
|
||||||
notifyEvent("openClientResult", "error");
|
notifyEvent("openClientResult", "error");
|
||||||
// Nothing is listening for the above event, so it's useless
|
// Nothing is listening for the above event, so it's useless
|
||||||
// Maybe figure out where to put a waitEventValue("openClientResult") ??
|
// Maybe figure out where to put a waitEventValue("openClientResult") ??
|
||||||
// In the meantime, let's do this the easy way
|
// In the meantime, let's do this the easy way
|
||||||
// Note that b32 dests will often not be resolvable at instantiation time;
|
|
||||||
// a delayed resolution system would be even better.
|
|
||||||
|
|
||||||
// Don't close() here, because it does a removeSession() and then
|
// Don't close() here, because it does a removeSession() and then
|
||||||
// TunnelController can't acquire() it to release() it.
|
// TunnelController can't acquire() it to release() it.
|
||||||
@@ -72,14 +74,53 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
|
|||||||
notifyEvent("openClientResult", "ok");
|
notifyEvent("openClientResult", "ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.9.9 moved from constructor */
|
||||||
|
private void buildAddresses(String destinations) {
|
||||||
|
if (destinations == null)
|
||||||
|
return;
|
||||||
|
StringTokenizer tok = new StringTokenizer(destinations, ", ");
|
||||||
|
synchronized(_addrs) {
|
||||||
|
_addrs.clear();
|
||||||
|
while (tok.hasMoreTokens()) {
|
||||||
|
String destination = tok.nextToken();
|
||||||
|
try {
|
||||||
|
// Try to resolve here but only log if it doesn't.
|
||||||
|
// Note that b32 _addrs will often not be resolvable at instantiation time.
|
||||||
|
// We will try again to resolve in clientConnectionRun()
|
||||||
|
I2PSocketAddress addr = new I2PSocketAddress(destination);
|
||||||
|
_addrs.add(addr);
|
||||||
|
if (addr.isUnresolved()) {
|
||||||
|
String name = addr.getHostName();
|
||||||
|
if (name.length() == 60 && name.endsWith(".b32.i2p"))
|
||||||
|
l.log("Warning - Could not resolve " + name +
|
||||||
|
", perhaps it is not up, will retry when connecting.");
|
||||||
|
else
|
||||||
|
l.log("Warning - Could not resolve " + name +
|
||||||
|
", you must add it to your address book for it to work.");
|
||||||
|
} else {
|
||||||
|
dests.add(addr.getAddress());
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
l.log("Bad destination " + destination + " - " + iae);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setReadTimeout(long ms) { readTimeout = ms; }
|
public void setReadTimeout(long ms) { readTimeout = ms; }
|
||||||
public long getReadTimeout() { return readTimeout; }
|
public long getReadTimeout() { return readTimeout; }
|
||||||
|
|
||||||
protected void clientConnectionRun(Socket s) {
|
protected void clientConnectionRun(Socket s) {
|
||||||
Destination destN = pickDestination();
|
|
||||||
I2PSocket i2ps = null;
|
I2PSocket i2ps = null;
|
||||||
try {
|
try {
|
||||||
i2ps = createI2PSocket(destN);
|
I2PSocketAddress addr = pickDestination();
|
||||||
|
if (addr == null)
|
||||||
|
throw new UnknownHostException("No valid destination configured");
|
||||||
|
Destination clientDest = addr.getAddress();
|
||||||
|
if (clientDest == null)
|
||||||
|
throw new UnknownHostException("Could not resolve " + addr.getHostName());
|
||||||
|
int port = addr.getPort();
|
||||||
|
i2ps = createI2PSocket(clientDest, port);
|
||||||
i2ps.setReadTimeout(readTimeout);
|
i2ps.setReadTimeout(readTimeout);
|
||||||
new I2PTunnelRunner(s, i2ps, sockLock, null, mySockets);
|
new I2PTunnelRunner(s, i2ps, sockLock, null, mySockets);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@@ -95,16 +136,34 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Destination pickDestination() {
|
private final I2PSocketAddress pickDestination() {
|
||||||
int size = dests.size();
|
synchronized(_addrs) {
|
||||||
if (size <= 0) {
|
int size = _addrs.size();
|
||||||
if (_log.shouldLog(Log.ERROR))
|
if (size <= 0) {
|
||||||
_log.error("No client targets?!");
|
if (_log.shouldLog(Log.ERROR))
|
||||||
return null;
|
_log.error("No client targets?!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (size == 1) // skip the rand in the most common case
|
||||||
|
return _addrs.get(0);
|
||||||
|
int index = _context.random().nextInt(size);
|
||||||
|
return _addrs.get(index);
|
||||||
}
|
}
|
||||||
if (size == 1) // skip the rand in the most common case
|
}
|
||||||
return dests.get(0);
|
|
||||||
int index = _context.random().nextInt(size);
|
/**
|
||||||
return dests.get(index);
|
* Update the dests then call super.
|
||||||
|
*
|
||||||
|
* @since 0.9.9
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void optionsUpdated(I2PTunnel tunnel) {
|
||||||
|
if (getTunnel() != tunnel)
|
||||||
|
return;
|
||||||
|
Properties props = tunnel.getClientOptions();
|
||||||
|
// see TunnelController.setSessionOptions()
|
||||||
|
String targets = props.getProperty("targetDestination");
|
||||||
|
buildAddresses(targets);
|
||||||
|
super.optionsUpdated(tunnel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -521,8 +521,25 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
|||||||
* @return a new I2PSocket
|
* @return a new I2PSocket
|
||||||
*/
|
*/
|
||||||
public I2PSocket createI2PSocket(Destination dest) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
|
public I2PSocket createI2PSocket(Destination dest) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
|
||||||
|
return createI2PSocket(dest, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new I2PSocket towards to the specified destination,
|
||||||
|
* adding it to the list of connections actually managed by this
|
||||||
|
* tunnel.
|
||||||
|
*
|
||||||
|
* @param dest The destination to connect to
|
||||||
|
* @param port The destination port to connect to 0 - 65535
|
||||||
|
* @return a new I2PSocket
|
||||||
|
* @since 0.9.9
|
||||||
|
*/
|
||||||
|
public I2PSocket createI2PSocket(Destination dest, int port)
|
||||||
|
throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
|
||||||
verifySocketManager();
|
verifySocketManager();
|
||||||
return createI2PSocket(dest, getDefaultOptions());
|
I2PSocketOptions opts = getDefaultOptions();
|
||||||
|
opts.setPort(port);
|
||||||
|
return createI2PSocket(dest, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,13 +1,18 @@
|
|||||||
package net.i2p.i2ptunnel;
|
package net.i2p.i2ptunnel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import net.i2p.I2PException;
|
import net.i2p.I2PException;
|
||||||
import net.i2p.client.streaming.I2PSocket;
|
import net.i2p.client.streaming.I2PSocket;
|
||||||
|
import net.i2p.client.streaming.I2PSocketAddress;
|
||||||
import net.i2p.data.Base32;
|
import net.i2p.data.Base32;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.i2ptunnel.irc.DCCClientManager;
|
import net.i2p.i2ptunnel.irc.DCCClientManager;
|
||||||
import net.i2p.i2ptunnel.irc.DCCHelper;
|
import net.i2p.i2ptunnel.irc.DCCHelper;
|
||||||
@@ -28,7 +33,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
|
|||||||
private static volatile long __clientId = 0;
|
private static volatile long __clientId = 0;
|
||||||
|
|
||||||
/** list of Destination objects that we point at */
|
/** list of Destination objects that we point at */
|
||||||
protected List<Destination> dests;
|
private final List<I2PSocketAddress> _addrs;
|
||||||
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1
|
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1
|
||||||
protected long readTimeout = DEFAULT_READ_TIMEOUT;
|
protected long readTimeout = DEFAULT_READ_TIMEOUT;
|
||||||
private final boolean _dccEnabled;
|
private final boolean _dccEnabled;
|
||||||
@@ -41,6 +46,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
|
|||||||
public static final String PROP_DCC = "i2ptunnel.ircclient.enableDCC";
|
public static final String PROP_DCC = "i2ptunnel.ircclient.enableDCC";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param destinations peers we target, comma- or space-separated. Since 0.9.9, each dest may be appended with :port
|
||||||
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
||||||
* valid config to contact the router
|
* valid config to contact the router
|
||||||
*/
|
*/
|
||||||
@@ -57,25 +63,15 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
|
|||||||
notifyThis,
|
notifyThis,
|
||||||
"IRC Client on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel, pkf);
|
"IRC Client on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel, pkf);
|
||||||
|
|
||||||
StringTokenizer tok = new StringTokenizer(destinations, ", ");
|
_addrs = new ArrayList(4);
|
||||||
dests = new ArrayList(2);
|
buildAddresses(destinations);
|
||||||
while (tok.hasMoreTokens()) {
|
|
||||||
String destination = tok.nextToken();
|
|
||||||
Destination destN = _context.namingService().lookup(destination);
|
|
||||||
if (destN == null)
|
|
||||||
l.log("Could not resolve " + destination);
|
|
||||||
else
|
|
||||||
dests.add(destN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dests.isEmpty()) {
|
if (_addrs.isEmpty()) {
|
||||||
l.log("No target destinations found");
|
l.log("No target destinations found");
|
||||||
notifyEvent("openClientResult", "error");
|
notifyEvent("openClientResult", "error");
|
||||||
// Nothing is listening for the above event, so it's useless
|
// Nothing is listening for the above event, so it's useless
|
||||||
// Maybe figure out where to put a waitEventValue("openClientResult") ??
|
// Maybe figure out where to put a waitEventValue("openClientResult") ??
|
||||||
// In the meantime, let's do this the easy way
|
// In the meantime, let's do this the easy way
|
||||||
// Note that b32 dests will often not be resolvable at instantiation time;
|
|
||||||
// a delayed resolution system would be even better.
|
|
||||||
|
|
||||||
// Don't close() here, because it does a removeSession() and then
|
// Don't close() here, because it does a removeSession() and then
|
||||||
// TunnelController can't acquire() it to release() it.
|
// TunnelController can't acquire() it to release() it.
|
||||||
@@ -95,14 +91,51 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
|
|||||||
notifyEvent("openIRCClientResult", "ok");
|
notifyEvent("openIRCClientResult", "ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.9.9 moved from constructor */
|
||||||
|
private void buildAddresses(String destinations) {
|
||||||
|
if (destinations == null)
|
||||||
|
return;
|
||||||
|
StringTokenizer tok = new StringTokenizer(destinations, ", ");
|
||||||
|
synchronized(_addrs) {
|
||||||
|
_addrs.clear();
|
||||||
|
while (tok.hasMoreTokens()) {
|
||||||
|
String destination = tok.nextToken();
|
||||||
|
try {
|
||||||
|
// Try to resolve here but only log if it doesn't.
|
||||||
|
// Note that b32 _addrs will often not be resolvable at instantiation time.
|
||||||
|
// We will try again to resolve in clientConnectionRun()
|
||||||
|
I2PSocketAddress addr = new I2PSocketAddress(destination);
|
||||||
|
_addrs.add(addr);
|
||||||
|
if (addr.isUnresolved()) {
|
||||||
|
String name = addr.getHostName();
|
||||||
|
if (name.length() == 60 && name.endsWith(".b32.i2p"))
|
||||||
|
l.log("Warning - Could not resolve " + name +
|
||||||
|
", perhaps it is not up, will retry when connecting.");
|
||||||
|
else
|
||||||
|
l.log("Warning - Could not resolve " + name +
|
||||||
|
", you must add it to your address book for it to work.");
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
l.log("Bad destination " + destination + " - " + iae);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void clientConnectionRun(Socket s) {
|
protected void clientConnectionRun(Socket s) {
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("New connection local addr is: " + s.getLocalAddress() +
|
_log.info("New connection local addr is: " + s.getLocalAddress() +
|
||||||
" from: " + s.getInetAddress());
|
" from: " + s.getInetAddress());
|
||||||
Destination clientDest = pickDestination();
|
|
||||||
I2PSocket i2ps = null;
|
I2PSocket i2ps = null;
|
||||||
|
I2PSocketAddress addr = pickDestination();
|
||||||
try {
|
try {
|
||||||
i2ps = createI2PSocket(clientDest);
|
if (addr == null)
|
||||||
|
throw new UnknownHostException("No valid destination configured");
|
||||||
|
Destination clientDest = addr.getAddress();
|
||||||
|
if (clientDest == null)
|
||||||
|
throw new UnknownHostException("Could not resolve " + addr.getHostName());
|
||||||
|
int port = addr.getPort();
|
||||||
|
i2ps = createI2PSocket(clientDest, port);
|
||||||
i2ps.setReadTimeout(readTimeout);
|
i2ps.setReadTimeout(readTimeout);
|
||||||
StringBuffer expectedPong = new StringBuffer();
|
StringBuffer expectedPong = new StringBuffer();
|
||||||
DCCHelper dcc = _dccEnabled ? new DCC(s.getLocalAddress().getAddress()) : null;
|
DCCHelper dcc = _dccEnabled ? new DCC(s.getLocalAddress().getAddress()) : null;
|
||||||
@@ -110,21 +143,18 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
|
|||||||
in.start();
|
in.start();
|
||||||
Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong, _log, dcc), "IRC Client " + __clientId + " out", true);
|
Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong, _log, dcc), "IRC Client " + __clientId + " out", true);
|
||||||
out.start();
|
out.start();
|
||||||
} catch (I2PException ex) {
|
|
||||||
if (_log.shouldLog(Log.ERROR))
|
|
||||||
_log.error("Error connecting", ex);
|
|
||||||
//l.log("Error connecting: " + ex.getMessage());
|
|
||||||
closeSocket(s);
|
|
||||||
if (i2ps != null) {
|
|
||||||
synchronized (sockLock) {
|
|
||||||
mySockets.remove(sockLock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// generally NoRouteToHostException
|
// generally NoRouteToHostException
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Error connecting", ex);
|
_log.warn("Error connecting", ex);
|
||||||
//l.log("Error connecting: " + ex.getMessage());
|
//l.log("Error connecting: " + ex.getMessage());
|
||||||
|
try {
|
||||||
|
// Send a response so the user doesn't just see a disconnect
|
||||||
|
// and blame his router or the network.
|
||||||
|
String name = addr != null ? addr.getHostName() : "undefined";
|
||||||
|
String msg = ":" + name + " 499 you :" + ex + "\r\n";
|
||||||
|
s.getOutputStream().write(DataHelper.getUTF8(msg));
|
||||||
|
} catch (IOException ioe) {}
|
||||||
closeSocket(s);
|
closeSocket(s);
|
||||||
if (i2ps != null) {
|
if (i2ps != null) {
|
||||||
synchronized (sockLock) {
|
synchronized (sockLock) {
|
||||||
@@ -135,17 +165,35 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Destination pickDestination() {
|
private final I2PSocketAddress pickDestination() {
|
||||||
int size = dests.size();
|
synchronized(_addrs) {
|
||||||
if (size <= 0) {
|
int size = _addrs.size();
|
||||||
if (_log.shouldLog(Log.ERROR))
|
if (size <= 0) {
|
||||||
_log.error("No client targets?!");
|
if (_log.shouldLog(Log.ERROR))
|
||||||
return null;
|
_log.error("No client targets?!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (size == 1) // skip the rand in the most common case
|
||||||
|
return _addrs.get(0);
|
||||||
|
int index = _context.random().nextInt(size);
|
||||||
|
return _addrs.get(index);
|
||||||
}
|
}
|
||||||
if (size == 1) // skip the rand in the most common case
|
}
|
||||||
return dests.get(0);
|
|
||||||
int index = _context.random().nextInt(size);
|
/**
|
||||||
return dests.get(index);
|
* Update the dests then call super.
|
||||||
|
*
|
||||||
|
* @since 0.9.9
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void optionsUpdated(I2PTunnel tunnel) {
|
||||||
|
if (getTunnel() != tunnel)
|
||||||
|
return;
|
||||||
|
Properties props = tunnel.getClientOptions();
|
||||||
|
// see TunnelController.setSessionOptions()
|
||||||
|
String targets = props.getProperty("targetDestination");
|
||||||
|
buildAddresses(targets);
|
||||||
|
super.optionsUpdated(tunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -424,7 +424,14 @@ public class TunnelController implements Logging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setSessionOptions() {
|
private void setSessionOptions() {
|
||||||
_tunnel.setClientOptions(getClientOptionProps());
|
Properties opts = getClientOptionProps();
|
||||||
|
// targetDestination does NOT start with "option.", but we still want
|
||||||
|
// to allow a change on the fly, so we pass it through this way,
|
||||||
|
// as a "spoofed" option. Since 0.9.9.
|
||||||
|
String target = getTargetDestination();
|
||||||
|
if (target != null)
|
||||||
|
opts.setProperty("targetDestination", target);
|
||||||
|
_tunnel.setClientOptions(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setI2CPOptions() {
|
private void setI2CPOptions() {
|
||||||
|
@@ -165,7 +165,11 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
|||||||
%>
|
%>
|
||||||
</label>
|
</label>
|
||||||
<input type="text" size="30" id="targetDestination" name="targetDestination" title="Destination of the Tunnel" value="<%=editBean.getClientDestination(curTunnel)%>" class="freetext" />
|
<input type="text" size="30" id="targetDestination" name="targetDestination" title="Destination of the Tunnel" value="<%=editBean.getClientDestination(curTunnel)%>" class="freetext" />
|
||||||
<span class="comment">(<%=intl._("name or destination")%>; <%=intl._("b32 not recommended")%>)</span>
|
<span class="comment">(<%=intl._("name, name:port, or destination")%>
|
||||||
|
<% if ("streamrclient".equals(tunnelType)) { /* deferred resolution unimplemented in streamr client */ %>
|
||||||
|
- <%=intl._("b32 not recommended")%>
|
||||||
|
<% } %> )
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% if (!"streamrclient".equals(tunnelType)) { %>
|
<% if (!"streamrclient".equals(tunnelType)) { %>
|
||||||
|
@@ -268,7 +268,11 @@
|
|||||||
<%=intl._("Tunnel Destination")%>(<span class="accessKey">T</span>):
|
<%=intl._("Tunnel Destination")%>(<span class="accessKey">T</span>):
|
||||||
</label>
|
</label>
|
||||||
<input type="text" size="30" id="targetDestination" name="targetDestination" title="Destination of the Tunnel" value="<%=(!"null".equals(request.getParameter("targetDestination")) ? request.getParameter("targetDestination") : "" ) %>" class="freetext" />
|
<input type="text" size="30" id="targetDestination" name="targetDestination" title="Destination of the Tunnel" value="<%=(!"null".equals(request.getParameter("targetDestination")) ? request.getParameter("targetDestination") : "" ) %>" class="freetext" />
|
||||||
<span class="comment">(<%=intl._("name or destination")%>; <%=intl._("b32 not recommended")%>)</span>
|
<span class="comment">(<%=intl._("name, name:port, or destination")%>
|
||||||
|
<% if ("streamrclient".equals(tunnelType)) { /* deferred resolution unimplemented in streamr client */ %>
|
||||||
|
- <%=intl._("b32 not recommended")%>
|
||||||
|
<% } %> )
|
||||||
|
</span>
|
||||||
</div><%
|
</div><%
|
||||||
} else {
|
} else {
|
||||||
%><input type="hidden" name="targetDestination" value="<%=request.getParameter("targetDestination")%>" /><%
|
%><input type="hidden" name="targetDestination" value="<%=request.getParameter("targetDestination")%>" /><%
|
||||||
|
@@ -11,22 +11,52 @@ import net.i2p.data.DataHelper;
|
|||||||
* Ports are not widely used in I2P, in most cases the port will be zero.
|
* Ports are not widely used in I2P, in most cases the port will be zero.
|
||||||
* See InetSocketAddress for javadocs.
|
* See InetSocketAddress for javadocs.
|
||||||
*
|
*
|
||||||
* Warning, this interface and implementation is preliminary and subject to change without notice.
|
|
||||||
*
|
|
||||||
* @since 0.9.1
|
* @since 0.9.1
|
||||||
*/
|
*/
|
||||||
public class I2PSocketAddress extends SocketAddress {
|
public class I2PSocketAddress extends SocketAddress {
|
||||||
|
|
||||||
private final int _port;
|
private final int _port;
|
||||||
private final Destination _dest;
|
private Destination _dest;
|
||||||
private final String _host;
|
private final String _host;
|
||||||
|
|
||||||
// no constructor for port-only "wildcard" address
|
/**
|
||||||
|
* Convenience constructor that parses host:port.
|
||||||
|
*
|
||||||
|
* Does a naming service lookup to resolve the dest.
|
||||||
|
* May take several seconds for b32.
|
||||||
|
* @param host hostname or b64 dest or b32, may have :port appended
|
||||||
|
* @throws IllegalArgumentException for port < 0 or port > 65535 or invalid port
|
||||||
|
* @since 0.9.9
|
||||||
|
*/
|
||||||
|
public I2PSocketAddress(String host) {
|
||||||
|
int port = 0;
|
||||||
|
int colon = host.indexOf(":");
|
||||||
|
if (colon > 0) {
|
||||||
|
try {
|
||||||
|
port = Integer.parseInt(host.substring(colon + 1));
|
||||||
|
host = host.substring(0, colon);
|
||||||
|
if (port < 0 || port > 65535)
|
||||||
|
throw new IllegalArgumentException("bad port " + port);
|
||||||
|
} catch (IndexOutOfBoundsException ioobe) {
|
||||||
|
throw new IllegalArgumentException("bad port " + host);
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
throw new IllegalArgumentException("bad port " + host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_port = port;
|
||||||
|
_dest = I2PAppContext.getGlobalContext().namingService().lookup(host);
|
||||||
|
_host = host;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does not do a reverse lookup. Host will be null.
|
* Does not do a reverse lookup. Host will be null.
|
||||||
|
* @throws IllegalArgumentException for port < 0 or port > 65535
|
||||||
*/
|
*/
|
||||||
public I2PSocketAddress(Destination dest, int port) {
|
public I2PSocketAddress(Destination dest, int port) {
|
||||||
|
if (dest == null)
|
||||||
|
throw new NullPointerException();
|
||||||
|
if (port < 0 || port > 65535)
|
||||||
|
throw new IllegalArgumentException("bad port " + port);
|
||||||
_port = port;
|
_port = port;
|
||||||
_dest = dest;
|
_dest = dest;
|
||||||
_host = null;
|
_host = null;
|
||||||
@@ -35,19 +65,27 @@ public class I2PSocketAddress extends SocketAddress {
|
|||||||
/**
|
/**
|
||||||
* Does a naming service lookup to resolve the dest.
|
* Does a naming service lookup to resolve the dest.
|
||||||
* May take several seconds for b32.
|
* May take several seconds for b32.
|
||||||
|
* @throws IllegalArgumentException for port < 0 or port > 65535
|
||||||
*/
|
*/
|
||||||
public I2PSocketAddress(String host, int port) {
|
public I2PSocketAddress(String host, int port) {
|
||||||
|
if (port < 0 || port > 65535)
|
||||||
|
throw new IllegalArgumentException("bad port " + port);
|
||||||
_port = port;
|
_port = port;
|
||||||
_dest = I2PAppContext.getGlobalContext().namingService().lookup(host);
|
_dest = I2PAppContext.getGlobalContext().namingService().lookup(host);
|
||||||
_host = host;
|
_host = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalArgumentException for port < 0 or port > 65535
|
||||||
|
*/
|
||||||
public static I2PSocketAddress createUnresolved(String host, int port) {
|
public static I2PSocketAddress createUnresolved(String host, int port) {
|
||||||
return new I2PSocketAddress(port, host);
|
return new I2PSocketAddress(port, host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** unresolved */
|
/** unresolved */
|
||||||
private I2PSocketAddress(int port, String host) {
|
private I2PSocketAddress(int port, String host) {
|
||||||
|
if (port < 0 || port > 65535)
|
||||||
|
throw new IllegalArgumentException("bad port " + port);
|
||||||
_port = port;
|
_port = port;
|
||||||
_dest = null;
|
_dest = null;
|
||||||
_host = host;
|
_host = host;
|
||||||
@@ -57,7 +95,14 @@ public class I2PSocketAddress extends SocketAddress {
|
|||||||
return _port;
|
return _port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Destination getAddress() {
|
/**
|
||||||
|
* Does a naming service lookup to resolve the dest if this was created unresolved
|
||||||
|
* or if the resolution failed in the constructor.
|
||||||
|
* If unresolved, this may take several seconds for b32.
|
||||||
|
*/
|
||||||
|
public synchronized Destination getAddress() {
|
||||||
|
if (_dest == null)
|
||||||
|
_dest = I2PAppContext.getGlobalContext().namingService().lookup(_host);
|
||||||
return _dest;
|
return _dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,9 @@
|
|||||||
2013-10-23 zzz
|
2013-10-23 zzz
|
||||||
|
* I2PTunnel standard and IRC clients:
|
||||||
|
- Allow host:port targets; set defaults in i2ptunnel.config (ticket #1066)
|
||||||
|
- Don't fail start if hostname is unresolvable; retry at connect time (ticket #946)
|
||||||
|
- Output IRC message on connect exception
|
||||||
|
- Update target list on-the-fly when configuration changes
|
||||||
* NetDB:
|
* NetDB:
|
||||||
- Increase RI publish interval to reduce the connection load on ffs
|
- Increase RI publish interval to reduce the connection load on ffs
|
||||||
- Save RI-last-published time; check it before publishing
|
- Save RI-last-published time; check it before publishing
|
||||||
|
@@ -35,7 +35,7 @@ tunnel.1.type=ircclient
|
|||||||
tunnel.1.sharedClient=false
|
tunnel.1.sharedClient=false
|
||||||
tunnel.1.interface=127.0.0.1
|
tunnel.1.interface=127.0.0.1
|
||||||
tunnel.1.listenPort=6668
|
tunnel.1.listenPort=6668
|
||||||
tunnel.1.targetDestination=irc.postman.i2p,irc.freshcoffee.i2p,irc.echelon.i2p
|
tunnel.1.targetDestination=irc.postman.i2p:6667,irc.freshcoffee.i2p:6667,irc.echelon.i2p:6667
|
||||||
tunnel.1.i2cpHost=127.0.0.1
|
tunnel.1.i2cpHost=127.0.0.1
|
||||||
tunnel.1.i2cpPort=7654
|
tunnel.1.i2cpPort=7654
|
||||||
tunnel.1.option.inbound.nickname=Irc2P
|
tunnel.1.option.inbound.nickname=Irc2P
|
||||||
@@ -63,7 +63,7 @@ tunnel.2.type=client
|
|||||||
tunnel.2.sharedClient=true
|
tunnel.2.sharedClient=true
|
||||||
tunnel.2.interface=127.0.0.1
|
tunnel.2.interface=127.0.0.1
|
||||||
tunnel.2.listenPort=8998
|
tunnel.2.listenPort=8998
|
||||||
tunnel.2.targetDestination=mtn.i2p2.i2p
|
tunnel.2.targetDestination=mtn.i2p2.i2p:4691
|
||||||
tunnel.2.i2cpHost=127.0.0.1
|
tunnel.2.i2cpHost=127.0.0.1
|
||||||
tunnel.2.i2cpPort=7654
|
tunnel.2.i2cpPort=7654
|
||||||
tunnel.2.option.inbound.nickname=shared clients
|
tunnel.2.option.inbound.nickname=shared clients
|
||||||
@@ -113,7 +113,7 @@ tunnel.4.option.inbound.lengthVariance=0
|
|||||||
tunnel.4.option.outbound.length=3
|
tunnel.4.option.outbound.length=3
|
||||||
tunnel.4.option.outbound.lengthVariance=0
|
tunnel.4.option.outbound.lengthVariance=0
|
||||||
tunnel.4.startOnLoad=true
|
tunnel.4.startOnLoad=true
|
||||||
tunnel.4.targetDestination=smtp.postman.i2p
|
tunnel.4.targetDestination=smtp.postman.i2p:25
|
||||||
tunnel.4.type=client
|
tunnel.4.type=client
|
||||||
tunnel.4.sharedClient=true
|
tunnel.4.sharedClient=true
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ tunnel.5.option.inbound.lengthVariance=0
|
|||||||
tunnel.5.option.outbound.length=3
|
tunnel.5.option.outbound.length=3
|
||||||
tunnel.5.option.outbound.lengthVariance=0
|
tunnel.5.option.outbound.lengthVariance=0
|
||||||
tunnel.5.startOnLoad=true
|
tunnel.5.startOnLoad=true
|
||||||
tunnel.5.targetDestination=pop.postman.i2p
|
tunnel.5.targetDestination=pop.postman.i2p:110
|
||||||
tunnel.5.type=client
|
tunnel.5.type=client
|
||||||
tunnel.5.sharedClient=true
|
tunnel.5.sharedClient=true
|
||||||
|
|
||||||
|
@@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 7;
|
public final static long BUILD = 8;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
Reference in New Issue
Block a user