Skip to content

Commit

Permalink
add fastpath support + unicode input
Browse files Browse the repository at this point in the history
  • Loading branch information
citronneur committed Jun 30, 2015
1 parent 0bbdb27 commit 866f630
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 20 deletions.
79 changes: 72 additions & 7 deletions lib/protocol/pdu/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -908,19 +908,20 @@ function updateDataPDU(updateData, opt) {
return self.updateData.obj.__UPDATE_TYPE__;
}),
updateData : updateData || new type.Factory(function(s) {
var readLength = new type.CallableValue(function() {
var options = { readLength : new type.CallableValue(function() {
return opt.readLength.value - 2;
});
})};
switch(self.updateType.value) {
case UpdateType.UPDATETYPE_BITMAP:
self.updateData = bitmapUpdateDataPDU(null, { readLength : readLength }).read(s);
self.updateData = bitmapUpdateDataPDU(null, options).read(s);
break;
case UpdateType.UPDATETYPE_SYNCHRONIZE:
// do nothing artefact of protocol
self.updateData = synchronizeUpdateDataPDU(null, { readLength : readLength }).read(s);
self.updateData = synchronizeUpdateDataPDU(null, options).read(s);
break;
default:
log.error('unknown updateDataPDU ' + self.updateType.value);
self.updateData = new type.BinaryString(null, options).read(s);
log.debug('unknown updateDataPDU ' + self.updateType.value);
}
})
};
Expand Down Expand Up @@ -987,6 +988,7 @@ function dataPDU(pduData, shareId, opt) {
self.pduData = updateDataPDU(null, options).read(s);
break;
default:
self.pduData = new type.BinaryString(null, options).read(s);
log.debug('unknown PDUType2 ' + self.shareDataHeader.obj.pduType2.value);
}
})
Expand Down Expand Up @@ -1029,7 +1031,67 @@ function pdu(userId, pduMessage, opt) {
self.pduMessage = dataPDU(null, null, options).read(s);
break;
default:
log.error('unknown pdu type ' + self.shareControlHeader.obj.pduType.value);
self.pduMessage = new type.BinaryString(null, options).read(s);
log.debug('unknown pdu type ' + self.shareControlHeader.obj.pduType.value);
}
})
};

return new type.Component(self, opt);
}

/**
* @see http://msdn.microsoft.com/en-us/library/dd306368.aspx
* @param opt {object} type option
* @returns {type.Component}
*/
function fastPathBitmapUpdateDataPDU (opt) {
var self = {
__FASTPATH_UPDATE_TYPE__ : FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP,
header : new type.UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, { constant : true }),
numberRectangles : new type.UInt16Le( function () {
return self.rectangles.obj.length;
}),
rectangles : new type.Factory( function (s) {
self.rectangles = new type.Component([]);
for(var i = 0; i < self.numberRectangles.value; i++) {
self.rectangles.obj.push(bitmapData().read(s));
}
})
};

return new type.Component(self, opt);
}

