CVE-2022-21208: Improper Validation of Specified Quantity in Input (CWE-1284)
value: The package node-opcua before 2.74.0 are vulnerable to Denial of Service (DoS) due to a missing limitation on the number of received chunks - per single session or in total for all concurrent sessions. An attacker can exploit this vulnerability by sending an unlimited number of huge chunks (e.g. 2GB each) without sending the Final closing chunk.
CWE description: The product receives input that is expected to specify a quantity (such as size or length), but it does not validate or incorrectly validates that the quantity has the required properties.
CVSS v3 base score: 7.5
Published: 2022-08-23T05:15Z
Repository: https://github.com/node-opcua/node-opcua
Language: TypeScript
Files changed: packages/node-opcua-client/source/client_base.ts, packages/node-opcua-client/source/private/client_base_impl.ts, packages/node-opcua-client/test/test_x509_signature.ts, packages/node-opcua-end2end-test/test/end_to_end/test_e2e_issue896_execute_method_access_control.ts, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionDiagnostics.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_call_service.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_issue445_currentSessionCount.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_monitoring_larger_number2.ts, packages/node-opcua-packet-assembler/source/packet_assembler.ts, packages/node-opcua-samples/bin/opcua_interceptor.js, packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts, packages/node-opcua-secure-channel/source/message_builder.ts, packages/node-opcua-secure-channel/source/message_chunker.ts, packages/node-opcua-secure-channel/source/server/server_secure_channel_layer.ts, packages/node-opcua-secure-channel/test/test_decrypt_unsign.js, packages/node-opcua-secure-channel/test/test_message_builder.js, packages/node-opcua-secure-channel/test/test_message_builder_with_sign_chunks.js, packages/node-opcua-secure-channel/test/test_secure_channel_layer.js, packages/node-opcua-secure-channel/test/test_secure_channel_service.js, packages/node-opcua-secure-channel/test/test_security.ts, packages/node-opcua-secure-channel/test/test_server_secure_channel_layer.js, packages/node-opcua-secure-channel/test/test_various_packets.js, packages/node-opcua-secure-channel/test_fixtures/fixture_problematic_ReadResponse.js, packages/node-opcua-secure-channel/test_helpers/fake_message_chunk_factory.ts, packages/node-opcua-secure-channel/test_helpers/verify_message_chunk.ts, packages/node-opcua-server/source/opcua_server.ts, packages/node-opcua-transport/source/client_tcp_transport.ts, packages/node-opcua-transport/source/index.ts, packages/node-opcua-transport/source/message_builder_base.ts, packages/node-opcua-transport/source/server_tcp_transport.ts, packages/node-opcua-transport/source/status_codes.ts, packages/node-opcua-transport/source/tcp_transport.ts, packages/node-opcua-transport/source/utils.ts, packages/node-opcua-transport/test/test_client_tcp_transport.js, packages/node-opcua-transport/test/test_message_builder_base.js, packages/node-opcua-transport/test/test_server_tcp_transport.js, packages/node-opcua-transport/test_helpers/direct_transport.ts, packages/node-opcua-transport/test_helpers/half_com_channel.ts
Commit date: 2022-06-02 13:05:16 +0200
Commit message: fix message chunk overflow detection

Diff: diff --git a/packages/node-opcua-client/source/client_base.ts b/packages/node-opcua-client/source/client_base.ts
index c49ed5675..a8144bcba 100644
--- a/packages/node-opcua-client/source/client_base.ts
+++ b/packages/node-opcua-client/source/client_base.ts
@@ -6,23 +6,13 @@ import { EventEmitter } from "events";
 import { LocaleId } from "node-opcua-basic-types";
 import { OPCUACertificateManager } from "node-opcua-certificate-manager";
 import { OPCUASecureObject } from "node-opcua-common";
 import { Certificate } from "node-opcua-crypto";
 import { ObjectRegistry } from "node-opcua-object-registry";
-import {
-    ClientSecureChannelLayer,
-    ConnectionStrategy,
-    ConnectionStrategyOptions,
-    SecurityPolicy} from "node-opcua-secure-channel";
-import {
-    FindServersOnNetworkRequestOptions,
-    FindServersRequestOptions,
-    ServerOnNetwork
-} from "node-opcua-service-discovery";
-import {
-    ApplicationDescription,
-    EndpointDescription} from "node-opcua-service-endpoints";
+import { ClientSecureChannelLayer, ConnectionStrategy, ConnectionStrategyOptions, SecurityPolicy } from "node-opcua-secure-channel";
+import { FindServersOnNetworkRequestOptions, FindServersRequestOptions, ServerOnNetwork } from "node-opcua-service-discovery";
+import { ApplicationDescription, EndpointDescription } from "node-opcua-service-endpoints";
 import { ChannelSecurityToken, MessageSecurityMode } from "node-opcua-service-secure-channel";
 import { ErrorCallback } from "node-opcua-status-code";
 
 import { ResponseCallback } from "./client_session";
 import { Request, Response } from "./common";
@@ -47,10 +37,26 @@ export interface FindEndpointResult {
     endpoints: EndpointDescription[];
 }
 
 export type FindEndpointCallback = (err: Error | null, result?: FindEndpointResult) => void;
 
+export interface TransportSettings {
+    maxChunkCount?: number;
+    /**
+     * @advanced
+     */
+    maxMessageSize?: number;
+    /**
+     * @advanced
+     */
+    sendBufferSize?: number;
+    /**
+     * @advanced
+     */
+    receiveBufferSize?: number;
+}
+
 export interface OPCUAClientBaseOptions {
     /**
      * the client application name
      * @default "NodeOPCUA-Client"
      */
@@ -129,10 +135,14 @@ export interface OPCUAClientBaseOptions {
 
     /**
      * discovery url:
      */
     discoveryUrl?: string;
+    /**
+     * @advanced
+     */
+    transportSetting?: TransportSettings
 }
 
 export interface GetEndpointsOptions {
     endpointUrl?: string;
     localeIds?: LocaleId[];
diff --git a/packages/node-opcua-client/source/private/client_base_impl.ts b/packages/node-opcua-client/source/private/client_base_impl.ts
index e470ca287..60e7ed8c6 100644
--- a/packages/node-opcua-client/source/private/client_base_impl.ts
+++ b/packages/node-opcua-client/source/private/client_base_impl.ts
@@ -620,11 +620,14 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
             defaultSecureTokenLifetime: this.defaultSecureTokenLifetime,
             parent: this,
             securityMode: this.securityMode,
             securityPolicy: this.securityPolicy,
             serverCertificate: this.serverCertificate,
-            tokenRenewalInterval: this.tokenRenewalInterval
+            tokenRenewalInterval: this.tokenRenewalInterval,
+            
+            // transportTimeout:
+
         });
         secureChannel.protocolVersion = this.protocolVersion;
 
         this._secureChannel = secureChannel;
 
diff --git a/packages/node-opcua-client/test/test_x509_signature.ts b/packages/node-opcua-client/test/test_x509_signature.ts
index cc8d30ce4..33df5556f 100644
--- a/packages/node-opcua-client/test/test_x509_signature.ts
+++ b/packages/node-opcua-client/test/test_x509_signature.ts
@@ -8,11 +8,11 @@ import "mocha";
 import { assert } from "node-opcua-assert";
 import { decodeExpandedNodeId } from "node-opcua-basic-types";
 import { BinaryStream } from "node-opcua-binary-stream";
 import { Certificate, PrivateKeyPEM, readCertificate, readPrivateKeyPEM, split_der } from "node-opcua-crypto";
 import { makeBufferFromTrace } from "node-opcua-debug";
-import { constructObject } from "node-opcua-factory";
+import { BaseUAObject, constructObject } from "node-opcua-factory";
 import {
     computeSignature,
     getCryptoFactory,
     MessageBuilder,
     MessageSecurityMode,
@@ -37,17 +37,18 @@ function readMessage(name: string): Buffer {
     const message = makeBufferFromTrace(text);
     return message;
 }
 
 async function decodeMessage(buffer: Buffer): Promise<any> {
-    /*
-    const offset = 16 * 3 + 6;
-    buffer = buffer.slice(offset);
-    */
-    const messageBuilder = new MessageBuilder({});
+    const messageBuilder = new MessageBuilder({
+        maxChunkCount: 1,
+        maxChunkSize: buffer.length + 100,
+        maxMessageSize: buffer.length + 100
+    });
+
     messageBuilder.setSecurity(MessageSecurityMode.None, SecurityPolicy.None);
-    let objMessage: any = null;
+    let objMessage: BaseUAObject | null = null;
     messageBuilder.once("full_message_body", (fullMessageBody: Buffer) => {
         const stream = new BinaryStream(fullMessageBody);
         const id = decodeExpandedNodeId(stream);
         objMessage = constructObject(id);
         objMessage.decode(stream);
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/test_e2e_issue896_execute_method_access_control.ts b/packages/node-opcua-end2end-test/test/end_to_end/test_e2e_issue896_execute_method_access_control.ts
index 6baa0f0d4..7e8b7955b 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/test_e2e_issue896_execute_method_access_control.ts
+++ b/packages/node-opcua-end2end-test/test/end_to_end/test_e2e_issue896_execute_method_access_control.ts
@@ -1,31 +1,31 @@
-import {allPermissions, OPCUAClient, OPCUAServer, StatusCodes, UserTokenType, WellKnownRoles, makeRoles} from "node-opcua";
+import { allPermissions, OPCUAClient, OPCUAServer, StatusCodes, UserTokenType, WellKnownRoles, makeRoles } from "node-opcua";
 import "should";
 
 const describe = require("node-opcua-leak-detector").describeWithLeakDetector;
 describe("Issue #896: Check Authorization for UAMethods", () => {
     const users = [
-        {username: "Gandalf", password: "g", roles: makeRoles([WellKnownRoles.AuthenticatedUser,WellKnownRoles.ConfigureAdmin])},
-        {username: "Frodo", password: "f", roles:  makeRoles([WellKnownRoles.AuthenticatedUser])},
+        { username: "Gandalf", password: "g", roles: makeRoles([WellKnownRoles.AuthenticatedUser, WellKnownRoles.ConfigureAdmin]) },
+        { username: "Frodo", password: "f", roles: makeRoles([WellKnownRoles.AuthenticatedUser]) }
     ];
 
     const port = 2226;
     const server = new OPCUAServer({
         port,
         userManager: {
-            getUserRoles: username => users.find(user => user.username === username)!.roles,
-            
-            isValidUser(username, password) {
-                const user = users.find(user => user.username === username);
+            getUserRoles: (username) => users.find((user) => user.username === username)!.roles,
+
+            isValidUser: (username: string, password: string) => {
+                const user = users.find((user) => user.username === username);
                 if (!user) return false;
                 return user.password === password;
             }
         }
-    })
+    });
 
     const client = OPCUAClient.create({
-        endpointMustExist: false,
+        endpointMustExist: false
     });
 
     let wasExecuted: boolean;
 
     before(async () => {
@@ -34,49 +34,51 @@ describe("Issue #896: Check Authorization for UAMethods", () => {
         const namespace = addressSpace.getOwnNamespace();
         const folder = namespace.addFolder(addressSpace.rootFolder.objects, {
             browseName: "e2e",
             nodeId: "ns=1;s=e2e"
         });
-        namespace.addMethod(folder, {
-            browseName: "doIt",
-            nodeId: "ns=1;s=doIt",
-            rolePermissions: [
-                { 
-                    roleId:  WellKnownRoles.ConfigureAdmin,
-                    permissions: allPermissions
-                }
-            ]
-            /*
+        namespace
+            .addMethod(folder, {
+                browseName: "doIt",
+                nodeId: "ns=1;s=doIt",
+                rolePermissions: [
+                    {
+                        roleId: WellKnownRoles.ConfigureAdmin,
+                        permissions: allPermissions
+                    }
+                ]
+                /*
             permissions: {
                  [Permission.Call]: ["!*", WellKnownRoles.ConfigureAdmin]
             }
             */
-        }).bindMethod((inputArguments, context, callback) => {
-            wasExecuted = true;
-            callback(null, {statusCode: StatusCodes.Good})
-        });
+            })
+            .bindMethod((inputArguments, context, callback) => {
+                wasExecuted = true;
+                callback(null, { statusCode: StatusCodes.Good });
+            });
         await server.start();
         return client.connect(`opc.tcp://localhost:${port}/UA/NodeOPCUA`);
     });
 
     after(async () => {
         await client.disconnect();
         await server.shutdown();
     });
 
-    beforeEach(() => wasExecuted = false);
+    beforeEach(() => (wasExecuted = false));
 
     it("should allow Gandalf to execute the method", async () => {
         const clientSession = await client.createSession({
             type: UserTokenType.UserName,
             userName: "Gandalf",
             password: "g"
         });
         const result = await clientSession.call({
             methodId: "ns=1;s=doIt",
             objectId: "ns=1;s=e2e",
-            inputArguments: [],
+            inputArguments: []
         });
         await clientSession.close();
         result.statusCode.should.eql(StatusCodes.Good);
         wasExecuted.should.eql(true);
     });
@@ -88,12 +90,12 @@ describe("Issue #896: Check Authorization for UAMethods", () => {
             password: "f"
         });
         const result = await clientSession.call({
             methodId: "ns=1;s=doIt",
             objectId: "ns=1;s=e2e",
-            inputArguments: [],
+            inputArguments: []
         });
         await clientSession.close();
         result.statusCode.should.eql(StatusCodes.BadUserAccessDenied);
         wasExecuted.should.eql(false);
     });
-});
\ No newline at end of file
+});
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionDiagnostics.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionDiagnostics.js
index 7e7434cb2..d81c56768 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionDiagnostics.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionDiagnostics.js
@@ -1,12 +1,7 @@
-/*global xit,it,describe,before,after,beforeEach,afterEach*/
 "use strict";
 
