node-opcua-transport 2.55.0 → 2.59.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 (43) hide show
  1. package/.mocharc.yml +10 -10
  2. package/LICENSE +20 -20
  3. package/dist/source/AcknowledgeMessage.js +5 -5
  4. package/dist/source/AcknowledgeMessage.js.map +1 -1
  5. package/dist/source/TCPErrorMessage.js.map +1 -1
  6. package/dist/source/client_tcp_transport.d.ts +3 -3
  7. package/dist/source/client_tcp_transport.js +2 -2
  8. package/dist/source/client_tcp_transport.js.map +1 -1
  9. package/dist/source/server_tcp_transport.d.ts +3 -0
  10. package/dist/source/server_tcp_transport.js +2 -7
  11. package/dist/source/server_tcp_transport.js.map +1 -1
  12. package/dist/source/tcp_transport.js +2 -2
  13. package/dist/source/tools.d.ts +1 -1
  14. package/dist/source/tools.js +4 -4
  15. package/dist/source/tools.js.map +1 -1
  16. package/dist/source/utils.js +1 -1
  17. package/dist/source/utils.js.map +1 -1
  18. package/dist/test-fixtures/fixture_full_tcp_packets.js +8 -8
  19. package/dist/test-fixtures/fixture_full_tcp_packets.js.map +1 -1
  20. package/dist/test_helpers/direct_transport.d.ts +1 -1
  21. package/dist/test_helpers/direct_transport.js.map +1 -1
  22. package/dist/test_helpers/fake_server.d.ts +2 -2
  23. package/dist/test_helpers/fake_server.js +1 -1
  24. package/dist/test_helpers/fake_server.js.map +1 -1
  25. package/dist/test_helpers/half_com_channel.js +2 -4
  26. package/dist/test_helpers/half_com_channel.js.map +1 -1
  27. package/dist/test_helpers/socket_transport.js +1 -0
  28. package/dist/test_helpers/socket_transport.js.map +1 -1
  29. package/package.json +11 -9
  30. package/source/AcknowledgeMessage.ts +7 -9
  31. package/source/TCPErrorMessage.ts +58 -57
  32. package/source/client_tcp_transport.ts +366 -366
  33. package/source/index.ts +11 -11
  34. package/source/message_builder_base.ts +2 -2
  35. package/source/server_tcp_transport.ts +11 -12
  36. package/source/tcp_transport.ts +455 -455
  37. package/source/tools.ts +4 -4
  38. package/source/utils.ts +1 -1
  39. package/test_helpers/direct_transport.ts +2 -2
  40. package/test_helpers/fake_server.ts +69 -71
  41. package/test_helpers/half_com_channel.ts +2 -5
  42. package/test_helpers/index.ts +4 -4
  43. package/test_helpers/socket_transport.ts +33 -34
