node-opcua-transport 2.97.0 → 2.98.1

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 (50) hide show
  1. package/dist/source/AcknowledgeMessage.d.ts +27 -27
  2. package/dist/source/AcknowledgeMessage.js +78 -78
  3. package/dist/source/AcknowledgeMessage.js.map +1 -1
  4. package/dist/source/HelloMessage.d.ts +27 -27
  5. package/dist/source/HelloMessage.js +94 -94
  6. package/dist/source/HelloMessage.js.map +1 -1
  7. package/dist/source/TCPErrorMessage.d.ts +18 -18
  8. package/dist/source/TCPErrorMessage.js +46 -46
  9. package/dist/source/TCPErrorMessage.js.map +1 -1
  10. package/dist/source/client_tcp_transport.d.ts +87 -87
  11. package/dist/source/client_tcp_transport.js +334 -334
  12. package/dist/source/client_tcp_transport.js.map +1 -1
  13. package/dist/source/index.d.ts +13 -13
  14. package/dist/source/index.js +29 -29
  15. package/dist/source/message_builder_base.d.ts +112 -112
  16. package/dist/source/message_builder_base.js +244 -244
  17. package/dist/source/message_builder_base.js.map +1 -1
  18. package/dist/source/server_tcp_transport.d.ts +44 -44
  19. package/dist/source/server_tcp_transport.js +232 -232
  20. package/dist/source/server_tcp_transport.js.map +1 -1
  21. package/dist/source/status_codes.d.ts +100 -100
  22. package/dist/source/status_codes.js +110 -110
  23. package/dist/source/tcp_transport.d.ts +136 -136
  24. package/dist/source/tcp_transport.js +378 -378
  25. package/dist/source/tcp_transport.js.map +1 -1
  26. package/dist/source/tools.d.ts +14 -14
  27. package/dist/source/tools.js +103 -103
  28. package/dist/source/utils.d.ts +3 -3
  29. package/dist/source/utils.js +9 -9
  30. package/dist/test-fixtures/fixture_full_tcp_packets.d.ts +21 -21
  31. package/dist/test-fixtures/fixture_full_tcp_packets.js +41 -41
  32. package/dist/test-fixtures/index.d.ts +1 -1
  33. package/dist/test-fixtures/index.js +17 -17
  34. package/dist/test_helpers/direct_transport.d.ts +18 -18
  35. package/dist/test_helpers/direct_transport.js +62 -62
  36. package/dist/test_helpers/fake_server.d.ts +19 -19
  37. package/dist/test_helpers/fake_server.js +54 -54
  38. package/dist/test_helpers/half_com_channel.d.ts +17 -17
  39. package/dist/test_helpers/half_com_channel.js +31 -31
  40. package/dist/test_helpers/index.d.ts +4 -4
  41. package/dist/test_helpers/index.js +20 -20
  42. package/dist/test_helpers/socket_transport.d.ts +10 -10
  43. package/dist/test_helpers/socket_transport.js +30 -30
  44. package/dist/tsconfig.tsbuildinfo +1 -0
  45. package/package.json +19 -15
  46. package/test_helpers/direct_transport.ts +0 -76
  47. package/test_helpers/fake_server.ts +0 -67
  48. package/test_helpers/half_com_channel.ts +0 -41
  49. package/test_helpers/index.ts +0 -4
  50. package/test_helpers/socket_transport.ts +0 -33
