Refactored code.
Piles of pedantic lock checks to ensure we don't get deadlocked, it's ugly.
This commit is contained in:
@ -113,7 +113,7 @@ public class BOB {
|
|||||||
public final static String PROP_BOB_PORT = "BOB.port";
|
public final static String PROP_BOB_PORT = "BOB.port";
|
||||||
public final static String PROP_BOB_HOST = "BOB.host";
|
public final static String PROP_BOB_HOST = "BOB.host";
|
||||||
private static int maxConnections = 0;
|
private static int maxConnections = 0;
|
||||||
private static nickname database;
|
private static NamedDB database;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a warning
|
* Log a warning
|
||||||
@ -141,7 +141,7 @@ public class BOB {
|
|||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
database = new nickname();
|
database = new NamedDB();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
boolean save = false;
|
boolean save = false;
|
||||||
// Set up all defaults to be passed forward to other threads.
|
// Set up all defaults to be passed forward to other threads.
|
||||||
@ -212,10 +212,10 @@ public class BOB {
|
|||||||
Socket server;
|
Socket server;
|
||||||
|
|
||||||
while((i++ < maxConnections) || (maxConnections == 0)) {
|
while((i++ < maxConnections) || (maxConnections == 0)) {
|
||||||
//doCMDS connection;
|
//DoCMDS connection;
|
||||||
|
|
||||||
server = listener.accept();
|
server = listener.accept();
|
||||||
doCMDS conn_c = new doCMDS(server, props, database, _log);
|
DoCMDS conn_c = new DoCMDS(server, props, database, _log);
|
||||||
Thread t = new Thread(conn_c);
|
Thread t = new Thread(conn_c);
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
1349
apps/BOB/src/net/i2p/BOB/DoCMDS.java
Normal file
1349
apps/BOB/src/net/i2p/BOB/DoCMDS.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -40,7 +40,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class I2Plistener implements Runnable {
|
public class I2Plistener implements Runnable {
|
||||||
|
|
||||||
private nickname info, database;
|
private NamedDB info, database;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private int tgwatch;
|
private int tgwatch;
|
||||||
public I2PSocketManager socketManager;
|
public I2PSocketManager socketManager;
|
||||||
@ -53,7 +53,7 @@ public class I2Plistener implements Runnable {
|
|||||||
* @param database
|
* @param database
|
||||||
* @param _log
|
* @param _log
|
||||||
*/
|
*/
|
||||||
I2Plistener(I2PSocketManager S, nickname info, nickname database, Log _log) {
|
I2Plistener(I2PSocketManager S, NamedDB info, NamedDB database, Log _log) {
|
||||||
this.database = database;
|
this.database = database;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this._log = _log;
|
this._log = _log;
|
||||||
|
@ -36,7 +36,7 @@ import net.i2p.client.streaming.I2PSocket;
|
|||||||
public class I2PtoTCP implements Runnable {
|
public class I2PtoTCP implements Runnable {
|
||||||
|
|
||||||
private I2PSocket I2P;
|
private I2PSocket I2P;
|
||||||
private nickname info, database;
|
private NamedDB info, database;
|
||||||
private Socket sock;
|
private Socket sock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,26 +46,50 @@ public class I2PtoTCP implements Runnable {
|
|||||||
* @param info
|
* @param info
|
||||||
* @param database
|
* @param database
|
||||||
*/
|
*/
|
||||||
I2PtoTCP(I2PSocket I2Psock, nickname info, nickname database) {
|
I2PtoTCP(I2PSocket I2Psock, NamedDB info, NamedDB database) {
|
||||||
this.I2P = I2Psock;
|
this.I2P = I2Psock;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void rlock() throws Exception {
|
||||||
|
database.getReadLock();
|
||||||
|
info.getReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runlock() throws Exception {
|
||||||
|
database.releaseReadLock();
|
||||||
|
info.releaseReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I2P stream to TCP stream thread starter
|
* I2P stream to TCP stream thread starter
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
|
String host;
|
||||||
|
int port;
|
||||||
|
boolean tell;
|
||||||
|
die: {
|
||||||
try {
|
try {
|
||||||
database.getReadLock();
|
try {
|
||||||
info.getReadLock();
|
rlock();
|
||||||
String host = info.get("OUTHOST").toString();
|
} catch(Exception e) {
|
||||||
int port = Integer.parseInt(info.get("OUTPORT").toString());
|
break die;
|
||||||
boolean tell = info.get("QUIET").equals(Boolean.FALSE);
|
}
|
||||||
info.releaseReadLock();
|
try {
|
||||||
database.releaseReadLock();
|
host = info.get("OUTHOST").toString();
|
||||||
|
port = Integer.parseInt(info.get("OUTPORT").toString());
|
||||||
|
tell = info.get("QUIET").equals(Boolean.FALSE);
|
||||||
|
} catch(Exception e) {
|
||||||
|
runlock();
|
||||||
|
break die;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
runlock();
|
||||||
|
} catch(Exception e) {
|
||||||
|
break die;
|
||||||
|
}
|
||||||
sock = new Socket(host, port);
|
sock = new Socket(host, port);
|
||||||
// make readers/writers
|
// make readers/writers
|
||||||
InputStream in = sock.getInputStream();
|
InputStream in = sock.getInputStream();
|
||||||
@ -97,14 +121,18 @@ public class I2PtoTCP implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
break die;
|
||||||
}
|
}
|
||||||
|
} // die
|
||||||
try {
|
try {
|
||||||
I2P.close();
|
I2P.close();
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
tell = false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
sock.close();
|
sock.close();
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
tell = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class MUXlisten implements Runnable {
|
public class MUXlisten implements Runnable {
|
||||||
|
|
||||||
private nickname database, info;
|
private NamedDB database, info;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private I2PSocketManager socketManager;
|
private I2PSocketManager socketManager;
|
||||||
private ByteArrayInputStream prikey;
|
private ByteArrayInputStream prikey;
|
||||||
@ -51,6 +51,7 @@ public class MUXlisten implements Runnable {
|
|||||||
private int backlog = 50; // should this be more? less?
|
private int backlog = 50; // should this be more? less?
|
||||||
boolean go_out;
|
boolean go_out;
|
||||||
boolean come_in;
|
boolean come_in;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor Will fail if INPORT is occupied.
|
* Constructor Will fail if INPORT is occupied.
|
||||||
*
|
*
|
||||||
@ -60,7 +61,7 @@ public class MUXlisten implements Runnable {
|
|||||||
* @throws net.i2p.I2PException
|
* @throws net.i2p.I2PException
|
||||||
* @throws java.io.IOException
|
* @throws java.io.IOException
|
||||||
*/
|
*/
|
||||||
MUXlisten(nickname database, nickname info, Log _log) throws I2PException, IOException {
|
MUXlisten(NamedDB database, NamedDB info, Log _log) throws I2PException, IOException, RuntimeException {
|
||||||
int port = 0;
|
int port = 0;
|
||||||
InetAddress host = null;
|
InetAddress host = null;
|
||||||
this.database = database;
|
this.database = database;
|
||||||
@ -99,22 +100,54 @@ public class MUXlisten implements Runnable {
|
|||||||
this.database.releaseWriteLock();
|
this.database.releaseWriteLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MUX sockets, fire off a thread to connect, get destination info, and do I/O
|
* MUX sockets, fire off a thread to connect, get destination info, and do I/O
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
this.database.getWriteLock();
|
try {
|
||||||
this.info.getWriteLock();
|
wlock();
|
||||||
|
try {
|
||||||
info.add("RUNNING", Boolean.TRUE);
|
info.add("RUNNING", Boolean.TRUE);
|
||||||
info.add("STARTING", Boolean.FALSE);
|
info.add("STARTING", Boolean.FALSE);
|
||||||
this.info.releaseWriteLock();
|
} catch(Exception e) {
|
||||||
this.database.releaseWriteLock();
|
wunlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
wunlock();
|
||||||
|
} catch(Exception e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
quit: {
|
||||||
try {
|
try {
|
||||||
tg = new ThreadGroup(N);
|
tg = new ThreadGroup(N);
|
||||||
|
die: {
|
||||||
// toss the connections to a new threads.
|
// toss the connections to a new threads.
|
||||||
// will wrap with TCP and UDP when UDP works
|
// will wrap with TCP and UDP when UDP works
|
||||||
|
|
||||||
@ -139,20 +172,41 @@ public class MUXlisten implements Runnable {
|
|||||||
} catch(InterruptedException e) {
|
} catch(InterruptedException e) {
|
||||||
// nop
|
// nop
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
this.database.getReadLock();
|
rlock();
|
||||||
this.info.getReadLock();
|
try {
|
||||||
spin = info.get("STOPPING").equals(Boolean.FALSE);
|
spin = info.get("STOPPING").equals(Boolean.FALSE);
|
||||||
this.database.releaseReadLock();
|
} catch(Exception e) {
|
||||||
this.info.releaseReadLock();
|
runlock();
|
||||||
|
break die;
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
|
break die;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
runlock();
|
||||||
|
} catch(Exception e) {
|
||||||
|
break die;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.database.getWriteLock();
|
try {
|
||||||
this.info.getWriteLock();
|
wlock();
|
||||||
|
try {
|
||||||
info.add("RUNNING", Boolean.FALSE);
|
info.add("RUNNING", Boolean.FALSE);
|
||||||
this.info.releaseWriteLock();
|
} catch(Exception e) {
|
||||||
this.database.releaseWriteLock();
|
wunlock();
|
||||||
|
break die;
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
|
break die;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
wunlock();
|
||||||
|
} catch(Exception e) {
|
||||||
|
break die;
|
||||||
|
}
|
||||||
|
} // die
|
||||||
// wait for child threads and thread groups to die
|
// wait for child threads and thread groups to die
|
||||||
while(tg.activeCount() + tg.activeGroupCount() != 0) {
|
while(tg.activeCount() + tg.activeGroupCount() != 0) {
|
||||||
try {
|
try {
|
||||||
@ -165,16 +219,24 @@ public class MUXlisten implements Runnable {
|
|||||||
// Zap reference to the ThreadGroup so the JVM can GC it.
|
// Zap reference to the ThreadGroup so the JVM can GC it.
|
||||||
tg = null;
|
tg = null;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
break quit;
|
||||||
}
|
}
|
||||||
|
} // quit
|
||||||
socketManager.destroySocketManager();
|
socketManager.destroySocketManager();
|
||||||
// zero out everything, just incase.
|
// zero out everything, just incase.
|
||||||
this.database.getWriteLock();
|
try {
|
||||||
this.info.getWriteLock();
|
wlock();
|
||||||
|
try {
|
||||||
info.add("STARTING", Boolean.FALSE);
|
info.add("STARTING", Boolean.FALSE);
|
||||||
info.add("STOPPING", Boolean.FALSE);
|
info.add("STOPPING", Boolean.FALSE);
|
||||||
info.add("RUNNING", Boolean.FALSE);
|
info.add("RUNNING", Boolean.FALSE);
|
||||||
this.info.releaseWriteLock();
|
} catch(Exception e) {
|
||||||
this.database.releaseWriteLock();
|
wunlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wunlock();
|
||||||
|
} catch(Exception e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ package net.i2p.BOB;
|
|||||||
*
|
*
|
||||||
* @author sponge
|
* @author sponge
|
||||||
*/
|
*/
|
||||||
public class nickname {
|
public class NamedDB {
|
||||||
|
|
||||||
private volatile Object[][] data;
|
private volatile Object[][] data;
|
||||||
private volatile int index, writersWaiting, readers;
|
private volatile int index, writersWaiting, readers;
|
||||||
@ -37,7 +37,7 @@ public class nickname {
|
|||||||
* make initial NULL object
|
* make initial NULL object
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public nickname() {
|
public NamedDB() {
|
||||||
this.data = new Object[1][2];
|
this.data = new Object[1][2];
|
||||||
this.index = this.writersWaiting = this.readers = 0;
|
this.index = this.writersWaiting = this.readers = 0;
|
||||||
}
|
}
|
||||||
@ -76,8 +76,9 @@ public class nickname {
|
|||||||
* Find objects in the array, returns it's index or throws exception
|
* Find objects in the array, returns it's index or throws exception
|
||||||
* @param key
|
* @param key
|
||||||
* @return an objects index
|
* @return an objects index
|
||||||
|
* @throws ArrayIndexOutOfBoundsException when key does not exist
|
||||||
*/
|
*/
|
||||||
public int idx(Object key) {
|
public int idx(Object key) throws ArrayIndexOutOfBoundsException {
|
||||||
for(int i = 0; i < index; i++) {
|
for(int i = 0; i < index; i++) {
|
||||||
if(key.equals(data[i][0])) {
|
if(key.equals(data[i][0])) {
|
||||||
return i;
|
return i;
|
||||||
@ -115,7 +116,6 @@ public class nickname {
|
|||||||
}
|
}
|
||||||
index -= didsomething;
|
index -= didsomething;
|
||||||
data = olddata;
|
data = olddata;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
@ -36,7 +36,7 @@ public class TCPio implements Runnable {
|
|||||||
|
|
||||||
private InputStream Ain;
|
private InputStream Ain;
|
||||||
private OutputStream Aout;
|
private OutputStream Aout;
|
||||||
private nickname info, database;
|
private NamedDB info, database;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -46,16 +46,13 @@ public class TCPio implements Runnable {
|
|||||||
* @param info
|
* @param info
|
||||||
* @param database
|
* @param database
|
||||||
*/
|
*/
|
||||||
TCPio(InputStream Ain, OutputStream Aout, nickname info, nickname database) {
|
TCPio(InputStream Ain, OutputStream Aout, NamedDB info, NamedDB database) {
|
||||||
this.Ain = Ain;
|
this.Ain = Ain;
|
||||||
this.Aout = Aout;
|
this.Aout = Aout;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* kill off the streams, to hopefully cause an IOException in the thread in order to kill it.
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Copy from source to destination...
|
* Copy from source to destination...
|
||||||
* and yes, we are totally OK to block here on writes,
|
* and yes, we are totally OK to block here on writes,
|
||||||
@ -73,18 +70,19 @@ public class TCPio implements Runnable {
|
|||||||
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||||
info.releaseReadLock();
|
info.releaseReadLock();
|
||||||
database.releaseReadLock();
|
database.releaseReadLock();
|
||||||
|
|
||||||
b = Ain.read(a, 0, 1);
|
b = Ain.read(a, 0, 1);
|
||||||
// System.out.println(info.get("NICKNAME").toString() + " " + b);
|
// System.out.println(info.get("NICKNAME").toString() + " " + b);
|
||||||
if(b > 0) {
|
if(b > 0) {
|
||||||
Aout.write(a, 0, 1);
|
Aout.write(a, 0, b);
|
||||||
// Aout.flush(); too slow!
|
|
||||||
} else if(b == 0) {
|
} else if(b == 0) {
|
||||||
|
Thread.yield(); // this should act like a mini sleep.
|
||||||
|
if(Ain.available() == 0) {
|
||||||
try {
|
try {
|
||||||
// Thread.yield();
|
// Thread.yield();
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
} catch(InterruptedException ex) {
|
} catch(InterruptedException ex) {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* according to the specs:
|
/* according to the specs:
|
||||||
*
|
*
|
||||||
@ -97,6 +95,8 @@ public class TCPio implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
// Eject!!! Eject!!!
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class TCPlistener implements Runnable {
|
public class TCPlistener implements Runnable {
|
||||||
|
|
||||||
private nickname info, database;
|
private NamedDB info, database;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private int tgwatch;
|
private int tgwatch;
|
||||||
public I2PSocketManager socketManager;
|
public I2PSocketManager socketManager;
|
||||||
@ -54,7 +54,7 @@ public class TCPlistener implements Runnable {
|
|||||||
* @param database
|
* @param database
|
||||||
* @param _log
|
* @param _log
|
||||||
*/
|
*/
|
||||||
TCPlistener(ServerSocket listener, I2PSocketManager S, nickname info, nickname database, Log _log) {
|
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Log _log) {
|
||||||
this.database = database;
|
this.database = database;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this._log = _log;
|
this._log = _log;
|
||||||
|
@ -45,7 +45,7 @@ import net.i2p.i2ptunnel.I2PTunnel;
|
|||||||
public class TCPtoI2P implements Runnable {
|
public class TCPtoI2P implements Runnable {
|
||||||
|
|
||||||
private I2PSocket I2P;
|
private I2PSocket I2P;
|
||||||
private nickname info, database;
|
private NamedDB info, database;
|
||||||
private Socket sock;
|
private Socket sock;
|
||||||
private I2PSocketManager socketManager;
|
private I2PSocketManager socketManager;
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ public class TCPtoI2P implements Runnable {
|
|||||||
* @return line of text as a String
|
* @return line of text as a String
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static String Lread(InputStream in) throws Exception {
|
private static String lnRead(InputStream in) throws Exception {
|
||||||
String S;
|
String S;
|
||||||
int b;
|
int b;
|
||||||
char c;
|
char c;
|
||||||
@ -87,7 +87,7 @@ public class TCPtoI2P implements Runnable {
|
|||||||
* @param info
|
* @param info
|
||||||
* @param database
|
* @param database
|
||||||
*/
|
*/
|
||||||
TCPtoI2P(I2PSocketManager i2p, Socket socket, nickname info, nickname database) {
|
TCPtoI2P(I2PSocketManager i2p, Socket socket, NamedDB info, NamedDB database) {
|
||||||
this.sock = socket;
|
this.sock = socket;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this.database = database;
|
this.database = database;
|
||||||
@ -119,7 +119,7 @@ public class TCPtoI2P implements Runnable {
|
|||||||
InputStream in = sock.getInputStream();
|
InputStream in = sock.getInputStream();
|
||||||
OutputStream out = sock.getOutputStream();
|
OutputStream out = sock.getOutputStream();
|
||||||
try {
|
try {
|
||||||
line = Lread(in);
|
line = lnRead(in);
|
||||||
input = line.toLowerCase();
|
input = line.toLowerCase();
|
||||||
Destination dest = null;
|
Destination dest = null;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class UDPIOthread implements I2PSessionListener, Runnable {
|
public class UDPIOthread implements I2PSessionListener, Runnable {
|
||||||
|
|
||||||
private nickname info;
|
private NamedDB info;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
private DataInputStream in;
|
private DataInputStream in;
|
||||||
@ -61,7 +61,7 @@ public class UDPIOthread implements I2PSessionListener, Runnable {
|
|||||||
* @param socket
|
* @param socket
|
||||||
* @param _session
|
* @param _session
|
||||||
*/
|
*/
|
||||||
UDPIOthread(nickname info, Log _log, Socket socket, I2PSession _session) {
|
UDPIOthread(NamedDB info, Log _log, Socket socket, I2PSession _session) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this._log = _log;
|
this._log = _log;
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
|
@ -1,729 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 = "-B";
|
|
||||||
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_DEST = "DESTINATION";
|
|
||||||
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";
|
|
||||||
// private static final String P_INSTATE = "INSTATE";
|
|
||||||
// private static final String P_OUTSTATE = "OUTSTATE";
|
|
||||||
|
|
||||||
/* command strings */
|
|
||||||
private static final String C_help = "help";
|
|
||||||
private static final String C_clear = "clear";
|
|
||||||
private static final String C_getdest = "getdest";
|
|
||||||
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_option = "option";
|
|
||||||
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 + " <command> * Get help on a command."},
|
|
||||||
{C_clear, C_clear + " * Clear the current nickname out of the list."},
|
|
||||||
{C_getdest, C_getdest + " * Return the destination for the current nickname."},
|
|
||||||
{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_option, C_option + " I2CPoption=something * Set an I2CP option. NOTE: Don't use any spaces."},
|
|
||||||
{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 + " True | False * Don't send to the application the incoming destination."},
|
|
||||||
{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_getdest + " " +
|
|
||||||
C_getkeys + " " +
|
|
||||||
C_getnick + " " +
|
|
||||||
C_inhost + " " +
|
|
||||||
C_inport + " " +
|
|
||||||
C_list + " " +
|
|
||||||
C_newkeys + " " +
|
|
||||||
C_option + " " +
|
|
||||||
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 = new Properties(props);
|
|
||||||
this.database = database;
|
|
||||||
this._log = _log;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void rlock() {
|
|
||||||
rlock(nickinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void rlock(nickname Arg) {
|
|
||||||
database.getReadLock();
|
|
||||||
Arg.getReadLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runlock() {
|
|
||||||
runlock(nickinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runlock(nickname Arg) {
|
|
||||||
Arg.releaseReadLock();
|
|
||||||
database.releaseReadLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wlock() {
|
|
||||||
wlock(nickinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wlock(nickname Arg) {
|
|
||||||
database.getWriteLock();
|
|
||||||
Arg.getWriteLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wunlock() {
|
|
||||||
wunlock(nickinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wunlock(nickname Arg) {
|
|
||||||
Arg.releaseWriteLock();
|
|
||||||
database.releaseWriteLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to print info from the database
|
|
||||||
*
|
|
||||||
* @param out
|
|
||||||
* @param info
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
public void trypnt(PrintStream out, nickname info, Object key) {
|
|
||||||
rlock(info);
|
|
||||||
try {
|
|
||||||
out.print(" " + key + ": ");
|
|
||||||
if(info.exists(key)) {
|
|
||||||
out.print(info.get(key));
|
|
||||||
} else {
|
|
||||||
out.print("not_set");
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
runlock(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print true or false if an object exists
|
|
||||||
*
|
|
||||||
* @param out
|
|
||||||
* @param info
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
public void tfpnt(PrintStream out, nickname info, Object key) {
|
|
||||||
rlock(info);
|
|
||||||
try {
|
|
||||||
out.print(" " + key + ": ");
|
|
||||||
out.print(info.exists(key));
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
runlock(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
rlock(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);
|
|
||||||
try {
|
|
||||||
out.println();
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
runlock(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print information on a specific record, indicated by nickname
|
|
||||||
* @param out
|
|
||||||
* @param Arg
|
|
||||||
*/
|
|
||||||
public void ttlpnt(PrintStream out, Object Arg) {
|
|
||||||
database.getReadLock();
|
|
||||||
if(database.exists(Arg)) {
|
|
||||||
try {
|
|
||||||
out.print("DATA");
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
nickprint(out, (nickname)database.get(Arg));
|
|
||||||
}
|
|
||||||
database.releaseReadLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this nickname's tunnel active?
|
|
||||||
*
|
|
||||||
* @param Arg
|
|
||||||
* @return true if the tunnel is active
|
|
||||||
*/
|
|
||||||
public boolean tunnelactive(nickname Arg) {
|
|
||||||
rlock(Arg);
|
|
||||||
boolean retval = (Arg.get(P_STARTING).equals(Boolean.TRUE) ||
|
|
||||||
Arg.get(P_STOPPING).equals(Boolean.TRUE) ||
|
|
||||||
Arg.get(P_RUNNING).equals(Boolean.TRUE));
|
|
||||||
runlock(Arg);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
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_getdest)) {
|
|
||||||
if(ns) {
|
|
||||||
if(dk) {
|
|
||||||
rlock();
|
|
||||||
try {
|
|
||||||
out.println("OK " + nickinfo.get(P_DEST));
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
runlock();
|
|
||||||
} else {
|
|
||||||
out.println("ERROR keys not set.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nns(out);
|
|
||||||
}
|
|
||||||
} else if(Command.equals(C_list)) {
|
|
||||||
// Produce a formatted list of all nicknames
|
|
||||||
database.getReadLock();
|
|
||||||
for(int i = 0; i < database.getcount(); i++) {
|
|
||||||
try {
|
|
||||||
info = (nickname)database.getnext(i);
|
|
||||||
} catch(Exception b) {
|
|
||||||
break; // something bad happened.
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
|
|
||||||
out.print("DATA");
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
info.getReadLock();
|
|
||||||
nickprint(out, info);
|
|
||||||
info.releaseReadLock();
|
|
||||||
}
|
|
||||||
database.releaseReadLock();
|
|
||||||
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);
|
|
||||||
wlock();
|
|
||||||
nickinfo.add(P_KEYS, prikey.toByteArray());
|
|
||||||
nickinfo.add(P_DEST, d.toBase64());
|
|
||||||
dk = true;
|
|
||||||
wunlock();
|
|
||||||
rlock();
|
|
||||||
try {
|
|
||||||
out.println("OK " + nickinfo.get(P_DEST));
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
runlock();
|
|
||||||
} 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();
|
|
||||||
rlock();
|
|
||||||
prikey.write(((byte[])nickinfo.get(P_KEYS)));
|
|
||||||
runlock();
|
|
||||||
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 {
|
|
||||||
wlock();
|
|
||||||
nickinfo.add(P_QUIET, new Boolean(Boolean.parseBoolean(Arg) == true));
|
|
||||||
wunlock();
|
|
||||||
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 {
|
|
||||||
try {
|
|
||||||
prikey = new ByteArrayOutputStream();
|
|
||||||
prikey.write(net.i2p.data.Base64.decode(Arg));
|
|
||||||
d.fromBase64(Arg);
|
|
||||||
} catch(Exception ex) {
|
|
||||||
Arg = "";
|
|
||||||
}
|
|
||||||
if((Arg.length() == 884) && is64ok(Arg)) {
|
|
||||||
wlock();
|
|
||||||
nickinfo.add(P_KEYS, prikey.toByteArray());
|
|
||||||
nickinfo.add(P_DEST, d.toBase64());
|
|
||||||
dk = true;
|
|
||||||
wunlock();
|
|
||||||
rlock();
|
|
||||||
try {
|
|
||||||
out.println("OK " + nickinfo.get(P_DEST));
|
|
||||||
} catch(Exception e) {
|
|
||||||
}
|
|
||||||
runlock();
|
|
||||||
} else {
|
|
||||||
out.println("ERROR not in BASE64 format");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nns(out);
|
|
||||||
}
|
|
||||||
} else if(Command.equals(C_setnick)) {
|
|
||||||
ns = dk = ip = op = false;
|
|
||||||
database.getReadLock();
|
|
||||||
try {
|
|
||||||
nickinfo = (nickname)database.get(Arg);
|
|
||||||
if(!tunnelactive(nickinfo)) {
|
|
||||||
nickinfo = null;
|
|
||||||
ns = true;
|
|
||||||
}
|
|
||||||
} catch(Exception b) {
|
|
||||||
nickinfo = null;
|
|
||||||
ns = true;
|
|
||||||
}
|
|
||||||
database.releaseReadLock();
|
|
||||||
// Clears and Sets the initial nickname structure to work with
|
|
||||||
if(ns) {
|
|
||||||
nickinfo = new nickname();
|
|
||||||
wlock();
|
|
||||||
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_INHOST, "localhost");
|
|
||||||
nickinfo.add(P_OUTHOST, "localhost");
|
|
||||||
Properties Q = new Properties(props);
|
|
||||||
Q.setProperty("inbound.nickname", Arg);
|
|
||||||
Q.setProperty("outbound.nickname", Arg);
|
|
||||||
nickinfo.add(P_PROPERTIES, Q);
|
|
||||||
wunlock();
|
|
||||||
out.println("OK Nickname set to " + Arg);
|
|
||||||
} else {
|
|
||||||
out.println("ERROR tunnel is active");
|
|
||||||
}
|
|
||||||
} else if(Command.equals(C_option)) {
|
|
||||||
if(ns) {
|
|
||||||
if(tunnelactive(nickinfo)) {
|
|
||||||
out.println("ERROR tunnel is active");
|
|
||||||
} else {
|
|
||||||
StringTokenizer otoken = new StringTokenizer(Arg, "="); // use a space as a delimiter
|
|
||||||
if(otoken.countTokens() != 2) {
|
|
||||||
out.println("ERROR to many or no options.");
|
|
||||||
} else {
|
|
||||||
String pname = otoken.nextToken();
|
|
||||||
String pval = otoken.nextToken();
|
|
||||||
rlock();
|
|
||||||
Properties Q = (Properties)nickinfo.get(P_PROPERTIES);
|
|
||||||
runlock();
|
|
||||||
Q.setProperty(pname, pval);
|
|
||||||
wlock();
|
|
||||||
nickinfo.add(P_PROPERTIES, Q);
|
|
||||||
wunlock();
|
|
||||||
out.println("OK " + pname + " set to " + pval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nns(out);
|
|
||||||
}
|
|
||||||
} else if(Command.equals(C_getnick)) {
|
|
||||||
// Get the nickname to work with...
|
|
||||||
database.getReadLock();
|
|
||||||
try {
|
|
||||||
nickinfo = (nickname)database.get(Arg);
|
|
||||||
ns = true;
|
|
||||||
} catch(RuntimeException b) {
|
|
||||||
nns(out);
|
|
||||||
}
|
|
||||||
database.releaseReadLock();
|
|
||||||
if(ns) {
|
|
||||||
rlock();
|
|
||||||
dk = nickinfo.exists(P_KEYS);
|
|
||||||
ip = nickinfo.exists(P_INPORT);
|
|
||||||
op = nickinfo.exists(P_OUTPORT);
|
|
||||||
runlock();
|
|
||||||
// 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;
|
|
||||||
wlock();
|
|
||||||
nickinfo.kill(P_INPORT);
|
|
||||||
try {
|
|
||||||
prt = Integer.parseInt(Arg);
|
|
||||||
if(prt > 1 && prt < 65536) {
|
|
||||||
nickinfo.add(P_INPORT, new Integer(prt));
|
|
||||||
}
|
|
||||||
} catch(NumberFormatException nfe) {
|
|
||||||
out.println("ERROR not a number");
|
|
||||||
}
|
|
||||||
wunlock();
|
|
||||||
rlock();
|
|
||||||
ip = nickinfo.exists(P_INPORT);
|
|
||||||
runlock();
|
|
||||||
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;
|
|
||||||
wlock();
|
|
||||||
nickinfo.kill(P_OUTPORT);
|
|
||||||
try {
|
|
||||||
prt = Integer.parseInt(Arg);
|
|
||||||
if(prt > 1 && prt < 65536) {
|
|
||||||
nickinfo.add(P_OUTPORT, new Integer(prt));
|
|
||||||
}
|
|
||||||
} catch(NumberFormatException nfe) {
|
|
||||||
out.println("ERROR not a number");
|
|
||||||
}
|
|
||||||
wunlock();
|
|
||||||
rlock();
|
|
||||||
ip = nickinfo.exists(P_OUTPORT);
|
|
||||||
runlock();
|
|
||||||
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 {
|
|
||||||
wlock();
|
|
||||||
nickinfo.add(P_INHOST, Arg);
|
|
||||||
wunlock();
|
|
||||||
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 {
|
|
||||||
wlock();
|
|
||||||
nickinfo.add(P_OUTHOST, Arg);
|
|
||||||
wunlock();
|
|
||||||
out.println("OK outhost set");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nns(out);
|
|
||||||
}
|
|
||||||
} else if(Command.equals(C_show)) {
|
|
||||||
// Get the current nickname properties
|
|
||||||
if(ns) {
|
|
||||||
out.print("OK");
|
|
||||||
rlock();
|
|
||||||
nickprint(out, nickinfo);
|
|
||||||
runlock();
|
|
||||||
} 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(database, nickinfo, _log);
|
|
||||||
Thread t = new Thread(tunnel);
|
|
||||||
t.start();
|
|
||||||
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) {
|
|
||||||
rlock();
|
|
||||||
if(nickinfo.get(P_RUNNING).equals(Boolean.TRUE) && nickinfo.get(P_STOPPING).equals(Boolean.FALSE) && nickinfo.get(P_STARTING).equals(Boolean.FALSE)) {
|
|
||||||
runlock();
|
|
||||||
wlock();
|
|
||||||
nickinfo.add(P_STOPPING, Boolean.TRUE);
|
|
||||||
wunlock();
|
|
||||||
out.println("OK tunnel stopping");
|
|
||||||
} else {
|
|
||||||
runlock();
|
|
||||||
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.getWriteLock();
|
|
||||||
database.kill(nickinfo.get(P_NICKNAME));
|
|
||||||
database.releaseWriteLock();
|
|
||||||
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, 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user