mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			477 lines
		
	
	
		
			No EOL
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			477 lines
		
	
	
		
			No EOL
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
| Copyright 2018-2020 Intel Corporation
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| /**
 | |
| * @description APF/CIRA Client for Duktape
 | |
| * @author Joko Sastriawan & Ylian Saint-Hilaire
 | |
| * @copyright Intel Corporation 2019
 | |
| * @license Apache-2.0
 | |
| * @version v0.0.2
 | |
| */
 | |
| 
 | |
| function CreateAPFClient(parent, args) {
 | |
|     if ((args.clientuuid == null) || (args.clientuuid.length != 36)) return null; // Require a UUID if this exact length
 | |
| 
 | |
|     var obj = {};
 | |
|     obj.parent = parent;
 | |
|     obj.args = args;
 | |
|     obj.http = require('http');
 | |
|     obj.net = require('net');
 | |
|     obj.forwardClient = null;
 | |
|     obj.downlinks = {};
 | |
|     obj.pfwd_idx = 0;
 | |
|     obj.timer = null; // Keep alive timer
 | |
| 
 | |
|     // Function copied from common.js
 | |
|     function ReadInt(v, p) { return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); }; // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
 | |
|     function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
 | |
|     function hex2rstr(d) { var r = '', m = ('' + d).match(/../g), t; while (t = m.shift()) { r += String.fromCharCode('0x' + t); } return r; };
 | |
|     function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }; // Convert decimal to hex
 | |
|     function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }; // Convert a raw string to a hex string
 | |
|     function d2h(d) { return (d / 256 + 1 / 512).toString(16).substring(2, 4); }
 | |
|     function buf2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += d2h(input[i]); } return r; };
 | |
|     function Debug(str) { if (obj.parent.debug) { console.log(str); } }
 | |
|     function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
 | |
|     function strToGuid(s) { s = s.replace(/-/g, ''); var ret = s.substring(6, 8) + s.substring(4, 6) + s.substring(2, 4) + s.substring(0, 2) + s.substring(10, 12) + s.substring(8, 10) + s.substring(14, 16) + s.substring(12, 14) + s.substring(16, 20) + s.substring(20); return ret; }
 | |
|     function binzerostring(len) { var res = ''; for (var l = 0; l < len; l++) { res += String.fromCharCode(0 & 0xFF); } return res; }
 | |
| 
 | |
|     // CIRA state
 | |
|     var CIRASTATE = {
 | |
|         INITIAL: 0,
 | |
|         PROTOCOL_VERSION_SENT: 1,
 | |
|         AUTH_SERVICE_REQUEST_SENT: 2,
 | |
|         AUTH_REQUEST_SENT: 3,
 | |
|         PFWD_SERVICE_REQUEST_SENT: 4,
 | |
|         GLOBAL_REQUEST_SENT: 5,
 | |
|         FAILED: -1
 | |
|     }
 | |
|     obj.cirastate = CIRASTATE.INITIAL;
 | |
| 
 | |
|     // REDIR state
 | |
|     var REDIR_TYPE = {
 | |
|         REDIR_UNKNOWN: 0,
 | |
|         REDIR_SOL: 1,
 | |
|         REDIR_KVM: 2,
 | |
|         REDIR_IDER: 3
 | |
|     }
 | |
| 
 | |
|     // redirection start command
 | |
|     obj.RedirectStartSol = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x53, 0x4F, 0x4C, 0x20);
 | |
|     obj.RedirectStartKvm = String.fromCharCode(0x10, 0x01, 0x00, 0x00, 0x4b, 0x56, 0x4d, 0x52);
 | |
|     obj.RedirectStartIder = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x49, 0x44, 0x45, 0x52);
 | |
| 
 | |
|     // Intel AMT forwarded port list for non-TLS mode
 | |
|     //var pfwd_ports = [16992, 623, 16994, 5900];
 | |
|     var pfwd_ports = [ 16992, 16993 ];
 | |
| 
 | |
|     // protocol definitions
 | |
