node-opcua-transport 2.68.0 → 2.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/source/client_tcp_transport.d.ts +8 -4
  2. package/dist/source/client_tcp_transport.js +15 -6
  3. package/dist/source/client_tcp_transport.js.map +1 -1
  4. package/dist/source/index.d.ts +5 -3
  5. package/dist/source/index.js +5 -3
  6. package/dist/source/index.js.map +1 -1
  7. package/dist/source/message_builder_base.d.ts +27 -7
  8. package/dist/source/message_builder_base.js +36 -13
  9. package/dist/source/message_builder_base.js.map +1 -1
  10. package/dist/source/server_tcp_transport.d.ts +1 -5
  11. package/dist/source/server_tcp_transport.js +41 -39
  12. package/dist/source/server_tcp_transport.js.map +1 -1
  13. package/dist/source/status_codes.d.ts +100 -0
  14. package/dist/source/status_codes.js +111 -0
  15. package/dist/source/status_codes.js.map +1 -0
  16. package/dist/source/tcp_transport.d.ts +21 -28
  17. package/dist/source/tcp_transport.js +86 -57
  18. package/dist/source/tcp_transport.js.map +1 -1
  19. package/dist/source/tools.d.ts +1 -0
  20. package/dist/source/utils.d.ts +3 -2
  21. package/dist/source/utils.js +4 -3
  22. package/dist/source/utils.js.map +1 -1
  23. package/dist/test_helpers/direct_transport.d.ts +4 -0
  24. package/dist/test_helpers/direct_transport.js.map +1 -1
  25. package/dist/test_helpers/fake_server.d.ts +2 -0
  26. package/dist/test_helpers/half_com_channel.d.ts +7 -0
  27. package/dist/test_helpers/half_com_channel.js.map +1 -1
  28. package/package.json +16 -17
  29. package/source/client_tcp_transport.ts +21 -9
  30. package/source/index.ts +5 -3
  31. package/source/message_builder_base.ts +68 -16
  32. package/source/server_tcp_transport.ts +50 -47
  33. package/source/status_codes.ts +109 -0
  34. package/source/tcp_transport.ts +118 -73
  35. package/source/utils.ts +3 -2
  36. package/test_helpers/direct_transport.ts +4 -1
  37. package/test_helpers/half_com_channel.ts +7 -0
@@ -1,6 +1,10 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { EventEmitter } from "events";
3
4
  import { HalfComChannel } from "./half_com_channel";
