diff --git a/apps/BOB/Demos/echo/echoclient/build.xml b/apps/BOB/Demos/echo/echoclient/build.xml new file mode 100644 index 000000000..4d233cee0 --- /dev/null +++ b/apps/BOB/Demos/echo/echoclient/build.xml @@ -0,0 +1,69 @@ + + + + + + Builds, tests, and runs the project echoclient. + + + diff --git a/apps/BOB/Demos/echo/echoclient/manifest.mf b/apps/BOB/Demos/echo/echoclient/manifest.mf new file mode 100644 index 000000000..328e8e5bc --- /dev/null +++ b/apps/BOB/Demos/echo/echoclient/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/apps/BOB/Demos/echo/echoclient/nbproject/build-impl.xml b/apps/BOB/Demos/echo/echoclient/nbproject/build-impl.xml new file mode 100644 index 000000000..73d61d2fc --- /dev/null +++ b/apps/BOB/Demos/echo/echoclient/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/BOB/Demos/echo/echoclient/nbproject/genfiles.properties b/apps/BOB/Demos/echo/echoclient/nbproject/genfiles.properties new file mode 100644 index 000000000..50793d57a --- /dev/null +++ b/apps/BOB/Demos/echo/echoclient/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=8ce3cee9 +build.xml.script.CRC32=d1de2df3 +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=8ce3cee9 +nbproject/build-impl.xml.script.CRC32=22d1fbbb +nbproject/build-impl.xml.stylesheet.CRC32=487672f9 diff --git a/apps/BOB/Demos/echo/echoclient/nbproject/private/private.properties b/apps/BOB/Demos/echo/echoclient/nbproject/private/private.properties new file mode 100644 index 000000000..d814cb447 --- /dev/null +++ b/apps/BOB/Demos/echo/echoclient/nbproject/private/private.properties @@ -0,0 +1,2 @@ +jaxws.endorsed.dir=/usr/local/netbeans-6.1/java2/modules/ext/jaxws21/api +user.properties.file=/root/.netbeans/6.1/build.properties diff --git a/apps/BOB/Demos/echo/echoclient/nbproject/project.properties b/apps/BOB/Demos/echo/echoclient/nbproject/project.properties new file mode 100644 index 000000000..dfaeb3909 --- /dev/null +++ b/apps/BOB/Demos/echo/echoclient/nbproject/project.properties @@ -0,0 +1,60 @@ +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}/echoclient.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +file.reference.BOB.jar=../../../dist/BOB.jar +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +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.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=net.i2p.BOB.Demos.echo.echoclient.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/BOB/Demos/echo/echoclient/nbproject/project.xml b/apps/BOB/Demos/echo/echoclient/nbproject/project.xml new file mode 100644 index 000000000..9c6fff904 --- /dev/null +++ b/apps/BOB/Demos/echo/echoclient/nbproject/project.xml @@ -0,0 +1,16 @@ + + + org.netbeans.modules.java.j2seproject + + + echoclient + 1.6.5 + + + + + + + + + diff --git a/apps/BOB/build.xml b/apps/BOB/build.xml new file mode 100644 index 000000000..f76222aea --- /dev/null +++ b/apps/BOB/build.xml @@ -0,0 +1,69 @@ + + + + + + Builds, tests, and runs the project BOB. + + + diff --git a/apps/BOB/manifest.mf b/apps/BOB/manifest.mf new file mode 100644 index 000000000..328e8e5bc --- /dev/null +++ b/apps/BOB/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/apps/BOB/nbproject/build-impl.xml b/apps/BOB/nbproject/build-impl.xml new file mode 100644 index 000000000..5dcf75563 --- /dev/null +++ b/apps/BOB/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/BOB/nbproject/genfiles.properties b/apps/BOB/nbproject/genfiles.properties new file mode 100644 index 000000000..55b2caf31 --- /dev/null +++ b/apps/BOB/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=209349b6 +build.xml.script.CRC32=05a1ffd9 +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=209349b6 +nbproject/build-impl.xml.script.CRC32=eeeca375 +nbproject/build-impl.xml.stylesheet.CRC32=487672f9 diff --git a/apps/BOB/nbproject/private/config.properties b/apps/BOB/nbproject/private/config.properties new file mode 100644 index 000000000..e69de29bb diff --git a/apps/BOB/nbproject/private/private.properties b/apps/BOB/nbproject/private/private.properties new file mode 100644 index 000000000..f11a1a7a7 --- /dev/null +++ b/apps/BOB/nbproject/private/private.properties @@ -0,0 +1,6 @@ +do.depend=false +do.jar=true +javac.debug=true +javadoc.preview=true +jaxws.endorsed.dir=/usr/local/netbeans-6.1/java2/modules/ext/jaxws21/api +user.properties.file=/root/.netbeans/6.1/build.properties diff --git a/apps/BOB/nbproject/private/private.xml b/apps/BOB/nbproject/private/private.xml new file mode 100644 index 000000000..c1f155a78 --- /dev/null +++ b/apps/BOB/nbproject/private/private.xml @@ -0,0 +1,4 @@ + + + + diff --git a/apps/BOB/nbproject/project.properties b/apps/BOB/nbproject/project.properties new file mode 100644 index 000000000..89d7ad1da --- /dev/null +++ b/apps/BOB/nbproject/project.properties @@ -0,0 +1,77 @@ +application.title=BOB +application.vendor=root +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}/BOB.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +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=../../core/java/build/i2p.jar +file.reference.i2p.jar-2=../i2p.i2p/core/java/build/i2p.jar +file.reference.i2ptunnel.jar=../i2ptunnel/java/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=../ministreaming/java/build/mstreaming.jar +file.reference.NetBeansProjects-i2p.i2p=../i2p.i2p/ +file.reference.streaming.jar=../../bob/i2p/i2p.i2p/build/streaming.jar +file.reference.streaming.jar-1=../streaming/java/build/streaming.jar +includes=** +jar.compress=false +javac.classpath=\ + ${file.reference.i2p.jar-1}:\ + ${file.reference.i2ptunnel.jar}:\ + ${file.reference.mstreaming.jar-1}:\ + ${file.reference.streaming.jar-1} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +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.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=net.i2p.BOB.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/BOB/nbproject/project.xml b/apps/BOB/nbproject/project.xml new file mode 100644 index 000000000..44eb60a6d --- /dev/null +++ b/apps/BOB/nbproject/project.xml @@ -0,0 +1,16 @@ + + + org.netbeans.modules.java.j2seproject + + + BOB + 1.6.5 + + + + + + + + + diff --git a/apps/BOB/src/net/i2p/BOB/BOB.java b/apps/BOB/src/net/i2p/BOB/BOB.java new file mode 100644 index 000000000..ab29f6444 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/BOB.java @@ -0,0 +1,157 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ +package net.i2p.BOB; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Properties; +import net.i2p.client.I2PClient; +import net.i2p.client.streaming.RetransmissionTimer; +import net.i2p.util.Log; +import net.i2p.util.SimpleTimer; + +/** + * + * BOB, main command socket listener, launches the command parser engine. + * + * @author sponge + */ +public class BOB { + + private final static Log _log = new Log(BOB.class); + public final static String PROP_CONFIG_LOCATION = "BOB.config"; + public final static String PROP_BOB_PORT = "BOB.port"; + public final static String PROP_BOB_HOST = "BOB.host"; + private static int maxConnections = 0; + private static nickname database; + + /** + * Log a warning + * + * @param arg + */ + public static void warn(String arg) { + System.out.println(arg); + _log.warn(arg); + } + + /** + * Log an error + * + * @param arg + */ + public static void error(String arg) { + System.out.println(arg); + _log.error(arg); + } + + /** + * Listen for incoming connections and handle them + * + * @param args + */ + public static void main(String[] args) { + database = new nickname(); + int i = 0; + 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(); + Properties props = new Properties(); + String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "bob.config"); + + // This is here just to ensure there is no interference with our threadgroups. + SimpleTimer Y = RetransmissionTimer.getInstance(); + i = Y.hashCode(); + + try { + props.load(new FileInputStream(configLocation)); + } catch(FileNotFoundException fnfe) { + warn("Unable to load up the BOB config file " + configLocation + ", Using defaults."); + warn(fnfe.toString()); + save = true; + } catch(IOException ioe) { + warn("IOException on BOB config file " + configLocation + ", using defaults."); + warn(ioe.toString()); + } + // Global router and client API configurations that are missing are set to defaults here. + if(!props.containsKey(I2PClient.PROP_TCP_HOST)) { + props.setProperty(I2PClient.PROP_TCP_HOST, "localhost"); + } + if(!props.containsKey(I2PClient.PROP_TCP_PORT)) { + props.setProperty(I2PClient.PROP_TCP_PORT, "7654"); + } + if(!props.containsKey(I2PClient.PROP_RELIABILITY)) { + props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT); + } + if(!props.containsKey(PROP_BOB_PORT)) { + props.setProperty(PROP_BOB_PORT, "2827"); // 0xB0B + } + if(!props.containsKey("inbound.length")) { + props.setProperty("inbound.length", "1"); + } + if(!props.containsKey("outbound.length")) { + props.setProperty("outbound.length", "1"); + } + if(!props.containsKey("inbound.lengthVariance")) { + props.setProperty("inbound.lengthVariance", "0"); + } + if(!props.containsKey("outbound.lengthVariance")) { + props.setProperty("outbound.lengthVariance", "0"); + } + if(!props.containsKey(PROP_BOB_HOST)) { + props.setProperty(PROP_BOB_HOST, "localhost"); + } + if(save) { + try { + warn("Writing new defaults file " + configLocation); + props.store(new FileOutputStream(configLocation), configLocation); + } catch(IOException ioe) { + warn("IOException on BOB config file " + configLocation + ", " + ioe); + } + } + + try { + ServerSocket listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST))); + Socket server; + + while((i++ < maxConnections) || (maxConnections == 0)) { + //doCMDS connection; + + server = listener.accept(); + doCMDS conn_c = new doCMDS(server, props, database, _log); + Thread t = new Thread(conn_c); + t.start(); + } + } catch(IOException ioe) { + warn("IOException on socket listen: " + ioe); + ioe.printStackTrace(); + } + } +} diff --git a/apps/BOB/src/net/i2p/BOB/COPYING b/apps/BOB/src/net/i2p/BOB/COPYING new file mode 100644 index 000000000..116db5958 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/COPYING @@ -0,0 +1,21 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) sponge + Planet Earth + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + +See... + + http://sam.zoy.org/wtfpl/ + and + http://en.wikipedia.org/wiki/WTFPL + +...for any additional details and license questions. diff --git a/apps/BOB/src/net/i2p/BOB/I2Plistener.java b/apps/BOB/src/net/i2p/BOB/I2Plistener.java new file mode 100644 index 000000000..f646466f6 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/I2Plistener.java @@ -0,0 +1,128 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ +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; +import net.i2p.util.Log; + +/** + * Listen on I2P and connect to TCP + * + * @author sponge + */ +public class I2Plistener implements Runnable { + + private nickname info; + private Log _log; + private int tgwatch; + public I2PSocketManager socketManager; + public I2PServerSocket serverSocket; + + /** + * Constructor + * @param S + * @param info + * @param _log + */ + I2Plistener(I2PSocketManager S, nickname info, Log _log) { + this.info = info; + this._log = _log; + this.socketManager = S; + serverSocket = socketManager.getServerSocket(); + tgwatch = 1; + } + + /** + * Simply listen on I2P port, and thread connections + * + * @throws RuntimeException + */ + public void run() throws RuntimeException { + boolean g = false; + I2PSocket sessSocket = null; + + // needed to hack in this method :-/ + serverSocket.setSoTimeout(1000); + if(info.exists("INPORT")) { + tgwatch = 2; + } + while(info.get("RUNNING").equals(true)) { + 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); + Thread t = new Thread(conn_c, "BOBI2PtoTCP"); + t.start(); + } + + } catch(I2PException e) { + System.out.println("Exception "+e); + } + } + + try { + serverSocket.close(); + } catch(I2PException e) { + // nop + } + + while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish +// System.out.println("STOP Thread count " + Thread.activeCount()); + try { + Thread.sleep(1000); //sleep for 1000 ms (One second) + } catch(Exception e) { + // nop + } + } +// System.out.println("STOP Thread count " + Thread.activeCount()); + // 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("destroySession Thread count " + Thread.activeCount()); + } + + + } +} diff --git a/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java b/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java new file mode 100644 index 000000000..58253542d --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java @@ -0,0 +1,106 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ +package net.i2p.BOB; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.UnknownHostException; +import net.i2p.client.streaming.I2PSocket; + +/** + * Process I2P->TCP + * + * @author sponge + */ +public class I2PtoTCP implements Runnable { + + private I2PSocket I2P; + private nickname info; + private Socket sock; + + /** + * Constructor + * + * @param I2Psock + * @param db + */ + I2PtoTCP(I2PSocket I2Psock, nickname db) { + this.I2P = I2Psock; + this.info = db; + } + + /** + * I2P stream to TCP stream thread starter + * + */ + public void run() { + + try { + sock = new Socket(info.get("OUTHOST").toString(), Integer.parseInt(info.get("OUTPORT").toString())); + // make readers/writers + InputStream in = sock.getInputStream(); + OutputStream out = sock.getOutputStream(); + InputStream Iin = I2P.getInputStream(); + OutputStream Iout = I2P.getOutputStream(); + I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default + + if(info.get("QUIET").equals(false)) { + // tell who is connecting + out.write(I2P.getPeerDestination().toBase64().getBytes()); + out.write(10); // nl + out.flush(); // not really needed, but... + } + // setup to cross the streams + TCPio conn_c = new TCPio(in, Iout, info); // app -> I2P + TCPio conn_a = new TCPio(Iin, out, info); // 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 { + Thread.sleep(10); //sleep for 10 ms + } catch(InterruptedException e) { + // nop + } + } + + } catch(UnknownHostException ex) { + // OOPS! + } catch(IOException ex) { + // OOPS! + } + try { + I2P.close(); + } catch(IOException ex) { + } + try { + sock.close(); + } catch(IOException ex) { + } + } +} diff --git a/apps/BOB/src/net/i2p/BOB/MUXlisten.java b/apps/BOB/src/net/i2p/BOB/MUXlisten.java new file mode 100644 index 000000000..680e3cd43 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/MUXlisten.java @@ -0,0 +1,118 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ +package net.i2p.BOB; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Properties; +import net.i2p.I2PException; +import net.i2p.client.streaming.I2PSocketManager; +import net.i2p.client.streaming.I2PSocketManagerFactory; +import net.i2p.util.Log; + +/** + * + * Multiplex listeners for TCP and I2P + * + * @author sponge + */ +public class MUXlisten implements Runnable { + + private nickname info; + private Log _log; + private I2PSocketManager socketManager; + private ByteArrayInputStream prikey; + private ThreadGroup tg; + private String N; + + /** + * Constructor + * + * @param info + * @param _log + * @throws net.i2p.I2PException + * @throws java.io.IOException + */ + MUXlisten(nickname info, Log _log) throws I2PException, IOException { + this.info = info; + this._log = _log; + this.info.add("STARTING", true); + + N = this.info.get("NICKNAME").toString(); + prikey = new ByteArrayInputStream((byte[])info.get("KEYS")); + socketManager = I2PSocketManagerFactory.createManager(prikey, (Properties)info.get("PROPERTIES")); + } + + /** + * MUX sockets, fire off a thread to connect, get destination info, and do I/O + * + */ + public void run() { + + tg = new ThreadGroup(N); + info.add("RUNNING", true); + info.add("STARTING", false); + + // toss the connections to a new threads. + // will wrap with TCP and UDP when UDP works + if(info.exists("OUTPORT")) { + // I2P -> TCP + I2Plistener conn = new I2Plistener(socketManager, info, _log); + Thread t = new Thread(tg, conn, "BOBI2Plistener " + N); + t.start(); + } + if(info.exists("INPORT")) { + // TCP -> I2P + TCPlistener conn = new TCPlistener(socketManager, info, _log); + Thread q = new Thread(tg, conn,"BOBTCPlistener" + N); + q.start(); + } + + while(info.get("STOPPING").equals(false)) { + try { + Thread.sleep(1000); //sleep for 1000 ms (One second) + } catch(InterruptedException e) { + // nop + } + } + + info.add("RUNNING", false); + // wait for child threads and thread groups to die + while (tg.activeCount() + tg.activeGroupCount() != 0) { + try { + Thread.sleep(1000); //sleep for 1000 ms (One second) + } catch(InterruptedException ex) { + // nop + } + } + + socketManager.destroySocketManager(); + tg.destroy(); + // Zap reference to the ThreadGroup so the JVM can GC it. + tg = null; + info.add("STOPPING", false); + info.add("STARTING", false); + + } +} diff --git a/apps/BOB/src/net/i2p/BOB/Main.java b/apps/BOB/src/net/i2p/BOB/Main.java new file mode 100644 index 000000000..3dfc9af21 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/Main.java @@ -0,0 +1,48 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ + +package net.i2p.BOB; + +import net.i2p.client.streaming.RetransmissionTimer; +import net.i2p.util.SimpleTimer; + +/** + * Start from command line + * + * @author sponge + * + */ + +public class Main { + + /** + * @param args the command line arguments, these are not used yet + */ + public static void main(String[] args) { + // THINK THINK THINK THINK THINK THINK + SimpleTimer Y = RetransmissionTimer.getInstance(); + BOB.main(args); + Y.removeSimpleTimer(); + } +} diff --git a/apps/BOB/src/net/i2p/BOB/TCPio.java b/apps/BOB/src/net/i2p/BOB/TCPio.java new file mode 100644 index 000000000..460f8aa58 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/TCPio.java @@ -0,0 +1,93 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ +package net.i2p.BOB; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Shove data from one stream to the other. + * + * @author sponge + */ +public class TCPio implements Runnable { + + private InputStream Ain; + private OutputStream Aout; + private nickname info; + + /** + * Constructor + * + * @param Ain + * @param Aout + * @param db + */ + TCPio(InputStream Ain, OutputStream Aout, nickname db) { + this.Ain = Ain; + this.Aout = Aout; + this.info = db; + } + + /** + * kill off the streams, to hopefully cause an IOException in the thread in order to kill it. + */ + /** + * Copy from source to destination... + * and yes, we are totally OK to block here on writes, + * The OS has buffers, and I intend to use them. + * + */ + public void run() { + int b; + byte a[] = new byte[1]; + try { + while(info.get("RUNNING").equals(true)) { + b = Ain.read(a, 0, 1); + // System.out.println(info.get("NICKNAME").toString() + " " + b); + if(b > 0) { + Aout.write(a,0,1); + // Aout.flush(); too slow! + } else if(b == 0) { + try { + // Thread.yield(); + Thread.sleep(10); + } catch(InterruptedException ex) { + } + } else { + /* according to the specs: + * + * The total number of bytes read into the buffer, + * or -1 is there is no more data because the end of + * the stream has been reached. + * + */ + return; + } + } + } catch(IOException e) { + } + } +} diff --git a/apps/BOB/src/net/i2p/BOB/TCPlistener.java b/apps/BOB/src/net/i2p/BOB/TCPlistener.java new file mode 100644 index 000000000..5c9f23def --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/TCPlistener.java @@ -0,0 +1,123 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ +package net.i2p.BOB; + +import java.io.IOException; +import java.net.InetAddress; +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.streaming.I2PServerSocket; +import net.i2p.client.streaming.I2PSocketManager; +import net.i2p.util.Log; + +/** + * Listen on TCP port and connect to I2P + * + * @author sponge + */ +public class TCPlistener implements Runnable { + + private nickname info; + private Log _log; + private int tgwatch; + public I2PSocketManager socketManager; + public I2PServerSocket serverSocket; + private int backlog = 50; // should this be more? less? + + /** + * Constructor + * @param S + * @param info + * @param _log + */ + TCPlistener(I2PSocketManager S, nickname info, Log _log) { + this.info = info; + this._log = _log; + this.socketManager = S; + tgwatch = 1; + } + + /** + * Simply listen on TCP port, and thread connections + * @throws java.lang.RuntimeException + */ + public void run() throws RuntimeException { + boolean g = false; + if(info.exists("OUTPORT")) { + tgwatch = 2; + } + try { +// System.out.println("Starting thread count " + Thread.activeCount()); + ServerSocket listener = new ServerSocket(Integer.parseInt(info.get("INPORT").toString()), backlog, InetAddress.getByName(info.get("INHOST").toString())); + Socket server = new Socket(); + listener.setSoTimeout(1000); + while(info.get("RUNNING").equals(true)) { +// System.out.println("Thread count " + Thread.activeCount()); + 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); + Thread t = new Thread(conn_c, "BOBTCPtoI2P"); + t.start(); + g = false; + } + } + listener.close(); + } catch(IOException ioe) { + // throw new RuntimeException(ioe); + } + +//System.out.println("STOP!"); + + while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish +// System.out.println("STOP Thread count " + Thread.activeCount()); + try { + Thread.sleep(1000); //sleep for 1000 ms (One second) + } catch(Exception e) { + // nop + } + } +// System.out.println("STOP Thread count " + Thread.activeCount()); + // 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("destroySession Thread count " + Thread.activeCount()); + } + } +} + + diff --git a/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java b/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java new file mode 100644 index 000000000..c1f1ba8e6 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/TCPtoI2P.java @@ -0,0 +1,186 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ +package net.i2p.BOB; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.net.ConnectException; +import java.net.NoRouteToHostException; +import java.net.Socket; +import net.i2p.I2PException; +import net.i2p.client.streaming.I2PSocket; +import net.i2p.client.streaming.I2PSocketManager; +import net.i2p.data.DataFormatException; +import net.i2p.data.Destination; +import net.i2p.i2ptunnel.I2PTunnel; + +/** + * + * Process TCP->I2P + * + * @author sponge + */ +public class TCPtoI2P implements Runnable { + + private I2PSocket I2P; + private nickname info; + private Socket sock; + private I2PSocketManager socketManager; + + /** + * This is a more forgiving readline, + * it works on unbuffered streams + * + * @param in + * @return line of text as a String + * @throws java.io.IOException + */ + public static String Lread(InputStream in) throws IOException { + String S; + int b; + char c; + + S = new String(); + + while(true) { + b = in.read(); + if(b == 13) { + //skip CR + continue; + } + if(b < 20 || b > 126) { + // exit on anything not legal + break; + } + c = (char)(b & 0x7f); // We only really give a fuck about ASCII + S = new String(S + c); + } + return S; + } + + /** + * Constructor + * @param i2p + * @param socket + * @param db + */ + TCPtoI2P(I2PSocketManager i2p, Socket socket, nickname db) { + this.sock = socket; + this.info = db; + this.socketManager = i2p; + } + + /** + * Print an error message to out + * + * @param e + * @param out + * @throws java.io.IOException + */ + private void Emsg(String e, OutputStream out) throws IOException { + System.out.println("ERROR TCPtoI2P: " + e); + out.write("ERROR".concat(e).getBytes()); + out.write(13); // cr + out.flush(); + sock.close(); + + } + + /** + * TCP stream to I2P stream thread starter + */ + public void run() { + String line, input; + + try { + + InputStream in = sock.getInputStream(); + OutputStream out = sock.getOutputStream(); + try { + line = Lread(in); + input = line.toLowerCase(); + Destination dest = null; + + if(input.endsWith(".i2p")) { + dest = I2PTunnel.destFromName(input); + line = dest.toBase64(); + } + dest = new Destination(); + dest.fromBase64(line); + + try { + // get a client socket + 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(); + // setup to cross the streams + TCPio conn_c = new TCPio(in, Iout, info); // app -> I2P + TCPio conn_a = new TCPio(Iin, out, info); // 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 { + Thread.sleep(10); //sleep for 10 ms + } catch(InterruptedException e) { + // nop + } + } + } catch(I2PException e) { + Emsg("ERROR " + e.toString(), out); + } catch(ConnectException e) { + Emsg("ERROR " + e.toString(), out); + } catch(NoRouteToHostException e) { + Emsg("ERROR " + e.toString(), out); + } catch(InterruptedIOException e) { + Emsg("ERROR " + e.toString(), out); + } + + } catch(DataFormatException e) { + Emsg("ERROR " + e.toString(), out); + } catch(NullPointerException e) { + Emsg("ERROR " + e.toString(), out); + } + } catch(IOException ioe) { + } + try { + I2P.close(); + } catch(IOException ex) { + } catch(NullPointerException e) { + } + + try { + sock.close(); + } catch(IOException ex) { + } catch(NullPointerException e) { + } + } +} + diff --git a/apps/BOB/src/net/i2p/BOB/UDPIOthread.java b/apps/BOB/src/net/i2p/BOB/UDPIOthread.java new file mode 100644 index 000000000..deb22b223 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/UDPIOthread.java @@ -0,0 +1,144 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ + +package net.i2p.BOB; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import net.i2p.client.I2PSession; +import net.i2p.client.I2PSessionException; +import net.i2p.client.I2PSessionListener; +import net.i2p.data.Destination; +import net.i2p.util.Log; + + +/** + * UDP IO on I2P + * + * FIX ME: Untested, and incomplete! + * I have no personal need to UDP yet, + * however alot of p2p apps pretty much demand it. + * The skeletal frame is here, just needs to be finished. + * + * @author sponge + */ +public class UDPIOthread implements I2PSessionListener, Runnable { + + private nickname info; + private Log _log; + private Socket socket; + private DataInputStream in; + private DataOutputStream out; + private I2PSession _session; + private Destination _peerDestination; + private boolean up; + +/** + * Constructor + * @param info + * @param _log + * @param socket + * @param _session + */ UDPIOthread(nickname info, Log _log, Socket socket, I2PSession _session) { + this.info = info; + this._log = _log; + this.socket = socket; + this._session = _session; + + } +/** + * + */ + public void run() { + byte data[] = new byte[1024]; + up = true; + try { + in = new DataInputStream(socket.getInputStream()); + out = new DataOutputStream(socket.getOutputStream()); + while(up) { + int c = in.read(data); + // Note: could do a loopback test here with a wrapper. + boolean ok = _session.sendMessage(_peerDestination, data, 0, c); + + if(!ok) { + up = false; // Is this the right thing to do?? + } + } + } catch(IOException ioe) { + _log.error("Error running", ioe); + } catch(I2PSessionException ise) { + _log.error("Error communicating", ise); + // } catch(DataFormatException dfe) { + // _log.error("Peer destination file is not valid", dfe); + } finally { + if(_session != null) { + try { + _session.destroySession(); + } catch(I2PSessionException ise) { + // ignored + } + } + } + } +/** + * + * @param session + * @param msgId + * @param size + */ + public void messageAvailable(I2PSession session, int msgId, long size) { +// _log.debug("Message available: id = " + msgId + " size = " + size); + try { + byte msg[] = session.receiveMessage(msgId); + out.write(msg); + out.flush(); + } catch(I2PSessionException ise) { + up = false; + } catch(IOException ioe) { + up = false; + } + } + + // Great, can these be used to kill ourselves. + + /** required by {@link I2PSessionListener I2PSessionListener} to notify of disconnect */ + public void disconnected(I2PSession session) { + _log.debug("Disconnected"); + // up = false; + } + + /** required by {@link I2PSessionListener I2PSessionListener} to notify of error */ + public void errorOccurred(I2PSession session, String message, Throwable error) { + _log.debug("Error occurred: " + message, error); + // up = false; + } + + /** required by {@link I2PSessionListener I2PSessionListener} to notify of abuse */ + public void reportAbuse(I2PSession session, int severity) { + _log.debug("Abuse reported of severity " + severity); + // up = false; + } +} diff --git a/apps/BOB/src/net/i2p/BOB/doCMDS.java b/apps/BOB/src/net/i2p/BOB/doCMDS.java new file mode 100644 index 000000000..9e4cdce88 --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/doCMDS.java @@ -0,0 +1,568 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ +package net.i2p.BOB; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.Socket; +import java.util.Properties; +import java.util.StringTokenizer; +import net.i2p.I2PException; +import net.i2p.client.I2PClientFactory; +import net.i2p.data.Destination; +import net.i2p.util.Log; + +/** + * Simplistic command parser for BOB + * + * @author sponge + * + */ +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 = "01", BEXT = "-6"; + public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT; + private Socket server; + private Properties props; + private nickname database; + private String line; + private Destination d; + private ByteArrayOutputStream prikey; + private boolean dk, ns, ip, op; + private nickname nickinfo; + private Log _log; + /* database strings */ + private static final String P_INHOST = "INHOST"; + private static final String P_INPORT = "INPORT"; + private static final String P_KEYS = "KEYS"; + private static final String P_NICKNAME = "NICKNAME"; + private static final String P_OUTHOST = "OUTHOST"; + private static final String P_OUTPORT = "OUTPORT"; + private static final String P_PROPERTIES = "PROPERTIES"; + private static final String P_QUIET = "QUIET"; + private static final String P_RUNNING = "RUNNING"; + private static final String P_STARTING = "STARTING"; + private static final String P_STOPPING = "STOPPING"; + /* command strings */ + private static final String C_help = "help"; + private static final String C_clear = "clear"; + private static final String C_getkeys = "getkeys"; + private static final String C_getnick = "getnick"; + private static final String C_inhost = "inhost"; + private static final String C_inport = "inport"; + private static final String C_list = "list"; + private static final String C_newkeys = "newkeys"; + private static final String C_outhost = "outhost"; + private static final String C_outport = "outport"; + private static final String C_quiet = "quiet"; + private static final String C_quit = "quit"; + private static final String C_setkeys = "setkeys"; + private static final String C_setnick = "setnick"; + private static final String C_show = "show"; + private static final String C_start = "start"; + private static final String C_status = "status"; + private static final String C_stop = "stop"; + + /* all the coomands available, plus description */ + private static final String C_ALL[][] = { + {C_help, C_help + " * Get help on a command."}, + {C_clear, C_clear + " * Clear the current nickname out of the list."}, + {C_getkeys, C_getkeys + " * Return the keypair for the current nickname."}, + {C_getnick, C_getnick + " tunnelname * Set the nickname from the database."}, + {C_inhost, C_inhost + " hostname | IP * Set the inbound hostname or IP."}, + {C_inport, C_inport + " port_number * Set the inbound port number nickname listens on."}, + {C_list, C_list + " * List all tunnels."}, + {C_newkeys, C_newkeys + " * Generate a new keypair for the current nickname."}, + {C_outhost, C_outhost + " hostname | IP * Set the outbound hostname or IP."}, + {C_outport, C_outport + " port_number * Set the outbound port that nickname contacts."}, + {C_quiet, C_quiet + " *"}, + {C_quit, C_quit + " * Quits this session with BOB."}, + {C_setkeys, C_setkeys + " BASE64_keypair * Sets the keypair for the current nickname."}, + {C_setnick, C_setnick + " nickname * Create a new nickname."}, + {C_show, C_show + " * Display the status of the current nickname."}, + {C_start, C_start + " * Start the current nickname tunnel."}, + {C_status, C_status + " nickname * Display status of a nicknamed tunnel."}, + {C_stop, C_stop + " * Stops the current nicknamed tunnel."}, + {"", "COMMANDS: " + // this is ugly, but... + C_help + " " + + C_clear + " " + + C_getkeys + " " + + C_getnick + " " + + C_inhost + " " + + C_inport + " " + + C_list + " " + + C_newkeys + " " + + C_outhost + " " + + C_outport + " " + + C_quiet + " " + + C_quit + " " + + C_setkeys + " " + + C_setnick + " " + + C_show + " " + + C_start + " " + + C_status + " " + + C_stop + }, + {" ", " "} // end of list + }; + + /** + * + * @param server + * @param props + * @param database + * @param _log + */ + doCMDS(Socket server, Properties props, nickname database, Log _log) { + this.server = server; + this.props = props; + this.database = database; + this._log = _log; + } + + /** + * Try to print info from the database + * + * @param out + * @param info + * @param key + */ + public void trypnt(PrintStream out, nickname info, Object key) { + out.print(" " + key + ": "); + if(info.exists(key)) { + out.print(info.get(key)); + } else { + out.print("not_set"); + } + } + + /** + * Print true or false if an object exists + * + * @param out + * @param info + * @param key + */ + public void tfpnt(PrintStream out, nickname info, Object key) { + out.print(" " + key + ": "); + out.print(info.exists(key)); + } + + /** + * Print an error message + * + * @param out + */ + public void nns(PrintStream out) { + out.println("ERROR no nickname has been set"); + } + + /** + * Dump various information from the database + * + * @param out + * @param info + */ + public void nickprint(PrintStream out, nickname info) { + trypnt(out, info, P_NICKNAME); + trypnt(out, info, P_STARTING); + trypnt(out, info, P_RUNNING); + trypnt(out, info, P_STOPPING); + tfpnt(out, info, P_KEYS); + trypnt(out, info, P_QUIET); + trypnt(out, info, P_INPORT); + trypnt(out, info, P_INHOST); + trypnt(out, info, P_OUTPORT); + trypnt(out, info, P_OUTHOST); + out.println(); + + } + + /** + * Print information on a specific record, indicated by nickname + * @param out + * @param database + * @param Arg + */ + public void ttlpnt(PrintStream out, nickname database, Object Arg) { + if(database.exists(Arg)) { + out.print("DATA"); + nickprint(out, (nickname)database.get(Arg)); + } + } + + /** + * Is this nickname's tunnel active? + * + * @param Arg + * @return true if the tunnel is active + */ + public boolean tunnelactive(nickname Arg) { + return (Arg.get(P_STARTING).equals(true) || + Arg.get(P_STOPPING).equals(true) || + Arg.get(P_RUNNING).equals(true)); + + } + + /** + * Does the base64 information look OK + * + * @param data + * @return + */ + private boolean is64ok(String data) { + String dest = new String(data); + if(dest.replaceAll("[a-zA-Z0-9~-]", "").length() == 0) { + return true; + } + return false; + } + + /** + * The actual parser. + * It probabbly needs a rewrite into functions, but I kind-of like inline code. + * + */ + public void run() { + dk = ns = ip = op = false; + + try { + // Get input from the client + BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream())); + PrintStream out = new PrintStream(server.getOutputStream()); + prikey = new ByteArrayOutputStream(); + out.println("BOB " + BOBversion); + out.println("OK"); + while((line = in.readLine()) != null) { + System.gc(); // yes, this does make a huge difference... + StringTokenizer token = new StringTokenizer(line, " "); // use a space as a delimiter + String Command = ""; + String Arg = ""; + nickname info; + + if(token.countTokens() != 0) { + Command = token.nextToken(); + Command = Command.toLowerCase(); + if(token.countTokens() != 0) { + Arg = token.nextToken(); + } else { + Arg = ""; + } + // The rest of the tokens are considered junk, + // and discarded without any warnings. + + if(Command.equals(C_help)) { + for(int i = 0; !C_ALL[i][0].equals(" "); i++) { + if(C_ALL[i][0].equalsIgnoreCase(Arg)) { + out.println("OK " + C_ALL[i][1]); + } + } + + } else if(Command.equals(C_list)) { + // Produce a formatted list of all nicknames + for(int i = 0; i < database.getcount(); i++) { + try { + info = (nickname)database.getnext(i); + } catch(RuntimeException b) { + break; // something bad happened. + } + + out.print("DATA"); + nickprint(out, info); + } + out.println("OK Listing done"); + } else if(Command.equals(C_quit)) { + // End the command session + break; + } else if(Command.equals(C_newkeys)) { + if(ns) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + try { + // Make a new PublicKey and PrivateKey + prikey = new ByteArrayOutputStream(); + d = I2PClientFactory.createClient().createDestination(prikey); + dk = true; + nickinfo.add(P_KEYS, prikey.toByteArray()); + // System.out.println(prikey.toByteArray().length); + out.println("OK " + d.toBase64()); + } catch(IOException ioe) { + BOB.error("Error generating keys" + ioe); + out.println("ERROR generating keys"); + } catch(I2PException ipe) { + BOB.error("Error generating keys" + ipe); + out.println("ERROR generating keys"); + } + } + } else { + nns(out); + } + } else if(Command.equals(C_getkeys)) { + // Return public key + if(dk) { + prikey = new ByteArrayOutputStream(); + prikey.write(((byte[])nickinfo.get(P_KEYS))); + out.println("OK " + net.i2p.data.Base64.encode(prikey.toByteArray())); + } else { + out.println("ERROR no public key has been set"); + } + } else if(Command.equals(C_quiet)) { + if(ns) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + nickinfo.add(P_QUIET, (Boolean.parseBoolean(Arg) == true)); + out.println("OK Quiet set"); + } + } else { + nns(out); + } + } else if(Command.equals(C_setkeys)) { + // Set the nickname to a privatekey in BASE64 format + if(ns) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + prikey = new ByteArrayOutputStream(); + prikey.write(net.i2p.data.Base64.decode(Arg)); + if((Arg.length() == 884) && is64ok(Arg)) { + nickinfo.add(P_KEYS, prikey.toByteArray()); + out.println("OK Keys set"); + dk = true; + } else { + out.println("ERROR not in BASE64 format"); + } + } + } else { + nns(out); + } + } else if(Command.equals(C_setnick)) { + ns = dk = ip = op = false; + try { + nickinfo = (nickname)database.get(Arg); + if(!tunnelactive(nickinfo)) { + nickinfo = null; + ns = true; + } + } catch(RuntimeException b) { + nickinfo = null; + ns = true; + } + + // Clears and Sets the initial nickname structure to work with + if(ns) { + nickinfo = new nickname(); + database.add(Arg, nickinfo); + nickinfo.add(P_NICKNAME, Arg); + nickinfo.add(P_STARTING, false); + nickinfo.add(P_RUNNING, false); + nickinfo.add(P_STOPPING, false); + nickinfo.add(P_QUIET, false); + nickinfo.add(P_INHOST, "localhost"); + nickinfo.add(P_OUTHOST, "localhost"); + Properties Q = props; + Q.setProperty("inbound.nickname", (String)nickinfo.get(P_NICKNAME)); + Q.setProperty("outbound.nickname", (String)nickinfo.get(P_NICKNAME)); + nickinfo.add(P_PROPERTIES, Q); + out.println("OK Nickname set to " + Arg); + } else { + out.println("ERROR tunnel is active"); + } + } else if(Command.equals(C_getnick)) { + // Get the nickname to work with... + try { + nickinfo = (nickname)database.get(Arg); + ns = true; + } catch(RuntimeException b) { + nns(out); + } + if(ns) { + dk = nickinfo.exists(P_KEYS); + ip = nickinfo.exists(P_INPORT); + op = nickinfo.exists(P_OUTPORT); + // Finally say OK. + out.println("OK Nickname set to " + Arg); + } + } else if(Command.equals(C_inport)) { + // Set the nickname inbound TO the router port + // app --> BOB + if(ns) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + int prt; + nickinfo.kill(P_INPORT); + try { + prt = Integer.parseInt(Arg); + if(prt > 1 && prt < 65536) { + nickinfo.add(P_INPORT, prt); + } + } catch(NumberFormatException nfe) { + out.println("ERROR not a number"); + } + ip = nickinfo.exists(P_INPORT); + if(ip) { + out.println("OK inbound port set"); + } else { + out.println("ERROR port out of range"); + } + } + } else { + nns(out); + } + } else if(Command.equals(C_outport)) { + // Set the nickname outbound FROM the router port + // BOB --> app + if(ns) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + int prt; + nickinfo.kill(P_OUTPORT); + try { + prt = Integer.parseInt(Arg); + if(prt > 1 && prt < 65536) { + nickinfo.add(P_OUTPORT, prt); + } + } catch(NumberFormatException nfe) { + out.println("ERROR not a number"); + } + ip = nickinfo.exists(P_OUTPORT); + if(ip) { + out.println("OK outbound port set"); + } else { + out.println("ERROR port out of range"); + } + } + } else { + nns(out); + } + } else if(Command.equals(C_inhost)) { + if(ns) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + nickinfo.add(P_INHOST, Arg); + out.println("OK inhost set"); + } + } else { + nns(out); + } + } else if(Command.equals(C_outhost)) { + if(ns) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + nickinfo.add(P_OUTHOST, Arg); + out.println("OK outhost set"); + } + } else { + nns(out); + } + } else if(Command.equals(C_show)) { + // Get the current nickname properties + if(ns) { + out.print("OK"); + nickprint(out, nickinfo); + } else { + nns(out); + } + } else if(Command.equals(C_start)) { + // Start the tunnel, if we have all the information + if(ns && dk && (ip || op)) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + MUXlisten tunnel; + try { + tunnel = new MUXlisten(nickinfo, _log); + Thread t = new Thread(tunnel); + t.start(); + nickinfo.add(P_STARTING, true); + out.println("OK tunnel starting"); + } catch(I2PException e) { + out.println("ERROR starting tunnel: " + e); + } catch(IOException e) { + out.println("ERROR starting tunnel: " + e); + } + } + } else { + out.println("ERROR tunnel settings incomplete"); + } + } else if(Command.equals(C_stop)) { + // Stop the tunnel, if it is running + if(ns) { + if(nickinfo.get(P_RUNNING).equals(true) && nickinfo.get(P_STOPPING).equals(false)) { + nickinfo.add(P_STOPPING, true); + out.println("OK tunnel stopping"); + } else { + out.println("ERROR tunnel is inactive"); + } + } else { + nns(out); + } + } else if(Command.equals(C_clear)) { + // Clear use of the nickname if stopped + if(ns) { + if(tunnelactive(nickinfo)) { + out.println("ERROR tunnel is active"); + } else { + database.kill(nickinfo.get(P_NICKNAME)); + dk = ns = ip = op = false; + out.println("OK cleared"); + } + } else { + nns(out); + } + } else if(Command.equals(C_status)) { + if(database.exists(Arg)) { + // Show status of a nickname + out.print("OK "); + ttlpnt(out, database, Arg); + } else { + nns(out); + } + } else { + out.println("ERROR UNKNOWN COMMAND! Try help"); + } + } + } + + // Say goodbye. + + out.println("OK Bye!"); + + server.close(); + } catch(IOException ioe) { + BOB.warn("IOException on socket listen: " + ioe); + ioe.printStackTrace(); + } + } +} diff --git a/apps/BOB/src/net/i2p/BOB/nickname.java b/apps/BOB/src/net/i2p/BOB/nickname.java new file mode 100644 index 000000000..b7b76b9ce --- /dev/null +++ b/apps/BOB/src/net/i2p/BOB/nickname.java @@ -0,0 +1,165 @@ +/** + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * Version 2, December 2004 + * + * Copyright (C) sponge + * Planet Earth + * Everyone is permitted to copy and distribute verbatim or modified + * copies of this license document, and changing it is allowed as long + * as the name is changed. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + * + * 0. You just DO WHAT THE FUCK YOU WANT TO. + * + * See... + * + * http://sam.zoy.org/wtfpl/ + * and + * http://en.wikipedia.org/wiki/WTFPL + * + * ...for any additional details and liscense questions. + */ + +package net.i2p.BOB; + +/** + * Internal database to relate nicknames to options to values + * + * @author sponge + */ +public class nickname { + + private Object[][] data; + private int index = 0; + + /** + * make initial NULL object + * + */ + public nickname() { + data = new Object[1][2]; + } + + /** + * Find objects in the array, returns it's index or throws exception + * @param key + * @return an objects index + */ + public synchronized int idx(Object key) { + for(int i = 0; i < index; i++) { + if(key.equals(data[i][0])) { + return i; + } + } + throw new ArrayIndexOutOfBoundsException("Can't locate key for index"); + } + + /** + * Delete an object from array if it exists + * + * @param key + */ + public synchronized void kill(Object key) { + + int i, j, k, l; + Object[][] olddata; + int didsomething = 0; + + try { + k = idx(key); + } catch(ArrayIndexOutOfBoundsException b) { + return; + } + olddata = new Object[index + 2][2]; + // copy to olddata, skipping 'k' + for(i = 0 , l = 0; l < index; i++, l++) { + if(i == k) { + l++; + didsomething++; + } + for(j = 0; j < 2; j++) { + olddata[i][j] = data[l][j]; + } + } + index -= didsomething; + data = olddata; + + } + + /** + * Add object to the array, deletes the old one if it exists + * + * @param key + * @param val + */ + public synchronized void add(Object key, Object val) { + Object[][] olddata; + int i, j; + i = 0; + kill(key); + + olddata = new Object[index + 2][2]; + // copy to olddata + for(i = 0; i < index; i++) { + for(j = 0; j < 2; j++) { + olddata[i][j] = data[i][j]; + } + } + data = olddata; + data[index++] = new Object[] {key, val}; + } + + /** + * Get the object, and return it, throws RuntimeException + * + * @param key + * @return Object + * @throws java.lang.RuntimeException + */ + public synchronized Object get(Object key) throws RuntimeException { + for(int i = 0; i < index; i++) { + if(key.equals(data[i][0])) { + return data[i][1]; + } + } + throw new RuntimeException("Key not found"); + } + + /** + * returns true if an object exists, else returns false + * + * @param key + * @return true if an object exists, else returns false + */ + public synchronized boolean exists(Object key) { + for(int i = 0; i < index; i++) { + if(key.equals(data[i][0])) { + return true; + } + } + return false; + + } + + /** + * + * @param i index + * @return an indexed Object + * @throws java.lang.RuntimeException + */ + public synchronized Object getnext(int i) throws RuntimeException { + if(i < index && i > -1) { + return data[i][1]; + } + throw new RuntimeException("No more data"); + } + + /** + * @return the count of how many objects + */ + public synchronized int getcount() { + return index; + } +} diff --git a/build.xml b/build.xml index 57ad97f85..86e82078f 100644 --- a/build.xml +++ b/build.xml @@ -23,6 +23,7 @@ + @@ -84,7 +85,7 @@ - + @@ -96,6 +97,7 @@ + @@ -141,6 +143,7 @@ + @@ -164,6 +167,7 @@ + @@ -199,6 +203,7 @@ + @@ -315,6 +320,7 @@ +