Commit 64c735bc authored by Tom Evans's avatar Tom Evans Committed by Dave Cridland

OF-857: Synchronize I/O for C2S connection

Use a lock to ensure the integrity of IoSession (MINA), especially when
using compression or TLS filters
parent ea81dc86
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
package org.jivesoftware.openfire.nio; package org.jivesoftware.openfire.nio;
import static org.jivesoftware.openfire.spi.ConnectionManagerImpl.COMPRESSION_FILTER_NAME;
import static org.jivesoftware.openfire.spi.ConnectionManagerImpl.EXECUTOR_FILTER_NAME; import static org.jivesoftware.openfire.spi.ConnectionManagerImpl.EXECUTOR_FILTER_NAME;
import static org.jivesoftware.openfire.spi.ConnectionManagerImpl.TLS_FILTER_NAME; import static org.jivesoftware.openfire.spi.ConnectionManagerImpl.TLS_FILTER_NAME;
import static org.jivesoftware.openfire.spi.ConnectionManagerImpl.COMPRESSION_FILTER_NAME;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
...@@ -31,6 +31,7 @@ import java.nio.charset.CharsetEncoder; ...@@ -31,6 +31,7 @@ import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction; import java.nio.charset.CodingErrorAction;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.concurrent.Semaphore;
import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
...@@ -114,11 +115,17 @@ public class NIOConnection implements Connection { ...@@ -114,11 +115,17 @@ public class NIOConnection implements Connection {
*/ */
private boolean closed; private boolean closed;
/**
* Lock used to ensure the integrity of the underlying IoSession
* (refer to https://issues.apache.org/jira/browse/DIRMINA-653 for details)
*/
private Semaphore ioSessionLock;
public NIOConnection(IoSession session, PacketDeliverer packetDeliverer) { public NIOConnection(IoSession session, PacketDeliverer packetDeliverer) {
this.ioSession = session; this.ioSession = session;
this.backupDeliverer = packetDeliverer; this.backupDeliverer = packetDeliverer;
closed = false; closed = false;
ioSessionLock = new Semaphore(1, true);
} }
public boolean validate() { public boolean validate() {
...@@ -253,11 +260,13 @@ public class NIOConnection implements Connection { ...@@ -253,11 +260,13 @@ public class NIOConnection implements Connection {
backupDeliverer.deliver(packet); backupDeliverer.deliver(packet);
} }
else { else {
boolean errorDelivering = false;
try {
ioSessionLock.acquire();
IoBuffer buffer = IoBuffer.allocate(4096); IoBuffer buffer = IoBuffer.allocate(4096);
buffer.setAutoExpand(true); buffer.setAutoExpand(true);
boolean errorDelivering = false;
try {
// OF-464: if the connection has been dropped, fail over to backupDeliverer (offline) // OF-464: if the connection has been dropped, fail over to backupDeliverer (offline)
if (!ioSession.isConnected()) { if (!ioSession.isConnected()) {
throw new IOException("Connection reset/closed by peer"); throw new IOException("Connection reset/closed by peer");
...@@ -276,6 +285,9 @@ public class NIOConnection implements Connection { ...@@ -276,6 +285,9 @@ public class NIOConnection implements Connection {
Log.debug("Error delivering packet:\n" + packet, e); Log.debug("Error delivering packet:\n" + packet, e);
errorDelivering = true; errorDelivering = true;
} }
finally {
ioSessionLock.release();
}
if (errorDelivering) { if (errorDelivering) {
close(); close();
// Retry sending the packet again. Most probably if the packet is a // Retry sending the packet again. Most probably if the packet is a
...@@ -295,11 +307,14 @@ public class NIOConnection implements Connection { ...@@ -295,11 +307,14 @@ public class NIOConnection implements Connection {
private void deliverRawText(String text, boolean asynchronous) { private void deliverRawText(String text, boolean asynchronous) {
if (!isClosed()) { if (!isClosed()) {
IoBuffer buffer = IoBuffer.allocate(text.length());
buffer.setAutoExpand(true);
boolean errorDelivering = false; boolean errorDelivering = false;
try { try {
ioSessionLock.acquire();
IoBuffer buffer = IoBuffer.allocate(text.length());
buffer.setAutoExpand(true);
//Charset charset = Charset.forName(CHARSET); //Charset charset = Charset.forName(CHARSET);
//buffer.putString(text, charset.newEncoder()); //buffer.putString(text, charset.newEncoder());
buffer.put(text.getBytes(CHARSET)); buffer.put(text.getBytes(CHARSET));
...@@ -327,6 +342,9 @@ public class NIOConnection implements Connection { ...@@ -327,6 +342,9 @@ public class NIOConnection implements Connection {
Log.debug("Error delivering raw text:\n" + text, e); Log.debug("Error delivering raw text:\n" + text, e);
errorDelivering = true; errorDelivering = true;
} }
finally {
ioSessionLock.release();
}
// Close the connection if delivering text fails and we are already not closing the connection // Close the connection if delivering text fails and we are already not closing the connection
if (errorDelivering && asynchronous) { if (errorDelivering && asynchronous) {
close(); close();
......
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