use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class I2PTunnelHTTPClient method clientConnectionRun.
/**
* Note: This does not handle RFC 2616 header line splitting,
* which is obsoleted in RFC 7230.
*/
protected void clientConnectionRun(Socket s) {
OutputStream out = null;
/**
* The URL after fixup, always starting with http:// or https://
*/
String targetRequest = null;
// in-net outproxy
boolean usingWWWProxy = false;
// local outproxy plugin
boolean usingInternalOutproxy = false;
Outproxy outproxy = null;
boolean usingInternalServer = false;
String internalPath = null;
String internalRawQuery = null;
String currentProxy = null;
long requestId = __requestId.incrementAndGet();
boolean shout = false;
I2PSocket i2ps = null;
try {
s.setSoTimeout(INITIAL_SO_TIMEOUT);
out = s.getOutputStream();
InputReader reader = new InputReader(s.getInputStream());
String line, method = null, protocol = null, host = null, destination = null;
StringBuilder newRequest = new StringBuilder();
boolean ahelperPresent = false;
boolean ahelperNew = false;
String ahelperKey = null;
String userAgent = null;
String authorization = null;
int remotePort = 0;
String referer = null;
URI origRequestURI = null;
while ((line = reader.readLine(method)) != null) {
line = line.trim();
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(getPrefix(requestId) + "Line=[" + line + "]");
}
String lowercaseLine = line.toLowerCase(Locale.US);
if (lowercaseLine.startsWith("connection: ") || lowercaseLine.startsWith("keep-alive: ") || lowercaseLine.startsWith("proxy-connection: ")) {
continue;
}
if (method == null) {
// first line (GET /base64/realaddr)
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(getPrefix(requestId) + "First line [" + line + "]");
}
String[] params = DataHelper.split(line, " ", 3);
if (params.length != 3) {
break;
}
String request = params[1];
// various obscure fixups
if (request.startsWith("/") && getTunnel().getClientOptions().getProperty("i2ptunnel.noproxy") != null) {
// what is this for ???
request = "http://i2p" + request;
} else if (request.startsWith("/eepproxy/")) {
// Deprecated
// /eepproxy/foo.i2p/bar/baz.html
String subRequest = request.substring("/eepproxy/".length());
if (subRequest.indexOf('/') == -1) {
subRequest += '/';
}
request = "http://" + subRequest;
/**
**
* } else if (request.toLowerCase(Locale.US).startsWith("http://i2p/")) {
* // http://i2p/b64key/bar/baz.html
* // we can't do this now by setting the URI host to the b64key, as
* // it probably contains '=' and '~' which are illegal,
* // and a host may not include escaped octets
* // This will get undone below.
* String subRequest = request.substring("http://i2p/".length());
* if (subRequest.indexOf("/") == -1)
* subRequest += "/";
* "http://" + "b64key/bar/baz.html"
* request = "http://" + subRequest;
* } else if (request.toLowerCase(Locale.US).startsWith("http://")) {
* // Unsupported
* // http://$b64key/...
* // This probably used to work, rewrite it so that
* // we can create a URI without illegal characters
* // This will get undone below.
* String oldPath = request.substring(7);
* int slash = oldPath.indexOf("/");
* if (slash < 0)
* slash = oldPath.length();
* if (slash >= 516 && !oldPath.substring(0, slash).contains("."))
* request = "http://i2p/" + oldPath;
***
*/
}
method = params[0];
if (method.toUpperCase(Locale.US).equals("CONNECT")) {
// this makes things easier later, by spoofing a
// protocol so the URI parser find the host and port
// For in-net outproxy, will be fixed up below
request = "https://" + request + '/';
}
// Now use the Java URI parser
// This will be the incoming URI but will then get modified
// to be the outgoing URI (with http:// if going to outproxy, otherwise without)
URI requestURI = null;
try {
try {
requestURI = new URI(request);
} catch (URISyntaxException use) {
// fixup []| in path/query not escaped by browsers, see ticket #2130
boolean error = true;
// find 3rd /
int idx = 0;
for (int i = 0; i < 2; i++) {
idx = request.indexOf('/', idx);
if (idx < 0)
break;
idx++;
}
if (idx > 0) {
String schemeHostPort = request.substring(0, idx);
String rest = request.substring(idx);
rest = rest.replace("[", "%5B");
rest = rest.replace("]", "%5D");
rest = rest.replace("|", "%7C");
String testRequest = schemeHostPort + rest;
if (!testRequest.equals(request)) {
try {
requestURI = new URI(testRequest);
request = testRequest;
error = false;
} catch (URISyntaxException use2) {
// didn't work, give up
}
}
}
// guess it wasn't []|
if (error)
throw use;
}
origRequestURI = requestURI;
if (requestURI.getRawUserInfo() != null || requestURI.getRawFragment() != null) {
// these should never be sent to the proxy in the request line
if (_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Removing userinfo or fragment [" + request + "]");
}
requestURI = changeURI(requestURI, null, 0, null);
}
if (requestURI.getPath() == null || requestURI.getPath().length() <= 0) {
// Add a path
if (_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Adding / path to [" + request + "]");
}
requestURI = changeURI(requestURI, null, 0, "/");
}
} catch (URISyntaxException use) {
if (_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Bad request [" + request + "]", use);
}
try {
out.write(getErrorPage("baduri", ERR_BAD_URI).getBytes("UTF-8"));
String msg = use.getLocalizedMessage();
if (msg != null) {
out.write(DataHelper.getASCII("<p>\n"));
out.write(DataHelper.getUTF8(DataHelper.escapeHTML(msg)));
out.write(DataHelper.getASCII("</p>\n"));
}
out.write(DataHelper.getASCII("</div>\n"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
}
return;
}
String protocolVersion = params[2];
protocol = requestURI.getScheme();
host = requestURI.getHost();
if (protocol == null || host == null) {
_log.warn("Null protocol or host: " + request + ' ' + protocol + ' ' + host);
method = null;
break;
}
int port = requestURI.getPort();
// Go through the various types of host names, set
// the host and destination variables accordingly,
// and transform the first line.
// For all i2p network hosts, ensure that the host is a
// Base 32 hostname so that we do not reveal our name for it
// in our addressbook (all naming is local),
// and it is removed from the request line.
String hostLowerCase = host.toLowerCase(Locale.US);
if (hostLowerCase.equals(LOCAL_SERVER)) {
// so we don't do any naming service lookups
destination = host;
usingInternalServer = true;
internalPath = requestURI.getPath();
internalRawQuery = requestURI.getRawQuery();
} else if (hostLowerCase.equals("i2p")) {
// pull the b64 _dest out of the first path element
String oldPath = requestURI.getPath().substring(1);
int slash = oldPath.indexOf('/');
if (slash < 0) {
slash = oldPath.length();
oldPath += '/';
}
String _dest = oldPath.substring(0, slash);
if (slash >= 516 && !_dest.contains(".")) {
// possible alternative:
// redirect to b32
destination = _dest;
host = getHostName(destination);
targetRequest = requestURI.toASCIIString();
String newURI = oldPath.substring(slash);
String query = requestURI.getRawQuery();
if (query != null) {
newURI += '?' + query;
}
try {
requestURI = new URI(newURI);
} catch (URISyntaxException use) {
// shouldnt happen
_log.warn(request, use);
method = null;
break;
}
} else {
_log.warn("Bad http://i2p/b64dest " + request);
host = null;
break;
}
} else if (hostLowerCase.endsWith(".i2p")) {
// Destination gets the host name
destination = host;
// Host becomes the destination's "{b32}.b32.i2p" string, or "i2p" on lookup failure
host = getHostName(destination);
int rPort = requestURI.getPort();
if (rPort > 0) {
// Save it to put in the I2PSocketOptions,
remotePort = rPort;
/**
******
* // but strip it from the URL
* if(_log.shouldLog(Log.WARN)) {
* _log.warn(getPrefix(requestId) + "Removing port from [" + request + "]");
* }
* try {
* requestURI = changeURI(requestURI, null, -1, null);
* } catch(URISyntaxException use) {
* _log.warn(request, use);
* method = null;
* break;
* }
*****
*/
} else if ("https".equals(protocol) || method.toUpperCase(Locale.US).equals("CONNECT")) {
remotePort = 443;
} else {
remotePort = 80;
}
String query = requestURI.getRawQuery();
if (query != null) {
boolean ahelperConflict = false;
// Try to find an address helper in the query
String[] helperStrings = removeHelper(query);
if (helperStrings != null && !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
query = helperStrings[0];
if (query.equals("")) {
query = null;
}
try {
requestURI = replaceQuery(requestURI, query);
} catch (URISyntaxException use) {
// shouldn't happen
_log.warn(request, use);
method = null;
break;
}
ahelperKey = helperStrings[1];
// Key contains data, lets not ignore it
if (ahelperKey.length() > 0) {
if (ahelperKey.endsWith(".i2p")) {
// allow i2paddresshelper=<b32>.b32.i2p syntax.
/*
also i2paddresshelper=name.i2p for aliases
i.e. on your eepsite put
<a href="?i2paddresshelper=name.i2p">This is the name I want to be called.</a>
*/
Destination _dest = _context.namingService().lookup(ahelperKey);
if (_dest == null) {
if (_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Could not find destination for " + ahelperKey);
}
String header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
try {
out.write(header.getBytes("UTF-8"));
out.write(("<p>" + _t("This seems to be a bad destination:") + " " + ahelperKey + " " + _t("i2paddresshelper cannot help you with a destination like that!") + "</p>").getBytes("UTF-8"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
}
return;
}
ahelperKey = _dest.toBase64();
}
ahelperPresent = true;
// ahelperKey will be validated later
if (host == null || "i2p".equals(host)) {
// Host lookup failed - resolvable only with addresshelper
// Store in local HashMap unless there is conflict
String old = addressHelpers.putIfAbsent(destination.toLowerCase(Locale.US), ahelperKey);
ahelperNew = old == null;
// inr address helper links without trailing '=', so omit from comparison
if ((!ahelperNew) && !old.replace("=", "").equals(ahelperKey.replace("=", ""))) {
// Conflict: handle when URL reconstruction done
ahelperConflict = true;
if (_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Addresshelper key conflict for site [" + destination + "], trusted key [" + old + "], specified key [" + ahelperKey + "].");
}
}
} else {
// If the host is resolvable from database, verify addresshelper key
// Silently bypass correct keys, otherwise alert
Destination hostDest = _context.namingService().lookup(destination);
if (hostDest != null) {
String destB64 = hostDest.toBase64();
if (destB64 != null && !destB64.equals(ahelperKey)) {
// Conflict: handle when URL reconstruction done
ahelperConflict = true;
if (_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Addresshelper key conflict for site [" + destination + "], trusted key [" + destB64 + "], specified key [" + ahelperKey + "].");
}
}
}
}
}
// ahelperKey
}
// Did addresshelper key conflict?
if (ahelperConflict) {
try {
// convert ahelperKey to b32
String alias = getHostName(ahelperKey);
if (alias.equals("i2p")) {
// bad ahelperKey
String header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
writeErrorMessage(header, out, targetRequest, false, destination);
} else {
String trustedURL = requestURI.toASCIIString();
URI conflictURI;
try {
conflictURI = changeURI(requestURI, alias, 0, null);
} catch (URISyntaxException use) {
// shouldn't happen
_log.warn(request, use);
method = null;
break;
}
String conflictURL = conflictURI.toASCIIString();
String header = getErrorPage("ahelper-conflict", ERR_AHELPER_CONFLICT);
out.write(header.getBytes("UTF-8"));
out.write("<p>".getBytes("UTF-8"));
out.write(_t("To visit the destination in your address book, click <a href=\"{0}\">here</a>. To visit the conflicting addresshelper destination, click <a href=\"{1}\">here</a>.", trustedURL, conflictURL).getBytes("UTF-8"));
out.write("</p>".getBytes("UTF-8"));
Hash h1 = ConvertToHash.getHash(requestURI.getHost());
Hash h2 = ConvertToHash.getHash(ahelperKey);
if (h1 != null && h2 != null) {
String conURL = _context.portMapper().getConsoleURL();
out.write(("\n<table class=\"conflict\"><tr><th align=\"center\">" + "<a href=\"" + trustedURL + "\">").getBytes("UTF-8"));
out.write(_t("Destination for {0} in address book", requestURI.getHost()).getBytes("UTF-8"));
out.write(("</a></th>\n<th align=\"center\">" + "<a href=\"" + conflictURL + "\">").getBytes("UTF-8"));
out.write(_t("Conflicting address helper destination").getBytes("UTF-8"));
out.write(("</a></th></tr>\n").getBytes("UTF-8"));
if (_context.portMapper().getPort(PortMapper.SVC_IMAGEGEN) > 0) {
out.write(("<tr><td align=\"center\">" + "<a href=\"" + trustedURL + "\">" + "<img src=\"" + conURL + "imagegen/id?s=160&c=" + h1.toBase64().replace("=", "%3d") + "\" width=\"160\" height=\"160\"></a>\n" + "</td>\n<td align=\"center\">" + "<a href=\"" + conflictURL + "\">" + "<img src=\"" + conURL + "imagegen/id?s=160&c=" + h2.toBase64().replace("=", "%3d") + "\" width=\"160\" height=\"160\"></a>\n" + "</td></tr>").getBytes("UTF-8"));
}
out.write("</table>".getBytes("UTF-8"));
}
out.write("</div>".getBytes("UTF-8"));
writeFooter(out);
}
reader.drain();
} catch (IOException ioe) {
// ignore
}
return;
}
}
// end query processing
String addressHelper = addressHelpers.get(destination);
if (addressHelper != null) {
host = getHostName(addressHelper);
}
// now strip everything but path and query from URI
targetRequest = requestURI.toASCIIString();
String newURI = requestURI.getRawPath();
if (query != null) {
newURI += '?' + query;
}
try {
requestURI = new URI(newURI);
} catch (URISyntaxException use) {
// shouldnt happen
_log.warn(request, use);
method = null;
break;
}
// end of (host endsWith(".i2p"))
} else if (hostLowerCase.equals("localhost") || host.equals("127.0.0.1") || host.startsWith("192.168.") || host.equals("[::1]")) {
// if somebody is trying to get to 192.168.example.com, oh well
try {
out.write(getErrorPage("localhost", ERR_LOCALHOST).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
}
return;
} 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;
int rPort = requestURI.getPort();
if (rPort > 0)
remotePort = rPort;
else if ("https".equals(protocol) || method.toUpperCase(Locale.US).equals("CONNECT"))
remotePort = 443;
else
remotePort = 80;
usingInternalOutproxy = true;
targetRequest = requestURI.toASCIIString();
if (_log.shouldLog(Log.DEBUG))
_log.debug(getPrefix(requestId) + " [" + host + "]: outproxy!");
}
}
}
if (!usingInternalOutproxy) {
if (port >= 0) {
host = host + ':' + port;
}
// The request must be forwarded to a WWW proxy
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Before selecting outproxy for " + host);
}
if ("https".equals(protocol) || method.toUpperCase(Locale.US).equals("CONNECT"))
currentProxy = selectSSLProxy();
else
currentProxy = selectProxy();
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("After selecting outproxy for " + host + ": " + currentProxy);
}
if (currentProxy == null) {
if (_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
}
l.log("No outproxy found for the request.");
try {
out.write(getErrorPage("noproxy", ERR_NO_OUTPROXY).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
}
return;
}
destination = currentProxy;
usingWWWProxy = true;
targetRequest = requestURI.toASCIIString();
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(getPrefix(requestId) + " [" + host + "]: wwwProxy!");
}
}
} else {
// Rather than look it up, just bail out.
if (_log.shouldLog(Log.WARN)) {
_log.warn("NODOTS, NOI2P: " + request);
}
try {
out.write(getErrorPage("denied", ERR_REQUEST_DENIED).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
}
return;
}
// end host name processing
boolean isValid = usingInternalOutproxy || usingWWWProxy || usingInternalServer || isSupportedAddress(host, protocol);
if (!isValid) {
if (_log.shouldLog(Log.INFO)) {
_log.info(getPrefix(requestId) + "notValid(" + host + ")");
}
method = null;
destination = null;
break;
}
if (method.toUpperCase(Locale.US).equals("CONNECT")) {
// fix up the change to requestURI above to get back to the original host:port
line = method + ' ' + requestURI.getHost() + ':' + requestURI.getPort() + ' ' + protocolVersion;
} else {
line = method + ' ' + requestURI.toASCIIString() + ' ' + protocolVersion;
}
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(getPrefix(requestId) + "NEWREQ: \"" + line + "\"");
_log.debug(getPrefix(requestId) + "HOST : \"" + host + "\"");
_log.debug(getPrefix(requestId) + "DEST : \"" + destination + "\"");
}
// end first line processing
} else {
if (lowercaseLine.startsWith("host: ") && !usingWWWProxy && !usingInternalOutproxy) {
// Note that we only pass the original Host: line through to the outproxy
// But we don't create a Host: line if it wasn't sent to us
line = "Host: " + host;
if (_log.shouldLog(Log.INFO)) {
_log.info(getPrefix(requestId) + "Setting host = " + host);
}
} else if (lowercaseLine.startsWith("user-agent: ")) {
// save for deciding whether to offer address book form
userAgent = lowercaseLine.substring(12);
if (!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT))) {
line = null;
continue;
}
} else if (lowercaseLine.startsWith("accept: ")) {
if (!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_ACCEPT))) {
// Replace with a standard one if possible
boolean html = lowercaseLine.indexOf("text/html") > 0;
boolean css = lowercaseLine.indexOf("text/css") > 0;
boolean img = lowercaseLine.indexOf("image") > 0;
if (html && !img && !css) {
// firefox, tor browser
line = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
} else if (img && !html && !css) {
// chrome
line = "Accept: image/webp,image/apng,image/*,*/*;q=0.8";
} else if (css && !html && !img) {
// chrome, firefox
line = "Accept: text/css,*/*;q=0.1";
}
// else allow as-is
}
} else if (lowercaseLine.startsWith("accept")) {
// But allow Accept-Encoding: gzip, deflate
if (!lowercaseLine.startsWith("accept-encoding: ") && !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_ACCEPT))) {
line = null;
continue;
}
} else if (lowercaseLine.startsWith("referer: ")) {
// save for address helper form below
referer = line.substring(9);
if (!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_REFERER))) {
try {
// Either strip or rewrite the referer line
URI refererURI = new URI(referer);
String refererHost = refererURI.getHost();
if (refererHost != null) {
String origHost = origRequestURI.getHost();
if (!refererHost.equals(origHost) || refererURI.getPort() != origRequestURI.getPort() || !DataHelper.eq(refererURI.getScheme(), origRequestURI.getScheme())) {
line = null;
// completely strip the line if everything doesn't match
continue;
}
// Strip to a relative URI, to hide the original host name
StringBuilder buf = new StringBuilder();
buf.append("Referer: ");
String refererPath = refererURI.getRawPath();
buf.append(refererPath != null ? refererPath : "/");
String refererQuery = refererURI.getRawQuery();
if (refererQuery != null)
buf.append('?').append(refererQuery);
line = buf.toString();
}
// else relative URI, leave in
} catch (URISyntaxException use) {
line = null;
// completely strip the line
continue;
}
}
// else allow
} else if (lowercaseLine.startsWith("via: ") && !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_VIA))) {
// line = "Via: i2p";
line = null;
// completely strip the line
continue;
} else if (lowercaseLine.startsWith("from: ")) {
// line = "From: i2p";
line = null;
// completely strip the line
continue;
} else if (lowercaseLine.startsWith("authorization: ntlm ")) {
// Block Windows NTLM after 401
line = null;
continue;
} else if (lowercaseLine.startsWith("proxy-authorization: ")) {
// This should be for us. It is a
// hop-by-hop header, and we definitely want to block Windows NTLM after a far-end 407.
// Response to far-end shouldn't happen, as we
// strip Proxy-Authenticate from the response in HTTPResponseOutputStream
// "proxy-authorization: ".length()
authorization = line.substring(21);
line = null;
continue;
} else if (lowercaseLine.startsWith("icy")) {
// icecast/shoutcast, We need to leave the user-agent alone.
shout = true;
}
}
if (line.length() == 0) {
// No more headers, add our own and break out of the loop
String ok = getTunnel().getClientOptions().getProperty("i2ptunnel.gzip");
boolean gzip = DEFAULT_GZIP;
if (ok != null) {
gzip = Boolean.parseBoolean(ok);
}
if (gzip && !usingInternalServer && !method.toUpperCase(Locale.US).equals("CONNECT")) {
// newRequest.append("Accept-Encoding: \r\n");
if (!usingInternalOutproxy)
newRequest.append("X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n");
}
if (!shout && !method.toUpperCase(Locale.US).equals("CONNECT")) {
if (!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT))) {
// let's not advertise to external sites that we are from I2P
if (usingWWWProxy || usingInternalOutproxy) {
newRequest.append(UA_CLEARNET);
} else {
newRequest.append(UA_I2P);
}
}
}
// 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((user + ':' + pw).getBytes("UTF-8"), true)).append("\r\n");
}
}
newRequest.append("Connection: close\r\n\r\n");
s.setSoTimeout(0);
break;
} else {
// HTTP spec
newRequest.append(line).append("\r\n");
}
}
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(getPrefix(requestId) + "NewRequest header: [" + newRequest.toString() + "]");
}
if (method == null || (destination == null && !usingInternalOutproxy)) {
// l.log("No HTTP method found in the request.");
try {
if (protocol != null && "http".equals(protocol.toLowerCase(Locale.US))) {
out.write(getErrorPage("denied", ERR_REQUEST_DENIED).getBytes("UTF-8"));
} else {
out.write(getErrorPage("protocol", ERR_BAD_PROTOCOL).getBytes("UTF-8"));
}
writeFooter(out);
} catch (IOException ioe) {
// ignore
}
return;
}
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(getPrefix(requestId) + "Destination: " + destination);
}
// 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");
}
}
try {
out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes("UTF-8"));
writeFooter(out);
} catch (IOException ioe) {
// ignore
}
return;
}
// Ignore all the headers
if (usingInternalServer) {
try {
// disable the add form if address helper is disabled
if (internalPath.equals("/add") && Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
out.write(ERR_HELPER_DISABLED.getBytes("UTF-8"));
} else {
LocalHTTPServer.serveLocalFile(out, method, internalPath, internalRawQuery, _proxyNonce);
}
} catch (IOException ioe) {
// ignore
}
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[] data;
byte[] response;
if (method.toUpperCase(Locale.US).equals("CONNECT")) {
data = null;
response = SUCCESS_RESPONSE.getBytes("UTF-8");
} else {
data = newRequest.toString().getBytes("ISO-8859-1");
response = null;
}
Thread t = new I2PTunnelOutproxyRunner(s, outSocket, sockLock, data, response, onTimeout);
// we are called from an unlimited thread pool, so run inline
// t.start();
t.run();
return;
}
// LOOKUP
// If the host is "i2p", the getHostName() lookup failed, don't try to
// look it up again as the naming service does not do negative caching
// so it will be slow.
Destination clientDest = null;
String addressHelper = addressHelpers.get(destination.toLowerCase(Locale.US));
if (addressHelper != null) {
clientDest = _context.namingService().lookup(addressHelper);
if (clientDest == null) {
// remove bad entries
addressHelpers.remove(destination.toLowerCase(Locale.US));
if (_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Could not find destination for " + addressHelper);
}
String header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
try {
writeErrorMessage(header, out, targetRequest, false, destination);
} catch (IOException ioe) {
// ignore
}
return;
}
} else if ("i2p".equals(host)) {
clientDest = null;
} else if (destination.length() == 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
// use existing session to look up for efficiency
verifySocketManager();
I2PSession sess = sockMgr.getSession();
if (!sess.isClosed()) {
byte[] hData = Base32.decode(destination.substring(0, 52));
if (hData != null) {
if (_log.shouldLog(Log.INFO)) {
_log.info("lookup in-session " + destination);
}
Hash hash = Hash.create(hData);
clientDest = sess.lookupDest(hash, 20 * 1000);
}
} else {
clientDest = _context.namingService().lookup(destination);
}
} else {
clientDest = _context.namingService().lookup(destination);
}
if (clientDest == null) {
// l.log("Could not resolve " + destination + ".");
if (_log.shouldLog(Log.WARN)) {
_log.warn("Unable to resolve " + destination + " (proxy? " + usingWWWProxy + ", request: " + targetRequest);
}
String header;
String jumpServers = null;
String extraMessage = null;
if (usingWWWProxy) {
header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN);
} else if (ahelperPresent) {
header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
} else if (destination.length() == 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
header = getErrorPage("nols", ERR_DESTINATION_UNKNOWN);
extraMessage = _t("Destination lease set not found");
} else {
header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN);
jumpServers = getTunnel().getClientOptions().getProperty(PROP_JUMP_SERVERS);
if (jumpServers == null) {
jumpServers = DEFAULT_JUMP_SERVERS;
}
int jumpDelay = 400 + _context.random().nextInt(256);
try {
Thread.sleep(jumpDelay);
} catch (InterruptedException ie) {
}
}
try {
writeErrorMessage(header, extraMessage, out, targetRequest, usingWWWProxy, destination, jumpServers);
} catch (IOException ioe) {
// ignore
}
return;
}
if (method.toUpperCase(Locale.US).equals("CONNECT") && !usingWWWProxy && !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_INTERNAL_SSL))) {
try {
writeErrorMessage(ERR_INTERNAL_SSL, out, targetRequest, false, destination);
} catch (IOException ioe) {
// ignore
}
if (_log.shouldLog(Log.WARN))
_log.warn("SSL to i2p destinations denied by configuration: " + targetRequest);
return;
}
// Don't do this for eepget, which uses a user-agent of "Wget"
if (ahelperNew && "GET".equals(method) && (userAgent == null || !userAgent.startsWith("Wget")) && !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
try {
writeHelperSaveForm(out, destination, ahelperKey, targetRequest, referer);
} catch (IOException ioe) {
// ignore
}
return;
}
// Syndie can't handle a redirect of a POST
if (ahelperPresent && !"POST".equals(method)) {
String uri = targetRequest;
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Auto redirecting to " + uri);
}
try {
out.write(("HTTP/1.1 301 Address Helper Accepted\r\n" + "Location: " + uri + "\r\n" + "Connection: close\r\n" + "Proxy-Connection: close\r\n" + "\r\n").getBytes("UTF-8"));
} catch (IOException ioe) {
// ignore
}
return;
}
Properties opts = new Properties();
// opts.setProperty("i2p.streaming.inactivityTimeout", ""+120*1000);
// 1 == disconnect. see ConnectionOptions in the new streaming lib, which i
// dont want to hard link to here
// opts.setProperty("i2p.streaming.inactivityTimeoutAction", ""+1);
I2PSocketOptions sktOpts = getDefaultOptions(opts);
if (remotePort > 0)
sktOpts.setPort(remotePort);
i2ps = createI2PSocket(clientDest, sktOpts);
OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
Thread t;
if (method.toUpperCase(Locale.US).equals("CONNECT")) {
byte[] data;
byte[] response;
if (usingWWWProxy) {
data = newRequest.toString().getBytes("ISO-8859-1");
response = null;
} else {
data = null;
response = SUCCESS_RESPONSE.getBytes("UTF-8");
}
t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
} else {
byte[] data = newRequest.toString().getBytes("ISO-8859-1");
t = new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
}
// 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(getPrefix(requestId) + "Error trying to connect", ex);
}
handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
} catch (I2PException ex) {
if (_log.shouldLog(Log.INFO)) {
_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.error("getPrefix(requestId) + Error trying to connect", oom);
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) {
}
}
}
use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class I2PTunnelHTTPServer method blockingHandle.
/**
* Called by the thread pool of I2PSocket handlers
*/
@Override
protected void blockingHandle(I2PSocket socket) {
Hash peerHash = socket.getPeerDestination().calculateHash();
String peerB32 = socket.getPeerDestination().toBase32();
if (_log.shouldLog(Log.INFO))
_log.info("Incoming connection to '" + toString() + "' port " + socket.getLocalPort() + " from: " + peerB32 + " port " + socket.getPort());
// threads.
try {
if (socket.getLocalPort() == 443) {
if (getTunnel().getClientOptions().getProperty("targetForPort.443") == null) {
try {
socket.getOutputStream().write(ERR_SSL.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
return;
}
Socket s = getSocket(socket.getPeerDestination().calculateHash(), 443);
Runnable t = new I2PTunnelRunner(s, socket, slock, null, null, null, (I2PTunnelRunner.FailCallback) null);
_clientExecutor.execute(t);
return;
}
long afterAccept = getTunnel().getContext().clock().now();
// The headers _should_ be in the first packet, but
// may not be, depending on the client-side options
StringBuilder command = new StringBuilder(128);
Map<String, List<String>> headers;
try {
// catch specific exceptions thrown, to return a good
// error to the client
headers = readHeaders(socket, null, command, CLIENT_SKIPHEADERS, getTunnel().getContext());
} catch (SocketTimeoutException ste) {
try {
socket.getOutputStream().write(ERR_REQUEST_TIMEOUT.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error in the HTTP request from " + peerB32, ste);
return;
} catch (EOFException eofe) {
try {
socket.getOutputStream().write(ERR_BAD_REQUEST.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error in the HTTP request from " + peerB32, eofe);
return;
} catch (LineTooLongException ltle) {
try {
socket.getOutputStream().write(ERR_HEADERS_TOO_LARGE.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error in the HTTP request from " + peerB32, ltle);
return;
} catch (RequestTooLongException rtle) {
try {
socket.getOutputStream().write(ERR_REQUEST_URI_TOO_LONG.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error in the HTTP request from " + peerB32, rtle);
return;
} catch (BadRequestException bre) {
try {
socket.getOutputStream().write(ERR_BAD_REQUEST.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error in the HTTP request from " + peerB32, bre);
return;
}
long afterHeaders = getTunnel().getContext().clock().now();
Properties opts = getTunnel().getClientOptions();
if (Boolean.parseBoolean(opts.getProperty(OPT_REJECT_INPROXY)) && (headers.containsKey("X-Forwarded-For") || headers.containsKey("X-Forwarded-Server") || // RFC 7239
headers.containsKey("Forwarded") || headers.containsKey("X-Forwarded-Host"))) {
if (_log.shouldLog(Log.WARN)) {
StringBuilder buf = new StringBuilder();
buf.append("Refusing inproxy access: ").append(peerB32);
List<String> h = headers.get("X-Forwarded-For");
if (h != null)
buf.append(" from: ").append(h.get(0));
h = headers.get("X-Forwarded-Server");
if (h != null)
buf.append(" via: ").append(h.get(0));
h = headers.get("X-Forwarded-Host");
if (h != null)
buf.append(" for: ").append(h.get(0));
h = headers.get("Forwarded");
if (h != null)
buf.append(h.get(0));
_log.warn(buf.toString());
}
try {
// Send a 403, so the user doesn't get an HTTP Proxy error message
// and blame his router or the network.
socket.getOutputStream().write(ERR_INPROXY.getBytes("UTF-8"));
} catch (IOException ioe) {
}
try {
socket.close();
} catch (IOException ioe) {
}
return;
}
if (Boolean.parseBoolean(opts.getProperty(OPT_REJECT_REFERER))) {
// reject absolute URIs only
List<String> h = headers.get("Referer");
if (h != null) {
String referer = h.get(0);
if (referer.length() > 9) {
// "Referer: "
referer = referer.substring(9);
if (referer.startsWith("http://") || referer.startsWith("https://")) {
if (_log.shouldLog(Log.WARN))
_log.warn("Refusing access from: " + peerB32 + " with Referer: " + referer);
try {
socket.getOutputStream().write(ERR_INPROXY.getBytes("UTF-8"));
} catch (IOException ioe) {
}
try {
socket.close();
} catch (IOException ioe) {
}
return;
}
}
}
}
if (Boolean.parseBoolean(opts.getProperty(OPT_REJECT_USER_AGENTS))) {
if (headers.containsKey("User-Agent")) {
String ua = headers.get("User-Agent").get(0);
if (!ua.startsWith("MYOB")) {
String blockAgents = opts.getProperty(OPT_USER_AGENTS);
if (blockAgents != null) {
String[] agents = DataHelper.split(blockAgents, ",");
for (int i = 0; i < agents.length; i++) {
String ag = agents[i].trim();
if (ag.equals("none"))
continue;
if (ag.length() > 0 && ua.contains(ag)) {
if (_log.shouldLog(Log.WARN))
_log.warn("Refusing access from: " + peerB32 + " with User-Agent: " + ua);
try {
socket.getOutputStream().write(ERR_INPROXY.getBytes("UTF-8"));
} catch (IOException ioe) {
}
try {
socket.close();
} catch (IOException ioe) {
}
return;
}
}
}
}
} else {
// no user-agent, block if blocklist contains "none"
String blockAgents = opts.getProperty(OPT_USER_AGENTS);
if (blockAgents != null) {
String[] agents = DataHelper.split(blockAgents, ",");
for (int i = 0; i < agents.length; i++) {
String ag = agents[i].trim();
if (ag.equals("none")) {
if (_log.shouldLog(Log.WARN))
_log.warn("Refusing access from: " + peerB32 + " with empty User-Agent");
try {
socket.getOutputStream().write(ERR_INPROXY.getBytes("UTF-8"));
} catch (IOException ioe) {
}
try {
socket.close();
} catch (IOException ioe) {
}
return;
}
}
}
}
}
if (_postThrottler != null && command.length() >= 5 && command.substring(0, 5).toUpperCase(Locale.US).equals("POST ")) {
if (_postThrottler.shouldThrottle(peerHash)) {
if (_log.shouldLog(Log.WARN))
_log.warn("Refusing POST since peer is throttled: " + peerB32);
try {
// Send a 429, so the user doesn't get an HTTP Proxy error message
// and blame his router or the network.
socket.getOutputStream().write(ERR_DENIED.getBytes("UTF-8"));
} catch (IOException ioe) {
}
try {
socket.close();
} catch (IOException ioe) {
}
return;
}
}
addEntry(headers, HASH_HEADER, peerHash.toBase64());
addEntry(headers, DEST32_HEADER, peerB32);
addEntry(headers, DEST64_HEADER, socket.getPeerDestination().toBase64());
// Port-specific spoofhost
String spoofHost;
int ourPort = socket.getLocalPort();
if (ourPort != 80 && ourPort > 0 && ourPort <= 65535) {
String portSpoof = opts.getProperty("spoofedHost." + ourPort);
if (portSpoof != null)
spoofHost = portSpoof.trim();
else
spoofHost = _spoofHost;
} else {
spoofHost = _spoofHost;
}
if (spoofHost != null)
setEntry(headers, "Host", spoofHost);
setEntry(headers, "Connection", "close");
// we keep the enc sent by the browser before clobbering it, since it may have
// been x-i2p-gzip
String enc = getEntryOrNull(headers, "Accept-Encoding");
String altEnc = getEntryOrNull(headers, "X-Accept-Encoding");
// according to rfc2616 s14.3, this *should* force identity, even if
// "identity;q=1, *;q=0" didn't.
// as of 0.9.23, the client passes this header through, and we do the same,
// so if the server and browser can do the compression/decompression, we don't have to
// setEntry(headers, "Accept-Encoding", "");
socket.setReadTimeout(readTimeout);
Socket s = getSocket(socket.getPeerDestination().calculateHash(), socket.getLocalPort());
long afterSocket = getTunnel().getContext().clock().now();
// instead of i2ptunnelrunner, use something that reads the HTTP
// request from the socket, modifies the headers, sends the request to the
// server, reads the response headers, rewriting to include Content-Encoding: x-i2p-gzip
// if it was one of the Accept-Encoding: values, and gzip the payload
boolean allowGZIP = true;
String val = opts.getProperty("i2ptunnel.gzip");
if ((val != null) && (!Boolean.parseBoolean(val)))
allowGZIP = false;
if (_log.shouldLog(Log.INFO))
_log.info("HTTP server encoding header: " + enc + "/" + altEnc);
boolean alt = (altEnc != null) && (altEnc.indexOf("x-i2p-gzip") >= 0);
boolean useGZIP = alt || ((enc != null) && (enc.indexOf("x-i2p-gzip") >= 0));
// Don't pass this on, outproxies should strip so I2P traffic isn't so obvious but they probably don't
if (alt)
headers.remove("X-Accept-Encoding");
String modifiedHeader = formatHeaders(headers, command);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Modified header: [" + modifiedHeader + "]");
Runnable t;
if (allowGZIP && useGZIP) {
t = new CompressedRequestor(s, socket, modifiedHeader, getTunnel().getContext(), _log);
} else {
t = new I2PTunnelRunner(s, socket, slock, null, DataHelper.getUTF8(modifiedHeader), null, (I2PTunnelRunner.FailCallback) null);
}
// run in the unlimited client pool
// t.start();
_clientExecutor.execute(t);
long afterHandle = getTunnel().getContext().clock().now();
long timeToHandle = afterHandle - afterAccept;
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle);
if ((timeToHandle > 1000) && (_log.shouldLog(Log.WARN)))
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort + " from: " + peerB32 + " [" + timeToHandle + ", read headers: " + (afterHeaders - afterAccept) + ", socket create: " + (afterSocket - afterHeaders) + ", start runners: " + (afterHandle - afterSocket) + "]");
} catch (SocketException ex) {
try {
// Send a 503, so the user doesn't get an HTTP Proxy error message
// and blame his router or the network.
socket.getOutputStream().write(ERR_UNAVAILABLE.getBytes("UTF-8"));
} catch (IOException ioe) {
}
try {
socket.close();
} catch (IOException ioe) {
}
// Don't complain too early, Jetty may not be ready.
int level = getTunnel().getContext().clock().now() - _startedOn > START_INTERVAL ? Log.ERROR : Log.WARN;
if (_log.shouldLog(level))
_log.log(level, "Error connecting to HTTP server " + remoteHost + ':' + remotePort, ex);
} catch (IOException ex) {
try {
socket.close();
} catch (IOException ioe) {
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error in the HTTP request from: " + peerB32, ex);
} catch (OutOfMemoryError oom) {
// java.lang.OutOfMemoryError: unable to create new native thread
try {
// Send a 503, so the user doesn't get an HTTP Proxy error message
// and blame his router or the network.
socket.getOutputStream().write(ERR_UNAVAILABLE.getBytes("UTF-8"));
} catch (IOException ioe) {
}
try {
socket.close();
} catch (IOException ioe) {
}
if (_log.shouldLog(Log.ERROR))
_log.error("OOM in HTTP server", oom);
}
}
use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class I2PTunnelIRCClient method clientConnectionRun.
protected void clientConnectionRun(Socket s) {
if (_log.shouldLog(Log.INFO))
_log.info("New connection local addr is: " + s.getLocalAddress() + " from: " + s.getInetAddress());
I2PSocket i2ps = null;
I2PSocketAddress addr = pickDestination();
try {
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);
StringBuffer expectedPong = new StringBuffer();
DCCHelper dcc = _dccEnabled ? new DCC(s.getLocalAddress().getAddress()) : null;
Thread in = new I2PAppThread(new IrcInboundFilter(s, i2ps, expectedPong, _log, dcc), "IRC Client " + _clientId + " in", true);
in.start();
// Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong, _log, dcc), "IRC Client " + _clientId + " out", true);
Runnable out = new IrcOutboundFilter(s, i2ps, expectedPong, _log, dcc);
// we are called from an unlimited thread pool, so run inline
// out.start();
out.run();
} catch (IOException ex) {
// generally NoRouteToHostException
if (_log.shouldLog(Log.WARN))
_log.warn("Error connecting", ex);
// 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) {
}
} catch (I2PException ex) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error connecting", ex);
// 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) {
}
} 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 I2PTunnelIRCServer method blockingHandle.
@Override
protected void blockingHandle(I2PSocket socket) {
if (_log.shouldLog(Log.INFO))
_log.info("Incoming connection to '" + toString() + "' port " + socket.getLocalPort() + " from: " + socket.getPeerDestination().calculateHash() + " port " + socket.getPort());
try {
String modifiedRegistration;
if (!this.method.equals("webirc")) {
// The headers _should_ be in the first packet, but
// may not be, depending on the client-side options
modifiedRegistration = filterRegistration(socket, cloakDest(socket.getPeerDestination()));
socket.setReadTimeout(readTimeout);
} else {
StringBuffer buf = new StringBuffer("WEBIRC ");
buf.append(this.webircPassword);
buf.append(" cgiirc ");
buf.append(cloakDest(socket.getPeerDestination()));
buf.append(' ');
buf.append(this.webircSpoofIP);
buf.append("\r\n");
modifiedRegistration = buf.toString();
}
Socket s = getSocket(socket.getPeerDestination().calculateHash(), socket.getLocalPort());
Thread t = new I2PTunnelRunner(s, socket, slock, null, DataHelper.getUTF8(modifiedRegistration), null, (I2PTunnelRunner.FailCallback) null);
// run in the unlimited client pool
// t.start();
_clientExecutor.execute(t);
} catch (RegistrationException ex) {
try {
// Send a response so the user doesn't just see a disconnect
// and blame his router or the network.
socket.getOutputStream().write(ERR_REGISTRATION.getBytes("ISO-8859-1"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new IRC Connection", ex);
} catch (EOFException ex) {
try {
// Send a response so the user doesn't just see a disconnect
// and blame his router or the network.
socket.getOutputStream().write(ERR_EOF.getBytes("ISO-8859-1"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new IRC Connection", ex);
} catch (SocketTimeoutException ex) {
try {
// Send a response so the user doesn't just see a disconnect
// and blame his router or the network.
socket.getOutputStream().write(ERR_TIMEOUT.getBytes("ISO-8859-1"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new IRC Connection", ex);
} catch (SocketException ex) {
try {
// Send a response so the user doesn't just see a disconnect
// and blame his router or the network.
socket.getOutputStream().write(ERR_UNAVAILABLE.getBytes("ISO-8859-1"));
} catch (IOException ioe) {
}
try {
socket.close();
} catch (IOException ioe) {
}
if (_log.shouldLog(Log.ERROR))
_log.error("Error connecting to IRC server " + remoteHost + ':' + remotePort, ex);
} catch (IOException ex) {
try {
socket.reset();
} catch (IOException ioe) {
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new IRC Connection", ex);
} catch (OutOfMemoryError oom) {
try {
socket.reset();
} catch (IOException ioe) {
}
if (_log.shouldLog(Log.ERROR))
_log.error("OOM in IRC server", oom);
}
}
use of net.i2p.client.streaming.I2PSocket in project i2p.i2p by i2p.
the class I2PTunnelServer method close.
/**
* Note that the tunnel can be reopened after this by calling startRunning().
* This does 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().
*/
public synchronized boolean close(boolean forced) {
if (!open)
return true;
if (task != null) {
task.close(forced);
}
synchronized (lock) {
if (!forced && sockMgr.listSockets().size() != 0) {
l.log("There are still active connections!");
for (I2PSocket skt : sockMgr.listSockets()) {
l.log("->" + skt);
}
return false;
}
l.log("Stopping tunnels for server at " + this.remoteHost + ':' + this.remotePort);
open = false;
try {
if (i2pss != null) {
i2pss.close();
i2pss = null;
}
I2PSession session = sockMgr.getSession();
getTunnel().removeSession(session);
session.destroySession();
} catch (I2PException ex) {
_log.error("Error destroying the session", ex);
// System.exit(1);
}
// l.log("Server shut down.");
if (_usePool && _executor != null) {
_executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
_executor.shutdownNow();
}
return true;
}
}
Aggregations