@Override
public StreamInbound createWebSocketInbound(String protocol, HttpServletRequest request) {
// Get tunnel
final GuacamoleTunnel tunnel;
try {
tunnel = doConnect(request);
}
catch (GuacamoleException e) {
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage());
logger.debug("Error connecting WebSocket tunnel.", e);
return null;
}
// Return new WebSocket which communicates through tunnel
return new StreamInbound() {
@Override
protected void onTextData(Reader reader) throws IOException {
GuacamoleWriter writer = tunnel.acquireWriter();
// Write all available data
try {
char[] buffer = new char[BUFFER_SIZE];
int num_read;
while ((num_read = reader.read(buffer)) > 0)
writer.write(buffer, 0, num_read);
}
catch (GuacamoleConnectionClosedException e) {
logger.debug("Connection to guacd closed.", e);
}
catch (GuacamoleException e) {
logger.debug("WebSocket tunnel write failed.", e);
}
tunnel.releaseWriter();
}
@Override
public void onOpen(final WsOutbound outbound) {
// Do not start connection if tunnel does not exist
if (tunnel == null) {
closeConnection(outbound, GuacamoleStatus.RESOURCE_NOT_FOUND);
return;
}
Thread readThread = new Thread() {
@Override
public void run() {
StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
GuacamoleReader reader = tunnel.acquireReader();
char[] readMessage;
try {
try {
// Attempt to read
while ((readMessage = reader.read()) != null) {
// Buffer message
buffer.append(readMessage);
// Flush if we expect to wait or buffer is getting full
if (!reader.available() || buffer.length() >= BUFFER_SIZE) {
outbound.writeTextMessage(CharBuffer.wrap(buffer));
buffer.setLength(0);
}
}
// No more data
closeConnection(outbound, GuacamoleStatus.SUCCESS);
}
// Catch any thrown guacamole exception and attempt
// to pass within the WebSocket connection, logging
// each error appropriately.
catch (GuacamoleClientException e) {
logger.info("WebSocket connection terminated: {}", e.getMessage());
logger.debug("WebSocket connection terminated due to client error.", e);
closeConnection(outbound, e.getStatus());
}
catch (GuacamoleConnectionClosedException e) {
logger.debug("Connection to guacd closed.", e);
closeConnection(outbound, GuacamoleStatus.SUCCESS);
}
catch (GuacamoleException e) {
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage());
logger.debug("Internal error during connection to guacd.", e);
closeConnection(outbound, e.getStatus());
}
}
catch (IOException e) {
logger.debug("I/O error prevents further reads.", e);
}
}
};
readThread.start();
}
@Override
public void onClose(int i) {
try {
if (tunnel != null)
tunnel.close();
}
catch (GuacamoleException e) {
logger.debug("Unable to close connection to guacd.", e);
}
}