/**
* @see http://msdn.microsoft.com/en-us/library/cc240622.aspx
* @param updateData {type.Component}
* @param opt {object} type option
* @returns {type.Component}
*/
function fastPathUpdatePDU (updateData, opt) {
var self = {
updateHeader : new type.UInt8( function () {
return self.updateData.obj.__FASTPATH_UPDATE_TYPE__;
}),
compressionFlags : new type.UInt8(null, { conditional : function () {
return (self.updateHeader.value >> 4) & FastPathOutputCompression.FASTPATH_OUTPUT_COMPRESSION_USED;
}}),
size : new type.UInt16Le( function () {
return self.updateData.size();
}),
updateData : updateData || new type.Factory( function (s) {
var options = { readLength : new type.CallableValue( function () {
return self.size.value;
}) };

switch (self.updateHeader.value & 0xf) {
case FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
self.updateData = fastPathBitmapUpdateDataPDU(options).read(s);
break;
default:
self.updateData = new type.BinaryString(null, options).read(s);
log.debug('unknown fast path pdu type ' + (self.updateHeader.value & 0xf));
}
})
};
Expand Down Expand Up @@ -1057,6 +1119,7 @@ module.exports = {
Display : Display,
ToogleFlag : ToogleFlag,
ErrorInfo : ErrorInfo,
FastPathUpdateType : FastPathUpdateType,
shareControlHeader : shareControlHeader,
shareDataHeader : shareDataHeader,
demandActivePDU : demandActivePDU,
Expand All @@ -1082,5 +1145,7 @@ module.exports = {
bitmapData : bitmapData,
bitmapUpdateDataPDU : bitmapUpdateDataPDU,
updateDataPDU : updateDataPDU,
dataPDU : dataPDU
dataPDU : dataPDU,
fastPathBitmapUpdateDataPDU : fastPathBitmapUpdateDataPDU,
fastPathUpdatePDU : fastPathUpdatePDU
};
37 changes: 33 additions & 4 deletions lib/protocol/pdu/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ var events = require('events');
var caps = require('./caps');
var data = require('./data');
var type = require('../../core').type;
var log = require('../../core').log;

/**
* Global channel for all graphic updates
* capabilities exchange and input handles
*/
function Global(transport) {
function Global(transport, fastPathTransport) {
this.transport = transport;
this.fastPathTransport = fastPathTransport;
// must be init via connect event
this.userId = 0;
this.serverCapabilities = [];
Expand Down Expand Up @@ -58,8 +60,8 @@ Global.prototype.sendDataPDU = function(message) {
* Client side of Global channel automata
* @param transport
*/
function Client(transport) {
Global.call(this, transport);
function Client(transport, fastPathTransport) {
Global.call(this, transport, fastPathTransport);
var self = this;
this.transport.once('connect', function(core, userId, channelId) {
self.connect(core, userId, channelId);
Expand All @@ -69,6 +71,12 @@ function Client(transport) {
self.emit('error', err);
});

if (this.fastPathTransport) {
this.fastPathTransport.on('fastPathData', function (secFlag, s) {
self.recvFastPath(secFlag, s);
});
}

// init client capabilities
this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL] = caps.generalCapability();
this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP] = caps.bitmapCapability();
Expand Down Expand Up @@ -253,6 +261,23 @@ Client.prototype.recvServerFontMapPDU = function(s) {
});
};

/**
* Main reveive fast path
* @param secFlag {integer}
* @param s {type.Stream}
*/
Client.prototype.recvFastPath = function (secFlag, s) {
while (s.availableLength() > 0) {
var pdu = data.fastPathUpdatePDU().read(s);
switch (pdu.obj.updateHeader.value & 0xf) {
case data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
this.emit('bitmap', pdu.obj.updateData.obj.rectangles.obj);
break;
default:
}
}
};

/**
* global channel automata state
* @param s {type.Stream}
Expand Down Expand Up @@ -297,6 +322,10 @@ Client.prototype.readDataPDU = function (dataPDU) {
}
};

/**
* Main upadate pdu receive function
* @param updateDataPDU
*/
Client.prototype.readUpdateDataPDU = function (updateDataPDU) {
switch(updateDataPDU.obj.updateType.value) {
case data.UpdateType.UPDATETYPE_BITMAP:
Expand All @@ -315,7 +344,7 @@ Client.prototype.sendConfirmActivePDU = function () {
generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED
| caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR
| caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM
/*| caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED*/;
| caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED;

var bitmapCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].obj;
bitmapCapability.preferredBitsPerPixel.value = this.gccCore.highColorDepth.value;
Expand Down
23 changes: 20 additions & 3 deletions lib/protocol/pdu/sec.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,9 @@ function securityHeader() {
* Security layer
* @param transport {events.EventEmitter}
*/
function Sec(transport) {
function Sec(transport, fastPathTransport) {
this.transport = transport;
this.fastPathTransport = fastPathTransport;
// init at connect event from transport layer
this.gccClient = null;
this.gccServer = null;
Expand All @@ -286,6 +287,12 @@ function Sec(transport) {

// basic encryption
this.enableEncryption = false;

if (this.fastPathTransport) {
this.fastPathTransport.on('fastPathData', function (secFlag, s) {
self.recvFastPath(secFlag, s);
});
}
};

//inherit from Layer
Expand Down Expand Up @@ -327,12 +334,22 @@ Sec.prototype.recv = function(s) {
this.emit('data', s);
};

/**
* Receive fast path data
* @param secFlag {integer} security flag
* @param s {type.Stream}
*/
Sec.prototype.recvFastPath = function (secFlag, s) {
// transparent because basic RDP security layer not implemented
this.emit('fastPathData', secFlag, s);
};

/**
* Client security layer
* @param transport {events.EventEmitter}
*/
function Client(transport) {
Sec.call(this, transport);
function Client(transport, fastPathTransport) {
Sec.call(this, transport, fastPathTransport);
// for basic RDP layer (in futur)
this.enableSecureCheckSum = false;
var self = this;
Expand Down
19 changes: 17 additions & 2 deletions lib/protocol/rdp.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ function RdpClient(config) {
this.tpkt = new TPKT(this.bufferLayer);
this.x224 = new x224.Client(this.tpkt);
this.mcs = new t125.mcs.Client(this.x224);
this.sec = new pdu.sec.Client(this.mcs);
this.global = new pdu.global.Client(this.sec);
this.sec = new pdu.sec.Client(this.mcs, this.tpkt);
this.global = new pdu.global.Client(this.sec, this.sec);

// credentials
if (config.domain) {
Expand Down Expand Up @@ -193,6 +193,21 @@ RdpClient.prototype.sendKeyEventScancode = function (code, isPressed, extended)
this.global.sendInputEvents([event]);
};

/**
* Send key event as unicode
* @param code {integer}
* @param isPressed {boolean}
*/
RdpClient.prototype.sendKeyEventUnicode = function (code, isPressed) {
var event = pdu.data.unicodeKeyEvent();
event.obj.unicode.value = code;

if (!isPressed) {
event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
}
this.global.sendInputEvents([event]);
}

function createClient(config) {
return new RdpClient(config);
};
Expand Down
51 changes: 47 additions & 4 deletions lib/protocol/tpkt.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,31 @@ inherits(TPKT, events.EventEmitter);
* @param s {type.Stream}
*/
TPKT.prototype.recvHeader = function(s) {
var version = new type.UInt8().read(s);
if(version.value === Action.FASTPATH_ACTION_X224) {
var version = new type.UInt8().read(s).value;
var self = this;
if(version === Action.FASTPATH_ACTION_X224) {
new type.UInt8().read(s);
var self = this;

this.transport.expect(2);
this.transport.once('data', function(s) {
self.recvExtendedHeader(s);
});
}
else {

this.secFlag = ((version >> 6) & 0x3);
var length = new type.UInt8().read(s).value;
if (length & 0x80) {
this.transport.expect(1);
this.transport.once('data', function(s) {
self.recvExtendedFastPathHeader(s, length);
});
}
else {
this.transport.expect(length - 2);
this.transport.once('data', function(s) {
self.recvFastPath(s);
});
}
}
};

Expand Down Expand Up @@ -102,6 +116,35 @@ TPKT.prototype.recvData = function(s) {
});
};

/**
* Read extended fastpath header
* @param s {type.Stream}
*/
TPKT.prototype.recvExtendedFastPathHeader = function (s, length) {
var rightPart = new type.UInt8().read(s).value;
var leftPart = length & ~0x80;
var packetSize = (leftPart << 8) + rightPart;

var self = this;
this.transport.expect(packetSize - 3);
this.transport.once('data', function(s) {
self.recvFastPath(s);
});
};

/**
* Read fast path data
* @param s {type.Stream}
*/
TPKT.prototype.recvFastPath = function (s) {
this.emit('fastPathData', this.secFlag, s);
var self = this;
this.transport.expect(2);
this.transport.once('data', function(s) {
self.recvHeader(s);
});
};

/**
* Send message throught TPKT layer
* @param message {type.*}
Expand Down

0 comments on commit 866f630

Please sign in to comment.