aboutsummaryrefslogtreecommitdiffstats
path: root/signaling-server/node_modules/socket.io/lib/transports
diff options
context:
space:
mode:
Diffstat (limited to 'signaling-server/node_modules/socket.io/lib/transports')
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/flashsocket.js129
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/htmlfile.js83
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/http-polling.js147
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/http.js122
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/index.js12
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/jsonp-polling.js97
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/websocket.js36
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/websocket/default.js376
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js642
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/websocket/hybi-16.js642
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/websocket/index.js11
-rw-r--r--signaling-server/node_modules/socket.io/lib/transports/xhr-polling.js69
12 files changed, 2366 insertions, 0 deletions
diff --git a/signaling-server/node_modules/socket.io/lib/transports/flashsocket.js b/signaling-server/node_modules/socket.io/lib/transports/flashsocket.js
new file mode 100644
index 0000000..dc2d78b
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/flashsocket.js
@@ -0,0 +1,129 @@
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+var WebSocket = require('./websocket');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = FlashSocket;
+
+/**
+ * The FlashSocket transport is just a proxy
+ * for WebSocket connections.
+ *
+ * @api public
+ */
+
+function FlashSocket (mng, data, req) {
+ return WebSocket.call(this, mng, data, req);
+}
+
+/**
+ * Inherits from WebSocket.
+ */
+
+FlashSocket.prototype.__proto__ = WebSocket.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+FlashSocket.prototype.name = 'flashsocket';
+
+/**
+ * Listens for new configuration changes of the Manager
+ * this way we can enable and disable the flash server.
+ *
+ * @param {Manager} Manager instance.
+ * @api private
+ */
+
+
+FlashSocket.init = function (manager) {
+ var server;
+ function create () {
+
+ // Drop out immediately if the user has
+ // disabled the flash policy server
+ if (!manager.get('flash policy server')) {
+ return;
+ }
+
+ server = require('policyfile').createServer({
+ log: function(msg){
+ manager.log.info(msg);
+ }
+ }, manager.get('origins'));
+
+ server.on('close', function (e) {
+ server = null;
+ });
+
+ server.listen(manager.get('flash policy port'), manager.server);
+
+ manager.flashPolicyServer = server;
+ }
+
+ // listen for origin changes, so we can update the server
+ manager.on('set:origins', function (value, key) {
+ if (!server) return;
+
+ // update the origins and compile a new response buffer
+ server.origins = Array.isArray(value) ? value : [value];
+ server.compile();
+ });
+
+ // destory the server and create a new server
+ manager.on('set:flash policy port', function (value, key) {
+ var transports = manager.get('transports');
+ if (~transports.indexOf('flashsocket')) {
+ if (server) {
+ if (server.port === value) return;
+ // destroy the server and rebuild it on a new port
+ try {
+ server.close();
+ }
+ catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ }
+ }
+ create();
+ }
+ });
+
+ // create or destroy the server
+ manager.on('set:flash policy server', function (value, key) {
+ var transports = manager.get('transports');
+ if (~transports.indexOf('flashsocket')) {
+ if (server && !value) {
+ // destroy the server
+ try {
+ server.close();
+ }
+ catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ }
+ }
+ } else if (!server && value) {
+ // create the server
+ create();
+ }
+ });
+
+ // only start the server
+ manager.on('set:transports', function (value, key){
+ if (!server && ~manager.get('transports').indexOf('flashsocket')) {
+ create();
+ }
+ });
+ // check if we need to initialize at start
+ if (~manager.get('transports').indexOf('flashsocket')){
+ create();
+ }
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/htmlfile.js b/signaling-server/node_modules/socket.io/lib/transports/htmlfile.js
new file mode 100644
index 0000000..fce0c0e
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/htmlfile.js
@@ -0,0 +1,83 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var HTTPTransport = require('./http');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = HTMLFile;
+
+/**
+ * HTMLFile transport constructor.
+ *
+ * @api public
+ */
+
+function HTMLFile (mng, data, req) {
+ HTTPTransport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+HTMLFile.prototype.__proto__ = HTTPTransport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+HTMLFile.prototype.name = 'htmlfile';
+
+/**
+ * Handles the request.
+ *
+ * @api private
+ */
+
+HTMLFile.prototype.handleRequest = function (req) {
+ HTTPTransport.prototype.handleRequest.call(this, req);
+
+ if (req.method == 'GET') {
+ req.res.writeHead(200, {
+ 'Content-Type': 'text/html; charset=UTF-8'
+ , 'Connection': 'keep-alive'
+ , 'Transfer-Encoding': 'chunked'
+ });
+
+ req.res.write(
+ '<html><body>'
+ + '<script>var _ = function (msg) { parent.s._(msg, document); };</script>'
+ + new Array(174).join(' ')
+ );
+ }
+};
+
+/**
+ * Performs the write.
+ *
+ * @api private
+ */
+
+HTMLFile.prototype.write = function (data) {
+ // escape all forward slashes. see GH-1251
+ data = '<script>_(' + JSON.stringify(data).replace(/\//g, '\\/') + ');</script>';
+
+ if (this.response.write(data)) {
+ this.drained = true;
+ }
+
+ this.log.debug(this.name + ' writing', data);
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/http-polling.js b/signaling-server/node_modules/socket.io/lib/transports/http-polling.js
new file mode 100644
index 0000000..89b7e04
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/http-polling.js
@@ -0,0 +1,147 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var HTTPTransport = require('./http');
+
+/**
+ * Exports the constructor.
+ */
+
+exports = module.exports = HTTPPolling;
+
+/**
+ * HTTP polling constructor.
+ *
+ * @api public.
+ */
+
+function HTTPPolling (mng, data, req) {
+ HTTPTransport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from HTTPTransport.
+ *
+ * @api public.
+ */
+
+HTTPPolling.prototype.__proto__ = HTTPTransport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+HTTPPolling.prototype.name = 'httppolling';
+
+/**
+ * Override setHandlers
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.setHandlers = function () {
+ HTTPTransport.prototype.setHandlers.call(this);
+ this.socket.removeListener('end', this.bound.end);
+ this.socket.removeListener('close', this.bound.close);
+};
+
+/**
+ * Removes heartbeat timeouts for polling.
+ */
+
+HTTPPolling.prototype.setHeartbeatInterval = function () {
+ return this;
+};
+
+/**
+ * Handles a request
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.handleRequest = function (req) {
+ HTTPTransport.prototype.handleRequest.call(this, req);
+
+ if (req.method == 'GET') {
+ var self = this;
+
+ this.pollTimeout = setTimeout(function () {
+ self.packet({ type: 'noop' });
+ self.log.debug(self.name + ' closed due to exceeded duration');
+ }, this.manager.get('polling duration') * 1000);
+
+ this.log.debug('setting poll timeout');
+ }
+};
+
+/**
+ * Clears polling timeout
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.clearPollTimeout = function () {
+ if (this.pollTimeout) {
+ clearTimeout(this.pollTimeout);
+ this.pollTimeout = null;
+ this.log.debug('clearing poll timeout');
+ }
+
+ return this;
+};
+
+/**
+ * Override clear timeouts to clear the poll timeout
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.clearTimeouts = function () {
+ HTTPTransport.prototype.clearTimeouts.call(this);
+
+ this.clearPollTimeout();
+};
+
+/**
+ * doWrite to clear poll timeout
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.doWrite = function () {
+ this.clearPollTimeout();
+};
+
+/**
+ * Performs a write.
+ *
+ * @api private.
+ */
+
+HTTPPolling.prototype.write = function (data, close) {
+ this.doWrite(data);
+ this.response.end();
+ this.onClose();
+};
+
+/**
+ * Override end.
+ *
+ * @api private
+ */
+
+HTTPPolling.prototype.end = function (reason) {
+ this.clearPollTimeout();
+ return HTTPTransport.prototype.end.call(this, reason);
+};
+
diff --git a/signaling-server/node_modules/socket.io/lib/transports/http.js b/signaling-server/node_modules/socket.io/lib/transports/http.js
new file mode 100644
index 0000000..fa94b59
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/http.js
@@ -0,0 +1,122 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var Transport = require('../transport')
+ , parser = require('../parser')
+ , qs = require('querystring');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = HTTPTransport;
+
+/**
+ * HTTP interface constructor. For all non-websocket transports.
+ *
+ * @api public
+ */
+
+function HTTPTransport (mng, data, req) {
+ Transport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+HTTPTransport.prototype.__proto__ = Transport.prototype;
+
+/**
+ * Handles a request.
+ *
+ * @api private
+ */
+
+HTTPTransport.prototype.handleRequest = function (req) {
+
+ // Always set the response in case an error is returned to the client
+ this.response = req.res;
+
+ if (req.method == 'POST') {
+ var buffer = ''
+ , res = req.res
+ , origin = req.headers.origin
+ , headers = { 'Content-Length': 1, 'Content-Type': 'text/plain; charset=UTF-8' }
+ , self = this;
+
+ req.on('data', function (data) {
+ buffer += data;
+
+ if (Buffer.byteLength(buffer) >= self.manager.get('destroy buffer size')) {
+ buffer = '';
+ req.connection.destroy();
+ }
+ });
+
+ req.on('end', function () {
+ res.writeHead(200, headers);
+ res.end('1');
+
+ self.onData(self.postEncoded ? qs.parse(buffer).d : buffer);
+ });
+
+ // prevent memory leaks for uncompleted requests
+ req.on('close', function () {
+ buffer = '';
+ self.onClose();
+ });
+
+ if (origin) {
+ // https://developer.mozilla.org/En/HTTP_Access_Control
+ headers['Access-Control-Allow-Origin'] = origin;
+ headers['Access-Control-Allow-Credentials'] = 'true';
+ headers['X-XSS-Protection'] = '0';
+ }
+ } else {
+ Transport.prototype.handleRequest.call(this, req);
+ }
+};
+
+/**
+ * Handles data payload.
+ *
+ * @api private
+ */
+
+HTTPTransport.prototype.onData = function (data) {
+ var messages = parser.decodePayload(data);
+ this.log.debug(this.name + ' received data packet', data);
+
+ for (var i = 0, l = messages.length; i < l; i++) {
+ this.onMessage(messages[i]);
+ }
+};
+
+/**
+ * Closes the request-response cycle
+ *
+ * @api private
+ */
+
+HTTPTransport.prototype.doClose = function () {
+ this.response.end();
+};
+
+/**
+ * Writes a payload of messages
+ *
+ * @api private
+ */
+
+HTTPTransport.prototype.payload = function (msgs) {
+ this.write(parser.encodePayload(msgs));
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/index.js b/signaling-server/node_modules/socket.io/lib/transports/index.js
new file mode 100644
index 0000000..b865559
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/index.js
@@ -0,0 +1,12 @@
+
+/**
+ * Export transports.
+ */
+
+module.exports = {
+ websocket: require('./websocket')
+ , flashsocket: require('./flashsocket')
+ , htmlfile: require('./htmlfile')
+ , 'xhr-polling': require('./xhr-polling')
+ , 'jsonp-polling': require('./jsonp-polling')
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/jsonp-polling.js b/signaling-server/node_modules/socket.io/lib/transports/jsonp-polling.js
new file mode 100644
index 0000000..ad7d5af
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/jsonp-polling.js
@@ -0,0 +1,97 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var HTTPPolling = require('./http-polling');
+var jsonpolling_re = /^\d+$/
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = JSONPPolling;
+
+/**
+ * JSON-P polling transport.
+ *
+ * @api public
+ */
+
+function JSONPPolling (mng, data, req) {
+ HTTPPolling.call(this, mng, data, req);
+
+ this.head = 'io.j[0](';
+ this.foot = ');';
+
+ if (data.query.i && jsonpolling_re.test(data.query.i)) {
+ this.head = 'io.j[' + data.query.i + '](';
+ }
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+JSONPPolling.prototype.__proto__ = HTTPPolling.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+JSONPPolling.prototype.name = 'jsonppolling';
+
+/**
+ * Make sure POST are decoded.
+ */
+
+JSONPPolling.prototype.postEncoded = true;
+
+/**
+ * Handles incoming data.
+ * Due to a bug in \n handling by browsers, we expect a JSONified string.
+ *
+ * @api private
+ */
+
+JSONPPolling.prototype.onData = function (data) {
+ try {
+ data = JSON.parse(data);
+ } catch (e) {
+ this.error('parse', 'reconnect');
+ return;
+ }
+
+ HTTPPolling.prototype.onData.call(this, data);
+};
+
+/**
+ * Performs the write.
+ *
+ * @api private
+ */
+
+JSONPPolling.prototype.doWrite = function (data) {
+ HTTPPolling.prototype.doWrite.call(this);
+
+ var data = data === undefined
+ ? '' : this.head + JSON.stringify(data) + this.foot;
+
+ this.response.writeHead(200, {
+ 'Content-Type': 'text/javascript; charset=UTF-8'
+ , 'Content-Length': Buffer.byteLength(data)
+ , 'Connection': 'Keep-Alive'
+ , 'X-XSS-Protection': '0'
+ });
+
+ this.response.write(data);
+ this.log.debug(this.name + ' writing', data);
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/websocket.js b/signaling-server/node_modules/socket.io/lib/transports/websocket.js
new file mode 100644
index 0000000..78a4304
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/websocket.js
@@ -0,0 +1,36 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var protocolVersions = require('./websocket/');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = WebSocket;
+
+/**
+ * HTTP interface constructor. Interface compatible with all transports that
+ * depend on request-response cycles.
+ *
+ * @api public
+ */
+
+function WebSocket (mng, data, req) {
+ var transport
+ , version = req.headers['sec-websocket-version'];
+ if (typeof version !== 'undefined' && typeof protocolVersions[version] !== 'undefined') {
+ transport = new protocolVersions[version](mng, data, req);
+ }
+ else transport = new protocolVersions['default'](mng, data, req);
+ if (typeof this.name !== 'undefined') transport.name = this.name;
+ return transport;
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/websocket/default.js b/signaling-server/node_modules/socket.io/lib/transports/websocket/default.js
new file mode 100644
index 0000000..cf3b8af
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/websocket/default.js
@@ -0,0 +1,376 @@
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var Transport = require('../../transport')
+ , EventEmitter = process.EventEmitter
+ , crypto = require('crypto')
+ , parser = require('../../parser');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = WebSocket;
+
+/**
+ * HTTP interface constructor. Interface compatible with all transports that
+ * depend on request-response cycles.
+ *
+ * @api public
+ */
+
+function WebSocket (mng, data, req) {
+ // parser
+ var self = this;
+
+ this.parser = new Parser({maxBuffer: mng.get('destroy buffer size')});
+ this.parser.on('data', function (packet) {
+ self.log.debug(self.name + ' received data packet', packet);
+ self.onMessage(parser.decodePacket(packet));
+ });
+ this.parser.on('close', function () {
+ self.end();
+ });
+ this.parser.on('error', function () {
+ self.end();
+ });
+ this.parser.on('kick', function (reason) {
+ self.log.warn(self.name + ' parser forced user kick: ' + reason);
+ self.onMessage({type: 'disconnect', endpoint: ''});
+ self.end();
+ });
+
+ Transport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+WebSocket.prototype.__proto__ = Transport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+WebSocket.prototype.name = 'websocket';
+
+/**
+ * Websocket draft version
+ *
+ * @api public
+ */
+
+WebSocket.prototype.protocolVersion = 'hixie-76';
+
+/**
+ * Called when the socket connects.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.onSocketConnect = function () {
+ var self = this;
+
+ this.socket.setNoDelay(true);
+
+ this.buffer = true;
+ this.buffered = [];
+
+ if (this.req.headers.upgrade !== 'WebSocket') {
+ this.log.warn(this.name + ' connection invalid');
+ this.end();
+ return;
+ }
+
+ var origin = this.req.headers['origin']
+ , waitingForNonce = false;
+ if(this.manager.settings['match origin protocol']){
+ location = (origin.indexOf('https')>-1 ? 'wss' : 'ws') + '://' + this.req.headers.host + this.req.url;
+ }else if(this.socket.encrypted){
+ location = 'wss://' + this.req.headers.host + this.req.url;
+ }else{
+ location = 'ws://' + this.req.headers.host + this.req.url;
+ }
+
+ if (this.req.headers['sec-websocket-key1']) {
+ // If we don't have the nonce yet, wait for it (HAProxy compatibility).
+ if (! (this.req.head && this.req.head.length >= 8)) {
+ waitingForNonce = true;
+ }
+
+ var headers = [
+ 'HTTP/1.1 101 WebSocket Protocol Handshake'
+ , 'Upgrade: WebSocket'
+ , 'Connection: Upgrade'
+ , 'Sec-WebSocket-Origin: ' + origin
+ , 'Sec-WebSocket-Location: ' + location
+ ];
+
+ if (this.req.headers['sec-websocket-protocol']){
+ headers.push('Sec-WebSocket-Protocol: '
+ + this.req.headers['sec-websocket-protocol']);
+ }
+ } else {
+ var headers = [
+ 'HTTP/1.1 101 Web Socket Protocol Handshake'
+ , 'Upgrade: WebSocket'
+ , 'Connection: Upgrade'
+ , 'WebSocket-Origin: ' + origin
+ , 'WebSocket-Location: ' + location
+ ];
+ }
+
+ try {
+ this.socket.write(headers.concat('', '').join('\r\n'));
+ this.socket.setTimeout(0);
+ this.socket.setNoDelay(true);
+ this.socket.setEncoding('utf8');
+ } catch (e) {
+ this.end();
+ return;
+ }
+
+ if (waitingForNonce) {
+ this.socket.setEncoding('binary');
+ } else if (this.proveReception(headers)) {
+ self.flush();
+ }
+
+ var headBuffer = '';
+
+ this.socket.on('data', function (data) {
+ if (waitingForNonce) {
+ headBuffer += data;
+
+ if (headBuffer.length < 8) {
+ return;
+ }
+
+ // Restore the connection to utf8 encoding after receiving the nonce
+ self.socket.setEncoding('utf8');
+ waitingForNonce = false;
+
+ // Stuff the nonce into the location where it's expected to be
+ self.req.head = headBuffer.substr(0, 8);
+ headBuffer = '';
+
+ if (self.proveReception(headers)) {
+ self.flush();
+ }
+
+ return;
+ }
+
+ self.parser.add(data);
+ });
+};
+
+/**
+ * Writes to the socket.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.write = function (data) {
+ if (this.open) {
+ this.drained = false;
+
+ if (this.buffer) {
+ this.buffered.push(data);
+ return this;
+ }
+
+ var length = Buffer.byteLength(data)
+ , buffer = new Buffer(2 + length);
+
+ buffer.write('\x00', 'binary');
+ buffer.write(data, 1, 'utf8');
+ buffer.write('\xff', 1 + length, 'binary');
+
+ try {
+ if (this.socket.write(buffer)) {
+ this.drained = true;
+ }
+ } catch (e) {
+ this.end();
+ }
+
+ this.log.debug(this.name + ' writing', data);
+ }
+};
+
+/**
+ * Flushes the internal buffer
+ *
+ * @api private
+ */
+
+WebSocket.prototype.flush = function () {
+ this.buffer = false;
+
+ for (var i = 0, l = this.buffered.length; i < l; i++) {
+ this.write(this.buffered.splice(0, 1)[0]);
+ }
+};
+
+/**
+ * Finishes the handshake.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.proveReception = function (headers) {
+ var self = this
+ , k1 = this.req.headers['sec-websocket-key1']
+ , k2 = this.req.headers['sec-websocket-key2'];
+
+ if (k1 && k2){
+ var 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){
+ self.log.warn('Invalid ' + self.name + ' key: "' + k + '".');
+ self.end();
+ return false;
+ }
+
+ n /= spaces;
+
+ md5.update(String.fromCharCode(
+ n >> 24 & 0xFF,
+ n >> 16 & 0xFF,
+ n >> 8 & 0xFF,
+ n & 0xFF));
+ });
+
+ md5.update(this.req.head.toString('binary'));
+
+ try {
+ this.socket.write(md5.digest('binary'), 'binary');
+ } catch (e) {
+ this.end();
+ }
+ }
+
+ return true;
+};
+
+/**
+ * Writes a payload.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.payload = function (msgs) {
+ for (var i = 0, l = msgs.length; i < l; i++) {
+ this.write(msgs[i]);
+ }
+
+ return this;
+};
+
+/**
+ * Closes the connection.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.doClose = function () {
+ this.socket.end();
+};
+
+/**
+ * WebSocket parser
+ *
+ * @api public
+ */
+
+function Parser (opts) {
+ this._maxBuffer = (opts && opts.maxBuffer) || 10E7;
+ this._dataLength = 0;
+ this.buffer = '';
+ this.i = 0;
+};
+
+/**
+ * Inherits from EventEmitter.
+ */
+
+Parser.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Adds data to the buffer.
+ *
+ * @api public
+ */
+
+Parser.prototype.add = function (data) {
+ this._dataLength += data.length;
+ if(this._dataLength > this._maxBuffer) {
+ this.buffer = ''; //Clear buffer
+ this.emit('kick', 'max buffer size reached');
+ return;
+ }
+
+ this.buffer += data;
+ this.parse();
+};
+
+/**
+ * Parses the buffer.
+ *
+ * @api private
+ */
+
+Parser.prototype.parse = function () {
+ for (var i = this.i, chr, l = this.buffer.length; i < l; i++){
+ chr = this.buffer[i];
+
+ if (this.buffer.length == 2 && this.buffer[1] == '\u0000') {
+ this.emit('close');
+ this.buffer = '';
+ this.i = 0;
+ return;
+ }
+
+ if (i === 0){
+ if (chr != '\u0000')
+ this.error('Bad framing. Expected null byte as first frame');
+ else
+ continue;
+ }
+
+ if (chr == '\ufffd'){
+ this.emit('data', this.buffer.substr(1, i - 1));
+ this.buffer = this.buffer.substr(i + 1);
+ this.i = 0;
+ return this.parse();
+ }
+ }
+};
+
+/**
+ * Handles an error
+ *
+ * @api private
+ */
+
+Parser.prototype.error = function (reason) {
+ this.buffer = '';
+ this.i = 0;
+ this.emit('error', reason);
+ return this;
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js b/signaling-server/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js
new file mode 100644
index 0000000..8f0759d
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/websocket/hybi-07-12.js
@@ -0,0 +1,642 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var Transport = require('../../transport')
+ , EventEmitter = process.EventEmitter
+ , crypto = require('crypto')
+ , url = require('url')
+ , parser = require('../../parser')
+ , util = require('../../util');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = WebSocket;
+exports.Parser = Parser;
+
+/**
+ * HTTP interface constructor. Interface compatible with all transports that
+ * depend on request-response cycles.
+ *
+ * @api public
+ */
+
+function WebSocket (mng, data, req) {
+ // parser
+ var self = this;
+
+ this.manager = mng;
+ this.parser = new Parser({maxBuffer: mng.get('destroy buffer size')});
+ this.parser.on('data', function (packet) {
+ self.onMessage(parser.decodePacket(packet));
+ });
+ this.parser.on('ping', function () {
+ // version 8 ping => pong
+ try {
+ self.socket.write('\u008a\u0000');
+ }
+ catch (e) {
+ self.end();
+ return;
+ }
+ });
+ this.parser.on('close', function () {
+ self.end();
+ });
+ this.parser.on('error', function (reason) {
+ self.log.warn(self.name + ' parser error: ' + reason);
+ self.end();
+ });
+ this.parser.on('kick', function (reason) {
+ self.log.warn(self.name + ' parser forced user kick: ' + reason);
+ self.onMessage({type: 'disconnect', endpoint: ''});
+ self.end();
+ });
+
+ Transport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+WebSocket.prototype.__proto__ = Transport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+WebSocket.prototype.name = 'websocket';
+
+/**
+ * Websocket draft version
+ *
+ * @api public
+ */
+
+WebSocket.prototype.protocolVersion = '07-12';
+
+/**
+ * Called when the socket connects.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.onSocketConnect = function () {
+ var self = this;
+
+ if (typeof this.req.headers.upgrade === 'undefined' ||
+ this.req.headers.upgrade.toLowerCase() !== 'websocket') {
+ this.log.warn(this.name + ' connection invalid');
+ this.end();
+ return;
+ }
+
+ var origin = this.req.headers['sec-websocket-origin']
+ , location = ((this.manager.settings['match origin protocol'] ?
+ origin.match(/^https/) : this.socket.encrypted) ?
+ 'wss' : 'ws')
+ + '://' + this.req.headers.host + this.req.url;
+
+ if (!this.verifyOrigin(origin)) {
+ this.log.warn(this.name + ' connection invalid: origin mismatch');
+ this.end();
+ return;
+ }
+
+ if (!this.req.headers['sec-websocket-key']) {
+ this.log.warn(this.name + ' connection invalid: received no key');
+ this.end();
+ return;
+ }
+
+ // calc key
+ var key = this.req.headers['sec-websocket-key'];
+ var shasum = crypto.createHash('sha1');
+ shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+ key = shasum.digest('base64');
+
+ var headers = [
+ 'HTTP/1.1 101 Switching Protocols'
+ , 'Upgrade: websocket'
+ , 'Connection: Upgrade'
+ , 'Sec-WebSocket-Accept: ' + key
+ ];
+
+ try {
+ this.socket.write(headers.concat('', '').join('\r\n'));
+ this.socket.setTimeout(0);
+ this.socket.setNoDelay(true);
+ } catch (e) {
+ this.end();
+ return;
+ }
+
+ this.socket.on('data', function (data) {
+ self.parser.add(data);
+ });
+};
+
+/**
+ * Verifies the origin of a request.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.verifyOrigin = function (origin) {
+ var origins = this.manager.get('origins');
+
+ if (origin === 'null') origin = '*';
+
+ if (origins.indexOf('*:*') !== -1) {
+ return true;
+ }
+
+ if (origin) {
+ try {
+ var parts = url.parse(origin);
+ parts.port = parts.port || 80;
+ var ok =
+ ~origins.indexOf(parts.hostname + ':' + parts.port) ||
+ ~origins.indexOf(parts.hostname + ':*') ||
+ ~origins.indexOf('*:' + parts.port);
+ if (!ok) this.log.warn('illegal origin: ' + origin);
+ return ok;
+ } catch (ex) {
+ this.log.warn('error parsing origin');
+ }
+ }
+ else {
+ this.log.warn('origin missing from websocket call, yet required by config');
+ }
+ return false;
+};
+
+/**
+ * Writes to the socket.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.write = function (data) {
+ if (this.open) {
+ var buf = this.frame(0x81, data);
+ try {
+ this.socket.write(buf, 'binary');
+ }
+ catch (e) {
+ this.end();
+ return;
+ }
+ this.log.debug(this.name + ' writing', data);
+ }
+};
+
+/**
+ * Writes a payload.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.payload = function (msgs) {
+ for (var i = 0, l = msgs.length; i < l; i++) {
+ this.write(msgs[i]);
+ }
+
+ return this;
+};
+
+/**
+ * Frame server-to-client output as a text packet.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.frame = function (opcode, str) {
+ var dataBuffer = new Buffer(str)
+ , dataLength = dataBuffer.length
+ , startOffset = 2
+ , secondByte = dataLength;
+ if (dataLength > 65536) {
+ startOffset = 10;
+ secondByte = 127;
+ }
+ else if (dataLength > 125) {
+ startOffset = 4;
+ secondByte = 126;
+ }
+ var outputBuffer = new Buffer(dataLength + startOffset);
+ outputBuffer[0] = opcode;
+ outputBuffer[1] = secondByte;
+ dataBuffer.copy(outputBuffer, startOffset);
+ switch (secondByte) {
+ case 126:
+ outputBuffer[2] = dataLength >>> 8;
+ outputBuffer[3] = dataLength % 256;
+ break;
+ case 127:
+ var l = dataLength;
+ for (var i = 1; i <= 8; ++i) {
+ outputBuffer[startOffset - i] = l & 0xff;
+ l >>>= 8;
+ }
+ }
+ return outputBuffer;
+};
+
+/**
+ * Closes the connection.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.doClose = function () {
+ this.socket.end();
+};
+
+/**
+ * WebSocket parser
+ *
+ * @api public
+ */
+
+function Parser (opts) {
+ this.state = {
+ activeFragmentedOperation: null,
+ lastFragment: false,
+ masked: false,
+ opcode: 0
+ };
+ this.overflow = null;
+ this.expectOffset = 0;
+ this.expectBuffer = null;
+ this.expectHandler = null;
+ this.currentMessage = '';
+ this._maxBuffer = (opts && opts.maxBuffer) || 10E7;
+ this._dataLength = 0;
+
+ var self = this;
+ this.opcodeHandlers = {
+ // text
+ '1': function(data) {
+ var finish = function(mask, data) {
+ self.currentMessage += self.unmask(mask, data);
+ if (self.state.lastFragment) {
+ self.emit('data', self.currentMessage);
+ self.currentMessage = '';
+ }
+ self.endPacket();
+ }
+
+ var expectData = function(length) {
+ if (self.state.masked) {
+ self.expect('Mask', 4, function(data) {
+ var mask = data;
+ self.expect('Data', length, function(data) {
+ finish(mask, data);
+ });
+ });
+ }
+ else {
+ self.expect('Data', length, function(data) {
+ finish(null, data);
+ });
+ }
+ }
+
+ // decode length
+ var firstLength = data[1] & 0x7f;
+ if (firstLength < 126) {
+ expectData(firstLength);
+ }
+ else if (firstLength == 126) {
+ self.expect('Length', 2, function(data) {
+ expectData(util.unpack(data));
+ });
+ }
+ else if (firstLength == 127) {
+ self.expect('Length', 8, function(data) {
+ if (util.unpack(data.slice(0, 4)) != 0) {
+ self.error('packets with length spanning more than 32 bit is currently not supported');
+ return;
+ }
+ var lengthBytes = data.slice(4); // note: cap to 32 bit length
+ expectData(util.unpack(data));
+ });
+ }
+ },
+ // binary
+ '2': function(data) {
+ var finish = function(mask, data) {
+ if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list
+ self.currentMessage.push(self.unmask(mask, data, true));
+ if (self.state.lastFragment) {
+ self.emit('binary', self.concatBuffers(self.currentMessage));
+ self.currentMessage = '';
+ }
+ self.endPacket();
+ }
+
+ var expectData = function(length) {
+ if (self.state.masked) {
+ self.expect('Mask', 4, function(data) {
+ var mask = data;
+ self.expect('Data', length, function(data) {
+ finish(mask, data);
+ });
+ });
+ }
+ else {
+ self.expect('Data', length, function(data) {
+ finish(null, data);
+ });
+ }
+ }
+
+ // decode length
+ var firstLength = data[1] & 0x7f;
+ if (firstLength < 126) {
+ expectData(firstLength);
+ }
+ else if (firstLength == 126) {
+ self.expect('Length', 2, function(data) {
+ expectData(util.unpack(data));
+ });
+ }
+ else if (firstLength == 127) {
+ self.expect('Length', 8, function(data) {
+ if (util.unpack(data.slice(0, 4)) != 0) {
+ self.error('packets with length spanning more than 32 bit is currently not supported');
+ return;
+ }
+ var lengthBytes = data.slice(4); // note: cap to 32 bit length
+ expectData(util.unpack(data));
+ });
+ }
+ },
+ // close
+ '8': function(data) {
+ self.emit('close');
+ self.reset();
+ },
+ // ping
+ '9': function(data) {
+ if (self.state.lastFragment == false) {
+ self.error('fragmented ping is not supported');
+ return;
+ }
+
+ var finish = function(mask, data) {
+ self.emit('ping', self.unmask(mask, data));
+ self.endPacket();
+ }
+
+ var expectData = function(length) {
+ if (self.state.masked) {
+ self.expect('Mask', 4, function(data) {
+ var mask = data;
+ self.expect('Data', length, function(data) {
+ finish(mask, data);
+ });
+ });
+ }
+ else {
+ self.expect('Data', length, function(data) {
+ finish(null, data);
+ });
+ }
+ }
+
+ // decode length
+ var firstLength = data[1] & 0x7f;
+ if (firstLength == 0) {
+ finish(null, null);
+ }
+ else if (firstLength < 126) {
+ expectData(firstLength);
+ }
+ else if (firstLength == 126) {
+ self.expect('Length', 2, function(data) {
+ expectData(util.unpack(data));
+ });
+ }
+ else if (firstLength == 127) {
+ self.expect('Length', 8, function(data) {
+ expectData(util.unpack(data));
+ });
+ }
+ }
+ }
+
+ this.expect('Opcode', 2, this.processPacket);
+};
+
+/**
+ * Inherits from EventEmitter.
+ */
+
+Parser.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Add new data to the parser.
+ *
+ * @api public
+ */
+
+Parser.prototype.add = function(data) {
+ this._dataLength += data.length;
+ if (this._dataLength > this._maxBuffer) {
+ // Clear data
+ this.overflow = null;
+ this.expectBuffer = null;
+ // Kick client
+ this.emit('kick', 'max buffer size reached');
+ return;
+ }
+ if (this.expectBuffer == null) {
+ this.addToOverflow(data);
+ return;
+ }
+ var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
+ data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
+ this.expectOffset += toRead;
+ if (toRead < data.length) {
+ // at this point the overflow buffer shouldn't at all exist
+ this.overflow = new Buffer(data.length - toRead);
+ data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
+ }
+ if (this.expectOffset == this.expectBuffer.length) {
+ var bufferForHandler = this.expectBuffer;
+ this.expectBuffer = null;
+ this.expectOffset = 0;
+ this.expectHandler.call(this, bufferForHandler);
+ }
+}
+
+/**
+ * Adds a piece of data to the overflow.
+ *
+ * @api private
+ */
+
+Parser.prototype.addToOverflow = function(data) {
+ if (this.overflow == null) this.overflow = data;
+ else {
+ var prevOverflow = this.overflow;
+ this.overflow = new Buffer(this.overflow.length + data.length);
+ prevOverflow.copy(this.overflow, 0);
+ data.copy(this.overflow, prevOverflow.length);
+ }
+}
+
+/**
+ * Waits for a certain amount of bytes to be available, then fires a callback.
+ *
+ * @api private
+ */
+
+Parser.prototype.expect = function(what, length, handler) {
+ if (length > this._maxBuffer) {
+ this.emit('kick', 'expected input larger than max buffer');
+ return;
+ }
+ this.expectBuffer = new Buffer(length);
+ this.expectOffset = 0;
+ this.expectHandler = handler;
+ if (this.overflow != null) {
+ var toOverflow = this.overflow;
+ this.overflow = null;
+ this.add(toOverflow);
+ }
+}
+
+/**
+ * Start processing a new packet.
+ *
+ * @api private
+ */
+
+Parser.prototype.processPacket = function (data) {
+ if ((data[0] & 0x70) != 0) {
+ this.error('reserved fields must be empty');
+ }
+ this.state.lastFragment = (data[0] & 0x80) == 0x80;
+ this.state.masked = (data[1] & 0x80) == 0x80;
+ var opcode = data[0] & 0xf;
+ if (opcode == 0) {
+ // continuation frame
+ this.state.opcode = this.state.activeFragmentedOperation;
+ if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
+ this.error('continuation frame cannot follow current opcode')
+ return;
+ }
+ }
+ else {
+ this.state.opcode = opcode;
+ if (this.state.lastFragment === false) {
+ this.state.activeFragmentedOperation = opcode;
+ }
+ }
+ var handler = this.opcodeHandlers[this.state.opcode];
+ if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
+ else handler(data);
+}
+
+/**
+ * Endprocessing a packet.
+ *
+ * @api private
+ */
+
+Parser.prototype.endPacket = function() {
+ this.expectOffset = 0;
+ this.expectBuffer = null;
+ this.expectHandler = null;
+ if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
+ // end current fragmented operation
+ this.state.activeFragmentedOperation = null;
+ }
+ this.state.lastFragment = false;
+ this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
+ this.state.masked = false;
+ this.expect('Opcode', 2, this.processPacket);
+}
+
+/**
+ * Reset the parser state.
+ *
+ * @api private
+ */
+
+Parser.prototype.reset = function() {
+ this.state = {
+ activeFragmentedOperation: null,
+ lastFragment: false,
+ masked: false,
+ opcode: 0
+ };
+ this.expectOffset = 0;
+ this.expectBuffer = null;
+ this.expectHandler = null;
+ this.overflow = null;
+ this.currentMessage = '';
+}
+
+/**
+ * Unmask received data.
+ *
+ * @api private
+ */
+
+Parser.prototype.unmask = function (mask, buf, binary) {
+ if (mask != null) {
+ for (var i = 0, ll = buf.length; i < ll; i++) {
+ buf[i] ^= mask[i % 4];
+ }
+ }
+ if (binary) return buf;
+ return buf != null ? buf.toString('utf8') : '';
+}
+
+/**
+ * Concatenates a list of buffers.
+ *
+ * @api private
+ */
+
+Parser.prototype.concatBuffers = function(buffers) {
+ var length = 0;
+ for (var i = 0, l = buffers.length; i < l; ++i) {
+ length += buffers[i].length;
+ }
+ var mergedBuffer = new Buffer(length);
+ var offset = 0;
+ for (var i = 0, l = buffers.length; i < l; ++i) {
+ buffers[i].copy(mergedBuffer, offset);
+ offset += buffers[i].length;
+ }
+ return mergedBuffer;
+}
+
+/**
+ * Handles an error
+ *
+ * @api private
+ */
+
+Parser.prototype.error = function (reason) {
+ this.reset();
+ this.emit('error', reason);
+ return this;
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/websocket/hybi-16.js b/signaling-server/node_modules/socket.io/lib/transports/websocket/hybi-16.js
new file mode 100644
index 0000000..2074fa1
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/websocket/hybi-16.js
@@ -0,0 +1,642 @@
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var Transport = require('../../transport')
+ , EventEmitter = process.EventEmitter
+ , crypto = require('crypto')
+ , url = require('url')
+ , parser = require('../../parser')
+ , util = require('../../util');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = WebSocket;
+exports.Parser = Parser;
+
+/**
+ * HTTP interface constructor. Interface compatible with all transports that
+ * depend on request-response cycles.
+ *
+ * @api public
+ */
+
+function WebSocket (mng, data, req) {
+ // parser
+ var self = this;
+
+ this.manager = mng;
+ this.parser = new Parser({maxBuffer: mng.get('destroy buffer size')});
+ this.parser.on('data', function (packet) {
+ self.onMessage(parser.decodePacket(packet));
+ });
+ this.parser.on('ping', function () {
+ // version 8 ping => pong
+ try {
+ self.socket.write('\u008a\u0000');
+ }
+ catch (e) {
+ self.end();
+ return;
+ }
+ });
+ this.parser.on('close', function () {
+ self.end();
+ });
+ this.parser.on('error', function (reason) {
+ self.log.warn(self.name + ' parser error: ' + reason);
+ self.end();
+ });
+ this.parser.on('kick', function (reason) {
+ self.log.warn(self.name + ' parser forced user kick: ' + reason);
+ self.onMessage({type: 'disconnect', endpoint: ''});
+ self.end();
+ });
+
+ Transport.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+WebSocket.prototype.__proto__ = Transport.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+WebSocket.prototype.name = 'websocket';
+
+/**
+ * Websocket draft version
+ *
+ * @api public
+ */
+
+WebSocket.prototype.protocolVersion = '16';
+
+/**
+ * Called when the socket connects.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.onSocketConnect = function () {
+ var self = this;
+
+ if (typeof this.req.headers.upgrade === 'undefined' ||
+ this.req.headers.upgrade.toLowerCase() !== 'websocket') {
+ this.log.warn(this.name + ' connection invalid');
+ this.end();
+ return;
+ }
+
+ var origin = this.req.headers['origin'] || ''
+ , location = ((this.manager.settings['match origin protocol'] ?
+ origin.match(/^https/) : this.socket.encrypted) ?
+ 'wss' : 'ws')
+ + '://' + this.req.headers.host + this.req.url;
+
+ if (!this.verifyOrigin(origin)) {
+ this.log.warn(this.name + ' connection invalid: origin mismatch');
+ this.end();
+ return;
+ }
+
+ if (!this.req.headers['sec-websocket-key']) {
+ this.log.warn(this.name + ' connection invalid: received no key');
+ this.end();
+ return;
+ }
+
+ // calc key
+ var key = this.req.headers['sec-websocket-key'];
+ var shasum = crypto.createHash('sha1');
+ shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+ key = shasum.digest('base64');
+
+ var headers = [
+ 'HTTP/1.1 101 Switching Protocols'
+ , 'Upgrade: websocket'
+ , 'Connection: Upgrade'
+ , 'Sec-WebSocket-Accept: ' + key
+ ];
+
+ try {
+ this.socket.write(headers.concat('', '').join('\r\n'));
+ this.socket.setTimeout(0);
+ this.socket.setNoDelay(true);
+ } catch (e) {
+ this.end();
+ return;
+ }
+
+ this.socket.on('data', function (data) {
+ self.parser.add(data);
+ });
+};
+
+/**
+ * Verifies the origin of a request.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.verifyOrigin = function (origin) {
+ var origins = this.manager.get('origins');
+
+ if (origin === 'null') origin = '*';
+
+ if (origins.indexOf('*:*') !== -1) {
+ return true;
+ }
+
+ if (origin) {
+ try {
+ var parts = url.parse(origin);
+ parts.port = parts.port || 80;
+ var ok =
+ ~origins.indexOf(parts.hostname + ':' + parts.port) ||
+ ~origins.indexOf(parts.hostname + ':*') ||
+ ~origins.indexOf('*:' + parts.port);
+ if (!ok) this.log.warn('illegal origin: ' + origin);
+ return ok;
+ } catch (ex) {
+ this.log.warn('error parsing origin');
+ }
+ }
+ else {
+ this.log.warn('origin missing from websocket call, yet required by config');
+ }
+ return false;
+};
+
+/**
+ * Writes to the socket.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.write = function (data) {
+ if (this.open) {
+ var buf = this.frame(0x81, data);
+ try {
+ this.socket.write(buf, 'binary');
+ }
+ catch (e) {
+ this.end();
+ return;
+ }
+ this.log.debug(this.name + ' writing', data);
+ }
+};
+
+/**
+ * Writes a payload.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.payload = function (msgs) {
+ for (var i = 0, l = msgs.length; i < l; i++) {
+ this.write(msgs[i]);
+ }
+
+ return this;
+};
+
+/**
+ * Frame server-to-client output as a text packet.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.frame = function (opcode, str) {
+ var dataBuffer = new Buffer(str)
+ , dataLength = dataBuffer.length
+ , startOffset = 2
+ , secondByte = dataLength;
+ if (dataLength > 65536) {
+ startOffset = 10;
+ secondByte = 127;
+ }
+ else if (dataLength > 125) {
+ startOffset = 4;
+ secondByte = 126;
+ }
+ var outputBuffer = new Buffer(dataLength + startOffset);
+ outputBuffer[0] = opcode;
+ outputBuffer[1] = secondByte;
+ dataBuffer.copy(outputBuffer, startOffset);
+ switch (secondByte) {
+ case 126:
+ outputBuffer[2] = dataLength >>> 8;
+ outputBuffer[3] = dataLength % 256;
+ break;
+ case 127:
+ var l = dataLength;
+ for (var i = 1; i <= 8; ++i) {
+ outputBuffer[startOffset - i] = l & 0xff;
+ l >>>= 8;
+ }
+ }
+ return outputBuffer;
+};
+
+/**
+ * Closes the connection.
+ *
+ * @api private
+ */
+
+WebSocket.prototype.doClose = function () {
+ this.socket.end();
+};
+
+/**
+ * WebSocket parser
+ *
+ * @api public
+ */
+
+function Parser (opts) {
+ this.state = {
+ activeFragmentedOperation: null,
+ lastFragment: false,
+ masked: false,
+ opcode: 0
+ };
+ this.overflow = null;
+ this.expectOffset = 0;
+ this.expectBuffer = null;
+ this.expectHandler = null;
+ this.currentMessage = '';
+ this._maxBuffer = (opts && opts.maxBuffer) || 10E7;
+ this._dataLength = 0;
+
+ var self = this;
+ this.opcodeHandlers = {
+ // text
+ '1': function(data) {
+ var finish = function(mask, data) {
+ self.currentMessage += self.unmask(mask, data);
+ if (self.state.lastFragment) {
+ self.emit('data', self.currentMessage);
+ self.currentMessage = '';
+ }
+ self.endPacket();
+ }
+
+ var expectData = function(length) {
+ if (self.state.masked) {
+ self.expect('Mask', 4, function(data) {
+ var mask = data;
+ self.expect('Data', length, function(data) {
+ finish(mask, data);
+ });
+ });
+ }
+ else {
+ self.expect('Data', length, function(data) {
+ finish(null, data);
+ });
+ }
+ }
+
+ // decode length
+ var firstLength = data[1] & 0x7f;
+ if (firstLength < 126) {
+ expectData(firstLength);
+ }
+ else if (firstLength == 126) {
+ self.expect('Length', 2, function(data) {
+ expectData(util.unpack(data));
+ });
+ }
+ else if (firstLength == 127) {
+ self.expect('Length', 8, function(data) {
+ if (util.unpack(data.slice(0, 4)) != 0) {
+ self.error('packets with length spanning more than 32 bit is currently not supported');
+ return;
+ }
+ var lengthBytes = data.slice(4); // note: cap to 32 bit length
+ expectData(util.unpack(data));
+ });
+ }
+ },
+ // binary
+ '2': function(data) {
+ var finish = function(mask, data) {
+ if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list
+ self.currentMessage.push(self.unmask(mask, data, true));
+ if (self.state.lastFragment) {
+ self.emit('binary', self.concatBuffers(self.currentMessage));
+ self.currentMessage = '';
+ }
+ self.endPacket();
+ }
+
+ var expectData = function(length) {
+ if (self.state.masked) {
+ self.expect('Mask', 4, function(data) {
+ var mask = data;
+ self.expect('Data', length, function(data) {
+ finish(mask, data);
+ });
+ });
+ }
+ else {
+ self.expect('Data', length, function(data) {
+ finish(null, data);
+ });
+ }
+ }
+
+ // decode length
+ var firstLength = data[1] & 0x7f;
+ if (firstLength < 126) {
+ expectData(firstLength);
+ }
+ else if (firstLength == 126) {
+ self.expect('Length', 2, function(data) {
+ expectData(util.unpack(data));
+ });
+ }
+ else if (firstLength == 127) {
+ self.expect('Length', 8, function(data) {
+ if (util.unpack(data.slice(0, 4)) != 0) {
+ self.error('packets with length spanning more than 32 bit is currently not supported');
+ return;
+ }
+ var lengthBytes = data.slice(4); // note: cap to 32 bit length
+ expectData(util.unpack(data));
+ });
+ }
+ },
+ // close
+ '8': function(data) {
+ self.emit('close');
+ self.reset();
+ },
+ // ping
+ '9': function(data) {
+ if (self.state.lastFragment == false) {
+ self.error('fragmented ping is not supported');
+ return;
+ }
+
+ var finish = function(mask, data) {
+ self.emit('ping', self.unmask(mask, data));
+ self.endPacket();
+ }
+
+ var expectData = function(length) {
+ if (self.state.masked) {
+ self.expect('Mask', 4, function(data) {
+ var mask = data;
+ self.expect('Data', length, function(data) {
+ finish(mask, data);
+ });
+ });
+ }
+ else {
+ self.expect('Data', length, function(data) {
+ finish(null, data);
+ });
+ }
+ }
+
+ // decode length
+ var firstLength = data[1] & 0x7f;
+ if (firstLength == 0) {
+ finish(null, null);
+ }
+ else if (firstLength < 126) {
+ expectData(firstLength);
+ }
+ else if (firstLength == 126) {
+ self.expect('Length', 2, function(data) {
+ expectData(util.unpack(data));
+ });
+ }
+ else if (firstLength == 127) {
+ self.expect('Length', 8, function(data) {
+ expectData(util.unpack(data));
+ });
+ }
+ }
+ }
+
+ this.expect('Opcode', 2, this.processPacket);
+};
+
+/**
+ * Inherits from EventEmitter.
+ */
+
+Parser.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Add new data to the parser.
+ *
+ * @api public
+ */
+
+Parser.prototype.add = function(data) {
+ this._dataLength += data.length;
+ if (this._dataLength > this._maxBuffer) {
+ // Clear data
+ this.overflow = null;
+ this.expectBuffer = null;
+ // Kick client
+ this.emit('kick', 'max buffer size reached');
+ return;
+ }
+ if (this.expectBuffer == null) {
+ this.addToOverflow(data);
+ return;
+ }
+ var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
+ data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
+ this.expectOffset += toRead;
+ if (toRead < data.length) {
+ // at this point the overflow buffer shouldn't at all exist
+ this.overflow = new Buffer(data.length - toRead);
+ data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
+ }
+ if (this.expectOffset == this.expectBuffer.length) {
+ var bufferForHandler = this.expectBuffer;
+ this.expectBuffer = null;
+ this.expectOffset = 0;
+ this.expectHandler.call(this, bufferForHandler);
+ }
+}
+
+/**
+ * Adds a piece of data to the overflow.
+ *
+ * @api private
+ */
+
+Parser.prototype.addToOverflow = function(data) {
+ if (this.overflow == null) this.overflow = data;
+ else {
+ var prevOverflow = this.overflow;
+ this.overflow = new Buffer(this.overflow.length + data.length);
+ prevOverflow.copy(this.overflow, 0);
+ data.copy(this.overflow, prevOverflow.length);
+ }
+}
+
+/**
+ * Waits for a certain amount of bytes to be available, then fires a callback.
+ *
+ * @api private
+ */
+
+Parser.prototype.expect = function(what, length, handler) {
+ if (length > this._maxBuffer) {
+ this.emit('kick', 'expected input larger than max buffer');
+ return;
+ }
+ this.expectBuffer = new Buffer(length);
+ this.expectOffset = 0;
+ this.expectHandler = handler;
+ if (this.overflow != null) {
+ var toOverflow = this.overflow;
+ this.overflow = null;
+ this.add(toOverflow);
+ }
+}
+
+/**
+ * Start processing a new packet.
+ *
+ * @api private
+ */
+
+Parser.prototype.processPacket = function (data) {
+ if ((data[0] & 0x70) != 0) {
+ this.error('reserved fields must be empty');
+ return;
+ }
+ this.state.lastFragment = (data[0] & 0x80) == 0x80;
+ this.state.masked = (data[1] & 0x80) == 0x80;
+ var opcode = data[0] & 0xf;
+ if (opcode == 0) {
+ // continuation frame
+ this.state.opcode = this.state.activeFragmentedOperation;
+ if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
+ this.error('continuation frame cannot follow current opcode')
+ return;
+ }
+ }
+ else {
+ this.state.opcode = opcode;
+ if (this.state.lastFragment === false) {
+ this.state.activeFragmentedOperation = opcode;
+ }
+ }
+ var handler = this.opcodeHandlers[this.state.opcode];
+ if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
+ else handler(data);
+}
+
+/**
+ * Endprocessing a packet.
+ *
+ * @api private
+ */
+
+Parser.prototype.endPacket = function() {
+ this.expectOffset = 0;
+ this.expectBuffer = null;
+ this.expectHandler = null;
+ if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
+ // end current fragmented operation
+ this.state.activeFragmentedOperation = null;
+ }
+ this.state.lastFragment = false;
+ this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
+ this.state.masked = false;
+ this.expect('Opcode', 2, this.processPacket);
+}
+
+/**
+ * Reset the parser state.
+ *
+ * @api private
+ */
+
+Parser.prototype.reset = function() {
+ this.state = {
+ activeFragmentedOperation: null,
+ lastFragment: false,
+ masked: false,
+ opcode: 0
+ };
+ this.expectOffset = 0;
+ this.expectBuffer = null;
+ this.expectHandler = null;
+ this.overflow = null;
+ this.currentMessage = '';
+}
+
+/**
+ * Unmask received data.
+ *
+ * @api private
+ */
+
+Parser.prototype.unmask = function (mask, buf, binary) {
+ if (mask != null) {
+ for (var i = 0, ll = buf.length; i < ll; i++) {
+ buf[i] ^= mask[i % 4];
+ }
+ }
+ if (binary) return buf;
+ return buf != null ? buf.toString('utf8') : '';
+}
+
+/**
+ * Concatenates a list of buffers.
+ *
+ * @api private
+ */
+
+Parser.prototype.concatBuffers = function(buffers) {
+ var length = 0;
+ for (var i = 0, l = buffers.length; i < l; ++i) {
+ length += buffers[i].length;
+ }
+ var mergedBuffer = new Buffer(length);
+ var offset = 0;
+ for (var i = 0, l = buffers.length; i < l; ++i) {
+ buffers[i].copy(mergedBuffer, offset);
+ offset += buffers[i].length;
+ }
+ return mergedBuffer;
+}
+
+/**
+ * Handles an error
+ *
+ * @api private
+ */
+
+Parser.prototype.error = function (reason) {
+ this.reset();
+ this.emit('error', reason);
+ return this;
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/websocket/index.js b/signaling-server/node_modules/socket.io/lib/transports/websocket/index.js
new file mode 100644
index 0000000..3a952b7
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/websocket/index.js
@@ -0,0 +1,11 @@
+
+/**
+ * Export websocket versions.
+ */
+
+module.exports = {
+ 7: require('./hybi-07-12'),
+ 8: require('./hybi-07-12'),
+ 13: require('./hybi-16'),
+ default: require('./default')
+};
diff --git a/signaling-server/node_modules/socket.io/lib/transports/xhr-polling.js b/signaling-server/node_modules/socket.io/lib/transports/xhr-polling.js
new file mode 100644
index 0000000..1db5aee
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/lib/transports/xhr-polling.js
@@ -0,0 +1,69 @@
+
+/*!
+ * socket.io-node
+ * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
+ * MIT Licensed
+ */
+
+/**
+ * Module requirements.
+ */
+
+var HTTPPolling = require('./http-polling');
+
+/**
+ * Export the constructor.
+ */
+
+exports = module.exports = XHRPolling;
+
+/**
+ * Ajax polling transport.
+ *
+ * @api public
+ */
+
+function XHRPolling (mng, data, req) {
+ HTTPPolling.call(this, mng, data, req);
+};
+
+/**
+ * Inherits from Transport.
+ */
+
+XHRPolling.prototype.__proto__ = HTTPPolling.prototype;
+
+/**
+ * Transport name
+ *
+ * @api public
+ */
+
+XHRPolling.prototype.name = 'xhr-polling';
+
+/**
+ * Frames data prior to write.
+ *
+ * @api private
+ */
+
+XHRPolling.prototype.doWrite = function (data) {
+ HTTPPolling.prototype.doWrite.call(this);
+
+ var origin = this.req.headers.origin
+ , headers = {
+ 'Content-Type': 'text/plain; charset=UTF-8'
+ , 'Content-Length': data === undefined ? 0 : Buffer.byteLength(data)
+ , 'Connection': 'Keep-Alive'
+ };
+
+ if (origin) {
+ // https://developer.mozilla.org/En/HTTP_Access_Control
+ headers['Access-Control-Allow-Origin'] = origin;
+ headers['Access-Control-Allow-Credentials'] = 'true';
+ }
+
+ this.response.writeHead(200, headers);
+ this.response.write(data);
+ this.log.debug(this.name + ' writing', data);
+};