Переглянути джерело

Remove files that are now in websockify.

https://github.com/kanaka/websockify is now the canonical location of
websockify (formerly wsproxy). A copy of the python version is kept
here for backwards compatibility and ease-of-use. The other versions
and related test scripts are in websockify.
Joel Martin 14 роки тому
батько
коміт
61265b3a7f
28 змінених файлів з 319 додано та 5825 видалено
  1. 0 1
      tests/wsecho.html
  2. 0 151
      tests/wsencoding.html
  3. 0 87
      tests/wsencoding.py
  4. 0 1
      tests/wstest.html
  5. 0 1
      tests/wstest.py
  6. 2 16
      utils/Makefile
  7. 8 160
      utils/README.md
  8. 0 919
      utils/VT100.js
  9. 0 1
      utils/include
  10. 0 466
      utils/md5.c
  11. 0 148
      utils/md5.h
  12. 0 3
      utils/md5_test.c
  13. 0 556
      utils/websocket.c
  14. 0 47
      utils/websocket.h
  15. 308 0
      utils/websockify
  16. 0 176
      utils/wsecho.html
  17. 0 90
      utils/wsecho.py
  18. 0 353
      utils/wsproxy.c
  19. 0 253
      utils/wsproxy.js
  20. 0 308
      utils/wsproxy.py
  21. 1 0
      utils/wsproxy.py
  22. 0 90
      utils/wstelnet.html
  23. 0 333
      utils/wstelnet.js
  24. 0 252
      utils/wstest.html
  25. 0 171
      utils/wstest.py
  26. 0 22
      utils/wswrap
  27. 0 1156
      utils/wswrapper.c
  28. 0 64
      utils/wswrapper.h

+ 0 - 1
tests/wsecho.html

@@ -1 +0,0 @@
-../utils/wsecho.html

+ 0 - 151
tests/wsencoding.html

