85 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			85 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| var Packer = require('proxy-packer');
 | |
| var Devices = require('./device-tracker');
 | |
| var Server = require('./server.js');
 | |
| 
 | |
| module.exports.store = { Devices: Devices };
 | |
| module.exports.create = function (state) {
 | |
|   state.deviceLists = {};
 | |
|   state.deviceCallbacks = {};
 | |
|   state.srvs = {};
 | |
| 
 | |
|   if (!parseInt(state.activityTimeout, 10)) {
 | |
|     state.activityTimeout = 2 * 60 * 1000;
 | |
|   }
 | |
|   if (!parseInt(state.pongTimeout, 10)) {
 | |
|     state.pongTimeout = 10 * 1000;
 | |
|   }
 | |
|   state.Devices = Devices;
 | |
| 
 | |
|   // TODO Use a Single TCP Handler
 | |
|   // Issues:
 | |
|   //   * dynamic ports are dedicated to a device or cluster
 | |
|   //   * servernames could come in on ports that belong to a different device
 | |
|   //   * servernames could come in that belong to no device
 | |
|   //   * this could lead to an attack / security vulnerability with ACME certificates
 | |
|   // Solutions
 | |
|   //   * Restrict dynamic ports to a particular device
 | |
|   //   * Restrict the use of servernames
 | |
| 
 | |
|   function onWsConnection(_ws, _upgradeReq) {
 | |
|     var srv = {};
 | |
|     var initToken;
 | |
|     srv.ws = _ws;
 | |
|     srv.upgradeReq = _upgradeReq;
 | |
|     srv.socketId = Packer.socketToId(srv.upgradeReq.socket);
 | |
|     srv.grants = {};
 | |
|     srv.clients = {};
 | |
|     srv.domainsMap = {};
 | |
|     srv.portsMap = {};
 | |
|     srv.pausedConns = [];
 | |
| 
 | |
|     if (state.debug) { console.log('[ws] connection', srv.socketId); }
 | |
| 
 | |
|     initToken = Server.parseAuth(state, srv);
 | |
| 
 | |
|     srv.ws._socket.on('drain', function () {
 | |
|       // the websocket library has it's own buffer apart from node's socket buffer, but that one
 | |
|       // is much more difficult to watch, so we watch for the lower level buffer to drain and
 | |
|       // then check to see if the upper level buffer is still too full to write to. Note that
 | |
|       // the websocket library buffer has something to do with compression, so I'm not requiring
 | |
|       // that to be 0 before we start up again.
 | |
|       if (srv.ws.bufferedAmount > 128*1024) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       srv.pausedConns.forEach(function (conn) {
 | |
|         if (!conn.manualPause) {
 | |
|           // console.log('resuming', conn.tunnelCid, 'now that the web socket has caught up');
 | |
|           conn.resume();
 | |
|         }
 | |
|       });
 | |
|       srv.pausedConns.length = 0;
 | |
|     });
 | |
| 
 | |
|     if (initToken) {
 | |
|       console.log('[wss.onConnection] token provided in http headers');
 | |
|       return Server.addToken(state, srv, initToken).then(function () {
 | |
|         Server.init(state, srv);
 | |
|       }).catch(function (err) {
 | |
|         Server.sendTunnelMsg(srv, null, [0, err], 'control');
 | |
|         srv.ws.close();
 | |
|       });
 | |
|     } else {
 | |
|       return Server.init(state, srv);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return {
 | |
|     tcp: require('./unwrap-tls').createTcpConnectionHandler(state)
 | |
|   , ws: onWsConnection
 | |
|   , isClientDomain: Devices.exist.bind(null, state.deviceLists)
 | |
|   };
 | |
| };
 |