diff --git a/apps/BOB/nbproject/project.properties b/apps/BOB/nbproject/project.properties index 7a94ff6ddd..9eeffd29f1 100644 --- a/apps/BOB/nbproject/project.properties +++ b/apps/BOB/nbproject/project.properties @@ -24,40 +24,24 @@ dist.dir=dist dist.jar=${dist.dir}/BOB.jar dist.javadoc.dir=${dist.dir}/javadoc excludes= -file.reference.build-javadoc=../../../i2p.i2p/build/javadoc -file.reference.core.jar=../i2p.i2p/core/dist/core.jar -file.reference.i2p.jar=../../bob/i2p/i2p.i2p/build/i2p.jar -file.reference.i2p.jar-1=../../build/i2p.jar -file.reference.i2p.jar-2=../i2p.i2p/core/java/build/i2p.jar -file.reference.i2p.jar-3=../../../i2p.i2p/build/i2p.jar -file.reference.i2ptunnel.jar=../../../i2p.i2p/build/i2ptunnel.jar -file.reference.java-src=../i2p.i2p/core/java/src/ -file.reference.jbigi.jar=../../bob/i2p/i2p.i2p/build/jbigi.jar -file.reference.mstreaming.jar=../../bob/i2p/i2p.i2p/build/mstreaming.jar -file.reference.mstreaming.jar-1=../../build/mstreaming.jar -file.reference.mstreaming.jar-2=../../../i2p.i2p/build/mstreaming.jar -file.reference.NetBeansProjects-i2p.i2p=../i2p.i2p/ -file.reference.router.jar=../../build/router.jar -file.reference.streaming.jar=../../bob/i2p/i2p.i2p/build/streaming.jar -file.reference.streaming.jar-1=../../../i2p.i2p/build/streaming.jar -file.reference.wrapper-freebsd=../../installer/lib/wrapper/freebsd/ -file.reference.wrapper-linux=../../installer/lib/wrapper/linux/ -file.reference.wrapper-linux64=../../installer/lib/wrapper/linux64/ -file.reference.wrapper-macosx=../../installer/lib/wrapper/macosx/ -file.reference.wrapper-solaris=../../installer/lib/wrapper/solaris/ -file.reference.wrapper-win32=../../installer/lib/wrapper/win32/ +file.reference.build-javadoc=../../i2p.i2p/build/javadoc +file.reference.i2p.jar=../../core/java/build/i2p.jar +file.reference.i2ptunnel.jar=../i2ptunnel/java/build/i2ptunnel.jar +file.reference.jbigi.jar=../../installer/lib/jbigi/jbigi.jar +file.reference.mstreaming.jar=../ministreaming/java/build/mstreaming.jar +file.reference.router.jar=../../router/java/build/router.jar +file.reference.streaming.jar=../streaming/java/build/streaming.jar file.reference.wrapper.jar=../../installer/lib/wrapper/linux/wrapper.jar includes=** jar.compress=false javac.classpath=\ - ${file.reference.wrapper.jar}:\ - ${file.reference.streaming.jar-1}:\ - ${file.reference.i2ptunnel.jar}:\ - ${file.reference.i2p.jar-1}:\ ${file.reference.router.jar}:\ - ${file.reference.mstreaming.jar-1}:\ - ${file.reference.mstreaming.jar-2}:\ - ${file.reference.i2p.jar-3} + ${file.reference.i2ptunnel.jar}:\ + ${file.reference.mstreaming.jar}:\ + ${file.reference.streaming.jar}:\ + ${file.reference.wrapper.jar}:\ + ${file.reference.i2p.jar}:\ + ${file.reference.router.jar} # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false diff --git a/apps/BOB/src/net/i2p/BOB/BOB.java b/apps/BOB/src/net/i2p/BOB/BOB.java index 59b46b8d74..830808a549 100644 --- a/apps/BOB/src/net/i2p/BOB/BOB.java +++ b/apps/BOB/src/net/i2p/BOB/BOB.java @@ -34,6 +34,9 @@ import java.util.Properties; import net.i2p.client.I2PClient; import net.i2p.client.streaming.RetransmissionTimer; import net.i2p.util.Log; +import net.i2p.util.SimpleScheduler; +import net.i2p.util.SimpleTimer2; + /** * * ################################################################################
@@ -157,12 +160,15 @@ public class BOB { boolean save = false; // Set up all defaults to be passed forward to other threads. // Re-reading the config file in each thread is pretty damn stupid. - // I2PClient client = I2PClientFactory.createClient(); String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "bob.config"); - // This is here just to ensure there is no interference with our threadgroups. RetransmissionTimer Y = RetransmissionTimer.getInstance(); + SimpleScheduler Y1 = SimpleScheduler.getInstance(); + SimpleTimer2 Y2 = SimpleTimer2.getInstance(); i = Y.hashCode(); + i = Y1.hashCode(); + i = Y2.hashCode(); + { try { FileInputStream fi = new FileInputStream(configLocation); diff --git a/apps/BOB/src/net/i2p/BOB/DoCMDS.java b/apps/BOB/src/net/i2p/BOB/DoCMDS.java index 099d69feca..16da28ce9c 100644 --- a/apps/BOB/src/net/i2p/BOB/DoCMDS.java +++ b/apps/BOB/src/net/i2p/BOB/DoCMDS.java @@ -46,7 +46,7 @@ public class DoCMDS implements Runnable { // FIX ME // I need a better way to do versioning, but this will do for now. - public static final String BMAJ = "00", BMIN = "00", BREV = "04", BEXT = ""; + public static final String BMAJ = "00", BMIN = "00", BREV = "05", BEXT = ""; public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT; private Socket server; private Properties props; @@ -748,14 +748,12 @@ public class DoCMDS implements Runnable { nickinfo = (NamedDB) database.get(Arg); if (!tunnelactive(nickinfo)) { nickinfo = null; - ns = - true; + ns = true; } } catch (Exception b) { nickinfo = null; - ns = - true; + ns = true; } try { @@ -775,10 +773,10 @@ public class DoCMDS implements Runnable { try { database.add(Arg, nickinfo); nickinfo.add(P_NICKNAME, Arg); - nickinfo.add(P_STARTING, Boolean.FALSE); - nickinfo.add(P_RUNNING, Boolean.FALSE); - nickinfo.add(P_STOPPING, Boolean.FALSE); - nickinfo.add(P_QUIET, Boolean.FALSE); + nickinfo.add(P_STARTING, new Boolean(false)); + nickinfo.add(P_RUNNING, new Boolean(false)); + nickinfo.add(P_STOPPING, new Boolean(false)); + nickinfo.add(P_QUIET, new Boolean(false)); nickinfo.add(P_INHOST, "localhost"); nickinfo.add(P_OUTHOST, "localhost"); Properties Q = new Properties(); @@ -1265,13 +1263,17 @@ public class DoCMDS implements Runnable { tunnel = new MUXlisten(database, nickinfo, _log); Thread t = new Thread(tunnel); t.start(); + try { + Thread.sleep(1000 * 10); // Slow down the startup. + } catch(InterruptedException ie) { + // ignore it + } out.println("OK tunnel starting"); } catch (I2PException e) { out.println("ERROR starting tunnel: " + e); } catch (IOException e) { out.println("ERROR starting tunnel: " + e); } - } } catch (Exception ex) { break die; @@ -1304,7 +1306,7 @@ public class DoCMDS implements Runnable { break die; } - nickinfo.add(P_STOPPING, Boolean.TRUE); + nickinfo.add(P_STOPPING, new Boolean(true)); try { wunlock(); diff --git a/apps/BOB/src/net/i2p/BOB/I2Plistener.java b/apps/BOB/src/net/i2p/BOB/I2Plistener.java index c59683270e..a8115893db 100644 --- a/apps/BOB/src/net/i2p/BOB/I2Plistener.java +++ b/apps/BOB/src/net/i2p/BOB/I2Plistener.java @@ -26,8 +26,6 @@ package net.i2p.BOB; import java.net.ConnectException; import java.net.SocketTimeoutException; import net.i2p.I2PException; -import net.i2p.client.I2PSession; -import net.i2p.client.I2PSessionException; import net.i2p.client.streaming.I2PServerSocket; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocketManager; @@ -42,24 +40,35 @@ public class I2Plistener implements Runnable { private NamedDB info, database; private Log _log; - private int tgwatch; +// private int tgwatch; public I2PSocketManager socketManager; public I2PServerSocket serverSocket; /** * Constructor + * @param SS * @param S * @param info * @param database * @param _log */ - I2Plistener(I2PSocketManager S, NamedDB info, NamedDB database, Log _log) { + I2Plistener(I2PServerSocket SS, I2PSocketManager S, NamedDB info, NamedDB database, Log _log) { this.database = database; this.info = info; this._log = _log; this.socketManager = S; - serverSocket = this.socketManager.getServerSocket(); - tgwatch = 1; + serverSocket = SS; +// tgwatch = 1; + } + + private void rlock() throws Exception { + database.getReadLock(); + info.getReadLock(); + } + + private void runlock() throws Exception { + database.releaseReadLock(); + info.releaseReadLock(); } /** @@ -70,68 +79,90 @@ public class I2Plistener implements Runnable { boolean g = false; I2PSocket sessSocket = null; - serverSocket.setSoTimeout(50); - database.getReadLock(); - info.getReadLock(); - if(info.exists("INPORT")) { - tgwatch = 2; - } - info.releaseReadLock(); - database.releaseReadLock(); - boolean spin = true; - while(spin) { +die: { + + serverSocket.setSoTimeout(50); +// try { +// if (info.exists("INPORT")) { +// tgwatch = 2; +// } +// } catch (Exception e) { +// try { +// runlock(); +// } catch (Exception e2) { +// break die; +// } +// break die; +// } + boolean spin = true; + while (spin) { - database.getReadLock(); - info.getReadLock(); - spin = info.get("RUNNING").equals(Boolean.TRUE); - info.releaseReadLock(); - database.releaseReadLock(); - try { try { - sessSocket = serverSocket.accept(); - g = true; - } catch(ConnectException ce) { - g = false; - } catch(SocketTimeoutException ste) { - g = false; + rlock(); + } catch (Exception e) { + break die; } - if(g) { - g = false; - // toss the connection to a new thread. - I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database); - Thread t = new Thread(conn_c, "BOBI2PtoTCP"); - t.start(); + try { + spin = info.get("RUNNING").equals(Boolean.TRUE); + } catch (Exception e) { + try { + runlock(); + } catch (Exception e2) { + break die; + } + break die; } + try { + try { + sessSocket = serverSocket.accept(); + g = true; + } catch (ConnectException ce) { + g = false; + } catch (SocketTimeoutException ste) { + g = false; + } + if (g) { + g = false; + // toss the connection to a new thread. + I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database); + Thread t = new Thread(conn_c, "BOBI2PtoTCP"); + t.start(); + } - } catch(I2PException e) { - // System.out.println("Exception " + e); + } catch (I2PException e) { + // System.out.println("Exception " + e); + } } } // System.out.println("I2Plistener: Close"); - try { - serverSocket.close(); - } catch(I2PException e) { - // nop - } - // need to kill off the socket manager too. - I2PSession session = socketManager.getSession(); - if(session != null) { - // System.out.println("I2Plistener: destroySession"); - try { - session.destroySession(); - } catch(I2PSessionException ex) { - // nop - } - } - // System.out.println("I2Plistener: Waiting for children"); - while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish - try { - Thread.sleep(100); //sleep for 100 ms (One tenth second) - } catch(Exception e) { - // nop - } - } - // System.out.println("I2Plistener: Done."); + + // Previous level does this cleanup now. + // + // try { + // serverSocket.close(); + // } catch (I2PException e) { + // nop + //} + // need to kill off the socket manager too. + // I2PSession session = socketManager.getSession(); + // if (session != null) { + // System.out.println("I2Plistener: destroySession"); + // try { + // session.destroySession(); + // } catch (I2PSessionException ex) { + // nop + // } + //} + // System.out.println("I2Plistener: Waiting for children"); + // while (Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish + // try { + // Thread.sleep(100); //sleep for 100 ms (One tenth second) + // } catch (Exception e) { + // nop + // } + //} + + // System.out.println("I2Plistener: Done."); } } diff --git a/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java b/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java index 5d24e19d36..0984823b6e 100644 --- a/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java +++ b/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java @@ -23,6 +23,7 @@ */ package net.i2p.BOB; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; @@ -105,8 +106,8 @@ die: { out.flush(); // not really needed, but... } // setup to cross the streams - TCPio conn_c = new TCPio(in, Iout, info, database); // app -> I2P - TCPio conn_a = new TCPio(Iin, out, info, database); // I2P -> app + TCPio conn_c = new TCPio(in, Iout /*, info, database */ ); // app -> I2P + TCPio conn_a = new TCPio(Iin, out /* , info, database */); // I2P -> app Thread t = new Thread(conn_c, "TCPioA"); Thread q = new Thread(conn_a, "TCPioB"); // Fire! @@ -116,7 +117,22 @@ die: { try { Thread.sleep(10); //sleep for 10 ms } catch(InterruptedException e) { - // nop + try { + in.close(); + } catch(Exception ex) { + } + try { + out.close(); + } catch(Exception ex) { + } + try { + Iin.close(); + } catch(Exception ex) { + } + try { + Iout.close(); + } catch(Exception ex) { + } } } // System.out.println("I2PtoTCP: Going away..."); diff --git a/apps/BOB/src/net/i2p/BOB/MUXlisten.java b/apps/BOB/src/net/i2p/BOB/MUXlisten.java index 89ab53fe62..dc30c5445d 100644 --- a/apps/BOB/src/net/i2p/BOB/MUXlisten.java +++ b/apps/BOB/src/net/i2p/BOB/MUXlisten.java @@ -29,10 +29,12 @@ import java.net.InetAddress; import java.net.ServerSocket; import java.util.Properties; import net.i2p.I2PException; +import net.i2p.client.I2PSession; +import net.i2p.client.I2PSessionException; +import net.i2p.client.streaming.I2PServerSocket; import net.i2p.client.streaming.I2PSocketManager; import net.i2p.client.streaming.I2PSocketManagerFactory; import net.i2p.util.Log; -import org.tanukisoftware.wrapper.WrapperManager; /** * @@ -56,8 +58,8 @@ public class MUXlisten implements Runnable { /** * Constructor Will fail if INPORT is occupied. * - * @param info - * @param database + * @param info DB entry for this tunnel + * @param database master database of tunnels * @param _log * @throws net.i2p.I2PException * @throws java.io.IOException @@ -73,9 +75,9 @@ public class MUXlisten implements Runnable { this.database.getReadLock(); this.info.getReadLock(); N = this.info.get("NICKNAME").toString(); - prikey = new ByteArrayInputStream((byte[])info.get("KEYS")); + prikey = new ByteArrayInputStream((byte[]) info.get("KEYS")); // Make a new copy so that anything else won't muck with our database. - Properties R = (Properties)info.get("PROPERTIES"); + Properties R = (Properties) info.get("PROPERTIES"); Properties Q = new Properties(); Lifted.copyProperties(R, Q); this.database.releaseReadLock(); @@ -85,7 +87,7 @@ public class MUXlisten implements Runnable { this.info.getReadLock(); this.go_out = info.exists("OUTPORT"); this.come_in = info.exists("INPORT"); - if(this.come_in) { + if (this.come_in) { port = Integer.parseInt(info.get("INPORT").toString()); host = InetAddress.getByName(info.get("INHOST").toString()); } @@ -93,14 +95,14 @@ public class MUXlisten implements Runnable { this.info.releaseReadLock(); socketManager = I2PSocketManagerFactory.createManager(prikey, Q); - if(this.come_in) { + if (this.come_in) { this.listener = new ServerSocket(port, backlog, host); } // Everything is OK as far as we can tell. this.database.getWriteLock(); this.info.getWriteLock(); - this.info.add("STARTING", Boolean.TRUE); + this.info.add("STARTING", new Boolean(true)); this.info.releaseWriteLock(); this.database.releaseWriteLock(); } @@ -130,67 +132,87 @@ public class MUXlisten implements Runnable { * */ public void run() { - + I2PServerSocket SS = null; + int ticks = 1200; // Allow 120 seconds, no more. try { wlock(); try { - info.add("RUNNING", Boolean.TRUE); - info.add("STARTING", Boolean.FALSE); - } catch(Exception e) { + info.add("RUNNING", new Boolean(true)); + } catch (Exception e) { wunlock(); return; } - } catch(Exception e) { + } catch (Exception e) { return; } try { wunlock(); - } catch(Exception e) { + } catch (Exception e) { return; } +// socketManager.addDisconnectListener(new DisconnectListener()); -quit: { +quit: + { try { tg = new ThreadGroup(N); -die: { +die: + { // toss the connections to a new threads. // will wrap with TCP and UDP when UDP works - if(go_out) { + if (go_out) { // I2P -> TCP - I2Plistener conn = new I2Plistener(socketManager, info, database, _log); + SS = socketManager.getServerSocket(); + I2Plistener conn = new I2Plistener(SS, socketManager, info, database, _log); Thread t = new Thread(tg, conn, "BOBI2Plistener " + N); t.start(); } - if(come_in) { + if (come_in) { // TCP -> I2P TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log); Thread q = new Thread(tg, conn, "BOBTCPlistener" + N); q.start(); } - boolean spin = true; - while(spin) { + try { + wlock(); try { - Thread.sleep(200); //sleep for 200 ms (Two thenths second) - } catch(InterruptedException e) { - // nop + info.add("STARTING", new Boolean(false)); + } catch (Exception e) { + wunlock(); + break die; + } + } catch (Exception e) { + break die; + } + try { + wunlock(); + } catch (Exception e) { + break die; + } + boolean spin = true; + while (spin) { + try { + Thread.sleep(1000); //sleep for 1 second + } catch (InterruptedException e) { + break die; } try { rlock(); try { spin = info.get("STOPPING").equals(Boolean.FALSE); - } catch(Exception e) { + } catch (Exception e) { runlock(); break die; } - } catch(Exception e) { + } catch (Exception e) { break die; } try { runlock(); - } catch(Exception e) { + } catch (Exception e) { break die; } } @@ -198,102 +220,186 @@ die: { try { wlock(); try { - info.add("RUNNING", Boolean.FALSE); - } catch(Exception e) { + info.add("RUNNING", new Boolean(false)); + } catch (Exception e) { wunlock(); break die; } - } catch(Exception e) { + } catch (Exception e) { break die; } try { wunlock(); - } catch(Exception e) { + } catch (Exception e) { break die; } } // die + if (SS != null) { + try { + SS.close(); + } catch (I2PException ex) { + //Logger.getLogger(MUXlisten.class.getName()).log(Level.SEVERE, null, ex); + } + } + if (this.come_in) { + try { + listener.close(); + } catch (IOException e) { + } + } + + I2PSession session = socketManager.getSession(); + if (session != null) { + // System.out.println("I2Plistener: destroySession"); + try { + session.destroySession(); + } catch (I2PSessionException ex) { + // nop + } + } try { - Thread.sleep(500); //sleep for 500 ms (One half second) - } catch(InterruptedException ex) { + socketManager.destroySocketManager(); + } catch (Exception e) { // nop } - // wait for child threads and thread groups to die + // Wait for child threads and thread groups to die // System.out.println("MUXlisten: waiting for children"); - if(tg.activeCount() + tg.activeGroupCount() != 0) { - tg.interrupt(); // unwedge any blocking threads. - while(tg.activeCount() + tg.activeGroupCount() != 0) { + if (tg.activeCount() + tg.activeGroupCount() != 0) { + while ((tg.activeCount() + tg.activeGroupCount() != 0) && ticks != 0) { + tg.interrupt(); // unwedge any blocking threads. + ticks--; try { Thread.sleep(100); //sleep for 100 ms (One tenth second) - } catch(InterruptedException ex) { - // nop + } catch (InterruptedException ex) { + break quit; } } + if (tg.activeCount() + tg.activeGroupCount() != 0) { + break quit; // Uh-oh. + } } tg.destroy(); // Zap reference to the ThreadGroup so the JVM can GC it. tg = null; - } catch(Exception e) { + } catch (Exception e) { // System.out.println("MUXlisten: Caught an exception" + e); break quit; } } // quit + // This is here to catch when something fucks up REALLY bad. - if(tg != null) { - System.out.println("BOB: MUXlisten: Something fucked up REALLY bad!"); - System.out.println("BOB: MUXlisten: Please email the following dump to sponge@mail.i2p"); - WrapperManager.requestThreadDump(); - System.out.println("BOB: MUXlisten: Something fucked up REALLY bad!"); - System.out.println("BOB: MUXlisten: Please email the above dump to sponge@mail.i2p"); - } - // zero out everything, just incase. - try { - socketManager.destroySocketManager(); - } catch(Exception e) { - // nop - } - try { - wlock(); - try { - info.add("STARTING", Boolean.FALSE); - info.add("STOPPING", Boolean.FALSE); - info.add("RUNNING", Boolean.FALSE); - } catch(Exception e) { - wunlock(); - return; + if (tg != null) { + if (SS != null) { + try { + SS.close(); + } catch (I2PException ex) { + //Logger.getLogger(MUXlisten.class.getName()).log(Level.SEVERE, null, ex); + } } - wunlock(); - } catch(Exception e) { - } - // This is here to catch when something fucks up REALLY bad. - if(tg != null) { - if(tg.activeCount() + tg.activeGroupCount() != 0) { + if (this.come_in) { + try { + listener.close(); + } catch (IOException e) { + } + } + try { + socketManager.destroySocketManager(); + } catch (Exception e) { + // nop + } + ticks = 600; // 60 seconds + if (tg.activeCount() + tg.activeGroupCount() != 0) { + while ((tg.activeCount() + tg.activeGroupCount() != 0) && ticks != 0) { tg.interrupt(); // unwedge any blocking threads. - while(tg.activeCount() + tg.activeGroupCount() != 0) { + ticks--; try { Thread.sleep(100); //sleep for 100 ms (One tenth second) - } catch(InterruptedException ex) { + } catch (InterruptedException ex) { // nop } } } - tg.destroy(); - // Zap reference to the ThreadGroup so the JVM can GC it. - tg = null; - } - - // Lastly try to close things again. - if(this.come_in) { - try { - listener.close(); - } catch(IOException e) { + if (tg.activeCount() + tg.activeGroupCount() == 0) { + tg.destroy(); + // Zap reference to the ThreadGroup so the JVM can GC it. + tg = null; + } else { + System.out.println("BOB: MUXlisten: Can't kill threads. Please send the following dump to sponge@mail.i2p"); + System.out.println("\n\nBOB: MUXlisten: ThreadGroup dump BEGIN"); + visit(tg, 0); + System.out.println("BOB: MUXlisten: ThreadGroup dump END\n\n"); } } + + // This is here to catch when something fucks up REALLY bad. +// if (tg != null) { +// System.out.println("BOB: MUXlisten: Something fucked up REALLY bad!"); +// System.out.println("BOB: MUXlisten: Please email the following dump to sponge@mail.i2p"); +// WrapperManager.requestThreadDump(); +// System.out.println("BOB: MUXlisten: Something fucked up REALLY bad!"); +// System.out.println("BOB: MUXlisten: Please email the above dump to sponge@mail.i2p"); +// } + // zero out everything. try { - socketManager.destroySocketManager(); - } catch(Exception e) { - // nop + wlock(); + try { + info.add("STARTING", new Boolean(false)); + info.add("STOPPING", new Boolean(false)); + info.add("RUNNING", new Boolean(false)); + } catch (Exception e) { + wunlock(); + return; + } + wunlock(); + } catch (Exception e) { } } + + + // Debugging... + + /** + * Find the root thread group and print them all. + * + */ + private void visitAllThreads() { + ThreadGroup root = Thread.currentThread().getThreadGroup().getParent(); + while (root.getParent() != null) { + root = root.getParent(); + } + + // Visit each thread group + visit(root, 0); + } + + /** + * Recursively visits all thread groups under `group' and dumps them. + * @param group ThreadGroup to visit + * @param level Current level + */ + private static void visit(ThreadGroup group, int level) { + // Get threads in `group' + int numThreads = group.activeCount(); + Thread[] threads = new Thread[numThreads * 2]; + numThreads = group.enumerate(threads, false); + String indent = "------------------------------------".substring(0, level) + "-> "; + // Enumerate each thread in `group' and print it. + for (int i = 0; i < numThreads; i++) { + // Get thread + Thread thread = threads[i]; + System.out.println("BOB: MUXlisten: " + indent + thread.toString()); + } + + // Get thread subgroups of `group' + int numGroups = group.activeGroupCount(); + ThreadGroup[] groups = new ThreadGroup[numGroups * 2]; + numGroups = group.enumerate(groups, false); + + // Recursively visit each subgroup + for (int i = 0; i < numGroups; i++) { + visit(groups[i], level + 1); + } + } } diff --git a/apps/BOB/src/net/i2p/BOB/Main.java b/apps/BOB/src/net/i2p/BOB/Main.java index 2d81fb30ed..aa56e83e02 100644 --- a/apps/BOB/src/net/i2p/BOB/Main.java +++ b/apps/BOB/src/net/i2p/BOB/Main.java @@ -24,7 +24,8 @@ package net.i2p.BOB; import net.i2p.client.streaming.RetransmissionTimer; - +import net.i2p.util.SimpleScheduler; +import net.i2p.util.SimpleTimer2; /** * Start from command line * @@ -39,7 +40,13 @@ public class Main { public static void main(String[] args) { // THINK THINK THINK THINK THINK THINK RetransmissionTimer Y = RetransmissionTimer.getInstance(); + SimpleScheduler Y1 = SimpleScheduler.getInstance(); + SimpleTimer2 Y2 = SimpleTimer2.getInstance(); + BOB.main(args); + + Y2.stop(); + Y1.stop(); Y.stop(); } } diff --git a/apps/BOB/src/net/i2p/BOB/TCPio.java b/apps/BOB/src/net/i2p/BOB/TCPio.java index c9f4ab64cd..d4b353c549 100644 --- a/apps/BOB/src/net/i2p/BOB/TCPio.java +++ b/apps/BOB/src/net/i2p/BOB/TCPio.java @@ -23,6 +23,7 @@ */ package net.i2p.BOB; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -35,21 +36,21 @@ public class TCPio implements Runnable { private InputStream Ain; private OutputStream Aout; - private NamedDB info, database; + // private NamedDB info, database; /** * Constructor * - * @param Ain - * @param Aout - * @param info - * @param database + * @param Ain InputStream + * @param Aout OutputStream + * + * param database */ - TCPio(InputStream Ain, OutputStream Aout, NamedDB info, NamedDB database) { + TCPio(InputStream Ain, OutputStream Aout /*, NamedDB info , NamedDB database */) { this.Ain = Ain; this.Aout = Aout; - this.info = info; - this.database = database; + // this.info = info; + // this.database = database; } /** @@ -86,11 +87,11 @@ public class TCPio implements Runnable { boolean spin = true; try { while(spin) { - database.getReadLock(); - info.getReadLock(); - spin = info.get("RUNNING").equals(Boolean.TRUE); - info.releaseReadLock(); - database.releaseReadLock(); + // database.getReadLock(); + // info.getReadLock(); + // spin = info.get("RUNNING").equals(Boolean.TRUE); + // info.releaseReadLock(); + // database.releaseReadLock(); b = Ain.read(a, 0, 1); // System.out.println(info.get("NICKNAME").toString() + " " + b); if(b > 0) { @@ -98,11 +99,11 @@ public class TCPio implements Runnable { } else if(b == 0) { Thread.yield(); // this should act like a mini sleep. if(Ain.available() == 0) { - try { +// try { // Thread.yield(); Thread.sleep(10); - } catch(InterruptedException ex) { - } +// } catch(InterruptedException ex) { +// } } } else { /* according to the specs: @@ -113,13 +114,25 @@ public class TCPio implements Runnable { * */ // System.out.println("TCPio: End Of Stream"); + Ain.close(); + Aout.close(); return; } } // System.out.println("TCPio: RUNNING = false"); } catch(Exception e) { // Eject!!! Eject!!! - // System.out.println("TCPio: Caught an exception " + e); + //System.out.println("TCPio: Caught an exception " + e); + try { + Ain.close(); + } catch (IOException ex) { +// Logger.getLogger(TCPio.class.getName()).log(Level.SEVERE, null, ex); + } + try { + Aout.close(); + } catch (IOException ex) { +// Logger.getLogger(TCPio.class.getName()).log(Level.SEVERE, null, ex); + } return; } // System.out.println("TCPio: Leaving."); diff --git a/apps/BOB/src/net/i2p/BOB/TCPlistener.java b/apps/BOB/src/net/i2p/BOB/TCPlistener.java index 30380a55dd..78155eb787 100644 --- a/apps/BOB/src/net/i2p/BOB/TCPlistener.java +++ b/apps/BOB/src/net/i2p/BOB/TCPlistener.java @@ -27,8 +27,8 @@ import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; -import net.i2p.client.I2PSession; -import net.i2p.client.I2PSessionException; +// import net.i2p.client.I2PSession; +// import net.i2p.client.I2PSessionException; import net.i2p.client.streaming.I2PServerSocket; import net.i2p.client.streaming.I2PSocketManager; import net.i2p.util.Log; @@ -63,6 +63,26 @@ public class TCPlistener implements Runnable { tgwatch = 1; } + private void rlock() throws Exception { + database.getReadLock(); + info.getReadLock(); + } + + private void runlock() throws Exception { + database.releaseReadLock(); + info.releaseReadLock(); + } + + private void wlock() throws Exception { + database.getWriteLock(); + info.getWriteLock(); + } + + private void wunlock() throws Exception { + info.releaseWriteLock(); + database.releaseWriteLock(); + } + /** * Simply listen on TCP port, and thread connections * @@ -70,77 +90,123 @@ public class TCPlistener implements Runnable { public void run() { boolean g = false; boolean spin = true; - database.getReadLock(); - info.getReadLock(); - if(info.exists("OUTPORT")) { - tgwatch = 2; - } - try { - Socket server = new Socket(); - listener.setSoTimeout(50); // Half of the expected time from MUXlisten - info.releaseReadLock(); - database.releaseReadLock(); - while(spin) { - database.getReadLock(); - info.getReadLock(); - spin = info.get("RUNNING").equals(Boolean.TRUE); - info.releaseReadLock(); - database.releaseReadLock(); - try { - server = listener.accept(); - g = true; - } catch(SocketTimeoutException ste) { - g = false; - } - if(g) { - // toss the connection to a new thread. - TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info, database); - Thread t = new Thread(conn_c, "BOBTCPtoI2P"); - t.start(); - g = false; - } - } - //System.out.println("TCPlistener: destroySession"); - listener.close(); - } catch(IOException ioe) { - try { - listener.close(); - } catch(IOException e) { - } - // Fatal failure, cause a stop event - database.getReadLock(); - info.getReadLock(); - spin = info.get("RUNNING").equals(Boolean.TRUE); - info.releaseReadLock(); - database.releaseReadLock(); - if(spin) { - database.getWriteLock(); - info.getWriteLock(); - info.add("STOPPING", new Boolean(true)); - info.add("RUNNING", new Boolean(false)); - info.releaseWriteLock(); - database.releaseWriteLock(); - } - } - // need to kill off the socket manager too. - I2PSession session = socketManager.getSession(); - if(session != null) { +die: { try { - session.destroySession(); - } catch(I2PSessionException ex) { - // nop + rlock(); + } catch (Exception e) { + break die; + } + try { + if (info.exists("OUTPORT")) { + tgwatch = 2; + } + } catch (Exception e) { + try { + runlock(); + } catch (Exception e2) { + break die; + } + break die; + } + try { + runlock(); + } catch (Exception e) { + break die; + } + try { + Socket server = new Socket(); + listener.setSoTimeout(50); // Half of the expected time from MUXlisten + while (spin) { + try { + rlock(); + } catch (Exception e) { + break die; + } + try { + spin = info.get("RUNNING").equals(Boolean.TRUE); + } catch (Exception e) { + try { + runlock(); + } catch (Exception e2) { + break die; + } + break die; + } + try { + server = listener.accept(); + g = true; + } catch (SocketTimeoutException ste) { + g = false; + } + if (g) { + // toss the connection to a new thread. + TCPtoI2P conn_c = new TCPtoI2P(socketManager, server /* , info, database */); + Thread t = new Thread(conn_c, "BOBTCPtoI2P"); + t.start(); + g = false; + } + } + //System.out.println("TCPlistener: destroySession"); + listener.close(); + } catch (IOException ioe) { + try { + listener.close(); + } catch (IOException e) { + } + // Fatal failure, cause a stop event + try { + rlock(); + try { + spin = info.get("RUNNING").equals(Boolean.TRUE); + } catch (Exception e) { + runlock(); + break die; + } + } catch (Exception e) { + break die; + } + if (spin) { + try { + wlock(); + try { + info.add("STOPPING", new Boolean(true)); + info.add("RUNNING", new Boolean(false)); + } catch (Exception e) { + wunlock(); + break die; + } + } catch (Exception e) { + break die; + } + try { + wunlock(); + } catch (Exception e) { + break die; + } + } } } - //System.out.println("TCPlistener: Waiting for children"); - while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish - try { - Thread.sleep(100); //sleep for 100 ms (One tenth second) - } catch(Exception e) { + // Previous level does this cleanup now. + // + // need to kill off the socket manager too. + // I2PSession session = socketManager.getSession(); + // if (session != null) { + // try { + // session.destroySession(); + // } catch (I2PSessionException ex) { // nop - } - } - //System.out.println("TCPlistener: Done."); + // } + //} + //System.out.println("TCPlistener: Waiting for children"); + //while (Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish + // try { + // Thread.sleep(100); //sleep for 100 ms (One tenth second) + // } catch (Exception e) { + // // nop + // } + //} + //System.out.println("TCPlistener: Done."); } } diff --git a/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java b/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java index df61e78e1b..c376e16fe1 100644 --- a/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java +++ b/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java @@ -45,7 +45,7 @@ import net.i2p.i2ptunnel.I2PTunnel; public class TCPtoI2P implements Runnable { private I2PSocket I2P; - private NamedDB info, database; + // private NamedDB info, database; private Socket sock; private I2PSocketManager socketManager; @@ -84,13 +84,13 @@ public class TCPtoI2P implements Runnable { * Constructor * @param i2p * @param socket - * @param info - * @param database + * param info + * param database */ - TCPtoI2P(I2PSocketManager i2p, Socket socket, NamedDB info, NamedDB database) { + TCPtoI2P(I2PSocketManager i2p, Socket socket /*, NamedDB info, NamedDB database */) { this.sock = socket; - this.info = info; - this.database = database; + // this.info = info; + // this.database = database; this.socketManager = i2p; } @@ -110,14 +110,19 @@ public class TCPtoI2P implements Runnable { /** * TCP stream to I2P stream thread starter + * */ public void run() { String line, input; + InputStream Iin = null; + OutputStream Iout = null; + InputStream in = null; + OutputStream out = null; try { - InputStream in = sock.getInputStream(); - OutputStream out = sock.getOutputStream(); + in = sock.getInputStream(); + out = sock.getOutputStream(); try { line = lnRead(in); input = line.toLowerCase(); @@ -135,22 +140,22 @@ public class TCPtoI2P implements Runnable { I2P = socketManager.connect(dest); I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default // make readers/writers - InputStream Iin = I2P.getInputStream(); - OutputStream Iout = I2P.getOutputStream(); + Iin = I2P.getInputStream(); + Iout = I2P.getOutputStream(); // setup to cross the streams - TCPio conn_c = new TCPio(in, Iout, info, database); // app -> I2P - TCPio conn_a = new TCPio(Iin, out, info, database); // I2P -> app + TCPio conn_c = new TCPio(in, Iout /*, info, database */); // app -> I2P + TCPio conn_a = new TCPio(Iin, out /*, info, database */); // I2P -> app Thread t = new Thread(conn_c, "TCPioA"); Thread q = new Thread(conn_a, "TCPioB"); // Fire! t.start(); q.start(); while(t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread - try { +// try { Thread.sleep(10); //sleep for 10 ms - } catch(InterruptedException e) { +// } catch(InterruptedException e) { // nop - } +// } } // System.out.println("TCPtoI2P: Going away..."); @@ -167,7 +172,24 @@ public class TCPtoI2P implements Runnable { } catch(Exception e) { Emsg("ERROR " + e.toString(), out); } - } catch(IOException ioe) { + } catch(Exception e) { + // bail on anything else + } + try { + in.close(); + } catch(Exception e) { + } + try { + out.close(); + } catch(Exception e) { + } + try { + Iin.close(); + } catch(Exception e) { + } + try { + Iout.close(); + } catch(Exception e) { } try { // System.out.println("TCPtoI2P: Close I2P"); @@ -181,6 +203,5 @@ public class TCPtoI2P implements Runnable { } catch(Exception e) { } // System.out.println("TCPtoI2P: Done."); - } } diff --git a/apps/desktopgui/LICENSE b/apps/desktopgui/LICENSE new file mode 100644 index 0000000000..61febe9011 --- /dev/null +++ b/apps/desktopgui/LICENSE @@ -0,0 +1,15 @@ +Desktop GUI: provides a simple GUI for I2P. +Copyright (C) 2009 Mathias De Maré + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; only version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. \ No newline at end of file diff --git a/apps/desktopgui/build.xml b/apps/desktopgui/build.xml new file mode 100644 index 0000000000..77bd6d7785 --- /dev/null +++ b/apps/desktopgui/build.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + Builds, tests, and runs the project desktopgui. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/desktopgui/desktopgui/resources/howto/howto.html b/apps/desktopgui/desktopgui/resources/howto/howto.html new file mode 100644 index 0000000000..ea1b025c7b --- /dev/null +++ b/apps/desktopgui/desktopgui/resources/howto/howto.html @@ -0,0 +1,261 @@ + + + Small Guide to I2P + + +

Small Guide to I2P

+ +

So, what's this all about?

+ +

I2P builds up a new net inside the usual internet, connecting nodes together + via encrypted connections. + It is a JAVA prgram with its most used part (the encryption of the data) written + in handoptimized assembler code. + It will use your bandwith, your RAM and your CPU. It will use them all up if you + do not limit it. + I2P will route unknown traffic through your node, even stuff you dislike. + As that data is encrypted, nobody knows whats data went to or drom your node. +

+ +

+ First, ALWAYS use the latest stable release. + Development releases are called "mtn version" and are marked with a -, e.g. + 0.6.5-1. Those are usually useable by all but could do harm to your I2P + experience. + You can get the latest MTN builds from my eepsite echelon.i2p, but always + remember: I built them, you need to trust me not to changed the code! + After you get the right "i2pupdate.zip" file, put that file into the I2P + directory and hit restart on the router console http://127.0.0.1:7657. + Do NOT deflate the zip file! +

+ +

+ I2P is very dynamic - after startup it tries to get known to other I2P routers + and measures their speed - you need to wait some 10-120 minutes until your + I2P router knows enough other ones to obtain full power of I2P. +

+ +

Filesharing

+ +

+ I2P is able to do anonymous filesharing. + But as there are NO gateways between real net and I2P, you can only share/ + download torrents from within I2P. Look e.g. postman.i2p or planet.i2p. + You CANNOT use azureus, utorrent or any other usual client. + You cannot download anonymous torrents from mininova, piratebay or else. + You need to use I2P internal torrents and I2P aware programs like + I2Psnark (builtin, suitable for 1-20 torrents) + I2PRufus (external, python, high CPU load, suitable >20 torrents) http://echelon.i2p/i2prufus + I2P-BT (external, python) + I2PsnarkXL (mod of I2Psnark made by fwd) +

+ +

+ There are also gnutella and edonkey clients: + i2phex for gnutella (http://echelon.i2p/i2phex) + imule for edonkey (http://echelon.i2p/imule) +

+ +

+ Remember, as I2P uses other routers to route your traffic via 1-6 other PCs, + your transferrates in P2P are slower than in usual internet. + But you are anonymous, no one can easily (within 2 months-2 years) get your IP! + torrents inside of I2P reaches up to 50 kb/sec, usual are 10-20 kb/sec per torrent + i2phex reaches up to 20 kb/sec, usually 5-10 kb/sec + imule in times reaches 10 kb/sec, usually 5-10 kb/sec +

+ +

+ In I2PHex and imule you can just tell "share file or directory", in torrent + you need to create a .torrent file and upload that (and ONLY that small .torrent) + file to the trackers like tracker.postman.i2p/ +

+ +

+ I2P is a smaller net (1000 users) which grows slowly. As of which amount of shared + data will slowly rise. +

+ +

+ I2P is anonymous and it does not censor - there is no administrator. + There IS unwanted stuff like kiddyporn, nazism, or else. + If you dislike all this, do not use I2P. + There is NO way to prohibite this stuff to appear in a anonymous net like I2P. + (as that stuff is available shows the anonymity and transfer function of I2P + is working well enough) + You can delete the destinations in question from your local hosts.txt file (or + deface them) which will partly prevent you to reach those bad sies by accident. +

+ +

Internet (the websites)

+ +

+ Only one outproxy (gateway I2P - webpages in usual Internet) is working. + It is NOT official from I2P, I2P does work without. + If that outproxy is slow, offline, gone,.. I2P still works on and cannot do + anything to change that failure. + That outproxy translates usual internet webpages into the I2P net and you can + reach them via your Router. + The best way for usual webpages is TOR, not that outproxy. + Remember: the owner of the outproxy got ALL traffic from all I2P users + visiting Internet pages and will risk that into the police! +

+ +

+ This proxy is false.i2p. In newer I2P routers it is enabled, but not in + older ones. Go to http://127.0.0.1:7657/i2ptunnel/index.jsp tunnels page and + click on the eepProxy tunnel. Change the entry for the "Outproxies" to false.i2p + and save. On the tunnels page, stop the epproxy tunnel and start it again, + now your router will use the false.i2p outproxy. +

+ +

+ No other (known) gateways are setup and running. No one we know will run + the gateway for torrent or any other P2P data (and risk his life). +

+ +

Bandwidth

+ +

http://127.0.0.1:7657/config.jsp

+ +

Setup your bandwith wisely. Know your linespeed!

+ +

+ E.g. most common terms are: + 1Mbit = roughly 100 kbyte/sec + 10 MBit = roughly 1100 kbyte/sec + 512 kbit = roughly 50 kbyte/sec + or in germany: + 16000er = roughly 1500 kbyte/sec + 6000er = roughly 600 kbyte/sec + 1000er = roughly 100 kb/sec +

+ +

+ Set your bandwith limits to 10% under your line speed and burst rate to + your line speed. + Set the bandwith share percentage to: + >80% if lowest bandwith setting is >50k + >50% if lowest bandwith setting is >30k + >20% if lowest bandwith setting is >16k +

+ +

There is no shared bandwith under 16k.

+ +

+ Limit your participating tunnels (shared bandwith) on: + http://127.0.0.1:7657/configadvanced.jsp + with the line: + router.maxParticipatingTunnels=500 +

+ +

+ 2000 is for roughly 600 kb/sec - very high value with high CPU load + 1000 is for roughly 300 kb/sec + 600 is a good value for 150-200kb/sec + 300 is roughly 90 kb/sec + 150 roughly 50 kb/sec + Remember: even failed tunnel requests will result in a part tunnel on the hops in between! + Those said, there are far more part tunnels unused than used in the live net under load, which + results in slower bandwith per tunnel in the end. + It is wise to first limit the bandwith and afterwards the part tunnels, e.g. set some more part + tunnels and let I2P reach the bandwith limit instead of the part tunnels limit! +

+ +

What is shared bandwidth?

+ +

+ I2P transports your date from the client to the server through 1-6 hops + (other I2P routers). Each of this hops sees the data from you as "participating + tunnel" - which is the shared bandwith of them. + With this in mind, I2P needs some amount of this shared bandwith at some + amount of routers. + Share as much as you are able of - others will thank you! +

+ +

+ With the "share percentage" set like above, you will obtain enough speed for + your own traffic and obtain some participating tunnels (if >16kb/sec) with some + noise traffic to hide your traffic in the stream. +

+ +

+ With release 0.6.5 there is some method to prefer your own traffic ahead + of shared traffic which will result in better experience to you! +

+ +

Addressbook

+ +

+ I2P uses a local addressbook to link short DNS names with the internal used 512bit + hashes (which are destination IDs). + Those links are saved insside the hosts.txt and userhosts.txt files in the i2p + directory. + Hosts which are not in those files cannot be reached via the short DNS names + and a error message with "jumper links" will appear. Those links will ask + some hosts services and forward to the correct site (if the site is known to them). + Those hosts services just made a form to add new "hosts" and those results public + available. + You can subscribe to those hosts service and let your hosts.txt file be updated + automatic. Go to http://127.0.0.1:7657/susidns/subscriptions.jsp SusiDNS + and enter the hosts services into the textbox (and save afterwards): + http://www.i2p2.i2p/hosts.txt + http://stats.i2p/cgi-bin/newhosts.txt + http://tino.i2p/hosts.txt + http://i2host.i2p/cgi-bin/i2hostag + You can add one of them, two or all. + SusiDNS will now ask those hosts for new entries to the hosts.txt and those + will be added to your hosts.txt. The userhosts.txt will ONLY be updated by + yourself (the user) and not be published into the net! + Remember, names once set could not be changed! If you loose your key (destination + ID) to your eepsite, service,..., there is no way to change the linking + between the DNS name and the (lost) destination ID automatic! Only manual by each + user itself - great topic to discuss of need to renew DNS hostnames. + As this subscription will not update old entries, you can "deface" unwanted + eepsites with a false key and if you hit the bad name in browser by accident, + you will not see the bad stuff! +

+ +

Out of Memory errors

+ +

+ If your router hits the Out of Memory error - check your logs! + Usual point for OOM are to much torrents in i2psnark - i2psnark is a real + memory hogg and >10 torrents it requiers hell a lot of memory! +

+ +

+ Maybe it is possible for you to increase the wrapper memory config. + This ONLY works if you start the I2P service restartable with console + (on Windows). + In I2P directory edit the wrapper.config file and change the values: + wrapper.java.maxmemory=256 (or even to 512, IF possible) + Afterwards shutdown I2P complete (the service) and restart it. +

+ +

Blocklists

+ +

+ Sometimes attackers trying to flood the I2P net and try to do some harm. + And some folks setting localnet IPs as their internet reachable address. + To prevent those bad router to harm the local router, I2P implemented + a local blocklist system. It is NOT integrated automatic as it could + really harm your I2P experience if setup the wrong way. + The way to enable blocklists is: + Get the file http://zzz.i2p/files/blocklist.txt and copy this file into the + I2P directory. + On http://127.0.0.1:7657/configadvanced.jsp set the option + router.blocklist.enable=true - click on Apply and restart the router + with the restart link left on router console. + The blockfile.txt file follows a special order, you´ll get it if you read it. + The first entry is the reason to be shown on http://127.0.0.1:7657/profiles.jsp + at the bottom in the shitlist section. + The second entry is the IP or the dest ID of a router. + Right now there are only private subnets in the blocklist AND one chinese router + which floods the floodfill DB while restarting every few minutes with a different + router ID and far to less bandwith for being a floodfill router. +

+ +

(By echelon -- echelon.i2p )

+ + diff --git a/apps/desktopgui/desktopgui/resources/logo/logo.jpg b/apps/desktopgui/desktopgui/resources/logo/logo.jpg new file mode 100644 index 0000000000..f1b5ccfc87 Binary files /dev/null and b/apps/desktopgui/desktopgui/resources/logo/logo.jpg differ diff --git a/apps/desktopgui/desktopgui/resources/logo/logo_green.jpg b/apps/desktopgui/desktopgui/resources/logo/logo_green.jpg new file mode 100644 index 0000000000..9a29b6d1c3 Binary files /dev/null and b/apps/desktopgui/desktopgui/resources/logo/logo_green.jpg differ diff --git a/apps/desktopgui/desktopgui/resources/logo/logo_orange.jpg b/apps/desktopgui/desktopgui/resources/logo/logo_orange.jpg new file mode 100644 index 0000000000..137a25e7a0 Binary files /dev/null and b/apps/desktopgui/desktopgui/resources/logo/logo_orange.jpg differ diff --git a/apps/desktopgui/desktopgui/resources/logo/logo_red.jpg b/apps/desktopgui/desktopgui/resources/logo/logo_red.jpg new file mode 100644 index 0000000000..1da8983812 Binary files /dev/null and b/apps/desktopgui/desktopgui/resources/logo/logo_red.jpg differ diff --git a/apps/desktopgui/lib/appframework.jar b/apps/desktopgui/lib/appframework.jar new file mode 100644 index 0000000000..0b8ff0145f Binary files /dev/null and b/apps/desktopgui/lib/appframework.jar differ diff --git a/apps/desktopgui/lib/swing-worker.jar b/apps/desktopgui/lib/swing-worker.jar new file mode 100644 index 0000000000..bcdd9d9102 Binary files /dev/null and b/apps/desktopgui/lib/swing-worker.jar differ diff --git a/apps/desktopgui/manifest.mf b/apps/desktopgui/manifest.mf new file mode 100644 index 0000000000..328e8e5bc3 --- /dev/null +++ b/apps/desktopgui/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/apps/desktopgui/nbproject/build-impl.xml b/apps/desktopgui/nbproject/build-impl.xml new file mode 100644 index 0000000000..f8fea458d1 --- /dev/null +++ b/apps/desktopgui/nbproject/build-impl.xml @@ -0,0 +1,629 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + diff --git a/apps/desktopgui/nbproject/genfiles.properties b/apps/desktopgui/nbproject/genfiles.properties new file mode 100644 index 0000000000..1b326007c7 --- /dev/null +++ b/apps/desktopgui/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=c4b345cd +build.xml.script.CRC32=9785bb9a +build.xml.stylesheet.CRC32=be360661 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=c4b345cd +nbproject/build-impl.xml.script.CRC32=74d3fda2 +nbproject/build-impl.xml.stylesheet.CRC32=487672f9 diff --git a/apps/desktopgui/nbproject/project.properties b/apps/desktopgui/nbproject/project.properties new file mode 100644 index 0000000000..b7a05f8ed6 --- /dev/null +++ b/apps/desktopgui/nbproject/project.properties @@ -0,0 +1,77 @@ +application.desc=An anonymous communication network. +application.homepage=http://www.i2p2.de +application.title=I2P Desktop GUI +application.vendor=I2P Developers +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/desktopgui.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +file.reference.appframework.jar=lib/appframework.jar +file.reference.i2p.jar=../../core/java/build/i2p.jar +file.reference.router.jar=../../router/java/build/router.jar +file.reference.swing-worker.jar=lib/swing-worker.jar +includes=** +jar.compress=false +javac.classpath=\ + ${file.reference.router.jar}:\ + ${file.reference.appframework.jar}:\ + ${file.reference.swing-worker.jar}:\ + ${file.reference.i2p.jar} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.6 +javac.target=1.6 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit.classpath}:\ + ${libs.junit_4.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.encoding.used=${javadoc.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +jnlp.codebase.type=local +jnlp.codebase.url=file:/home/mathias/Documenten/Programmeren/i2p_monotone/repo/i2p.i2p/apps/desktopgui/dist/ +jnlp.enabled=false +jnlp.offline-allowed=false +jnlp.signed=false +main.class=desktopgui.Main +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/apps/desktopgui/nbproject/project.xml b/apps/desktopgui/nbproject/project.xml new file mode 100644 index 0000000000..09409a64cd --- /dev/null +++ b/apps/desktopgui/nbproject/project.xml @@ -0,0 +1,19 @@ + + + org.netbeans.modules.java.j2seproject + + + desktopgui + 1.6.5 + + + + + + + + + + + + diff --git a/apps/desktopgui/src/META-INF/services/org.jdesktop.application.Application b/apps/desktopgui/src/META-INF/services/org.jdesktop.application.Application new file mode 100644 index 0000000000..6cd2ac1fb1 --- /dev/null +++ b/apps/desktopgui/src/META-INF/services/org.jdesktop.application.Application @@ -0,0 +1 @@ +desktopgui.Main \ No newline at end of file diff --git a/apps/desktopgui/src/desktopgui/Main.java b/apps/desktopgui/src/desktopgui/Main.java new file mode 100644 index 0000000000..9d9708c8dd --- /dev/null +++ b/apps/desktopgui/src/desktopgui/Main.java @@ -0,0 +1,109 @@ +package desktopgui; + +/* + * Main.java + */ + + + +import gui.Tray; +import gui.SpeedSelector; +import java.awt.SystemTray; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import org.jdesktop.application.Application; +import org.jdesktop.application.SingleFrameApplication; +import persistence.PropertyManager; + +/** + * The main class of the application. + */ +public class Main extends SingleFrameApplication { + + /** + * At startup create and show the main frame of the application. + */ + @Override protected void startup() { + Properties props = PropertyManager.loadProps(); + + //First load: present screen with information (to help choose I2P settings) + if(props.getProperty(FIRSTLOAD).equals("true")) { + props.setProperty(FIRSTLOAD, "false"); + PropertyManager.saveProps(props); + new SpeedSelector(); //Start speed selector GUI + } + + if(SystemTray.isSupported()) { + tray = new Tray(); + } + else { //Alternative if SystemTray is not supported on the platform + } + } + + /** + * This method is to initialize the specified window by injecting resources. + * Windows shown in our application come fully initialized from the GUI + * builder, so this additional configuration is not needed. + */ + @Override protected void configureWindow(java.awt.Window root) { + } + + /** + * A convenient static getter for the application instance. + * @return the instance of Main + */ + public static Main getApplication() { + return Application.getInstance(Main.class); + } + + /** + * Main method launching the application. + */ + public static void main(String[] args) { + System.setProperty("java.awt.headless", "false"); //Make sure I2P is running in GUI mode for our application + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } catch (InstantiationException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } catch (UnsupportedLookAndFeelException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + + Main main = getApplication(); + main.launchForeverLoop(); + main.startup(); + } + + /** + * Avoids the app terminating because no Window is opened anymore. + * More info: http://java.sun.com/javase/6/docs/api/java/awt/doc-files/AWTThreadIssues.html#Autoshutdown + */ + public void launchForeverLoop() { + Runnable r = new Runnable() { + public void run() { + try { + Object o = new Object(); + synchronized (o) { + o.wait(); + } + } catch (InterruptedException ie) { + } + } + }; + Thread t = new Thread(r); + t.setDaemon(false); + t.start(); + } + + private Tray tray = null; + ///Indicates if this is the first time the application loads + ///(is only true at the very start of loading the first time!) + private static final String FIRSTLOAD = "firstLoad"; +} diff --git a/apps/desktopgui/src/desktopgui/resources/Main.properties b/apps/desktopgui/src/desktopgui/resources/Main.properties new file mode 100644 index 0000000000..fb7218ceae --- /dev/null +++ b/apps/desktopgui/src/desktopgui/resources/Main.properties @@ -0,0 +1,11 @@ +# Application global resources + +Application.name = desktopgui +Application.title = I2P Desktop GUI +Application.version = 0.7.1 +Application.vendor = I2P Developers +Application.homepage = http://www.i2p2.de +Application.description = An anonymous communication network. +Application.vendorId = I2P +Application.id = desktopgui +Application.lookAndFeel = system diff --git a/apps/desktopgui/src/desktopgui/resources/Main_nl_BE.properties b/apps/desktopgui/src/desktopgui/resources/Main_nl_BE.properties new file mode 100644 index 0000000000..81107aca91 --- /dev/null +++ b/apps/desktopgui/src/desktopgui/resources/Main_nl_BE.properties @@ -0,0 +1,11 @@ +# Application global resources + +Application.name = desktopgui +Application.title = I2P Desktop GUI +Application.version = 0.7.1 +Application.vendor = I2P Ontwikkelaars +Application.homepage = http://www.i2p2.de +Application.description = Een anoniem communicatienetwerk. +Application.vendorId = I2P +Application.id = desktopgui +Application.lookAndFeel = system diff --git a/apps/desktopgui/src/gui/GeneralConfiguration.form b/apps/desktopgui/src/gui/GeneralConfiguration.form new file mode 100644 index 0000000000..070e201382 --- /dev/null +++ b/apps/desktopgui/src/gui/GeneralConfiguration.form @@ -0,0 +1,103 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/apps/desktopgui/src/gui/GeneralConfiguration.java b/apps/desktopgui/src/gui/GeneralConfiguration.java new file mode 100644 index 0000000000..b9c7403813 --- /dev/null +++ b/apps/desktopgui/src/gui/GeneralConfiguration.java @@ -0,0 +1,106 @@ +/* + * GeneralConfiguration.java + * + * Created on 10 april 2009, 19:04 + */ + +package gui; + +/** + * + * @author mathias + */ +public class GeneralConfiguration extends javax.swing.JFrame { + + /** Creates new form GeneralConfiguration */ + public GeneralConfiguration() { + initComponents(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jTabbedPane1 = new javax.swing.JTabbedPane(); + jPanel1 = new javax.swing.JPanel(); + jPanel2 = new javax.swing.JPanel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setName("Form"); // NOI18N + + jTabbedPane1.setName("jTabbedPane1"); // NOI18N + + jPanel1.setName("jPanel1"); // NOI18N + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 474, Short.MAX_VALUE) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 338, Short.MAX_VALUE) + ); + + org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(GeneralConfiguration.class); + jTabbedPane1.addTab(resourceMap.getString("jPanel1.TabConstraints.tabTitle"), jPanel1); // NOI18N + + jPanel2.setName("jPanel2"); // NOI18N + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 474, Short.MAX_VALUE) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 338, Short.MAX_VALUE) + ); + + jTabbedPane1.addTab(resourceMap.getString("jPanel2.TabConstraints.tabTitle"), jPanel2); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 478, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 369, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + new GeneralConfiguration().setVisible(true); + } + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JTabbedPane jTabbedPane1; + // End of variables declaration//GEN-END:variables + +} diff --git a/apps/desktopgui/src/gui/JPopupTrayIcon.java b/apps/desktopgui/src/gui/JPopupTrayIcon.java new file mode 100644 index 0000000000..83872e4a51 --- /dev/null +++ b/apps/desktopgui/src/gui/JPopupTrayIcon.java @@ -0,0 +1,176 @@ +/* +* Created on Sep 15, 2008 5:51:33 PM +*/ + +/* + * This class is part of fishfarm project: https://fishfarm.dev.java.net/ + * It is licensed under the GPL version 2.0 with Classpath Exception. + * + * Copyright (C) 2008 Michael Bien + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +package gui; + +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.TrayIcon; +import java.awt.Window; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JWindow; +import javax.swing.RootPaneContainer; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; + + + +/** + * JPopupMenu compatible TrayIcon based on Alexander Potochkin's JXTrayIcon + * (http://weblogs.java.net/blog/alexfromsun/archive/2008/02/jtrayicon_updat.html) + * but uses a JWindow instead of a JDialog to workaround some bugs on linux. + * + * @author Michael Bien + */ +public class JPopupTrayIcon extends TrayIcon { + + private JPopupMenu menu; + + private Window window; + private PopupMenuListener popupListener; + + private final static boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("windows"); + + public JPopupTrayIcon(Image image) { + super(image); + init(); + } + + public JPopupTrayIcon(Image image, String tooltip) { + super(image, tooltip); + init(); + } + + public JPopupTrayIcon(Image image, String tooltip, PopupMenu popup) { + super(image, tooltip, popup); + init(); + } + + public JPopupTrayIcon(Image image, String tooltip, JPopupMenu popup) { + super(image, tooltip); + init(); + setJPopupMenu(popup); + } + + + private final void init() { + + + popupListener = new PopupMenuListener() { + + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { +// System.out.println("popupMenuWillBecomeVisible"); + } + + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { +// System.out.println("popupMenuWillBecomeInvisible"); + if(window != null) { + window.dispose(); + window = null; + } + } + + @Override + public void popupMenuCanceled(PopupMenuEvent e) { +// System.out.println("popupMenuCanceled"); + if(window != null) { + window.dispose(); + window = null; + } + } + }; + + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { +// System.out.println(e.getPoint()); + showJPopupMenu(e); + } + + @Override + public void mouseReleased(MouseEvent e) { +// System.out.println(e.getPoint()); + showJPopupMenu(e); + } + }); + + } + + private final void showJPopupMenu(MouseEvent e) { + if(e.isPopupTrigger() && menu != null) { + if (window == null) { + + if(IS_WINDOWS) { + window = new JDialog((Frame)null); + ((JDialog)window).setUndecorated(true); + }else{ + window = new JWindow((Frame)null); + } + window.setAlwaysOnTop(true); + Dimension size = menu.getPreferredSize(); + + Point centerPoint = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint(); + if(e.getY() > centerPoint.getY()) + window.setLocation(e.getX(), e.getY() - size.height); + else + window.setLocation(e.getX(), e.getY()); + + window.setVisible(true); + + menu.show(((RootPaneContainer)window).getContentPane(), 0, 0); + + // popup works only for focused windows + window.toFront(); + + } + } + } + + + public final JPopupMenu getJPopupMenu() { + return menu; + } + + public final void setJPopupMenu(JPopupMenu menu) { + if (this.menu != null) { + this.menu.removePopupMenuListener(popupListener); + } + this.menu = menu; + menu.addPopupMenuListener(popupListener); + } + +} diff --git a/apps/desktopgui/src/gui/LogViewer.form b/apps/desktopgui/src/gui/LogViewer.form new file mode 100644 index 0000000000..b53b410bac --- /dev/null +++ b/apps/desktopgui/src/gui/LogViewer.form @@ -0,0 +1,101 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/apps/desktopgui/src/gui/LogViewer.java b/apps/desktopgui/src/gui/LogViewer.java new file mode 100644 index 0000000000..2dad70c1fc --- /dev/null +++ b/apps/desktopgui/src/gui/LogViewer.java @@ -0,0 +1,163 @@ +/* + * LogViewer.java + * + * Created on 10 april 2009, 19:17 + */ + +package gui; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.WindowConstants; + +/** + * + * @author mathias + */ +public class LogViewer extends javax.swing.JFrame { + + /** Creates new form LogViewer */ + public LogViewer() { + initComponents(); + readLogText(); + this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + this.setVisible(true); + } + + private void readLogText() { + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + String s = ""; + File f = new File(LOGLOCATION); + if(f.exists()) { + try { + BufferedReader br = new BufferedReader(new FileReader(f)); + while(true) { + String line = br.readLine(); + if(line != null) + s += JTEXTNEWLINE + line; + else + break; + } + } + catch(Exception e) { + s = "An error has occurred while loading the logfiles:" + JTEXTNEWLINE + e.getMessage(); + } + } + logText.setText(s); + } + + }); + t.start(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + textScroll = new javax.swing.JScrollPane(); + logText = new javax.swing.JTextArea(); + explanationText = new javax.swing.JLabel(); + refreshButton = new javax.swing.JButton(); + clearButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setName("Form"); // NOI18N + + textScroll.setName("textScroll"); // NOI18N + + logText.setColumns(20); + logText.setRows(5); + logText.setName("logText"); // NOI18N + textScroll.setViewportView(logText); + + org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(LogViewer.class); + explanationText.setText(resourceMap.getString("explanationText.text")); // NOI18N + explanationText.setName("explanationText"); // NOI18N + + refreshButton.setText(resourceMap.getString("refreshButton.text")); // NOI18N + refreshButton.setName("refreshButton"); // NOI18N + refreshButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + refreshButtonActionPerformed(evt); + } + }); + + clearButton.setText(resourceMap.getString("clearButton.text")); // NOI18N + clearButton.setName("clearButton"); // NOI18N + clearButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + clearButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(12, 12, 12) + .addComponent(explanationText, javax.swing.GroupLayout.PREFERRED_SIZE, 561, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + .addComponent(textScroll, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 722, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(refreshButton) + .addGap(18, 18, 18) + .addComponent(clearButton) + .addContainerGap(587, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(explanationText, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(refreshButton) + .addComponent(clearButton)) + .addGap(14, 14, 14) + .addComponent(textScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 330, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + +private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed + File f = new File(LOGLOCATION); + f.delete(); + try { + f.createNewFile();//GEN-LAST:event_clearButtonActionPerformed + } catch (IOException ex) { + Logger.getLogger(LogViewer.class.getName()).log(Level.SEVERE, null, ex); + } + readLogText(); +} + +private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed + readLogText(); +}//GEN-LAST:event_refreshButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton clearButton; + private javax.swing.JLabel explanationText; + private javax.swing.JTextArea logText; + private javax.swing.JButton refreshButton; + private javax.swing.JScrollPane textScroll; + // End of variables declaration//GEN-END:variables + + private static final String LOGLOCATION = "wrapper.log"; + private static final String JTEXTNEWLINE = "\n"; +} diff --git a/apps/desktopgui/src/gui/SpeedSelector.form b/apps/desktopgui/src/gui/SpeedSelector.form new file mode 100644 index 0000000000..79d25ae965 --- /dev/null +++ b/apps/desktopgui/src/gui/SpeedSelector.form @@ -0,0 +1,178 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/apps/desktopgui/src/gui/SpeedSelector.java b/apps/desktopgui/src/gui/SpeedSelector.java new file mode 100644 index 0000000000..bce18621f2 --- /dev/null +++ b/apps/desktopgui/src/gui/SpeedSelector.java @@ -0,0 +1,195 @@ +/* + * ProfileSelector.java + * + * Created on 3 april 2009, 13:57 + */ + +package gui; + +import java.awt.Dimension; +import java.awt.Point; +import java.util.Properties; +import javax.swing.JComboBox; +import javax.swing.JTextField; +import persistence.PropertyManager; +import util.IntegerVerifier; + +/** + * + * @author mathias + */ +public class SpeedSelector extends javax.swing.JFrame { + + /** Creates new form ProfileSelector */ + public SpeedSelector() { + this.props = PropertyManager.getProps(); + initComponents(); + initComponentsCustom(); + initSpeeds(props); + this.setVisible(true); + this.setLocationRelativeTo(null); + this.requestFocus(); + } + + public SpeedSelector(Point point) { + this(); + this.setLocation(point); + } + + public void initComponentsCustom() { + ((JTextField)uploadChoice.getEditor().getEditorComponent()).setInputVerifier(new IntegerVerifier()); + ((JTextField)downloadChoice.getEditor().getEditorComponent()).setInputVerifier(new IntegerVerifier()); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + nextButton = new javax.swing.JButton(); + uploadLabel = new javax.swing.JLabel(); + downloadLabel = new javax.swing.JLabel(); + uploadChoice = new javax.swing.JComboBox(); + downloadChoice = new javax.swing.JComboBox(); + speedExplanation = new javax.swing.JLabel(); + uploadkbps = new javax.swing.JComboBox(); + downloadkbps = new javax.swing.JComboBox(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(SpeedSelector.class); + setTitle(resourceMap.getString("Form.title")); // NOI18N + setMinimumSize(new java.awt.Dimension(610, 330)); + setName("Form"); // NOI18N + setResizable(false); + getContentPane().setLayout(null); + + nextButton.setText(resourceMap.getString("nextButton.text")); // NOI18N + nextButton.setMaximumSize(new java.awt.Dimension(72, 29)); + nextButton.setMinimumSize(new java.awt.Dimension(72, 29)); + nextButton.setName("nextButton"); // NOI18N + nextButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + nextButtonMouseClicked(evt); + } + }); + getContentPane().add(nextButton); + nextButton.setBounds(440, 250, 90, 29); + + uploadLabel.setText(resourceMap.getString("uploadLabel.text")); // NOI18N + uploadLabel.setName("uploadLabel"); // NOI18N + getContentPane().add(uploadLabel); + uploadLabel.setBounds(20, 60, 246, 30); + + downloadLabel.setText(resourceMap.getString("downloadLabel.text")); // NOI18N + downloadLabel.setName("downloadLabel"); // NOI18N + getContentPane().add(downloadLabel); + downloadLabel.setBounds(20, 110, 263, 30); + + uploadChoice.setEditable(true); + uploadChoice.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "100", "200", "500", "1000", "2000", "4000", "8000", "10000", "20000", "50000", "100000" })); + uploadChoice.setSelectedIndex(3); + uploadChoice.setName("uploadChoice"); // NOI18N + getContentPane().add(uploadChoice); + uploadChoice.setBounds(300, 60, 154, 27); + + downloadChoice.setEditable(true); + downloadChoice.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "100", "200", "500", "1000", "2000", "4000", "8000", "10000", "20000", "50000", "100000" })); + downloadChoice.setSelectedIndex(3); + downloadChoice.setName("downloadChoice"); // NOI18N + getContentPane().add(downloadChoice); + downloadChoice.setBounds(300, 110, 154, 27); + + speedExplanation.setText(resourceMap.getString("speedExplanation.text")); // NOI18N + speedExplanation.setName("speedExplanation"); // NOI18N + getContentPane().add(speedExplanation); + speedExplanation.setBounds(20, 160, 570, 60); + + uploadkbps.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kbps", "kBps" })); + uploadkbps.setName("uploadKbit"); // NOI18N + uploadkbps.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + uploadkbpsActionPerformed(evt); + } + }); + getContentPane().add(uploadkbps); + uploadkbps.setBounds(470, 60, 68, 27); + + downloadkbps.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kbps", "kBps" })); + downloadkbps.setName("downloadKbit"); // NOI18N + downloadkbps.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + downloadkbpsActionPerformed(evt); + } + }); + getContentPane().add(downloadkbps); + downloadkbps.setBounds(470, 110, 68, 27); + + pack(); + }// //GEN-END:initComponents + +private void nextButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_nextButtonMouseClicked + if(uploadkbps.getSelectedIndex() == KILOBIT) + props.setProperty(SpeedSelectorConstants.MAXUPLOADCAPABLE, uploadChoice.getSelectedItem().toString()); + else + props.setProperty(SpeedSelectorConstants.MAXUPLOADCAPABLE, "" + Integer.parseInt(uploadChoice.getSelectedItem().toString())*8); + if(downloadkbps.getSelectedIndex() == KILOBIT) + props.setProperty(SpeedSelectorConstants.MAXDOWNLOADCAPABLE, downloadChoice.getSelectedItem().toString()); + else + props.setProperty(SpeedSelectorConstants.MAXDOWNLOADCAPABLE, "" + Integer.parseInt(downloadChoice.getSelectedItem().toString())*8); + PropertyManager.saveProps(props); + new SpeedSelector2(this.getLocationOnScreen()); + this.dispose(); +}//GEN-LAST:event_nextButtonMouseClicked + +private void uploadkbpsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_uploadkbpsActionPerformed + kbpsSwitchPerformed(uploadkbps, uploadChoice); +}//GEN-LAST:event_uploadkbpsActionPerformed + +private void downloadkbpsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadkbpsActionPerformed + kbpsSwitchPerformed(downloadkbps, downloadChoice); +}//GEN-LAST:event_downloadkbpsActionPerformed + +private void kbpsSwitchPerformed(JComboBox kbps, JComboBox speed) { + int index = kbps.getSelectedIndex(); + int previous = Integer.parseInt(speed.getSelectedItem().toString()); + if(index == KILOBIT) { + speed.setSelectedItem("" + previous*8); + } + else { + speed.setSelectedItem("" + previous/8); + } +} + +private void initSpeeds(Properties props) { + String up = props.getProperty(SpeedSelectorConstants.MAXUPLOADCAPABLE); + String down = props.getProperty(SpeedSelectorConstants.MAXDOWNLOADCAPABLE); + + if(up == null) + props.setProperty(SpeedSelectorConstants.MAXUPLOADCAPABLE, "1000"); + if(down == null) + props.setProperty(SpeedSelectorConstants.MAXDOWNLOADCAPABLE, "1000"); + + uploadChoice.setSelectedItem(props.getProperty(SpeedSelectorConstants.MAXUPLOADCAPABLE)); + downloadChoice.setSelectedItem(props.getProperty(SpeedSelectorConstants.MAXDOWNLOADCAPABLE)); +} + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JComboBox downloadChoice; + private javax.swing.JLabel downloadLabel; + private javax.swing.JComboBox downloadkbps; + private javax.swing.JButton nextButton; + private javax.swing.JLabel speedExplanation; + private javax.swing.JComboBox uploadChoice; + private javax.swing.JLabel uploadLabel; + private javax.swing.JComboBox uploadkbps; + // End of variables declaration//GEN-END:variables + + Properties props; + private static final int KILOBIT = 0; + private static final int KILOBYTE = 1; +} diff --git a/apps/desktopgui/src/gui/SpeedSelector2.form b/apps/desktopgui/src/gui/SpeedSelector2.form new file mode 100644 index 0000000000..5c305de19b --- /dev/null +++ b/apps/desktopgui/src/gui/SpeedSelector2.form @@ -0,0 +1,117 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/apps/desktopgui/src/gui/SpeedSelector2.java b/apps/desktopgui/src/gui/SpeedSelector2.java new file mode 100644 index 0000000000..1177b57258 --- /dev/null +++ b/apps/desktopgui/src/gui/SpeedSelector2.java @@ -0,0 +1,160 @@ +/* + * ProfileSelector2.java + * + * Created on 3 april 2009, 14:36 + */ + +package gui; + +import java.awt.Dimension; +import java.awt.Point; +import java.util.Enumeration; +import java.util.Properties; +import javax.swing.AbstractButton; +import persistence.PropertyManager; + +/** + * + * @author mathias + */ +public class SpeedSelector2 extends javax.swing.JFrame { + Properties props; + + /** Creates new form ProfileSelector2 */ + public SpeedSelector2(Point point) { + this.props = PropertyManager.getProps(); + initComponents(); + this.setLocation(point); + loadButtonSelection(); + this.setVisible(true); + this.requestFocus(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonGroup1 = new javax.swing.ButtonGroup(); + nextButton = new javax.swing.JButton(); + returnButton = new javax.swing.JButton(); + questionLabel = new javax.swing.JLabel(); + browseButton = new javax.swing.JRadioButton(); + downloadButton = new javax.swing.JRadioButton(); + jLabel1 = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(SpeedSelector2.class); + setTitle(resourceMap.getString("Form.title")); // NOI18N + setMinimumSize(new java.awt.Dimension(610, 330)); + setName("Form"); // NOI18N + setResizable(false); + getContentPane().setLayout(null); + + nextButton.setText(resourceMap.getString("nextButton.text")); // NOI18N + nextButton.setName("nextButton"); // NOI18N + nextButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + nextButtonMouseClicked(evt); + } + }); + getContentPane().add(nextButton); + nextButton.setBounds(440, 250, 90, 29); + + returnButton.setText(resourceMap.getString("returnButton.text")); // NOI18N + returnButton.setName("returnButton"); // NOI18N + returnButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + returnButtonMouseClicked(evt); + } + }); + getContentPane().add(returnButton); + returnButton.setBounds(336, 250, 90, 29); + + questionLabel.setText(resourceMap.getString("questionLabel.text")); // NOI18N + questionLabel.setName("questionLabel"); // NOI18N + getContentPane().add(questionLabel); + questionLabel.setBounds(30, 40, 265, 17); + + buttonGroup1.add(browseButton); + browseButton.setText(resourceMap.getString("browseButton.text")); // NOI18N + browseButton.setActionCommand(resourceMap.getString("browseButton.actionCommand")); // NOI18N + browseButton.setName("browseButton"); // NOI18N + getContentPane().add(browseButton); + browseButton.setBounds(40, 120, 520, 40); + + buttonGroup1.add(downloadButton); + downloadButton.setText(resourceMap.getString("downloadButton.text")); // NOI18N + downloadButton.setActionCommand(resourceMap.getString("downloadButton.actionCommand")); // NOI18N + downloadButton.setName("downloadButton"); // NOI18N + getContentPane().add(downloadButton); + downloadButton.setBounds(40, 70, 499, 40); + + jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N + jLabel1.setName("jLabel1"); // NOI18N + getContentPane().add(jLabel1); + jLabel1.setBounds(30, 170, 530, 70); + + pack(); + }// //GEN-END:initComponents + +private void returnButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_returnButtonMouseClicked + saveButtonSelection(); + PropertyManager.saveProps(props); + new SpeedSelector(this.getLocationOnScreen()); + this.dispose(); +}//GEN-LAST:event_returnButtonMouseClicked + +private void nextButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_nextButtonMouseClicked + saveButtonSelection(); + PropertyManager.saveProps(props); + new SpeedSelector3(this.getLocationOnScreen(), this.getSize()); + this.dispose(); +}//GEN-LAST:event_nextButtonMouseClicked + +private void loadButtonSelection() { + + Enumeration elements = buttonGroup1.getElements(); + while(elements.hasMoreElements()) { + AbstractButton button = elements.nextElement(); + if(button == null) + continue; + if(props.getProperty(SpeedSelectorConstants.USERTYPE) == null) + break; + String type = button.getActionCommand(); + if(type.equals(props.getProperty(SpeedSelectorConstants.USERTYPE))) { + button.setSelected(true); + break; + } + } +} + +private void saveButtonSelection() { + Enumeration elements = buttonGroup1.getElements(); + while(elements.hasMoreElements()) { + AbstractButton button = elements.nextElement(); + if(button == null) + continue; + if(button.isSelected()) { + String type = button.getActionCommand(); + props.setProperty(SpeedSelectorConstants.USERTYPE, type); + break; + } + } +} + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JRadioButton browseButton; + private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.JRadioButton downloadButton; + private javax.swing.JLabel jLabel1; + private javax.swing.JButton nextButton; + private javax.swing.JLabel questionLabel; + private javax.swing.JButton returnButton; + // End of variables declaration//GEN-END:variables + +} diff --git a/apps/desktopgui/src/gui/SpeedSelector3.form b/apps/desktopgui/src/gui/SpeedSelector3.form new file mode 100644 index 0000000000..9c6ef533aa --- /dev/null +++ b/apps/desktopgui/src/gui/SpeedSelector3.form @@ -0,0 +1,337 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/apps/desktopgui/src/gui/SpeedSelector3.java b/apps/desktopgui/src/gui/SpeedSelector3.java new file mode 100644 index 0000000000..1f523befda --- /dev/null +++ b/apps/desktopgui/src/gui/SpeedSelector3.java @@ -0,0 +1,439 @@ +/* + * ProfileSelector3.java + * + * Created on 3 april 2009, 15:17 + */ + +package gui; + +import java.awt.Dimension; +import java.awt.Point; +import java.util.Properties; +import javax.swing.JComboBox; +import javax.swing.JTextField; +import persistence.PropertyManager; +import router.configuration.SpeedHandler; +import router.configuration.SpeedHelper; + +/** + * + * @author mathias + */ +public class SpeedSelector3 extends javax.swing.JFrame { + Properties props; + + /** Creates new form ProfileSelector3 */ + public SpeedSelector3(Point point, Dimension dimension) { + this.props = PropertyManager.getProps(); + initComponents(); + this.setLocation(point); + this.setSize(dimension); + initSpeeds(); + initUsage(); + this.setVisible(true); + this.requestFocus(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + finishButton = new javax.swing.JButton(); + previousButton = new javax.swing.JButton(); + settingsInfo = new javax.swing.JLabel(); + uploadLabel = new javax.swing.JLabel(); + downloadLabel = new javax.swing.JLabel(); + uploadBurstLabel = new javax.swing.JLabel(); + downloadBurstLabel = new javax.swing.JLabel(); + uploadUsageLabel = new javax.swing.JLabel(); + downloadUsageLabel = new javax.swing.JLabel(); + uploadField = new javax.swing.JTextField(); + uploadBurstField = new javax.swing.JTextField(); + downloadField = new javax.swing.JTextField(); + downloadBurstField = new javax.swing.JTextField(); + kbpsBurstDownload = new javax.swing.JComboBox(); + kbpsUpload = new javax.swing.JComboBox(); + kbpsBurstUpload = new javax.swing.JComboBox(); + kbpsDownload = new javax.swing.JComboBox(); + uploadGB = new javax.swing.JLabel(); + uploadMonth = new javax.swing.JTextField(); + downloadMonth = new javax.swing.JTextField(); + downloadGB = new javax.swing.JLabel(); + explanation = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(desktopgui.Main.class).getContext().getResourceMap(SpeedSelector3.class); + setTitle(resourceMap.getString("Form.title")); // NOI18N + setMinimumSize(new java.awt.Dimension(670, 330)); + setName("Form"); // NOI18N + setResizable(false); + getContentPane().setLayout(null); + + finishButton.setText(resourceMap.getString("finishButton.text")); // NOI18N + finishButton.setName("finishButton"); // NOI18N + finishButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + finishButtonMouseClicked(evt); + } + }); + getContentPane().add(finishButton); + finishButton.setBounds(440, 250, 90, 29); + + previousButton.setText(resourceMap.getString("previousButton.text")); // NOI18N + previousButton.setName("previousButton"); // NOI18N + previousButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + previousButtonMouseClicked(evt); + } + }); + getContentPane().add(previousButton); + previousButton.setBounds(336, 250, 90, 29); + + settingsInfo.setText(resourceMap.getString("settingsInfo.text")); // NOI18N + settingsInfo.setName("settingsInfo"); // NOI18N + getContentPane().add(settingsInfo); + settingsInfo.setBounds(20, 30, 532, 17); + + uploadLabel.setText(resourceMap.getString("uploadLabel.text")); // NOI18N + uploadLabel.setName("uploadLabel"); // NOI18N + getContentPane().add(uploadLabel); + uploadLabel.setBounds(20, 70, 140, 30); + + downloadLabel.setText(resourceMap.getString("downloadLabel.text")); // NOI18N + downloadLabel.setName("downloadLabel"); // NOI18N + getContentPane().add(downloadLabel); + downloadLabel.setBounds(340, 70, 160, 30); + + uploadBurstLabel.setText(resourceMap.getString("uploadBurstLabel.text")); // NOI18N + uploadBurstLabel.setName("uploadBurstLabel"); // NOI18N + getContentPane().add(uploadBurstLabel); + uploadBurstLabel.setBounds(20, 110, 140, 30); + + downloadBurstLabel.setText(resourceMap.getString("downloadBurstLabel.text")); // NOI18N + downloadBurstLabel.setName("downloadBurstLabel"); // NOI18N + getContentPane().add(downloadBurstLabel); + downloadBurstLabel.setBounds(340, 110, 160, 30); + + uploadUsageLabel.setText(resourceMap.getString("uploadUsageLabel.text")); // NOI18N + uploadUsageLabel.setName("uploadUsageLabel"); // NOI18N + getContentPane().add(uploadUsageLabel); + uploadUsageLabel.setBounds(20, 150, 19, 30); + + downloadUsageLabel.setText(resourceMap.getString("downloadUsageLabel.text")); // NOI18N + downloadUsageLabel.setName("downloadUsageLabel"); // NOI18N + getContentPane().add(downloadUsageLabel); + downloadUsageLabel.setBounds(340, 150, 19, 30); + + uploadField.setText(resourceMap.getString("uploadField.text")); // NOI18N + uploadField.setMinimumSize(new java.awt.Dimension(77, 27)); + uploadField.setName("uploadField"); // NOI18N + uploadField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + speedFieldKeyReleased(evt); + } + }); + getContentPane().add(uploadField); + uploadField.setBounds(160, 70, 77, 27); + + uploadBurstField.setText(resourceMap.getString("uploadBurstField.text")); // NOI18N + uploadBurstField.setMinimumSize(new java.awt.Dimension(77, 27)); + uploadBurstField.setName("uploadBurstField"); // NOI18N + getContentPane().add(uploadBurstField); + uploadBurstField.setBounds(160, 110, 77, 27); + + downloadField.setText(resourceMap.getString("downloadField.text")); // NOI18N + downloadField.setMinimumSize(new java.awt.Dimension(77, 27)); + downloadField.setName("downloadField"); // NOI18N + downloadField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + speedFieldKeyReleased(evt); + } + }); + getContentPane().add(downloadField); + downloadField.setBounds(500, 70, 77, 27); + + downloadBurstField.setText(resourceMap.getString("downloadBurstField.text")); // NOI18N + downloadBurstField.setMinimumSize(new java.awt.Dimension(77, 27)); + downloadBurstField.setName("downloadBurstField"); // NOI18N + getContentPane().add(downloadBurstField); + downloadBurstField.setBounds(500, 110, 77, 27); + + kbpsBurstDownload.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kbps", "kBps" })); + kbpsBurstDownload.setName("kbpsBurstDownload"); // NOI18N + kbpsBurstDownload.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + kbpsBurstDownloadActionPerformed(evt); + } + }); + getContentPane().add(kbpsBurstDownload); + kbpsBurstDownload.setBounds(580, 110, 68, 27); + + kbpsUpload.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kbps", "kBps" })); + kbpsUpload.setName("kbpsUpload"); // NOI18N + kbpsUpload.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + kbpsUploadActionPerformed(evt); + } + }); + getContentPane().add(kbpsUpload); + kbpsUpload.setBounds(240, 70, 68, 27); + + kbpsBurstUpload.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kbps", "kBps" })); + kbpsBurstUpload.setName("kbpsBurstUpload"); // NOI18N + kbpsBurstUpload.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + kbpsBurstUploadActionPerformed(evt); + } + }); + getContentPane().add(kbpsBurstUpload); + kbpsBurstUpload.setBounds(240, 110, 68, 27); + + kbpsDownload.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kbps", "kBps" })); + kbpsDownload.setName("kbpsDownload"); // NOI18N + kbpsDownload.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + kbpsDownloadActionPerformed(evt); + } + }); + getContentPane().add(kbpsDownload); + kbpsDownload.setBounds(580, 70, 68, 27); + + uploadGB.setText(resourceMap.getString("uploadUsageLabel.text")); // NOI18N + uploadGB.setName("uploadUsageLabel"); // NOI18N + getContentPane().add(uploadGB); + uploadGB.setBounds(240, 150, 45, 30); + + uploadMonth.setText(resourceMap.getString("uploadMonth.text")); // NOI18N + uploadMonth.setName("uploadMonth"); // NOI18N + uploadMonth.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + monthKeyReleased(evt); + } + }); + getContentPane().add(uploadMonth); + uploadMonth.setBounds(160, 150, 77, 27); + + downloadMonth.setText(resourceMap.getString("downloadMonth.text")); // NOI18N + downloadMonth.setName("downloadMonth"); // NOI18N + downloadMonth.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + monthKeyReleased(evt); + } + }); + getContentPane().add(downloadMonth); + downloadMonth.setBounds(500, 150, 77, 27); + + downloadGB.setText(resourceMap.getString("downloadUsageLabel.text")); // NOI18N + downloadGB.setName("downloadUsageLabel"); // NOI18N + getContentPane().add(downloadGB); + downloadGB.setBounds(580, 150, 19, 30); + + explanation.setText(resourceMap.getString("explanation.text")); // NOI18N + explanation.setName("explanation"); // NOI18N + getContentPane().add(explanation); + explanation.setBounds(20, 180, 600, 70); + + pack(); + }// //GEN-END:initComponents + +private void previousButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_previousButtonMouseClicked + saveSpeeds(); + PropertyManager.saveProps(props); + new SpeedSelector2(this.getLocationOnScreen()); + this.dispose(); +}//GEN-LAST:event_previousButtonMouseClicked + +private void finishButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_finishButtonMouseClicked + saveSpeeds(); + PropertyManager.saveProps(props); + + int maxDownload = Integer.parseInt(props.getProperty(SpeedSelectorConstants.MAXDOWNLOAD)); + int maxUpload = Integer.parseInt(props.getProperty(SpeedSelectorConstants.MAXUPLOAD)); + int maxUploadBurst = Integer.parseInt(props.getProperty(SpeedSelectorConstants.MAXUPLOADBURST)); + int maxDownloadBurst = Integer.parseInt(props.getProperty(SpeedSelectorConstants.MAXDOWNLOADBURST)); + + //Working in kB, not kb! + SpeedHandler.setInboundBandwidth(maxDownload/8); + SpeedHandler.setOutboundBandwidth(maxUpload/8); + SpeedHandler.setInboundBurstBandwidth(maxDownloadBurst/8); + SpeedHandler.setOutboundBurstBandwidth(maxUploadBurst/8); + + this.dispose(); +}//GEN-LAST:event_finishButtonMouseClicked + +private void speedFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_speedFieldKeyReleased + try { + String upload = ""; + if(kbpsUpload.getSelectedIndex() == KILOBIT) + upload = uploadField.getText(); + else + upload = "" + Integer.parseInt(uploadField.getText())*8; + String download = ""; + if(kbpsDownload.getSelectedIndex() == KILOBIT) + download = downloadField.getText(); + else + download = "" + Integer.parseInt(downloadField.getText())*8; + initUsage(upload, download); + } + catch(NumberFormatException e) { + return; + } +}//GEN-LAST:event_speedFieldKeyReleased + +private void kbpsUploadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_kbpsUploadActionPerformed + kbpsSwitchPerformed(kbpsUpload, uploadField); +}//GEN-LAST:event_kbpsUploadActionPerformed + +private void kbpsBurstUploadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_kbpsBurstUploadActionPerformed + kbpsSwitchPerformed(kbpsBurstUpload, uploadBurstField); +}//GEN-LAST:event_kbpsBurstUploadActionPerformed + +private void kbpsDownloadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_kbpsDownloadActionPerformed + kbpsSwitchPerformed(kbpsDownload, downloadField); +}//GEN-LAST:event_kbpsDownloadActionPerformed + +private void kbpsBurstDownloadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_kbpsBurstDownloadActionPerformed + kbpsSwitchPerformed(kbpsBurstDownload, downloadBurstField); +}//GEN-LAST:event_kbpsBurstDownloadActionPerformed + +private void monthKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_monthKeyReleased + try { + int uploadMonthValue = Integer.parseInt(uploadMonth.getText()); + int downloadMonthValue = Integer.parseInt(downloadMonth.getText()); + + String upload = ""; + String burstUpload = ""; + String download = ""; + String burstDownload = ""; + + if(kbpsUpload.getSelectedIndex() == KILOBIT) + upload = "" + SpeedHelper.calculateSpeed(uploadMonthValue)*8; //kbit + else + upload = "" + SpeedHelper.calculateSpeed(uploadMonthValue); //kbyte + + if(kbpsBurstUpload.getSelectedIndex() == KILOBIT) + burstUpload = "" + SpeedHelper.calculateSpeed(uploadMonthValue)*8; //kbit + else + burstUpload = "" + SpeedHelper.calculateSpeed(uploadMonthValue); //kbyte + + if(kbpsDownload.getSelectedIndex() == KILOBIT) + download = "" + SpeedHelper.calculateSpeed(downloadMonthValue)*8; //kbit + else + download = "" + SpeedHelper.calculateSpeed(downloadMonthValue); //kbyte + + if(kbpsBurstDownload.getSelectedIndex() == KILOBIT) + burstDownload = "" + SpeedHelper.calculateSpeed(downloadMonthValue)*8; //kbit + else + burstDownload = "" + SpeedHelper.calculateSpeed(downloadMonthValue); //kbyte + + initSpeeds(upload, burstUpload, download, burstDownload); + } + catch(NumberFormatException e) { + e.printStackTrace(); + return; + } +}//GEN-LAST:event_monthKeyReleased + +private void kbpsSwitchPerformed(JComboBox kbps, JTextField speed) { + int index = kbps.getSelectedIndex(); + int previous = Integer.parseInt(speed.getText()); + if(index == KILOBIT) { + speed.setText("" + previous*8); + } + else { + speed.setText("" + previous/8); + } +} + + protected void initSpeeds() { + String up = "" + SpeedHelper.calculateSpeed( + props.getProperty(SpeedSelectorConstants.MAXUPLOADCAPABLE), props.getProperty(SpeedSelectorConstants.USERTYPE)); + String upBurst = "" + SpeedHelper.calculateSpeed( + props.getProperty(SpeedSelectorConstants.MAXUPLOADCAPABLE), props.getProperty(SpeedSelectorConstants.USERTYPE)); + String down = "" + SpeedHelper.calculateSpeed( + props.getProperty(SpeedSelectorConstants.MAXDOWNLOADCAPABLE), props.getProperty(SpeedSelectorConstants.USERTYPE)); + String downBurst = "" + SpeedHelper.calculateSpeed( + props.getProperty(SpeedSelectorConstants.MAXDOWNLOADCAPABLE), props.getProperty(SpeedSelectorConstants.USERTYPE)); + String userType = props.getProperty(SpeedSelectorConstants.USERTYPE); + + initSpeeds(up, upBurst, down, downBurst); + } + + protected void initSpeeds(String up, String upBurst, String down, String downBurst) { + uploadField.setText(up); + uploadBurstField.setText(upBurst); + downloadField.setText(down); + downloadBurstField.setText(downBurst); + } + + protected void saveSpeeds() { + if(kbpsUpload.getSelectedIndex() == KILOBIT) + props.setProperty(SpeedSelectorConstants.MAXUPLOAD, uploadField.getText()); + else + props.setProperty(SpeedSelectorConstants.MAXUPLOAD, "" + Integer.parseInt(uploadField.getText())*8); + if(kbpsBurstUpload.getSelectedIndex() == KILOBIT) + props.setProperty(SpeedSelectorConstants.MAXUPLOADBURST, uploadBurstField.getText()); + else + props.setProperty(SpeedSelectorConstants.MAXUPLOADBURST, "" + Integer.parseInt(uploadBurstField.getText())*8); + if(kbpsDownload.getSelectedIndex() == KILOBIT) + props.setProperty(SpeedSelectorConstants.MAXDOWNLOAD, downloadField.getText()); + else + props.setProperty(SpeedSelectorConstants.MAXDOWNLOAD, "" + Integer.parseInt(downloadField.getText())*8); + if(kbpsBurstDownload.getSelectedIndex() == KILOBIT) + props.setProperty(SpeedSelectorConstants.MAXDOWNLOADBURST, downloadBurstField.getText()); + else + props.setProperty(SpeedSelectorConstants.MAXDOWNLOADBURST, "" + Integer.parseInt(downloadBurstField.getText())*8); + } + + protected void initUsage(String upload, String download) { + uploadMonth.setText("" + SpeedHelper.calculateMonthlyUsage(Integer.parseInt(upload)/8)); + downloadMonth.setText("" + SpeedHelper.calculateMonthlyUsage(Integer.parseInt(download)/8)); + } + + protected void initUsage() { + String upload = ""; + if(kbpsUpload.getSelectedIndex() == KILOBIT) + upload = uploadField.getText(); + else + upload = "" + Integer.parseInt(uploadField.getText())/8; + String download = ""; + if(kbpsDownload.getSelectedIndex() == KILOBIT) + download = downloadField.getText(); + else + download = "" + Integer.parseInt(downloadField.getText())/8; + initUsage(upload, download); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextField downloadBurstField; + private javax.swing.JLabel downloadBurstLabel; + private javax.swing.JTextField downloadField; + private javax.swing.JLabel downloadGB; + private javax.swing.JLabel downloadLabel; + private javax.swing.JTextField downloadMonth; + private javax.swing.JLabel downloadUsageLabel; + private javax.swing.JLabel explanation; + private javax.swing.JButton finishButton; + private javax.swing.JComboBox kbpsBurstDownload; + private javax.swing.JComboBox kbpsBurstUpload; + private javax.swing.JComboBox kbpsDownload; + private javax.swing.JComboBox kbpsUpload; + private javax.swing.JButton previousButton; + private javax.swing.JLabel settingsInfo; + private javax.swing.JTextField uploadBurstField; + private javax.swing.JLabel uploadBurstLabel; + private javax.swing.JTextField uploadField; + private javax.swing.JLabel uploadGB; + private javax.swing.JLabel uploadLabel; + private javax.swing.JTextField uploadMonth; + private javax.swing.JLabel uploadUsageLabel; + // End of variables declaration//GEN-END:variables + + private static final int KILOBIT = 0; + private static final int KILOBYTE = 1; +} diff --git a/apps/desktopgui/src/gui/SpeedSelectorConstants.java b/apps/desktopgui/src/gui/SpeedSelectorConstants.java new file mode 100644 index 0000000000..ea5e32427b --- /dev/null +++ b/apps/desktopgui/src/gui/SpeedSelectorConstants.java @@ -0,0 +1,25 @@ +package gui; + +/** + * + * @author mathias + */ +public class SpeedSelectorConstants { + ///Maximum upload speed for the internet connection + public static final String MAXUPLOADCAPABLE = "maxUploadCapable"; + ///Maximum download speed for the internet connection + public static final String MAXDOWNLOADCAPABLE = "maxDownloadCapable"; + + //User profile type: what behaviour does this user have while using IP2? + public static final String USERTYPE = "userType"; + + //Maximum upload speed for I2P + public static final String MAXUPLOAD = "maxUpload"; + //Maximum upload burst speed for I2P + public static final String MAXUPLOADBURST = "maxUploadBurst"; + + //Maximum download speed for I2P + public static final String MAXDOWNLOAD = "maxDownload"; + //Maximum download burst speed for I2P + public static final String MAXDOWNLOADBURST = "maxDownloadBurst"; +} diff --git a/apps/desktopgui/src/gui/Tray.java b/apps/desktopgui/src/gui/Tray.java new file mode 100644 index 0000000000..5a8da78db9 --- /dev/null +++ b/apps/desktopgui/src/gui/Tray.java @@ -0,0 +1,194 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package gui; + +import desktopgui.*; +import java.awt.AWTException; +import java.awt.Desktop; +import java.awt.Image; +import java.awt.SystemTray; +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import router.RouterHandler; +import router.RouterHelper; +import router.configuration.PeerHelper; + +/** + * + * @author mathias + */ +public class Tray { + + public Tray() { + tray = SystemTray.getSystemTray(); + loadSystemTray(); + } + + private void loadSystemTray() { + + Image image = Toolkit.getDefaultToolkit().getImage("desktopgui/resources/logo/logo.jpg"); + + final JPopupMenu popup = new JPopupMenu(); + + //Create menu items to put in the popup menu + JMenuItem browserLauncher = new JMenuItem("Launch browser"); + browserLauncher.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + if(Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + try { + if(desktop.isSupported(Desktop.Action.BROWSE)) { + desktop.browse(new URI("http://localhost:7657")); + } + else { + trayIcon.displayMessage("Browser not found", "The default browser for your system was not found.", TrayIcon.MessageType.WARNING); + } + } catch (URISyntaxException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } catch(IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + }); + JMenuItem howto = new JMenuItem("How to use I2P"); + howto.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + if(Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + try { + File f = new File("desktopgui/resources/howto/howto.html"); + desktop.browse(new URI("file://" + f.getAbsolutePath())); + } catch (URISyntaxException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } catch(IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + }); + JMenu config = new JMenu("Configuration"); + JMenuItem speedConfig = new JMenuItem("Speed"); + speedConfig.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + (new SpeedSelector()).setVisible(true); + } + + }); + JMenuItem advancedConfig = new JMenuItem("Advanced Configuration"); + advancedConfig.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + if(Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI("http://localhost:7657/config.jsp")); + } catch (URISyntaxException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } catch(IOException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + }); + JMenuItem viewLog = new JMenuItem("View log"); + viewLog.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + new LogViewer(); + } + + }); + JMenuItem shutdown = new JMenuItem("Shutdown I2P"); + shutdown.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + RouterHandler.setStatus(RouterHandler.SHUTDOWN_GRACEFULLY); + long shutdownTime = RouterHelper.getGracefulShutdownTimeRemaining(); + System.out.println(shutdownTime); + if(shutdownTime>0) { + trayIcon.displayMessage("Shutting down...", "Shutdown time remaining: " + shutdownTime/1000 + " seconds." + + System.getProperty("line.separator") + "Shutdown will not happen immediately, because we are still participating in the network.", TrayIcon.MessageType.INFO); + } + else { + trayIcon.displayMessage("Shutting down...", "Shutting down immediately.", TrayIcon.MessageType.INFO); + } + } + + }); + + //Add menu items to popup menu + popup.add(browserLauncher); + popup.add(howto); + + config.add(speedConfig); + config.add(advancedConfig); + popup.add(config); + + popup.add(viewLog); + + popup.add(shutdown); + + //Add tray icon + trayIcon = new JPopupTrayIcon(image, "I2P: the anonymous network", popup); + PeerHelper.addReachabilityListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + trayIcon.setToolTip("I2P Network status: " + PeerHelper.getReachability()); + } + + }); + PeerHelper.addActivePeerListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + int activePeers = PeerHelper.getActivePeers(); + if(activePeers == 0) + trayIcon.setImage(Toolkit.getDefaultToolkit().getImage("desktopgui/resources/logo/logo_red.jpg")); + else if(activePeers < 10) + trayIcon.setImage(Toolkit.getDefaultToolkit().getImage("desktopgui/resources/logo/logo_orange.jpg")); + else + trayIcon.setImage(Toolkit.getDefaultToolkit().getImage("desktopgui/resources/logo/logo_green.jpg")); + + } + + }); + + try { + tray.add(trayIcon); + } catch (AWTException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + } + + private SystemTray tray = null; + private JPopupTrayIcon trayIcon = null; + +} diff --git a/apps/desktopgui/src/gui/resources/LogViewer.properties b/apps/desktopgui/src/gui/resources/LogViewer.properties new file mode 100644 index 0000000000..8cb0e62091 --- /dev/null +++ b/apps/desktopgui/src/gui/resources/LogViewer.properties @@ -0,0 +1,3 @@ +refreshButton.text=Refresh +clearButton.text=Clear +explanationText.text=Explanation ... diff --git a/apps/desktopgui/src/gui/resources/SpeedSelector.properties b/apps/desktopgui/src/gui/resources/SpeedSelector.properties new file mode 100644 index 0000000000..00eb6c973d --- /dev/null +++ b/apps/desktopgui/src/gui/resources/SpeedSelector.properties @@ -0,0 +1,6 @@ + +Form.title=I2P Speed Configuration +nextButton.text=Next +uploadLabel.text=What is your maximum upload speed? +downloadLabel.text=What is your maximum download speed? +speedExplanation.text=The maximum speed is set by your provider. It can be given in kilobit (kbps) or kilobyte (kBps).
One kilobyte equals eight kilobit. diff --git a/apps/desktopgui/src/gui/resources/SpeedSelector2.properties b/apps/desktopgui/src/gui/resources/SpeedSelector2.properties new file mode 100644 index 0000000000..909518ada2 --- /dev/null +++ b/apps/desktopgui/src/gui/resources/SpeedSelector2.properties @@ -0,0 +1,9 @@ +returnButton.text=Previous +Form.title=I2P Speed Configuration +questionLabel.text=Which of these descriptions fits you best? +browseButton.text=Browsing: I want to use I2P to browse websites anonymously, no heavy usage. +downloadButton.text=Downloading: I want to use I2P for downloads and filesharing, heavy usage. +nextButton.text=Next +browseButton.actionCommand=Browsing +downloadButton.actionCommand=Downloading +jLabel1.text=I2P can be used for many different purposes. Here, we present two possible descriptions. If you use a lot of bandwidth in I2P (for example using downloading), please check the downloading option. If your bandwidth usage is limited, please check the browsing option. diff --git a/apps/desktopgui/src/gui/resources/SpeedSelector3.properties b/apps/desktopgui/src/gui/resources/SpeedSelector3.properties new file mode 100644 index 0000000000..6dca3ca516 --- /dev/null +++ b/apps/desktopgui/src/gui/resources/SpeedSelector3.properties @@ -0,0 +1,17 @@ +Form.title=I2P Configuration +previousButton.text=Previous +finishButton.text=Finish +uploadLabel.text=Upload Speed: +uploadBurstLabel.text=Burst Upload Speed: +downloadLabel.text=Download Speed: +downloadBurstLabel.text=Burst Download Speed: +uploadUsageLabel.text=GB +downloadUsageLabel.text=GB +uploadField.text=jTextField1 +uploadBurstField.text=jTextField2 +downloadField.text=jTextField4 +downloadBurstField.text=jTextField5 +uploadMonth.text=jTextField1 +downloadMonth.text=jTextField2 +settingsInfo.text=The profile information your entered, indicates that these are your optimal settings: +explanation.text=We give a suggested upload and download speed. If your provider imposes a monthly bandwidth limit (usually given in gigabyte (GB)), please enter a value lower than that limit. If you run I2P only 50% of the time, you can double the bandwidth limit to use the same amount as when you are online 100% of the time. diff --git a/apps/desktopgui/src/persistence/PropertyManager.java b/apps/desktopgui/src/persistence/PropertyManager.java new file mode 100644 index 0000000000..bacbf348ac --- /dev/null +++ b/apps/desktopgui/src/persistence/PropertyManager.java @@ -0,0 +1,72 @@ +package persistence; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author mathias + */ +public class PropertyManager { + + public static void setProps(Properties props) { + PropertyManager.props = props; + } + + public static Properties getProps() { + return props; + } + + public static Properties loadProps() { + Properties defaultProps = new Properties(); + defaultProps.setProperty("firstLoad", "true"); + + // create application properties with default + Properties applicationProps = new Properties(defaultProps); + + // now load properties from last invocation + FileInputStream in; + try { + in = new FileInputStream(PROPSLOCATION); + applicationProps.load(in); + in.close(); + } catch (FileNotFoundException ex) { + //Nothing serious, just means it's being loaded for the first time. + } catch(IOException ex) { + Logger.getLogger(PropertyManager.class.getName()).log(Level.INFO, null, ex); + } + props = applicationProps; + return applicationProps; + } + + public static void saveProps(Properties props) { + FileOutputStream out; + try { + File d = new File(PROPSDIRECTORY); + if(!d.exists()) + d.mkdir(); + File f = new File(PROPSLOCATION); + if(!f.exists()) + f.createNewFile(); + out = new FileOutputStream(f); + props.store(out, PROPSLOCATION); + } catch (FileNotFoundException ex) { + Logger.getLogger(PropertyManager.class.getName()).log(Level.SEVERE, null, ex); + } catch(IOException ex) { + Logger.getLogger(PropertyManager.class.getName()).log(Level.SEVERE, null, ex); + } + } + + private static Properties props; + + ///Location where we store the Application Properties + public static final String PROPSDIRECTORY = "desktopgui"; + public static final String PROPSFILENAME = "appProperties"; + public static final String PROPSLOCATION = PROPSDIRECTORY + File.separator + PROPSFILENAME; +} diff --git a/apps/desktopgui/src/router/RouterHandler.java b/apps/desktopgui/src/router/RouterHandler.java new file mode 100644 index 0000000000..0752f877b5 --- /dev/null +++ b/apps/desktopgui/src/router/RouterHandler.java @@ -0,0 +1,38 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package router; + +import java.util.logging.Level; +import java.util.logging.Logger; +import net.i2p.router.RouterContext; + +/** + * + * @author mathias + */ +public class RouterHandler { + public static final int SHUTDOWN_GRACEFULLY = 0; + public static void setStatus(int status) { + if(status == SHUTDOWN_GRACEFULLY) { + Thread t = new Thread(new Runnable() { + + public void run() { + RouterContext context = RouterHelper.getContext(); + context.router().shutdownGracefully(); + while(context.router().getShutdownTimeRemaining()>0) + try { + Thread.sleep(context.router().getShutdownTimeRemaining()); + } catch (InterruptedException ex) { + Logger.getLogger(RouterHandler.class.getName()).log(Level.SEVERE, null, ex); + } + System.exit(0); + } + + }); + t.start(); + } + } +} diff --git a/apps/desktopgui/src/router/RouterHelper.java b/apps/desktopgui/src/router/RouterHelper.java new file mode 100644 index 0000000000..6d3cddd03d --- /dev/null +++ b/apps/desktopgui/src/router/RouterHelper.java @@ -0,0 +1,17 @@ +package router; + +import net.i2p.router.RouterContext; + +/** + * + * @author mathias + */ +public class RouterHelper { + public static RouterContext getContext() { + return (RouterContext) RouterContext.listContexts().get(0); + } + + public static long getGracefulShutdownTimeRemaining() { + return RouterHelper.getContext().router().getShutdownTimeRemaining(); + } +} diff --git a/apps/desktopgui/src/router/configuration/PeerHelper.java b/apps/desktopgui/src/router/configuration/PeerHelper.java new file mode 100644 index 0000000000..2272456f8d --- /dev/null +++ b/apps/desktopgui/src/router/configuration/PeerHelper.java @@ -0,0 +1,165 @@ +package router.configuration; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import net.i2p.data.RouterAddress; +import net.i2p.router.CommSystemFacade; +import net.i2p.router.RouterContext; +import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; +import net.i2p.router.transport.ntcp.NTCPAddress; +import router.RouterHelper; + +/** + * Part of the code imported and adapted from the I2P Router Console (which is licensed as public domain) + */ +public class PeerHelper { + public static String getReachability() { + RouterContext context = RouterHelper.getContext(); + if (context.router().getUptime() > 60*1000 + && (!context.router().gracefulShutdownInProgress()) + && !context.clientManager().isAlive()) + return "ERROR: Client Manager I2CP Error - check logs"; // not a router problem but the user should know + if (!context.clock().getUpdatedSuccessfully()) + return "ERROR: ClockSkew"; + if (context.router().isHidden()) + return "Hidden"; + + int status = context.commSystem().getReachabilityStatus(); + switch (status) { + case CommSystemFacade.STATUS_OK: + RouterAddress ra = context.router().getRouterInfo().getTargetAddress("NTCP"); + if (ra == null || (new NTCPAddress(ra)).isPubliclyRoutable()) + return "OK"; + return "ERROR: Private TCP Address"; + case CommSystemFacade.STATUS_DIFFERENT: + return "ERROR: You are behind a symmetric NAT."; + case CommSystemFacade.STATUS_REJECT_UNSOLICITED: + if (context.router().getRouterInfo().getTargetAddress("NTCP") != null) + return "WARNING: You are behind a firewall and have Inbound TCP Enabled"; + if (((FloodfillNetworkDatabaseFacade)context.netDb()).floodfillEnabled()) + return "WARNING: You are behind a firewall and are a floodfill router"; + if (context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0) + return "WARNING: You are behind a firewall and are a fast router"; + return "Firewalled"; + case CommSystemFacade.STATUS_HOSED: + return "ERROR: The UDP port is already in use. Set i2np.udp.internalPort=xxxx to a different value in the advanced config and restart"; + case CommSystemFacade.STATUS_UNKNOWN: // fallthrough + default: + ra = context.router().getRouterInfo().getTargetAddress("UDP"); + if (ra == null && context.router().getUptime() > 5*60*1000) { + if (context.getProperty(PROP_I2NP_NTCP_HOSTNAME) == null || + context.getProperty(PROP_I2NP_NTCP_PORT) == null) + return "ERROR: UDP is disabled and the inbound TCP host/port combination is not set"; + else + return "WARNING: You are behind a firewall and have UDP Disabled"; + } + return "Testing"; + } + } + + /** + * How many peers we are talking to now + * + */ + public static int getActivePeers() { + RouterContext context = RouterHelper.getContext(); + if (context == null) + return 0; + else + return context.commSystem().countActivePeers(); + } + + public static void addActivePeerListener(ActionListener listener) { + synchronized(activePeerListeners) { + activePeerListeners.add(listener); + if(activePeerTimer == null) { + activePeerTimer = new Timer(); + TimerTask t = new TimerTask() { + private int activePeers = 0; + + @Override + public void run() { + int newActivePeers = getActivePeers(); + if(!(activePeers == newActivePeers)) { + synchronized(activePeerListeners) { + for(int i=0; i reachabilityListeners = new ArrayList(); + private static Timer reachabilityTimer = null; + + private static List activePeerListeners = new ArrayList(); + private static Timer activePeerTimer = null; + + /** copied from various private components */ + public final static String PROP_I2NP_UDP_PORT = "i2np.udp.port"; + public final static String PROP_I2NP_INTERNAL_UDP_PORT = "i2np.udp.internalPort"; + public final static String PROP_I2NP_NTCP_HOSTNAME = "i2np.ntcp.hostname"; + public final static String PROP_I2NP_NTCP_PORT = "i2np.ntcp.port"; + public final static String PROP_I2NP_NTCP_AUTO_PORT = "i2np.ntcp.autoip"; + public final static String PROP_I2NP_NTCP_AUTO_IP = "i2np.ntcp.autoport"; +} diff --git a/apps/desktopgui/src/router/configuration/SpeedHandler.java b/apps/desktopgui/src/router/configuration/SpeedHandler.java new file mode 100644 index 0000000000..235790792a --- /dev/null +++ b/apps/desktopgui/src/router/configuration/SpeedHandler.java @@ -0,0 +1,34 @@ +package router.configuration; + +import net.i2p.router.RouterContext; +import net.i2p.router.transport.FIFOBandwidthRefiller; +import router.RouterHelper; + +/** + * + * @author mathias + */ +public class SpeedHandler { + + public static void setInboundBandwidth(int kbytes) { + context.router().setConfigSetting(FIFOBandwidthRefiller.PROP_INBOUND_BANDWIDTH, "" + kbytes); + context.router().saveConfig(); + } + + public static void setOutboundBandwidth(int kbytes) { + context.router().setConfigSetting(FIFOBandwidthRefiller.PROP_OUTBOUND_BANDWIDTH, "" + kbytes); + context.router().saveConfig(); + } + + public static void setInboundBurstBandwidth(int kbytes) { + context.router().setConfigSetting(FIFOBandwidthRefiller.PROP_INBOUND_BURST_BANDWIDTH, "" + kbytes); + context.router().saveConfig(); + } + + public static void setOutboundBurstBandwidth(int kbytes) { + context.router().setConfigSetting(FIFOBandwidthRefiller.PROP_OUTBOUND_BURST_BANDWIDTH, "" + kbytes); + context.router().saveConfig(); + } + + private static final RouterContext context = RouterHelper.getContext(); +} diff --git a/apps/desktopgui/src/router/configuration/SpeedHelper.java b/apps/desktopgui/src/router/configuration/SpeedHelper.java new file mode 100644 index 0000000000..acad2adb14 --- /dev/null +++ b/apps/desktopgui/src/router/configuration/SpeedHelper.java @@ -0,0 +1,32 @@ +package router.configuration; + +/** + * + * @author mathias + */ +public class SpeedHelper { + public static final String USERTYPE_BROWSING = "Browsing"; + public static final String USERTYPE_DOWNLOADING = "Downloading"; + + public static int calculateSpeed(String capable, String profile) { + int capableSpeed = Integer.parseInt(capable); + int advisedSpeed = capableSpeed; + if(capableSpeed > 1000) { + if(profile.equals(USERTYPE_BROWSING)) //Don't overdo usage for people just wanting to browse (we don't want to drive them away due to resource hogging) + advisedSpeed *= 0.6; + else if(profile.equals(USERTYPE_DOWNLOADING)) + advisedSpeed *= 0.8; + } + else + advisedSpeed *= 0.6; //Lower available bandwidth: don't hog all the bandwidth + return advisedSpeed; + } + + public static int calculateMonthlyUsage(int kbytes) { + return (int) ((((long)kbytes)*3600*24*31)/1000000); + } + + public static int calculateSpeed(int gigabytes) { + return (int) (((long)gigabytes)*1000000/31/24/3600); + } +} diff --git a/apps/desktopgui/src/util/IntegerVerifier.java b/apps/desktopgui/src/util/IntegerVerifier.java new file mode 100644 index 0000000000..74f87961da --- /dev/null +++ b/apps/desktopgui/src/util/IntegerVerifier.java @@ -0,0 +1,32 @@ +package util; + +import javax.swing.InputVerifier; +import javax.swing.JComponent; +import javax.swing.JTextField; + +/** + * + * @author mathias + */ + +public class IntegerVerifier extends InputVerifier { + + @Override + public boolean verify(JComponent arg0) { + JTextField jtf = (JTextField) arg0; + return verify(jtf.getText()); + } + + @Override + public boolean shouldYieldFocus(JComponent input) { + return verify(input); + } + + public static boolean verify(String s) { + for(int i=0;i '9' || s.charAt(i) < '0') + return false; + return true; + } + +} \ No newline at end of file diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/BufferLogger.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/BufferLogger.java index 29f954fc4f..4c3da08988 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/BufferLogger.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/BufferLogger.java @@ -14,7 +14,7 @@ import net.i2p.util.Log; */ class BufferLogger implements Logging { private final static Log _log = new Log(BufferLogger.class); - private ByteArrayOutputStream _baos; + private ByteArrayOutputStream _baos; // should be final and use a factory. LINT private boolean _ignore; /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java index 411b2c4426..12940a81bc 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java @@ -59,13 +59,16 @@ class HTTPResponseOutputStream extends FilterOutputStream { _buf1 = new byte[1]; } + @Override public void write(int c) throws IOException { _buf1[0] = (byte)c; write(_buf1, 0, 1); } + @Override public void write(byte buf[]) throws IOException { write(buf, 0, buf.length); } + @Override public void write(byte buf[], int off, int len) throws IOException { if (_headerWritten) { out.write(buf, off, len); @@ -207,6 +210,7 @@ class HTTPResponseOutputStream extends FilterOutputStream { out.write("\r\n".getBytes()); // end of the headers } + @Override public void close() throws IOException { out.close(); } @@ -303,11 +307,13 @@ class HTTPResponseOutputStream extends FilterOutputStream { return true; } } + @Override public String toString() { return "Read: " + getTotalRead() + " expanded: " + getTotalExpanded() + " remaining: " + getRemaining() + " finished: " + getFinished(); } } + @Override public String toString() { return super.toString() + ": " + _in; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index b11f954e7e..015f5c9c58 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -75,7 +75,7 @@ public class I2PTunnel implements Logging, EventDispatcher { private static long __tunnelId = 0; private long _tunnelId; private Properties _clientOptions; - private List _sessions; + private final List _sessions; public static final int PACKET_DELAY = 100; @@ -89,7 +89,7 @@ public class I2PTunnel implements Logging, EventDispatcher { private static final String nocli_args[] = { "-nocli", "-die"}; - private List tasks = new ArrayList(); + private final List tasks = new ArrayList(); private int next_task_id = 1; private Set listeners = new HashSet(); @@ -606,9 +606,9 @@ public class I2PTunnel implements Logging, EventDispatcher { */ public void runHttpClient(String args[], Logging l) { if (args.length >= 1 && args.length <= 3) { - int port = -1; + int clientPort = -1; try { - port = Integer.parseInt(args[0]); + clientPort = Integer.parseInt(args[0]); } catch (NumberFormatException nfe) { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); @@ -642,12 +642,12 @@ public class I2PTunnel implements Logging, EventDispatcher { I2PTunnelTask task; ownDest = !isShared; try { - task = new I2PTunnelHTTPClient(port, l, ownDest, proxy, (EventDispatcher) this, this); + task = new I2PTunnelHTTPClient(clientPort, l, ownDest, proxy, (EventDispatcher) this, this); addtask(task); notifyEvent("httpclientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create an httpclient [" + host + ":"+ port + "]", iae); - l.log("Invalid I2PTunnel configuration [" + host + ":" + port + "]"); + _log.error(getPrefix() + "Invalid I2PTunnel config to create an httpclient [" + host + ":"+ clientPort + "]", iae); + l.log("Invalid I2PTunnel configuration [" + host + ":" + clientPort + "]"); notifyEvent("httpclientTaskId", Integer.valueOf(-1)); } } else { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java index 502bb28d5c..12931f3a27 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java @@ -44,11 +44,11 @@ public class I2PTunnelClient extends I2PTunnelClientBase { while (tok.hasMoreTokens()) { String destination = tok.nextToken(); try { - Destination dest = I2PTunnel.destFromName(destination); - if (dest == null) + Destination destN = I2PTunnel.destFromName(destination); + if (destN == null) l.log("Could not resolve " + destination); else - dests.add(dest); + dests.add(destN); } catch (DataFormatException dfe) { l.log("Bad format parsing \"" + destination + "\""); } @@ -71,10 +71,10 @@ public class I2PTunnelClient extends I2PTunnelClientBase { public long getReadTimeout() { return readTimeout; } protected void clientConnectionRun(Socket s) { - Destination dest = pickDestination(); + Destination destN = pickDestination(); I2PSocket i2ps = null; try { - i2ps = createI2PSocket(dest); + i2ps = createI2PSocket(destN); i2ps.setReadTimeout(readTimeout); new I2PTunnelRunner(s, i2ps, sockLock, null, mySockets); } catch (Exception ex) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index b6eb392243..c4eafde506 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -41,8 +41,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna private static volatile long __clientId = 0; protected long _clientId; - protected Object sockLock = new Object(); // Guards sockMgr and mySockets - protected I2PSocketManager sockMgr; + protected final Object sockLock = new Object(); // Guards sockMgr and mySockets + protected I2PSocketManager sockMgr; // should be final and use a factory. LINT protected List mySockets = new ArrayList(); protected Destination dest = null; @@ -52,20 +52,20 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna private ServerSocket ss; - private Object startLock = new Object(); + private final Object startLock = new Object(); private boolean startRunning = false; - private Object closeLock = new Object(); + // private Object closeLock = new Object(); - private byte[] pubkey; + // private byte[] pubkey; private String handlerName; private String privKeyFile; - private Object conLock = new Object(); + // private Object conLock = new Object(); /** List of Socket for those accept()ed but not yet started up */ - private List _waitingSockets = new ArrayList(); + private List _waitingSockets = new ArrayList(); // should be final and use a factory. LINT /** How many connections will we allow to be in the process of being built at once? */ private int _numConnectionBuilders; /** How long will we allow sockets to sit in the _waitingSockets map before killing them? */ @@ -100,7 +100,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } /** - * @param privKeyFile null to generate a transient key + * @param pkf null to generate a transient key * * @throws IllegalArgumentException if the I2CP configuration is b0rked so * badly that we cant create a socketManager @@ -278,6 +278,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } } sockManager.setName("Client"); + tunnel.addSession(sockManager.getSession()); return sockManager; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index bf7ebf0a7a..d781866d95 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -17,7 +17,6 @@ import net.i2p.I2PAppContext; import net.i2p.I2PException; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocketOptions; -import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; import net.i2p.util.EventDispatcher; @@ -55,7 +54,7 @@ import net.i2p.util.Log; public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runnable { private static final Log _log = new Log(I2PTunnelConnectClient.class); - private List _proxyList; + private final List _proxyList; private final static byte[] ERR_DESTINATION_UNKNOWN = ("HTTP/1.1 503 Service Unavailable\r\n"+ @@ -116,12 +115,12 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna I2PTunnel tunnel) throws IllegalArgumentException { super(localPort, ownDest, l, notifyThis, "HTTPHandler " + (++__clientId), tunnel); + _proxyList = new ArrayList(); if (waitEventValue("openBaseClientResult").equals("error")) { notifyEvent("openConnectClientResult", "error"); return; } - _proxyList = new ArrayList(); if (wwwProxy != null) { StringTokenizer tok = new StringTokenizer(wwwProxy, ","); while (tok.hasMoreTokens()) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 8e5ef9f4dc..93c8e86742 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -50,7 +50,7 @@ import net.i2p.util.Log; public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable { private static final Log _log = new Log(I2PTunnelHTTPClient.class); - private List proxyList; + private final List proxyList; private HashMap addressHelpers = new HashMap(); @@ -145,12 +145,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable I2PTunnel tunnel) throws IllegalArgumentException { super(localPort, ownDest, l, notifyThis, "HTTPHandler " + (++__clientId), tunnel); + proxyList = new ArrayList(); if (waitEventValue("openBaseClientResult").equals("error")) { notifyEvent("openHTTPClientResult", "error"); return; } - proxyList = new ArrayList(); if (wwwProxy != null) { StringTokenizer tok = new StringTokenizer(wwwProxy, ","); while (tok.hasMoreTokens()) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientRunner.java index 9ade9021f5..6afc940f7d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientRunner.java @@ -30,11 +30,13 @@ public class I2PTunnelHTTPClientRunner extends I2PTunnelRunner { _log = I2PAppContext.getGlobalContext().logManager().getLog(I2PTunnelHTTPClientRunner.class); } + @Override protected OutputStream getSocketOut() throws IOException { OutputStream raw = super.getSocketOut(); return new HTTPResponseOutputStream(raw); } + @Override protected void close(OutputStream out, InputStream in, OutputStream i2pout, InputStream i2pin, Socket s, I2PSocket i2ps, Thread t1, Thread t2) throws InterruptedException, IOException { try { i2pin.close(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java index d6cb40a259..d43639cb7e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java @@ -59,6 +59,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { * Called by the thread pool of I2PSocket handlers * */ + @Override protected void blockingHandle(I2PSocket socket) { long afterAccept = getTunnel().getContext().clock().now(); long afterSocket = -1; @@ -247,7 +248,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { super(o); } + @Override protected boolean shouldCompress() { return true; } + @Override protected void finishHeaders() throws IOException { if (_log.shouldLog(Log.INFO)) _log.info("Including x-i2p-gzip as the content encoding in the response"); @@ -255,6 +258,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { super.finishHeaders(); } + @Override protected void beginProcessing() throws IOException { if (_log.shouldLog(Log.INFO)) _log.info("Beginning compression processing"); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index 732c222a71..8b62702198 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -51,11 +51,11 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable while (tok.hasMoreTokens()) { String destination = tok.nextToken(); try { - Destination dest = I2PTunnel.destFromName(destination); - if (dest == null) + Destination destN = I2PTunnel.destFromName(destination); + if (destN == null) l.log("Could not resolve " + destination); else - dests.add(dest); + dests.add(destN); } catch (DataFormatException dfe) { l.log("Bad format parsing \"" + destination + "\""); } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java index 7e12aa30a6..2e209dbd74 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java @@ -3,22 +3,18 @@ package net.i2p.i2ptunnel; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; import java.util.Properties; -import net.i2p.I2PAppContext; import net.i2p.client.streaming.I2PSocket; import net.i2p.crypto.SHA256Generator; -import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; import net.i2p.data.Hash; import net.i2p.data.Base32; import net.i2p.util.EventDispatcher; -import net.i2p.util.I2PThread; import net.i2p.util.Log; /** @@ -83,6 +79,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable { this.hostname = opts.getProperty(PROP_HOSTNAME, PROP_HOSTNAME_DEFAULT); } + @Override protected void blockingHandle(I2PSocket socket) { try { // give them 15 seconds to send in the request diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java index f237b97efb..76480a9403 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java @@ -36,7 +36,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL private Socket s; private I2PSocket i2ps; - Object slock, finishLock = new Object(); + final Object slock, finishLock = new Object(); boolean finished = false; HashMap ostreams, sockets; byte[] initialI2PData; @@ -114,6 +114,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL protected InputStream getSocketIn() throws IOException { return s.getInputStream(); } protected OutputStream getSocketOut() throws IOException { return s.getOutputStream(); } + @Override public void run() { try { InputStream in = getSocketIn(); @@ -239,6 +240,7 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL start(); } + @Override public void run() { String from = i2ps.getThisDestination().calculateHash().toBase64().substring(0,6); String to = i2ps.getPeerDestination().calculateHash().toBase64().substring(0,6); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java index fa3478c71d..76246d7b66 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java @@ -18,8 +18,6 @@ import java.util.Properties; import net.i2p.I2PAppContext; import net.i2p.I2PException; -import net.i2p.client.I2PClient; -import net.i2p.client.I2PClientFactory; import net.i2p.client.streaming.I2PServerSocket; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocketManager; @@ -36,8 +34,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { protected I2PSocketManager sockMgr; protected I2PServerSocket i2pss; - private Object lock = new Object(); - protected Object slock = new Object(); + private final Object lock = new Object(); + protected final Object slock = new Object(); protected InetAddress remoteHost; protected int remotePort; @@ -203,17 +201,17 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { public void run() { if (shouldUsePool()) { - I2PServerSocket i2pss = sockMgr.getServerSocket(); + I2PServerSocket i2pS_S = sockMgr.getServerSocket(); int handlers = getHandlerCount(); for (int i = 0; i < handlers; i++) { - I2PThread handler = new I2PThread(new Handler(i2pss), "Handle Server " + i); + I2PThread handler = new I2PThread(new Handler(i2pS_S), "Handle Server " + i); handler.start(); } } else { - I2PServerSocket i2pss = sockMgr.getServerSocket(); + I2PServerSocket i2pS_S = sockMgr.getServerSocket(); while (true) { try { - final I2PSocket i2ps = i2pss.accept(); + final I2PSocket i2ps = i2pS_S.accept(); if (i2ps == null) throw new I2PException("I2PServerSocket closed"); new I2PThread(new Runnable() { public void run() { blockingHandle(i2ps); } }).start(); } catch (I2PException ipe) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelTask.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelTask.java index 6aa8ca18f7..4a6a0bb66e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelTask.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelTask.java @@ -73,6 +73,7 @@ public abstract class I2PTunnelTask implements EventDispatcher { public void reportAbuse(I2PSession session, int severity) { } + @Override public String toString() { return name; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java index 019bc7826c..f57ecd23d1 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java @@ -37,11 +37,11 @@ public class I2Ping extends I2PTunnelTask implements Runnable { private String command; private long timeout = PING_TIMEOUT; - private Object simulLock = new Object(); + private final Object simulLock = new Object(); private int simulPings = 0; private long lastPingTime = 0; - private Object lock = new Object(), slock = new Object(); + private final Object lock = new Object(), slock = new Object(); //public I2Ping(String cmd, Logging l, // boolean ownDest) { @@ -197,6 +197,7 @@ public class I2Ping extends I2PTunnelTask implements Runnable { start(); } + @Override public void run() { try { Destination dest = I2PTunnel.destFromName(destination); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java index 3b6e765399..16f418be9e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java @@ -40,7 +40,7 @@ public class TunnelControllerGroup { * no more tunnels are using it) * */ - private Map _sessions; + private final Map _sessions; public static TunnelControllerGroup getInstance() { synchronized (TunnelControllerGroup.class) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/ReplyTracker.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/ReplyTracker.java index f6a124c951..fbdf2939d1 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/ReplyTracker.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/ReplyTracker.java @@ -1,6 +1,5 @@ package net.i2p.i2ptunnel.socks; -import java.util.concurrent.ConcurrentHashMap; import java.util.Map; import net.i2p.data.Destination; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java index 5e52926074..cc397c414c 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java @@ -379,7 +379,7 @@ public class SOCKS5Server extends SOCKSServer { // This isn't really the right place for this, we can't stop the tunnel once it starts. static SOCKSUDPTunnel _tunnel; - static Object _startLock = new Object(); + static final Object _startLock = new Object(); static byte[] dummyIP = new byte[4]; /** * We got a UDP associate command. diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServer.java index 06c3fab552..09e9284deb 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServer.java @@ -9,7 +9,6 @@ package net.i2p.i2ptunnel.socks; import java.net.Socket; import net.i2p.client.streaming.I2PSocket; -import net.i2p.i2ptunnel.I2PTunnel; import net.i2p.util.Log; /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPTunnel.java index 0adaa19506..0490a6f0af 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPTunnel.java @@ -7,10 +7,7 @@ import java.util.Map; import net.i2p.data.Destination; import net.i2p.i2ptunnel.I2PTunnel; -import net.i2p.i2ptunnel.Logging; -import net.i2p.i2ptunnel.udp.*; import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPClientBase; -import net.i2p.util.EventDispatcher; /** * A Datagram Tunnel that can have multiple bidirectional ports on the UDP side. @@ -63,12 +60,14 @@ public class SOCKSUDPTunnel extends I2PTunnelUDPClientBase { } } + @Override public final void startRunning() { super.startRunning(); // demuxer start() doesn't do anything startall(); } + @Override public boolean close(boolean forced) { stopall(); return super.close(forced); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Pinger.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Pinger.java index a3a7975361..29d1186c4d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Pinger.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Pinger.java @@ -54,6 +54,6 @@ public class Pinger implements Source, Runnable { protected Sink sink; protected Thread thread; - protected Object waitlock; + protected Object waitlock; // should be final and use a factory. LINT protected boolean running; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java index 87ea0eefe6..9c1d584ae0 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java @@ -7,7 +7,6 @@ package net.i2p.i2ptunnel.streamr; import java.net.InetAddress; -import net.i2p.data.Destination; import net.i2p.i2ptunnel.I2PTunnel; import net.i2p.i2ptunnel.Logging; import net.i2p.i2ptunnel.udp.*; @@ -38,6 +37,7 @@ public class StreamrConsumer extends I2PTunnelUDPClientBase { this.pinger.setSink(this); } + @Override public final void startRunning() { super.startRunning(); // send subscribe-message @@ -45,6 +45,7 @@ public class StreamrConsumer extends I2PTunnelUDPClientBase { l.log("Streamr client ready"); } + @Override public boolean close(boolean forced) { // send unsubscribe-message this.pinger.stop(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java index b801cb94f4..7d6b14491d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java @@ -9,7 +9,6 @@ package net.i2p.i2ptunnel.streamr; import java.io.File; // i2p -import net.i2p.client.I2PSession; import net.i2p.i2ptunnel.I2PTunnel; import net.i2p.i2ptunnel.Logging; import net.i2p.i2ptunnel.udp.*; @@ -45,12 +44,14 @@ public class StreamrProducer extends I2PTunnelUDPServerBase { this.server.setSink(this.multi); } + @Override public final void startRunning() { super.startRunning(); this.server.start(); l.log("Streamr server ready"); } + @Override public boolean close(boolean forced) { this.server.stop(); this.multi.stop(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Subscriber.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Subscriber.java index 97abdb8890..377292ddef 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Subscriber.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Subscriber.java @@ -6,17 +6,12 @@ package net.i2p.i2ptunnel.streamr; // system -import java.io.File; import java.util.Set; // i2p import net.i2p.client.I2PSession; import net.i2p.data.Destination; -import net.i2p.i2ptunnel.I2PTunnel; -import net.i2p.i2ptunnel.Logging; import net.i2p.i2ptunnel.udp.*; -import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPServerBase; -import net.i2p.util.EventDispatcher; import net.i2p.util.ConcurrentHashSet; /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java index f7a1bf541e..e08596af11 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java @@ -69,5 +69,5 @@ public class I2PSink implements Sink { protected boolean raw; protected I2PSession sess; protected Destination dest; - protected I2PDatagramMaker maker; + protected I2PDatagramMaker maker; // should be final and use a factory. LINT } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java index 54d5a7d97d..2da942a74a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java @@ -67,5 +67,5 @@ public class I2PSinkAnywhere implements Sink { protected boolean raw; protected I2PSession sess; protected Destination dest; - protected I2PDatagramMaker maker; + protected I2PDatagramMaker maker; // should be final and use a factory. LINT } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java index c92da6ae8a..14945c8422 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java @@ -5,21 +5,9 @@ package net.i2p.i2ptunnel.udpTunnel; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.NoRouteToHostException; import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Properties; import net.i2p.I2PAppContext; -import net.i2p.I2PException; import net.i2p.client.I2PClient; import net.i2p.client.I2PClientFactory; import net.i2p.client.I2PSession; @@ -31,10 +19,31 @@ import net.i2p.i2ptunnel.I2PTunnelTask; import net.i2p.i2ptunnel.Logging; import net.i2p.i2ptunnel.udp.*; import net.i2p.util.EventDispatcher; -import net.i2p.util.I2PThread; import net.i2p.util.Log; -public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements Source, Sink { + /** + * Base client class that sets up an I2P Datagram client destination. + * The UDP side is not implemented here, as there are at least + * two possibilities: + * + * 1) UDP side is a "server" + * Example: Streamr Consumer + * - Configure a destination host and port + * - External application sends no data + * - Extending class must have a constructor with host and port arguments + * + * 2) UDP side is a client/server + * Example: SOCKS UDP (DNS requests?) + * - configure an inbound port and a destination host and port + * - External application sends and receives data + * - Extending class must have a constructor with host and 2 port arguments + * + * So the implementing class must create a UDPSource and/or UDPSink, + * and must call setSink(). + * + * @author zzz with portions from welterde's streamr + */ + public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements Source, Sink { private static final Log _log = new Log(I2PTunnelUDPClientBase.class); protected I2PAppContext _context; @@ -69,33 +78,11 @@ public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements So private Source _i2pSource; private Sink _i2pSink; private Destination _otherDest; - /** - * Base client class that sets up an I2P Datagram client destination. - * The UDP side is not implemented here, as there are at least - * two possibilities: - * - * 1) UDP side is a "server" - * Example: Streamr Consumer - * - Configure a destination host and port - * - External application sends no data - * - Extending class must have a constructor with host and port arguments - * - * 2) UDP side is a client/server - * Example: SOCKS UDP (DNS requests?) - * - configure an inbound port and a destination host and port - * - External application sends and receives data - * - Extending class must have a constructor with host and 2 port arguments - * - * So the implementing class must create a UDPSource and/or UDPSink, - * and must call setSink(). - * * @throws IllegalArgumentException if the I2CP configuration is b0rked so * badly that we cant create a socketManager - * - * @author zzz with portions from welterde's streamr */ - public I2PTunnelUDPClientBase(String destination, Logging l, EventDispatcher notifyThis, + public I2PTunnelUDPClientBase(String destination, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) throws IllegalArgumentException { super("UDPServer", notifyThis, tunnel); _clientId = ++__clientId; @@ -107,11 +94,11 @@ public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements So // create i2pclient and destination I2PClient client = I2PClientFactory.createClient(); - Destination dest; + Destination destN; byte[] key; try { ByteArrayOutputStream out = new ByteArrayOutputStream(512); - dest = client.createDestination(out); + destN = client.createDestination(out); key = out.toByteArray(); } catch(Exception exc) { throw new RuntimeException("failed to create i2p-destination", exc); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java index 8dcd66a365..6ba8379f94 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java @@ -3,54 +3,24 @@ */ package net.i2p.i2ptunnel.udpTunnel; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.util.Iterator; -import java.util.Properties; -import net.i2p.I2PAppContext; import net.i2p.I2PException; import net.i2p.client.I2PClient; import net.i2p.client.I2PClientFactory; import net.i2p.client.I2PSession; import net.i2p.client.I2PSessionException; -import net.i2p.data.Base64; import net.i2p.data.Destination; import net.i2p.i2ptunnel.I2PTunnel; import net.i2p.i2ptunnel.I2PTunnelTask; import net.i2p.i2ptunnel.Logging; import net.i2p.i2ptunnel.udp.*; import net.i2p.util.EventDispatcher; -import net.i2p.util.I2PThread; import net.i2p.util.Log; -public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sink { - - private final static Log _log = new Log(I2PTunnelUDPServerBase.class); - - private Object lock = new Object(); - protected Object slock = new Object(); - - private static volatile long __serverId = 0; - - protected Logging l; - - private static final long DEFAULT_READ_TIMEOUT = -1; // 3*60*1000; - /** default timeout to 3 minutes - override if desired */ - protected long readTimeout = DEFAULT_READ_TIMEOUT; - - private I2PSession _session; - private Source _i2pSource; - private Sink _i2pSink; - /** * Base client class that sets up an I2P Datagram server destination. * The UDP side is not implemented here, as there are at least @@ -70,11 +40,34 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin * * So the implementing class must create a UDPSource and/or UDPSink, * and must call setSink(). + * + * @author zzz with portions from welterde's streamr + */ + +public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sink { + + private final static Log _log = new Log(I2PTunnelUDPServerBase.class); + + private final Object lock = new Object(); + protected Object slock = new Object(); + + private static volatile long __serverId = 0; + + protected Logging l; + + private static final long DEFAULT_READ_TIMEOUT = -1; // 3*60*1000; + /** default timeout to 3 minutes - override if desired */ + protected long readTimeout = DEFAULT_READ_TIMEOUT; + + private I2PSession _session; + private Source _i2pSource; + private Sink _i2pSink; + + /** * * @throws IllegalArgumentException if the I2CP configuration is b0rked so * badly that we cant create a socketManager * - * @author zzz with portions from welterde's streamr */ public I2PTunnelUDPServerBase(boolean verify, File privkey, String privkeyname, Logging l, diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java index 0a909c62ec..a029de725a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java @@ -8,7 +8,6 @@ package net.i2p.i2ptunnel.web; * */ -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; diff --git a/apps/streaming/java/src/net/i2p/client/streaming/Connection.java b/apps/streaming/java/src/net/i2p/client/streaming/Connection.java index 6b99fdc00a..f73632683c 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/Connection.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/Connection.java @@ -187,12 +187,12 @@ public class Connection { if (_log.shouldLog(Log.DEBUG)) _log.debug("Outbound window is full (" + _outboundPackets.size() + "/" + _options.getWindowSize() + "/" + _activeResends + "), waiting " + timeLeft); - try { _outboundPackets.wait(Math.min(timeLeft,250l)); } catch (InterruptedException ie) {} + try { _outboundPackets.wait(Math.min(timeLeft,250l)); } catch (InterruptedException ie) { if (_log.shouldLog(Log.DEBUG)) _log.debug("InterruptedException while Outbound window is full (" + _outboundPackets.size() + "/" + _activeResends +")"); return false;} } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Outbound window is full (" + _outboundPackets.size() + "/" + _activeResends + "), waiting indefinitely"); - try { _outboundPackets.wait(250); } catch (InterruptedException ie) {} //10*1000 + try { _outboundPackets.wait(250); } catch (InterruptedException ie) {if (_log.shouldLog(Log.DEBUG)) _log.debug("InterruptedException while Outbound window is full (" + _outboundPackets.size() + "/" + _activeResends + ")"); return false;} //10*1000 } } else { _context.statManager().addRateData("stream.chokeSizeEnd", _outboundPackets.size(), _context.clock().now() - start); @@ -810,7 +810,11 @@ public class Connection { synchronized (_connectLock) { _connectLock.wait(timeLeft); } - } catch (InterruptedException ie) {} + } catch (InterruptedException ie) { + if (_log.shouldLog(Log.DEBUG)) _log.debug("waitForConnect(): InterruptedException"); + _connectionError = "InterruptedException"; + return; + } } } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java index b96eaea633..2d198ad66e 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java @@ -126,7 +126,7 @@ class ConnectionHandler { if (timeoutMs <= 0) { try { syn = _synQueue.take(); // waits forever - } catch (InterruptedException ie) {} + } catch (InterruptedException ie) { break;} } else { long remaining = expiration - _context.clock().now(); // (dont think this applies anymore for LinkedBlockingQueue) @@ -138,7 +138,7 @@ class ConnectionHandler { break; try { syn = _synQueue.poll(remaining, TimeUnit.MILLISECONDS); // waits the specified time max - } catch (InterruptedException ie) {} + } catch (InterruptedException ie) { } break; } } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/PacketLocal.java b/apps/streaming/java/src/net/i2p/client/streaming/PacketLocal.java index cbb89e79ec..197b927541 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/PacketLocal.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/PacketLocal.java @@ -213,7 +213,7 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat timeRemaining = 10*1000; wait(timeRemaining); } - } catch (InterruptedException ie) {} + } catch (InterruptedException ie) { break; } } if (!writeSuccessful()) releasePayload(); diff --git a/build.xml b/build.xml index ef84b2aab3..3a30ff8e7f 100644 --- a/build.xml +++ b/build.xml @@ -487,4 +487,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java index b08d01c264..a3e5e57a7f 100644 --- a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java @@ -146,8 +146,8 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession { * I2PSession.PROTO_STREAMING * I2PSession.PROTO_DATAGRAM * 255 disallowed - * @param fromport 1-65535 or 0 for unset - * @param toport 1-65535 or 0 for unset + * @param fromPort 1-65535 or 0 for unset + * @param toPort 1-65535 or 0 for unset */ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expires, diff --git a/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java b/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java index 13b01a67ad..79066c4c62 100644 --- a/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java +++ b/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java @@ -178,7 +178,11 @@ public class I2CPMessageReader { // pause .5 secs when we're paused try { Thread.sleep(500); - } catch (InterruptedException ie) { // nop + } catch (InterruptedException ie) { + // we should break away here. + _log.warn("Breaking away stream", ie); + _listener.disconnected(I2CPMessageReader.this); + cancelRunner(); } } } diff --git a/core/java/src/net/i2p/util/ConvertToHash.java b/core/java/src/net/i2p/util/ConvertToHash.java index 0878556400..28da87d217 100644 --- a/core/java/src/net/i2p/util/ConvertToHash.java +++ b/core/java/src/net/i2p/util/ConvertToHash.java @@ -16,12 +16,15 @@ import net.i2p.data.Hash; * Base32 desthash.b32.i2p * example.i2p * - * @return null on failure - * * @author zzz */ public class ConvertToHash { + /** + * Convert any kind of destination String to a hash + * + * @return null on failure + */ public static Hash getHash(String peer) { if (peer == null) return null; diff --git a/core/java/src/net/i2p/util/SimpleScheduler.java b/core/java/src/net/i2p/util/SimpleScheduler.java index becf100995..ee7d36e99a 100644 --- a/core/java/src/net/i2p/util/SimpleScheduler.java +++ b/core/java/src/net/i2p/util/SimpleScheduler.java @@ -1,7 +1,6 @@ package net.i2p.util; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.ThreadFactory; @@ -43,6 +42,7 @@ public class SimpleScheduler { _name = name; _count = 0; _executor = new ScheduledThreadPoolExecutor(THREADS, new CustomThreadFactory()); + _executor.prestartAllCoreThreads(); } /** @@ -91,6 +91,11 @@ public class SimpleScheduler { public Thread newThread(Runnable r) { Thread rv = Executors.defaultThreadFactory().newThread(r); rv.setName(_name + ' ' + (++_count) + '/' + THREADS); +// Uncomment this to test threadgrouping, but we should be all safe now that the constructor preallocates! +// String name = rv.getThreadGroup().getName(); +// if(!name.equals("main")) { +// (new Exception("OWCH! DAMN! Wrong ThreadGroup `" + name +"', `" + rv.getName() + "'")).printStackTrace(); +// } rv.setDaemon(true); return rv; } @@ -144,9 +149,11 @@ public class SimpleScheduler { _timeoutMs = timeoutMs; _scheduled = initialDelay + System.currentTimeMillis(); } + @Override public void schedule() { _executor.scheduleWithFixedDelay(this, _initialDelay, _timeoutMs, TimeUnit.MILLISECONDS); } + @Override public void run() { super.run(); _scheduled = _timeoutMs + System.currentTimeMillis(); diff --git a/core/java/src/net/i2p/util/SimpleTimer2.java b/core/java/src/net/i2p/util/SimpleTimer2.java index 6239ed42f2..b2af33cf2b 100644 --- a/core/java/src/net/i2p/util/SimpleTimer2.java +++ b/core/java/src/net/i2p/util/SimpleTimer2.java @@ -5,7 +5,6 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.ThreadFactory; -import java.util.Map; import net.i2p.I2PAppContext; @@ -42,6 +41,7 @@ public class SimpleTimer2 { _name = name; _count = 0; _executor = new CustomScheduledThreadPoolExecutor(THREADS, new CustomThreadFactory()); + _executor.prestartAllCoreThreads(); } /** @@ -56,6 +56,7 @@ public class SimpleTimer2 { super(threads, factory); } + @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (t != null) // shoudn't happen, caught in RunnableEvent.run() @@ -67,6 +68,11 @@ public class SimpleTimer2 { public Thread newThread(Runnable r) { Thread rv = Executors.defaultThreadFactory().newThread(r); rv.setName(_name + ' ' + (++_count) + '/' + THREADS); +// Uncomment this to test threadgrouping, but we should be all safe now that the constructor preallocates! +// String name = rv.getThreadGroup().getName(); +// if(!name.equals("main")) { +// (new Exception("OWCH! DAMN! Wrong ThreadGroup `" + name +"', `" + rv.getName() + "'")).printStackTrace(); +// } rv.setDaemon(true); return rv; } @@ -232,6 +238,7 @@ public class SimpleTimer2 { public abstract void timeReached(); } + @Override public String toString() { return _name; } diff --git a/history.txt b/history.txt index f027db23a5..5d2643a9d0 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,94 @@ +2009-04-11 sponge + * i2ptunnel janitorial work and fixes on most locks. + Some locks still need work, and are marked with LINT in the comment. + Just grep for "LINT" to see where the remaining places are. + +2009-04-10 sponge + * More BOB threadgroup fixes, plus debug dump when things go wrong. + * Fixes to streaminglib, I2CP, which are related to the TG problem. + * JavaDocs fixups. + +2009-04-08 sponge + * More hopeful fixups to the infamous orpahned tunnel problem. *Sigh* + +2009-04-08 zzz + * IPV6/localhost: + - Enable IPv6 stack in the JVM, hopefully won't break anything + - Patch Jetty to support binding to IPv6 addresses + - Allow multiple bind addresses for the router console + in the clients.config file; for new installs the + default is now "127.0.0.1,::1" + - Change most instances of "localhost" to "127.0.0.1" + throughout the code + * Router: + - Move some classes to private static inner + +2009-04-07 sponge + * BOB prevent jvac from optimizing out thread-group code from -10 + +2009-04-07 zzz + * NTCP: Prevent occasional NPE introduced in -4 + * streamr: Synchronize DatagramMaker + +2009-04-07 sponge + * SimpleTimer2, SimpleScheduler fixed so that the threads all run from + The main threadgroup, not in the current possible child threadgroup. + So long as any SimpleTimer2/SimpleScheduler is started *BEFORE* any + child threadgroups, the constructors are threadgroup safe. What would + be super cool is if they were to be all jailed within thier very own + threadgroup too, but, I2P isn't up to the task of this yet. + * Fixes to BOB to ensure the above is true. + +2009-04-06 sponge + * Debugging to make SimpleTimer2 and SimpleScheduler easier to debug. + * Fix for the config files in the GUI from mathiasdm + +2009-04-04 sponge + * Hopeful fixups to the infamous orpahned tunnel problem. + * BOB now 0.0.5 + +2009-04-04 zzz + * NTCP: Don't bid on messages too big to handle + +2009-04-03 zzz + * Console: + - Fix bug with IE buttons not working, + because it sends the label instead of the value + - Display version of downloaded update + * Update: + - Change default to "Download and verify" + - Change news fetch default to 24h (was 12h) + +2009-04-03 sponge + * Fix broken dependencies for BOB.jar + * Router build version incremented to 5. + +2009-04-02 zzz + * Profiles: + - Remove unused calculators and RateStats: + CapacityCalculator, StrictSpeedCalculator, IsFailingCalculator; + sendFailureSize, processSuccessRate, processfailureRate, commErrorRate, + tunnelTestResponseTimeSlow + - Reduced number of Rates in these RateStats: + sendSuccessSize, receiveSize, rejectRate, failRate + - ~5KB/profile savings total + - Deflate speed calculation once an hour instead of once a day, + to improve fast tier selection + - Remove dup comment in persisted files + * StatisticsManager - effective in 0.7.2: + - Spoof uptime to 90m for all + - Change tunnel stats from 10m to 60m + * Transport: + - Maintain a router hash -> IP map in transport, + to support additional IP checks (unused for now) + - Catch error on pre-2.6 kernels + - Some concurrent conversion + - Fix an HTML error on peers.jsp + +2009-04-01 zzz + * I2PTunnel: Fix tunnel close + http://forum.i2p/viewtopic.php?t=3231 + 2009-03-30 zzz * I2CP: - Implement BandwidthLimitsMessage diff --git a/installer/resources/wrapper.config b/installer/resources/wrapper.config index 4d09ba12c2..42958ba779 100644 --- a/installer/resources/wrapper.config +++ b/installer/resources/wrapper.config @@ -54,6 +54,10 @@ wrapper.java.classpath.17=lib/systray.jar wrapper.java.classpath.18=lib/systray4j.jar # BOB wrapper.java.classpath.19=lib/BOB.jar +# desktopgui +wrapper.java.classpath.20=lib/appframework.jar +wrapper.java.classpath.21=lib/swing-worker.jar +wrapper.java.classpath.22=lib/desktopgui.jar # Java Library Path (location of Wrapper.DLL or libwrapper.so) wrapper.java.library.path.1=. diff --git a/readme.html b/readme.html index 0e4891b5d8..c359913350 100644 --- a/readme.html +++ b/readme.html @@ -16,6 +16,7 @@ you can:

  • eepsites.i2p: an anonymously hosted search engine of eepsites
  • ugha.i2p: ugha's eepsite, a wiki that anyone can edit, and lots of links
  • fproxy.tino.i2p: Freenet proxy
  • +
  • echelon.i2p: software archive and information for I2P
  • There are many more eepsites - just follow the links from the ones you see, bookmark your favorites, and visit them often! diff --git a/readme_de.html b/readme_de.html index 1534585dab..e6fd916188 100644 --- a/readme_de.html +++ b/readme_de.html @@ -12,7 +12,8 @@
  • eepsites.i2p: Eine anonym gehostete Suchseite für Eepsites
  • ugha.i2p: Ugha's Eepsite, ein öffentliches Wiki mit vielen Links
  • fproxy.tino.i2p: Freenet proxy
  • - +
  • echelon.i2p: Software Archive und Informationen zu I2P
  • + Es gibt viel mehr Eepsites - folge einfach den Links die du findest, bookmarke Deine Favoriten und besuche sie oft!
  • Im Internet surfen - Es gibt einen HTTP "outproxy" in I2P in Deinem diff --git a/readme_fr.html b/readme_fr.html index 5e619cff2b..f2accf826c 100644 --- a/readme_fr.html +++ b/readme_fr.html @@ -11,6 +11,7 @@
  • eepsites.i2p: un moteur de recherche d'eepsites
  • ugha.i2p: l'eepsite d'ugha, un wiki que chaucun peut éditer ainsi que
  • fproxy.tino.i2p: un proxy Freenet 0.5
  • +
  • echelon.i2p: archive
  • Il y a bien plus d'eepsites - suivez juste les liens au départ de ceux sur lesquels vous êtes, mettez-les dans vos favoris et visitez-les souvent!
  • Parcourez le web - Il y a pour l'instant un outproxy HTTP sur I2P attaché à votre propre proxy HTTP sur le port 4444 - vous devez simplement configurer le proxy de votre navigateur pour l'utiliser (comme expliqué ci-dessus) et aller sur n'importe quel URL normale - vos requêtes seront relayées par le réseau i2p.
  • diff --git a/readme_sv.html b/readme_sv.html index b1f59fa04d..eab177cd14 100644 --- a/readme_sv.html +++ b/readme_sv.html @@ -27,6 +27,7 @@ sökmotor wiki som alla kan förändra, innehåller många länkar
  • fproxy.tino.i2p: Freenet proxy
  • +
  • echelon.i2p: software archive and information for I2P
  • Det finns många fler eepsidor - följ bara länkarna från dom du ser, spara dina favoriter och besök dom ofta! diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 1d4797d6fc..9900aa2884 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -17,7 +17,7 @@ import net.i2p.CoreVersion; public class RouterVersion { public final static String ID = "$Revision: 1.548 $ $Date: 2008-06-07 23:00:00 $"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 1; + public final static long BUILD = 16; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID);