├── LICENSE
├── README.md
├── doc
└── jsmodem.txt
├── emulator
├── Makefile
├── cpux86-ta.js
├── cpux86.js
├── include
│ ├── base64.js
│ ├── util.js
│ ├── web-socket-js
│ │ ├── README.txt
│ │ ├── WebSocketMain.swf
│ │ ├── swfobject.js
│ │ └── web_socket.js
│ ├── websock.js
│ └── webutil.js
├── index.html
├── jslinux.js
├── jsmodem.js
├── linuxstart.bin
├── masq.sh
├── patch_jslinux.js
├── root.bin
├── serve.sh
├── stop.sh
├── term.js
├── utils.js
├── vmlinux-2.6.20.bin
├── websocket.py
└── websockify
└── linuxstart
├── Makefile
├── README
├── config_linux-2.6.20
├── config_linux-2.6.36
├── libc.c
├── libc.h
├── linuxstart.c
├── linuxstart.h
├── linuxstart_head.S
└── patch_linux-2.6.20
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Yauhen Yakimovich
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## JSModem
2 |
3 | Provides a virtual modem device for JSLinux platform. It is a result of
4 | studying project conducted on PC emulator that was implemented in JS by Fabrice
5 | Bellard (see http://bellard.org/jslinux). There is a screencast discussing this
6 | project http://www.youtube.com/watch?v=MEsmgHrKQYM.
7 |
8 | ### Licensing
9 |
10 | * The software behind jslinux emulator is the intellectual property of Fabrice
11 | Bellard (see jslinux.org for further details).
12 | * The rest of the patch is licensed under MIT license (see copy of it in
13 | LICENSE).
14 |
15 | ### Installation
16 |
17 | * Get a copy by cloning the repo from `git@github.com:ewiger/jsmodem.git`
18 |
19 | * Run make all in jsmodem/emulator to download and patch JSLinux from
20 | http://bellard.org/jslinux (This step is still valid but left as a fallback.
21 | Right now the jslinux version is in sync with the version on the website
22 | of Aug 20, 2011).
23 |
24 | * Start serving JSLinux locally with `sudo ./serve.sh`
25 |
26 | * Navigate to `http://localhost:2080/` This should boot the guest system.
27 |
28 | * Login as root and run ./ppp_up to bring up the ppp interface. Check it with
29 | ifconfig and ping.
30 |
31 | ### Requirements
32 |
33 | JSModem script is heavily based on JSLinux project, hence browser must be
34 | modern enough to support it. Another project *websockify* provides websockets
35 | abstraction with fallback to flash.
36 |
37 | To serve on host system one will need
38 |
39 | * python 2.6+
40 |
41 | * bash
42 |
43 | * sed
44 |
45 | * gawk
46 |
47 | * grep
48 |
49 | * pppd
50 |
51 | * socat
52 |
53 | * iptables
54 |
55 | ### Tested
56 |
57 | Internet connection was tested on
58 |
59 | * *host server*: linux 2.6.35 - ubuntu 10.10 Maverick,
60 | linux 2.6.38-11 - 11.04 Natty Narwhal
61 | *host client:* Chrome 12.0.742.112 (linux), FF 3.6.8 (linux),
62 | Chrome 14.0.835.202 (linux)
63 |
64 |
65 | ### Feedback
66 |
67 | For now, best way to give some feedback is to email eugeny dot yakimovitch at
68 | gmail dot com with subject jsmodem. Test reports are greatly appreciated.
69 |
70 | wbr,
71 | yy
72 |
--------------------------------------------------------------------------------
/doc/jsmodem.txt:
--------------------------------------------------------------------------------
1 | sudo socat -d -d PTY,link=/dev/vppp,raw,echo=0 TCP-LISTEN:2001
2 | sudo pppd /dev/vppp debug nodetach noauth passive 10.0.5.1:10.0.5.2
3 |
4 | pppd /dev/ttyS1 noauth defaultroute usepeerdns
5 |
6 | >> port read LSR: 96 -> 1100000 (THR is empty, and line is idle)
7 | >> port read RBR: 0 -> no more bytes are present.
8 | >> port read IIR: 1 -> 1 (No interrupt pending)
9 | >> port read MSR: 0 -> reset LSB
10 | >> port read LSR: 96 -> 1100000 (THR is empty, and line is idle)
11 | >> port read IIR: 1 -> 1 (No interrupt pending)
12 | >> port write LCR: 3 -> 11 (Data word length 1 1 8 bits)
13 | >> port write MCR: 8 -> 1000 (Auxiliary output 2)
14 | >> port write IER: 2 -> 10 (Transmitter holding register empty)
15 | >> port read LSR: 96 -> 1100000 (THR is empty, and line is idle)
16 | >> port read IIR: 2 -> 10 (Transmitter holding register empty)
17 | >> port write IER: 0 -> disable interrupts
18 | >> port read IIR: 1 -> 1 (No interrupt pending)
19 | >> port write IER: 5 -> enable interrupts (Received data available, Receiver line status register change)
20 | >> port read LSR: 96 -> 1100000 (THR is empty, and line is idle)
21 | >> port read RBR: 0 -> no more bytes are present.
22 | >> port read IIR: 1 -> 1 (No interrupt pending)
23 | >> port read MSR: 0 -> reset LSB
24 | >> port write IER: 5 -> enable interrupts (Received data available, Receiver line status register change)
25 | >> port write LCR: 147 -> 10010011 (set word length to 8 bits, No parity, Break signal disabled, DLAB : DLL and DLM accessible)
26 | >> port write THR: 12 -> 00001100 (transmit)
27 | >> port write IER: 0 -> disable interrupts
28 | >> port write LCR: 19 -> 00010011 (set word length to 8 bits, No parity, Break signal disabled, DLAB : RBR, THR and IER accessible)
29 | >> port write FCR: 0 -> 0 (Disable transmit FIFO)
30 | >> port write MCR: 8 -> 1000 (Auxiliary output 2)
31 | >> port write MCR: 11 -> 1011 (Data terminal ready, Request to send, Auxiliary output 2)
32 | >> port read LSR: 96 -> 1100000 (THR is empty, and line is idle)
33 | >> port write IER: 13 -> 1101 enable interrupts (Received data available, Receiver line status register change, Modem status register change)
34 | >> port write LCR: 147 -> 10010011 (set word length to 8 bits, No parity, Break signal disabled, DLAB : DLL and DLM accessible)
35 | >> port write THR: 12 -> 00001100 (transmit)
36 | >> port write IER: 0 -> disable interrupts
37 | >> port write LCR: 19 -> 00010011 (set word length to 8 bits, No parity, Break signal disabled, DLAB : RBR, THR and IER accessible)
38 | >> port write FCR: 0 -> 0 (Disable transmit FIFO)
39 | >> port write MCR: 11 -> 1011 (Data terminal ready, Request to send, Auxiliary output 2)
40 | >> port write IER: 13 -> 1101 enable interrupts (Received data available, Receiver line status register change, Modem status register change)
41 | >> port write MSR: 0 -> is RO ?
42 |
43 |
--------------------------------------------------------------------------------
/emulator/Makefile:
--------------------------------------------------------------------------------
1 | WGET=/usr/bin/wget
2 | JSLINUX_URL=http://bellard.org/jslinux/
3 | # Patch jslinux.js?
4 | ifeq ($(shell if [ -e jslinux.js ] ; then echo 1 ; else echo 0 ; fi), 0)
5 | PATCH_JSLINUX=1
6 | else
7 | ifeq ($(shell if test "jslinux.js" -ot "jsmodem.js" ; then echo 1 ; else echo 0 ; fi), 1)
8 | PATCH_JSLINUX=1
9 | endif
10 | endif
11 |
12 |
13 | all: jslinux
14 |
15 | jslinux: cpux86.js cpux86-ta.js jslinux.js term.js utils.js
16 | ifeq (${PATCH_JSLINUX},1)
17 | patch -p1 < ./patch_jslinux.js
18 | endif
19 |
20 | cpux86.js:
21 | ${WGET} ${JSLINUX_URL}cpux86.js
22 |
23 | cpux86-ta.js:
24 | ${WGET} ${JSLINUX_URL}cpux86-ta.js
25 |
26 | jslinux.js:
27 | ${WGET} ${JSLINUX_URL}jslinux.js
28 |
29 | term.js:
30 | ${WGET} ${JSLINUX_URL}term.js
31 |
32 | utils.js:
33 | ${WGET} ${JSLINUX_URL}utils.js
34 |
35 |
36 | clean:
37 | rm -f cpux86.js cpux86-ta.js jslinux.js term.js utils.js
38 |
39 |
--------------------------------------------------------------------------------
/emulator/cpux86.js:
--------------------------------------------------------------------------------
1 | /*
2 | PC Emulator wrapper
3 |
4 | Copyright (c) 2012 Fabrice Bellard
5 |
6 | Redistribution or commercial use is prohibited without the author's
7 | permission.
8 | */
9 | "use strict";
10 |
11 | function test_typed_arrays()
12 | {
13 | return (window.Uint8Array &&
14 | window.Uint16Array &&
15 | window.Int32Array &&
16 | window.ArrayBuffer);
17 | }
18 |
19 | if (test_typed_arrays()) {
20 | include("cpux86-ta.js");
21 | } else {
22 | include("cpux86-std.js");
23 | document.write('');
24 | }
25 |
--------------------------------------------------------------------------------
/emulator/include/base64.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Modified from:
3 | * http://lxr.mozilla.org/mozilla/source/extensions/xml-rpc/src/nsXmlRpcClient.js#956
4 | */
5 |
6 | /* ***** BEGIN LICENSE BLOCK *****
7 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
8 | *
9 | * The contents of this file are subject to the Mozilla Public License Version
10 | * 1.1 (the "License"); you may not use this file except in compliance with
11 | * the License. You may obtain a copy of the License at
12 | * http://www.mozilla.org/MPL/
13 | *
14 | * Software distributed under the License is distributed on an "AS IS" basis,
15 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 | * for the specific language governing rights and limitations under the
17 | * License.
18 | *
19 | * The Original Code is Mozilla XML-RPC Client component.
20 | *
21 | * The Initial Developer of the Original Code is
22 | * Digital Creations 2, Inc.
23 | * Portions created by the Initial Developer are Copyright (C) 2000
24 | * the Initial Developer. All Rights Reserved.
25 | *
26 | * Contributor(s):
27 | * Martijn Pieters (original author)
28 | * Samuel Sieb
29 | *
30 | * Alternatively, the contents of this file may be used under the terms of
31 | * either the GNU General Public License Version 2 or later (the "GPL"), or
32 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 | * in which case the provisions of the GPL or the LGPL are applicable instead
34 | * of those above. If you wish to allow use of your version of this file only
35 | * under the terms of either the GPL or the LGPL, and not to allow others to
36 | * use your version of this file under the terms of the MPL, indicate your
37 | * decision by deleting the provisions above and replace them with the notice
38 | * and other provisions required by the GPL or the LGPL. If you do not delete
39 | * the provisions above, a recipient may use your version of this file under
40 | * the terms of any one of the MPL, the GPL or the LGPL.
41 | *
42 | * ***** END LICENSE BLOCK ***** */
43 |
44 | "use strict";
45 | /*jslint white: false, bitwise: false, plusplus: false */
46 | /*global console */
47 |
48 | var Base64 = {
49 |
50 | /* Convert data (an array of integers) to a Base64 string. */
51 | toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
52 | base64Pad : '=',
53 |
54 | encode: function (data) {
55 | var result = '',
56 | chrTable = Base64.toBase64Table.split(''),
57 | pad = Base64.base64Pad,
58 | length = data.length,
59 | i;
60 | // Convert every three bytes to 4 ascii characters.
61 | for (i = 0; i < (length - 2); i += 3) {
62 | result += chrTable[data[i] >> 2];
63 | result += chrTable[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
64 | result += chrTable[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
65 | result += chrTable[data[i+2] & 0x3f];
66 | }
67 |
68 | // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
69 | if (length%3) {
70 | i = length - (length%3);
71 | result += chrTable[data[i] >> 2];
72 | if ((length%3) === 2) {
73 | result += chrTable[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
74 | result += chrTable[(data[i+1] & 0x0f) << 2];
75 | result += pad;
76 | } else {
77 | result += chrTable[(data[i] & 0x03) << 4];
78 | result += pad + pad;
79 | }
80 | }
81 |
82 | return result;
83 | },
84 |
85 | /* Convert Base64 data to a string */
86 | toBinaryTable : [
87 | -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
88 | -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
89 | -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
90 | 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
91 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
92 | 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
93 | -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
94 | 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
95 | ],
96 |
97 | decode: function (data, offset) {
98 | offset = typeof(offset) !== 'undefined' ? offset : 0;
99 | var binTable = Base64.toBinaryTable,
100 | pad = Base64.base64Pad,
101 | result, result_length, idx, i, c, padding,
102 | leftbits = 0, // number of bits decoded, but yet to be appended
103 | leftdata = 0, // bits decoded, but yet to be appended
104 | data_length = data.indexOf('=') - offset;
105 |
106 | if (data_length < 0) { data_length = data.length - offset; }
107 |
108 | /* Every four characters is 3 resulting numbers */
109 | result_length = (data_length >> 2) * 3 + Math.floor((data_length%4)/1.5);
110 | result = new Array(result_length);
111 |
112 | // Convert one by one.
113 | for (idx = 0, i = offset; i < data.length; i++) {
114 | c = binTable[data.charCodeAt(i) & 0x7f];
115 | padding = (data.charAt(i) === pad);
116 | // Skip illegal characters and whitespace
117 | if (c === -1) {
118 | console.error("Illegal character '" + data.charCodeAt(i) + "'");
119 | continue;
120 | }
121 |
122 | // Collect data into leftdata, update bitcount
123 | leftdata = (leftdata << 6) | c;
124 | leftbits += 6;
125 |
126 | // If we have 8 or more bits, append 8 bits to the result
127 | if (leftbits >= 8) {
128 | leftbits -= 8;
129 | // Append if not padding.
130 | if (!padding) {
131 | result[idx++] = (leftdata >> leftbits) & 0xff;
132 | }
133 | leftdata &= (1 << leftbits) - 1;
134 | }
135 | }
136 |
137 | // If there are any bits left, the base64 string was corrupted
138 | if (leftbits) {
139 | throw {name: 'Base64-Error',
140 | message: 'Corrupted base64 string'};
141 | }
142 |
143 | return result;
144 | }
145 |
146 | }; /* End of Base64 namespace */
147 |
--------------------------------------------------------------------------------
/emulator/include/util.js:
--------------------------------------------------------------------------------
1 | /*
2 | * from noVNC: HTML5 VNC client
3 | * Copyright (C) 2010 Joel Martin
4 | * Licensed under LGPL-3 (see LICENSE.txt)
5 | *
6 | * See README.md for usage and integration instructions.
7 | */
8 |
9 | "use strict";
10 | /*jslint bitwise: false, white: false */
11 | /*global window, console, document, navigator, ActiveXObject */
12 |
13 | // Globals defined here
14 | var Util = {}, $D;
15 |
16 |
17 | /*
18 | * Make arrays quack
19 | */
20 |
21 | Array.prototype.push8 = function (num) {
22 | this.push(num & 0xFF);
23 | };
24 |
25 | Array.prototype.push16 = function (num) {
26 | this.push((num >> 8) & 0xFF,
27 | (num ) & 0xFF );
28 | };
29 | Array.prototype.push32 = function (num) {
30 | this.push((num >> 24) & 0xFF,
31 | (num >> 16) & 0xFF,
32 | (num >> 8) & 0xFF,
33 | (num ) & 0xFF );
34 | };
35 |
36 | /*
37 | * ------------------------------------------------------
38 | * Namespaced in Util
39 | * ------------------------------------------------------
40 | */
41 |
42 | /*
43 | * Logging/debug routines
44 | */
45 |
46 | Util._log_level = 'warn';
47 | Util.init_logging = function (level) {
48 | if (typeof level === 'undefined') {
49 | level = Util._log_level;
50 | } else {
51 | Util._log_level = level;
52 | }
53 | if (typeof window.console === "undefined") {
54 | if (typeof window.opera !== "undefined") {
55 | window.console = {
56 | 'log' : window.opera.postError,
57 | 'warn' : window.opera.postError,
58 | 'error': window.opera.postError };
59 | } else {
60 | window.console = {
61 | 'log' : function(m) {},
62 | 'warn' : function(m) {},
63 | 'error': function(m) {}};
64 | }
65 | }
66 |
67 | Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
68 | switch (level) {
69 | case 'debug': Util.Debug = function (msg) { console.log(msg); };
70 | case 'info': Util.Info = function (msg) { console.log(msg); };
71 | case 'warn': Util.Warn = function (msg) { console.warn(msg); };
72 | case 'error': Util.Error = function (msg) { console.error(msg); };
73 | case 'none':
74 | break;
75 | default:
76 | throw("invalid logging type '" + level + "'");
77 | }
78 | };
79 | Util.get_logging = function () {
80 | return Util._log_level;
81 | }
82 | // Initialize logging level
83 | Util.init_logging();
84 |
85 |
86 | // Set defaults for Crockford style function namespaces
87 | Util.conf_default = function(cfg, api, v, type, defval, desc) {
88 | // Description
89 | api['get_' + v + '_desc'] = desc;
90 | // Default getter
91 | if (typeof api['get_' + v] === 'undefined') {
92 | api['get_' + v] = function () {
93 | return cfg[v];
94 | };
95 | }
96 | // Default setter
97 | if (typeof api['set_' + v] === 'undefined') {
98 | api['set_' + v] = function (val) {
99 | if (type in {'boolean':1, 'bool':1}) {
100 | if ((!val) || (val in {'0':1, 'no':1, 'false':1})) {
101 | val = false;
102 | } else {
103 | val = true;
104 | }
105 | } else if (type in {'integer':1, 'int':1}) {
106 | val = parseInt(val, 10);
107 | }
108 | cfg[v] = val;
109 | };
110 | }
111 |
112 | if (typeof cfg[v] === 'undefined') {
113 | // Set to default
114 | api['set_' + v](defval);
115 | } else {
116 | // Coerce existing setting to the right type
117 | api['set_' + v](cfg[v]);
118 | }
119 | };
120 |
121 |
122 |
123 | /*
124 | * Cross-browser routines
125 | */
126 |
127 | // Get DOM element position on page
128 | Util.getPosition = function (obj) {
129 | var x = 0, y = 0;
130 | if (obj.offsetParent) {
131 | do {
132 | x += obj.offsetLeft;
133 | y += obj.offsetTop;
134 | obj = obj.offsetParent;
135 | } while (obj);
136 | }
137 | return {'x': x, 'y': y};
138 | };
139 |
140 | // Get mouse event position in DOM element
141 | Util.getEventPosition = function (e, obj, scale) {
142 | var evt, docX, docY, pos;
143 | //if (!e) evt = window.event;
144 | evt = (e ? e : window.event);
145 | if (evt.pageX || evt.pageY) {
146 | docX = evt.pageX;
147 | docY = evt.pageY;
148 | } else if (evt.clientX || evt.clientY) {
149 | docX = evt.clientX + document.body.scrollLeft +
150 | document.documentElement.scrollLeft;
151 | docY = evt.clientY + document.body.scrollTop +
152 | document.documentElement.scrollTop;
153 | }
154 | pos = Util.getPosition(obj);
155 | if (typeof scale === "undefined") {
156 | scale = 1;
157 | }
158 | return {'x': (docX - pos.x) / scale, 'y': (docY - pos.y) / scale};
159 | };
160 |
161 |
162 | // Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events
163 | Util.addEvent = function (obj, evType, fn){
164 | if (obj.attachEvent){
165 | var r = obj.attachEvent("on"+evType, fn);
166 | return r;
167 | } else if (obj.addEventListener){
168 | obj.addEventListener(evType, fn, false);
169 | return true;
170 | } else {
171 | throw("Handler could not be attached");
172 | }
173 | };
174 |
175 | Util.removeEvent = function(obj, evType, fn){
176 | if (obj.detachEvent){
177 | var r = obj.detachEvent("on"+evType, fn);
178 | return r;
179 | } else if (obj.removeEventListener){
180 | obj.removeEventListener(evType, fn, false);
181 | return true;
182 | } else {
183 | throw("Handler could not be removed");
184 | }
185 | };
186 |
187 | Util.stopEvent = function(e) {
188 | if (e.stopPropagation) { e.stopPropagation(); }
189 | else { e.cancelBubble = true; }
190 |
191 | if (e.preventDefault) { e.preventDefault(); }
192 | else { e.returnValue = false; }
193 | };
194 |
195 |
196 | // Set browser engine versions. Based on mootools.
197 | Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
198 |
199 | Util.Engine = {
200 | 'presto': (function() {
201 | return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
202 | 'trident': (function() {
203 | return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()),
204 | 'webkit': (function() {
205 | try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()),
206 | //'webkit': (function() {
207 | // return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()),
208 | 'gecko': (function() {
209 | return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }())
210 | };
211 | if (Util.Engine.webkit) {
212 | // Extract actual webkit version if available
213 | Util.Engine.webkit = (function(v) {
214 | var re = new RegExp('WebKit/([0-9\.]*) ');
215 | v = (navigator.userAgent.match(re) || ['', v])[1];
216 | return parseFloat(v, 10);
217 | })(Util.Engine.webkit);
218 | }
219 |
220 | Util.Flash = (function(){
221 | var v, version;
222 | try {
223 | v = navigator.plugins['Shockwave Flash'].description;
224 | } catch(err1) {
225 | try {
226 | v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
227 | } catch(err2) {
228 | v = '0 r0';
229 | }
230 | }
231 | version = v.match(/\d+/g);
232 | return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
233 | }());
234 |
--------------------------------------------------------------------------------
/emulator/include/web-socket-js/README.txt:
--------------------------------------------------------------------------------
1 | * How to try
2 |
3 | Assuming you have Web server (e.g. Apache) running at http://example.com/ .
4 |
5 | - Download web_socket.rb from:
6 | http://github.com/gimite/web-socket-ruby/tree/master
7 | - Run sample Web Socket server (echo server) in example.com with: (#1)
8 | $ ruby web-socket-ruby/samples/echo_server.rb example.com 10081
9 | - If your server already provides socket policy file at port 843, modify the file to allow access to port 10081. Otherwise you can skip this step. See below for details.
10 | - Publish the web-socket-js directory with your Web server (e.g. put it in ~/public_html).
11 | - Change ws://localhost:10081 to ws://example.com:10081 in sample.html.
12 | - Open sample.html in your browser.
13 | - After "onopen" is shown, input something, click [Send] and confirm echo back.
14 |
15 | #1: First argument of echo_server.rb means that it accepts Web Socket connection from HTML pages in example.com.
16 |
17 |
18 | * Troubleshooting
19 |
20 | If it doesn't work, try these:
21 |
22 | 1. Try Chrome and Firefox 3.x.
23 | - It doesn't work on Chrome:
24 | -- It's likely an issue of your code or the server. Debug your code as usual e.g. using console.log.
25 | - It works on Chrome but it doesn't work on Firefox:
26 | -- It's likely an issue of web-socket-js specific configuration (e.g. 3 and 4 below).
27 | - It works on both Chrome and Firefox, but it doesn't work on your browser:
28 | -- Check "Supported environment" section below. Your browser may not be supported by web-socket-js.
29 |
30 | 2. Add this line before your code:
31 | WEB_SOCKET_DEBUG = true;
32 | and use Developer Tools (Chrome/Safari) or Firebug (Firefox) to see if console.log outputs any errors.
33 |
34 | 3. Make sure you do NOT open your HTML page as local file e.g. file:///.../sample.html. web-socket-js doesn't work on local file. Open it via Web server e.g. http:///.../sample.html.
35 |
36 | 4. If you are NOT using web-socket-ruby as your WebSocket server, you need to place Flash socket policy file on your server. See "Flash socket policy file" section below for details.
37 |
38 | 5. Check if sample.html bundled with web-socket-js works.
39 |
40 | 6. Make sure the port used for WebSocket (10081 in example above) is not blocked by your server/client's firewall.
41 |
42 | 7. Install debugger version of Flash Player available here to see Flash errors:
43 | http://www.adobe.com/support/flashplayer/downloads.html
44 |
45 |
46 | * Supported environments
47 |
48 | It should work on:
49 | - Google Chrome 4 or later (just uses native implementation)
50 | - Firefox 3.x, Internet Explorer 8 + Flash Player 9 or later
51 |
52 | It may or may not work on other browsers such as Safari, Opera or IE 6. Patch for these browsers are appreciated, but I will not work on fixing issues specific to these browsers by myself.
53 |
54 |
55 | * Flash socket policy file
56 |
57 | This implementation uses Flash's socket, which means that your server must provide Flash socket policy file to declare the server accepts connections from Flash.
58 |
59 | If you use web-socket-ruby available at
60 | http://github.com/gimite/web-socket-ruby/tree/master
61 | , you don't need anything special, because web-socket-ruby handles Flash socket policy file request. But if you already provide socket policy file at port 843, you need to modify the file to allow access to Web Socket port, because it precedes what web-socket-ruby provides.
62 |
63 | If you use other Web Socket server implementation, you need to provide socket policy file yourself. See
64 | http://www.lightsphere.com/dev/articles/flash_socket_policy.html
65 | for details and sample script to run socket policy file server. node.js implementation is available here:
66 | http://github.com/LearnBoost/Socket.IO-node/blob/master/lib/socket.io/transports/flashsocket.js
67 |
68 | Actually, it's still better to provide socket policy file at port 843 even if you use web-socket-ruby. Flash always try to connect to port 843 first, so providing the file at port 843 makes startup faster.
69 |
70 |
71 | * Cookie considerations
72 |
73 | Cookie is sent if Web Socket host is the same as the origin of JavaScript. Otherwise it is not sent, because I don't know way to send right Cookie (which is Cookie of the host of Web Socket, I heard).
74 |
75 | Note that it's technically possible that client sends arbitrary string as Cookie and any other headers (by modifying this library for example) once you place Flash socket policy file in your server. So don't trust Cookie and other headers if you allow connection from untrusted origin.
76 |
77 |
78 | * Proxy considerations
79 |
80 | The WebSocket spec (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol) specifies instructions for User Agents to support proxied connections by implementing the HTTP CONNECT method.
81 |
82 | The AS3 Socket class doesn't implement this mechanism, which renders it useless for the scenarios where the user trying to open a socket is behind a proxy.
83 |
84 | The class RFC2817Socket (by Christian Cantrell) effectively lets us implement this, as long as the proxy settings are known and provided by the interface that instantiates the WebSocket. As such, if you want to support proxied conncetions, you'll have to supply this information to the WebSocket constructor when Flash is being used. One way to go about it would be to ask the user for proxy settings information if the initial connection fails.
85 |
86 |
87 | * How to host HTML file and SWF file in different domains
88 |
89 | By default, HTML file and SWF file must be in the same domain. You can follow steps below to allow hosting them in different domain.
90 |
91 | WARNING: If you use the method below, HTML files in ANY domains can send arbitrary TCP data to your WebSocket server, regardless of configuration in Flash socket policy file. Arbitrary TCP data means that they can even fake request headers including Origin and Cookie.
92 |
93 | - Unzip WebSocketMainInsecure.zip to extract WebSocketMainInsecure.swf.
94 | - Put WebSocketMainInsecure.swf on your server, instead of WebSocketMain.swf.
95 | - In JavaScript, set WEB_SOCKET_SWF_LOCATION to URL of your WebSocketMainInsecure.swf.
96 |
97 |
98 | * How to build WebSocketMain.swf
99 |
100 | Install Flex 4 SDK:
101 | http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4
102 |
103 | $ cd flash-src
104 | $ ./build.sh
105 |
106 |
107 | * License
108 |
109 | New BSD License.
110 |
--------------------------------------------------------------------------------
/emulator/include/web-socket-js/WebSocketMain.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ewiger/jsmodem/98915f0f51cd6cab32690cba6e5bcefd93f6d29c/emulator/include/web-socket-js/WebSocketMain.swf
--------------------------------------------------------------------------------
/emulator/include/web-socket-js/swfobject.js:
--------------------------------------------------------------------------------
1 | /* SWFObject v2.2
2 | is released under the MIT License
3 | */
4 | var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab
2 | // License: New BSD License
3 | // Reference: http://dev.w3.org/html5/websockets/
4 | // Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
5 |
6 | (function() {
7 |
8 | if (window.WebSocket) return;
9 |
10 | var console = window.console;
11 | if (!console || !console.log || !console.error) {
12 | console = {log: function(){ }, error: function(){ }};
13 | }
14 |
15 | if (!swfobject.hasFlashPlayerVersion("10.0.0")) {
16 | console.error("Flash Player >= 10.0.0 is required.");
17 | return;
18 | }
19 | if (location.protocol == "file:") {
20 | console.error(
21 | "WARNING: web-socket-js doesn't work in file:///... URL " +
22 | "unless you set Flash Security Settings properly. " +
23 | "Open the page via Web server i.e. http://...");
24 | }
25 |
26 | /**
27 | * This class represents a faux web socket.
28 | * @param {string} url
29 | * @param {string} protocol
30 | * @param {string} proxyHost
31 | * @param {int} proxyPort
32 | * @param {string} headers
33 | */
34 | WebSocket = function(url, protocol, proxyHost, proxyPort, headers) {
35 | var self = this;
36 | self.__id = WebSocket.__nextId++;
37 | WebSocket.__instances[self.__id] = self;
38 | self.readyState = WebSocket.CONNECTING;
39 | self.bufferedAmount = 0;
40 | self.__events = {};
41 | // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
42 | // Otherwise, when onopen fires immediately, onopen is called before it is set.
43 | setTimeout(function() {
44 | WebSocket.__addTask(function() {
45 | WebSocket.__flash.create(
46 | self.__id, url, protocol, proxyHost || null, proxyPort || 0, headers || null);
47 | });
48 | }, 0);
49 | };
50 |
51 | /**
52 | * Send data to the web socket.
53 | * @param {string} data The data to send to the socket.
54 | * @return {boolean} True for success, false for failure.
55 | */
56 | WebSocket.prototype.send = function(data) {
57 | if (this.readyState == WebSocket.CONNECTING) {
58 | throw "INVALID_STATE_ERR: Web Socket connection has not been established";
59 | }
60 | // We use encodeURIComponent() here, because FABridge doesn't work if
61 | // the argument includes some characters. We don't use escape() here
62 | // because of this:
63 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
64 | // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
65 | // preserve all Unicode characters either e.g. "\uffff" in Firefox.
66 | // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
67 | // additional testing.
68 | var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
69 | if (result < 0) { // success
70 | return true;
71 | } else {
72 | this.bufferedAmount += result;
73 | return false;
74 | }
75 | };
76 |
77 | /**
78 | * Close this web socket gracefully.
79 | */
80 | WebSocket.prototype.close = function() {
81 | if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
82 | return;
83 | }
84 | this.readyState = WebSocket.CLOSING;
85 | WebSocket.__flash.close(this.__id);
86 | };
87 |
88 | /**
89 | * Implementation of {@link DOM 2 EventTarget Interface}
90 | *
91 | * @param {string} type
92 | * @param {function} listener
93 | * @param {boolean} useCapture
94 | * @return void
95 | */
96 | WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
97 | if (!(type in this.__events)) {
98 | this.__events[type] = [];
99 | }
100 | this.__events[type].push(listener);
101 | };
102 |
103 | /**
104 | * Implementation of {@link DOM 2 EventTarget Interface}
105 | *
106 | * @param {string} type
107 | * @param {function} listener
108 | * @param {boolean} useCapture
109 | * @return void
110 | */
111 | WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
112 | if (!(type in this.__events)) return;
113 | var events = this.__events[type];
114 | for (var i = events.length - 1; i >= 0; --i) {
115 | if (events[i] === listener) {
116 | events.splice(i, 1);
117 | break;
118 | }
119 | }
120 | };
121 |
122 | /**
123 | * Implementation of {@link DOM 2 EventTarget Interface}
124 | *
125 | * @param {Event} event
126 | * @return void
127 | */
128 | WebSocket.prototype.dispatchEvent = function(event) {
129 | var events = this.__events[event.type] || [];
130 | for (var i = 0; i < events.length; ++i) {
131 | events[i](event);
132 | }
133 | var handler = this["on" + event.type];
134 | if (handler) handler(event);
135 | };
136 |
137 | /**
138 | * Handles an event from Flash.
139 | * @param {Object} flashEvent
140 | */
141 | WebSocket.prototype.__handleEvent = function(flashEvent) {
142 | if ("readyState" in flashEvent) {
143 | this.readyState = flashEvent.readyState;
144 | }
145 |
146 | var jsEvent;
147 | if (flashEvent.type == "open" || flashEvent.type == "error") {
148 | jsEvent = this.__createSimpleEvent(flashEvent.type);
149 | } else if (flashEvent.type == "close") {
150 | // TODO implement jsEvent.wasClean
151 | jsEvent = this.__createSimpleEvent("close");
152 | } else if (flashEvent.type == "message") {
153 | var data = decodeURIComponent(flashEvent.message);
154 | jsEvent = this.__createMessageEvent("message", data);
155 | } else {
156 | throw "unknown event type: " + flashEvent.type;
157 | }
158 |
159 | this.dispatchEvent(jsEvent);
160 | };
161 |
162 | WebSocket.prototype.__createSimpleEvent = function(type) {
163 | if (document.createEvent && window.Event) {
164 | var event = document.createEvent("Event");
165 | event.initEvent(type, false, false);
166 | return event;
167 | } else {
168 | return {type: type, bubbles: false, cancelable: false};
169 | }
170 | };
171 |
172 | WebSocket.prototype.__createMessageEvent = function(type, data) {
173 | if (document.createEvent && window.MessageEvent && !window.opera) {
174 | var event = document.createEvent("MessageEvent");
175 | event.initMessageEvent("message", false, false, data, null, null, window, null);
176 | return event;
177 | } else {
178 | // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
179 | return {type: type, data: data, bubbles: false, cancelable: false};
180 | }
181 | };
182 |
183 | /**
184 | * Define the WebSocket readyState enumeration.
185 | */
186 | WebSocket.CONNECTING = 0;
187 | WebSocket.OPEN = 1;
188 | WebSocket.CLOSING = 2;
189 | WebSocket.CLOSED = 3;
190 |
191 | WebSocket.__flash = null;
192 | WebSocket.__instances = {};
193 | WebSocket.__tasks = [];
194 | WebSocket.__nextId = 0;
195 |
196 | /**
197 | * Load a new flash security policy file.
198 | * @param {string} url
199 | */
200 | WebSocket.loadFlashPolicyFile = function(url){
201 | WebSocket.__addTask(function() {
202 | WebSocket.__flash.loadManualPolicyFile(url);
203 | });
204 | };
205 |
206 | /**
207 | * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
208 | */
209 | WebSocket.__initialize = function() {
210 | if (WebSocket.__flash) return;
211 |
212 | if (WebSocket.__swfLocation) {
213 | // For backword compatibility.
214 | window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
215 | }
216 | if (!window.WEB_SOCKET_SWF_LOCATION) {
217 | console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
218 | return;
219 | }
220 | var container = document.createElement("div");
221 | container.id = "webSocketContainer";
222 | // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
223 | // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
224 | // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
225 | // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
226 | // the best we can do as far as we know now.
227 | container.style.position = "absolute";
228 | if (WebSocket.__isFlashLite()) {
229 | container.style.left = "0px";
230 | container.style.top = "0px";
231 | } else {
232 | container.style.left = "-100px";
233 | container.style.top = "-100px";
234 | }
235 | var holder = document.createElement("div");
236 | holder.id = "webSocketFlash";
237 | container.appendChild(holder);
238 | document.body.appendChild(container);
239 | // See this article for hasPriority:
240 | // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
241 | swfobject.embedSWF(
242 | WEB_SOCKET_SWF_LOCATION,
243 | "webSocketFlash",
244 | "1" /* width */,
245 | "1" /* height */,
246 | "10.0.0" /* SWF version */,
247 | null,
248 | null,
249 | {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
250 | null,
251 | function(e) {
252 | if (!e.success) {
253 | console.error("[WebSocket] swfobject.embedSWF failed");
254 | }
255 | });
256 | };
257 |
258 | /**
259 | * Called by Flash to notify JS that it's fully loaded and ready
260 | * for communication.
261 | */
262 | WebSocket.__onFlashInitialized = function() {
263 | // We need to set a timeout here to avoid round-trip calls
264 | // to flash during the initialization process.
265 | setTimeout(function() {
266 | WebSocket.__flash = document.getElementById("webSocketFlash");
267 | WebSocket.__flash.setCallerUrl(location.href);
268 | WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
269 | for (var i = 0; i < WebSocket.__tasks.length; ++i) {
270 | WebSocket.__tasks[i]();
271 | }
272 | WebSocket.__tasks = [];
273 | }, 0);
274 | };
275 |
276 | /**
277 | * Called by Flash to notify WebSockets events are fired.
278 | */
279 | WebSocket.__onFlashEvent = function() {
280 | setTimeout(function() {
281 | try {
282 | // Gets events using receiveEvents() instead of getting it from event object
283 | // of Flash event. This is to make sure to keep message order.
284 | // It seems sometimes Flash events don't arrive in the same order as they are sent.
285 | var events = WebSocket.__flash.receiveEvents();
286 | for (var i = 0; i < events.length; ++i) {
287 | WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
288 | }
289 | } catch (e) {
290 | console.error(e);
291 | }
292 | }, 0);
293 | return true;
294 | };
295 |
296 | // Called by Flash.
297 | WebSocket.__log = function(message) {
298 | console.log(decodeURIComponent(message));
299 | };
300 |
301 | // Called by Flash.
302 | WebSocket.__error = function(message) {
303 | console.error(decodeURIComponent(message));
304 | };
305 |
306 | WebSocket.__addTask = function(task) {
307 | if (WebSocket.__flash) {
308 | task();
309 | } else {
310 | WebSocket.__tasks.push(task);
311 | }
312 | };
313 |
314 | /**
315 | * Test if the browser is running flash lite.
316 | * @return {boolean} True if flash lite is running, false otherwise.
317 | */
318 | WebSocket.__isFlashLite = function() {
319 | if (!window.navigator || !window.navigator.mimeTypes) {
320 | return false;
321 | }
322 | var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
323 | if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
324 | return false;
325 | }
326 | return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
327 | };
328 |
329 | if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
330 | if (window.addEventListener) {
331 | window.addEventListener("load", function(){
332 | WebSocket.__initialize();
333 | }, false);
334 | } else {
335 | window.attachEvent("onload", function(){
336 | WebSocket.__initialize();
337 | });
338 | }
339 | }
340 |
341 | })();
342 |
--------------------------------------------------------------------------------
/emulator/include/websock.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Websock: high-performance binary WebSockets
3 | * Copyright (C) 2011 Joel Martin
4 | * Licensed under LGPL-3 (see LICENSE.txt)
5 | *
6 | * Websock is similar to the standard WebSocket object but Websock
7 | * enables communication with raw TCP sockets (i.e. the binary stream)
8 | * via websockify. This is accomplished by base64 encoding the data
9 | * stream between Websock and websockify.
10 | *
11 | * Websock has built-in receive queue buffering; the message event
12 | * does not contain actual data but is simply a notification that
13 | * there is new data available. Several rQ* methods are available to
14 | * read binary data off of the receive queue.
15 | */
16 |
17 |
18 | // Load Flash WebSocket emulator if needed
19 |
20 | if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
21 | Websock_native = true;
22 | } else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
23 | Websock_native = true;
24 | window.WebSocket = window.MozWebSocket;
25 | } else {
26 | /* no builtin WebSocket so load web_socket.js */
27 | Websock_native = false;
28 | (function () {
29 | function get_INCLUDE_URI() {
30 | return (typeof INCLUDE_URI !== "undefined") ?
31 | INCLUDE_URI : "include/";
32 | }
33 |
34 | var start = "
28 |
29 |
30 |
31 |
32 |
33 |
34 |
39 |
40 |