node-opcua-transport 2.167.0 → 2.169.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.
- package/dist/source/AcknowledgeMessage.d.ts +5 -5
- package/dist/source/AcknowledgeMessage.js +5 -5
- package/dist/source/AcknowledgeMessage.js.map +1 -1
- package/dist/source/HelloMessage.d.ts +3 -3
- package/dist/source/HelloMessage.js +6 -6
- package/dist/source/HelloMessage.js.map +1 -1
- package/dist/source/TCPErrorMessage.d.ts +3 -3
- package/dist/source/TCPErrorMessage.js.map +1 -1
- package/dist/source/client_tcp_transport.d.ts +5 -2
- package/dist/source/client_tcp_transport.js +24 -25
- package/dist/source/client_tcp_transport.js.map +1 -1
- package/dist/source/i_hello_ack_limits.d.ts +1 -1
- package/dist/source/index.d.ts +2 -2
- package/dist/source/index.js +2 -2
- package/dist/source/index.js.map +1 -1
- package/dist/source/message_builder_base.d.ts +14 -27
- package/dist/source/message_builder_base.js +14 -13
- package/dist/source/message_builder_base.js.map +1 -1
- package/dist/source/server_tcp_transport.d.ts +6 -3
- package/dist/source/server_tcp_transport.js +34 -22
- package/dist/source/server_tcp_transport.js.map +1 -1
- package/dist/source/tcp_transport.d.ts +11 -15
- package/dist/source/tcp_transport.js +45 -52
- package/dist/source/tcp_transport.js.map +1 -1
- package/dist/source/tools.d.ts +3 -3
- package/dist/source/tools.js +7 -7
- package/dist/source/tools.js.map +1 -1
- package/dist/test_helpers/ITransportPair.d.ts +1 -1
- package/dist/test_helpers/fake_server.d.ts +3 -3
- package/dist/test_helpers/fake_server.js +11 -7
- package/dist/test_helpers/fake_server.js.map +1 -1
- package/dist/test_helpers/half_com_channel.d.ts +6 -6
- package/dist/test_helpers/half_com_channel.js +6 -6
- package/dist/test_helpers/half_com_channel.js.map +1 -1
- package/dist/test_helpers/index.d.ts +1 -1
- package/dist/test_helpers/index.js +1 -1
- package/dist/test_helpers/index.js.map +1 -1
- package/dist/test_helpers/transport_pair_direct.d.ts +2 -2
- package/dist/test_helpers/transport_pair_direct.js +2 -2
- package/dist/test_helpers/transport_pair_direct.js.map +1 -1
- package/dist/test_helpers/transport_pair_socket.d.ts +3 -3
- package/dist/test_helpers/transport_pair_socket.js +3 -3
- package/dist/test_helpers/transport_pair_socket.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/source/AcknowledgeMessage.ts +10 -11
- package/source/HelloMessage.ts +9 -9
- package/source/TCPErrorMessage.ts +3 -3
- package/source/client_tcp_transport.ts +28 -33
- package/source/i_hello_ack_limits.ts +1 -1
- package/source/index.ts +4 -4
- package/source/message_builder_base.ts +31 -43
- package/source/server_tcp_transport.ts +36 -32
- package/source/tcp_transport.ts +51 -68
- package/source/tools.ts +12 -18
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module node-opcua-transport
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
import { createConnection } from "net";
|
|
6
|
-
import
|
|
4
|
+
|
|
5
|
+
import { createConnection } from "node:net";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import { types } from "node:util";
|
|
7
8
|
import chalk from "chalk";
|
|
8
9
|
|
|
9
10
|
import { assert } from "node-opcua-assert";
|
|
10
11
|
import { BinaryStream } from "node-opcua-binary-stream";
|
|
11
12
|
import { readMessageHeader } from "node-opcua-chunkmanager";
|
|
12
|
-
import { ErrorCallback } from "node-opcua-status-code";
|
|
13
13
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
14
|
-
import {
|
|
15
|
-
import { decodeMessage, packTcpMessage, parseEndpointUrl } from "./tools";
|
|
16
|
-
|
|
14
|
+
import type { ErrorCallback } from "node-opcua-status-code";
|
|
17
15
|
import { AcknowledgeMessage } from "./AcknowledgeMessage";
|
|
18
16
|
import { HelloMessage } from "./HelloMessage";
|
|
19
17
|
import { TCPErrorMessage } from "./TCPErrorMessage";
|
|
18
|
+
import { getFakeTransport, type ISocketLike, TCP_transport } from "./tcp_transport";
|
|
19
|
+
import { decodeMessage, packTcpMessage, parseEndpointUrl } from "./tools";
|
|
20
20
|
import { doTraceHelloAck } from "./utils";
|
|
21
21
|
|
|
22
22
|
const doDebug = checkDebugFlag(__filename);
|
|
@@ -37,22 +37,17 @@ function createClientSocket(endpointUrl: string, timeout: number): ISocketLike {
|
|
|
37
37
|
socket = createConnection({ host: hostname, port, timeout }, () => {
|
|
38
38
|
doDebug && debugLog(`connected to server! ${hostname}:${port} timeout:${timeout} `);
|
|
39
39
|
});
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
socket.setNoDelay(false);
|
|
42
42
|
socket.setKeepAlive(true, timeout >> 1);
|
|
43
43
|
|
|
44
|
-
|
|
45
44
|
return socket;
|
|
46
45
|
case "fake:":
|
|
47
46
|
assert(ep.protocol === "fake:", " Unsupported transport protocol");
|
|
48
47
|
socket = getFakeTransport();
|
|
49
48
|
return socket;
|
|
50
|
-
|
|
51
|
-
case "websocket:":
|
|
52
|
-
case "http:":
|
|
53
|
-
case "https:":
|
|
54
49
|
default: {
|
|
55
|
-
const msg =
|
|
50
|
+
const msg = `[NODE-OPCUA-E05] this transport protocol is not supported :${ep.protocol}`;
|
|
56
51
|
errorLog(msg);
|
|
57
52
|
throw new Error(msg);
|
|
58
53
|
}
|
|
@@ -117,6 +112,7 @@ export interface TransportSettingsOptions {
|
|
|
117
112
|
*
|
|
118
113
|
*
|
|
119
114
|
*/
|
|
115
|
+
// biome-ignore lint/suspicious/noUnsafeDeclarationMerging: typed EventEmitter events - extending parent's event map in subclass hierarchy
|
|
120
116
|
export class ClientTCP_transport extends TCP_transport {
|
|
121
117
|
public static defaultMaxChunk = 0; // 0 - no limits
|
|
122
118
|
public static defaultMaxMessageSize = 0; // 0 - no limits
|
|
@@ -168,25 +164,24 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
168
164
|
}
|
|
169
165
|
|
|
170
166
|
public connect(endpointUrl: string, callback: ErrorCallback): void {
|
|
171
|
-
|
|
172
167
|
this.endpointUrl = endpointUrl;
|
|
173
|
-
this.serverUri =
|
|
168
|
+
this.serverUri = `urn:${gHostname}:Sample`;
|
|
174
169
|
/* c8 ignore next */
|
|
175
|
-
doDebug && debugLog(chalk.cyan(
|
|
170
|
+
doDebug && debugLog(chalk.cyan(`ClientTCP_transport#connect(endpointUrl = ${endpointUrl})`));
|
|
176
171
|
let socket: ISocketLike | null = null;
|
|
177
172
|
try {
|
|
178
|
-
const
|
|
173
|
+
const _ep = parseEndpointUrl(endpointUrl);
|
|
179
174
|
socket = createClientSocket(endpointUrl, this.timeout);
|
|
180
|
-
|
|
175
|
+
|
|
181
176
|
socket.setTimeout(this.timeout >> 1, () => {
|
|
182
177
|
this.forceConnectionBreak();
|
|
183
178
|
});
|
|
184
|
-
|
|
185
179
|
} catch (err) {
|
|
186
180
|
/* c8 ignore next */
|
|
187
181
|
doDebug && debugLog("CreateClientSocket has failed");
|
|
188
182
|
|
|
189
|
-
|
|
183
|
+
callback(err as Error);
|
|
184
|
+
return;
|
|
190
185
|
}
|
|
191
186
|
|
|
192
187
|
/**
|
|
@@ -226,7 +221,7 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
226
221
|
if (!err) {
|
|
227
222
|
/* c8 ignore next */
|
|
228
223
|
if (!this._socket) {
|
|
229
|
-
return callback(new Error("Abandoned"));
|
|
224
|
+
return callback(new Error("Abandoned"));
|
|
230
225
|
}
|
|
231
226
|
// install error handler to detect connection break
|
|
232
227
|
this._socket.on("error", _on_socket_error_after_connection);
|
|
@@ -270,30 +265,30 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
270
265
|
|
|
271
266
|
this._install_socket(socket);
|
|
272
267
|
|
|
273
|
-
this._socket
|
|
274
|
-
this._socket
|
|
275
|
-
this._socket
|
|
268
|
+
this._socket?.once("error", _on_socket_error_for_connect);
|
|
269
|
+
this._socket?.once("end", _on_socket_end_for_connect);
|
|
270
|
+
this._socket?.once("connect", _on_socket_connect);
|
|
276
271
|
}
|
|
277
272
|
|
|
278
273
|
private _handle_ACK_response(messageChunk: Buffer, callback: ErrorCallback) {
|
|
279
274
|
const _stream = new BinaryStream(messageChunk);
|
|
280
275
|
const messageHeader = readMessageHeader(_stream);
|
|
281
|
-
let err;
|
|
276
|
+
let err: Error | null = null;
|
|
282
277
|
/* c8 ignore next */
|
|
283
278
|
if (messageHeader.isFinal !== "F") {
|
|
284
279
|
err = new Error(" invalid ACK message");
|
|
285
280
|
return callback(err);
|
|
286
281
|
}
|
|
287
282
|
|
|
288
|
-
let responseClass;
|
|
289
|
-
let response;
|
|
283
|
+
let responseClass: typeof AcknowledgeMessage | typeof TCPErrorMessage;
|
|
284
|
+
let response: AcknowledgeMessage | TCPErrorMessage;
|
|
290
285
|
|
|
291
286
|
if (messageHeader.msgType === "ERR") {
|
|
292
287
|
responseClass = TCPErrorMessage;
|
|
293
288
|
_stream.rewind();
|
|
294
289
|
response = decodeMessage(_stream, responseClass) as TCPErrorMessage;
|
|
295
290
|
|
|
296
|
-
err = new Error(
|
|
291
|
+
err = new Error(`ACK: ERR received ${response.statusCode.toString()} : ${response.reason}`);
|
|
297
292
|
(err as any).statusCode = response.statusCode;
|
|
298
293
|
// c8 ignore next
|
|
299
294
|
doTraceHelloAck && warningLog("receiving ERR instead of Ack", response.toString());
|
|
@@ -302,10 +297,10 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
302
297
|
} else {
|
|
303
298
|
responseClass = AcknowledgeMessage;
|
|
304
299
|
_stream.rewind();
|
|
305
|
-
response = decodeMessage(_stream, responseClass);
|
|
300
|
+
response = decodeMessage(_stream, responseClass) as AcknowledgeMessage;
|
|
306
301
|
|
|
307
|
-
this.parameters = response
|
|
308
|
-
this.setLimits(response
|
|
302
|
+
this.parameters = response;
|
|
303
|
+
this.setLimits(response);
|
|
309
304
|
|
|
310
305
|
// c8 ignore next
|
|
311
306
|
doTraceHelloAck && warningLog("receiving Ack\n", response.toString());
|
|
@@ -319,7 +314,7 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
319
314
|
doDebug && debugLog("entering _send_HELLO_request");
|
|
320
315
|
|
|
321
316
|
assert(this._socket);
|
|
322
|
-
assert(isFinite(this.protocolVersion));
|
|
317
|
+
assert(Number.isFinite(this.protocolVersion));
|
|
323
318
|
assert(this.endpointUrl.length > 0, " expecting a valid endpoint url");
|
|
324
319
|
|
|
325
320
|
const { maxChunkCount, maxMessageSize, receiveBufferSize, sendBufferSize } = this._helloSettings;
|
package/source/index.ts
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
10
10
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
11
11
|
* subject to the following conditions:
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
13
|
* The above copyright notice and this permission notice shall be included in all
|
|
14
14
|
* copies or substantial portions of the Software.
|
|
15
|
-
*
|
|
15
|
+
*
|
|
16
16
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
17
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
18
18
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
export * from "./AcknowledgeMessage";
|
|
27
27
|
export * from "./client_tcp_transport";
|
|
28
28
|
export * from "./HelloMessage";
|
|
29
|
+
export * from "./i_hello_ack_limits";
|
|
29
30
|
export * from "./message_builder_base";
|
|
30
31
|
export * from "./server_tcp_transport";
|
|
31
32
|
export * from "./status_codes";
|
|
32
|
-
export * from "./tcp_transport";
|
|
33
33
|
export * from "./TCPErrorMessage";
|
|
34
|
+
export * from "./tcp_transport";
|
|
34
35
|
export * from "./tools";
|
|
35
36
|
export * from "./utils";
|
|
36
|
-
export * from "./i_hello_ack_limits";
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module node-opcua-transport
|
|
3
3
|
*/
|
|
4
|
-
import { EventEmitter } from "events";
|
|
4
|
+
import { EventEmitter } from "node:events";
|
|
5
5
|
import { assert } from "node-opcua-assert";
|
|
6
6
|
|
|
7
7
|
import { decodeStatusCode, decodeString, decodeUInt32 } from "node-opcua-basic-types";
|
|
8
8
|
import { BinaryStream } from "node-opcua-binary-stream";
|
|
9
9
|
|
|
10
10
|
import { readMessageHeader, SequenceHeader } from "node-opcua-chunkmanager";
|
|
11
|
-
import {
|
|
12
|
-
import { MessageHeader, PacketAssembler, PacketInfo } from "node-opcua-packet-assembler";
|
|
13
|
-
import { StatusCode } from "node-opcua-status-code";
|
|
11
|
+
import { hexDump, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
12
|
+
import { type MessageHeader, PacketAssembler, type PacketInfo } from "node-opcua-packet-assembler";
|
|
13
|
+
import type { StatusCode } from "node-opcua-status-code";
|
|
14
14
|
import { get_clock_tick } from "node-opcua-utils";
|
|
15
15
|
import { StatusCodes2 } from "./status_codes";
|
|
16
|
+
|
|
16
17
|
const doPerfMonitoring = process.env.NODEOPCUADEBUG && process.env.NODEOPCUADEBUG.indexOf("PERF") >= 0;
|
|
17
18
|
|
|
18
19
|
const errorLog = make_errorLog("MessageBuilder");
|
|
19
|
-
const
|
|
20
|
+
const _debugLog = make_debugLog("MessageBuilder");
|
|
20
21
|
const warningLog = make_warningLog("MessageBuilder");
|
|
21
22
|
|
|
22
23
|
export function readRawMessageHeader(data: Buffer): PacketInfo {
|
|
@@ -35,50 +36,32 @@ export interface MessageBuilderBaseOptions {
|
|
|
35
36
|
maxChunkSize?: number;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
export interface
|
|
39
|
+
export interface MessageBuilderBaseEvents {
|
|
39
40
|
/**
|
|
40
|
-
*
|
|
41
41
|
* notify the observers that a new message is being built
|
|
42
|
-
* @event
|
|
43
|
-
* @param info
|
|
44
|
-
* @param data
|
|
42
|
+
* @event startChunk
|
|
45
43
|
*/
|
|
46
|
-
|
|
47
|
-
on(eventName: "startChunk", eventHandler: (info: PacketInfo, data: Buffer) => void): this;
|
|
44
|
+
startChunk: [info: PacketInfo, data: Buffer];
|
|
48
45
|
/**
|
|
49
46
|
* notify the observers that new message chunk has been received
|
|
50
47
|
* @event chunk
|
|
51
|
-
* @param messageChunk the raw message chunk
|
|
52
48
|
*/
|
|
53
|
-
|
|
54
|
-
on(eventName: "chunk", eventHandler: (chunk: Buffer) => void): this;
|
|
49
|
+
chunk: [chunk: Buffer];
|
|
55
50
|
/**
|
|
56
51
|
* notify the observers that an error has occurred
|
|
57
52
|
* @event error
|
|
58
|
-
* @param error the error to raise
|
|
59
53
|
*/
|
|
60
|
-
|
|
61
|
-
on(eventName: "error", eventHandler: (err: Error, statusCode: StatusCode, requestId: number | null) => void): this;
|
|
54
|
+
error: [err: Error, statusCode: StatusCode, requestId: number | null];
|
|
62
55
|
/**
|
|
63
56
|
* notify the observers that a full message has been received
|
|
64
57
|
* @event full_message_body
|
|
65
|
-
* @param full_message_body the full message body made of all concatenated chunks.
|
|
66
58
|
*/
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
full_message_body: [fullMessageBody: Buffer];
|
|
69
60
|
/**
|
|
70
|
-
*
|
|
71
|
-
* @
|
|
72
|
-
* @param info
|
|
73
|
-
* @param data
|
|
61
|
+
* notify the observers that a request has been abandoned
|
|
62
|
+
* @event abandon
|
|
74
63
|
*/
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
emit(eventName: "startChunk", info: PacketInfo, data: Buffer): boolean;
|
|
78
|
-
emit(eventName: "chunk", chunk: Buffer): boolean;
|
|
79
|
-
emit(eventName: "error", err: Error, statusCode: StatusCode, requestId: number | null): boolean;
|
|
80
|
-
emit(eventName: "full_message_body", fullMessageBody: Buffer): boolean;
|
|
81
|
-
emit(eventName: "abandon", requestId: number): boolean;
|
|
64
|
+
abandon: [requestId: number];
|
|
82
65
|
}
|
|
83
66
|
/**
|
|
84
67
|
*
|
|
@@ -158,7 +141,7 @@ export class MessageBuilderBase extends EventEmitter {
|
|
|
158
141
|
|
|
159
142
|
this.#_packetAssembler.on("error", (err) => {
|
|
160
143
|
warningLog("packet assembler ", err.message);
|
|
161
|
-
|
|
144
|
+
this._report_error(StatusCodes2.BadTcpMessageTooLarge, `packet assembler: ${err.message}`);
|
|
162
145
|
});
|
|
163
146
|
|
|
164
147
|
this.#_securityDefeated = false;
|
|
@@ -185,7 +168,7 @@ export class MessageBuilderBase extends EventEmitter {
|
|
|
185
168
|
}
|
|
186
169
|
}
|
|
187
170
|
|
|
188
|
-
protected _decodeMessageBody(
|
|
171
|
+
protected _decodeMessageBody(_fullMessageBody: Buffer): boolean {
|
|
189
172
|
return true;
|
|
190
173
|
}
|
|
191
174
|
|
|
@@ -202,11 +185,11 @@ export class MessageBuilderBase extends EventEmitter {
|
|
|
202
185
|
}
|
|
203
186
|
return true;
|
|
204
187
|
} catch (err) {
|
|
205
|
-
return this._report_error(StatusCodes2.BadTcpInternalError,
|
|
188
|
+
return this._report_error(StatusCodes2.BadTcpInternalError, `_read_headers error ${err instanceof Error ? err.message : String(err)}`);
|
|
206
189
|
}
|
|
207
190
|
}
|
|
208
191
|
|
|
209
|
-
protected _report_abandon(
|
|
192
|
+
protected _report_abandon(_channelId: number, _tokenId: number, sequenceHeader: SequenceHeader): false {
|
|
210
193
|
// the server has not been able to send a complete message and has abandoned the request
|
|
211
194
|
// the connection can probably continue
|
|
212
195
|
this.#_hasReceivedError = false; ///
|
|
@@ -251,7 +234,10 @@ export class MessageBuilderBase extends EventEmitter {
|
|
|
251
234
|
this.totalMessageSize += chunk.length;
|
|
252
235
|
|
|
253
236
|
if (this.totalMessageSize > this.maxMessageSize) {
|
|
254
|
-
return this._report_error(
|
|
237
|
+
return this._report_error(
|
|
238
|
+
StatusCodes2.BadTcpMessageTooLarge,
|
|
239
|
+
`max message size exceeded: ${this.maxMessageSize} : total message size ${this.totalMessageSize}`
|
|
240
|
+
);
|
|
255
241
|
}
|
|
256
242
|
|
|
257
243
|
const binaryStream = new BinaryStream(chunk);
|
|
@@ -263,11 +249,12 @@ export class MessageBuilderBase extends EventEmitter {
|
|
|
263
249
|
assert(binaryStream.length >= 12);
|
|
264
250
|
|
|
265
251
|
// verify message chunk length
|
|
266
|
-
if (this.messageHeader
|
|
252
|
+
if (this.messageHeader?.length !== chunk.length) {
|
|
267
253
|
// tslint:disable:max-line-length
|
|
268
254
|
return this._report_error(
|
|
269
255
|
StatusCodes2.BadTcpInternalError,
|
|
270
|
-
`Invalid messageChunk size: the provided chunk is ${chunk.length} bytes long but header specifies ${
|
|
256
|
+
`Invalid messageChunk size: the provided chunk is ${chunk.length} bytes long but header specifies ${
|
|
257
|
+
this.messageHeader?.length
|
|
271
258
|
}`
|
|
272
259
|
);
|
|
273
260
|
}
|
|
@@ -282,7 +269,7 @@ export class MessageBuilderBase extends EventEmitter {
|
|
|
282
269
|
this.#offsetBodyStart = offsetBodyStart;
|
|
283
270
|
|
|
284
271
|
// add message body to a queue
|
|
285
|
-
// We use subarray here to avoid copy.
|
|
272
|
+
// We use subarray here to avoid copy.
|
|
286
273
|
// This assumes PacketAssembler manages the buffer lifecycle appropriately.
|
|
287
274
|
const sharedBuffer = chunk.subarray(this.#offsetBodyStart, offsetBodyEnd);
|
|
288
275
|
this.#blocks.push(sharedBuffer);
|
|
@@ -329,7 +316,7 @@ export class MessageBuilderBase extends EventEmitter {
|
|
|
329
316
|
const stream = new BinaryStream(chunk);
|
|
330
317
|
readMessageHeader(stream);
|
|
331
318
|
assert(stream.length === 8);
|
|
332
|
-
// instead of
|
|
319
|
+
// instead of
|
|
333
320
|
// const securityHeader = new SymmetricAlgorithmSecurityHeader();
|
|
334
321
|
// securityHeader.decode(stream);
|
|
335
322
|
|
|
@@ -341,11 +328,12 @@ export class MessageBuilderBase extends EventEmitter {
|
|
|
341
328
|
|
|
342
329
|
return this._report_abandon(channelId, tokenId, sequenceHeader);
|
|
343
330
|
} catch (err) {
|
|
331
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
344
332
|
warningLog(hexDump(chunk));
|
|
345
|
-
warningLog("Cannot interpret message chunk: ",
|
|
333
|
+
warningLog("Cannot interpret message chunk: ", errMessage);
|
|
346
334
|
return this._report_error(
|
|
347
335
|
StatusCodes2.BadTcpInternalError,
|
|
348
|
-
|
|
336
|
+
`Error decoding message header ${errMessage}`
|
|
349
337
|
);
|
|
350
338
|
}
|
|
351
339
|
} else if (messageHeader.isFinal === "C") {
|
|
@@ -3,24 +3,22 @@
|
|
|
3
3
|
*/
|
|
4
4
|
// tslint:disable:class-name
|
|
5
5
|
// system
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import { assert } from "node-opcua-assert";
|
|
9
|
-
|
|
10
|
-
// opcua requires
|
|
11
|
-
import { checkDebugFlag, hexDump, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
12
9
|
import { BinaryStream } from "node-opcua-binary-stream";
|
|
13
10
|
import { verify_message_chunk } from "node-opcua-chunkmanager";
|
|
14
|
-
|
|
15
|
-
import {
|
|
11
|
+
// opcua requires
|
|
12
|
+
import { checkDebugFlag, hexDump, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
13
|
+
import { type ErrorCallback, type StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
16
14
|
|
|
17
15
|
// this package requires
|
|
18
16
|
import { AcknowledgeMessage } from "./AcknowledgeMessage";
|
|
19
17
|
import { HelloMessage } from "./HelloMessage";
|
|
20
|
-
import {
|
|
18
|
+
import type { IHelloAckLimits } from "./i_hello_ack_limits";
|
|
19
|
+
import { type ISocketLike, TCP_transport } from "./tcp_transport";
|
|
21
20
|
import { decodeMessage, packTcpMessage } from "./tools";
|
|
22
21
|
import { doTraceHelloAck } from "./utils";
|
|
23
|
-
import { IHelloAckLimits } from "./i_hello_ack_limits";
|
|
24
22
|
|
|
25
23
|
const debugLog = make_debugLog("TRANSPORT");
|
|
26
24
|
const errorLog = make_errorLog("TRANSPORT");
|
|
@@ -65,8 +63,6 @@ const defaultTransportParameters = {
|
|
|
65
63
|
maxMaxChunkCount: 9000
|
|
66
64
|
};
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
|
|
70
66
|
export function adjustLimitsWithParameters(helloMessage: IHelloAckLimits, params: ITransportParameters): IHelloAckLimits {
|
|
71
67
|
const defaultReceiveBufferSize = 64 * 1024;
|
|
72
68
|
const defaultSendBufferSize = 64 * 1024;
|
|
@@ -104,7 +100,6 @@ export function adjustLimitsWithParameters(helloMessage: IHelloAckLimits, params
|
|
|
104
100
|
};
|
|
105
101
|
}
|
|
106
102
|
|
|
107
|
-
|
|
108
103
|
const defaultAdjustLimits = (hello: IHelloAckLimits) => adjustLimitsWithParameters(hello, defaultTransportParameters);
|
|
109
104
|
interface ServerTCP_transportOptions {
|
|
110
105
|
adjustLimits?: (hello: IHelloAckLimits) => IHelloAckLimits;
|
|
@@ -134,8 +129,8 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
134
129
|
|
|
135
130
|
public toString() {
|
|
136
131
|
let str = super.toString();
|
|
137
|
-
str +=
|
|
138
|
-
str +=
|
|
132
|
+
str += `helloReceived...... = ${this._helloReceived}\n`;
|
|
133
|
+
str += `aborted............ = ${this._aborted}\n`;
|
|
139
134
|
return str;
|
|
140
135
|
}
|
|
141
136
|
|
|
@@ -170,7 +165,7 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
170
165
|
*/
|
|
171
166
|
public init(socket: ISocketLike, callback: ErrorCallback): void {
|
|
172
167
|
// c8 ignore next
|
|
173
|
-
debugLog
|
|
168
|
+
debugLog?.(chalk.cyan("init socket"));
|
|
174
169
|
|
|
175
170
|
assert(!this._socket, "init already called!");
|
|
176
171
|
this._install_socket(socket);
|
|
@@ -186,12 +181,13 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
186
181
|
if (this._aborted) {
|
|
187
182
|
errorLog("Internal Er!ror: _abortWithError already called! Should not happen here");
|
|
188
183
|
// already called
|
|
189
|
-
|
|
184
|
+
callback(new Error(statusCode.name));
|
|
185
|
+
return;
|
|
190
186
|
}
|
|
191
187
|
this._aborted = 1;
|
|
192
188
|
|
|
193
189
|
this._socket?.setTimeout(0);
|
|
194
|
-
const err = new Error(extraErrorDescription
|
|
190
|
+
const err = new Error(`${extraErrorDescription} StatusCode = ${statusCode.name}`);
|
|
195
191
|
this._theCloseError = err;
|
|
196
192
|
setTimeout(() => {
|
|
197
193
|
// send the error message and close the connection
|
|
@@ -235,8 +231,8 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
235
231
|
/* c8 ignore next*/
|
|
236
232
|
if (doDebug) {
|
|
237
233
|
verify_message_chunk(messageChunk);
|
|
238
|
-
debugLog(
|
|
239
|
-
debugLog(
|
|
234
|
+
debugLog(`server send: ${chalk.yellow("ACK")}`);
|
|
235
|
+
debugLog(`server send: ${hexDump(messageChunk)}`);
|
|
240
236
|
debugLog("acknowledgeMessage=", acknowledgeMessage);
|
|
241
237
|
}
|
|
242
238
|
|
|
@@ -252,8 +248,13 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
252
248
|
if (err) {
|
|
253
249
|
callback(err);
|
|
254
250
|
} else {
|
|
251
|
+
// c8 ignore next
|
|
252
|
+
if (!data) {
|
|
253
|
+
callback(new Error("No data received"));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
255
256
|
// pass to next stage handle the HEL message
|
|
256
|
-
this._on_HEL_message(data
|
|
257
|
+
this._on_HEL_message(data, callback);
|
|
257
258
|
}
|
|
258
259
|
});
|
|
259
260
|
}
|
|
@@ -268,14 +269,18 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
268
269
|
|
|
269
270
|
/* c8 ignore next*/
|
|
270
271
|
if (doDebug) {
|
|
271
|
-
debugLog(
|
|
272
|
-
debugLog(
|
|
272
|
+
debugLog(`SERVER received ${chalk.yellow(msgType)}`);
|
|
273
|
+
debugLog(`SERVER received ${hexDump(data)}`);
|
|
273
274
|
}
|
|
274
275
|
|
|
275
276
|
if (msgType === "HEL") {
|
|
276
277
|
try {
|
|
277
278
|
assert(data.length >= 24);
|
|
278
|
-
const
|
|
279
|
+
const decoded = decodeMessage(stream, HelloMessage);
|
|
280
|
+
if (!(decoded instanceof HelloMessage)) {
|
|
281
|
+
throw new Error("expecting a HelloMessage");
|
|
282
|
+
}
|
|
283
|
+
const helloMessage = decoded;
|
|
279
284
|
|
|
280
285
|
// OPCUA Spec 1.03 part 6 - page 41
|
|
281
286
|
// The Server shall always accept versions greater than what it supports.
|
|
@@ -292,11 +297,12 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
292
297
|
if (helloMessage.protocolVersion === 0xdeadbeef || helloMessage.protocolVersion < this.protocolVersion) {
|
|
293
298
|
// Note: 0xDEADBEEF is our special version number to simulate BadProtocolVersionUnsupported in tests
|
|
294
299
|
// invalid protocol version requested by client
|
|
295
|
-
|
|
300
|
+
this._abortWithError(
|
|
296
301
|
StatusCodes.BadProtocolVersionUnsupported,
|
|
297
|
-
|
|
302
|
+
`Protocol Version Error${this.protocolVersion}`,
|
|
298
303
|
callback
|
|
299
304
|
);
|
|
305
|
+
return;
|
|
300
306
|
}
|
|
301
307
|
|
|
302
308
|
// OPCUA Spec 1.04 part 6 - page 45
|
|
@@ -305,11 +311,12 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
305
311
|
// pieces (called ‘MessageChunks’) that are smaller than the buffer size allowed by the
|
|
306
312
|
// TransportProtocol. UASC requires a TransportProtocol buffer size that is at least 8 192 bytes
|
|
307
313
|
if (helloMessage.receiveBufferSize < minimumBufferSize || helloMessage.sendBufferSize < minimumBufferSize) {
|
|
308
|
-
|
|
314
|
+
this._abortWithError(
|
|
309
315
|
StatusCodes.BadConnectionRejected,
|
|
310
|
-
|
|
316
|
+
`Buffer size too small (should be at least ${minimumBufferSize}`,
|
|
311
317
|
callback
|
|
312
318
|
);
|
|
319
|
+
return;
|
|
313
320
|
}
|
|
314
321
|
// the helloMessage shall only be received once.
|
|
315
322
|
this._helloReceived = true;
|
|
@@ -317,16 +324,13 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
317
324
|
callback(); // no Error
|
|
318
325
|
} catch (err) {
|
|
319
326
|
// connection rejected because of malformed message
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
types.isNativeError(err) ? err.message : "",
|
|
323
|
-
callback
|
|
324
|
-
);
|
|
327
|
+
this._abortWithError(StatusCodes.BadConnectionRejected, err instanceof Error ? err.message : "", callback);
|
|
328
|
+
return;
|
|
325
329
|
}
|
|
326
330
|
} else {
|
|
327
331
|
// invalid packet , expecting HEL
|
|
328
332
|
/* c8 ignore next*/
|
|
329
|
-
doDebug && debugLog(chalk.red("BadCommunicationError ")
|
|
333
|
+
doDebug && debugLog(`${chalk.red("BadCommunicationError ")}Expecting 'HEL' message to initiate communication`);
|
|
330
334
|
this._abortWithError(StatusCodes.BadCommunicationError, "Expecting 'HEL' message to initiate communication", callback);
|
|
331
335
|
}
|
|
332
336
|
}
|