global.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * Copyright (c) 2014-2015 Sylvain Peyrefitte
  3. *
  4. * This file is part of node-rdpjs.
  5. *
  6. * node-rdpjs is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. var inherits = require('util').inherits;
  20. var events = require('events');
  21. var caps = require('./caps');
  22. var data = require('./data');
  23. var type = require('../../core').type;
  24. var log = require('../../core').log;
  25. /**
  26. * Global channel for all graphic updates
  27. * capabilities exchange and input handles
  28. */
  29. function Global(transport, fastPathTransport) {
  30. this.transport = transport;
  31. this.fastPathTransport = fastPathTransport;
  32. // must be init via connect event
  33. this.userId = 0;
  34. this.serverCapabilities = [];
  35. this.clientCapabilities = [];
  36. }
  37. //inherit from Layer
  38. inherits(Global, events.EventEmitter);
  39. /**
  40. * Send formated PDU message
  41. * @param message {type.Component} PDU message
  42. */
  43. Global.prototype.sendPDU = function(message) {
  44. this.transport.send(data.pdu(this.userId, message));
  45. };
  46. /**
  47. * Send formated Data PDU message
  48. * @param message {type.Component} PDU message
  49. */
  50. Global.prototype.sendDataPDU = function(message) {
  51. this.sendPDU(data.dataPDU(message, this.shareId));
  52. };
  53. /**
  54. * Client side of Global channel automata
  55. * @param transport
  56. */
  57. function Client(transport, fastPathTransport) {
  58. Global.call(this, transport, fastPathTransport);
  59. var self = this;
  60. this.transport.once('connect', function(core, userId, channelId) {
  61. self.connect(core, userId, channelId);
  62. }).on('close', function() {
  63. self.emit('close');
  64. }).on('error', function (err) {
  65. self.emit('error', err);
  66. });
  67. if (this.fastPathTransport) {
  68. this.fastPathTransport.on('fastPathData', function (secFlag, s) {
  69. self.recvFastPath(secFlag, s);
  70. });
  71. }
  72. // init client capabilities
  73. this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL] = caps.generalCapability();
  74. this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP] = caps.bitmapCapability();
  75. this.clientCapabilities[caps.CapsType.CAPSTYPE_ORDER] = caps.orderCapability(
  76. new type.Component([
  77. new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
  78. new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
  79. new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
  80. new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0)
  81. ]));
  82. this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAPCACHE] = caps.bitmapCacheCapability();
  83. this.clientCapabilities[caps.CapsType.CAPSTYPE_POINTER] = caps.pointerCapability();
  84. this.clientCapabilities[caps.CapsType.CAPSTYPE_INPUT] = caps.inputCapability();
  85. this.clientCapabilities[caps.CapsType.CAPSTYPE_BRUSH] = caps.brushCapability();
  86. this.clientCapabilities[caps.CapsType.CAPSTYPE_GLYPHCACHE] = caps.glyphCapability(
  87. new type.Component([
  88. caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(),
  89. caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry()
  90. ]));
  91. this.clientCapabilities[caps.CapsType.CAPSTYPE_OFFSCREENCACHE] = caps.offscreenBitmapCacheCapability();
  92. this.clientCapabilities[caps.CapsType.CAPSTYPE_VIRTUALCHANNEL] = caps.virtualChannelCapability();
  93. this.clientCapabilities[caps.CapsType.CAPSTYPE_SOUND] = caps.soundCapability();
  94. this.clientCapabilities[caps.CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE] = caps.multiFragmentUpdate();
  95. }
  96. // inherit from Layer
  97. inherits(Client, Global);
  98. /**
  99. * connect function
  100. * @param gccCore {type.Component(clientCoreData)}
  101. */
  102. Client.prototype.connect = function(gccCore, userId, channelId) {
  103. this.gccCore = gccCore;
  104. this.userId = userId;
  105. this.channelId = channelId;
  106. var self = this;
  107. this.transport.once('data', function(s) {
  108. self.recvDemandActivePDU(s);
  109. });
  110. };
  111. /**
  112. * close stack
  113. */
  114. Client.prototype.close = function() {
  115. this.transport.close();
  116. };
  117. /**
  118. * Receive capabilities from server
  119. * @param s {type.Stream}
  120. */
  121. Client.prototype.recvDemandActivePDU = function(s) {
  122. var pdu = data.pdu().read(s);
  123. if (pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DEMANDACTIVEPDU) {
  124. log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
  125. // loop on state
  126. var self = this;
  127. this.transport.once('data', function(s) {
  128. self.recvDemandActivePDU(s);
  129. });
  130. return;
  131. }
  132. // store share id
  133. this.shareId = pdu.obj.pduMessage.obj.shareId.value;
  134. // store server capabilities
  135. for(var i in pdu.obj.pduMessage.obj.capabilitySets.obj) {
  136. var cap = pdu.obj.pduMessage.obj.capabilitySets.obj[i].obj.capability;
  137. if(!cap.obj) {
  138. continue;
  139. }
  140. this.serverCapabilities[cap.obj.__TYPE__] = cap;
  141. }
  142. this.transport.enableSecureCheckSum = !!(this.serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].obj.extraFlags.value & caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM);
  143. this.sendConfirmActivePDU();
  144. this.sendClientFinalizeSynchronizePDU();
  145. var self = this;
  146. this.transport.once('data', function(s) {
  147. self.recvServerSynchronizePDU(s);
  148. });
  149. };
  150. /**
  151. * global channel automata state
  152. * @param s {type.Stream}
  153. */
  154. Client.prototype.recvServerSynchronizePDU = function(s) {
  155. var pdu = data.pdu().read(s);
  156. if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
  157. || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_SYNCHRONIZE) {
  158. log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
  159. // loop on state
  160. var self = this;
  161. this.transport.once('data', function(s) {
  162. self.recvServerSynchronizePDU(s);
  163. });
  164. return;
  165. }
  166. var self = this;
  167. this.transport.once('data', function(s) {
  168. self.recvServerControlCooperatePDU(s);
  169. });
  170. };
  171. /**
  172. * global channel automata state
  173. * @param s {type.Stream}
  174. */
  175. Client.prototype.recvServerControlCooperatePDU = function(s) {
  176. var pdu = data.pdu().read(s);
  177. if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
  178. || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_CONTROL
  179. || pdu.obj.pduMessage.obj.pduData.obj.action.value !== data.Action.CTRLACTION_COOPERATE) {
  180. log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
  181. // loop on state
  182. var self = this;
  183. this.transport.once('data', function(s) {
  184. self.recvServerControlCooperatePDU(s);
  185. });
  186. }
  187. var self = this;
  188. this.transport.once('data', function(s) {
  189. self.recvServerControlGrantedPDU(s);
  190. });
  191. };
  192. /**
  193. * global channel automata state
  194. * @param s {type.Stream}
  195. */
  196. Client.prototype.recvServerControlGrantedPDU = function(s) {
  197. var pdu = data.pdu().read(s);
  198. if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
  199. || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_CONTROL
  200. || pdu.obj.pduMessage.obj.pduData.obj.action.value !== data.Action.CTRLACTION_GRANTED_CONTROL) {
  201. log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
  202. // loop on state
  203. var self = this;
  204. this.transport.once('data', function(s) {
  205. self.recvServerControlGrantedPDU(s);
  206. });
  207. }
  208. var self = this;
  209. this.transport.once('data', function(s) {
  210. self.recvServerFontMapPDU(s);
  211. });
  212. };
  213. /**
  214. * global channel automata state
  215. * @param s {type.Stream}
  216. */
  217. Client.prototype.recvServerFontMapPDU = function(s) {
  218. var pdu = data.pdu().read(s);
  219. if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
  220. || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_FONTMAP) {
  221. log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
  222. // loop on state
  223. var self = this;
  224. this.transport.once('data', function(s) {
  225. self.recvServerFontMapPDU(s);
  226. });
  227. }
  228. this.emit('connect');
  229. var self = this;
  230. this.transport.on('data', function(s) {
  231. self.recvPDU(s);
  232. });
  233. };
  234. /**
  235. * Main reveive fast path
  236. * @param secFlag {integer}
  237. * @param s {type.Stream}
  238. */
  239. Client.prototype.recvFastPath = function (secFlag, s) {
  240. while (s.availableLength() > 0) {
  241. var pdu = data.fastPathUpdatePDU().read(s);
  242. switch (pdu.obj.updateHeader.value & 0xf) {
  243. case data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP: {
  244. this.emit('bitmap', pdu.obj.updateData.obj.rectangles.obj);
  245. break;
  246. }
  247. case data.FastPathUpdateType.FASTPATH_UPDATETYPE_COLOR: {
  248. this.emit('pointer', pdu.obj.updateData.obj.cursorId, pdu.obj.updateData.obj.cursorStr);
  249. break;
  250. }
  251. default:
  252. }
  253. }
  254. };
  255. /**
  256. * global channel automata state
  257. * @param s {type.Stream}
  258. */
  259. Client.prototype.recvPDU = function(s) {
  260. while (s.availableLength() > 0) {
  261. var pdu = data.pdu().read(s);
  262. switch(pdu.obj.shareControlHeader.obj.pduType.value) {
  263. case data.PDUType.PDUTYPE_DEACTIVATEALLPDU:
  264. var self = this;
  265. this.transport.removeAllListeners('data');
  266. this.transport.once('data', function(s) {
  267. self.recvDemandActivePDU(s);
  268. });
  269. break;
  270. case data.PDUType.PDUTYPE_DATAPDU:
  271. this.readDataPDU(pdu.obj.pduMessage)
  272. break;
  273. default:
  274. log.debug('ignore pdu type ' + pdu.obj.shareControlHeader.obj.pduType.value);
  275. }
  276. }
  277. };
  278. /**
  279. * main receive for data PDU packet
  280. * @param dataPDU {data.dataPDU}
  281. */
  282. Client.prototype.readDataPDU = function (dataPDU) {
  283. switch(dataPDU.obj.shareDataHeader.obj.pduType2.value) {
  284. case data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU:
  285. break;
  286. case data.PDUType2.PDUTYPE2_SHUTDOWN_DENIED:
  287. this.transport.close();
  288. break;
  289. case data.PDUType2.PDUTYPE2_SAVE_SESSION_INFO:
  290. this.emit('session');
  291. break;
  292. case data.PDUType2.PDUTYPE2_UPDATE:
  293. this.readUpdateDataPDU(dataPDU.obj.pduData)
  294. break;
  295. }
  296. };
  297. /**
  298. * Main upadate pdu receive function
  299. * @param updateDataPDU
  300. */
  301. Client.prototype.readUpdateDataPDU = function (updateDataPDU) {
  302. switch(updateDataPDU.obj.updateType.value) {
  303. case data.UpdateType.UPDATETYPE_BITMAP:
  304. this.emit('bitmap', updateDataPDU.obj.updateData.obj.rectangles.obj)
  305. break;
  306. }
  307. };
  308. /**
  309. * send all client capabilities
  310. */
  311. Client.prototype.sendConfirmActivePDU = function () {
  312. var generalCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].obj;
  313. generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS;
  314. generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT;
  315. generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED
  316. | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR
  317. | caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM
  318. | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED;
  319. var bitmapCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].obj;
  320. bitmapCapability.preferredBitsPerPixel.value = this.gccCore.highColorDepth.value;
  321. bitmapCapability.desktopWidth.value = this.gccCore.desktopWidth.value;
  322. bitmapCapability.desktopHeight.value = this.gccCore.desktopHeight.value;
  323. var orderCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_ORDER].obj;
  324. orderCapability.orderFlags.value |= caps.OrderFlag.ZEROBOUNDSDELTASSUPPORT;
  325. var inputCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_INPUT].obj;
  326. inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX | caps.InputFlags.INPUT_FLAG_UNICODE;
  327. inputCapability.keyboardLayout = this.gccCore.kbdLayout;
  328. inputCapability.keyboardType = this.gccCore.keyboardType;
  329. inputCapability.keyboardSubType = this.gccCore.keyboardSubType;
  330. inputCapability.keyboardrFunctionKey = this.gccCore.keyboardFnKeys;
  331. inputCapability.imeFileName = this.gccCore.imeFileName;
  332. var capabilities = new type.Component([]);
  333. for(var i in this.clientCapabilities) {
  334. capabilities.obj.push(caps.capability(this.clientCapabilities[i]));
  335. }
  336. var confirmActivePDU = data.confirmActivePDU(capabilities, this.shareId);
  337. this.sendPDU(confirmActivePDU);
  338. };
  339. /**
  340. * send synchronize PDU
  341. */
  342. Client.prototype.sendClientFinalizeSynchronizePDU = function() {
  343. this.sendDataPDU(data.synchronizeDataPDU(this.channelId));
  344. this.sendDataPDU(data.controlDataPDU(data.Action.CTRLACTION_COOPERATE));
  345. this.sendDataPDU(data.controlDataPDU(data.Action.CTRLACTION_REQUEST_CONTROL));
  346. this.sendDataPDU(data.fontListDataPDU());
  347. };
  348. /**
  349. * Send input event as slow path input
  350. * @param inputEvents {array}
  351. */
  352. Client.prototype.sendInputEvents = function (inputEvents) {
  353. var pdu = data.clientInputEventPDU(new type.Component(inputEvents.map(function (e) {
  354. return data.slowPathInputEvent(e);
  355. })));
  356. this.sendDataPDU(pdu);
  357. };
  358. /**
  359. * Module exports
  360. */
  361. module.exports = {
  362. Client : Client
  363. };