Wolfmans Howlings

A programmers Blog about Programming solutions and a few other issues

A TCP socket bridge for Javascript

Posted by Jim Morris on Sat Sep 12 16:07:22 -0700 2009

In the process of rewriting my voice server in Erlang, I decided a new web-based Javascript UI would also be welcome. One problem of course is my voice server requires a TCP connection and a UDP socket for sending voice, not to mention the whole voice capture, playback thing.

In order for this to work the voice and playback would need to be written in a Java Applet, so it made sense to put the whole TCP/UDP communications stuff in there too.

Firefox uses Liveconnect in its Javascript that allows Javascript to call methods in a Java Applet directly, and also for Java to call Javascript functions, as Javascript has no way of opening an arbitrary TCP socket that would have to be in the Java Applet.

One thing that seems to not be documented in the Livescript docs, is that the Java method that is called directly from Javascript is not run with any privileges at all, including the one that allows TCP connections back to the same server that served up the Applet, or any privileges that a signed Jar would have. So if you try to call an open socket from javascript you will get the dreaded error: java.security.AccessControlException: access denied (java.net.SocketPermission connect,resolve)

I found by Googling that a workaround is to run a thread from the Java Applet start() method, and pass any commands that require privileges to that thread. This thread must be started from the Applet.start() method, not from any method called from Javascript. However this will not work if the page is opened as a file, only if it is served over http.

I came across many clever methods of doing this in my research, one was to pass a Runnable into this thread, so you can have that thread run arbitrary Java code. However I wanted something a little simpler as for now I would do a TCP socket bridge, which only required three calls, Open, Close and Write. There was no need to pass in a Runnable to do that. The Open needed to be a synchronous call, the close and write could be asynchronous.

The relatively simple solution I came up with using the concurrency libraries in recent versions of Java is shown here, other versions can be found on the web.

After starting up the Communication Thread from the Applet start(), I pass in one of the commands I want it to execute, I use the SynchonousQueue class, to make sure only one command can be executed at a time, and in the case of open() I use another SynchonousQueue to return the results. This makes the open() call totally synchronous and will block (and hang the browser) until either the socket is opened, fails to open, or a timeout occurs.

I am writing JSON strings to the server as that provides a nice way to do a simple RPC protocol that can be easily generated in Javascript, and I return JSON as again Javascript can handle that easily. As the server is Erlang I use {packet, 2} in the TCP socket meaning each packet is preceded by the BigEndian count of the size of the packet, this gets over the need to make sure the entire JSON has been received before decoding it.

If you do not want to sign your applet in a jar then you need to only connect to the same server the applet is served from, so the code allows for open to only specify the port, and it figures out the host name. There is also an open call that specifies an arbitrary host, but for this to work you need to sign the jar. (In my case I will need to sign the jar eventually as the capture audio calls require special privileges). There are plenty of howtos on the web about self-signing jars so I won't go into it here.

Onto the code...

The applet is loaded as the following html shows with a simple sample...

The javascript library that talks to the Java Applet is in e4socketbridge.js Any incoming data from the server needs to be sent to the Javascript, to handle that I have a readThread that listens on the TCP socket for any incoming data, reads the entire packet based on the 2 byte header, then calls a Javascript function which would handle that event. I'm not exactly sure how Javascript handles asynchronous calls from different Java threads, but it seems to work OK, and there is some mention of Javascript being able to handle this kind of thing. Note I put timeouts on any method that could hang, because the entire browser hangs when those calls into the Java Applet hang, and debugging that was ugly, having to kill off the browser everytime. I use a 2 byte header so no packet can be bigger than 65k, this helps avoid DOS (Denial of Service) attacks where someone could tie up a process in the server by specifying it was going to send a huge packet, this could also cause the server to run out of memory. The downside is I have to manually break up anything that needs to send more than 65k. If you are not concerned about the potential DOS use {packet, 4} instead, and change it to send a 4 byte integer instead.

Posted in Java,Javascript  |  Tags java,javascript,applet  |  no comments


(leave email »)