|     var APFProtocol = {
 | |
|         UNKNOWN: 0,
 | |
|         DISCONNECT: 1,
 | |
|         SERVICE_REQUEST: 5,
 | |
|         SERVICE_ACCEPT: 6,
 | |
|         USERAUTH_REQUEST: 50,
 | |
|         USERAUTH_FAILURE: 51,
 | |
|         USERAUTH_SUCCESS: 52,
 | |
|         GLOBAL_REQUEST: 80,
 | |
|         REQUEST_SUCCESS: 81,
 | |
|         REQUEST_FAILURE: 82,
 | |
|         CHANNEL_OPEN: 90,
 | |
|         CHANNEL_OPEN_CONFIRMATION: 91,
 | |
|         CHANNEL_OPEN_FAILURE: 92,
 | |
|         CHANNEL_WINDOW_ADJUST: 93,
 | |
|         CHANNEL_DATA: 94,
 | |
|         CHANNEL_CLOSE: 97,
 | |
|         PROTOCOLVERSION: 192,
 | |
|         KEEPALIVE_REQUEST: 208,
 | |
|         KEEPALIVE_REPLY: 209,
 | |
|         KEEPALIVE_OPTIONS_REQUEST: 210,
 | |
|         KEEPALIVE_OPTIONS_REPLY: 211,
 | |
|         JSON_CONTROL: 250 // This is a Mesh specific command that sends JSON to and from the MPS server.
 | |
|     }
 | |
| 
 | |
|     var APFDisconnectCode = {
 | |
|         HOST_NOT_ALLOWED_TO_CONNECT: 1,
 | |
|         PROTOCOL_ERROR: 2,
 | |
|         KEY_EXCHANGE_FAILED: 3,
 | |
|         RESERVED: 4,
 | |
|         MAC_ERROR: 5,
 | |
|         COMPRESSION_ERROR: 6,
 | |
|         SERVICE_NOT_AVAILABLE: 7,
 | |
|         PROTOCOL_VERSION_NOT_SUPPORTED: 8,
 | |
|         HOST_KEY_NOT_VERIFIABLE: 9,
 | |
|         CONNECTION_LOST: 10,
 | |
|         BY_APPLICATION: 11,
 | |
|         TOO_MANY_CONNECTIONS: 12,
 | |
|         AUTH_CANCELLED_BY_USER: 13,
 | |
|         NO_MORE_AUTH_METHODS_AVAILABLE: 14,
 | |
|         INVALID_CREDENTIALS: 15,
 | |
|         CONNECTION_TIMED_OUT: 16,
 | |
|         BY_POLICY: 17,
 | |
|         TEMPORARILY_UNAVAILABLE: 18
 | |
|     }
 | |
| 
 | |
|     var APFChannelOpenFailCodes = {
 | |
|         ADMINISTRATIVELY_PROHIBITED: 1,
 | |
|         CONNECT_FAILED: 2,
 | |
|         UNKNOWN_CHANNEL_TYPE: 3,
 | |
|         RESOURCE_SHORTAGE: 4,
 | |
|     }
 | |
| 
 | |
|     var APFChannelOpenFailureReasonCode = {
 | |
|         AdministrativelyProhibited: 1,
 | |
|         ConnectFailed: 2,
 | |
|         UnknownChannelType: 3,
 | |
|         ResourceShortage: 4,
 | |
|     }
 | |
| 
 | |
