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/source/tcp_transport.ts
CHANGED
|
@@ -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(
|
|
21
|
-
const doDebug = checkDebugFlag(
|
|
22
|
-
const errorLog = make_errorLog(
|
|
23
|
-
const warningLog = make_warningLog(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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():
|
|
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:
|
|
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
|
|
113
|
-
private
|
|
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 =
|
|
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
|
|
210
|
-
return this.
|
|
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
|
-
|
|
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
|
-
|
|
236
|
-
this.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
|
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
|
-
|
|
303
|
-
|
|
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", (
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 = (
|
|
437
|
-
|
|
438
|
-
|
|
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.
|
|
506
|
+
this._socket.prependOnceListener("close", this._on_error_during_one_time_message_receiver);
|
|
442
507
|
}
|
|
443
|
-
}
|
|
444
508
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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(
|
|
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
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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.
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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(
|
|
564
|
+
private _on_socket_end() {
|
|
509
565
|
// istanbul ignore next
|
|
510
|
-
|
|
511
|
-
|
|
566
|
+
doDebug && debugLog(chalk.red(` SOCKET END : ${this.name}`), "is disconnecting ", this.isDisconnecting());
|
|
567
|
+
if (this.isDisconnecting()) {
|
|
568
|
+
return;
|
|
512
569
|
}
|
|
513
|
-
|
|
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
|
-
|
|
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"}
|