@@ -1,151 +0,0 @@
-<html>
-
-    <head><title>WebSockets Test</title></head>
-
-    <body>
-
-        Host: <input id='host' style='width:100'>&nbsp;
-        Port: <input id='port' style='width:50'>&nbsp;
-        Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
-        <input id='connectButton' type='button' value='Start' style='width:100px'
-            onclick="connect();">&nbsp;
-
-        <br>
-        Messages:<br>
-        <textarea id="messages" style="font-size: 9;" cols=80 rows=25></textarea>
-    </body>
-
-
-    <!-- Uncomment to activate firebug lite -->
-    <!--
-    <script type='text/javascript' 
-        src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-    -->
-
-    <script src="include/base64.js"></script>
-    <script src="include/util.js"></script>
-    <script src="include/webutil.js"></script>
-
-    <script>
-
-        var host = null, port = null;
-        var ws = null;
-        var VNC_native_ws = true;
-
-        function message(str) {
-            console.log(str);
-            cell = $D('messages');
-            cell.innerHTML += str + "\n";
-            cell.scrollTop = cell.scrollHeight;
-        }
-
-        function print_response(str) {
-            message("str.length: " + str.length);
-            for (i=0; i < str.length; i++) {
-                message(i + ": " + (str.charCodeAt(i) % 256));
-            }
-
-        }
-
-        function send() {
-            var str = "";
-            str = str + String.fromCharCode(0x81);
-            str = str + String.fromCharCode(0xff);
-            for (var i=0; i<256; i+=4) {
-                str = str + String.fromCharCode(i);
-            }
-            str = str + String.fromCharCode(0);
-            str = str + String.fromCharCode(0x40);
-            str = str + String.fromCharCode(0x41);
-            str = str + String.fromCharCode(0xff);
-            str = str + String.fromCharCode(0x81);
-            ws.send(str);
-        }
-
-        function init_ws() {
-            console.log(">> init_ws");
-            var scheme = "ws://";
-            if ($D('encrypt').checked) {
-                scheme = "wss://";
-            }
-            var uri = scheme + host + ":" + port;
-            console.log("connecting to " + uri);
-            ws = new WebSocket(uri);
-
-            ws.onmessage = function(e) {
-                console.log(">> WebSockets.onmessage");
-                print_response(e.data);
-                console.log("<< WebSockets.onmessage");
-            };
-            ws.onopen = function(e) {
-                console.log(">> WebSockets.onopen");
-                send();
-                console.log("<< WebSockets.onopen");
-            };
-            ws.onclose = function(e) {
-                console.log(">> WebSockets.onclose");
-                console.log("<< WebSockets.onclose");
-            };
-            ws.onerror = function(e) {
-                console.log(">> WebSockets.onerror");
-                console.log("   " + e);
-                console.log("<< WebSockets.onerror");
-            };
-
-            console.log("<< init_ws");
-        }
-
-        function connect() {
-            console.log(">> connect");
-            host = $D('host').value;
-            port = $D('port').value;
-            if ((!host) || (!port)) {
-                console.log("must set host and port");
-                return;
-            }
-
-            if (ws) {
-                ws.close();
-            }
-            init_ws();
-
-            $D('connectButton').value = "Stop";
-            $D('connectButton').onclick = disconnect;
-            console.log("<< connect");
-        }
-
-        function disconnect() {
-            console.log(">> disconnect");
-            if (ws) {
-                ws.close();
-            }
-
-            $D('connectButton').value = "Start";
-            $D('connectButton').onclick = connect;
-            console.log("<< disconnect");
-        }
-
-
-        /* If no builtin websockets then load web_socket.js */
-        if (! window.WebSocket) {
-            console.log("Loading web-socket-js flash bridge");
-            var extra = "<script src='include/web-socket-js/swfobject.js'><\/script>";
-            extra += "<script src='include/web-socket-js/FABridge.js'><\/script>";
-            extra += "<script src='include/web-socket-js/web_socket.js'><\/script>";
-            document.write(extra);
-            VNC_native_ws = false;
-        }
-
-        window.onload = function() {
-            console.log("onload");
-            if (! VNC_native_ws) {
-                WebSocket.__swfLocation = "include/web-socket-js/WebSocketMain.swf";
-                WebSocket.__initialize();
-            }
-            var url = document.location.href;
-            $D('host').value = (url.match(/host=([^&#]*)/) || ['',''])[1];
-            $D('port').value = (url.match(/port=([^&#]*)/) || ['',''])[1];
-        }
-    </script>
-
-</html>

+ 0 - 87
tests/wsencoding.py

@@ -1,87 +0,0 @@
-#!/usr/bin/python
-
-'''
-WebSocket server-side load test program. Sends and receives traffic
-that has a random payload (length and content) that is checksummed and
-given a sequence number. Any errors are reported and counted.
-'''
-
-import sys, os, socket, ssl, time, traceback
-import random, time
-from base64 import b64encode, b64decode
-from codecs import utf_8_encode, utf_8_decode
-from select import select
-
-sys.path.insert(0,os.path.dirname(__file__) + "/../utils/")
-from websocket import *
-
-buffer_size = 65536
-recv_cnt = send_cnt = 0
-
-
-def check(buf):
-
-    if buf[0] != '\x00' or buf[-1] != '\xff':
-        raise Exception("Invalid WS packet")
-
-    for decoded in decode(buf):
-        nums = [ord(c) for c in decoded]
-        print "Received nums: ", nums
-
-    return
-
-
-def responder(client):
-    cpartial = ""
-    socks = [client]
-    sent = False
-    received = False
-
-    while True:
-        ins, outs, excepts = select(socks, socks, socks, 1)
-        if excepts: raise Exception("Socket exception")
-
-        if client in ins:
-            buf = client.recv(buffer_size)
-            if len(buf) == 0: raise Exception("Client closed")
-            received = True
-            #print "Client recv: %s (%d)" % (repr(buf[1:-1]), len(buf))
-            if buf[-1] == '\xff':
-                if cpartial:
-                    err = check(cpartial + buf)
-                    cpartial = ""
-                else:
-                    err = check(buf)
-                if err:
-                    print err
-            else:
-                print "received partitial"
-                cpartial = cpartial + buf
-
-        if received and not sent and client in outs:
-            sent = True
-            #nums = "".join([unichr(c) for c in range(0,256)])
-            #nums = "".join([chr(c) for c in range(1,128)])
-            #nums = nums + chr(194) + chr(128) + chr(194) + chr(129)
-            #nums = "".join([chr(c) for c in range(0,256)])
-            nums = "\x81\xff"
-            nums = nums + "".join([chr(c) for c in range(0,256,4)])
-            nums = nums + "\x00\x40\x41\xff\x81"
-#            print nums
-            client.send(encode(nums))
-#            client.send("\x00" + nums + "\xff")
-#            print "Sent characters 0-255"
-#            #print "Client send: %s (%d)" % (repr(nums), len(nums))
-
-if __name__ == '__main__':
-    try:
-        if len(sys.argv) < 2: raise
-        listen_port = int(sys.argv[1])
-    except:
-        print "Usage: <listen_port>"
-        sys.exit(1)
-
-    settings['listen_port'] = listen_port
-    settings['daemon'] = False
-    settings['handler'] = responder
-    start_server()

+ 0 - 1
tests/wstest.html

@@ -1 +0,0 @@
-../utils/wstest.html

+ 0 - 1
tests/wstest.py

@@ -1 +0,0 @@
-../utils/wstest.py

+ 2 - 16
utils/Makefile

@@ -1,25 +1,11 @@
-TARGETS=wsproxy wswrapper.so rebind.so
+TARGETS=rebind.so
 CFLAGS += -fPIC
 
 all: $(TARGETS)
 
-wsproxy: wsproxy.o websocket.o md5.o
-	$(CC) $(LDFLAGS) $^ -lssl -lcrypto -lresolv -o $@
-
-wswrapper.o: wswrapper.h
-wswrapper.so: wswrapper.o md5.o
-	$(CC) $(LDFLAGS) $^ -shared -fPIC -ldl -lresolv -o $@
-
 rebind.so: rebind.o
 	$(CC) $(LDFLAGS) $^ -shared -fPIC -ldl -o $@
 
-websocket.o: websocket.c websocket.h md5.h
-wsproxy.o: wsproxy.c websocket.h
-wswrapper.o: wswrapper.c
-	$(CC) -c $(CFLAGS) -o $@ $*.c
-md5.o: md5.c md5.h
-	$(CC) -c $(CFLAGS) -o $@ $*.c -DHAVE_MEMCPY -DSTDC_HEADERS
-
 clean:
-	rm -f wsproxy wswrapper.so *.o
+	rm -f rebind.o rebind.so
 

+ 8 - 160
utils/README.md

@@ -1,163 +1,11 @@
 ## WebSockets Proxy
 
-
-### wsproxy
-
-At the most basic level, wsproxy just translates WebSockets traffic
-to normal socket traffic. wsproxy accepts the WebSockets handshake,
-parses it, and then begins forwarding traffic between the client and
-the target in both directions. WebSockets payload data is UTF-8
-encoded so in order to transport binary data it must use an encoding
-that can be encapsulated within UTF-8. wsproxy uses base64 to encode
-all traffic to and from the client. Also, WebSockets traffic starts
-with '\0' (0) and ends with '\xff' (255). Some buffering is done in
-case the data from the client is not a full WebSockets frame (i.e.
-does not end in 255).
-
-
-#### Additional wsproxy features
-
-These are not necessary for the basic operation.
-
-* Daemonizing: When the `-D` option is specified, wsproxy runs
-  in the background as a daemon process.
-
-* SSL (the wss:// WebSockets URI): This is detected automatically by
-  wsproxy by sniffing the first byte sent from the client and then
-  wrapping the socket if the data starts with '\x16' or '\x80'
-  (indicating SSL).
-
-* Flash security policy: wsproxy detects flash security policy
-  requests (again by sniffing the first packet) and answers with an
-  appropriate flash security policy response (and then closes the
-  port). This means no separate flash security policy server is needed
-  for supporting the flash WebSockets fallback emulator.
-
-* Session recording: This feature that allows recording of the traffic
-  sent and received from the client to a file using the `--record`
-  option.
-
-* Mini-webserver: wsproxy can detect and respond to normal web
-  requests on the same port as the WebSockets proxy and Flash security
-  policy. This functionality is activate with the `--web DIR` option
-  where DIR is the root of the web directory to serve.
-
-* Wrap a program: see the "Wrap a Program" section below.
-
-
-#### Implementations of wsproxy
-
-There are three implementations of wsproxy: python, C, and Node
-(node.js). wswrapper is only implemented in C.
-
-Here is the feature support matrix for the the wsproxy
-implementations:
-
-<table>
-    <tr>
-        <th>Program</th>
-        <th>Language</th>
-        <th>Multiprocess</th>
-        <th>Daemonize</th>
-        <th>SSL/wss</th>
-        <th>Flash Policy Server</th>
-        <th>Session Record</th>
-        <th>Web Server</th>
-        <th>Program Wrap</th>
-    </tr> <tr>
-        <td>wsproxy.py</td>
-        <td>python</td>
-        <td>yes</td>
-        <td>yes</td>
-        <td>yes 1</td>
-        <td>yes</td>
-        <td>yes</td>
-        <td>yes</td>
-        <td>yes</td>
-    </tr> <tr>
-        <td>wsproxy</td>
-        <td>C</td>
-        <td>yes</td>
-        <td>yes</td>
-        <td>yes</td>
-        <td>yes</td>
-        <td>no</td>
-        <td>no</td>
-        <td>no</td>
-    </tr>
-    </tr> <tr>
-        <td>wsproxy.js</td>
-        <td>Node (node.js)</td>
-        <td>yes</td>
-        <td>no</td>
-        <td>no</td>
-        <td>no</td>
-        <td>no</td>
-        <td>no</td>
-        <td>no</td>
-    </tr>
-</table>
-
-
-* Note 1: to use SSL/wss with python 2.5 or older, see the following
-  section on *Building the Python ssl module*.
-
-
-### Wrap a Program
-
-In addition to proxying from a source address to a target address
-(which may be on a different system), wsproxy has the ability to
-launch a program on the local system and proxy WebSockets traffic to
-a normal TCP port owned/bound by the program.
-
-The is accomplished with a small LD_PRELOAD library (`rebind.so`)
-which intercepts bind() system calls by the program. The specified
-port is moved to a new localhost/loopback free high port. wsproxy
-then proxies WebSockets traffic directed to the original port to the
-new (moved) port of the program.
-
-The program wrap mode is invoked by replacing the target with `--`
-followed by the program command line to wrap.
-
-    `./utils/wsproxy.py 2023 -- PROGRAM ARGS`
-
-The `--wrap-mode` option can be used to indicate what action to take
-when the wrapped program exits or daemonizes.
-
-Here is an example of using wsproxy to wrap the vncserver command
-(which backgrounds itself):
-
-    `./utils/wsproxy.py 5901 --wrap-mode=ignore -- vncserver -geometry 1024x768 :1`
-
-Here is an example of wrapping telnetd (from krb5-telnetd).telnetd
-exits after the connection closes so the wrap mode is set to respawn
-the command:
-
-    `sudo ./utils/wsproxy.py 2023 --wrap-mode=respawn -- telnetd -debug 2023`
-
-The `utils/wstelnet.html` page demonstrates a simple WebSockets based
-telnet client.
-
-
-### Building the Python ssl module (for python 2.5 and older)
-
-* Install the build dependencies. On Ubuntu use this command:
-
-    `sudo aptitude install python-dev bluetooth-dev`
-
-* Download, build the ssl module and symlink to it:
-
-    `cd noVNC/utils`
-
-    `wget http://pypi.python.org/packages/source/s/ssl/ssl-1.15.tar.gz`
-
-    `tar xvzf ssl-1.15.tar.gz`
-
-    `cd ssl-1.15`
-
-    `make`
-
-    `cd ../`
-
-    `ln -sf ssl-1.15/build/lib.linux-*/ssl ssl`
+wsproxy has become [websockify](https://github.com/kanaka/websockify).
+A copy of the python version of websockify (named wsproxy.py) is kept
+here for ease of use. The other versions of websockify (C, Node.js)
+and the associated test programs have been moved to
+[websockify](https://github.com/kanaka/websockify).
+
+For more detailed description and usage information please refer to
+the [websockify README](https://github.com/kanaka/websockify/blob/master/README.md).
 

+ 0 - 919
utils/VT100.js

@@ -1,919 +0,0 @@
-// VT100.js -- a text terminal emulator in JavaScript with a ncurses-like
-// interface and a POSIX-like interface. (The POSIX-like calls are
-// implemented on top of the ncurses-like calls, not the other way round.)
-//
-// Released under the GNU LGPL v2.1, by Frank Bi <bi@zompower.tk>
-//
-// 2007-08-12	- refresh():
-//		  - factor out colour code to html_colours_()
-//		  - fix handling of A_REVERSE | A_DIM
-//		  - simplify initial <br /> output code
-//		  - fix underlining colour
-//		- fix attron() not to turn off attributes
-//		- decouple A_STANDOUT and A_BOLD
-// 2007-08-11	- getch() now calls refresh()
-// 2007-08-06	- Safari compat fix -- turn '\r' into '\n' for onkeypress
-// 2007-08-05	- Opera compat fixes for onkeypress
-// 2007-07-30	- IE compat fixes:
-//		  - change key handling code
-//		  - add <br />...<br />&nbsp; so that 1st and last lines align
-// 2007-07-28	- change wrapping behaviour -- writing at the right edge no
-//		  longer causes the cursor to immediately wrap around
-//		- add <b>...</b> to output to make A_STANDOUT stand out more
-//		- add handling of backspace, tab, return keys
-//		- fix doc. of VT100() constructor
-//		- change from GPL to LGPL
-// 2007-07-09	- initial release
-//
-// class VT100
-//	A_NORMAL, A_UNDERLINE, A_REVERSE, A_BLINK, A_DIM, A_BOLD, A_STANDOUT
-//	=class constants=
-//			Attribute constants.
-//	VT100(wd, ht, scr_id) =constructor=
-//			Creates a virtual terminal with width `wd', and
-//			height `ht'. The terminal will be displayed between
-//			<pre>...</pre> tags which have element ID `scr_id'.
-//	addch(ch [, attr])
-//			Writes out the character `ch'. If `attr' is given,
-//			it specifies the attributes for the character,
-//			otherwise the current attributes are used.
-//	addstr(stuff)	Writes out the string `stuff' using the current
-//			attributes.
-//	attroff(mode)	Turns off any current options given in mode.
-//	attron(mode)	Turns on any options given in mode.
-//	attrset(mode)	Sets the current options to mode.
-//	bkgdset(attr)	Sets the background attributes to attr.
-//	clear()		Clears the terminal using the background attributes,
-//			and homes the cursor.
-//	clrtobol()	Clears the portion of the terminal from the cursor
-//			to the bottom.
-//	clrtoeol()	Clears the portion of the current line after the
-//			cursor.
-//	curs_set(vis [, grab])
-//			If `vis' is 0, makes the cursor invisible; otherwise
-//			make it visible. If `grab' is given and true, starts
-//			capturing keyboard events (for `getch()'); if given
-//			and false, stops capturing events.
-//	echo()		Causes key strokes to be automatically echoed on the
-//			terminal.
-//	erase()		Same as `clear()'.
-//	getch(isr)	Arranges to call `isr' when a key stroke is
-//			received. The received character and the terminal
-//			object are passed as arguments to `isr'.
-//	getmaxyx()	Returns an associative array with the maximum row
-//			(`y') and column (`x') numbers for the terminal.
-//	getyx()		Returns an associative array with the current row
-//			(`y') and column (`x') of the cursor.
-//	move(r, c)	Moves the cursor to row `r', column `c'.
-//	noecho()	Stops automatically echoing key strokes.
-//	refresh()	Updates the display.
-//	scroll()	Scrolls the terminal up one line.
-//	standend()	Same as `attrset(VT100.A_NORMAL)'.
-//	standout()	Same as `attron(VT100.A_STANDOUT)'.
-//	write(stuff)	Writes `stuff' to the terminal and immediately
-//			updates the display; (some) escape sequences are
-//			interpreted and acted on.
-
-// constructor
-function VT100(wd, ht, scr_id)
-{
-	var r;
-	var c;
-	var scr = document.getElementById(scr_id);
-	this.wd_ = wd;
-	this.ht_ = ht;
-	this.scrolled_ = 0;
-	this.bkgd_ = {
-			mode: VT100.A_NORMAL,
-			fg: VT100.COLOR_WHITE,
-			bg: VT100.COLOR_BLACK
-		     };
-	this.c_attr_ = {
-			mode: VT100.A_NORMAL,
-			fg: VT100.COLOR_WHITE,
-			bg: VT100.COLOR_BLACK
-		     };
-	this.text_ = new Array(ht);
-	this.attr_ = new Array(ht);
-	for (r = 0; r < ht; ++r) {
-		this.text_[r] = new Array(wd);
-		this.attr_[r] = new Array(wd);
-	}
-	this.scr_ = scr;
-	this.cursor_vis_ = true;
-	this.grab_events_ = false;
-	this.getch_isr_ = undefined;
-	this.key_buf_ = [];
-	this.echo_ = true;
-	this.esc_state_ = 0;
-	// Internal debug setting.
-	this.debug_ = 0;
-	this.clear();
-	this.refresh();
-}
-
-// public constants -- colours and colour pairs
-VT100.COLOR_BLACK = 0;
-VT100.COLOR_BLUE = 1;
-VT100.COLOR_GREEN = 2;
-VT100.COLOR_CYAN = 3;
-VT100.COLOR_RED = 4;
-VT100.COLOR_MAGENTA = 5;
-VT100.COLOR_YELLOW = 6;
-VT100.COLOR_WHITE = 7;
-VT100.COLOR_PAIRS = 256;
-VT100.COLORS = 8;
-// public constants -- attributes
-VT100.A_NORMAL = 0;
-VT100.A_UNDERLINE = 1;
-VT100.A_REVERSE = 2;
-VT100.A_BLINK = 4;
-VT100.A_DIM = 8;
-VT100.A_BOLD = 16;
-VT100.A_STANDOUT = 32;
-VT100.A_PROTECT = VT100.A_INVIS = 0; // ?
-// other public constants
-VT100.TABSIZE = 8;
-// private constants
-VT100.ATTR_FLAGS_ = VT100.A_UNDERLINE | VT100.A_REVERSE | VT100.A_BLINK |
-		    VT100.A_DIM | VT100.A_BOLD | VT100.A_STANDOUT |
-		    VT100.A_PROTECT | VT100.A_INVIS;
-VT100.COLOR_SHIFT_ = 6;
-VT100.browser_ie_ = (navigator.appName.indexOf("Microsoft") != -1);
-VT100.browser_opera_ = (navigator.appName.indexOf("Opera") != -1);
-// class variables
-VT100.the_vt_ = undefined;
-
-// class methods
-
-// this is actually an event handler
-VT100.handle_onkeypress_ = function VT100_handle_onkeypress(event)
-{
-	var vt = VT100.the_vt_, ch;
-	if (vt === undefined)
-		return true;
-	if (VT100.browser_ie_ || VT100.browser_opera_) {
-		ch = event.keyCode;
-		if (ch == 13)
-			ch = 10;
-		else if (ch > 255 || (ch < 32 && ch != 8))
-			return true;
-		ch = String.fromCharCode(ch);
-	} else {
-		ch = event.charCode;
-		//dump("ch: " + ch + "\n");
-		//dump("ctrl?: " + event.ctrlKey + "\n");
-		vt.debug("onkeypress:: keyCode: " + event.keyCode + ", ch: " + event.charCode);
-		if (ch) {
-			if (ch > 255)
-				return true;
-			if (event.ctrlKey && event.shiftKey) {
-				// Don't send the copy/paste commands.
-				var charStr = String.fromCharCode(ch);
-				if (charStr == 'C' || charStr == 'V') {
-					return false;
-				}
-			}
-			if (event.ctrlKey) {
-				ch = String.fromCharCode(ch - 96);
-			} else {
-				ch = String.fromCharCode(ch);
-				if (ch == '\r')
-					ch = '\n';
-			}
-		} else {
-			switch (event.keyCode) {
-			    case event.DOM_VK_BACK_SPACE:
-				ch = '\b';
-				break;
-			    case event.DOM_VK_TAB:
-				ch = '\t';
-				// Stop tab from moving to another element.
-				event.preventDefault();
-				break;
-			    case event.DOM_VK_RETURN:
-			    case event.DOM_VK_ENTER:
-				ch = '\n';
-				break;
-			    case event.DOM_VK_UP:
-				ch = '\x1b[A';
-				break;
-			    case event.DOM_VK_DOWN:
-				ch = '\x1b[B';
-				break;
-			    case event.DOM_VK_RIGHT:
-				ch = '\x1b[C';
-				break;
-			    case event.DOM_VK_LEFT:
-				ch = '\x1b[D';
-				break;
-			    case event.DOM_VK_DELETE:
-				ch = '\x1b[3~';
-				break;
-			    case event.DOM_VK_HOME:
-				ch = '\x1b[H';
-				break;
-			    case event.DOM_VK_ESCAPE:
-				ch = '\x1bc';
-				break;
-			    default:
-				return true;
-			}
-		}
-	}
-	vt.key_buf_.push(ch);
-	setTimeout(VT100.go_getch_, 0);
-	return false;
-}
-
-// this is actually an event handler
-VT100.handle_onkeydown_ = function VT100_handle_onkeydown()
-{
-	var vt = VT100.the_vt_, ch;
-	switch (event.keyCode) {
-	    case 8:
-		ch = '\b';	break;
-	    default:
-		return true;
-	}
-	vt.key_buf_.push(ch);
-	setTimeout(VT100.go_getch_, 0);
-	return false;
-}
-
-VT100.go_getch_ = function VT100_go_getch()
-{
-	var vt = VT100.the_vt_;
-	if (vt === undefined)
-		return;
-	var isr = vt.getch_isr_;
-	vt.getch_isr_ = undefined;
-	if (isr === undefined)
-		return;
-	var ch = vt.key_buf_.shift();
-	if (ch === undefined) {
-		vt.getch_isr_ = isr;
-		return;
-	}
-	if (vt.echo_)
-		vt.addch(ch);
-	isr(ch, vt);
-}
-
-// object methods
-
-VT100.prototype.may_scroll_ = function()
-{
-	var ht = this.ht_, cr = this.row_;
-	while (cr >= ht) {
-		this.scroll();
-		--cr;
-	}
-	this.row_ = cr;
-}
-
-VT100.prototype.html_colours_ = function(attr)
-{
-	var fg, bg, co0, co1;
-	fg = attr.fg;
-	bg = attr.bg;
-	switch (attr.mode & (VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD)) {
-	    case 0:
-	    case VT100.A_DIM | VT100.A_BOLD:
-		co0 = '00';  co1 = 'c0';
-		break;
-	    case VT100.A_BOLD:
-		co0 = '00';  co1 = 'ff';
-		break;
-	    case VT100.A_DIM:
-		if (fg == VT100.COLOR_BLACK)
-			co0 = '40';
-		else
-			co0 = '00';
-		co1 = '40';
-		break;
-	    case VT100.A_REVERSE:
-	    case VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD:
-		co0 = 'c0';  co1 = '40';
-		break;
-	    case VT100.A_REVERSE | VT100.A_BOLD:
-		co0 = 'c0';  co1 = '00';
-		break;
-	    default:
-		if (fg == VT100.COLOR_BLACK)
-			co0 = '80';
-		else
-			co0 = 'c0';
-		co1 = 'c0';
-	}
-	return {
-		f: '#' + (fg & 4 ? co1 : co0) +
-			 (fg & 2 ? co1 : co0) +
-			 (fg & 1 ? co1 : co0),
-		b: '#' + (bg & 4 ? co1 : co0) +
-			 (bg & 2 ? co1 : co0) +
-			 (bg & 1 ? co1 : co0)
-	    };
-}
-
-VT100.prototype.addch = function(ch, attr)
-{
-	var cc = this.col_;
-	this.debug("addch:: ch: " + ch + ", attr: " + attr);
-	switch (ch) {
-	    case '\b':
-		if (cc != 0)
-			--cc;
-		break;
-	    case '\n':
-		++this.row_;
-		cc = 0;
-		this.clrtoeol();
-		this.may_scroll_();
-		break;
-	    case '\r':
-		this.may_scroll_();
-		cc = 0;
-		break;
-	    case '\t':
-		this.may_scroll_();
-		cc += VT100.TABSIZE - cc % VT100.TABSIZE;
-		if (cc >= this.wd_) {
-			++this.row_;
-			cc -= this.wd_;
-		}
-		break;
-	    default:
-		if (attr === undefined)
-			attr = this._cloneAttr(this.c_attr_);
-		if (cc >= this.wd_) {
-			++this.row_;
-			cc = 0;
-		}
-		this.may_scroll_();
-		this.text_[this.row_][cc] = ch;
-		this.attr_[this.row_][cc] = attr;
-		++cc;
-	}
-	this.col_ = cc;
-}
-
-VT100.prototype.addstr = function(stuff)
-{
-	for (var i = 0; i < stuff.length; ++i)
-		this.addch(stuff.charAt(i));
-}
-
-VT100.prototype._cloneAttr = function VT100_cloneAttr(a)
-{
-	return {
-		mode: a.mode,
-		fg: a.fg,
-		bg: a.bg
-	};
-}
-
-VT100.prototype.attroff = function(a)
-{
-	//dump("attroff: " + a + "\n");
-	a &= VT100.ATTR_FLAGS_;
-	this.c_attr_.mode &= ~a;
-}
-
-VT100.prototype.attron = function(a)
-{
-	//dump("attron: " + a + "\n");
-	a &= VT100.ATTR_FLAGS_;
-	this.c_attr_.mode |= a;
-}
-
-VT100.prototype.attrset = function(a)
-{
-	//dump("attrset: " + a + "\n");
-	this.c_attr_.mode = a;
-}
-
-VT100.prototype.fgset = function(fg)
-{
-	//dump("fgset: " + fg + "\n");
-	this.c_attr_.fg = fg;
-}
-
-VT100.prototype.bgset = function(bg)
-{
-	//dump("bgset: " + bg + "\n");
-	if (bg !== 0) {
-            this.warn("bgset: " + bg + "\n");
-        }
-	this.c_attr_.bg = bg;
-}
-
-VT100.prototype.bkgdset = function(a)
-{
-	this.bkgd_ = a;
-}
-
-VT100.prototype.clear = function()
-{
-	this.debug("clear");
-	this.row_ = this.col_ = 0;
-	this.scrolled_ = 0;
-	for (r = 0; r < this.ht_; ++r) {
-		for (c = 0; c < this.wd_; ++c) {
-			this.text_[r][c] = ' ';
-			this.attr_[r][c] = this._cloneAttr(this.bkgd_);
-		}
-	}
-}
-
-VT100.prototype.clrtobot = function()
-{
-	this.debug("clrtobot, row: " + this.row_);
-	var ht = this.ht_;
-	var wd = this.wd_;
-	this.clrtoeol();
-	for (var r = this.row_ + 1; r < ht; ++r) {
-		for (var c = 0; c < wd; ++c) {
-			this.text_[r][c] = ' ';
-			this.attr_[r][c] = this.bkgd_;
-		}
-	}
-}
-
-VT100.prototype.clrtoeol = function()
-{
-	this.debug("clrtoeol, col: " + this.col_);
-	var r = this.row_;
-	if (r >= this.ht_)
-		return;
-	for (var c = this.col_; c < this.wd_; ++c) {
-		this.text_[r][c] = ' ';
-		this.attr_[r][c] = this.bkgd_;
-	}
-}
-
-VT100.prototype.clearpos = function(row, col)
-{
-	this.debug("clearpos (" + row + ", " + col + ")");
-	if (row < 0 || row >= this.ht_)
-		return;
-	if (col < 0 || col >= this.wd_)
-		return;
-	this.text_[row][col] = ' ';
-	this.attr_[row][col] = this.bkgd_;
-}
-
-VT100.prototype.curs_set = function(vis, grab, eventist)
-{
-	this.debug("curs_set:: vis: " + vis + ", grab: " + grab);
-	if (vis !== undefined)
-		this.cursor_vis_ = (vis > 0);
-	if (eventist === undefined)
-		eventist = window;
-	if (grab === true || grab === false) {
-		if (grab === this.grab_events_)
-			return;
-		if (grab) {
-			this.grab_events_ = true;
-			VT100.the_vt_ = this;
-			eventist.addEventListener("keypress", VT100.handle_onkeypress_, false);
-			if (VT100.browser_ie_)
-				document.onkeydown = VT100.handle_onkeydown_;
-		} else {
-			eventist.removeEventListener("keypress", VT100.handle_onkeypress_, false);
-			if (VT100.browser_ie_)
-				document.onkeydown = VT100.handle_onkeydown_;
-			this.grab_events_ = false;
-			VT100.the_vt_ = undefined;
-		}
-	}
-}
-
-VT100.prototype.echo = function()
-{
-	this.debug("echo on");
-	this.echo_ = true;
-}
-
-VT100.prototype.erase = VT100.prototype.clear;
-
-VT100.prototype.getch = function(isr)
-{
-	this.debug("getch");
-	this.refresh();
-	this.getch_isr_ = isr;
-	setTimeout(VT100.go_getch_, 0);
-}
-
-VT100.prototype.getmaxyx = function()
-{
-	return { y: this.ht_ - 1, x: this.wd_ - 1 };
-}
-
-VT100.prototype.getyx = function()
-{
-	return { y: this.row_, x: this.col_ };
-}
-
-VT100.prototype.move = function(r, c)
-{
-	this.debug("move: (" + r + ", " + c + ")");
-	if (r < 0)
-		r = 0;
-	else if (r >= this.ht_)
-		r = this.ht_ - 1;
-	if (c < 0)
-		c = 0;
-	else if (c >= this.wd_)
-		c = this.wd_ - 1;
-	this.row_ = r;
-	this.col_ = c;
-}
-
-VT100.prototype.noecho = function()
-{
-	this.debug("echo off");
-	this.echo_ = false;
-}
-
-VT100.prototype.refresh = function()
-{
-	this.debug("refresh");
-	var r, c, stuff = "", start_tag = "", end_tag = "", at = -1, n_at, ch,
-	    pair, cr, cc, ht, wd, cv, added_end_tag;
-	ht = this.ht_;
-	wd = this.wd_;
-	cr = this.row_;
-	cc = this.col_;
-	cv = this.cursor_vis_;
-	var innerHTML = this.scr_.innerHTML;
-	if (cc >= wd)
-		cc = wd - 1;
-	for (r = 0; r < ht; ++r) {
-		if (r > 0) {
-			stuff += '\n';
-		}
-		for (c = 0; c < wd; ++c) {
-			added_end_tag = false;
-			n_at = this.attr_[r][c];
-			if (cv && r == cr && c == cc) {
-				// Draw the cursor here.
-				n_at = this._cloneAttr(n_at);
-				n_at.mode ^= VT100.A_REVERSE;
-			}
-			// If the attributes changed, make a new span.
-			if (n_at.mode != at.mode || n_at.fg != at.fg || n_at.bg != at.bg) {
-				if (c > 0) {
-					stuff += end_tag;
-				}
-				start_tag = "";
-				end_tag = "";
-				if (n_at.mode & VT100.A_BLINK) {
-					start_tag = "<blink>";
-					end_tag = "</blink>" + end_tag;
-				}
-				if (n_at.mode & VT100.A_STANDOUT)
-					n_at.mode |= VT100.A_BOLD;
-				pair = this.html_colours_(n_at);
-				start_tag += '<span style="color:' + pair.f +
-				             ';background-color:' + pair.b;
-				if (n_at.mode & VT100.A_UNDERLINE)
-					start_tag += ';text-decoration:underline';
-				start_tag += ';">';
-				stuff += start_tag;
-				end_tag = "</span>" + end_tag;
-				at = n_at;
-				added_end_tag = true;
-			} else if (c == 0) {
-				stuff += start_tag;
-			}
-			ch = this.text_[r][c];
-			switch (ch) {
-			    case '&':
-				stuff += '&amp;';	break;
-			    case '<':
-				stuff += '&lt;';	break;
-			    case '>':
-				stuff += '&gt;';	break;
-			    case ' ':
-				//stuff += '&nbsp;';	break;
-				stuff += ' ';	break;
-			    default:
-				stuff += ch;
-			}
-		}
-		if (!added_end_tag)
-			stuff += end_tag;
-	}
-	this.scr_.innerHTML = "<b>" + stuff + "</b>\n";
-}
-
-VT100.prototype.scroll = function()
-{
-	this.scrolled_ += 1;
-	this.debug("scrolled: " + this.scrolled_);
-	var n_text = this.text_[0], n_attr = this.attr_[0],
-	    ht = this.ht_, wd = this.wd_;
-	for (var r = 1; r < ht; ++r) {
-		this.text_[r - 1] = this.text_[r];
-		this.attr_[r - 1] = this.attr_[r];
-	}
-	this.text_[ht - 1] = n_text;
-	this.attr_[ht - 1] = n_attr;
-	for (var c = 0; c < wd; ++c) {
-		n_text[c] = ' ';
-		n_attr[c] = this.bkgd_;
-	}
-}
-
-VT100.prototype.standend = function()
-{
-	//this.debug("standend");
-	this.attrset(0);
-}
-
-VT100.prototype.standout = function()
-{
-	//this.debug("standout");
-	this.attron(VT100.A_STANDOUT);
-}
-
-VT100.prototype.write = function(stuff)
-{
-	var ch, x, r, c, i, j, yx, myx;
-	for (i = 0; i < stuff.length; ++i) {
-		ch = stuff.charAt(i);
-		if (ch == '\x0D') {
-			this.debug("write:: ch: " + ch.charCodeAt(0) + ", '\\x0D'");
-		} else {
-			this.debug("write:: ch: " + ch.charCodeAt(0) + ", '" + (ch == '\x1b' ? "ESC" : ch) + "'");
-		}
-		//dump("ch: " + ch.charCodeAt(0) + ", '" + (ch == '\x1b' ? "ESC" : ch) + "'\n");
-		switch (ch) {
-		    case '\x00':
-		    case '\x7f':
-		    case '\x07':  /* bell, ignore it */
-			this.debug("write:: ignoring bell character: " + ch);
-			continue;
-		    case '\a':
-		    case '\b':
-		    case '\t':
-		    case '\r':
-			this.addch(ch);
-			continue;
-		    case '\n':
-		    case '\v':
-		    case '\f': // what a mess
-			yx = this.getyx();
-			myx = this.getmaxyx();
-			if (yx.y >= myx.y) {
-				this.scroll();
-				this.move(myx.y, 0);
-			} else
-				this.move(yx.y + 1, 0);
-			continue;
-		    case '\x18':
-		    case '\x1a':
-			this.esc_state_ = 0;
-			this.debug("write:: set escape state: 0");
-			continue;
-		    case '\x1b':
-			this.esc_state_ = 1;
-			this.debug("write:: set escape state: 1");
-			continue;
-		    case '\x9b':
-			this.esc_state_ = 2;
-			this.debug("write:: set escape state: 2");
-			continue;
-		}
-		// not a recognized control character
-		switch (this.esc_state_) {
-		    case 0: // not in escape sequence
-			this.addch(ch);
-			break;
-		    case 1: // just saw ESC
-			switch (ch) {
-			    case '[':
-				this.esc_state_ = 2;
-				this.debug("write:: set escape state: 2");
-				break;
-			    case '=':
-				/* Set keypade mode (ignored) */
-				this.debug("write:: set keypade mode: ignored");
-				this.esc_state_ = 0;
-				break;
-			    case '>':
-				/* Reset keypade mode (ignored) */
-				this.debug("write:: reset keypade mode: ignored");
-				this.esc_state_ = 0;
-				break;
-			    case 'H':
-				/* Set tab at cursor column (ignored) */
-				this.debug("write:: set tab cursor column: ignored");
-				this.esc_state_ = 0;
-				break;
-			}
-			break;
-		    case 2: // just saw CSI
-			switch (ch) {
-			    case 'K':
-				/* Erase in Line */
-				this.esc_state_ = 0;
-				this.clrtoeol();
-				continue;
-			    case 'H':
-				/* Move to (0,0). */
-				this.esc_state_ = 0;
-				this.move(0, 0);
-				continue;
-			    case 'J':
-				/* Clear to the bottom. */
-				this.esc_state_ = 0;
-				this.clrtobot();
-				continue;
-			    case '?':
-				/* Special VT100 mode handling. */
-				this.esc_state_ = 5;
-				this.debug("write:: special vt100 mode");
-				continue;
-			}
-			// Drop through to next case.
-			this.csi_parms_ = [0];
-			this.debug("write:: set escape state: 3");
-			this.esc_state_ = 3;
-		    case 3: // saw CSI and parameters
-			switch (ch) {
-			    case '0':
-			    case '1':
-			    case '2':
-			    case '3':
-			    case '4':
-			    case '5':
-			    case '6':
-			    case '7':
-			    case '8':
-			    case '9':
-				x = this.csi_parms_.pop();
-				this.csi_parms_.push(x * 10 + ch * 1);
-				this.debug("csi_parms_: " + this.csi_parms_);
-				continue;
-			    case ';':
-				if (this.csi_parms_.length < 17)
-					this.csi_parms_.push(0);
-				continue;
-			}
-			this.esc_state_ = 0;
-			switch (ch) {
-			    case 'A':
-				// Cursor Up 		<ESC>[{COUNT}A
-				this.move(this.row_ - Math.max(1, this.csi_parms_[0]),
-					  this.col_);
-				break;
-			    case 'B':
-				// Cursor Down 		<ESC>[{COUNT}B
-				this.move(this.row_ + Math.max(1, this.csi_parms_[0]),
-					  this.col_);
-				break;
-			    case 'C':
-				// Cursor Forward 	<ESC>[{COUNT}C
-				this.move(this.row_,
-					  this.col_ + Math.max(1, this.csi_parms_[0]));
-				break;
-			    case 'c':
-				this.warn("write:: got TERM query");
-                                break;
-			    case 'D':
-				// Cursor Backward 	<ESC>[{COUNT}D
-				this.move(this.row_,
-					  this.col_ - Math.max(1, this.csi_parms_[0]));
-				break;
-			    case 'f':
-			    case 'H':
-				// Cursor Home 		<ESC>[{ROW};{COLUMN}H
-				this.csi_parms_.push(0);
-				this.move(this.csi_parms_[0] - 1,
-					  this.csi_parms_[1] - 1);
-				break;
-			    case 'J':
-				switch (this.csi_parms_[0]) {
-				    case 0:
-					this.clrtobot();
-					break;
-				    case 2:
-					this.clear();
-					this.move(0, 0);
-				}
-				break;
-			    case 'm':
-				for (j=0; j<this.csi_parms_.length; ++j) {
-					x = this.csi_parms_[j];
-					switch (x) {
-					    case 0:
-						this.standend();
-						this.fgset(this.bkgd_.fg);
-						this.bgset(this.bkgd_.bg);
-						break;
-					    case 1:
-						this.attron(VT100.A_BOLD);
-						break;
-					    case 30:
-						this.fgset(VT100.COLOR_BLACK);
-						break;
-					    case 31:
-						this.fgset(VT100.COLOR_RED);
-						break;
-					    case 32:
-						this.fgset(VT100.COLOR_GREEN);
-						break;
-					    case 33:
-						this.fgset(VT100.COLOR_YELLOW);
-						break;
-					    case 34:
-						this.fgset(VT100.COLOR_BLUE);
-						break;
-					    case 35:
-						this.fgset(VT100.COLOR_MAGENTA);
-						break;
-					    case 36:
-						this.fgset(VT100.COLOR_CYAN);
-						break;
-					    case 37:
-						this.fgset(VT100.COLOR_WHITE);
-						break;
-					    case 40:
-						this.bgset(VT100.COLOR_BLACK);
-						break;
-					    case 41:
-						this.bgset(VT100.COLOR_RED);
-						break;
-					    case 42:
-						this.bgset(VT100.COLOR_GREEN);
-						break;
-					    case 44:
-						this.bgset(VT100.COLOR_YELLOW);
-						break;
-					    case 44:
-						this.bgset(VT100.COLOR_BLUE);
-						break;
-					    case 45:
-						this.bgset(VT100.COLOR_MAGENTA);
-						break;
-					    case 46:
-						this.bgset(VT100.COLOR_CYAN);
-						break;
-					    case 47:
-						this.bgset(VT100.COLOR_WHITE);
-						break;
-					}
-				}
-				break;
-			    case 'r':
-				// 1,24r - set scrolling region (ignored)
-				break;
-			    case '[':
-				this.debug("write:: set escape state: 4");
-				this.esc_state_ = 4;
-				break;
-			    case 'g':
-				// 0g: clear tab at cursor (ignored)
-				// 3g: clear all tabs (ignored)
-				break;
-			    default:
-				this.warn("write:: unknown command: " + ch);
-				this.csi_parms_ = [];
-				break;
-			}
-			break;
-		    case 4: // saw CSI [
-			this.esc_state_ = 0; // gobble char.
-			break;
-		    case 5: // Special mode handling, saw <ESC>[?
-			// Expect a number - the reset type
-			this.csi_parms_ = [ch];
-			this.esc_state_ = 6;
-			break;
-		    case 6: // Reset mode handling, saw <ESC>[?1
-			// Expect a letter - the mode target, example:
-			// <ESC>[?1l : cursor key mode = cursor
-			// <ESC>[?1h : save current screen, create new empty
-			//             screen and position at 0,0
-			// <ESC>[?5l : White on blk
-			// XXX: Ignored for now.
-			//dump("Saw reset mode: <ESC>[?" + this.csi_parms_[0] + ch + "\n");
-			this.esc_state_ = 0;
-			this.debug("write:: set escape state: 0");
-			break;
-		}
-	}
-	this.refresh();
-}
-
-VT100.prototype.debug = function(message) {
-	if (this.debug_) {
-		dump(message + "\n");
-	}
-}
-
-VT100.prototype.warn = function(message) {
-	dump(message + "\n");
-}

+ 0 - 1
utils/include

@@ -1 +0,0 @@
-../include

+ 0 - 466
utils/md5.c

@@ -1,466 +0,0 @@
-/* Functions to compute MD5 message digest of files or memory blocks.
-   according to the definition of MD5 in RFC 1321 from April 1992.
-   Copyright (C) 1995,1996,1997,1999,2000,2001,2005
-    Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sys/types.h>
-
-#if STDC_HEADERS || defined _LIBC
-# include <stdlib.h>
-# include <string.h>
-#else
-# ifndef HAVE_MEMCPY
-#  define memcpy(d, s, n) (bcopy ((s), (d), (n)), (d))
-# endif
-#endif
-
-#ifndef __THROW
-#define __THROW
-#endif
-
-#include "md5.h"
-
-#ifdef _LIBC
-# include <endian.h>
-# if __BYTE_ORDER == __BIG_ENDIAN
-#  define WORDS_BIGENDIAN 1
-# endif
-/* We need to keep the namespace clean so define the MD5 function
-   protected using leading __ .  */
-# define md5_init_ctx __md5_init_ctx
-# define md5_process_block __md5_process_block
-# define md5_process_bytes __md5_process_bytes
-# define md5_finish_ctx __md5_finish_ctx
-# define md5_read_ctx __md5_read_ctx
-# define md5_stream __md5_stream
-# define md5_buffer __md5_buffer
-#else
-/* Squelch compiler complaints */
-void md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx);
-void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx);
-#endif
-
-#ifdef WORDS_BIGENDIAN
-# define SWAP(n)                                                        \
-    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
-#else
-# define SWAP(n) (n)
-#endif
-
-
-/* This array contains the bytes used to pad the buffer to the next
-   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
-static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
-
-
-/* Initialize structure containing state of computation.
-   (RFC 1321, 3.3: Step 3)  */
-void
-md5_init_ctx (ctx)
-     struct md5_ctx *ctx;
-{
-  ctx->A = 0x67452301;
-  ctx->B = 0xefcdab89;
-  ctx->C = 0x98badcfe;
-  ctx->D = 0x10325476;
-
-  ctx->total[0] = ctx->total[1] = 0;
-  ctx->buflen = 0;
-}
-
-/* Put result from CTX in first 16 bytes following RESBUF.  The result
-   must be in little endian byte order.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-void *
-md5_read_ctx (ctx, resbuf)
-     const struct md5_ctx *ctx;
-     void *resbuf;
-{
-  ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
-  ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
-  ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
-  ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
-
-  return resbuf;
-}
-
-/* Process the remaining bytes in the internal buffer and the usual
-   prolog according to the standard and write the result to RESBUF.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-void *
-md5_finish_ctx (ctx, resbuf)
-     struct md5_ctx *ctx;
-     void *resbuf;
-{
-  /* Take yet unprocessed bytes into account.  */
-  md5_uint32 bytes = ctx->buflen;
-  size_t pad;
-
-  /* Now count remaining bytes.  */
-  ctx->total[0] += bytes;
-  if (ctx->total[0] < bytes)
-    ++ctx->total[1];
-
-  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
-  memcpy (&ctx->buffer[bytes], fillbuf, pad);
-
-  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
-  *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
-  *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
-                            (ctx->total[0] >> 29));
-
-  /* Process last bytes.  */
-  md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
-
-  return md5_read_ctx (ctx, resbuf);
-}
-
-/* Compute MD5 message digest for bytes read from STREAM.  The
-   resulting message digest number will be written into the 16 bytes
-   beginning at RESBLOCK.  */
-int
-md5_stream (stream, resblock)
-     FILE *stream;
-     void *resblock;
-{
-  /* Important: BLOCKSIZE must be a multiple of 64.  */
-#define BLOCKSIZE 4096
-  struct md5_ctx ctx;
-  char buffer[BLOCKSIZE + 72];
-  size_t sum;
-
-  /* Initialize the computation context.  */
-  md5_init_ctx (&ctx);
-
-  /* Iterate over full file contents.  */
-  while (1)
-    {
-      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-     computation function processes the whole buffer so that with the
-     next round of the loop another block can be read.  */
-      size_t n;
-      sum = 0;
-
-      /* Read block.  Take care for partial reads.  */
-      do
-    {
-      n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-      sum += n;
-    }
-      while (sum < BLOCKSIZE && n != 0);
-      if (n == 0 && ferror (stream))
-        return 1;
-
-      /* If end of file is reached, end the loop.  */
-      if (n == 0)
-    break;
-
-      /* Process buffer with BLOCKSIZE bytes.  Note that
-            BLOCKSIZE % 64 == 0
-       */
-      md5_process_block (buffer, BLOCKSIZE, &ctx);
-    }
-
-  /* Add the last bytes if necessary.  */
-  if (sum > 0)
-    md5_process_bytes (buffer, sum, &ctx);
-
-  /* Construct result in desired memory.  */
-  md5_finish_ctx (&ctx, resblock);
-  return 0;
-}
-
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
-   result is always in little endian byte order, so that a byte-wise
-   output yields to the wanted ASCII representation of the message
-   digest.  */
-void *
-md5_buffer (buffer, len, resblock)
-     const char *buffer;
-     size_t len;
-     void *resblock;
-{
-  struct md5_ctx ctx;
-
-  /* Initialize the computation context.  */
-  md5_init_ctx (&ctx);
-
-  /* Process whole buffer but last len % 64 bytes.  */
-  md5_process_bytes (buffer, len, &ctx);
-
-  /* Put result in desired memory area.  */
-  return md5_finish_ctx (&ctx, resblock);
-}
-
-
-void
-md5_process_bytes (buffer, len, ctx)
-     const void *buffer;
-     size_t len;
-     struct md5_ctx *ctx;
-{
-  /* When we already have some bits in our internal buffer concatenate
-     both inputs first.  */
-  if (ctx->buflen != 0)
-    {
-      size_t left_over = ctx->buflen;
-      size_t add = 128 - left_over > len ? len : 128 - left_over;
-
-      memcpy (&ctx->buffer[left_over], buffer, add);
-      ctx->buflen += add;
-
-      if (ctx->buflen > 64)
-    {
-      md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
-
-      ctx->buflen &= 63;
-      /* The regions in the following copy operation cannot overlap.  */
-      memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
-          ctx->buflen);
-    }
-
-      buffer = (const char *) buffer + add;
-      len -= add;
-    }
-
-  /* Process available complete blocks.  */
-  if (len >= 64)
-    {
-#if !_STRING_ARCH_unaligned
-/* To check alignment gcc has an appropriate operator.  Other
-   compilers don't.  */
-# if __GNUC__ >= 2
-#  define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0)
-# else
-#  define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0)
-# endif
-      if (UNALIGNED_P (buffer))
-    while (len > 64)
-      {
-        md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
-        buffer = (const char *) buffer + 64;
-        len -= 64;
-      }
-      else
-#endif
-    {
-      md5_process_block (buffer, len & ~63, ctx);
-      buffer = (const char *) buffer + (len & ~63);
-      len &= 63;
-    }
-    }
-
-  /* Move remaining bytes in internal buffer.  */
-  if (len > 0)
-    {
-      size_t left_over = ctx->buflen;
-
-      memcpy (&ctx->buffer[left_over], buffer, len);
-      left_over += len;
-      if (left_over >= 64)
-    {
-      md5_process_block (ctx->buffer, 64, ctx);
-      left_over -= 64;
-      memcpy (ctx->buffer, &ctx->buffer[64], left_over);
-    }
-      ctx->buflen = left_over;
-    }
-}
-
-
-/* These are the four functions used in the four steps of the MD5 algorithm
-   and defined in the RFC 1321.  The first function is a little bit optimized
-   (as found in Colin Plumbs public domain implementation).  */
-/* #define FF(b, c, d) ((b & c) | (~b & d)) */
-#define FF(b, c, d) (d ^ (b & (c ^ d)))
-#define FG(b, c, d) FF (d, b, c)
-#define FH(b, c, d) (b ^ c ^ d)
-#define FI(b, c, d) (c ^ (b | ~d))
-
-/* Process LEN bytes of BUFFER, accumulating context into CTX.
-   It is assumed that LEN % 64 == 0.  */
-
-void
-md5_process_block (buffer, len, ctx)
-     const void *buffer;
-     size_t len;
-     struct md5_ctx *ctx;
-{
-  md5_uint32 correct_words[16];
-  const md5_uint32 *words = buffer;
-  size_t nwords = len / sizeof (md5_uint32);
-  const md5_uint32 *endp = words + nwords;
-  md5_uint32 A = ctx->A;
-  md5_uint32 B = ctx->B;
-  md5_uint32 C = ctx->C;
-  md5_uint32 D = ctx->D;
-
-  /* First increment the byte count.  RFC 1321 specifies the possible
-     length of the file up to 2^64 bits.  Here we only compute the
-     number of bytes.  Do a double word increment.  */
-  ctx->total[0] += len;
-  if (ctx->total[0] < len)
-    ++ctx->total[1];
-
-  /* Process all bytes in the buffer with 64 bytes in each round of
-     the loop.  */
-  while (words < endp)
-    {
-      md5_uint32 *cwp = correct_words;
-      md5_uint32 A_save = A;
-      md5_uint32 B_save = B;
-      md5_uint32 C_save = C;
-      md5_uint32 D_save = D;
-
-      /* First round: using the given function, the context and a constant
-     the next context is computed.  Because the algorithms processing
-     unit is a 32-bit word and it is determined to work on words in
-     little endian byte order we perhaps have to change the byte order
-     before the computation.  To reduce the work for the next steps
-     we store the swapped words in the array CORRECT_WORDS.  */
-
-#define OP(a, b, c, d, s, T)                                            \
-      do                                                                \
-        {                                                               \
-      a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;         \
-      ++words;                                                  \
-      CYCLIC (a, s);                                            \
-      a += b;                                                   \
-        }                                                               \
-      while (0)
-
-      /* It is unfortunate that C does not provide an operator for
-     cyclic rotation.  Hope the C compiler is smart enough.  */
-#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
-
-      /* Before we start, one word to the strange constants.
-     They are defined in RFC 1321 as
-
-     T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
-       */
-
-      /* Round 1.  */
-      OP (A, B, C, D,  7, 0xd76aa478);
-      OP (D, A, B, C, 12, 0xe8c7b756);
-      OP (C, D, A, B, 17, 0x242070db);
-      OP (B, C, D, A, 22, 0xc1bdceee);
-      OP (A, B, C, D,  7, 0xf57c0faf);
-      OP (D, A, B, C, 12, 0x4787c62a);
-      OP (C, D, A, B, 17, 0xa8304613);
-      OP (B, C, D, A, 22, 0xfd469501);
-      OP (A, B, C, D,  7, 0x698098d8);
-      OP (D, A, B, C, 12, 0x8b44f7af);
-      OP (C, D, A, B, 17, 0xffff5bb1);
-      OP (B, C, D, A, 22, 0x895cd7be);
-      OP (A, B, C, D,  7, 0x6b901122);
-      OP (D, A, B, C, 12, 0xfd987193);
-      OP (C, D, A, B, 17, 0xa679438e);
-      OP (B, C, D, A, 22, 0x49b40821);
-
-      /* For the second to fourth round we have the possibly swapped words
-     in CORRECT_WORDS.  Redefine the macro to take an additional first
-     argument specifying the function to use.  */
-#undef OP
-#define OP(f, a, b, c, d, k, s, T)                                      \
-      do                                                                \
-    {                                                           \
-      a += f (b, c, d) + correct_words[k] + T;                  \
-      CYCLIC (a, s);                                            \
-      a += b;                                                   \
-    }                                                           \
-      while (0)
-
-      /* Round 2.  */
-      OP (FG, A, B, C, D,  1,  5, 0xf61e2562);
-      OP (FG, D, A, B, C,  6,  9, 0xc040b340);
-      OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
-      OP (FG, B, C, D, A,  0, 20, 0xe9b6c7aa);
-      OP (FG, A, B, C, D,  5,  5, 0xd62f105d);
-      OP (FG, D, A, B, C, 10,  9, 0x02441453);
-      OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
-      OP (FG, B, C, D, A,  4, 20, 0xe7d3fbc8);
-      OP (FG, A, B, C, D,  9,  5, 0x21e1cde6);
-      OP (FG, D, A, B, C, 14,  9, 0xc33707d6);
-      OP (FG, C, D, A, B,  3, 14, 0xf4d50d87);
-      OP (FG, B, C, D, A,  8, 20, 0x455a14ed);
-      OP (FG, A, B, C, D, 13,  5, 0xa9e3e905);
-      OP (FG, D, A, B, C,  2,  9, 0xfcefa3f8);
-      OP (FG, C, D, A, B,  7, 14, 0x676f02d9);
-      OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
-
-      /* Round 3.  */
-      OP (FH, A, B, C, D,  5,  4, 0xfffa3942);
-      OP (FH, D, A, B, C,  8, 11, 0x8771f681);
-      OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
-      OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
-      OP (FH, A, B, C, D,  1,  4, 0xa4beea44);
-      OP (FH, D, A, B, C,  4, 11, 0x4bdecfa9);
-      OP (FH, C, D, A, B,  7, 16, 0xf6bb4b60);
-      OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
-      OP (FH, A, B, C, D, 13,  4, 0x289b7ec6);
-      OP (FH, D, A, B, C,  0, 11, 0xeaa127fa);
-      OP (FH, C, D, A, B,  3, 16, 0xd4ef3085);
-      OP (FH, B, C, D, A,  6, 23, 0x04881d05);
-      OP (FH, A, B, C, D,  9,  4, 0xd9d4d039);
-      OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
-      OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
-      OP (FH, B, C, D, A,  2, 23, 0xc4ac5665);
-
-      /* Round 4.  */
-      OP (FI, A, B, C, D,  0,  6, 0xf4292244);
-      OP (FI, D, A, B, C,  7, 10, 0x432aff97);
-      OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
-      OP (FI, B, C, D, A,  5, 21, 0xfc93a039);
-      OP (FI, A, B, C, D, 12,  6, 0x655b59c3);
-      OP (FI, D, A, B, C,  3, 10, 0x8f0ccc92);
-      OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
-      OP (FI, B, C, D, A,  1, 21, 0x85845dd1);
-      OP (FI, A, B, C, D,  8,  6, 0x6fa87e4f);
-      OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
-      OP (FI, C, D, A, B,  6, 15, 0xa3014314);
-      OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
-      OP (FI, A, B, C, D,  4,  6, 0xf7537e82);
-      OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
-      OP (FI, C, D, A, B,  2, 15, 0x2ad7d2bb);
-      OP (FI, B, C, D, A,  9, 21, 0xeb86d391);
-
-      /* Add the starting values of the context.  */
-      A += A_save;
-      B += B_save;
-      C += C_save;
-      D += D_save;
-    }
-
-  /* Put checksum in context given as argument.  */
-  ctx->A = A;
-  ctx->B = B;
-  ctx->C = C;
-  ctx->D = D;
-}

+ 0 - 148
utils/md5.h

@@ -1,148 +0,0 @@
-/* Declaration of functions and data types used for MD5 sum computing
-   library functions.
-   Copyright (C) 1995-1997,1999,2000,2001,2004,2005
-      Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#ifndef _MD5_H
-#define _MD5_H 1
-
-#include <stdio.h>
-
-#if defined HAVE_LIMITS_H || _LIBC
-# include <limits.h>
-#endif
-
-#define MD5_DIGEST_SIZE 16
-#define MD5_BLOCK_SIZE 64
-
-/* The following contortions are an attempt to use the C preprocessor
-   to determine an unsigned integral type that is 32 bits wide.  An
-   alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
-   doing that would require that the configure script compile and *run*
-   the resulting executable.  Locally running cross-compiled executables
-   is usually not possible.  */
-
-#ifdef _LIBC
-# include <stdint.h>
-typedef uint32_t md5_uint32;
-typedef uintptr_t md5_uintptr;
-#else
-# if defined __STDC__ && __STDC__
-#  define UINT_MAX_32_BITS 4294967295U
-# else
-#  define UINT_MAX_32_BITS 0xFFFFFFFF
-# endif
-
-/* If UINT_MAX isn't defined, assume it's a 32-bit type.
-   This should be valid for all systems GNU cares about because
-   that doesn't include 16-bit systems, and only modern systems
-   (that certainly have <limits.h>) have 64+-bit integral types.  */
-
-# ifndef UINT_MAX
-#  define UINT_MAX UINT_MAX_32_BITS
-# endif
-
-# if UINT_MAX == UINT_MAX_32_BITS
-   typedef unsigned int md5_uint32;
-# else
-#  if USHRT_MAX == UINT_MAX_32_BITS
-    typedef unsigned short md5_uint32;
-#  else
-#   if ULONG_MAX == UINT_MAX_32_BITS
-     typedef unsigned long md5_uint32;
-#   else
-     /* The following line is intended to evoke an error.
-        Using #error is not portable enough.  */
-     "Cannot determine unsigned 32-bit data type."
-#   endif
-#  endif
-# endif
-/* We have to make a guess about the integer type equivalent in size
-   to pointers which should always be correct.  */
-typedef unsigned long int md5_uintptr;
-#endif
-
-/* Structure to save state of computation between the single steps.  */
-struct md5_ctx
-{
-  md5_uint32 A;
-  md5_uint32 B;
-  md5_uint32 C;
-  md5_uint32 D;
-
-  md5_uint32 total[2];
-  md5_uint32 buflen;
-  char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
-};
-
-/*
- * The following three functions are build up the low level used in
- * the functions `md5_stream' and `md5_buffer'.
- */
-
-/* Initialize structure containing state of computation.
-   (RFC 1321, 3.3: Step 3)  */
-extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW;
-
-/* Starting with the result of former calls of this function (or the
-   initialization function update the context for the next LEN bytes
-   starting at BUFFER.
-   It is necessary that LEN is a multiple of 64!!! */
-extern void __md5_process_block (const void *buffer, size_t len,
-                 struct md5_ctx *ctx) __THROW;
-
-/* Starting with the result of former calls of this function (or the
-   initialization function update the context for the next LEN bytes
-   starting at BUFFER.
-   It is NOT required that LEN is a multiple of 64.  */
-extern void __md5_process_bytes (const void *buffer, size_t len,
-                 struct md5_ctx *ctx) __THROW;
-
-/* Process the remaining bytes in the buffer and put result from CTX
-   in first 16 bytes following RESBUF.  The result is always in little
-   endian byte order, so that a byte-wise output yields to the wanted
-   ASCII representation of the message digest.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW;
-
-
-/* Put result from CTX in first 16 bytes following RESBUF.  The result is
-   always in little endian byte order, so that a byte-wise output yields
-   to the wanted ASCII representation of the message digest.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW;
-
-
-/* Compute MD5 message digest for bytes read from STREAM.  The
-   resulting message digest number will be written into the 16 bytes
-   beginning at RESBLOCK.  */
-extern int __md5_stream (FILE *stream, void *resblock) __THROW;
-
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
-   result is always in little endian byte order, so that a byte-wise
-   output yields to the wanted ASCII representation of the message
-   digest.  */
-extern void *__md5_buffer (const char *buffer, size_t len,
-               void *resblock) __THROW;
-
-#endif /* md5.h */

+ 0 - 3
utils/md5_test.c

@@ -1,3 +0,0 @@
-int main () {
-    printf("hello world\n");
-}

+ 0 - 556
utils/websocket.c

@@ -1,556 +0,0 @@
-/*
- * WebSocket lib with support for "wss://" encryption.
- * Copyright 2010 Joel Martin
- * Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
- *
- * You can make a cert/key with openssl using:
- * openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
- * as taken from http://docs.python.org/dev/library/ssl.html#certificates
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <strings.h>
-#include <sys/types.h> 
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <signal.h> // daemonizing
-#include <fcntl.h>  // daemonizing
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-#include <resolv.h>      /* base64 encode/decode */
-#include "websocket.h"
-
-const char server_handshake[] = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n\
-Upgrade: WebSocket\r\n\
-Connection: Upgrade\r\n\
-%sWebSocket-Origin: %s\r\n\
-%sWebSocket-Location: %s://%s%s\r\n\
-%sWebSocket-Protocol: sample\r\n\
-\r\n%s";
-
-const char policy_response[] = "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\n";
-
-/*
- * Global state
- *
- *   Warning: not thread safe
- */
-int ssl_initialized = 0;
-int pipe_error = 0;
-char *tbuf, *cbuf, *tbuf_tmp, *cbuf_tmp;
-unsigned int bufsize, dbufsize;
-settings_t settings;
-
-void traffic(char * token) {
-    if ((settings.verbose) && (! settings.daemon)) {
-        fprintf(stdout, "%s", token);
-        fflush(stdout);
-    }
-}
-
-void error(char *msg)
-{
-    perror(msg);
-}
-
-void fatal(char *msg)
-{
-    perror(msg);
-    exit(1);
-}
-
-/* resolve host with also IP address parsing */ 
-int resolve_host(struct in_addr *sin_addr, const char *hostname) 
-{ 
-    if (!inet_aton(hostname, sin_addr)) { 
-        struct addrinfo *ai, *cur; 
-        struct addrinfo hints; 
-        memset(&hints, 0, sizeof(hints)); 
-        hints.ai_family = AF_INET; 
-        if (getaddrinfo(hostname, NULL, &hints, &ai)) 
-            return -1; 
-        for (cur = ai; cur; cur = cur->ai_next) { 
-            if (cur->ai_family == AF_INET) { 
-                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr; 
-                freeaddrinfo(ai); 
-                return 0; 
-            } 
-        } 
-        freeaddrinfo(ai); 
-        return -1; 
-    } 
-    return 0; 
-} 
-
-
-/*
- * SSL Wrapper Code
- */
-
-ssize_t ws_recv(ws_ctx_t *ctx, void *buf, size_t len) {
-    if (ctx->ssl) {
-        //handler_msg("SSL recv\n");
-        return SSL_read(ctx->ssl, buf, len);
-    } else {
-        return recv(ctx->sockfd, buf, len, 0);
-    }
-}
-
-ssize_t ws_send(ws_ctx_t *ctx, const void *buf, size_t len) {
-    if (ctx->ssl) {
-        //handler_msg("SSL send\n");
-        return SSL_write(ctx->ssl, buf, len);
-    } else {
-        return send(ctx->sockfd, buf, len, 0);
-    }
-}
-
-ws_ctx_t *ws_socket(int socket) {
-    ws_ctx_t *ctx;
-    ctx = malloc(sizeof(ws_ctx_t));
-    ctx->sockfd = socket;
-    ctx->ssl = NULL;
-    ctx->ssl_ctx = NULL;
-    return ctx;
-}
-
-ws_ctx_t *ws_socket_ssl(int socket, char * certfile, char * keyfile) {
-    int ret;
-    char msg[1024];
-    char * use_keyfile;
-    ws_ctx_t *ctx;
-    ctx = ws_socket(socket);
-
-    if (keyfile && (keyfile[0] != '\0')) {
-        // Separate key file
-        use_keyfile = keyfile;
-    } else {
-        // Combined key and cert file
-        use_keyfile = certfile;
-    }
-
-    // Initialize the library
-    if (! ssl_initialized) {
-        SSL_library_init();
-        OpenSSL_add_all_algorithms();
-        SSL_load_error_strings();
-        ssl_initialized = 1;
-
-    }
-
-    ctx->ssl_ctx = SSL_CTX_new(TLSv1_server_method());
-    if (ctx->ssl_ctx == NULL) {
-        ERR_print_errors_fp(stderr);
-        fatal("Failed to configure SSL context");
-    }
-
-    if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, use_keyfile,
-                                    SSL_FILETYPE_PEM) <= 0) {
-        sprintf(msg, "Unable to load private key file %s\n", use_keyfile);
-        fatal(msg);
-    }
-
-    if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, certfile,
-                                     SSL_FILETYPE_PEM) <= 0) {
-        sprintf(msg, "Unable to load certificate file %s\n", certfile);
-        fatal(msg);
-    }
-
-//    if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, "DEFAULT") != 1) {
-//        sprintf(msg, "Unable to set cipher\n");
-//        fatal(msg);
-//    }
-
-    // Associate socket and ssl object
-    ctx->ssl = SSL_new(ctx->ssl_ctx);
-    SSL_set_fd(ctx->ssl, socket);
-
-    ret = SSL_accept(ctx->ssl);
-    if (ret < 0) {
-        ERR_print_errors_fp(stderr);
-        return NULL;
-    }
-
-    return ctx;
-}
-
-int ws_socket_free(ws_ctx_t *ctx) {
-    if (ctx->ssl) {
-        SSL_free(ctx->ssl);
-        ctx->ssl = NULL;
-    }
-    if (ctx->ssl_ctx) {
-        SSL_CTX_free(ctx->ssl_ctx);
-        ctx->ssl_ctx = NULL;
-    }
-    if (ctx->sockfd) {
-        shutdown(ctx->sockfd, SHUT_RDWR);
-        close(ctx->sockfd);
-        ctx->sockfd = 0;
-    }
-    free(ctx);
-}
-
-/* ------------------------------------------------------- */
-
-
-int encode(u_char const *src, size_t srclength, char *target, size_t targsize) {
-    int i, sz = 0, len = 0;
-    unsigned char chr;
-    target[sz++] = '\x00';
-    len = b64_ntop(src, srclength, target+sz, targsize-sz);
-    if (len < 0) {
-        return len;
-    }
-    sz += len;
-    target[sz++] = '\xff';
-    return sz;
-}
-
-int decode(char *src, size_t srclength, u_char *target, size_t targsize) {
-    char *start, *end, cntstr[4];
-    int i, len, framecount = 0, retlen = 0;
-    unsigned char chr;
-    if ((src[0] != '\x00') || (src[srclength-1] != '\xff')) {
-        handler_emsg("WebSocket framing error\n");
-        return -1;
-    }
-    start = src+1; // Skip '\x00' start
-    do {
-        /* We may have more than one frame */
-        end = memchr(start, '\xff', srclength);
-        *end = '\x00';
-        len = b64_pton(start, target+retlen, targsize-retlen);
-        if (len < 0) {
-            return len;
-        }
-        retlen += len;
-        start = end + 2; // Skip '\xff' end and '\x00' start 
-        framecount++;
-    } while (end < (src+srclength-1));
-    if (framecount > 1) {
-        snprintf(cntstr, 3, "%d", framecount);
-        traffic(cntstr);
-    }
-    return retlen;
-}
-
-int parse_handshake(char *handshake, headers_t *headers) {
-    char *start, *end;
-
-    if ((strlen(handshake) < 92) || (bcmp(handshake, "GET ", 4) != 0)) {
-        return 0;
-    }
-    start = handshake+4;
-    end = strstr(start, " HTTP/1.1");
-    if (!end) { return 0; }
-    strncpy(headers->path, start, end-start);
-    headers->path[end-start] = '\0';
-
-    start = strstr(handshake, "\r\nHost: ");
-    if (!start) { return 0; }
-    start += 8;
-    end = strstr(start, "\r\n");
-    strncpy(headers->host, start, end-start);
-    headers->host[end-start] = '\0';
-
-    start = strstr(handshake, "\r\nOrigin: ");
-    if (!start) { return 0; }
-    start += 10;
-    end = strstr(start, "\r\n");
-    strncpy(headers->origin, start, end-start);
-    headers->origin[end-start] = '\0';
-   
-    start = strstr(handshake, "\r\n\r\n");
-    if (!start) { return 0; }
-    start += 4;
-    if (strlen(start) == 8) {
-        strncpy(headers->key3, start, 8);
-        headers->key3[8] = '\0';
-
-        start = strstr(handshake, "\r\nSec-WebSocket-Key1: ");
-        if (!start) { return 0; }
-        start += 22;
-        end = strstr(start, "\r\n");
-        strncpy(headers->key1, start, end-start);
-        headers->key1[end-start] = '\0';
-    
-        start = strstr(handshake, "\r\nSec-WebSocket-Key2: ");
-        if (!start) { return 0; }
-        start += 22;
-        end = strstr(start, "\r\n");
-        strncpy(headers->key2, start, end-start);
-        headers->key2[end-start] = '\0';
-    } else {
-        headers->key1[0] = '\0';
-        headers->key2[0] = '\0';
-        headers->key3[0] = '\0';
-    }
-
-    return 1;
-}
-
-int gen_md5(headers_t *headers, char *target) {
-    unsigned int i, spaces1 = 0, spaces2 = 0;
-    unsigned long num1 = 0, num2 = 0;
-    unsigned char buf[17];
-    for (i=0; i < strlen(headers->key1); i++) {
-        if (headers->key1[i] == ' ') {
-            spaces1 += 1;
-        }
-        if ((headers->key1[i] >= 48) && (headers->key1[i] <= 57)) {
-            num1 = num1 * 10 + (headers->key1[i] - 48);
-        }
-    }
-    num1 = num1 / spaces1;
-
-    for (i=0; i < strlen(headers->key2); i++) {
-        if (headers->key2[i] == ' ') {
-            spaces2 += 1;
-        }
-        if ((headers->key2[i] >= 48) && (headers->key2[i] <= 57)) {
-            num2 = num2 * 10 + (headers->key2[i] - 48);
-        }
-    }
-    num2 = num2 / spaces2;
-
-    /* Pack it big-endian */
-    buf[0] = (num1 & 0xff000000) >> 24;
-    buf[1] = (num1 & 0xff0000) >> 16;
-    buf[2] = (num1 & 0xff00) >> 8;
-    buf[3] =  num1 & 0xff;
-
-    buf[4] = (num2 & 0xff000000) >> 24;
-    buf[5] = (num2 & 0xff0000) >> 16;
-    buf[6] = (num2 & 0xff00) >> 8;
-    buf[7] =  num2 & 0xff;
-
-    strncpy(buf+8, headers->key3, 8);
-    buf[16] = '\0';
-
-    md5_buffer(buf, 16, target);
-    target[16] = '\0';
-
-    return 1;
-}
-
-    
-
-ws_ctx_t *do_handshake(int sock) {
-    char handshake[4096], response[4096], trailer[17];
-    char *scheme, *pre;
-    headers_t headers;
-    int len, ret;
-    ws_ctx_t * ws_ctx;
-
-    // Peek, but don't read the data
-    len = recv(sock, handshake, 1024, MSG_PEEK);
-    handshake[len] = 0;
-    if (len == 0) {
-        handler_msg("ignoring empty handshake\n");
-        return NULL;
-    } else if (bcmp(handshake, "<policy-file-request/>", 22) == 0) {
-        len = recv(sock, handshake, 1024, 0);
-        handshake[len] = 0;
-        handler_msg("sending flash policy response\n");
-        send(sock, policy_response, sizeof(policy_response), 0);
-        return NULL;
-    } else if ((bcmp(handshake, "\x16", 1) == 0) ||
-               (bcmp(handshake, "\x80", 1) == 0)) {
-        // SSL
-        if (!settings.cert) {
-            handler_msg("SSL connection but no cert specified\n");
-            return NULL;
-        } else if (access(settings.cert, R_OK) != 0) {
-            handler_msg("SSL connection but '%s' not found\n",
-                        settings.cert);
-            return NULL;
-        }
-        ws_ctx = ws_socket_ssl(sock, settings.cert, settings.key);
-        if (! ws_ctx) { return NULL; }
-        scheme = "wss";
-        handler_msg("using SSL socket\n");
-    } else if (settings.ssl_only) {
-        handler_msg("non-SSL connection disallowed\n");
-        return NULL;
-    } else {
-        ws_ctx = ws_socket(sock);
-        if (! ws_ctx) { return NULL; }
-        scheme = "ws";
-        handler_msg("using plain (not SSL) socket\n");
-    }
-    len = ws_recv(ws_ctx, handshake, 4096);
-    if (len == 0) {
-        handler_emsg("Client closed during handshake\n");
-        return NULL;
-    }
-    handshake[len] = 0;
-
-    if (!parse_handshake(handshake, &headers)) {
-        handler_emsg("Invalid WS request\n");
-        return NULL;
-    }
-
-    if (headers.key3[0] != '\0') {
-        gen_md5(&headers, trailer);
-        pre = "Sec-";
-        handler_msg("using protocol version 76\n");
-    } else {
-        trailer[0] = '\0';
-        pre = "";
-        handler_msg("using protocol version 75\n");
-    }
-    
-    sprintf(response, server_handshake, pre, headers.origin, pre, scheme,
-            headers.host, headers.path, pre, trailer);
-    //handler_msg("response: %s\n", response);
-    ws_send(ws_ctx, response, strlen(response));
-
-    return ws_ctx;
-}
-
-void signal_handler(sig) {
-    switch (sig) {
-        case SIGHUP: break; // ignore for now
-        case SIGPIPE: pipe_error = 1; break; // handle inline
-        case SIGTERM: exit(0); break;
-    }
-}
-
-void daemonize(int keepfd) {
-    int pid, i;
-
-    umask(0);
-    chdir('/');
-    setgid(getgid());
-    setuid(getuid());
-
-    /* Double fork to daemonize */
-    pid = fork();
-    if (pid<0) { fatal("fork error"); }
-    if (pid>0) { exit(0); }  // parent exits
-    setsid();                // Obtain new process group
-    pid = fork();
-    if (pid<0) { fatal("fork error"); }
-    if (pid>0) { exit(0); }  // parent exits
-
-    /* Signal handling */
-    signal(SIGHUP, signal_handler);   // catch HUP
-    signal(SIGTERM, signal_handler);  // catch kill
-
-    /* Close open files */
-    for (i=getdtablesize(); i>=0; --i) {
-        if (i != keepfd) {
-            close(i);
-        } else if (settings.verbose) {
-            printf("keeping fd %d\n", keepfd);
-        }
-    }
-    i=open("/dev/null", O_RDWR);  // Redirect stdin
-    dup(i);                       // Redirect stdout
-    dup(i);                       // Redirect stderr
-}
-
-
-void start_server() {
-    int lsock, csock, pid, clilen, sopt = 1, i;
-    struct sockaddr_in serv_addr, cli_addr;
-    ws_ctx_t *ws_ctx;
-
-    /* Initialize buffers */
-    bufsize = 65536;
-    if (! (tbuf = malloc(bufsize)) )
-            { fatal("malloc()"); }
-    if (! (cbuf = malloc(bufsize)) )
-            { fatal("malloc()"); }
-    if (! (tbuf_tmp = malloc(bufsize)) )
-            { fatal("malloc()"); }
-    if (! (cbuf_tmp = malloc(bufsize)) )
-            { fatal("malloc()"); }
-
-    lsock = socket(AF_INET, SOCK_STREAM, 0);
-    if (lsock < 0) { error("ERROR creating listener socket"); }
-    bzero((char *) &serv_addr, sizeof(serv_addr));
-    serv_addr.sin_family = AF_INET;
-    serv_addr.sin_port = htons(settings.listen_port);
-
-    /* Resolve listen address */
-    if (settings.listen_host && (settings.listen_host[0] != '\0')) {
-        if (resolve_host(&serv_addr.sin_addr, settings.listen_host) < -1) {
-            fatal("Could not resolve listen address");
-        }
-    } else {
-        serv_addr.sin_addr.s_addr = INADDR_ANY;
-    }
-
-    setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *)&sopt, sizeof(sopt));
-    if (bind(lsock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
-        fatal("ERROR on binding listener socket");
-    }
-    listen(lsock,100);
-
-    signal(SIGPIPE, signal_handler);  // catch pipe
-
-    if (settings.daemon) {
-        daemonize(lsock);
-    }
-
-    // Reep zombies
-    signal(SIGCHLD, SIG_IGN);
-
-    printf("Waiting for connections on %s:%d\n",
-            settings.listen_host, settings.listen_port);
-
-    while (1) {
-        clilen = sizeof(cli_addr);
-        pipe_error = 0;
-        pid = 0;
-        csock = accept(lsock, 
-                       (struct sockaddr *) &cli_addr, 
-                       &clilen);
-        if (csock < 0) {
-            error("ERROR on accept");
-            continue;
-        }
-        handler_msg("got client connection from %s\n",
-                    inet_ntoa(cli_addr.sin_addr));
-        /* base64 is 4 bytes for every 3
-         *    20 for WS '\x00' / '\xff' and good measure  */
-        dbufsize = (bufsize * 3)/4 - 20;
-
-        handler_msg("forking handler process\n");
-        pid = fork();
-
-        if (pid == 0) {  // handler process
-            ws_ctx = do_handshake(csock);
-            if (ws_ctx == NULL) {
-                handler_msg("No connection after handshake\n");
-                break;   // Child process exits
-            }
-
-            settings.handler(ws_ctx);
-            if (pipe_error) {
-                handler_emsg("Closing due to SIGPIPE\n");
-            }
-            break;   // Child process exits
-        } else {         // parent process
-            settings.handler_id += 1;
-        }
-    }
-    if (pid == 0) {
-        if (ws_ctx) {
-            ws_socket_free(ws_ctx);
-        } else {
-            shutdown(csock, SHUT_RDWR);
-            close(csock);
-        }
-        handler_msg("handler exit\n");
-    } else {
-        handler_msg("wsproxy exit\n");
-    }
-
-}
-

+ 0 - 47
utils/websocket.h

@@ -1,47 +0,0 @@
-#include <openssl/ssl.h>
-
-typedef struct {
-    int      sockfd;
-    SSL_CTX *ssl_ctx;
-    SSL     *ssl;
-} ws_ctx_t;
-
-typedef struct {
-    int verbose;
-    char listen_host[256];
-    int listen_port;
-    void (*handler)(ws_ctx_t*);
-    int handler_id;
-    char *cert;
-    char *key;
-    int ssl_only;
-    int daemon;
-} settings_t;
-
-typedef struct {
-    char path[1024+1];
-    char host[1024+1];
-    char origin[1024+1];
-    char key1[1024+1];
-    char key2[1024+1];
-    char key3[8+1];
-} headers_t;
-
-
-ssize_t ws_recv(ws_ctx_t *ctx, void *buf, size_t len);
-
-ssize_t ws_send(ws_ctx_t *ctx, const void *buf, size_t len);
-
-/* base64.c declarations */
-//int b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize);
-//int b64_pton(char const *src, u_char *target, size_t targsize);
-
-#define gen_handler_msg(stream, ...) \
-    if (! settings.daemon) { \
-        fprintf(stream, "  %d: ", settings.handler_id); \
-        fprintf(stream, __VA_ARGS__); \
-    }
-
-#define handler_msg(...) gen_handler_msg(stdout, __VA_ARGS__);
-#define handler_emsg(...) gen_handler_msg(stderr, __VA_ARGS__);
-

+ 308 - 0
utils/websockify

@@ -0,0 +1,308 @@
+#!/usr/bin/python
+
+'''
+A WebSocket to TCP socket proxy with support for "wss://" encryption.
+Copyright 2010 Joel Martin
+Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
+
+You can make a cert/key with openssl using:
+openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
+as taken from http://docs.python.org/dev/library/ssl.html#certificates
+
+'''
+
+import socket, optparse, time, os, sys, subprocess
+from select import select
+from websocket import WebSocketServer
+
+class WebSocketProxy(WebSocketServer):
+    """
+    Proxy traffic to and from a WebSockets client to a normal TCP
+    socket server target. All traffic to/from the client is base64
+    encoded/decoded to allow binary data to be sent/received to/from
+    the target.
+    """
+
+    buffer_size = 65536
+
+    traffic_legend = """
+Traffic Legend:
+    }  - Client receive
+    }. - Client receive partial
+    {  - Target receive
+
+    >  - Target send
+    >. - Target send partial
+    <  - Client send
+    <. - Client send partial
+"""
+
+    def __init__(self, *args, **kwargs):
+        # Save off proxy specific options
+        self.target_host   = kwargs.pop('target_host')
+        self.target_port   = kwargs.pop('target_port')
+        self.wrap_cmd      = kwargs.pop('wrap_cmd')
+        self.wrap_mode     = kwargs.pop('wrap_mode')
+        # Last 3 timestamps command was run
+        self.wrap_times    = [0, 0, 0]
+
+        if self.wrap_cmd:
+            rebinder_path = ['./', os.path.dirname(sys.argv[0])]
+            self.rebinder = None
+
+            for rdir in rebinder_path:
+                rpath = os.path.join(rdir, "rebind.so")
+                if os.path.exists(rpath):
+                    self.rebinder = rpath
+                    break
+
+            if not self.rebinder:
+                raise Exception("rebind.so not found, perhaps you need to run make")
+
+            self.target_host = "127.0.0.1"  # Loopback
+            # Find a free high port
+            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            sock.bind(('', 0))
+            self.target_port = sock.getsockname()[1]
+            sock.close()
+
+            os.environ.update({
+                "LD_PRELOAD": self.rebinder,
+                "REBIND_OLD_PORT": str(kwargs['listen_port']),
+                "REBIND_NEW_PORT": str(self.target_port)})
+
+        WebSocketServer.__init__(self, *args, **kwargs)
+
+    def run_wrap_cmd(self):
+        print "Starting '%s'" % " ".join(self.wrap_cmd)
+        self.wrap_times.append(time.time())
+        self.wrap_times.pop(0)
+        self.cmd = subprocess.Popen(
+                self.wrap_cmd, env=os.environ)
+        self.spawn_message = True
+
+    def started(self):
+        """
+        Called after Websockets server startup (i.e. after daemonize)
+        """
+        # Need to call wrapped command after daemonization so we can
+        # know when the wrapped command exits
+        if self.wrap_cmd:
+            print "  - proxying from %s:%s to '%s' (port %s)\n" % (
+                    self.listen_host, self.listen_port,
+                    " ".join(self.wrap_cmd), self.target_port)
+            self.run_wrap_cmd()
+        else:
+            print "  - proxying from %s:%s to %s:%s\n" % (
+                    self.listen_host, self.listen_port,
+                    self.target_host, self.target_port)
+
+    def poll(self):
+        # If we are wrapping a command, check it's status
+
+        if self.wrap_cmd and self.cmd:
+            ret = self.cmd.poll()
+            if ret != None:
+                self.vmsg("Wrapped command exited (or daemon). Returned %s" % ret)
+                self.cmd = None
+
+        if self.wrap_cmd and self.cmd == None:
+            # Response to wrapped command being gone
+            if self.wrap_mode == "ignore":
+                pass
+            elif self.wrap_mode == "exit":
+                sys.exit(ret)
+            elif self.wrap_mode == "respawn":
+                now = time.time()
+                avg = sum(self.wrap_times)/len(self.wrap_times)
+                if (now - avg) < 10:
+                    # 3 times in the last 10 seconds
+                    if self.spawn_message:
+                        print "Command respawning too fast"
+                        self.spawn_message = False
+                else:
+                    self.run_wrap_cmd()
+
+    # 
+    # Routines above this point are run in the master listener
+    # process.
+    #
+
+    #
+    # Routines below this point are connection handler routines and
+    # will be run in a separate forked process for each connection.
+    #
+
+    def new_client(self, client):
+        """
+        Called after a new WebSocket connection has been established.
+        """
+
+        self.rec = None
+        if self.record:
+            # Record raw frame data as a JavaScript compatible file
+            fname = "%s.%s" % (self.record,
+                                self.handler_id)
+            self.msg("opening record file: %s" % fname)
+            self.rec = open(fname, 'w+')
+            self.rec.write("var VNC_frame_data = [\n")
+
+        # Connect to the target
+        self.msg("connecting to: %s:%s" % (
+                 self.target_host, self.target_port))
+        tsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        tsock.connect((self.target_host, self.target_port))
+
+        if self.verbose and not self.daemon:
+            print self.traffic_legend
+
+        # Stat proxying
+        try:
+            self.do_proxy(client, tsock)
+        except:
+            if tsock: tsock.close()
+            if self.rec:
+                self.rec.write("'EOF']\n")
+                self.rec.close()
+            raise
+
+    def do_proxy(self, client, target):
+        """
+        Proxy client WebSocket to normal target socket.
+        """
+        cqueue = []
+        cpartial = ""
+        tqueue = []
+        rlist = [client, target]
+        tstart = int(time.time()*1000)
+
+        while True:
+            wlist = []
+            tdelta = int(time.time()*1000) - tstart
+
+            if tqueue: wlist.append(target)
+            if cqueue: wlist.append(client)
+            ins, outs, excepts = select(rlist, wlist, [], 1)
+            if excepts: raise Exception("Socket exception")
+
+            if target in outs:
+                # Send queued client data to the target
+                dat = tqueue.pop(0)
+                sent = target.send(dat)
+                if sent == len(dat):
+                    self.traffic(">")
+                else:
+                    # requeue the remaining data
+                    tqueue.insert(0, dat[sent:])
+                    self.traffic(".>")
+
+            if client in outs:
+                # Send queued target data to the client
+                dat = cqueue.pop(0)
+                sent = client.send(dat)
+                if sent == len(dat):
+                    self.traffic("<")
+                    if self.rec:
+                        self.rec.write("%s,\n" %
+                                repr("{%s{" % tdelta + dat[1:-1]))
+                else:
+                    cqueue.insert(0, dat[sent:])
+                    self.traffic("<.")
+
+
+            if target in ins:
+                # Receive target data, encode it and queue for client
+                buf = target.recv(self.buffer_size)
+                if len(buf) == 0: raise self.EClose("Target closed")
+
+                cqueue.append(self.encode(buf))
+                self.traffic("{")
+
+            if client in ins:
+                # Receive client data, decode it, and queue for target
+                buf = client.recv(self.buffer_size)
+                if len(buf) == 0: raise self.EClose("Client closed")
+
+                if buf == '\xff\x00':
+                    raise self.EClose("Client sent orderly close frame")
+                elif buf[-1] == '\xff':
+                    if buf.count('\xff') > 1:
+                        self.traffic(str(buf.count('\xff')))
+                    self.traffic("}")
+                    if self.rec:
+                        self.rec.write("%s,\n" %
+                                (repr("}%s}" % tdelta + buf[1:-1])))
+                    if cpartial:
+                        # Prepend saved partial and decode frame(s)
+                        tqueue.extend(self.decode(cpartial + buf))
+                        cpartial = ""
+                    else:
+                        # decode frame(s)
+                        tqueue.extend(self.decode(buf))
+                else:
+                    # Save off partial WebSockets frame
+                    self.traffic(".}")
+                    cpartial = cpartial + buf
+
+if __name__ == '__main__':
+    usage = "\n    %prog [options]"
+    usage += " [source_addr:]source_port target_addr:target_port"
+    usage += "\n    %prog [options]"
+    usage += " [source_addr:]source_port -- WRAP_COMMAND_LINE"
+    parser = optparse.OptionParser(usage=usage)
+    parser.add_option("--verbose", "-v", action="store_true",
+            help="verbose messages and per frame traffic")
+    parser.add_option("--record",
+            help="record sessions to FILE.[session_number]", metavar="FILE")
+    parser.add_option("--daemon", "-D",
+            dest="daemon", action="store_true",
+            help="become a daemon (background process)")
+    parser.add_option("--cert", default="self.pem",
+            help="SSL certificate file")
+    parser.add_option("--key", default=None,
+            help="SSL key file (if separate from cert)")
+    parser.add_option("--ssl-only", action="store_true",
+            help="disallow non-encrypted connections")
+    parser.add_option("--web", default=None, metavar="DIR",
+            help="run webserver on same port. Serve files from DIR.")
+    parser.add_option("--wrap-mode", default="exit", metavar="MODE",
+            choices=["exit", "ignore", "respawn"],
+            help="action to take when the wrapped program exits "
+            "or daemonizes: exit (default), ignore, respawn")
+    (opts, args) = parser.parse_args()
+
+    # Sanity checks
+    if len(args) < 2:
+        parser.error("Too few arguments")
+    if sys.argv.count('--'):
+        opts.wrap_cmd = args[1:]
+    else:
+        opts.wrap_cmd = None
+        if len(args) > 2:
+            parser.error("Too many arguments")
+
+    if opts.ssl_only and not os.path.exists(opts.cert):
+        parser.error("SSL only and %s not found" % opts.cert)
+
+    # Parse host:port and convert ports to numbers
+    if args[0].count(':') > 0:
+        opts.listen_host, opts.listen_port = args[0].split(':')
+    else:
+        opts.listen_host, opts.listen_port = '', args[0]
+    try:    opts.listen_port = int(opts.listen_port)
+    except: parser.error("Error parsing listen port")
+
+    if opts.wrap_cmd:
+        opts.target_host = None
+        opts.target_port = None
+    else:
+        if args[1].count(':') > 0:
+            opts.target_host, opts.target_port = args[1].split(':')
+        else:
+            parser.error("Error parsing target")
+        try:    opts.target_port = int(opts.target_port)
+        except: parser.error("Error parsing target port")
+
+    # Create and start the WebSockets proxy
+    server = WebSocketProxy(**opts.__dict__)
+    server.start_server()

+ 0 - 176
utils/wsecho.html

@@ -1,176 +0,0 @@
-<html>
-
-    <head>
-        <title>WebSockets Echo Test</title>
-        <script src="include/base64.js"></script>
-        <script src="include/util.js"></script>
-        <script src="include/webutil.js"></script> 
-        <!-- Uncomment to activate firebug lite -->
-        <!--
-        <script type='text/javascript' 
-            src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-        -->
-
-
-    </head>
-
-    <body>
-
-        Host: <input id='host' style='width:100'>&nbsp;
-        Port: <input id='port' style='width:50'>&nbsp;
-        Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
-        <input id='connectButton' type='button' value='Start' style='width:100px'
-            onclick="connect();">&nbsp;
-
-
-        <br>
-        Log:<br>
-        <textarea id="messages" style="font-size: 9;" cols=80 rows=25></textarea>
-    </body>
-
-
-    <script>
-        var ws, host = null, port = null,
-            msg_cnt = 0, send_cnt = 1, echoDelay = 500,
-            echo_ref;
-
-        function message(str) {
-            console.log(str);
-            cell = $D('messages');
-            cell.innerHTML += msg_cnt + ": " + str + "\n";
-            cell.scrollTop = cell.scrollHeight;
-            msg_cnt++;
-        }
-
-        Array.prototype.pushStr = function (str) {
-            var n = str.length;
-            for (var i=0; i < n; i++) {
-                this.push(str.charCodeAt(i));
-            }
-        }
-
-        function send_msg() {
-            if (ws.bufferedAmount > 0) {
-                console.log("Delaying send");
-                return;
-            }
-            var str = "Message #" + send_cnt, arr = [];
-            arr.pushStr(str)
-            ws.send(Base64.encode(arr));
-            message("Sent message: '" + str + "'");
-            send_cnt++;
-        }
-
-        function update_stats() {
-            $D('sent').innerHTML = sent;
-            $D('received').innerHTML = received;
-            $D('errors').innerHTML = errors;
-        }
-
-        function init_ws() {
-            console.log(">> init_ws");
-            console.log("<< init_ws");
-        }
-
-        function connect() {
-            var host = $D('host').value,
-                port = $D('port').value,
-                scheme = "ws://", uri;
-
-            console.log(">> connect");
-            if ((!host) || (!port)) {
-                console.log("must set host and port");
-                return;
-            }
-
-            if (ws) {
-                ws.close();
-            }
-
-            if ($D('encrypt').checked) {
-                scheme = "wss://";
-            }
-            uri = scheme + host + ":" + port;
-            message("connecting to " + uri);
-            ws = new WebSocket(uri);
-
-            ws.onmessage = function(e) {
-                //console.log(">> WebSockets.onmessage");
-                var arr = Base64.decode(e.data), str = "", i;
-
-                for (i = 0; i < arr.length; i++) {
-                    str = str + String.fromCharCode(arr[i]);
-                }
-
-                message("Received message '" + str + "'");
-                //console.log("<< WebSockets.onmessage");
-            };
-            ws.onopen = function(e) {
-                console.log(">> WebSockets.onopen");
-                echo_ref = setInterval(send_msg, echoDelay);
-                console.log("<< WebSockets.onopen");
-            };
-            ws.onclose = function(e) {
-                console.log(">> WebSockets.onclose");
-                if (echo_ref) {
-                    clearInterval(echo_ref);
-                    echo_ref = null;
-                }
-                console.log("<< WebSockets.onclose");
-            };
-            ws.onerror = function(e) {
-                console.log(">> WebSockets.onerror");
-                if (echo_ref) {
-                    clearInterval(echo_ref);
-                    echo_ref = null;
-                }
-                console.log("<< WebSockets.onerror");
-            };
-
-            $D('connectButton').value = "Stop";
-            $D('connectButton').onclick = disconnect;
-            console.log("<< connect");
-        }
-
-        function disconnect() {
-            console.log(">> disconnect");
-            if (ws) {
-                ws.close();
-            }
-
-            if (echo_ref) {
-                clearInterval(echo_ref);
-            }
-
-            $D('connectButton').value = "Start";
-            $D('connectButton').onclick = connect;
-            console.log("<< disconnect");
-        }
-
-
-        /* If no builtin websockets then load web_socket.js */
-        if (window.WebSocket) {
-            VNC_native_ws = true;
-        } else {
-            VNC_native_ws = false;
-            console.log("Loading web-socket-js flash bridge");
-            var extra = "<script src='include/web-socket-js/swfobject.js'><\/script>";
-            extra += "<script src='include/web-socket-js/FABridge.js'><\/script>";
-            extra += "<script src='include/web-socket-js/web_socket.js'><\/script>";
-            document.write(extra);
-        }
-
-        window.onload = function() {
-            console.log("onload");
-            if (!VNC_native_ws) {
-                console.log("initializing web-socket-js flash bridge");
-                WebSocket.__swfLocation = "include/web-socket-js/WebSocketMain.swf";
-                WebSocket.__initialize();
-            }
-            var url = document.location.href;
-            $D('host').value = (url.match(/host=([^&#]*)/) || ['',''])[1];
-            $D('port').value = (url.match(/port=([^&#]*)/) || ['',''])[1];
-        }
-    </script>
-
-</html>

+ 0 - 90
utils/wsecho.py

@@ -1,90 +0,0 @@
-#!/usr/bin/python
-
-'''
-A WebSocket server that echos back whatever it receives from the client.
-Copyright 2010 Joel Martin
-Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
-
-You can make a cert/key with openssl using:
-openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
-as taken from http://docs.python.org/dev/library/ssl.html#certificates
-
-'''
-
-import sys, socket, select
-from websocket import WebSocketServer
-
-class WebSocketEcho(WebSocketServer):
-    """
-    WebSockets server that echo back whatever is received from the
-    client. All traffic to/from the client is base64
-    encoded/decoded.
-    """
-    buffer_size = 8096
-
-    def new_client(self, client):
-        """
-        Echo back whatever is received.
-        """
-
-        cqueue = []
-        cpartial = ""
-        rlist = [client]
-
-        while True:
-            wlist = []
-
-            if cqueue: wlist.append(client)
-            ins, outs, excepts = select.select(rlist, wlist, [], 1)
-            if excepts: raise Exception("Socket exception")
-
-            if client in outs:
-                # Send queued target data to the client
-                dat = cqueue.pop(0)
-                sent = client.send(dat)
-                self.vmsg("Sent %s/%s bytes of frame: '%s'" % (
-                          sent, len(dat), self.decode(dat)[0]))
-                if sent != len(dat):
-                    # requeue the remaining data
-                    cqueue.insert(0, dat[sent:])
-
-
-            if client in ins:
-                # Receive client data, decode it, and send it back
-                buf = client.recv(self.buffer_size)
-                if len(buf) == 0: raise self.EClose("Client closed")
-
-                if buf == '\xff\x00':
-                    raise self.EClose("Client sent orderly close frame")
-                elif buf[-1] == '\xff':
-                    if cpartial:
-                        # Prepend saved partial and decode frame(s)
-                        frames = self.decode(cpartial + buf)
-                        cpartial = ""
-                    else:
-                        # decode frame(s)
-                        frames = self.decode(buf)
-
-                    for frame in frames:
-                        self.vmsg("Received frame: %s" % repr(frame))
-                        cqueue.append(self.encode(frame))
-                else:
-                    # Save off partial WebSockets frame
-                    self.vmsg("Received partial frame")
-                    cpartial = cpartial + buf
-
-if __name__ == '__main__':
-    try:
-        if len(sys.argv) < 1: raise
-        listen_port = int(sys.argv[1])
-    except:
-        print "Usage: %s <listen_port>" % sys.argv[0]
-        sys.exit(1)
-
-    server = WebSocketEcho(
-            listen_port=listen_port,
-            verbose=True,
-            cert='self.pem',
-            web='.')
-    server.start_server()
-

+ 0 - 353
utils/wsproxy.c

@@ -1,353 +0,0 @@
-/*
- * A WebSocket to TCP socket proxy with support for "wss://" encryption.
- * Copyright 2010 Joel Martin
- * Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
- *
- * You can make a cert/key with openssl using:
- * openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
- * as taken from http://docs.python.org/dev/library/ssl.html#certificates
- */
-#include <stdio.h>
-#include <errno.h>
-#include <limits.h>
-#include <getopt.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <sys/select.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include "websocket.h"
-
-char traffic_legend[] = "\n\
-Traffic Legend:\n\
-    }  - Client receive\n\
-    }. - Client receive partial\n\
-    {  - Target receive\n\
-\n\
-    >  - Target send\n\
-    >. - Target send partial\n\
-    <  - Client send\n\
-    <. - Client send partial\n\
-";
-
-char USAGE[] = "Usage: [options] " \
-               "[source_addr:]source_port target_addr:target_port\n\n" \
-               "  --verbose|-v       verbose messages and per frame traffic\n" \
-               "  --daemon|-D        become a daemon (background process)\n" \
-               "  --cert CERT        SSL certificate file\n" \
-               "  --key KEY          SSL key file (if separate from cert)\n" \
-               "  --ssl-only         disallow non-encrypted connections";
-
-#define usage(fmt, args...) \
-    fprintf(stderr, "%s\n\n", USAGE); \
-    fprintf(stderr, fmt , ## args); \
-    exit(1);
-
-char target_host[256];
-int target_port;
-
-extern pipe_error;
-extern settings_t settings;
-extern char *tbuf, *cbuf, *tbuf_tmp, *cbuf_tmp;
-extern unsigned int bufsize, dbufsize;
-
-void do_proxy(ws_ctx_t *ws_ctx, int target) {
-    fd_set rlist, wlist, elist;
-    struct timeval tv;
-    int i, maxfd, client = ws_ctx->sockfd;
-    unsigned int tstart, tend, cstart, cend, ret;
-    ssize_t len, bytes;
-
-    tstart = tend = cstart = cend = 0;
-    maxfd = client > target ? client+1 : target+1;
-
-    while (1) {
-        tv.tv_sec = 1;
-        tv.tv_usec = 0;
-
-        FD_ZERO(&rlist);
-        FD_ZERO(&wlist);
-        FD_ZERO(&elist);
-
-        FD_SET(client, &elist);
-        FD_SET(target, &elist);
-
-        if (tend == tstart) {
-            // Nothing queued for target, so read from client
-            FD_SET(client, &rlist);
-        } else {
-            // Data queued for target, so write to it
-            FD_SET(target, &wlist);
-        }
-        if (cend == cstart) {
-            // Nothing queued for client, so read from target
-            FD_SET(target, &rlist);
-        } else {
-            // Data queued for client, so write to it
-            FD_SET(client, &wlist);
-        }
-
-        ret = select(maxfd, &rlist, &wlist, &elist, &tv);
-        if (pipe_error) { break; }
-
-        if (FD_ISSET(target, &elist)) {
-            handler_emsg("target exception\n");
-            break;
-        }
-        if (FD_ISSET(client, &elist)) {
-            handler_emsg("client exception\n");
-            break;
-        }
-
-        if (ret == -1) {
-            handler_emsg("select(): %s\n", strerror(errno));
-            break;
-        } else if (ret == 0) {
-            //handler_emsg("select timeout\n");
-            continue;
-        }
-
-        if (FD_ISSET(target, &wlist)) {
-            len = tend-tstart;
-            bytes = send(target, tbuf + tstart, len, 0);
-            if (pipe_error) { break; }
-            if (bytes < 0) {
-                handler_emsg("target connection error: %s\n",
-                             strerror(errno));
-                break;
-            }
-            tstart += bytes;
-            if (tstart >= tend) {
-                tstart = tend = 0;
-                traffic(">");
-            } else {
-                traffic(">.");
-            }
-        }
-
-        if (FD_ISSET(client, &wlist)) {
-            len = cend-cstart;
-            bytes = ws_send(ws_ctx, cbuf + cstart, len);
-            if (pipe_error) { break; }
-            if (len < 3) {
-                handler_emsg("len: %d, bytes: %d: %d\n", len, bytes, *(cbuf + cstart));
-            }
-            cstart += bytes;
-            if (cstart >= cend) {
-                cstart = cend = 0;
-                traffic("<");
-            } else {
-                traffic("<.");
-            }
-        }
-
-        if (FD_ISSET(target, &rlist)) {
-            bytes = recv(target, cbuf_tmp, dbufsize , 0);
-            if (pipe_error) { break; }
-            if (bytes <= 0) {
-                handler_emsg("target closed connection\n");
-                break;
-            }
-            cstart = 0;
-            cend = encode(cbuf_tmp, bytes, cbuf, bufsize);
-            /*
-            printf("encoded: ");
-            for (i=0; i< cend; i++) {
-                printf("%u,", (unsigned char) *(cbuf+i));
-            }
-            printf("\n");
-            */
-            if (cend < 0) {
-                handler_emsg("encoding error\n");
-                break;
-            }
-            traffic("{");
-        }
-
-        if (FD_ISSET(client, &rlist)) {
-            bytes = ws_recv(ws_ctx, tbuf_tmp, bufsize-1);
-            if (pipe_error) { break; }
-            if (bytes <= 0) {
-                handler_emsg("client closed connection\n");
-                break;
-            } else if ((bytes == 2) &&
-                       (tbuf_tmp[0] == '\xff') && 
-                       (tbuf_tmp[1] == '\x00')) {
-                handler_emsg("client sent orderly close frame\n");
-                break;
-            }
-            /*
-            printf("before decode: ");
-            for (i=0; i< bytes; i++) {
-                printf("%u,", (unsigned char) *(tbuf_tmp+i));
-            }
-            printf("\n");
-            */
-            len = decode(tbuf_tmp, bytes, tbuf, bufsize-1);
-            /*
-            printf("decoded: ");
-            for (i=0; i< len; i++) {
-                printf("%u,", (unsigned char) *(tbuf+i));
-            }
-            printf("\n");
-            */
-            if (len < 0) {
-                handler_emsg("decoding error\n");
-                break;
-            }
-            traffic("}");
-            tstart = 0;
-            tend = len;
-        }
-    }
-}
-
-void proxy_handler(ws_ctx_t *ws_ctx) {
-    int tsock = 0;
-    struct sockaddr_in taddr;
-
-    handler_msg("connecting to: %s:%d\n", target_host, target_port);
-
-    tsock = socket(AF_INET, SOCK_STREAM, 0);
-    if (tsock < 0) {
-        handler_emsg("Could not create target socket: %s\n",
-                     strerror(errno));
-        return;
-    }
-    bzero((char *) &taddr, sizeof(taddr));
-    taddr.sin_family = AF_INET;
-    taddr.sin_port = htons(target_port);
-
-    /* Resolve target address */
-    if (resolve_host(&taddr.sin_addr, target_host) < -1) {
-        handler_emsg("Could not resolve target address: %s\n",
-                     strerror(errno));
-    }
-
-    if (connect(tsock, (struct sockaddr *) &taddr, sizeof(taddr)) < 0) {
-        handler_emsg("Could not connect to target: %s\n",
-                     strerror(errno));
-        close(tsock);
-        return;
-    }
-
-    if ((settings.verbose) && (! settings.daemon)) {
-        printf("%s", traffic_legend);
-    }
-
-    do_proxy(ws_ctx, tsock);
-
-    close(tsock);
-}
-
-int main(int argc, char *argv[])
-{
-    int fd, c, option_index = 0;
-    static int ssl_only = 0, daemon = 0, verbose = 0;
-    char *found;
-    static struct option long_options[] = {
-        {"verbose",    no_argument,       &verbose,    'v'},
-        {"ssl-only",   no_argument,       &ssl_only,    1 },
-        {"daemon",     no_argument,       &daemon,     'D'},
-        /* ---- */
-        {"cert",       required_argument, 0,           'c'},
-        {"key",        required_argument, 0,           'k'},
-        {0, 0, 0, 0}
-    };
-
-    settings.cert = realpath("self.pem", NULL);
-    if (!settings.cert) {
-        /* Make sure it's always set to something */
-        settings.cert = "self.pem";
-    }
-    settings.key = "";
-
-    while (1) {
-        c = getopt_long (argc, argv, "vDc:k:",
-                         long_options, &option_index);
-
-        /* Detect the end */
-        if (c == -1) { break; }
-
-        switch (c) {
-            case 0:
-                break; // ignore
-            case 1:
-                break; // ignore
-            case 'v':
-                verbose = 1;
-                break;
-            case 'D':
-                daemon = 1;
-                break;
-            case 'c':
-                settings.cert = realpath(optarg, NULL);
-                if (! settings.cert) {
-                    usage("No cert file at %s\n", optarg);
-                }
-                break;
-            case 'k':
-                settings.key = realpath(optarg, NULL);
-                if (! settings.key) {
-                    usage("No key file at %s\n", optarg);
-                }
-                break;
-            default:
-                usage("");
-        }
-    }
-    settings.verbose      = verbose;
-    settings.ssl_only     = ssl_only;
-    settings.daemon       = daemon;
-
-    if ((argc-optind) != 2) {
-        usage("Invalid number of arguments\n");
-    }
-
-    found = strstr(argv[optind], ":");
-    if (found) {
-        memcpy(settings.listen_host, argv[optind], found-argv[optind]);
-        settings.listen_port = strtol(found+1, NULL, 10);
-    } else {
-        settings.listen_host[0] = '\0';
-        settings.listen_port = strtol(argv[optind], NULL, 10);
-    }
-    optind++;
-    if (settings.listen_port == 0) {
-        usage("Could not parse listen_port\n");
-    }
-
-    found = strstr(argv[optind], ":");
-    if (found) {
-        memcpy(target_host, argv[optind], found-argv[optind]);
-        target_port = strtol(found+1, NULL, 10);
-    } else {
-        usage("Target argument must be host:port\n");
-    }
-    if (target_port == 0) {
-        usage("Could not parse target port\n");
-    }
-
-    if (ssl_only) {
-        if (!access(settings.cert, R_OK)) {
-            usage("SSL only and cert file '%s' not found\n", settings.cert);
-        }
-    } else if (access(settings.cert, R_OK) != 0) {
-        fprintf(stderr, "Warning: '%s' not found\n", settings.cert);
-    }
-
-    //printf("  verbose: %d\n",   settings.verbose);
-    //printf("  ssl_only: %d\n",  settings.ssl_only);
-    //printf("  daemon: %d\n",    settings.daemon);
-    //printf("  cert: %s\n",      settings.cert);
-    //printf("  key: %s\n",       settings.key);
-
-    settings.handler = proxy_handler; 
-    start_server();
-
-    free(tbuf);
-    free(cbuf);
-    free(tbuf_tmp);
-    free(cbuf_tmp);
-}

+ 0 - 253
utils/wsproxy.js

@@ -1,253 +0,0 @@
-// A WebSocket to TCP socket proxy
-// Copyright 2010 Joel Martin
-// Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
-
-var net = require('net'),
-    sys = require('sys'),
-    crypto = require('crypto'),
-    source_arg, source_host, source_port,
-    target_arg, target_host, target_port;
-
-// md5 calculation borrowed from Socket.IO (MIT license)
-function gen_md5(headers, k3) {
-    var k1 = headers['sec-websocket-key1'],
-        k2 = headers['sec-websocket-key2'],
-        md5 = crypto.createHash('md5');
-
-    [k1, k2].forEach(function(k){
-    var n = parseInt(k.replace(/[^\d]/g, '')),
-        spaces = k.replace(/[^ ]/g, '').length;
-
-    if (spaces === 0 || n % spaces !== 0){
-        return false;
-    }
-
-    n /= spaces;
-
-    md5.update(String.fromCharCode(
-        n >> 24 & 0xFF,
-        n >> 16 & 0xFF,
-        n >> 8  & 0xFF,
-        n       & 0xFF));
-    });
-
-    md5.update(k3.toString('binary'));
-
-    return md5.digest('binary');
-}
-
-function encode(buf) {
-    return String.fromCharCode(0) + 
-           buf.toString('base64', 0) +
-           String.fromCharCode(255);
-}
-
-function decode(data) {
-    var i, len = 0, strs, retstrs = [],
-        buf = new Buffer(data.length),
-        str = data.toString('binary', 1, data.length-1);
-
-    if (str.indexOf('\xff') > -1) {
-        // We've gotten multiple frames at once
-        strs = str.split('\xff\x00')
-        for (i = 0; i < strs.length; i++) {
-            len = buf.write(strs[i], 0, 'base64');
-            retstrs.push(buf.toString('binary', 0, len));
-        }
-        return retstrs.join("");
-    } else {
-        len = buf.write(str, 0, 'base64');
-        return buf.toString('binary', 0, len);
-    }
-}
-
-
-var server = net.createServer(function (client) {
-    var handshake = "", headers = {}, header,
-        version, path, k1, k2, k3, target = null;
-
-    function cleanup() {
-        client.end();
-        if (target) {
-            target.end();
-            target = null;
-        }
-    }
-
-    function do_handshake(data) {
-        var i, idx, dlen = data.length, lines, location, rheaders,
-            sec_hdr;
-        //sys.log("received handshake data: " + data);
-        handshake += data.toString('utf8');
-        if ((data[dlen-12] != 13) ||
-            (data[dlen-11] != 10) ||
-            (data[dlen-10] != 13) ||
-            (data[dlen-9] != 10)) {
-            //sys.log("Got partial handshake");
-            return;
-        }
-        //sys.log("Got whole handshake");
-
-        if (handshake.indexOf('GET ') != 0) {
-            sys.error("Got invalid handshake");
-            client.end();
-            return;
-        }
-
-        lines = handshake.split('\r\n');
-        path = lines[0].split(' ')[1];
-        //sys.log("path: " + path);
-
-        k3 = data.slice(dlen-8, dlen);
-        for (i = 1; i < lines.length; i++) {
-            //sys.log("lines[i]: " + lines[i]);
-            if (lines[i].length == 0) { break; }
-            idx = lines[i].indexOf(': ');
-            if (idx < 0) {
-                sys.error("Got invalid handshake header");
-                client.end();
-                return;
-            }
-            header = lines[i].slice(0, idx).toLowerCase();
-            headers[header] = lines[i].slice(idx+2);
-        }
-        //console.dir(headers);
-        //sys.log("k3: " + k3 + ", k3.length: " + k3.length);
-
-        if (headers.upgrade !== 'WebSocket') {
-            sys.error("Upgrade header is not 'WebSocket'");
-            client.end();
-            return;
-        }
-
-        location = (headers.origin.substr(0, 5) == 'https' ? 'wss' : 'ws')
-            + '://' + headers.host + path;
-        //sys.log("location: " + location);
-
-        if ('sec-websocket-key1' in headers) {
-            version = 76;
-            sec_hdr = "Sec-";
-        } else {
-            version = 75;
-            sec_hdr = "";
-        }
-        sys.log("using protocol version " + version);
-
-        rheaders = [
-            'HTTP/1.1 101 WebSocket Protocol Handshake',
-            'Upgrade: WebSocket',
-            'Connection: Upgrade',
-            sec_hdr + 'WebSocket-Origin: ' + headers.origin,
-            sec_hdr + 'WebSocket-Location: ' + location
-        ];
-        if ('sec-websocket-protocol' in headers) {
-            rheaders.push('Sec-WebSocket-Protocol: ' + headers['sec-websocket-protocol']);
-        }
-        rheaders.push('');
-        if (version === 76) {
-            rheaders.push(gen_md5(headers, k3));
-        }
-
-        // Switch listener to normal data path
-        client.on('data', client_data);
-        //client.setEncoding('utf8');
-        client.removeListener('data', do_handshake);
-        // Do not delay writes
-        client.setNoDelay(true);
-
-        // Send the handshake response
-        try {
-            //sys.log("response: " + rheaders.join('\r\n'));
-            client.write(rheaders.join('\r\n'), 'binary');
-        } catch(e) {
-            sys.error("Failed to send handshake response");
-            client.end();
-            return;
-        }
-
-        // Create a connection to the target
-        target = net.createConnection(target_port, target_host);
-        target.on('data', target_data);
-        target.on('end', function () {
-            sys.log("received target end");
-            cleanup();
-        });
-        target.on('error', function (exc) {
-            sys.log("received target error: " + exc);
-            cleanup();
-        });
-    }
-
-    function client_data(data) {
-        var ret;
-        //sys.log("received client data: " + data);
-        //sys.log("             decoded: " + decode(data));
-        try {
-            ret = target.write(decode(data), 'binary');
-            if (! ret) {
-                sys.log("target write returned false");
-            }
-        } catch(e) {
-            sys.log("fatal error writing to target");
-            cleanup();
-        }
-    }
-
-    function target_data(data) {
-        //sys.log("received target data: " + data);
-        //sys.log("             encoded: " + encode(data));
-        try {
-            client.write(encode(data), 'binary');
-        } catch(e) {
-            sys.log("fatal error writing to client");
-            cleanup();
-        }
-    }
-
-    client.on('connect', function () {
-        sys.log("Got client connection");
-    });
-    client.on('data', do_handshake);
-    client.on('end', function () {
-        sys.log("recieved client end");
-        cleanup();
-    });
-    client.on('error', function (exc) {
-        sys.log("recieved client error: " + exc);
-        cleanup();
-    });
-});
-
-
-// parse source and target into parts
-source_arg = process.argv[2];
-target_arg = process.argv[3];
-try {
-    var idx;
-    idx = source_arg.indexOf(":");
-    if (idx >= 0) {
-        source_host = source_arg.slice(0, idx);
-        source_port = parseInt(source_arg.slice(idx+1), 10);
-    } else {
-        source_host = "";
-        source_port = parseInt(source_arg, 10);
-    }
-
-    idx = target_arg.indexOf(":");
-    if (idx < 0) {
-        throw("target must be host:port");
-    }
-    target_host = target_arg.slice(0, idx);
-    target_port = parseInt(target_arg.slice(idx+1), 10);
-
-    if (isNaN(source_port) || isNaN(target_port)) {
-        throw("illegal port");
-    }
-} catch(e) {
-    console.error("wsproxy.py [source_addr:]source_port target_addr:target_port");
-    process.exit(2);
-}
-
-sys.log("source: " + source_host + ":" + source_port);
-sys.log("target: " + target_host + ":" + target_port);
-server.listen(source_port, source_host);

+ 0 - 308
utils/wsproxy.py

@@ -1,308 +0,0 @@
-#!/usr/bin/python
-
-'''
-A WebSocket to TCP socket proxy with support for "wss://" encryption.
-Copyright 2010 Joel Martin
-Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
-
-You can make a cert/key with openssl using:
-openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
-as taken from http://docs.python.org/dev/library/ssl.html#certificates
-
-'''
-
-import socket, optparse, time, os, sys, subprocess
-from select import select
-from websocket import WebSocketServer
-
-class WebSocketProxy(WebSocketServer):
-    """
-    Proxy traffic to and from a WebSockets client to a normal TCP
-    socket server target. All traffic to/from the client is base64
-    encoded/decoded to allow binary data to be sent/received to/from
-    the target.
-    """
-
-    buffer_size = 65536
-
-    traffic_legend = """
-Traffic Legend:
-    }  - Client receive
-    }. - Client receive partial
-    {  - Target receive
-
-    >  - Target send
-    >. - Target send partial
-    <  - Client send
-    <. - Client send partial
-"""
-
-    def __init__(self, *args, **kwargs):
-        # Save off proxy specific options
-        self.target_host   = kwargs.pop('target_host')
-        self.target_port   = kwargs.pop('target_port')
-        self.wrap_cmd      = kwargs.pop('wrap_cmd')
-        self.wrap_mode     = kwargs.pop('wrap_mode')
-        # Last 3 timestamps command was run
-        self.wrap_times    = [0, 0, 0]
-
-        if self.wrap_cmd:
-            rebinder_path = ['./', os.path.dirname(sys.argv[0])]
-            self.rebinder = None
-
-            for rdir in rebinder_path:
-                rpath = os.path.join(rdir, "rebind.so")
-                if os.path.exists(rpath):
-                    self.rebinder = rpath
-                    break
-
-            if not self.rebinder:
-                raise Exception("rebind.so not found, perhaps you need to run make")
-
-            self.target_host = "127.0.0.1"  # Loopback
-            # Find a free high port
-            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            sock.bind(('', 0))
-            self.target_port = sock.getsockname()[1]
-            sock.close()
-
-            os.environ.update({
-                "LD_PRELOAD": self.rebinder,
-                "REBIND_OLD_PORT": str(kwargs['listen_port']),
-                "REBIND_NEW_PORT": str(self.target_port)})
-
-        WebSocketServer.__init__(self, *args, **kwargs)
-
-    def run_wrap_cmd(self):
-        print "Starting '%s'" % " ".join(self.wrap_cmd)
-        self.wrap_times.append(time.time())
-        self.wrap_times.pop(0)
-        self.cmd = subprocess.Popen(
-                self.wrap_cmd, env=os.environ)
-        self.spawn_message = True
-
-    def started(self):
-        """
-        Called after Websockets server startup (i.e. after daemonize)
-        """
-        # Need to call wrapped command after daemonization so we can
-        # know when the wrapped command exits
-        if self.wrap_cmd:
-            print "  - proxying from %s:%s to '%s' (port %s)\n" % (
-                    self.listen_host, self.listen_port,
-                    " ".join(self.wrap_cmd), self.target_port)
-            self.run_wrap_cmd()
-        else:
-            print "  - proxying from %s:%s to %s:%s\n" % (
-                    self.listen_host, self.listen_port,
-                    self.target_host, self.target_port)
-
-    def poll(self):
-        # If we are wrapping a command, check it's status
-
-        if self.wrap_cmd and self.cmd:
-            ret = self.cmd.poll()
-            if ret != None:
-                self.vmsg("Wrapped command exited (or daemon). Returned %s" % ret)
-                self.cmd = None
-
-        if self.wrap_cmd and self.cmd == None:
-            # Response to wrapped command being gone
-            if self.wrap_mode == "ignore":
-                pass
-            elif self.wrap_mode == "exit":
-                sys.exit(ret)
-            elif self.wrap_mode == "respawn":
-                now = time.time()
-                avg = sum(self.wrap_times)/len(self.wrap_times)
-                if (now - avg) < 10:
-                    # 3 times in the last 10 seconds
-                    if self.spawn_message:
-                        print "Command respawning too fast"
-                        self.spawn_message = False
-                else:
-                    self.run_wrap_cmd()
-
-    # 
-    # Routines above this point are run in the master listener
-    # process.
-    #
-
-    #
-    # Routines below this point are connection handler routines and
-    # will be run in a separate forked process for each connection.
-    #
-
-    def new_client(self, client):
-        """
-        Called after a new WebSocket connection has been established.
-        """
-
-        self.rec = None
-        if self.record:
-            # Record raw frame data as a JavaScript compatible file
-            fname = "%s.%s" % (self.record,
-                                self.handler_id)
-            self.msg("opening record file: %s" % fname)
-            self.rec = open(fname, 'w+')
-            self.rec.write("var VNC_frame_data = [\n")
-
-        # Connect to the target
-        self.msg("connecting to: %s:%s" % (
-                 self.target_host, self.target_port))
-        tsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        tsock.connect((self.target_host, self.target_port))
-
-        if self.verbose and not self.daemon:
-            print self.traffic_legend
-
-        # Stat proxying
-        try:
-            self.do_proxy(client, tsock)
-        except:
-            if tsock: tsock.close()
-            if self.rec:
-                self.rec.write("'EOF']\n")
-                self.rec.close()
-            raise
-
-    def do_proxy(self, client, target):
-        """
-        Proxy client WebSocket to normal target socket.
-        """
-        cqueue = []
-        cpartial = ""
-        tqueue = []
-        rlist = [client, target]
-        tstart = int(time.time()*1000)
-
-        while True:
-            wlist = []
-            tdelta = int(time.time()*1000) - tstart
-
-            if tqueue: wlist.append(target)
-            if cqueue: wlist.append(client)
-            ins, outs, excepts = select(rlist, wlist, [], 1)
-            if excepts: raise Exception("Socket exception")
-
-            if target in outs:
-                # Send queued client data to the target
-                dat = tqueue.pop(0)
-                sent = target.send(dat)
-                if sent == len(dat):
-                    self.traffic(">")
-                else:
-                    # requeue the remaining data
-                    tqueue.insert(0, dat[sent:])
-                    self.traffic(".>")
-
-            if client in outs:
-                # Send queued target data to the client
-                dat = cqueue.pop(0)
-                sent = client.send(dat)
-                if sent == len(dat):
-                    self.traffic("<")
-                    if self.rec:
-                        self.rec.write("%s,\n" %
-                                repr("{%s{" % tdelta + dat[1:-1]))
-                else:
-                    cqueue.insert(0, dat[sent:])
-                    self.traffic("<.")
-
-
-            if target in ins:
-                # Receive target data, encode it and queue for client
-                buf = target.recv(self.buffer_size)
-                if len(buf) == 0: raise self.EClose("Target closed")
-
-                cqueue.append(self.encode(buf))
-                self.traffic("{")
-
-            if client in ins:
-                # Receive client data, decode it, and queue for target
-                buf = client.recv(self.buffer_size)
-                if len(buf) == 0: raise self.EClose("Client closed")
-
-                if buf == '\xff\x00':
-                    raise self.EClose("Client sent orderly close frame")
-                elif buf[-1] == '\xff':
-                    if buf.count('\xff') > 1:
-                        self.traffic(str(buf.count('\xff')))
-                    self.traffic("}")
-                    if self.rec:
-                        self.rec.write("%s,\n" %
-                                (repr("}%s}" % tdelta + buf[1:-1])))
-                    if cpartial:
-                        # Prepend saved partial and decode frame(s)
-                        tqueue.extend(self.decode(cpartial + buf))
-                        cpartial = ""
-                    else:
-                        # decode frame(s)
-                        tqueue.extend(self.decode(buf))
-                else:
-                    # Save off partial WebSockets frame
-                    self.traffic(".}")
-                    cpartial = cpartial + buf
-
-if __name__ == '__main__':
-    usage = "\n    %prog [options]"
-    usage += " [source_addr:]source_port target_addr:target_port"
-    usage += "\n    %prog [options]"
-    usage += " [source_addr:]source_port -- WRAP_COMMAND_LINE"
-    parser = optparse.OptionParser(usage=usage)
-    parser.add_option("--verbose", "-v", action="store_true",
-            help="verbose messages and per frame traffic")
-    parser.add_option("--record",
-            help="record sessions to FILE.[session_number]", metavar="FILE")
-    parser.add_option("--daemon", "-D",
-            dest="daemon", action="store_true",
-            help="become a daemon (background process)")
-    parser.add_option("--cert", default="self.pem",
-            help="SSL certificate file")
-    parser.add_option("--key", default=None,
-            help="SSL key file (if separate from cert)")
-    parser.add_option("--ssl-only", action="store_true",
-            help="disallow non-encrypted connections")
-    parser.add_option("--web", default=None, metavar="DIR",
-            help="run webserver on same port. Serve files from DIR.")
-    parser.add_option("--wrap-mode", default="exit", metavar="MODE",
-            choices=["exit", "ignore", "respawn"],
-            help="action to take when the wrapped program exits "
-            "or daemonizes: exit (default), ignore, respawn")
-    (opts, args) = parser.parse_args()
-
-    # Sanity checks
-    if len(args) < 2:
-        parser.error("Too few arguments")
-    if sys.argv.count('--'):
-        opts.wrap_cmd = args[1:]
-    else:
-        opts.wrap_cmd = None
-        if len(args) > 2:
-            parser.error("Too many arguments")
-
-    if opts.ssl_only and not os.path.exists(opts.cert):
-        parser.error("SSL only and %s not found" % opts.cert)
-
-    # Parse host:port and convert ports to numbers
-    if args[0].count(':') > 0:
-        opts.listen_host, opts.listen_port = args[0].split(':')
-    else:
-        opts.listen_host, opts.listen_port = '', args[0]
-    try:    opts.listen_port = int(opts.listen_port)
-    except: parser.error("Error parsing listen port")
-
-    if opts.wrap_cmd:
-        opts.target_host = None
-        opts.target_port = None
-    else:
-        if args[1].count(':') > 0:
-            opts.target_host, opts.target_port = args[1].split(':')
-        else:
-            parser.error("Error parsing target")
-        try:    opts.target_port = int(opts.target_port)
-        except: parser.error("Error parsing target port")
-
-    # Create and start the WebSockets proxy
-    server = WebSocketProxy(**opts.__dict__)
-    server.start_server()

+ 1 - 0
utils/wsproxy.py

@@ -0,0 +1 @@
+websockify

+ 0 - 90
utils/wstelnet.html

@@ -1,90 +0,0 @@
-<html>
-
-    <head>
-        <title>Telnet Client using WebSockets</title>
-        <script src="include/base64.js"></script>
-        <script src="include/util.js"></script>
-        <script src="include/webutil.js"></script> 
-        <script src="include/canvas.js"></script> 
-        <script src="VT100.js"></script> 
-        <script src="wstelnet.js"></script> 
-        <!-- Uncomment to activate firebug lite -->
-        <!--
-        <script type='text/javascript' 
-            src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-        -->
-
-
-    </head>
-
-    <body>
-
-        Host: <input id='host' style='width:100'>&nbsp;
-        Port: <input id='port' style='width:50'>&nbsp;
-        Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
-        <input id='connectButton' type='button' value='Connect' style='width:100px'
-            onclick="connect();">&nbsp;
-
-        <br><br>
-
-        <pre id="terminal"></pre>
-
-        <script>
-            var telnet;
-
-            function connect() {
-                telnet.connect($D('host').value,
-                               $D('port').value,
-                               $D('encrypt').checked);
-                $D('connectButton').disabled = true;
-                $D('connectButton').value = "Connecting";
-            }
-
-            function disconnect() {
-                $D('connectButton').disabled = true;
-                $D('connectButton').value = "Disconnecting";
-                telnet.disconnect();
-            }
-
-            function connected() {
-                $D('connectButton').disabled = false;
-                $D('connectButton').value = "Disconnect";
-                $D('connectButton').onclick = disconnect;
-            }
-
-            function disconnected() {
-                $D('connectButton').disabled = false;
-                $D('connectButton').value = "Connect";
-                $D('connectButton').onclick = connect;
-            }
-
-            /* If no builtin websockets then load web_socket.js */
-            if (window.WebSocket) {
-                VNC_native_ws = true;
-            } else {
-                VNC_native_ws = false;
-                console.log("Loading web-socket-js flash bridge");
-                var extra = "<script src='include/web-socket-js/swfobject.js'><\/script>";
-                extra += "<script src='include/web-socket-js/FABridge.js'><\/script>";
-                extra += "<script src='include/web-socket-js/web_socket.js'><\/script>";
-                document.write(extra);
-            }
-
-            window.onload = function() {
-                console.log("onload");
-                if (!VNC_native_ws) {
-                    console.log("initializing web-socket-js flash bridge");
-                    WebSocket.__swfLocation = "include/web-socket-js/WebSocketMain.swf";
-                    WebSocket.__initialize();
-                }
-                var url = document.location.href;
-                $D('host').value = (url.match(/host=([^&#]*)/) || ['',''])[1];
-                $D('port').value = (url.match(/port=([^&#]*)/) || ['',''])[1];
-                
-                telnet = Telnet('terminal', connected, disconnected);
-            }
-        </script>
-
-    </body>
-
-</html>

+ 0 - 333
utils/wstelnet.js

@@ -1,333 +0,0 @@
-/*
- * WebSockets telnet client
- * Copyright (C) 2011 Joel Martin
- * Licensed under LGPL-3 (see LICENSE.txt)
- *
- * Includes VT100.js from:
- *   http://code.google.com/p/sshconsole
- * Which was modified from:
- *   http://fzort.org/bi/o.php#vt100_js
- *
- * Telnet protocol:
- *   http://www.networksorcery.com/enp/protocol/telnet.htm
- *   http://www.networksorcery.com/enp/rfc/rfc1091.txt
- *
- * ANSI escape sequeneces:
- *   http://en.wikipedia.org/wiki/ANSI_escape_code
- *   http://ascii-table.com/ansi-escape-sequences-vt-100.php
- *   http://www.termsys.demon.co.uk/vtansi.htm
- *   http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
- *
- * ASCII codes:
- *   http://en.wikipedia.org/wiki/ASCII
- *   http://www.hobbyprojects.com/ascii-table/ascii-table.html
- *
- * Other web consoles:
- *   http://stackoverflow.com/questions/244750/ajax-console-window-with-ansi-vt100-support
- */
-
-
-
-
-function Telnet(target, connect_callback, disconnect_callback) {
-
-var that = {},  // Public API interface
-    vt100, ws, sQ = [];
-    termType = "VT100";
-
-
-Array.prototype.pushStr = function (str) {
-    var n = str.length;
-    for (var i=0; i < n; i++) {
-        this.push(str.charCodeAt(i));
-    }
-}
-
-function do_send() {
-    if (sQ.length > 0) {
-        Util.Debug("Sending " + sQ);
-        ws.send(Base64.encode(sQ));
-        sQ = [];
-    }
-}
-
-function do_recv(e) {
-    //console.log(">> do_recv");
-    var arr = Base64.decode(e.data), str = "",
-        chr, cmd, code, value;
-
-    Util.Debug("Received array '" + arr + "'");
-    while (arr.length > 0) {
-        chr = arr.shift();
-        switch (chr) {
-        case 255:   // IAC
-            cmd = chr;
-            code = arr.shift();
-            value = arr.shift();
-            switch (code) {
-            case 254: // DONT
-                Util.Debug("Got Cmd DONT '" + value + "', ignoring");
-                break;
-            case 253: // DO
-                Util.Debug("Got Cmd DO '" + value + "'");
-                if (value === 24) {
-                    // Terminal type
-                    Util.Info("Send WILL '" + value + "' (TERM-TYPE)");
-                    sQ.push(255, 251, value);
-                } else {
-                    // Refuse other DO requests with a WONT
-                    Util.Debug("Send WONT '" + value + "'");
-                    sQ.push(255, 252, value);
-                }
-                break;
-            case 252: // WONT
-                Util.Debug("Got Cmd WONT '" + value + "', ignoring");
-                break;
-            case 251: // WILL
-                Util.Debug("Got Cmd WILL '" + value + "'");
-                if (value === 1) {
-                    // Affirm echo with DO
-                    Util.Info("Send Cmd DO '" + value + "' (echo)");
-                    sQ.push(255, 253, value);
-                } else {
-                    // Reject other WILL offers with a DONT
-                    Util.Debug("Send Cmd DONT '" + value + "'");
-                    sQ.push(255, 254, value);
-                }
-                break;
-            case 250: // SB (subnegotiation)
-                if (value === 24) {
-                    Util.Info("Got IAC SB TERM-TYPE SEND(1) IAC SE");
-                    // TERM-TYPE subnegotiation
-                    if (arr[0] === 1 &&
-                        arr[1] === 255 &&
-                        arr[2] === 240) {
-                        arr.shift(); arr.shift(); arr.shift();
-                        Util.Info("Send IAC SB TERM-TYPE IS(0) '" + 
-                                  termType + "' IAC SE");
-                        sQ.push(255, 250, 24, 0); 
-                        sQ.pushStr(termType);
-                        sQ.push(255, 240);
-                    } else {
-                        Util.Info("Invalid subnegotiation received" + arr);
-                    }
-                } else {
-                    Util.Info("Ignoring SB " + value);
-                }
-                break;
-            default:
-                Util.Info("Got Cmd " + cmd + " " + value + ", ignoring"); }
-            continue;
-        case 242:   // Data Mark (Synch)
-            cmd = chr;
-            code = arr.shift();
-            value = arr.shift();
-            Util.Info("Ignoring Data Mark (Synch)");
-            break;
-        default:   // everything else
-            str += String.fromCharCode(chr);
-        }
-    }
-
-    if (sQ) {
-        do_send();
-    }
-
-    if (str) {
-        vt100.write(str);
-    }
-
-    //console.log("<< do_recv");
-}
-
-
-
-that.connect = function(host, port, encrypt) {
-    var host = host,
-        port = port,
-        scheme = "ws://", uri;
-
-    Util.Debug(">> connect");
-    if ((!host) || (!port)) {
-        console.log("must set host and port");
-        return;
-    }
-
-    if (ws) {
-        ws.close();
-    }
-
-    if (encrypt) {
-        scheme = "wss://";
-    }
-    uri = scheme + host + ":" + port;
-    Util.Info("connecting to " + uri);
-    ws = new WebSocket(uri);
-
-    ws.onmessage = do_recv;
-
-    ws.onopen = function(e) {
-        Util.Info(">> WebSockets.onopen");
-        vt100.curs_set(true, true);
-        connect_callback();
-        Util.Info("<< WebSockets.onopen");
-    };
-    ws.onclose = function(e) {
-        Util.Info(">> WebSockets.onclose");
-        that.disconnect();
-        Util.Info("<< WebSockets.onclose");
-    };
-    ws.onerror = function(e) {
-        Util.Info(">> WebSockets.onerror");
-        that.disconnect();
-        Util.Info("<< WebSockets.onerror");
-    };
-
-    Util.Debug("<< connect");
-}
-
-that.disconnect = function() {
-    Util.Debug(">> disconnect");
-    if (ws) {
-        ws.close();
-    }
-    vt100.curs_set(true, false);
-
-    disconnect_callback();
-    Util.Debug("<< disconnect");
-}
-
-
-function constructor() {
-    /* Initialize the terminal emulator/renderer */
-
-    vt100 = new VT100(80, 24, target);
-
-    // Turn off local echo
-    vt100.noecho();
-
-
-    /*
-     * Override VT100 I/O routines
-     */
-
-    // Set handler for sending characters
-    vt100.getch(
-        function send_chr(chr, vt) {
-            var i;
-            Util.Debug(">> send_chr: " + chr);
-            for (i = 0; i < chr.length; i++) {
-                sQ.push(chr.charCodeAt(i));
-            }
-            do_send();
-            vt100.getch(send_chr);
-        }
-    );
-
-    vt100.debug = function(message) {
-        Util.Debug(message + "\n");
-    }
-
-    vt100.warn = function(message) {
-        Util.Warn(message + "\n");
-    }
-
-    vt100.curs_set = function(vis, grab, eventist)
-    {
-        this.debug("curs_set:: vis: " + vis + ", grab: " + grab);
-        if (vis !== undefined)
-            this.cursor_vis_ = (vis > 0);
-        if (eventist === undefined)
-            eventist = window;
-        if (grab === true || grab === false) {
-            if (grab === this.grab_events_)
-                return;
-            if (grab) {
-                this.grab_events_ = true;
-                VT100.the_vt_ = this;
-                Util.addEvent(eventist, 'keydown', vt100.key_down);
-                Util.addEvent(eventist, 'keyup', vt100.key_up);
-            } else {
-                Util.removeEvent(eventist, 'keydown', vt100.key_down);
-                Util.removeEvent(eventist, 'keyup', vt100.key_up);
-                this.grab_events_ = false;
-                VT100.the_vt_ = undefined;
-            }
-        }
-    }
-
-    vt100.key_down = function(e) {
-        var vt = VT100.the_vt_, keysym, ch, str = "";
-
-        if (vt === undefined)
-            return true;
-
-        keysym = getKeysym(e);
-
-        if (keysym < 128) {
-            if (e.ctrlKey) {
-                if (keysym == 64) {
-                    // control 0
-                    ch = 0;
-                } else if ((keysym >= 97) && (keysym <= 122)) {
-                    // control codes 1-26
-                    ch = keysym - 96;
-                } else if ((keysym >= 91) && (keysym <= 95)) {
-                    // control codes 27-31
-                    ch = keysym - 64;
-                } else {
-                    Util.Info("Debug unknown control keysym: " + keysym);
-                }
-            } else {
-                ch = keysym;
-            }
-            str = String.fromCharCode(ch);
-        } else {
-            switch (keysym) {
-            case 65505: // Shift, do not send directly
-                break;
-            case 65507: // Ctrl, do not send directly
-                break;
-            case 65293: // Carriage return, line feed
-                str = '\n'; break;
-            case 65288: // Backspace
-                str = '\b'; break;
-            case 65307: // Escape
-                str = '\x1b'; break;
-            case 65361: // Left arrow 
-                str = '\x1b[D'; break;
-            case 65362: // Up arrow 
-                str = '\x1b[A'; break;
-            case 65363: // Right arrow 
-                str = '\x1b[C'; break;
-            case 65364: // Down arrow 
-                str = '\x1b[B'; break;
-            default:
-                Util.Info("Unrecoginized keysym " + keysym);
-            }
-        }
-
-        if (str) {
-            vt.key_buf_.push(str);
-            setTimeout(VT100.go_getch_, 0);
-        }
-
-        Util.stopEvent(e);
-        return false;
-    }
-
-    vt100.key_up = function(e) {
-        var vt = VT100.the_vt_;
-        if (vt === undefined)
-            return true;
-        Util.stopEvent(e);
-        return false;
-    }
-
-
-    return that;
-}
-
-return constructor(); // Return the public API interface
-
-} // End of Telnet()

+ 0 - 252
utils/wstest.html

@@ -1,252 +0,0 @@
-<html>
-
-    <head>
-        <title>WebSockets Test</title>
-        <script src="include/base64.js"></script>
-        <script src="include/util.js"></script>
-        <script src="include/webutil.js"></script> 
-        <!-- Uncomment to activate firebug lite -->
-        <!--
-        <script type='text/javascript' 
-            src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-        -->
-
-
-    </head>
-
-    <body>
-
-        Host: <input id='host' style='width:100'>&nbsp;
-        Port: <input id='port' style='width:50'>&nbsp;
-        Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
-        Send Delay (ms): <input id='sendDelay' style='width:50' value="100">&nbsp;
-        <input id='connectButton' type='button' value='Start' style='width:100px'
-            onclick="connect();">&nbsp;
-
-        <br><br>
-        <table border=1>
-            <tr>
-                <th align="right">Packets sent:</th>
-                <td align="right"><div id='sent'>0</div></td>
-            </tr><tr>
-                <th align="right">Good Packets Received:</th>
-                <td align="right"><div id='received'>0</div></td>
-            </tr><tr>
-                <th align="right">Errors (Bad Packets Received:)</th>
-                <td align="right"><div id='errors'>0</div></td>
-            </tr>
-        </table>
-
-        <br>
-        Errors:<br>
-        <textarea id="error" style="font-size: 9;" cols=80 rows=25></textarea>
-    </body>
-
-
-    <script>
-
-        function error(str) {
-            console.error(str);
-            cell = $D('error');
-            cell.innerHTML += errors + ": " + str + "\n";
-            cell.scrollTop = cell.scrollHeight;
-        }
-
-        var host = null, port = null, sendDelay = 0;
-        var ws = null, update_ref = null, send_ref = null;
-        var sent = 0, received = 0, errors = 0;
-        var max_send = 2000;
-        var recv_seq = 0, send_seq = 0;
-
-        Array.prototype.pushStr = function (str) {
-            var n = str.length;
-            for (var i=0; i < n; i++) {
-                this.push(str.charCodeAt(i));
-            }
-        }
-
-
-
-        function add (x,y) {
-            return parseInt(x,10)+parseInt(y,10);
-        }
-
-        function check_respond(data) {
-            //console.log(">> check_respond");
-            var decoded, first, last, str, length, chksum, nums, arr;
-            decoded = Base64.decode(data);
-            first = String.fromCharCode(decoded.shift());
-            last = String.fromCharCode(decoded.pop());
-
-            if (first != "^") {
-                errors++;
-                error("Packet missing start char '^'");
-                return;
-            }
-            if (last != "$") {
-                errors++;
-                error("Packet missing end char '$'");
-                return;
-            }
-            arr = decoded.map(function(num) {
-                    return String.fromCharCode(num); 
-                } ).join('').split(':');
-            seq    = arr[0];
-            length = arr[1];
-            chksum = arr[2];
-            nums   = arr[3];
-
-            //console.log("   length:" + length + " chksum:" + chksum + " nums:" + nums);
-            if (seq != recv_seq) {
-                errors++;
-                error("Expected seq " + recv_seq + " but got " + seq);
-                recv_seq = parseInt(seq,10) + 1;   // Back on track
-                return;
-            }
-            recv_seq++;
-            if (nums.length != length) {
-                errors++;
-                error("Expected length " + length + " but got " + nums.length);
-                return;
-            }
-            //real_chksum = nums.reduce(add);
-            real_chksum = 0;
-            for (var i=0; i < nums.length; i++) {
-                real_chksum += parseInt(nums.charAt(i), 10);
-            }
-            if (real_chksum != chksum) {
-                errors++
-                error("Expected chksum " + chksum + " but real chksum is " + real_chksum);
-                return;
-            }
-            received++;
-            //console.log("   Packet checks out: length:" + length + " chksum:" + chksum);
-            //console.log("<< check_respond");
-        }
-
-        function send() {
-            if (ws.bufferedAmount > 0) {
-                console.log("Delaying send");
-                return;
-            }
-            var length = Math.floor(Math.random()*(max_send-9)) + 10; // 10 - max_send
-            var numlist = [], arr = [];
-            for (var i=0; i < length; i++) {
-                numlist.push( Math.floor(Math.random()*10) );
-            }
-            //chksum = numlist.reduce(add);
-            chksum = 0;
-            for (var i=0; i < numlist.length; i++) {
-                chksum += parseInt(numlist[i], 10);
-            }
-            var nums = numlist.join('');
-            arr.pushStr("^" + send_seq + ":" + length + ":" + chksum + ":" + nums + "$")
-            send_seq ++;
-            ws.send(Base64.encode(arr));
-            sent++;
-        }
-
-        function update_stats() {
-            $D('sent').innerHTML = sent;
-            $D('received').innerHTML = received;
-            $D('errors').innerHTML = errors;
-        }
-
-        function init_ws() {
-            console.log(">> init_ws");
-            var scheme = "ws://";
-            if ($D('encrypt').checked) {
-                scheme = "wss://";
-            }
-            var uri = scheme + host + ":" + port;
-            console.log("connecting to " + uri);
-            ws = new WebSocket(uri);
-
-            ws.onmessage = function(e) {
-                //console.log(">> WebSockets.onmessage");
-                check_respond(e.data);
-                //console.log("<< WebSockets.onmessage");
-            };
-            ws.onopen = function(e) {
-                console.log(">> WebSockets.onopen");
-                send_ref = setInterval(send, sendDelay);
-                console.log("<< WebSockets.onopen");
-            };
-            ws.onclose = function(e) {
-                console.log(">> WebSockets.onclose");
-                clearInterval(send_ref);
-                console.log("<< WebSockets.onclose");
-            };
-            ws.onerror = function(e) {
-                console.log(">> WebSockets.onerror");
-                console.log("   " + e);
-                console.log("<< WebSockets.onerror");
-            };
-
-            console.log("<< init_ws");
-        }
-
-        function connect() {
-            console.log(">> connect");
-            host = $D('host').value;
-            port = $D('port').value;
-            sendDelay = parseInt($D('sendDelay').value, 10);
-            if ((!host) || (!port)) {
-                console.log("must set host and port");
-                return;
-            }
-
-            if (ws) {
-                ws.close();
-            }
-            init_ws();
-            update_ref = setInterval(update_stats, 1);
-
-            $D('connectButton').value = "Stop";
-            $D('connectButton').onclick = disconnect;
-            console.log("<< connect");
-        }
-
-        function disconnect() {
-            console.log(">> disconnect");
-            if (ws) {
-                ws.close();
-            }
-
-            clearInterval(update_ref);
-            update_stats(); // Final numbers
-            recv_seq = 0;
-            send_seq = 0;
-
-            $D('connectButton').value = "Start";
-            $D('connectButton').onclick = connect;
-            console.log("<< disconnect");
-        }
-
-
-        /* If no builtin websockets then load web_socket.js */
-        if (window.WebSocket) {
-            VNC_native_ws = true;
-        } else {
-            VNC_native_ws = false;
-            console.log("Loading web-socket-js flash bridge");
-            var extra = "<script src='include/web-socket-js/swfobject.js'><\/script>";
-            extra += "<script src='include/web-socket-js/FABridge.js'><\/script>";
-            extra += "<script src='include/web-socket-js/web_socket.js'><\/script>";
-            document.write(extra);
-        }
-
-        window.onload = function() {
-            console.log("onload");
-            if (!VNC_native_ws) {
-                console.log("initializing web-socket-js flash bridge");
-                WebSocket.__swfLocation = "include/web-socket-js/WebSocketMain.swf";
-                WebSocket.__initialize();
-            }
-            var url = document.location.href;
-            $D('host').value = (url.match(/host=([^&#]*)/) || ['',''])[1];
-            $D('port').value = (url.match(/port=([^&#]*)/) || ['',''])[1];
-        }
-    </script>
-
-</html>

+ 0 - 171
utils/wstest.py

@@ -1,171 +0,0 @@
-#!/usr/bin/python
-
-'''
-WebSocket server-side load test program. Sends and receives traffic
-that has a random payload (length and content) that is checksummed and
-given a sequence number. Any errors are reported and counted.
-'''
-
-import sys, os, socket, ssl, time, traceback
-import random, time
-from select import select
-
-sys.path.insert(0,os.path.dirname(__file__) + "/../utils/")
-from websocket import WebSocketServer
-
-
-class WebSocketTest(WebSocketServer):
-
-    buffer_size = 65536
-    max_packet_size = 10000
-    recv_cnt = 0
-    send_cnt = 0
-
-    def __init__(self, *args, **kwargs):
-        self.errors = 0
-        self.delay = kwargs.pop('delay')
-
-        print "Prepopulating random array"
-        self.rand_array = []
-        for i in range(0, self.max_packet_size):
-            self.rand_array.append(random.randint(0, 9))
-
-        WebSocketServer.__init__(self, *args, **kwargs)
-
-    def new_client(self, client):
-        self.send_cnt = 0
-        self.recv_cnt = 0
-
-        try:
-            self.responder(client)
-        except:
-            print "accumulated errors:", self.errors
-            self.errors = 0
-            raise
-
-    def responder(self, client):
-        cqueue = []
-        cpartial = ""
-        socks = [client]
-        last_send = time.time() * 1000
-
-        while True:
-            ins, outs, excepts = select(socks, socks, socks, 1)
-            if excepts: raise Exception("Socket exception")
-
-            if client in ins:
-                buf = client.recv(self.buffer_size)
-                if len(buf) == 0:
-                    raise self.EClose("Client closed")
-                #print "Client recv: %s (%d)" % (repr(buf[1:-1]), len(buf))
-                if buf[-1] == '\xff':
-                    if cpartial:
-                        err = self.check(cpartial + buf)
-                        cpartial = ""
-                    else:
-                        err = self.check(buf)
-                    if err:
-                        self.traffic("}")
-                        self.errors = self.errors + 1
-                        print err
-                    else:
-                        self.traffic(">")
-                else:
-                    self.traffic(".>")
-                    cpartial = cpartial + buf
-
-            now = time.time() * 1000
-            if client in outs and now > (last_send + self.delay):
-                last_send = now
-                #print "Client send: %s" % repr(cqueue[0])
-                client.send(self.generate())
-                self.traffic("<")
-
-    def generate(self):
-        length = random.randint(10, self.max_packet_size)
-        numlist = self.rand_array[self.max_packet_size-length:]
-        # Error in length
-        #numlist.append(5)
-        chksum = sum(numlist)
-        # Error in checksum
-        #numlist[0] = 5
-        nums = "".join( [str(n) for n in numlist] )
-        data = "^%d:%d:%d:%s$" % (self.send_cnt, length, chksum, nums)
-        self.send_cnt += 1
-
-        return WebSocketServer.encode(data)
-
-
-    def check(self, buf):
-        try:
-            data_list = WebSocketServer.decode(buf)
-        except:
-            print "\n<BOF>" + repr(buf) + "<EOF>"
-            return "Failed to decode"
-
-        err = ""
-        for data in data_list:
-            if data.count('$') > 1:
-                raise Exception("Multiple parts within single packet")
-            if len(data) == 0:
-                self.traffic("_")
-                continue
-
-            if data[0] != "^":
-                err += "buf did not start with '^'\n"
-                continue
-
-            try:
-                cnt, length, chksum, nums = data[1:-1].split(':')
-                cnt    = int(cnt)
-                length = int(length)
-                chksum = int(chksum)
-            except:
-                print "\n<BOF>" + repr(data) + "<EOF>"
-                err += "Invalid data format\n"
-                continue
-
-            if self.recv_cnt != cnt:
-                err += "Expected count %d but got %d\n" % (self.recv_cnt, cnt)
-                self.recv_cnt = cnt + 1
-                continue
-
-            self.recv_cnt += 1
-
-            if len(nums) != length:
-                err += "Expected length %d but got %d\n" % (length, len(nums))
-                continue
-
-            inv = nums.translate(None, "0123456789")
-            if inv:
-                err += "Invalid characters found: %s\n" % inv
-                continue
-
-            real_chksum = 0
-            for num in nums:
-                real_chksum += int(num)
-
-            if real_chksum != chksum:
-                err += "Expected checksum %d but real chksum is %d\n" % (chksum, real_chksum)
-        return err
-
-
-if __name__ == '__main__':
-    try:
-        if len(sys.argv) < 2: raise
-        listen_port = int(sys.argv[1])
-        if len(sys.argv) == 3:
-            delay = int(sys.argv[2])
-        else:
-            delay = 10
-    except:
-        print "Usage: %s <listen_port> [delay_ms]" % sys.argv[0]
-        sys.exit(1)
-
-    server = WebSocketTest(
-            listen_port=listen_port,
-            verbose=True,
-            cert='self.pem',
-            web='.',
-            delay=delay)
-    server.start_server()

+ 0 - 22
utils/wswrap

@@ -1,22 +0,0 @@
-#!/bin/bash
-
-usage() {
-    echo "Usage: $(basename $0) PORT CMDLINE"
-    echo
-    echo "    PORT     Port to wrap with WebSockets support"
-    echo "    CMDLINE  Command line to wrap"
-    exit 2
-}
-
-# Parameter defaults
-mydir=$(readlink -f $(dirname ${0}))
-
-# Process parameters
-#while [ "${1}" != "${1#-}" ]; do
-#    param=$1; shift
-#done
-
-export WSWRAP_PORT="${1}"; shift
-
-LD_PRELOAD=${mydir}/wswrapper.so "${@}"
-

+ 0 - 1156
utils/wswrapper.c

@@ -1,1156 +0,0 @@
-/*
- * wswrap/wswrapper: Add WebSockets support to any service.
- * Copyright 2010 Joel Martin
- * Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
- *
- * wswrapper is an LD_PRELOAD library that converts a TCP listen socket of an
- * existing program to a be a WebSockets socket. The `wswrap` script can be
- * used to easily launch a program using wswrapper. Here is an example of
- * using wswrapper with vncserver. wswrapper will convert the socket listening
- * on port 5901 to be a WebSockets port:
- *
- *  cd noVNC/utils
- *  ./wswrap 5901 vncserver -geometry 640x480 :1
- *
- * This is tricky a subtle process so there are some serious limitations:
- * - multi-threaded programs may not work
- * - programs that fork may behave in strange and mysterious ways (such as
- *   fork bombing your system)
- * - programs using ppoll or epoll will not work correctly
- * - doesn't support fopencookie, streams, putc, etc.
- *
- * **********************************************************************
- * WARNING:
- * Due to the above limitations, this code should be considered an experiment
- * only. Consider using the program wrap mode of wsproxy.py instead.
- * **********************************************************************
- */
-
-#define DO_MSG 1
-#define DO_DEBUG 1
-#define DO_TRACE 1
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#define __USE_GNU 1 // Pull in RTLD_NEXT
-#include <dlfcn.h>
-
-#include <poll.h>
-#include <sys/poll.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <resolv.h>      /* base64 encode/decode */
-#include <sys/time.h>
-#include "md5.h"
-#include "wswrapper.h"
-
-/*
- * If WSWRAP_PORT environment variable is set then listen to the bind fd that
- * matches WSWRAP_PORT
- */
-int              _WS_listen_fd  = -1;
-int              _WS_nfds       = 0;
-int              _WS_fds[WS_MAX_FDS];
-_WS_connection  *_WS_connections[65536];
-
-
-/* 
- * Utillity routines
- */
-    
-/*
- * Subtract the `struct timeval' values X and Y, storing the
- * result in RESULT. If TS is set then RESULT and X are really
- * type-cast `struct timespec` so scale them appropriately.
- * Return 1 if the difference is negative or 0, otherwise 0.
- */
-int _WS_subtract_time (result, x, y, ts)
-    struct timeval *result, *x, *y;
-{
-    int scale = ts ? 1000 : 1;
-    /* Perform the carry for the later subtraction by updating y. */
-    if ((x->tv_usec / scale) < y->tv_usec) {
-        int sec = (y->tv_usec - (x->tv_usec / scale)) / 1000000 + 1;
-        y->tv_usec -= 1000000 * sec;
-        y->tv_sec += sec;
-    }
-    if ((x->tv_usec / scale) - y->tv_usec > 1000000) {
-        int sec = ((x->tv_usec / scale) - y->tv_usec) / 1000000;
-        y->tv_usec += 1000000 * sec;
-        y->tv_sec -= sec;
-    }
-
-    /* Compute the time remaining to wait.
-     * tv_usec is certainly positive. */
-    result->tv_sec = x->tv_sec - y->tv_sec;
-    result->tv_usec = x->tv_usec - (y->tv_usec * scale);
-
-    /* Return 1 if result is negative or 0. */
-    return x->tv_sec <= y->tv_sec;
-}
-
-int _WS_alloc(int fd) {
-    if (_WS_connections[fd]) {
-        RET_ERROR(ENOMEM, "Memory already allocated for fd %d\n", fd);
-    }
-    if (! (_WS_connections[fd] = malloc(sizeof(_WS_connection)))) {
-        RET_ERROR(ENOMEM, "Could not allocate interposer memory\n");
-    }
-    _WS_connections[fd]->rcarry_cnt = 0;
-    _WS_connections[fd]->rcarry[0]  = '\0';
-    _WS_connections[fd]->newframe   = 1;
-    _WS_connections[fd]->refcnt     = 1;
-
-    /* Add to search list for select/pselect */
-    _WS_fds[_WS_nfds] = fd;
-    _WS_nfds++;
-
-    return 0;
-}
-
-int _WS_free(int fd) {
-    int i;
-    _WS_connection * wsptr;
-    wsptr = _WS_connections[fd];
-    if (wsptr) {
-        TRACE(">> _WS_free(%d)\n", fd);
-
-        wsptr->refcnt--;
-        if (wsptr->refcnt <= 0) {
-            free(wsptr);
-            DEBUG("freed memory for fd %d\n", fd);
-        }
-        _WS_connections[fd] = NULL;
-
-        /* Remove from the search list for select/pselect */
-        for (i = 0; i < _WS_nfds; i++) {
-            if (_WS_fds[i] == fd) {
-                break;
-            }
-        }
-        if (_WS_nfds - i - 1 > 0) {
-            memmove(_WS_fds + i, _WS_fds + i + 1, _WS_nfds - i - 1);
-        }
-        _WS_nfds--;
-
-        MSG("finished interposing on fd %d\n", fd);
-        TRACE("<< _WS_free(%d)\n", fd);
-    }
-}
-
-
-/* 
- * WebSocket handshake routines
- */
-
-/* For WebSockets v76, use key1, key2 and key3 to generate md5 hash */
-int _WS_gen_md5(char *key1, char *key2, char *key3, char *target) {
-    unsigned int i, spaces1 = 0, spaces2 = 0;
-    unsigned long num1 = 0, num2 = 0;
-    unsigned char buf[17];
-
-    /* Parse number 1 from key 1 */
-    for (i=0; i < strlen(key1); i++) {
-        if (key1[i] == ' ') {
-            spaces1 += 1;
-        }
-        if ((key1[i] >= 48) && (key1[i] <= 57)) {
-            num1 = num1 * 10 + (key1[i] - 48);
-        }
-    }
-    num1 = num1 / spaces1;
-
-    /* Parse number 2 from key 2 */
-    for (i=0; i < strlen(key2); i++) {
-        if (key2[i] == ' ') {
-            spaces2 += 1;
-        }
-        if ((key2[i] >= 48) && (key2[i] <= 57)) {
-            num2 = num2 * 10 + (key2[i] - 48);
-        }
-    }
-    num2 = num2 / spaces2;
-
-    /* Pack it big-endian as the first 8 bytes */
-    buf[0] = (num1 & 0xff000000) >> 24;
-    buf[1] = (num1 & 0xff0000) >> 16;
-    buf[2] = (num1 & 0xff00) >> 8;
-    buf[3] =  num1 & 0xff;
-
-    buf[4] = (num2 & 0xff000000) >> 24;
-    buf[5] = (num2 & 0xff0000) >> 16;
-    buf[6] = (num2 & 0xff00) >> 8;
-    buf[7] =  num2 & 0xff;
-
-    /* Add key 3 as the last 8 bytes */
-    strncpy(buf+8, key3, 8);
-    buf[16] = '\0';
-
-    /* md5 hash all 16 bytes to generate 16 byte target */
-    md5_buffer(buf, 16, target);
-    target[16] = '\0';
-
-    return 1;
-}
-
-/* Do v75 and v76 handshake on WebSocket connection */
-int _WS_handshake(int sockfd)
-{
-    int sz = 0, len, idx;
-    int ret = -1, save_errno = EPROTO;
-    char *last, *start, *end;
-    long flags;
-    char handshake[4096], response[4096],
-         path[1024], prefix[5] = "", scheme[10] = "ws", host[1024],
-         origin[1024], key1[100], key2[100], key3[9], chksum[17];
-
-    static void * (*rfunc)(), * (*wfunc)();
-    if (!rfunc) rfunc = (void *(*)()) dlsym(RTLD_NEXT, "recv");
-    if (!wfunc) wfunc = (void *(*)()) dlsym(RTLD_NEXT, "send");
-    DEBUG("_WS_handshake starting\n");
-
-    /* Disable NONBLOCK if set */
-    flags = fcntl(sockfd, F_GETFL, 0);
-    if (flags & O_NONBLOCK) {
-        fcntl(sockfd, F_SETFL, flags^O_NONBLOCK);
-    }
-
-    while (1) {
-        len = (int) rfunc(sockfd, handshake+sz, 4095, 0);
-        if (len < 1) {
-            ret = len;
-            save_errno = errno;
-            break;
-        }
-        sz += len;
-        handshake[sz] = '\x00';
-        if (sz < 4) {
-            // Not enough yet
-            continue;
-        }
-        if (strstr(handshake, "GET ") != handshake) {
-            MSG("Got non-WebSockets client connection\n");
-            break;
-        }
-        last = strstr(handshake, "\r\n\r\n");
-        if (! last) {
-            continue;
-        }
-        if (! strstr(handshake, "Upgrade: WebSocket\r\n")) {
-            MSG("Invalid WebSockets handshake\n");
-            break;
-        }
-
-        /* Now parse out the data elements */
-        start = handshake+4;
-        end = strstr(start, " HTTP/1.1");
-        if (!end) { break; }
-        snprintf(path, end-start+1, "%s", start);
-
-        start = strstr(handshake, "\r\nHost: ");
-        if (!start) { break; }
-        start += 8;
-        end = strstr(start, "\r\n");
-        snprintf(host, end-start+1, "%s", start);
-
-        start = strstr(handshake, "\r\nOrigin: ");
-        if (!start) { break; }
-        start += 10;
-        end = strstr(start, "\r\n");
-        snprintf(origin, end-start+1, "%s", start);
-
-        start = strstr(handshake, "\r\n\r\n") + 4;
-        if (strlen(start) == 8) {
-            sprintf(prefix, "Sec-");
-
-            snprintf(key3, 8+1, "%s", start);
-
-            start = strstr(handshake, "\r\nSec-WebSocket-Key1: ");
-            if (!start) { break; }
-            start += 22;
-            end = strstr(start, "\r\n");
-            snprintf(key1, end-start+1, "%s", start);
-
-            start = strstr(handshake, "\r\nSec-WebSocket-Key2: ");
-            if (!start) { break; }
-            start += 22;
-            end = strstr(start, "\r\n");
-            snprintf(key2, end-start+1, "%s", start);
-
-            _WS_gen_md5(key1, key2, key3, chksum);
-
-            //DEBUG("Got handshake (v76): %s\n", handshake);
-            MSG("New WebSockets client (v76)\n");
-
-        } else {
-            sprintf(prefix, "");
-            sprintf(key1, "");
-            sprintf(key2, "");
-            sprintf(key3, "");
-            sprintf(chksum, "");
-
-            //DEBUG("Got handshake (v75): %s\n", handshake);
-            MSG("New WebSockets client (v75)\n");
-        }
-        sprintf(response, _WS_response, prefix, origin, prefix, scheme,
-                host, path, prefix, chksum);
-        //DEBUG("Handshake response: %s\n", response);
-        wfunc(sockfd, response, strlen(response), 0);
-        save_errno = 0;
-        ret = 0;
-        break;
-    }
-
-    /* Re-enable NONBLOCK if it was set */
-    if (flags & O_NONBLOCK) {
-        fcntl(sockfd, F_SETFL, flags);
-    }
-    errno = save_errno;
-    return ret;
-}
-
-/* 
- * Strip empty WebSockets frames and return a positive value if there is
- * enough data to base64 decode (a 4 byte chunk). If nonblock is not set then
- * it will block until there is enough data (or until an error occurs).
- */
-ssize_t _WS_ready(int sockfd, int nonblock)
-{
-    _WS_connection *ws = _WS_connections[sockfd];
-    char buf[6];
-    int count, len, flags, i;
-    static void * (*rfunc)();
-    if (!rfunc) rfunc = (void *(*)()) dlsym(RTLD_NEXT, "recv");
-
-    TRACE(">> _WS_ready(%d, %d)\n", sockfd, nonblock);
-
-    count = 4 + ws->newframe;
-    flags = MSG_PEEK;
-    if (nonblock) {
-        flags |= MSG_DONTWAIT;
-    }
-    while (1) {
-        len = (int) rfunc(sockfd, buf, count, flags);
-        if (len < 1) {
-            TRACE("<< _WS_ready(%d, %d) len %d, errno: %d\n",
-                  sockfd, nonblock, len, errno);
-            return len;
-        }
-        if (len >= 2 && buf[0] == '\x00' && buf[1] == '\xff') {
-            /* Strip emtpy frame */
-            DEBUG("_WS_ready(%d, %d), strip empty\n", sockfd, nonblock);
-            len = (int) rfunc(sockfd, buf, 2, 0);
-            if (len < 2) {
-                MSG("Failed to strip empty frame headers\n");
-                TRACE("<< _WS_ready: failed to strip empty frame headers\n");
-                return len;
-            } else if (len == 2 && nonblock) {
-                errno = EAGAIN;
-                TRACE("<< _WS_ready(%d, %d), len == 2, EAGAIN\n",
-                      sockfd, nonblock);
-                return -1;
-            }
-            continue;
-        }
-        if (len < count) {
-            if (nonblock) {
-                errno = EAGAIN;
-                TRACE("<< _WS_ready(%d, %d), len < count, EAGAIN\n",
-                      sockfd, nonblock);
-                return -1;
-            } else {
-                fprintf(stderr, "_WS_ready(%d, %d), loop: len %d, buf:",
-                        sockfd, nonblock, len, (unsigned char) buf[0]);
-                for (i = 0; i < len; i++) {
-                    fprintf(stderr, "%d", (unsigned char) buf[i]);
-                }
-                fprintf(stderr, "\n");
-
-                continue;
-            }
-        }
-        TRACE("<< _WS_ready(%d, %d) len: %d\n", sockfd, nonblock, len);
-        return len;
-    }
-}
-
-/*
- * WebSockets recv/read interposer routine
- */
-ssize_t _WS_recv(int recvf, int sockfd, const void *buf,
-                 size_t len, int flags)
-{
-    _WS_connection *ws = _WS_connections[sockfd];
-    int rawcount, deccount, left, striplen, decodelen, ready;
-    ssize_t retlen, rawlen;
-    int sockflags;
-    int i;
-    char *fstart, *fend, *cstart;
-
-    static void * (*rfunc)(), * (*rfunc2)();
-    if (!rfunc) rfunc = (void *(*)()) dlsym(RTLD_NEXT, "recv");
-    if (!rfunc2) rfunc2 = (void *(*)()) dlsym(RTLD_NEXT, "read");
-
-    if (! ws) {
-        // Not our file descriptor, just pass through
-        if (recvf) {
-            return (ssize_t) rfunc(sockfd, buf, len, flags);
-        } else {
-            return (ssize_t) rfunc2(sockfd, buf, len);
-        }
-    }
-    TRACE(">> _WS_recv(%d)\n", sockfd);
-
-    if (len == 0) {
-        TRACE("<< _WS_recv(%d) len == 0\n", sockfd);
-        return 0;
-    }
-
-    sockflags = fcntl(sockfd, F_GETFL, 0);
-    if (sockflags & O_NONBLOCK) {
-        TRACE("_WS_recv(%d, _, %d) with O_NONBLOCK\n", sockfd, len);
-    } else {
-        TRACE("_WS_recv(%d, _, %d) without O_NONBLOCK\n", sockfd, len);
-    }
-
-    left = len;
-    retlen = 0;
-
-    /* first copy in carry-over bytes from previous recv/read */
-    if (ws->rcarry_cnt) {
-        if (ws->rcarry_cnt == 1) {
-            DEBUG("Using carry byte: %u (", ws->rcarry[0]);
-        } else if (ws->rcarry_cnt == 2) {
-            DEBUG("Using carry bytes: %u,%u (", ws->rcarry[0],
-                    ws->rcarry[1]);
-        } else {
-            RET_ERROR(EIO, "Too many carry-over bytes\n");
-        }
-        if (len <= ws->rcarry_cnt) {
-            DEBUG("final)\n");
-            memcpy((char *) buf, ws->rcarry, len);
-            ws->rcarry_cnt -= len;
-            return len;
-        } else {
-            DEBUG("prepending)\n");
-            memcpy((char *) buf, ws->rcarry, ws->rcarry_cnt);
-            retlen += ws->rcarry_cnt;
-            left -= ws->rcarry_cnt;
-            ws->rcarry_cnt = 0;
-        }
-    }
-
-    /* Determine the number of base64 encoded bytes needed */
-    rawcount = (left * 4) / 3 + 3;
-    rawcount -= rawcount%4;
-
-    if (rawcount > WS_BUFSIZE - 1) {
-        RET_ERROR(ENOMEM, "recv of %d bytes is larger than buffer\n", rawcount);
-    }
-
-    ready = _WS_ready(sockfd, 0);
-    if (ready < 1) {
-        if (retlen) {
-            /* We had some carry over, don't error until next call */
-            errno = 0;
-        } else {
-            retlen = ready;
-        }
-        TRACE("<< _WS_recv(%d, _, %d) retlen %d\n", sockfd, len, retlen);
-        return retlen;
-    }
-
-    /* We have enough data to return something */
-
-    /* Peek at everything available */
-    rawlen = (ssize_t) rfunc(sockfd, ws->rbuf, WS_BUFSIZE-1,
-                             flags | MSG_PEEK);
-    if (rawlen <= 0) {
-        RET_ERROR(EPROTO, "Socket was ready but then had failure");
-    }
-    fstart = ws->rbuf;
-    fstart[rawlen] = '\x00';
-
-
-    if (ws->newframe) {
-        if (fstart[0] != '\x00') {
-            RET_ERROR(EPROTO, "Missing frame start\n");
-        }
-        fstart++;
-        rawlen--;
-        ws->newframe = 0;
-    }
-
-    fend = memchr(fstart, '\xff', rawlen);
-
-    if (fend) {
-        ws->newframe = 1;
-        if ((fend - fstart) % 4) {
-            RET_ERROR(EPROTO, "Frame length is not multiple of 4\n");
-        }
-    } else {
-        fend = fstart + rawlen - (rawlen % 4);
-        if (fend - fstart < 4) {
-            RET_ERROR(EPROTO, "Frame too short\n");
-        }
-    }
-
-    /* Determine amount to consume */
-    if (rawcount < fend - fstart) {
-        ws->newframe = 0;
-        deccount = rawcount;
-    } else {
-        deccount = fend - fstart;
-    }
-
-    /* Now consume what was processed (if not MSG_PEEK) */
-    if (flags & MSG_PEEK) {
-        DEBUG("_WS_recv(%d, _, %d) MSG_PEEK, not consuming\n", sockfd, len);
-    } else {
-        rfunc(sockfd, ws->rbuf, fstart - ws->rbuf + deccount + ws->newframe, flags);
-    }
-
-    fstart[deccount] = '\x00'; // base64 terminator
-
-    /* Do base64 decode into the return buffer */
-    decodelen = b64_pton(fstart, (char *) buf + retlen, deccount);
-    if (decodelen <= 0) {
-        RET_ERROR(EPROTO, "Base64 decode error\n");
-    }
-
-    /* Calculate return length and carry-over */
-    if (decodelen <= left) {
-        retlen += decodelen;
-    } else {
-        retlen += left;
-
-        if (! (flags & MSG_PEEK)) {
-            /* Add anything left over to the carry-over */
-            ws->rcarry_cnt = decodelen - left;
-            if (ws->rcarry_cnt > 2) {
-                RET_ERROR(EPROTO, "Got too much base64 data\n");
-            }
-            memcpy(ws->rcarry, buf + retlen, ws->rcarry_cnt);
-            if (ws->rcarry_cnt == 1) {
-                DEBUG("Saving carry byte: %u\n", ws->rcarry[0]);
-            } else if (ws->rcarry_cnt == 2) {
-                DEBUG("Saving carry bytes: %u,%u\n", ws->rcarry[0],
-                        ws->rcarry[1]);
-            } else {
-                RET_ERRO(EPROTO, "Too many carry bytes!\n");
-            }
-        }
-    }
-    ((char *) buf)[retlen] = '\x00';
-
-    TRACE("<< _WS_recv(%d) retlen %d\n", sockfd, retlen);
-    return retlen;
-}
-
-/*
- * WebSockets send and write interposer routine
- */
-ssize_t _WS_send(int sendf, int sockfd, const void *buf,
-                 size_t len, int flags)
-{
-    _WS_connection *ws = _WS_connections[sockfd];
-    int rawlen, enclen, rlen, over, left, clen, retlen, dbufsize;
-    int sockflags;
-    char * target;
-    int i;
-    static void * (*sfunc)(), * (*sfunc2)();
-    if (!sfunc) sfunc   = (void *(*)()) dlsym(RTLD_NEXT, "send");
-    if (!sfunc2) sfunc2 = (void *(*)()) dlsym(RTLD_NEXT, "write");
-
-    if (! ws) {
-        // Not our file descriptor, just pass through
-        if (sendf) {
-            return (ssize_t) sfunc(sockfd, buf, len, flags);
-        } else {
-            return (ssize_t) sfunc2(sockfd, buf, len);
-        }
-    }
-    TRACE(">> _WS_send(%d, _, %d)\n", sockfd, len);
-
-    sockflags = fcntl(sockfd, F_GETFL, 0);
-
-    dbufsize = (WS_BUFSIZE * 3)/4 - 2;
-    if (len > dbufsize) {
-        RET_ERROR(ENOMEM, "send of %d bytes is larger than send buffer\n", len);
-    }
-
-    /* base64 encode and add frame markers */
-    rawlen = 0;
-    ws->sbuf[rawlen++] = '\x00';
-    enclen = b64_ntop(buf, len, ws->sbuf+rawlen, WS_BUFSIZE-rawlen);
-    if (enclen < 0) {
-        RET_ERROR(EPROTO, "Base64 encoding error\n");
-    }
-    rawlen += enclen;
-    ws->sbuf[rawlen++] = '\xff';
-
-    rlen = (int) sfunc(sockfd, ws->sbuf, rawlen, flags);
-
-    if (rlen <= 0) {
-        TRACE("<< _WS_send(%d, _, %d) send failed, returning\n", sockfd, len);
-        return rlen;
-    } else if (rlen < rawlen) {
-        /* Spin until we can send a whole base64 chunck and frame end */
-        over = (rlen - 1) % 4;  
-        left = (4 - over) % 4 + 1; // left to send
-        DEBUG("_WS_send: rlen: %d (over: %d, left: %d), rawlen: %d\n",
-              rlen, over, left, rawlen);
-        rlen += left;
-        ws->sbuf[rlen-1] = '\xff';
-        i = 0;
-        do {
-            i++;
-            clen = (int) sfunc(sockfd, ws->sbuf + rlen - left, left, flags);
-            if (clen > 0) {
-                left -= clen;
-            } else if (clen == 0) {
-                MSG("_WS_send: got clen %d\n", clen);
-            } else if (!(sockflags & O_NONBLOCK)) {
-                MSG("<< _WS_send: clen %d\n", clen);
-                return clen;
-            }
-            if (i > 1000000) { 
-                RET_ERROR(EIO, "Could not send final part of frame\n");
-            }
-        } while (left > 0);
-        //DEBUG("_WS_send: spins until finished %d\n", i);
-        DEBUG("_WS_send: spins until finished %d\n", i);
-    }
-
-
-    /*
-     * Report back the number of original characters sent,
-     * not the raw number sent
-     */
-
-    /* Adjust for framing */
-    retlen = rlen - 2;
-
-    /* Adjust for base64 padding */
-    if (ws->sbuf[rlen-1] == '=') { retlen --; }
-    if (ws->sbuf[rlen-2] == '=') { retlen --; }
-
-    /* Scale return value for base64 encoding size */
-    retlen = (retlen*3)/4;
-
-    TRACE(">> _WS_send(%d, _, %d) retlen %d\n", sockfd, len, retlen);
-    return (ssize_t) retlen;
-}
-
-/*
- * Interpose select/pselect/poll.
- *
- * WebSocket descriptors are not ready until we have received a frame start
- * ('\x00') and at least 4 bytes of base64 encoded data. In addition we may
- * have carry-over data from the last 4 bytes of base64 data in which case the
- * WebSockets socket is ready even though there might not be data in the raw
- * socket itself.
- */
-
-/* Interpose on select (mode==0) and pselect (mode==1) */
-int _WS_select(int mode, int nfds, fd_set *readfds,
-               fd_set *writefds, fd_set *exceptfds,
-               void *timeptr, const sigset_t *sigmask)
-{
-    _WS_connection *ws;
-    fd_set carryfds, savefds;
-    /* Assumes timeptr is two longs whether timeval or timespec */
-    struct timeval savetv, starttv, nowtv, difftv;
-    int carrycnt = 0, less = 0;
-    int ret, i, ready, fd;
-    static void * (*func0)(), * (*func1)();
-    if (!func0) func0 = (void *(*)()) dlsym(RTLD_NEXT, "select");
-    if (!func1) func1 = (void *(*)()) dlsym(RTLD_NEXT, "pselect");
-
-    if ((_WS_listen_fd == -1) || (_WS_nfds == 0)) {
-        if (mode == 0) {
-            ret = (int) func0(nfds, readfds, writefds, exceptfds,
-                              timeptr);
-        } else if (mode == 1) {
-            ret = (int) func1(nfds, readfds, writefds, exceptfds,
-                              timeptr, sigmask);
-        }
-        return ret;
-    }
-
-#ifdef DO_TRACE
-    TRACE(">> _WS_select(%d, %d, _, _, _, _)\n", mode, nfds);
-    for (i = 0; i < _WS_nfds; i++) {
-        fd = _WS_fds[i];
-        if (readfds && (FD_ISSET(fd, readfds))) {
-            TRACE("   WS %d is in readfds\n", fd, nfds);
-        }
-        if (writefds && (FD_ISSET(fd, writefds))) {
-            TRACE("   WS %d is in writefds\n", fd, nfds);
-        }
-        if (exceptfds && (FD_ISSET(fd, exceptfds))) {
-            TRACE("   WS %d is in exceptfds\n", fd, nfds);
-        }
-    }
-#endif
-    if (timeptr) {
-        memcpy(&savetv, timeptr, sizeof(savetv));
-        gettimeofday(&starttv, NULL);
-    }
-
-    /* If we have carry-over return it right away */
-    FD_ZERO(&carryfds);
-    if (readfds) {
-        memcpy(&savefds, readfds, sizeof(savefds));
-        for (i = 0; i < _WS_nfds; i++) {
-            fd = _WS_fds[i];
-            ws = _WS_connections[fd];
-            if ((ws->rcarry_cnt) && (FD_ISSET(fd, readfds))) {
-                FD_SET(fd, &carryfds);
-                carrycnt++;
-            }
-        }
-    }
-    if (carrycnt) {
-        if (writefds) {
-            FD_ZERO(writefds);
-        }
-        if (exceptfds) {
-            FD_ZERO(writefds);
-        }
-        memcpy(readfds, &carryfds, sizeof(carryfds));
-        TRACE("<< _WS_select(%d, %d, _, _, _, _) carrycnt %d\n",
-              mode, nfds, carrycnt);
-        return carrycnt;
-    }
-
-    do {
-        if (timeptr) {
-            TRACE("   _WS_select tv/ts: %ld:%ld\n",
-                ((struct timeval *) timeptr)->tv_sec,
-                ((struct timeval *) timeptr)->tv_usec);
-        }
-        if (mode == 0) {
-            ret = (int) func0(nfds, readfds, writefds, exceptfds,
-                              timeptr);
-        } else if (mode == 1) {
-            ret = (int) func1(nfds, readfds, writefds, exceptfds,
-                              timeptr, sigmask);
-        }
-        if (! readfds) {
-            break;
-        }
-        if (ret <= 0) {
-            break;
-        }
-
-        for (i = 0; i < _WS_nfds; i++) {
-            fd = _WS_fds[i];
-            ws = _WS_connections[fd];
-            if (FD_ISSET(fd, readfds)) {
-                ready = _WS_ready(fd, 1);
-                if (ready == 0) {
-                    /* 0 means EOF which is also a ready condition */
-                    DEBUG("_WS_select: detected %d is closed\n", fd);
-                } else if (ready < 0) {
-                    DEBUG("_WS_select: FD_CLR(%d,readfds) - not enough to decode\n", fd);
-                    FD_CLR(fd, readfds);
-                    ret--;
-                }
-            }
-        }
-        errno = 0; /* errno could be set by _WS_ready */
-
-        if (ret == 0) {
-            /*
-             * If all the ready readfds were WebSockets, but none of
-             * them were really ready (empty frames) then we select again. But
-             * first restore original values less passage of time.
-             */
-            if (! timeptr) {
-                /* No timeout, spin forever */
-                continue;
-            }
-            memcpy(readfds, &savefds, sizeof(savefds));
-            gettimeofday(&nowtv, NULL);
-            /* Amount of time that has passed */
-            _WS_subtract_time(&difftv, &nowtv, &starttv, 0);
-            /* Subtract from original timout */
-            less = _WS_subtract_time((struct timeval *) timeptr,
-                                     &savetv, &difftv, mode);
-            if (less) {
-                /* Timer has expired */
-                TRACE("  _WS_select expired timer\n", mode, nfds);
-                break;
-            }
-        }
-    } while (ret == 0);
-
-    /* Restore original time value for pselect glibc does */
-    if (timeptr && mode == 1) {
-        memcpy(timeptr, &savetv, sizeof(savetv));
-    }
-
-#ifdef DO_TRACE
-    TRACE("<< _WS_select(%d, %d, _, _, _, _) ret %d, errno %d\n",
-          mode, nfds, ret, errno);
-    for (i = 0; i < _WS_nfds; i++) {
-        fd = _WS_fds[i];
-        if (readfds && (FD_ISSET(fd, readfds))) {
-            TRACE("   WS %d is set in readfds\n", fd, nfds);
-        }
-        if (writefds && (FD_ISSET(fd, writefds))) {
-            TRACE("   WS %d is set in writefds\n", fd, nfds);
-        }
-        if (exceptfds && (FD_ISSET(fd, exceptfds))) {
-            TRACE("   WS %d is set in exceptfds\n", fd, nfds);
-        }
-    }
-#endif
-    return ret;
-}
-
-/* Interpose on poll (mode==0) and ppoll (mode==1) */
-int _WS_poll(int mode, struct pollfd *fds, nfds_t nfds, int timeout,
-             struct timespec *ptimeout, sigset_t *sigmask)
-{
-    _WS_connection *ws;
-    int savetimeout;
-    struct timespec savets;
-    struct timeval starttv, nowtv, difftv;
-    struct pollfd *pfd;
-    int carrycnt = 0, less = 0;
-    int ret, i, ready, fd;
-    static void * (*func0)(), * (*func1)();
-    if (!func0) func0 = (void *(*)()) dlsym(RTLD_NEXT, "poll");
-    if (!func1) func1 = (void *(*)()) dlsym(RTLD_NEXT, "ppoll");
-
-    if ((_WS_listen_fd == -1) || (_WS_nfds == 0)) {
-        if (mode == 0) {
-            ret = (int) func0(fds, nfds, timeout);
-        } else if (mode == 1) {
-            ret = (int) func1(fds, nfds, ptimeout, sigmask);
-        }
-        return ret;
-    }
-
-    TRACE(">> _WS_poll(%d, %ld, _, _, _, _)\n", mode, nfds);
-    if (mode == 0) {
-        savetimeout = timeout;
-    } else if (mode == 1) {
-        memcpy(&savets, ptimeout, sizeof(savets));
-    }
-    gettimeofday(&starttv, NULL);
-
-    do {
-        TRACE("   _WS_poll(%d, %ld, _, _, _, _) tv/ts: %ld:%ld\n", mode, nfds,
-              ptimeout->tv_sec, ptimeout->tv_nsec);
-
-        if (mode == 0) {
-            ret = (int) func0(fds, nfds, timeout);
-        } else if (mode == 1) {
-            ret = (int) func1(fds, nfds, ptimeout, sigmask);
-        }
-        if (ret <= 0) {
-            break;
-        }
-
-        for (i = 0; i < nfds; i++) {
-            pfd = &fds[i];
-            if (! (pfd->events & POLLIN)) {
-                continue;
-            }
-            ws = _WS_connections[pfd->fd];
-            if (! ws) {
-                continue;
-            }
-            if (ws->rcarry_cnt) {
-                if (! (pfd->revents & POLLIN)) {
-                    pfd->revents |= POLLIN;
-                    ret++;
-                }
-            } else if (pfd->revents & POLLIN) {
-                ready = _WS_ready(pfd->fd, 1);
-                if (ready == 0) {
-                    /* 0 means EOF which is also a ready condition */
-                    DEBUG("_WS_poll: detected %d is closed\n", fd);
-                } else if (ready < 0) {
-                    DEBUG("_WS_poll: not enough to decode\n", fd);
-                    pfd->revents -= POLLIN;
-                    ret--;
-                }
-            }
-        }
-        errno = 0; /* errno could be set by _WS_ready */
-
-        if (ret == 0) {
-            /*
-             * If all the ready readfds were WebSockets, but none of
-             * them were really ready (empty frames) then we select again. But
-             * first restore original values less passage of time.
-             */
-            gettimeofday(&nowtv, NULL);
-            /* Amount of time that has passed */
-            _WS_subtract_time(&difftv, &nowtv, &starttv, 0);
-            if (mode == 0) {
-                if (timeout < 0) {
-                    /* Negative timeout means infinite */
-                    continue;
-                }
-                timeout -= difftv.tv_sec * 1000 + difftv.tv_usec / 1000;
-                if (timeout <= 0) {
-                    less = 1;
-                }
-            } else if (mode == 1) {
-                /* Subtract from original timout */
-                less = _WS_subtract_time((struct timeval *) ptimeout,
-                                         (struct timeval *) &savets,
-                                         &difftv, 1);
-            }
-            if (less) {
-                /* Timer has expired */
-                TRACE("  _WS_poll expired timer\n", mode, nfds);
-                break;
-            }
-        }
-    } while (ret == 0);
-
-    /* Restore original time value for pselect glibc does */
-    if (mode == 1) {
-        memcpy(ptimeout, &savets, sizeof(savets));
-    }
-
-    TRACE("<< _WS_poll(%d, %ld, _, _, _, _) ret %d, errno %d\n",
-          mode, nfds, ret, errno);
-    return ret;
-}
-
-
-/*
- * Overload (LD_PRELOAD) standard library network routines
- */
-
-int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
-{
-    static void * (*func)();
-    struct sockaddr_in * addr_in = (struct sockaddr_in *)addr;
-    char * WSWRAP_PORT, * end;
-    int ret, envport, bindport = htons(addr_in->sin_port);
-    if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "bind");
-    TRACE(">> bind(%d, _, %d)\n", sockfd, addrlen);
-
-    ret = (int) func(sockfd, addr, addrlen);
-
-    if (addr_in->sin_family != AF_INET) {
-        // TODO: handle IPv6
-        TRACE("<< bind, ignoring non-IPv4 socket\n");
-        return ret;
-    }
-
-    WSWRAP_PORT = getenv("WSWRAP_PORT");
-    if ((! WSWRAP_PORT) || (*WSWRAP_PORT == '\0')) {
-        // TODO: interpose on all sockets when WSWRAP_PORT not set
-        TRACE("<< bind, not interposing: WSWRAP_PORT is not set\n");
-        return ret;
-    }
-
-    envport = strtol(WSWRAP_PORT, &end, 10);
-    if ((envport == 0) || (*end != '\0')) {
-        TRACE("<< bind, not interposing: WSWRAP_PORT is not a number\n");
-        return ret;
-    }
-
-    if (envport != bindport) {
-        TRACE("<< bind, not interposing on port: %d (fd %d)\n", bindport, sockfd);
-        return ret;
-    }
-
-    _WS_listen_fd = sockfd;
-
-    TRACE("<< bind, listening for WebSockets connections on port: %d (fd %d)\n", envport, sockfd);
-    return ret;
-}
-
-int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
-{
-    int fd, ret, envfd;
-    static void * (*func)();
-    if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "accept");
-    TRACE("<< accept(%d, _, _)\n", sockfd);
-
-    fd = (int) func(sockfd, addr, addrlen);
-
-    if (_WS_listen_fd == -1) {
-        TRACE("<< accept: not interposing\n");
-        return fd;
-    }
-
-    if (_WS_listen_fd != sockfd) {
-        TRACE("<< accept: not interposing on fd %d\n", sockfd);
-        return fd;
-    }
-
-
-    if (_WS_connections[fd]) {
-        RET_ERROR(EINVAL, "already interposing on fd %d\n", fd);
-    } else {
-        /* It's a port we're interposing on so allocate memory for it */
-        if (_WS_nfds >= WS_MAX_FDS) {
-            RET_ERROR(ENOMEM, "Too many interposer fds\n");
-        }
-        if (_WS_alloc(fd) < 0) {
-            return -1;
-        }
-
-        ret = _WS_handshake(fd);
-        if (ret < 0) {
-            _WS_free(fd);
-            errno = EPROTO;
-            TRACE("<< accept(%d, _, _): ret %d\n", sockfd, ret);
-            return ret;
-        }
-        MSG("interposing on fd %d (allocated memory)\n", fd);
-    }
-
-    return fd;
-}
-
-int close(int fd)
-{
-    static void * (*func)();
-    if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "close");
-
-    TRACE("close(%d) called\n", fd);
-
-    _WS_free(fd);
-
-    return (int) func(fd);
-}
-
-
-ssize_t read(int fd, void *buf, size_t count)
-{
-    TRACE("read(%d, _, %d) called\n", fd, count);
-    return (ssize_t) _WS_recv(0, fd, buf, count, 0);
-}
-
-ssize_t write(int fd, const void *buf, size_t count)
-{
-    TRACE("write(%d, _, %d) called\n", fd, count);
-    return (ssize_t) _WS_send(0, fd, buf, count, 0);
-}
-
-ssize_t recv(int sockfd, void *buf, size_t len, int flags)
-{
-    TRACE("recv(%d, _, %d, %d) called\n", sockfd, len, flags);
-    return (ssize_t) _WS_recv(1, sockfd, buf, len, flags);
-}
-
-ssize_t send(int sockfd, const void *buf, size_t len, int flags)
-{
-    TRACE("send(%d, _, %d, %d) called\n", sockfd, len, flags);
-    return (ssize_t) _WS_send(1, sockfd, buf, len, flags);
-}
-
-int select(int nfds, fd_set *readfds, fd_set *writefds,
-           fd_set *exceptfds, struct timeval *timeout)
-{
-    TRACE("select(%d, _, _, _, _) called\n", nfds);
-    return _WS_select(0, nfds, readfds, writefds, exceptfds,
-                      (void *) timeout, NULL);
-}
-
-int pselect(int nfds, fd_set *readfds, fd_set *writefds,
-            fd_set *exceptfds, const struct timespec *timeout,
-            const sigset_t *sigmask)
-{
-    TRACE("pselect(%d, _, _, _, _, _) called\n", nfds);
-    return _WS_select(1, nfds, readfds, writefds, exceptfds,
-                      (void *) timeout, sigmask);
-}
-
-int poll(struct pollfd *fds, nfds_t nfds, int timeout)
-{
-    TRACE("poll(_, %ld, %d) called\n", nfds, timeout);
-    return _WS_poll(0, fds, nfds, timeout, NULL, NULL);
-}
-
-int ppoll(struct pollfd *fds, nfds_t nfds,
-          const struct timespec *timeout, const sigset_t *sigmask)
-{
-    TRACE("ppoll(_, %ld, _, _) called\n", nfds);
-    return _WS_poll(0, fds, nfds, 0, (struct timespec *)timeout,
-                    (sigset_t *)sigmask);
-}
-
-int dup(int oldfd) {
-    int ret;
-    static void * (*func)();
-    if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "dup");
-
-    TRACE(">> dup(%d) called\n", oldfd);
-
-    ret = (int) func(oldfd);
-
-    TRACE("<< dup(%d) ret %d\n", oldfd, ret);
-    return ret;
-}
-
-int dup2(int oldfd, int newfd) {
-    int ret;
-    static void * (*func)();
-    if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "dup2");
-
-    TRACE(">> dup2(%d, %d) called\n", oldfd, newfd);
-
-    ret = (int) func(oldfd, newfd);
-    if ((! _WS_connections[oldfd]) && (! _WS_connections[newfd])) {
-        return ret;
-    }
-
-    if ((ret < 0) || (oldfd == newfd) ||
-        (_WS_connections[oldfd] == _WS_connections[newfd])) {
-        TRACE("<< dup2(%d, %d) ret %d\n", oldfd, newfd, ret);
-        return ret;
-    }
-    
-    /* dup2 behavior is to close newfd if it's open */
-    if (_WS_connections[newfd]) {
-        _WS_free(newfd);
-    }
-
-    if (! _WS_connections[oldfd]) {
-        TRACE("<< dup2(%d, %d) ret %d\n", oldfd, newfd, ret);
-        return ret;
-    }
-
-    MSG("interposing on duplicated fd %d\n", newfd);
-    /* oldfd and newfd are now descriptors for the same socket,
-     * re-use the same context memory area */
-    _WS_connections[newfd] = _WS_connections[oldfd];
-    _WS_connections[newfd]->refcnt++;
-
-    /* Add to search list for select/pselect */
-    _WS_fds[_WS_nfds] = newfd;
-    _WS_nfds++;
-
-    TRACE("<< dup2(%d, %d) ret %d\n", oldfd, newfd, ret);
-    return ret;
-
-}
-
-int dup3(int oldfd, int newfd, int flags) {
-    int ret;
-    static void * (*func)();
-    if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "dup3");
-
-    TRACE(">> dup3(%d, %d, %d) called\n", oldfd, newfd, flags);
-
-    ret = (int) func(oldfd, newfd, flags);
-
-    TRACE("<< dup3(%d, %d, %d) ret %d\n", oldfd, newfd, flags, ret);
-    return ret;
-}
-

+ 0 - 64
utils/wswrapper.h

@@ -1,64 +0,0 @@
-/*
- * wswrap/wswrapper: Add WebSockets support to any service.
- * Copyright 2010 Joel Martin
- * Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
- */
-
-#ifdef DO_MSG
-#define MSG(...) \
-    fprintf(stderr, "wswrapper: "); \
-    fprintf(stderr, __VA_ARGS__);
-#else
-#define MSG(...)
-#endif
-
-#ifdef DO_DEBUG
-#define DEBUG(...) \
-    if (DO_DEBUG) { \
-        fprintf(stderr, "wswrapper: "); \
-        fprintf(stderr, __VA_ARGS__); \
-    }
-#else
-#define DEBUG(...)
-#endif
-
-#ifdef DO_TRACE
-#define TRACE(...) \
-    if (DO_TRACE) { \
-        fprintf(stderr, "wswrapper: "); \
-        fprintf(stderr, __VA_ARGS__); \
-    }
-#else
-#define TRACE(...)
-#endif
-
-#define RET_ERROR(eno, ...) \
-    fprintf(stderr, "wswrapper error: "); \
-    fprintf(stderr, __VA_ARGS__); \
-    errno = eno; \
-    return -1;
-
-
-const char _WS_response[] = "\
-HTTP/1.1 101 Web Socket Protocol Handshake\r\n\
-Upgrade: WebSocket\r\n\
-Connection: Upgrade\r\n\
-%sWebSocket-Origin: %s\r\n\
-%sWebSocket-Location: %s://%s%s\r\n\
-%sWebSocket-Protocol: sample\r\n\
-\r\n%s";
-
-#define WS_BUFSIZE 65536
-#define WS_MAX_FDS 1024
-
-/* Buffers and state for each wrapped WebSocket connection */
-typedef struct {
-    char rbuf[WS_BUFSIZE];
-    char sbuf[WS_BUFSIZE];
-    int  rcarry_cnt;
-    char rcarry[3];
-    int  newframe;
-    int  refcnt;
-} _WS_connection;
-
-