|     obj.onSecureConnect = function onSecureConnect(resp, ws, head) {
 | |
|         Debug("APF Secure WebSocket connected.");
 | |
|         //console.log(JSON.stringify(resp));                
 | |
|         obj.forwardClient.tag = { accumulator: [] };
 | |
|         obj.forwardClient.ws = ws;
 | |
|         obj.forwardClient.ws.on('end', function () {
 | |
|             Debug("APF: Connection is closing.");
 | |
|             if (obj.timer != null) {
 | |
|                 clearInterval(obj.timer);
 | |
|                 obj.timer = null;
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         obj.forwardClient.ws.on('data', function (data) {
 | |
|             obj.forwardClient.tag.accumulator += hex2rstr(buf2hex(data));
 | |
|             try {
 | |
|                 var len = 0;
 | |
|                 do {
 | |
|                     len = ProcessData(obj.forwardClient);
 | |
|                     if (len > 0) {
 | |
|                         obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len);
 | |
|                     }
 | |
|                     if (obj.cirastate == CIRASTATE.FAILED) {
 | |
|                         Debug("APF: in a failed state, destroying socket.")
 | |
|                         obj.forwardClient.ws.end();
 | |
|                     }
 | |
|                 } while (len > 0);
 | |
|             } catch (e) {
 | |
|                 Debug(e);
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         obj.forwardClient.ws.on('error', function (e) {
 | |
|             Debug("APF: Connection error, ending connecting.");
 | |
|             if (obj.timer != null) {
 | |
|                 clearInterval(obj.timer);
 | |
|                 obj.timer = null;
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         obj.state = CIRASTATE.INITIAL;
 | |
|         if ((typeof obj.args.conntype == 'number') && (obj.args.conntype != 0)) { SendJsonControl(obj.forwardClient.ws, { action: 'connType', value: obj.args.conntype } ); }
 | |
|         SendProtocolVersion(obj.forwardClient.ws, obj.args.clientuuid);
 | |
|         SendServiceRequest(obj.forwardClient.ws, 'auth@amt.intel.com');
 | |
|     }
 | |
| 
 | |
|     function SendJsonControl(socket, o) {
 | |
|         var data = JSON.stringify(o)
 | |
|         socket.write(String.fromCharCode(APFProtocol.JSON_CONTROL) + IntToStr(data.length) + data);
 | |
|         Debug("APF: Send JSON control: " + data);
 | |
|     }
 | |
| 
 | |
|     function SendProtocolVersion(socket, uuid) {
 | |
|         var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64);
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send protocol version 1 0 " + uuid);
 | |
|         obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
 | |
|     }
 | |
| 
 | |
|     function SendServiceRequest(socket, service) {
 | |
|         var data = String.fromCharCode(APFProtocol.SERVICE_REQUEST) + IntToStr(service.length) + service;
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send service request " + service);
 | |
|         if (service == 'auth@amt.intel.com') {
 | |
|             obj.cirastate = CIRASTATE.AUTH_SERVICE_REQUEST_SENT;
 | |
|         } else if (service == 'pfwd@amt.intel.com') {
 | |
|             obj.cirastate = CIRASTATE.PFWD_SERVICE_REQUEST_SENT;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     function SendUserAuthRequest(socket, user, pass) {
 | |
|         var service = "pfwd@amt.intel.com";
 | |
|         var data = String.fromCharCode(APFProtocol.USERAUTH_REQUEST) + IntToStr(user.length) + user + IntToStr(service.length) + service;
 | |
|         //password auth
 | |
|         data += IntToStr(8) + 'password';
 | |
|         data += binzerostring(1) + IntToStr(pass.length) + pass;
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send username password authentication to MPS");
 | |
|         obj.cirastate = CIRASTATE.AUTH_REQUEST_SENT;
 | |
|     }
 | |
| 
 | |
|     function SendGlobalRequestPfwd(socket, amthostname, amtport) {
 | |
|         var tcpipfwd = 'tcpip-forward';
 | |
|         var data = String.fromCharCode(APFProtocol.GLOBAL_REQUEST) + IntToStr(tcpipfwd.length) + tcpipfwd + binzerostring(1, 1);
 | |
|         data += IntToStr(amthostname.length) + amthostname + IntToStr(amtport);
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
 | |
|         obj.cirastate = CIRASTATE.GLOBAL_REQUEST_SENT;
 | |
|     }
 | |
| 
 | |
|     function SendKeepAliveRequest(socket) {
 | |
|         var data = String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255);
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send keepalive request");
 | |
|     }
 | |
| 
 | |
|     function SendKeepAliveReply(socket, cookie) {
 | |
|         var data = String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie);
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send keepalive reply");
 | |
|     }
 | |
| 
 | |
|     function ProcessData(socket) {
 | |
|         var cmd = socket.tag.accumulator.charCodeAt(0);
 | |
|         var len = socket.tag.accumulator.length;
 | |
|         var data = socket.tag.accumulator;
 | |
|         if (len == 0) { return 0; }
 | |
| 
 | |
|         // Respond to MPS according to obj.cirastate
 | |
|         switch (cmd) {
 | |
|             case APFProtocol.SERVICE_ACCEPT: {
 | |
|                 var slen = ReadInt(data, 1);
 | |
|                 var service = data.substring(5, 6 + slen);
 | |
|                 Debug("APF: Service request to " + service + " accepted.");
 | |
|                 if (service == 'auth@amt.intel.com') {
 | |
|                     if (obj.cirastate >= CIRASTATE.AUTH_SERVICE_REQUEST_SENT) {
 | |
|                         SendUserAuthRequest(socket.ws, obj.args.mpsuser, obj.args.mpspass);
 | |
|                     }
 | |
|                 } else if (service == 'pfwd@amt.intel.com') {
 | |
|                     if (obj.cirastate >= CIRASTATE.PFWD_SERVICE_REQUEST_SENT) {
 | |
|                         SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
 | |
|                     }
 | |
|                 }
 | |
|                 return 5 + slen;
 | |
|             }
 | |
|             case APFProtocol.REQUEST_SUCCESS: {
 | |
|                 if (len >= 5) {
 | |
|                     var port = ReadInt(data, 1);
 | |
|                     Debug("APF: Request to port forward " + port + " successful.");
 | |
|                     // iterate to pending port forward request
 | |
|                     if (obj.pfwd_idx < pfwd_ports.length) {
 | |
|                         SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
 | |
|                     } else {
 | |
|                         // no more port forward, now setup timer to send keep alive
 | |
|                         Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms.");
 | |
|                         obj.timer = setInterval(function () {
 | |
|                             SendKeepAliveRequest(obj.forwardClient.ws);
 | |
|                         }, obj.args.mpskeepalive);//
 | |
|                     }
 | |
|                     return 5;
 | |
|                 }
 | |
|                 Debug("APF: Request successful.");
 | |
|                 return 1;
 | |
|             }
 | |
|             case APFProtocol.USERAUTH_SUCCESS: {
 | |
|                 Debug("APF: User Authentication successful");
 | |
|                 // Send Pfwd service request
 | |
|                 SendServiceRequest(socket.ws, 'pfwd@amt.intel.com');
 | |
|                 return 1;
 | |
|             }
 | |
|             case APFProtocol.USERAUTH_FAILURE: {
 | |
|                 Debug("APF: User Authentication failed");
 | |
|                 obj.cirastate = CIRASTATE.FAILED;
 | |
|                 return 14;
 | |
|             }
 | |
|             case APFProtocol.KEEPALIVE_REQUEST: {
 | |
|                 Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1));
 | |
|                 SendKeepAliveReply(socket.ws, ReadInt(data, 1));
 | |
|                 return 5;
 | |
|             }
 | |
|             case APFProtocol.KEEPALIVE_REPLY: {
 | |
|                 Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1));
 | |
|                 return 5;
 | |
|             }
 | |
|             // Channel management
 | |
|             case APFProtocol.CHANNEL_OPEN: {
 | |
|                 // Parse CHANNEL OPEN request
 | |
|                 var p_res = parseChannelOpen(data);
 | |
|                 Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res));
 | |
|                 // Check if target port is in pfwd_ports
 | |
|                 if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
 | |
|                     // Connect socket to that port
 | |
|                     var chan = obj.net.createConnection({ host: obj.args.clientaddress, port: p_res.target_port }, function () {
 | |
|                         //require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "CHANNEL_OPEN-open" });
 | |
|                         // obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting
 | |
|                         SendChannelOpenConfirm(socket.ws, p_res);
 | |
|                     });
 | |
| 
 | |
|                     // Setup flow control
 | |
|                     chan.maxInWindow = p_res.window_size; // Oddly, we are using the same window size as the other side.
 | |
|                     chan.curInWindow = 0;
 | |
| 
 | |
|                     chan.on('data', function (ddata) {
 | |
|                         // Relay data to fordwardclient
 | |
|                         // TODO: Implement flow control
 | |
|                         SendChannelData(socket.ws, p_res.sender_chan, ddata.length, ddata);
 | |
|                     });
 | |
| 
 | |
|                     chan.on('error', function (e) {
 | |
|                         Debug("Downlink connection error: " + e);
 | |
|                     });
 | |
| 
 | |
|                     chan.on('end', function () {
 | |
|                         var chan = obj.downlinks[p_res.sender_chan];
 | |
|                         if (chan != null) {
 | |
|                             try {
 | |
|                                 Debug("Socket ends.");
 | |
|                                 SendChannelClose(socket.ws, p_res.sender_chan);
 | |
|                                 chan.xclosed = 1;
 | |
|                                 // Add some delay before removing... otherwise race condition
 | |
|                                 setTimeout(function () { delete obj.downlinks[p_res.sender_chan]; }, 100);
 | |
|                             } catch (e) {
 | |
|                                 Debug("Downlink connection exception: " + e);
 | |
|                             }
 | |
|                         }
 | |
|                     });
 | |
| 
 | |
|                     obj.downlinks[p_res.sender_chan] = chan;
 | |
|                 } else {
 | |
|                     // Not a supported port, fail the connection
 | |
|                     SendChannelOpenFailure(socket.ws, p_res);
 | |
|                 }
 | |
|                 return p_res.len;
 | |
|             }
 | |
|             case APFProtocol.CHANNEL_OPEN_CONFIRMATION: {
 | |
|                 Debug("APF: CHANNEL_OPEN_CONFIRMATION");
 | |
|                 return 17;
 | |
|             }
 | |
|             case APFProtocol.CHANNEL_CLOSE: {
 | |
|                 var rcpt_chan = ReadInt(data, 1);
 | |
|                 Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
 | |
|                 var chan = obj.downlinks[rcpt_chan];
 | |
|                 if ((chan != null) && (chan.xclosed !== 1)) {
 | |
|                     SendChannelClose(socket.ws, rcpt_chan);
 | |
|                     try { obj.downlinks[rcpt_chan].end(); } catch (e) { }
 | |
|                     delete obj.downlinks[rcpt_chan];
 | |
|                 }
 | |
|                 return 5;
 | |
|             }
 | |
|             case APFProtocol.CHANNEL_DATA: {
 | |
|                 Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data)));
 | |
