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.
Files changed (36) hide show
  1. package/dist/source/client_tcp_transport.d.ts +4 -9
  2. package/dist/source/client_tcp_transport.js +38 -71
  3. package/dist/source/client_tcp_transport.js.map +1 -1
  4. package/dist/source/server_tcp_transport.d.ts +3 -15
  5. package/dist/source/server_tcp_transport.js +40 -41
  6. package/dist/source/server_tcp_transport.js.map +1 -1
  7. package/dist/source/tcp_transport.d.ts +45 -28
  8. package/dist/source/tcp_transport.js +160 -110
  9. package/dist/source/tcp_transport.js.map +1 -1
  10. package/dist/test_helpers/ITransportPair.d.ts +7 -0
  11. package/dist/test_helpers/ITransportPair.js +3 -0
  12. package/dist/test_helpers/ITransportPair.js.map +1 -0
  13. package/dist/test_helpers/fake_server.d.ts +2 -0
  14. package/dist/test_helpers/fake_server.js +3 -0
  15. package/dist/test_helpers/fake_server.js.map +1 -1
  16. package/dist/test_helpers/half_com_channel.d.ts +17 -10
  17. package/dist/test_helpers/half_com_channel.js +63 -4
  18. package/dist/test_helpers/half_com_channel.js.map +1 -1
  19. package/dist/test_helpers/index.d.ts +2 -2
  20. package/dist/test_helpers/index.js +2 -2
  21. package/dist/test_helpers/index.js.map +1 -1
  22. package/dist/test_helpers/{direct_transport.d.ts → transport_pair_direct.d.ts} +2 -6
  23. package/dist/test_helpers/{direct_transport.js → transport_pair_direct.js} +11 -18
  24. package/dist/test_helpers/transport_pair_direct.js.map +1 -0
  25. package/dist/test_helpers/transport_pair_socket.d.ts +14 -0
  26. package/dist/test_helpers/transport_pair_socket.js +33 -0
  27. package/dist/test_helpers/transport_pair_socket.js.map +1 -0
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +3 -2
  30. package/source/client_tcp_transport.ts +56 -89
  31. package/source/server_tcp_transport.ts +48 -50
  32. package/source/tcp_transport.ts +226 -157
  33. package/dist/test_helpers/direct_transport.js.map +0 -1
  34. package/dist/test_helpers/socket_transport.d.ts +0 -10
  35. package/dist/test_helpers/socket_transport.js +0 -31
  36. package/dist/test_helpers/socket_transport.js.map +0 -1
@@ -1,8 +1,8 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
1
2
  /**
2
3
  * @module node-opcua-transport
3
4
  */
4
5
  import { EventEmitter } from "events";
5
- import { Socket } from "net";
6
6
  import * as chalk from "chalk";
7
7
 
8
8
  import { assert } from "node-opcua-assert";
@@ -17,37 +17,100 @@ import { doTraceIncomingChunk } from "./utils";
17
17
  import { TCPErrorMessage } from "./TCPErrorMessage";
18
18
  import { packTcpMessage } from "./tools";
19
19
 
20
- const debugLog = make_debugLog(__filename);
21
- const doDebug = checkDebugFlag(__filename);
22
- const errorLog = make_errorLog(__filename);
23
- const warningLog = make_warningLog(__filename);
20
+ const debugLog = make_debugLog("TRANSPORT");
21
+ const doDebug = checkDebugFlag("TRANSPORT");
22
+ const errorLog = make_errorLog("TRANSPORT");
23
+ const warningLog = make_warningLog("TRANSPORT");
24
24
 