5
+ export interface DirectTransport {
6
+ on(eventName: "end", eventHandler: () => void): this;
7
+ }
4
8
  export declare class DirectTransport extends EventEmitter {
5
9
  client: HalfComChannel;
6
10
  server: HalfComChannel;
@@ -1 +1 @@
1
- {"version":3,"file":"direct_transport.js","sourceRoot":"","sources":["../../test_helpers/direct_transport.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AACtC,yDAA2C;AAC3C,sCAA6C;AAC7C,yDAAoD;AAEpD,MAAa,eAAgB,SAAQ,qBAAY;IAM7C;QACI,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,MAAM,GAAG,IAAI,iCAAc,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,IAAI,iCAAc,EAAE,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACjC,IAAA,0BAAM,EAAC,IAAI,YAAY,MAAM,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACjC,IAAA,0BAAM,EAAC,IAAI,YAAY,MAAM,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAU,EAAE,EAAE;YACjC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAChC,IAAI,IAAI,EAAE;gBACN,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;aAC3B;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,GAAG,mCAAmC,CAAC;IACnD,CAAC;IAEM,UAAU,CAAC,IAAgB;QAC9B,IAAA,yBAAgB,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,EAAE,CAAC;IACX,CAAC;IAEM,QAAQ,CAAC,IAAgB;QAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAClB,IAAI,IAAI,EAAE;YACN,YAAY,CAAC,IAAI,CAAC,CAAC;SACtB;IACL,CAAC;IAEM,WAAW;QACd,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;YAClB,OAAO,IAAI,CAAC;SACf;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC;IAEM,YAAY,CAAC,IAAoD;QACpE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACJ;AAnED,0CAmEC"}
1
+ {"version":3,"file":"direct_transport.js","sourceRoot":"","sources":["../../test_helpers/direct_transport.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AACtC,yDAA2C;AAC3C,sCAA6C;AAC7C,yDAAoD;AAKpD,MAAa,eAAgB,SAAQ,qBAAY;IAM7C;QACI,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,MAAM,GAAG,IAAI,iCAAc,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,IAAI,iCAAc,EAAE,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACjC,IAAA,0BAAM,EAAC,IAAI,YAAY,MAAM,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACjC,IAAA,0BAAM,EAAC,IAAI,YAAY,MAAM,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE;YAClC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAChC,IAAI,IAAI,EAAE;gBACN,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;aAC3B;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,GAAG,mCAAmC,CAAC;IACnD,CAAC;IAEM,UAAU,CAAC,IAAgB;QAC9B,IAAA,yBAAgB,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,EAAE,CAAC;IACX,CAAC;IAEM,QAAQ,CAAC,IAAgB;QAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAClB,IAAI,IAAI,EAAE;YACN,YAAY,CAAC,IAAI,CAAC,CAAC;SACtB;IACL,CAAC;IAEM,WAAW;QACd,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;YAClB,OAAO,IAAI,CAAC;SACf;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC;IAEM,YAAY,CAAC,IAAoD;QACpE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACJ;AAnED,0CAmEC"}
@@ -1,4 +1,6 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
2
4
  import { EventEmitter } from "events";
3
5
  import * as net from "net";
4
6
  export declare class FakeServer extends EventEmitter {
@@ -1,5 +1,12 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { EventEmitter } from "events";
4
+ export interface HalfComChannel {
5
+ on(eventName: "data", eventHandler: (data: Buffer) => void): this;
6
+ on(eventName: "send_data", eventHandler: (data: Buffer) => void): this;
7
+ on(eventName: "ending", eventHandler: () => void): this;
8
+ on(eventName: "end", eventHandler: (err?: Error) => void): this;
9
+ }
3
10
  export declare class HalfComChannel extends EventEmitter {
4
11
  _hasEnded: boolean;
5
12
  constructor();
@@ -1 +1 @@
1
- {"version":3,"file":"half_com_channel.js","sourceRoot":"","sources":["../../test_helpers/half_com_channel.ts"],"names":[],"mappings":";;;AAAA,yDAAyD;AACzD,mCAAsC;AACtC,yDAA2C;AAE3C,MAAa,cAAe,SAAQ,qBAAY;IAG5C;QACI,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,IAAqB;QAC9B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;YAC1B,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAC5B;QACD,IAAA,0BAAM,EAAC,IAAI,YAAY,MAAM,EAAE,yCAAyC,CAAC,CAAC;QAC1E,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAEM,GAAG;QACN,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YACjB,IAAA,0BAAM,EAAC,CAAC,IAAI,CAAC,SAAS,EAAE,gDAAgD,CAAC,CAAC;YAC1E,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SACpB;IACL,CAAC;IAEM,OAAO,KAAU,CAAC;IAElB,UAAU,KAAU,CAAC;CAC/B;AA7BD,wCA6BC"}
1
+ {"version":3,"file":"half_com_channel.js","sourceRoot":"","sources":["../../test_helpers/half_com_channel.ts"],"names":[],"mappings":";;;AAAA,yDAAyD;AACzD,mCAAsC;AACtC,yDAA2C;AAS3C,MAAa,cAAe,SAAQ,qBAAY;IAG5C;QACI,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,IAAqB;QAC9B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;YAC1B,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAC5B;QACD,IAAA,0BAAM,EAAC,IAAI,YAAY,MAAM,EAAE,yCAAyC,CAAC,CAAC;QAC1E,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAEM,GAAG;QACN,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YACjB,IAAA,0BAAM,EAAC,CAAC,IAAI,CAAC,SAAS,EAAE,gDAAgD,CAAC,CAAC;YAC1E,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SACpB;IACL,CAAC;IAEM,OAAO,KAAU,CAAC;IAElB,UAAU,KAAU,CAAC;CAC/B;AA7BD,wCA6BC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-opcua-transport",
3
- "version": "2.68.0",
3
+ "version": "2.70.0",
4
4
  "description": "pure nodejs OPCUA SDK - module -transport",
5
5
  "main": "./dist/source/index.js",
6
6
  "types": "./dist/source/index.d.ts",
@@ -14,24 +14,23 @@
14
14
  "dependencies": {
15
15
  "chalk": "4.1.2",
16
16
  "node-opcua-assert": "2.66.0",
17
- "node-opcua-basic-types": "2.68.0",
18
- "node-opcua-binary-stream": "2.67.0",
19
- "node-opcua-buffer-utils": "2.67.0",
20
- "node-opcua-chunkmanager": "2.68.0",
21
- "node-opcua-debug": "2.68.0",
22
- "node-opcua-factory": "2.68.0",
23
- "node-opcua-nodeid": "2.68.0",
24
- "node-opcua-object-registry": "2.68.0",
25
- "node-opcua-packet-assembler": "2.66.0",
26
- "node-opcua-status-code": "2.67.0",
27
- "node-opcua-types": "2.68.0",
28
- "node-opcua-utils": "2.67.0"
17
+ "node-opcua-basic-types": "2.70.0",
18
+ "node-opcua-binary-stream": "2.69.0",
19
+ "node-opcua-buffer-utils": "2.69.0",
20
+ "node-opcua-chunkmanager": "2.70.0",
21
+ "node-opcua-debug": "2.69.0",
22
+ "node-opcua-factory": "2.70.0",
23
+ "node-opcua-nodeid": "2.70.0",
24
+ "node-opcua-object-registry": "2.69.0",
25
+ "node-opcua-packet-assembler": "2.69.0",
26
+ "node-opcua-status-code": "2.70.0",
27
+ "node-opcua-types": "2.70.0",
28
+ "node-opcua-utils": "2.69.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@types/node": "17.0.23",
32
- "node-opcua-debug": "2.66.0",
31
+ "@types/node": "17.0.36",
33
32
  "should": "^13.2.3",
34
- "sinon": "^13.0.1"
33
+ "sinon": "^14.0.0"
35
34
  },
36
35
  "author": "Etienne Rossignon",
37
36
  "license": "MIT",
@@ -48,5 +47,5 @@
48
47
  "internet of things"
49
48
  ],
50
49
  "homepage": "http://node-opcua.github.io/",
51
- "gitHead": "363b466440d0910acddd0cde2c37792ce4724d76"
50
+ "gitHead": "3b692ffb3e2ef0542da32f349fb0c76b3acc75ce"
52
51
  }
@@ -56,12 +56,12 @@ function createClientSocket(endpointUrl: string): Socket {
56
56
  }
57
57
  }
58
58
  export interface ClientTCP_transport {
59
- on(eventName: "message", eventHandler: (message: Buffer) => void): this;
59
+ on(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
60
60
  on(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
61
61
  on(eventName: "close", eventHandler: (err: Error | null) => void): this;
62
62
  on(eventName: "connection_break", eventHandler: () => void): this;
63
63
 
64
- once(eventName: "message", eventHandler: (message: Buffer) => void): this;
64
+ once(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
65
65
  once(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
66
66
  once(eventName: "close", eventHandler: (err: Error | null) => void): this;
67
67
  once(eventName: "connection_break", eventHandler: () => void): this;
@@ -96,8 +96,8 @@ export interface ClientTCP_transport {
96
96
  *
97
97
  * ....
98
98
  *
99
- * transport.on("message",function(message_chunk) {
100
- * // do something with message from server...
99
+ * transport.on("chunk",function(message_chunk) {
100
+ * // do something with chunk from server...
101
101
  * });
102
102
  *
103
103
  *
@@ -106,6 +106,11 @@ export interface ClientTCP_transport {
106
106
  *
107
107
  */
108
108
  export class ClientTCP_transport extends TCP_transport {
109
+ public static defaultMaxChunk = 0; // 0 - no limits
110
+ public static defaultMaxMessageSize = 0; // 0 - no limits
111
+ public static defaultReceiveBufferSize = 1024 * 64 * 10;
112
+ public static defaultSendBufferSize = 1024 * 64 * 10; // 8192 min,
113
+
109
114
  public endpointUrl: string;
110
115
  public serverUri: string;
111
116
  public numberOfRetry: number;
@@ -121,6 +126,11 @@ export class ClientTCP_transport extends TCP_transport {
121
126
  this.serverUri = "";
122
127
  this._counter = 0;
123
128
  this.numberOfRetry = 0;
129
+
130
+ // initially before HEL/ACK
131
+ this.maxChunkCount = 1;
132
+ this.maxMessageSize = 4 * 1024;
133
+ this.receiveBufferSize = 4 * 1024;
124
134
  }
125
135
 
126
136
  public dispose(): void {
@@ -238,6 +248,7 @@ export class ClientTCP_transport extends TCP_transport {
238
248
  this._socket.once("error", _on_socket_error_for_connect);
239
249
  this._socket.once("end", _on_socket_end_for_connect);
240
250
  this._socket.once("connect", _on_socket_connect);
251
+
241
252
  this._install_socket(this._socket);
242
253
  }
243
254
 
@@ -280,7 +291,9 @@ export class ClientTCP_transport extends TCP_transport {
280
291
  responseClass = AcknowledgeMessage;
281
292
  _stream.rewind();
282
293
  response = decodeMessage(_stream, responseClass);
294
+
283
295
  this.parameters = response as AcknowledgeMessage;
296
+ this.setLimits(response as AcknowledgeMessage);
284
297
 
285
298
  // istanbul ignore next
286
299
  if (doTraceHelloAck) {
@@ -304,12 +317,11 @@ export class ClientTCP_transport extends TCP_transport {
304
317
  // the server will receive it as message from the client
305
318
  const helloMessage = new HelloMessage({
306
319
  endpointUrl: this.endpointUrl,
307
- maxChunkCount: 0, // 0 - no limits
308
- maxMessageSize: 0, // 0 - no limits
309
-
310
320
  protocolVersion: this.protocolVersion,
311
- receiveBufferSize: 1024 * 64 * 10,
312
- sendBufferSize: 1024 * 64 * 10 // 8192 min,
321
+ maxChunkCount: ClientTCP_transport.defaultMaxChunk,
322
+ maxMessageSize: ClientTCP_transport.defaultMaxMessageSize,
323
+ receiveBufferSize: ClientTCP_transport.defaultReceiveBufferSize,
324
+ sendBufferSize: ClientTCP_transport.defaultSendBufferSize
313
325
  });
314
326
  // istanbul ignore next
315
327
  if (doTraceHelloAck) {
package/source/index.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * @module node-opcua-transport
3
3
  */
4
- export * from "./HelloMessage";
5
4
  export * from "./AcknowledgeMessage";
6
- export * from "./TCPErrorMessage";
7
5
  export * from "./client_tcp_transport";
6
+ export * from "./HelloMessage";
7
+ export * from "./message_builder_base";
8
8
  export * from "./server_tcp_transport";
9
+ export * from "./status_codes";
9
10
  export * from "./tcp_transport";
11
+ export * from "./TCPErrorMessage";
10
12
  export * from "./tools";
11
- export * from "./message_builder_base";
13
+ export * from "./utils";
@@ -7,14 +7,17 @@ import { assert } from "node-opcua-assert";
7
7
  import { BinaryStream } from "node-opcua-binary-stream";
8
8
  import { createFastUninitializedBuffer } from "node-opcua-buffer-utils";
9
9
  import { readMessageHeader, SequenceHeader } from "node-opcua-chunkmanager";
10
- import { make_errorLog, make_debugLog } from "node-opcua-debug";
10
+ import { make_errorLog, make_debugLog, make_warningLog } from "node-opcua-debug";
11
11
  import { MessageHeader, PacketAssembler, PacketInfo } from "node-opcua-packet-assembler";
12
+ import { StatusCode } from "node-opcua-status-code";
12
13
  import { get_clock_tick } from "node-opcua-utils";
14
+ import { StatusCodes2 } from "./status_codes";
13
15
 
14
16
  const doPerfMonitoring = process.env.NODEOPCUADEBUG && process.env.NODEOPCUADEBUG.indexOf("PERF") >= 0;
15
17
 
16
18
  const errorLog = make_errorLog("MessageBuilder");
17
19
  const debugLog = make_debugLog("MessageBuilder");
20
+ const warningLog = make_warningLog("MessageBuilder");
18
21
 
19
22
  export function readRawMessageHeader(data: Buffer): PacketInfo {
20
23
  const messageHeader = readMessageHeader(new BinaryStream(data));
@@ -25,6 +28,24 @@ export function readRawMessageHeader(data: Buffer): PacketInfo {
25
28
  };
26
29
  }
27
30
 
31
+ export interface MessageBuilderBaseOptions {
32
+ signatureLength?: number;
33
+ maxMessageSize?: number;
34
+ maxChunkCount?: number;
35
+ maxChunkSize?: number;
36
+ }
37
+
38
+ export interface MessageBuilderBase {
39
+ on(eventName: "startChunk", eventHandler: (info: PacketInfo, data: Buffer) => void): this;
40
+ on(eventName: "chunk", eventHandler: (chunk: Buffer) => void): this;
41
+ on(eventName: "error", eventHandler: (err: Error, statusCode: StatusCode, requestId: number | null) => void): this;
42
+ on(eventName: "full_message_body", eventHandler: (fullMessageBody: Buffer) => void): this;
43
+
44
+ emit(eventName: "startChunk", info: PacketInfo, data: Buffer): boolean;
45
+ emit(eventName: "chunk", chunk: Buffer): boolean;
46
+ emit(eventName: "error", err: Error, statusCode: StatusCode, requestId: number | null): boolean;
47
+ emit(eventName: "full_message_body", fullMessageBody: Buffer): boolean;
48
+ }
28
49
  /**
29
50
  * @class MessageBuilderBase
30
51
  * @extends EventEmitter
@@ -35,8 +56,16 @@ export function readRawMessageHeader(data: Buffer): PacketInfo {
35
56
  *
36
57
  */
37
58
  export class MessageBuilderBase extends EventEmitter {
38
- public readonly signatureLength: number;
39
- public readonly options: { signatureLength?: number };
59
+ public static defaultMaxChunkCount = 1000;
60
+ public static defaultMaxMessageSize = 1024 * 64;
61
+ public static defaultMaxChunkSize = 1024 * 8;
62
+
63
+ public readonly signatureLength: number;
64
+ public readonly maxMessageSize: number;
65
+ public readonly maxChunkCount: number;
66
+ public readonly maxChunkSize: number;
67
+
68
+ public readonly options: MessageBuilderBaseOptions;
40
69
  public readonly _packetAssembler: PacketAssembler;
41
70
  public channelId: number;
42
71
  public totalMessageSize: number;
@@ -57,7 +86,7 @@ export class MessageBuilderBase extends EventEmitter {
57
86
  private readonly _expectedChannelId: number;
58
87
  private offsetBodyStart: number;
59
88
 
60
- constructor(options?: { signatureLength?: number }) {
89
+ constructor(options?: MessageBuilderBaseOptions) {
61
90
  super();
62
91
 
63
92
  this.id = "";
@@ -69,20 +98,29 @@ export class MessageBuilderBase extends EventEmitter {
69
98
  this.messageChunks = [];
70
99
  this._expectedChannelId = 0;
71
100
 
72
- options = options || {};
101
+ options = options || {
102
+ maxMessageSize: 0,
103
+ maxChunkCount: 0,
104
+ maxChunkSize: 0
105
+ };
73
106
 
74
107
  this.signatureLength = options.signatureLength || 0;
75
108
 
109
+ this.maxMessageSize = options.maxMessageSize || MessageBuilderBase.defaultMaxMessageSize;
110
+ this.maxChunkCount = options.maxChunkCount || MessageBuilderBase.defaultMaxChunkCount;
111
+ this.maxChunkSize = options.maxChunkSize || MessageBuilderBase.defaultMaxChunkSize;
112
+
76
113
  this.options = options;
77
114
 
78
115
  this._packetAssembler = new PacketAssembler({
79
- minimumSizeInBytes: 0,
80
- readMessageFunc: readRawMessageHeader
116
+ minimumSizeInBytes: 8,
117
+ maxChunkSize: this.maxChunkSize,
118
+ readChunkFunc: readRawMessageHeader
81
119
  });
82
120
 
83
- this._packetAssembler.on("message", (messageChunk) => this._feed_messageChunk(messageChunk));
121
+ this._packetAssembler.on("chunk", (messageChunk) => this._feed_messageChunk(messageChunk));
84
122
 
85
- this._packetAssembler.on("newMessage", (info, data) => {
123
+ this._packetAssembler.on("startChunk", (info, data) => {
86
124
  if (doPerfMonitoring) {
87
125
  // record tick 0: when the first data is received
88
126
  this._tick0 = get_clock_tick();
@@ -94,7 +132,12 @@ export class MessageBuilderBase extends EventEmitter {
94
132
  * @param info
95
133
  * @param data
96
134
  */
97
- this.emit("start_chunk", info, data);
135
+ this.emit("startChunk", info, data);
136
+ });
137
+
138
+ this._packetAssembler.on("error", (err) => {
139
+ warningLog("packet assembler ", err.message);
140
+ return this._report_error(StatusCodes2.BadTcpMessageTooLarge, "packet assembler: " + err.message);
98
141
  });
99
142
 
100
143
  this._securityDefeated = false;
@@ -135,15 +178,15 @@ export class MessageBuilderBase extends EventEmitter {
135
178
 
136
179
  // verifying secure ChannelId
137
180
  if (this._expectedChannelId && this.channelId !== this._expectedChannelId) {
138
- return this._report_error("Invalid secure channel Id");
181
+ return this._report_error(StatusCodes2.BadTcpSecureChannelUnknown, "Invalid secure channel Id");
139
182
  }
140
183
  return true;
141
184
  } catch (err) {
142
- return false;
185
+ return this._report_error(StatusCodes2.BadTcpInternalError, "_read_headers error " + (err as Error).message);
143
186
  }
144
187
  }
145
188
 
146
- protected _report_error(errorMessage: string): false {
189
+ protected _report_error(statusCode: StatusCode, errorMessage: string): false {
147
190
  this._hasReceivedError = true;
148
191
  /**
149
192
  * notify the observers that an error has occurred
@@ -152,7 +195,7 @@ export class MessageBuilderBase extends EventEmitter {
152
195
  */
153
196
  debugLog("Error ", this.id, errorMessage);
154
197
  // xx errorLog(new Error());
155
- this.emit("error", new Error(errorMessage), this.sequenceHeader ? this.sequenceHeader.requestId : null);
198
+ this.emit("error", new Error(errorMessage), statusCode, this.sequenceHeader ? this.sequenceHeader.requestId : null);
156
199
  return false;
157
200
  }
158
201
 
@@ -177,13 +220,21 @@ export class MessageBuilderBase extends EventEmitter {
177
220
  return false;
178
221
  }
179
222
 
223
+ if (this.messageChunks.length + 1 > this.maxChunkCount) {
224
+ return this._report_error(StatusCodes2.BadTcpMessageTooLarge, `max chunk count exceeded: ${this.maxChunkCount}`);
225
+ }
226
+
180
227
  this.messageChunks.push(chunk);
181
228
  this.totalMessageSize += chunk.length;
182
229
 
230
+ if (this.totalMessageSize > this.maxMessageSize) {
231
+ return this._report_error(StatusCodes2.BadTcpMessageTooLarge, `max message size exceeded: ${this.maxMessageSize}`);
232
+ }
233
+
183
234
  const binaryStream = new BinaryStream(chunk);
184
235
 
185
236
  if (!this._read_headers(binaryStream)) {
186
- return this._report_error(`Invalid message header detected`);
237
+ return this._report_error(StatusCodes2.BadTcpInternalError, `Invalid message header detected`);
187
238
  }
188
239
 
189
240
  assert(binaryStream.length >= 12);
@@ -192,6 +243,7 @@ export class MessageBuilderBase extends EventEmitter {
192
243
  if (this.messageHeader!.length !== chunk.length) {
193
244
  // tslint:disable:max-line-length
194
245
  return this._report_error(
246
+ StatusCodes2.BadTcpInternalError,
195
247
  `Invalid messageChunk size: the provided chunk is ${chunk.length} bytes long but header specifies ${
196
248
  this.messageHeader!.length
197
249
  }`
@@ -254,7 +306,7 @@ export class MessageBuilderBase extends EventEmitter {
254
306
  this._init_new();
255
307
  return true;
256
308
  } else if (messageHeader.isFinal === "A") {
257
- return this._report_error("received and Abort Message");
309
+ return this._report_error(StatusCodes2.BadRequestInterrupted, "received and Abort Message");
258
310
  } else if (messageHeader.isFinal === "C") {
259
311
  return this._append(chunk);
260
312
  }
@@ -55,12 +55,6 @@ const minimumBufferSize = 8192;
55
55
  export class ServerTCP_transport extends TCP_transport {
56
56
  public static throttleTime = 1000;
57
57
 
58
- public receiveBufferSize: number;
59
- public sendBufferSize: number;
60
- public maxMessageSize: number;
61
- public maxChunkCount: number;
62
- public protocolVersion: number;
63
-
64
58
  private _aborted: number;
65
59
  private _helloReceived: boolean;
66
60
 
@@ -68,14 +62,16 @@ export class ServerTCP_transport extends TCP_transport {
68
62
  super();
69
63
  this._aborted = 0;
70
64
  this._helloReceived = false;
71
- this.receiveBufferSize = 0;
72
- this.sendBufferSize = 0;
73
- this.maxMessageSize = 0;
74
- this.maxChunkCount = 0;
75
- this.protocolVersion = 0;
65
+
66
+ // before HEL/ACK
67
+ this.maxChunkCount = 1;
68
+ this.maxMessageSize = 4 * 1024;
69
+ this.receiveBufferSize = 4 * 1024;
76
70
  }
77
71
 
78
72
  protected _write_chunk(messageChunk: Buffer): void {
73
+
74
+ // istanbul ignore next
79
75
  if (this.sendBufferSize > 0 && messageChunk.length > this.sendBufferSize) {
80
76
  errorLog(
81
77
  "write chunk exceed sendBufferSize messageChunk length = ",
@@ -84,6 +80,7 @@ export class ServerTCP_transport extends TCP_transport {
84
80
  this.sendBufferSize
85
81
  );
86
82
  }
83
+
87
84
  super._write_chunk(messageChunk);
88
85
  }
89
86
  /**
@@ -115,57 +112,63 @@ export class ServerTCP_transport extends TCP_transport {
115
112
  public abortWithError(statusCode: StatusCode, extraErrorDescription: string, callback: ErrorCallback): void {
116
113
  return this._abortWithError(statusCode, extraErrorDescription, callback);
117
114
  }
115
+
118
116
  private _abortWithError(statusCode: StatusCode, extraErrorDescription: string, callback: ErrorCallback): void {
119
- if (debugLog) {
120
- debugLog(chalk.cyan("_abortWithError"));
117
+ // When a fatal error occurs, the Server shall send an Error Message to the Client and
118
+ // closes the TransportConnection gracefully.
119
+ doDebug && debugLog(chalk.cyan("_abortWithError"));
120
+
121
+ /* istanbul ignore next */
122
+ if (this._aborted) {
123
+ // already called
124
+ return callback(new Error(statusCode.name));
121
125
  }
126
+ this._aborted = 1;
122
127
 
123
- assert(typeof callback === "function", "expecting a callback");
128
+ setTimeout(() => {
129
+ // send the error message and close the connection
130
+ this.sendErrorMessage(statusCode, statusCode.description);
124
131
 
125
- /* istanbul ignore else */
126
- if (!this._aborted) {
127
- this._aborted = 1;
128
- setTimeout(() => {
129
- // send the error message and close the connection
130
- assert(Object.prototype.hasOwnProperty.call(StatusCodes, statusCode.name));
132
+ this.disconnect(() => {
133
+ this._aborted = 2;
134
+ callback(new Error(extraErrorDescription + " StatusCode = " + statusCode.name));
135
+ });
136
+ }, ServerTCP_transport.throttleTime);
137
+ }
131
138
 
132
- /* istanbul ignore next*/
133
- if (doDebug) {
134
- debugLog(chalk.red(" Server aborting because ") + chalk.cyan(statusCode.name));
135
- debugLog(chalk.red(" extraErrorDescription ") + chalk.cyan(extraErrorDescription));
136
- }
139
+ private _send_ACK_response(helloMessage: HelloMessage): void {
140
+ assert(helloMessage.receiveBufferSize >= minimumBufferSize);
141
+ assert(helloMessage.sendBufferSize >= minimumBufferSize);
137
142
 
138
- const errorResponse = new TCPErrorMessage({
139
- reason: statusCode.description,
140
- statusCode
141
- });
143
+ const minBufferSize = 8192;
144
+ const maxBufferSize = 64 * 1024;
142
145
 
143
- const messageChunk = packTcpMessage("ERR", errorResponse);
146
+ const minMaxMessageSize = 128 * 1024;
147
+ const defaultMaxMessageSize = 16 * 1024 * 1024;
148
+ const maxMaxMessageSize = 128 * 1024 * 1024;
144
149
 
145
- this.write(messageChunk);
150
+ const minMaxChunkCount = 1;
151
+ const defaultMaxChunkCount = defaultMaxMessageSize / maxBufferSize;
152
+ const maxMaxChunkCount = 9000;
146
153
 
147
- this.disconnect(() => {
148
- this._aborted = 2;
149
- callback(new Error(extraErrorDescription + " StatusCode = " + statusCode.name));
150
- });
151
- }, ServerTCP_transport.throttleTime);
152
- } else {
153
- callback(new Error(statusCode.name));
154
- }
155
- }
154
+ const receiveBufferSize = 32 * 1024;
155
+ const sendBufferSize = 32 * 1024;
156
156
 
157
- private _send_ACK_response(helloMessage: HelloMessage): void {
158
- assert(helloMessage.receiveBufferSize >= minimumBufferSize);
159
- assert(helloMessage.sendBufferSize >= minimumBufferSize);
157
+ if (!helloMessage.maxChunkCount && helloMessage.sendBufferSize) {
158
+ helloMessage.maxChunkCount = helloMessage.maxMessageSize / helloMessage.sendBufferSize;
159
+ }
160
160
 
161
- this.receiveBufferSize = clamp_value(helloMessage.receiveBufferSize, 8192, 512 * 1024);
162
- this.sendBufferSize = clamp_value(helloMessage.sendBufferSize, 8192, 512 * 1024);
163
- this.maxMessageSize = clamp_value(helloMessage.maxMessageSize, 100000, 64 * 1024 * 1024);
164
- this.maxChunkCount = clamp_value(helloMessage.maxChunkCount, 0, 65535);
161
+ this.setLimits({
162
+ receiveBufferSize: clamp_value(helloMessage.receiveBufferSize || receiveBufferSize, minBufferSize, maxBufferSize),
163
+ sendBufferSize: clamp_value(helloMessage.sendBufferSize || sendBufferSize, minBufferSize, maxBufferSize),
164
+ maxMessageSize: clamp_value(helloMessage.maxMessageSize || defaultMaxMessageSize, minMaxMessageSize, maxMaxMessageSize),
165
+ maxChunkCount: clamp_value(helloMessage.maxChunkCount || defaultMaxChunkCount, minMaxChunkCount, maxMaxChunkCount)
166
+ });
165
167
 
166
168
  // istanbul ignore next
167
169
  if (doTraceHelloAck) {
168
170
  console.log(`received Hello \n${helloMessage.toString()}`);
171
+ console.log("Client accepts only message of size => ", this.maxMessageSize);
169
172
  }
170
173
 
171
174
  debugLog("Client accepts only message of size => ", this.maxMessageSize);
@@ -0,0 +1,109 @@
1
+ import { StatusCodes } from "node-opcua-status-code";
2
+
3
+ export const StatusCodes2 = {
4
+ /**
5
+ * The Server cannot process the request because it is too busy.
6
+ *
7
+ * It is up to the Server to determine when it needs to return this Message.
8
+ *
9
+ * A Server can control the how frequently a Client reconnects by waiting to return this error.
10
+ */
11
+ BadTcpServerTooBusy: StatusCodes.BadTcpServerTooBusy,
12
+ /**
13
+ * The type of the Message specified in the header invalid.
14
+ * Each Message starts with a 4-byte sequence of ASCII values that identifies the Message type.
15
+ * The Server returns this error if the Message type is not accepted.
16
+ * Some of the Message types are defined by the SecureChannel layer.
17
+ */
18
+ BadTcpMessageTypeInvalid: StatusCodes.BadTcpMessageTypeInvalid,
19
+ /**
20
+ * The SecureChannelId and/or TokenId are not currently in use.
21
+ * This error is reported by the SecureChannel layer.
22
+ */
23
+ BadTcpSecureChannelUnknown: StatusCodes.BadTcpSecureChannelUnknown,
24
+ /**
25
+ * The size of the Message specified in the header is too large.
26
+ * The Server returns this error if the Message size exceeds its maximum buffer size
27
+ * or the receive buffer size negotiated during the Hello/Acknowledge exchange.
28
+ */
29
+ BadTcpMessageTooLarge: StatusCodes.BadTcpMessageTooLarge,
30
+
31
+ /**
32
+ * A timeout occurred while accessing a resource.
33
+ * It is up to the Server to determine when a timeout occurs.
34
+ */
35
+ BadTimeout: StatusCodes.BadTimeout,
36
+ /**
37
+ * There are not enough resources to process the request.
38
+ * The Server returns this error when it runs out of memory or encounters similar resource problems.
39
+ * A Server can control the how frequently a Client reconnects by waiting to return this error.
40
+ */
41
+ BadTcpNotEnoughResources: StatusCodes.BadTcpNotEnoughResources,
42
+ /**
43
+ * An internal error occurred.
44
+ * This should only be returned if an unexpected configuration or programming error occurs.
45
+ */
46
+ BadTcpInternalError: StatusCodes.BadTcpInternalError,
47
+ /**
48
+ * The Server does not recognize the EndpointUrl specified.
49
+ */
50
+ BadTcpEndpointUrlInvalid: StatusCodes.BadTcpEndpointUrlInvalid,
51
+ /**
52
+ * The Message was rejected because it could not be verified.
53
+ */
54
+ BadSecurityChecksFailed: StatusCodes.BadSecurityChecksFailed,
55
+ /**
56
+ * The request could not be sent because of a network interruption.
57
+ */
58
+ BadRequestInterrupted: StatusCodes.BadRequestInterrupted,
59
+ /**
60
+ * Timeout occurred while processing the request.
61
+ */
62
+ BadRequestTimeout: StatusCodes.BadRequestTimeout,
63
+ /**
64
+ * The secure channel has been closed.
65
+ */
66
+ BadSecureChannelClosed: StatusCodes.BadSecureChannelClosed,
67
+ /**
68
+ * The SecurityToken has expired or is not recognized. BadSecureChannelTokenUnknown
69
+ */
70
+ BadSecureChannelTokenUnknown: StatusCodes.BadSecureChannelTokenUnknown,
71
+ /**
72
+ * The sender Certificate is not trusted by the receiver.
73
+ */
74
+ BadCertificateUntrusted: StatusCodes.BadCertificateUntrusted,
75
+ /**
76
+ * The sender Certificate has expired or is not yet valid.
77
+ */
78
+ BadCertificateTimeInvalid: StatusCodes.BadCertificateTimeInvalid,
79
+ /**
80
+ * The issuer for the sender Certificate has expired or is not yet valid.
81
+ */
82
+ BadCertificateIssuerTimeInvalid: StatusCodes.BadCertificateIssuerTimeInvalid,
83
+ /**
84
+ * The sender’s Certificate may not be used for establishing a secure channel.
85
+ */
86
+ BadCertificateUseNotAllowed: StatusCodes.BadCertificateUseNotAllowed,
87
+ /**
88
+ * The issuer Certificate may not be used as a Certificate Authority.
89
+ */
90
+ BadCertificateIssuerUseNotAllowed: StatusCodes.BadCertificateIssuerUseNotAllowed,
91
+ /**
92
+ * Could not verify the revocation status of the sender’s Certificate.
93
+ */
94
+ BadCertificateRevocationUnknown: StatusCodes.BadCertificateRevocationUnknown,
95
+ /**
96
+ * Could not verify the revocation status of the issuer Certificate.
97
+ */
98
+ BadCertificateIssuerRevocationUnknown: StatusCodes.BadCertificateIssuerRevocationUnknown,
99
+ /**
100
+ * The sender Certificate has been revoked by the issuer.
101
+ */
102
+ BadCertificateRevoked: StatusCodes.BadCertificateRevoked
103
+ /**The issuer Certificate has been revoked by its issuer.
104
+ */
105
+ // todo BadIssuerCertificateRevoked: StatusCodes.BadIssuerCertificateRevoked,
106
+ /** The receiver Certificate thumbprint is not recognized by the receiver.
107
+ */
108
+ // todo .. BadCertificateUnknown: StatusCodes.BadCertificateUnknown
109
+ };