|                 var rcpt_chan = ReadInt(data, 1);
 | |
|                 var chan_data_len = ReadInt(data, 5);
 | |
|                 var chan_data = data.substring(9, 9 + chan_data_len);
 | |
|                 var chan = obj.downlinks[rcpt_chan];
 | |
|                 if (chan != null) {
 | |
|                     chan.curInWindow += chan_data_len;
 | |
|                     try {
 | |
|                         chan.write(chan_data, 'binary', function () {
 | |
|                             Debug("Write completed.");
 | |
|                             // If the incoming window is over half used, send an adjust.
 | |
|                             if (this.curInWindow > (this.maxInWindow / 2)) { SendChannelWindowAdjust(socket.ws, rcpt_chan, this.curInWindow); this.curInWindow = 0; }
 | |
|                         });
 | |
|                     } catch (e) {
 | |
|                         Debug("Cannot forward data to downlink socket.");
 | |
|                     }
 | |
|                 }
 | |
|                 return 9 + chan_data_len;
 | |
|             }
 | |
|             case APFProtocol.CHANNEL_WINDOW_ADJUST: {
 | |
|                 Debug("APF: CHANNEL_WINDOW_ADJUST ");
 | |
|                 return 9;
 | |
|             }
 | |
|             default: {
 | |
|                 Debug("CMD: " + cmd + " is not implemented.");
 | |
|                 obj.cirastate = CIRASTATE.FAILED;
 | |
|                 return 0;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     function parseChannelOpen(data) {
 | |
|         var result = { cmd: APFProtocol.CHANNEL_OPEN };
 | |
|         var chan_type_slen = ReadInt(data, 1);
 | |
|         result.chan_type = data.substring(5, 5 + chan_type_slen);
 | |
|         result.sender_chan = ReadInt(data, 5 + chan_type_slen);
 | |
|         result.window_size = ReadInt(data, 9 + chan_type_slen);
 | |
|         var c_len = ReadInt(data, 17 + chan_type_slen);
 | |
|         result.target_address = data.substring(21 + chan_type_slen, 21 + chan_type_slen + c_len);
 | |
|         result.target_port = ReadInt(data, 21 + chan_type_slen + c_len);
 | |
|         var o_len = ReadInt(data, 25 + chan_type_slen + c_len);
 | |
|         result.origin_address = data.substring(29 + chan_type_slen + c_len, 29 + chan_type_slen + c_len + o_len);
 | |
|         result.origin_port = ReadInt(data, 29 + chan_type_slen + c_len + o_len);
 | |
|         result.len = 33 + chan_type_slen + c_len + o_len;
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     function SendChannelOpenFailure(socket, chan_data) {
 | |
|         var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan)
 | |
|             + IntToStr(2) + IntToStr(0) + IntToStr(0);
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send ChannelOpenFailure");
 | |
|     }
 | |
| 
 | |
|     function SendChannelOpenConfirm(socket, chan_data) {
 | |
|         var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + IntToStr(chan_data.sender_chan)
 | |
|             + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.window_size) + IntToStr(0xFFFFFFFF);
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send ChannelOpenConfirmation");
 | |
|     }
 | |