25
- export interface MockSocket {
25
+ const doDebugFlow = false;
26
+
27
+ export interface ISocketLike extends EventEmitter {
28
+ remoteAddress?: string;
29
+ remotePort?: number;
30
+
31
+ write(data: string | Buffer, callback?: (err?: Error) => void | undefined): void;
32
+ end(): void;
33
+ setKeepAlive(enable?: boolean, initialDelay?: number): this;
34
+ setNoDelay(noDelay?: boolean): this;
35
+ setTimeout(timeout: number, callback?: () => void): this;
36
+
37
+ destroy(err?: Error): void;
38
+ destroyed: boolean;
39
+
40
+ on(event: "close", listener: (hadError: boolean) => void): this;
41
+ on(event: "connect", listener: () => void): this;
42
+ on(event: "data", listener: (data: Buffer) => void): this;
43
+ on(event: "end", listener: () => void): this;
44
+ on(event: "error", listener: (err: Error) => void): this;
45
+ on(event: "timeout", listener: () => void): this;
46
+ once(event: "close", listener: (hadError: boolean) => void): this;
47
+ once(event: "connect", listener: () => void): this;
48
+ once(event: "data", listener: (data: Buffer) => void): this;
49
+ once(event: "end", listener: () => void): this;
50
+ once(event: "error", listener: (err: Error) => void): this;
51
+ once(event: "timeout", listener: () => void): this;
52
+ prependListener(event: "close", listener: (hadError: boolean) => void): this;
53
+ prependListener(event: "connect", listener: () => void): this;
54
+ prependListener(event: "data", listener: (data: Buffer) => void): this;
55
+ prependListener(event: "end", listener: () => void): this;
56
+ prependListener(event: "error", listener: (err: Error) => void): this;
57
+ prependListener(event: "timeout", listener: () => void): this;
58
+ }
59
+
60
+ export interface IMockSocket extends ISocketLike {
26
61
  invalid?: boolean;
27
- [key: string]: any;
62
+ // [key: string]: any;
63
+ write(data: string | Buffer, callback?: (err?: Error) => void | undefined): void;
28
64
  destroy(): void;
29
65
  end(): void;
66
+
67
+ setKeepAlive(enable?: boolean, initialDelay?: number): this;
68
+ setNoDelay(noDelay?: boolean): this;
69
+ setTimeout(timeout: number, callback?: () => void): this;
30
70
  }
31
- let fakeSocket: MockSocket = {
32
- invalid: true,
33
71
 
34
- destroy() {
72
+ const defaultFakeSocket = {
73
+ invalid: true,
74
+ destroyed: false,
75
+ destroy(err?: Error) {
76
+ this.destroyed = true;
35
77
  errorLog("MockSocket.destroy");
36
78
  },
37
79
 
38
80
  end() {
39
81
  errorLog("MockSocket.end");
82
+ },
83
+
84
+ write(data: string | Buffer, callback?: (err?: Error) => void | undefined): void {
85
+ /** */
86
+ if (callback) {
87
+ callback();
88
+ }
89
+ },
90
+
91
+ setKeepAlive(enable?: boolean, initialDelay?: number) {
92
+ return this;
93
+ },
94
+ setNoDelay(noDelay?: boolean) {
95
+ return this;
96
+ },
97
+ setTimeout(timeout: number, callback?: () => void) {
98
+ return this;
40
99
  }
41
100
  };
42
101
 
43
- export function setFakeTransport(mockSocket: MockSocket): void {
102
+ let fakeSocket: IMockSocket = defaultFakeSocket as IMockSocket;
103
+
104
+ export function setFakeTransport(mockSocket: IMockSocket): void {
44
105
  fakeSocket = mockSocket;
45
106
  }
46
107
 
47
- export function getFakeTransport(): any {
108
+ export function getFakeTransport(): ISocketLike {
48
109
  if (fakeSocket.invalid) {
49
110
  throw new Error("getFakeTransport: setFakeTransport must be called first - BadProtocolVersionUnsupported");
50
111
  }
112
+ process.nextTick(() => fakeSocket.emit("connect"));
113
+
51
114
  return fakeSocket;
52
115
  }
53
116
 
@@ -60,12 +123,6 @@ export interface TCP_transport {
60
123
  * @param message_chunk the message chunk
61
124
  */
62
125
  on(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
63
- /**
64
- * notify the observers that the transport layer has been disconnected.
65
- * @event socket_closed
66
- * @param err the Error object or null
67
- */
68
- on(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
69
126
  /**
70
127
  * notify the observers that the transport layer has been disconnected.
71
128
  * @event close
@@ -73,10 +130,8 @@ export interface TCP_transport {
73
130
  on(eventName: "close", eventHandler: (err: Error | null) => void): this;
74
131
 
75
132
  once(eventName: "chunk", eventHandler: (messageChunk: Buffer) => void): this;
76
- once(eventName: "socket_closed", eventHandler: (err: Error | null) => void): this;
77
133
  once(eventName: "close", eventHandler: (err: Error | null) => void): this;
78
134
 
79
- emit(eventName: "socket_closed", err?: Error | null): boolean;
80
135
  emit(eventName: "close", err?: Error | null): boolean;
81
136
  emit(eventName: "chunk", messageChunk: Buffer): boolean;
82
137
  }
@@ -100,21 +155,21 @@ export class TCP_transport extends EventEmitter {
100
155
  public chunkReadCount: number;
101
156
  public name: string;
102
157
 
103
- public _socket: Socket | null;
158
+ public _socket: ISocketLike | null;
159
+ private _closedEmitted: Error | string | undefined = undefined;
104
160
 
105
161
  /**
106
162
  * the size of the header in bytes
107
163
  * @default 8
108
164
  */
109
165
  private readonly headerSize: 8;
110
- private _disconnecting: boolean;
111
166
  private _timerId: NodeJS.Timer | null;
112
- private _onSocketClosedHasBeenCalled: boolean;
113
- private _onSocketEndedHasBeenCalled: boolean;
114
- private _theCallback?: CallbackWithData;
115
- private _on_error_during_one_time_message_receiver: any;
167
+ private _theCallback?: (err?: Error | null, data?: Buffer) => void;
168
+ private _on_error_during_one_time_message_receiver: ((hadError: boolean) => void) | undefined;
116
169
  private packetAssembler?: PacketAssembler;
117
170
  private _timeout: number;
171
+ private _isDisconnecting = false;
172
+ protected _theCloseError: Error | null = null;
118
173
 
119
174
  constructor() {
120
175
  super();
@@ -123,7 +178,7 @@ export class TCP_transport extends EventEmitter {
123
178
  counter += 1;
124
179
 
125
180
  this._timerId = null;
126
- this._timeout = 30000; // 30 seconds timeout
181
+ this._timeout = 5000; // 5 seconds timeout
127
182
  this._socket = null;
128
183
  this.headerSize = 8;
129
184
 
@@ -133,8 +188,6 @@ export class TCP_transport extends EventEmitter {
133
188
  this.sendBufferSize = 0;
134
189
  this.protocolVersion = 0;
135
190
 
136
- this._disconnecting = false;
137
-
138
191
  this.bytesWritten = 0;
139
192
  this.bytesRead = 0;
140
193
 
@@ -142,11 +195,25 @@ export class TCP_transport extends EventEmitter {
142
195
  this.chunkWrittenCount = 0;
143
196
  this.chunkReadCount = 0;
144
197
 
145
- this._onSocketClosedHasBeenCalled = false;
146
- this._onSocketEndedHasBeenCalled = false;
147
198
  TCP_transport.registry.register(this);
148
199
  }
149
200
 
201
+ public toString() {
202
+ let str = "\n";
203
+ str += " name.............. = " + this.name + "\n";
204
+ str += " protocolVersion... = " + this.protocolVersion + "\n";
205
+ str += " maxMessageSize.... = " + this.maxMessageSize + "\n";
206
+ str += " maxChunkCount..... = " + this.maxChunkCount + "\n";
207
+ str += " receiveBufferSize. = " + this.receiveBufferSize + "\n";
208
+ str += " sendBufferSize.... = " + this.sendBufferSize + "\n";
209
+ str += " bytesRead......... = " + this.bytesRead + "\n";
210
+ str += " bytesWritten...... = " + this.bytesWritten + "\n";
211
+ str += " chunkWrittenCount. = " + this.chunkWrittenCount + "\n";
212
+ str += " chunkReadCount.... = " + this.chunkReadCount + "\n";
213
+ str += " closeEmitted ? ....= " + this._closedEmitted + "\n";
214
+ return str;
215
+ }
216
+
150
217
  public setLimits({
151
218
  receiveBufferSize,
152
219
  sendBufferSize,
@@ -163,12 +230,11 @@ export class TCP_transport extends EventEmitter {
163
230
  this.maxMessageSize = maxMessageSize;
164
231
  this.maxChunkCount = maxChunkCount;
165
232
 
166
- if(maxMessageSize / sendBufferSize > maxChunkCount || maxMessageSize / receiveBufferSize > maxChunkCount)
167
- {
233
+ if (maxMessageSize / sendBufferSize > maxChunkCount || maxMessageSize / receiveBufferSize > maxChunkCount) {
168
234
  warningLog(`Warning : maxMessageSize / sendBufferSize ${maxMessageSize / sendBufferSize}> maxChunkCount ${maxChunkCount}
169
235
  || maxMessageSize / receiveBufferSize ${maxMessageSize / receiveBufferSize} < maxChunkCount `);
170
236
  }
171
-
237
+
172
238
  // reinstall packetAssembler with correct limits
173
239
  this._install_packetAssembler();
174
240
  }
@@ -177,15 +243,17 @@ export class TCP_transport extends EventEmitter {
177
243
  return this._timeout;
178
244
  }
179
245
  public set timeout(value: number) {
246
+ assert(!this._timerId);
180
247
  debugLog("Setting socket " + this.name + " timeout = ", value);
181
248
  this._timeout = value;
182
249
  }
250
+
183
251
  public dispose(): void {
184
252
  this._cleanup_timers();
185
253
  assert(!this._timerId);
186
254
  if (this._socket) {
187
255
  this._socket.destroy();
188
- this._socket.removeAllListeners();
256
+ // this._socket.removeAllListeners();
189
257
  this._socket = null;
190
258
  }
191
259
  TCP_transport.registry.unregister(this);
@@ -206,8 +274,8 @@ export class TCP_transport extends EventEmitter {
206
274
  });
207
275
  }
208
276
 
209
- public get isDisconnecting(): boolean {
210
- return this._disconnecting;
277
+ public isDisconnecting(): boolean {
278
+ return !this._socket || this._isDisconnecting;
211
279
  }
212
280
  /**
213
281
  * disconnect the TCP layer and close the underlying socket.
@@ -219,33 +287,31 @@ export class TCP_transport extends EventEmitter {
219
287
  */
220
288
  public disconnect(callback: ErrorCallback): void {
221
289
  assert(typeof callback === "function", "expecting a callback function, but got " + callback);
222
-
223
- if (this._disconnecting) {
290
+ if (!this._socket || this._isDisconnecting) {
291
+ if (!this._isDisconnecting) {
292
+ this.dispose();
293
+ }
224
294
  callback();
225
295
  return;
226
296
  }
297
+ this._isDisconnecting = true;
227
298
 
228
- assert(!this._disconnecting, "TCP Transport has already been disconnected");
229
- this._disconnecting = true;
230
-
231
- // xx assert(!this._theCallback,
232
- // "disconnect shall not be called while the 'one time message receiver' is in operation");
233
299
  this._cleanup_timers();
234
300
 
235
- if (this._socket) {
236
- this._socket.end();
237
- this._socket && this._socket.destroy();
238
- // xx this._socket.removeAllListeners();
239
- this._socket = null;
240
- }
241
- this.on_socket_ended(null);
242
- setImmediate(() => {
243
- callback();
301
+ this._socket.prependOnceListener("close", () => {
302
+ this._emitClose(null);
303
+ setImmediate(() => {
304
+ callback();
305
+ });
244
306
  });
307
+
308
+ this._socket.end();
309
+ this._socket && this._socket.destroy();
310
+ this._socket = null;
245
311
  }
246
312
 
247
313
  public isValid(): boolean {
248
- return this._socket !== null && !this._socket.destroyed && !this._disconnecting;
314
+ return this._socket !== null && !this._socket.destroyed;
249
315
  }
250
316
 
251
317
  protected _write_chunk(messageChunk: Buffer, callback?: (err?: Error) => void | undefined): void {
@@ -260,15 +326,6 @@ export class TCP_transport extends EventEmitter {
260
326
  }
261
327
  }
262
328
 
263
- protected on_socket_ended(err: Error | null): void {
264
- if (!this._onSocketEndedHasBeenCalled) {
265
- this._onSocketEndedHasBeenCalled = true; // we don't want to send close event twice ...
266
- this.emit("close", err || null);
267
- } else {
268
- debugLog("on_socket_ended has already been called");
269
- }
270
- }
271
-
272
329
  protected _install_packetAssembler() {
273
330
  if (this.packetAssembler) {
274
331
  this.packetAssembler.removeAllListeners();
@@ -298,14 +355,24 @@ export class TCP_transport extends EventEmitter {
298
355
  this.prematureTerminate(new Error("Packet Assembler : " + err.message), statusCode);
299
356
  });
300
357
  }
301
- /**
302
- * @method _install_socket
303
- * @param socket {Socket}
304
- * @protected
305
- */
306
- protected _install_socket(socket: Socket): void {
358
+
359
+ protected _install_socket(socket: ISocketLike): void {
360
+ // note: it is possible that a transport may be recycled and re-used again after a connection break
307
361
  assert(socket);
362
+ assert(!this._socket, "already have a socket");
308
363
  this._socket = socket;
364
+ this._closedEmitted = undefined;
365
+ this._theCloseError = null;
366
+ assert(this._closedEmitted === undefined, "TCP Transport has already been closed !");
367
+
368
+ this._socket.setKeepAlive(true);
369
+ // Setting true for noDelay will immediately fire off data each time socket.write() is called.
370
+ this._socket.setNoDelay(true);
371
+ // set socket timeout
372
+ debugLog(" TCP_transport#install => setting " + this.name + " _socket.setTimeout to ", this.timeout);
373
+ // let use a large timeout here to make sure that we not conflict with our internal timeout
374
+ this._socket.setTimeout(this.timeout);
375
+
309
376
  if (doDebug) {
310
377
  debugLog(" TCP_transport#_install_socket ", this.name);
311
378
  }
@@ -315,23 +382,14 @@ export class TCP_transport extends EventEmitter {
315
382
  this._socket
316
383
  .on("data", (data: Buffer) => this._on_socket_data(data))
317
384
  .on("close", (hadError) => this._on_socket_close(hadError))
318
- .on("end", (err: Error) => this._on_socket_end(err))
319
- .on("error", (err: Error) => this._on_socket_error(err));
320
-
321
- // set socket timeout
322
- debugLog(" TCP_transport#install => setting " + this.name + " _socket.setTimeout to ", this.timeout);
323
-
324
- // let use a large timeout here to make sure that we not conflict with our internal timeout
325
- this._socket.setTimeout(this.timeout + 2000, () => {
326
- debugLog(` _socket ${this.name} has timed out (timeout = ${this.timeout})`);
327
- this.prematureTerminate(new Error("socket timeout : timeout=" + this.timeout), StatusCodes2.BadTimeout);
328
- });
385
+ .on("end", () => this._on_socket_end())
386
+ .on("error", (err: Error) => this._on_socket_error(err))
387
+ .on("timeout", () => this._on_socket_timeout());
329
388
  }
330
389
 
331
390
  public sendErrorMessage(statusCode: StatusCode, extraErrorDescription: string | null): void {
332
391
  // When the Client receives an Error Message it reports the error to the application and closes the TransportConnection gracefully.
333
392
  // If a Client encounters a fatal error, it shall report the error to the application and send a CloseSecureChannel Message.
334
-
335
393
  /* istanbul ignore next*/
336
394
  if (doDebug) {
337
395
  debugLog(chalk.red(" sendErrorMessage ") + chalk.cyan(statusCode.toString()));
@@ -350,19 +408,18 @@ export class TCP_transport extends EventEmitter {
350
408
  public prematureTerminate(err: Error, statusCode: StatusCode): void {
351
409
  // https://reference.opcfoundation.org/v104/Core/docs/Part6/6.7.3/
352
410
 
353
- debugLog("prematureTerminate", err ? err.message : "", statusCode.toString());
411
+ debugLog("prematureTerminate", err ? err.message : "", statusCode.toString(), "has socket = ", !!this._socket);
412
+
413
+ doDebugFlow && console.log("prematureTerminate from", "has socket = ", !!this._socket, new Error().stack);
354
414
 
355
415
  if (this._socket) {
356
416
  err.message = "premature socket termination " + err.message;
357
417
  // we consider this as an error
358
418
  const _s = this._socket;
359
- _s.end();
360
- _s.destroy(); // new Error("Socket has timed out"));
361
- _s.emit("error", err);
362
419
  this._socket = null;
420
+ _s.destroy(err);
363
421
  this.dispose();
364
422
  }
365
- // this.gracefullShutdown(err);
366
423
  }
367
424
  /**
368
425
  * @method _install_one_time_message_receiver
@@ -381,31 +438,22 @@ export class TCP_transport extends EventEmitter {
381
438
  protected _install_one_time_message_receiver(callback: CallbackWithData): void {
382
439
  assert(!this._theCallback, "callback already set");
383
440
  assert(typeof callback === "function");
384
- this._theCallback = callback;
385
- this._start_one_time_message_receiver();
441
+ this._start_one_time_message_receiver(callback);
386
442
  }
387
443
 
388
444
  private _fulfill_pending_promises(err: Error | null, data?: Buffer): boolean {
389
- this._cleanup_timers();
390
-
391
- if (this._socket && this._on_error_during_one_time_message_receiver) {
392
- this._socket.removeListener("close", this._on_error_during_one_time_message_receiver);
393
- this._on_error_during_one_time_message_receiver = null;
394
- }
395
-
445
+ if (!this._theCallback) return false;
446
+ doDebugFlow && console.log("_fulfill_pending_promises from", new Error().stack);
396
447
  const callback = this._theCallback;
397
448
  this._theCallback = undefined;
398
-
399
- if (callback) {
400
- callback(err, data);
401
- return true;
402
- }
403
- return false;
449
+ callback(err, data);
450
+ return true;
404
451
  }
405
452
 
406
453
  private _on_message_chunk_received(messageChunk: Buffer) {
407
454
  if (doTraceIncomingChunk) {
408
- console.log(hexDump(messageChunk));
455
+ warningLog("Transport", this.name);
456
+ warningLog(hexDump(messageChunk));
409
457
  }
410
458
  const hadCallback = this._fulfill_pending_promises(null, messageChunk);
411
459
  this.chunkReadCount++;
@@ -421,34 +469,49 @@ export class TCP_transport extends EventEmitter {
421
469
  }
422
470
  }
423
471
 
424
- private _start_one_time_message_receiver() {
425
- assert(!this._timerId, "timer already started");
472
+ private _start_one_time_message_receiver(callback: CallbackWithData) {
473
+ assert(!this._timerId && !this._on_error_during_one_time_message_receiver, "timer already started");
426
474
 
475
+ const _cleanUp = () => {
476
+ this._cleanup_timers();
477
+ if (this._on_error_during_one_time_message_receiver) {
478
+ this._socket?.removeListener("close", this._on_error_during_one_time_message_receiver);
479
+ this._on_error_during_one_time_message_receiver = undefined;
480
+ }
481
+ };
482
+
483
+ const onTimeout = () => {
484
+ _cleanUp();
485
+ this._fulfill_pending_promises(
486
+ new Error(`Timeout(A) in waiting for data on socket ( timeout was = ${this.timeout} ms)`)
487
+ );
488
+ this.dispose();
489
+ };
427
490
  // Setup timeout detection timer ....
428
491
  this._timerId = setTimeout(() => {
429
492
  this._timerId = null;
430
- this._fulfill_pending_promises(new Error(`Timeout in waiting for data on socket ( timeout was = ${this.timeout} ms)`));
493
+ onTimeout();
431
494
  }, this.timeout);
432
495
 
433
496
  // also monitored
434
497
  if (this._socket) {
435
498
  // to do = intercept socket error as well
436
- this._on_error_during_one_time_message_receiver = (err?: Error) => {
437
- this._fulfill_pending_promises(
438
- new Error(`ERROR in waiting for data on socket ( timeout was = ${this.timeout} ms) ` + err?.message)
499
+ this._on_error_during_one_time_message_receiver = (hadError: boolean) => {
500
+ const err = new Error(
501
+ `ERROR in waiting for data on socket ( timeout was = ${this.timeout} ms) hadError` + hadError
439
502
  );
503
+ this._emitClose(err);
504
+ this._fulfill_pending_promises(err);
440
505
  };
441
- this._socket.on("close", this._on_error_during_one_time_message_receiver);
506
+ this._socket.prependOnceListener("close", this._on_error_during_one_time_message_receiver);
442
507
  }
443
- }
444
508
 
445
- private on_socket_closed(err?: Error) {
446
- if (this._onSocketClosedHasBeenCalled) {
447
- return;
448
- }
449
- assert(!this._onSocketClosedHasBeenCalled);
450
- this._onSocketClosedHasBeenCalled = true; // we don't want to send close event twice ...
451
- this.emit("socket_closed", err || null);
509
+ const _callback = callback;
510
+ this._theCallback = (err?: Error | null, data?: Buffer) => {
511
+ _cleanUp();
512
+ this._theCallback = undefined;
513
+ _callback(err!, data);
514
+ };
452
515
  }
453
516
 
454
517
  private _on_socket_data(data: Buffer): void {
@@ -465,59 +528,65 @@ export class TCP_transport extends EventEmitter {
465
528
  private _on_socket_close(hadError: boolean) {
466
529
  // istanbul ignore next
467
530
  if (doDebug) {
468
- debugLog(chalk.red(" SOCKET CLOSE : "), chalk.yellow("had_error ="), chalk.cyan(hadError.toString()), this.name);
531
+ debugLog(chalk.red(` SOCKET CLOSE ${this.name}: `), chalk.yellow("had_error ="), chalk.cyan(hadError.toString()));
469
532
  }
470
- if (this._socket) {
471
- debugLog(
472
- " remote address = ",
473
- this._socket.remoteAddress,
474
- " ",
475
- this._socket.remoteFamily,
476
- " ",
477
- this._socket.remotePort
478
- );
479
- }
480
- if (hadError) {
481
- if (this._socket) {
482
- this._socket.destroy();
483
- }
484
- }
485
- const err = hadError ? new Error("ERROR IN SOCKET " + hadError.toString()) : undefined;
486
- this.on_socket_closed(err);
487
533
  this.dispose();
534
+ if (this._theCallback) return;
535
+ // if (hadError) {
536
+ // if (this._socket) {
537
+ // this._socket.destroy();
538
+ // }
539
+ // }
540
+ this._emitClose();
488
541
  }
489
542
 
490
- private _on_socket_ended_message(err?: Error) {
491
- if (this._disconnecting) {
492
- return;
493
- }
494
-
495
- debugLog(chalk.red("Transport Connection ended") + " " + this.name);
496
- assert(!this._disconnecting);
497
- err = err || new Error("_socket has been disconnected by third party");
543
+ protected _emitClose(err?: Error | null) {
544
+ err = err || this._theCloseError;
545
+ doDebugFlow && console.log("_emitClose ", err?.message || "", "from", new Error().stack);
498
546
 
499
- this.on_socket_ended(err);
500
-
501
- this._disconnecting = true;
502
-
503
- debugLog(" bytesRead = ", this.bytesRead);
504
- debugLog(" bytesWritten = ", this.bytesWritten);
505
- this._fulfill_pending_promises(new Error("Connection aborted - ended by server : " + (err ? err.message : "")));
547
+ if (!this._closedEmitted) {
548
+ this._closedEmitted = err || "noError";
549
+ this.emit("close", err || null);
550
+ // if (this._theCallback) {
551
+ // const callback = this._theCallback;
552
+ // this._theCallback = undefined;
553
+ // callback(err || null);
554
+ // }
555
+ } else {
556
+ debugLog("Already emitted close event", (this._closedEmitted as any).message);
557
+ debugLog("err = ", err?.message);
558
+ debugLog("");
559
+ debugLog("Already emitted close event", this._closedEmitted);
560
+ debugLog("err = ", err?.message, err);
561
+ }
506
562
  }
507
563
 
508
- private _on_socket_end(err: Error) {
564
+ private _on_socket_end() {
509
565
  // istanbul ignore next
510
- if (doDebug) {
511
- debugLog(chalk.red(" SOCKET END : err="), chalk.yellow(err ? err.message : "null"), this.name);
566
+ doDebug && debugLog(chalk.red(` SOCKET END : ${this.name}`), "is disconnecting ", this.isDisconnecting());
567
+ if (this.isDisconnecting()) {
568
+ return;
512
569
  }
513
- this._on_socket_ended_message(err);
570
+ //
571
+ debugLog(chalk.red(" Transport Connection ended") + " " + this.name);
572
+ const err = new Error(this.name + ": socket has been disconnected by third party");
573
+ debugLog(" bytesRead = ", this.bytesRead);
574
+ debugLog(" bytesWritten = ", this.bytesWritten);
575
+ this._theCloseError = err;
576
+
577
+ this._fulfill_pending_promises(new Error("Connection aborted - ended by server : " + (err ? err.message : "")));
514
578
  }
515
579
 
516
580
  private _on_socket_error(err: Error) {
517
581
  // istanbul ignore next
518
- if (doDebug) {
519
- debugLog(chalk.red(" SOCKET ERROR : "), chalk.yellow(err.message), this.name);
520
- }
582
+ debugLog(chalk.red(` _on_socket_error: ${this.name}`), chalk.yellow(err.message));
521
583
  // node The "close" event will be called directly following this event.
584
+ // this._emitClose(err);
585
+ }
586
+
587
+ private _on_socket_timeout() {
588
+ const msg = `socket timeout : timeout=${this.timeout} ${this.name}`;
589
+ doDebug && debugLog(msg);
590
+ this.prematureTerminate(new Error(msg), StatusCodes2.BadTimeout);
522
591
  }
523
592
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"direct_transport.js","sourceRoot":"","sources":["../../test_helpers/direct_transport.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AACtC,yDAA2C;AAC3C,sCAA6C;AAC7C,yDAAoD;AAKpD,MAAa,eAAgB,SAAQ,qBAAY;IAM7C;QACI,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,MAAM,GAAG,IAAI,iCAAc,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,IAAI,iCAAc,EAAE,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACjC,IAAA,0BAAM,EAAC,IAAI,YAAY,MAAM,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACjC,IAAA,0BAAM,EAAC,IAAI,YAAY,MAAM,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE;YAClC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAChC,IAAI,IAAI,EAAE;gBACN,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;aAC3B;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,GAAG,mCAAmC,CAAC;IACnD,CAAC;IAEM,UAAU,CAAC,IAAgB;QAC9B,IAAA,yBAAgB,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,EAAE,CAAC;IACX,CAAC;IAEM,QAAQ,CAAC,IAAgB;QAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAClB,IAAI,IAAI,EAAE;YACN,YAAY,CAAC,IAAI,CAAC,CAAC;SACtB;IACL,CAAC;IAEM,WAAW;QACd,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;YAClB,OAAO,IAAI,CAAC;SACf;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC;IAEM,YAAY,CAAC,IAAoD;QACpE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACJ;AAnED,0CAmEC"}
@@ -1,10 +0,0 @@
1
- import { FakeServer } from "./fake_server";
2
- export declare class SocketTransport extends FakeServer {
3
- private client;
4
- private server?;
5
- constructor({ port }: {
6
- port: number;
7
- });
8
- initialize(done: () => void): void;
9
- shutdown(done: (err?: Error) => void): void;
10
- }
@@ -1,31 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SocketTransport = void 0;
4
- // tslint:disable:no-empty
5
- const net = require("net");
6
- const fake_server_1 = require("./fake_server");
7
- class SocketTransport extends fake_server_1.FakeServer {
8
- constructor({ port }) {
9
- super({ port });
10
- this.client = new net.Socket();
11
- this.client.connect(this.port, (err) => {
12
- /** */
13
- });
14
- }
15
- initialize(done) {
16
- super.initialize(() => {
17
- this.tcpServer.on("connection", (socket) => {
18
- this.server = this._serverSocket;
19
- done();
20
- });
21
- });
22
- }
23
- shutdown(done) {
24
- this.client.end();
25
- super.shutdown((err) => {
26
- done(err);
27
- });
28
- }
29
- }
30
- exports.SocketTransport = SocketTransport;
31
- //# sourceMappingURL=socket_transport.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"socket_transport.js","sourceRoot":"","sources":["../../test_helpers/socket_transport.ts"],"names":[],"mappings":";;;AAAA,0BAA0B;AAC1B,2BAA2B;AAC3B,+CAA2C;AAE3C,MAAa,eAAgB,SAAQ,wBAAU;IAI3C,YAAY,EAAE,IAAI,EAAoB;QAClC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAEhB,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAW,EAAQ,EAAE;YACjD,MAAM;QACV,CAAC,CAAC,CAAC;IACP,CAAC;IAEM,UAAU,CAAC,IAAgB;QAC9B,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE;YAClB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAkB,EAAE,EAAE;gBACnD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC;gBACjC,IAAI,EAAE,CAAC;YACX,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;IAEM,QAAQ,CAAC,IAA2B;QACvC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAClB,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAW,EAAE,EAAE;YAC3B,IAAI,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACP,CAAC;CACJ;AA5BD,0CA4BC"}