Changeset c7c7731


Ignore:
Timestamp:
Dec 15, 2010 3:09:48 PM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
8e709ee
Parents:
46b8bef (diff), 77f910e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

propagate from branch 'i2p.i2p' (head 3d405c867f6903bf1d69b04c1daebf3146882525)

to branch 'i2p.i2p.zzz.test4' (head bfd85b10fdd1542526a4b9c53e5d4a733087f317)

Files:
10 added
1 deleted
61 edited

Legend:

Unmodified
Added
Removed
  • apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java

    r46b8bef rc7c7731  
    429429            }
    430430          };
    431         String threadName = peer.toString();
     431        String threadName = "Snark peer " + peer.toString();
    432432        new I2PAppThread(r, threadName).start();
    433433        return true;
  • apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java

    r46b8bef rc7c7731  
    7373  public TrackerClient(I2PSnarkUtil util, MetaInfo meta, PeerCoordinator coordinator)
    7474  {
     75    super();
    7576    // Set unique name.
    76     super("TrackerClient-" + urlencode(coordinator.getID()));
     77    String id = urlencode(coordinator.getID());
     78    setName("TrackerClient " + id.substring(id.length() - 12));
    7779    _util = util;
    7880    this.meta = meta;
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java

    r46b8bef rc7c7731  
    1717import java.io.PipedOutputStream;
    1818import java.util.zip.GZIPInputStream;
     19import java.util.concurrent.RejectedExecutionException;
    1920
    2021import net.i2p.I2PAppContext;
     
    229230        PipedInputStream pi = new PipedInputStream();
    230231        PipedOutputStream po = new PipedOutputStream(pi);
    231         new I2PAppThread(new Pusher(pi, out), "HTTP decompressor").start();
     232        // Run in the client thread pool, as there should be an unused thread
     233        // there after the accept().
     234        // Overridden in I2PTunnelHTTPServer, where it does not use the client pool.
     235        try {
     236            I2PTunnelClientBase._executor.execute(new Pusher(pi, out));
     237        } catch (RejectedExecutionException ree) {
     238            // shouldn't happen
     239            throw ree;
     240        }
    232241        out = po;
    233242    }
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java

    r46b8bef rc7c7731  
    1616
    1717public class I2PTunnelClient extends I2PTunnelClientBase {
    18 
    19     private static final Log _log = new Log(I2PTunnelClient.class);
    2018
    2119    /** list of Destination objects that we point at */
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java

    r46b8bef rc7c7731  
    1818import java.util.List;
    1919import java.util.Properties;
     20import java.util.concurrent.Executor;
     21import java.util.concurrent.Executors;
     22import java.util.concurrent.SynchronousQueue;
     23import java.util.concurrent.RejectedExecutionException;
     24import java.util.concurrent.ThreadPoolExecutor;
     25import java.util.concurrent.TimeUnit;
     26import java.util.concurrent.ThreadFactory;
    2027
    2128import net.i2p.I2PAppContext;
     
    3542public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runnable {
    3643
    37     private static final Log _log = new Log(I2PTunnelClientBase.class);
    38     protected I2PAppContext _context;
    39     protected Logging l;
     44    protected final Log _log;
     45    protected final I2PAppContext _context;
     46    protected final Logging l;
    4047
    4148    static final long DEFAULT_CONNECT_TIMEOUT = 60 * 1000;
     
    6572    private String privKeyFile;
    6673
    67     // private Object conLock = new Object();
    68    
    69     /** List of Socket for those accept()ed but not yet started up */
    70     protected final List _waitingSockets = new ArrayList(4); // FIXME should be final and use a factory. FIXME
    71     /** How many connections will we allow to be in the process of being built at once? */
    72     private int _numConnectionBuilders;
    73     /** How long will we allow sockets to sit in the _waitingSockets map before killing them? */
    74     private int _maxWaitTime;
    75    
    76     /**
    77      * How many concurrent connections this I2PTunnel instance will allow to be
    78      * in the process of connecting (or if less than 1, there is no limit)?
    79      */
    80     public static final String PROP_NUM_CONNECTION_BUILDERS = "i2ptunnel.numConnectionBuilders";
    81     /**
    82      * How long will we let a socket wait after being accept()ed without getting
    83      * pumped through a connection builder (in milliseconds).  If this time is
    84      * reached, the socket is unceremoniously closed and discarded.  If the max
    85      * wait time is less than 1, there is no limit.
    86      *
    87      */
    88     public static final String PROP_MAX_WAIT_TIME = "i2ptunnel.maxWaitTime";
    89    
    90     private static final int DEFAULT_NUM_CONNECTION_BUILDERS = 5;
    91     private static final int DEFAULT_MAX_WAIT_TIME = 30*1000;
    92 
    9374    // true if we are chained from a server.
    9475    private boolean chained = false;
     76
     77    /** how long to wait before dropping an idle thread */
     78    private static final long HANDLER_KEEPALIVE_MS = 2*60*1000;
     79
     80    /**
     81     *  We keep a static pool of socket handlers for all clients,
     82     *  as there is no need for isolation on the client side.
     83     *  Extending classes may use it for other purposes.
     84     *  Not for use by servers, as there is no limit on threads.
     85     */
     86    static final Executor _executor;
     87    private static int _executorThreadCount;
     88    static {
     89        _executor = new CustomThreadPoolExecutor();
     90    }
    9591
    9692    public I2PTunnelClientBase(int localPort, Logging l, I2PSocketManager sktMgr,
     
    110106        _context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
    111107        _context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
    112 
    113         Thread t = new I2PAppThread(this);
    114         t.setName("Client " + _clientId);
     108        _log = _context.logManager().getLog(getClass());
     109
     110        Thread t = new I2PAppThread(this, "Client " + tunnel.listenHost + ':' + localPort);
    115111        listenerReady = false;
    116112        t.start();
     
    126122        }
    127123
    128         configurePool(tunnel);
    129 
    130124        if (open && listenerReady) {
    131125            l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
     
    136130        }
    137131    }
     132
    138133    public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l,
    139134                               EventDispatcher notifyThis, String handlerName,
     
    164159        _context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
    165160        _context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
     161        _log = _context.logManager().getLog(getClass());
    166162
    167163        // normalize path so we can find it
     
    211207        }
    212208
    213         configurePool(tunnel);
    214        
    215209        if (open && listenerReady) {
    216210            if (openNow)
     
    225219    }
    226220   
    227     /**
    228      * build and configure the pool handling accept()ed but not yet
    229      * established connections
    230      *
    231      */
    232     private void configurePool(I2PTunnel tunnel) {
    233         //_waitingSockets = new ArrayList(4);
    234        
    235         Properties opts = tunnel.getClientOptions();
    236         String maxWait = opts.getProperty(PROP_MAX_WAIT_TIME, DEFAULT_MAX_WAIT_TIME+"");
    237         try {
    238             _maxWaitTime = Integer.parseInt(maxWait);
    239         } catch (NumberFormatException nfe) {
    240             _maxWaitTime = DEFAULT_MAX_WAIT_TIME;
    241         }
    242        
    243         String numBuild = opts.getProperty(PROP_NUM_CONNECTION_BUILDERS, DEFAULT_NUM_CONNECTION_BUILDERS+"");
    244         try {
    245             _numConnectionBuilders = Integer.parseInt(numBuild);
    246         } catch (NumberFormatException nfe) {
    247             _numConnectionBuilders = DEFAULT_NUM_CONNECTION_BUILDERS;
    248         }
    249 
    250         for (int i = 0; i < _numConnectionBuilders; i++) {
    251             String name = "ClientBuilder" + _clientId + '.' + i;
    252             I2PAppThread b = new I2PAppThread(new TunnelConnectionBuilder(), name);
    253             b.setDaemon(true);
    254             b.start();
    255         }
    256     }
    257 
    258221    /**
    259222     * Sets the this.sockMgr field if it is null, or if we want a new one
     
    322285     */
    323286    protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) {
     287        // shadows instance _log
     288        Log _log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class);
    324289        if (socketManager != null) {
    325290            I2PSession s = socketManager.getSession();
     
    379344     */
    380345    protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf, Logging log) {
     346        // shadows instance _log
     347        Log _log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class);
    381348        Properties props = new Properties();
    382349        props.putAll(tunnel.getClientOptions());
     
    538505                    notifyAll();
    539506                }
    540                 synchronized (_waitingSockets) { _waitingSockets.notifyAll(); }
    541507                return;
    542508            }
     
    567533            }
    568534
    569             while (true) {
     535            while (open) {
    570536                Socket s = ss.accept();
    571                 long before = System.currentTimeMillis();
    572537                manageConnection(s);
    573                 long total = System.currentTimeMillis() - before;
    574                 _context.statManager().addRateData("i2ptunnel.client.manageTime", total, total);
    575538            }
    576539        } catch (IOException ex) {
     
    587550            }
    588551        }
    589         synchronized (_waitingSockets) {
    590             _waitingSockets.notifyAll();
    591         }
    592552    }
    593553
     
    599559    protected void manageConnection(Socket s) {
    600560        if (s == null) return;
    601         if (_numConnectionBuilders <= 0) {
    602             new I2PAppThread(new BlockingRunner(s), "Clinet run").start();
    603             return;
    604         }
    605        
    606         if (_maxWaitTime > 0)
    607             SimpleScheduler.getInstance().addEvent(new CloseEvent(s), _maxWaitTime);
    608 
    609         synchronized (_waitingSockets) {
    610             _waitingSockets.add(s);
    611             _waitingSockets.notifyAll();
     561        try {
     562            _executor.execute(new BlockingRunner(s));
     563        } catch (RejectedExecutionException ree) {
     564             // should never happen, we have an unbounded pool and never stop the executor
     565             try {
     566                 s.close();
     567             } catch (IOException ioe) {}
     568        }
     569    }
     570
     571    /**
     572     * Not really needed for now but in case we want to add some hooks like afterExecute().
     573     */
     574    private static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
     575        public CustomThreadPoolExecutor() {
     576             super(0, Integer.MAX_VALUE, HANDLER_KEEPALIVE_MS, TimeUnit.MILLISECONDS,
     577                   new SynchronousQueue(), new CustomThreadFactory());
     578        }
     579    }
     580
     581    /** just to set the name and set Daemon */
     582    private static class CustomThreadFactory implements ThreadFactory {
     583        public Thread newThread(Runnable r) {
     584            Thread rv = Executors.defaultThreadFactory().newThread(r);
     585            rv.setName("I2PTunnel Client Runner " + (++_executorThreadCount));
     586            rv.setDaemon(true);
     587            return rv;
    612588        }
    613589    }
    614590
    615591    /**
    616      * Blocking runner, used during the connection establishment whenever we
    617      * are not using the queued builders.
    618      *
     592     * Blocking runner, used during the connection establishment
    619593     */
    620594    private class BlockingRunner implements Runnable {
     
    626600    }
    627601   
    628     /**
    629      * Remove and close the socket from the waiting list, if it is still there.
    630      *
    631      */
    632     private class CloseEvent implements SimpleTimer.TimedEvent {
    633         private Socket _s;
    634         public CloseEvent(Socket s) { _s = s; }
    635         public void timeReached() {
    636             int remaining = 0;
    637             boolean stillWaiting = false;
    638             synchronized (_waitingSockets) {
    639                 stillWaiting = _waitingSockets.remove(_s);
    640                 remaining = _waitingSockets.size();
    641             }
    642             if (stillWaiting) {
    643                 try { _s.close(); } catch (IOException ioe) {}
    644                 if (_log.shouldLog(Log.INFO)) {
    645                     _context.statManager().addRateData("i2ptunnel.client.closeBacklog", remaining, 0);
    646                     _log.info("Closed a waiting socket because of backlog");
    647                 }
    648             } else {
    649                 _context.statManager().addRateData("i2ptunnel.client.closeNoBacklog", remaining, 0);
    650             }
    651         }
    652     }
    653 
    654602    public boolean close(boolean forced) {
    655603        if (_log.shouldLog(Log.INFO))
     
    689637        }
    690638       
    691         synchronized (_waitingSockets) { _waitingSockets.notifyAll(); }
    692639        return true;
    693640    }
     
    697644            s.close();
    698645        } catch (IOException ex) {
    699             _log.error("Could not close socket", ex);
     646            //_log.error("Could not close socket", ex);
    700647        }
    701648    }
    702649   
    703     /**
    704      * Pool runner pulling sockets off the waiting list and pushing them
    705      * through clientConnectionRun.  This dies when the I2PTunnel instance
    706      * is closed.
    707      *
    708      */
    709     private class TunnelConnectionBuilder implements Runnable {
    710         public void run() {
    711             Socket s = null;
    712             while (open) {
    713                 try {
    714                     synchronized (_waitingSockets) {
    715                         if (_waitingSockets.isEmpty())
    716                             _waitingSockets.wait();
    717                         else
    718                             s = (Socket)_waitingSockets.remove(0);
    719                     }
    720                 } catch (InterruptedException ie) {}
    721                
    722                 if (s != null) {
    723                     long before = System.currentTimeMillis();
    724                     clientConnectionRun(s);
    725                     long total = System.currentTimeMillis() - before;
    726                     _context.statManager().addRateData("i2ptunnel.client.buildRunTime", total, 0);
    727                 }
    728                 s = null;
    729             }
    730         }
    731     }
    732 
    733650    /**
    734651     * Manage a connection in a separate thread. This only works if
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java

    r46b8bef rc7c7731  
    5959 */
    6060public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements Runnable {
    61     private static final Log _log = new Log(I2PTunnelConnectClient.class);
    6261
    6362    private final static byte[] ERR_DESTINATION_UNKNOWN =
     
    341340        }
    342341        public void run() {
    343             if (_log.shouldLog(Log.DEBUG))
    344                 _log.debug("Timeout occured requesting " + _target);
     342            //if (_log.shouldLog(Log.DEBUG))
     343            //    _log.debug("Timeout occured requesting " + _target);
    345344            handleConnectClientException(new RuntimeException("Timeout"), _out,
    346345                                      _target, _usingProxy, _wwwProxy, _requestId);
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPBidirServer.java

    r46b8bef rc7c7731  
    1212
    1313public class I2PTunnelHTTPBidirServer extends I2PTunnelHTTPServer {
    14     private final static Log log = new Log(I2PTunnelHTTPBidirServer.class);
    1514
    1615    public I2PTunnelHTTPBidirServer(InetAddress host, int port, int proxyport, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java

    r46b8bef rc7c7731  
    6262 */
    6363public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runnable {
    64     private static final Log _log = new Log(I2PTunnelHTTPClient.class);
    6564
    6665    private HashMap addressHelpers = new HashMap();
     
    895894        }
    896895        public void run() {
    897             if (_log.shouldLog(Log.DEBUG))
    898                 _log.debug("Timeout occured requesting " + _target);
     896            //if (_log.shouldLog(Log.DEBUG))
     897            //    _log.debug("Timeout occured requesting " + _target);
    899898            handleHTTPClientException(new RuntimeException("Timeout"), _out,
    900899                                      _target, _usingProxy, _wwwProxy, _requestId);
     
    903902    }
    904903
    905     private static String DEFAULT_JUMP_SERVERS =
     904    public static final String DEFAULT_JUMP_SERVERS =
    906905                                           "http://i2host.i2p/cgi-bin/i2hostjump?," +
    907906                                           "http://stats.i2p/cgi-bin/jump.cgi?a=," +
     
    941940                        String jumphost = jurl.substring(7);  // "http://"
    942941                        jumphost = jumphost.substring(0, jumphost.indexOf('/'));
    943                         Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(jumphost);
    944                         if (dest == null) continue;
     942                        if (!jumphost.endsWith(".i2p"))
     943                            continue;
     944                        if (!jumphost.endsWith(".b32.i2p")) {
     945                            Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(jumphost);
     946                            if (dest == null) continue;
     947                        }
    945948
    946949                        out.write("<br><a href=\"".getBytes());
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java

    r46b8bef rc7c7731  
    2626 */
    2727public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implements Runnable {
    28     private static final Log _log = new Log(I2PTunnelHTTPClientBase.class);
     28
    2929    protected final List<String> _proxyList;
    3030
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java

    r46b8bef rc7c7731  
    3232 */
    3333public class I2PTunnelHTTPServer extends I2PTunnelServer {
    34     private final static Log _log = new Log(I2PTunnelHTTPServer.class);
     34
    3535    /** what Host: should we seem to be to the webserver? */
    3636    private String _spoofHost;
     
    4141    private static final String SERVER_HEADER = "Server";
    4242    private static final String[] SERVER_SKIPHEADERS = {SERVER_HEADER};
     43    private static final long HEADER_TIMEOUT = 60*1000;
     44
     45    private final static byte[] ERR_UNAVAILABLE =
     46        ("HTTP/1.1 503 Service Unavailable\r\n"+
     47         "Content-Type: text/html; charset=iso-8859-1\r\n"+
     48         "Cache-control: no-cache\r\n"+
     49         "Connection: close\r\n"+
     50         "Proxy-Connection: close\r\n"+
     51         "\r\n"+
     52         "<html><head><title>503 Service Unavailable<title></head>\n"+
     53         "<body><h2>503 Service Unavailable</h2>\n" +
     54         "<p>This I2P eepsite is unavailable. It may be down or undergoing maintenance.</p>\n" +
     55         "</body></html>")
     56         .getBytes();
    4357
    4458    public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
     
    7488        //threads.
    7589        try {
    76             // give them 5 seconds to send in the HTTP request
    77             socket.setReadTimeout(5*1000);
     90            // The headers _should_ be in the first packet, but
     91            // may not be, depending on the client-side options
     92            socket.setReadTimeout(HEADER_TIMEOUT);
    7893
    7994            InputStream in = socket.getInputStream();
     
    131146                new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null);
    132147            }
     148
     149            long afterHandle = getTunnel().getContext().clock().now();
     150            long timeToHandle = afterHandle - afterAccept;
     151            getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle, 0);
     152            if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
     153                _log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
     154                          " [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
    133155        } catch (SocketException ex) {
    134156            try {
     157                // Send a 503, so the user doesn't get an HTTP Proxy error message
     158                // and blame his router or the network.
     159                socket.getOutputStream().write(ERR_UNAVAILABLE);
     160            } catch (IOException ioe) {}
     161            try {
    135162                socket.close();
    136             } catch (IOException ioe) {
    137                 if (_log.shouldLog(Log.ERROR))
    138                     _log.error("Error while closing the received i2p con", ex);
    139             }
     163            } catch (IOException ioe) {}
     164            if (_log.shouldLog(Log.ERROR))
     165                _log.error("Error connecting to HTTP server " + remoteHost + ':' + remotePort, ex);
    140166        } catch (IOException ex) {
    141167            try {
     
    151177                _log.error("OOM in HTTP server", oom);
    152178        }
    153 
    154         long afterHandle = getTunnel().getContext().clock().now();
    155         long timeToHandle = afterHandle - afterAccept;
    156         getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle, 0);
    157         if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
    158             _log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
    159179    }
    160180   
     
    170190            _ctx = ctx;
    171191        }
     192
    172193        public void run() {
    173194            if (_log.shouldLog(Log.INFO))
     
    184205                serverout.write(_headers.getBytes());
    185206                browserin = _browser.getInputStream();
    186                 I2PAppThread sender = new I2PAppThread(new Sender(serverout, browserin, "server: browser to server"), Thread.currentThread().getName() + "hcs");
     207                I2PAppThread sender = new I2PAppThread(new Sender(serverout, browserin, "server: browser to server", _log), Thread.currentThread().getName() + "hcs");
    187208                sender.start();
    188209               
     
    234255
    235256    private static class Sender implements Runnable {
    236         private OutputStream _out;
    237         private InputStream _in;
    238         private String _name;
    239         public Sender(OutputStream out, InputStream in, String name) {
     257        private final OutputStream _out;
     258        private final InputStream _in;
     259        private final String _name;
     260        // shadows _log in super()
     261        private final Log _log;
     262
     263        public Sender(OutputStream out, InputStream in, String name, Log log) {
    240264            _out = out;
    241265            _in = in;
    242266            _name = name;
    243         }
     267            _log = log;
     268        }
     269
    244270        public void run() {
    245271            if (_log.shouldLog(Log.INFO))
     
    278304        @Override
    279305        protected void finishHeaders() throws IOException {
    280             if (_log.shouldLog(Log.INFO))
    281                 _log.info("Including x-i2p-gzip as the content encoding in the response");
     306            //if (_log.shouldLog(Log.INFO))
     307            //    _log.info("Including x-i2p-gzip as the content encoding in the response");
    282308            out.write("Content-encoding: x-i2p-gzip\r\n".getBytes());
    283309            super.finishHeaders();
     
    286312        @Override
    287313        protected void beginProcessing() throws IOException {
    288             if (_log.shouldLog(Log.INFO))
    289                 _log.info("Beginning compression processing");
     314            //if (_log.shouldLog(Log.INFO))
     315            //    _log.info("Beginning compression processing");
    290316            //out.flush();
    291317            _gzipOut = new InternalGZIPOutputStream(out);
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java

    r46b8bef rc7c7731  
    2121public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable {
    2222
    23     private static final Log _log = new Log(I2PTunnelIRCClient.class);
    24    
    2523    /** used to assign unique IDs to the threads / clients.  no logic or functionality */
    2624    private static volatile long __clientId = 0;
     
    131129        private I2PSocket remote;
    132130        private StringBuffer expectedPong;
     131        // shadows _log in super()
     132        private final Log _log = new Log(I2PTunnelIRCClient.class);
    133133               
    134134        public IrcInboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
     
    208208            private I2PSocket remote;
    209209            private StringBuffer expectedPong;
     210            // shadows _log in super()
     211            private final Log _log = new Log(I2PTunnelIRCClient.class);
    210212               
    211213            public IrcOutboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
     
    309311         catch (IndexOutOfBoundsException ioobe) // wtf, server sent borked command?
    310312        {
    311            _log.warn("Dropping defective message: index out of bounds while extracting command.");
     313           //_log.warn("Dropping defective message: index out of bounds while extracting command.");
    312314           return null;
    313315        }
     
    432434                expectedPong.append("PONG ").append(field[2]).append(" :").append(field[1]); // PONG serverLocation nonce
    433435            } else {
    434                 if (_log.shouldLog(Log.ERROR))
    435                     _log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
     436                //if (_log.shouldLog(Log.ERROR))
     437                //    _log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
    436438                rv = null;
    437439            }
    438440           
    439             if (_log.shouldLog(Log.WARN))
    440                 _log.warn("sending ping [" + rv + "], waiting for [" + expectedPong + "] orig was [" + s  + "]");
     441            //if (_log.shouldLog(Log.WARN))
     442            //    _log.warn("sending ping [" + rv + "], waiting for [" + expectedPong + "] orig was [" + s  + "]");
    441443           
    442444            return rv;
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java

    r46b8bef rc7c7731  
    6262    public static final String PROP_HOSTNAME="ircserver.fakeHostname";
    6363    public static final String PROP_HOSTNAME_DEFAULT="%f.b32.i2p";
    64    
    65     private static final Log _log = new Log(I2PTunnelIRCServer.class);
    66    
     64    private static final long HEADER_TIMEOUT = 60*1000;
    6765   
    6866    /**
     
    109107                        String modifiedRegistration;
    110108                        if(!this.method.equals("webirc")) {
    111                                 // give them 15 seconds to send in the request
    112                                 socket.setReadTimeout(15*1000);
     109                                // The headers _should_ be in the first packet, but
     110                                // may not be, depending on the client-side options
     111                                socket.setReadTimeout(HEADER_TIMEOUT);
    113112                                InputStream in = socket.getInputStream();
    114113                                modifiedRegistration = filterRegistration(in, cloakDest(socket.getPeerDestination()));
     
    127126            new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
    128127        } catch (SocketException ex) {
     128            // TODO send the equivalent of a 503?
    129129            try {
    130130                socket.close();
    131             } catch (IOException ioe) {
    132                 if (_log.shouldLog(Log.ERROR))
    133                     _log.error("Error while closing the received i2p con", ex);
    134             }
     131            } catch (IOException ioe) {}
     132            if (_log.shouldLog(Log.ERROR))
     133                _log.error("Error connecting to IRC server " + remoteHost + ':' + remotePort, ex);
    135134        } catch (IOException ex) {
    136135            try {
     
    182181                throw new IOException("Too many lines before USER or SERVER, giving up");
    183182            s = s.trim();
    184             if (_log.shouldLog(Log.DEBUG))
    185                 _log.debug("Got line: " + s);
     183            //if (_log.shouldLog(Log.DEBUG))
     184            //    _log.debug("Got line: " + s);
    186185
    187186            String field[]=s.split(" ",5);
     
    215214                break;
    216215        }
    217         if (_log.shouldLog(Log.DEBUG))
    218             _log.debug("All done, sending: " + buf.toString());
     216        //if (_log.shouldLog(Log.DEBUG))
     217        //    _log.debug("All done, sending: " + buf.toString());
    219218        return buf.toString();
    220219    }
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java

    r46b8bef rc7c7731  
    1717import java.util.Iterator;
    1818import java.util.Properties;
     19import java.util.concurrent.Executors;
     20import java.util.concurrent.SynchronousQueue;
     21import java.util.concurrent.RejectedExecutionException;
     22import java.util.concurrent.ThreadPoolExecutor;
     23import java.util.concurrent.TimeUnit;
     24import java.util.concurrent.ThreadFactory;
    1925
    2026import net.i2p.I2PAppContext;
     
    3137public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
    3238
    33     private final static Log _log = new Log(I2PTunnelServer.class);
    34 
     39    protected final Log _log;
    3540    protected I2PSocketManager sockMgr;
    3641    protected I2PServerSocket i2pss;
     
    4954    protected long readTimeout = DEFAULT_READ_TIMEOUT;
    5055
    51     private static final boolean DEFAULT_USE_POOL = false;
     56    /** do we use threads? default true (ignored for standard servers, always false) */
     57    private static final String PROP_USE_POOL = "i2ptunnel.usePool";
     58    private static final boolean DEFAULT_USE_POOL = true;
    5259    protected static volatile long __serverId = 0;
     60    /** max number of threads  - this many slowlorisses will DOS this server, but too high could OOM the JVM */
    5361    private static final String PROP_HANDLER_COUNT = "i2ptunnel.blockingHandlerCount";
    54     private static final int DEFAULT_HANDLER_COUNT = 10;
    55 
    56 
     62    private static final int DEFAULT_HANDLER_COUNT = 65;
     63    /** min number of threads */
     64    private static final int MIN_HANDLERS = 0;
     65    /** how long to wait before dropping an idle thread */
     66    private static final long HANDLER_KEEPALIVE_MS = 30*1000;
    5767
    5868    protected I2PTunnelTask task = null;
     
    6878    public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
    6979        super("Server at " + host + ':' + port, notifyThis, tunnel);
     80        _log = tunnel.getContext().logManager().getLog(getClass());
    7081        ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(privData));
    71         SetUsePool(tunnel);
    7282        init(host, port, bais, privData, l);
    7383    }
     
    8090                           EventDispatcher notifyThis, I2PTunnel tunnel) {
    8191        super("Server at " + host + ':' + port, notifyThis, tunnel);
    82         SetUsePool(tunnel);
     92        _log = tunnel.getContext().logManager().getLog(getClass());
    8393        FileInputStream fis = null;
    8494        try {
     
    100110    public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l,  EventDispatcher notifyThis, I2PTunnel tunnel) {
    101111        super("Server at " + host + ':' + port, notifyThis, tunnel);
    102         SetUsePool(tunnel);
     112        _log = tunnel.getContext().logManager().getLog(getClass());
    103113        init(host, port, privData, privkeyname, l);
    104     }
    105 
    106 
    107     private void SetUsePool(I2PTunnel Tunnel) {
    108         String usePool = Tunnel.getClientOptions().getProperty("i2ptunnel.usePool");
    109         if (usePool != null)
    110             _usePool = "true".equalsIgnoreCase(usePool);
    111         else
    112             _usePool = DEFAULT_USE_POOL;
    113114    }
    114115
     
    142143            _log.log(Log.CRIT, "Cannot read private key data for " + privkeyname, ioe);
    143144            return;
     145        }
     146
     147        // extending classes default to threaded, but for a standard server, we can't get slowlorissed
     148        _usePool = !getClass().equals(I2PTunnelServer.class);
     149        if (_usePool) {
     150            String usePool = getTunnel().getClientOptions().getProperty(PROP_USE_POOL);
     151            if (usePool != null)
     152                _usePool = "true".equalsIgnoreCase(usePool);
     153            else
     154                _usePool = DEFAULT_USE_POOL;
    144155        }
    145156
     
    200211     */
    201212    public void startRunning() {
    202         Thread t = new I2PAppThread(this);
    203         t.setName("Server " + (++__serverId));
     213        Thread t = new I2PAppThread(this, "Server " + remoteHost + ':' + remotePort, true);
    204214        t.start();
    205215    }
     
    237247                return false;
    238248            }
    239             l.log("Stopping tunnels for server at " + getTunnel().listenHost + ':' + this.remotePort);
     249            l.log("Stopping tunnels for server at " + this.remoteHost + ':' + this.remotePort);
    240250            try {
    241251                if (i2pss != null) i2pss.close();
     
    260270                if (rv <= 0)
    261271                    rv = DEFAULT_HANDLER_COUNT;
    262             } catch (NumberFormatException nfe) {
    263                 rv = DEFAULT_HANDLER_COUNT;
    264             }
     272            } catch (NumberFormatException nfe) {}
    265273        }
    266274        return rv;
    267275    }
    268276   
     277    /**
     278     *  If usePool is set, this starts the executor pool.
     279     *  Then, do the accept() loop, and either
     280     *  hands each I2P socket to the executor or runs it in-line.
     281     */
    269282    public void run() {
    270         if (shouldUsePool()) {
    271             I2PServerSocket i2pS_S = sockMgr.getServerSocket();
    272             int handlers = getHandlerCount();
    273             for (int i = 0; i < handlers; i++) {
    274                 I2PAppThread handler = new I2PAppThread(new Handler(i2pS_S), "Handle Server " + i);
    275                 handler.start();
    276             }
    277         } else {
    278             I2PServerSocket i2pS_S = sockMgr.getServerSocket();
    279             while (true) {
     283        I2PServerSocket i2pS_S = sockMgr.getServerSocket();
     284        ThreadPoolExecutor executor = null;
     285        if (_log.shouldLog(Log.WARN)) {
     286            if (_usePool)
     287                _log.warn("Starting executor with " + getHandlerCount() + " threads max");
     288            else
     289                _log.warn("Threads disabled, running blockingHandles inline");
     290        }
     291        if (_usePool) {
     292            executor = new CustomThreadPoolExecutor(getHandlerCount(), "ServerHandler pool " + remoteHost + ':' + remotePort);
     293        }
     294        while (open) {
     295            try {
     296                final I2PSocket i2ps = i2pS_S.accept();
     297                if (i2ps == null) throw new I2PException("I2PServerSocket closed");
     298                if (_usePool) {
     299                    try {
     300                        executor.execute(new Handler(i2ps));
     301                    } catch (RejectedExecutionException ree) {
     302                         try {
     303                             i2ps.close();
     304                         } catch (IOException ioe) {}
     305                         if (open && _log.shouldLog(Log.ERROR))
     306                             _log.error("ServerHandler queue full for " + remoteHost + ':' + remotePort +
     307                                        "; increase " + PROP_HANDLER_COUNT + '?', ree);
     308                    }
     309                } else {
     310                    // use only for standard servers that can't get slowlorissed! Not for http or irc
     311                    blockingHandle(i2ps);
     312                }
     313            } catch (I2PException ipe) {
     314                if (_log.shouldLog(Log.ERROR))
     315                    _log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
     316                return;
     317            } catch (ConnectException ce) {
     318                if (_log.shouldLog(Log.ERROR))
     319                    _log.error("Error accepting", ce);
     320                // not killing the server..
    280321                try {
    281                     final I2PSocket i2ps = i2pS_S.accept();
    282                     if (i2ps == null) throw new I2PException("I2PServerSocket closed");
    283                     new I2PAppThread(new Runnable() { public void run() { blockingHandle(i2ps); } }).start();
    284                 } catch (I2PException ipe) {
    285                     if (_log.shouldLog(Log.ERROR))
    286                         _log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
    287                     return;
    288                 } catch (ConnectException ce) {
    289                     if (_log.shouldLog(Log.ERROR))
    290                         _log.error("Error accepting", ce);
    291                     // not killing the server..
    292                 } catch(SocketTimeoutException ste) {
    293                     // ignored, we never set the timeout
    294                 }
    295             }
    296         }
    297     }
    298    
     322                    Thread.currentThread().sleep(500);
     323                } catch (InterruptedException ie) {}
     324            } catch(SocketTimeoutException ste) {
     325                // ignored, we never set the timeout
     326            }
     327        }
     328        if (executor != null)
     329            executor.shutdownNow();
     330    }
     331   
     332    /**
     333     * Not really needed for now but in case we want to add some hooks like afterExecute().
     334     */
     335    private static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
     336        public CustomThreadPoolExecutor(int max, String name) {
     337             super(MIN_HANDLERS, max, HANDLER_KEEPALIVE_MS, TimeUnit.MILLISECONDS,
     338                   new SynchronousQueue(), new CustomThreadFactory(name));
     339        }
     340    }
     341
     342    /** just to set the name and set Daemon */
     343    private static class CustomThreadFactory implements ThreadFactory {
     344        private String _name;
     345
     346        public CustomThreadFactory(String name) {
     347            _name = name;
     348        }
     349
     350        public Thread newThread(Runnable r) {
     351            Thread rv = Executors.defaultThreadFactory().newThread(r);
     352            rv.setName(_name);
     353            rv.setDaemon(true);
     354            return rv;
     355        }
     356    }
     357
    299358    public boolean shouldUsePool() { return _usePool; }
    300359   
    301360    /**
    302      * minor thread pool to pull off the accept() concurrently.  there are still lots
    303      * (and lots) of wasted threads within the I2PTunnelRunner, but its a start
    304      *
     361     * Run the blockingHandler.
    305362     */
    306363    private class Handler implements Runnable {
    307         private I2PServerSocket _serverSocket;
    308         public Handler(I2PServerSocket serverSocket) {
    309             _serverSocket = serverSocket;
    310         }
     364        private I2PSocket _i2ps;
     365
     366        public Handler(I2PSocket socket) {
     367            _i2ps = socket;
     368        }
     369
    311370        public void run() {
    312             while (open) {
    313                 try {
    314                     blockingHandle(_serverSocket.accept());   
    315                 } catch (I2PException ex) {
    316                     _log.error("Error while waiting for I2PConnections", ex);
    317                     return;
    318                 } catch (IOException ex) {
    319                     _log.error("Error while waiting for I2PConnections", ex);
    320                     return;
    321                 }
    322             }
     371            blockingHandle(_i2ps);   
    323372        }
    324373    }
     
    336385            afterSocket = I2PAppContext.getGlobalContext().clock().now();
    337386            new I2PTunnelRunner(s, socket, slock, null, null);
     387
     388            long afterHandle = I2PAppContext.getGlobalContext().clock().now();
     389            long timeToHandle = afterHandle - afterAccept;
     390            if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
     391                _log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
     392                          " [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
    338393        } catch (SocketException ex) {
    339394            try {
    340395                socket.close();
    341             } catch (IOException ioe) {
    342                 _log.error("Error while closing the received i2p con", ex);
    343             }
     396            } catch (IOException ioe) {}
     397            if (_log.shouldLog(Log.ERROR))
     398                _log.error("Error connecting to server " + remoteHost + ':' + remotePort, ex);
    344399        } catch (IOException ex) {
    345400            _log.error("Error while waiting for I2PConnections", ex);
    346401        }
    347 
    348         long afterHandle = I2PAppContext.getGlobalContext().clock().now();
    349         long timeToHandle = afterHandle - afterAccept;
    350         if (timeToHandle > 1000)
    351             _log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
    352402    }
    353403}
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java

    r46b8bef rc7c7731  
    3131public class I2PSOCKSIRCTunnel extends I2PSOCKSTunnel {
    3232
    33     private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(I2PSOCKSIRCTunnel.class);
    3433    private static int __clientId = 0;
    3534
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java

    r46b8bef rc7c7731  
    2727public class I2PSOCKSTunnel extends I2PTunnelClientBase {
    2828
    29     private static final Log _log = new Log(I2PSOCKSTunnel.class);
    3029    private HashMap<String, List<String>> proxies = null;  // port# + "" or "default" -> hostname list
    3130    protected Destination outProxyDest = null;
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java

    r46b8bef rc7c7731  
    4646 public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements Source, Sink {
    4747
    48     private static final Log _log = new Log(I2PTunnelUDPClientBase.class);
    4948    protected I2PAppContext _context;
    5049    protected Logging l;
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java

    r46b8bef rc7c7731  
    4747public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sink {
    4848
    49     private final static Log _log = new Log(I2PTunnelUDPServerBase.class);
     49    private final Log _log;
    5050
    5151    private final Object lock = new Object();
     
    7474                           EventDispatcher notifyThis, I2PTunnel tunnel) {
    7575        super("UDPServer <- " + privkeyname, notifyThis, tunnel);
     76        _log = tunnel.getContext().logManager().getLog(I2PTunnelUDPServerBase.class);
    7677        FileInputStream fis = null;
    7778        try {
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java

    r46b8bef rc7c7731  
    1919import net.i2p.data.Signature;
    2020import net.i2p.data.SigningPrivateKey;
     21import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
    2122import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
    2223import net.i2p.i2ptunnel.TunnelController;
     
    172173    }
    173174   
    174     public boolean getAccess(int tunnel) {
    175         return getBooleanProperty(tunnel, "i2cp.enableAccessList");
     175    public String getAccessMode(int tunnel) {
     176        if (getBooleanProperty(tunnel, PROP_ENABLE_ACCESS_LIST))
     177            return "1";
     178        if (getBooleanProperty(tunnel, PROP_ENABLE_BLACKLIST))
     179            return "2";
     180        return "0";
    176181    }
    177182   
    178183    public String getAccessList(int tunnel) {
    179184        return getProperty(tunnel, "i2cp.accessList", "").replace(",", "\n");
     185    }
     186   
     187    public String getJumpList(int tunnel) {
     188        return getProperty(tunnel, I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
     189                           I2PTunnelHTTPClient.DEFAULT_JUMP_SERVERS).replace(",", "\n");
    180190    }
    181191   
     
    235245    }
    236246   
     247    /** all of these are @since 0.8.3 */
     248    public String getLimitMinute(int tunnel) {
     249        return getProperty(tunnel, PROP_MAX_CONNS_MIN, "0");
     250    }
     251
     252    public String getLimitHour(int tunnel) {
     253        return getProperty(tunnel, PROP_MAX_CONNS_HOUR, "0");
     254    }
     255
     256    public String getLimitDay(int tunnel) {
     257        return getProperty(tunnel, PROP_MAX_CONNS_DAY, "0");
     258    }
     259
     260    public String getTotalMinute(int tunnel) {
     261        return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_MIN, "0");
     262    }
     263
     264    public String getTotalHour(int tunnel) {
     265        return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_HOUR, "0");
     266    }
     267
     268    public String getTotalDay(int tunnel) {
     269        return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_DAY, "0");
     270    }
     271
     272    public String getMaxStreams(int tunnel) {
     273        return getProperty(tunnel, PROP_MAX_STREAMS, "0");
     274    }
     275
    237276    private int getProperty(int tunnel, String prop, int def) {
    238277        TunnelController tun = getController(tunnel);
     
    271310    }
    272311   
     312    /** @since 0.8.3 */
     313    public boolean isRouterContext() {
     314        return _context.isRouterContext();
     315    }
     316
    273317    public String getI2CPHost(int tunnel) {
     318        if (_context.isRouterContext())
     319            return _("internal");
    274320        TunnelController tun = getController(tunnel);
    275321        if (tun != null)
     
    280326   
    281327    public String getI2CPPort(int tunnel) {
     328        if (_context.isRouterContext())
     329            return _("internal");
    282330        TunnelController tun = getController(tunnel);
    283331        if (tun != null)
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java

    r46b8bef rc7c7731  
    2525import net.i2p.data.PrivateKeyFile;
    2626import net.i2p.data.SessionKey;
     27import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
    2728import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
    2829import net.i2p.i2ptunnel.TunnelController;
     
    538539        _description = (description != null ? description.trim() : null);
    539540    }
    540     /** I2CP host the router is on */
     541    /** I2CP host the router is on, ignored when in router context */
    541542    public void setClientHost(String host) {
    542543        _i2cpHost = (host != null ? host.trim() : null);
    543544    }
    544     /** I2CP port the router is on */
     545    /** I2CP port the router is on, ignored when in router context */
    545546    public void setClientport(String port) {
    546547        _i2cpPort = (port != null ? port.trim() : null);
     
    644645        _booleanOptions.add("i2cp.encryptLeaseSet");
    645646    }
    646     public void setAccess(String moo) {
    647         _booleanOptions.add("i2cp.enableAccessList");
    648     }
     647
     648    protected static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList";
     649    protected static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList";
     650
     651    public void setAccessMode(String val) {
     652        if ("1".equals(val))
     653            _booleanOptions.add(PROP_ENABLE_ACCESS_LIST);
     654        else if ("2".equals(val))
     655            _booleanOptions.add(PROP_ENABLE_BLACKLIST);
     656    }
     657
    649658    public void setDelayOpen(String moo) {
    650659        _booleanOptions.add("i2cp.delayOpen");
     
    672681            _otherOptions.put("i2cp.leaseSetKey", val.trim());
    673682    }
     683
    674684    public void setAccessList(String val) {
    675685        if (val != null)
    676686            _otherOptions.put("i2cp.accessList", val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
    677687    }
     688
     689    public void setJumpList(String val) {
     690        if (val != null)
     691            _otherOptions.put(I2PTunnelHTTPClient.PROP_JUMP_SERVERS, val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
     692    }
     693
    678694    public void setCloseTime(String val) {
    679695        if (val != null) {
     
    713729    }
    714730   
     731    /** all of these are @since 0.8.3 */
     732    protected static final String PROP_MAX_CONNS_MIN = "i2p.streaming.maxConnsPerMinute";
     733    protected static final String PROP_MAX_CONNS_HOUR = "i2p.streaming.maxConnsPerHour";
     734    protected static final String PROP_MAX_CONNS_DAY = "i2p.streaming.maxConnsPerDay";
     735    protected static final String PROP_MAX_TOTAL_CONNS_MIN = "i2p.streaming.maxTotalConnsPerMinute";
     736    protected static final String PROP_MAX_TOTAL_CONNS_HOUR = "i2p.streaming.maxTotalConnsPerHour";
     737    protected static final String PROP_MAX_TOTAL_CONNS_DAY = "i2p.streaming.maxTotalConnsPerDay";
     738    protected static final String PROP_MAX_STREAMS = "i2p.streaming.maxConcurrentStreams";
     739
     740    public void setLimitMinute(String s) {
     741        if (s != null)
     742            _otherOptions.put(PROP_MAX_CONNS_MIN, s.trim());
     743    }
     744
     745    public void setLimitHour(String s) {
     746        if (s != null)
     747            _otherOptions.put(PROP_MAX_CONNS_HOUR, s.trim());
     748    }
     749
     750    public void setLimitDay(String s) {
     751        if (s != null)
     752            _otherOptions.put(PROP_MAX_CONNS_DAY, s.trim());
     753    }
     754
     755    public void setTotalMinute(String s) {
     756        if (s != null)
     757            _otherOptions.put(PROP_MAX_TOTAL_CONNS_MIN, s.trim());
     758    }
     759
     760    public void setTotalHour(String s) {
     761        if (s != null)
     762            _otherOptions.put(PROP_MAX_TOTAL_CONNS_HOUR, s.trim());
     763    }
     764
     765    public void setTotalDay(String s) {
     766        if (s != null)
     767            _otherOptions.put(PROP_MAX_TOTAL_CONNS_DAY, s.trim());
     768    }
     769
     770    public void setMaxStreams(String s) {
     771        if (s != null)
     772            _otherOptions.put(PROP_MAX_STREAMS, s.trim());
     773    }
     774
    715775    /** params needed for hashcash and dest modification */
    716776    public void setEffort(String val) {
     
    905965        };
    906966    private static final String _booleanServerOpts[] = {
    907         "i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", "i2cp.enableAccessList"
     967        "i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST
    908968        };
    909969    private static final String _otherClientOpts[] = {
    910970        "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
    911         "proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword"
     971        "proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword",
     972        I2PTunnelHTTPClient.PROP_JUMP_SERVERS
    912973        };
    913974    private static final String _otherServerOpts[] = {
    914         "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList"
     975        "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
     976         PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
     977         PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
     978         PROP_MAX_STREAMS
    915979        };
    916     protected static final Set _noShowSet = new HashSet();
     980    protected static final Set _noShowSet = new HashSet(64);
    917981    static {
    918982        _noShowSet.addAll(Arrays.asList(_noShowOpts));
     
    930994        if (_description != null)
    931995            config.setProperty("description", _description);
    932         if (_i2cpHost != null)
    933             config.setProperty("i2cpHost", _i2cpHost);
    934         if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) ) {
    935             config.setProperty("i2cpPort", _i2cpPort);
    936         } else {
    937             config.setProperty("i2cpPort", "7654");
     996        if (!_context.isRouterContext()) {
     997            if (_i2cpHost != null)
     998                config.setProperty("i2cpHost", _i2cpHost);
     999            if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) ) {
     1000                config.setProperty("i2cpPort", _i2cpPort);
     1001            } else {
     1002                config.setProperty("i2cpPort", "7654");
     1003            }
    9381004        }
    9391005        if (_privKeyFile != null)
     
    10211087    }
    10221088
    1023     private String _(String key) {
     1089    protected String _(String key) {
    10241090        return Messages._(key, _context);
    10251091    }
  • apps/i2ptunnel/jsp/editClient.jsp

    r46b8bef rc7c7731  
    287287
    288288            <div id="optionsField" class="rowItem">
    289                 <label><%=intl._("I2CP Options")%>:</label>
     289                <label><%=intl._("Router I2CP Address")%>:</label>
    290290            </div>
    291291            <div id="optionsHostField" class="rowItem">
     
    293293                    <%=intl._("Host")%>(<span class="accessKey">o</span>):
    294294                </label>
    295                 <input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" />               
     295                <input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" <% if (editBean.isRouterContext()) { %> readonly="readonly" <% } %> />               
    296296            </div>
    297297            <div id="optionsPortField" class="rowItem">
     
    299299                    <%=intl._("Port")%>(<span class="accessKey">r</span>):
    300300                </label>
    301                 <input type="text" id="port" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" />               
     301                <input type="text" id="clientPort" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" <% if (editBean.isRouterContext()) { %> readonly="readonly" <% } %> />               
    302302            </div>
    303303                 
     
    465465            </div>
    466466         <% } // httpclient || connect || socks || socksirc %>
     467
     468         <% if ("httpclient".equals(tunnelType)) { %>
     469            <div id="optionsField" class="rowItem">
     470                <label><%=intl._("Jump URL List")%>:</label>
     471            </div>
     472            <div id="hostField" class="rowItem">
     473                <textarea rows="2" style="height: 8em;" cols="60" id="hostField" name="jumpList" title="List of helper URLs to offer when a host is not found in your addressbook" wrap="off"><%=editBean.getJumpList(curTunnel)%></textarea>               
     474            </div>
     475            <div class="subdivider">
     476                <hr />
     477            </div>
     478         <% } // httpclient %>
    467479
    468480            <div id="customOptionsField" class="rowItem">
  • apps/i2ptunnel/jsp/editServer.jsp

    r46b8bef rc7c7731  
    306306
    307307            <div id="optionsField" class="rowItem">
    308                 <label><%=intl._("I2CP Options")%>:</label>
     308                <label><%=intl._("Router I2CP Address")%>:</label>
    309309            </div>
    310310            <div id="optionsHostField" class="rowItem">
     
    312312                    <%=intl._("Host")%>(<span class="accessKey">o</span>):
    313313                </label>
    314                 <input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" />               
     314                <input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" <% if (editBean.isRouterContext()) { %> readonly="readonly" <% } %> />               
    315315            </div>
    316316            <div id="optionsPortField" class="rowItem">
     
    318318                    <%=intl._("Port")%>(<span class="accessKey">r</span>):
    319319                </label>
    320                 <input type="text" id="clientPort" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" />               
     320                <input type="text" id="clientPort" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" <% if (editBean.isRouterContext()) { %> readonly="readonly" <% } %> />               
    321321            </div>
    322322           
     
    334334                    <%=intl._("Enable")%>:
    335335                </label>
    336                 <input value="1" type="checkbox" id="startOnLoad" name="encrypt" title="Encrypt LeaseSet"<%=(editBean.getEncrypt(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />               
     336                <input value="1" type="checkbox" id="startOnLoad" name="encrypt" title="ONLY clients with the encryption key will be able to connect"<%=(editBean.getEncrypt(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />               
    337337            </div>
    338338            <div id="portField" class="rowItem">
     
    360360            </div>
    361361            <div id="portField" class="rowItem">
    362                 <label for="access" accesskey="s">
    363                     <%=intl._("Enable")%>:
    364                 </label>
    365                 <input value="1" type="checkbox" id="startOnLoad" name="access" title="Enable Access List"<%=(editBean.getAccess(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />               
     362                <label><%=intl._("Disable")%></label>
     363                <input value="0" type="radio" id="startOnLoad" name="accessMode" title="Allow all clients"<%=(editBean.getAccessMode(curTunnel).equals("0") ? " checked=\"checked\"" : "")%> class="tickbox" />               
     364                <label><%=intl._("Whitelist")%></label>
     365                <input value="1" type="radio" id="startOnLoad" name="accessMode" title="Allow listed clients only"<%=(editBean.getAccessMode(curTunnel).equals("1") ? " checked=\"checked\"" : "")%> class="tickbox" />               
     366                <label><%=intl._("Blacklist")%></label>
     367                <input value="2" type="radio" id="startOnLoad" name="accessMode" title="Reject listed clients"<%=(editBean.getAccessMode(curTunnel).equals("2") ? " checked=\"checked\"" : "")%> class="tickbox" />               
    366368            </div>
    367369            <div id="hostField" class="rowItem">
     
    369371                    <%=intl._("Access List")%>:
    370372                </label>
    371                 <textarea rows="2" style="height: 4em;" cols="60" id="hostField" name="accessList" title="Access List" wrap="off"><%=editBean.getAccessList(curTunnel)%></textarea>               
    372                 <span class="comment"><%=intl._("(Restrict to these clients only)")%></span>
     373                <textarea rows="2" style="height: 8em;" cols="60" id="hostField" name="accessList" title="Access List" wrap="off"><%=editBean.getAccessList(curTunnel)%></textarea>               
    373374            </div>
    374375                 
     376            <div class="subdivider">
     377                <hr />
     378            </div>
     379
     380            <div class="rowItem">
     381              <div id="optionsField" class="rowItem">
     382                  <label><%=intl._("Inbound connection limits (0 to disable)")%><br><%=intl._("Per client")%>:</label>
     383              </div>
     384              <div id="portField" class="rowItem">
     385                  <label><%=intl._("Per minute")%>:</label>
     386                  <input type="text" id="port" name="limitMinute" value="<%=editBean.getLimitMinute(curTunnel)%>" class="freetext" />               
     387              </div>
     388              <div id="portField" class="rowItem">
     389                  <label><%=intl._("Per hour")%>:</label>
     390                  <input type="text" id="port" name="limitHour" value="<%=editBean.getLimitHour(curTunnel)%>" class="freetext" />               
     391              </div>
     392              <div id="portField" class="rowItem">
     393                  <label><%=intl._("Per day")%>:</label>
     394                  <input type="text" id="port" name="limitDay" value="<%=editBean.getLimitDay(curTunnel)%>" class="freetext" />               
     395              </div>
     396            </div>
     397            <div class="rowItem">
     398              <div id="optionsField" class="rowItem">
     399                  <label><%=intl._("Total")%>:</label>
     400              </div>
     401              <div id="portField" class="rowItem">
     402                  <input type="text" id="port" name="totalMinute" value="<%=editBean.getTotalMinute(curTunnel)%>" class="freetext" />               
     403              </div>
     404              <div id="portField" class="rowItem">
     405                  <input type="text" id="port" name="totalHour" value="<%=editBean.getTotalHour(curTunnel)%>" class="freetext" />               
     406              </div>
     407              <div id="portField" class="rowItem">
     408                  <input type="text" id="port" name="totalDay" value="<%=editBean.getTotalDay(curTunnel)%>" class="freetext" />               
     409              </div>
     410            </div>
     411            <div class="rowItem">
     412              <div id="optionsField" class="rowItem">
     413                  <label><%=intl._("Max concurrent connections (0 to disable)")%>:</label>
     414              </div>
     415              <div id="portField" class="rowItem">
     416                  <input type="text" id="port" name="maxStreams" value="<%=editBean.getMaxStreams(curTunnel)%>" class="freetext" />               
     417              </div>
     418            </div>
     419
    375420            <div class="subdivider">
    376421                <hr />
  • apps/ministreaming/java/src/net/i2p/client/streaming/I2PServerSocket.java

    r46b8bef rc7c7731  
    2020     * Waits for the next socket connecting.  If a remote user tried to make a
    2121     * connection and the local application wasn't .accept()ing new connections,
    22      * they should get refused (if .accept() doesnt occur in some small period)
     22     * they should get refused (if .accept() doesnt occur in some small period).
     23     * Warning - unlike regular ServerSocket, may return null.
    2324     *
    24      * @return a connected I2PSocket
     25     * @return a connected I2PSocket OR NULL
    2526     *
    2627     * @throws I2PException if there is a problem with reading a new socket
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java

    r46b8bef rc7c7731  
    44import net.i2p.crypto.TrustedUpdate;
    55import net.i2p.data.DataHelper;
     6import net.i2p.util.FileUtil;
    67
    78/**
     
    6263    public static final String DEFAULT_UPDATE_URL;
    6364    static {
    64         String foo;
    65         try {
    66             Class.forName("java.util.jar.Pack200", false, ClassLoader.getSystemClassLoader());
    67             foo = PACK200_URLS;
    68         } catch (ClassNotFoundException cnfe) {
    69             foo = NO_PACK200_URLS;
    70         }
    71         DEFAULT_UPDATE_URL = foo;
     65        if (FileUtil.isPack200Supported())
     66            DEFAULT_UPDATE_URL = PACK200_URLS;
     67        else
     68            DEFAULT_UPDATE_URL = NO_PACK200_URLS;
    7269    }
    7370
  • apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java

    r46b8bef rc7c7731  
    6060    }
    6161    public void setRefreshDelay(String str) {
    62         try { _refreshDelaySeconds = Math.max(Integer.parseInt(str), MIN_REFRESH); } catch (NumberFormatException nfe) {}
     62        try {
     63            int rds = Integer.parseInt(str);
     64            if (rds > 0)
     65                _refreshDelaySeconds = Math.max(rds, MIN_REFRESH);
     66            else
     67                _refreshDelaySeconds = -1;
     68        } catch (NumberFormatException nfe) {}
    6369    }
    6470   
     
    8490                           + "&amp;width=" + (3 * _width)
    8591                           + "&amp;height=" + (3 * _height)
    86                            + "\" / target=\"_blank\">");
     92                           + "\" target=\"_blank\">");
    8793                String title = _("Combined bandwidth graph");
    8894                _out.write("<img class=\"statimage\" width=\""
     
    130136    }
    131137
     138    private static final int[] times = { 60, 2*60, 5*60, 10*60, 30*60, 60*60, -1 };
     139
    132140    public String getForm() {
    133141        String prev = System.getProperty("net.i2p.router.web.GraphHelper.nonce");
     
    146154                       + "\"> " + _("pixels") + ", " + _("height") + ": <input size=\"4\" type=\"text\" name=\"height\" value=\"" + _height 
    147155                       + "\"> " + _("pixels") + "<br>\n");
    148             _out.write(_("Refresh delay") + ": <select name=\"refreshDelay\"><option value=\"60\">1 " + _("minute") + "</option><option value=\"120\">2 " + _("minutes") + "</option><option value=\"300\">5 " + _("minutes") + "</option><option value=\"600\">10 " + _("minutes") + "</option><option value=\"1800\">30 " + _("minutes") + "</option><option value=\"3600\">1 " + _("hour") + "</option><option value=\"-1\">" + _("Never") + "</option></select><br>\n");
    149             _out.write("<hr><div class=\"formaction\"><input type=\"submit\" value=\"" + _("Redraw") + "\"></div></form>");
     156            _out.write(_("Refresh delay") + ": <select name=\"refreshDelay\">");
     157            for (int i = 0; i < times.length; i++) {
     158                _out.write("<option value=\"");
     159                _out.write(Integer.toString(times[i]));
     160                _out.write("\"");
     161                if (times[i] == _refreshDelaySeconds)
     162                    _out.write(" selected=\"true\"");
     163                _out.write(">");
     164                if (times[i] > 0)
     165                    _out.write(DataHelper.formatDuration2(times[i] * 1000));
     166                else
     167                    _out.write(_("Never"));
     168                _out.write("</option>\n");
     169            }
     170            _out.write("</select><br>\n" +
     171                       "<hr><div class=\"formaction\"><input type=\"submit\" value=\"" + _("Redraw") + "\"></div></form>");
    150172        } catch (IOException ioe) {
    151173            ioe.printStackTrace();
  • apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java

    r46b8bef rc7c7731  
    5454            pathInContext = "/index.jsp";
    5555        } else if (pathInContext.indexOf("/", 1) < 0 &&
    56                    !pathInContext.endsWith(".jsp")) {
     56                   (!pathInContext.endsWith(".jsp")) &&
     57                   (!pathInContext.endsWith(".txt"))) {
    5758            // add .jsp to pages at top level
    5859            pathInContext += ".jsp";
  • apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java

    r46b8bef rc7c7731  
    55import java.io.FilenameFilter;
    66import java.io.IOException;
     7import java.security.KeyStore;
    78import java.util.List;
    89import java.util.Properties;
     
    1112import net.i2p.I2PAppContext;
    1213import net.i2p.apps.systray.SysTray;
     14import net.i2p.data.Base32;
    1315import net.i2p.data.DataHelper;
    1416import net.i2p.router.RouterContext;
     
    1618import net.i2p.util.I2PAppThread;
    1719import net.i2p.util.SecureDirectory;
     20import net.i2p.util.SecureFileOutputStream;
     21import net.i2p.util.ShellCommand;
    1822
    1923import org.mortbay.http.DigestAuthenticator;
    2024import org.mortbay.http.HashUserRealm;
    2125import org.mortbay.http.SecurityConstraint;
     26import org.mortbay.http.SslListener;
    2227import org.mortbay.http.handler.SecurityHandler;
    2328import org.mortbay.jetty.Server;
    2429import org.mortbay.jetty.servlet.WebApplicationContext;
    2530import org.mortbay.jetty.servlet.WebApplicationHandler;
     31import org.mortbay.util.InetAddrPort;
    2632
    2733public class RouterConsoleRunner {
    2834    private Server _server;
    29     private String _listenPort = "7657";
    30     private String _listenHost = "127.0.0.1";
    31     private String _webAppsDir = "./webapps/";
     35    private String _listenPort;
     36    private String _listenHost;
     37    private String _sslListenPort;
     38    private String _sslListenHost;
     39    private String _webAppsDir;
    3240    private static final String PROP_WEBAPP_CONFIG_FILENAME = "router.webappsConfigFile";
    3341    private static final String DEFAULT_WEBAPP_CONFIG_FILENAME = "webapps.config";
     
    3644    public static final String PREFIX = "webapps.";
    3745    public static final String ENABLED = ".startOnLoad";
     46    private static final String PROP_KEYSTORE_PASSWORD = "routerconsole.keystorePassword";
     47    private static final String DEFAULT_KEYSTORE_PASSWORD = "changeit";
     48    private static final String PROP_KEY_PASSWORD = "routerconsole.keyPassword";
     49    private static final String DEFAULT_LISTEN_PORT = "7657";
     50    private static final String DEFAULT_LISTEN_HOST = "127.0.0.1";
     51    private static final String DEFAULT_WEBAPPS_DIR = "./webapps/";
     52    private static final String USAGE = "Bad RouterConsoleRunner arguments, check clientApp.0.args in your clients.config file! " +
     53                                        "Usage: [[port host[,host]] [-s sslPort [host[,host]]] [webAppsDir]]";
    3854   
    3955    static {
     
    4359   
    4460    /**
     61     *  <pre>
     62     *  non-SSL:
     63     *  RouterConsoleRunner
     64     *  RouterConsoleRunner 7657
     65     *  RouterConsoleRunner 7657 127.0.0.1
     66     *  RouterConsoleRunner 7657 127.0.0.1,::1
     67     *  RouterConsoleRunner 7657 127.0.0.1,::1 ./webapps/
     68     *
     69     *  SSL:
     70     *  RouterConsoleRunner -s 7657
     71     *  RouterConsoleRunner -s 7657 127.0.0.1
     72     *  RouterConsoleRunner -s 7657 127.0.0.1,::1
     73     *  RouterConsoleRunner -s 7657 127.0.0.1,::1 ./webapps/
     74     *
     75     *  If using both, non-SSL must be first:
     76     *  RouterConsoleRunner 7657 127.0.0.1 -s 7667
     77     *  RouterConsoleRunner 7657 127.0.0.1 -s 7667 127.0.0.1
     78     *  RouterConsoleRunner 7657 127.0.0.1,::1 -s 7667 127.0.0.1,::1
     79     *  RouterConsoleRunner 7657 127.0.0.1,::1 -s 7667 127.0.0.1,::1 ./webapps/
     80     *  </pre>
     81     *
    4582     *  @param args second arg may be a comma-separated list of bind addresses,
    4683     *              for example ::1,127.0.0.1
     
    5188     */
    5289    public RouterConsoleRunner(String args[]) {
    53         if (args.length == 3) {
    54             _listenPort = args[0].trim();
    55             _listenHost = args[1].trim();
    56             _webAppsDir = args[2].trim();
     90        if (args.length == 0) {
     91            // _listenHost and _webAppsDir are defaulted below
     92            _listenPort = DEFAULT_LISTEN_PORT;
     93        } else {
     94            boolean ssl = false;
     95            for (int i = 0; i < args.length; i++) {
     96                if (args[i].equals("-s"))
     97                    ssl = true;
     98                else if ((!ssl) && _listenPort == null)
     99                    _listenPort = args[i];
     100                else if ((!ssl) && _listenHost == null)
     101                    _listenHost = args[i];
     102                else if (ssl && _sslListenPort == null)
     103                    _sslListenPort = args[i];
     104                else if (ssl && _sslListenHost == null)
     105                    _sslListenHost = args[i];
     106                else if (_webAppsDir == null)
     107                    _webAppsDir = args[i];
     108                else {
     109                    System.err.println(USAGE);
     110                    throw new IllegalArgumentException(USAGE);
     111                }
     112            }
     113        }
     114        if (_listenHost == null)
     115           _listenHost = DEFAULT_LISTEN_HOST;
     116        if (_sslListenHost == null)
     117           _sslListenHost = _listenHost;
     118        if (_webAppsDir == null)
     119           _webAppsDir = DEFAULT_WEBAPPS_DIR;
     120        // _listenPort and _sslListenPort are not defaulted, if one or the other is null, do not enable
     121        if (_listenPort == null && _sslListenPort == null) {
     122            System.err.println(USAGE);
     123            throw new IllegalArgumentException(USAGE);
    57124        }
    58125    }
     
    97164        WebApplicationHandler baseHandler = null;
    98165        try {
    99             StringTokenizer tok = new StringTokenizer(_listenHost, " ,");
    100166            int boundAddresses = 0;
    101             while (tok.hasMoreTokens()) {
    102                 String host = tok.nextToken().trim();
     167
     168            // add standard listeners
     169            if (_listenPort != null) {
     170                StringTokenizer tok = new StringTokenizer(_listenHost, " ,");
     171                while (tok.hasMoreTokens()) {
     172                    String host = tok.nextToken().trim();
     173                    try {
     174                        if (host.indexOf(":") >= 0) // IPV6 - requires patched Jetty 5
     175                            _server.addListener('[' + host + "]:" + _listenPort);
     176                        else
     177                            _server.addListener(host + ':' + _listenPort);
     178                        boundAddresses++;
     179                    } catch (IOException ioe) { // this doesn't seem to work, exceptions don't happen until start() below
     180                        System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ' ' + ioe);
     181                    }
     182                }
     183            }
     184
     185            // add SSL listeners
     186            int sslPort = 0;
     187            if (_sslListenPort != null) {
    103188                try {
    104                     if (host.indexOf(":") >= 0) // IPV6 - requires patched Jetty 5
    105                         _server.addListener('[' + host + "]:" + _listenPort);
    106                     else
    107                         _server.addListener(host + ':' + _listenPort);
    108                     boundAddresses++;
    109                 } catch (IOException ioe) { // this doesn't seem to work, exceptions don't happen until start() below
    110                     System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ' ' + ioe);
    111                 }
    112             }
     189                    sslPort = Integer.parseInt(_sslListenPort);
     190                } catch (NumberFormatException nfe) {}
     191                if (sslPort <= 0)
     192                    System.err.println("Bad routerconsole SSL port " + _sslListenPort);
     193            }
     194            if (sslPort > 0) {
     195                I2PAppContext ctx = I2PAppContext.getGlobalContext();
     196                File keyStore = new File(ctx.getConfigDir(), "keystore/console.ks");
     197                if (verifyKeyStore(keyStore)) {
     198                    StringTokenizer tok = new StringTokenizer(_sslListenHost, " ,");
     199                    while (tok.hasMoreTokens()) {
     200                        String host = tok.nextToken().trim();
     201                        // doing it this way means we don't have to escape an IPv6 host with []
     202                        InetAddrPort iap = new InetAddrPort(host, sslPort);
     203                        try {
     204                            SslListener ssll = new SslListener(iap);
     205                            // the keystore path and password
     206                            ssll.setKeystore(keyStore.getAbsolutePath());
     207                            ssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
     208                            // the X.509 cert password (if not present, verifyKeyStore() returned false)
     209                            ssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
     210                            _server.addListener(ssll);
     211                            boundAddresses++;
     212                        } catch (Exception e) {   // probably no exceptions at this point
     213                            System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + " for SSL: " + e);
     214                        }
     215                    }
     216                } else {
     217                    System.err.println("Unable to create or access keystore for SSL: " + keyStore.getAbsolutePath());
     218                }
     219            }
     220
    113221            if (boundAddresses <= 0) {
    114                 System.err.println("Unable to bind routerconsole to any address on port " + _listenPort);
     222                System.err.println("Unable to bind routerconsole to any address on port " + _listenPort + (sslPort > 0 ? (" or SSL port " + sslPort) : ""));
    115223                return;
    116224            }
     
    202310    }
    203311   
     312    /**
     313     * @return success if it exists and we have a password, or it was created successfully.
     314     * @since 0.8.3
     315     */
     316    private static boolean verifyKeyStore(File ks) {
     317        if (ks.exists()) {
     318            I2PAppContext ctx = I2PAppContext.getGlobalContext();
     319            boolean rv = ctx.getProperty(PROP_KEY_PASSWORD) != null;
     320            if (!rv)
     321                System.err.println("Console SSL error, must set " + PROP_KEY_PASSWORD + " in " + (new File(ctx.getConfigDir(), "router.config")).getAbsolutePath());
     322            return rv;
     323        }
     324        File dir = ks.getParentFile();
     325        if (!dir.exists()) {
     326            File sdir = new SecureDirectory(dir.getAbsolutePath());
     327            if (!sdir.mkdir())
     328                return false;
     329        }
     330        return createKeyStore(ks);
     331    }
     332
     333
     334    /**
     335     * Call out to keytool to create a new keystore with a keypair in it.
     336     * Trying to do this programatically is a nightmare, requiring either BouncyCastle
     337     * libs or using proprietary Sun libs, and it's a huge mess.
     338     *
     339     * @return success
     340     * @since 0.8.3
     341     */
     342    private static boolean createKeyStore(File ks) {
     343        I2PAppContext ctx = I2PAppContext.getGlobalContext();
     344        // make a random 48 character password (30 * 8 / 5)
     345        byte[] rand = new byte[30];
     346        ctx.random().nextBytes(rand);
     347        String keyPassword = Base32.encode(rand);
     348        // and one for the cname
     349        ctx.random().nextBytes(rand);
     350        String cname = Base32.encode(rand) + ".console.i2p.net";
     351
     352        String keytool = (new File(System.getProperty("java.home"), "bin/keytool")).getAbsolutePath();
     353        String[] args = new String[] {
     354                   keytool,
     355                   "-genkey",            // -genkeypair preferred in newer keytools, but this works with more
     356                   "-storetype", KeyStore.getDefaultType(),
     357                   "-keystore", ks.getAbsolutePath(),
     358                   "-storepass", DEFAULT_KEYSTORE_PASSWORD,
     359                   "-alias", "console",
     360                   "-dname", "CN=" + cname + ",OU=Console,O=I2P Anonymous Network,L=XX,ST=XX,C=XX",
     361                   "-validity", "3652",  // 10 years
     362                   "-keyalg", "DSA",
     363                   "-keysize", "1024",
     364                   "-keypass", keyPassword};
     365        boolean success = (new ShellCommand()).executeSilentAndWaitTimed(args, 30);  // 30 secs
     366        if (success) {
     367            success = ks.exists();
     368            if (success) {
     369                SecureFileOutputStream.setPerms(ks);
     370                try {
     371                    RouterContext rctx = (RouterContext) ctx;
     372                    rctx.router().setConfigSetting(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD);
     373                    rctx.router().setConfigSetting(PROP_KEY_PASSWORD, keyPassword);
     374                    rctx.router().saveConfig();
     375                } catch (Exception e) {}  // class cast exception
     376            }
     377        }
     378        if (success) {
     379            System.err.println("Created self-signed certificate for " + cname + " in keystore: " + ks.getAbsolutePath() + "\n" +
     380                               "The certificate name was generated randomly, and is not associated with your " +
     381                               "IP address, host name, router identity, or destination keys.");
     382        } else {
     383            System.err.println("Failed to create console SSL keystore using command line:");
     384            StringBuilder buf = new StringBuilder(256);
     385            for (int i = 0;  i < args.length; i++) {
     386                buf.append('"').append(args[i]).append("\" ");
     387            }
     388            System.err.println(buf.toString());
     389            System.err.println("This is for the Sun/Oracle keytool, others may be incompatible.\n" +
     390                               "If you create the keystore manually, you must add " + PROP_KEYSTORE_PASSWORD + " and " + PROP_KEY_PASSWORD +
     391                               " to " + (new File(ctx.getConfigDir(), "router.config")).getAbsolutePath());
     392        }
     393        return success;
     394    }
     395
    204396    static void initialize(WebApplicationContext context) {
    205397        String password = getPassword();
  • apps/routerconsole/jsp/web.xml

    r46b8bef rc7c7731  
    1818    </servlet-mapping>
    1919   
     20    <servlet-mapping>
     21      <servlet-name>net.i2p.router.web.jsp.viewhistory_jsp</servlet-name>
     22      <url-pattern>/history.txt</url-pattern>
     23    </servlet-mapping>
     24   
    2025    <session-config>
    2126        <session-timeout>
  • apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java

    r46b8bef rc7c7731  
    1616   
    1717    /**
     18     * Warning, unlike regular ServerSocket, may return null
    1819     *
    19      * @return I2PSocket
     20     * @return I2PSocket OR NULL
    2021     * @throws net.i2p.I2PException
    2122     * @throws SocketTimeoutException
  • apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java

    r46b8bef rc7c7731  
    115115    /**
    116116     *
    117      * @return connected I2PSocket
     117     * @return connected I2PSocket OR NULL
    118118     * @throws net.i2p.I2PException
    119119     * @throws java.net.SocketTimeoutException
  • build.xml

    r46b8bef rc7c7731  
    77        <property name="javac.compilerargs" value="-warn:-unchecked,raw,unused,serial" />
    88    -->
    9     <!-- Add Apache Harmony's Pack200 library if you don't have java.util.jar.Pack200
    10          See core/java/src/net/i2p/util/FileUtil.java for code changes required
    11          to use this library instead of Sun's version.
    12          Or to comment it all out if you don't have either.
     9    <!-- Additional classpath. No longer required; we find pack200 classes at runtime.
     10         See core/java/src/net/i2p/util/FileUtil.java for more info.
    1311    -->
    1412    <!--
     
    240238            doctitle="I2P Javadocs for Release ${release.number} Build ${build.number}"
    241239            windowtitle="I2P Anonymous Network - Java Documentation - Version ${release.number}">
    242             <group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:freenet.support.CPUInformation:org.bouncycastle.crypto:org.bouncycastle.crypto.*:gnu.crypto.*:gnu.gettext:org.xlattice.crypto.filters:com.nettgryppa.security" />
     240            <group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.crypto:org.bouncycastle.crypto.*:gnu.crypto.*:gnu.gettext:org.xlattice.crypto.filters:com.nettgryppa.security" />
    243241            <group title="Streaming Library" packages="net.i2p.client.streaming" />
    244242            <group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:org.cybergarage.*:org.freenetproject" />
  • core/java/src/net/i2p/I2PAppContext.java

    r46b8bef rc7c7731  
    44import java.util.HashSet;
    55import java.util.Properties;
     6import java.util.Random;
    67import java.util.Set;
    78
     
    2223import net.i2p.crypto.SessionKeyManager;
    2324import net.i2p.crypto.TransientSessionKeyManager;
     25import net.i2p.data.Base64;
    2426import net.i2p.data.RoutingKeyGenerator;
     27import net.i2p.internal.InternalClientManager;
    2528import net.i2p.stat.StatManager;
    2629import net.i2p.util.Clock;
     
    364367                String d = getProperty("i2p.dir.temp", System.getProperty("java.io.tmpdir"));
    365368                // our random() probably isn't warmed up yet
    366                 String f = "i2p-" + Math.abs((new java.util.Random()).nextInt()) + ".tmp";
     369                byte[] rand = new byte[6];
     370                (new Random()).nextBytes(rand);
     371                String f = "i2p-" + Base64.encode(rand) + ".tmp";
    367372                _tmpDir = new SecureDirectory(d, f);
    368373                if (_tmpDir.exists()) {
    369                     // good or bad ?
     374                    // good or bad ? loop and try again?
    370375                } else if (_tmpDir.mkdir()) {
    371376                    _tmpDir.deleteOnExit();
     
    844849        return false;
    845850    }
     851
     852    /**
     853     *  Use this to connect to the router in the same JVM.
     854     *  @return always null in I2PAppContext, the client manager if in RouterContext
     855     *  @since 0.8.3
     856     */
     857    public InternalClientManager internalClientManager() {
     858        return null;
     859    }
    846860}
  • core/java/src/net/i2p/client/ClientWriterRunner.java

    r46b8bef rc7c7731  
    1010import net.i2p.data.i2cp.I2CPMessageImpl;
    1111import net.i2p.data.i2cp.I2CPMessageException;
     12import net.i2p.internal.PoisonI2CPMessage;
    1213import net.i2p.util.I2PAppThread;
    1314
     
    5152        _messagesToWrite.clear();
    5253        try {
    53             _messagesToWrite.put(new PoisonMessage());
     54            _messagesToWrite.put(new PoisonI2CPMessage());
    5455        } catch (InterruptedException ie) {}
    5556    }
     
    6364                continue;
    6465            }
    65             if (msg.getType() == PoisonMessage.MESSAGE_TYPE)
     66            if (msg.getType() == PoisonI2CPMessage.MESSAGE_TYPE)
    6667                break;
    6768            // only thread, we don't need synchronized
     
    8182        _messagesToWrite.clear();
    8283    }
    83 
    84     /**
    85      * End-of-stream msg used to stop the concurrent queue
    86      * See http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html
    87      *
    88      */
    89     private static class PoisonMessage extends I2CPMessageImpl {
    90         public static final int MESSAGE_TYPE = 999999;
    91         public int getType() {
    92             return MESSAGE_TYPE;
    93         }
    94         public void doReadMessage(InputStream buf, int size) throws I2CPMessageException, IOException {}
    95         public byte[] doWriteMessage() throws I2CPMessageException, IOException { return null; }
    96     }
    9784}
  • core/java/src/net/i2p/client/I2PSessionImpl.java

    r46b8bef rc7c7731  
    4040import net.i2p.data.i2cp.MessagePayloadMessage;
    4141import net.i2p.data.i2cp.SessionId;
    42 import net.i2p.util.I2PThread;
    43 import net.i2p.util.InternalSocket;
     42import net.i2p.internal.I2CPMessageQueue;
     43import net.i2p.internal.InternalClientManager;
     44import net.i2p.internal.QueuedI2CPMessageReader;
     45import net.i2p.util.I2PAppThread;
    4446import net.i2p.util.Log;
    4547import net.i2p.util.SimpleScheduler;
     
    6769    private LeaseSet _leaseSet;
    6870
    69     /** hostname of router */
     71    /** hostname of router - will be null if in RouterContext */
    7072    protected String _hostname;
    71     /** port num to router */
     73    /** port num to router - will be 0 if in RouterContext */
    7274    protected int _portNum;
    7375    /** socket for comm */
     
    8082    protected /* FIXME final FIXME */OutputStream _out;
    8183
     84    /**
     85     *  Used for internal connections to the router.
     86     *  If this is set, _socket, _writer, and _out will be null.
     87     *  @since 0.8.3
     88     */
     89    protected I2CPMessageQueue _queue;
     90
    8291    /** who we send events to */
    8392    protected I2PSessionListener _sessionListener;
     
    122131    private long _lastActivity;
    123132    private boolean _isReduced;
     133
     134    /** SSL interface (only) @since 0.8.3 */
     135    protected static final String PROP_ENABLE_SSL = "i2cp.SSL";
    124136
    125137    void dateUpdated() {
     
    173185        _options = new Properties();
    174186        _options.putAll(filter(options));
    175         _hostname = _options.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
    176         String portNum = _options.getProperty(I2PClient.PROP_TCP_PORT, LISTEN_PORT + "");
    177         try {
    178             _portNum = Integer.parseInt(portNum);
    179         } catch (NumberFormatException nfe) {
    180             if (_log.shouldLog(Log.WARN))
    181                 _log.warn(getPrefix() + "Invalid port number specified, defaulting to "
    182                           + LISTEN_PORT, nfe);
    183             _portNum = LISTEN_PORT;
    184         }
    185 
    186         // auto-add auth if required, not set in the options, and we are in the same JVM
    187         if (_context.isRouterContext() &&
     187        if (_context.isRouterContext()) {
     188            // just for logging
     189            _hostname = "[internal connection]";
     190        } else {
     191            _hostname = _options.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
     192            String portNum = _options.getProperty(I2PClient.PROP_TCP_PORT, LISTEN_PORT + "");
     193            try {
     194                _portNum = Integer.parseInt(portNum);
     195            } catch (NumberFormatException nfe) {
     196                if (_log.shouldLog(Log.WARN))
     197                    _log.warn(getPrefix() + "Invalid port number specified, defaulting to "
     198                              + LISTEN_PORT, nfe);
     199                _portNum = LISTEN_PORT;
     200            }
     201        }
     202
     203        // auto-add auth if required, not set in the options, and we are not in the same JVM
     204        if ((!_context.isRouterContext()) &&
    188205            Boolean.valueOf(_context.getProperty("i2cp.auth")).booleanValue() &&
    189206            ((!options.containsKey("i2cp.username")) || (!options.containsKey("i2cp.password")))) {
     
    273290        _closed = false;
    274291        _availabilityNotifier.stopNotifying();
    275         I2PThread notifier = new I2PThread(_availabilityNotifier);
    276         notifier.setName("Notifier " + _myDestination.calculateHash().toBase64().substring(0,4));
    277         notifier.setDaemon(true);
    278         notifier.start();
    279292       
    280293        if ( (_options != null) &&
     
    286299        long startConnect = _context.clock().now();
    287300        try {
    288             // If we are in the router JVM, connect using the interal pseudo-socket
    289             _socket = InternalSocket.getSocket(_hostname, _portNum);
    290             // _socket.setSoTimeout(1000000); // Uhmmm we could really-really use a real timeout, and handle it.
    291             _out = _socket.getOutputStream();
    292             synchronized (_out) {
    293                 _out.write(I2PClient.PROTOCOL_BYTE);
    294                 _out.flush();
    295             }
    296             _writer = new ClientWriterRunner(_out, this);
    297             InputStream in = _socket.getInputStream();
    298             _reader = new I2CPMessageReader(in, this);
     301            // If we are in the router JVM, connect using the interal queue
     302            if (_context.isRouterContext()) {
     303                // _socket, _out, and _writer remain null
     304                InternalClientManager mgr = _context.internalClientManager();
     305                if (mgr == null)
     306                    throw new I2PSessionException("Router is not ready for connections");
     307                // the following may throw an I2PSessionException
     308                _queue = mgr.connect();
     309                _reader = new QueuedI2CPMessageReader(_queue, this);
     310            } else {
     311                if (Boolean.valueOf(_options.getProperty(PROP_ENABLE_SSL)).booleanValue())
     312                    _socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
     313                else
     314                    _socket = new Socket(_hostname, _portNum);
     315                // _socket.setSoTimeout(1000000); // Uhmmm we could really-really use a real timeout, and handle it.
     316                _out = _socket.getOutputStream();
     317                synchronized (_out) {
     318                    _out.write(I2PClient.PROTOCOL_BYTE);
     319                    _out.flush();
     320                }
     321                _writer = new ClientWriterRunner(_out, this);
     322                InputStream in = _socket.getInputStream();
     323                _reader = new I2CPMessageReader(in, this);
     324            }
     325            Thread notifier = new I2PAppThread(_availabilityNotifier, "ClientNotifier " + getPrefix(), true);
     326            notifier.start();
    299327            if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "before startReading");
    300328            _reader.startReading();
     
    436464    }
    437465
     466    /**
     467     *  This notifies the client of payload messages.
     468     *  Needs work.
     469     */
    438470    protected class AvailabilityNotifier implements Runnable {
    439471        private List _pendingIds;
     
    498530   
    499531    /**
    500      * Recieve notification of some I2CP message and handle it if possible
    501      *
     532     * The I2CPMessageEventListener callback.
     533     * Recieve notification of some I2CP message and handle it if possible.
     534     * @param reader unused
    502535     */
    503536    public void messageReceived(I2CPMessageReader reader, I2CPMessage message) {
     
    516549
    517550    /**
    518      * Recieve notifiation of an error reading the I2CP stream
     551     * The I2CPMessageEventListener callback.
     552     * Recieve notifiation of an error reading the I2CP stream.
     553     * @param reader unused
    519554     * @param error non-null
    520555     */
     
    568603     */
    569604    void sendMessage(I2CPMessage message) throws I2PSessionException {
    570         if (isClosed() || _writer == null)
     605        if (isClosed())
    571606            throw new I2PSessionException("Already closed");
    572         _writer.addMessage(message);
     607        else if (_queue != null)
     608            _queue.offer(message);  // internal
     609        else if (_writer == null)
     610            throw new I2PSessionException("Already closed");
     611        else
     612            _writer.addMessage(message);
    573613    }
    574614
     
    582622        int level;
    583623        String msgpfx;
    584         if ((error instanceof EOFException) ||
    585             (error.getMessage() != null && error.getMessage().startsWith("Pipe closed"))) {
     624        if (error instanceof EOFException) {
    586625            level = Log.WARN;
    587626            msgpfx = "Router closed connection: ";
     
    632671            }
    633672        }
    634         _availabilityNotifier.stopNotifying();
     673        // SimpleSession does not initialize
     674        if (_availabilityNotifier != null)
     675            _availabilityNotifier.stopNotifying();
    635676        _closed = true;
    636677        _closing = false;
     
    649690            _reader.stopReading();
    650691            _reader = null;
     692        }
     693        if (_queue != null) {
     694            // internal
     695            _queue.close();
    651696        }
    652697        if (_writer != null) {
     
    667712
    668713    /**
    669      * Recieve notification that the I2CP connection was disconnected
     714     * The I2CPMessageEventListener callback.
     715     * Recieve notification that the I2CP connection was disconnected.
     716     * @param reader unused
    670717     */
    671718    public void disconnected(I2CPMessageReader reader) {
     
    734781        else
    735782            buf.append(getClass().getSimpleName());
    736         buf.append(" #");
    737783        if (_sessionId != null)
    738             buf.append(_sessionId.getSessionId());
    739         else
    740             buf.append("n/a");
     784            buf.append(" #").append(_sessionId.getSessionId());
    741785        buf.append("]: ");
    742786        return buf.toString();
  • core/java/src/net/i2p/client/I2PSimpleSession.java

    r46b8bef rc7c7731  
    2020import net.i2p.data.i2cp.GetBandwidthLimitsMessage;
    2121import net.i2p.data.i2cp.I2CPMessageReader;
    22 import net.i2p.util.I2PThread;
    23 import net.i2p.util.InternalSocket;
     22import net.i2p.internal.I2CPMessageQueue;
     23import net.i2p.internal.InternalClientManager;
     24import net.i2p.internal.QueuedI2CPMessageReader;
     25import net.i2p.util.I2PAppThread;
    2426
    2527/**
     
    4547     */
    4648    public I2PSimpleSession(I2PAppContext context, Properties options) throws I2PSessionException {
     49        // Warning, does not call super()
    4750        _context = context;
    4851        _log = context.logManager().getLog(I2PSimpleSession.class);
     
    5053        _closed = true;
    5154        _closing = false;
    52         _availabilityNotifier = new AvailabilityNotifier();
    5355        if (options == null)
    5456            options = System.getProperties();
     
    6668    public void connect() throws I2PSessionException {
    6769        _closed = false;
    68         _availabilityNotifier.stopNotifying();
    69         I2PThread notifier = new I2PThread(_availabilityNotifier);
    70         notifier.setName("Simple Notifier");
    71         notifier.setDaemon(true);
    72         notifier.start();
    7370       
    7471        try {
    75             // If we are in the router JVM, connect using the interal pseudo-socket
    76             _socket = InternalSocket.getSocket(_hostname, _portNum);
    77             _out = _socket.getOutputStream();
    78             synchronized (_out) {
    79                 _out.write(I2PClient.PROTOCOL_BYTE);
    80                 _out.flush();
     72            // If we are in the router JVM, connect using the interal queue
     73            if (_context.isRouterContext()) {
     74                // _socket, _out, and _writer remain null
     75                InternalClientManager mgr = _context.internalClientManager();
     76                if (mgr == null)
     77                    throw new I2PSessionException("Router is not ready for connections");
     78                // the following may throw an I2PSessionException
     79                _queue = mgr.connect();
     80                _reader = new QueuedI2CPMessageReader(_queue, this);
     81            } else {
     82                if (Boolean.valueOf(getOptions().getProperty(PROP_ENABLE_SSL)).booleanValue())
     83                    _socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
     84                else
     85                    _socket = new Socket(_hostname, _portNum);
     86                _out = _socket.getOutputStream();
     87                synchronized (_out) {
     88                    _out.write(I2PClient.PROTOCOL_BYTE);
     89                    _out.flush();
     90                }
     91                _writer = new ClientWriterRunner(_out, this);
     92                InputStream in = _socket.getInputStream();
     93                _reader = new I2CPMessageReader(in, this);
    8194            }
    82             _writer = new ClientWriterRunner(_out, this);
    83             InputStream in = _socket.getInputStream();
    84             _reader = new I2CPMessageReader(in, this);
     95            // we do not receive payload messages, so we do not need an AvailabilityNotifier
    8596            _reader.startReading();
    8697
  • core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java

    r46b8bef rc7c7731  
    2828    private final static Log _log = new Log(I2CPMessageReader.class);
    2929    private InputStream _stream;
    30     private I2CPMessageEventListener _listener;
    31     private I2CPMessageReaderRunner _reader;
    32     private Thread _readerThread;
     30    protected I2CPMessageEventListener _listener;
     31    protected I2CPMessageReaderRunner _reader;
     32    protected Thread _readerThread;
    3333   
    34     private static volatile long __readerId = 0;
     34    protected static volatile long __readerId = 0;
    3535
    3636    public I2CPMessageReader(InputStream stream, I2CPMessageEventListener lsnr) {
     
    4141        _readerThread.setDaemon(true);
    4242        _readerThread.setName("I2CP Reader " + (++__readerId));
     43    }
     44
     45    /**
     46     * For internal extension only. No stream.
     47     * @since 0.8.3
     48     */
     49    protected I2CPMessageReader(I2CPMessageEventListener lsnr) {
     50        setListener(lsnr);
    4351    }
    4452
     
    115123    }
    116124
    117     private class I2CPMessageReaderRunner implements Runnable {
    118         private volatile boolean _doRun;
    119         private volatile boolean _stayAlive;
     125    protected class I2CPMessageReaderRunner implements Runnable {
     126        protected volatile boolean _doRun;
     127        protected volatile boolean _stayAlive;
    120128
    121129        public I2CPMessageReaderRunner() {
     
    176184                    }
    177185                }
    178                 if (!_doRun) {
     186                // ??? unused
     187                if (_stayAlive && !_doRun) {
    179188                    // pause .5 secs when we're paused
    180189                    try {
  • core/java/src/net/i2p/util/FileUtil.java

    r46b8bef rc7c7731  
    1010import java.io.InputStreamReader;
    1111import java.io.OutputStream;
     12import java.lang.reflect.Constructor;
     13import java.lang.reflect.Method;
    1214import java.util.ArrayList;
    1315import java.util.Enumeration;
     
    1719import java.util.zip.ZipFile;
    1820
    19 // Pack200 import
    20 // you must also uncomment the correct line in unpack() below
    21 // For gcj, gij, etc., comment both out
     21// Pack200 now loaded dynamically in unpack() below
    2222//
    2323// For Sun, OpenJDK, IcedTea, etc, use this
    24 import java.util.jar.Pack200;
    25 
     24//import java.util.jar.Pack200;
     25//
    2626// For Apache Harmony or if you put its pack200.jar in your library directory use this
    2727//import org.apache.harmony.unpack200.Archive;
     
    232232   
    233233    /**
    234      * This won't work right if one of the two options in unpack() is commented out.
     234     * Public since 0.8.3
    235235     * @since 0.8.1
    236236     */
    237     private static boolean isPack200Supported() {
     237    public static boolean isPack200Supported() {
    238238        try {
    239239            Class.forName("java.util.jar.Pack200", false, ClassLoader.getSystemClassLoader());
     
    241241        } catch (Exception e) {}
    242242        try {
    243             Class.forName("org.apache.harmony.pack200.Archive", false, ClassLoader.getSystemClassLoader());
     243            Class.forName("org.apache.harmony.unpack200.Archive", false, ClassLoader.getSystemClassLoader());
    244244            return true;
    245245        } catch (Exception e) {}
     
    247247    }
    248248
    249     /**
     249    private static boolean _failedOracle;
     250    private static boolean _failedApache;
     251
     252    /**
     253     * Unpack using either Oracle or Apache's unpack200 library,
     254     * with the classes discovered at runtime so neither is required at compile time.
     255     *
    250256     * Caller must close streams
     257     * @throws IOException on unpack error or if neither library is available.
     258     *         Will not throw ClassNotFoundException.
     259     * @throws org.apache.harmony.pack200.Pack200Exception which is not an IOException
    251260     * @since 0.8.1
    252261     */
    253262    private static void unpack(InputStream in, JarOutputStream out) throws Exception {
    254263        // For Sun, OpenJDK, IcedTea, etc, use this
    255         Pack200.newUnpacker().unpack(in, out);
     264        //Pack200.newUnpacker().unpack(in, out);
     265        if (!_failedOracle) {
     266            try {
     267                Class p200 = Class.forName("java.util.jar.Pack200", true, ClassLoader.getSystemClassLoader());
     268                Method newUnpacker = p200.getMethod("newUnpacker", (Class[]) null);
     269                Object unpacker = newUnpacker.invoke(null,(Object[])  null);
     270                Method unpack = unpacker.getClass().getMethod("unpack", new Class[] {InputStream.class, JarOutputStream.class});
     271                // throws IOException
     272                unpack.invoke(unpacker, new Object[] {in, out});
     273                return;
     274            } catch (ClassNotFoundException e) {
     275                _failedOracle = true;
     276                //e.printStackTrace();
     277            } catch (NoSuchMethodException e) {
     278                _failedOracle = true;
     279                //e.printStackTrace();
     280            }
     281        }
    256282
    257283        // ------------------
    258284        // For Apache Harmony or if you put its pack200.jar in your library directory use this
    259285        //(new Archive(in, out)).unpack();
    260 
     286        if (!_failedApache) {
     287            try {
     288                Class p200 = Class.forName("org.apache.harmony.unpack200.Archive", true, ClassLoader.getSystemClassLoader());
     289                Constructor newUnpacker = p200.getConstructor(new Class[] {InputStream.class, JarOutputStream.class});
     290                Object unpacker = newUnpacker.newInstance(new Object[] {in, out});
     291                Method unpack = unpacker.getClass().getMethod("unpack", (Class[]) null);
     292                // throws IOException or Pack200Exception
     293                unpack.invoke(unpacker, (Object[]) null);
     294                return;
     295            } catch (ClassNotFoundException e) {
     296                _failedApache = true;
     297                //e.printStackTrace();
     298            } catch (NoSuchMethodException e) {
     299                _failedApache = true;
     300                //e.printStackTrace();
     301            }
     302        }
    261303
    262304        // ------------------
    263305        // For gcj, gij, etc., use this
    264         //throw new IOException("Pack200 not supported");
     306        throw new IOException("Unpack200 not supported");
    265307    }
    266308
     
    379421   
    380422    /**
    381      * Usage: FileUtil (delete path | copy source dest)
     423     * Usage: FileUtil (delete path | copy source dest | unzip path.zip)
    382424     *
    383425     */
    384426    public static void main(String args[]) {
    385427        if ( (args == null) || (args.length < 2) ) {
    386             testRmdir();
     428            System.err.println("Usage: delete path | copy source dest | unzip path.zip");
     429            //testRmdir();
    387430        } else if ("delete".equals(args[0])) {
    388431            boolean deleted = FileUtil.rmdir(args[1], false);
     
    408451    }
    409452   
     453  /*****
    410454    private static void testRmdir() {
    411455        File t = new File("rmdirTest/test/subdir/blah");
     
    418462            System.out.println("PASS: rmdirTest deleted");
    419463    }
     464   *****/
    420465}
  • core/java/src/net/i2p/util/I2PThread.java

    r46b8bef rc7c7731  
    6262    }
    6363
    64     private void log(int level, String msg) { log(level, msg, null); }
    65     private void log(int level, String msg, Throwable t) {
     64    private static void log(int level, String msg) { log(level, msg, null); }
     65    private static void log(int level, String msg, Throwable t) {
    6666        // we cant assume log is created
    6767        if (_log == null) _log = new Log(I2PThread.class);
     
    7373    public void run() {
    7474        _name = Thread.currentThread().getName();
    75         log(Log.DEBUG, "New thread started: " + _name, _createdBy);
     75        log(Log.INFO, "New thread started" + (isDaemon() ? " (daemon): " : ": ") + _name, _createdBy);
    7676        try {
    7777            super.run();
    7878        } catch (Throwable t) {
    7979            try {
    80                 log(Log.CRIT, "Killing thread " + getName(), t);
     80                log(Log.CRIT, "Thread terminated unexpectedly: " + getName(), t);
    8181            } catch (Throwable woof) {
    8282                System.err.println("Died within the OOM itself");
     
    8686                fireOOM((OutOfMemoryError)t);
    8787        }
    88         log(Log.DEBUG, "Thread finished gracefully: " + _name);
     88        log(Log.INFO, "Thread finished normally: " + _name);
    8989    }
    9090   
    9191    @Override
    9292    protected void finalize() throws Throwable {
    93         log(Log.DEBUG, "Thread finalized: " + _name);
     93        //log(Log.DEBUG, "Thread finalized: " + _name);
    9494        super.finalize();
    9595    }
  • core/java/src/net/i2p/util/ShellCommand.java

    r46b8bef rc7c7731  
    5252    private class CommandThread extends Thread {
    5353
    54         final Object  caller;
    55         boolean consumeOutput;
    56         String  shellCommand;
    57 
    58         CommandThread(Object caller, String shellCommand, boolean consumeOutput) {
     54        private final Object  caller;
     55        private final boolean consumeOutput;
     56        private final Object shellCommand;
     57
     58        /**
     59         *  @param shellCommand either a String or a String[] (since 0.8.3)
     60         */
     61        CommandThread(Object caller, Object shellCommand, boolean consumeOutput) {
    5962            super("CommandThread");
    6063            this.caller = caller;
    6164            this.shellCommand = shellCommand;
    6265            this.consumeOutput = consumeOutput;
    63             _commandSuccessful = false;
    64             _commandCompleted = false;
    6566        }
    6667
     
    201202     * <code>STDIN</code> of the shell process via {@link #getInputStream()}.
    202203     *
     204     * Warning, no good way to quote or escape spaces in arguments with this method.
     205     * @deprecated unused
     206     *
    203207     * @param shellCommand The command for the shell to execute.
    204208     */
     
    216220     * {@link #getInputStream()}.
    217221     *
     222     * Warning, no good way to quote or escape spaces in arguments with this method.
     223     * @deprecated unused
     224     *
    218225     * @param  shellCommand The command for the shell to execute.
    219226     * @return              <code>true</code> if the spawned shell process
     
    237244     * {@link #getErrorStream()}, respectively. Input can be passed to the
    238245     * <code>STDIN</code> of the shell process via {@link #getInputStream()}.
     246     *
     247     * Warning, no good way to quote or escape spaces in arguments with this method.
     248     * @deprecated unused
    239249     *
    240250     * @param  shellCommand The command for the shell to execute.
     
    277287     * command will not be displayed.
    278288     *
     289     * Warning, no good way to quote or escape spaces in arguments with this method.
     290     * @deprecated unused
     291     *
    279292     * @param  shellCommand The command for the shell to execute.
    280293     * @throws IOException
     
    288301     * all of the command's resulting shell processes have completed. Any output
    289302     * produced by the executed command will not be displayed.
     303     *
     304     * Warning, no good way to quote or escape spaces in arguments with this method.
    290305     *
    291306     * @param  shellCommand The command for the shell to execute.
     
    308323     * executed command will not be displayed.
    309324     *
    310      * @param  shellCommand The command for the shell to execute.
     325     * Warning, no good way to quote or escape spaces in arguments when shellCommand is a String.
     326     * Use a String array for best results, especially on Windows.
     327     *
     328     * @param  shellCommand The command for the shell to execute, as a String.
     329     *                      You can't quote arguments successfully.
     330     *                      See Runtime.exec(String) for more info.
    311331     * @param  seconds      The method will return <code>true</code> if this
    312332     *                      number of seconds elapses without the process
     
    318338     */
    319339    public synchronized boolean executeSilentAndWaitTimed(String shellCommand, int seconds) {
    320 
     340        return executeSAWT(shellCommand, seconds);
     341    }
     342
     343    /**
     344     * Passes a command to the shell for execution. This method blocks until
     345     * all of the command's resulting shell processes have completed unless a
     346     * specified number of seconds has elapsed first. Any output produced by the
     347     * executed command will not be displayed.
     348     *
     349     * @param  commandArray The command for the shell to execute,
     350     *                      as a String[].
     351     *                      See Runtime.exec(String[]) for more info.
     352     * @param  seconds      The method will return <code>true</code> if this
     353     *                      number of seconds elapses without the process
     354     *                      returning an exit status. A value of <code>0</code>
     355     *                      here disables waiting.
     356     * @return              <code>true</code> if the spawned shell process
     357     *                      returns an exit status of 0 (indicating success),
     358     *                      else <code>false</code>.
     359     * @since 0.8.3
     360     */
     361    public synchronized boolean executeSilentAndWaitTimed(String[] commandArray, int seconds) {
     362        return executeSAWT(commandArray, seconds);
     363    }
     364
     365    /** @since 0.8.3 */
     366    private boolean executeSAWT(Object shellCommand, int seconds) {
    321367        _commandThread = new CommandThread(this, shellCommand, CONSUME_OUTPUT);
    322368        _commandThread.start();
     
    365411    }
    366412   
    367     private boolean execute(String shellCommand, boolean consumeOutput, boolean waitForExitStatus) {
     413    /**
     414     *  @param shellCommand either a String or a String[] (since 0.8.3) - quick hack
     415     */
     416    private boolean execute(Object shellCommand, boolean consumeOutput, boolean waitForExitStatus) {
    368417
    369418        StreamConsumer processStderrConsumer;
     
    375424
    376425        try {
    377             _process = Runtime.getRuntime().exec(shellCommand, null);
     426            // easy way so we don't have to copy this whole method
     427            if (shellCommand instanceof String)
     428                _process = Runtime.getRuntime().exec((String)shellCommand);
     429            else if (shellCommand instanceof String[])
     430                _process = Runtime.getRuntime().exec((String[])shellCommand);
     431            else
     432               throw new ClassCastException("shell command must be a String or a String[]");
    378433            if (consumeOutput) {
    379434                processStderrConsumer = new StreamConsumer(_process.getErrorStream());
  • core/java/src/net/i2p/util/SimpleScheduler.java

    r46b8bef rc7c7731  
    2929    private static final SimpleScheduler _instance = new SimpleScheduler();
    3030    public static SimpleScheduler getInstance() { return _instance; }
    31     private static final int THREADS = 4;
     31    private static final int MIN_THREADS = 2;
     32    private static final int MAX_THREADS = 4;
    3233    private I2PAppContext _context;
    3334    private Log _log;
     
    3536    private String _name;
    3637    private int _count;
     38    private final int _threads;
    3739
    3840    protected SimpleScheduler() { this("SimpleScheduler"); }
     
    4244        _name = name;
    4345        _count = 0;
    44         _executor = new ScheduledThreadPoolExecutor(THREADS, new CustomThreadFactory());
     46        long maxMemory = Runtime.getRuntime().maxMemory();
     47        _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
     48        _executor = new ScheduledThreadPoolExecutor(_threads, new CustomThreadFactory());
    4549        _executor.prestartAllCoreThreads();
    4650    }
     
    6670    }
    6771   
     72    /**
     73     * Queue up the given event to be fired after timeoutMs and every
     74     * timeoutMs thereafter. The TimedEvent must not do its own rescheduling.
     75     * As all Exceptions are caught in run(), these will not prevent
     76     * subsequent executions (unlike SimpleTimer, where the TimedEvent does
     77     * its own rescheduling).
     78     */
    6879    public void addPeriodicEvent(SimpleTimer.TimedEvent event, long timeoutMs) {
    6980        addPeriodicEvent(event, timeoutMs, timeoutMs);
     
    91102        public Thread newThread(Runnable r) {
    92103            Thread rv = Executors.defaultThreadFactory().newThread(r);
    93             rv.setName(_name +  ' ' + (++_count) + '/' + THREADS);
     104            rv.setName(_name +  ' ' + (++_count) + '/' + _threads);
    94105// Uncomment this to test threadgrouping, but we should be all safe now that the constructor preallocates!
    95106//            String name = rv.getThreadGroup().getName();
  • core/java/src/net/i2p/util/SimpleTimer.java

    r46b8bef rc7c7731  
    1919    private static final SimpleTimer _instance = new SimpleTimer();
    2020    public static SimpleTimer getInstance() { return _instance; }
    21     private I2PAppContext _context;
    22     private Log _log;
     21    private final I2PAppContext _context;
     22    private final Log _log;
    2323    /** event time (Long) to event (TimedEvent) mapping */
    2424    private final TreeMap _events;
     
    2727    private final List _readyEvents;
    2828    private SimpleStore runn;
     29    private static final int MIN_THREADS = 2;
     30    private static final int MAX_THREADS = 4;
    2931
    3032    protected SimpleTimer() { this("SimpleTimer"); }
     
    4042        runner.setDaemon(true);
    4143        runner.start();
    42         for (int i = 0; i < 3; i++) {
     44        long maxMemory = Runtime.getRuntime().maxMemory();
     45        int threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
     46        for (int i = 1; i <= threads ; i++) {
    4347            I2PThread executor = new I2PThread(new Executor(_context, _log, _readyEvents, runn));
    44             executor.setName(name + "Executor " + i);
     48            executor.setName(name + "Executor " + i + '/' + threads);
    4549            executor.setDaemon(true);
    4650            executor.start();
  • core/java/src/net/i2p/util/SimpleTimer2.java

    r46b8bef rc7c7731  
    2828    private static final SimpleTimer2 _instance = new SimpleTimer2();
    2929    public static SimpleTimer2 getInstance() { return _instance; }
    30     private static final int THREADS = 4;
     30    private static final int MIN_THREADS = 2;
     31    private static final int MAX_THREADS = 4;
    3132    private I2PAppContext _context;
    3233    private static Log _log; // static so TimedEvent can use it
     
    3435    private String _name;
    3536    private int _count;
     37    private final int _threads;
    3638
    3739    protected SimpleTimer2() { this("SimpleTimer2"); }
     
    4143        _name = name;
    4244        _count = 0;
    43         _executor = new CustomScheduledThreadPoolExecutor(THREADS, new CustomThreadFactory());
     45        long maxMemory = Runtime.getRuntime().maxMemory();
     46        _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
     47        _executor = new CustomScheduledThreadPoolExecutor(_threads, new CustomThreadFactory());
    4448        _executor.prestartAllCoreThreads();
    4549    }
     
    6872        public Thread newThread(Runnable r) {
    6973            Thread rv = Executors.defaultThreadFactory().newThread(r);
    70             rv.setName(_name + ' ' + (++_count) + '/' + THREADS);
     74            rv.setName(_name + ' ' + (++_count) + '/' + _threads);
    7175// Uncomment this to test threadgrouping, but we should be all safe now that the constructor preallocates!
    7276//            String name = rv.getThreadGroup().getName();
  • installer/resources/clients.config

    r46b8bef rc7c7731  
    77
    88# fire up the web console
     9## There are several choices, here are some examples:
     10## non-SSL, bind to local IPv4 only
     11#clientApp.0.args=7657 127.0.0.1 ./webapps/
     12## non-SSL, bind to local IPv6 only
     13#clientApp.0.args=7657 ::1 ./webapps/
     14## non-SSL, bind to all IPv4 addresses
     15#clientApp.0.args=7657 0.0.0.0 ./webapps/
     16## non-SSL, bind to all IPv6 addresses
     17#clientApp.0.args=7657 :: ./webapps/
     18## For SSL only, change clientApp.4.args below to https://
     19## SSL only
     20#clientApp.0.args=-s 7657 ::1,127.0.0.1 ./webapps/
     21## non-SSL and SSL
     22#clientApp.0.args=7657 ::1,127.0.0.1 -s 7667 ::1,127.0.0.1 ./webapps/
     23## non-SSL only, both IPv6 and IPv4 local interfaces
    924clientApp.0.args=7657 ::1,127.0.0.1 ./webapps/
    1025clientApp.0.main=net.i2p.router.web.RouterConsoleRunner
  • installer/resources/jetty.xml

    r46b8bef rc7c7731  
    7272
    7373  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
    74   <!-- Add a HTTPS SSL listener on port 8443                           -->
     74  <!-- Add a HTTPS SSL listener on port 8443                               -->
     75  <!--                                                                     -->
     76  <!-- In the unlikely event you would want SSL support for your eepsite.  -->
     77  <!-- You would need to generate a selfsigned certificate in a keystore   -->
     78  <!-- in ~/.i2p/eepsite/keystore.ks, for example with the command line:   -->
     79  <!--
     80       keytool -genkey -storetype JKS -keystore ~/.i2p/eepsite/keystore.ks -storepass changeit -alias console -dname CN=xyz123.eepsite.i2p.net,OU=Eepsite,O=I2P Anonymous Network,L=XX,ST=XX,C=XX -validity 3650 -keyalg DSA -keysize 1024 -keypass myKeyPassword
     81   -->
     82  <!-- Change the CN and key password in the example, of course.           -->
     83  <!-- You wouldn't want to open this up to the regular internet,          -->
     84  <!-- would you?? Untested and not recommended.                           -->
    7585  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
    7686  <!-- UNCOMMENT TO ACTIVATE
    7787  <Call name="addListener">
    7888    <Arg>
    79       <New class="org.mortbay.http.SunJsseListener">
     89      <New class="org.mortbay.http.SslListener">
    8090        <Set name="Port">8443</Set>
    8191        <Set name="PoolName">main</Set>
    82         <Set name="Keystore"><SystemProperty name="jetty.home" default="."/>/etc/demokeystore</Set>
    83         <Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
    84         <Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
     92        <Set name="Keystore">./eepsite/keystore.ks</Set>
     93        <!-- the keystore password -->
     94        <Set name="Password">changeit</Set>
     95        <!-- the X.509 certificate password -->
     96        <Set name="KeyPassword">myKeyPassword</Set>
    8597        <Set name="NonPersistentUserAgent">MSIE 5</Set>
    8698      </New>
  • router/java/src/net/i2p/data/i2np/I2NPMessageReader.java

    r46b8bef rc7c7731  
    162162                    }
    163163                }
    164                 if (!_doRun) {
     164                // ??? unused
     165                if (_stayAlive && !_doRun) {
    165166                    // pause .5 secs when we're paused
    166167                    try { Thread.sleep(500); } catch (InterruptedException ie) {}
  • router/java/src/net/i2p/router/JobQueue.java

    r46b8bef rc7c7731  
    396396                    JobQueueRunner runner = new JobQueueRunner(_context, i);
    397397                    _queueRunners.put(Integer.valueOf(i), runner);
    398                     Thread t = new I2PThread(runner);
    399                     t.setName("JobQueue"+(_runnerId++));
     398                    Thread t = new I2PThread(runner, "JobQueue " + (++_runnerId) + '/' + numThreads, false);
    400399                    //t.setPriority(I2PThread.MAX_PRIORITY-1);
    401                     t.setDaemon(false);
    402400                    t.start();
    403401                }
  • router/java/src/net/i2p/router/Router.java

    r46b8bef rc7c7731  
    12821282    private void beginMarkingLiveliness() {
    12831283        File f = getPingFile();
    1284         // not an I2PThread for context creation issues
    1285         Thread t = new Thread(new MarkLiveliness(_context, this, f));
    1286         t.setName("Mark router liveliness");
    1287         t.setDaemon(true);
    1288         t.start();
     1284        SimpleScheduler.getInstance().addPeriodicEvent(new MarkLiveliness(this, f), 0, LIVELINESS_DELAY);
    12891285    }
    12901286   
     
    15241520}
    15251521
    1526 private static class MarkLiveliness implements Runnable {
    1527     private RouterContext _context;
     1522/**
     1523 *  Write a timestamp to the ping file where the wrapper can see it
     1524 */
     1525private static class MarkLiveliness implements SimpleTimer.TimedEvent {
    15281526    private Router _router;
    15291527    private File _pingFile;
    1530     public MarkLiveliness(RouterContext ctx, Router router, File pingFile) {
    1531         _context = ctx;
     1528
     1529    public MarkLiveliness(Router router, File pingFile) {
    15321530        _router = router;
    15331531        _pingFile = pingFile;
    1534     }
    1535     public void run() {
    15361532        _pingFile.deleteOnExit();
    1537         do {
     1533    }
     1534
     1535    public void timeReached() {
     1536        if (_router.isAlive())
    15381537            ping();
    1539             try { Thread.sleep(Router.LIVELINESS_DELAY); } catch (InterruptedException ie) {}
    1540         } while (_router.isAlive());
    1541         _pingFile.delete();
     1538        else
     1539            _pingFile.delete();
    15421540    }
    15431541
  • router/java/src/net/i2p/router/RouterContext.java

    r46b8bef rc7c7731  
    77import net.i2p.I2PAppContext;
    88import net.i2p.data.Hash;
     9import net.i2p.internal.InternalClientManager;
    910import net.i2p.router.client.ClientManagerFacadeImpl;
    1011import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
     
    3536public class RouterContext extends I2PAppContext {
    3637    private Router _router;
    37     private ClientManagerFacade _clientManagerFacade;
     38    private ClientManagerFacadeImpl _clientManagerFacade;
    3839    private ClientMessagePool _clientMessagePool;
    3940    private JobQueue _jobQueue;
     
    107108
    108109    public void initAll() {
    109         if ("false".equals(getProperty("i2p.dummyClientFacade", "false")))
    110             _clientManagerFacade = new ClientManagerFacadeImpl(this);
    111         else
    112             _clientManagerFacade = new DummyClientManagerFacade(this);
     110        if (getBooleanProperty("i2p.dummyClientFacade"))
     111            System.err.println("i2p.dummpClientFacade currently unsupported");
     112        _clientManagerFacade = new ClientManagerFacadeImpl(this);
     113        // removed since it doesn't implement InternalClientManager for now
     114        //else
     115        //    _clientManagerFacade = new DummyClientManagerFacade(this);
    113116        _clientMessagePool = new ClientMessagePool(this);
    114117        _jobQueue = new JobQueue(this);
     
    396399        return true;
    397400    }
     401
     402    /**
     403     *  Use this to connect to the router in the same JVM.
     404     *  @return the client manager
     405     *  @since 0.8.3
     406     */
     407    public InternalClientManager internalClientManager() {
     408        return _clientManagerFacade;
     409    }
    398410}
  • router/java/src/net/i2p/router/client/ClientConnectionRunner.java

    r46b8bef rc7c7731  
    5151 * @author jrandom
    5252 */
    53 public class ClientConnectionRunner {
     53class ClientConnectionRunner {
    5454    private Log _log;
    55     private RouterContext _context;
     55    protected final RouterContext _context;
    5656    private ClientManager _manager;
    5757    /** socket for this particular peer connection */
     
    7272    private Set<MessageId> _acceptedPending;
    7373    /** thingy that does stuff */
    74     private I2CPMessageReader _reader;
     74    protected I2CPMessageReader _reader;
    7575    /** just for this destination */
    7676    private SessionKeyManager _sessionKeyManager;
     
    110110    public void startRunning() {
    111111        try {
    112             _reader = new I2CPMessageReader(_socket.getInputStream(), new ClientMessageEventListener(_context, this));
     112            _reader = new I2CPMessageReader(_socket.getInputStream(), new ClientMessageEventListener(_context, this, true));
    113113            _writer = new ClientWriterRunner(_context, this);
    114114            I2PThread t = new I2PThread(_writer);
     
    470470            stopRunning();
    471471        } catch (IOException ioe) {
    472             // only warn if client went away
    473             int level;
    474             String emsg;
    475             if (ioe.getMessage() != null && ioe.getMessage().startsWith("Pipe closed")) {
    476                 level = Log.WARN;
    477                 emsg = "Error sending I2CP message - client went away";
    478             } else {
    479                 level = Log.ERROR;
    480                 emsg = "IO Error sending I2CP message to client";
    481             }
    482             if (_log.shouldLog(level))
    483                 _log.log(level, emsg, ioe);
     472            if (_log.shouldLog(Log.ERROR))
     473                _log.error("IO Error sending I2CP message to client", ioe);
    484474            stopRunning();
    485475        } catch (Throwable t) {
  • router/java/src/net/i2p/router/client/ClientListenerRunner.java

    r46b8bef rc7c7731  
    2525 * @author jrandom
    2626 */
    27 public class ClientListenerRunner implements Runnable {
    28     protected Log _log;
    29     protected RouterContext _context;
    30     protected ClientManager _manager;
     27class ClientListenerRunner implements Runnable {
     28    protected final Log _log;
     29    protected final RouterContext _context;
     30    protected final ClientManager _manager;
    3131    protected ServerSocket _socket;
    32     protected int _port;
    33     private boolean _bindAllInterfaces;
     32    protected final int _port;
     33    protected final boolean _bindAllInterfaces;
    3434    protected boolean _running;
    3535    protected boolean _listening;
     
    3939    public ClientListenerRunner(RouterContext context, ClientManager manager, int port) {
    4040        _context = context;
    41         _log = _context.logManager().getLog(ClientListenerRunner.class);
     41        _log = _context.logManager().getLog(getClass());
    4242        _manager = manager;
    4343        _port = port;
    44        
    45         String val = context.getProperty(BIND_ALL_INTERFACES);
    46         _bindAllInterfaces = Boolean.valueOf(val).booleanValue();
     44        _bindAllInterfaces = context.getBooleanProperty(BIND_ALL_INTERFACES);
    4745    }
    4846   
    49     public void setPort(int port) { _port = port; }
    50     public int getPort() { return _port; }
    5147    public boolean isListening() { return _running && _listening; }
    5248   
     49    /**
     50     * Get a ServerSocket.
     51     * Split out so it can be overridden for SSL.
     52     * @since 0.8.3
     53     */
     54    protected ServerSocket getServerSocket() throws IOException {
     55        if (_bindAllInterfaces) {
     56            if (_log.shouldLog(Log.INFO))
     57                _log.info("Listening on port " + _port + " on all interfaces");
     58            return new ServerSocket(_port);
     59        } else {
     60            String listenInterface = _context.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_HOST,
     61                                                          ClientManagerFacadeImpl.DEFAULT_HOST);
     62            if (_log.shouldLog(Log.INFO))
     63                _log.info("Listening on port " + _port + " of the specific interface: " + listenInterface);
     64            return new ServerSocket(_port, 0, InetAddress.getByName(listenInterface));
     65        }
     66    }
     67               
    5368    /**
    5469     * Start up the socket listener, listens for connections, and
     
    6378        while (_running) {
    6479            try {
    65                 if (_bindAllInterfaces) {
    66                     if (_log.shouldLog(Log.INFO))
    67                         _log.info("Listening on port " + _port + " on all interfaces");
    68                     _socket = new ServerSocket(_port);
    69                 } else {
    70                     String listenInterface = _context.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_HOST,
    71                                                                   ClientManagerFacadeImpl.DEFAULT_HOST);
    72                     if (_log.shouldLog(Log.INFO))
    73                         _log.info("Listening on port " + _port + " of the specific interface: " + listenInterface);
    74                     _socket = new ServerSocket(_port, 0, InetAddress.getByName(listenInterface));
    75                 }
    76                
     80                _socket = getServerSocket();
    7781               
    7882                if (_log.shouldLog(Log.DEBUG))
     
    132136   
    133137    /** give the i2cp client 5 seconds to show that they're really i2cp clients */
    134     private final static int CONNECT_TIMEOUT = 5*1000;
     138    protected final static int CONNECT_TIMEOUT = 5*1000;
     139    private final static int LOOP_DELAY = 250;
    135140
    136141    /**
     
    142147        try {
    143148            InputStream is = socket.getInputStream();
    144             for (int i = 0; i < 20; i++) {
     149            for (int i = 0; i < CONNECT_TIMEOUT / LOOP_DELAY; i++) {
    145150                if (is.available() > 0)
    146151                    return is.read() == I2PClient.PROTOCOL_BYTE;
    147                 try { Thread.sleep(250); } catch (InterruptedException ie) {}
     152                try { Thread.sleep(LOOP_DELAY); } catch (InterruptedException ie) {}
    148153            }
    149154        } catch (IOException ioe) {}
     
    152157        return false;
    153158    }
     159
    154160    /**
    155161     * Handle the connection by passing it off to a {@link ClientConnectionRunner ClientConnectionRunner}
  • router/java/src/net/i2p/router/client/ClientManager.java

    r46b8bef rc7c7731  
    1616import java.util.Map;
    1717import java.util.Set;
    18 
     18import java.util.concurrent.LinkedBlockingQueue;
     19
     20import net.i2p.client.I2PSessionException;
    1921import net.i2p.crypto.SessionKeyManager;
    2022import net.i2p.data.DataHelper;
     
    2426import net.i2p.data.Payload;
    2527import net.i2p.data.TunnelId;
     28import net.i2p.data.i2cp.I2CPMessage;
    2629import net.i2p.data.i2cp.MessageId;
    2730import net.i2p.data.i2cp.SessionConfig;
     31import net.i2p.internal.I2CPMessageQueue;
    2832import net.i2p.router.ClientManagerFacade;
    2933import net.i2p.router.ClientMessage;
     
    4044 * @author jrandom
    4145 */
    42 public class ClientManager {
    43     private Log _log;
     46class ClientManager {
     47    private final Log _log;
    4448    private ClientListenerRunner _listener;
    45     private ClientListenerRunner _internalListener;
    4649    private final HashMap<Destination, ClientConnectionRunner>  _runners;        // Destination --> ClientConnectionRunner
    4750    private final Set<ClientConnectionRunner> _pendingRunners; // ClientConnectionRunner for clients w/out a Dest yet
    48     private RouterContext _ctx;
     51    private final RouterContext _ctx;
     52    private boolean _isStarted;
     53
     54    /** Disable external interface, allow internal clients only @since 0.8.3 */
     55    private static final String PROP_DISABLE_EXTERNAL = "i2cp.disableInterface";
     56    /** SSL interface (only) @since 0.8.3 */
     57    private static final String PROP_ENABLE_SSL = "i2cp.SSL";
    4958
    5059    /** ms to wait before rechecking for inbound messages to deliver to clients */
     
    5463        _ctx = context;
    5564        _log = context.logManager().getLog(ClientManager.class);
    56         _ctx.statManager().createRateStat("client.receiveMessageSize",
    57                                               "How large are messages received by the client?",
    58                                               "ClientMessages",
    59                                               new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
     65        //_ctx.statManager().createRateStat("client.receiveMessageSize",
     66        //                                      "How large are messages received by the client?",
     67        //                                      "ClientMessages",
     68        //                                      new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
    6069        _runners = new HashMap();
    6170        _pendingRunners = new HashSet();
     
    6574    /** Todo: Start a 3rd listener for IPV6? */
    6675    private void startListeners(int port) {
    67         _listener = new ClientListenerRunner(_ctx, this, port);
    68         Thread t = new I2PThread(_listener);
    69         t.setName("ClientListener:" + port);
    70         t.setDaemon(true);
    71         t.start();
    72         _internalListener = new InternalClientListenerRunner(_ctx, this, port);
    73         t = new I2PThread(_internalListener);
    74         t.setName("ClientListener:" + port + "-i");
    75         t.setDaemon(true);
    76         t.start();
     76        if (!_ctx.getBooleanProperty(PROP_DISABLE_EXTERNAL)) {
     77            // there's no option to start both an SSL and non-SSL listener
     78            if (_ctx.getBooleanProperty(PROP_ENABLE_SSL))
     79                _listener = new SSLClientListenerRunner(_ctx, this, port);
     80            else
     81                _listener = new ClientListenerRunner(_ctx, this, port);
     82            Thread t = new I2PThread(_listener, "ClientListener:" + port, true);
     83            t.start();
     84        }
     85        _isStarted = true;
    7786    }
    7887   
     
    96105   
    97106    public void shutdown() {
     107        _isStarted = false;
    98108        _log.info("Shutting down the ClientManager");
    99         _listener.stopListening();
    100         _internalListener.stopListening();
     109        if (_listener != null)
     110            _listener.stopListening();
    101111        Set<ClientConnectionRunner> runners = new HashSet();
    102112        synchronized (_runners) {
     
    118128    }
    119129   
    120     public boolean isAlive() { return _listener.isListening(); }
     130    /**
     131     *  The InternalClientManager interface.
     132     *  Connects to the router, receiving a message queue to talk to the router with.
     133     *  @throws I2PSessionException if the router isn't ready
     134     *  @since 0.8.3
     135     */
     136    public I2CPMessageQueue internalConnect() throws I2PSessionException {
     137        if (!_isStarted)
     138            throw new I2PSessionException("Router client manager is shut down");
     139        // for now we make these unlimited size
     140        LinkedBlockingQueue<I2CPMessage> in = new LinkedBlockingQueue();
     141        LinkedBlockingQueue<I2CPMessage> out = new LinkedBlockingQueue();
     142        I2CPMessageQueue myQueue = new I2CPMessageQueueImpl(in, out);
     143        I2CPMessageQueue hisQueue = new I2CPMessageQueueImpl(out, in);
     144        ClientConnectionRunner runner = new QueuedClientConnectionRunner(_ctx, this, myQueue);
     145        registerConnection(runner);
     146        return hisQueue;
     147    }
     148
     149    public boolean isAlive() {
     150        return _isStarted && (_listener == null || _listener.isListening());
     151    }
    121152
    122153    public void registerConnection(ClientConnectionRunner runner) {
     
    470501
    471502            if (runner != null) {
    472                 _ctx.statManager().addRateData("client.receiveMessageSize",
    473                                                    _msg.getPayload().getSize(), 0);
     503                //_ctx.statManager().addRateData("client.receiveMessageSize",
     504                //                                   _msg.getPayload().getSize(), 0);
    474505                runner.receiveMessage(_msg.getDestination(), null, _msg.getPayload());
    475506            } else {
  • router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java

    r46b8bef rc7c7731  
    1515import java.util.Set;
    1616
     17import net.i2p.client.I2PSessionException;
    1718import net.i2p.crypto.SessionKeyManager;
    1819import net.i2p.data.DataHelper;
     
    2223import net.i2p.data.i2cp.MessageId;
    2324import net.i2p.data.i2cp.SessionConfig;
     25import net.i2p.internal.I2CPMessageQueue;
     26import net.i2p.internal.InternalClientManager;
    2427import net.i2p.router.ClientManagerFacade;
    2528import net.i2p.router.ClientMessage;
     
    3336 * @author jrandom
    3437 */
    35 public class ClientManagerFacadeImpl extends ClientManagerFacade {
     38public class ClientManagerFacadeImpl extends ClientManagerFacade implements InternalClientManager {
    3639    private final static Log _log = new Log(ClientManagerFacadeImpl.class);
    3740    private ClientManager _manager;
     
    221224            return Collections.EMPTY_SET;
    222225    }
     226
     227    /**
     228     *  The InternalClientManager interface.
     229     *  Connect to the router, receiving a message queue to talk to the router with.
     230     *  @throws I2PSessionException if the router isn't ready
     231     *  @since 0.8.3
     232     */
     233    public I2CPMessageQueue connect() throws I2PSessionException {
     234        if (_manager != null)
     235            return _manager.internalConnect();
     236        throw new I2PSessionException("No manager yet");
     237    }
    223238}
  • router/java/src/net/i2p/router/client/ClientMessageEventListener.java

    r46b8bef rc7c7731  
    4343 */
    4444class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventListener {
    45     private Log _log;
    46     private RouterContext _context;
    47     private ClientConnectionRunner _runner;
    48    
    49     public ClientMessageEventListener(RouterContext context, ClientConnectionRunner runner) {
     45    private final Log _log;
     46    private final RouterContext _context;
     47    private final ClientConnectionRunner _runner;
     48    private final boolean  _enforceAuth;
     49   
     50    /**
     51     *  @param enforceAuth set false for in-JVM, true for socket access
     52     */
     53    public ClientMessageEventListener(RouterContext context, ClientConnectionRunner runner, boolean enforceAuth) {
    5054        _context = context;
    5155        _log = _context.logManager().getLog(ClientMessageEventListener.class);
    5256        _runner = runner;
     57        _enforceAuth = enforceAuth;
    5358        _context.statManager().createRateStat("client.distributeTime", "How long it took to inject the client message into the router", "ClientMessages", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
    5459    }
     
    154159
    155160        // Auth, since 0.8.2
    156         // In-JVM accesses have access to the same context properties, so
    157         // they will be set on the client side... therefore we don't need to pass in
    158         // some indication of (socket instanceof InternalSocket)
    159         if (Boolean.valueOf(_context.getProperty("i2cp.auth")).booleanValue()) {
     161        if (_enforceAuth && Boolean.valueOf(_context.getProperty("i2cp.auth")).booleanValue()) {
    160162            String configUser = _context.getProperty("i2cp.username");
    161163            String configPW = _context.getProperty("i2cp.password");
  • router/java/src/net/i2p/router/client/ClientWriterRunner.java

    r46b8bef rc7c7731  
    99import net.i2p.data.i2cp.I2CPMessageImpl;
    1010import net.i2p.data.i2cp.I2CPMessageException;
     11import net.i2p.internal.PoisonI2CPMessage;
    1112import net.i2p.router.RouterContext;
    1213import net.i2p.util.Log;
     
    5354        _messagesToWrite.clear();
    5455        try {
    55             _messagesToWrite.put(new PoisonMessage());
     56            _messagesToWrite.put(new PoisonI2CPMessage());
    5657        } catch (InterruptedException ie) {}
    5758    }
     
    6566                continue;
    6667            }
    67             if (msg.getType() == PoisonMessage.MESSAGE_TYPE)
     68            if (msg.getType() == PoisonI2CPMessage.MESSAGE_TYPE)
    6869                break;
    6970            _runner.writeMessage(msg);
    7071        }
    7172    }
    72 
    73     /**
    74      * End-of-stream msg used to stop the concurrent queue
    75      * See http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html
    76      *
    77      */
    78     private static class PoisonMessage extends I2CPMessageImpl {
    79         public static final int MESSAGE_TYPE = 999999;
    80         public int getType() {
    81             return MESSAGE_TYPE;
    82         }
    83         public void doReadMessage(InputStream buf, int size) throws I2CPMessageException, IOException {}
    84         public byte[] doWriteMessage() throws I2CPMessageException, IOException { return null; }
    85     }
    8673}
  • router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java

    r46b8bef rc7c7731  
    4646        _log = _context.logManager().getLog(CommSystemFacadeImpl.class);
    4747        _manager = null;
     48        _context.statManager().createRateStat("transport.getBidsJobTime", "How long does it take?", "Transport", new long[] { 10*60*1000l });
    4849        startGeoIP();
    4950    }
     
    132133        //GetBidsJob j = new GetBidsJob(_context, this, msg);
    133134        //j.runJob();
     135        long before = _context.clock().now();
    134136        GetBidsJob.getBids(_context, this, msg);
     137        _context.statManager().addRateData("transport.getBidsJobTime", _context.clock().now() - before, 0);
    135138    }
    136139   
  • router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java

    r46b8bef rc7c7731  
    2525 */
    2626public class NTCPSendFinisher {
    27     private static final int THREADS = 4;
     27    private static final int MIN_THREADS = 1;
     28    private static final int MAX_THREADS = 4;
    2829    private final I2PAppContext _context;
    2930    private final NTCPTransport _transport;
    3031    private final Log _log;
    31     private int _count;
     32    private static int _count;
    3233    private ThreadPoolExecutor _executor;
     34    private static int _threads;
    3335
    3436    public NTCPSendFinisher(I2PAppContext context, NTCPTransport transport) {
     
    3638        _log = _context.logManager().getLog(NTCPSendFinisher.class);
    3739        _transport = transport;
     40        _context.statManager().createRateStat("ntcp.sendFinishTime", "How long to queue and excecute msg.afterSend()", "ntcp", new long[] {5*1000});
    3841    }
    3942   
    4043    public void start() {
    4144        _count = 0;
    42         _executor = new CustomThreadPoolExecutor();
     45        long maxMemory = Runtime.getRuntime().maxMemory();
     46        _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024))));
     47        _executor = new CustomThreadPoolExecutor(_threads);
    4348    }
    4449
     
    5863   
    5964    // not really needed for now but in case we want to add some hooks like afterExecute()
    60     private class CustomThreadPoolExecutor extends ThreadPoolExecutor {
    61         public CustomThreadPoolExecutor() {
     65    private static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
     66        public CustomThreadPoolExecutor(int num) {
    6267             // use unbounded queue, so maximumPoolSize and keepAliveTime have no effect
    63              super(THREADS, THREADS, 1000, TimeUnit.MILLISECONDS,
     68             super(num, num, 1000, TimeUnit.MILLISECONDS,
    6469                   new LinkedBlockingQueue(), new CustomThreadFactory());
    6570        }
    6671    }
    6772
    68     private class CustomThreadFactory implements ThreadFactory {
     73    private static class CustomThreadFactory implements ThreadFactory {
    6974        public Thread newThread(Runnable r) {
    7075            Thread rv = Executors.defaultThreadFactory().newThread(r);
    71             rv.setName("NTCPSendFinisher " + (++_count) + '/' + THREADS);
     76            rv.setName("NTCPSendFinisher " + (++_count) + '/' + _threads);
    7277            rv.setDaemon(true);
    7378            return rv;
     
    7984     */
    8085    private class RunnableEvent implements Runnable {
    81         private OutNetMessage _msg;
     86        private final OutNetMessage _msg;
     87        private final long _queued;
    8288
    8389        public RunnableEvent(OutNetMessage msg) {
    8490            _msg = msg;
     91            _queued = _context.clock().now();
    8592        }
    8693
     
    8895            try {
    8996                _transport.afterSend(_msg, true, false, _msg.getSendTime());
     97                _context.statManager().addRateData("ntcp.sendFinishTime", _context.clock().now() - _queued, 0);
    9098            } catch (Throwable t) {
    9199                _log.log(Log.CRIT, " wtf, afterSend borked", t);
  • router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java

    r46b8bef rc7c7731  
    434434    }
    435435
    436     private static final int NUM_CONCURRENT_READERS = 3;
    437     private static final int NUM_CONCURRENT_WRITERS = 3;
     436    private static final int MIN_CONCURRENT_READERS = 2;  // unless < 32MB
     437    private static final int MIN_CONCURRENT_WRITERS = 2;  // unless < 32MB
     438    private static final int MAX_CONCURRENT_READERS = 4;
     439    private static final int MAX_CONCURRENT_WRITERS = 4;
    438440
    439441    /**
     
    450452            return _myAddress != null ? _myAddress.toRouterAddress() : null;
    451453        if (_log.shouldLog(Log.WARN)) _log.warn("Starting ntcp transport listening");
    452         _finisher.start();
    453         _pumper.startPumping();
    454 
    455         _reader.startReading(NUM_CONCURRENT_READERS);
    456         _writer.startWriting(NUM_CONCURRENT_WRITERS);
    457 
     454
     455        startIt();
    458456        configureLocalAddress();
    459457        return bindAddress();
     
    472470            return _myAddress != null ? _myAddress.toRouterAddress() : null;
    473471        if (_log.shouldLog(Log.WARN)) _log.warn("Restarting ntcp transport listening");
    474         _finisher.start();
    475         _pumper.startPumping();
    476 
    477         _reader.startReading(NUM_CONCURRENT_READERS);
    478         _writer.startWriting(NUM_CONCURRENT_WRITERS);
    479 
     472
     473        startIt();
    480474        if (addr == null)
    481475            _myAddress = null;
     
    483477            _myAddress = new NTCPAddress(addr);
    484478        return bindAddress();
     479    }
     480
     481    /**
     482     *  Start up. Caller must synchronize.
     483     *  @since 0.8.3
     484     */
     485    private void startIt() {
     486        _finisher.start();
     487        _pumper.startPumping();
     488
     489        long maxMemory = Runtime.getRuntime().maxMemory();
     490        int nr, nw;
     491        if (maxMemory < 32*1024*1024) {
     492            nr = nw = 1;
     493        } else if (maxMemory < 64*1024*1024) {
     494            nr = nw = 2;
     495        } else {
     496            nr = Math.max(MIN_CONCURRENT_READERS, Math.min(MAX_CONCURRENT_READERS, _context.bandwidthLimiter().getInboundKBytesPerSecond() / 20));
     497            nw = Math.max(MIN_CONCURRENT_WRITERS, Math.min(MAX_CONCURRENT_WRITERS, _context.bandwidthLimiter().getOutboundKBytesPerSecond() / 20));
     498        }
     499        _reader.startReading(nr);
     500        _writer.startWriting(nw);
    485501    }
    486502
  • router/java/src/net/i2p/router/transport/ntcp/Reader.java

    r46b8bef rc7c7731  
    1616 */
    1717class Reader {
    18     private RouterContext _context;
    19     private Log _log;
     18    private final RouterContext _context;
     19    private final Log _log;
    2020    // TODO change to LBQ ??
    2121    private final List<NTCPConnection> _pendingConnections;
    22     private List<NTCPConnection> _liveReads;
    23     private List<NTCPConnection> _readAfterLive;
    24     private List<Runner> _runners;
     22    private final List<NTCPConnection> _liveReads;
     23    private final List<NTCPConnection> _readAfterLive;
     24    private final List<Runner> _runners;
    2525   
    2626    public Reader(RouterContext ctx) {
     
    3434   
    3535    public void startReading(int numReaders) {
    36         for (int i = 0; i < numReaders; i++) {
     36        for (int i = 1; i <= numReaders; i++) {
    3737            Runner r = new Runner();
    38             I2PThread t = new I2PThread(r, "NTCP read " + i, true);
     38            I2PThread t = new I2PThread(r, "NTCP reader " + i + '/' + numReaders, true);
    3939            _runners.add(r);
    4040            t.start();
  • router/java/src/net/i2p/router/transport/ntcp/Writer.java

    r46b8bef rc7c7731  
    1515 */
    1616class Writer {
    17     private RouterContext _context;
    18     private Log _log;
     17    private final RouterContext _context;
     18    private final Log _log;
    1919    private final List<NTCPConnection> _pendingConnections;
    20     private List<NTCPConnection> _liveWrites;
    21     private List<NTCPConnection> _writeAfterLive;
    22     private List<Runner> _runners;
     20    private final List<NTCPConnection> _liveWrites;
     21    private final List<NTCPConnection> _writeAfterLive;
     22    private final List<Runner> _runners;
    2323   
    2424    public Writer(RouterContext ctx) {
     
    3232   
    3333    public void startWriting(int numWriters) {
    34         for (int i = 0; i < numWriters; i++) {
     34        for (int i = 1; i <=numWriters; i++) {
    3535            Runner r = new Runner();
    36             I2PThread t = new I2PThread(r, "NTCP write " + i, true);
     36            I2PThread t = new I2PThread(r, "NTCP writer " + i + '/' + numWriters, true);
    3737            _runners.add(r);
    3838            t.start();
  • router/java/src/net/i2p/router/transport/udp/MessageReceiver.java

    r46b8bef rc7c7731  
    2828    private boolean _alive;
    2929    //private ByteCache _cache;
    30     private static final int THREADS = 5;
     30    private static final int MIN_THREADS = 2;  // unless < 32MB
     31    private static final int MAX_THREADS = 5;
     32    private final int _threadCount;
    3133    private static final long POISON_IMS = -99999999999l;
    3234   
     
    3638        _transport = transport;
    3739        _completeMessages = new LinkedBlockingQueue();
     40
     41        long maxMemory = Runtime.getRuntime().maxMemory();
     42        if (maxMemory < 32*1024*1024)
     43            _threadCount = 1;
     44        else if (maxMemory < 64*1024*1024)
     45            _threadCount = 2;
     46        else
     47            _threadCount = Math.max(MIN_THREADS, Math.min(MAX_THREADS, ctx.bandwidthLimiter().getInboundKBytesPerSecond() / 20));
     48
    3849        // the runners run forever, no need to have a cache
    3950        //_cache = ByteCache.getInstance(64, I2NPMessage.MAX_SIZE);
    4051        _context.statManager().createRateStat("udp.inboundExpired", "How many messages were expired before reception?", "udp", UDPTransport.RATES);
    41         _context.statManager().createRateStat("udp.inboundRemaining", "How many messages were remaining when a message is pulled off the complete queue?", "udp", UDPTransport.RATES);
     52        //_context.statManager().createRateStat("udp.inboundRemaining", "How many messages were remaining when a message is pulled off the complete queue?", "udp", UDPTransport.RATES);
    4253        _context.statManager().createRateStat("udp.inboundReady", "How many messages were ready when a message is added to the complete queue?", "udp", UDPTransport.RATES);
    4354        _context.statManager().createRateStat("udp.inboundReadTime", "How long it takes to parse in the completed fragments into a message?", "udp", UDPTransport.RATES);
     
    5061    public void startup() {
    5162        _alive = true;
    52         for (int i = 0; i < THREADS; i++) {
    53             I2PThread t = new I2PThread(new Runner(), "UDP message receiver " + i + '/' + THREADS, true);
     63        for (int i = 0; i < _threadCount; i++) {
     64            I2PThread t = new I2PThread(new Runner(), "UDP message receiver " + (i+1) + '/' + _threadCount, true);
    5465            t.start();
    5566        }
     
    6576        _alive = false;
    6677        _completeMessages.clear();
    67         for (int i = 0; i < THREADS; i++) {
     78        for (int i = 0; i < _threadCount; i++) {
    6879            InboundMessageState ims = new InboundMessageState(_context, POISON_IMS, null);
    6980            _completeMessages.offer(ims);
     
    120131            if (message != null) {
    121132                long before = System.currentTimeMillis();
    122                 if (remaining > 0)
    123                     _context.statManager().addRateData("udp.inboundRemaining", remaining, 0);
     133                //if (remaining > 0)
     134                //    _context.statManager().addRateData("udp.inboundRemaining", remaining, 0);
    124135                int size = message.getCompleteSize();
    125136                if (_log.shouldLog(Log.INFO))
  • router/java/src/net/i2p/router/transport/udp/PacketHandler.java

    r46b8bef rc7c7731  
    3232    private final Handler[] _handlers;
    3333   
    34     private static final int NUM_HANDLERS = 5;
     34    private static final int MIN_NUM_HANDLERS = 2;  // unless < 32MB
     35    private static final int MAX_NUM_HANDLERS = 5;
    3536    /** let packets be up to 30s slow */
    3637    private static final long GRACE_PERIOD = Router.CLOCK_FUDGE_FACTOR + 30*1000;
    3738   
    38     PacketHandler(RouterContext ctx, UDPTransport transport, UDPEndpoint endpoint, EstablishmentManager establisher, InboundMessageFragments inbound, PeerTestManager testManager, IntroductionManager introManager) {// LINT -- Exporting non-public type through public API
     39    PacketHandler(RouterContext ctx, UDPTransport transport, UDPEndpoint endpoint, EstablishmentManager establisher,
     40                  InboundMessageFragments inbound, PeerTestManager testManager, IntroductionManager introManager) {
    3941        _context = ctx;
    4042        _log = ctx.logManager().getLog(PacketHandler.class);
     
    4547        _testManager = testManager;
    4648        _introManager = introManager;
    47         _handlers = new Handler[NUM_HANDLERS];
    48         for (int i = 0; i < NUM_HANDLERS; i++) {
     49
     50        long maxMemory = Runtime.getRuntime().maxMemory();
     51        int num_handlers;
     52        if (maxMemory < 32*1024*1024)
     53            num_handlers = 1;
     54        else if (maxMemory < 64*1024*1024)
     55            num_handlers = 2;
     56        else
     57            num_handlers = Math.max(MIN_NUM_HANDLERS, Math.min(MAX_NUM_HANDLERS, ctx.bandwidthLimiter().getInboundKBytesPerSecond() / 20));
     58        _handlers = new Handler[num_handlers];
     59        for (int i = 0; i < num_handlers; i++) {
    4960            _handlers[i] = new Handler();
    5061        }
     62
    5163        _context.statManager().createRateStat("udp.handleTime", "How long it takes to handle a received packet after its been pulled off the queue", "udp", UDPTransport.RATES);
    5264        _context.statManager().createRateStat("udp.queueTime", "How long after a packet is received can we begin handling it", "udp", UDPTransport.RATES);
     
    8092    public void startup() {
    8193        _keepReading = true;
    82         for (int i = 0; i < NUM_HANDLERS; i++) {
    83             I2PThread t = new I2PThread(_handlers[i], "UDP Packet handler " + i + '/' + NUM_HANDLERS, true);
     94        for (int i = 0; i < _handlers.length; i++) {
     95            I2PThread t = new I2PThread(_handlers[i], "UDP Packet handler " + (i+1) + '/' + _handlers.length, true);
    8496            t.start();
    8597        }
     
    92104    String getHandlerStatus() {
    93105        StringBuilder rv = new StringBuilder();
    94         rv.append("Handlers: ").append(NUM_HANDLERS);
    95         for (int i = 0; i < NUM_HANDLERS; i++) {
     106        rv.append("Handlers: ").append(_handlers.length);
     107        for (int i = 0; i < _handlers.length; i++) {
    96108            Handler handler = _handlers[i];
    97109            rv.append(" handler ").append(i).append(" state: ").append(handler._state);
  • router/java/src/net/i2p/router/tunnel/TunnelGatewayPumper.java

    r46b8bef rc7c7731  
    1717    private final BlockingQueue<PumpedTunnelGateway> _wantsPumping;
    1818    private boolean _stop;
    19     private static final int PUMPERS = 4;
     19    private static final int MIN_PUMPERS = 1;
     20    private static final int MAX_PUMPERS = 4;
     21    private final int _pumpers;
    2022   
    2123    /** Creates a new instance of TunnelGatewayPumper */
     
    2426        _wantsPumping = new LinkedBlockingQueue();
    2527        _stop = false;
    26         for (int i = 0; i < PUMPERS; i++)
    27             new I2PThread(this, "Tunnel GW pumper " + i + '/' + PUMPERS, true).start();
     28        long maxMemory = Runtime.getRuntime().maxMemory();
     29        _pumpers = (int) Math.max(MIN_PUMPERS, Math.min(MAX_PUMPERS, 1 + (maxMemory / (32*1024*1024))));
     30        for (int i = 0; i < _pumpers; i++)
     31            new I2PThread(this, "Tunnel GW pumper " + (i+1) + '/' + _pumpers, true).start();
    2832    }
    2933
     
    3236        _wantsPumping.clear();
    3337        PumpedTunnelGateway poison = new PoisonPTG(_context);
    34         for (int i = 0; i < PUMPERS; i++)
     38        for (int i = 0; i < _pumpers; i++)
    3539            _wantsPumping.offer(poison);
    3640        for (int i = 1; i <= 5 && !_wantsPumping.isEmpty(); i++) {
Note: See TracChangeset for help on using the changeset viewer.