mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 22:59:54 +01:00
Interrupt the other side of a duplex connection if an exception occurs.
This commit is contained in:
@@ -25,8 +25,8 @@ public interface TransportConnectionReader {
|
|||||||
* the connection has been marked as closed.
|
* the connection has been marked as closed.
|
||||||
* @param exception true if the connection is being closed because of an
|
* @param exception true if the connection is being closed because of an
|
||||||
* exception. This may affect how resources are disposed of.
|
* exception. This may affect how resources are disposed of.
|
||||||
* @param recognised true if the pseudo-random tag was recognised. This may
|
* @param recognised true if the connection is definitely a Briar transport
|
||||||
* affect how resources are disposed of.
|
* connection. This may affect how resources are disposed of.
|
||||||
*/
|
*/
|
||||||
void dispose(boolean exception, boolean recognised) throws IOException;
|
void dispose(boolean exception, boolean recognised) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,88 +69,18 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
ioExecutor.execute(new DispatchOutgoingDuplexConnection(c, t, d));
|
ioExecutor.execute(new DispatchOutgoingDuplexConnection(c, t, d));
|
||||||
}
|
}
|
||||||
|
|
||||||
private StreamContext readAndRecogniseTag(TransportId t,
|
private byte[] readTag(TransportId t, TransportConnectionReader r)
|
||||||
TransportConnectionReader r) {
|
throws IOException {
|
||||||
// Read the tag
|
// Read the tag
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
try {
|
InputStream in = r.getInputStream();
|
||||||
InputStream in = r.getInputStream();
|
int offset = 0;
|
||||||
int offset = 0;
|
while(offset < tag.length) {
|
||||||
while(offset < tag.length) {
|
int read = in.read(tag, offset, tag.length - offset);
|
||||||
int read = in.read(tag, offset, tag.length - offset);
|
if(read == -1) throw new EOFException();
|
||||||
if(read == -1) throw new EOFException();
|
offset += read;
|
||||||
offset += read;
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
dispose(r, true, false);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// Recognise the tag
|
|
||||||
StreamContext ctx = null;
|
|
||||||
try {
|
|
||||||
ctx = tagRecogniser.recogniseTag(t, tag);
|
|
||||||
} catch(DbException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
dispose(r, true, false);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(ctx == null) dispose(r, false, false);
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runAndDispose(StreamContext ctx, TransportConnectionReader r) {
|
|
||||||
MessagingSession in =
|
|
||||||
messagingSessionFactory.createIncomingSession(ctx, r);
|
|
||||||
ContactId contactId = ctx.getContactId();
|
|
||||||
TransportId transportId = ctx.getTransportId();
|
|
||||||
connectionRegistry.registerConnection(contactId, transportId);
|
|
||||||
try {
|
|
||||||
in.run();
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
dispose(r, true, true);
|
|
||||||
return;
|
|
||||||
} finally {
|
|
||||||
connectionRegistry.unregisterConnection(contactId, transportId);
|
|
||||||
}
|
|
||||||
dispose(r, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dispose(TransportConnectionReader r, boolean exception,
|
|
||||||
boolean recognised) {
|
|
||||||
try {
|
|
||||||
r.dispose(exception, recognised);
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runAndDispose(StreamContext ctx, TransportConnectionWriter w,
|
|
||||||
boolean duplex) {
|
|
||||||
MessagingSession out =
|
|
||||||
messagingSessionFactory.createOutgoingSession(ctx, w, duplex);
|
|
||||||
ContactId contactId = ctx.getContactId();
|
|
||||||
TransportId transportId = ctx.getTransportId();
|
|
||||||
connectionRegistry.registerConnection(contactId, transportId);
|
|
||||||
try {
|
|
||||||
out.run();
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
dispose(w, true);
|
|
||||||
return;
|
|
||||||
} finally {
|
|
||||||
connectionRegistry.unregisterConnection(contactId, transportId);
|
|
||||||
}
|
|
||||||
dispose(w, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dispose(TransportConnectionWriter w, boolean exception) {
|
|
||||||
try {
|
|
||||||
w.dispose(exception);
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
}
|
||||||
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DispatchIncomingSimplexConnection implements Runnable {
|
private class DispatchIncomingSimplexConnection implements Runnable {
|
||||||
@@ -166,10 +96,46 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
// Read and recognise the tag
|
// Read and recognise the tag
|
||||||
StreamContext ctx = readAndRecogniseTag(transportId, reader);
|
StreamContext ctx;
|
||||||
if(ctx == null) return;
|
try {
|
||||||
|
byte[] tag = readTag(transportId, reader);
|
||||||
|
ctx = tagRecogniser.recogniseTag(transportId, tag);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeReader(true, false);
|
||||||
|
return;
|
||||||
|
} catch(DbException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeReader(true, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(ctx == null) {
|
||||||
|
LOG.info("Unrecognised tag");
|
||||||
|
disposeReader(true, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ContactId contactId = ctx.getContactId();
|
||||||
|
connectionRegistry.registerConnection(contactId, transportId);
|
||||||
// Run the incoming session
|
// Run the incoming session
|
||||||
runAndDispose(ctx, reader);
|
MessagingSession incomingSession =
|
||||||
|
messagingSessionFactory.createIncomingSession(ctx, reader);
|
||||||
|
try {
|
||||||
|
incomingSession.run();
|
||||||
|
disposeReader(false, true);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeReader(true, true);
|
||||||
|
} finally {
|
||||||
|
connectionRegistry.unregisterConnection(contactId, transportId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeReader(boolean exception, boolean recognised) {
|
||||||
|
try {
|
||||||
|
reader.dispose(exception, recognised);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,11 +157,32 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
StreamContext ctx = keyManager.getStreamContext(contactId,
|
StreamContext ctx = keyManager.getStreamContext(contactId,
|
||||||
transportId);
|
transportId);
|
||||||
if(ctx == null) {
|
if(ctx == null) {
|
||||||
dispose(writer, false);
|
LOG.warning("Could not allocate stream context");
|
||||||
|
disposeWriter(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
connectionRegistry.registerConnection(contactId, transportId);
|
||||||
// Run the outgoing session
|
// Run the outgoing session
|
||||||
runAndDispose(ctx, writer, false);
|
MessagingSession outgoingSession =
|
||||||
|
messagingSessionFactory.createOutgoingSession(ctx,
|
||||||
|
writer, false);
|
||||||
|
try {
|
||||||
|
outgoingSession.run();
|
||||||
|
disposeWriter(false);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeWriter(true);
|
||||||
|
} finally {
|
||||||
|
connectionRegistry.unregisterConnection(contactId, transportId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeWriter(boolean exception) {
|
||||||
|
try {
|
||||||
|
writer.dispose(exception);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +192,10 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
private final TransportConnectionReader reader;
|
private final TransportConnectionReader reader;
|
||||||
private final TransportConnectionWriter writer;
|
private final TransportConnectionWriter writer;
|
||||||
|
|
||||||
|
private volatile ContactId contactId = null;
|
||||||
|
private volatile MessagingSession incomingSession = null;
|
||||||
|
private volatile MessagingSession outgoingSession = null;
|
||||||
|
|
||||||
private DispatchIncomingDuplexConnection(TransportId transportId,
|
private DispatchIncomingDuplexConnection(TransportId transportId,
|
||||||
DuplexTransportConnection transport) {
|
DuplexTransportConnection transport) {
|
||||||
this.transportId = transportId;
|
this.transportId = transportId;
|
||||||
@@ -214,39 +205,85 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
// Read and recognise the tag
|
// Read and recognise the tag
|
||||||
StreamContext ctx = readAndRecogniseTag(transportId, reader);
|
StreamContext ctx;
|
||||||
if(ctx == null) return;
|
try {
|
||||||
|
byte[] tag = readTag(transportId, reader);
|
||||||
|
ctx = tagRecogniser.recogniseTag(transportId, tag);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeReader(true, false);
|
||||||
|
return;
|
||||||
|
} catch(DbException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeReader(true, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(ctx == null) {
|
||||||
|
LOG.info("Unrecognised tag");
|
||||||
|
disposeReader(true, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
contactId = ctx.getContactId();
|
||||||
|
connectionRegistry.registerConnection(contactId, transportId);
|
||||||
// Start the outgoing session on another thread
|
// Start the outgoing session on another thread
|
||||||
ioExecutor.execute(new DispatchIncomingDuplexConnectionSide2(
|
ioExecutor.execute(new Runnable() {
|
||||||
ctx.getContactId(), transportId, writer));
|
public void run() {
|
||||||
|
runOutgoingSession();
|
||||||
|
}
|
||||||
|
});
|
||||||
// Run the incoming session
|
// Run the incoming session
|
||||||
runAndDispose(ctx, reader);
|
incomingSession = messagingSessionFactory.createIncomingSession(ctx,
|
||||||
}
|
reader);
|
||||||
}
|
try {
|
||||||
|
incomingSession.run();
|
||||||
private class DispatchIncomingDuplexConnectionSide2 implements Runnable {
|
disposeReader(false, true);
|
||||||
|
} catch(IOException e) {
|
||||||
private final ContactId contactId;
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
private final TransportId transportId;
|
disposeReader(true, true);
|
||||||
private final TransportConnectionWriter writer;
|
} finally {
|
||||||
|
connectionRegistry.unregisterConnection(contactId, transportId);
|
||||||
private DispatchIncomingDuplexConnectionSide2(ContactId contactId,
|
}
|
||||||
TransportId transportId, TransportConnectionWriter writer) {
|
|
||||||
this.contactId = contactId;
|
|
||||||
this.transportId = transportId;
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
private void runOutgoingSession() {
|
||||||
// Allocate a stream context
|
// Allocate a stream context
|
||||||
StreamContext ctx = keyManager.getStreamContext(contactId,
|
StreamContext ctx = keyManager.getStreamContext(contactId,
|
||||||
transportId);
|
transportId);
|
||||||
if(ctx == null) {
|
if(ctx == null) {
|
||||||
dispose(writer, false);
|
LOG.warning("Could not allocate stream context");
|
||||||
|
disposeWriter(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Run the outgoing session
|
// Run the outgoing session
|
||||||
runAndDispose(ctx, writer, true);
|
outgoingSession = messagingSessionFactory.createOutgoingSession(ctx,
|
||||||
|
writer, true);
|
||||||
|
try {
|
||||||
|
outgoingSession.run();
|
||||||
|
disposeWriter(false);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeWriter(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeReader(boolean exception, boolean recognised) {
|
||||||
|
if(exception && outgoingSession != null)
|
||||||
|
outgoingSession.interrupt();
|
||||||
|
try {
|
||||||
|
reader.dispose(exception, recognised);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeWriter(boolean exception) {
|
||||||
|
if(exception && incomingSession != null)
|
||||||
|
incomingSession.interrupt();
|
||||||
|
try {
|
||||||
|
writer.dispose(exception);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,6 +294,9 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
private final TransportConnectionReader reader;
|
private final TransportConnectionReader reader;
|
||||||
private final TransportConnectionWriter writer;
|
private final TransportConnectionWriter writer;
|
||||||
|
|
||||||
|
private volatile MessagingSession incomingSession = null;
|
||||||
|
private volatile MessagingSession outgoingSession = null;
|
||||||
|
|
||||||
private DispatchOutgoingDuplexConnection(ContactId contactId,
|
private DispatchOutgoingDuplexConnection(ContactId contactId,
|
||||||
TransportId transportId, DuplexTransportConnection transport) {
|
TransportId transportId, DuplexTransportConnection transport) {
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
@@ -270,42 +310,88 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
StreamContext ctx = keyManager.getStreamContext(contactId,
|
StreamContext ctx = keyManager.getStreamContext(contactId,
|
||||||
transportId);
|
transportId);
|
||||||
if(ctx == null) {
|
if(ctx == null) {
|
||||||
dispose(writer, false);
|
LOG.warning("Could not allocate stream context");
|
||||||
|
disposeWriter(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
connectionRegistry.registerConnection(contactId, transportId);
|
||||||
// Start the incoming session on another thread
|
// Start the incoming session on another thread
|
||||||
ioExecutor.execute(new DispatchOutgoingDuplexConnectionSide2(
|
ioExecutor.execute(new Runnable() {
|
||||||
contactId, transportId, reader));
|
public void run() {
|
||||||
|
runIncomingSession();
|
||||||
|
}
|
||||||
|
});
|
||||||
// Run the outgoing session
|
// Run the outgoing session
|
||||||
runAndDispose(ctx, writer, true);
|
outgoingSession = messagingSessionFactory.createOutgoingSession(ctx,
|
||||||
}
|
writer, true);
|
||||||
}
|
try {
|
||||||
|
outgoingSession.run();
|
||||||
private class DispatchOutgoingDuplexConnectionSide2 implements Runnable {
|
disposeWriter(false);
|
||||||
|
} catch(IOException e) {
|
||||||
private final ContactId contactId;
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
private final TransportId transportId;
|
disposeWriter(true);
|
||||||
private final TransportConnectionReader reader;
|
} finally {
|
||||||
|
connectionRegistry.unregisterConnection(contactId, transportId);
|
||||||
private DispatchOutgoingDuplexConnectionSide2(ContactId contactId,
|
}
|
||||||
TransportId transportId, TransportConnectionReader reader) {
|
|
||||||
this.contactId = contactId;
|
|
||||||
this.transportId = transportId;
|
|
||||||
this.reader = reader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
private void runIncomingSession() {
|
||||||
// Read and recognise the tag
|
// Read and recognise the tag
|
||||||
StreamContext ctx = readAndRecogniseTag(transportId, reader);
|
StreamContext ctx;
|
||||||
if(ctx == null) return;
|
try {
|
||||||
|
byte[] tag = readTag(transportId, reader);
|
||||||
|
ctx = tagRecogniser.recogniseTag(transportId, tag);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeReader(true, true);
|
||||||
|
return;
|
||||||
|
} catch(DbException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeReader(true, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Unrecognised tags are suspicious in this case
|
||||||
|
if(ctx == null) {
|
||||||
|
LOG.warning("Unrecognised tag for returning stream");
|
||||||
|
disposeReader(true, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Check that the stream comes from the expected contact
|
// Check that the stream comes from the expected contact
|
||||||
if(!ctx.getContactId().equals(contactId)) {
|
if(!ctx.getContactId().equals(contactId)) {
|
||||||
LOG.warning("Wrong contact ID for duplex connection");
|
LOG.warning("Wrong contact ID for returning stream");
|
||||||
dispose(reader, true, true);
|
disposeReader(true, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Run the incoming session
|
// Run the incoming session
|
||||||
runAndDispose(ctx, reader);
|
incomingSession = messagingSessionFactory.createIncomingSession(ctx,
|
||||||
|
reader);
|
||||||
|
try {
|
||||||
|
incomingSession.run();
|
||||||
|
disposeReader(false, true);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
disposeReader(true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeReader(boolean exception, boolean recognised) {
|
||||||
|
if(exception && outgoingSession != null)
|
||||||
|
outgoingSession.interrupt();
|
||||||
|
try {
|
||||||
|
reader.dispose(exception, recognised);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeWriter(boolean exception) {
|
||||||
|
if(exception && incomingSession != null)
|
||||||
|
incomingSession.interrupt();
|
||||||
|
try {
|
||||||
|
writer.dispose(exception);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user