| 
 | |
|     function SendChannelWindowAdjust(socket, chan, size) {
 | |
|         var data = String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size);
 | |
|         socket.write(data);
 | |
|         Debug("APF: Send ChannelWindowAdjust: " + rstr2hex(data));
 | |
|     }
 | |
| 
 | |
|     function SendChannelData(socket, chan, len, data) {
 | |
|         var buf = String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(len) + data;
 | |
|         socket.write(buf);
 | |
|         Debug("APF: Send ChannelData: " + rstr2hex(buf));
 | |
|     }
 | |
| 
 | |
|     function SendChannelClose(socket, chan) {
 | |
|         var buf = String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan);
 | |
|         socket.write(buf);
 | |
|         Debug("APF: Send ChannelClose ");
 | |
|     }
 | |
| 
 | |
|     obj.connect = function () {
 | |
|         if (obj.forwardClient != null) {
 | |
|             try {
 | |
|                 obj.forwardClient.ws.end();
 | |
|             } catch (e) {
 | |
|                 Debug(e);
 | |
|             }
 | |
|             //obj.forwardClient = null;
 | |
|         }
 | |
|         obj.cirastate = CIRASTATE.INITIAL;
 | |
|         obj.pfwd_idx = 0;
 | |
| 
 | |
|         //obj.forwardClient = new obj.ws(obj.args.mpsurl, obj.tlsoptions);
 | |
|         //obj.forwardClient.on("open", obj.onSecureConnect);
 | |
| 
 | |
|         var wsoptions = obj.http.parseUri(obj.args.mpsurl);
 | |
|         wsoptions.rejectUnauthorized = 0;
 | |
|         obj.forwardClient = obj.http.request(wsoptions);
 | |
|         obj.forwardClient.upgrade = obj.onSecureConnect;
 | |
|         obj.forwardClient.end(); // end request, trigger completion of HTTP request
 | |
|     }
 | |
| 
 | |
|     obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (e) { Debug(e); } }
 | |
| 
 | |
|     return obj;
 | |
| }
 | |
| 
 | |
| module.exports = CreateAPFClient; 
 |