@@ -1,380 +1,380 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TCP_transport = exports.getFakeTransport = exports.setFakeTransport = void 0;
4
- /**
5
- * @module node-opcua-transport
6
- */
7
- const events_1 = require("events");
8
- const chalk = require("chalk");
9
- const node_opcua_assert_1 = require("node-opcua-assert");
10
- const node_opcua_debug_1 = require("node-opcua-debug");
11
- const node_opcua_object_registry_1 = require("node-opcua-object-registry");
12
- const node_opcua_packet_assembler_1 = require("node-opcua-packet-assembler");
13
- const status_codes_1 = require("./status_codes");
14
- const message_builder_base_1 = require("./message_builder_base");
15
- const utils_1 = require("./utils");
16
- const TCPErrorMessage_1 = require("./TCPErrorMessage");
17
- const tools_1 = require("./tools");
18
- const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
19
- const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
20
- const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
21
- const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
22
- let fakeSocket = {
23
- invalid: true,
24
- destroy() {
25
- errorLog("MockSocket.destroy");
26
- },
27
- end() {
28
- errorLog("MockSocket.end");
29
- }
30
- };
31
- function setFakeTransport(mockSocket) {
32
- fakeSocket = mockSocket;
33
- }
34
- exports.setFakeTransport = setFakeTransport;
35
- function getFakeTransport() {
36
- if (fakeSocket.invalid) {
37
- throw new Error("getFakeTransport: setFakeTransport must be called first - BadProtocolVersionUnsupported");
38
- }
39
- return fakeSocket;
40
- }
41
- exports.getFakeTransport = getFakeTransport;
42
- let counter = 0;
43
- // tslint:disable:class-name
44
- class TCP_transport extends events_1.EventEmitter {
45
- constructor() {
46
- super();
47
- this.name = this.constructor.name + counter;
48
- counter += 1;
49
- this._timerId = null;
50
- this._timeout = 30000; // 30 seconds timeout
51
- this._socket = null;
52
- this.headerSize = 8;
53
- this.maxMessageSize = 0;
54
- this.maxChunkCount = 0;
55
- this.receiveBufferSize = 0;
56
- this.sendBufferSize = 0;
57
- this.protocolVersion = 0;
58
- this._disconnecting = false;
59
- this.bytesWritten = 0;
60
- this.bytesRead = 0;
61
- this._theCallback = undefined;
62
- this.chunkWrittenCount = 0;
63
- this.chunkReadCount = 0;
64
- this._onSocketClosedHasBeenCalled = false;
65
- this._onSocketEndedHasBeenCalled = false;
66
- TCP_transport.registry.register(this);
67
- }
68
- setLimits({ receiveBufferSize, sendBufferSize, maxMessageSize, maxChunkCount }) {
69
- this.receiveBufferSize = receiveBufferSize;
70
- this.sendBufferSize = sendBufferSize;
71
- this.maxMessageSize = maxMessageSize;
72
- this.maxChunkCount = maxChunkCount;
73
- if (maxMessageSize / sendBufferSize > maxChunkCount || maxMessageSize / receiveBufferSize > maxChunkCount) {
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TCP_transport = exports.getFakeTransport = exports.setFakeTransport = void 0;
4
+ /**
5
+ * @module node-opcua-transport
6
+ */
7
+ const events_1 = require("events");
8
+ const chalk = require("chalk");
9
+ const node_opcua_assert_1 = require("node-opcua-assert");
10
+ const node_opcua_debug_1 = require("node-opcua-debug");
11
+ const node_opcua_object_registry_1 = require("node-opcua-object-registry");
12
+ const node_opcua_packet_assembler_1 = require("node-opcua-packet-assembler");
13
+ const status_codes_1 = require("./status_codes");
14
+ const message_builder_base_1 = require("./message_builder_base");
15
+ const utils_1 = require("./utils");
16
+ const TCPErrorMessage_1 = require("./TCPErrorMessage");
17
+ const tools_1 = require("./tools");
18
+ const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
19
+ const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
20
+ const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
21
+ const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
22
+ let fakeSocket = {
23
+ invalid: true,
24
+ destroy() {
25
+ errorLog("MockSocket.destroy");
26
+ },
27
+ end() {
28
+ errorLog("MockSocket.end");
29
+ }
30
+ };
31
+ function setFakeTransport(mockSocket) {
32
+ fakeSocket = mockSocket;
33
+ }
34
+ exports.setFakeTransport = setFakeTransport;
35
+ function getFakeTransport() {
36
+ if (fakeSocket.invalid) {
37
+ throw new Error("getFakeTransport: setFakeTransport must be called first - BadProtocolVersionUnsupported");
38
+ }
39
+ return fakeSocket;
40
+ }
41
+ exports.getFakeTransport = getFakeTransport;
42
+ let counter = 0;
43
+ // tslint:disable:class-name
44
+ class TCP_transport extends events_1.EventEmitter {
45
+ constructor() {
46
+ super();
47
+ this.name = this.constructor.name + counter;
48
+ counter += 1;
49
+ this._timerId = null;
50
+ this._timeout = 30000; // 30 seconds timeout
51
+ this._socket = null;
52
+ this.headerSize = 8;
53
+ this.maxMessageSize = 0;
54
+ this.maxChunkCount = 0;
55
+ this.receiveBufferSize = 0;
56
+ this.sendBufferSize = 0;
57
+ this.protocolVersion = 0;
58
+ this._disconnecting = false;
59
+ this.bytesWritten = 0;
60
+ this.bytesRead = 0;
61
+ this._theCallback = undefined;
62
+ this.chunkWrittenCount = 0;
63
+ this.chunkReadCount = 0;
64
+ this._onSocketClosedHasBeenCalled = false;
65
+ this._onSocketEndedHasBeenCalled = false;
66
+ TCP_transport.registry.register(this);
67
+ }
68
+ setLimits({ receiveBufferSize, sendBufferSize, maxMessageSize, maxChunkCount }) {
69
+ this.receiveBufferSize = receiveBufferSize;
70
+ this.sendBufferSize = sendBufferSize;
71
+ this.maxMessageSize = maxMessageSize;
72
+ this.maxChunkCount = maxChunkCount;
73
+ if (maxMessageSize / sendBufferSize > maxChunkCount || maxMessageSize / receiveBufferSize > maxChunkCount) {
74
74
  warningLog(`Warning : maxMessageSize / sendBufferSize ${maxMessageSize / sendBufferSize}> maxChunkCount ${maxChunkCount}
75
- || maxMessageSize / receiveBufferSize ${maxMessageSize / receiveBufferSize} < maxChunkCount `);
76
- }
77
- // reinstall packetAssembler with correct limits
78
- this._install_packetAssembler();
79
- }
80
- get timeout() {
81
- return this._timeout;
82
- }
83
- set timeout(value) {
84
- debugLog("Setting socket " + this.name + " timeout = ", value);
85
- this._timeout = value;
86
- }
87
- dispose() {
88
- this._cleanup_timers();
89
- (0, node_opcua_assert_1.assert)(!this._timerId);
90
- if (this._socket) {
91
- this._socket.destroy();
92
- this._socket.removeAllListeners();
93
- this._socket = null;
94
- }
95
- TCP_transport.registry.unregister(this);
96
- }
97
- /**
98
- * write the message_chunk on the socket.
99
- * @method write
100
- * @param messageChunk
101
- */
102
- write(messageChunk, callback) {
103
- const header = (0, message_builder_base_1.readRawMessageHeader)(messageChunk);
104
- (0, node_opcua_assert_1.assert)(header.length === messageChunk.length);
105
- const c = header.messageHeader.isFinal;
106
- (0, node_opcua_assert_1.assert)(c === "F" || c === "C" || c === "A");
107
- this._write_chunk(messageChunk, (err) => {
108
- callback && callback(err);
109
- });
110
- }
111
- get isDisconnecting() {
112
- return this._disconnecting;
113
- }
114
- /**
115
- * disconnect the TCP layer and close the underlying socket.
116
- * The ```"close"``` event will be emitted to the observers with err=null.
117
- *
118
- * @method disconnect
119
- * @async
120
- * @param callback
121
- */
122
- disconnect(callback) {
123
- (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function, but got " + callback);
124
- if (this._disconnecting) {
125
- callback();
126
- return;
127
- }
128
- (0, node_opcua_assert_1.assert)(!this._disconnecting, "TCP Transport has already been disconnected");
129
- this._disconnecting = true;
130
- // xx assert(!this._theCallback,
131
- // "disconnect shall not be called while the 'one time message receiver' is in operation");
132
- this._cleanup_timers();
133
- if (this._socket) {
134
- this._socket.end();
135
- this._socket && this._socket.destroy();
136
- // xx this._socket.removeAllListeners();
137
- this._socket = null;
138
- }
139
- this.on_socket_ended(null);
140
- setImmediate(() => {
141
- callback();
142
- });
143
- }
144
- isValid() {
145
- return this._socket !== null && !this._socket.destroyed && !this._disconnecting;
146
- }
147
- _write_chunk(messageChunk, callback) {
148
- if (this._socket !== null) {
149
- this.bytesWritten += messageChunk.length;
150
- this.chunkWrittenCount++;
151
- this._socket.write(messageChunk, callback);
152
- }
153
- else {
154
- if (callback) {
155
- callback();
156
- }
157
- }
158
- }
159
- on_socket_ended(err) {
160
- if (!this._onSocketEndedHasBeenCalled) {
161
- this._onSocketEndedHasBeenCalled = true; // we don't want to send close event twice ...
162
- this.emit("close", err || null);
163
- }
164
- else {
165
- debugLog("on_socket_ended has already been called");
166
- }
167
- }
168
- _install_packetAssembler() {
169
- if (this.packetAssembler) {
170
- this.packetAssembler.removeAllListeners();
171
- this.packetAssembler = undefined;
172
- }
173
- // install packet assembler ...
174
- this.packetAssembler = new node_opcua_packet_assembler_1.PacketAssembler({
175
- readChunkFunc: message_builder_base_1.readRawMessageHeader,
176
- minimumSizeInBytes: this.headerSize,
177
- maxChunkSize: this.receiveBufferSize //Math.max(this.receiveBufferSize, this.sendBufferSize)
178
- });
179
- this.packetAssembler.on("chunk", (chunk) => this._on_message_chunk_received(chunk));
180
- this.packetAssembler.on("error", (err, code) => {
181
- let statusCode = status_codes_1.StatusCodes2.BadTcpMessageTooLarge;
182
- switch (code) {
183
- case node_opcua_packet_assembler_1.PacketAssemblerErrorCode.ChunkSizeExceeded:
184
- statusCode = status_codes_1.StatusCodes2.BadTcpMessageTooLarge;
185
- break;
186
- default:
187
- statusCode = status_codes_1.StatusCodes2.BadTcpInternalError;
188
- }
189
- this.sendErrorMessage(statusCode, err.message);
190
- this.prematureTerminate(new Error("Packet Assembler : " + err.message), statusCode);
191
- });
192
- }
193
- /**
194
- * @method _install_socket
195
- * @param socket {Socket}
196
- * @protected
197
- */
198
- _install_socket(socket) {
199
- (0, node_opcua_assert_1.assert)(socket);
200
- this._socket = socket;
201
- if (doDebug) {
202
- debugLog(" TCP_transport#_install_socket ", this.name);
203
- }
204
- this._install_packetAssembler();
205
- this._socket
206
- .on("data", (data) => this._on_socket_data(data))
207
- .on("close", (hadError) => this._on_socket_close(hadError))
208
- .on("end", (err) => this._on_socket_end(err))
209
- .on("error", (err) => this._on_socket_error(err));
210
- // set socket timeout
211
- debugLog(" TCP_transport#install => setting " + this.name + " _socket.setTimeout to ", this.timeout);
212
- // let use a large timeout here to make sure that we not conflict with our internal timeout
213
- this._socket.setTimeout(this.timeout + 2000, () => {
214
- debugLog(` _socket ${this.name} has timed out (timeout = ${this.timeout})`);
215
- this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout), status_codes_1.StatusCodes2.BadTimeout);
216
- });
217
- }
218
- sendErrorMessage(statusCode, extraErrorDescription) {
219
- // When the Client receives an Error Message it reports the error to the application and closes the TransportConnection gracefully.
220
- // If a Client encounters a fatal error, it shall report the error to the application and send a CloseSecureChannel Message.
221
- /* istanbul ignore next*/
222
- if (doDebug) {
223
- debugLog(chalk.red(" sendErrorMessage ") + chalk.cyan(statusCode.toString()));
224
- debugLog(chalk.red(" extraErrorDescription ") + chalk.cyan(extraErrorDescription));
225
- }
226
- const reason = `${statusCode.toString()}:${extraErrorDescription || ""}`;
227
- const errorResponse = new TCPErrorMessage_1.TCPErrorMessage({
228
- statusCode,
229
- reason
230
- });
231
- const messageChunk = (0, tools_1.packTcpMessage)("ERR", errorResponse);
232
- this.write(messageChunk);
233
- }
234
- prematureTerminate(err, statusCode) {
235
- // https://reference.opcfoundation.org/v104/Core/docs/Part6/6.7.3/
236
- debugLog("prematureTerminate", err ? err.message : "", statusCode.toString());
237
- if (this._socket) {
238
- err.message = "premature socket termination " + err.message;
239
- // we consider this as an error
240
- const _s = this._socket;
241
- _s.end();
242
- _s.destroy(); // new Error("Socket has timed out"));
243
- _s.emit("error", err);
244
- this._socket = null;
245
- this.dispose();
246
- }
247
- // this.gracefullShutdown(err);
248
- }
249
- /**
250
- * @method _install_one_time_message_receiver
251
- *
252
- * install a one time message receiver callback
253
- *
254
- * Rules:
255
- * * TCP_transport will not emit the ```message``` event, while the "one time message receiver" is in operation.
256
- * * the TCP_transport will wait for the next complete message chunk and call the provided callback func
257
- * ```callback(null,messageChunk);```
258
- *
259
- * if a messageChunk is not received within ```TCP_transport.timeout``` or if the underlying socket reports
260
- * an error, the callback function will be called with an Error.
261
- *
262
- */
263
- _install_one_time_message_receiver(callback) {
264
- (0, node_opcua_assert_1.assert)(!this._theCallback, "callback already set");
265
- (0, node_opcua_assert_1.assert)(typeof callback === "function");
266
- this._theCallback = callback;
267
- this._start_one_time_message_receiver();
268
- }
269
- _fulfill_pending_promises(err, data) {
270
- this._cleanup_timers();
271
- if (this._socket && this._on_error_during_one_time_message_receiver) {
272
- this._socket.removeListener("close", this._on_error_during_one_time_message_receiver);
273
- this._on_error_during_one_time_message_receiver = null;
274
- }
275
- const callback = this._theCallback;
276
- this._theCallback = undefined;
277
- if (callback) {
278
- callback(err, data);
279
- return true;
280
- }
281
- return false;
282
- }
283
- _on_message_chunk_received(messageChunk) {
284
- if (utils_1.doTraceIncomingChunk) {
285
- console.log((0, node_opcua_debug_1.hexDump)(messageChunk));
286
- }
287
- const hadCallback = this._fulfill_pending_promises(null, messageChunk);
288
- this.chunkReadCount++;
289
- if (!hadCallback) {
290
- this.emit("chunk", messageChunk);
291
- }
292
- }
293
- _cleanup_timers() {
294
- if (this._timerId) {
295
- clearTimeout(this._timerId);
296
- this._timerId = null;
297
- }
298
- }
299
- _start_one_time_message_receiver() {
300
- (0, node_opcua_assert_1.assert)(!this._timerId, "timer already started");
301
- // Setup timeout detection timer ....
302
- this._timerId = setTimeout(() => {
303
- this._timerId = null;
304
- this._fulfill_pending_promises(new Error(`Timeout in waiting for data on socket ( timeout was = ${this.timeout} ms)`));
305
- }, this.timeout);
306
- // also monitored
307
- if (this._socket) {
308
- // to do = intercept socket error as well
309
- this._on_error_during_one_time_message_receiver = (err) => {
310
- this._fulfill_pending_promises(new Error(`ERROR in waiting for data on socket ( timeout was = ${this.timeout} ms) ` + (err === null || err === void 0 ? void 0 : err.message)));
311
- };
312
- this._socket.on("close", this._on_error_during_one_time_message_receiver);
313
- }
314
- }
315
- on_socket_closed(err) {
316
- if (this._onSocketClosedHasBeenCalled) {
317
- return;
318
- }
319
- (0, node_opcua_assert_1.assert)(!this._onSocketClosedHasBeenCalled);
320
- this._onSocketClosedHasBeenCalled = true; // we don't want to send close event twice ...
321
- this.emit("socket_closed", err || null);
322
- }
323
- _on_socket_data(data) {
324
- // istanbul ignore next
325
- if (!this.packetAssembler) {
326
- throw new Error("internal Error");
327
- }
328
- this.bytesRead += data.length;
329
- if (data.length > 0) {
330
- this.packetAssembler.feed(data);
331
- }
332
- }
333
- _on_socket_close(hadError) {
334
- // istanbul ignore next
335
- if (doDebug) {
336
- debugLog(chalk.red(" SOCKET CLOSE : "), chalk.yellow("had_error ="), chalk.cyan(hadError.toString()), this.name);
337
- }
338
- if (this._socket) {
339
- debugLog(" remote address = ", this._socket.remoteAddress, " ", this._socket.remoteFamily, " ", this._socket.remotePort);
340
- }
341
- if (hadError) {
342
- if (this._socket) {
343
- this._socket.destroy();
344
- }
345
- }
346
- const err = hadError ? new Error("ERROR IN SOCKET " + hadError.toString()) : undefined;
347
- this.on_socket_closed(err);
348
- this.dispose();
349
- }
350
- _on_socket_ended_message(err) {
351
- if (this._disconnecting) {
352
- return;
353
- }
354
- debugLog(chalk.red("Transport Connection ended") + " " + this.name);
355
- (0, node_opcua_assert_1.assert)(!this._disconnecting);
356
- err = err || new Error("_socket has been disconnected by third party");
357
- this.on_socket_ended(err);
358
- this._disconnecting = true;
359
- debugLog(" bytesRead = ", this.bytesRead);
360
- debugLog(" bytesWritten = ", this.bytesWritten);
361
- this._fulfill_pending_promises(new Error("Connection aborted - ended by server : " + (err ? err.message : "")));
362
- }
363
- _on_socket_end(err) {
364
- // istanbul ignore next
365
- if (doDebug) {
366
- debugLog(chalk.red(" SOCKET END : err="), chalk.yellow(err ? err.message : "null"), this.name);
367
- }
368
- this._on_socket_ended_message(err);
369
- }
370
- _on_socket_error(err) {
371
- // istanbul ignore next
372
- if (doDebug) {
373
- debugLog(chalk.red(" SOCKET ERROR : "), chalk.yellow(err.message), this.name);
374
- }
375
- // node The "close" event will be called directly following this event.
376
- }
377
- }
378
- exports.TCP_transport = TCP_transport;
379
- TCP_transport.registry = new node_opcua_object_registry_1.ObjectRegistry();
75
+ || maxMessageSize / receiveBufferSize ${maxMessageSize / receiveBufferSize} < maxChunkCount `);
76
+ }
77
+ // reinstall packetAssembler with correct limits
78
+ this._install_packetAssembler();
79
+ }
80
+ get timeout() {
81
+ return this._timeout;
82
+ }
83
+ set timeout(value) {
84
+ debugLog("Setting socket " + this.name + " timeout = ", value);
85
+ this._timeout = value;
86
+ }
87
+ dispose() {
88
+ this._cleanup_timers();
89
+ (0, node_opcua_assert_1.assert)(!this._timerId);
90
+ if (this._socket) {
91
+ this._socket.destroy();
92
+ this._socket.removeAllListeners();
93
+ this._socket = null;
94
+ }
95
+ TCP_transport.registry.unregister(this);
96
+ }
97
+ /**
98
+ * write the message_chunk on the socket.
99
+ * @method write
100
+ * @param messageChunk
101
+ */
102
+ write(messageChunk, callback) {
103
+ const header = (0, message_builder_base_1.readRawMessageHeader)(messageChunk);
104
+ (0, node_opcua_assert_1.assert)(header.length === messageChunk.length);
105
+ const c = header.messageHeader.isFinal;
106
+ (0, node_opcua_assert_1.assert)(c === "F" || c === "C" || c === "A");
107
+ this._write_chunk(messageChunk, (err) => {
108
+ callback && callback(err);
109
+ });
110
+ }
111
+ get isDisconnecting() {
112
+ return this._disconnecting;
113
+ }
114
+ /**
115
+ * disconnect the TCP layer and close the underlying socket.
116
+ * The ```"close"``` event will be emitted to the observers with err=null.
117
+ *
118
+ * @method disconnect
119
+ * @async
120
+ * @param callback
121
+ */
122
+ disconnect(callback) {
123
+ (0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function, but got " + callback);
124
+ if (this._disconnecting) {
125
+ callback();
126
+ return;
127
+ }
128
+ (0, node_opcua_assert_1.assert)(!this._disconnecting, "TCP Transport has already been disconnected");
129
+ this._disconnecting = true;
130
+ // xx assert(!this._theCallback,
131
+ // "disconnect shall not be called while the 'one time message receiver' is in operation");
132
+ this._cleanup_timers();
133
+ if (this._socket) {
134
+ this._socket.end();
135
+ this._socket && this._socket.destroy();
136
+ // xx this._socket.removeAllListeners();
137
+ this._socket = null;
138
+ }
139
+ this.on_socket_ended(null);
140
+ setImmediate(() => {
141
+ callback();
142
+ });
143
+ }
144
+ isValid() {
145
+ return this._socket !== null && !this._socket.destroyed && !this._disconnecting;
146
+ }
147
+ _write_chunk(messageChunk, callback) {
148
+ if (this._socket !== null) {
149
+ this.bytesWritten += messageChunk.length;
150
+ this.chunkWrittenCount++;
151
+ this._socket.write(messageChunk, callback);
152
+ }
153
+ else {
154
+ if (callback) {
155
+ callback();
156
+ }
157
+ }
158
+ }
159
+ on_socket_ended(err) {
160
+ if (!this._onSocketEndedHasBeenCalled) {
161
+ this._onSocketEndedHasBeenCalled = true; // we don't want to send close event twice ...
162
+ this.emit("close", err || null);
163
+ }
164
+ else {
165
+ debugLog("on_socket_ended has already been called");
166
+ }
167
+ }
168
+ _install_packetAssembler() {
169
+ if (this.packetAssembler) {
170
+ this.packetAssembler.removeAllListeners();
171
+ this.packetAssembler = undefined;
172
+ }
173
+ // install packet assembler ...
174
+ this.packetAssembler = new node_opcua_packet_assembler_1.PacketAssembler({
175
+ readChunkFunc: message_builder_base_1.readRawMessageHeader,
176
+ minimumSizeInBytes: this.headerSize,
177
+ maxChunkSize: this.receiveBufferSize //Math.max(this.receiveBufferSize, this.sendBufferSize)
178
+ });
179
+ this.packetAssembler.on("chunk", (chunk) => this._on_message_chunk_received(chunk));
180
+ this.packetAssembler.on("error", (err, code) => {
181
+ let statusCode = status_codes_1.StatusCodes2.BadTcpMessageTooLarge;
182
+ switch (code) {
183
+ case node_opcua_packet_assembler_1.PacketAssemblerErrorCode.ChunkSizeExceeded:
184
+ statusCode = status_codes_1.StatusCodes2.BadTcpMessageTooLarge;
185
+ break;
186
+ default:
187
+ statusCode = status_codes_1.StatusCodes2.BadTcpInternalError;
188
+ }
189
+ this.sendErrorMessage(statusCode, err.message);
190
+ this.prematureTerminate(new Error("Packet Assembler : " + err.message), statusCode);
191
+ });
192
+ }
193
+ /**
194
+ * @method _install_socket
195
+ * @param socket {Socket}
196
+ * @protected
197
+ */
198
+ _install_socket(socket) {
199
+ (0, node_opcua_assert_1.assert)(socket);
200
+ this._socket = socket;
201
+ if (doDebug) {
202
+ debugLog(" TCP_transport#_install_socket ", this.name);
203
+ }
204
+ this._install_packetAssembler();
205
+ this._socket
206
+ .on("data", (data) => this._on_socket_data(data))
207
+ .on("close", (hadError) => this._on_socket_close(hadError))
208
+ .on("end", (err) => this._on_socket_end(err))
209
+ .on("error", (err) => this._on_socket_error(err));
210
+ // set socket timeout
211
+ debugLog(" TCP_transport#install => setting " + this.name + " _socket.setTimeout to ", this.timeout);
212
+ // let use a large timeout here to make sure that we not conflict with our internal timeout
213
+ this._socket.setTimeout(this.timeout + 2000, () => {
214
+ debugLog(` _socket ${this.name} has timed out (timeout = ${this.timeout})`);
215
+ this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout), status_codes_1.StatusCodes2.BadTimeout);
216
+ });
217
+ }
218
+ sendErrorMessage(statusCode, extraErrorDescription) {
219
+ // When the Client receives an Error Message it reports the error to the application and closes the TransportConnection gracefully.
220
+ // If a Client encounters a fatal error, it shall report the error to the application and send a CloseSecureChannel Message.
221
+ /* istanbul ignore next*/
222
+ if (doDebug) {
223
+ debugLog(chalk.red(" sendErrorMessage ") + chalk.cyan(statusCode.toString()));
224
+ debugLog(chalk.red(" extraErrorDescription ") + chalk.cyan(extraErrorDescription));
225
+ }
226
+ const reason = `${statusCode.toString()}:${extraErrorDescription || ""}`;
227
+ const errorResponse = new TCPErrorMessage_1.TCPErrorMessage({
228
+ statusCode,
229
+ reason
230
+ });
231
+ const messageChunk = (0, tools_1.packTcpMessage)("ERR", errorResponse);
232
+ this.write(messageChunk);
233
+ }
234
+ prematureTerminate(err, statusCode) {
235
+ // https://reference.opcfoundation.org/v104/Core/docs/Part6/6.7.3/
236
+ debugLog("prematureTerminate", err ? err.message : "", statusCode.toString());
237
+ if (this._socket) {
238
+ err.message = "premature socket termination " + err.message;
239
+ // we consider this as an error
240
+ const _s = this._socket;
241
+ _s.end();
242
+ _s.destroy(); // new Error("Socket has timed out"));
243
+ _s.emit("error", err);
244
+ this._socket = null;
245
+ this.dispose();
246
+ }
247
+ // this.gracefullShutdown(err);
248
+ }
249
+ /**
250
+ * @method _install_one_time_message_receiver
251
+ *
252
+ * install a one time message receiver callback
253
+ *
254
+ * Rules:
255
+ * * TCP_transport will not emit the ```message``` event, while the "one time message receiver" is in operation.
256
+ * * the TCP_transport will wait for the next complete message chunk and call the provided callback func
257
+ * ```callback(null,messageChunk);```
258
+ *
259
+ * if a messageChunk is not received within ```TCP_transport.timeout``` or if the underlying socket reports
260
+ * an error, the callback function will be called with an Error.
261
+ *
262
+ */
263
+ _install_one_time_message_receiver(callback) {
264
+ (0, node_opcua_assert_1.assert)(!this._theCallback, "callback already set");
265
+ (0, node_opcua_assert_1.assert)(typeof callback === "function");
266
+ this._theCallback = callback;
267
+ this._start_one_time_message_receiver();
268
+ }
269
+ _fulfill_pending_promises(err, data) {
270
+ this._cleanup_timers();
271
+ if (this._socket && this._on_error_during_one_time_message_receiver) {
272
+ this._socket.removeListener("close", this._on_error_during_one_time_message_receiver);
273
+ this._on_error_during_one_time_message_receiver = null;
274
+ }
275
+ const callback = this._theCallback;
276
+ this._theCallback = undefined;
277
+ if (callback) {
278
+ callback(err, data);
279
+ return true;
280
+ }
281
+ return false;
282
+ }
283
+ _on_message_chunk_received(messageChunk) {
284
+ if (utils_1.doTraceIncomingChunk) {
285
+ console.log((0, node_opcua_debug_1.hexDump)(messageChunk));
286
+ }
287
+ const hadCallback = this._fulfill_pending_promises(null, messageChunk);
288
+ this.chunkReadCount++;
289
+ if (!hadCallback) {
290
+ this.emit("chunk", messageChunk);
291
+ }
292
+ }
293
+ _cleanup_timers() {
294
+ if (this._timerId) {
295
+ clearTimeout(this._timerId);
296
+ this._timerId = null;
297
+ }
298
+ }
299
+ _start_one_time_message_receiver() {
300
+ (0, node_opcua_assert_1.assert)(!this._timerId, "timer already started");
301
+ // Setup timeout detection timer ....
302
+ this._timerId = setTimeout(() => {
303
+ this._timerId = null;
304
+ this._fulfill_pending_promises(new Error(`Timeout in waiting for data on socket ( timeout was = ${this.timeout} ms)`));
305
+ }, this.timeout);
306
+ // also monitored
307
+ if (this._socket) {
308
+ // to do = intercept socket error as well
309
+ this._on_error_during_one_time_message_receiver = (err) => {
310
+ this._fulfill_pending_promises(new Error(`ERROR in waiting for data on socket ( timeout was = ${this.timeout} ms) ` + (err === null || err === void 0 ? void 0 : err.message)));
311
+ };
312
+ this._socket.on("close", this._on_error_during_one_time_message_receiver);
313
+ }
314
+ }
315
+ on_socket_closed(err) {
316
+ if (this._onSocketClosedHasBeenCalled) {
317
+ return;
318
+ }
319
+ (0, node_opcua_assert_1.assert)(!this._onSocketClosedHasBeenCalled);
320
+ this._onSocketClosedHasBeenCalled = true; // we don't want to send close event twice ...
321
+ this.emit("socket_closed", err || null);
322
+ }
323
+ _on_socket_data(data) {
324
+ // istanbul ignore next
325
+ if (!this.packetAssembler) {
326
+ throw new Error("internal Error");
327
+ }
328
+ this.bytesRead += data.length;
329
+ if (data.length > 0) {
330
+ this.packetAssembler.feed(data);
331
+ }
332
+ }
333
+ _on_socket_close(hadError) {
334
+ // istanbul ignore next
335
+ if (doDebug) {
336
+ debugLog(chalk.red(" SOCKET CLOSE : "), chalk.yellow("had_error ="), chalk.cyan(hadError.toString()), this.name);
337
+ }
338
+ if (this._socket) {
339
+ debugLog(" remote address = ", this._socket.remoteAddress, " ", this._socket.remoteFamily, " ", this._socket.remotePort);
340
+ }
341
+ if (hadError) {
342
+ if (this._socket) {
343
+ this._socket.destroy();
344
+ }
345
+ }
346
+ const err = hadError ? new Error("ERROR IN SOCKET " + hadError.toString()) : undefined;
347
+ this.on_socket_closed(err);
348
+ this.dispose();
349
+ }
350
+ _on_socket_ended_message(err) {
351
+ if (this._disconnecting) {
352
+ return;
353
+ }
354
+ debugLog(chalk.red("Transport Connection ended") + " " + this.name);
355
+ (0, node_opcua_assert_1.assert)(!this._disconnecting);
356
+ err = err || new Error("_socket has been disconnected by third party");
357
+ this.on_socket_ended(err);
358
+ this._disconnecting = true;
359
+ debugLog(" bytesRead = ", this.bytesRead);
360
+ debugLog(" bytesWritten = ", this.bytesWritten);
361
+ this._fulfill_pending_promises(new Error("Connection aborted - ended by server : " + (err ? err.message : "")));
362
+ }
363
+ _on_socket_end(err) {
364
+ // istanbul ignore next
365
+ if (doDebug) {
366
+ debugLog(chalk.red(" SOCKET END : err="), chalk.yellow(err ? err.message : "null"), this.name);
367
+ }
368
+ this._on_socket_ended_message(err);
369
+ }
370
+ _on_socket_error(err) {
371
+ // istanbul ignore next
372
+ if (doDebug) {
373
+ debugLog(chalk.red(" SOCKET ERROR : "), chalk.yellow(err.message), this.name);
374
+ }
375
+ // node The "close" event will be called directly following this event.
376
+ }
377
+ }
378
+ TCP_transport.registry = new node_opcua_object_registry_1.ObjectRegistry();
379
+ exports.TCP_transport = TCP_transport;
380
380
  //# sourceMappingURL=tcp_transport.js.map