domotz-remote-pawn
Version:
Domotz Agent
190 lines (172 loc) • 5.55 kB
JavaScript
"use strict";
var util = require ("util");
var packets = require ("../packets");
var opcodes = require ("../opcodes");
var errors = require ("../errors");
var Request = require ("../request");
var knownExtensions = require ("../known-extensions");
var IncomingRequest = module.exports = function (args){
Request.call (this, args.helper._rinfo.address, args.helper._rinfo.port,
args.globalOptions.retries, args.globalOptions.extensions.timeout);
this._isRRQ = !args.reader;
this._globalOptions = args.globalOptions;
this._maxDataLength = 4;
this._file = args.message.file;
this._size = args.size || null;
this._requestUserExtensions = args.message.userExtensions;
this._responseUserExtensions = null;
this._oackSent = false;
this._firstPacket = true;
this._requestExtensions = args.message.extensions;
this._responseExtensions = null;
var me = this;
this._initSocket (args.helper._socket, function (message){
if (me._firstPacket){
me._firstPacket = false;
me._requestTimer.reset ();
}
me._onMessage (message);
});
//The socket is still not bound to an address and port because no packet has
//been still sent, so the stats cannot be emitted yet (the call to address()
//fails)
//The socket must be manually bound
this._socket.bind (0, null, function (){
if (me._requestExtensions === null){
//The client doesn't send extensions, it's probably that it doesn't
//rollover automatically (old client), so we can abort the transfer
//prematurely
//Check the size (65535x512)
if (me._isRRQ && me._size > 33553920){
return me._sendErrorAndClose (errors.EFBIG);
}
me._onReady (me._createStats (512, 1), 0);
if (!me._isRRQ){
//The ACK of the block 0 is retransmitted from the reader
me._sendAck (0);
}
}else{
//Send OACK
me._sendOackMessage (me._requestExtensions);
}
});
};
util.inherits (IncomingRequest, Request);
IncomingRequest.prototype.continueRequest = function (size){
this._setSize (size);
if (this._requestExtensions === null){
this.onContinue ();
}else{
if( this._responseExtensions.tsize !== undefined){
this._responseExtensions.tsize = size;
}
//Set the user extensions
for (var p in this._responseUserExtensions){
//Ignore invalid extensions
if (knownExtensions[p]) continue;
if (this._requestUserExtensions[p] === undefined) continue;
this._responseExtensions[p] = this._responseUserExtensions[p];
}
this._sendAndRetransmit (packets.oack.serialize (this._responseExtensions));
}
};
IncomingRequest.prototype._createStats = function (blockSize, windowSize){
//Save max data length
this._maxDataLength += blockSize;
var address = this._socket.address ();
return {
blockSize: blockSize,
windowSize: windowSize,
size: this._size,
userExtensions: this._requestUserExtensions,
retries: this._globalOptions.retries,
timeout: this._timeout,
localAddress: address.address,
localPort: address.port,
remoteAddress: this._address,
remotePort: this._port,
};
};
IncomingRequest.prototype._onMessage = function (buffer){
var op = buffer.readUInt16BE (0);
if (op === opcodes.DATA){
if (!this._isRRQ){
if (buffer.length < 4 || buffer.length > this._maxDataLength){
return this._sendErrorAndClose (errors.EBADMSG);
}
try{
this._onData (packets.data.deserialize (buffer));
}catch (error){
this._sendErrorAndClose (error);
}
}else{
this._sendErrorAndClose (errors.EBADOP);
}
}else if (op === opcodes.ACK){
if (this._isRRQ){
if (buffer.length !== 4){
return this._sendErrorAndClose (errors.EBADMSG);
}
if (this._oackSent){
this._oackSent = false;
if (buffer.readUInt16BE (2) !== 0){
this._sendErrorAndClose (errors.EBADMSG);
}else{
this.onContinue ();
}
}else{
try{
this._onAck (packets.ack.deserialize (buffer));
}catch (error){
this._sendErrorAndClose (error);
}
}
}else{
this._sendErrorAndClose (errors.EBADOP);
}
}else if (op === opcodes.ERROR){
if (buffer.length < 4) return this._closeWithError (errors.EBADMSG);
try{
this._close (new Error (packets.error.deserialize (buffer).message));
}catch (error){
return this._closeWithError (error);
}
}else{
this._sendErrorAndClose (errors.EBADOP);
}
};
IncomingRequest.prototype._sendOackMessage = function (extensions){
var ext = {};
if (extensions.blksize !== undefined){
var blksize = this._globalOptions.extensions.blksize;
ext.blksize = extensions.blksize > blksize ? blksize : extensions.blksize;
}
if (extensions.windowsize !== undefined){
var windowsize = this._globalOptions.extensions.windowsize;
ext.windowsize = extensions.windowsize > windowsize
? windowsize
: extensions.windowsize;
}
if (extensions.tsize !== undefined){
if (!this._isRRQ) this._size = extensions.tsize;
ext.tsize = extensions.tsize;
//ext.tsize is set later, when the request continues (RRQ)
}
if (extensions.rollover !== undefined){
ext.rollover = 0;
}
this._oackSent = true;
var me = this;
var ready = function (){
me._onReady (me._createStats (ext.blksize || 512, ext.windowsize || 1),
0, true);
};
if (this._isRRQ){
//Save the extensions
this._responseExtensions = ext;
ready ();
}else{
ready ();
this._sendAndRetransmit (packets.oack.serialize (ext));
}
};