Commit 0d75703d authored by Guus der Kinderen's avatar Guus der Kinderen

OF-883: Prevent sending data to known disconnected peers.

By closing a session when the new MINA inputClosed() handler is triggered, we run
the risk of sending data to the peer. As that peer is known to be dead, this is
pointless (and potentially dangerous - deadlocks have been observed that are likely
related to this scenario).

To prevent sending data during session closure, the close() method has been
overloaded with an argument that indicates if the peer is known to be dead. When
set, its implementation will not attempt to send data.
parent 1b2dd66e
......@@ -144,9 +144,29 @@ public interface Connection {
* <li>Call notifyEvent all listeners that the channel is shutting down.
* <li>Close the socket.
* </ul>
*
* An invocation of this method is equal to invoking {@link #close(boolean)} with a parameter
* that is false.
*/
public void close();
/**
* Close this session including associated socket connection. The order of
* events for closing the session is:
* <ul>
* <li>Set closing flag to prevent redundant shutdowns.
* <li>Call notifyEvent all listeners that the channel is shutting down.
* <li>Close the socket.
* </ul>
*
* This method takes into account the connection state of the peer. Specifically,
* when the peer is known to be in a disconnected state, no data will be sent
* (otherwise, this method can trigger the delivery of an end-of-stream signal).
*
* @param peerIsKnownToBeDisconnected should be set to true when the peer is known to no longer be available.
*/
public void close( boolean peerIsKnownToBeDisconnected );
/**
* Notification message indicating that the server is being shutdown. Implementors
* should send a stream error whose condition is system-shutdown before closing
......
......@@ -442,6 +442,10 @@ public class SocketConnection implements Connection {
}
public void close() {
close( false );
}
public void close( boolean peerIsKnownToBeDisconnected ) {
boolean wasClosed = false;
synchronized (this) {
if (!isClosed()) {
......@@ -449,26 +453,29 @@ public class SocketConnection implements Connection {
if (session != null) {
session.setStatus(Session.STATUS_CLOSED);
}
boolean allowedToWrite = false;
try {
requestWriting();
allowedToWrite = true;
// Register that we started sending data on the connection
writeStarted();
writer.write("</stream:stream>");
if (flashClient) {
writer.write('\0');
if ( !peerIsKnownToBeDisconnected ) {
boolean allowedToWrite = false;
try {
requestWriting();
allowedToWrite = true;
// Register that we started sending data on the connection
writeStarted();
writer.write("</stream:stream>");
if (flashClient) {
writer.write('\0');
}
writer.flush();
}
writer.flush();
}
catch (IOException e) {
// Do nothing
}
finally {
// Register that we finished sending data on the connection
writeFinished();
if (allowedToWrite) {
releaseWriting();
catch (IOException e) {
// Do nothing
}
finally {
// Register that we finished sending data on the connection
writeFinished();
if (allowedToWrite) {
releaseWriting();
}
}
}
}
......
......@@ -169,6 +169,10 @@ public abstract class VirtualConnection implements Connection {
* has been closed.
*/
public void close() {
close( false );
}
public void close(boolean peerIsKnownToBeDisconnected) {
boolean wasClosed = false;
synchronized (this) {
if (!isClosed()) {
......
......@@ -111,7 +111,7 @@ public abstract class ConnectionHandler extends IoHandlerAdapter {
public void inputClosed( IoSession session ) throws Exception {
final Connection connection = (Connection) session.getAttribute(CONNECTION);
if ( connection != null ) {
connection.close();
connection.close( true );
}
}
......
......@@ -219,7 +219,11 @@ public class NIOConnection implements Connection {
return backupDeliverer;
}
public void close()
public void close() {
close( false );
}
public void close( boolean peerIsKnownToBeDisconnected )
{
boolean notifyClose = false;
synchronized ( this ) {
......@@ -234,13 +238,16 @@ public class NIOConnection implements Connection {
if ( state != State.CLOSING )
{
state = State.CLOSING;
try
{
deliverRawText( flashClient ? "</flash:stream>" : "</stream:stream>" );
}
catch ( Exception e )
if ( !peerIsKnownToBeDisconnected )
{
// Ignore
try
{
deliverRawText( flashClient ? "</flash:stream>" : "</stream:stream>" );
}
catch ( Exception e )
{
// Ignore
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment