Issue
I am trying to create something like node-websockify which is basically a simple proxy server to transfer data from a novnc server to a novnc client, I am using approach mentioned here
I have strange error happening while sending ByteBuffer to remote client. As said before client is a noVNC client, with node-websockify and tightvnc worked perfectly
import org.eclipse.jetty.websocket.server.WebSocketHandler;
org.eclipse.jetty.server.Server serverr = new org.eclipse.jetty.server.Server(8090);
WebSocketHandler wsh = new WebSockify();
serverr.setHandler(wsh);
serverr.start();
serverr.join();
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.api.extensions.Frame;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.server.WebSocketHandler;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebSocket
public class WebSockify extends WebSocketHandler {
private static String authorizationHeader = "";
Socket vncSocket;
int vncPort = 5900;
String vncPassword = "1234560";
@Override
public void configure(WebSocketServletFactory webSocketServletFactory) {
webSocketServletFactory.register(WebSockify.class);
}
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
System.out.println("Received handle " + target);
try {
if (this.getWebSocketFactory().isUpgradeRequest(request, response)) {
System.out.println("Adding header");
response.addHeader("Sec-WebSocket-Protocol", "binary");
if (this.getWebSocketFactory().acceptWebSocket(request, response)) {
System.out.println("websocket accepted");
baseRequest.setHandled(true);
return;
}
System.out.println("websocket not accepted");
if (response.isCommitted()) {
System.out.println("response commited.");
return;
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
} finally {
super.handle(target, baseRequest, request, response);
}
}
@OnWebSocketConnect
public void onConnect(final Session session) throws IOException, InterruptedException {
System.out.println("Connect: " + session.getRemoteAddress().getAddress());
System.out.println(session.getUpgradeRequest().getRequestURI());
System.out.println("session open ? " + session.isOpen());
vncSocket = new Socket("127.0.0.1", vncPort);
Thread readThread = new Thread(new Runnable() {
public void run() {
try {
System.out.println("session open ? " + session.isOpen());
byte[] b = new byte[1500];
int readBytes;
while (true) {
readBytes = vncSocket.getInputStream().read(b);
System.out.println("session open ? " + session.isOpen());
System.out.println("read bytes " + readBytes + ", " + new String(b));
if (readBytes == -1) {
break;
}
if (readBytes > 0) {
System.out.println("session open ? " + session.isOpen());
ByteBuffer bb = ByteBuffer.wrap(b, 0, readBytes);
session.getRemote().sendBytes(bb);
}
}
} catch (IOException e) {
e.printStackTrace();
System.err.println(e);
}
}
});
readThread.start();
}
@OnWebSocketFrame
public void onFrame(Frame f) throws IOException {
System.out.printf("Frame: %d\n", f.getPayloadLength());
byte[] data = new byte[f.getPayloadLength()];
f.getPayload().get(data);
vncSocket.getOutputStream().write(data);
}
@OnWebSocketError
public void onError(Throwable cause) {
System.err.println(cause.getMessage());
}
}
the error and console output is
session open ? true
Exception in thread "Thread-8" org.eclipse.jetty.websocket.api.WebSocketException: RemoteEndpoint unavailable, current state [CLOSED], expecting [OPEN or CONNECTED] at org.eclipse.jetty.websocket.common.WebSocketSession.getRemote(WebSocketSession.java:308) at com.hossein.main.WebSockify$1.run(WebSockify.java:91) at java.lang.Thread.run(Unknown Source)
looks like the session.open()
returns true but next line session.getRemote().sendBytes()
causes the error.
can you help me figure out why ?
Found something, the problem happens when I work with session inside the thread, I mean if I dont create a new thread the session.getRemote().sendBytes()
works fine.
Solution
It has nothing to do with the threading, actually it was due to wrong handshake between client and server
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
System.out.println("Received handle " + target);
try {
if (this.getWebSocketFactory().isUpgradeRequest(request, response)) {
System.out.println("Adding header");
// NO NEED, the client already put this header in the request
//so no need to be added again
//response.addHeader("Sec-WebSocket-Protocol", "binary");
if (this.getWebSocketFactory().acceptWebSocket(request, response)) {
System.out.println("websocket accepted");
baseRequest.setHandled(true);
return;
}
System.out.println("websocket not accepted");
if (response.isCommitted()) {
System.out.println("response commited.");
return;
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
} finally {
// has to be removed, because this cause an Upgrade header to be added with is already existed and causes .
//super.handle(target, baseRequest, request, response);
}
}
Answered By - Bahram