Changeset d1bd893


Ignore:
Timestamp:
May 18, 2014 9:13:22 PM (7 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
4167cd95
Parents:
2467856
Message:
  • I2PTunnel:
    • Display custom error pages for I2PSocketExceptions (ticket #788)
    • Tag I2PSocketException text for translation (no bundles yet)
    • Move methods from superclasses to I2PTunnelHTTPClientBase
    • Fix connect client error pages, but they aren't displayed anyway
    • Don't start I2PTunnelRunner threads in constructor (ticket #973)
    • Synch close() in I2PTunnelServer
    • Cleanups and javadocs
Files:
2 added
14 edited

Legend:

Unmodified
Added
Removed
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java

    r2467856 rd1bd893  
    123123            i2ps = createI2PSocket(clientDest, port);
    124124            i2ps.setReadTimeout(readTimeout);
    125             new I2PTunnelRunner(s, i2ps, sockLock, null, mySockets);
     125            Thread t = new I2PTunnelRunner(s, i2ps, sockLock, null, null, mySockets,
     126                                (I2PTunnelRunner.FailCallback) null);
     127            t.start();
    126128        } catch (Exception ex) {
    127129            if (_log.shouldLog(Log.INFO))
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java

    r2467856 rd1bd893  
    6060    public static final String AUTH_REALM = "I2P SSL Proxy";
    6161
    62     private final static byte[] ERR_DESTINATION_UNKNOWN =
    63         ("HTTP/1.1 503 Service Unavailable\r\n"+
    64          "Content-Type: text/html; charset=iso-8859-1\r\n"+
    65          "Cache-control: no-cache\r\n"+
    66          "\r\n"+
    67          "<html><body><H1>I2P ERROR: DESTINATION NOT FOUND</H1>"+
    68          "That I2P Destination was not found. "+
    69          "The host (or the outproxy, if you're using one) could also "+
    70          "be temporarily offline.  You may want to <b>retry</b>.  "+
    71          "Could not find the following Destination:<BR><BR><div>")
    72         .getBytes();
    73    
    7462    private final static byte[] ERR_BAD_PROTOCOL =
    7563        ("HTTP/1.1 405 Bad Method\r\n"+
     
    294282                byte[] header;
    295283                if (usingWWWProxy)
    296                     header = getErrorPage("dnfp-header.ht", ERR_DESTINATION_UNKNOWN);
     284                    header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN);
    297285                else
    298                     header = getErrorPage("dnfh-header.ht", ERR_DESTINATION_UNKNOWN);
     286                    header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN);
    299287                writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination);
    300288                s.close();
     
    309297            else
    310298                response = SUCCESS_RESPONSE;
    311             Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
    312             // starts itself
    313             new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
    314         } catch (SocketException ex) {
    315             _log.info(getPrefix(requestId) + "Error trying to connect", ex);
    316             handleConnectClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
    317             closeSocket(s);
     299            OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
     300            Thread t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
     301            t.start();
    318302        } catch (IOException ex) {
    319303            _log.info(getPrefix(requestId) + "Error trying to connect", ex);
    320             handleConnectClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
     304            handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
    321305            closeSocket(s);
    322306        } catch (I2PException ex) {
    323307            _log.info("getPrefix(requestId) + Error trying to connect", ex);
    324             handleConnectClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
     308            handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
    325309            closeSocket(s);
    326310        } catch (OutOfMemoryError oom) {
    327311            IOException ex = new IOException("OOM");
    328312            _log.info("getPrefix(requestId) + Error trying to connect", ex);
    329             handleConnectClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
     313            handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
    330314            closeSocket(s);
    331315        }
    332316    }
    333317
    334     private static class OnTimeout implements Runnable {
    335         private final Socket _socket;
    336         private final OutputStream _out;
    337         private final String _target;
    338         private final boolean _usingProxy;
    339         private final String _wwwProxy;
    340         private final long _requestId;
    341 
    342         public OnTimeout(Socket s, OutputStream out, String target, boolean usingProxy, String wwwProxy, long id) {
    343             _socket = s;
    344             _out = out;
    345             _target = target;
    346             _usingProxy = usingProxy;
    347             _wwwProxy = wwwProxy;
    348             _requestId = id;
    349         }
    350 
    351         public void run() {
    352             //if (_log.shouldLog(Log.DEBUG))
    353             //    _log.debug("Timeout occured requesting " + _target);
    354             handleConnectClientException(new RuntimeException("Timeout"), _out,
    355                                       _target, _usingProxy, _wwwProxy, _requestId);
    356             closeSocket(_socket);
    357         }
    358     }
    359    
    360318    private static void writeErrorMessage(byte[] errMessage, OutputStream out) throws IOException {
    361319        if (out == null)
    362320            return;
    363321        out.write(errMessage);
    364         out.write("\n</body></html>\n".getBytes());
    365         out.flush();
    366     }
    367 
    368     private static void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
    369                                           boolean usingWWWProxy, String wwwProxy) throws IOException {
    370         if (out != null) {
    371             out.write(errMessage);
    372             if (targetRequest != null) {
    373                 out.write(targetRequest.getBytes());
    374                 if (usingWWWProxy)
    375                     out.write(("<br />WWW proxy: " + wwwProxy).getBytes());
    376             }
    377             out.write("</div>".getBytes());
    378             out.write("\n</body></html>\n".getBytes());
    379             out.flush();
    380         }
    381     }
    382 
    383     private static void handleConnectClientException(Exception ex, OutputStream out, String targetRequest,
    384                                                   boolean usingWWWProxy, String wwwProxy, long requestId) {
    385         if (out == null)
    386             return;
    387         byte[] header;
    388         if (usingWWWProxy)
    389             header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp-header.ht", ERR_DESTINATION_UNKNOWN);
    390         else
    391             header = getErrorPage(I2PAppContext.getGlobalContext(), "dnf-header.ht", ERR_DESTINATION_UNKNOWN);
    392         try {
    393             writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy);
    394         } catch (IOException ioe) {}
     322        writeFooter(out);
    395323    }
    396324}
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java

    r2467856 rd1bd893  
    1111import java.net.URI;
    1212import java.net.URISyntaxException;
    13 import java.util.Date;
    1413import java.util.Locale;
    1514import java.util.Properties;
     
    3635import net.i2p.util.Log;
    3736import net.i2p.util.PortMapper;
    38 import net.i2p.util.Translate;
    3937
    4038/**
     
    9492            "<html><body><H1>I2P ERROR: REQUEST DENIED</H1>" +
    9593            "You attempted to connect to a non-I2P website or location.<BR>").getBytes();
    96     private final static byte[] ERR_DESTINATION_UNKNOWN =
    97                                 ("HTTP/1.1 503 Service Unavailable\r\n" +
    98             "Content-Type: text/html; charset=iso-8859-1\r\n" +
    99             "Cache-control: no-cache\r\n" +
    100             "\r\n" +
    101             "<html><body><H1>I2P ERROR: DESTINATION NOT FOUND</H1>" +
    102             "That I2P Destination was not found. Perhaps you pasted in the " +
    103             "wrong BASE64 I2P Destination or the link you are following is " +
    104             "bad. The host (or the WWW proxy, if you're using one) could also " +
    105             "be temporarily offline.  You may want to <b>retry</b>.  " +
    106             "Could not find the following Destination:<BR><BR><div>").getBytes();
     94
    10795    /*****
    10896    private final static byte[] ERR_TIMEOUT =
     
    643631                                        // bad ahelperKey
    644632                                        byte[] header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
    645                                         writeErrorMessage(header, out, targetRequest, false, destination, null);
     633                                        writeErrorMessage(header, out, targetRequest, false, destination);
    646634                                    } else {
    647635                                        String trustedURL = requestURI.toASCIIString();
     
    952940            if (usingInternalOutproxy) {
    953941                Socket outSocket = outproxy.connect(host, remotePort);
    954                 Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
     942                OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
    955943                byte[] data;
    956944                byte[] response;
     
    962950                    response = null;
    963951                }
    964                 new I2PTunnelOutproxyRunner(s, outSocket, sockLock, data, response, onTimeout);
     952                Thread t = new I2PTunnelOutproxyRunner(s, outSocket, sockLock, data, response, onTimeout);
     953                t.start();
    965954                return;
    966955            }
     
    981970                    }
    982971                    byte[] header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
    983                     writeErrorMessage(header, out, targetRequest, false, destination, null);
     972                    writeErrorMessage(header, out, targetRequest, false, destination);
    984973                    s.close();
    985974                    return;
     
    10191008                    header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
    10201009                } else if(destination.length() == 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
    1021                     header = getErrorPage("dnf", ERR_DESTINATION_UNKNOWN);
     1010                    header = getErrorPage("nols", ERR_DESTINATION_UNKNOWN);
    10221011                } else {
    10231012                    header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN);
     
    10681057                sktOpts.setPort(remotePort);
    10691058            I2PSocket i2ps = createI2PSocket(clientDest, sktOpts);
    1070             Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
     1059            OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
    10711060            if (method.toUpperCase(Locale.US).equals("CONNECT")) {
    10721061                byte[] data;
     
    10791068                    response = I2PTunnelConnectClient.SUCCESS_RESPONSE;
    10801069                }
    1081                 new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
     1070                Thread t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
     1071                t.start();
    10821072            } else {
    10831073                byte[] data = newRequest.toString().getBytes("ISO-8859-1");
    1084                 new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
     1074                Thread t = new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
     1075                t.start();
    10851076            }
    10861077        } catch(IOException ex) {
     
    10891080            }
    10901081            //l.log("Error connecting: " + ex.getMessage());
    1091             handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
     1082            handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
    10921083            closeSocket(s);
    10931084        } catch(I2PException ex) {
     
    10961087            }
    10971088            //l.log("Error connecting: " + ex.getMessage());
    1098             handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
     1089            handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
    10991090            closeSocket(s);
    11001091        } catch(OutOfMemoryError oom) {
     
    11021093            _log.error("getPrefix(requestId) + Error trying to connect", oom);
    11031094            //l.log("Error connecting: " + ex.getMessage());
    1104             handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
     1095            handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
    11051096            closeSocket(s);
    11061097        }
     
    12301221    }
    12311222
    1232     /**
    1233      *  Public only for LocalHTTPServer, not for general use
    1234      */
    1235     public static void writeFooter(OutputStream out) throws IOException {
    1236         // the css is hiding this div for now, but we'll keep it here anyway
    1237         out.write("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
    1238         out.write(new Date().toString().getBytes());
    1239         out.write("</i></div></body></html>\n".getBytes());
    1240         out.flush();
    1241     }
    1242 
    1243     private static class OnTimeout implements Runnable {
    1244 
    1245         private final Socket _socket;
    1246         private final OutputStream _out;
    1247         private final String _target;
    1248         private final boolean _usingProxy;
    1249         private final String _wwwProxy;
    1250         private final long _requestId;
    1251 
    1252         public OnTimeout(Socket s, OutputStream out, String target, boolean usingProxy, String wwwProxy, long id) {
    1253             _socket = s;
    1254             _out = out;
    1255             _target = target;
    1256             _usingProxy = usingProxy;
    1257             _wwwProxy = wwwProxy;
    1258             _requestId = id;
    1259         }
    1260 
    1261         public void run() {
    1262             //if (_log.shouldLog(Log.DEBUG))
    1263             //    _log.debug("Timeout occured requesting " + _target);
    1264             handleHTTPClientException(new RuntimeException("Timeout"), _out,
    1265                     _target, _usingProxy, _wwwProxy, _requestId);
    1266             closeSocket(_socket);
    1267         }
    1268     }
    12691223    public static final String DEFAULT_JUMP_SERVERS =
    12701224                               "http://i2host.i2p/cgi-bin/i2hostjump?," +
     
    12731227            "http://i2pjump.i2p/jump/";
    12741228            //"http://i2jump.i2p/";
    1275 
    1276     /**
    1277      *  @param jumpServers comma- or space-separated list, or null
    1278      */
    1279     private static void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
    1280                                           boolean usingWWWProxy, String wwwProxy, String jumpServers) throws IOException {
    1281         if(out != null) {
    1282             out.write(errMessage);
    1283             if(targetRequest != null) {
    1284                 String uri = targetRequest.replace("&", "&amp;");
    1285                 out.write("<a href=\"".getBytes());
    1286                 out.write(uri.getBytes());
    1287                 out.write("\">".getBytes());
    1288                 out.write(uri.getBytes());
    1289                 out.write("</a>".getBytes());
    1290                 if(usingWWWProxy) {
    1291                     out.write(("<br><br><b>").getBytes());
    1292                     out.write(_("HTTP Outproxy").getBytes("UTF-8"));
    1293                     out.write((":</b> " + wwwProxy).getBytes());
    1294                 }
    1295                 if(jumpServers != null && jumpServers.length() > 0) {
    1296                     boolean first = true;
    1297                     if(uri.startsWith("http://")) {
    1298                         uri = uri.substring(7);
    1299                     }
    1300                     StringTokenizer tok = new StringTokenizer(jumpServers, ", ");
    1301                     while(tok.hasMoreTokens()) {
    1302                         String jurl = tok.nextToken();
    1303                         String jumphost;
    1304                         try {
    1305                             URI jURI = new URI(jurl);
    1306                             String proto = jURI.getScheme();
    1307                             jumphost = jURI.getHost();
    1308                             if (proto == null || jumphost == null ||
    1309                                 !proto.toLowerCase(Locale.US).equals("http"))
    1310                                 continue;
    1311                             jumphost = jumphost.toLowerCase(Locale.US);
    1312                             if (!jumphost.endsWith(".i2p"))
    1313                                 continue;
    1314                         } catch(URISyntaxException use) {
    1315                             continue;
    1316                         }
    1317                         // Skip jump servers we don't know
    1318                         if(!jumphost.endsWith(".b32.i2p")) {
    1319                             Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(jumphost);
    1320                             if(dest == null) {
    1321                                 continue;
    1322                             }
    1323                         }
    1324 
    1325                         if (first) {
    1326                             first = false;
    1327                             out.write("<br><br>".getBytes());
    1328                             out.write(_("Click a link below to look for an address helper by using a \"jump\" service:").getBytes("UTF-8"));
    1329                             out.write("<br>\n".getBytes());
    1330                         }
    1331                         out.write("<br><a href=\"".getBytes());
    1332                         out.write(jurl.getBytes());
    1333                         out.write(uri.getBytes());
    1334                         out.write("\">".getBytes());
    1335                         // Translators: parameter is a host name
    1336                         out.write(_("{0} jump service", jumphost).getBytes());
    1337                         out.write("</a>\n".getBytes());
    1338                     }
    1339                 }
    1340             }
    1341             out.write("</div>".getBytes());
    1342             writeFooter(out);
    1343         }
    1344     }
    1345 
    1346     private static void handleHTTPClientException(Exception ex, OutputStream out, String targetRequest,
    1347                                                   boolean usingWWWProxy, String wwwProxy, long requestId) {
    1348 
    1349         // static
    1350         //if (_log.shouldLog(Log.WARN))
    1351         //    _log.warn(getPrefix(requestId) + "Error sending to " + wwwProxy + " (proxy? " + usingWWWProxy + ", request: " + targetRequest, ex);
    1352         if(out != null) {
    1353             try {
    1354                 byte[] header;
    1355                 if(usingWWWProxy) {
    1356                     header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp", ERR_DESTINATION_UNKNOWN);
    1357                 } else {
    1358                     header = getErrorPage(I2PAppContext.getGlobalContext(), "dnf", ERR_DESTINATION_UNKNOWN);
    1359                 }
    1360                 writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy, null);
    1361             } catch(IOException ioe) {
    1362                 // static
    1363                 //_log.warn(getPrefix(requestId) + "Error writing out the 'destination was unknown' " + "message", ioe);
    1364             }
    1365         } else {
    1366             // static
    1367             //_log.warn(getPrefix(requestId) + "Client disconnected before we could say that destination " + "was unknown", ex);
    1368         }
    1369     }
    13701229
    13711230    /** @param host ignored */
     
    15271386    }
    15281387     ****/
    1529 
    1530     /** these strings go in the jar, not the war */
    1531     private static final String BUNDLE_NAME = "net.i2p.i2ptunnel.proxy.messages";
    1532 
    1533     /** lang in routerconsole.lang property, else current locale */
    1534     protected static String _(String key) {
    1535         return Translate.getString(key, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
    1536     }
    1537 
    1538     /** {0} */
    1539     protected static String _(String key, Object o) {
    1540         return Translate.getString(key, o, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
    1541     }
    1542 
    1543     /** {0} and {1} */
    1544     protected static String _(String key, Object o, Object o2) {
    1545         return Translate.getString(key, o, o2, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
    1546     }
    15471388}
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java

    r2467856 rd1bd893  
    44package net.i2p.i2ptunnel;
    55
     6import java.io.File;
    67import java.io.FileInputStream;
    78import java.io.IOException;
     9import java.io.OutputStream;
    810import java.io.Reader;
    911import java.io.UnsupportedEncodingException;
    1012import java.net.Socket;
     13import java.net.URI;
     14import java.net.URISyntaxException;
    1115import java.util.ArrayList;
    12 import java.io.File;
    1316import java.util.BitSet;
     17import java.util.Date;
    1418import java.util.HashMap;
    1519import java.util.Iterator;
     
    2428
    2529import net.i2p.I2PAppContext;
     30import net.i2p.client.streaming.I2PSocketException;
    2631import net.i2p.client.streaming.I2PSocketManager;
    2732import net.i2p.data.Base64;
    2833import net.i2p.data.DataHelper;
     34import net.i2p.data.Destination;
     35import net.i2p.data.i2cp.MessageStatusMessage;
    2936import net.i2p.util.EepGet;
    3037import net.i2p.util.EventDispatcher;
     
    3239import net.i2p.util.Log;
    3340import net.i2p.util.PasswordManager;
     41import net.i2p.util.Translate;
    3442import net.i2p.util.TranslateReader;
    3543
     
    7482         .getBytes();
    7583   
     84    protected final static byte[] ERR_DESTINATION_UNKNOWN =
     85                                ("HTTP/1.1 503 Service Unavailable\r\n" +
     86            "Content-Type: text/html; charset=iso-8859-1\r\n" +
     87            "Cache-control: no-cache\r\n" +
     88            "\r\n" +
     89            "<html><body><H1>I2P ERROR: DESTINATION NOT FOUND</H1>" +
     90            "That I2P Destination was not found. Perhaps you pasted in the " +
     91            "wrong BASE64 I2P Destination or the link you are following is " +
     92            "bad. The host (or the WWW proxy, if you're using one) could also " +
     93            "be temporarily offline.  You may want to <b>retry</b>.  " +
     94            "Could not find the following Destination:<BR><BR><div>").getBytes();
     95
    7696    private final byte[] _proxyNonce;
    7797    private final ConcurrentHashMap<String, NonceInfo> _nonces;
    7898    private final AtomicInteger _nonceCleanCounter = new AtomicInteger();
    7999
    80     protected String getPrefix(long requestId) { return "Client[" + _clientId + "/" + requestId + "]: "; }
     100    protected String getPrefix(long requestId) {
     101        return "HTTPClient[" + _clientId + '/' + requestId + "]: ";
     102    }
    81103   
    82104    protected String selectProxy() {
     
    482504    }
    483505
     506    /** these strings go in the jar, not the war */
    484507    private static final String BUNDLE_NAME = "net.i2p.i2ptunnel.proxy.messages";
    485508
     
    506529        // we won't ever get here
    507530    }
     531
     532    /**
     533     *  @since 0.9.14 moved from superclasses
     534     */
     535    protected class OnTimeout implements I2PTunnelRunner.FailCallback {
     536        private final Socket _socket;
     537        private final OutputStream _out;
     538        private final String _target;
     539        private final boolean _usingProxy;
     540        private final String _wwwProxy;
     541        private final long _requestId;
     542
     543        public OnTimeout(Socket s, OutputStream out, String target, boolean usingProxy, String wwwProxy, long id) {
     544            _socket = s;
     545            _out = out;
     546            _target = target;
     547            _usingProxy = usingProxy;
     548            _wwwProxy = wwwProxy;
     549            _requestId = id;
     550        }
     551
     552        public void onFail(Exception ex) {
     553            Throwable cause = ex.getCause();
     554            if (cause != null && cause instanceof I2PSocketException) {
     555                I2PSocketException ise = (I2PSocketException) cause;
     556                handleI2PSocketException(ise, _out, _target, _usingProxy, _wwwProxy);
     557            } else {
     558                handleClientException(ex, _out, _target, _usingProxy, _wwwProxy, _requestId);
     559            }
     560            closeSocket(_socket);
     561        }
     562    }
     563
     564    /**
     565     *  @since 0.9.14 moved from superclasses
     566     */
     567    protected void handleClientException(Exception ex, OutputStream out, String targetRequest,
     568                                         boolean usingWWWProxy, String wwwProxy, long requestId) {
     569        if (out == null)
     570            return;
     571        byte[] header;
     572        if (usingWWWProxy)
     573            header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp", ERR_DESTINATION_UNKNOWN);
     574        else
     575            header = getErrorPage(I2PAppContext.getGlobalContext(), "dnf", ERR_DESTINATION_UNKNOWN);
     576        try {
     577            writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy);
     578        } catch (IOException ioe) {}
     579    }
     580
     581    /**
     582     *  Generate an error page based on the status code
     583     *  in our custom exception.
     584     *
     585     *  @since 0.9.14
     586     */
     587    protected void handleI2PSocketException(I2PSocketException ise, OutputStream out, String targetRequest,
     588                                            boolean usingWWWProxy, String wwwProxy) {
     589        if (out == null)
     590            return;
     591        int status = ise.getStatus();
     592        String error;
     593        //TODO MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION
     594        if (status == MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET) {
     595            error = usingWWWProxy ? "nolsp" : "nols";
     596        } else {
     597            error = usingWWWProxy ? "dnfp" : "dnf";
     598        }
     599        byte[] header = getErrorPage(error, ERR_DESTINATION_UNKNOWN);
     600        String message = ise.getLocalizedMessage();
     601        try {
     602            writeErrorMessage(header, message, out, targetRequest, usingWWWProxy, wwwProxy);
     603        } catch(IOException ioe) {}
     604    }
     605
     606    /**
     607     *  No jump servers or extra message
     608     *  @since 0.9.14
     609     */
     610    protected void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
     611                                     boolean usingWWWProxy, String wwwProxy) throws IOException {
     612        writeErrorMessage(errMessage, null, out, targetRequest, usingWWWProxy, wwwProxy, null);
     613    }
     614
     615    /**
     616     *  No extra message
     617     *  @param jumpServers comma- or space-separated list, or null
     618     *  @since 0.9.14 moved from superclasses
     619     */
     620    protected void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
     621                                     boolean usingWWWProxy, String wwwProxy, String jumpServers) throws IOException {
     622        writeErrorMessage(errMessage, null, out, targetRequest, usingWWWProxy, wwwProxy, jumpServers);
     623    }
     624
     625    /**
     626     *  No jump servers
     627     *  @param extraMessage extra message
     628     *  @since 0.9.14
     629     */
     630    protected void writeErrorMessage(byte[] errMessage, String extraMessage,
     631                                     OutputStream out, String targetRequest,
     632                                     boolean usingWWWProxy, String wwwProxy) throws IOException {
     633        writeErrorMessage(errMessage, extraMessage, out, targetRequest, usingWWWProxy, wwwProxy, null);
     634    }
     635
     636    /**
     637     *  @param jumpServers comma- or space-separated list, or null
     638     *  @param msg extra message
     639     *  @since 0.9.14
     640     */
     641    protected void writeErrorMessage(byte[] errMessage, String extraMessage,
     642                                     OutputStream out, String targetRequest,
     643                                     boolean usingWWWProxy, String wwwProxy,
     644                                     String jumpServers) throws IOException {
     645        if (out == null)
     646            return;
     647        out.write(errMessage);
     648        if (targetRequest != null) {
     649            String uri = targetRequest.replace("&", "&amp;");
     650            out.write("<a href=\"".getBytes());
     651            out.write(uri.getBytes());
     652            out.write("\">".getBytes());
     653            out.write(uri.getBytes());
     654            out.write("</a>".getBytes());
     655            if (usingWWWProxy) {
     656                out.write(("<br><br><b>").getBytes());
     657                out.write(_("HTTP Outproxy").getBytes("UTF-8"));
     658                out.write((":</b> " + wwwProxy).getBytes());
     659            }
     660            if (extraMessage != null) {
     661                out.write(("<br><br><b>" + extraMessage + "</b>").getBytes());
     662            }
     663            if (jumpServers != null && jumpServers.length() > 0) {
     664                boolean first = true;
     665                if(uri.startsWith("http://")) {
     666                    uri = uri.substring(7);
     667                }
     668                StringTokenizer tok = new StringTokenizer(jumpServers, ", ");
     669                while(tok.hasMoreTokens()) {
     670                    String jurl = tok.nextToken();
     671                    String jumphost;
     672                    try {
     673                        URI jURI = new URI(jurl);
     674                        String proto = jURI.getScheme();
     675                        jumphost = jURI.getHost();
     676                        if (proto == null || jumphost == null ||
     677                            !proto.toLowerCase(Locale.US).equals("http"))
     678                            continue;
     679                        jumphost = jumphost.toLowerCase(Locale.US);
     680                        if (!jumphost.endsWith(".i2p"))
     681                            continue;
     682                    } catch(URISyntaxException use) {
     683                        continue;
     684                    }
     685                    // Skip jump servers we don't know
     686                    if (!jumphost.endsWith(".b32.i2p")) {
     687                        Destination dest = _context.namingService().lookup(jumphost);
     688                        if(dest == null) {
     689                            continue;
     690                        }
     691                    }
     692
     693                    if (first) {
     694                        first = false;
     695                        out.write("<br><br>".getBytes());
     696                        out.write(_("Click a link below to look for an address helper by using a \"jump\" service:").getBytes("UTF-8"));
     697                        out.write("<br>\n".getBytes());
     698                    }
     699                    out.write("<br><a href=\"".getBytes());
     700                    out.write(jurl.getBytes());
     701                    out.write(uri.getBytes());
     702                    out.write("\">".getBytes());
     703                    // Translators: parameter is a host name
     704                    out.write(_("{0} jump service", jumphost).getBytes());
     705                    out.write("</a>\n".getBytes());
     706                }
     707            }
     708        }
     709        out.write("</div>".getBytes());
     710        writeFooter(out);
     711    }
     712
     713    /**
     714     *  Flushes.
     715     *
     716     *  Public only for LocalHTTPServer, not for general use
     717     *  @since 0.9.14 moved from I2PTunnelHTTPClient
     718     */
     719    public static void writeFooter(OutputStream out) throws IOException {
     720        // The css is hiding this div for now, but we'll keep it here anyway
     721        // Tag the strings below for translation if we unhide it.
     722        out.write("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
     723        out.write(new Date().toString().getBytes());
     724        out.write("</i></div></body></html>\n".getBytes());
     725        out.flush();
     726    }
     727
     728    /**
     729     *  Translate
     730     *  @since 0.9.14 moved from I2PTunnelHTTPClient
     731     */
     732    protected String _(String key) {
     733        return Translate.getString(key, _context, BUNDLE_NAME);
     734    }
     735
     736    /**
     737     *  Translate
     738     *  {0}
     739     *  @since 0.9.14 moved from I2PTunnelHTTPClient
     740     */
     741    protected String _(String key, Object o) {
     742        return Translate.getString(key, o, _context, BUNDLE_NAME);
     743    }
     744
     745    /**
     746     *  Translate
     747     *  {0} and {1}
     748     *  @since 0.9.14 moved from I2PTunnelHTTPClient
     749     */
     750    protected String _(String key, Object o, Object o2) {
     751        return Translate.getString(key, o, o2, _context, BUNDLE_NAME);
     752    }
    508753}
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientRunner.java

    r2467856 rd1bd893  
    2222 * servers could ignore that, potentially confusing the user.
    2323 *
     24 *  Warning - not maintained as a stable API for external use.
    2425 */
    2526public class I2PTunnelHTTPClientRunner extends I2PTunnelRunner {
     27
     28    /**
     29     *  Does NOT start itself. Caller must call start().
     30     */
    2631    public I2PTunnelHTTPClientRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
    27                                      List<I2PSocket> sockList, Runnable onTimeout) {
    28         super(s, i2ps, slock, initialI2PData, sockList, onTimeout);
     32                                     List<I2PSocket> sockList, FailCallback onFail) {
     33        super(s, i2ps, slock, initialI2PData, null, sockList, onFail);
    2934    }
    3035
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java

    r2467856 rd1bd893  
    308308                req.start();
    309309            } else {
    310                 new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null);
     310                Thread t = new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(),
     311                                               null, (I2PTunnelRunner.FailCallback) null);
     312                t.start();
    311313            }
    312314
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java

    r2467856 rd1bd893  
    139139                        }
    140140            Socket s = getSocket(socket.getPeerDestination().calculateHash(), socket.getLocalPort());
    141             new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
     141            Thread t = new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(),
     142                                           null, (I2PTunnelRunner.FailCallback) null);
     143            t.start();
    142144        } catch (SocketException ex) {
    143145            try {
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java

    r2467856 rd1bd893  
    2626/**
    2727 *  Like I2PTunnelRunner but socket-to-socket
     28 *
     29 *  Warning - not maintained as a stable API for external use.
    2830 *
    2931 *  @since 0.9.11
     
    5557    private final long startedOn;
    5658    /** if we die before receiving any data, run this job */
    57     private final Runnable onTimeout;
     59    private final I2PTunnelRunner.FailCallback onTimeout;
    5860    private long totalSent;
    5961    private long totalReceived;
     
    6264   
    6365    /**
    64      *  Starts itself (fixme)
     66     *  Does NOT start itself. Caller must call start().
    6567     *
    6668     *  @param slock the socket lock, non-null
    6769     *  @param initialI2PData may be null
    68      *  @param onTimeout May be null. If non-null and no data (except initial data) was sent or received,
     70     *  @param onTimeout May be null. If non-null and no data (except initial data) was received,
    6971                         it will be run before closing s.
    7072     */
    7173    public I2PTunnelOutproxyRunner(Socket s, Socket i2ps, Object slock, byte[] initialI2PData,
    72                                    byte[] initialSocketData, Runnable onTimeout) {
     74                                   byte[] initialSocketData, I2PTunnelRunner.FailCallback onTimeout) {
    7375        this.s = s;
    7476        this.i2ps = i2ps;
     
    8486        _runnerId = __runnerId.incrementAndGet();
    8587        setName("OutproxyRunner " + _runnerId);
    86         start();
    8788    }
    8889
     
    145146            Thread t1 = new StreamForwarder(in, i2pout, true);
    146147            Thread t2 = new StreamForwarder(i2pin, out, false);
     148            // TODO can we run one of these inline and save a thread?
     149            t1.start();
     150            t2.start();
    147151            synchronized (finishLock) {
    148152                while (!finished) {
     
    160164                // Run even if totalSent > 0, as that's probably POST data.
    161165                if (totalReceived <= 0)
    162                     onTimeout.run();
     166                    onTimeout.onFail(null);
    163167            }
    164168           
     
    243247    }
    244248   
     249    /**
     250     *  Forward data in one direction
     251     */
    245252    private class StreamForwarder extends I2PAppThread {
    246253
     
    251258        private final ByteCache _cache;
    252259
     260        /**
     261         *  Does not start itself. Caller must start()
     262         */
    253263        private StreamForwarder(InputStream in, OutputStream out, boolean toI2P) {
    254264            this.in = in;
     
    258268            _cache = ByteCache.getInstance(32, NETWORK_BUFFER_SIZE);
    259269            setName("OutproxyForwarder " + _runnerId + '.' + __forwarderId.incrementAndGet());
    260             start();
    261270        }
    262271
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java

    r2467856 rd1bd893  
    2626import net.i2p.util.Log;
    2727
     28/**
     29 *  A thread that starts two more threads, one to forward traffic in each direction.
     30 *
     31 *  Warning - not maintained as a stable API for external use.
     32 */
    2833public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErrorListener {
    2934    protected final Log _log;
     
    4449    private final I2PSocket i2ps;
    4550    private final Object slock, finishLock = new Object();
    46     volatile boolean finished = false;
     51    private volatile boolean finished;
    4752    private final byte[] initialI2PData;
    4853    private final byte[] initialSocketData;
     
    5459    /** if we die before receiving any data, run this job */
    5560    private final Runnable onTimeout;
     61    private final FailCallback _onFail;
    5662    private long totalSent;
    5763    private long totalReceived;
     
    5965    private static final AtomicLong __forwarderId = new AtomicLong();
    6066   
     67    /**
     68     *  For use in new constructor
     69     *  @since 0.9.14
     70     */
     71    public interface FailCallback {
     72        /**
     73         *  @param e may be null
     74         */
     75        public void onFail(Exception e);
     76    }
     77
     78    /**
     79     *  Starts itself
     80     *
     81     *  @param slock the socket lock, non-null
     82     *  @param initialI2PData may be null
     83     *  @param sockList may be null. Caller must add i2ps to the list! It will be removed here on completion.
     84     *                               Will synchronize on slock when removing.
     85     *  @deprecated use FailCallback constructor
     86     */
    6187    public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
    6288                           List<I2PSocket> sockList) {
    63         this(s, i2ps, slock, initialI2PData, null, sockList, null);
    64     }
    65 
    66     public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
    67                            byte[] initialSocketData, List<I2PSocket> sockList) {
    68         this(s, i2ps, slock, initialI2PData, initialSocketData, sockList, null);
    69     }
    70 
    71     public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
    72                            List<I2PSocket> sockList, Runnable onTimeout) {
    73         this(s, i2ps, slock, initialI2PData, null, sockList, onTimeout);
     89        this(s, i2ps, slock, initialI2PData, null, sockList, null, null, true);
    7490    }
    7591
     
    8298     *  @param sockList may be null. Caller must add i2ps to the list! It will be removed here on completion.
    8399     *                               Will synchronize on slock when removing.
    84      *  @param onTimeout May be null. If non-null and no data (except initial data) was sent or received,
    85                          it will be run before closing s.
     100     *  @deprecated use FailCallback constructor
     101     */
     102    public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
     103                           byte[] initialSocketData, List<I2PSocket> sockList) {
     104        this(s, i2ps, slock, initialI2PData, initialSocketData, sockList, null, null, true);
     105    }
     106
     107    /**
     108     *  Starts itself
     109     *
     110     *  @param slock the socket lock, non-null
     111     *  @param initialI2PData may be null
     112     *  @param sockList may be null. Caller must add i2ps to the list! It will be removed here on completion.
     113     *                               Will synchronize on slock when removing.
     114     *  @param onTimeout May be null. If non-null and no data (except initial data) was received,
     115     *                   it will be run before closing s.
     116     *  @deprecated use FailCallback constructor
     117     */
     118    public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
     119                           List<I2PSocket> sockList, Runnable onTimeout) {
     120        this(s, i2ps, slock, initialI2PData, null, sockList, onTimeout, null, true);
     121    }
     122
     123    /**
     124     *  Starts itself
     125     *
     126     *  @param slock the socket lock, non-null
     127     *  @param initialI2PData may be null
     128     *  @param initialSocketData may be null
     129     *  @param sockList may be null. Caller must add i2ps to the list! It will be removed here on completion.
     130     *                               Will synchronize on slock when removing.
     131     *  @param onTimeout May be null. If non-null and no data (except initial data) was received,
     132     *                   it will be run before closing s.
     133     *  @deprecated use FailCallback constructor
    86134     */
    87135    public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
    88136                           byte[] initialSocketData, List<I2PSocket> sockList, Runnable onTimeout) {
     137        this(s, i2ps, slock, initialI2PData, null, sockList, onTimeout, null, true);
     138    }
     139
     140    /**
     141     *  Recommended new constructor. Does NOT start itself. Caller must call start().
     142     *
     143     *  @param slock the socket lock, non-null
     144     *  @param initialI2PData may be null
     145     *  @param initialSocketData may be null
     146     *  @param sockList may be null. Caller must add i2ps to the list! It will be removed here on completion.
     147     *                               Will synchronize on slock when removing.
     148     *  @param onFail May be null. If non-null and no data (except initial data) was received,
     149     *                it will be run before closing s.
     150     */
     151    public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
     152                           byte[] initialSocketData, List<I2PSocket> sockList, FailCallback onFail) {
     153        this(s, i2ps, slock, initialI2PData, null, sockList, null, onFail, false);
     154    }
     155
     156    /**
     157     *  Base constructor
     158     *
     159     *  @param slock the socket lock, non-null
     160     *  @param initialI2PData may be null
     161     *  @param initialSocketData may be null
     162     *  @param sockList may be null. Caller must add i2ps to the list! It will be removed here on completion.
     163     *                               Will synchronize on slock when removing.
     164     *  @param onTimeout May be null. If non-null and no data (except initial data) was received,
     165     *                   it will be run before closing s.
     166     *  @param onFail Trumps onTimeout
     167     *  @param shouldStart should thread be started in constructor (bad, false recommended)
     168     */
     169    private I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
     170                            byte[] initialSocketData, List<I2PSocket> sockList, Runnable onTimeout,
     171                            FailCallback onFail, boolean shouldStart) {
    89172        this.sockList = sockList;
    90173        this.s = s;
     
    94177        this.initialSocketData = initialSocketData;
    95178        this.onTimeout = onTimeout;
     179        _onFail = onFail;
    96180        lastActivityOn = -1;
    97181        startedOn = Clock.getInstance().now();
     
    101185        _runnerId = __runnerId.incrementAndGet();
    102186        setName("I2PTunnelRunner " + _runnerId);
    103         start();
     187        if (shouldStart)
     188            start();
    104189    }
    105190
     
    182267            if (!(s instanceof InternalSocket))
    183268                in = new BufferedInputStream(in, 2*NETWORK_BUFFER_SIZE);
    184             Thread t1 = new StreamForwarder(in, i2pout, true);
    185             Thread t2 = new StreamForwarder(i2pin, out, false);
     269            StreamForwarder toI2P = new StreamForwarder(in, i2pout, true);
     270            StreamForwarder fromI2P = new StreamForwarder(i2pin, out, false);
     271            // TODO can we run one of these inline and save a thread?
     272            toI2P.start();
     273            fromI2P.start();
    186274            synchronized (finishLock) {
    187275                while (!finished) {
     
    193281           
    194282            // this task is useful for the httpclient
    195             if (onTimeout != null) {
     283            if (onTimeout != null || _onFail != null) {
    196284                if (_log.shouldLog(Log.DEBUG))
    197285                    _log.debug("runner has a timeout job, totalReceived = " + totalReceived
     
    201289                // responsibility to know that and decide whether or not to write to the socket.
    202290                // HTTPClient never sets initialSocketData.
    203                 if (totalReceived <= 0)
    204                     onTimeout.run();
     291                if (totalReceived <= 0) {
     292                    if (_onFail != null) {
     293                        Exception e = fromI2P.getFailure();
     294                        if (e == null)
     295                            e = toI2P.getFailure();
     296                        _onFail.onFail(e);
     297                    } else {
     298                        onTimeout.run();
     299                    }
     300                }
    205301            }
    206302           
    207303            // now one connection is dead - kill the other as well, after making sure we flush
    208             close(out, in, i2pout, i2pin, s, i2ps, t1, t2);
     304            close(out, in, i2pout, i2pin, s, i2ps, toI2P, fromI2P);
    209305        } catch (InterruptedException ex) {
    210306            if (_log.shouldLog(Log.ERROR))
     
    292388    }
    293389   
     390    /**
     391     * Deprecated, unimplemented in streaming, never called.
     392     */
    294393    public void errorOccurred() {
    295394        synchronized (finishLock) {
     
    307406    }
    308407   
     408    /**
     409     *  Forward data in one direction
     410     */
    309411    private class StreamForwarder extends I2PAppThread {
    310412
     
    314416        private final boolean _toI2P;
    315417        private final ByteCache _cache;
    316 
    317         private StreamForwarder(InputStream in, OutputStream out, boolean toI2P) {
     418        private volatile Exception _failure;
     419
     420        /**
     421         *  Does not start itself. Caller must start()
     422         */
     423        public StreamForwarder(InputStream in, OutputStream out, boolean toI2P) {
    318424            this.in = in;
    319425            this.out = out;
     
    322428            _cache = ByteCache.getInstance(32, NETWORK_BUFFER_SIZE);
    323429            setName("StreamForwarder " + _runnerId + '.' + __forwarderId.incrementAndGet());
    324             start();
    325430        }
    326431
     
    378483                    }
    379484                }
     485                _failure = ex;
    380486            } catch (InterruptedIOException ex) {
    381487                if (_log.shouldLog(Log.WARN))
    382488                    _log.warn(direction + ": Closing connection due to timeout (error: \""
    383489                              + ex.getMessage() + "\")");
     490                _failure = ex;
    384491            } catch (IOException ex) {
    385492                if (!finished) {
     
    389496                //else
    390497                //    _log.warn("You may ignore this", ex);
     498                _failure = ex;
    391499            } finally {
    392500                _cache.release(ba);
     
    409517                    // or else the timeout job can't write the error message to the stream.
    410518                    // close() above will close it after the timeout job is run.
    411                     if (!(onTimeout != null && (!_toI2P) && totalReceived <= 0))
     519                    if (!((onTimeout != null || _onFail != null) && (!_toI2P) && totalReceived <= 0))
    412520                        out.close();
    413521                    else if (_log.shouldLog(Log.INFO))
     
    424532            }
    425533        }
     534
     535        /**
     536         *  @since 0.9.14
     537         */
     538        public Exception getFailure() {
     539            return _failure;
     540        }
    426541    }
    427542}
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java

    r2467856 rd1bd893  
    315315    }
    316316
    317     public boolean close(boolean forced) {
     317    public synchronized boolean close(boolean forced) {
    318318        if (!open) return true;
    319319        if (task != null) {
     
    524524            Socket s = getSocket(socket.getPeerDestination().calculateHash(), socket.getLocalPort());
    525525            afterSocket = getTunnel().getContext().clock().now();
    526             new I2PTunnelRunner(s, socket, slock, null, null);
     526            Thread t = new I2PTunnelRunner(s, socket, slock, null, null,
     527                                           null, (I2PTunnelRunner.FailCallback) null);
     528            t.start();
    527529
    528530            long afterHandle = getTunnel().getContext().clock().now();
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java

    r2467856 rd1bd893  
    7676        try {
    7777            i2ps = createI2PSocket(dest, opts);
    78             new Runner(s, i2ps);
     78            Thread t = new Runner(s, i2ps);
     79            t.start();
    7980        } catch (Exception ex) {
    8081            _log.error("Could not make DCC connection to " + _dest + ':' + _remotePort, ex);
     
    116117    private class Runner extends I2PTunnelRunner {
    117118
     119        /**
     120         *  Does NOT start itself. Caller must call start().
     121         */
    118122        public Runner(Socket s, I2PSocket i2ps) {
    119             // super calls start()
    120             super(s, i2ps, sockLock, null, mySockets);
     123            super(s, i2ps, sockLock, null, null, mySockets, (FailCallback) null);
    121124        }
    122125
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCServer.java

    r2467856 rd1bd893  
    110110                Socket s = new Socket(local.ia, local.port);
    111111                _sockList.add(socket);
    112                 new I2PTunnelRunner(s, socket, slock, null, _sockList);
     112                Thread t = new I2PTunnelRunner(s, socket, slock, null, null, _sockList,
     113                                               (I2PTunnelRunner.FailCallback) null);
     114                t.start();
    113115                local.socket = socket;
    114116                local.expire = getTunnel().getContext().clock().now() + OUTBOUND_EXPIRE;
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java

    r2467856 rd1bd893  
    5555            Socket clientSock = serv.getClientSocket();
    5656            I2PSocket destSock = serv.getDestinationI2PSocket(this);
    57             new I2PTunnelRunner(clientSock, destSock, sockLock, null, mySockets);
     57            Thread t = new I2PTunnelRunner(clientSock, destSock, sockLock, null, null, mySockets,
     58                                           (I2PTunnelRunner.FailCallback) null);
     59            t.start();
    5860        } catch (SOCKSException e) {
    5961            if (_log.shouldLog(Log.WARN))
  • apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketException.java

    r2467856 rd1bd893  
    33import java.net.SocketException;
    44
     5import net.i2p.I2PAppContext;
    56import net.i2p.client.SendMessageStatusListener;
    67import net.i2p.data.i2cp.MessageStatusMessage;
     8import net.i2p.util.Translate;
    79
    810/**
    9  *  An I2P-specific IOException thrown from input and output streams.
     11 *  An I2P-specific IOException thrown from input and output streams,
    1012 *  with a stored status code to be used for programmatic responses.
    1113 *
     
    1618    private final int _status;
    1719    private static final int CUSTOM = -1;
     20    private static final String BUNDLE_NAME = "net.i2p.client.streaming.messages";
    1821
    1922    /**
     
    5356            case MessageStatusMessage.STATUS_SEND_BEST_EFFORT_FAILURE:
    5457            case MessageStatusMessage.STATUS_SEND_GUARANTEED_FAILURE:
    55                 return "Message timeout";
     58                return _x("Message timeout");
    5659
    5760            case MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL:
    58                 return "Failed delivery to local destination";
     61                return _x("Failed delivery to local destination");
    5962
    6063            case MessageStatusMessage.STATUS_SEND_FAILURE_ROUTER:
    61                 return "Local router failure";
     64                return _x("Local router failure");
    6265
    6366            case MessageStatusMessage.STATUS_SEND_FAILURE_NETWORK:
    64                 return "Local network failure";
     67                return _x("Local network failure");
    6568
    6669            case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_SESSION:
    67                 return "Session closed";
     70                return _x("Session closed");
    6871
    6972            case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_MESSAGE:
    70                 return "Invalid message";
     73                return _x("Invalid message");
    7174
    7275            case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_OPTIONS:
    73                 return "Invalid message options";
     76                return _x("Invalid message options");
    7477
    7578            case MessageStatusMessage.STATUS_SEND_FAILURE_OVERFLOW:
    76                 return "Buffer overflow";
     79                return _x("Buffer overflow");
    7780
    7881            case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED:
    79                 return "Message expired";
     82                return _x("Message expired");
    8083
    8184            case MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL_LEASESET:
    82                 return "Local lease set invalid";
     85                return _x("Local lease set invalid");
    8386
    8487            case MessageStatusMessage.STATUS_SEND_FAILURE_NO_TUNNELS:
    85                 return "No local tunnels";
     88                return _x("No local tunnels");
    8689
    8790            case MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION:
    88                 return "Unsupported encryption options";
     91                return _x("Unsupported encryption options");
    8992
    9093            case MessageStatusMessage.STATUS_SEND_FAILURE_DESTINATION:
    91                 return "Invalid destination";
     94                return _x("Invalid destination");
    9295
    9396            case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET:
    94                 return "Local router failure";
     97                return _x("Local router failure");
    9598
    9699            case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED_LEASESET:
    97                 return "Destination lease set expired";
     100                return _x("Destination lease set expired");
    98101
    99102            case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET:
    100                 return "Destination lease set not found";
     103                return _x("Destination lease set not found");
    101104
    102105            case SendMessageStatusListener.STATUS_CANCELLED:
    103                 return "Local destination shutdown";
     106                return _x("Local destination shutdown");
    104107
    105108            case CUSTOM:
     
    110113        }
    111114    }
     115
     116    /**
     117     *  Translated
     118     */
     119    @Override
     120    public String getLocalizedMessage() {
     121        String s = getMessage();
     122        if (s == null)
     123            return null;
     124        return Translate.getString(s, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
     125    }
     126
     127    /**
     128     *  Tag for translation
     129     */
     130    private static String _x(String s) {
     131        return s;
     132    }
    112133}
Note: See TracChangeset for help on using the changeset viewer.