/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
* (c) 2003 - 2004 mihi
*/
package net.i2p.i2ptunnel.irc;
import java.net.Socket;
import java.io.IOException;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.I2PTunnel;
import net.i2p.i2ptunnel.I2PTunnelClientBase;
import net.i2p.i2ptunnel.I2PTunnelRunner;
import net.i2p.i2ptunnel.Logging;
import net.i2p.util.EventDispatcher;
import net.i2p.util.Log;
/**
* A standard client, using an existing socket manager.
* Targets a single destination and port.
* Naming resolution is delayed until connect time.
*
* @since 0.8.9
*/
public class I2PTunnelDCCClient extends I2PTunnelClientBase {
// delay resolution until connect time
private final String _dest;
private final int _remotePort;
private long _expires;
private static final long INBOUND_EXPIRE = 30*60*1000;
private static final long INBOUND_STOP_EXPIRE = 30*60*1000;
public static final String CONNECT_START_EVENT = "connectionStarted";
public static final String CONNECT_STOP_EVENT = "connectionStopped";
/**
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @param dest the target, presumably b32
* @param localPort if 0, use any port, get actual port selected with getLocalPort()
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
*/
public I2PTunnelDCCClient(String dest, int localPort, int remotePort, Logging l,
I2PSocketManager sktMgr, EventDispatcher notifyThis,
I2PTunnel tunnel, long clientId) throws IllegalArgumentException {
super(localPort, l, sktMgr, tunnel, notifyThis, clientId);
_dest = dest;
_remotePort = remotePort;
_expires = tunnel.getContext().clock().now() + INBOUND_EXPIRE;
setName("DCC send -> " + dest + ':' + remotePort);
}
/**
* Accept one connection only.
*/
protected void clientConnectionRun(Socket s) {
I2PSocket i2ps = null;
if (_log.shouldLog(Log.INFO))
_log.info("Opening DCC connection to " + _dest + ':' + _remotePort);
Destination dest = _context.namingService().lookup(_dest);
if (dest == null) {
_log.error("Could not find leaseset for DCC connection to " + _dest + ':' + _remotePort);
closeSocket(s);
stop();
notifyEvent(CONNECT_STOP_EVENT, Integer.valueOf(getLocalPort()));
return;
}
I2PSocketOptions opts = sockMgr.buildOptions();
opts.setPort(_remotePort);
try {
i2ps = createI2PSocket(dest, opts);
Thread t = new Runner(s, i2ps);
// we are called from an unlimited thread pool, so run inline
//t.start();
t.run();
} catch (IOException ex) {
_log.error("Could not make DCC connection to " + _dest + ':' + _remotePort, ex);
closeSocket(s);
if (i2ps != null) {
try { i2ps.close(); } catch (IOException ioe) {}
}
notifyEvent(CONNECT_STOP_EVENT, Integer.valueOf(getLocalPort()));
} catch (I2PException ex) {
_log.error("Could not make DCC connection to " + _dest + ':' + _remotePort, ex);
closeSocket(s);
if (i2ps != null) {
try { i2ps.close(); } catch (IOException ioe) {}
}
notifyEvent(CONNECT_STOP_EVENT, Integer.valueOf(getLocalPort()));
}
stop();
}
public long getExpires() {
return _expires;
}
public String getDest() {
return _dest;
}
public int getRemotePort() {
return _remotePort;
}
/**
* Stop listening for new sockets.
* We can't call super.close() as it kills all sockets in the sockMgr
*/
public void stop() {
open = false;
try {
ss.close();
} catch (IOException ioe) {}
}
/**
* Just so we can do the callbacks
*/
private class Runner extends I2PTunnelRunner {
/**
* Does NOT start itself. Caller must call start().
*/
public Runner(Socket s, I2PSocket i2ps) {
super(s, i2ps, sockLock, null, null, mySockets, (FailCallback) null);
}
@Override
public void run() {
_expires = getTunnel().getContext().clock().now() + INBOUND_STOP_EXPIRE;
notifyEvent(CONNECT_START_EVENT, I2PTunnelDCCClient.this);
super.run();
_expires = getTunnel().getContext().clock().now() + INBOUND_STOP_EXPIRE;
notifyEvent(CONNECT_STOP_EVENT, Integer.valueOf(getLocalPort()));
}
}
}