* ministreaming:

- small pedantic fix
    * streaming:
      - Fix a deadly race condition.
      - Some small pedantic fixes.
    * core:
      - Fix a deadly race condition.
    * BOB:
      - Fixed some races that occured from fixing races in streaming and core.
      - Some badly needed code refactoring to depend less on the database.
This commit is contained in:
sponge
2009-07-16 03:03:33 +00:00
parent 5d40ad1749
commit 5106c37ac4
18 changed files with 1157 additions and 1078 deletions

View File

@@ -1,7 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/1">
<file>file:/root/NetBeansProjects/i2p.i2p/apps/BOB/src/net/i2p/BOB/I2PtoTCP.java</file>
</open-files>
</project-private>

View File

@@ -166,6 +166,7 @@ public class BOB {
public static void stop() {
spin.set(false);
}
/**
* Listen for incoming connections and handle them
*
@@ -189,8 +190,9 @@ public class BOB {
try {
{
File cfg = new File(configLocation);
if (!cfg.isAbsolute())
if (!cfg.isAbsolute()) {
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
}
try {
FileInputStream fi = new FileInputStream(cfg);
props.load(fi);
@@ -234,8 +236,9 @@ public class BOB {
}
if (save) {
File cfg = new File(configLocation);
if (!cfg.isAbsolute())
if (!cfg.isAbsolute()) {
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
}
try {
warn("Writing new defaults file " + cfg.getAbsolutePath());
FileOutputStream fo = new FileOutputStream(cfg);

View File

@@ -36,6 +36,9 @@ import net.i2p.I2PException;
import net.i2p.client.I2PClientFactory;
import net.i2p.data.Destination;
import net.i2p.util.Log;
// needed only for debugging.
// import java.util.logging.Level;
// import java.util.logging.Logger;
/**
* Simplistic command parser for BOB
@@ -47,7 +50,7 @@ public class DoCMDS implements Runnable {
// FIX ME
// I need a better way to do versioning, but this will do for now.
public static final String BMAJ = "00", BMIN = "00", BREV = "07", BEXT = "";
public static final String BMAJ = "00", BMIN = "00", BREV = "08", BEXT = "";
public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT;
private Socket server;
private Properties props;
@@ -404,7 +407,7 @@ public class DoCMDS implements Runnable {
*/
public void run() {
dk = ns = ip = op = false;
try {
try {
// Get input from the client
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
@@ -1444,10 +1447,17 @@ public class DoCMDS implements Runnable {
out.println("OK Bye!");
server.close();
} catch (IOException ioe) {
BOB.warn("IOException on socket listen: " + ioe);
ioe.printStackTrace();
// not really needed, except to debug.
// BOB.warn("IOException on socket listen: " + ioe);
// ioe.printStackTrace();
}
} finally {
try {
server.close();
} catch (IOException ex) {
// nop
}
}
}
// Debugging... None of this is normally used.

View File

@@ -25,6 +25,7 @@ package net.i2p.BOB;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocket;
@@ -43,6 +44,7 @@ public class I2Plistener implements Runnable {
// private int tgwatch;
public I2PSocketManager socketManager;
public I2PServerSocket serverSocket;
private AtomicBoolean lives;
/**
* Constructor
@@ -52,13 +54,14 @@ public class I2Plistener implements Runnable {
* @param database
* @param _log
*/
I2Plistener(I2PServerSocket SS, I2PSocketManager S, NamedDB info, NamedDB database, Log _log) {
I2Plistener(I2PServerSocket SS, I2PSocketManager S, NamedDB info, NamedDB database, Log _log, AtomicBoolean lives) {
this.database = database;
this.info = info;
this._log = _log;
this.socketManager = S;
serverSocket = SS;
this.serverSocket = SS;
// tgwatch = 1;
this.lives = lives;
}
private void rlock() throws Exception {
@@ -82,27 +85,10 @@ public class I2Plistener implements Runnable {
try {
die:
{
try {
serverSocket.setSoTimeout(50);
boolean spin = true;
while (spin) {
try {
rlock();
} catch (Exception e) {
break die;
}
try {
spin = info.get("RUNNING").equals(Boolean.TRUE);
} catch (Exception e) {
try {
runlock();
} catch (Exception e2) {
break die;
}
break die;
}
try {
while (lives.get()) {
try {
sessSocket = serverSocket.accept();
g = true;
@@ -115,14 +101,15 @@ public class I2Plistener implements Runnable {
g = false;
conn++;
// toss the connection to a new thread.
I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database);
I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database, lives);
Thread t = new Thread(conn_c, Thread.currentThread().getName() + " I2PtoTCP " + conn);
t.start();
}
} catch (Exception e) {
// System.out.println("Exception " + e);
}
} catch (I2PException e) {
// bad shit
System.out.println("Exception " + e);
}
}
} finally {

View File

@@ -26,6 +26,7 @@ package net.i2p.BOB;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicBoolean;
import net.i2p.client.streaming.I2PSocket;
/**
@@ -38,6 +39,7 @@ public class I2PtoTCP implements Runnable {
private I2PSocket I2P;
private NamedDB info, database;
private Socket sock;
private AtomicBoolean lives;
/**
* Constructor
@@ -46,10 +48,11 @@ public class I2PtoTCP implements Runnable {
* @param info
* @param database
*/
I2PtoTCP(I2PSocket I2Psock, NamedDB info, NamedDB database) {
I2PtoTCP(I2PSocket I2Psock, NamedDB info, NamedDB database, AtomicBoolean lives) {
this.I2P = I2Psock;
this.info = info;
this.database = database;
this.lives = lives;
}
private void rlock() {
@@ -113,35 +116,19 @@ public class I2PtoTCP implements Runnable {
out.flush(); // not really needed, but...
}
// setup to cross the streams
TCPio conn_c = new TCPio(in, Iout /*, info, database */); // app -> I2P
TCPio conn_a = new TCPio(Iin, out /* , info, database */); // I2P -> app
TCPio conn_c = new TCPio(in, Iout, lives); // app -> I2P
TCPio conn_a = new TCPio(Iin, out, lives); // I2P -> app
t = new Thread(conn_c, Thread.currentThread().getName() + " TCPioA");
q = new Thread(conn_a, Thread.currentThread().getName() + " TCPioB");
// Fire!
t.start();
q.start();
boolean spin = true;
while (t.isAlive() && q.isAlive() && spin) { // AND is used here to kill off the other thread
while (t.isAlive() && q.isAlive() && lives.get()) { // AND is used here to kill off the other thread
try {
Thread.sleep(10); //sleep for 10 ms
} catch (InterruptedException e) {
break die;
}
try {
rlock();
} catch (Exception e) {
break die;
}
try {
spin = info.get("RUNNING").equals(Boolean.TRUE);
} catch (Exception e) {
try {
runlock();
} catch (Exception e2) {
break die;
}
break die;
}
}
// System.out.println("I2PtoTCP: Going away...");
} catch (Exception e) {
@@ -150,14 +137,6 @@ public class I2PtoTCP implements Runnable {
}
} // die
} finally {
try {
t.interrupt();
} catch (Exception e) {
}
try {
q.interrupt();
} catch (Exception e) {
}
try {
in.close();
} catch (Exception ex) {
@@ -174,6 +153,14 @@ public class I2PtoTCP implements Runnable {
Iout.close();
} catch (Exception ex) {
}
try {
t.interrupt();
} catch (Exception e) {
}
try {
q.interrupt();
} catch (Exception e) {
}
try {
// System.out.println("I2PtoTCP: Close I2P");
I2P.close();

View File

@@ -54,6 +54,7 @@ public class MUXlisten implements Runnable {
boolean go_out;
boolean come_in;
private AtomicBoolean lock;
private AtomicBoolean lives;
/**
* Constructor Will fail if INPORT is occupied.
@@ -65,6 +66,7 @@ public class MUXlisten implements Runnable {
* @throws java.io.IOException
*/
MUXlisten(AtomicBoolean lock, NamedDB database, NamedDB info, Log _log) throws I2PException, IOException, RuntimeException {
try {
int port = 0;
InetAddress host = null;
this.lock = lock;
@@ -72,9 +74,16 @@ public class MUXlisten implements Runnable {
this.database = database;
this.info = info;
this._log = _log;
lives = new AtomicBoolean(false);
this.database.getWriteLock();
this.info.getWriteLock();
this.info.add("STARTING", new Boolean(true));
this.info.releaseWriteLock();
this.database.releaseWriteLock();
this.database.getReadLock();
this.info.getReadLock();
N = this.info.get("NICKNAME").toString();
prikey = new ByteArrayInputStream((byte[]) info.get("KEYS"));
// Make a new copy so that anything else won't muck with our database.
@@ -99,13 +108,44 @@ public class MUXlisten implements Runnable {
if (this.come_in) {
this.listener = new ServerSocket(port, backlog, host);
}
// Everything is OK as far as we can tell.
// I2PException, IOException, RuntimeException
// To bad we can't just catch and enumerate....
// } catch (I2PException e) {
// Something went bad.
// this.database.getWriteLock();
// this.info.getWriteLock();
// this.info.add("STARTING", new Boolean(false));
// this.info.releaseWriteLock();
// this.database.releaseWriteLock();
// throw new I2PException(e);
} catch (IOException e) {
// Something went bad.
this.database.getWriteLock();
this.info.getWriteLock();
this.info.add("STARTING", new Boolean(true));
this.info.add("STARTING", new Boolean(false));
this.info.releaseWriteLock();
this.database.releaseWriteLock();
throw new IOException(e);
} catch (RuntimeException e) {
// Something went bad.
this.database.getWriteLock();
this.info.getWriteLock();
this.info.add("STARTING", new Boolean(false));
this.info.releaseWriteLock();
this.database.releaseWriteLock();
throw new RuntimeException(e);
} catch (Exception e) {
// Something else went bad.
this.database.getWriteLock();
this.info.getWriteLock();
this.info.add("STARTING", new Boolean(false));
this.info.releaseWriteLock();
this.database.releaseWriteLock();
// throw new Exception(e);
// Debugging, I guess.
e.printStackTrace();
throw new RuntimeException(e);
}
}
private void rlock() throws Exception {
@@ -142,18 +182,22 @@ public class MUXlisten implements Runnable {
try {
info.add("RUNNING", new Boolean(true));
} catch (Exception e) {
lock.set(false);
wunlock();
return;
}
} catch (Exception e) {
lock.set(false);
return;
}
try {
wunlock();
} catch (Exception e) {
lock.set(false);
return;
}
// socketManager.addDisconnectListener(new DisconnectListener());
lives.set(true);
lock.set(false);
quit:
{
@@ -166,14 +210,14 @@ public class MUXlisten implements Runnable {
if (go_out) {
// I2P -> TCP
SS = socketManager.getServerSocket();
I2Plistener conn = new I2Plistener(SS, socketManager, info, database, _log);
I2Plistener conn = new I2Plistener(SS, socketManager, info, database, _log, lives);
t = new Thread(tg, conn, "BOBI2Plistener " + N);
t.start();
}
if (come_in) {
// TCP -> I2P
TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log);
TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log, lives);
q = new Thread(tg, conn, "BOBTCPlistener " + N);
q.start();
}
@@ -195,7 +239,7 @@ public class MUXlisten implements Runnable {
break quit;
}
boolean spin = true;
while (spin) {
while (spin && lives.get()) {
try {
Thread.sleep(1000); //sleep for 1 second
} catch (InterruptedException e) {
@@ -226,26 +270,30 @@ public class MUXlisten implements Runnable {
}
} // quit
} finally {
// Start cleanup.
while (!lock.compareAndSet(false, true)) {
// wait
lives.set(false);
// Some grace time.
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
// zero out everything.
try {
wlock();
try {
info.add("STARTING", new Boolean(false));
info.add("STOPPING", new Boolean(false));
info.add("STOPPING", new Boolean(true));
info.add("RUNNING", new Boolean(false));
} catch (Exception e) {
lock.set(false);
wunlock();
return;
}
wunlock();
} catch (Exception e) {
}
// Start cleanup.
while (!lock.compareAndSet(false, true)) {
// wait
}
if (SS != null) {
try {
SS.close();
@@ -261,11 +309,28 @@ public class MUXlisten implements Runnable {
// Some grace time.
try {
Thread.sleep(250);
Thread.sleep(100);
} catch (InterruptedException ex) {
}
// zero out everything.
try {
wlock();
try {
info.add("STARTING", new Boolean(false));
info.add("STOPPING", new Boolean(false));
info.add("RUNNING", new Boolean(false));
} catch (Exception e) {
lock.set(false);
wunlock();
return;
}
wunlock();
} catch (Exception e) {
}
lock.set(false); // Should we force waiting for all threads??
// Wait around till all threads are collected.
if (tg != null) {
String boner = tg.getName();
@@ -276,7 +341,7 @@ public class MUXlisten implements Runnable {
// visit(tg, 0, boner);
int foo = tg.activeCount() + tg.activeGroupCount();
// hopefully no longer needed!
// int bar = foo;
// int bar = lives;
// System.out.println("BOB: MUXlisten: Waiting on threads for " + boner);
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
// visit(tg, 0, boner);
@@ -284,12 +349,12 @@ public class MUXlisten implements Runnable {
// Happily spin forever :-(
while (foo != 0) {
foo = tg.activeCount() + tg.activeGroupCount();
// if (foo != bar && foo != 0) {
// if (lives != bar && lives != 0) {
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
// visit(tg, 0, boner);
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n");
// }
// bar = foo;
// bar = lives;
try {
Thread.sleep(100); //sleep for 100 ms (One tenth second)
} catch (InterruptedException ex) {
@@ -356,5 +421,4 @@ public class MUXlisten implements Runnable {
visit(groups[i], level + 1, groups[i].getName());
}
}
}

View File

@@ -26,6 +26,7 @@ package net.i2p.BOB;
import net.i2p.client.streaming.RetransmissionTimer;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer2;
/**
* Start from command line
*

View File

@@ -26,6 +26,7 @@ package net.i2p.BOB;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Shove data from one stream to the other.
@@ -36,7 +37,7 @@ public class TCPio implements Runnable {
private InputStream Ain;
private OutputStream Aout;
// private NamedDB info, database;
private AtomicBoolean lives;
/**
* Constructor
@@ -46,11 +47,10 @@ public class TCPio implements Runnable {
*
* param database
*/
TCPio(InputStream Ain, OutputStream Aout /*, NamedDB info , NamedDB database */) {
TCPio(InputStream Ain, OutputStream Aout, AtomicBoolean lives) {
this.Ain = Ain;
this.Aout = Aout;
// this.info = info;
// this.database = database;
this.lives = lives;
}
/**
@@ -84,10 +84,9 @@ public class TCPio implements Runnable {
int b;
byte a[] = new byte[1];
boolean spin = true;
try {
try {
while (spin) {
while (lives.get()) {
b = Ain.read(a, 0, 1);
if (b > 0) {
Aout.write(a, 0, b);
@@ -105,9 +104,6 @@ public class TCPio implements Runnable {
*
*/
// System.out.println("TCPio: End Of Stream");
// Ain.close();
// Aout.close();
//return;
break;
}
}

View File

@@ -29,6 +29,7 @@ import java.net.Socket;
import java.net.SocketTimeoutException;
// import net.i2p.client.I2PSession;
// import net.i2p.client.I2PSessionException;
import java.util.concurrent.atomic.AtomicBoolean;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.util.Log;
@@ -45,6 +46,7 @@ public class TCPlistener implements Runnable {
public I2PSocketManager socketManager;
public I2PServerSocket serverSocket;
private ServerSocket listener;
private AtomicBoolean lives;
/**
* Constructor
@@ -53,12 +55,13 @@ public class TCPlistener implements Runnable {
* @param database
* @param _log
*/
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Log _log) {
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Log _log, AtomicBoolean lives) {
this.database = database;
this.info = info;
this._log = _log;
this.socketManager = S;
this.listener = listener;
this.lives = lives;
}
private void rlock() throws Exception {
@@ -77,7 +80,6 @@ public class TCPlistener implements Runnable {
*/
public void run() {
boolean g = false;
boolean spin = true;
int conn = 0;
try {
die:
@@ -85,22 +87,7 @@ public class TCPlistener implements Runnable {
try {
Socket server = new Socket();
listener.setSoTimeout(50); // We don't block, we cycle and check.
while (spin) {
try {
rlock();
} catch (Exception e) {
break die;
}
try {
spin = info.get("RUNNING").equals(Boolean.TRUE);
} catch (Exception e) {
try {
runlock();
} catch (Exception e2) {
break die;
}
break die;
}
while (lives.get()) {
try {
server = listener.accept();
g = true;
@@ -110,7 +97,7 @@ public class TCPlistener implements Runnable {
if (g) {
conn++;
// toss the connection to a new thread.
TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info, database);
TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info, database, lives);
Thread t = new Thread(conn_c, Thread.currentThread().getName() + " TCPtoI2P " + conn);
t.start();
g = false;

View File

@@ -30,6 +30,7 @@ import java.io.OutputStream;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicBoolean;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
@@ -49,6 +50,7 @@ public class TCPtoI2P implements Runnable {
private NamedDB info, database;
private Socket sock;
private I2PSocketManager socketManager;
private AtomicBoolean lives;
/**
* Constructor
@@ -57,11 +59,12 @@ public class TCPtoI2P implements Runnable {
* param info
* param database
*/
TCPtoI2P(I2PSocketManager i2p, Socket socket , NamedDB info, NamedDB database) {
TCPtoI2P(I2PSocketManager i2p, Socket socket, NamedDB info, NamedDB database, AtomicBoolean lives) {
this.sock = socket;
this.info = info;
this.database = database;
this.socketManager = i2p;
this.lives = lives;
}
/**
@@ -157,19 +160,15 @@ public class TCPtoI2P implements Runnable {
Iin = I2P.getInputStream();
Iout = I2P.getOutputStream();
// setup to cross the streams
TCPio conn_c = new TCPio(in, Iout /*, info, database */); // app -> I2P
TCPio conn_a = new TCPio(Iin, out /*, info, database */); // I2P -> app
TCPio conn_c = new TCPio(in, Iout, lives); // app -> I2P
TCPio conn_a = new TCPio(Iin, out, lives); // I2P -> app
t = new Thread(conn_c, Thread.currentThread().getName() + " TCPioA");
q = new Thread(conn_a, Thread.currentThread().getName() + " TCPioB");
// Fire!
t.start();
q.start();
boolean spin = true;
while (t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread
while (t.isAlive() && q.isAlive() && lives.get()) { // AND is used here to kill off the other thread
Thread.sleep(10); //sleep for 10 ms
rlock();
spin = info.get("RUNNING").equals(Boolean.TRUE);
runlock();
}
} catch (I2PException e) {
Emsg(e.toString(), out);

View File

@@ -20,15 +20,15 @@ class I2PServerSocketImpl implements I2PServerSocket {
private final static Log _log = new Log(I2PServerSocketImpl.class);
private I2PSocketManager mgr;
/** list of sockets waiting for the client to accept them */
private List<I2PSocket> pendingSockets = Collections.synchronizedList(new ArrayList<I2PSocket>(4));
private final List<I2PSocket> pendingSockets = Collections.synchronizedList(new ArrayList<I2PSocket>(4));
/** have we been closed */
private volatile boolean closing = false;
/** lock on this when accepting a pending socket, and wait on it for notification of acceptance */
private Object socketAcceptedLock = new Object();
private final Object socketAcceptedLock = new Object();
/** lock on this when adding a new socket to the pending list, and wait on it accordingly */
private Object socketAddedLock = new Object();
private final Object socketAddedLock = new Object();
/**
* Set Sock Option accept timeout stub, does nothing in ministreaming

View File

@@ -40,15 +40,15 @@ import net.i2p.util.Log;
class I2PSocketManagerImpl implements I2PSocketManager, I2PSessionListener {
private I2PAppContext _context;
private Log _log;
private I2PSession _session;
private /* final */ I2PSession _session;
private I2PServerSocketImpl _serverSocket = null;
private Object lock = new Object(); // for locking socket lists
private final Object lock = new Object(); // for locking socket lists
private HashMap<String,I2PSocket> _outSockets;
private HashMap<String,I2PSocket> _inSockets;
private I2PSocketOptions _defaultOptions;
private long _acceptTimeout;
private String _name;
private List<DisconnectListener> _listeners;
private final List<DisconnectListener> _listeners = new ArrayList<DisconnectListener>(1);;
private static int __managerId = 0;
public static final short ACK = 0x51;
@@ -79,7 +79,7 @@ class I2PSocketManagerImpl implements I2PSocketManager, I2PSessionListener {
_inSockets = new HashMap<String,I2PSocket>(16);
_outSockets = new HashMap<String,I2PSocket>(16);
_acceptTimeout = ACCEPT_TIMEOUT_DEFAULT;
_listeners = new ArrayList<DisconnectListener>(1);
// _listeners = new ArrayList<DisconnectListener>(1);
setSession(session);
setDefaultOptions(buildOptions(opts));
_context.statManager().createRateStat("streaming.lifetime", "How long before the socket is closed?", "streaming", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });

View File

@@ -230,8 +230,8 @@ public class I2PSocketManagerFull implements I2PSocketManager {
*
*/
public void destroySocketManager() {
_connectionManager.disconnectAllHard();
_connectionManager.setAllowIncomingConnections(false);
_connectionManager.disconnectAllHard();
// should we destroy the _session too?
// yes, since the old lib did (and SAM wants it to, and i dont know why not)
if ( (_session != null) && (!_session.isClosed()) ) {

View File

@@ -102,6 +102,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
/** lock that we wait upon, that the SetDateMessageHandler notifies */
private final Object _dateReceivedLock = new Object();
/** whether the session connection is in the process of being opened */
protected boolean _opening;
/** monitor for waiting until opened */
private final Object _openingWait = new Object();
/**
* thread that we tell when new messages are available who then tells us
* to fetch them. The point of this is so that the fetch doesn't block the
@@ -136,6 +141,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
_log = context.logManager().getLog(I2PSessionImpl.class);
_handlerMap = new I2PClientMessageHandlerMap(context);
_closed = true;
_opening = false;
_closing = false;
_producer = new I2CPMessageProducer(context);
_availabilityNotifier = new AvailabilityNotifier();
@@ -212,6 +218,17 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
return _leaseSet;
}
void setOpening(boolean ls) {
_opening = ls;
synchronized (_openingWait) {
_openingWait.notifyAll();
}
}
boolean getOpening() {
return _opening;
}
/**
* Load up the destKeyFile for our Destination, PrivateKey, and SigningPrivateKey
*
@@ -235,6 +252,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* not reachable
*/
public void connect() throws I2PSessionException {
setOpening(true);
_closed = false;
_availabilityNotifier.stopNotifying();
I2PThread notifier = new I2PThread(_availabilityNotifier);
@@ -294,11 +312,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
+ (connected - startConnect)
+ "ms - ready to participate in the network!");
startIdleMonitor();
setOpening(false);
} catch (UnknownHostException uhe) {
_closed = true;
setOpening(false);
throw new I2PSessionException(getPrefix() + "Invalid session configuration", uhe);
} catch (IOException ioe) {
_closed = true;
setOpening(false);
throw new I2PSessionException(getPrefix() + "Problem connecting to " + _hostname + " on port " + _portNum, ioe);
}
}
@@ -547,13 +568,28 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
/**
* Tear down the session, and do NOT reconnect
* Tear down the session, and do NOT reconnect.
*
* Blocks if session has not been fully started.
*/
public void destroySession() {
destroySession(true);
}
/**
* Tear down the session, and do NOT reconnect.
*
* Blocks if session has not been fully started.
*/
public void destroySession(boolean sendDisconnect) {
while (_opening) {
synchronized (_openingWait) {
try {
_openingWait.wait(1000);
} catch (InterruptedException ie) { // nop
}
}
}
if (_closed) return;
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "Destroy the session", new Exception("DestroySession()"));

View File

@@ -1,3 +1,15 @@
2009-07-16 sponge
* ministreaming:
- small pedantic fix
* streaming:
- Fix a deadly race condition.
- Some small pedantic fixes.
* core:
- Fix a deadly race condition.
* BOB:
- Fixed some races that occured from fixing races in streaming and core.
- Some badly needed code refactoring to depend less on the database.
2009-07-15 zzz
* Console:
- Make light the default theme

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 12;
public final static long BUILD = 13;
/** for example "-test" */
public final static String EXTRA = "";
public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;