414652 - WebSocket's sendMessage() may hang on congested connections.
Fixed by using Locks instead of the synchronized keyword, and by using tryLock() in flushBuffer() and flush(), that are called by WebSocketConnection.handle(). It is quite a hack, but the real fix is in Jetty 9 where the architecture is different and there are two different paths for reading and writing, so that this problem could not even happen.
This commit is contained in:
parent
f983629434
commit
4ce4615597
|
@ -19,14 +19,16 @@
|
|||
package org.eclipse.jetty.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** WebSocketGenerator.
|
||||
/**
|
||||
* WebSocketGenerator.
|
||||
* This class generates websocket packets.
|
||||
* It is fully synchronized because it is likely that async
|
||||
* threads will call the addMessage methods while other
|
||||
|
@ -34,20 +36,19 @@ import org.eclipse.jetty.io.EofException;
|
|||
*/
|
||||
public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
||||
{
|
||||
final private WebSocketBuffers _buffers;
|
||||
final private EndPoint _endp;
|
||||
private Buffer _buffer;
|
||||
private final Lock _lock = new ReentrantLock();
|
||||
private final WebSocketBuffers _buffers;
|
||||
private final EndPoint _endp;
|
||||
private final byte[] _mask = new byte[4];
|
||||
private final MaskGen _maskGen;
|
||||
private Buffer _buffer;
|
||||
private int _m;
|
||||
private boolean _opsent;
|
||||
private final MaskGen _maskGen;
|
||||
private boolean _closed;
|
||||
|
||||
public WebSocketGeneratorRFC6455(WebSocketBuffers buffers, EndPoint endp)
|
||||
{
|
||||
_buffers=buffers;
|
||||
_endp=endp;
|
||||
_maskGen=null;
|
||||
this(buffers, endp, null);
|
||||
}
|
||||
|
||||
public WebSocketGeneratorRFC6455(WebSocketBuffers buffers, EndPoint endp, MaskGen maskGen)
|
||||
|
@ -57,15 +58,24 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
|||
_maskGen = maskGen;
|
||||
}
|
||||
|
||||
public synchronized Buffer getBuffer()
|
||||
public Buffer getBuffer()
|
||||
{
|
||||
_lock.lock();
|
||||
try
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
public synchronized void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException
|
||||
finally
|
||||
{
|
||||
// System.err.printf("<< %s %s %s\n",TypeUtil.toHexString(flags),TypeUtil.toHexString(opcode),length);
|
||||
_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException
|
||||
{
|
||||
_lock.lock();
|
||||
try
|
||||
{
|
||||
if (_closed)
|
||||
throw new EofException("Closed");
|
||||
if (opcode == WebSocketConnectionRFC6455.OP_CLOSE)
|
||||
|
@ -186,8 +196,18 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
|||
_buffer = null;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int flushBuffer() throws IOException
|
||||
public int flushBuffer() throws IOException
|
||||
{
|
||||
if (!_lock.tryLock())
|
||||
return 0;
|
||||
|
||||
try
|
||||
{
|
||||
if (!_endp.isOpen())
|
||||
throw new EofException();
|
||||
|
@ -202,13 +222,23 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
|||
|
||||
return 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int flush() throws IOException
|
||||
public int flush() throws IOException
|
||||
{
|
||||
if (!_lock.tryLock())
|
||||
return 0;
|
||||
|
||||
try
|
||||
{
|
||||
if (_buffer == null)
|
||||
return 0;
|
||||
int result = flushBuffer();
|
||||
|
||||
int result = flushBuffer();
|
||||
if (!_endp.isBlocking())
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
|
@ -230,13 +260,29 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
|||
_buffer.compact();
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isBufferEmpty()
|
||||
public boolean isBufferEmpty()
|
||||
{
|
||||
_lock.lock();
|
||||
try
|
||||
{
|
||||
return _buffer == null || _buffer.length() == 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void returnBuffer()
|
||||
public void returnBuffer()
|
||||
{
|
||||
_lock.lock();
|
||||
try
|
||||
{
|
||||
if (_buffer != null && _buffer.length() == 0)
|
||||
{
|
||||
|
@ -244,6 +290,11 @@ public class WebSocketGeneratorRFC6455 implements WebSocketGenerator
|
|||
_buffer = null;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
|
|
Loading…
Reference in New Issue