Bugfixes for BOB, Important database locking to prevent thread collisions.
This commit is contained in:
@ -40,7 +40,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class I2Plistener implements Runnable {
|
public class I2Plistener implements Runnable {
|
||||||
|
|
||||||
private nickname info;
|
private nickname info, database;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private int tgwatch;
|
private int tgwatch;
|
||||||
public I2PSocketManager socketManager;
|
public I2PSocketManager socketManager;
|
||||||
@ -50,9 +50,11 @@ public class I2Plistener implements Runnable {
|
|||||||
* Constructor
|
* Constructor
|
||||||
* @param S
|
* @param S
|
||||||
* @param info
|
* @param info
|
||||||
|
* @param database
|
||||||
* @param _log
|
* @param _log
|
||||||
*/
|
*/
|
||||||
I2Plistener(I2PSocketManager S, nickname info, Log _log) {
|
I2Plistener(I2PSocketManager S, nickname info, nickname database, Log _log) {
|
||||||
|
this.database = database;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this._log = _log;
|
this._log = _log;
|
||||||
this.socketManager = S;
|
this.socketManager = S;
|
||||||
@ -62,38 +64,48 @@ public class I2Plistener implements Runnable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Simply listen on I2P port, and thread connections
|
* Simply listen on I2P port, and thread connections
|
||||||
*
|
*
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public void run() throws RuntimeException {
|
public void run() throws RuntimeException {
|
||||||
boolean g = false;
|
boolean g = false;
|
||||||
I2PSocket sessSocket = null;
|
I2PSocket sessSocket = null;
|
||||||
|
|
||||||
// needed to hack in this method :-/
|
|
||||||
serverSocket.setSoTimeout(1000);
|
serverSocket.setSoTimeout(1000);
|
||||||
|
database.getReadLock();
|
||||||
|
info.getReadLock();
|
||||||
if(info.exists("INPORT")) {
|
if(info.exists("INPORT")) {
|
||||||
tgwatch = 2;
|
tgwatch = 2;
|
||||||
}
|
}
|
||||||
while(info.get("RUNNING").equals(Boolean.TRUE)) {
|
info.releaseReadLock();
|
||||||
|
database.releaseReadLock();
|
||||||
|
boolean spin = true;
|
||||||
|
while(spin) {
|
||||||
|
|
||||||
|
database.getReadLock();
|
||||||
|
info.getReadLock();
|
||||||
|
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||||
|
info.releaseReadLock();
|
||||||
|
database.releaseReadLock();
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
sessSocket = serverSocket.accept();
|
sessSocket = serverSocket.accept();
|
||||||
g = true;
|
g = true;
|
||||||
} catch(ConnectException ce) {
|
} catch(ConnectException ce) {
|
||||||
g = false;
|
g = false;
|
||||||
} catch (SocketTimeoutException ste) {
|
} catch(SocketTimeoutException ste) {
|
||||||
g = false;
|
g = false;
|
||||||
}
|
}
|
||||||
if(g) {
|
if(g) {
|
||||||
g = false;
|
g = false;
|
||||||
// toss the connection to a new thread.
|
// toss the connection to a new thread.
|
||||||
I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info);
|
I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database);
|
||||||
Thread t = new Thread(conn_c, "BOBI2PtoTCP");
|
Thread t = new Thread(conn_c, "BOBI2PtoTCP");
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(I2PException e) {
|
} catch(I2PException e) {
|
||||||
System.out.println("Exception "+e);
|
// System.out.println("Exception " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,18 +36,20 @@ 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;
|
private nickname info, database;
|
||||||
private Socket sock;
|
private Socket sock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param I2Psock
|
* @param I2Psock
|
||||||
* @param db
|
* @param info
|
||||||
|
* @param database
|
||||||
*/
|
*/
|
||||||
I2PtoTCP(I2PSocket I2Psock, nickname db) {
|
I2PtoTCP(I2PSocket I2Psock, nickname info, nickname database) {
|
||||||
this.I2P = I2Psock;
|
this.I2P = I2Psock;
|
||||||
this.info = db;
|
this.info = info;
|
||||||
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,7 +59,14 @@ public class I2PtoTCP implements Runnable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sock = new Socket(info.get("OUTHOST").toString(), Integer.parseInt(info.get("OUTPORT").toString()));
|
database.getReadLock();
|
||||||
|
info.getReadLock();
|
||||||
|
String host = info.get("OUTHOST").toString();
|
||||||
|
int port = Integer.parseInt(info.get("OUTPORT").toString());
|
||||||
|
boolean tell = info.get("QUIET").equals(Boolean.FALSE);
|
||||||
|
info.releaseReadLock();
|
||||||
|
database.releaseReadLock();
|
||||||
|
sock = new Socket(host, port);
|
||||||
// make readers/writers
|
// make readers/writers
|
||||||
InputStream in = sock.getInputStream();
|
InputStream in = sock.getInputStream();
|
||||||
OutputStream out = sock.getOutputStream();
|
OutputStream out = sock.getOutputStream();
|
||||||
@ -65,15 +74,15 @@ public class I2PtoTCP implements Runnable {
|
|||||||
OutputStream Iout = I2P.getOutputStream();
|
OutputStream Iout = I2P.getOutputStream();
|
||||||
I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
|
I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
|
||||||
|
|
||||||
if(info.get("QUIET").equals(Boolean.FALSE)) {
|
if(tell) {
|
||||||
// tell who is connecting
|
// tell who is connecting
|
||||||
out.write(I2P.getPeerDestination().toBase64().getBytes());
|
out.write(I2P.getPeerDestination().toBase64().getBytes());
|
||||||
out.write(10); // nl
|
out.write(10); // nl
|
||||||
out.flush(); // not really needed, but...
|
out.flush(); // not really needed, but...
|
||||||
}
|
}
|
||||||
// setup to cross the streams
|
// setup to cross the streams
|
||||||
TCPio conn_c = new TCPio(in, Iout, info); // app -> I2P
|
TCPio conn_c = new TCPio(in, Iout, info, database); // app -> I2P
|
||||||
TCPio conn_a = new TCPio(Iin, out, info); // I2P -> app
|
TCPio conn_a = new TCPio(Iin, out, info, database); // I2P -> app
|
||||||
Thread t = new Thread(conn_c, "TCPioA");
|
Thread t = new Thread(conn_c, "TCPioA");
|
||||||
Thread q = new Thread(conn_a, "TCPioB");
|
Thread q = new Thread(conn_a, "TCPioB");
|
||||||
// Fire!
|
// Fire!
|
||||||
|
@ -39,7 +39,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class MUXlisten implements Runnable {
|
public class MUXlisten implements Runnable {
|
||||||
|
|
||||||
private nickname info;
|
private nickname database, info;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private I2PSocketManager socketManager;
|
private I2PSocketManager socketManager;
|
||||||
private ByteArrayInputStream prikey;
|
private ByteArrayInputStream prikey;
|
||||||
@ -50,18 +50,31 @@ public class MUXlisten implements Runnable {
|
|||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param info
|
* @param info
|
||||||
|
* @param database
|
||||||
* @param _log
|
* @param _log
|
||||||
* @throws net.i2p.I2PException
|
* @throws net.i2p.I2PException
|
||||||
* @throws java.io.IOException
|
* @throws java.io.IOException
|
||||||
*/
|
*/
|
||||||
MUXlisten(nickname info, Log _log) throws I2PException, IOException {
|
MUXlisten(nickname database, nickname info, Log _log) throws I2PException, IOException {
|
||||||
|
this.database = database;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this._log = _log;
|
this._log = _log;
|
||||||
this.info.add("STARTING", Boolean.TRUE);
|
|
||||||
|
|
||||||
|
this.database.getReadLock();
|
||||||
|
this.info.getReadLock();
|
||||||
N = this.info.get("NICKNAME").toString();
|
N = this.info.get("NICKNAME").toString();
|
||||||
prikey = new ByteArrayInputStream((byte[])info.get("KEYS"));
|
prikey = new ByteArrayInputStream((byte[])info.get("KEYS"));
|
||||||
socketManager = I2PSocketManagerFactory.createManager(prikey, (Properties)info.get("PROPERTIES"));
|
Properties Q = (Properties)info.get("PROPERTIES");
|
||||||
|
this.database.releaseReadLock();
|
||||||
|
this.info.releaseReadLock();
|
||||||
|
|
||||||
|
this.database.getWriteLock();
|
||||||
|
this.info.getWriteLock();
|
||||||
|
this.info.add("STARTING", Boolean.TRUE);
|
||||||
|
this.info.releaseWriteLock();
|
||||||
|
this.database.releaseWriteLock();
|
||||||
|
|
||||||
|
socketManager = I2PSocketManagerFactory.createManager(prikey, Q);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,49 +83,82 @@ public class MUXlisten implements Runnable {
|
|||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
tg = new ThreadGroup(N);
|
this.database.getWriteLock();
|
||||||
|
this.info.getWriteLock();
|
||||||
info.add("RUNNING", Boolean.TRUE);
|
info.add("RUNNING", Boolean.TRUE);
|
||||||
info.add("STARTING", Boolean.FALSE);
|
info.add("STARTING", Boolean.FALSE);
|
||||||
|
this.info.releaseWriteLock();
|
||||||
|
this.database.releaseWriteLock();
|
||||||
|
|
||||||
// toss the connections to a new threads.
|
try {
|
||||||
// will wrap with TCP and UDP when UDP works
|
tg = new ThreadGroup(N);
|
||||||
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(Boolean.FALSE)) {
|
// toss the connections to a new threads.
|
||||||
try {
|
// will wrap with TCP and UDP when UDP works
|
||||||
Thread.sleep(1000); //sleep for 1000 ms (One second)
|
this.database.getReadLock();
|
||||||
} catch(InterruptedException e) {
|
this.info.getReadLock();
|
||||||
// nop
|
boolean go_out = info.exists("OUTPORT");
|
||||||
|
boolean come_in = info.exists("INPORT");
|
||||||
|
this.database.releaseReadLock();
|
||||||
|
this.info.releaseReadLock();
|
||||||
|
|
||||||
|
if(go_out) {
|
||||||
|
// I2P -> TCP
|
||||||
|
I2Plistener conn = new I2Plistener(socketManager, info, database, _log);
|
||||||
|
Thread t = new Thread(tg, conn, "BOBI2Plistener " + N);
|
||||||
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(come_in) {
|
||||||
|
// TCP -> I2P
|
||||||
|
TCPlistener conn = new TCPlistener(socketManager, info, database, _log);
|
||||||
|
Thread q = new Thread(tg, conn, "BOBTCPlistener" + N);
|
||||||
|
q.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean spin = true;
|
||||||
|
while(spin) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000); //sleep for 1000 ms (One second)
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
this.database.getReadLock();
|
||||||
|
this.info.getReadLock();
|
||||||
|
spin = info.get("STOPPING").equals(Boolean.FALSE);
|
||||||
|
this.database.releaseReadLock();
|
||||||
|
this.info.releaseReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.database.getWriteLock();
|
||||||
|
this.info.getWriteLock();
|
||||||
|
info.add("RUNNING", Boolean.FALSE);
|
||||||
|
this.info.releaseWriteLock();
|
||||||
|
this.database.releaseWriteLock();
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tg.destroy();
|
||||||
|
// Zap reference to the ThreadGroup so the JVM can GC it.
|
||||||
|
tg = null;
|
||||||
|
} catch(Exception e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
info.add("RUNNING", Boolean.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();
|
socketManager.destroySocketManager();
|
||||||
tg.destroy();
|
// zero out everything, just incase.
|
||||||
// Zap reference to the ThreadGroup so the JVM can GC it.
|
this.database.getWriteLock();
|
||||||
tg = null;
|
this.info.getWriteLock();
|
||||||
info.add("STOPPING", Boolean.FALSE);
|
|
||||||
info.add("STARTING", Boolean.FALSE);
|
info.add("STARTING", Boolean.FALSE);
|
||||||
|
info.add("STOPPING", Boolean.FALSE);
|
||||||
|
info.add("RUNNING", Boolean.FALSE);
|
||||||
|
this.info.releaseWriteLock();
|
||||||
|
this.database.releaseWriteLock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,19 +36,21 @@ public class TCPio implements Runnable {
|
|||||||
|
|
||||||
private InputStream Ain;
|
private InputStream Ain;
|
||||||
private OutputStream Aout;
|
private OutputStream Aout;
|
||||||
private nickname info;
|
private nickname info, database;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param Ain
|
* @param Ain
|
||||||
* @param Aout
|
* @param Aout
|
||||||
* @param db
|
* @param info
|
||||||
|
* @param database
|
||||||
*/
|
*/
|
||||||
TCPio(InputStream Ain, OutputStream Aout, nickname db) {
|
TCPio(InputStream Ain, OutputStream Aout, nickname info, nickname database) {
|
||||||
this.Ain = Ain;
|
this.Ain = Ain;
|
||||||
this.Aout = Aout;
|
this.Aout = Aout;
|
||||||
this.info = db;
|
this.info = info;
|
||||||
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,13 +65,20 @@ public class TCPio implements Runnable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
int b;
|
int b;
|
||||||
byte a[] = new byte[1];
|
byte a[] = new byte[1];
|
||||||
|
boolean spin = true;
|
||||||
try {
|
try {
|
||||||
while(info.get("RUNNING").equals(Boolean.TRUE)) {
|
while(spin) {
|
||||||
|
database.getReadLock();
|
||||||
|
info.getReadLock();
|
||||||
|
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||||
|
info.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, 1);
|
||||||
// Aout.flush(); too slow!
|
// Aout.flush(); too slow!
|
||||||
} else if(b == 0) {
|
} else if(b == 0) {
|
||||||
try {
|
try {
|
||||||
// Thread.yield();
|
// Thread.yield();
|
||||||
@ -87,7 +96,7 @@ public class TCPio implements Runnable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(IOException e) {
|
} catch(Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ import net.i2p.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class TCPlistener implements Runnable {
|
public class TCPlistener implements Runnable {
|
||||||
|
|
||||||
private nickname info;
|
private nickname info, database;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private int tgwatch;
|
private int tgwatch;
|
||||||
public I2PSocketManager socketManager;
|
public I2PSocketManager socketManager;
|
||||||
@ -52,9 +52,11 @@ public class TCPlistener implements Runnable {
|
|||||||
* Constructor
|
* Constructor
|
||||||
* @param S
|
* @param S
|
||||||
* @param info
|
* @param info
|
||||||
|
* @param database
|
||||||
* @param _log
|
* @param _log
|
||||||
*/
|
*/
|
||||||
TCPlistener(I2PSocketManager S, nickname info, Log _log) {
|
TCPlistener(I2PSocketManager S, nickname info, nickname database, Log _log) {
|
||||||
|
this.database = database;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this._log = _log;
|
this._log = _log;
|
||||||
this.socketManager = S;
|
this.socketManager = S;
|
||||||
@ -67,6 +69,8 @@ public class TCPlistener implements Runnable {
|
|||||||
*/
|
*/
|
||||||
public void run() throws RuntimeException {
|
public void run() throws RuntimeException {
|
||||||
boolean g = false;
|
boolean g = false;
|
||||||
|
database.getReadLock();
|
||||||
|
info.getReadLock();
|
||||||
if(info.exists("OUTPORT")) {
|
if(info.exists("OUTPORT")) {
|
||||||
tgwatch = 2;
|
tgwatch = 2;
|
||||||
}
|
}
|
||||||
@ -75,7 +79,15 @@ public class TCPlistener implements Runnable {
|
|||||||
ServerSocket listener = new ServerSocket(Integer.parseInt(info.get("INPORT").toString()), backlog, InetAddress.getByName(info.get("INHOST").toString()));
|
ServerSocket listener = new ServerSocket(Integer.parseInt(info.get("INPORT").toString()), backlog, InetAddress.getByName(info.get("INHOST").toString()));
|
||||||
Socket server = new Socket();
|
Socket server = new Socket();
|
||||||
listener.setSoTimeout(1000);
|
listener.setSoTimeout(1000);
|
||||||
while(info.get("RUNNING").equals(Boolean.TRUE)) {
|
info.releaseReadLock();
|
||||||
|
database.releaseReadLock();
|
||||||
|
boolean spin = true;
|
||||||
|
while(spin) {
|
||||||
|
database.getReadLock();
|
||||||
|
info.getReadLock();
|
||||||
|
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||||
|
info.releaseReadLock();
|
||||||
|
database.releaseReadLock();
|
||||||
// System.out.println("Thread count " + Thread.activeCount());
|
// System.out.println("Thread count " + Thread.activeCount());
|
||||||
try {
|
try {
|
||||||
server = listener.accept();
|
server = listener.accept();
|
||||||
@ -85,7 +97,7 @@ public class TCPlistener implements Runnable {
|
|||||||
}
|
}
|
||||||
if(g) {
|
if(g) {
|
||||||
// toss the connection to a new thread.
|
// toss the connection to a new thread.
|
||||||
TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info);
|
TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info, database);
|
||||||
Thread t = new Thread(conn_c, "BOBTCPtoI2P");
|
Thread t = new Thread(conn_c, "BOBTCPtoI2P");
|
||||||
t.start();
|
t.start();
|
||||||
g = false;
|
g = false;
|
||||||
|
@ -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;
|
private nickname info, database;
|
||||||
private Socket sock;
|
private Socket sock;
|
||||||
private I2PSocketManager socketManager;
|
private I2PSocketManager socketManager;
|
||||||
|
|
||||||
@ -84,11 +84,13 @@ public class TCPtoI2P implements Runnable {
|
|||||||
* Constructor
|
* Constructor
|
||||||
* @param i2p
|
* @param i2p
|
||||||
* @param socket
|
* @param socket
|
||||||
* @param db
|
* @param info
|
||||||
|
* @param database
|
||||||
*/
|
*/
|
||||||
TCPtoI2P(I2PSocketManager i2p, Socket socket, nickname db) {
|
TCPtoI2P(I2PSocketManager i2p, Socket socket, nickname info, nickname database) {
|
||||||
this.sock = socket;
|
this.sock = socket;
|
||||||
this.info = db;
|
this.info = info;
|
||||||
|
this.database = database;
|
||||||
this.socketManager = i2p;
|
this.socketManager = i2p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,8 +138,8 @@ public class TCPtoI2P implements Runnable {
|
|||||||
InputStream Iin = I2P.getInputStream();
|
InputStream Iin = I2P.getInputStream();
|
||||||
OutputStream Iout = I2P.getOutputStream();
|
OutputStream Iout = I2P.getOutputStream();
|
||||||
// setup to cross the streams
|
// setup to cross the streams
|
||||||
TCPio conn_c = new TCPio(in, Iout, info); // app -> I2P
|
TCPio conn_c = new TCPio(in, Iout, info, database); // app -> I2P
|
||||||
TCPio conn_a = new TCPio(Iin, out, info); // I2P -> app
|
TCPio conn_a = new TCPio(Iin, out, info, database); // I2P -> app
|
||||||
Thread t = new Thread(conn_c, "TCPioA");
|
Thread t = new Thread(conn_c, "TCPioA");
|
||||||
Thread q = new Thread(conn_a, "TCPioB");
|
Thread q = new Thread(conn_a, "TCPioB");
|
||||||
// Fire!
|
// Fire!
|
||||||
|
@ -46,7 +46,7 @@ public class doCMDS implements Runnable {
|
|||||||
|
|
||||||
// FIX ME
|
// FIX ME
|
||||||
// I need a better way to do versioning, but this will do for now.
|
// 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 = "-8";
|
public static final String BMAJ = "00", BMIN = "00", BREV = "01", BEXT = "-9";
|
||||||
public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT;
|
public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT;
|
||||||
private Socket server;
|
private Socket server;
|
||||||
private Properties props;
|
private Properties props;
|
||||||
@ -153,6 +153,42 @@ public class doCMDS implements Runnable {
|
|||||||
this._log = _log;
|
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
|
* Try to print info from the database
|
||||||
*
|
*
|
||||||
@ -161,12 +197,17 @@ public class doCMDS implements Runnable {
|
|||||||
* @param key
|
* @param key
|
||||||
*/
|
*/
|
||||||
public void trypnt(PrintStream out, nickname info, Object key) {
|
public void trypnt(PrintStream out, nickname info, Object key) {
|
||||||
out.print(" " + key + ": ");
|
rlock(info);
|
||||||
if(info.exists(key)) {
|
try {
|
||||||
out.print(info.get(key));
|
out.print(" " + key + ": ");
|
||||||
} else {
|
if(info.exists(key)) {
|
||||||
out.print("not_set");
|
out.print(info.get(key));
|
||||||
|
} else {
|
||||||
|
out.print("not_set");
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
}
|
}
|
||||||
|
runlock(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,8 +218,13 @@ public class doCMDS implements Runnable {
|
|||||||
* @param key
|
* @param key
|
||||||
*/
|
*/
|
||||||
public void tfpnt(PrintStream out, nickname info, Object key) {
|
public void tfpnt(PrintStream out, nickname info, Object key) {
|
||||||
out.print(" " + key + ": ");
|
rlock(info);
|
||||||
out.print(info.exists(key));
|
try {
|
||||||
|
out.print(" " + key + ": ");
|
||||||
|
out.print(info.exists(key));
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
|
runlock(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -197,6 +243,7 @@ public class doCMDS implements Runnable {
|
|||||||
* @param info
|
* @param info
|
||||||
*/
|
*/
|
||||||
public void nickprint(PrintStream out, nickname info) {
|
public void nickprint(PrintStream out, nickname info) {
|
||||||
|
rlock(info);
|
||||||
trypnt(out, info, P_NICKNAME);
|
trypnt(out, info, P_NICKNAME);
|
||||||
trypnt(out, info, P_STARTING);
|
trypnt(out, info, P_STARTING);
|
||||||
trypnt(out, info, P_RUNNING);
|
trypnt(out, info, P_RUNNING);
|
||||||
@ -207,21 +254,28 @@ public class doCMDS implements Runnable {
|
|||||||
trypnt(out, info, P_INHOST);
|
trypnt(out, info, P_INHOST);
|
||||||
trypnt(out, info, P_OUTPORT);
|
trypnt(out, info, P_OUTPORT);
|
||||||
trypnt(out, info, P_OUTHOST);
|
trypnt(out, info, P_OUTHOST);
|
||||||
out.println();
|
try {
|
||||||
|
out.println();
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
|
runlock(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print information on a specific record, indicated by nickname
|
* Print information on a specific record, indicated by nickname
|
||||||
* @param out
|
* @param out
|
||||||
* @param database
|
|
||||||
* @param Arg
|
* @param Arg
|
||||||
*/
|
*/
|
||||||
public void ttlpnt(PrintStream out, nickname database, Object Arg) {
|
public void ttlpnt(PrintStream out, Object Arg) {
|
||||||
|
database.getReadLock();
|
||||||
if(database.exists(Arg)) {
|
if(database.exists(Arg)) {
|
||||||
out.print("DATA");
|
try {
|
||||||
|
out.print("DATA");
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
nickprint(out, (nickname)database.get(Arg));
|
nickprint(out, (nickname)database.get(Arg));
|
||||||
}
|
}
|
||||||
|
database.releaseReadLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -231,10 +285,12 @@ public class doCMDS implements Runnable {
|
|||||||
* @return true if the tunnel is active
|
* @return true if the tunnel is active
|
||||||
*/
|
*/
|
||||||
public boolean tunnelactive(nickname Arg) {
|
public boolean tunnelactive(nickname Arg) {
|
||||||
return (Arg.get(P_STARTING).equals(Boolean.TRUE) ||
|
rlock(Arg);
|
||||||
|
boolean retval = (Arg.get(P_STARTING).equals(Boolean.TRUE) ||
|
||||||
Arg.get(P_STOPPING).equals(Boolean.TRUE) ||
|
Arg.get(P_STOPPING).equals(Boolean.TRUE) ||
|
||||||
Arg.get(P_RUNNING).equals(Boolean.TRUE));
|
Arg.get(P_RUNNING).equals(Boolean.TRUE));
|
||||||
|
runlock(Arg);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -267,7 +323,6 @@ public class doCMDS implements Runnable {
|
|||||||
out.println("BOB " + BOBversion);
|
out.println("BOB " + BOBversion);
|
||||||
out.println("OK");
|
out.println("OK");
|
||||||
while((line = in.readLine()) != null) {
|
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
|
StringTokenizer token = new StringTokenizer(line, " "); // use a space as a delimiter
|
||||||
String Command = "";
|
String Command = "";
|
||||||
String Arg = "";
|
String Arg = "";
|
||||||
@ -293,7 +348,12 @@ public class doCMDS implements Runnable {
|
|||||||
} else if(Command.equals(C_getdest)) {
|
} else if(Command.equals(C_getdest)) {
|
||||||
if(ns) {
|
if(ns) {
|
||||||
if(dk) {
|
if(dk) {
|
||||||
out.println("OK " + nickinfo.get(P_DEST));
|
rlock();
|
||||||
|
try {
|
||||||
|
out.println("OK " + nickinfo.get(P_DEST));
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
|
runlock();
|
||||||
} else {
|
} else {
|
||||||
out.println("ERROR keys not set.");
|
out.println("ERROR keys not set.");
|
||||||
}
|
}
|
||||||
@ -302,16 +362,23 @@ public class doCMDS implements Runnable {
|
|||||||
}
|
}
|
||||||
} else if(Command.equals(C_list)) {
|
} else if(Command.equals(C_list)) {
|
||||||
// Produce a formatted list of all nicknames
|
// Produce a formatted list of all nicknames
|
||||||
|
database.getReadLock();
|
||||||
for(int i = 0; i < database.getcount(); i++) {
|
for(int i = 0; i < database.getcount(); i++) {
|
||||||
try {
|
try {
|
||||||
info = (nickname)database.getnext(i);
|
info = (nickname)database.getnext(i);
|
||||||
} catch(RuntimeException b) {
|
} catch(Exception b) {
|
||||||
break; // something bad happened.
|
break; // something bad happened.
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
|
||||||
out.print("DATA");
|
out.print("DATA");
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
|
info.getReadLock();
|
||||||
nickprint(out, info);
|
nickprint(out, info);
|
||||||
|
info.releaseReadLock();
|
||||||
}
|
}
|
||||||
|
database.releaseReadLock();
|
||||||
out.println("OK Listing done");
|
out.println("OK Listing done");
|
||||||
} else if(Command.equals(C_quit)) {
|
} else if(Command.equals(C_quit)) {
|
||||||
// End the command session
|
// End the command session
|
||||||
@ -325,11 +392,17 @@ public class doCMDS implements Runnable {
|
|||||||
// Make a new PublicKey and PrivateKey
|
// Make a new PublicKey and PrivateKey
|
||||||
prikey = new ByteArrayOutputStream();
|
prikey = new ByteArrayOutputStream();
|
||||||
d = I2PClientFactory.createClient().createDestination(prikey);
|
d = I2PClientFactory.createClient().createDestination(prikey);
|
||||||
dk = true;
|
wlock();
|
||||||
nickinfo.add(P_KEYS, prikey.toByteArray());
|
nickinfo.add(P_KEYS, prikey.toByteArray());
|
||||||
nickinfo.add(P_DEST, d.toBase64());
|
nickinfo.add(P_DEST, d.toBase64());
|
||||||
// System.out.println(prikey.toByteArray().length);
|
dk = true;
|
||||||
out.println("OK " + nickinfo.get(P_DEST));
|
wunlock();
|
||||||
|
rlock();
|
||||||
|
try {
|
||||||
|
out.println("OK " + nickinfo.get(P_DEST));
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
|
runlock();
|
||||||
} catch(IOException ioe) {
|
} catch(IOException ioe) {
|
||||||
BOB.error("Error generating keys" + ioe);
|
BOB.error("Error generating keys" + ioe);
|
||||||
out.println("ERROR generating keys");
|
out.println("ERROR generating keys");
|
||||||
@ -345,7 +418,9 @@ public class doCMDS implements Runnable {
|
|||||||
// Return public key
|
// Return public key
|
||||||
if(dk) {
|
if(dk) {
|
||||||
prikey = new ByteArrayOutputStream();
|
prikey = new ByteArrayOutputStream();
|
||||||
|
rlock();
|
||||||
prikey.write(((byte[])nickinfo.get(P_KEYS)));
|
prikey.write(((byte[])nickinfo.get(P_KEYS)));
|
||||||
|
runlock();
|
||||||
out.println("OK " + net.i2p.data.Base64.encode(prikey.toByteArray()));
|
out.println("OK " + net.i2p.data.Base64.encode(prikey.toByteArray()));
|
||||||
} else {
|
} else {
|
||||||
out.println("ERROR no public key has been set");
|
out.println("ERROR no public key has been set");
|
||||||
@ -355,7 +430,9 @@ public class doCMDS implements Runnable {
|
|||||||
if(tunnelactive(nickinfo)) {
|
if(tunnelactive(nickinfo)) {
|
||||||
out.println("ERROR tunnel is active");
|
out.println("ERROR tunnel is active");
|
||||||
} else {
|
} else {
|
||||||
|
wlock();
|
||||||
nickinfo.add(P_QUIET, new Boolean(Boolean.parseBoolean(Arg) == true));
|
nickinfo.add(P_QUIET, new Boolean(Boolean.parseBoolean(Arg) == true));
|
||||||
|
wunlock();
|
||||||
out.println("OK Quiet set");
|
out.println("OK Quiet set");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -375,10 +452,17 @@ public class doCMDS implements Runnable {
|
|||||||
Arg = "";
|
Arg = "";
|
||||||
}
|
}
|
||||||
if((Arg.length() == 884) && is64ok(Arg)) {
|
if((Arg.length() == 884) && is64ok(Arg)) {
|
||||||
|
wlock();
|
||||||
nickinfo.add(P_KEYS, prikey.toByteArray());
|
nickinfo.add(P_KEYS, prikey.toByteArray());
|
||||||
nickinfo.add(P_DEST, d.toBase64());
|
nickinfo.add(P_DEST, d.toBase64());
|
||||||
out.println("OK " + nickinfo.get(P_DEST));
|
|
||||||
dk = true;
|
dk = true;
|
||||||
|
wunlock();
|
||||||
|
rlock();
|
||||||
|
try {
|
||||||
|
out.println("OK " + nickinfo.get(P_DEST));
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
|
runlock();
|
||||||
} else {
|
} else {
|
||||||
out.println("ERROR not in BASE64 format");
|
out.println("ERROR not in BASE64 format");
|
||||||
}
|
}
|
||||||
@ -388,20 +472,22 @@ public class doCMDS implements Runnable {
|
|||||||
}
|
}
|
||||||
} else if(Command.equals(C_setnick)) {
|
} else if(Command.equals(C_setnick)) {
|
||||||
ns = dk = ip = op = false;
|
ns = dk = ip = op = false;
|
||||||
|
database.getReadLock();
|
||||||
try {
|
try {
|
||||||
nickinfo = (nickname)database.get(Arg);
|
nickinfo = (nickname)database.get(Arg);
|
||||||
if(!tunnelactive(nickinfo)) {
|
if(!tunnelactive(nickinfo)) {
|
||||||
nickinfo = null;
|
nickinfo = null;
|
||||||
ns = true;
|
ns = true;
|
||||||
}
|
}
|
||||||
} catch(RuntimeException b) {
|
} catch(Exception b) {
|
||||||
nickinfo = null;
|
nickinfo = null;
|
||||||
ns = true;
|
ns = true;
|
||||||
}
|
}
|
||||||
|
database.releaseReadLock();
|
||||||
// Clears and Sets the initial nickname structure to work with
|
// Clears and Sets the initial nickname structure to work with
|
||||||
if(ns) {
|
if(ns) {
|
||||||
nickinfo = new nickname();
|
nickinfo = new nickname();
|
||||||
|
wlock();
|
||||||
database.add(Arg, nickinfo);
|
database.add(Arg, nickinfo);
|
||||||
nickinfo.add(P_NICKNAME, Arg);
|
nickinfo.add(P_NICKNAME, Arg);
|
||||||
nickinfo.add(P_STARTING, Boolean.FALSE);
|
nickinfo.add(P_STARTING, Boolean.FALSE);
|
||||||
@ -410,10 +496,11 @@ public class doCMDS implements Runnable {
|
|||||||
nickinfo.add(P_QUIET, Boolean.FALSE);
|
nickinfo.add(P_QUIET, Boolean.FALSE);
|
||||||
nickinfo.add(P_INHOST, "localhost");
|
nickinfo.add(P_INHOST, "localhost");
|
||||||
nickinfo.add(P_OUTHOST, "localhost");
|
nickinfo.add(P_OUTHOST, "localhost");
|
||||||
Properties Q = props;
|
Properties Q = new Properties(props);
|
||||||
Q.setProperty("inbound.nickname", (String)nickinfo.get(P_NICKNAME));
|
Q.setProperty("inbound.nickname", Arg);
|
||||||
Q.setProperty("outbound.nickname", (String)nickinfo.get(P_NICKNAME));
|
Q.setProperty("outbound.nickname", Arg);
|
||||||
nickinfo.add(P_PROPERTIES, Q);
|
nickinfo.add(P_PROPERTIES, Q);
|
||||||
|
wunlock();
|
||||||
out.println("OK Nickname set to " + Arg);
|
out.println("OK Nickname set to " + Arg);
|
||||||
} else {
|
} else {
|
||||||
out.println("ERROR tunnel is active");
|
out.println("ERROR tunnel is active");
|
||||||
@ -429,9 +516,13 @@ public class doCMDS implements Runnable {
|
|||||||
} else {
|
} else {
|
||||||
String pname = otoken.nextToken();
|
String pname = otoken.nextToken();
|
||||||
String pval = otoken.nextToken();
|
String pval = otoken.nextToken();
|
||||||
|
rlock();
|
||||||
Properties Q = (Properties)nickinfo.get(P_PROPERTIES);
|
Properties Q = (Properties)nickinfo.get(P_PROPERTIES);
|
||||||
|
runlock();
|
||||||
Q.setProperty(pname, pval);
|
Q.setProperty(pname, pval);
|
||||||
|
wlock();
|
||||||
nickinfo.add(P_PROPERTIES, Q);
|
nickinfo.add(P_PROPERTIES, Q);
|
||||||
|
wunlock();
|
||||||
out.println("OK " + pname + " set to " + pval);
|
out.println("OK " + pname + " set to " + pval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -440,16 +531,20 @@ public class doCMDS implements Runnable {
|
|||||||
}
|
}
|
||||||
} else if(Command.equals(C_getnick)) {
|
} else if(Command.equals(C_getnick)) {
|
||||||
// Get the nickname to work with...
|
// Get the nickname to work with...
|
||||||
|
database.getReadLock();
|
||||||
try {
|
try {
|
||||||
nickinfo = (nickname)database.get(Arg);
|
nickinfo = (nickname)database.get(Arg);
|
||||||
ns = true;
|
ns = true;
|
||||||
} catch(RuntimeException b) {
|
} catch(RuntimeException b) {
|
||||||
nns(out);
|
nns(out);
|
||||||
}
|
}
|
||||||
|
database.releaseReadLock();
|
||||||
if(ns) {
|
if(ns) {
|
||||||
|
rlock();
|
||||||
dk = nickinfo.exists(P_KEYS);
|
dk = nickinfo.exists(P_KEYS);
|
||||||
ip = nickinfo.exists(P_INPORT);
|
ip = nickinfo.exists(P_INPORT);
|
||||||
op = nickinfo.exists(P_OUTPORT);
|
op = nickinfo.exists(P_OUTPORT);
|
||||||
|
runlock();
|
||||||
// Finally say OK.
|
// Finally say OK.
|
||||||
out.println("OK Nickname set to " + Arg);
|
out.println("OK Nickname set to " + Arg);
|
||||||
}
|
}
|
||||||
@ -461,6 +556,7 @@ public class doCMDS implements Runnable {
|
|||||||
out.println("ERROR tunnel is active");
|
out.println("ERROR tunnel is active");
|
||||||
} else {
|
} else {
|
||||||
int prt;
|
int prt;
|
||||||
|
wlock();
|
||||||
nickinfo.kill(P_INPORT);
|
nickinfo.kill(P_INPORT);
|
||||||
try {
|
try {
|
||||||
prt = Integer.parseInt(Arg);
|
prt = Integer.parseInt(Arg);
|
||||||
@ -470,7 +566,10 @@ public class doCMDS implements Runnable {
|
|||||||
} catch(NumberFormatException nfe) {
|
} catch(NumberFormatException nfe) {
|
||||||
out.println("ERROR not a number");
|
out.println("ERROR not a number");
|
||||||
}
|
}
|
||||||
|
wunlock();
|
||||||
|
rlock();
|
||||||
ip = nickinfo.exists(P_INPORT);
|
ip = nickinfo.exists(P_INPORT);
|
||||||
|
runlock();
|
||||||
if(ip) {
|
if(ip) {
|
||||||
out.println("OK inbound port set");
|
out.println("OK inbound port set");
|
||||||
} else {
|
} else {
|
||||||
@ -488,6 +587,7 @@ public class doCMDS implements Runnable {
|
|||||||
out.println("ERROR tunnel is active");
|
out.println("ERROR tunnel is active");
|
||||||
} else {
|
} else {
|
||||||
int prt;
|
int prt;
|
||||||
|
wlock();
|
||||||
nickinfo.kill(P_OUTPORT);
|
nickinfo.kill(P_OUTPORT);
|
||||||
try {
|
try {
|
||||||
prt = Integer.parseInt(Arg);
|
prt = Integer.parseInt(Arg);
|
||||||
@ -497,7 +597,10 @@ public class doCMDS implements Runnable {
|
|||||||
} catch(NumberFormatException nfe) {
|
} catch(NumberFormatException nfe) {
|
||||||
out.println("ERROR not a number");
|
out.println("ERROR not a number");
|
||||||
}
|
}
|
||||||
|
wunlock();
|
||||||
|
rlock();
|
||||||
ip = nickinfo.exists(P_OUTPORT);
|
ip = nickinfo.exists(P_OUTPORT);
|
||||||
|
runlock();
|
||||||
if(ip) {
|
if(ip) {
|
||||||
out.println("OK outbound port set");
|
out.println("OK outbound port set");
|
||||||
} else {
|
} else {
|
||||||
@ -512,7 +615,9 @@ public class doCMDS implements Runnable {
|
|||||||
if(tunnelactive(nickinfo)) {
|
if(tunnelactive(nickinfo)) {
|
||||||
out.println("ERROR tunnel is active");
|
out.println("ERROR tunnel is active");
|
||||||
} else {
|
} else {
|
||||||
|
wlock();
|
||||||
nickinfo.add(P_INHOST, Arg);
|
nickinfo.add(P_INHOST, Arg);
|
||||||
|
wunlock();
|
||||||
out.println("OK inhost set");
|
out.println("OK inhost set");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -523,7 +628,9 @@ public class doCMDS implements Runnable {
|
|||||||
if(tunnelactive(nickinfo)) {
|
if(tunnelactive(nickinfo)) {
|
||||||
out.println("ERROR tunnel is active");
|
out.println("ERROR tunnel is active");
|
||||||
} else {
|
} else {
|
||||||
|
wlock();
|
||||||
nickinfo.add(P_OUTHOST, Arg);
|
nickinfo.add(P_OUTHOST, Arg);
|
||||||
|
wunlock();
|
||||||
out.println("OK outhost set");
|
out.println("OK outhost set");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -533,7 +640,9 @@ public class doCMDS implements Runnable {
|
|||||||
// Get the current nickname properties
|
// Get the current nickname properties
|
||||||
if(ns) {
|
if(ns) {
|
||||||
out.print("OK");
|
out.print("OK");
|
||||||
|
rlock();
|
||||||
nickprint(out, nickinfo);
|
nickprint(out, nickinfo);
|
||||||
|
runlock();
|
||||||
} else {
|
} else {
|
||||||
nns(out);
|
nns(out);
|
||||||
}
|
}
|
||||||
@ -545,9 +654,8 @@ public class doCMDS implements Runnable {
|
|||||||
} else {
|
} else {
|
||||||
MUXlisten tunnel;
|
MUXlisten tunnel;
|
||||||
try {
|
try {
|
||||||
tunnel = new MUXlisten(nickinfo, _log);
|
tunnel = new MUXlisten(database, nickinfo, _log);
|
||||||
Thread t = new Thread(tunnel);
|
Thread t = new Thread(tunnel);
|
||||||
nickinfo.add(P_STARTING, Boolean.TRUE);
|
|
||||||
t.start();
|
t.start();
|
||||||
out.println("OK tunnel starting");
|
out.println("OK tunnel starting");
|
||||||
} catch(I2PException e) {
|
} catch(I2PException e) {
|
||||||
@ -562,10 +670,15 @@ public class doCMDS implements Runnable {
|
|||||||
} else if(Command.equals(C_stop)) {
|
} else if(Command.equals(C_stop)) {
|
||||||
// Stop the tunnel, if it is running
|
// Stop the tunnel, if it is running
|
||||||
if(ns) {
|
if(ns) {
|
||||||
if(nickinfo.get(P_RUNNING).equals(Boolean.TRUE) && nickinfo.get(P_STOPPING).equals(Boolean.FALSE)) {
|
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);
|
nickinfo.add(P_STOPPING, Boolean.TRUE);
|
||||||
|
wunlock();
|
||||||
out.println("OK tunnel stopping");
|
out.println("OK tunnel stopping");
|
||||||
} else {
|
} else {
|
||||||
|
runlock();
|
||||||
out.println("ERROR tunnel is inactive");
|
out.println("ERROR tunnel is inactive");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -577,7 +690,9 @@ public class doCMDS implements Runnable {
|
|||||||
if(tunnelactive(nickinfo)) {
|
if(tunnelactive(nickinfo)) {
|
||||||
out.println("ERROR tunnel is active");
|
out.println("ERROR tunnel is active");
|
||||||
} else {
|
} else {
|
||||||
|
database.getWriteLock();
|
||||||
database.kill(nickinfo.get(P_NICKNAME));
|
database.kill(nickinfo.get(P_NICKNAME));
|
||||||
|
database.releaseWriteLock();
|
||||||
dk = ns = ip = op = false;
|
dk = ns = ip = op = false;
|
||||||
out.println("OK cleared");
|
out.println("OK cleared");
|
||||||
}
|
}
|
||||||
@ -588,7 +703,7 @@ public class doCMDS implements Runnable {
|
|||||||
if(database.exists(Arg)) {
|
if(database.exists(Arg)) {
|
||||||
// Show status of a nickname
|
// Show status of a nickname
|
||||||
out.print("OK ");
|
out.print("OK ");
|
||||||
ttlpnt(out, database, Arg);
|
ttlpnt(out, Arg);
|
||||||
} else {
|
} else {
|
||||||
nns(out);
|
nns(out);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
*
|
*
|
||||||
* ...for any additional details and liscense questions.
|
* ...for any additional details and liscense questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.i2p.BOB;
|
package net.i2p.BOB;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,17 +28,54 @@ package net.i2p.BOB;
|
|||||||
*
|
*
|
||||||
* @author sponge
|
* @author sponge
|
||||||
*/
|
*/
|
||||||
public class nickname {
|
public class nickname {
|
||||||
|
|
||||||
private Object[][] data;
|
|
||||||
private int index = 0;
|
|
||||||
|
|
||||||
|
private static final int maxWritersWaiting = 2;
|
||||||
|
private volatile Object[][] data;
|
||||||
|
private volatile int index, writersWaiting, readers;
|
||||||
|
private volatile boolean writingInProgress;
|
||||||
/**
|
/**
|
||||||
* make initial NULL object
|
* make initial NULL object
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public nickname() {
|
public nickname() {
|
||||||
data = new Object[1][2];
|
this.data = new Object[1][2];
|
||||||
|
this.index = this.writersWaiting = this.readers = 0;
|
||||||
|
this.writingInProgress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public void getReadLock() {
|
||||||
|
while(writingInProgress | (writersWaiting >= maxWritersWaiting)) {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch(InterruptedException ie) {
|
||||||
|
}
|
||||||
|
readers++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public void releaseReadLock() {
|
||||||
|
readers--;
|
||||||
|
if((readers == 0) & (writersWaiting > 0)) {
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public void getWriteLock() {
|
||||||
|
writersWaiting++;
|
||||||
|
while((readers > 0) | writingInProgress) {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch(InterruptedException ie) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writersWaiting--;
|
||||||
|
writingInProgress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public void releaseWriteLock() {
|
||||||
|
writingInProgress = false;
|
||||||
|
notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,7 +110,7 @@ public class nickname {
|
|||||||
}
|
}
|
||||||
olddata = new Object[index + 2][2];
|
olddata = new Object[index + 2][2];
|
||||||
// copy to olddata, skipping 'k'
|
// copy to olddata, skipping 'k'
|
||||||
for(i = 0 , l = 0; l < index; i++, l++) {
|
for(i = 0 , l = 0; l < index; i++, l++) {
|
||||||
if(i == k) {
|
if(i == k) {
|
||||||
l++;
|
l++;
|
||||||
didsomething++;
|
didsomething++;
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
2008-10-09 sponge
|
||||||
|
* Update version to -3
|
||||||
|
* BOB database threadlocking fixes
|
||||||
|
|
||||||
2008-10-08 sponge
|
2008-10-08 sponge
|
||||||
* Update version to -2
|
* Update version to -2
|
||||||
* Bugfixes and additions to BOB
|
* Bugfixes and additions to BOB
|
||||||
|
@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
|
|||||||
public class RouterVersion {
|
public class RouterVersion {
|
||||||
public final static String ID = "$Revision: 1.548 $ $Date: 2008-06-07 23:00:00 $";
|
public final static String ID = "$Revision: 1.548 $ $Date: 2008-06-07 23:00:00 $";
|
||||||
public final static String VERSION = "0.6.4";
|
public final static String VERSION = "0.6.4";
|
||||||
public final static long BUILD = 2;
|
public final static long BUILD = 3;
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||||
System.out.println("Router ID: " + RouterVersion.ID);
|
System.out.println("Router ID: " + RouterVersion.ID);
|
||||||
|
Reference in New Issue
Block a user