node-opcua-transport 2.99.0 → 2.102.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/client_tcp_transport.d.ts +4 -9
- package/dist/source/client_tcp_transport.js +38 -71
- package/dist/source/client_tcp_transport.js.map +1 -1
- package/dist/source/server_tcp_transport.d.ts +3 -15
- package/dist/source/server_tcp_transport.js +40 -41
- package/dist/source/server_tcp_transport.js.map +1 -1
- package/dist/source/tcp_transport.d.ts +45 -28
- package/dist/source/tcp_transport.js +160 -110
- package/dist/source/tcp_transport.js.map +1 -1
- package/dist/test_helpers/ITransportPair.d.ts +7 -0
- package/dist/test_helpers/ITransportPair.js +3 -0
- package/dist/test_helpers/ITransportPair.js.map +1 -0
- package/dist/test_helpers/fake_server.d.ts +2 -0
- package/dist/test_helpers/fake_server.js +3 -0
- package/dist/test_helpers/fake_server.js.map +1 -1
- package/dist/test_helpers/half_com_channel.d.ts +17 -10
- package/dist/test_helpers/half_com_channel.js +63 -4
- package/dist/test_helpers/half_com_channel.js.map +1 -1
- package/dist/test_helpers/index.d.ts +2 -2
- package/dist/test_helpers/index.js +2 -2
- package/dist/test_helpers/index.js.map +1 -1
- package/dist/test_helpers/{direct_transport.d.ts → transport_pair_direct.d.ts} +2 -6
- package/dist/test_helpers/{direct_transport.js → transport_pair_direct.js} +11 -18
- package/dist/test_helpers/transport_pair_direct.js.map +1 -0
- package/dist/test_helpers/transport_pair_socket.d.ts +14 -0
- package/dist/test_helpers/transport_pair_socket.js +33 -0
- package/dist/test_helpers/transport_pair_socket.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/source/client_tcp_transport.ts +56 -89
- package/source/server_tcp_transport.ts +48 -50
- package/source/tcp_transport.ts +226 -157
- package/dist/test_helpers/direct_transport.js.map +0 -1
- package/dist/test_helpers/socket_transport.d.ts +0 -10
- package/dist/test_helpers/socket_transport.js +0 -31
- package/dist/test_helpers/socket_transport.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-opcua-transport",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.102.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",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"node-opcua-utils": "2.98.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
+
"node-opcua-leak-detector": "2.99.0",
|
|
29
30
|
"should": "^13.2.3",
|
|
30
31
|
"sinon": "^15.0.3"
|
|
31
32
|
},
|
|
@@ -44,7 +45,7 @@
|
|
|
44
45
|
"internet of things"
|
|
45
46
|
],
|
|
46
47
|
"homepage": "http://node-opcua.github.io/",
|
|
47
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "07dcdd8e8c7f2b55544c6e23023093e35674829c",
|
|
48
49
|
"files": [
|
|
49
50
|
"dist",
|
|
50
51
|
"source"
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @module node-opcua-transport
|
|
3
3
|
*/
|
|
4
4
|
import * as os from "os";
|
|
5
|
-
import { createConnection
|
|
5
|
+
import { createConnection } from "net";
|
|
6
|
+
import { types } from "util";
|
|
6
7
|
import * as chalk from "chalk";
|
|
7
8
|
|
|
8
9
|
import { assert } from "node-opcua-assert";
|
|
@@ -11,7 +12,7 @@ import { readMessageHeader } from "node-opcua-chunkmanager";
|
|
|
11
12
|
import { ErrorCallback } from "node-opcua-status-code";
|
|
12
13
|
|
|
13
14
|
import * as debug from "node-opcua-debug";
|
|
14
|
-
import { getFakeTransport, TCP_transport } from "./tcp_transport";
|
|
15
|
+
import { getFakeTransport, ISocketLike, TCP_transport } from "./tcp_transport";
|
|
15
16
|
import { decodeMessage, packTcpMessage, parseEndpointUrl } from "./tools";
|
|
16
17
|
|
|
17
18
|
import { AcknowledgeMessage } from "./AcknowledgeMessage";
|
|
@@ -25,31 +26,27 @@ const warningLog = debug.make_warningLog(__filename);
|
|
|
25
26
|
const errorLog = debug.make_errorLog(__filename);
|
|
26
27
|
const gHostname = os.hostname();
|
|
27
28
|
|
|
28
|
-
function createClientSocket(endpointUrl: string):
|
|
29
|
+
function createClientSocket(endpointUrl: string, timeout: number): ISocketLike {
|
|
29
30
|
// create a socket based on Url
|
|
30
31
|
const ep = parseEndpointUrl(endpointUrl);
|
|
31
32
|
const port = parseInt(ep.port!, 10);
|
|
32
33
|
const hostname = ep.hostname!;
|
|
33
|
-
|
|
34
|
+
|
|
35
|
+
let socket: ISocketLike;
|
|
34
36
|
switch (ep.protocol) {
|
|
35
37
|
case "opc.tcp:":
|
|
36
|
-
socket = createConnection({ host: hostname, port })
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// Setting true for noDelay will immediately fire off data each time socket.write() is called.
|
|
41
|
-
socket.setNoDelay(true);
|
|
42
|
-
|
|
38
|
+
socket = createConnection({ host: hostname, port, timeout }, () => {
|
|
39
|
+
doDebug && debugLog(`connected to server! ${hostname}:${port} timeout:${timeout} `);
|
|
40
|
+
});
|
|
43
41
|
return socket;
|
|
44
42
|
case "fake:":
|
|
45
|
-
socket = getFakeTransport();
|
|
46
43
|
assert(ep.protocol === "fake:", " Unsupported transport protocol");
|
|
47
|
-
|
|
44
|
+
socket = getFakeTransport();
|
|
48
45
|
return socket;
|
|
49
46
|
|
|
50
47
|
case "websocket:":
|
|
51
48
|
case "http:":
|
|
52
|
-
case "https:
|
|
49
|
+
case "https:":
|
|
53
50
|
default: {
|
|
54
51
|
const msg = "[NODE-OPCUA-E05] this transport protocol is not supported :" + ep.protocol;
|
|
55
52
|
errorLog(msg);
|
|
@@ -59,19 +56,16 @@ function createClientSocket(endpointUrl: string): Socket {
|
|
|
59
56
|
}
|
|
60
57
|
export interface ClientTCP_transport {
|
|
61
58
|
on(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
|
|
62
|
-
on(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
|
|
63
59
|
on(eventName: "close", eventHandler: (err: Error | null) => void): this;
|
|
64
60
|
on(eventName: "connection_break", eventHandler: () => void): this;
|
|
65
61
|
on(eventName: "connect", eventHandler: () => void): this;
|
|
66
62
|
|
|
67
63
|
once(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
|
|
68
|
-
once(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
|
|
69
64
|
once(eventName: "close", eventHandler: (err: Error | null) => void): this;
|
|
70
65
|
once(eventName: "connection_break", eventHandler: () => void): this;
|
|
71
66
|
once(eventName: "connect", eventHandler: () => void): this;
|
|
72
67
|
|
|
73
68
|
emit(eventName: "chunk", messageChunk: Buffer): boolean;
|
|
74
|
-
emit(eventName: "socket_closed", err?: Error | null): boolean;
|
|
75
69
|
emit(eventName: "close", err?: Error | null): boolean;
|
|
76
70
|
emit(eventName: "connection_break"): boolean;
|
|
77
71
|
emit(eventName: "connect"): boolean;
|
|
@@ -99,7 +93,7 @@ export interface TransportSettingsOptions {
|
|
|
99
93
|
*
|
|
100
94
|
* transport.timeout = 10000;
|
|
101
95
|
*
|
|
102
|
-
* transport.connect(function(err)) {
|
|
96
|
+
* transport.connect(function (err)) {
|
|
103
97
|
* if (err) {
|
|
104
98
|
* // cannot connect
|
|
105
99
|
* } else {
|
|
@@ -109,16 +103,16 @@ export interface TransportSettingsOptions {
|
|
|
109
103
|
* });
|
|
110
104
|
* ....
|
|
111
105
|
*
|
|
112
|
-
* transport.write(message_chunk,'F');
|
|
106
|
+
* transport.write(message_chunk, 'F');
|
|
113
107
|
*
|
|
114
108
|
* ....
|
|
115
109
|
*
|
|
116
|
-
* transport.on("chunk",function(message_chunk) {
|
|
110
|
+
* transport.on("chunk", function (message_chunk) {
|
|
117
111
|
* // do something with chunk from server...
|
|
118
112
|
* });
|
|
119
113
|
*
|
|
120
114
|
*
|
|
121
|
-
*
|
|
115
|
+
* ```
|
|
122
116
|
*
|
|
123
117
|
*
|
|
124
118
|
*/
|
|
@@ -133,7 +127,6 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
133
127
|
public numberOfRetry: number;
|
|
134
128
|
public parameters?: AcknowledgeMessage;
|
|
135
129
|
|
|
136
|
-
private connected: boolean;
|
|
137
130
|
private _counter: number;
|
|
138
131
|
private _helloSettings: {
|
|
139
132
|
maxChunkCount: number;
|
|
@@ -143,7 +136,6 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
143
136
|
};
|
|
144
137
|
constructor(transportSettings?: TransportSettingsOptions) {
|
|
145
138
|
super();
|
|
146
|
-
this.connected = false;
|
|
147
139
|
this.endpointUrl = "";
|
|
148
140
|
this.serverUri = "";
|
|
149
141
|
this._counter = 0;
|
|
@@ -169,9 +161,8 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
169
161
|
|
|
170
162
|
public dispose(): void {
|
|
171
163
|
/* istanbul ignore next */
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
164
|
+
doDebug && debugLog(" ClientTCP_transport disposed");
|
|
165
|
+
|
|
175
166
|
super.dispose();
|
|
176
167
|
}
|
|
177
168
|
|
|
@@ -185,24 +176,25 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
185
176
|
|
|
186
177
|
this.serverUri = "urn:" + gHostname + ":Sample";
|
|
187
178
|
/* istanbul ignore next */
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
179
|
+
doDebug && debugLog(chalk.cyan("ClientTCP_transport#connect(endpointUrl = " + endpointUrl + ")"));
|
|
180
|
+
|
|
181
|
+
let socket: ISocketLike | null = null;
|
|
191
182
|
try {
|
|
192
|
-
|
|
183
|
+
socket = createClientSocket(endpointUrl, this.timeout);
|
|
193
184
|
} catch (err) {
|
|
194
185
|
/* istanbul ignore next */
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
186
|
+
doDebug && debugLog("CreateClientSocket has failed");
|
|
187
|
+
|
|
198
188
|
return callback(err as Error);
|
|
199
189
|
}
|
|
200
190
|
|
|
191
|
+
/**
|
|
192
|
+
*
|
|
193
|
+
*/
|
|
201
194
|
const _on_socket_error_after_connection = (err: Error) => {
|
|
202
195
|
/* istanbul ignore next */
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
196
|
+
doDebug && debugLog(" _on_socket_error_after_connection ClientTCP_transport Socket Error", err.message);
|
|
197
|
+
|
|
206
198
|
// EPIPE : EPIPE (Broken pipe): A write on a pipe, socket, or FIFO for which there is no process to read the
|
|
207
199
|
// data. Commonly encountered at the net and http layers, indicative that the remote side of the stream
|
|
208
200
|
// being written to has been closed.
|
|
@@ -210,7 +202,11 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
210
202
|
// ECONNRESET (Connection reset by peer): A connection was forcibly closed by a peer. This normally results
|
|
211
203
|
// from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered
|
|
212
204
|
// via the http and net module
|
|
213
|
-
|
|
205
|
+
|
|
206
|
+
// socket termination could happen:
|
|
207
|
+
// * when the socket times out (lost of connection, network outage, etc...)
|
|
208
|
+
// * or, when the server abruptly disconnects the socket ( in case of invalid communication for instance)
|
|
209
|
+
if (err.message.match(/ECONNRESET|EPIPE|premature socket termination/)) {
|
|
214
210
|
/**
|
|
215
211
|
* @event connection_break
|
|
216
212
|
*
|
|
@@ -221,11 +217,10 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
221
217
|
|
|
222
218
|
const _on_socket_connect = () => {
|
|
223
219
|
/* istanbul ignore next */
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
220
|
+
doDebug && debugLog("entering _on_socket_connect");
|
|
221
|
+
|
|
227
222
|
_remove_connect_listeners();
|
|
228
|
-
this._perform_HEL_ACK_transaction((err
|
|
223
|
+
this._perform_HEL_ACK_transaction((err) => {
|
|
229
224
|
if (!err) {
|
|
230
225
|
/* istanbul ignore next */
|
|
231
226
|
if (!this._socket) {
|
|
@@ -234,7 +229,6 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
234
229
|
// install error handler to detect connection break
|
|
235
230
|
this._socket.on("error", _on_socket_error_after_connection);
|
|
236
231
|
|
|
237
|
-
this.connected = true;
|
|
238
232
|
/**
|
|
239
233
|
* notify the observers that the transport is connected (the socket is connected and the the HEL/ACK
|
|
240
234
|
* transaction has been done)
|
|
@@ -252,22 +246,16 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
252
246
|
const _on_socket_error_for_connect = (err: Error) => {
|
|
253
247
|
// this handler will catch attempt to connect to an inaccessible address.
|
|
254
248
|
/* istanbul ignore next */
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
assert(err instanceof Error);
|
|
249
|
+
doDebug && debugLog(chalk.cyan("ClientTCP_transport#connect - _on_socket_error_for_connect"), err.message);
|
|
250
|
+
assert(types.isNativeError(err));
|
|
259
251
|
_remove_connect_listeners();
|
|
260
252
|
callback(err);
|
|
261
253
|
};
|
|
262
254
|
|
|
263
|
-
const _on_socket_end_for_connect = (
|
|
255
|
+
const _on_socket_end_for_connect = () => {
|
|
264
256
|
/* istanbul ignore next */
|
|
265
|
-
|
|
266
|
-
debugLog(
|
|
267
|
-
chalk.cyan("ClientTCP_transport#connect -> _on_socket_end_for_connect Socket has been closed by server"),
|
|
268
|
-
err
|
|
269
|
-
);
|
|
270
|
-
}
|
|
257
|
+
doDebug &&
|
|
258
|
+
debugLog(chalk.cyan("ClientTCP_transport#connect -> _on_socket_end_for_connect Socket has been closed by server"));
|
|
271
259
|
};
|
|
272
260
|
|
|
273
261
|
const _remove_connect_listeners = () => {
|
|
@@ -279,21 +267,11 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
279
267
|
this._socket.removeListener("end", _on_socket_end_for_connect);
|
|
280
268
|
};
|
|
281
269
|
|
|
282
|
-
this.
|
|
283
|
-
this._socket.once("end", _on_socket_end_for_connect);
|
|
284
|
-
this._socket.once("connect", _on_socket_connect);
|
|
270
|
+
this._install_socket(socket);
|
|
285
271
|
|
|
286
|
-
this.
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
protected on_socket_ended(err: Error | null): void {
|
|
290
|
-
debugLog("on_socket_ended", this.name, err ? err.message : "");
|
|
291
|
-
if (this.connected) {
|
|
292
|
-
super.on_socket_ended(err);
|
|
293
|
-
}
|
|
294
|
-
// if (this._socket) {
|
|
295
|
-
// this._socket.removeAllListeners();
|
|
296
|
-
// }
|
|
272
|
+
this._socket!.once("error", _on_socket_error_for_connect);
|
|
273
|
+
this._socket!.once("end", _on_socket_end_for_connect);
|
|
274
|
+
this._socket!.once("connect", _on_socket_connect);
|
|
297
275
|
}
|
|
298
276
|
|
|
299
277
|
private _handle_ACK_response(messageChunk: Buffer, callback: ErrorCallback) {
|
|
@@ -317,9 +295,8 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
317
295
|
err = new Error("ACK: ERR received " + response.statusCode.toString() + " : " + response.reason);
|
|
318
296
|
(err as any).statusCode = response.statusCode;
|
|
319
297
|
// istanbul ignore next
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
298
|
+
doTraceHelloAck && warningLog("receiving ERR instead of Ack", response.toString());
|
|
299
|
+
|
|
323
300
|
callback(err);
|
|
324
301
|
} else {
|
|
325
302
|
responseClass = AcknowledgeMessage;
|
|
@@ -330,9 +307,7 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
330
307
|
this.setLimits(response as AcknowledgeMessage);
|
|
331
308
|
|
|
332
309
|
// istanbul ignore next
|
|
333
|
-
|
|
334
|
-
warningLog("receiving Ack\n", response.toString());
|
|
335
|
-
}
|
|
310
|
+
doTraceHelloAck && warningLog("receiving Ack\n", response.toString());
|
|
336
311
|
|
|
337
312
|
callback();
|
|
338
313
|
}
|
|
@@ -340,9 +315,8 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
340
315
|
|
|
341
316
|
private _send_HELLO_request() {
|
|
342
317
|
/* istanbul ignore next */
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
318
|
+
doDebug && debugLog("entering _send_HELLO_request");
|
|
319
|
+
|
|
346
320
|
assert(this._socket);
|
|
347
321
|
assert(isFinite(this.protocolVersion));
|
|
348
322
|
assert(this.endpointUrl.length > 0, " expecting a valid endpoint url");
|
|
@@ -360,9 +334,7 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
360
334
|
sendBufferSize
|
|
361
335
|
});
|
|
362
336
|
// istanbul ignore next
|
|
363
|
-
|
|
364
|
-
warningLog(`sending Hello\n ${helloMessage.toString()}`);
|
|
365
|
-
}
|
|
337
|
+
doTraceHelloAck && warningLog(`sending Hello\n ${helloMessage.toString()} `);
|
|
366
338
|
|
|
367
339
|
const messageChunk = packTcpMessage("HEL", helloMessage);
|
|
368
340
|
this._write_chunk(messageChunk);
|
|
@@ -370,9 +342,7 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
370
342
|
|
|
371
343
|
private _on_ACK_response(externalCallback: ErrorCallback, err: Error | null, data?: Buffer) {
|
|
372
344
|
/* istanbul ignore next */
|
|
373
|
-
|
|
374
|
-
debugLog("entering _on_ACK_response");
|
|
375
|
-
}
|
|
345
|
+
doDebug && debugLog("entering _on_ACK_response");
|
|
376
346
|
|
|
377
347
|
assert(typeof externalCallback === "function");
|
|
378
348
|
assert(this._counter === 0, "Ack response should only be received once !");
|
|
@@ -382,7 +352,6 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
382
352
|
externalCallback(err || new Error("no data"));
|
|
383
353
|
if (this._socket) {
|
|
384
354
|
this._socket.end();
|
|
385
|
-
// Xx this._socket.removeAllListeners();
|
|
386
355
|
}
|
|
387
356
|
} else {
|
|
388
357
|
this._handle_ACK_response(data, externalCallback);
|
|
@@ -398,14 +367,12 @@ export class ClientTCP_transport extends TCP_transport {
|
|
|
398
367
|
assert(typeof callback === "function");
|
|
399
368
|
this._counter = 0;
|
|
400
369
|
/* istanbul ignore next */
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
370
|
+
doDebug && debugLog("entering _perform_HEL_ACK_transaction");
|
|
371
|
+
|
|
404
372
|
this._install_one_time_message_receiver((err: Error | null, data?: Buffer) => {
|
|
405
373
|
/* istanbul ignore next */
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
374
|
+
doDebug && debugLog("before _on_ACK_response ", err ? err.message : "");
|
|
375
|
+
|
|
409
376
|
this._on_ACK_response(callback, err, data);
|
|
410
377
|
});
|
|
411
378
|
this._send_HELLO_request();
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// tslint:disable:class-name
|
|
5
5
|
// system
|
|
6
6
|
import { Socket } from "net";
|
|
7
|
+
import { types } from "util";
|
|
7
8
|
import * as chalk from "chalk";
|
|
8
9
|
import { assert } from "node-opcua-assert";
|
|
9
10
|
|
|
@@ -17,16 +18,15 @@ import { ErrorCallback } from "node-opcua-status-code";
|
|
|
17
18
|
// this package requires
|
|
18
19
|
import { AcknowledgeMessage } from "./AcknowledgeMessage";
|
|
19
20
|
import { HelloMessage } from "./HelloMessage";
|
|
20
|
-
import { TCP_transport } from "./tcp_transport";
|
|
21
|
+
import { ISocketLike, TCP_transport } from "./tcp_transport";
|
|
21
22
|
import { decodeMessage, packTcpMessage } from "./tools";
|
|
22
23
|
import { doTraceHelloAck } from "./utils";
|
|
23
24
|
|
|
24
25
|
const hexDump = debug.hexDump;
|
|
25
|
-
const debugLog = debug.make_debugLog(
|
|
26
|
-
const errorLog = debug.make_errorLog(
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
type CallbackFunc = (err: null | Error) => void;
|
|
26
|
+
const debugLog = debug.make_debugLog("TRANSPORT");
|
|
27
|
+
const errorLog = debug.make_errorLog("TRANSPORT");
|
|
28
|
+
const warningLog = debug.make_warningLog("TRANSPORT");
|
|
29
|
+
const doDebug = debug.checkDebugFlag("TRANSPORT");
|
|
30
30
|
|
|
31
31
|
function clamp_value(value: number, minVal: number, maxVal: number): number {
|
|
32
32
|
assert(minVal < maxVal);
|
|
@@ -45,12 +45,6 @@ function clamp_value(value: number, minVal: number, maxVal: number): number {
|
|
|
45
45
|
|
|
46
46
|
const minimumBufferSize = 8192;
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
* @class ServerTCP_transport
|
|
50
|
-
* @extends TCP_transport
|
|
51
|
-
* @constructor
|
|
52
|
-
*
|
|
53
|
-
*/
|
|
54
48
|
export class ServerTCP_transport extends TCP_transport {
|
|
55
49
|
public static throttleTime = 1000;
|
|
56
50
|
|
|
@@ -68,6 +62,13 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
68
62
|
this.receiveBufferSize = 4 * 1024;
|
|
69
63
|
}
|
|
70
64
|
|
|
65
|
+
public toString() {
|
|
66
|
+
let str = super.toString();
|
|
67
|
+
str += "helloReceived...... = " + this._helloReceived + "\n";
|
|
68
|
+
str += "aborted............ = " + this._aborted + "\n";
|
|
69
|
+
return str;
|
|
70
|
+
}
|
|
71
|
+
|
|
71
72
|
protected _write_chunk(messageChunk: Buffer): void {
|
|
72
73
|
// istanbul ignore next
|
|
73
74
|
if (this.sendBufferSize > 0 && messageChunk.length > this.sendBufferSize) {
|
|
@@ -78,9 +79,9 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
78
79
|
this.sendBufferSize
|
|
79
80
|
);
|
|
80
81
|
}
|
|
81
|
-
|
|
82
82
|
super._write_chunk(messageChunk);
|
|
83
83
|
}
|
|
84
|
+
|
|
84
85
|
/**
|
|
85
86
|
* Initialize the server transport.
|
|
86
87
|
*
|
|
@@ -97,10 +98,11 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
97
98
|
*
|
|
98
99
|
*
|
|
99
100
|
*/
|
|
100
|
-
public init(socket:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
public init(socket: ISocketLike, callback: ErrorCallback): void {
|
|
102
|
+
assert(socket, "missing called!");
|
|
103
|
+
// istanbul ignore next
|
|
104
|
+
debugLog && debugLog(chalk.cyan("init socket"));
|
|
105
|
+
|
|
104
106
|
assert(!this._socket, "init already called!");
|
|
105
107
|
assert(typeof callback === "function", "expecting a valid callback ");
|
|
106
108
|
|
|
@@ -108,30 +110,28 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
108
110
|
this._install_HEL_message_receiver(callback);
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
public abortWithError(statusCode: StatusCode, extraErrorDescription: string, callback: ErrorCallback): void {
|
|
112
|
-
return this._abortWithError(statusCode, extraErrorDescription, callback);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
113
|
private _abortWithError(statusCode: StatusCode, extraErrorDescription: string, callback: ErrorCallback): void {
|
|
116
114
|
// When a fatal error occurs, the Server shall send an Error Message to the Client and
|
|
117
115
|
// closes the TransportConnection gracefully.
|
|
118
|
-
doDebug && debugLog(chalk.cyan("_abortWithError"));
|
|
116
|
+
doDebug && debugLog(this.name, chalk.cyan("_abortWithError", statusCode.toString(), extraErrorDescription));
|
|
119
117
|
|
|
120
118
|
/* istanbul ignore next */
|
|
121
119
|
if (this._aborted) {
|
|
120
|
+
errorLog("Internal Er!ror: _abortWithError already called! Should not happen here");
|
|
122
121
|
// already called
|
|
123
122
|
return callback(new Error(statusCode.name));
|
|
124
123
|
}
|
|
125
124
|
this._aborted = 1;
|
|
126
125
|
|
|
126
|
+
this._socket?.setTimeout(0);
|
|
127
|
+
const err = new Error(extraErrorDescription + " StatusCode = " + statusCode.name);
|
|
128
|
+
this._theCloseError = err;
|
|
127
129
|
setTimeout(() => {
|
|
128
130
|
// send the error message and close the connection
|
|
129
131
|
this.sendErrorMessage(statusCode, statusCode.description);
|
|
130
|
-
|
|
131
|
-
this.
|
|
132
|
-
|
|
133
|
-
callback(new Error(extraErrorDescription + " StatusCode = " + statusCode.name));
|
|
134
|
-
});
|
|
132
|
+
this.prematureTerminate(err, statusCode);
|
|
133
|
+
this._emitClose(err);
|
|
134
|
+
callback(err);
|
|
135
135
|
}, ServerTCP_transport.throttleTime);
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -179,11 +179,12 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
179
179
|
|
|
180
180
|
// istanbul ignore next
|
|
181
181
|
if (doTraceHelloAck) {
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
warningLog(`received Hello \n${helloMessage.toString()}`);
|
|
183
|
+
warningLog("Client accepts only message of size => ", this.maxMessageSize);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
// istanbul ignore next
|
|
187
|
+
doDebug && debugLog("Client accepts only message of size => ", this.maxMessageSize);
|
|
187
188
|
|
|
188
189
|
const acknowledgeMessage = new AcknowledgeMessage({
|
|
189
190
|
maxChunkCount: this.maxChunkCount,
|
|
@@ -194,9 +195,7 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
194
195
|
});
|
|
195
196
|
|
|
196
197
|
// istanbul ignore next
|
|
197
|
-
|
|
198
|
-
console.log(`sending Ack \n${acknowledgeMessage.toString()}`);
|
|
199
|
-
}
|
|
198
|
+
doTraceHelloAck && warningLog(`sending Ack \n${acknowledgeMessage.toString()}`);
|
|
200
199
|
|
|
201
200
|
const messageChunk = packTcpMessage("ACK", acknowledgeMessage);
|
|
202
201
|
|
|
@@ -213,12 +212,12 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
213
212
|
}
|
|
214
213
|
|
|
215
214
|
private _install_HEL_message_receiver(callback: ErrorCallback): void {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
215
|
+
// istanbul ignore next
|
|
216
|
+
doDebug && debugLog(chalk.cyan("_install_HEL_message_receiver "));
|
|
217
|
+
|
|
219
218
|
this._install_one_time_message_receiver((err?: Error | null, data?: Buffer) => {
|
|
220
219
|
if (err) {
|
|
221
|
-
|
|
220
|
+
callback(err);
|
|
222
221
|
} else {
|
|
223
222
|
// handle the HEL message
|
|
224
223
|
this._on_HEL_message(data!, callback);
|
|
@@ -227,9 +226,9 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
227
226
|
}
|
|
228
227
|
|
|
229
228
|
private _on_HEL_message(data: Buffer, callback: ErrorCallback): void {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
// istanbul ignore next
|
|
230
|
+
doDebug && debugLog(chalk.cyan("_on_HEL_message"));
|
|
231
|
+
|
|
233
232
|
assert(!this._helloReceived);
|
|
234
233
|
const stream = new BinaryStream(data);
|
|
235
234
|
const msgType = data.subarray(0, 3).toString("utf-8");
|
|
@@ -244,16 +243,17 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
244
243
|
try {
|
|
245
244
|
assert(data.length >= 24);
|
|
246
245
|
const helloMessage = decodeMessage(stream, HelloMessage) as HelloMessage;
|
|
247
|
-
assert(isFinite(this.protocolVersion));
|
|
248
246
|
|
|
249
247
|
// OPCUA Spec 1.03 part 6 - page 41
|
|
250
248
|
// The Server shall always accept versions greater than what it supports.
|
|
251
249
|
if (helloMessage.protocolVersion !== this.protocolVersion) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
`
|
|
256
|
-
|
|
250
|
+
// istanbul ignore next
|
|
251
|
+
doDebug &&
|
|
252
|
+
debugLog(
|
|
253
|
+
`warning ! client sent helloMessage.protocolVersion = ` +
|
|
254
|
+
` 0x${helloMessage.protocolVersion.toString(16)} ` +
|
|
255
|
+
`whereas server protocolVersion is 0x${this.protocolVersion.toString(16)}`
|
|
256
|
+
);
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
if (helloMessage.protocolVersion === 0xdeadbeef || helloMessage.protocolVersion < this.protocolVersion) {
|
|
@@ -283,15 +283,13 @@ export class ServerTCP_transport extends TCP_transport {
|
|
|
283
283
|
this._send_ACK_response(helloMessage);
|
|
284
284
|
} catch (err) {
|
|
285
285
|
// connection rejected because of malformed message
|
|
286
|
-
return this._abortWithError(StatusCodes.BadConnectionRejected, err
|
|
286
|
+
return this._abortWithError(StatusCodes.BadConnectionRejected, types.isNativeError(err) ? err.message : "", callback);
|
|
287
287
|
}
|
|
288
288
|
callback(); // no Error
|
|
289
289
|
} else {
|
|
290
290
|
// invalid packet , expecting HEL
|
|
291
291
|
/* istanbul ignore next*/
|
|
292
|
-
|
|
293
|
-
debugLog(chalk.red("BadCommunicationError ") + "Expecting 'HEL' message to initiate communication");
|
|
294
|
-
}
|
|
292
|
+
doDebug && debugLog(chalk.red("BadCommunicationError ") + "Expecting 'HEL' message to initiate communication");
|
|
295
293
|
this._abortWithError(StatusCodes.BadCommunicationError, "Expecting 'HEL' message to initiate communication", callback);
|
|
296
294
|
}
|
|
297
295
|
}
|