-
-
-
-const { assert } = require("node-opcua-assert");
 const async = require("async");
 const should = require("should");
 const sinon = require("sinon");
 
 const opcua = require("node-opcua");
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_call_service.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_call_service.js
index deddf2245..fbb33dc6a 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_call_service.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_call_service.js
@@ -32,11 +32,11 @@ module.exports = function (test) {
     describe("testing CALL SERVICE on a fake server exposing the temperature device", function () {
         let client, endpointUrl;
 
         beforeEach(function (done) {
             client = OPCUAClient.create({
-                requestedSessionTimeout: 600 * 1000 // use long session time out
+                requestedSessionTimeout: 600 * 1000, // use long session time out
             });
             endpointUrl = test.endpointUrl;
             done();
         });
 
@@ -268,11 +268,11 @@ module.exports = function (test) {
                 done
             );
         });
 
         it("Q3-5 should return BadTooManyOperations when CallRequest has too many methods to call", function (done) {
-            const too_many = 50000;
+            const too_many = 5000;
             const methodToCalls = [];
             for (let i = 0; i < too_many; i++) {
                 methodToCalls.push({
                     objectId: coerceNodeId("ns=0;i=2253"), // SERVER
                     methodId: coerceNodeId("ns=0;i=11492"), // GetMonitoredItem
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_issue445_currentSessionCount.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_issue445_currentSessionCount.js
index 873011ae6..6a13e6a53 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_issue445_currentSessionCount.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_issue445_currentSessionCount.js
@@ -1,20 +1,18 @@
-const async = require("async");
 const should = require("should");
 const chalk = require("chalk");
 const {
     AttributeIds,
     VariableIds,
     OPCUAClient,
     resolveNodeId,
-    ClientMonitoredItem,
-    StatusCodes,
     TimestampsToReturn,
     MonitoringMode
 } = require("node-opcua");
-const { make_debugLog, make_errorLog, checkDebugFlag } = require("node-opcua-debug");
+const { make_debugLog, checkDebugFlag } = require("node-opcua-debug");
 const { perform_operation_on_subscription_async } = require("../../test_helpers/perform_operation_on_client_session");
+const { pause } = require("../discovery/_helper");
 
 function f(func) {
     return function (callback) {
         console.log("       * " + func.name.replace(/_/g, " ").replace(/(given|when|then)/, chalk.green("**$1**")));
         return func(callback);
@@ -25,19 +23,23 @@ const debugLog = make_debugLog("TEST");
 const errorLog = make_debugLog("TEST");
 const doDebug = checkDebugFlag("TEST");
 
 let sessionCounter = 0;
 async function connectAndCreateSession(endpointUrl) {
+
+    await pause(100);
+
     const client = OPCUAClient.create({
         name: "client" + sessionCounter++,
     });
     await client.connect(endpointUrl);
     const session = await client.createSession();
     return { client, session };
 }
 
 async function closeSessionAndDisconnect({ client, session }) {
+    await pause(100);
     await session.close();
     await client.disconnect();
 }
 
 const currentSessionCountNodeId = resolveNodeId(VariableIds.Server_ServerDiagnostics_ServerDiagnosticsSummary_CurrentSessionCount);
@@ -63,12 +65,13 @@ async function installMonitoredItem(subscription, nodeId) {
         recordedValue.push(dataValue.value.value);
         debugLog("change =", recordedValue);
     });
     return await new Promise((resolve, reject) => {
         const timer = setTimeout(() => {
+            console.log(monitoredItem);
             reject(new Error("Never received changedx for id" + nodeId.toString()));
-        }, 5000);
+        }, 15000);
 
         monitoredItem.once("changed", function (dataValue) {
             clearTimeout(timer);
             resolve([recordedValue, monitoredItem]);
         });
@@ -83,32 +86,34 @@ async function installCumulatedSessionCounter(subscription) {
     return await installMonitoredItem(subscription, cumulatedSessionCountNodeId);
 }
 
 async function waitSessionCountChange(currentSessionCountMonitoredItem) {
 
-    return await new Promise((resolve,reject) => {
+    return await new Promise((resolve, reject) => {
         const timer = setTimeout(() => {
+            console.log(currentSessionCountMonitoredItem);
             reject(new Error("Never received ", currentSessionCountMonitoredItem.toString()));
-        }, 5000);
+        }, 15000);
 
         currentSessionCountMonitoredItem.once("changed", function (dataValue) {
             clearTimeout(timer);
             const new_currentSessionCount = dataValue.value.value;
             debugLog("new currentSessionCount=", dataValue.toString());
             resolve(new_currentSessionCount);
         });
+
     });
 }
 
 module.exports = function (test) {
     describe("Testing bug #445 - server.serverDiagnosticsSummary.currentSessionCount", function () {
         it("test that current SessionCount increments and decrements appropriately", async () => {
             const endpointUrl = test.endpointUrl;
 
             const client = OPCUAClient.create({});
 
-            await perform_operation_on_subscription_async(client, endpointUrl, async function (session, subscription) {
+            await perform_operation_on_subscription_async(client, endpointUrl, async (session, subscription) => {
                 const [recordedCurrentSessionCountValues, currentSessionCountMonitoredItem] = await installCurrentSessionCounter(
                     subscription
                 );
 
                 const [recordedCumulatedSessionCountValues] = await installCumulatedSessionCounter(subscription);
@@ -122,10 +127,11 @@ module.exports = function (test) {
                 async function connectAndWaitCurrentSessionCountChange() {
                     debugLog("connecting", session.name);
                     const promises = [waitSessionCountChange(currentSessionCountMonitoredItem), connectAndCreateSession(endpointUrl)];
                     return await Promise.all(promises);
                 }
+
                 async function disconnectAndWaitCurrentSessionCountChange({ client, session }) {
                     debugLog("disconnecting", session.name);
 
                     const promises = [waitSessionCountChange(currentSessionCountMonitoredItem), closeSessionAndDisconnect({ client, session })];
                     return await Promise.all(promises);
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_monitoring_larger_number2.ts b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_monitoring_larger_number2.ts
index 0e9106c03..3dbf12234 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_monitoring_larger_number2.ts
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_monitoring_larger_number2.ts
@@ -1,5 +1,6 @@
+import { clearTimeout } from "timers";
 import {
     AddressSpace,
     assert,
     AttributeIds,
     ClientSession,
@@ -16,16 +17,14 @@ import {
     OPCUAClientOptions,
     ReadValueIdOptions,
     StatusCode,
     TimestampsToReturn
 } from "node-opcua";
-import sinon = require("sinon");
-import should = require("should");
+import * as should from "should";
 
 import { make_debugLog, checkDebugFlag } from "node-opcua-debug";
 import { itemsToMonitor1 } from "./_helpers_items_to_monitor";
-import { clearTimeout } from "timers";
 const debugLog = make_debugLog("TEST");
 const doDebug = checkDebugFlag("TEST");
 
 interface ClientSidePublishEnginePrivate extends ClientSidePublishEngine {
     internalSendPublishRequest(): void;
@@ -116,16 +115,20 @@ export function t(test: any) {
         });
 
         it("Should monitor a large number of node efficiently", async () => {
             const { session, subscription, publishEngine } = s;
 
+            session.on("session_closed", ()=>{ 
+                console.log("session_closed");  
+            });
+
             const namespaceArray = await session.readNamespaceArray();
             const simulationNamespaceIndex = namespaceArray.indexOf("urn://node-opcua-simulator");
             console.log("simulationNamespaceIndex = ", simulationNamespaceIndex);
 
             let itemToMonitors: ReadValueIdOptions[] = itemsToMonitor1;
-            while (itemToMonitors.length + itemsToMonitor1.length < 10000) {
+            while (itemToMonitors.length + itemsToMonitor1.length < 2200) {
                 itemToMonitors = itemToMonitors.concat([...itemsToMonitor1]);
             }
 
             const dataValues = await session.read(itemToMonitors);
             console.log(
@@ -154,11 +157,14 @@ export function t(test: any) {
                 console.log("set event handler on group");
 
                 console.time("B");
 
                 await new Promise<void>((resolve) => {
-                    const timerId = setTimeout(() => resolve(), 12000);
+
+
+                    const timerId = setTimeout(() => resolve(), 5000);
+                    
                     group.on("changed", (monitoredItem, dataValue, index) => {
                         counter++;
                         if (counter === itemToMonitors.length) {
                             clearTimeout(timerId);
                             resolve();
diff --git a/packages/node-opcua-packet-assembler/source/packet_assembler.ts b/packages/node-opcua-packet-assembler/source/packet_assembler.ts
index 87e2a28c5..fff136569 100644
--- a/packages/node-opcua-packet-assembler/source/packet_assembler.ts
+++ b/packages/node-opcua-packet-assembler/source/packet_assembler.ts
@@ -29,14 +29,18 @@ export interface PacketAssemblerOptions {
     // the minimum number of bytes that need to be received before the readChunkFunc can be called
     minimumSizeInBytes: number;
     maxChunkSize: number;
 }
 
+export enum PacketAssemblerErrorCode {
+    ChunkSizeExceeded = 1,
+    ChunkTooSmall = 2
+}
 export interface PacketAssembler {
     on(eventName: "startChunk", eventHandler: (packetInfo: PacketInfo, partial: Buffer) => void): this;
     on(eventName: "chunk", eventHandler: (chunk: Buffer) => void): this;
-    on(eventName: "error", eventHandler: (err: Error) => void): this;
+    on(eventName: "error", eventHandler: (err: Error, errCode: PacketAssemblerErrorCode) => void): this;
 }
 /**
  * this class is used to assemble partial data from the tranport layer
  * into message chunks
  */
@@ -84,18 +88,18 @@ export class PacketAssembler extends EventEmitter {
             // we can extract the expected length here
             this.packetInfo = this._readPacketInfo(data);
 
             assert(this.currentLength === 0);
             if (this.packetInfo.length < this.minimumSizeInBytes) {
-                this.emit("error", new Error("maximum message size exceeded"));
+                this.emit("error", new Error("chunk is too small "), PacketAssemblerErrorCode.ChunkTooSmall);
                 return;
             }
 
             if (this.packetInfo.length > this.maxChunkSize) {
                 const message = `maximum chunk size exceeded (maxChunkSize=${this.maxChunkSize} current chunk size = ${this.packetInfo.length})`;
                 warningLog(message);
-                this.emit("error", new Error(message));
+                this.emit("error", new Error(message), PacketAssemblerErrorCode.ChunkSizeExceeded);
                 return;
             }
             // we can now emit an event to signal the start of a new packet
             this.emit("startChunk", this.packetInfo, data);
             this.expectedLength = this.packetInfo.length;
diff --git a/packages/node-opcua-samples/bin/opcua_interceptor.js b/packages/node-opcua-samples/bin/opcua_interceptor.js
index 20484de52..eb3c639aa 100644
--- a/packages/node-opcua-samples/bin/opcua_interceptor.js
+++ b/packages/node-opcua-samples/bin/opcua_interceptor.js
@@ -1,13 +1,14 @@
 /* eslint no-process-exit: 0 */
 "use strict";
-const argv = require("yargs")
-    .usage("Usage: $0 --portServer [num] --port [num]  --hostname <hostname> -block")
-    .argv;
 const net = require("net");
 
+const chalk = require("chalk");
 
+const argv = require("yargs")
+    .usage("Usage: $0 --portServer [num] --port [num]  --hostname <hostname> -block")
+    .argv;
 
 const opcua = require("node-opcua");
 
 const hexDump = require("node-opcua-utils").hexDump;
 const MessageBuilder = require("../lib/misc/message_builder").MessageBuilder;
@@ -16,12 +17,10 @@ const BinaryStream = require("../lib/misc/binaryStream").BinaryStream;
 const analyseExtensionObject = require("../lib/misc/analyzePacket").analyseExtensionObject;
 const messageHeaderToString = require("../lib/misc/message_header").messageHeaderToString;
 
 const s = require("../lib/datamodel/structures");
 
-const chalk = require("chalk");
-
 const remote_port = parseInt(argv.port, 10) || 4841;
 const hostname = argv.hostname || "localhost";
 
 const my_port = parseInt(argv.portServer, 10) || remote_port + 1;
 
@@ -40,11 +39,11 @@ TrafficAnalyser.prototype.add = function (data) {
     }
     const messageHeader = opcua.readMessageHeader(stream);
 
     if (messageHeader.msgType === "ERR") {
 
-        var err = new s.TCPErrorMessage();
+        const err = new s.TCPErrorMessage();
         err.decode(stream);
         console.log(" Error 0x" + err.statusCode.toString() + " reason:" + err.reason);
         console.log(hexDump(data));
     }
 
@@ -110,10 +109,11 @@ require("net").createServer(function (socket) {
         console.log(" server -> client : packet length " + data.length);
         ta_server.add(data);
         try {
             socket.write(data);
         } catch (err) {
+            /** */
         }
     });
 
     socket.on("data", function (data) {
         console.log(" client -> server : packet length " + data.length);
diff --git a/packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts b/packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts
index ad48060fb..f6d23ed84 100644
--- a/packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts
+++ b/packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts
@@ -17,18 +17,20 @@ import { BinaryStream } from "node-opcua-binary-stream";
 import { get_clock_tick, timestamp } from "node-opcua-utils";
 
 import { readMessageHeader, verify_message_chunk } from "node-opcua-chunkmanager";
 import { checkDebugFlag, hexDump, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
 import { ChannelSecurityToken, coerceMessageSecurityMode, MessageSecurityMode } from "node-opcua-service-secure-channel";
-import { CallbackT, StatusCodes } from "node-opcua-status-code";
+import { CallbackT, StatusCode, StatusCodes } from "node-opcua-status-code";
 import { ClientTCP_transport } from "node-opcua-transport";
+import { StatusCodes2 } from "node-opcua-transport";
 import { ErrorCallback } from "node-opcua-status-code";
 import { BaseUAObject } from "node-opcua-factory";
 
 import { MessageBuilder, SecurityToken } from "../message_builder";
 import { ChunkMessageOptions, MessageChunker } from "../message_chunker";
 import { messageHeaderToString } from "../message_header_to_string";
+
 import {
     coerceSecurityPolicy,
     computeDerivedKeys,
     DerivedKeys1,
     getCryptoFactory,
@@ -274,11 +276,11 @@ export class ClientSecureChannelLayer extends EventEmitter {
     private clientNonce: any;
     private readonly messageChunker: MessageChunker;
     private readonly defaultSecureTokenLifetime: number;
     private readonly tokenRenewalInterval: number;
     private readonly serverCertificate: Certificate | null;
-    private readonly messageBuilder: MessageBuilder;
+    private messageBuilder?: MessageBuilder;
 
     private _requests: { [key: string]: RequestData };
 
     private __in_normal_close_operation: boolean;
     private _timeout_request_count: number;
@@ -343,29 +345,54 @@ export class ClientSecureChannelLayer extends EventEmitter {
             );
             assert(this.securityPolicy !== SecurityPolicy.None, "Security Policy None is not a valid choice");
             // make sure that we do not have a chain here ...
         }
 
+        this._requests = {};
+
+        this.__in_normal_close_operation = false;
+
+        this._timeout_request_count = 0;
+
+        this._securityTokenTimeoutId = null;
+
+        this.transportTimeout = options.transportTimeout || ClientSecureChannelLayer.defaultTransportTimeout;
+
+        this.channelId = 0;
+
+        this.connectionStrategy = coerceConnectionStrategy(options.connectionStrategy);
+    }
+
+    private _install_message_builder() {
+        // istanbul ignore next
+        if (!this._transport || !this._transport.parameters) {
+            throw new Error("internal error");
+        }
         this.messageBuilder = new MessageBuilder({
             name: "client",
             privateKey: this.getPrivateKey() || undefined,
-            securityMode: this.securityMode
+            securityMode: this.securityMode,
+            maxChunkSize: this._transport.receiveBufferSize || 0,
+            maxChunkCount: this._transport.maxChunkCount || 0,
+            maxMessageSize: this._transport.maxMessageSize || 0
         });
-        this._requests = {};
 
         this.messageBuilder
-            .on("message", (response: Response, msgType: string, requestId: number) => {
-                this._on_message_received(response, msgType, requestId);
+            .on("message", (response: BaseUAObject, msgType: string, requestId: number, channelId: number) => {
+                this._on_message_received(response as Response, msgType, requestId);
             })
-            .on("start_chunk", () => {
+            .on("startChunk", () => {
                 //
                 if (doPerfMonitoring) {
                     this._tick2 = get_clock_tick();
                 }
             })
-            .on("error", (err, requestId) => {
-                //
+            .on("error", (err: Error, statusCode: StatusCode, requestId: number | null) => {
+                if (!requestId) {
+                    return;
+                }
+
                 let requestData = this._requests[requestId];
 
                 if (doDebug) {
                     debugLog("request id = ", requestId, err);
                     debugLog(" message was ");
@@ -377,24 +404,11 @@ export class ClientSecureChannelLayer extends EventEmitter {
                     if (doTraceClientRequestContent) {
                         errorLog(" message was 2:", requestData ? requestData.request.toString() : "<null>");
                     }
                 }
             });
-
-        this.__in_normal_close_operation = false;
-
-        this._timeout_request_count = 0;
-
-        this._securityTokenTimeoutId = null;
-
-        this.transportTimeout = options.transportTimeout || ClientSecureChannelLayer.defaultTransportTimeout;
-
-        this.channelId = 0;
-
-        this.connectionStrategy = coerceConnectionStrategy(options.connectionStrategy);
     }
-
     public getPrivateKey(): PrivateKeyPEM | null {
         return this.parent ? this.parent.getPrivateKey() : null;
     }
 
     public getCertificateChain(): Certificate | null {
@@ -680,13 +694,13 @@ export class ClientSecureChannelLayer extends EventEmitter {
                 callback();
             });
         });
     }
 
-    public closeWithError(err: Error, callback: ErrorCallback): void {
+    public closeWithError(err: Error, statusCode: StatusCode, callback: ErrorCallback): void {
         if (this._transport) {
-            this._transport.prematureTerminate(err);
+            this._transport.prematureTerminate(err, statusCode);
         }
         callback();
     }
 
     private on_transaction_completed(transactionStatistics: ClientTransactionStatistics) {
@@ -774,13 +788,13 @@ export class ClientSecureChannelLayer extends EventEmitter {
 
         requestData.response = response;
 
         if (doPerfMonitoring) {
             // record tick2 : after response message has been received, before message processing
-            requestData._tick2 = this.messageBuilder._tick1;
+            requestData._tick2 = this.messageBuilder!._tick1;
         }
-        requestData.bytesRead = this.messageBuilder.totalMessageSize;
+        requestData.bytesRead = this.messageBuilder!.totalMessageSize;
 
         if (doPerfMonitoring) {
             // record tick3 : after response message has been received, before message processing
             requestData._tick3 = get_clock_tick();
         }
@@ -1025,11 +1039,11 @@ export class ClientSecureChannelLayer extends EventEmitter {
                         warningLog(" client : server nonce is invalid  (invalid length)!");
                         return callback(new Error(" Invalid server nonce length"));
                     }
                 }
 
-                const cryptoFactory = this.messageBuilder.cryptoFactory;
+                const cryptoFactory = this.messageBuilder!.cryptoFactory;
                 if (cryptoFactory) {
                     assert(this.serverNonce instanceof Buffer);
                     /* istanbul ignore next */
                     if (!this.serverNonce) {
                         throw new Error("internal error");
@@ -1042,11 +1056,11 @@ export class ClientSecureChannelLayer extends EventEmitter {
                 // istanbul ignore next
                 if (doDebug) {
                     debugLog("Server has send a new security Token");
                 }
 
-                this.messageBuilder.pushNewToken(this.securityToken, derivedServerKeys);
+                this.messageBuilder!.pushNewToken(this.securityToken, derivedServerKeys);
 
                 this._install_security_token_watchdog();
 
                 this._isOpened = true;
             }
@@ -1057,11 +1071,13 @@ export class ClientSecureChannelLayer extends EventEmitter {
     private _on_connection(transport: ClientTCP_transport, callback: ErrorCallback) {
         assert(this._pending_transport === transport);
         this._pending_transport = undefined;
         this._transport = transport;
 
-        this._transport.on("message", (messageChunk: Buffer) => {
+        this._install_message_builder();
+
+        this._transport.on("chunk", (messageChunk: Buffer) => {
             /**
              * notify the observers that ClientSecureChannelLayer has received a message chunk
              * @event receive_chunk
              * @param message_chunk
              */
@@ -1238,13 +1254,17 @@ export class ClientSecureChannelLayer extends EventEmitter {
             } else {
                 if (doDebug) {
                     debugLog("ClientSecureChannelLayer: Warning: securityToken hasn't been renewed -> err ", err);
                 }
                 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX CHECK ME !!!
-                this.closeWithError(new Error("Restarting because Request has timed out during OpenSecureChannel"), () => {
-                    /* */
-                });
+                this.closeWithError(
+                    new Error("Restarting because Request has timed out during OpenSecureChannel"),
+                    StatusCodes2.BadRequestTimeout,
+                    () => {
+                        /* */
+                    }
+                );
             }
         });
     }
 
     private _on_receive_message_chunk(messageChunk: Buffer) {
@@ -1254,11 +1274,11 @@ export class ClientSecureChannelLayer extends EventEmitter {
             const messageHeader = readMessageHeader(_stream);
             debugLog("CLIENT RECEIVED " + chalk.yellow(JSON.stringify(messageHeader) + ""));
             debugLog("\n" + hexDump(messageChunk));
             debugLog(messageHeaderToString(messageChunk));
         }
-        this.messageBuilder.feed(messageChunk);
+        this.messageBuilder!.feed(messageChunk);
     }
 
     /**
      * @method makeRequestId
      * @return  newly generated request id
diff --git a/packages/node-opcua-secure-channel/source/message_builder.ts b/packages/node-opcua-secure-channel/source/message_builder.ts
index 030c767cb..4a30d65f8 100644
--- a/packages/node-opcua-secure-channel/source/message_builder.ts
+++ b/packages/node-opcua-secure-channel/source/message_builder.ts
@@ -27,16 +27,16 @@ import {
     AsymmetricAlgorithmSecurityHeader,
     coerceMessageSecurityMode,
     MessageSecurityMode,
     CloseSecureChannelRequest
 } from "node-opcua-service-secure-channel";
-import { decodeStatusCode } from "node-opcua-status-code";
-import { MessageBuilderBase } from "node-opcua-transport";
+import { decodeStatusCode, coerceStatusCode, StatusCodes, StatusCode } from "node-opcua-status-code";
+import { MessageBuilderBase, MessageBuilderBaseOptions, StatusCodes2 } from "node-opcua-transport";
 import { timestamp } from "node-opcua-utils";
 import { SequenceHeader } from "node-opcua-chunkmanager";
 
-import { chooseSecurityHeader, SymmetricAlgorithmSecurityHeader } from "./secure_channel_service";
+import { chooseSecurityHeader, MessageChunker, SymmetricAlgorithmSecurityHeader } from "./secure_channel_service";
 
 import { SecurityHeader } from "./secure_message_chunk_manager";
 import {
     asymmetricVerifyChunk,
     coerceSecurityPolicy,
@@ -67,11 +67,11 @@ const defaultObjectFactory = {
 export interface ObjectFactory {
     constructObject: (expandedNodeId: ExpandedNodeId) => BaseUAObject;
     hasConstructor: (expandedNodeId: ExpandedNodeId) => boolean;
 }
 
-export interface MessageBuilderOptions {
+export interface MessageBuilderOptions extends MessageBuilderBaseOptions {
     securityMode?: MessageSecurityMode;
     privateKey?: PrivateKeyPEM;
     objectFactory?: ObjectFactory;
     signatureLength?: number;
     name?: string;
@@ -83,10 +83,35 @@ export interface SecurityTokenAndDerivedKeys {
 }
 
 const invalidPrivateKey = "<invalid>";
 let counter = 0;
 
+type PacketInfo = any;
+
+export interface MessageBuilder extends MessageBuilderBase {
+    on(eventName: "startChunk", eventHandler: (info: PacketInfo, data: Buffer) => void): this;
+    on(eventName: "chunk", eventHandler: (chunk: Buffer) => void): this;
+    on(eventName: "error", eventHandler: (err: Error, statusCode: StatusCode, requestId: number | null) => void): this;
+    on(eventName: "full_message_body", eventHandler: (fullMessageBody: Buffer) => void): this;
+    on(
+        eventName: "message",
+        eventHandler: (obj: BaseUAObject, msgType: string, requestId: number, channelId: number) => void
+    ): this;
+
+    on(eventName: "invalid_message", eventHandler: (obj: BaseUAObject) => void): this;
+    on(eventName: "invalid_sequence_number", eventHandler: (expectedSequenceNumber: number, sequenceNumber: number) => void): this;
+    on(eventName: "new_token", eventHandler: (tokenId: number) => void): this;
+
+    emit(eventName: "startChunk", info: PacketInfo, data: Buffer): boolean;
+    emit(eventName: "chunk", chunk: Buffer): boolean;
+    emit(eventName: "error", err: Error, statusCode: StatusCode, requestId: number | null): boolean;
+    emit(eventName: "full_message_body", fullMessageBody: Buffer): boolean;
+    emit(eventName: "message", obj: BaseUAObject, msgType: string, requestId: number, channelId: number): boolean;
+    emit(eventName: "invalid_message", evobj: BaseUAObject): boolean;
+    emit(eventName: "invalid_sequence_number", expectedSequenceNumber: number, sequenceNumber: number): boolean;
+    emit(eventName: "new_token", tokenId: number): boolean;
+}
 /**
  * @class MessageBuilder
  * @extends MessageBuilderBase
  * @constructor
  *
@@ -247,25 +272,45 @@ export class MessageBuilder extends MessageBuilderBase {
         } catch (err) {
             return false;
         }
     }
 
+    protected _reportErrMessage(message: Buffer) {
+        try {
+            const binaryStream = new BinaryStream(message);
+            const msgType = binaryStream.readUInt32();
+            const msgLength = binaryStream.readUInt32();
+            if (message.length === msgLength) {
+                const errorCode = binaryStream.readUInt32();
+                const additionalInfo = decodeString(binaryStream);
+                // invalid message type
+                const m1 = `ERR: ${errorCode} ${additionalInfo}`;
+                warningLog(m1);
+                return this._report_error(coerceStatusCode(errorCode), m1);
+            } else {
+                return this._report_error(StatusCodes.BadTcpInternalError, message.toString("hex"));
+            }
+        } catch (err) {
+            console.log(hexDump(message));
+            return this._report_error(StatusCodes.BadTcpInternalError, message.toString("hex"));
+        }
+    }
+
     protected _decodeMessageBody(fullMessageBody: Buffer): boolean {
         // istanbul ignore next
         if (!this.messageHeader || !this.securityHeader) {
-            return this._report_error("internal error");
+            return this._report_error(StatusCodes2.BadTcpInternalError, "internal error");
         }
 
         const msgType = this.messageHeader.msgType;
 
         if (msgType === "ERR") {
-            // invalid message type
-            return this._report_error("ERROR RECEIVED");
+            return this._reportErrMessage(fullMessageBody);
         }
         if (msgType === "HEL" || msgType === "ACK") {
             // invalid message type
-            return this._report_error("Invalid message type ( HEL/ACK )");
+            return this._report_error(StatusCodes2.BadTcpMessageTypeInvalid, "Invalid message type ( HEL/ACK )");
         }
 
         if (msgType === "CLO" && fullMessageBody.length === 0 && this.sequenceHeader) {
             // The Client closes the connection by sending a CloseSecureChannel request and closing the
             // socket gracefully. When the Server receives this Message, it shall release all resources
@@ -283,24 +328,24 @@ export class MessageBuilder extends MessageBuilderBase {
         try {
             id = decodeExpandedNodeId(binaryStream);
         } catch (err) {
             // this may happen if the message is not well formed or has been altered
             // we better off reporting an error and abort the communication
-            return this._report_error(err instanceof Error ? err.message : " err");
+            return this._report_error(StatusCodes2.BadTcpInternalError, err instanceof Error ? err.message : " err");
         }
 
         if (!this.objectFactory.hasConstructor(id)) {
             // the datatype NodeId is not supported by the server and unknown in the factory
             // we better off reporting an error and abort the communication
-            return this._report_error("cannot construct object with nodeID " + id.toString());
+            return this._report_error(StatusCodes.BadNotSupported, "cannot construct object with nodeID " + id.toString());
         }
 
         // construct the object
         const objMessage = this.objectFactory.constructObject(id);
 
         if (!objMessage) {
-            return this._report_error("cannot construct object with nodeID " + id);
+            return this._report_error(StatusCodes.BadNotSupported, "cannot construct object with nodeID " + id);
         } else {
             if (this._safe_decode_message_body(fullMessageBody, objMessage, binaryStream)) {
                 /* istanbul ignore next */
                 if (doDebug) {
                     const o = objMessage as any;
diff --git a/packages/node-opcua-secure-channel/source/message_chunker.ts b/packages/node-opcua-secure-channel/source/message_chunker.ts
index 3fc79b1cc..c5fb9cf61 100644
--- a/packages/node-opcua-secure-channel/source/message_chunker.ts
+++ b/packages/node-opcua-secure-channel/source/message_chunker.ts
@@ -8,11 +8,11 @@ import { encodeExpandedNodeId } from "node-opcua-basic-types";
 import { BinaryStream } from "node-opcua-binary-stream";
 import { DerivedKeys } from "node-opcua-crypto";
 import { BaseUAObject } from "node-opcua-factory";
 import { AsymmetricAlgorithmSecurityHeader, SymmetricAlgorithmSecurityHeader } from "node-opcua-service-secure-channel";
 import { timestamp } from "node-opcua-utils";
-import { make_errorLog, make_warningLog} from "node-opcua-debug";
+import { make_errorLog, make_warningLog } from "node-opcua-debug";
 
 import { SecureMessageChunkManager, SecureMessageChunkManagerOptions, SecurityHeader } from "./secure_message_chunk_manager";
 import { SequenceNumberGenerator } from "./sequence_number_generator";
 
 const doTraceChunk = process.env.NODEOPCUADEBUG && process.env.NODEOPCUADEBUG.indexOf("CHUNK") >= 0;
@@ -37,21 +37,23 @@ export interface ChunkMessageOptions extends SecureMessageChunkManagerOptions {
  * @param options.securityHeader  {Object} SecurityHeader
  * @param [options.derivedKeys] {Object} derivedKeys
  * @constructor
  */
 export class MessageChunker {
+    public static defaultMaxMessageSize: number = 16 * 1024 * 1024;
+
     public securityHeader?: any;
 
     private readonly sequenceNumberGenerator: SequenceNumberGenerator;
     private _stream?: BinaryStream;
     private derivedKeys?: DerivedKeys | null;
     public maxMessageSize: number;
 
     constructor(options?: MessageChunkerOptions) {
         options = options || {};
         this.sequenceNumberGenerator = new SequenceNumberGenerator();
-        this.maxMessageSize = options.maxMessageSize || 16 *1024*1024;
+        this.maxMessageSize = options.maxMessageSize || MessageChunker.defaultMaxMessageSize;
         this.update(options);
     }
 
     public dispose(): void {
         this.securityHeader = null;
@@ -122,11 +124,13 @@ export class MessageChunker {
                         "l=",
                         binSize.toString().padStart(6)
                     );
                 }
                 if (totalSize > this.maxMessageSize) {
-                    errorLog(`[NODE-OPCUA-E55] message size ${totalSize} exceeds the negotiated message size ${this.maxMessageSize} nb chunks ${nbChunks}`);
+                    errorLog(
+                        `[NODE-OPCUA-E55] message size ${totalSize} exceeds the negotiated message size ${this.maxMessageSize} nb chunks ${nbChunks}`
+                    );
                 }
                 messageChunkCallback(null);
             });
 
         chunkManager.write(stream.buffer, stream.buffer.length);
diff --git a/packages/node-opcua-secure-channel/source/server/server_secure_channel_layer.ts b/packages/node-opcua-secure-channel/source/server/server_secure_channel_layer.ts
index 0c3b8ade2..3c3c2f9d6 100644
--- a/packages/node-opcua-secure-channel/source/server/server_secure_channel_layer.ts
+++ b/packages/node-opcua-secure-channel/source/server/server_secure_channel_layer.ts
@@ -1,5 +1,6 @@
+/* eslint-disable max-statements */
 /**
  * @module node-opcua-secure-channel
  */
 import * as crypto from "crypto";
 import { EventEmitter } from "events";
@@ -14,11 +15,12 @@ import {
     extractPublicKeyFromCertificate,
     makeSHA1Thumbprint,
     PrivateKeyPEM,
     PublicKeyLength,
     rsa_length,
-    exploreCertificate
+    exploreCertificate,
+    hexDump
 } from "node-opcua-crypto";
 
 import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
 import { BaseUAObject } from "node-opcua-factory";
 import { analyze_object_binary_encoding } from "node-opcua-packet-analyzer";
@@ -27,17 +29,19 @@ import {
     hasTokenExpired,
     MessageSecurityMode,
     SymmetricAlgorithmSecurityHeader
 } from "node-opcua-service-secure-channel";
 import { StatusCode, StatusCodes } from "node-opcua-status-code";
-import { ServerTCP_transport } from "node-opcua-transport";
+import { ServerTCP_transport, StatusCodes2 } from "node-opcua-transport";
 import { get_clock_tick, timestamp } from "node-opcua-utils";
 import { Callback2, ErrorCallback } from "node-opcua-status-code";
 
 import { EndpointDescription } from "node-opcua-service-endpoints";
 import { ICertificateManager } from "node-opcua-certificate-manager";
 import { ObjectRegistry } from "node-opcua-object-registry";
+import { doTraceIncomingChunk } from "node-opcua-transport";
+
 import { SecureMessageChunkManagerOptions, SecurityHeader } from "../secure_message_chunk_manager";
 
 import { getThumbprint, ICertificateKeyPairProvider, Request, Response } from "../common";
 import { MessageBuilder, ObjectFactory } from "../message_builder";
 import { ChunkMessageOptions, MessageChunker } from "../message_chunker";
@@ -247,11 +251,13 @@ export class ServerSecureChannelLayer extends EventEmitter {
     public static registry = new ObjectRegistry({});
     public _on_response: ((msgType: string, response: Response, message: Message) => void) | null;
     public sessionTokens: { [key: string]: IServerSessionBase };
     public channelId: number | null;
     public timeout: number;
-    public readonly messageBuilder: MessageBuilder;
+
+    public messageBuilder?: MessageBuilder;
+
     public receiverCertificate: Buffer | null;
     public clientCertificate: Buffer | null;
     public clientNonce: Buffer | null;
     /**
      * the channel message security mode
@@ -346,26 +352,10 @@ export class ServerSecureChannelLayer extends EventEmitter {
 
         assert(this.securityToken.channelId > 0);
 
         this.serverNonce = null; // will be created when needed
 
-        this.messageBuilder = new MessageBuilder({
-            name: "server",
-            objectFactory: options.objectFactory,
-            privateKey: this.getPrivateKey()
-        });
-
-        this.messageBuilder.on("error", (err) => {
-            // istanbul ignore next
-            if (doDebug) {
-                debugLog(chalk.red("xxxxx error "), err.message.yellow, err.stack);
-                debugLog(chalk.red("xxxxx Server is now closing socket, without further notice"));
-            }
-            // close socket immediately
-            this.close(undefined);
-        });
-
         // at first use a anonymous connection
         this.securityHeader = new AsymmetricAlgorithmSecurityHeader({
             receiverCertificateThumbprint: null,
             securityPolicyUri: "http://opcfoundation.org/UA/SecurityPolicy#None",
             senderCertificate: null
@@ -389,40 +379,71 @@ export class ServerSecureChannelLayer extends EventEmitter {
         this._securityTokenTimeout = null;
 
         this._transactionsCount = 0;
 
         this.sessionTokens = {};
+
+        this.objectFactory = options.objectFactory;
+
         // xx #422 self.setMaxListeners(200); // increase the number of max listener
     }
 
+    private _build_message_builder() {
+        this.messageBuilder = new MessageBuilder({
+            name: "server",
+            objectFactory: this.objectFactory,
+            privateKey: this.getPrivateKey(),
+            maxChunkSize: this.transport.receiveBufferSize,
+            maxChunkCount: this.transport.maxChunkCount,
+            maxMessageSize: this.transport.maxMessageSize
+        });
+        debugLog(" this.transport.maxChunkCount", this.transport.maxChunkCount);
+        debugLog(" this.transport.maxMessageSize", this.transport.maxMessageSize);
+
+        this.messageBuilder.on("error", (err, statusCode) => {
+
+            warningLog("ServerSecureChannel:MessageBuilder: ", err.message);
+            
+            // istanbul ignore next
+            if (doDebug) {
+                debugLog(chalk.red("Error "), err.message, err.stack);
+                debugLog(chalk.red("Server is now closing socket, without further notice"));
+            }
+
+            this.transport.sendErrorMessage(statusCode, err.message);
+
+            // close socket immediately
+            this.close(undefined);
+        });
+    }
+
     public dispose(): void {
         debugLog("ServerSecureChannelLayer#dispose");
         if (this.timeoutId) {
             clearTimeout(this.timeoutId);
             this.timeoutId = null;
         }
         assert(!this.timeoutId, "timeout must have been cleared");
         assert(!this._securityTokenTimeout, "_securityTokenTimeout must have been cleared");
-        assert(this.messageBuilder, "dispose already called ?");
 
         this.parent = null;
         this.serverNonce = null;
         this.objectFactory = undefined;
 
         if (this.messageBuilder) {
             this.messageBuilder.dispose();
-            // xx this.messageBuilder = null;
+            this.messageBuilder = undefined;
         }
         this.securityHeader = null;
 
         if (this.messageChunker) {
             this.messageChunker.dispose();
             // xx this.messageChunker = null;
         }
         if (this.transport) {
             this.transport.dispose();
-            (this as any).transport = null;
+            (this as any).transport = undefined;
         }
         this.channelId = 0xdeadbeef;
         this.timeoutId = null;
         this.sessionTokens = {};
         this.removeAllListeners();
@@ -450,12 +471,16 @@ export class ServerSecureChannelLayer extends EventEmitter {
         }
         return this.parent.getEndpointDescription(this.securityMode, securityPolicy, endpointUri);
     }
 
     public setSecurity(securityMode: MessageSecurityMode, securityPolicy: SecurityPolicy): void {
+        if (!this.messageBuilder) {
+            this._build_message_builder();
+        }
+        assert(this.messageBuilder);
         // TODO verify that the endpoint really supports this mode
-        this.messageBuilder.setSecurity(securityMode, securityPolicy);
+        this.messageBuilder!.setSecurity(securityMode, securityPolicy);
     }
 
     /**
      * @method getCertificateChain
      * @return the X509 DER form certificate
@@ -508,18 +533,23 @@ export class ServerSecureChannelLayer extends EventEmitter {
 
         this.transport.init(socket, (err?: Error) => {
             if (err) {
                 callback(err);
             } else {
+                this._build_message_builder();
+
                 this._rememberClientAddressAndPort();
 
                 this.messageChunker.maxMessageSize = this.transport.maxMessageSize;
 
                 // bind low level TCP transport to messageBuilder
-                this.transport.on("message", (messageChunk: Buffer) => {
-                    assert(this.messageBuilder);
-                    this.messageBuilder.feed(messageChunk);
+                this.transport.on("chunk", (messageChunk: Buffer) => {
+                    // istanbul ignore next
+                    if (doTraceIncomingChunk) {
+                        console.log(hexDump(messageChunk));
+                    }
+                    this.messageBuilder!.feed(messageChunk);
                 });
                 debugLog("ServerSecureChannelLayer : Transport layer has been initialized");
                 debugLog("... now waiting for OpenSecureChannelRequest...");
 
                 ServerSecureChannelLayer.registry.register(this);
@@ -620,16 +650,11 @@ export class ServerSecureChannelLayer extends EventEmitter {
                 return this._send_chunk(callback, messageChunk);
             }
         );
     }
 
-    public send_fatal_error_and_abort(
-        statusCode: StatusCode,
-        description: string,
-        message: Message,
-        callback: ErrorCallback
-    ): void {
+    private _sendFatalErrorAndAbort(statusCode: StatusCode, description: string, message: Message, callback: ErrorCallback): void {
         this.transport.abortWithError(statusCode, description, () => {
             this.close(() => {
                 callback(new Error(description + " statusCode = " + statusCode.toString()));
             });
         });
@@ -798,21 +823,27 @@ export class ServerSecureChannelLayer extends EventEmitter {
     ) {
         /* istanbul ignore next */
         if (doTraceServerMessage) {
             traceRequestMessage(request, channelId, this._counter);
         }
+
+        /* istanbul ignore next */
+        if (!(this.messageBuilder && this.messageBuilder.sequenceHeader && this.messageBuilder.securityHeader)) {
+            return this._on_OpenSecureChannelRequestError(
+                StatusCodes.BadCommunicationError,
+                "internal error",
+                { request, requestId },
+                callback
+            );
+        }
+
         const message = {
             request,
             requestId,
             securityHeader: this.messageBuilder.securityHeader
         };
 
-        /* istanbul ignore next */
-        if (!(this.messageBuilder && this.messageBuilder.sequenceHeader && this.messageBuilder.securityHeader)) {
-            return this._on_OpenSecureChannelRequestError(StatusCodes.BadCommunicationError, "internal error", message, callback);
-        }
-
         requestId = this.messageBuilder.sequenceHeader.requestId;
         if (requestId <= 0) {
             return this._on_OpenSecureChannelRequestError(
                 StatusCodes.BadCommunicationError,
                 "Invalid requestId",
@@ -866,13 +897,18 @@ export class ServerSecureChannelLayer extends EventEmitter {
             return this._on_OpenSecureChannelRequestError(StatusCodes.BadSecurityPolicyRejected, description, message, callback);
         }
 
         this.messageBuilder
             .on("message", (request, msgType, requestId, channelId) => {
-                this._on_common_message(request, msgType, requestId, channelId);
+                this._on_common_message(request as Request, msgType, requestId, channelId);
             })
-            .on("start_chunk", () => {
+            .on("error", (err: Error, statusCode: StatusCode, requestId: number | null) => {
+                /** */
+                this.transport.sendErrorMessage(statusCode, err.message);
+                this.close();
+            })
+            .on("startChunk", () => {
                 if (doPerfMonitoring) {
                     // record tick 0: when the first chunk is received
                     this._tick0 = get_clock_tick();
                 }
             });
@@ -909,22 +945,22 @@ export class ServerSecureChannelLayer extends EventEmitter {
         this._install_wait_for_open_secure_channel_request_timeout(callback, timeout);
 
         const errorHandler = (err: Error) => {
             this._cancel_wait_for_open_secure_channel_request_timeout();
 
-            this.messageBuilder.removeListener("message", messageHandler);
+            this.messageBuilder!.removeListener("message", messageHandler);
             this.close(() => {
                 callback(new Error("/Expecting OpenSecureChannelRequest to be valid " + err.message));
             });
         };
         const messageHandler = (request: Request, msgType: string, requestId: number, channelId: number) => {
             this._cancel_wait_for_open_secure_channel_request_timeout();
-            this.messageBuilder.removeListener("error", errorHandler);
+            this.messageBuilder!.removeListener("error", errorHandler);
             this._on_initial_open_secure_channel_request(callback, request, msgType, requestId, channelId);
         };
-        this.messageBuilder.once("error", errorHandler);
-        this.messageBuilder.once("message", messageHandler);
+        this.messageBuilder!.once("error", errorHandler);
+        this.messageBuilder!.once("message", messageHandler);
     }
 
     private _send_chunk(callback: ErrorCallback | undefined, messageChunk: Buffer | null) {
         if (messageChunk) {
             this.transport.write(messageChunk);
@@ -949,11 +985,11 @@ export class ServerSecureChannelLayer extends EventEmitter {
     }
 
     private _get_security_options_for_OPN(): SecureMessageChunkManagerOptions | null {
         // install sign & sign-encrypt behavior
         if (this.securityMode === MessageSecurityMode.Sign || this.securityMode === MessageSecurityMode.SignAndEncrypt) {
-            const cryptoFactory = this.messageBuilder.cryptoFactory;
+            const cryptoFactory = this.messageBuilder!.cryptoFactory;
             /* istanbul ignore next */
             if (!cryptoFactory) {
                 throw new Error("Internal Error");
             }
             assert(cryptoFactory, "ServerSecureChannelLayer must have a crypto strategy");
@@ -987,11 +1023,11 @@ export class ServerSecureChannelLayer extends EventEmitter {
 
     private _get_security_options_for_MSG(): SecureMessageChunkManagerOptionsPartial | null {
         if (this.securityMode === MessageSecurityMode.None) {
             return null;
         }
-        const cryptoFactory = this.messageBuilder.cryptoFactory;
+        const cryptoFactory = this.messageBuilder!.cryptoFactory;
 
         /* istanbul ignore next */
         if (!cryptoFactory || !this.derivedKeys) {
             return null;
         }
@@ -1161,11 +1197,11 @@ export class ServerSecureChannelLayer extends EventEmitter {
         this.securityHeader = this._prepare_security_header(request, message);
 
         /* istanbul ignore next */
         if (!this.securityHeader) {
             warningLog("Cannot find SecurityHeader !!!!!!!! ");
-            return this.send_fatal_error_and_abort(StatusCodes.BadInternalError, "invalid request", message, callback);
+            return this._sendFatalErrorAndAbort(StatusCodes2.BadSecurityChecksFailed, "invalid request", message, callback);
         }
 
         assert(this.securityHeader);
 
         this.clientNonce = request.clientNonce;
@@ -1177,11 +1213,11 @@ export class ServerSecureChannelLayer extends EventEmitter {
 
         this._set_lifetime(request.requestedLifetime);
 
         this._prepare_security_token(request);
 
-        const cryptoFactory = this.messageBuilder.cryptoFactory;
+        const cryptoFactory = this.messageBuilder!.cryptoFactory;
         if (cryptoFactory) {
             // serverNonce: A random number that shall not be used in any other request. A new
             //    serverNonce shall be generated for each time a SecureChannel is renewed.
             //    This parameter shall have a length equal to key size used for the symmetric
             //    encryption algorithm that is identified by the securityPolicyUri.
@@ -1208,11 +1244,11 @@ export class ServerSecureChannelLayer extends EventEmitter {
             // to help us decrypting and verifying messages received from client
             this.derivedKeys = computeDerivedKeys(cryptoFactory, this.serverNonce, this.clientNonce);
         }
 
         const derivedClientKeys = this.derivedKeys ? this.derivedKeys.derivedClientKeys : null;
-        this.messageBuilder.pushNewToken(this.securityToken, derivedClientKeys);
+        this.messageBuilder!.pushNewToken(this.securityToken, derivedClientKeys);
 
         const derivedServerKeys = this.derivedKeys ? this.derivedKeys.derivedServerKeys : undefined;
 
         this.messageChunker.update({
             // for OPN
@@ -1313,15 +1349,15 @@ export class ServerSecureChannelLayer extends EventEmitter {
         if (doTraceServerMessage) {
             traceRequestMessage(request, channelId, this._counter);
         }
 
         /* istanbul ignore next */
-        if (this.messageBuilder.sequenceHeader === null) {
+        if (this.messageBuilder!.sequenceHeader === null) {
             throw new Error("Internal Error");
         }
 
-        requestId = this.messageBuilder.sequenceHeader.requestId;
+        requestId = this.messageBuilder!.sequenceHeader.requestId;
 
         const message: Message = {
             channel: this,
             request,
             requestId
@@ -1345,11 +1381,11 @@ export class ServerSecureChannelLayer extends EventEmitter {
                 }
 
                 if (this.securityToken && channelId !== this.securityToken.channelId) {
                     // response = new ServiceFault({responseHeader: {serviceResult: certificate_status}});
                     debugLog("Invalid channelId detected =", channelId, " <> ", this.securityToken.channelId);
-                    return this.send_fatal_error_and_abort(
+                    return this._sendFatalErrorAndAbort(
                         StatusCodes.BadCommunicationError,
                         "Invalid Channel Id specified " + this.securityToken.channelId,
                         message,
                         () => {
                             /** */
@@ -1431,11 +1467,11 @@ export class ServerSecureChannelLayer extends EventEmitter {
         debugLog("ServerSecureChannel sendError: ", serviceResult.toString(), description, message.request.constructor.name);
 
         // turn of security mode as we haven't manage to set it to
         this.securityMode = MessageSecurityMode.None;
         // setTimeout(() => {
-        this.send_fatal_error_and_abort(serviceResult, description, message, callback);
+        this._sendFatalErrorAndAbort(serviceResult, description, message, callback);
         // }, ServerSecureChannelLayer.throttleTime); // Throttling keep connection on hold for a while.
     }
 }
 
 (ServerSecureChannelLayer as any).prototype.checkCertificateCallback = callbackify(
diff --git a/packages/node-opcua-secure-channel/test/test_decrypt_unsign.js b/packages/node-opcua-secure-channel/test/test_decrypt_unsign.js
index c0edbe424..b7632b6c5 100644
--- a/packages/node-opcua-secure-channel/test/test_decrypt_unsign.js
+++ b/packages/node-opcua-secure-channel/test/test_decrypt_unsign.js
@@ -86,11 +86,11 @@ const privateKey = inlineText(
     });
 
 
 describe("testing message decryption", function() {
 
-    it("should decrypt an OPN packet and verify that the signature is correct", function() {
+    xit("should decrypt an OPN packet and verify that the signature is correct", function() {
 
 
         // extract the client certificate from the unencrypted part
         const senderCertificate = buffer.slice(0x4C, 0x475 + 0x4C);
 
@@ -99,13 +99,15 @@ describe("testing message decryption", function() {
         const encrypted_part = buffer.slice(start);
 
         // decrypt the encrypted part
         const decrypted_part = crypto_utils.privateDecrypt_long(encrypted_part, privateKey, 128);
 
+        // 1496
         // recompose the buffer
         decrypted_part.copy(buffer, start);
         buffer = buffer.slice(0, start + decrypted_part.length);
+
         buffer.length.should.equal(start + 3 * (128 - 11));
 
         // verify signature
         const publicKey = crypto_utils.toPem(senderCertificate, "CERTIFICATE");
         const options = {
diff --git a/packages/node-opcua-secure-channel/test/test_message_builder.js b/packages/node-opcua-secure-channel/test/test_message_builder.js
index bc83fc5f6..ffdc0688b 100644
--- a/packages/node-opcua-secure-channel/test/test_message_builder.js
+++ b/packages/node-opcua-secure-channel/test/test_message_builder.js
@@ -1,14 +1,14 @@
 const should = require("should");
 
-const { MessageBuilder } = require("..");
-const { SecurityPolicy, MessageSecurityMode} = require("..");
 
 const packets = require("node-opcua-transport/dist/test-fixtures");
 
 const { redirectToFile } = require("node-opcua-debug/nodeJS");
 const debugLog = require("node-opcua-debug").make_debugLog(__filename);
+const { MessageBuilder } = require("..");
+const { SecurityPolicy, MessageSecurityMode } = require("..");
 
 describe("MessageBuilder", function () {
     it("should raise a error event if a HEL or ACK packet is fed instead of a MSG packet ", function (done) {
         const messageBuilder = new MessageBuilder();
 
@@ -67,11 +67,11 @@ describe("MessageBuilder", function () {
                         done();
                     });
 
                 messageBuilder.feed(bad_packet); // OpenSecureChannel message
             },
-            function () {}
+            function () {/** */ }
         );
     }
 
     it("should raise an error if the embedded object id is not known", function (done) {
         const bad_packet = Buffer.from(packets.openChannelRequest1);
@@ -99,11 +99,11 @@ describe("MessageBuilder", function () {
 
     it("should emit a 'invalid_sequence_number' event if a message does not have a 1-increased sequence number", function (done) {
         const messageBuilder = new MessageBuilder();
 
         messageBuilder
-            .on("message", (message) => {})
+            .on("message", (message) => { /** */})
             .on("error", (err) => {
                 console.log(err);
                 done(Error("should not get there"));
             })
             .on("invalid_sequence_number", function (expected, found) {
@@ -119,11 +119,11 @@ describe("MessageBuilder", function () {
     it("some random packet - encrypted ", (done) => {
         const messageBuilder = new MessageBuilder({
         });
         messageBuilder.setSecurity(MessageSecurityMode.Sign, SecurityPolicy.Basic256);
         messageBuilder
-            .on("message", (message) => {})
+            .on("message", (message) => { /** */})
             .on("error", (err) => {
                 console.log(err);
                 done();
             })
             .on("invalid_sequence_number", function (expected, found) {
diff --git a/packages/node-opcua-secure-channel/test/test_message_builder_with_sign_chunks.js b/packages/node-opcua-secure-channel/test/test_message_builder_with_sign_chunks.js
index 3b2a7e05f..f5c28b18c 100644
--- a/packages/node-opcua-secure-channel/test/test_message_builder_with_sign_chunks.js
+++ b/packages/node-opcua-secure-channel/test/test_message_builder_with_sign_chunks.js
@@ -3,16 +3,21 @@ const should = require("should");
 const chalk = require("chalk");
 
 const debugLog = require("node-opcua-debug").make_debugLog("TEST");
 const { hexDump } = require("node-opcua-debug");
 const { MessageSecurityMode } = require("node-opcua-service-secure-channel");
-const crypto_utils = require("node-opcua-crypto");
+const { readPrivateRsaKey } = require("node-opcua-crypto");
 
 const { make_lorem_ipsum_buffer } = require("node-opcua-test-helpers");
 const { getFixture } = require("node-opcua-test-fixtures");
 
-const fake_message_chunk_factory = require("../dist/test_helpers/fake_message_chunk_factory");
+const {
+    iterateOnSymmetricEncryptedChunk,
+    iterateOnSignedAndEncryptedMessageChunks,
+    iterateOnSignedMessageChunks,
+    derivedKeys
+} = require("../dist/test_helpers/fake_message_chunk_factory");
 
 const { MessageBuilder, SecurityPolicy } = require("..");
 
 const private_key_filename = getFixture("certs/server_key_1024.pem");
 
@@ -24,27 +29,31 @@ describe("MessageBuilder with SIGN support", function () {
     const data = make_lorem_ipsum_buffer();
 
     const someBuffer = Buffer.from(data, data.length);
 
     it("should not emit an error event if chunks have valid signature", function (done) {
-        const options = {};
 
-        const messageBuilder = new MessageBuilder(options);
-        messageBuilder.privateKey = crypto_utils.readPrivateRsaKey(private_key_filename);
+        const messageBuilder = new MessageBuilder({
+            maxChunkCount: 10,
+            maxMessageSize: someBuffer.length * 10,
+            maxChunkSize: someBuffer.length  + 1000 ,
+        });
+        messageBuilder.privateKey = readPrivateRsaKey(private_key_filename);
 
         messageBuilder._decodeMessageBody = fake_decodeMessageBody;
 
         messageBuilder
             .on("full_message_body", (message) => {
                 done();
             })
-            .on("message", (message) => {/** */})
+            .on("message", (message) => {/** */ })
             .on("error", (error) => {
+                console.log("ERROR", error);
                 done(error);
             });
 
-        fake_message_chunk_factory.iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
+        iterateOnSignedMessageChunks(someBuffer, (err, chunk) => {
             should.not.exist(err);
             messageBuilder.feed(chunk.slice(0, 20));
             messageBuilder.feed(chunk.slice(20));
         });
     });
@@ -71,11 +80,11 @@ describe("MessageBuilder with SIGN support", function () {
             })
             .on("error", (err) => {
                 done(new Error(" we are not expecting a error event in this case" + err));
             });
 
-        fake_message_chunk_factory.iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
+        iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
             should.not.exist(err);
             messageBuilder.feed(chunk.slice(0, 20));
             messageBuilder.feed(chunk.slice(20));
         });
     });
@@ -98,11 +107,11 @@ describe("MessageBuilder with SIGN support", function () {
                 debugLog(chalk.yellow("this chunk has a altered body ( signature verification failed)"));
                 //xx debugLog(hexDump(chunk));
                 done();
             });
 
-        fake_message_chunk_factory.iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
+        iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
             should.not.exist(err);
 
             // alter artificially the chunk
             // this will damage the chunk signature
             chunk.write("####*** TEMPERED ***#####", 0x3a0);
@@ -118,25 +127,25 @@ describe("MessageBuilder with SIGN & ENCRYPT support (OPN) ", function () {
 
     it("should not emit an error event with valid SIGN & ENCRYPT chunks", function (done) {
         const options = {};
 
         const messageBuilder = new MessageBuilder(options);
-        messageBuilder.privateKey = crypto_utils.readPrivateRsaKey(private_key_filename);
+        messageBuilder.privateKey = readPrivateRsaKey(private_key_filename);
 
         messageBuilder._decodeMessageBody = fake_decodeMessageBody;
 
         messageBuilder
             .on("full_message_body", (message) => {
                 message.toString().should.eql(lorem_ipsum_buffer.toString());
                 done();
             })
-            .on("message", (message) => {/** */})
+            .on("message", (message) => {/** */ })
             .on("error", (error) => {
                 done(error);
             });
 
-        fake_message_chunk_factory.iterateOnSignedAndEncryptedMessageChunks(lorem_ipsum_buffer, function (err, chunk) {
+        iterateOnSignedAndEncryptedMessageChunks(lorem_ipsum_buffer, function (err, chunk) {
             should.not.exist(err);
             //xx console.log(hexDump(chunk));
             messageBuilder.feed(chunk.slice(0, 20));
             messageBuilder.feed(chunk.slice(20));
         });
@@ -145,34 +154,39 @@ describe("MessageBuilder with SIGN & ENCRYPT support (OPN) ", function () {
 
 describe("MessageBuilder with SIGN & ENCRYPT support (MSG) ", function () {
     const lorem_ipsum_buffer = make_lorem_ipsum_buffer();
 
     it("should process a signed and encrypted message", function (done) {
-        const options = {};
-        const messageBuilder = new MessageBuilder(options);
+        const messageBuilder = new MessageBuilder({
+            maxMessageSize: 1000000,
+            maxChunkSize: 2048,
+            maxChunkCount: 5
+        });
         messageBuilder._decodeMessageBody = fake_decodeMessageBody;
 
         messageBuilder.securityPolicy = SecurityPolicy.Basic128Rsa15;
 
-        messageBuilder.privateKey = crypto_utils.readPrivateRsaKey(private_key_filename);
+        messageBuilder.privateKey = readPrivateRsaKey(private_key_filename);
 
         messageBuilder.securityMode = MessageSecurityMode.SignAndEncrypt;
 
-        messageBuilder.pushNewToken({ tokenId: 10 }, fake_message_chunk_factory.derivedKeys);
+        messageBuilder.pushNewToken({ tokenId: 10 }, derivedKeys);
 
+        let _err;
         messageBuilder
             .on("full_message_body", (message) => {
                 //xx console.log(hexDump(message));
                 message.toString().should.eql(lorem_ipsum_buffer.toString());
                 done();
             })
-            .on("message", (message) => {/** */})
+            .on("message", (message) => {/** */ })
             .on("error", (error) => {
+                console.log("err ", error.message);
                 done(error);
             });
 
-        fake_message_chunk_factory.iterateOnSymmetricEncryptedChunk(lorem_ipsum_buffer, function (err, chunk) {
+        iterateOnSymmetricEncryptedChunk(lorem_ipsum_buffer, function (err, chunk) {
             should.not.exist(err);
             messageBuilder.feed(chunk);
         });
     });
 });
diff --git a/packages/node-opcua-secure-channel/test/test_secure_channel_layer.js b/packages/node-opcua-secure-channel/test/test_secure_channel_layer.js
index 4f05ade42..0041378b0 100644
--- a/packages/node-opcua-secure-channel/test/test_secure_channel_layer.js
+++ b/packages/node-opcua-secure-channel/test/test_secure_channel_layer.js
@@ -2,10 +2,11 @@
 
 const { promisify } = require("util");
 const should = require("should");
 const { ReadRequest } = require("node-opcua-types");
 const { make_debugLog, checkDebugFlag } = require("node-opcua-debug");
+const { StatusCodes } = require("node-opcua-status-code");
 
 const { ClientSecureChannelLayer, ServerSecureChannelLayer } = require("..");
 
 
 const debugLog = make_debugLog("TEST");
@@ -74,11 +75,11 @@ function startServer(holder, callback) {
         const serverChannel = new ServerSecureChannelLayer({
             timeout: 1000 * 1000
         });
         holder.serverChannel = serverChannel;
         serverChannel.timeout = 1000 * 1000;
-        serverChannel.init(socket, function () {});
+        serverChannel.init(socket, function () {/** */ });
     });
 
     callback();
 }
 function simulate_server_abrupt_shutdown(holder) {
@@ -172,11 +173,11 @@ describe("Testing ClientSecureChannel with BackOff reconnection strategy", funct
         secureChannel.on("backoff", function (number, delay) {
             debugLog(number + " " + delay + "ms");
             nbRetry = number + 1;
             if (number === 2) {
                 debugLog("Let's abort the connection now");
-                secureChannel.abortConnection(function () {});
+                secureChannel.abortConnection(function () {/** */ });
             }
         });
         secureChannel.create(endpoint, function (err) {
             nbRetry.should.not.equal(options.connectionStrategy.maxRetry);
             nbRetry.should.be.greaterThan(2);
@@ -187,11 +188,13 @@ describe("Testing ClientSecureChannel with BackOff reconnection strategy", funct
                 setTimeout(done, 100);
             });
         });
     });
 
+    // eslint-disable-next-line @typescript-eslint/no-this-alias
     const test = this;
+
     it("WW2-c secureChannel that starts before the server is up and running should eventually connect without error", function (done) {
         const options = {
             connectionStrategy: {
                 maxRetry: 3000,
                 initialDelay: 10,
@@ -290,11 +293,12 @@ describe("Testing ClientSecureChannel with BackOff reconnection strategy", funct
         await pause(10000);
 
         async function closeChannel() {
             await promisify(secureChannel.close).call(secureChannel);
         }
-        await closeChannel().should.be.rejectedWith(/Transport disconnected/);
+
+        await closeChannel(); // .should.be.rejectedWith(/Transport disconnected/);
 
         await promisify(stopServer)(holder);
 
         debugLog("DONE! ");
     });
@@ -320,12 +324,13 @@ describe("Testing ClientSecureChannel with BackOff reconnection strategy", funct
 
         try {
             const endpoint = `opc.tcp://localhost:${port}/UA/Sample`;
             await promisify(secureChannel.create).call(secureChannel, endpoint);
 
-            await promisify(secureChannel.closeWithError).call(secureChannel, new Error("Sabotage"));
+            await promisify(secureChannel.closeWithError).call(secureChannel, StatusCodes.Bad, new Error("Sabotage"));
         } catch (err) {
+            console.log(err.message);
             throw err;
         } finally {
             debugLog("Done ");
             await promisify(stopServer)(holder);
         }
diff --git a/packages/node-opcua-secure-channel/test/test_secure_channel_service.js b/packages/node-opcua-secure-channel/test/test_secure_channel_service.js
index c06f4281b..97ac97d31 100644
--- a/packages/node-opcua-secure-channel/test/test_secure_channel_service.js
+++ b/packages/node-opcua-secure-channel/test/test_secure_channel_service.js
@@ -67,11 +67,11 @@ describe("SecureMessageChunkManager", function() {
                     const messageBuilder = new MessageBuilder();
                     messageBuilder
                         .on("full_message_body", function(full_message_body) {
                             compare_buffers(fullBufferForVerif, full_message_body, 40);
                         })
-                        .on("message", function(reconstructed_message) {
+                        .on("message", (reconstructed_message) => {
                             // message has been fully reconstructed here :
                             // check that the reconstructed message equal the original_message
 
                             //xx console.log("message = ", util.inspect(reconstructed_message, {colors: true,depth: 10}));
                             //xx console.log("origianm= ",  util.inspect(endPointResponse, {colors: true,depth: 10}));
@@ -111,11 +111,11 @@ describe("SecureMessageChunkManager", function() {
         messageBuilder
             .on("full_message_body", function(full_message_body) {
                 debugLog(" On raw Buffer \n");
                 debugLog(hexDump(full_message_body));
             })
-            .on("message", function(message) {
+            .on("message", (message) => {
                 debugLog(" message ", message);
 
                 message.responseHeader.serviceResult.value.should.eql(0x80820000);
 
                 done();
diff --git a/packages/node-opcua-secure-channel/test/test_security.ts b/packages/node-opcua-secure-channel/test/test_security.ts
index ec827c42d..1f6f9ab6c 100644
--- a/packages/node-opcua-secure-channel/test/test_security.ts
+++ b/packages/node-opcua-secure-channel/test/test_security.ts
@@ -124,13 +124,11 @@ describe("Testing secure client and server connection", () => {
         ): void {
             s.call(this, msgType, response, message, callback);
         };
 
         function simulateOpenSecureChannel(callback: SimpleCallback) {
-           
             clientChannel.create("fake://foobar:123", (err?: Error) => {
-                
                 if (param.shouldFailAtClientConnection) {
                     if (!err) {
                         return callback(new Error(" Should have failed here !"));
                     }
                     callback();
@@ -153,12 +151,12 @@ describe("Testing secure client and server connection", () => {
             });
 
             doDebug && console.log(" now sending a request " + request.constructor.name);
 
             clientChannel.performMessageTransaction(request, (err, response) => {
-                doDebug &&  console.log("client received a response ", response?.constructor.name);
-                doDebug &&  console.log(response?.toString());
+                doDebug && console.log("client received a response ", response?.constructor.name);
+                doDebug && console.log(response?.toString());
                 callback(err || undefined);
             });
         }
 
         const transportServer = directTransport.server as any as Socket;
@@ -218,10 +216,13 @@ describe("Testing secure client and server connection", () => {
                     });
                     //  clientChannel.connect("")
                     callback();
                 },
                 (callback: SimpleCallback) => {
+
+                    (serverSChannel as any)._build_message_builder();
+
                     serverSChannel.setSecurity(param.securityMode, param.securityPolicy);
                     if (param.clientCertificate) {
                         const certMan = serverSChannel.certificateManager;
                         certMan.trustCertificate(param.clientCertificate, (err?: Error | null) => {
                             callback(err!);
@@ -316,14 +317,15 @@ describe("Testing secure client and server connection", () => {
             },
             done
         );
     }
 
-    it("client & server channel  - with security ", (done) => {
+    it("RR-client & server channel  - with security ", (done) => {
         performTest1(2048, 2048, SecurityPolicy.Basic128Rsa15, done);
     });
 
+
     it("client & server channel  - A", (done) => {
         performTest1(2048, 2048, SecurityPolicy.Basic128Rsa15, done);
     });
 
     for (const sizeC of [1024, 2048, 3072, 4096]) {
diff --git a/packages/node-opcua-secure-channel/test/test_server_secure_channel_layer.js b/packages/node-opcua-secure-channel/test/test_server_secure_channel_layer.js
index 25feff503..36caaaf2a 100644
--- a/packages/node-opcua-secure-channel/test/test_server_secure_channel_layer.js
+++ b/packages/node-opcua-secure-channel/test/test_server_secure_channel_layer.js
@@ -1,16 +1,22 @@
 const should = require("should");
 
 const { StatusCodes } = require("node-opcua-status-code");
-
-const { ServerSecureChannelLayer, MessageSecurityMode, SecurityPolicy } = require("..");
+const { HelloMessage } = require("node-opcua-transport");
+const { OpenSecureChannelRequest, SecurityTokenRequestType, ReadRequest } = require("node-opcua-types");
+const { hexDump } = require("node-opcua-crypto");
 
 const debugLog = require("node-opcua-debug").make_debugLog(__filename);
 const { DirectTransport } = require("node-opcua-transport/dist/test_helpers");
 const { GetEndpointsResponse } = require("node-opcua-service-endpoints");
 const fixtures = require("node-opcua-transport/dist/test-fixtures");
+const { BinaryStream } = require("node-opcua-binary-stream");
+
+const { ServerSecureChannelLayer, MessageSecurityMode, SecurityPolicy, MessageChunker } = require("..");
+const { pause } = require("../../node-opcua-end2end-test/test/discovery/_helper");
 
+// eslint-disable-next-line import/order
 const describe = require("node-opcua-leak-detector").describeWithLeakDetector;
 describe("testing ServerSecureChannelLayer ", function () {
     this.timeout(10000);
 
     it("KK1 should create a ServerSecureChannelLayer", () => {
@@ -141,11 +147,11 @@ describe("testing ServerSecureChannelLayer ", function () {
                 const { getEndpointsRequest1 } = fixtures; // GetEndPoints
                 getEndpointsRequest1.writeInt16LE(serverSecureChannel.channelId, 8);
                 node.client.write(getEndpointsRequest1);
             });
         });
-        serverSecureChannel.on("message", function (message) {
+        serverSecureChannel.on("message", (message) => {
             message.request.schema.name.should.equal("GetEndpointsRequest");
             setImmediate(() => {
                 serverSecureChannel.close(() => {
                     serverSecureChannel.dispose();
                     done();
@@ -175,21 +181,20 @@ describe("testing ServerSecureChannelLayer ", function () {
         serverSecureChannel.init(node.server, (err) => {
             should.not.exist(err);
         });
 
         let nb_on_message_calls = 0;
-        serverSecureChannel.on("message", function (message) {
+        serverSecureChannel.on("message", (message) => {
             console.log("message ", message.request.toString());
             message.request.schema.name.should.not.equal("CloseSecureChannelRequest");
             nb_on_message_calls.should.equal(0);
             nb_on_message_calls += 1;
 
             message.request.schema.name.should.equal("GetEndpointsRequest");
-            serverSecureChannel.send_response("MSG", new GetEndpointsResponse(), message, () => {});
+            serverSecureChannel.send_response("MSG", new GetEndpointsResponse(), message, () => {/** */ });
         });
 
-        let isDone = false;
         serverSecureChannel.on("abort", () => {
             console.log("Receive Abort");
         });
         async function send(message) {
             await new Promise((resolve) => {
@@ -224,19 +229,20 @@ describe("testing ServerSecureChannelLayer ", function () {
 
         serverSecureChannel.dispose();
         serverSecureChannel = null;
 
         node.shutdown(() => {
-            isDone = true;
+            /** */
         });
     });
 
     function fuzzTest(messages, done) {
         const node = new DirectTransport();
 
         let server_has_emitted_the_abort_message = false;
         let serverSecureChannel = new ServerSecureChannelLayer({});
+
         serverSecureChannel.setSecurity(MessageSecurityMode.None, SecurityPolicy.None);
 
         serverSecureChannel.timeout = 1000;
 
         let err;
@@ -262,18 +268,21 @@ describe("testing ServerSecureChannelLayer ", function () {
     }
     it("FUZZ4- should not crash with a corrupted openChannelRequest message", (done) => {
         const { helloMessage1, getEndpointsRequest1 } = fixtures;
         fuzzTest([helloMessage1, getEndpointsRequest1], done);
     });
+
     it("FUZZ5- should not crash with a corrupted openChannelRequest message", (done) => {
         const { helloMessage1, altered_openChannelRequest1 } = fixtures; // HEL
         fuzzTest([helloMessage1, altered_openChannelRequest1], done);
     });
+
     it("FUZZ6- should not crash with a corrupted openChannelRequest message", (done) => {
         const { helloMessage1, altered_openChannelRequest2 } = fixtures; // HEL
         fuzzTest([helloMessage1, altered_openChannelRequest2], done);
     });
+
     it("FUZZ7- should not crash with a corrupted request message", (done) => {
         function test(messages, done) {
             const node = new DirectTransport();
 
             let server_has_emitted_the_abort_message = false;
@@ -317,6 +326,136 @@ describe("testing ServerSecureChannelLayer ", function () {
         }
 
         const { helloMessage1, openChannelRequest1, altered_getEndpointsRequest1 } = fixtures; // HEL
         test([helloMessage1, openChannelRequest1, altered_getEndpointsRequest1], done);
     });
+
+    it("KK8 should not accept message with too large chunk", async () => {
+        const node = new DirectTransport();
+
+        let serverSecureChannel = new ServerSecureChannelLayer({
+        });
+
+        serverSecureChannel.setSecurity(MessageSecurityMode.None, SecurityPolicy.None);
+        serverSecureChannel.timeout = 100000;
+
+
+        let initialized = false;
+        serverSecureChannel.init(node.server, (err) => {
+            initialized = true;
+            should.not.exist(err);
+        });
+
+        async function send(chunk) {
+            return await new Promise((resolve) => {
+                node.client.once("data", (data) => {
+                    resolve(data);
+                });
+                node.client.write(chunk);
+            });
+        }
+
+        async function send1(msg, request) {
+
+            const l = request.binaryStoreSize();
+
+            // craft a HELLO Message        
+            const b = new BinaryStream(l + 8);
+            b.writeInt8(msg[0].charCodeAt(0));
+            b.writeInt8(msg[1].charCodeAt(0));
+            b.writeInt8(msg[2].charCodeAt(0));
+            b.writeInt8("F".charCodeAt(0));
+            b.writeUInt32(0);
+            request.encode(b);
+            b.buffer.writeInt32LE(b.length, 4);
+
+            console.log(`sending\n${hexDump(b.buffer)}`)
+
+            const rep = await send(b.buffer);
+            console.log(`receiving\n${hexDump(rep)}`);
+            return rep;
+        }
+        async function sendHello() {
+            // eslint-disable-next-line no-undef
+            const helloMessage = new HelloMessage({
+                protocolVersion: 0,// UInt32;
+                receiveBufferSize: 8 * 1024,// UInt32;
+                sendBufferSize: 8 * 1024,
+                maxMessageSize: 16 * 1024,
+                maxChunkCount: 2,
+                endpointUrl: "opc.tcp://localhost:1234/SomeEndpoint"
+            });
+            await send1("HEL", helloMessage);
+
+        }
+
+        let requestId = 1;
+        async function send2(msg, request, tweakerFunc) {
+            const messageChunker = new MessageChunker();
+
+            return await new Promise((resolve,reject) => {
+                node.client.once("data", (chunk) => {
+                    requestId += 1;
+                    console.log(`receiving\n${hexDump(chunk)}`);
+                    resolve(chunk);
+                    resolve();
+                });
+                node.client.once("error", (err) => {
+                    reject(err);
+                })
+                messageChunker.chunkSecureMessage(msg, {
+                    requestId,
+                    securityMode: MessageSecurityMode.None,
+                }, request, (chunk) => {
+                    if (chunk) {
+                        if (tweakerFunc) {
+                            chunk = tweakerFunc(chunk);
+                        }
+                        console.log(`sending\n${hexDump(chunk)}`);
+                        node.client.write(chunk)
+                    } else {
+                        console.log("done.");
+                    }
+                });
+            });
+
+        }
+
+        async function sendOpenChannel() {
+
+            const openChannelRequest = new OpenSecureChannelRequest({
+                clientNonce: null,
+                clientProtocolVersion: 0,
+                requestHeader: {
+                },
+                requestType: SecurityTokenRequestType.Init,
+                requestedLifetime: 100000,
+                securityMode: MessageSecurityMode.None,
+            });
+            return await send2("OPN", openChannelRequest);
+
+        }
+
+        async function sendTooLargeChunkMessage() {
+            return await send2("MSG", new ReadRequest({}), (chunk)=>{
+                chunk.writeUInt32LE(0xFFFF,4);
+                return chunk;
+            });
+        }
+
+        await sendHello();
+        await sendOpenChannel();
+        await sendTooLargeChunkMessage();
+
+        // console.log(serverSecureChannel.transport);
+
+        await new Promise((resolve) => {
+            serverSecureChannel.close(() => {
+                serverSecureChannel.dispose();
+                resolve();
+            });
+        });
+        node.shutdown(() => {/** */ });
+
+    });
+
 });
diff --git a/packages/node-opcua-secure-channel/test/test_various_packets.js b/packages/node-opcua-secure-channel/test/test_various_packets.js
index a91617a8f..7bd90ce9f 100644
--- a/packages/node-opcua-secure-channel/test/test_various_packets.js
+++ b/packages/node-opcua-secure-channel/test/test_various_packets.js
@@ -1,40 +1,45 @@
 const should = require("should");
 
-const MessageBuilder = require("..").MessageBuilder;
 const packets = require("node-opcua-transport/dist/test-fixtures");
 const { BinaryStream } = require("node-opcua-binary-stream");
+const { decodeExpandedNodeId } = require("node-opcua-basic-types");
+const { analyseExtensionObject } = require("node-opcua-packet-analyzer");
 
+const { MessageBuilder } = require("..");
+const { MessageSecurityMode, SecurityPolicy } = require("..");
 
-xdescribe("testing with problematic packet", function () {
+const full_message_body = require("../test_fixtures/fixture_problematic_ReadResponse.js").packet_ReadResponse;
+
+describe("testing with problematic packet", function () {
 
     it("should raise a message event after reassembling and decoding a message ", function (done) {
 
         const messageBuilder = new MessageBuilder();
-        messageBuilder.setSecurity(MessageSecurityMode.None,SecurityPolicy.None);
+        messageBuilder.setSecurity(MessageSecurityMode.None, SecurityPolicy.None);
 
         let full_message_body_event_received = false;
         let on_message__received = false;
 
         messageBuilder.
-        on("message", function (message) {
-            on_message__received = true;
-            message.schema.name.should.equal("GetEndpointsResponse");
+            on("message", function (message) {
+                on_message__received = true;
+                message.schema.name.should.equal("GetEndpointsResponse");
 
-            on_message__received.should.equal(true);
-            full_message_body_event_received.should.equal(true);
-            done();
+                on_message__received.should.equal(true);
+                full_message_body_event_received.should.equal(true);
+                done();
 
-        }).
-        on("full_message_body", function (full_message_body) {
-            full_message_body_event_received = true;
+            }).
+            on("full_message_body", function (full_message_body) {
+                full_message_body_event_received = true;
 
-        }).
-        on("error", function (err) {
-            should.not.exist(err);
-            throw new Error("should not get there");
-        });
+            }).
+            on("error", function (err) {
+                should.not.exist(err);
+                throw new Error("should not get there");
+            });
 
         messageBuilder.feed(packets.getEndpointsRequest2_chunk1); // GEP response chunk  1
         messageBuilder.feed(packets.getEndpointsRequest2_chunk2); // GEP response chunk  2
     });
 
@@ -42,54 +47,47 @@ xdescribe("testing with problematic packet", function () {
 
         const messageBuilder = new MessageBuilder();
 
         let messageCount = 0;
         messageBuilder.
-        on("message", function (message) {
-            messageCount += 1;
-            if (messageCount === 2) {
-                done();
-            }
-        }).
-        on("error", function (err) {
-            console.log(err);
-            throw new Error("should not get there");
-        }).
-        on("invalid_sequence_number", function (expected, found) {
-            throw new Error("should not received a invalid_sequence_number here");
-        });
+            on("message", function (message) {
+                messageCount += 1;
+                if (messageCount === 2) {
+                    done();
+                }
+            }).
+            on("error", function (err) {
+                console.log(err);
+                throw new Error("should not get there");
+            }).
+            on("invalid_sequence_number", function (expected, found) {
+                throw new Error("should not received a invalid_sequence_number here");
+            });
 
 
         messageBuilder.feed(packets.openChannelRequest1); // OpenSecureChannelRequest chunk 2
         messageBuilder.feed(packets.getEndpointsRequest1); // OpenSecureChannelRequest chunk 3
 
     });
     it("should decode this problematic ReadResponse ", function (done) {
 
-        //
-        const services = require("../src/services");
-
-        const ec = require("node-opcua-basic-types");
 
-        const full_message_body = require("../test_fixtures/fixture_problematic_ReadResponse.js").packet_ReadResponse;
         const binaryStream = new BinaryStream(full_message_body);
 
         // read expandedNodeId:
-        const id = ec.decodeExpandedNodeId(binaryStream);
+        const id = decodeExpandedNodeId(binaryStream);
 
-        this.objectFactory = require("node-opcua-factory");
+        // this.objectFactory = objectFactory;
 
-        // construct the object
-        const objMessage = this.objectFactory.constructObject(id);
+        // // construct the object
+        // const objMessage = this.objectFactory.constructObject(id);
 
-        if (!objMessage) {
-            console.log(services);
-            console.log("cannot construct object with id" + id.toString());
-        }
-        objMessage.constructor.name.should.eql("ReadResponse");
+        // if (!objMessage) {
+        //     console.log("cannot construct object with id" + id.toString());
+        // }
+        // objMessage.constructor.name.should.eql("ReadResponse");
 
-        const analyseExtensionObject = require("node-opcua-packet-analyzer").analyseExtensionObject;
 
         analyseExtensionObject(full_message_body);
 
         done();
     });
diff --git a/packages/node-opcua-secure-channel/test_fixtures/fixture_problematic_ReadResponse.js b/packages/node-opcua-secure-channel/test_fixtures/fixture_problematic_ReadResponse.js
index 080be314d..b6d90471b 100644
--- a/packages/node-opcua-secure-channel/test_fixtures/fixture_problematic_ReadResponse.js
+++ b/packages/node-opcua-secure-channel/test_fixtures/fixture_problematic_ReadResponse.js
@@ -1,11 +1,11 @@
 "use strict";
 
-const { makebuffer_from_trace  } = require("node-opcua-debug");
+const { makeBufferFromTrace  } = require("node-opcua-debug");
 
 
-exports.packet_ReadResponse= makebuffer_from_trace(function () {
+exports.packet_ReadResponse= makeBufferFromTrace(function () {
     /*
      00000000: 01 00 7a 02 87 bb 66 e8 6e 19 d1 01 e0 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00    ..z..;fhn.Q.`...................
      00000020: 0d c1 18 00 00 00 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 03 00    .A..............................
      00000040: 00 00 02 00 00 00 04 00 00 00 03 00 00 00 c4 c6 a9 cf 30 19 d1 01 87 bb 66 e8 6e 19 d1 01 09 03    ..............DF)O0.Q..;fhn.Q...
      00000060: 03 87 bb 66 e8 6e 19 d1 01 09 03 03 87 bb 66 e8 6e 19 d1 01 00 00 00 00                            ..;fhn.Q.....;fhn.Q.....
diff --git a/packages/node-opcua-secure-channel/test_helpers/fake_message_chunk_factory.ts b/packages/node-opcua-secure-channel/test_helpers/fake_message_chunk_factory.ts
index 37470c0e6..2f8403bc6 100644
--- a/packages/node-opcua-secure-channel/test_helpers/fake_message_chunk_factory.ts
+++ b/packages/node-opcua-secure-channel/test_helpers/fake_message_chunk_factory.ts
@@ -99,11 +99,11 @@ const globalOptions = {
     algorithm: "aes-128-cbc"
 };
 
 export const derivedKeys: DerivedKeys = computeDerivedKeys(secret, seed, globalOptions);
 
-export function iterateOnSymmetricEncryptedChunk(buffer: Buffer, callback: ChunkVisitorFunc) {
+export function iterateOnSymmetricEncryptedChunk(buffer: Buffer, onChunkFunc: ChunkVisitorFunc) {
 
     const options: SecureMessageChunkManagerOptions = {
         chunkSize: 1024,
         encryptBufferFunc:  (chunk: Buffer) => encryptBufferWithDerivedKeys(chunk, derivedKeys),
         plainBlockSize: derivedKeys.encryptingBlockSize,
@@ -118,9 +118,9 @@ export function iterateOnSymmetricEncryptedChunk(buffer: Buffer, callback: Chunk
     const securityHeader = new SymmetricAlgorithmSecurityHeader({
         tokenId: 10
     });
 
     const msgChunkManager = new SecureMessageChunkManager("MSG", options, securityHeader, sequenceNumberGenerator);
-    msgChunkManager.on("chunk", (chunk, final) => callback(null, chunk));
+    msgChunkManager.on("chunk", (chunk, final) => onChunkFunc(null, chunk));
     msgChunkManager.write(buffer, buffer.length);
     msgChunkManager.end();
 }
diff --git a/packages/node-opcua-secure-channel/test_helpers/verify_message_chunk.ts b/packages/node-opcua-secure-channel/test_helpers/verify_message_chunk.ts
index a96c03796..0768fb6f0 100644
--- a/packages/node-opcua-secure-channel/test_helpers/verify_message_chunk.ts
+++ b/packages/node-opcua-secure-channel/test_helpers/verify_message_chunk.ts
@@ -6,25 +6,35 @@ import { MessageBuilder, messageHeaderToString, MessageSecurityMode, SecurityPol
  *
  * @param packets
  */
 export function verify_multi_chunk_message(packets: any[]) {
 
-    const messageBuilder = new MessageBuilder({});
+    const maxChunkSize = packets.map((p) => p.length).reduce((a, b) => Math.max(a, b), 0);
+
+    const messageBuilder = new MessageBuilder({
+        maxChunkCount: packets.length + 1,
+        maxMessageSize: 1000000,
+        maxChunkSize
+    });
     messageBuilder.setSecurity(MessageSecurityMode.None, SecurityPolicy.None);
 
     messageBuilder.on("full_message_body", (fullMessageBody: Buffer) => {
         console.log("full_message_body received:");
         analyseExtensionObject(fullMessageBody, 0, 0);
     });
-    messageBuilder.on("start_chunk", (info) => {
+    messageBuilder.on("startChunk", (info) => {
         console.log(" starting new chunk ", info.messageHeader);
     });
 
     messageBuilder.on("chunk", (messageChunk) => {
         console.log(messageHeaderToString(messageChunk));
     });
 
+    messageBuilder.on("error", (err) => {
+        console.log("verify_multi_chunk_message : err", err.message);
+    });
+
     let totalLength = 0;
     packets.forEach((packet) => {
         if (packet instanceof Array) {
             packet = Buffer.from(packet);
         }
diff --git a/packages/node-opcua-server/source/opcua_server.ts b/packages/node-opcua-server/source/opcua_server.ts
index 45428640c..cfca536de 100644
--- a/packages/node-opcua-server/source/opcua_server.ts
+++ b/packages/node-opcua-server/source/opcua_server.ts
@@ -165,12 +165,11 @@ import { ClosingReason, CreateSessionOption, ServerEngine } from "./server_engin
 import { ServerSession } from "./server_session";
 import { CreateMonitoredItemHook, DeleteMonitoredItemHook, Subscription } from "./server_subscription";
 import { ISocketData } from "./i_socket_data";
 import { IChannelData } from "./i_channel_data";
 import { UAUserManagerBase, makeUserManager, UserManagerOptions } from "./user_manager";
-import { bindRoleSet} from "./user_manager_ua";
-
+import { bindRoleSet } from "./user_manager_ua";
 
 function isSubscriptionIdInvalid(subscriptionId: number): boolean {
     return subscriptionId < 0 || subscriptionId >= 0xffffffff;
 }
 
@@ -1401,11 +1400,11 @@ export class OPCUAServer extends OPCUABaseServer {
     protected computeServerSignature(
         channel: ServerSecureChannelLayer,
         clientCertificate: Certificate,
         clientNonce: Nonce
     ): SignatureData | undefined {
-        return computeSignature(clientCertificate, clientNonce, this.getPrivateKey(), channel.messageBuilder.securityPolicy);
+        return computeSignature(clientCertificate, clientNonce, this.getPrivateKey(), channel.messageBuilder!.securityPolicy);
     }
 
     /**
      *
      * @param session
@@ -1417,11 +1416,11 @@ export class OPCUAServer extends OPCUABaseServer {
         session: ServerSession,
         channel: ServerSecureChannelLayer,
         clientSignature: SignatureData
     ): boolean {
         const clientCertificate = channel.receiverCertificate!;
-        const securityPolicy = channel.messageBuilder.securityPolicy;
+        const securityPolicy = channel.messageBuilder!.securityPolicy;
         const serverCertificate = this.getCertificate();
 
         const result = verifySignature(serverCertificate, session.nonce!, clientSignature, clientCertificate, securityPolicy);
 
         return result;
@@ -1470,11 +1469,11 @@ export class OPCUAServer extends OPCUABaseServer {
         userIdentityToken: X509IdentityToken,
         userTokenSignature: SignatureData,
         callback: (err: Error | null, statusCode?: StatusCode) => void
     ): void {
         assert(userIdentityToken instanceof X509IdentityToken);
-        assert(typeof callback === 'function');
+        assert(typeof callback === "function");
 
         const securityPolicy = adjustSecurityPolicy(channel, userTokenPolicy.securityPolicyUri);
 
         const cryptoFactory = getCryptoFactory(securityPolicy);
         /* istanbul ignore next */
@@ -1603,11 +1602,11 @@ export class OPCUAServer extends OPCUABaseServer {
         userIdentityToken: UserIdentityToken,
         userTokenSignature: SignatureData,
         endpointDescription: EndpointDescription,
         callback: (err: Error | null, statusCode?: StatusCode) => void
     ): void {
-        assert(typeof callback === 'function');
+        assert(typeof callback === "function");
         /* istanbul ignore next */
         if (!userIdentityToken) {
             throw new Error("Invalid token");
         }
 
diff --git a/packages/node-opcua-transport/source/client_tcp_transport.ts b/packages/node-opcua-transport/source/client_tcp_transport.ts
index ece32cdc5..e3755a67f 100644
--- a/packages/node-opcua-transport/source/client_tcp_transport.ts
+++ b/packages/node-opcua-transport/source/client_tcp_transport.ts
@@ -54,16 +54,16 @@ function createClientSocket(endpointUrl: string): Socket {
             throw new Error(msg);
         }
     }
 }
 export interface ClientTCP_transport {
-    on(eventName: "message", eventHandler: (message: Buffer) => void): this;
+    on(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
     on(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
     on(eventName: "close", eventHandler: (err: Error | null) => void): this;
     on(eventName: "connection_break", eventHandler: () => void): this;
 
-    once(eventName: "message", eventHandler: (message: Buffer) => void): this;
+    once(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
     once(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
     once(eventName: "close", eventHandler: (err: Error | null) => void): this;
     once(eventName: "connection_break", eventHandler: () => void): this;
 }
 
@@ -94,20 +94,25 @@ export interface ClientTCP_transport {
  *
  *    transport.write(message_chunk,'F');
  *
  *    ....
  *
- *    transport.on("message",function(message_chunk) {
- *        // do something with message from server...
+ *    transport.on("chunk",function(message_chunk) {
+ *        // do something with chunk from server...
  *    });
  *
  *
  *    ```
  *
  *
  */
 export class ClientTCP_transport extends TCP_transport {
+    public static defaultMaxChunk = 0; // 0 - no limits
+    public static defaultMaxMessageSize = 0; // 0 - no limits
+    public static defaultReceiveBufferSize = 1024 * 64 * 10;
+    public static defaultSendBufferSize = 1024 * 64 * 10; // 8192 min,
+
     public endpointUrl: string;
     public serverUri: string;
     public numberOfRetry: number;
     public parameters?: AcknowledgeMessage;
 
@@ -119,10 +124,15 @@ export class ClientTCP_transport extends TCP_transport {
         this.connected = false;
         this.endpointUrl = "";
         this.serverUri = "";
         this._counter = 0;
         this.numberOfRetry = 0;
+
+        // initially before HEL/ACK
+        this.maxChunkCount = 1;
+        this.maxMessageSize = 4 * 1024;
+        this.receiveBufferSize = 4 * 1024;
     }
 
     public dispose(): void {
         /* istanbul ignore next */
         if (doDebug) {
@@ -236,10 +246,11 @@ export class ClientTCP_transport extends TCP_transport {
         };
 
         this._socket.once("error", _on_socket_error_for_connect);
         this._socket.once("end", _on_socket_end_for_connect);
         this._socket.once("connect", _on_socket_connect);
+
         this._install_socket(this._socket);
     }
 
     protected on_socket_ended(err: Error | null): void {
         debugLog("on_socket_ended", this.name, err ? err.message : "");
@@ -278,11 +289,13 @@ export class ClientTCP_transport extends TCP_transport {
             callback(err);
         } else {
             responseClass = AcknowledgeMessage;
             _stream.rewind();
             response = decodeMessage(_stream, responseClass);
+
             this.parameters = response as AcknowledgeMessage;
+            this.setLimits(response as AcknowledgeMessage);
 
             // istanbul ignore next
             if (doTraceHelloAck) {
                 warningLog("receiving Ack\n", response.toString());
             }
@@ -302,16 +315,15 @@ export class ClientTCP_transport extends TCP_transport {
 
         // Write a message to the socket as soon as the client is connected,
         // the server will receive it as message from the client
         const helloMessage = new HelloMessage({
             endpointUrl: this.endpointUrl,
-            maxChunkCount: 0, // 0 - no limits
-            maxMessageSize: 0, // 0 - no limits
-
             protocolVersion: this.protocolVersion,
-            receiveBufferSize: 1024 * 64 * 10,
-            sendBufferSize: 1024 * 64 * 10 // 8192 min,
+            maxChunkCount: ClientTCP_transport.defaultMaxChunk,
+            maxMessageSize: ClientTCP_transport.defaultMaxMessageSize,
+            receiveBufferSize: ClientTCP_transport.defaultReceiveBufferSize,
+            sendBufferSize: ClientTCP_transport.defaultSendBufferSize
         });
         // istanbul ignore next
         if (doTraceHelloAck) {
             warningLog(`sending Hello\n ${helloMessage.toString()}`);
         }
diff --git a/packages/node-opcua-transport/source/index.ts b/packages/node-opcua-transport/source/index.ts
index 678e61363..3891e4f02 100644
--- a/packages/node-opcua-transport/source/index.ts
+++ b/packages/node-opcua-transport/source/index.ts
@@ -1,11 +1,13 @@
 /**
  * @module node-opcua-transport
  */
-export * from "./HelloMessage";
 export * from "./AcknowledgeMessage";
-export * from "./TCPErrorMessage";
 export * from "./client_tcp_transport";
+export * from "./HelloMessage";
+export * from "./message_builder_base";
 export * from "./server_tcp_transport";
+export * from "./status_codes";
 export * from "./tcp_transport";
+export * from "./TCPErrorMessage";
 export * from "./tools";
-export * from "./message_builder_base";
+export * from "./utils";
diff --git a/packages/node-opcua-transport/source/message_builder_base.ts b/packages/node-opcua-transport/source/message_builder_base.ts
index aa4e47472..de39d68cf 100644
--- a/packages/node-opcua-transport/source/message_builder_base.ts
+++ b/packages/node-opcua-transport/source/message_builder_base.ts
@@ -5,40 +5,69 @@ import { EventEmitter } from "events";
 import { assert } from "node-opcua-assert";
 
 import { BinaryStream } from "node-opcua-binary-stream";
 import { createFastUninitializedBuffer } from "node-opcua-buffer-utils";
 import { readMessageHeader, SequenceHeader } from "node-opcua-chunkmanager";
-import { make_errorLog, make_debugLog } from "node-opcua-debug";
+import { make_errorLog, make_debugLog, make_warningLog } from "node-opcua-debug";
 import { MessageHeader, PacketAssembler, PacketInfo } from "node-opcua-packet-assembler";
+import { StatusCode } from "node-opcua-status-code";
 import { get_clock_tick } from "node-opcua-utils";
+import { StatusCodes2 } from "./status_codes";
 
 const doPerfMonitoring = process.env.NODEOPCUADEBUG && process.env.NODEOPCUADEBUG.indexOf("PERF") >= 0;
 
 const errorLog = make_errorLog("MessageBuilder");
 const debugLog = make_debugLog("MessageBuilder");
+const warningLog = make_warningLog("MessageBuilder");
 
 export function readRawMessageHeader(data: Buffer): PacketInfo {
     const messageHeader = readMessageHeader(new BinaryStream(data));
     return {
         extra: "",
         length: messageHeader.length,
         messageHeader
     };
 }
 
+export interface MessageBuilderBaseOptions {
+    signatureLength?: number;
+    maxMessageSize?: number;
+    maxChunkCount?: number;
+    maxChunkSize?: number;
+}
+
+export interface MessageBuilderBase {
+    on(eventName: "startChunk", eventHandler: (info: PacketInfo, data: Buffer) => void): this;
+    on(eventName: "chunk", eventHandler: (chunk: Buffer) => void): this;
+    on(eventName: "error", eventHandler: (err: Error, statusCode: StatusCode, requestId: number | null) => void): this;
+    on(eventName: "full_message_body", eventHandler: (fullMessageBody: Buffer) => void): this;
+
+    emit(eventName: "startChunk", info: PacketInfo, data: Buffer): boolean;
+    emit(eventName: "chunk", chunk: Buffer): boolean;
+    emit(eventName: "error", err: Error, statusCode: StatusCode, requestId: number | null): boolean;
+    emit(eventName: "full_message_body", fullMessageBody: Buffer): boolean;
+}
 /**
  * @class MessageBuilderBase
  * @extends EventEmitter
  * @uses PacketAssembler
  * @constructor
  * @param options {Object}
  * @param [options.signatureLength=0] {number}
  *
  */
 export class MessageBuilderBase extends EventEmitter {
-    public readonly signatureLength: number;    
-    public readonly options: { signatureLength?: number };
+    public static defaultMaxChunkCount = 1000;
+    public static defaultMaxMessageSize = 1024 * 64;
+    public static defaultMaxChunkSize = 1024 * 8;
+
+    public readonly signatureLength: number;
+    public readonly maxMessageSize: number;
+    public readonly maxChunkCount: number;
+    public readonly maxChunkSize: number;
+
+    public readonly options: MessageBuilderBaseOptions;
     public readonly _packetAssembler: PacketAssembler;
     public channelId: number;
     public totalMessageSize: number;
     public sequenceHeader: SequenceHeader | null;
 
@@ -55,11 +84,11 @@ export class MessageBuilderBase extends EventEmitter {
     private _hasReceivedError: boolean;
     private blocks: Buffer[];
     private readonly _expectedChannelId: number;
     private offsetBodyStart: number;
 
-    constructor(options?: { signatureLength?: number }) {
+    constructor(options?: MessageBuilderBaseOptions) {
         super();
 
         this.id = "";
 
         this._tick0 = 0;
@@ -67,24 +96,33 @@ export class MessageBuilderBase extends EventEmitter {
         this._hasReceivedError = false;
         this.blocks = [];
         this.messageChunks = [];
         this._expectedChannelId = 0;
 
-        options = options || {};
+        options = options || {
+            maxMessageSize: 0,
+            maxChunkCount: 0,
+            maxChunkSize: 0
+        };
 
         this.signatureLength = options.signatureLength || 0;
 
+        this.maxMessageSize = options.maxMessageSize || MessageBuilderBase.defaultMaxMessageSize;
+        this.maxChunkCount = options.maxChunkCount || MessageBuilderBase.defaultMaxChunkCount;
+        this.maxChunkSize = options.maxChunkSize || MessageBuilderBase.defaultMaxChunkSize;
+
         this.options = options;
 
         this._packetAssembler = new PacketAssembler({
-            minimumSizeInBytes: 0,
-            readMessageFunc: readRawMessageHeader
+            minimumSizeInBytes: 8,
+            maxChunkSize: this.maxChunkSize,
+            readChunkFunc: readRawMessageHeader
         });
 
-        this._packetAssembler.on("message", (messageChunk) => this._feed_messageChunk(messageChunk));
+        this._packetAssembler.on("chunk", (messageChunk) => this._feed_messageChunk(messageChunk));
 
-        this._packetAssembler.on("newMessage", (info, data) => {
+        this._packetAssembler.on("startChunk", (info, data) => {
             if (doPerfMonitoring) {
                 // record tick 0: when the first data is received
                 this._tick0 = get_clock_tick();
             }
             /**
@@ -92,11 +130,16 @@ export class MessageBuilderBase extends EventEmitter {
              * notify the observers that a new message is being built
              * @event start_chunk
              * @param info
              * @param data
              */
-            this.emit("start_chunk", info, data);
+            this.emit("startChunk", info, data);
+        });
+
+        this._packetAssembler.on("error", (err) => {
+            warningLog("packet assembler ", err.message);
+            return this._report_error(StatusCodes2.BadTcpMessageTooLarge, "packet assembler: " + err.message);
         });
 
         this._securityDefeated = false;
         this.totalBodySize = 0;
         this.totalMessageSize = 0;
@@ -133,28 +176,28 @@ export class MessageBuilderBase extends EventEmitter {
             this.channelId = binaryStream.readUInt32();
             assert(binaryStream.length === 12);
 
             // verifying secure ChannelId
             if (this._expectedChannelId && this.channelId !== this._expectedChannelId) {
-                return this._report_error("Invalid secure channel Id");
+                return this._report_error(StatusCodes2.BadTcpSecureChannelUnknown, "Invalid secure channel Id");
             }
             return true;
         } catch (err) {
-            return false;
+            return this._report_error(StatusCodes2.BadTcpInternalError, "_read_headers error " + (err as Error).message);
         }
     }
 
-    protected _report_error(errorMessage: string): false {
+    protected _report_error(statusCode: StatusCode, errorMessage: string): false {
         this._hasReceivedError = true;
         /**
          * notify the observers that an error has occurred
          * @event error
          * @param error the error to raise
          */
         debugLog("Error  ", this.id, errorMessage);
         // xx errorLog(new Error());
-        this.emit("error", new Error(errorMessage), this.sequenceHeader ? this.sequenceHeader.requestId : null);
+        this.emit("error", new Error(errorMessage), statusCode, this.sequenceHeader ? this.sequenceHeader.requestId : null);
         return false;
     }
 
     private _init_new() {
         this._securityDefeated = false;
@@ -175,25 +218,34 @@ export class MessageBuilderBase extends EventEmitter {
         if (this._hasReceivedError) {
             // the message builder is in error mode and further message chunks should be discarded.
             return false;
         }
 
+        if (this.messageChunks.length + 1 > this.maxChunkCount) {
+            return this._report_error(StatusCodes2.BadTcpMessageTooLarge, `max chunk count exceeded: ${this.maxChunkCount}`);
+        }
+
         this.messageChunks.push(chunk);
         this.totalMessageSize += chunk.length;
 
+        if (this.totalMessageSize > this.maxMessageSize) {
+            return this._report_error(StatusCodes2.BadTcpMessageTooLarge, `max message size exceeded: ${this.maxMessageSize}`);
+        }
+
         const binaryStream = new BinaryStream(chunk);
 
         if (!this._read_headers(binaryStream)) {
-            return this._report_error(`Invalid message header detected`);
+            return this._report_error(StatusCodes2.BadTcpInternalError, `Invalid message header detected`);
         }
 
         assert(binaryStream.length >= 12);
 
         // verify message chunk length
         if (this.messageHeader!.length !== chunk.length) {
             // tslint:disable:max-line-length
             return this._report_error(
+                StatusCodes2.BadTcpInternalError,
                 `Invalid messageChunk size: the provided chunk is ${chunk.length} bytes long but header specifies ${
                     this.messageHeader!.length
                 }`
             );
         }
@@ -252,11 +304,11 @@ export class MessageBuilderBase extends EventEmitter {
             this._decodeMessageBody(fullMessageBody);
             // be ready for next block
             this._init_new();
             return true;
         } else if (messageHeader.isFinal === "A") {
-            return this._report_error("received and Abort Message");
+            return this._report_error(StatusCodes2.BadRequestInterrupted, "received and Abort Message");
         } else if (messageHeader.isFinal === "C") {
             return this._append(chunk);
         }
         return false;
     }
diff --git a/packages/node-opcua-transport/source/server_tcp_transport.ts b/packages/node-opcua-transport/source/server_tcp_transport.ts
index 4406179c2..f01c70ae5 100644
--- a/packages/node-opcua-transport/source/server_tcp_transport.ts
+++ b/packages/node-opcua-transport/source/server_tcp_transport.ts
@@ -53,39 +53,36 @@ const minimumBufferSize = 8192;
  *
  */
 export class ServerTCP_transport extends TCP_transport {
     public static throttleTime = 1000;
 
-    public receiveBufferSize: number;
-    public sendBufferSize: number;
-    public maxMessageSize: number;
-    public maxChunkCount: number;
-    public protocolVersion: number;
-
     private _aborted: number;
     private _helloReceived: boolean;
 
     constructor() {
         super();
         this._aborted = 0;
         this._helloReceived = false;
-        this.receiveBufferSize = 0;
-        this.sendBufferSize = 0;
-        this.maxMessageSize = 0;
-        this.maxChunkCount = 0;
-        this.protocolVersion = 0;
+
+        // before HEL/ACK
+        this.maxChunkCount = 1;
+        this.maxMessageSize = 4 * 1024;
+        this.receiveBufferSize = 4 * 1024;
     }
 
     protected _write_chunk(messageChunk: Buffer): void {
+
+        // istanbul ignore next
         if (this.sendBufferSize > 0 && messageChunk.length > this.sendBufferSize) {
             errorLog(
                 "write chunk exceed sendBufferSize messageChunk length = ",
                 messageChunk.length,
                 "sendBufferSize = ",
                 this.sendBufferSize
             );
         }
+        
         super._write_chunk(messageChunk);
     }
     /**
      * Initialize the server transport.
      *
@@ -113,61 +110,67 @@ export class ServerTCP_transport extends TCP_transport {
     }
 
     public abortWithError(statusCode: StatusCode, extraErrorDescription: string, callback: ErrorCallback): void {
         return this._abortWithError(statusCode, extraErrorDescription, callback);
     }
+
     private _abortWithError(statusCode: StatusCode, extraErrorDescription: string, callback: ErrorCallback): void {
-        if (debugLog) {
-            debugLog(chalk.cyan("_abortWithError"));
+        // When a fatal error occurs, the Server shall send an Error Message to the Client and
+        // closes the TransportConnection gracefully.
+        doDebug && debugLog(chalk.cyan("_abortWithError"));
+        
+        /* istanbul ignore next */
+        if (this._aborted) {
+            // already called
+            return callback(new Error(statusCode.name));
         }
+        this._aborted = 1;
 
-        assert(typeof callback === "function", "expecting a callback");
+        setTimeout(() => {
+            // send the error message and close the connection
+            this.sendErrorMessage(statusCode, statusCode.description);
 
-        /* istanbul ignore else */
-        if (!this._aborted) {
-            this._aborted = 1;
-            setTimeout(() => {
-                // send the error message and close the connection
-                assert(Object.prototype.hasOwnProperty.call(StatusCodes, statusCode.name));
+            this.disconnect(() => {
+                this._aborted = 2;
+                callback(new Error(extraErrorDescription + " StatusCode = " + statusCode.name));
+            });
+        }, ServerTCP_transport.throttleTime);
+    }
 
-                /* istanbul ignore next*/
-                if (doDebug) {
-                    debugLog(chalk.red(" Server aborting because ") + chalk.cyan(statusCode.name));
-                    debugLog(chalk.red(" extraErrorDescription   ") + chalk.cyan(extraErrorDescription));
-                }
+    private _send_ACK_response(helloMessage: HelloMessage): void {
+        assert(helloMessage.receiveBufferSize >= minimumBufferSize);
+        assert(helloMessage.sendBufferSize >= minimumBufferSize);
 
-                const errorResponse = new TCPErrorMessage({
-                    reason: statusCode.description,
-                    statusCode
-                });
+        const minBufferSize = 8192;
+        const maxBufferSize = 64 * 1024;
 
-                const messageChunk = packTcpMessage("ERR", errorResponse);
+        const minMaxMessageSize = 128 * 1024;
+        const defaultMaxMessageSize = 16 * 1024 * 1024;
+        const maxMaxMessageSize = 128 * 1024 * 1024;
 
-                this.write(messageChunk);
+        const minMaxChunkCount = 1;
+        const defaultMaxChunkCount = defaultMaxMessageSize / maxBufferSize;
+        const maxMaxChunkCount = 9000;
 
-                this.disconnect(() => {
-                    this._aborted = 2;
-                    callback(new Error(extraErrorDescription + " StatusCode = " + statusCode.name));
-                });
-            }, ServerTCP_transport.throttleTime);
-        } else {
-            callback(new Error(statusCode.name));
-        }
-    }
+        const receiveBufferSize = 32 * 1024;
+        const sendBufferSize = 32 * 1024;
 
-    private _send_ACK_response(helloMessage: HelloMessage): void {
-        assert(helloMessage.receiveBufferSize >= minimumBufferSize);
-        assert(helloMessage.sendBufferSize >= minimumBufferSize);
+        if (!helloMessage.maxChunkCount && helloMessage.sendBufferSize) {
+            helloMessage.maxChunkCount = helloMessage.maxMessageSize / helloMessage.sendBufferSize;
+        }
 
-        this.receiveBufferSize = clamp_value(helloMessage.receiveBufferSize, 8192, 512 * 1024);
-        this.sendBufferSize = clamp_value(helloMessage.sendBufferSize, 8192, 512 * 1024);
-        this.maxMessageSize = clamp_value(helloMessage.maxMessageSize, 100000, 64 * 1024 * 1024);
-        this.maxChunkCount = clamp_value(helloMessage.maxChunkCount, 0, 65535);
+        this.setLimits({
+            receiveBufferSize: clamp_value(helloMessage.receiveBufferSize || receiveBufferSize, minBufferSize, maxBufferSize),
+            sendBufferSize: clamp_value(helloMessage.sendBufferSize || sendBufferSize, minBufferSize, maxBufferSize),
+            maxMessageSize: clamp_value(helloMessage.maxMessageSize || defaultMaxMessageSize, minMaxMessageSize, maxMaxMessageSize),
+            maxChunkCount: clamp_value(helloMessage.maxChunkCount || defaultMaxChunkCount, minMaxChunkCount, maxMaxChunkCount)
+        });
 
         // istanbul ignore next
         if (doTraceHelloAck) {
             console.log(`received Hello \n${helloMessage.toString()}`);
+            console.log("Client accepts only message of size => ", this.maxMessageSize);
         }
 
         debugLog("Client accepts only message of size => ", this.maxMessageSize);
 
         const acknowledgeMessage = new AcknowledgeMessage({
diff --git a/packages/node-opcua-transport/source/status_codes.ts b/packages/node-opcua-transport/source/status_codes.ts
new file mode 100644
index 000000000..d0c4222e1
--- /dev/null
+++ b/packages/node-opcua-transport/source/status_codes.ts
@@ -0,0 +1,109 @@
+import { StatusCodes } from "node-opcua-status-code";
+
+export const StatusCodes2 = {
+    /**
+     * The Server cannot process the request because it is too busy.
+     *
+     * It is up to the Server to determine when it needs to return this Message.
+     *
+     * A Server can control the how frequently a Client reconnects by waiting to return this error.
+     */
+    BadTcpServerTooBusy: StatusCodes.BadTcpServerTooBusy,
+    /**
+     * The type of the Message specified in the header invalid.
+     * Each Message starts with a 4-byte sequence of ASCII values that identifies the Message type.
+     * The Server returns this error if the Message type is not accepted.
+     * Some of the Message types are defined by the SecureChannel layer.
+     */
+    BadTcpMessageTypeInvalid: StatusCodes.BadTcpMessageTypeInvalid,
+    /**
+     * The SecureChannelId and/or TokenId are not currently in use.
+     * This error is reported by the SecureChannel layer.
+     */
+    BadTcpSecureChannelUnknown: StatusCodes.BadTcpSecureChannelUnknown,
+    /**
+     * The size of the Message specified in the header is too large.
+     * The Server returns this error if the Message size exceeds its maximum buffer size
+     * or the receive buffer size negotiated during the Hello/Acknowledge exchange.
+     */
+    BadTcpMessageTooLarge: StatusCodes.BadTcpMessageTooLarge,
+
+    /**
+     * A timeout occurred while accessing a resource.
+     * It is up to the Server to determine when a timeout occurs.
+     */
+    BadTimeout: StatusCodes.BadTimeout,
+    /**
+     * There are not enough resources to process the request.
+     * The Server returns this error when it runs out of memory or encounters similar resource problems.
+     * A Server can control the how frequently a Client reconnects by waiting to return this error.
+     */
+    BadTcpNotEnoughResources: StatusCodes.BadTcpNotEnoughResources,
+    /**
+     * An internal error occurred.
+     * This should only be returned if an unexpected configuration or programming error occurs.
+     */
+    BadTcpInternalError: StatusCodes.BadTcpInternalError,
+    /**
+     * The Server does not recognize the EndpointUrl specified.
+     */
+    BadTcpEndpointUrlInvalid: StatusCodes.BadTcpEndpointUrlInvalid,
+    /**
+     * The Message was rejected because it could not be verified.
+     */
+    BadSecurityChecksFailed: StatusCodes.BadSecurityChecksFailed,
+    /**
+     * The request could not be sent because of a network interruption.
+     */
+    BadRequestInterrupted: StatusCodes.BadRequestInterrupted,
+    /**
+     * Timeout occurred while processing the request.
+     */
+    BadRequestTimeout: StatusCodes.BadRequestTimeout,
+    /**
+     * The secure channel has been closed.
+     */
+    BadSecureChannelClosed: StatusCodes.BadSecureChannelClosed,
+    /**
+     * The SecurityToken has expired or is not recognized. BadSecureChannelTokenUnknown
+     */
+    BadSecureChannelTokenUnknown: StatusCodes.BadSecureChannelTokenUnknown,
+    /**
+     * The sender Certificate is not trusted by the receiver.
+     */
+    BadCertificateUntrusted: StatusCodes.BadCertificateUntrusted,
+    /**
+     * The sender Certificate has expired or is not yet valid.
+     */
+    BadCertificateTimeInvalid: StatusCodes.BadCertificateTimeInvalid,
+    /**
+     * The issuer for the sender Certificate has expired or is not yet valid.
+     */
+    BadCertificateIssuerTimeInvalid: StatusCodes.BadCertificateIssuerTimeInvalid,
+    /**
+     * The sender’s Certificate may not be used for establishing a secure channel.
+     */
+    BadCertificateUseNotAllowed: StatusCodes.BadCertificateUseNotAllowed,
+    /**
+     * The issuer Certificate may not be used as a Certificate Authority.
+     */
+    BadCertificateIssuerUseNotAllowed: StatusCodes.BadCertificateIssuerUseNotAllowed,
+    /**
+     * Could not verify the revocation status of the sender’s Certificate.
+     */
+    BadCertificateRevocationUnknown: StatusCodes.BadCertificateRevocationUnknown,
+    /**
+     * Could not verify the revocation status of the issuer Certificate.
+     */
+    BadCertificateIssuerRevocationUnknown: StatusCodes.BadCertificateIssuerRevocationUnknown,
+    /**
+     * The sender Certificate has been revoked by the issuer.
+     */
+    BadCertificateRevoked: StatusCodes.BadCertificateRevoked
+    /**The issuer Certificate has been revoked by its issuer.
+     */
+    // todo  BadIssuerCertificateRevoked: StatusCodes.BadIssuerCertificateRevoked,
+    /** The receiver Certificate thumbprint is not recognized by the receiver.
+     */
+    // todo .. BadCertificateUnknown: StatusCodes.BadCertificateUnknown
+};
diff --git a/packages/node-opcua-transport/source/tcp_transport.ts b/packages/node-opcua-transport/source/tcp_transport.ts
index f392033dd..1ef58a2c2 100644
--- a/packages/node-opcua-transport/source/tcp_transport.ts
+++ b/packages/node-opcua-transport/source/tcp_transport.ts
@@ -1,36 +1,38 @@
 /**
  * @module node-opcua-transport
  */
 import { EventEmitter } from "events";
 import { Socket } from "net";
-
 import * as chalk from "chalk";
 
 import { assert } from "node-opcua-assert";
-import { createFastUninitializedBuffer } from "node-opcua-buffer-utils";
-import * as debug from "node-opcua-debug";
+import { BinaryStream } from "node-opcua-binary-stream";
+import { make_debugLog, checkDebugFlag, make_errorLog, hexDump } from "node-opcua-debug";
 import { ObjectRegistry } from "node-opcua-object-registry";
-import { PacketAssembler } from "node-opcua-packet-assembler";
-import { ErrorCallback, CallbackWithData } from "node-opcua-status-code";
+import { PacketAssembler, PacketAssemblerErrorCode } from "node-opcua-packet-assembler";
+import { ErrorCallback, CallbackWithData, StatusCode } from "node-opcua-status-code";
 
+import { StatusCodes2 } from "./status_codes";
 import { readRawMessageHeader } from "./message_builder_base";
-import { writeTCPMessageHeader } from "./tools";
+import { doTraceIncomingChunk } from "./utils";
+import { TCPErrorMessage } from "./TCPErrorMessage";
+import { packTcpMessage } from "./tools";
 
-const debugLog = debug.make_debugLog(__filename);
-const doDebug = debug.checkDebugFlag(__filename);
-const errorLog = debug.make_errorLog(__filename);
+const debugLog = make_debugLog(__filename);
+const doDebug = checkDebugFlag(__filename);
+const errorLog = make_errorLog(__filename);
 
 export interface MockSocket {
     invalid?: boolean;
     [key: string]: any;
     destroy(): void;
     end(): void;
 }
 let fakeSocket: MockSocket = {
     invalid: true,
-    
+
     destroy() {
         errorLog("MockSocket.destroy");
     },
 
     end() {
@@ -50,15 +52,15 @@ export function getFakeTransport(): any {
 }
 
 let counter = 0;
 
 export interface TCP_transport {
-    on(eventName: "message", eventHandler: (message: Buffer) => void): this;
+    on(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
     on(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
     on(eventName: "close", eventHandler: (err: Error | null) => void): this;
 
-    once(eventName: "message", eventHandler: (message: Buffer) => void): this;
+    once(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
     once(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
     once(eventName: "close", eventHandler: (err: Error | null) => void): this;
 }
 // tslint:disable:class-name
 export class TCP_transport extends EventEmitter {
@@ -67,10 +69,14 @@ export class TCP_transport extends EventEmitter {
     /**
      * indicates the version number of the OPCUA protocol used
      * @default  0
      */
     public protocolVersion: number;
+    public maxMessageSize: number;
+    public maxChunkCount: number;
+    public sendBufferSize: number;
+    public receiveBufferSize: number;
 
     public bytesWritten: number;
     public bytesRead: number;
     public chunkWrittenCount: number;
     public chunkReadCount: number;
@@ -87,11 +93,10 @@ export class TCP_transport extends EventEmitter {
     private _timerId: NodeJS.Timer | null;
     private _onSocketClosedHasBeenCalled: boolean;
     private _onSocketEndedHasBeenCalled: boolean;
     private _theCallback?: CallbackWithData;
     private _on_error_during_one_time_message_receiver: any;
-    private _pendingBuffer?: any;
     private packetAssembler?: PacketAssembler;
     private _timeout: number;
 
     constructor() {
         super();
@@ -101,14 +106,18 @@ export class TCP_transport extends EventEmitter {
 
         this._timerId = null;
         this._timeout = 30000; // 30 seconds timeout
         this._socket = null;
         this.headerSize = 8;
+
+        this.maxMessageSize = 0;
+        this.maxChunkCount = 0;
+        this.receiveBufferSize = 0;
+        this.sendBufferSize = 0;
         this.protocolVersion = 0;
 
         this._disconnecting = false;
-        this._pendingBuffer = undefined;
 
         this.bytesWritten = 0;
         this.bytesRead = 0;
 
         this._theCallback = undefined;
@@ -118,10 +127,30 @@ export class TCP_transport extends EventEmitter {
         this._onSocketClosedHasBeenCalled = false;
         this._onSocketEndedHasBeenCalled = false;
         TCP_transport.registry.register(this);
     }
 
+    public setLimits({
+        receiveBufferSize,
+        sendBufferSize,
+        maxMessageSize,
+        maxChunkCount
+    }: {
+        receiveBufferSize: number;
+        sendBufferSize: number;
+        maxMessageSize: number;
+        maxChunkCount: number;
+    }) {
+        this.receiveBufferSize = receiveBufferSize;
+        this.sendBufferSize = sendBufferSize;
+        this.maxMessageSize = maxMessageSize;
+        this.maxChunkCount = maxChunkCount;
+
+        // reinstall packetAssembler with correct limits
+        this._install_packetAssembler();
+    }
+
     public get timeout(): number {
         return this._timeout;
     }
     public set timeout(value: number) {
         debugLog("Setting socket " + this.name + " timeout = ", value);
@@ -136,56 +165,23 @@ export class TCP_transport extends EventEmitter {
             this._socket = null;
         }
         TCP_transport.registry.unregister(this);
     }
 
-    /**
-     * ```createChunk``` is used to construct a pre-allocated chunk to store up to ```length``` bytes of data.
-     * The created chunk includes a prepended header for ```chunk_type``` of size ```self.headerSize```.
-     *
-     * @method createChunk
-     * @param msgType
-     * @param chunkType {String} chunk type. should be 'F' 'C' or 'A'
-     * @param length
-     * @return a buffer object with the required length representing the chunk.
-     *
-     * Note:
-     *  - only one chunk can be created at a time.
-     *  - a created chunk should be committed using the ```write``` method before an other one is created.
-     */
-    public createChunk(msgType: string, chunkType: string, length: number): Buffer {
-        assert(msgType === "MSG");
-        assert(this._pendingBuffer === undefined, "createChunk has already been called ( use write first)");
-
-        const totalLength = length + this.headerSize;
-        const buffer = createFastUninitializedBuffer(totalLength);
-        writeTCPMessageHeader("MSG", chunkType, totalLength, buffer);
-        this._pendingBuffer = buffer;
-
-        return buffer;
-    }
-
     /**
      * write the message_chunk on the socket.
      * @method write
      * @param messageChunk
-     *
-     * Notes:
-     *  - the message chunk must have been created by ```createChunk```.
-     *  - once a message chunk has been written, it is possible to call ```createChunk``` again.
-     *
      */
-    public write(messageChunk: Buffer): void {
-        assert(
-            this._pendingBuffer === undefined || this._pendingBuffer === messageChunk,
-            " write should be used with buffer created by createChunk"
-        );
+    public write(messageChunk: Buffer, callback?: (err?: Error) => void | undefined): void {
         const header = readRawMessageHeader(messageChunk);
         assert(header.length === messageChunk.length);
-        assert(["F", "C", "A"].indexOf(header.messageHeader.isFinal) !== -1);
-        this._write_chunk(messageChunk);
-        this._pendingBuffer = undefined;
+        const c = header.messageHeader.isFinal;
+        assert(c === "F" || c === "C" || c === "A");
+        this._write_chunk(messageChunk, (err) => {
+            callback && callback(err);
+        });
     }
 
     public get isDisconnecting(): boolean {
         return this._disconnecting;
     }
@@ -226,15 +222,19 @@ export class TCP_transport extends EventEmitter {
 
     public isValid(): boolean {
         return this._socket !== null && !this._socket.destroyed && !this._disconnecting;
     }
 
-    protected _write_chunk(messageChunk: Buffer): void {
+    protected _write_chunk(messageChunk: Buffer, callback?: (err?: Error) => void | undefined): void {
         if (this._socket !== null) {
             this.bytesWritten += messageChunk.length;
             this.chunkWrittenCount++;
-            this._socket.write(messageChunk);
+            this._socket.write(messageChunk, callback);
+        } else {
+            if (callback) {
+                callback();
+            }
         }
     }
 
     protected on_socket_ended(err: Error | null): void {
         assert(!this._onSocketEndedHasBeenCalled);
@@ -245,10 +245,39 @@ export class TCP_transport extends EventEmitter {
          * @param err the Error object or null
          */
         this.emit("close", err || null);
     }
 
+    protected _install_packetAssembler() {
+        if (this.packetAssembler) {
+            this.packetAssembler.removeAllListeners();
+            this.packetAssembler = undefined;
+        }
+
+        // install packet assembler ...
+        this.packetAssembler = new PacketAssembler({
+            readChunkFunc: readRawMessageHeader,
+            minimumSizeInBytes: this.headerSize,
+            maxChunkSize: this.receiveBufferSize //Math.max(this.receiveBufferSize, this.sendBufferSize)
+        });
+
+        this.packetAssembler.on("chunk", (chunk: Buffer) => this._on_message_chunk_received(chunk));
+
+        this.packetAssembler.on("error", (err, code) => {
+            let statusCode = StatusCodes2.BadTcpMessageTooLarge;
+            switch (code) {
+                case PacketAssemblerErrorCode.ChunkSizeExceeded:
+                    statusCode = StatusCodes2.BadTcpMessageTooLarge;
+                    break;
+                default:
+                    statusCode = StatusCodes2.BadTcpInternalError;
+            }
+
+            this.sendErrorMessage(statusCode, err.message);
+            this.prematureTerminate(new Error("Packet Assembler : " + err.message), statusCode);
+        });
+    }
     /**
      * @method _install_socket
      * @param socket {Socket}
      * @protected
      */
@@ -257,22 +286,11 @@ export class TCP_transport extends EventEmitter {
         this._socket = socket;
         if (doDebug) {
             debugLog("  TCP_transport#_install_socket ", this.name);
         }
 
-        // install packet assembler ...
-        this.packetAssembler = new PacketAssembler({
-            readMessageFunc: readRawMessageHeader,
-
-            minimumSizeInBytes: this.headerSize
-        });
-
-        /* istanbul ignore next */
-        if (!this.packetAssembler) {
-            throw new Error("Internal Error");
-        }
-        this.packetAssembler.on("message", (messageChunk: Buffer) => this._on_message_received(messageChunk));
+        this._install_packetAssembler();
 
         this._socket
             .on("data", (data: Buffer) => this._on_socket_data(data))
             .on("close", (hadError) => this._on_socket_close(hadError))
             .on("end", (err: Error) => this._on_socket_end(err))
@@ -282,27 +300,50 @@ export class TCP_transport extends EventEmitter {
         debugLog("  TCP_transport#install => setting " + this.name + " _socket.setTimeout to ", this.timeout);
 
         // let use a large timeout here to make sure that we not conflict with our internal timeout
         this._socket!.setTimeout(this.timeout + 2000, () => {
             debugLog(` _socket ${this.name} has timed out (timeout = ${this.timeout})`);
-            this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout));
+            this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout), StatusCodes2.BadTimeout);
         });
     }
 
-    public prematureTerminate(err: Error): void {
-        debugLog("prematureTerminate", err ? err.message : "");
+    public sendErrorMessage(statusCode: StatusCode, extraErrorDescription: string | null): void {
+        // When the Client receives an Error Message it reports the error to the application and closes the TransportConnection gracefully.
+        // If a Client encounters a fatal error, it shall report the error to the application and send a CloseSecureChannel Message.
+
+        /* istanbul ignore next*/
+        if (doDebug) {
+            debugLog(chalk.red(" sendErrorMessage        ") + chalk.cyan(statusCode.toString()));
+            debugLog(chalk.red(" extraErrorDescription   ") + chalk.cyan(extraErrorDescription));
+        }
+
+        const reason = `${statusCode.toString()}:${extraErrorDescription || ""}`;
+        const errorResponse = new TCPErrorMessage({
+            statusCode,
+            reason
+        });
+        const messageChunk = packTcpMessage("ERR", errorResponse);
+        this.write(messageChunk);
+    }
+
+    public prematureTerminate(err: Error, statusCode: StatusCode): void {
+        // https://reference.opcfoundation.org/v104/Core/docs/Part6/6.7.3/
+
+        debugLog("prematureTerminate", err ? err.message : "", statusCode.toString());
+
         if (this._socket) {
-            err.message = "socket has timeout: EPIPE: " + err.message;
+            err.message = "premature socket termination " + err.message;
             // we consider this as an error
             const _s = this._socket;
             _s.end();
             _s.destroy(); // new Error("Socket has timed out"));
             _s.emit("error", err);
             this._socket = null;
             this.dispose();
             _s.removeAllListeners();
         }
+        // this.gracefullShutdown(err);
     }
     /**
      * @method _install_one_time_message_receiver
      *
      * install a one time message receiver callback
@@ -339,20 +380,23 @@ export class TCP_transport extends EventEmitter {
             return true;
         }
         return false;
     }
 
-    private _on_message_received(messageChunk: Buffer) {
+    private _on_message_chunk_received(messageChunk: Buffer) {
+        if (doTraceIncomingChunk) {
+            console.log(hexDump(messageChunk));
+        }
         const hadCallback = this._fulfill_pending_promises(null, messageChunk);
         this.chunkReadCount++;
         if (!hadCallback) {
             /**
              * notify the observers that a message chunk has been received
              * @event message
              * @param message_chunk the message chunk
              */
-            this.emit("message", messageChunk);
+            this.emit("chunk", messageChunk);
         }
     }
 
     private _cleanup_timers() {
         if (this._timerId) {
@@ -395,10 +439,11 @@ export class TCP_transport extends EventEmitter {
          */
         this.emit("socket_closed", err || null);
     }
 
     private _on_socket_data(data: Buffer): void {
+        // istanbul ignore next
         if (!this.packetAssembler) {
             throw new Error("internal Error");
         }
         this.bytesRead += data.length;
         if (data.length > 0) {
diff --git a/packages/node-opcua-transport/source/utils.ts b/packages/node-opcua-transport/source/utils.ts
index ea9da4e94..d02748817 100644
--- a/packages/node-opcua-transport/source/utils.ts
+++ b/packages/node-opcua-transport/source/utils.ts
@@ -1,4 +1,5 @@
 //
 const transportFlag = (process.env?.NODEOPCUADEBUG?.match(/TRANSPORT{([^}]*)}/) || [])[1] || "";
-export const doTraceHelloAck = transportFlag.match(/HELACK/);
-export const doTraceChunk = transportFlag.match(/CHUNK/);
+export const doTraceHelloAck = !!transportFlag.match(/HELACK/);
+export const doTraceChunk = !!transportFlag.match(/CHUNK/);
+export const doTraceIncomingChunk = !!transportFlag.match(/FLOW/);
diff --git a/packages/node-opcua-transport/test/test_client_tcp_transport.js b/packages/node-opcua-transport/test/test_client_tcp_transport.js
index bbe3e5751..f8d182c05 100644
--- a/packages/node-opcua-transport/test/test_client_tcp_transport.js
+++ b/packages/node-opcua-transport/test/test_client_tcp_transport.js
@@ -1,26 +1,26 @@
 "use strict";
 const should = require("should");
-const { assert } = require("node-opcua-assert");
 const chalk = require("chalk");
 const sinon = require("sinon");
 
-const { StatusCodes, StatusCode } = require("node-opcua-status-code");
-
+const { assert } = require("node-opcua-assert");
 const { hexDump } = require("node-opcua-debug");
-
+const { make_debugLog, make_errorLog } = require("node-opcua-debug");
+const { StatusCodes, StatusCode } = require("node-opcua-status-code");
 const { compare_buffers } = require("node-opcua-utils");
 
-const { make_debugLog, make_errorLog } = require("node-opcua-debug");
+
 const debugLog = make_debugLog("TEST");
 const errorLog = make_errorLog("TEST");
 
 const { FakeServer } = require("../dist/test_helpers");
 
 const port = 5678;
 
 const { AcknowledgeMessage, TCPErrorMessage, ClientTCP_transport, packTcpMessage } = require("..");
+const { MessageBuilderBase, writeTCPMessageHeader } = require("..");
 
 describe("testing ClientTCP_transport", function () {
     this.timeout(15000);
 
     let transport;
@@ -213,11 +213,11 @@ describe("testing ClientTCP_transport", function () {
         fakeServer.pushResponse(spyOnServerWrite);
         fakeServer.pushResponse(spyOnServerWrite);
 
         transport.timeout = 1000; // very short timeout;
 
-        transport.on("message", function (message_chunk) {
+        transport.on("chunk", function (message_chunk) {
             debugLog(chalk.cyan.bold(hexDump(message_chunk)));
             compare_buffers(message_chunk.slice(8), message1);
 
             spyOnConnect.callCount.should.eql(1);
             spyOnClose.callCount.should.eql(0);
@@ -226,16 +226,38 @@ describe("testing ClientTCP_transport", function () {
             spyOnServerWrite.callCount.should.eql(2);
 
             done();
         });
 
-        transport.connect(endpointUrl, function (err) {
+
+        /**
+         * ```createChunk``` is used to construct a pre-allocated chunk to store up to ```length``` bytes of data.
+         * The created chunk includes a prepended header for ```chunk_type``` of size ```self.headerSize```.
+         *
+         * @method createChunk
+         * @param msgType
+         * @param chunkType {String} chunk type. should be 'F' 'C' or 'A'
+         * @param length
+         * @return a buffer object with the required length representing the chunk.
+         *
+         * Note:
+         *  - only one chunk can be created at a time.
+         *  - a created chunk should be committed using the ```write``` method before an other one is created.
+         */
+        function createChunk(msgType, chunkType, headerSize, length) {
+            assert(msgType === "MSG");
+            const totalLength = length + headerSize;
+            const buffer = Buffer.alloc(totalLength);
+            writeTCPMessageHeader("MSG", chunkType, totalLength, buffer);
+            return buffer;
+        }
+        transport.connect(endpointUrl, (err) => {
             if (err) {
                 errorLog(chalk.bgWhite.red(" err = "), err.message);
             }
             assert(!err);
-            const buf = transport.createChunk("MSG", "F", message1.length);
+            const buf = createChunk("MSG", "F", transport.headerSize, message1.length);
             message1.copy(buf, transport.headerSize, 0, message1.length);
             transport.write(buf);
         });
     });
 
diff --git a/packages/node-opcua-transport/test/test_message_builder_base.js b/packages/node-opcua-transport/test/test_message_builder_base.js
index 63eac9c73..a0383d4ca 100644
--- a/packages/node-opcua-transport/test/test_message_builder_base.js
+++ b/packages/node-opcua-transport/test/test_message_builder_base.js
@@ -1,6 +1,8 @@
 "use strict";
+const sinon = require("sinon");
+
 const { BinaryStream } = require("node-opcua-binary-stream");
 const { compare_buffers } = require("node-opcua-utils");
 
 const { MessageBuilderBase, writeTCPMessageHeader } = require("..");
 
@@ -23,11 +25,11 @@ describe("MessageBuilderBase", function () {
         builder.on("full_message_body", function (full_message_body) {
             compare_buffers(full_message_body, message_body, message_body.length);
             done();
         });
 
-        builder.on("chunk", function (message_chunk) {
+        builder.on("chunk", (message_chunk) => {
             compare_buffers(message_chunk, original_message_chunk, original_message_chunk.length);
         });
 
         builder.feed(original_message_chunk);
     });
@@ -45,15 +47,100 @@ describe("MessageBuilderBase", function () {
             done();
         });
 
         const expected = [original_message_chunk_1, original_message_chunk_2];
         let expected_count = 0;
-        builder.on("chunk", function (message_chunk) {
+        builder.on("chunk", (message_chunk) => {
             const expected_chunk = expected[expected_count];
             expected_count += 1;
             compare_buffers(message_chunk, expected_chunk, expected_chunk.length);
         });
 
         builder.feed(original_message_chunk_1);
         builder.feed(original_message_chunk_2);
     });
+
+    it("should not allow more chunks that maxChunkCount ", function (done) {
+
+        const builder = new MessageBuilderBase({
+            maxChunkCount: 5,
+            maxMessageSize: 64 * 1024,
+        });
+
+        const onChunkSpy = sinon.spy();
+        builder.on("chunk", onChunkSpy);
+
+        const onFullMessageBodySpy = sinon.spy();
+        builder.on("full_message_body", onFullMessageBodySpy);
+
+        const onErrorSpy = sinon.spy();
+        builder.on("error", onErrorSpy);
+
+        const message_body = Buffer.alloc(16 * 1024);
+        const chunk1 = wrap_message_in_chunk(message_body.slice(0 * 1024, 1 * 1024), "C");
+        const chunk2 = wrap_message_in_chunk(message_body.slice(1 * 1024, 2 * 1024), "C");
+        const chunk3 = wrap_message_in_chunk(message_body.slice(2 * 1024, 3 * 1024), "C");
+        const chunk4 = wrap_message_in_chunk(message_body.slice(3 * 1024, 4 * 1024), "C");
+        const chunk5 = wrap_message_in_chunk(message_body.slice(4 * 1024, 5 * 1024), "C");
+        const chunk6 = wrap_message_in_chunk(message_body.slice(5 * 1024, 6 * 1024), "C");
+        const chunk7 = wrap_message_in_chunk(message_body.slice(6 * 1024, 7 * 1024), "F");
+
+        builder.feed(chunk1);
+        builder.feed(chunk2);
+        builder.feed(chunk3);
+        builder.feed(chunk4);
+        builder.feed(chunk5);
+        builder.feed(chunk6);
+        builder.feed(chunk7);
+
+        onChunkSpy.callCount.should.eql(6);
+        onErrorSpy.callCount.should.eql(1);
+        onFullMessageBodySpy.callCount.should.eql(0);
+
+        onErrorSpy.getCall(0).args[0].should.match(/max chunk count exceeded/);
+
+        done();
+
+    });
+    it("should not allow message bigger than maxMessageSize ", function (done) {
+
+        const builder = new MessageBuilderBase({
+            maxChunkCount:  1000,
+            maxMessageSize: 4 * 1024,
+        });
+
+        const onChunkSpy = sinon.spy();
+        builder.on("chunk", onChunkSpy);
+
+        const onFullMessageBodySpy = sinon.spy();
+        builder.on("full_message_body", onFullMessageBodySpy);
+
+        const onErrorSpy = sinon.spy();
+        builder.on("error", onErrorSpy);
+
+        const message_body = Buffer.alloc(16 * 1024);
+        const chunk1 = wrap_message_in_chunk(message_body.slice(0 * 1024, 1 * 1024), "C");
+        const chunk2 = wrap_message_in_chunk(message_body.slice(1 * 1024, 2 * 1024), "C");
+        const chunk3 = wrap_message_in_chunk(message_body.slice(2 * 1024, 3 * 1024), "C");
+        const chunk4 = wrap_message_in_chunk(message_body.slice(3 * 1024, 4 * 1024), "C");
+        const chunk5 = wrap_message_in_chunk(message_body.slice(4 * 1024, 5 * 1024), "C");
+        const chunk6 = wrap_message_in_chunk(message_body.slice(5 * 1024, 6 * 1024), "C");
+        const chunk7 = wrap_message_in_chunk(message_body.slice(6 * 1024, 7 * 1024), "F");
+
+        builder.feed(chunk1);
+        builder.feed(chunk2);
+        builder.feed(chunk3);
+        builder.feed(chunk4);
+        builder.feed(chunk5);
+        builder.feed(chunk6);
+        builder.feed(chunk7);
+
+        onChunkSpy.callCount.should.eql(4);
+        onErrorSpy.callCount.should.eql(1);
+        onFullMessageBodySpy.callCount.should.eql(0);
+
+        onErrorSpy.getCall(0).args[0].should.match(/maxMessageSize/);
+        
+        done();
+
+    });
 });
diff --git a/packages/node-opcua-transport/test/test_server_tcp_transport.js b/packages/node-opcua-transport/test/test_server_tcp_transport.js
index 0e417561e..d8a3d1c19 100644
--- a/packages/node-opcua-transport/test/test_server_tcp_transport.js
+++ b/packages/node-opcua-transport/test/test_server_tcp_transport.js
@@ -81,11 +81,11 @@ describe("testing ServerTCP_transport", function () {
         transport.init(fakeSocket.server, (err) => {
             initError = err;
             debugLog("failed !", err.message);
         });
 
-        transport.on("message", (messageChunk) => {
+        transport.on("chunk", (messageChunk) => {
             // console.log("message ", messageChunk);
             done(new Error("Not expecting an message"));
         });
         transport.on("close", (err) => {
             debugLog("close", err);
@@ -144,15 +144,25 @@ describe("testing ServerTCP_transport", function () {
     });
 
     function perform_sever_receiving_a_HEL_MESSAGE_followed_by_OpenChannelRequest_scenario(done) {
         const transport = new ServerTCP_transport();
 
+        transport.setLimits({
+            maxChunkCount: 10000,
+            maxMessageSize: 10000,
+            receiveBufferSize: 10000,
+            sendBufferSize: 10000
+        });
+
         transport.init(fakeSocket.server, (err) => {
+            if (err) {
+                console.log(err.message);
+            }
             assert(!err);
         });
 
-        transport.on("message", (messageChunk) => {
+        transport.on("chunk", (messageChunk) => {
             utils.compare_buffers(messageChunk, openChannelRequest);
 
             // it should provide bytesRead and bytesWritten
             transport.bytesRead.should.be.greaterThan(0);
             transport.bytesWritten.should.be.greaterThan(20);
@@ -271,11 +281,11 @@ describe("testing ServerTCP_transport", function () {
         const transport = new ServerTCP_transport();
         transport.init(fakeSocket.server, (err) => {
             /** */
         });
 
-        transport.on("message", (messageChunk) => {
+        transport.on("chunk", (messageChunk) => {
             // console.log("message ", messageChunk);
             done();
         });
 
         const b = Buffer.from("434c4f46180000000c000000010000000f0000000f000000", "hex");
diff --git a/packages/node-opcua-transport/test_helpers/direct_transport.ts b/packages/node-opcua-transport/test_helpers/direct_transport.ts
index 566641c0f..8aed5d478 100644
--- a/packages/node-opcua-transport/test_helpers/direct_transport.ts
+++ b/packages/node-opcua-transport/test_helpers/direct_transport.ts
@@ -1,10 +1,13 @@
 import { EventEmitter } from "events";
 import { assert } from "node-opcua-assert";
 import { setFakeTransport } from "../source";
 import { HalfComChannel } from "./half_com_channel";
 
+export interface DirectTransport {
+    on(eventName: "end", eventHandler:()=>void): this;
+}
 export class DirectTransport extends EventEmitter {
     public client: HalfComChannel;
     public server: HalfComChannel;
     public url: string;
 
@@ -30,11 +33,11 @@ export class DirectTransport extends EventEmitter {
         this.client.on("ending", () => {
             this.server.emit("end");
             this.server._hasEnded = true;
         });
 
-        this.server.on("end", (err: Error) => {
+        this.server.on("end", (err?: Error) => {
             this.emit("end", err);
         });
 
         this.server.on("data", (data: Buffer) => {
             const func = this.popResponse();
diff --git a/packages/node-opcua-transport/test_helpers/half_com_channel.ts b/packages/node-opcua-transport/test_helpers/half_com_channel.ts
index 0df951c78..255d0c56d 100644
--- a/packages/node-opcua-transport/test_helpers/half_com_channel.ts
+++ b/packages/node-opcua-transport/test_helpers/half_com_channel.ts
@@ -1,9 +1,16 @@
 /* eslint-disable @typescript-eslint/no-empty-function */
 import { EventEmitter } from "events";
 import { assert } from "node-opcua-assert";
 
+export interface HalfComChannel {
+    on(eventName: "data", eventHandler:(data: Buffer)=>void): this;
+    on(eventName: "send_data", eventHandler:(data: Buffer)=>void): this;
+    on(eventName: "ending", eventHandler:()=>void): this;
+    on(eventName: "end", eventHandler:(err?: Error)=>void): this;
+
+}
 export class HalfComChannel extends EventEmitter {
     public _hasEnded: boolean;
 
     constructor() {
         super();

Vulnerable code: import {
    ClientSecureChannelLayer,
    ConnectionStrategy,
    ConnectionStrategyOptions,
    SecurityPolicy} from "node-opcua-secure-channel";
import {
    FindServersOnNetworkRequestOptions,
    FindServersRequestOptions,
    ServerOnNetwork
} from "node-opcua-service-discovery";
import {
    ApplicationDescription,
    EndpointDescription} from "node-opcua-service-endpoints";
            tokenRenewalInterval: this.tokenRenewalInterval
import { constructObject } from "node-opcua-factory";
    /*
    const offset = 16 * 3 + 6;
    buffer = buffer.slice(offset);
    */
    const messageBuilder = new MessageBuilder({});
    let objMessage: any = null;
import {allPermissions, OPCUAClient, OPCUAServer, StatusCodes, UserTokenType, WellKnownRoles, makeRoles} from "node-opcua";
        {username: "Gandalf", password: "g", roles: makeRoles([WellKnownRoles.AuthenticatedUser,WellKnownRoles.ConfigureAdmin])},
        {username: "Frodo", password: "f", roles:  makeRoles([WellKnownRoles.AuthenticatedUser])},
            getUserRoles: username => users.find(user => user.username === username)!.roles,
            
            isValidUser(username, password) {
                const user = users.find(user => user.username === username);
    })
        endpointMustExist: false,
        namespace.addMethod(folder, {
            browseName: "doIt",
            nodeId: "ns=1;s=doIt",
            rolePermissions: [
                { 
                    roleId:  WellKnownRoles.ConfigureAdmin,
                    permissions: allPermissions
                }
            ]
            /*
        }).bindMethod((inputArguments, context, callback) => {
            wasExecuted = true;
            callback(null, {statusCode: StatusCodes.Good})
        });
    beforeEach(() => wasExecuted = false);
            inputArguments: [],
            inputArguments: [],
});
/*global xit,it,describe,before,after,beforeEach,afterEach*/



const { assert } = require("node-opcua-assert");
                requestedSessionTimeout: 600 * 1000 // use long session time out
            const too_many = 50000;
const async = require("async");
    ClientMonitoredItem,
    StatusCodes,
const { make_debugLog, make_errorLog, checkDebugFlag } = require("node-opcua-debug");
        }, 5000);
    return await new Promise((resolve,reject) => {
        }, 5000);
            await perform_operation_on_subscription_async(client, endpointUrl, async function (session, subscription) {
import sinon = require("sinon");
import should = require("should");
import { clearTimeout } from "timers";
            while (itemToMonitors.length + itemsToMonitor1.length < 10000) {
                    const timerId = setTimeout(() => resolve(), 12000);
    on(eventName: "error", eventHandler: (err: Error) => void): this;
                this.emit("error", new Error("maximum message size exceeded"));
                this.emit("error", new Error(message));
const argv = require("yargs")
    .usage("Usage: $0 --portServer [num] --port [num]  --hostname <hostname> -block")
    .argv;
const chalk = require("chalk");

        var err = new s.TCPErrorMessage();
import { CallbackT, StatusCodes } from "node-opcua-status-code";
    private readonly messageBuilder: MessageBuilder;
            securityMode: this.securityMode
        this._requests = {};
            .on("message", (response: Response, msgType: string, requestId: number) => {
                this._on_message_received(response, msgType, requestId);
            .on("start_chunk", () => {
            .on("error", (err, requestId) => {
                //

        this.__in_normal_close_operation = false;

        this._timeout_request_count = 0;

        this._securityTokenTimeoutId = null;

        this.transportTimeout = options.transportTimeout || ClientSecureChannelLayer.defaultTransportTimeout;

        this.channelId = 0;

        this.connectionStrategy = coerceConnectionStrategy(options.connectionStrategy);

    public closeWithError(err: Error, callback: ErrorCallback): void {
            this._transport.prematureTerminate(err);
            requestData._tick2 = this.messageBuilder._tick1;
        requestData.bytesRead = this.messageBuilder.totalMessageSize;
                const cryptoFactory = this.messageBuilder.cryptoFactory;
                this.messageBuilder.pushNewToken(this.securityToken, derivedServerKeys);
        this._transport.on("message", (messageChunk: Buffer) => {
                this.closeWithError(new Error("Restarting because Request has timed out during OpenSecureChannel"), () => {
                    /* */
                });
        this.messageBuilder.feed(messageChunk);
import { decodeStatusCode } from "node-opcua-status-code";
import { MessageBuilderBase } from "node-opcua-transport";
import { chooseSecurityHeader, SymmetricAlgorithmSecurityHeader } from "./secure_channel_service";
export interface MessageBuilderOptions {
            return this._report_error("internal error");
            // invalid message type
            return this._report_error("ERROR RECEIVED");
            return this._report_error("Invalid message type ( HEL/ACK )");
            return this._report_error(err instanceof Error ? err.message : " err");
            return this._report_error("cannot construct object with nodeID " + id.toString());
            return this._report_error("cannot construct object with nodeID " + id);
import { make_errorLog, make_warningLog} from "node-opcua-debug";
        this.maxMessageSize = options.maxMessageSize || 16 *1024*1024;
                    errorLog(`[NODE-OPCUA-E55] message size ${totalSize} exceeds the negotiated message size ${this.maxMessageSize} nb chunks ${nbChunks}`);
    exploreCertificate
import { ServerTCP_transport } from "node-opcua-transport";
    public readonly messageBuilder: MessageBuilder;
        this.messageBuilder = new MessageBuilder({
            name: "server",
            objectFactory: options.objectFactory,
            privateKey: this.getPrivateKey()
        });

        this.messageBuilder.on("error", (err) => {
            // istanbul ignore next
            if (doDebug) {
                debugLog(chalk.red("xxxxx error "), err.message.yellow, err.stack);
                debugLog(chalk.red("xxxxx Server is now closing socket, without further notice"));
            }
            // close socket immediately
            this.close(undefined);
        });

        assert(this.messageBuilder, "dispose already called ?");
            // xx this.messageBuilder = null;
            (this as any).transport = null;
        this.messageBuilder.setSecurity(securityMode, securityPolicy);
                this.transport.on("message", (messageChunk: Buffer) => {
                    assert(this.messageBuilder);
                    this.messageBuilder.feed(messageChunk);
    public send_fatal_error_and_abort(
        statusCode: StatusCode,
        description: string,
        message: Message,
        callback: ErrorCallback
    ): void {
        /* istanbul ignore next */
        if (!(this.messageBuilder && this.messageBuilder.sequenceHeader && this.messageBuilder.securityHeader)) {
            return this._on_OpenSecureChannelRequestError(StatusCodes.BadCommunicationError, "internal error", message, callback);
        }

                this._on_common_message(request, msgType, requestId, channelId);
            .on("start_chunk", () => {
            this.messageBuilder.removeListener("message", messageHandler);
            this.messageBuilder.removeListener("error", errorHandler);
        this.messageBuilder.once("error", errorHandler);
        this.messageBuilder.once("message", messageHandler);
            const cryptoFactory = this.messageBuilder.cryptoFactory;
        const cryptoFactory = this.messageBuilder.cryptoFactory;
            return this.send_fatal_error_and_abort(StatusCodes.BadInternalError, "invalid request", message, callback);
        const cryptoFactory = this.messageBuilder.cryptoFactory;
        this.messageBuilder.pushNewToken(this.securityToken, derivedClientKeys);
        if (this.messageBuilder.sequenceHeader === null) {
        requestId = this.messageBuilder.sequenceHeader.requestId;
                    return this.send_fatal_error_and_abort(
        this.send_fatal_error_and_abort(serviceResult, description, message, callback);
    it("should decrypt an OPN packet and verify that the signature is correct", function() {
const { MessageBuilder } = require("..");
const { SecurityPolicy, MessageSecurityMode} = require("..");
            function () {}
            .on("message", (message) => {})
            .on("message", (message) => {})
const crypto_utils = require("node-opcua-crypto");
const fake_message_chunk_factory = require("../dist/test_helpers/fake_message_chunk_factory");
        const options = {};
        const messageBuilder = new MessageBuilder(options);
        messageBuilder.privateKey = crypto_utils.readPrivateRsaKey(private_key_filename);
            .on("message", (message) => {/** */})
        fake_message_chunk_factory.iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
        fake_message_chunk_factory.iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
        fake_message_chunk_factory.iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
        messageBuilder.privateKey = crypto_utils.readPrivateRsaKey(private_key_filename);
            .on("message", (message) => {/** */})
        fake_message_chunk_factory.iterateOnSignedAndEncryptedMessageChunks(lorem_ipsum_buffer, function (err, chunk) {
        const options = {};
        const messageBuilder = new MessageBuilder(options);
        messageBuilder.privateKey = crypto_utils.readPrivateRsaKey(private_key_filename);
        messageBuilder.pushNewToken({ tokenId: 10 }, fake_message_chunk_factory.derivedKeys);
            .on("message", (message) => {/** */})
        fake_message_chunk_factory.iterateOnSymmetricEncryptedChunk(lorem_ipsum_buffer, function (err, chunk) {
        serverChannel.init(socket, function () {});
                secureChannel.abortConnection(function () {});
        await closeChannel().should.be.rejectedWith(/Transport disconnected/);
            await promisify(secureChannel.closeWithError).call(secureChannel, new Error("Sabotage"));
                        .on("message", function(reconstructed_message) {
            .on("message", function(message) {
           
                
                doDebug &&  console.log("client received a response ", response?.constructor.name);
                doDebug &&  console.log(response?.toString());
    it("client & server channel  - with security ", (done) => {

const { ServerSecureChannelLayer, MessageSecurityMode, SecurityPolicy } = require("..");
        serverSecureChannel.on("message", function (message) {
        serverSecureChannel.on("message", function (message) {
            serverSecureChannel.send_response("MSG", new GetEndpointsResponse(), message, () => {});
        let isDone = false;
            isDone = true;
const MessageBuilder = require("..").MessageBuilder;
xdescribe("testing with problematic packet", function () {
        messageBuilder.setSecurity(MessageSecurityMode.None,SecurityPolicy.None);
        on("message", function (message) {
            on_message__received = true;
            message.schema.name.should.equal("GetEndpointsResponse");
            on_message__received.should.equal(true);
            full_message_body_event_received.should.equal(true);
            done();
        }).
        on("full_message_body", function (full_message_body) {
            full_message_body_event_received = true;
        }).
        on("error", function (err) {
            should.not.exist(err);
            throw new Error("should not get there");
        });
        on("message", function (message) {
            messageCount += 1;
            if (messageCount === 2) {
                done();
            }
        }).
        on("error", function (err) {
            console.log(err);
            throw new Error("should not get there");
        }).
        on("invalid_sequence_number", function (expected, found) {
            throw new Error("should not received a invalid_sequence_number here");
        });
        //
        const services = require("../src/services");

        const ec = require("node-opcua-basic-types");
        const full_message_body = require("../test_fixtures/fixture_problematic_ReadResponse.js").packet_ReadResponse;
        const id = ec.decodeExpandedNodeId(binaryStream);
        this.objectFactory = require("node-opcua-factory");
        // construct the object
        const objMessage = this.objectFactory.constructObject(id);
        if (!objMessage) {
            console.log(services);
            console.log("cannot construct object with id" + id.toString());
        }
        objMessage.constructor.name.should.eql("ReadResponse");
        const analyseExtensionObject = require("node-opcua-packet-analyzer").analyseExtensionObject;
const { makebuffer_from_trace  } = require("node-opcua-debug");
exports.packet_ReadResponse= makebuffer_from_trace(function () {
export function iterateOnSymmetricEncryptedChunk(buffer: Buffer, callback: ChunkVisitorFunc) {
    msgChunkManager.on("chunk", (chunk, final) => callback(null, chunk));
    const messageBuilder = new MessageBuilder({});
    messageBuilder.on("start_chunk", (info) => {
import { bindRoleSet} from "./user_manager_ua";

        return computeSignature(clientCertificate, clientNonce, this.getPrivateKey(), channel.messageBuilder.securityPolicy);
        const securityPolicy = channel.messageBuilder.securityPolicy;
        assert(typeof callback === 'function');
        assert(typeof callback === 'function');
    on(eventName: "message", eventHandler: (message: Buffer) => void): this;
    once(eventName: "message", eventHandler: (message: Buffer) => void): this;
 *    transport.on("message",function(message_chunk) {
 *        // do something with message from server...
            maxChunkCount: 0, // 0 - no limits
            maxMessageSize: 0, // 0 - no limits

            receiveBufferSize: 1024 * 64 * 10,
            sendBufferSize: 1024 * 64 * 10 // 8192 min,
export * from "./HelloMessage";
export * from "./TCPErrorMessage";
export * from "./message_builder_base";
import { make_errorLog, make_debugLog } from "node-opcua-debug";
    public readonly signatureLength: number;    
    public readonly options: { signatureLength?: number };
    constructor(options?: { signatureLength?: number }) {
        options = options || {};
            minimumSizeInBytes: 0,
            readMessageFunc: readRawMessageHeader
        this._packetAssembler.on("message", (messageChunk) => this._feed_messageChunk(messageChunk));
        this._packetAssembler.on("newMessage", (info, data) => {
            this.emit("start_chunk", info, data);
                return this._report_error("Invalid secure channel Id");
            return false;
    protected _report_error(errorMessage: string): false {
        this.emit("error", new Error(errorMessage), this.sequenceHeader ? this.sequenceHeader.requestId : null);
            return this._report_error(`Invalid message header detected`);
            return this._report_error("received and Abort Message");
    public receiveBufferSize: number;
    public sendBufferSize: number;
    public maxMessageSize: number;
    public maxChunkCount: number;
    public protocolVersion: number;

        this.receiveBufferSize = 0;
        this.sendBufferSize = 0;
        this.maxMessageSize = 0;
        this.maxChunkCount = 0;
        this.protocolVersion = 0;
        if (debugLog) {
            debugLog(chalk.cyan("_abortWithError"));
        assert(typeof callback === "function", "expecting a callback");
        /* istanbul ignore else */
        if (!this._aborted) {
            this._aborted = 1;
            setTimeout(() => {
                // send the error message and close the connection
                assert(Object.prototype.hasOwnProperty.call(StatusCodes, statusCode.name));
                /* istanbul ignore next*/
                if (doDebug) {
                    debugLog(chalk.red(" Server aborting because ") + chalk.cyan(statusCode.name));
                    debugLog(chalk.red(" extraErrorDescription   ") + chalk.cyan(extraErrorDescription));
                }
                const errorResponse = new TCPErrorMessage({
                    reason: statusCode.description,
                    statusCode
                });
                const messageChunk = packTcpMessage("ERR", errorResponse);
                this.write(messageChunk);
                this.disconnect(() => {
                    this._aborted = 2;
                    callback(new Error(extraErrorDescription + " StatusCode = " + statusCode.name));
                });
            }, ServerTCP_transport.throttleTime);
        } else {
            callback(new Error(statusCode.name));
        }
    }
    private _send_ACK_response(helloMessage: HelloMessage): void {
        assert(helloMessage.receiveBufferSize >= minimumBufferSize);
        assert(helloMessage.sendBufferSize >= minimumBufferSize);
        this.receiveBufferSize = clamp_value(helloMessage.receiveBufferSize, 8192, 512 * 1024);
        this.sendBufferSize = clamp_value(helloMessage.sendBufferSize, 8192, 512 * 1024);
        this.maxMessageSize = clamp_value(helloMessage.maxMessageSize, 100000, 64 * 1024 * 1024);
        this.maxChunkCount = clamp_value(helloMessage.maxChunkCount, 0, 65535);

import { createFastUninitializedBuffer } from "node-opcua-buffer-utils";
import * as debug from "node-opcua-debug";
import { PacketAssembler } from "node-opcua-packet-assembler";
import { ErrorCallback, CallbackWithData } from "node-opcua-status-code";
import { writeTCPMessageHeader } from "./tools";
const debugLog = debug.make_debugLog(__filename);
const doDebug = debug.checkDebugFlag(__filename);
const errorLog = debug.make_errorLog(__filename);
    
    on(eventName: "message", eventHandler: (message: Buffer) => void): this;
    once(eventName: "message", eventHandler: (message: Buffer) => void): this;
    private _pendingBuffer?: any;
        this._pendingBuffer = undefined;
    /**
     * ```createChunk``` is used to construct a pre-allocated chunk to store up to ```length``` bytes of data.
     * The created chunk includes a prepended header for ```chunk_type``` of size ```self.headerSize```.
     *
     * @method createChunk
     * @param msgType
     * @param chunkType {String} chunk type. should be 'F' 'C' or 'A'
     * @param length
     * @return a buffer object with the required length representing the chunk.
     *
     * Note:
     *  - only one chunk can be created at a time.
     *  - a created chunk should be committed using the ```write``` method before an other one is created.
     */
    public createChunk(msgType: string, chunkType: string, length: number): Buffer {
        assert(msgType === "MSG");
        assert(this._pendingBuffer === undefined, "createChunk has already been called ( use write first)");

        const totalLength = length + this.headerSize;
        const buffer = createFastUninitializedBuffer(totalLength);
        writeTCPMessageHeader("MSG", chunkType, totalLength, buffer);
        this._pendingBuffer = buffer;

        return buffer;
    }

     *
     * Notes:
     *  - the message chunk must have been created by ```createChunk```.
     *  - once a message chunk has been written, it is possible to call ```createChunk``` again.
     *
    public write(messageChunk: Buffer): void {
        assert(
            this._pendingBuffer === undefined || this._pendingBuffer === messageChunk,
            " write should be used with buffer created by createChunk"
        );
        assert(["F", "C", "A"].indexOf(header.messageHeader.isFinal) !== -1);
        this._write_chunk(messageChunk);
        this._pendingBuffer = undefined;
    protected _write_chunk(messageChunk: Buffer): void {
            this._socket.write(messageChunk);
        // install packet assembler ...
        this.packetAssembler = new PacketAssembler({
            readMessageFunc: readRawMessageHeader,

            minimumSizeInBytes: this.headerSize
        });

        /* istanbul ignore next */
        if (!this.packetAssembler) {
            throw new Error("Internal Error");
        }
        this.packetAssembler.on("message", (messageChunk: Buffer) => this._on_message_received(messageChunk));
            this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout));
    public prematureTerminate(err: Error): void {
        debugLog("prematureTerminate", err ? err.message : "");
            err.message = "socket has timeout: EPIPE: " + err.message;
    private _on_message_received(messageChunk: Buffer) {
            this.emit("message", messageChunk);
export const doTraceHelloAck = transportFlag.match(/HELACK/);
export const doTraceChunk = transportFlag.match(/CHUNK/);
const { assert } = require("node-opcua-assert");
const { StatusCodes, StatusCode } = require("node-opcua-status-code");


const { make_debugLog, make_errorLog } = require("node-opcua-debug");
        transport.on("message", function (message_chunk) {
        transport.connect(endpointUrl, function (err) {
            const buf = transport.createChunk("MSG", "F", message1.length);
        builder.on("chunk", function (message_chunk) {
        builder.on("chunk", function (message_chunk) {
        transport.on("message", (messageChunk) => {
        transport.on("message", (messageChunk) => {
        transport.on("message", (messageChunk) => {
        this.server.on("end", (err: Error) => {
Fixed code: import { ClientSecureChannelLayer, ConnectionStrategy, ConnectionStrategyOptions, SecurityPolicy } from "node-opcua-secure-channel";
import { FindServersOnNetworkRequestOptions, FindServersRequestOptions, ServerOnNetwork } from "node-opcua-service-discovery";
import { ApplicationDescription, EndpointDescription } from "node-opcua-service-endpoints";
export interface TransportSettings {
    maxChunkCount?: number;
    /**
     * @advanced
     */
    maxMessageSize?: number;
    /**
     * @advanced
     */
    sendBufferSize?: number;
    /**
     * @advanced
     */
    receiveBufferSize?: number;
}

    /**
     * @advanced
     */
    transportSetting?: TransportSettings
            tokenRenewalInterval: this.tokenRenewalInterval,
            
            // transportTimeout:

import { BaseUAObject, constructObject } from "node-opcua-factory";
    const messageBuilder = new MessageBuilder({
        maxChunkCount: 1,
        maxChunkSize: buffer.length + 100,
        maxMessageSize: buffer.length + 100
    });

    let objMessage: BaseUAObject | null = null;
import { allPermissions, OPCUAClient, OPCUAServer, StatusCodes, UserTokenType, WellKnownRoles, makeRoles } from "node-opcua";
        { username: "Gandalf", password: "g", roles: makeRoles([WellKnownRoles.AuthenticatedUser, WellKnownRoles.ConfigureAdmin]) },
        { username: "Frodo", password: "f", roles: makeRoles([WellKnownRoles.AuthenticatedUser]) }
            getUserRoles: (username) => users.find((user) => user.username === username)!.roles,

            isValidUser: (username: string, password: string) => {
                const user = users.find((user) => user.username === username);
    });
        endpointMustExist: false
        namespace
            .addMethod(folder, {
                browseName: "doIt",
                nodeId: "ns=1;s=doIt",
                rolePermissions: [
                    {
                        roleId: WellKnownRoles.ConfigureAdmin,
                        permissions: allPermissions
                    }
                ]
                /*
            })
            .bindMethod((inputArguments, context, callback) => {
                wasExecuted = true;
                callback(null, { statusCode: StatusCodes.Good });
            });
    beforeEach(() => (wasExecuted = false));
            inputArguments: []
            inputArguments: []
});
                requestedSessionTimeout: 600 * 1000, // use long session time out
            const too_many = 5000;
const { make_debugLog, checkDebugFlag } = require("node-opcua-debug");
const { pause } = require("../discovery/_helper");

    await pause(100);

    await pause(100);
            console.log(monitoredItem);
        }, 15000);
    return await new Promise((resolve, reject) => {
            console.log(currentSessionCountMonitoredItem);
        }, 15000);

            await perform_operation_on_subscription_async(client, endpointUrl, async (session, subscription) => {

import { clearTimeout } from "timers";
import * as should from "should";
            session.on("session_closed", ()=>{ 
                console.log("session_closed");  
            });

            while (itemToMonitors.length + itemsToMonitor1.length < 2200) {


                    const timerId = setTimeout(() => resolve(), 5000);
                    
export enum PacketAssemblerErrorCode {
    ChunkSizeExceeded = 1,
    ChunkTooSmall = 2
}
    on(eventName: "error", eventHandler: (err: Error, errCode: PacketAssemblerErrorCode) => void): this;
                this.emit("error", new Error("chunk is too small "), PacketAssemblerErrorCode.ChunkTooSmall);
                this.emit("error", new Error(message), PacketAssemblerErrorCode.ChunkSizeExceeded);
const chalk = require("chalk");
const argv = require("yargs")
    .usage("Usage: $0 --portServer [num] --port [num]  --hostname <hostname> -block")
    .argv;
        const err = new s.TCPErrorMessage();
            /** */
import { CallbackT, StatusCode, StatusCodes } from "node-opcua-status-code";
import { StatusCodes2 } from "node-opcua-transport";

    private messageBuilder?: MessageBuilder;
        this._requests = {};

        this.__in_normal_close_operation = false;

        this._timeout_request_count = 0;

        this._securityTokenTimeoutId = null;

        this.transportTimeout = options.transportTimeout || ClientSecureChannelLayer.defaultTransportTimeout;

        this.channelId = 0;

        this.connectionStrategy = coerceConnectionStrategy(options.connectionStrategy);
    }

    private _install_message_builder() {
        // istanbul ignore next
        if (!this._transport || !this._transport.parameters) {
            throw new Error("internal error");
        }
            securityMode: this.securityMode,
            maxChunkSize: this._transport.receiveBufferSize || 0,
            maxChunkCount: this._transport.maxChunkCount || 0,
            maxMessageSize: this._transport.maxMessageSize || 0
            .on("message", (response: BaseUAObject, msgType: string, requestId: number, channelId: number) => {
                this._on_message_received(response as Response, msgType, requestId);
            .on("startChunk", () => {
            .on("error", (err: Error, statusCode: StatusCode, requestId: number | null) => {
                if (!requestId) {
                    return;
                }

    public closeWithError(err: Error, statusCode: StatusCode, callback: ErrorCallback): void {
            this._transport.prematureTerminate(err, statusCode);
            requestData._tick2 = this.messageBuilder!._tick1;
        requestData.bytesRead = this.messageBuilder!.totalMessageSize;
                const cryptoFactory = this.messageBuilder!.cryptoFactory;
                this.messageBuilder!.pushNewToken(this.securityToken, derivedServerKeys);
        this._install_message_builder();

        this._transport.on("chunk", (messageChunk: Buffer) => {
                this.closeWithError(
                    new Error("Restarting because Request has timed out during OpenSecureChannel"),
                    StatusCodes2.BadRequestTimeout,
                    () => {
                        /* */
                    }
                );
        this.messageBuilder!.feed(messageChunk);
import { decodeStatusCode, coerceStatusCode, StatusCodes, StatusCode } from "node-opcua-status-code";
import { MessageBuilderBase, MessageBuilderBaseOptions, StatusCodes2 } from "node-opcua-transport";
import { chooseSecurityHeader, MessageChunker, SymmetricAlgorithmSecurityHeader } from "./secure_channel_service";
export interface MessageBuilderOptions extends MessageBuilderBaseOptions {
type PacketInfo = any;

export interface MessageBuilder extends MessageBuilderBase {
    on(eventName: "startChunk", eventHandler: (info: PacketInfo, data: Buffer) => void): this;
    on(eventName: "chunk", eventHandler: (chunk: Buffer) => void): this;
    on(eventName: "error", eventHandler: (err: Error, statusCode: StatusCode, requestId: number | null) => void): this;
    on(eventName: "full_message_body", eventHandler: (fullMessageBody: Buffer) => void): this;
    on(
        eventName: "message",
        eventHandler: (obj: BaseUAObject, msgType: string, requestId: number, channelId: number) => void
    ): this;

    on(eventName: "invalid_message", eventHandler: (obj: BaseUAObject) => void): this;
    on(eventName: "invalid_sequence_number", eventHandler: (expectedSequenceNumber: number, sequenceNumber: number) => void): this;
    on(eventName: "new_token", eventHandler: (tokenId: number) => void): this;

    emit(eventName: "startChunk", info: PacketInfo, data: Buffer): boolean;
    emit(eventName: "chunk", chunk: Buffer): boolean;
    emit(eventName: "error", err: Error, statusCode: StatusCode, requestId: number | null): boolean;
    emit(eventName: "full_message_body", fullMessageBody: Buffer): boolean;
    emit(eventName: "message", obj: BaseUAObject, msgType: string, requestId: number, channelId: number): boolean;
    emit(eventName: "invalid_message", evobj: BaseUAObject): boolean;
    emit(eventName: "invalid_sequence_number", expectedSequenceNumber: number, sequenceNumber: number): boolean;
    emit(eventName: "new_token", tokenId: number): boolean;
}
    protected _reportErrMessage(message: Buffer) {
        try {
            const binaryStream = new BinaryStream(message);
            const msgType = binaryStream.readUInt32();
            const msgLength = binaryStream.readUInt32();
            if (message.length === msgLength) {
                const errorCode = binaryStream.readUInt32();
                const additionalInfo = decodeString(binaryStream);
                // invalid message type
                const m1 = `ERR: ${errorCode} ${additionalInfo}`;
                warningLog(m1);
                return this._report_error(coerceStatusCode(errorCode), m1);
            } else {
                return this._report_error(StatusCodes.BadTcpInternalError, message.toString("hex"));
            }
        } catch (err) {
            console.log(hexDump(message));
            return this._report_error(StatusCodes.BadTcpInternalError, message.toString("hex"));
        }
    }

            return this._report_error(StatusCodes2.BadTcpInternalError, "internal error");
            return this._reportErrMessage(fullMessageBody);
            return this._report_error(StatusCodes2.BadTcpMessageTypeInvalid, "Invalid message type ( HEL/ACK )");
            return this._report_error(StatusCodes2.BadTcpInternalError, err instanceof Error ? err.message : " err");
            return this._report_error(StatusCodes.BadNotSupported, "cannot construct object with nodeID " + id.toString());
            return this._report_error(StatusCodes.BadNotSupported, "cannot construct object with nodeID " + id);
import { make_errorLog, make_warningLog } from "node-opcua-debug";
    public static defaultMaxMessageSize: number = 16 * 1024 * 1024;

        this.maxMessageSize = options.maxMessageSize || MessageChunker.defaultMaxMessageSize;
                    errorLog(
                        `[NODE-OPCUA-E55] message size ${totalSize} exceeds the negotiated message size ${this.maxMessageSize} nb chunks ${nbChunks}`
                    );
/* eslint-disable max-statements */
    exploreCertificate,
    hexDump
import { ServerTCP_transport, StatusCodes2 } from "node-opcua-transport";
import { doTraceIncomingChunk } from "node-opcua-transport";


    public messageBuilder?: MessageBuilder;


        this.objectFactory = options.objectFactory;

    private _build_message_builder() {
        this.messageBuilder = new MessageBuilder({
            name: "server",
            objectFactory: this.objectFactory,
            privateKey: this.getPrivateKey(),
            maxChunkSize: this.transport.receiveBufferSize,
            maxChunkCount: this.transport.maxChunkCount,
            maxMessageSize: this.transport.maxMessageSize
        });
        debugLog(" this.transport.maxChunkCount", this.transport.maxChunkCount);
        debugLog(" this.transport.maxMessageSize", this.transport.maxMessageSize);

        this.messageBuilder.on("error", (err, statusCode) => {

            warningLog("ServerSecureChannel:MessageBuilder: ", err.message);
            
            // istanbul ignore next
            if (doDebug) {
                debugLog(chalk.red("Error "), err.message, err.stack);
                debugLog(chalk.red("Server is now closing socket, without further notice"));
            }

            this.transport.sendErrorMessage(statusCode, err.message);

            // close socket immediately
            this.close(undefined);
        });
    }

            this.messageBuilder = undefined;
            (this as any).transport = undefined;
        if (!this.messageBuilder) {
            this._build_message_builder();
        }
        assert(this.messageBuilder);
        this.messageBuilder!.setSecurity(securityMode, securityPolicy);
                this._build_message_builder();

                this.transport.on("chunk", (messageChunk: Buffer) => {
                    // istanbul ignore next
                    if (doTraceIncomingChunk) {
                        console.log(hexDump(messageChunk));
                    }
                    this.messageBuilder!.feed(messageChunk);
    private _sendFatalErrorAndAbort(statusCode: StatusCode, description: string, message: Message, callback: ErrorCallback): void {

        /* istanbul ignore next */
        if (!(this.messageBuilder && this.messageBuilder.sequenceHeader && this.messageBuilder.securityHeader)) {
            return this._on_OpenSecureChannelRequestError(
                StatusCodes.BadCommunicationError,
                "internal error",
                { request, requestId },
                callback
            );
        }

                this._on_common_message(request as Request, msgType, requestId, channelId);
            .on("error", (err: Error, statusCode: StatusCode, requestId: number | null) => {
                /** */
                this.transport.sendErrorMessage(statusCode, err.message);
                this.close();
            })
            .on("startChunk", () => {
            this.messageBuilder!.removeListener("message", messageHandler);
            this.messageBuilder!.removeListener("error", errorHandler);
        this.messageBuilder!.once("error", errorHandler);
        this.messageBuilder!.once("message", messageHandler);
            const cryptoFactory = this.messageBuilder!.cryptoFactory;
        const cryptoFactory = this.messageBuilder!.cryptoFactory;
            return this._sendFatalErrorAndAbort(StatusCodes2.BadSecurityChecksFailed, "invalid request", message, callback);
        const cryptoFactory = this.messageBuilder!.cryptoFactory;
        this.messageBuilder!.pushNewToken(this.securityToken, derivedClientKeys);
        if (this.messageBuilder!.sequenceHeader === null) {
        requestId = this.messageBuilder!.sequenceHeader.requestId;
                    return this._sendFatalErrorAndAbort(
        this._sendFatalErrorAndAbort(serviceResult, description, message, callback);
    xit("should decrypt an OPN packet and verify that the signature is correct", function() {
        // 1496

const { MessageBuilder } = require("..");
const { SecurityPolicy, MessageSecurityMode } = require("..");
            function () {/** */ }
            .on("message", (message) => { /** */})
            .on("message", (message) => { /** */})
const { readPrivateRsaKey } = require("node-opcua-crypto");
const {
    iterateOnSymmetricEncryptedChunk,
    iterateOnSignedAndEncryptedMessageChunks,
    iterateOnSignedMessageChunks,
    derivedKeys
} = require("../dist/test_helpers/fake_message_chunk_factory");
        const messageBuilder = new MessageBuilder({
            maxChunkCount: 10,
            maxMessageSize: someBuffer.length * 10,
            maxChunkSize: someBuffer.length  + 1000 ,
        });
        messageBuilder.privateKey = readPrivateRsaKey(private_key_filename);
            .on("message", (message) => {/** */ })
                console.log("ERROR", error);
        iterateOnSignedMessageChunks(someBuffer, (err, chunk) => {
        iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
        iterateOnSignedMessageChunks(someBuffer, function (err, chunk) {
        messageBuilder.privateKey = readPrivateRsaKey(private_key_filename);
            .on("message", (message) => {/** */ })
        iterateOnSignedAndEncryptedMessageChunks(lorem_ipsum_buffer, function (err, chunk) {
        const messageBuilder = new MessageBuilder({
            maxMessageSize: 1000000,
            maxChunkSize: 2048,
            maxChunkCount: 5
        });
        messageBuilder.privateKey = readPrivateRsaKey(private_key_filename);
        messageBuilder.pushNewToken({ tokenId: 10 }, derivedKeys);
        let _err;
            .on("message", (message) => {/** */ })
                console.log("err ", error.message);
        iterateOnSymmetricEncryptedChunk(lorem_ipsum_buffer, function (err, chunk) {
const { StatusCodes } = require("node-opcua-status-code");
        serverChannel.init(socket, function () {/** */ });
                secureChannel.abortConnection(function () {/** */ });
    // eslint-disable-next-line @typescript-eslint/no-this-alias


        await closeChannel(); // .should.be.rejectedWith(/Transport disconnected/);
            await promisify(secureChannel.closeWithError).call(secureChannel, StatusCodes.Bad, new Error("Sabotage"));
            console.log(err.message);
                        .on("message", (reconstructed_message) => {
            .on("message", (message) => {
                doDebug && console.log("client received a response ", response?.constructor.name);
                doDebug && console.log(response?.toString());

                    (serverSChannel as any)._build_message_builder();

    it("RR-client & server channel  - with security ", (done) => {

const { HelloMessage } = require("node-opcua-transport");
const { OpenSecureChannelRequest, SecurityTokenRequestType, ReadRequest } = require("node-opcua-types");
const { hexDump } = require("node-opcua-crypto");
const { BinaryStream } = require("node-opcua-binary-stream");

const { ServerSecureChannelLayer, MessageSecurityMode, SecurityPolicy, MessageChunker } = require("..");
const { pause } = require("../../node-opcua-end2end-test/test/discovery/_helper");
// eslint-disable-next-line import/order
        serverSecureChannel.on("message", (message) => {
        serverSecureChannel.on("message", (message) => {
            serverSecureChannel.send_response("MSG", new GetEndpointsResponse(), message, () => {/** */ });
            /** */





    it("KK8 should not accept message with too large chunk", async () => {
        const node = new DirectTransport();

        let serverSecureChannel = new ServerSecureChannelLayer({
        });

        serverSecureChannel.setSecurity(MessageSecurityMode.None, SecurityPolicy.None);
        serverSecureChannel.timeout = 100000;


        let initialized = false;
        serverSecureChannel.init(node.server, (err) => {
            initialized = true;
            should.not.exist(err);
        });

        async function send(chunk) {
            return await new Promise((resolve) => {
                node.client.once("data", (data) => {
                    resolve(data);
                });
                node.client.write(chunk);
            });
        }

        async function send1(msg, request) {

            const l = request.binaryStoreSize();

            // craft a HELLO Message        
            const b = new BinaryStream(l + 8);
            b.writeInt8(msg[0].charCodeAt(0));
            b.writeInt8(msg[1].charCodeAt(0));
            b.writeInt8(msg[2].charCodeAt(0));
            b.writeInt8("F".charCodeAt(0));
            b.writeUInt32(0);
            request.encode(b);
            b.buffer.writeInt32LE(b.length, 4);

            console.log(`sending\n${hexDump(b.buffer)}`)

            const rep = await send(b.buffer);
            console.log(`receiving\n${hexDump(rep)}`);
            return rep;
        }
        async function sendHello() {
            // eslint-disable-next-line no-undef
            const helloMessage = new HelloMessage({
                protocolVersion: 0,// UInt32;
                receiveBufferSize: 8 * 1024,// UInt32;
                sendBufferSize: 8 * 1024,
                maxMessageSize: 16 * 1024,
                maxChunkCount: 2,
                endpointUrl: "opc.tcp://localhost:1234/SomeEndpoint"
            });
            await send1("HEL", helloMessage);

        }

        let requestId = 1;
        async function send2(msg, request, tweakerFunc) {
            const messageChunker = new MessageChunker();

            return await new Promise((resolve,reject) => {
                node.client.once("data", (chunk) => {
                    requestId += 1;
                    console.log(`receiving\n${hexDump(chunk)}`);
                    resolve(chunk);
                    resolve();
                });
                node.client.once("error", (err) => {
                    reject(err);
                })
                messageChunker.chunkSecureMessage(msg, {
                    requestId,
                    securityMode: MessageSecurityMode.None,
                }, request, (chunk) => {
                    if (chunk) {
                        if (tweakerFunc) {
                            chunk = tweakerFunc(chunk);
                        }
                        console.log(`sending\n${hexDump(chunk)}`);
                        node.client.write(chunk)
                    } else {
                        console.log("done.");
                    }
                });
            });

        }

        async function sendOpenChannel() {

            const openChannelRequest = new OpenSecureChannelRequest({
                clientNonce: null,
                clientProtocolVersion: 0,
                requestHeader: {
                },
                requestType: SecurityTokenRequestType.Init,
                requestedLifetime: 100000,
                securityMode: MessageSecurityMode.None,
            });
            return await send2("OPN", openChannelRequest);

        }

        async function sendTooLargeChunkMessage() {
            return await send2("MSG", new ReadRequest({}), (chunk)=>{
                chunk.writeUInt32LE(0xFFFF,4);
                return chunk;
            });
        }

        await sendHello();
        await sendOpenChannel();
        await sendTooLargeChunkMessage();

        // console.log(serverSecureChannel.transport);

        await new Promise((resolve) => {
            serverSecureChannel.close(() => {
                serverSecureChannel.dispose();
                resolve();
            });
        });
        node.shutdown(() => {/** */ });

    });

const { decodeExpandedNodeId } = require("node-opcua-basic-types");
const { analyseExtensionObject } = require("node-opcua-packet-analyzer");
const { MessageBuilder } = require("..");
const { MessageSecurityMode, SecurityPolicy } = require("..");
const full_message_body = require("../test_fixtures/fixture_problematic_ReadResponse.js").packet_ReadResponse;

describe("testing with problematic packet", function () {
        messageBuilder.setSecurity(MessageSecurityMode.None, SecurityPolicy.None);
            on("message", function (message) {
                on_message__received = true;
                message.schema.name.should.equal("GetEndpointsResponse");
                on_message__received.should.equal(true);
                full_message_body_event_received.should.equal(true);
                done();
            }).
            on("full_message_body", function (full_message_body) {
                full_message_body_event_received = true;
            }).
            on("error", function (err) {
                should.not.exist(err);
                throw new Error("should not get there");
            });
            on("message", function (message) {
                messageCount += 1;
                if (messageCount === 2) {
                    done();
                }
            }).
            on("error", function (err) {
                console.log(err);
                throw new Error("should not get there");
            }).
            on("invalid_sequence_number", function (expected, found) {
                throw new Error("should not received a invalid_sequence_number here");
            });
        const id = decodeExpandedNodeId(binaryStream);
        // this.objectFactory = objectFactory;
        // // construct the object
        // const objMessage = this.objectFactory.constructObject(id);
        // if (!objMessage) {
        //     console.log("cannot construct object with id" + id.toString());
        // }
        // objMessage.constructor.name.should.eql("ReadResponse");
const { makeBufferFromTrace  } = require("node-opcua-debug");
exports.packet_ReadResponse= makeBufferFromTrace(function () {
export function iterateOnSymmetricEncryptedChunk(buffer: Buffer, onChunkFunc: ChunkVisitorFunc) {
    msgChunkManager.on("chunk", (chunk, final) => onChunkFunc(null, chunk));
    const maxChunkSize = packets.map((p) => p.length).reduce((a, b) => Math.max(a, b), 0);

    const messageBuilder = new MessageBuilder({
        maxChunkCount: packets.length + 1,
        maxMessageSize: 1000000,
        maxChunkSize
    });
    messageBuilder.on("startChunk", (info) => {
    messageBuilder.on("error", (err) => {
        console.log("verify_multi_chunk_message : err", err.message);
    });

import { bindRoleSet } from "./user_manager_ua";
        return computeSignature(clientCertificate, clientNonce, this.getPrivateKey(), channel.messageBuilder!.securityPolicy);
        const securityPolicy = channel.messageBuilder!.securityPolicy;
        assert(typeof callback === "function");
        assert(typeof callback === "function");
    on(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
    once(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
 *    transport.on("chunk",function(message_chunk) {
 *        // do something with chunk from server...
    public static defaultMaxChunk = 0; // 0 - no limits
    public static defaultMaxMessageSize = 0; // 0 - no limits
    public static defaultReceiveBufferSize = 1024 * 64 * 10;
    public static defaultSendBufferSize = 1024 * 64 * 10; // 8192 min,


        // initially before HEL/ACK
        this.maxChunkCount = 1;
        this.maxMessageSize = 4 * 1024;
        this.receiveBufferSize = 4 * 1024;


            this.setLimits(response as AcknowledgeMessage);
            maxChunkCount: ClientTCP_transport.defaultMaxChunk,
            maxMessageSize: ClientTCP_transport.defaultMaxMessageSize,
            receiveBufferSize: ClientTCP_transport.defaultReceiveBufferSize,
            sendBufferSize: ClientTCP_transport.defaultSendBufferSize
export * from "./HelloMessage";
export * from "./message_builder_base";
export * from "./status_codes";
export * from "./TCPErrorMessage";
export * from "./utils";
import { make_errorLog, make_debugLog, make_warningLog } from "node-opcua-debug";
import { StatusCode } from "node-opcua-status-code";
import { StatusCodes2 } from "./status_codes";
const warningLog = make_warningLog("MessageBuilder");
export interface MessageBuilderBaseOptions {
    signatureLength?: number;
    maxMessageSize?: number;
    maxChunkCount?: number;
    maxChunkSize?: number;
}

export interface MessageBuilderBase {
    on(eventName: "startChunk", eventHandler: (info: PacketInfo, data: Buffer) => void): this;
    on(eventName: "chunk", eventHandler: (chunk: Buffer) => void): this;
    on(eventName: "error", eventHandler: (err: Error, statusCode: StatusCode, requestId: number | null) => void): this;
    on(eventName: "full_message_body", eventHandler: (fullMessageBody: Buffer) => void): this;

    emit(eventName: "startChunk", info: PacketInfo, data: Buffer): boolean;
    emit(eventName: "chunk", chunk: Buffer): boolean;
    emit(eventName: "error", err: Error, statusCode: StatusCode, requestId: number | null): boolean;
    emit(eventName: "full_message_body", fullMessageBody: Buffer): boolean;
}
    public static defaultMaxChunkCount = 1000;
    public static defaultMaxMessageSize = 1024 * 64;
    public static defaultMaxChunkSize = 1024 * 8;

    public readonly signatureLength: number;
    public readonly maxMessageSize: number;
    public readonly maxChunkCount: number;
    public readonly maxChunkSize: number;

    public readonly options: MessageBuilderBaseOptions;
    constructor(options?: MessageBuilderBaseOptions) {
        options = options || {
            maxMessageSize: 0,
            maxChunkCount: 0,
            maxChunkSize: 0
        };
        this.maxMessageSize = options.maxMessageSize || MessageBuilderBase.defaultMaxMessageSize;
        this.maxChunkCount = options.maxChunkCount || MessageBuilderBase.defaultMaxChunkCount;
        this.maxChunkSize = options.maxChunkSize || MessageBuilderBase.defaultMaxChunkSize;

            minimumSizeInBytes: 8,
            maxChunkSize: this.maxChunkSize,
            readChunkFunc: readRawMessageHeader
        this._packetAssembler.on("chunk", (messageChunk) => this._feed_messageChunk(messageChunk));
        this._packetAssembler.on("startChunk", (info, data) => {
            this.emit("startChunk", info, data);
        });

        this._packetAssembler.on("error", (err) => {
            warningLog("packet assembler ", err.message);
            return this._report_error(StatusCodes2.BadTcpMessageTooLarge, "packet assembler: " + err.message);
                return this._report_error(StatusCodes2.BadTcpSecureChannelUnknown, "Invalid secure channel Id");
            return this._report_error(StatusCodes2.BadTcpInternalError, "_read_headers error " + (err as Error).message);
    protected _report_error(statusCode: StatusCode, errorMessage: string): false {
        this.emit("error", new Error(errorMessage), statusCode, this.sequenceHeader ? this.sequenceHeader.requestId : null);
        if (this.messageChunks.length + 1 > this.maxChunkCount) {
            return this._report_error(StatusCodes2.BadTcpMessageTooLarge, `max chunk count exceeded: ${this.maxChunkCount}`);
        }

        if (this.totalMessageSize > this.maxMessageSize) {
            return this._report_error(StatusCodes2.BadTcpMessageTooLarge, `max message size exceeded: ${this.maxMessageSize}`);
        }

            return this._report_error(StatusCodes2.BadTcpInternalError, `Invalid message header detected`);
                StatusCodes2.BadTcpInternalError,
            return this._report_error(StatusCodes2.BadRequestInterrupted, "received and Abort Message");

        // before HEL/ACK
        this.maxChunkCount = 1;
        this.maxMessageSize = 4 * 1024;
        this.receiveBufferSize = 4 * 1024;

        // istanbul ignore next
        

        // When a fatal error occurs, the Server shall send an Error Message to the Client and
        // closes the TransportConnection gracefully.
        doDebug && debugLog(chalk.cyan("_abortWithError"));
        
        /* istanbul ignore next */
        if (this._aborted) {
            // already called
            return callback(new Error(statusCode.name));
        this._aborted = 1;
        setTimeout(() => {
            // send the error message and close the connection
            this.sendErrorMessage(statusCode, statusCode.description);
            this.disconnect(() => {
                this._aborted = 2;
                callback(new Error(extraErrorDescription + " StatusCode = " + statusCode.name));
            });
        }, ServerTCP_transport.throttleTime);
    }
    private _send_ACK_response(helloMessage: HelloMessage): void {
        assert(helloMessage.receiveBufferSize >= minimumBufferSize);
        assert(helloMessage.sendBufferSize >= minimumBufferSize);
        const minBufferSize = 8192;
        const maxBufferSize = 64 * 1024;
        const minMaxMessageSize = 128 * 1024;
        const defaultMaxMessageSize = 16 * 1024 * 1024;
        const maxMaxMessageSize = 128 * 1024 * 1024;
        const minMaxChunkCount = 1;
        const defaultMaxChunkCount = defaultMaxMessageSize / maxBufferSize;
        const maxMaxChunkCount = 9000;
        const receiveBufferSize = 32 * 1024;
        const sendBufferSize = 32 * 1024;
        if (!helloMessage.maxChunkCount && helloMessage.sendBufferSize) {
            helloMessage.maxChunkCount = helloMessage.maxMessageSize / helloMessage.sendBufferSize;
        }
        this.setLimits({
            receiveBufferSize: clamp_value(helloMessage.receiveBufferSize || receiveBufferSize, minBufferSize, maxBufferSize),
            sendBufferSize: clamp_value(helloMessage.sendBufferSize || sendBufferSize, minBufferSize, maxBufferSize),
            maxMessageSize: clamp_value(helloMessage.maxMessageSize || defaultMaxMessageSize, minMaxMessageSize, maxMaxMessageSize),
            maxChunkCount: clamp_value(helloMessage.maxChunkCount || defaultMaxChunkCount, minMaxChunkCount, maxMaxChunkCount)
        });
            console.log("Client accepts only message of size => ", this.maxMessageSize);
import { StatusCodes } from "node-opcua-status-code";

export const StatusCodes2 = {
    /**
     * The Server cannot process the request because it is too busy.
     *
     * It is up to the Server to determine when it needs to return this Message.
     *
     * A Server can control the how frequently a Client reconnects by waiting to return this error.
     */
    BadTcpServerTooBusy: StatusCodes.BadTcpServerTooBusy,
    /**
     * The type of the Message specified in the header invalid.
     * Each Message starts with a 4-byte sequence of ASCII values that identifies the Message type.
     * The Server returns this error if the Message type is not accepted.
     * Some of the Message types are defined by the SecureChannel layer.
     */
    BadTcpMessageTypeInvalid: StatusCodes.BadTcpMessageTypeInvalid,
    /**
     * The SecureChannelId and/or TokenId are not currently in use.
     * This error is reported by the SecureChannel layer.
     */
    BadTcpSecureChannelUnknown: StatusCodes.BadTcpSecureChannelUnknown,
    /**
     * The size of the Message specified in the header is too large.
     * The Server returns this error if the Message size exceeds its maximum buffer size
     * or the receive buffer size negotiated during the Hello/Acknowledge exchange.
     */
    BadTcpMessageTooLarge: StatusCodes.BadTcpMessageTooLarge,

    /**
     * A timeout occurred while accessing a resource.
     * It is up to the Server to determine when a timeout occurs.
     */
    BadTimeout: StatusCodes.BadTimeout,
    /**
     * There are not enough resources to process the request.
     * The Server returns this error when it runs out of memory or encounters similar resource problems.
     * A Server can control the how frequently a Client reconnects by waiting to return this error.
     */
    BadTcpNotEnoughResources: StatusCodes.BadTcpNotEnoughResources,
    /**
     * An internal error occurred.
     * This should only be returned if an unexpected configuration or programming error occurs.
     */
    BadTcpInternalError: StatusCodes.BadTcpInternalError,
    /**
     * The Server does not recognize the EndpointUrl specified.
     */
    BadTcpEndpointUrlInvalid: StatusCodes.BadTcpEndpointUrlInvalid,
    /**
     * The Message was rejected because it could not be verified.
     */
    BadSecurityChecksFailed: StatusCodes.BadSecurityChecksFailed,
    /**
     * The request could not be sent because of a network interruption.
     */
    BadRequestInterrupted: StatusCodes.BadRequestInterrupted,
    /**
     * Timeout occurred while processing the request.
     */
    BadRequestTimeout: StatusCodes.BadRequestTimeout,
    /**
     * The secure channel has been closed.
     */
    BadSecureChannelClosed: StatusCodes.BadSecureChannelClosed,
    /**
     * The SecurityToken has expired or is not recognized. BadSecureChannelTokenUnknown
     */
    BadSecureChannelTokenUnknown: StatusCodes.BadSecureChannelTokenUnknown,
    /**
     * The sender Certificate is not trusted by the receiver.
     */
    BadCertificateUntrusted: StatusCodes.BadCertificateUntrusted,
    /**
     * The sender Certificate has expired or is not yet valid.
     */
    BadCertificateTimeInvalid: StatusCodes.BadCertificateTimeInvalid,
    /**
     * The issuer for the sender Certificate has expired or is not yet valid.
     */
    BadCertificateIssuerTimeInvalid: StatusCodes.BadCertificateIssuerTimeInvalid,
    /**
     * The sender’s Certificate may not be used for establishing a secure channel.
     */
    BadCertificateUseNotAllowed: StatusCodes.BadCertificateUseNotAllowed,
    /**
     * The issuer Certificate may not be used as a Certificate Authority.
     */
    BadCertificateIssuerUseNotAllowed: StatusCodes.BadCertificateIssuerUseNotAllowed,
    /**
     * Could not verify the revocation status of the sender’s Certificate.
     */
    BadCertificateRevocationUnknown: StatusCodes.BadCertificateRevocationUnknown,
    /**
     * Could not verify the revocation status of the issuer Certificate.
     */
    BadCertificateIssuerRevocationUnknown: StatusCodes.BadCertificateIssuerRevocationUnknown,
    /**
     * The sender Certificate has been revoked by the issuer.
     */
    BadCertificateRevoked: StatusCodes.BadCertificateRevoked
    /**The issuer Certificate has been revoked by its issuer.
     */
    // todo  BadIssuerCertificateRevoked: StatusCodes.BadIssuerCertificateRevoked,
    /** The receiver Certificate thumbprint is not recognized by the receiver.
     */
    // todo .. BadCertificateUnknown: StatusCodes.BadCertificateUnknown
};
import { BinaryStream } from "node-opcua-binary-stream";
import { make_debugLog, checkDebugFlag, make_errorLog, hexDump } from "node-opcua-debug";
import { PacketAssembler, PacketAssemblerErrorCode } from "node-opcua-packet-assembler";
import { ErrorCallback, CallbackWithData, StatusCode } from "node-opcua-status-code";
import { StatusCodes2 } from "./status_codes";
import { doTraceIncomingChunk } from "./utils";
import { TCPErrorMessage } from "./TCPErrorMessage";
import { packTcpMessage } from "./tools";
const debugLog = make_debugLog(__filename);
const doDebug = checkDebugFlag(__filename);
const errorLog = make_errorLog(__filename);

    on(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
    once(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
    public maxMessageSize: number;
    public maxChunkCount: number;
    public sendBufferSize: number;
    public receiveBufferSize: number;

        this.maxMessageSize = 0;
        this.maxChunkCount = 0;
        this.receiveBufferSize = 0;
        this.sendBufferSize = 0;
    public setLimits({
        receiveBufferSize,
        sendBufferSize,
        maxMessageSize,
        maxChunkCount
    }: {
        receiveBufferSize: number;
        sendBufferSize: number;
        maxMessageSize: number;
        maxChunkCount: number;
    }) {
        this.receiveBufferSize = receiveBufferSize;
        this.sendBufferSize = sendBufferSize;
        this.maxMessageSize = maxMessageSize;
        this.maxChunkCount = maxChunkCount;

        // reinstall packetAssembler with correct limits
        this._install_packetAssembler();
    }

    public write(messageChunk: Buffer, callback?: (err?: Error) => void | undefined): void {
        const c = header.messageHeader.isFinal;
        assert(c === "F" || c === "C" || c === "A");
        this._write_chunk(messageChunk, (err) => {
            callback && callback(err);
        });
    protected _write_chunk(messageChunk: Buffer, callback?: (err?: Error) => void | undefined): void {
            this._socket.write(messageChunk, callback);
        } else {
            if (callback) {
                callback();
            }
    protected _install_packetAssembler() {
        if (this.packetAssembler) {
            this.packetAssembler.removeAllListeners();
            this.packetAssembler = undefined;
        }

        // install packet assembler ...
        this.packetAssembler = new PacketAssembler({
            readChunkFunc: readRawMessageHeader,
            minimumSizeInBytes: this.headerSize,
            maxChunkSize: this.receiveBufferSize //Math.max(this.receiveBufferSize, this.sendBufferSize)
        });

        this.packetAssembler.on("chunk", (chunk: Buffer) => this._on_message_chunk_received(chunk));

        this.packetAssembler.on("error", (err, code) => {
            let statusCode = StatusCodes2.BadTcpMessageTooLarge;
            switch (code) {
                case PacketAssemblerErrorCode.ChunkSizeExceeded:
                    statusCode = StatusCodes2.BadTcpMessageTooLarge;
                    break;
                default:
                    statusCode = StatusCodes2.BadTcpInternalError;
            }

            this.sendErrorMessage(statusCode, err.message);
            this.prematureTerminate(new Error("Packet Assembler : " + err.message), statusCode);
        });
    }
        this._install_packetAssembler();
            this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout), StatusCodes2.BadTimeout);
    public sendErrorMessage(statusCode: StatusCode, extraErrorDescription: string | null): void {
        // When the Client receives an Error Message it reports the error to the application and closes the TransportConnection gracefully.
        // If a Client encounters a fatal error, it shall report the error to the application and send a CloseSecureChannel Message.

        /* istanbul ignore next*/
        if (doDebug) {
            debugLog(chalk.red(" sendErrorMessage        ") + chalk.cyan(statusCode.toString()));
            debugLog(chalk.red(" extraErrorDescription   ") + chalk.cyan(extraErrorDescription));
        }

        const reason = `${statusCode.toString()}:${extraErrorDescription || ""}`;
        const errorResponse = new TCPErrorMessage({
            statusCode,
            reason
        });
        const messageChunk = packTcpMessage("ERR", errorResponse);
        this.write(messageChunk);
    }

    public prematureTerminate(err: Error, statusCode: StatusCode): void {
        // https://reference.opcfoundation.org/v104/Core/docs/Part6/6.7.3/

        debugLog("prematureTerminate", err ? err.message : "", statusCode.toString());

            err.message = "premature socket termination " + err.message;
        // this.gracefullShutdown(err);
    private _on_message_chunk_received(messageChunk: Buffer) {
        if (doTraceIncomingChunk) {
            console.log(hexDump(messageChunk));
        }
            this.emit("chunk", messageChunk);
        // istanbul ignore next
export const doTraceHelloAck = !!transportFlag.match(/HELACK/);
export const doTraceChunk = !!transportFlag.match(/CHUNK/);
export const doTraceIncomingChunk = !!transportFlag.match(/FLOW/);
const { assert } = require("node-opcua-assert");
const { make_debugLog, make_errorLog } = require("node-opcua-debug");
const { StatusCodes, StatusCode } = require("node-opcua-status-code");

const { MessageBuilderBase, writeTCPMessageHeader } = require("..");
        transport.on("chunk", function (message_chunk) {

        /**
         * ```createChunk``` is used to construct a pre-allocated chunk to store up to ```length``` bytes of data.
         * The created chunk includes a prepended header for ```chunk_type``` of size ```self.headerSize```.
         *
         * @method createChunk
         * @param msgType
         * @param chunkType {String} chunk type. should be 'F' 'C' or 'A'
         * @param length
         * @return a buffer object with the required length representing the chunk.
         *
         * Note:
         *  - only one chunk can be created at a time.
         *  - a created chunk should be committed using the ```write``` method before an other one is created.
         */
        function createChunk(msgType, chunkType, headerSize, length) {
            assert(msgType === "MSG");
            const totalLength = length + headerSize;
            const buffer = Buffer.alloc(totalLength);
            writeTCPMessageHeader("MSG", chunkType, totalLength, buffer);
            return buffer;
        }
        transport.connect(endpointUrl, (err) => {
            const buf = createChunk("MSG", "F", transport.headerSize, message1.length);
const sinon = require("sinon");

        builder.on("chunk", (message_chunk) => {
        builder.on("chunk", (message_chunk) => {

    it("should not allow more chunks that maxChunkCount ", function (done) {

        const builder = new MessageBuilderBase({
            maxChunkCount: 5,
            maxMessageSize: 64 * 1024,
        });

        const onChunkSpy = sinon.spy();
        builder.on("chunk", onChunkSpy);

        const onFullMessageBodySpy = sinon.spy();
        builder.on("full_message_body", onFullMessageBodySpy);

        const onErrorSpy = sinon.spy();
        builder.on("error", onErrorSpy);

        const message_body = Buffer.alloc(16 * 1024);
        const chunk1 = wrap_message_in_chunk(message_body.slice(0 * 1024, 1 * 1024), "C");
        const chunk2 = wrap_message_in_chunk(message_body.slice(1 * 1024, 2 * 1024), "C");
        const chunk3 = wrap_message_in_chunk(message_body.slice(2 * 1024, 3 * 1024), "C");
        const chunk4 = wrap_message_in_chunk(message_body.slice(3 * 1024, 4 * 1024), "C");
        const chunk5 = wrap_message_in_chunk(message_body.slice(4 * 1024, 5 * 1024), "C");
        const chunk6 = wrap_message_in_chunk(message_body.slice(5 * 1024, 6 * 1024), "C");
        const chunk7 = wrap_message_in_chunk(message_body.slice(6 * 1024, 7 * 1024), "F");

        builder.feed(chunk1);
        builder.feed(chunk2);
        builder.feed(chunk3);
        builder.feed(chunk4);
        builder.feed(chunk5);
        builder.feed(chunk6);
        builder.feed(chunk7);

        onChunkSpy.callCount.should.eql(6);
        onErrorSpy.callCount.should.eql(1);
        onFullMessageBodySpy.callCount.should.eql(0);

        onErrorSpy.getCall(0).args[0].should.match(/max chunk count exceeded/);

        done();

    });
    it("should not allow message bigger than maxMessageSize ", function (done) {

        const builder = new MessageBuilderBase({
            maxChunkCount:  1000,
            maxMessageSize: 4 * 1024,
        });

        const onChunkSpy = sinon.spy();
        builder.on("chunk", onChunkSpy);

        const onFullMessageBodySpy = sinon.spy();
        builder.on("full_message_body", onFullMessageBodySpy);

        const onErrorSpy = sinon.spy();
        builder.on("error", onErrorSpy);

        const message_body = Buffer.alloc(16 * 1024);
        const chunk1 = wrap_message_in_chunk(message_body.slice(0 * 1024, 1 * 1024), "C");
        const chunk2 = wrap_message_in_chunk(message_body.slice(1 * 1024, 2 * 1024), "C");
        const chunk3 = wrap_message_in_chunk(message_body.slice(2 * 1024, 3 * 1024), "C");
        const chunk4 = wrap_message_in_chunk(message_body.slice(3 * 1024, 4 * 1024), "C");
        const chunk5 = wrap_message_in_chunk(message_body.slice(4 * 1024, 5 * 1024), "C");
        const chunk6 = wrap_message_in_chunk(message_body.slice(5 * 1024, 6 * 1024), "C");
        const chunk7 = wrap_message_in_chunk(message_body.slice(6 * 1024, 7 * 1024), "F");

        builder.feed(chunk1);
        builder.feed(chunk2);
        builder.feed(chunk3);
        builder.feed(chunk4);
        builder.feed(chunk5);
        builder.feed(chunk6);
        builder.feed(chunk7);

        onChunkSpy.callCount.should.eql(4);
        onErrorSpy.callCount.should.eql(1);
        onFullMessageBodySpy.callCount.should.eql(0);

        onErrorSpy.getCall(0).args[0].should.match(/maxMessageSize/);
        
        done();

    });
        transport.on("chunk", (messageChunk) => {
        transport.setLimits({
            maxChunkCount: 10000,
            maxMessageSize: 10000,
            receiveBufferSize: 10000,
            sendBufferSize: 10000
        });

            if (err) {
                console.log(err.message);
            }
        transport.on("chunk", (messageChunk) => {
        transport.on("chunk", (messageChunk) => {
export interface DirectTransport {
    on(eventName: "end", eventHandler:()=>void): this;
}
        this.server.on("end", (err?: Error) => {
export interface HalfComChannel {
    on(eventName: "data", eventHandler:(data: Buffer)=>void): this;
    on(eventName: "send_data", eventHandler:(data: Buffer)=>void): this;
    on(eventName: "ending", eventHandler:()=>void): this;
    on(eventName: "end", eventHandler:(err?: Error)=>void): this;

}