diff --git a/aedes.js b/aedes.js index c02d2898..fd4f9b72 100644 --- a/aedes.js +++ b/aedes.js @@ -29,7 +29,8 @@ const defaultOptions = { trustProxy: false, trustedProxies: [], queueLimit: 42, - maxClientsIdLength: 23 + maxClientsIdLength: 23, + keepaliveLimit: 0 } function Aedes (opts) { @@ -47,6 +48,7 @@ function Aedes (opts) { this.counter = 0 this.queueLimit = opts.queueLimit this.connectTimeout = opts.connectTimeout + this.keepaliveLimit = opts.keepaliveLimit this.maxClientsIdLength = opts.maxClientsIdLength this.mq = opts.mq || mqemitter({ concurrency: opts.concurrency, diff --git a/docs/Aedes.md b/docs/Aedes.md index 67f15e7c..46bc4dc0 100644 --- a/docs/Aedes.md +++ b/docs/Aedes.md @@ -42,6 +42,7 @@ - `heartbeatInterval` `` an interval in millisconds at which server beats its health signal in `$SYS//heartbeat` topic. __Default__: `60000` - `id` `` aedes broker unique identifier. __Default__: `uuidv4()` - `connectTimeout` `` maximum waiting time in milliseconds waiting for a [`CONNECT`][CONNECT] packet. __Default__: `30000` + - `keepaliveLimit` `` maximum client keep alive time allowed, 0 means no limit. __Default__: `0` - Returns `` Create a new Aedes server. diff --git a/lib/handlers/connect.js b/lib/handlers/connect.js index a4c32d05..6e27e6ad 100644 --- a/lib/handlers/connect.js +++ b/lib/handlers/connect.js @@ -36,7 +36,8 @@ const errorMessages = [ 'identifier rejected', 'Server unavailable', 'bad user name or password', - 'not authorized' + 'not authorized', + 'keep alive limit exceeded' ] function handleConnect (client, packet, done) { @@ -66,9 +67,14 @@ function init (client, packet, done) { if (packet.protocolVersion === 3 && clientId.length > client.broker.maxClientsIdLength) { returnCode = 2 } + // check if the client keepalive is compatible with broker settings + if (client.broker.keepaliveLimit && (!packet.keepalive || packet.keepalive > client.broker.keepaliveLimit)) { + returnCode = 6 + } if (returnCode > 0) { const error = new Error(errorMessages[returnCode]) error.errorCode = returnCode + console.error(error) doConnack( { client, returnCode, sessionPresent: false }, done.bind(this, error)) diff --git a/test/connect.js b/test/connect.js index d1607386..fb6de7f9 100644 --- a/test/connect.js +++ b/test/connect.js @@ -97,6 +97,40 @@ test('reject client requested for unsupported protocol version', function (t) { }) }) +test('reject clients that exceed the keepalive limit', function (t) { + t.plan(3) + + const broker = aedes({ + keepaliveLimit: 100 + }) + t.teardown(broker.close.bind(broker)) + + const s = setup(broker) + + s.inStream.write({ + cmd: 'connect', + keepalive: 150 + }) + s.outStream.on('data', function (packet) { + console.log(packet) + t.same(packet, { + cmd: 'connack', + returnCode: 6, + length: 2, + qos: 0, + retain: false, + dup: false, + topic: null, + payload: null, + sessionPresent: false + }, 'unsuccessful connack, keep alive limit exceeded') + }) + broker.on('connectionError', function (client, err) { + t.equal(err.message, 'keep alive limit exceeded') + t.equal(broker.connectedClients, 0) + }) +}) + // Guarded in mqtt-packet test('reject clients with no clientId running on MQTT 3.1.0', function (t) { t.plan(3) diff --git a/test/types/aedes.test-d.ts b/test/types/aedes.test-d.ts index 744ee3da..cc145919 100644 --- a/test/types/aedes.test-d.ts +++ b/test/types/aedes.test-d.ts @@ -23,6 +23,7 @@ broker = new Aedes({ heartbeatInterval: 60000, connectTimeout: 30000, maxClientsIdLength: 23, + keepaliveLimit: 0, preConnect: (client: Client, packet: ConnectPacket, callback) => { if (client.req) { callback(new Error('not websocket stream'), false) diff --git a/types/instance.d.ts b/types/instance.d.ts index f912a95e..22bd3aef 100644 --- a/types/instance.d.ts +++ b/types/instance.d.ts @@ -75,6 +75,7 @@ export interface AedesOptions { concurrency?: number; heartbeatInterval?: number; connectTimeout?: number; + keepaliveLimit?: number; queueLimit?: number; maxClientsIdLength?: number; preConnect?: PreConnectHandler;