@@ -1,366 +1,366 @@
1
- /**
2
- * @module node-opcua-transport
3
- */
4
- // tslint:disable:class-name
5
- // system
6
- import * as os from "os";
7
- import * as chalk from "chalk";
8
-
9
- import { createConnection, Socket } from "net";
10
- import { assert } from "node-opcua-assert";
11
- import { BinaryStream } from "node-opcua-binary-stream";
12
- import { readMessageHeader } from "node-opcua-chunkmanager";
13
- import { ErrorCallback } from "node-opcua-status-code";
14
-
15
- import { getFakeTransport, TCP_transport } from "./tcp_transport";
16
- import { decodeMessage, packTcpMessage, parseEndpointUrl } from "./tools";
17
-
18
- import * as debug from "node-opcua-debug";
19
- import { AcknowledgeMessage } from "./AcknowledgeMessage";
20
- import { HelloMessage } from "./HelloMessage";
21
- import { TCPErrorMessage } from "./TCPErrorMessage";
22
- import { doTraceHelloAck } from "./utils";
23
-
24
- const doDebug = debug.checkDebugFlag(__filename);
25
- const debugLog = debug.make_debugLog(__filename);
26
- const errorLog = debug.make_errorLog(__filename);
27
- const gHostname = os.hostname();
28
-
29
- function createClientSocket(endpointUrl: string): Socket {
30
- // create a socket based on Url
31
- const ep = parseEndpointUrl(endpointUrl);
32
- const port = parseInt(ep.port!, 10);
33
- const hostname = ep.hostname!;
34
- let socket: Socket;
35
- switch (ep.protocol) {
36
- case "opc.tcp:":
37
- socket = createConnection({ host: hostname, port });
38
-
39
- // // Setting true for noDelay will immediately fire off data each time socket.write() is called.
40
- socket.setNoDelay(true);
41
-
42
- return socket;
43
- case "fake:":
44
- socket = getFakeTransport();
45
- assert(ep.protocol === "fake:", " Unsupported transport protocol");
46
- process.nextTick(() => socket.emit("connect"));
47
- return socket;
48
-
49
- case "websocket:":
50
- case "http:":
51
- case "https:FF":
52
- default: {
53
- const msg = "[NODE-OPCUA-E05] this transport protocol is not supported :" + ep.protocol;
54
- errorLog(msg);
55
- throw new Error(msg);
56
- }
57
- }
58
- }
59
- export interface ClientTCP_transport {
60
- on(eventName: "message", eventHandler: (message: Buffer) => void): this;
61
- once(eventName: "message", eventHandler: (message: Buffer) => void): this;
62
- on(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
63
- once(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
64
- on(eventName: "close", eventHandler: (err: Error | null) => void): this;
65
- once(eventName: "close", eventHandler: (err: Error | null) => void): this;
66
- //
67
- on(eventName: "connection_break", eventHandler: () => void): this;
68
- once(eventName: "connection_break", eventHandler: () => void): this;
69
- }
70
-
71
- /**
72
- * a ClientTCP_transport connects to a remote server socket and
73
- * initiates a communication with a HEL/ACK transaction.
74
- * It negotiates the communication parameters with the other end.
75
- *
76
- * @class ClientTCP_transport
77
- * @extends TCP_transport
78
- * @constructor
79
- * @example
80
- *
81
- * ```javascript
82
- * const transport = ClientTCP_transport(url);
83
- *
84
- * transport.timeout = 10000;
85
- *
86
- * transport.connect(function(err)) {
87
- * if (err) {
88
- * // cannot connect
89
- * } else {
90
- * // connected
91
- *
92
- * }
93
- * });
94
- * ....
95
- *
96
- * transport.write(message_chunk,'F');
97
- *
98
- * ....
99
- *
100
- * transport.on("message",function(message_chunk) {
101
- * // do something with message from server...
102
- * });
103
- *
104
- *
105
- * ```
106
- *
107
- *
108
- */
109
- export class ClientTCP_transport extends TCP_transport {
110
- public endpointUrl: string;
111
- public serverUri: string;
112
- public numberOfRetry: number;
113
- public parameters?: AcknowledgeMessage;
114
-
115
- private connected: boolean;
116
- private _counter: number;
117
-
118
- constructor() {
119
- super();
120
- this.connected = false;
121
- this.endpointUrl = "";
122
- this.serverUri = "";
123
- this._counter = 0;
124
- this.numberOfRetry = 0;
125
- }
126
-
127
- public dispose() {
128
- /* istanbul ignore next */
129
- if (doDebug) {
130
- debugLog(" ClientTCP_transport disposed");
131
- }
132
- super.dispose();
133
- }
134
-
135
- public connect(endpointUrl: string, callback: ErrorCallback) {
136
- assert(arguments.length === 2);
137
- assert(typeof callback === "function");
138
-
139
- const ep = parseEndpointUrl(endpointUrl);
140
-
141
- this.endpointUrl = endpointUrl;
142
-
143
- this.serverUri = "urn:" + gHostname + ":Sample";
144
- /* istanbul ignore next */
145
- if (doDebug) {
146
- debugLog(chalk.cyan("ClientTCP_transport#connect(endpointUrl = " + endpointUrl + ")"));
147
- }
148
- try {
149
- this._socket = createClientSocket(endpointUrl);
150
- } catch (err) {
151
- /* istanbul ignore next */
152
- if (doDebug) {
153
- debugLog("CreateClientSocket has failed");
154
- }
155
- return callback(err as Error);
156
- }
157
-
158
- const _on_socket_error_after_connection = (err: Error) => {
159
- /* istanbul ignore next */
160
- if (doDebug) {
161
- debugLog(" _on_socket_error_after_connection ClientTCP_transport Socket Error", err.message);
162
- }
163
- // EPIPE : EPIPE (Broken pipe): A write on a pipe, socket, or FIFO for which there is no process to read the
164
- // data. Commonly encountered at the net and http layers, indicative that the remote side of the stream
165
- // being written to has been closed.
166
-
167
- // ECONNRESET (Connection reset by peer): A connection was forcibly closed by a peer. This normally results
168
- // from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered
169
- // via the http and net module
170
- if (err.message.match(/ECONNRESET|EPIPE/)) {
171
- /**
172
- * @event connection_break
173
- *
174
- */
175
- this.emit("connection_break");
176
- }
177
- };
178
-
179
- const _on_socket_connect = () => {
180
- /* istanbul ignore next */
181
- if (doDebug) {
182
- debugLog("entering _on_socket_connect");
183
- }
184
- _remove_connect_listeners();
185
- this._perform_HEL_ACK_transaction((err?: Error) => {
186
- if (!err) {
187
- /* istanbul ignore next */
188
- if (!this._socket) {
189
- throw new Error("internal error");
190
- }
191
- // install error handler to detect connection break
192
- this._socket.on("error", _on_socket_error_after_connection);
193
-
194
- this.connected = true;
195
- /**
196
- * notify the observers that the transport is connected (the socket is connected and the the HEL/ACK
197
- * transaction has been done)
198
- * @event connect
199
- *
200
- */
201
- this.emit("connect");
202
- } else {
203
- debugLog("_perform_HEL_ACK_transaction has failed with err=", err.message);
204
- }
205
- callback(err);
206
- });
207
- };
208
-
209
- const _on_socket_error_for_connect = (err: Error) => {
210
- // this handler will catch attempt to connect to an inaccessible address.
211
- /* istanbul ignore next */
212
- if (doDebug) {
213
- debugLog(chalk.cyan("ClientTCP_transport#connect - _on_socket_error_for_connect"), err.message);
214
- }
215
- assert(err instanceof Error);
216
- _remove_connect_listeners();
217
- callback(err);
218
- };
219
-
220
- const _on_socket_end_for_connect = (err: Error | null) => {
221
- /* istanbul ignore next */
222
- if (doDebug) {
223
- debugLog(
224
- chalk.cyan("ClientTCP_transport#connect -> _on_socket_end_for_connect Socket has been closed by server"),
225
- err
226
- );
227
- }
228
- };
229
-
230
- const _remove_connect_listeners = () => {
231
- /* istanbul ignore next */
232
- if (!this._socket) {
233
- return;
234
- }
235
- this._socket.removeListener("error", _on_socket_error_for_connect);
236
- this._socket.removeListener("end", _on_socket_end_for_connect);
237
- };
238
-
239
- this._socket.once("error", _on_socket_error_for_connect);
240
- this._socket.once("end", _on_socket_end_for_connect);
241
- this._socket.once("connect", _on_socket_connect);
242
- this._install_socket(this._socket);
243
- }
244
-
245
- protected on_socket_ended(err: Error | null) {
246
- debugLog("on_socket_ended", this.name, err ? err.message : "");
247
- if (this.connected) {
248
- super.on_socket_ended(err);
249
- }
250
- // if (this._socket) {
251
- // this._socket.removeAllListeners();
252
- // }
253
- }
254
-
255
- private _handle_ACK_response(messageChunk: Buffer, callback: ErrorCallback) {
256
- const _stream = new BinaryStream(messageChunk);
257
- const messageHeader = readMessageHeader(_stream);
258
- let err;
259
- /* istanbul ignore next */
260
- if (messageHeader.isFinal !== "F") {
261
- err = new Error(" invalid ACK message");
262
- return callback(err);
263
- }
264
-
265
- let responseClass;
266
- let response;
267
-
268
- if (messageHeader.msgType === "ERR") {
269
- responseClass = TCPErrorMessage;
270
- _stream.rewind();
271
- response = decodeMessage(_stream, responseClass) as TCPErrorMessage;
272
-
273
- err = new Error("ACK: ERR received " + response.statusCode.toString() + " : " + response.reason);
274
- (err as any).statusCode = response.statusCode;
275
- // istanbul ignore next
276
- if (doTraceHelloAck) {
277
- console.log("receiving ERR instead of Ack", response.toString());
278
- }
279
- callback(err);
280
- } else {
281
- responseClass = AcknowledgeMessage;
282
- _stream.rewind();
283
- response = decodeMessage(_stream, responseClass);
284
- this.parameters = response as AcknowledgeMessage;
285
-
286
- // istanbul ignore next
287
- if (doTraceHelloAck) {
288
- console.log("receiving Ack\n", response.toString());
289
- }
290
-
291
- callback();
292
- }
293
- }
294
-
295
- private _send_HELLO_request() {
296
- /* istanbul ignore next */
297
- if (doDebug) {
298
- debugLog("entering _send_HELLO_request");
299
- }
300
- assert(this._socket);
301
- assert(isFinite(this.protocolVersion));
302
- assert(this.endpointUrl.length > 0, " expecting a valid endpoint url");
303
-
304
- // Write a message to the socket as soon as the client is connected,
305
- // the server will receive it as message from the client
306
- const helloMessage = new HelloMessage({
307
- endpointUrl: this.endpointUrl,
308
- maxChunkCount: 0, // 0 - no limits
309
- maxMessageSize: 0, // 0 - no limits
310
-
311
- protocolVersion: this.protocolVersion,
312
- receiveBufferSize: 1024 * 64 * 10,
313
- sendBufferSize: 1024 * 64 * 10 // 8192 min,
314
- });
315
- // istanbul ignore next
316
- if (doTraceHelloAck) {
317
- console.log(`sending Hello\n ${helloMessage.toString()}`);
318
- }
319
-
320
- const messageChunk = packTcpMessage("HEL", helloMessage);
321
- this._write_chunk(messageChunk);
322
- }
323
-
324
- private _on_ACK_response(externalCallback: ErrorCallback, err: Error | null, data?: Buffer) {
325
- /* istanbul ignore next */
326
- if (doDebug) {
327
- debugLog("entering _on_ACK_response");
328
- }
329
-
330
- assert(typeof externalCallback === "function");
331
- assert(this._counter === 0, "Ack response should only be received once !");
332
- this._counter += 1;
333
-
334
- if (err || !data) {
335
- externalCallback(err || new Error("no data"));
336
- if (this._socket) {
337
- this._socket.end();
338
- // Xx this._socket.removeAllListeners();
339
- }
340
- } else {
341
- this._handle_ACK_response(data, externalCallback);
342
- }
343
- }
344
-
345
- private _perform_HEL_ACK_transaction(callback: ErrorCallback) {
346
- /* istanbul ignore next */
347
- if (!this._socket) {
348
- return callback(new Error("No socket available to perform HEL/ACK transaction"));
349
- }
350
- assert(this._socket, "expecting a valid socket to send a message");
351
- assert(typeof callback === "function");
352
- this._counter = 0;
353
- /* istanbul ignore next */
354
- if (doDebug) {
355
- debugLog("entering _perform_HEL_ACK_transaction");
356
- }
357
- this._install_one_time_message_receiver((err: Error | null, data?: Buffer) => {
358
- /* istanbul ignore next */
359
- if (doDebug) {
360
- debugLog("before _on_ACK_response ", err ? err.message : "");
361
- }
362
- this._on_ACK_response(callback, err, data);
363
- });
364
- this._send_HELLO_request();
365
- }
366
- }
1
+ /**
2
+ * @module node-opcua-transport
3
+ */
4
+ // tslint:disable:class-name
5
+ // system
6
+ import * as os from "os";
7
+ import { createConnection, Socket } from "net";
8
+ import * as chalk from "chalk";
9
+
10
+ import { assert } from "node-opcua-assert";
11
+ import { BinaryStream } from "node-opcua-binary-stream";
12
+ import { readMessageHeader } from "node-opcua-chunkmanager";
13
+ import { ErrorCallback } from "node-opcua-status-code";
14
+
15
+ import * as debug from "node-opcua-debug";
16
+ import { getFakeTransport, TCP_transport } from "./tcp_transport";
17
+ import { decodeMessage, packTcpMessage, parseEndpointUrl } from "./tools";
18
+
19
+ import { AcknowledgeMessage } from "./AcknowledgeMessage";
20
+ import { HelloMessage } from "./HelloMessage";
21
+ import { TCPErrorMessage } from "./TCPErrorMessage";
22
+ import { doTraceHelloAck } from "./utils";
23
+
24
+ const doDebug = debug.checkDebugFlag(__filename);
25
+ const debugLog = debug.make_debugLog(__filename);
26
+ const errorLog = debug.make_errorLog(__filename);
27
+ const gHostname = os.hostname();
28
+
29
+ function createClientSocket(endpointUrl: string): Socket {
30
+ // create a socket based on Url
31
+ const ep = parseEndpointUrl(endpointUrl);
32
+ const port = parseInt(ep.port!, 10);
33
+ const hostname = ep.hostname!;
34
+ let socket: Socket;
35
+ switch (ep.protocol) {
36
+ case "opc.tcp:":
37
+ socket = createConnection({ host: hostname, port });
38
+
39
+ // // Setting true for noDelay will immediately fire off data each time socket.write() is called.
40
+ socket.setNoDelay(true);
41
+
42
+ return socket;
43
+ case "fake:":
44
+ socket = getFakeTransport();
45
+ assert(ep.protocol === "fake:", " Unsupported transport protocol");
46
+ process.nextTick(() => socket.emit("connect"));
47
+ return socket;
48
+
49
+ case "websocket:":
50
+ case "http:":
51
+ case "https:FF":
52
+ default: {
53
+ const msg = "[NODE-OPCUA-E05] this transport protocol is not supported :" + ep.protocol;
54
+ errorLog(msg);
55
+ throw new Error(msg);
56
+ }
57
+ }
58
+ }
59
+ export interface ClientTCP_transport {
60
+ on(eventName: "message", eventHandler: (message: Buffer) => void): this;
61
+ on(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
62
+ on(eventName: "close", eventHandler: (err: Error | null) => void): this;
63
+ on(eventName: "connection_break", eventHandler: () => void): this;
64
+
65
+ once(eventName: "message", eventHandler: (message: Buffer) => void): this;
66
+ once(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
67
+ once(eventName: "close", eventHandler: (err: Error | null) => void): this;
68
+ once(eventName: "connection_break", eventHandler: () => void): this;
69
+ }
70
+
71
+ /**
72
+ * a ClientTCP_transport connects to a remote server socket and
73
+ * initiates a communication with a HEL/ACK transaction.
74
+ * It negotiates the communication parameters with the other end.
75
+ *
76
+ * @class ClientTCP_transport
77
+ * @extends TCP_transport
78
+ * @constructor
79
+ * @example
80
+ *
81
+ * ```javascript
82
+ * const transport = ClientTCP_transport(url);
83
+ *
84
+ * transport.timeout = 10000;
85
+ *
86
+ * transport.connect(function(err)) {
87
+ * if (err) {
88
+ * // cannot connect
89
+ * } else {
90
+ * // connected
91
+ *
92
+ * }
93
+ * });
94
+ * ....
95
+ *
96
+ * transport.write(message_chunk,'F');
97
+ *
98
+ * ....
99
+ *
100
+ * transport.on("message",function(message_chunk) {
101
+ * // do something with message from server...
102
+ * });
103
+ *
104
+ *
105
+ * ```
106
+ *
107
+ *
108
+ */
109
+ export class ClientTCP_transport extends TCP_transport {
110
+ public endpointUrl: string;
111
+ public serverUri: string;
112
+ public numberOfRetry: number;
113
+ public parameters?: AcknowledgeMessage;
114
+
115
+ private connected: boolean;
116
+ private _counter: number;
117
+
118
+ constructor() {
119
+ super();
120
+ this.connected = false;
121
+ this.endpointUrl = "";
122
+ this.serverUri = "";
123
+ this._counter = 0;
124
+ this.numberOfRetry = 0;
125
+ }
126
+
127
+ public dispose(): void {
128
+ /* istanbul ignore next */
129
+ if (doDebug) {
130
+ debugLog(" ClientTCP_transport disposed");
131
+ }
132
+ super.dispose();
133
+ }
134
+
135
+ public connect(endpointUrl: string, callback: ErrorCallback): void {
136
+ assert(arguments.length === 2);
137
+ assert(typeof callback === "function");
138
+
139
+ const ep = parseEndpointUrl(endpointUrl);
140
+
141
+ this.endpointUrl = endpointUrl;
142
+
143
+ this.serverUri = "urn:" + gHostname + ":Sample";
144
+ /* istanbul ignore next */
145
+ if (doDebug) {
146
+ debugLog(chalk.cyan("ClientTCP_transport#connect(endpointUrl = " + endpointUrl + ")"));
147
+ }
148
+ try {
149
+ this._socket = createClientSocket(endpointUrl);
150
+ } catch (err) {
151
+ /* istanbul ignore next */
152
+ if (doDebug) {
153
+ debugLog("CreateClientSocket has failed");
154
+ }
155
+ return callback(err as Error);
156
+ }
157
+
158
+ const _on_socket_error_after_connection = (err: Error) => {
159
+ /* istanbul ignore next */
160
+ if (doDebug) {
161
+ debugLog(" _on_socket_error_after_connection ClientTCP_transport Socket Error", err.message);
162
+ }
163
+ // EPIPE : EPIPE (Broken pipe): A write on a pipe, socket, or FIFO for which there is no process to read the
164
+ // data. Commonly encountered at the net and http layers, indicative that the remote side of the stream
165
+ // being written to has been closed.
166
+
167
+ // ECONNRESET (Connection reset by peer): A connection was forcibly closed by a peer. This normally results
168
+ // from a loss of the connection on the remote socket due to a timeout or reboot. Commonly encountered
169
+ // via the http and net module
170
+ if (err.message.match(/ECONNRESET|EPIPE/)) {
171
+ /**
172
+ * @event connection_break
173
+ *
174
+ */
175
+ this.emit("connection_break");
176
+ }
177
+ };
178
+
179
+ const _on_socket_connect = () => {
180
+ /* istanbul ignore next */
181
+ if (doDebug) {
182
+ debugLog("entering _on_socket_connect");
183
+ }
184
+ _remove_connect_listeners();
185
+ this._perform_HEL_ACK_transaction((err?: Error) => {
186
+ if (!err) {
187
+ /* istanbul ignore next */
188
+ if (!this._socket) {
189
+ throw new Error("internal error");
190
+ }
191
+ // install error handler to detect connection break
192
+ this._socket.on("error", _on_socket_error_after_connection);
193
+
194
+ this.connected = true;
195
+ /**
196
+ * notify the observers that the transport is connected (the socket is connected and the the HEL/ACK
197
+ * transaction has been done)
198
+ * @event connect
199
+ *
200
+ */
201
+ this.emit("connect");
202
+ } else {
203
+ debugLog("_perform_HEL_ACK_transaction has failed with err=", err.message);
204
+ }
205
+ callback(err);
206
+ });
207
+ };
208
+
209
+ const _on_socket_error_for_connect = (err: Error) => {
210
+ // this handler will catch attempt to connect to an inaccessible address.
211
+ /* istanbul ignore next */
212
+ if (doDebug) {
213
+ debugLog(chalk.cyan("ClientTCP_transport#connect - _on_socket_error_for_connect"), err.message);
214
+ }
215
+ assert(err instanceof Error);
216
+ _remove_connect_listeners();
217
+ callback(err);
218
+ };
219
+
220
+ const _on_socket_end_for_connect = (err: Error | null) => {
221
+ /* istanbul ignore next */
222
+ if (doDebug) {
223
+ debugLog(
224
+ chalk.cyan("ClientTCP_transport#connect -> _on_socket_end_for_connect Socket has been closed by server"),
225
+ err
226
+ );
227
+ }
228
+ };
229
+
230
+ const _remove_connect_listeners = () => {
231
+ /* istanbul ignore next */
232
+ if (!this._socket) {
233
+ return;
234
+ }
235
+ this._socket.removeListener("error", _on_socket_error_for_connect);
236
+ this._socket.removeListener("end", _on_socket_end_for_connect);
237
+ };
238
+
239
+ this._socket.once("error", _on_socket_error_for_connect);
240
+ this._socket.once("end", _on_socket_end_for_connect);
241
+ this._socket.once("connect", _on_socket_connect);
242
+ this._install_socket(this._socket);
243
+ }
244
+
245
+ protected on_socket_ended(err: Error | null): void {
246
+ debugLog("on_socket_ended", this.name, err ? err.message : "");
247
+ if (this.connected) {
248
+ super.on_socket_ended(err);
249
+ }
250
+ // if (this._socket) {
251
+ // this._socket.removeAllListeners();
252
+ // }
253
+ }
254
+
255
+ private _handle_ACK_response(messageChunk: Buffer, callback: ErrorCallback) {
256
+ const _stream = new BinaryStream(messageChunk);
257
+ const messageHeader = readMessageHeader(_stream);
258
+ let err;
259
+ /* istanbul ignore next */
260
+ if (messageHeader.isFinal !== "F") {
261
+ err = new Error(" invalid ACK message");
262
+ return callback(err);
263
+ }
264
+
265
+ let responseClass;
266
+ let response;
267
+
268
+ if (messageHeader.msgType === "ERR") {
269
+ responseClass = TCPErrorMessage;
270
+ _stream.rewind();
271
+ response = decodeMessage(_stream, responseClass) as TCPErrorMessage;
272
+
273
+ err = new Error("ACK: ERR received " + response.statusCode.toString() + " : " + response.reason);
274
+ (err as any).statusCode = response.statusCode;
275
+ // istanbul ignore next
276
+ if (doTraceHelloAck) {
277
+ console.log("receiving ERR instead of Ack", response.toString());
278
+ }
279
+ callback(err);
280
+ } else {
281
+ responseClass = AcknowledgeMessage;
282
+ _stream.rewind();
283
+ response = decodeMessage(_stream, responseClass);
284
+ this.parameters = response as AcknowledgeMessage;
285
+
286
+ // istanbul ignore next
287
+ if (doTraceHelloAck) {
288
+ console.log("receiving Ack\n", response.toString());
289
+ }
290
+
291
+ callback();
292
+ }
293
+ }
294
+
295
+ private _send_HELLO_request() {
296
+ /* istanbul ignore next */
297
+ if (doDebug) {
298
+ debugLog("entering _send_HELLO_request");
299
+ }
300
+ assert(this._socket);
301
+ assert(isFinite(this.protocolVersion));
302
+ assert(this.endpointUrl.length > 0, " expecting a valid endpoint url");
303
+
304
+ // Write a message to the socket as soon as the client is connected,
305
+ // the server will receive it as message from the client
306
+ const helloMessage = new HelloMessage({
307
+ endpointUrl: this.endpointUrl,
308
+ maxChunkCount: 0, // 0 - no limits
309
+ maxMessageSize: 0, // 0 - no limits
310
+
311
+ protocolVersion: this.protocolVersion,
312
+ receiveBufferSize: 1024 * 64 * 10,
313
+ sendBufferSize: 1024 * 64 * 10 // 8192 min,
314
+ });
315
+ // istanbul ignore next
316
+ if (doTraceHelloAck) {
317
+ console.log(`sending Hello\n ${helloMessage.toString()}`);
318
+ }
319
+
320
+ const messageChunk = packTcpMessage("HEL", helloMessage);
321
+ this._write_chunk(messageChunk);
322
+ }
323
+
324
+ private _on_ACK_response(externalCallback: ErrorCallback, err: Error | null, data?: Buffer) {
325
+ /* istanbul ignore next */
326
+ if (doDebug) {
327
+ debugLog("entering _on_ACK_response");
328
+ }
329
+
330
+ assert(typeof externalCallback === "function");
331
+ assert(this._counter === 0, "Ack response should only be received once !");
332
+ this._counter += 1;
333
+
334
+ if (err || !data) {
335
+ externalCallback(err || new Error("no data"));
336
+ if (this._socket) {
337
+ this._socket.end();
338
+ // Xx this._socket.removeAllListeners();
339
+ }
340
+ } else {
341
+ this._handle_ACK_response(data, externalCallback);
342
+ }
343
+ }
344
+
345
+ private _perform_HEL_ACK_transaction(callback: ErrorCallback) {
346
+ /* istanbul ignore next */
347
+ if (!this._socket) {
348
+ return callback(new Error("No socket available to perform HEL/ACK transaction"));
349
+ }
350
+ assert(this._socket, "expecting a valid socket to send a message");
351
+ assert(typeof callback === "function");
352
+ this._counter = 0;
353
+ /* istanbul ignore next */
354
+ if (doDebug) {
355
+ debugLog("entering _perform_HEL_ACK_transaction");
356
+ }
357
+ this._install_one_time_message_receiver((err: Error | null, data?: Buffer) => {
358
+ /* istanbul ignore next */
359
+ if (doDebug) {
360
+ debugLog("before _on_ACK_response ", err ? err.message : "");
361
+ }
362
+ this._on_ACK_response(callback, err, data);
363
+ });
364
+ this._send_HELLO_request();
365
+ }
366
+ }