use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class SAMv3StreamSession method connect.
/**
* Connect the SAM STREAM session to the specified Destination
* for a single connection, using the socket stolen from the handler.
*
* @param handler The handler that communicates with the requesting client
* @param dest Base64-encoded Destination to connect to
* @param props Options to be used for connection
*
* @throws DataFormatException if the destination is not valid
* @throws ConnectException if the destination refuses connections
* @throws NoRouteToHostException if the destination can't be reached
* @throws InterruptedIOException if the connection timeouts
* @throws I2PException if there's another I2P-related error
* @throws IOException
*/
public void connect(SAMv3Handler handler, String dest, Properties props) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, IOException {
boolean verbose = !Boolean.parseBoolean(props.getProperty("SILENT"));
Destination d = SAMUtils.getDest(dest);
I2PSocketOptions opts = socketMgr.buildOptions(props);
if (props.getProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT) == null)
opts.setConnectTimeout(60 * 1000);
String fromPort = props.getProperty("FROM_PORT");
if (fromPort != null) {
try {
opts.setLocalPort(Integer.parseInt(fromPort));
} catch (NumberFormatException nfe) {
throw new I2PException("Bad port " + fromPort);
}
}
String toPort = props.getProperty("TO_PORT");
if (toPort != null) {
try {
opts.setPort(Integer.parseInt(toPort));
} catch (NumberFormatException nfe) {
throw new I2PException("Bad port " + toPort);
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Connecting new I2PSocket...");
// blocking connection (SAMv3)
I2PSocket i2ps = socketMgr.connect(d, opts);
SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
if (rec == null)
throw new InterruptedIOException();
handler.notifyStreamResult(verbose, "OK", null);
handler.stealSocket();
ReadableByteChannel fromClient = handler.getClientSocket();
ReadableByteChannel fromI2P = Channels.newChannel(i2ps.getInputStream());
WritableByteChannel toClient = handler.getClientSocket();
WritableByteChannel toI2P = Channels.newChannel(i2ps.getOutputStream());
SAMBridge bridge = handler.getBridge();
(new I2PAppThread(rec.getThreadGroup(), new Pipe(fromClient, toI2P, bridge), "ConnectV3 SAMPipeClientToI2P")).start();
(new I2PAppThread(rec.getThreadGroup(), new Pipe(fromI2P, toClient, bridge), "ConnectV3 SAMPipeI2PToClient")).start();
}
use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class SAMStreamSession method connect.
/**
* Connect the SAM STREAM session to the specified Destination
*
* @param id Unique id for the connection
* @param dest Base64-encoded Destination to connect to
* @param props Options to be used for connection
*
* @return true if successful
* @throws DataFormatException if the destination is not valid
* @throws SAMInvalidDirectionException if trying to connect through a
* receive-only session
* @throws ConnectException if the destination refuses connections
* @throws NoRouteToHostException if the destination can't be reached
* @throws InterruptedIOException if the connection timeouts
* @throws I2PException if there's another I2P-related error
* @throws IOException
*/
public boolean connect(int id, String dest, Properties props) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, SAMInvalidDirectionException, IOException {
if (!canCreate) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Trying to create an outgoing connection using a receive-only session");
throw new SAMInvalidDirectionException("Trying to create connections through a receive-only session");
}
if (checkSocketHandlerId(id)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("The specified id (" + id + ") is already in use");
return false;
}
Destination d = SAMUtils.getDest(dest);
I2PSocketOptions opts = socketMgr.buildOptions(props);
if (props.getProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT) == null)
opts.setConnectTimeout(60 * 1000);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Connecting new I2PSocket...");
// blocking connection (SAMv1)
I2PSocket i2ps = socketMgr.connect(d, opts);
createSocketHandler(i2ps, id);
recv.notifyStreamOutgoingConnection(id, "OK", null);
return true;
}
use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class I2PTunnelClient method clientConnectionRun.
protected void clientConnectionRun(Socket s) {
I2PSocket i2ps = null;
try {
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);
I2PTunnelRunner t = new I2PTunnelRunner(s, i2ps, sockLock, null, null, mySockets, (I2PTunnelRunner.FailCallback) null);
// we are called from an unlimited thread pool, so run inline
// t.start();
t.run();
} catch (IOException ex) {
if (_log.shouldLog(Log.INFO))
_log.info("Error connecting", ex);
} catch (I2PException ex) {
if (_log.shouldLog(Log.INFO))
_log.info("Error connecting", ex);
} finally {
// only because we are running it inline
closeSocket(s);
if (i2ps != null) {
try {
i2ps.close();
} catch (IOException ioe) {
}
synchronized (sockLock) {
mySockets.remove(i2ps);
}
}
}
}
use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class I2PTunnelClientBase method close.
/**
* Note that the tunnel can be reopened after this by calling startRunning().
* This may not release all resources. In particular, the I2PSocketManager remains
* and it may have timer threads that continue running.
*
* To release all resources permanently, call destroy().
*
* Does nothing if open is already false.
* Sets open = false but does not notifyAll().
*
* @return success
*/
public boolean close(boolean forced) {
if (_log.shouldLog(Log.INFO))
_log.info("close() called: forced = " + forced + " open = " + open + " sockMgr = " + sockMgr);
if (!open)
return true;
// to return with an error in that situation quickly.
synchronized (sockLock) {
if (sockMgr != null) {
mySockets.retainAll(sockMgr.listSockets());
if ((!forced) && (!mySockets.isEmpty())) {
l.log("Not closing, there are still active connections!");
_log.debug("can't close: there are still active connections!");
for (I2PSocket s : mySockets) {
l.log(" -> " + s.toString());
}
return false;
}
if (!chained) {
I2PSession session = sockMgr.getSession();
getTunnel().removeSession(session);
if (_ownDest) {
try {
session.destroySession();
} catch (I2PException ex) {
}
}
// TCG will try to destroy it too
}
// else the app chaining to this one closes it!
}
l.log("Stopping client " + toString());
open = false;
try {
if (ss != null)
ss.close();
} catch (IOException ex) {
if (_log.shouldDebug())
_log.debug("error closing", ex);
return false;
}
// l.log("Client closed.");
}
return true;
}
use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class I2PTunnelConnectClient method clientConnectionRun.
protected void clientConnectionRun(Socket s) {
InputStream in = null;
OutputStream out = null;
String targetRequest = null;
boolean usingWWWProxy = false;
String currentProxy = null;
// local outproxy plugin
boolean usingInternalOutproxy = false;
Outproxy outproxy = null;
long requestId = __requestId.incrementAndGet();
I2PSocket i2ps = null;
try {
s.setSoTimeout(INITIAL_SO_TIMEOUT);
out = s.getOutputStream();
in = s.getInputStream();
String line, method = null, host = null, destination = null, restofline = null;
StringBuilder newRequest = new StringBuilder();
String authorization = null;
int remotePort = 443;
while (true) {
// Use this rather than BufferedReader because we can't have readahead,
// since we are passing the stream on to I2PTunnelRunner
line = DataHelper.readLine(in);
if (line == null) {
break;
}
line = line.trim();
if (_log.shouldLog(Log.DEBUG))
_log.debug(getPrefix(requestId) + "Line=[" + line + "]");
if (method == null) {
// first line CONNECT blah.i2p:80 HTTP/1.1
int pos = line.indexOf(' ');
// empty first line
if (pos == -1)
break;
method = line.substring(0, pos);
String request = line.substring(pos + 1);
pos = request.indexOf(':');
if (pos == -1) {
pos = request.indexOf(' ');
} else {
int spos = request.indexOf(' ');
if (spos > 0) {
try {
remotePort = Integer.parseInt(request.substring(pos + 1, spos));
} catch (NumberFormatException nfe) {
break;
} catch (IndexOutOfBoundsException ioobe) {
break;
}
}
}
if (pos == -1) {
host = request;
restofline = "";
} else {
host = request.substring(0, pos);
// ":80 HTTP/1.1" or " HTTP/1.1"
restofline = request.substring(pos);
}
if (host.toLowerCase(Locale.US).endsWith(".i2p")) {
// Destination gets the host name
destination = host;
} else if (host.contains(".") || host.startsWith("[")) {
if (Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USE_OUTPROXY_PLUGIN, "true"))) {
ClientAppManager mgr = _context.clientAppManager();
if (mgr != null) {
ClientApp op = mgr.getRegisteredApp(Outproxy.NAME);
if (op != null) {
outproxy = (Outproxy) op;
usingInternalOutproxy = true;
if (host.startsWith("[")) {
host = host.substring(1);
if (host.endsWith("]"))
host = host.substring(0, host.length() - 1);
}
}
}
}
if (!usingInternalOutproxy) {
// The request must be forwarded to a outproxy
currentProxy = selectProxy();
if (currentProxy == null) {
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
writeErrorMessage(ERR_NO_OUTPROXY, out);
return;
}
destination = currentProxy;
usingWWWProxy = true;
// HTTP spec
newRequest.append("CONNECT ").append(host).append(restofline).append("\r\n");
}
} else if (host.toLowerCase(Locale.US).equals("localhost")) {
writeErrorMessage(ERR_LOCALHOST, out);
return;
} else {
// full b64 address (hopefully)
destination = host;
}
targetRequest = host;
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(getPrefix(requestId) + "METHOD:" + method + ":\n" + "HOST :" + host + ":\n" + "PORT :" + remotePort + ":\n" + "REST :" + restofline + ":\n" + "DEST :" + destination + ":\n" + "www proxy? " + usingWWWProxy + " internal proxy? " + usingInternalOutproxy);
}
} else if (line.toLowerCase(Locale.US).startsWith("proxy-authorization: ")) {
// strip Proxy-Authenticate from the response in HTTPResponseOutputStream
// save for auth check below
// "proxy-authorization: ".length()
authorization = line.substring(21);
line = null;
} else if (line.length() > 0) {
// Additional lines - shouldn't be too many. Firefox sends:
// User-Agent: blabla
// Proxy-Connection: keep-alive
// Host: blabla.i2p
//
// We could send these (filtered like in HTTPClient) on to the outproxy,
// but for now just chomp them all.
line = null;
} else {
// Add Proxy-Authentication header for next hop (outproxy)
if (usingWWWProxy && Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_AUTH))) {
// specific for this proxy
String user = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_USER_PREFIX + currentProxy);
String pw = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_PW_PREFIX + currentProxy);
if (user == null || pw == null) {
// if not, look at default user and pw
user = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_USER);
pw = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_PW);
}
if (user != null && pw != null) {
newRequest.append("Proxy-Authorization: Basic ").append(// true = use standard alphabet
Base64.encode(DataHelper.getUTF8(user + ':' + pw), true)).append("\r\n");
}
}
// HTTP spec
newRequest.append("\r\n");
s.setSoTimeout(0);
// do it
break;
}
}
if (method == null || !"CONNECT".equals(method.toUpperCase(Locale.US))) {
writeErrorMessage(ERR_BAD_PROTOCOL, out);
return;
}
// no destination, going to outproxy plugin
if (usingInternalOutproxy) {
Socket outSocket = outproxy.connect(host, remotePort);
OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
byte[] response = SUCCESS_RESPONSE.getBytes("UTF-8");
Thread t = new I2PTunnelOutproxyRunner(s, outSocket, sockLock, null, response, onTimeout);
// we are called from an unlimited thread pool, so run inline
t.run();
return;
}
if (destination == null) {
writeErrorMessage(ERR_BAD_PROTOCOL, out);
return;
}
// Authorization
AuthResult result = authorize(s, requestId, method, authorization);
if (result != AuthResult.AUTH_GOOD) {
if (_log.shouldLog(Log.WARN)) {
if (authorization != null)
_log.warn(getPrefix(requestId) + "Auth failed, sending 407 again");
else
_log.warn(getPrefix(requestId) + "Auth required, sending 407");
}
out.write(DataHelper.getASCII(getAuthError(result == AuthResult.AUTH_STALE)));
return;
}
Destination clientDest = _context.namingService().lookup(destination);
if (clientDest == null) {
String header;
if (usingWWWProxy)
header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN);
else
header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN);
writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination);
return;
}
I2PSocketOptions sktOpts = getDefaultOptions();
if (!usingWWWProxy && remotePort > 0)
sktOpts.setPort(remotePort);
i2ps = createI2PSocket(clientDest, sktOpts);
byte[] data = null;
byte[] response = null;
if (usingWWWProxy)
data = newRequest.toString().getBytes("ISO-8859-1");
else
response = SUCCESS_RESPONSE.getBytes("UTF-8");
OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
Thread t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
// we are called from an unlimited thread pool, so run inline
// t.start();
t.run();
} catch (IOException ex) {
_log.info(getPrefix(requestId) + "Error trying to connect", ex);
handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
} catch (I2PException ex) {
_log.info("getPrefix(requestId) + Error trying to connect", ex);
handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
} catch (OutOfMemoryError oom) {
IOException ex = new IOException("OOM");
_log.info("getPrefix(requestId) + Error trying to connect", ex);
handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
} finally {
// only because we are running it inline
closeSocket(s);
if (i2ps != null)
try {
i2ps.close();
} catch (IOException ioe) {
}
}
}
Aggregations