@libp2p/tcp 10.1.19 → 11.0.0-049bfa0fa
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/index.min.js +1 -1
- package/dist/index.min.js.map +4 -4
- package/dist/src/index.d.ts +0 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/listener.d.ts +3 -4
- package/dist/src/listener.d.ts.map +1 -1
- package/dist/src/listener.js +14 -12
- package/dist/src/listener.js.map +1 -1
- package/dist/src/socket-to-conn.d.ts +5 -12
- package/dist/src/socket-to-conn.d.ts.map +1 -1
- package/dist/src/socket-to-conn.js +98 -173
- package/dist/src/socket-to-conn.js.map +1 -1
- package/dist/src/tcp.d.ts.map +1 -1
- package/dist/src/tcp.js +9 -9
- package/dist/src/tcp.js.map +1 -1
- package/dist/src/utils.d.ts +1 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +18 -8
- package/dist/src/utils.js.map +1 -1
- package/package.json +11 -11
- package/src/index.ts +0 -5
- package/src/listener.ts +16 -15
- package/src/socket-to-conn.ts +114 -200
- package/src/tcp.ts +9 -9
- package/src/utils.ts +19 -8
- package/dist/typedoc-urls.json +0 -20
package/dist/src/utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Multiaddr } from '@multiformats/multiaddr';
|
|
2
2
|
import type { ListenOptions, IpcSocketConnectOpts, TcpSocketConnectOpts } from 'net';
|
|
3
3
|
export type NetConfig = ListenOptions | (IpcSocketConnectOpts & TcpSocketConnectOpts);
|
|
4
|
-
export declare function multiaddrToNetConfig(addr: Multiaddr,
|
|
4
|
+
export declare function multiaddrToNetConfig(addr: Multiaddr, options?: NetConfig): NetConfig;
|
|
5
5
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/src/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,KAAK,CAAA;AAEpF,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,CAAA;AAErF,wBAAgB,oBAAoB,CAAE,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,SAAc,GAAG,SAAS,CA4BzF"}
|
package/dist/src/utils.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import os from 'os';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import { InvalidParametersError } from '@libp2p/interface';
|
|
4
|
+
import { getNetConfig } from '@libp2p/utils';
|
|
5
|
+
import { CODE_UNIX } from '@multiformats/multiaddr';
|
|
6
|
+
import { Unix } from '@multiformats/multiaddr-matcher';
|
|
7
|
+
export function multiaddrToNetConfig(addr, options = {}) {
|
|
8
|
+
if (Unix.exactMatch(addr)) {
|
|
9
|
+
const listenPath = addr.getComponents().find(c => c.code === CODE_UNIX)?.value;
|
|
10
|
+
if (listenPath == null) {
|
|
11
|
+
throw new InvalidParametersError(`Multiaddr ${addr} was not a Unix address`);
|
|
12
|
+
}
|
|
13
|
+
// unix socket listening
|
|
7
14
|
if (os.platform() === 'win32') {
|
|
8
15
|
// Use named pipes on Windows systems.
|
|
9
16
|
return { path: path.join('\\\\.\\pipe\\', listenPath) };
|
|
@@ -12,12 +19,15 @@ export function multiaddrToNetConfig(addr, config = {}) {
|
|
|
12
19
|
return { path: listenPath };
|
|
13
20
|
}
|
|
14
21
|
}
|
|
15
|
-
const
|
|
22
|
+
const config = getNetConfig(addr);
|
|
23
|
+
const host = config.host;
|
|
24
|
+
const port = config.port;
|
|
16
25
|
// tcp listening
|
|
17
26
|
return {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
ipv6Only:
|
|
27
|
+
host,
|
|
28
|
+
port,
|
|
29
|
+
ipv6Only: config.type === 'ip6',
|
|
30
|
+
...options
|
|
21
31
|
};
|
|
22
32
|
}
|
|
23
33
|
//# sourceMappingURL=utils.js.map
|
package/dist/src/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAA;AAMtD,MAAM,UAAU,oBAAoB,CAAE,IAAe,EAAE,UAAqB,EAAE;IAC5E,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,KAAK,CAAA;QAE9E,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,sBAAsB,CAAC,aAAa,IAAI,yBAAyB,CAAC,CAAA;QAC9E,CAAC;QAED,wBAAwB;QACxB,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;YAC9B,sCAAsC;YACtC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,EAAE,CAAA;QACzD,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAA;QAC7B,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;IACjC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;IACxB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;IAExB,gBAAgB;IAChB,OAAO;QACL,IAAI;QACJ,IAAI;QACJ,QAAQ,EAAE,MAAM,CAAC,IAAI,KAAK,KAAK;QAC/B,GAAG,OAAO;KACX,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/tcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0-049bfa0fa",
|
|
4
4
|
"description": "A TCP transport for libp2p",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/transport-tcp#readme",
|
|
@@ -53,23 +53,23 @@
|
|
|
53
53
|
"test:electron-main": "aegir test -t electron-main"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@libp2p/interface": "
|
|
57
|
-
"@libp2p/utils": "
|
|
58
|
-
"@multiformats/multiaddr": "^
|
|
59
|
-
"@multiformats/multiaddr-matcher": "^
|
|
56
|
+
"@libp2p/interface": "3.0.0-049bfa0fa",
|
|
57
|
+
"@libp2p/utils": "7.0.0-049bfa0fa",
|
|
58
|
+
"@multiformats/multiaddr": "^13.0.1",
|
|
59
|
+
"@multiformats/multiaddr-matcher": "^3.0.1",
|
|
60
60
|
"@types/sinon": "^17.0.4",
|
|
61
61
|
"main-event": "^1.0.1",
|
|
62
|
-
"p-defer": "^4.0.1",
|
|
63
62
|
"p-event": "^6.0.1",
|
|
64
63
|
"progress-events": "^1.0.1",
|
|
65
|
-
"
|
|
66
|
-
"stream-to-it": "^1.0.1"
|
|
64
|
+
"uint8arraylist": "^2.4.8"
|
|
67
65
|
},
|
|
68
66
|
"devDependencies": {
|
|
69
|
-
"@libp2p/logger": "
|
|
70
|
-
"aegir": "^47.0.
|
|
67
|
+
"@libp2p/logger": "6.0.0-049bfa0fa",
|
|
68
|
+
"aegir": "^47.0.22",
|
|
69
|
+
"delay": "^6.0.0",
|
|
70
|
+
"p-defer": "^4.0.1",
|
|
71
71
|
"p-wait-for": "^5.0.2",
|
|
72
|
-
"sinon": "^
|
|
72
|
+
"sinon": "^21.0.0",
|
|
73
73
|
"sinon-ts": "^2.0.0",
|
|
74
74
|
"wherearewe": "^2.0.1"
|
|
75
75
|
},
|
package/src/index.ts
CHANGED
|
@@ -59,11 +59,6 @@ export interface TCPOptions {
|
|
|
59
59
|
*/
|
|
60
60
|
outboundSocketInactivityTimeout?: number
|
|
61
61
|
|
|
62
|
-
/**
|
|
63
|
-
* When closing a socket, wait this long for it to close gracefully before it is closed more forcibly
|
|
64
|
-
*/
|
|
65
|
-
socketCloseTimeout?: number
|
|
66
|
-
|
|
67
62
|
/**
|
|
68
63
|
* Set this property to reject connections when the server's connection count gets high.
|
|
69
64
|
* https://nodejs.org/api/net.html#servermaxconnections
|
package/src/listener.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import net from 'net'
|
|
1
|
+
import net from 'node:net'
|
|
2
2
|
import { AlreadyStartedError, InvalidParametersError, NotStartedError } from '@libp2p/interface'
|
|
3
|
-
import { getThinWaistAddresses } from '@libp2p/utils
|
|
3
|
+
import { getThinWaistAddresses } from '@libp2p/utils'
|
|
4
4
|
import { multiaddr } from '@multiformats/multiaddr'
|
|
5
5
|
import { TypedEventEmitter, setMaxListeners } from 'main-event'
|
|
6
6
|
import { pEvent } from 'p-event'
|
|
@@ -8,13 +8,12 @@ import { toMultiaddrConnection } from './socket-to-conn.js'
|
|
|
8
8
|
import { multiaddrToNetConfig } from './utils.js'
|
|
9
9
|
import type { CloseServerOnMaxConnectionsOpts, TCPCreateListenerOptions } from './index.js'
|
|
10
10
|
import type { NetConfig } from './utils.js'
|
|
11
|
-
import type { ComponentLogger, Logger, MultiaddrConnection, CounterGroup, MetricGroup, Metrics, Listener, ListenerEvents, Upgrader } from '@libp2p/interface'
|
|
11
|
+
import type { ComponentLogger, Logger, MultiaddrConnection, CounterGroup, MetricGroup, Metrics, Listener, ListenerEvents, Upgrader, AbortOptions } from '@libp2p/interface'
|
|
12
12
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
13
13
|
|
|
14
14
|
interface Context extends TCPCreateListenerOptions {
|
|
15
15
|
upgrader: Upgrader
|
|
16
|
-
|
|
17
|
-
socketCloseTimeout?: number
|
|
16
|
+
inactivityTimeout?: number
|
|
18
17
|
maxConnections?: number
|
|
19
18
|
backlog?: number
|
|
20
19
|
metrics?: Metrics
|
|
@@ -61,6 +60,7 @@ export class TCPListener extends TypedEventEmitter<ListenerEvents> implements Li
|
|
|
61
60
|
|
|
62
61
|
context.keepAlive = context.keepAlive ?? true
|
|
63
62
|
context.noDelay = context.noDelay ?? true
|
|
63
|
+
context.allowHalfOpen = context.allowHalfOpen ?? false
|
|
64
64
|
|
|
65
65
|
this.shutdownController = new AbortController()
|
|
66
66
|
setMaxListeners(Infinity, this.shutdownController.signal)
|
|
@@ -161,14 +161,14 @@ export class TCPListener extends TypedEventEmitter<ListenerEvents> implements Li
|
|
|
161
161
|
|
|
162
162
|
let maConn: MultiaddrConnection
|
|
163
163
|
try {
|
|
164
|
-
maConn = toMultiaddrConnection(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
socketCloseTimeout: this.context.socketCloseTimeout,
|
|
164
|
+
maConn = toMultiaddrConnection({
|
|
165
|
+
socket,
|
|
166
|
+
inactivityTimeout: this.context.inactivityTimeout,
|
|
168
167
|
metrics: this.metrics?.events,
|
|
169
168
|
metricPrefix: `${this.addr} `,
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
direction: 'inbound',
|
|
170
|
+
localAddr: this.status.listeningAddr,
|
|
171
|
+
log: this.context.logger.forComponent('libp2p:tcp:connection')
|
|
172
172
|
})
|
|
173
173
|
} catch (err: any) {
|
|
174
174
|
this.log.error('inbound connection failed', err)
|
|
@@ -210,6 +210,7 @@ export class TCPListener extends TypedEventEmitter<ListenerEvents> implements Li
|
|
|
210
210
|
this.context.closeServerOnMaxConnections != null &&
|
|
211
211
|
this.sockets.size >= this.context.closeServerOnMaxConnections.closeAbove
|
|
212
212
|
) {
|
|
213
|
+
this.log('pausing incoming connections as limit is exceeded - %d/%d', this.sockets.size, this.context.closeServerOnMaxConnections.closeAbove)
|
|
213
214
|
this.pause()
|
|
214
215
|
}
|
|
215
216
|
})
|
|
@@ -264,11 +265,11 @@ export class TCPListener extends TypedEventEmitter<ListenerEvents> implements Li
|
|
|
264
265
|
}
|
|
265
266
|
}
|
|
266
267
|
|
|
267
|
-
async close (): Promise<void> {
|
|
268
|
+
async close (options?: AbortOptions): Promise<void> {
|
|
268
269
|
const events: Array<Promise<void>> = []
|
|
269
270
|
|
|
270
271
|
if (this.server.listening) {
|
|
271
|
-
events.push(pEvent(this.server, 'close'))
|
|
272
|
+
events.push(pEvent(this.server, 'close', options))
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
// shut down the server socket, permanently
|
|
@@ -281,7 +282,7 @@ export class TCPListener extends TypedEventEmitter<ListenerEvents> implements Li
|
|
|
281
282
|
// the server socket in case new sockets are opened during the shutdown
|
|
282
283
|
this.sockets.forEach(socket => {
|
|
283
284
|
if (socket.readable) {
|
|
284
|
-
events.push(pEvent(socket, 'close'))
|
|
285
|
+
events.push(pEvent(socket, 'close', options))
|
|
285
286
|
socket.destroy()
|
|
286
287
|
}
|
|
287
288
|
})
|
|
@@ -320,7 +321,7 @@ export class TCPListener extends TypedEventEmitter<ListenerEvents> implements Li
|
|
|
320
321
|
return
|
|
321
322
|
}
|
|
322
323
|
|
|
323
|
-
this.log('
|
|
324
|
+
this.log('%s server on %s', permanent ? 'closing' : 'pausing', this.server.address())
|
|
324
325
|
|
|
325
326
|
// NodeJS implementation tracks listening status with `this._handle` property.
|
|
326
327
|
// - Server.close() sets this._handle to null immediately. If this._handle is null, NotStartedError is thrown
|
package/src/socket-to-conn.ts
CHANGED
|
@@ -1,230 +1,144 @@
|
|
|
1
1
|
import { InvalidParametersError, TimeoutError } from '@libp2p/interface'
|
|
2
|
-
import { ipPortToMultiaddr
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import type { ComponentLogger, MultiaddrConnection, CounterGroup } from '@libp2p/interface'
|
|
9
|
-
import type { AbortOptions, Multiaddr } from '@multiformats/multiaddr'
|
|
2
|
+
import { AbstractMultiaddrConnection, ipPortToMultiaddr } from '@libp2p/utils'
|
|
3
|
+
import { Unix } from '@multiformats/multiaddr-matcher'
|
|
4
|
+
import { pEvent } from 'p-event'
|
|
5
|
+
import type { AbortOptions, MultiaddrConnection } from '@libp2p/interface'
|
|
6
|
+
import type { AbstractMultiaddrConnectionInit, SendResult } from '@libp2p/utils'
|
|
7
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
10
8
|
import type { Socket } from 'net'
|
|
11
|
-
import type {
|
|
9
|
+
import type { Uint8ArrayList } from 'uint8arraylist'
|
|
12
10
|
|
|
13
|
-
interface
|
|
14
|
-
|
|
11
|
+
export interface TCPSocketMultiaddrConnectionInit extends Omit<AbstractMultiaddrConnectionInit, 'name' | 'stream' | 'remoteAddr'> {
|
|
12
|
+
socket: Socket
|
|
15
13
|
remoteAddr?: Multiaddr
|
|
16
|
-
localAddr?: Multiaddr
|
|
17
|
-
socketInactivityTimeout?: number
|
|
18
|
-
socketCloseTimeout?: number
|
|
19
|
-
metrics?: CounterGroup
|
|
20
|
-
metricPrefix?: string
|
|
21
|
-
logger: ComponentLogger
|
|
22
|
-
direction: 'inbound' | 'outbound'
|
|
23
14
|
}
|
|
24
15
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* https://github.com/libp2p/interface-transport#multiaddrconnection
|
|
28
|
-
*/
|
|
29
|
-
export const toMultiaddrConnection = (socket: Socket, options: ToConnectionOptions): MultiaddrConnection => {
|
|
30
|
-
let closePromise: DeferredPromise<void>
|
|
31
|
-
const direction = options.direction
|
|
32
|
-
const metrics = options.metrics
|
|
33
|
-
const metricPrefix = options.metricPrefix ?? ''
|
|
34
|
-
const inactivityTimeout = options.socketInactivityTimeout ?? SOCKET_TIMEOUT
|
|
35
|
-
const closeTimeout = options.socketCloseTimeout ?? CLOSE_TIMEOUT
|
|
36
|
-
let timedOut = false
|
|
37
|
-
let errored = false
|
|
38
|
-
|
|
39
|
-
// Check if we are connected on a unix path
|
|
40
|
-
if (options.listeningAddr?.getPath() != null) {
|
|
41
|
-
options.remoteAddr = options.listeningAddr
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (options.remoteAddr?.getPath() != null) {
|
|
45
|
-
options.localAddr = options.remoteAddr
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// handle socket errors
|
|
49
|
-
socket.on('error', err => {
|
|
50
|
-
errored = true
|
|
51
|
-
|
|
52
|
-
if (!timedOut) {
|
|
53
|
-
maConn.log.error('%s socket error - %e', direction, err)
|
|
54
|
-
metrics?.increment({ [`${metricPrefix}error`]: true })
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
socket.destroy()
|
|
58
|
-
maConn.timeline.close = Date.now()
|
|
59
|
-
})
|
|
16
|
+
class TCPSocketMultiaddrConnection extends AbstractMultiaddrConnection {
|
|
17
|
+
private socket: Socket
|
|
60
18
|
|
|
61
|
-
|
|
19
|
+
constructor (init: TCPSocketMultiaddrConnectionInit) {
|
|
20
|
+
let remoteAddr = init.remoteAddr
|
|
62
21
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
remoteAddr = toMultiaddr(socket.remoteAddress, socket.remotePort)
|
|
73
|
-
}
|
|
22
|
+
// check if we are connected on a unix path
|
|
23
|
+
if (init.localAddr != null && Unix.matches(init.localAddr)) {
|
|
24
|
+
remoteAddr = init.localAddr
|
|
25
|
+
} else if (remoteAddr == null) {
|
|
26
|
+
if (init.socket.remoteAddress == null || init.socket.remotePort == null) {
|
|
27
|
+
// this can be undefined if the socket is destroyed (for example, if the client disconnected)
|
|
28
|
+
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketremoteaddress
|
|
29
|
+
throw new InvalidParametersError('Could not determine remote address or port')
|
|
30
|
+
}
|
|
74
31
|
|
|
75
|
-
|
|
76
|
-
const lOptsStr = lOpts.path ?? `${lOpts.host ?? ''}:${lOpts.port ?? ''}`
|
|
77
|
-
const { sink, source } = duplex(socket)
|
|
78
|
-
|
|
79
|
-
// by default there is no timeout
|
|
80
|
-
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketsettimeouttimeout-callback
|
|
81
|
-
socket.setTimeout(inactivityTimeout)
|
|
82
|
-
|
|
83
|
-
socket.once('timeout', () => {
|
|
84
|
-
timedOut = true
|
|
85
|
-
maConn.log('%s %s socket read timeout', direction, lOptsStr)
|
|
86
|
-
metrics?.increment({ [`${metricPrefix}timeout`]: true })
|
|
87
|
-
|
|
88
|
-
// if the socket times out due to inactivity we must manually close the connection
|
|
89
|
-
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#event-timeout
|
|
90
|
-
socket.destroy(new TimeoutError())
|
|
91
|
-
maConn.timeline.close = Date.now()
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
socket.once('close', () => {
|
|
95
|
-
// record metric for clean exit
|
|
96
|
-
if (!timedOut && !errored) {
|
|
97
|
-
maConn.log('%s %s socket close', direction, lOptsStr)
|
|
98
|
-
metrics?.increment({ [`${metricPrefix}close`]: true })
|
|
32
|
+
remoteAddr = ipPortToMultiaddr(init.socket.remoteAddress, init.socket.remotePort)
|
|
99
33
|
}
|
|
100
34
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
35
|
+
super({
|
|
36
|
+
...init,
|
|
37
|
+
remoteAddr
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
this.socket = init.socket
|
|
41
|
+
|
|
42
|
+
// handle incoming data
|
|
43
|
+
this.socket.on('data', buf => {
|
|
44
|
+
this.onData(buf)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// handle socket errors
|
|
48
|
+
this.socket.on('error', err => {
|
|
49
|
+
this.log('tcp error', remoteAddr, err)
|
|
50
|
+
|
|
51
|
+
this.abort(err)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// by default there is no timeout
|
|
55
|
+
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketsettimeouttimeout-callback
|
|
56
|
+
this.socket.setTimeout(init.inactivityTimeout ?? (2 * 60 * 1_000))
|
|
57
|
+
|
|
58
|
+
this.socket.once('timeout', () => {
|
|
59
|
+
this.log('tcp timeout', remoteAddr)
|
|
60
|
+
// if the socket times out due to inactivity we must manually close the connection
|
|
61
|
+
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#event-timeout
|
|
62
|
+
this.abort(new TimeoutError())
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
this.socket.once('end', () => {
|
|
66
|
+
this.log('tcp end', remoteAddr)
|
|
67
|
+
|
|
68
|
+
// the remote sent a FIN packet which means no more data will be sent
|
|
69
|
+
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#event-end
|
|
70
|
+
// half open TCP sockets are disabled by default so Node.js should send a
|
|
71
|
+
// FIN in response to this event and then emit a 'close' event, during
|
|
72
|
+
// which we tear down the MultiaddrConnection so there is nothing to do
|
|
73
|
+
// until that occurs
|
|
74
|
+
this.onTransportClosed()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
this.socket.once('close', hadError => {
|
|
78
|
+
this.log('tcp close', remoteAddr)
|
|
79
|
+
|
|
80
|
+
if (hadError) {
|
|
81
|
+
this.abort(new Error('TCP transmission error'))
|
|
82
|
+
return
|
|
135
83
|
}
|
|
136
84
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
},
|
|
85
|
+
this.onTransportClosed()
|
|
86
|
+
})
|
|
140
87
|
|
|
141
|
-
|
|
88
|
+
// the socket can accept more data
|
|
89
|
+
this.socket.on('drain', () => {
|
|
90
|
+
this.log('tcp drain')
|
|
142
91
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
timeline: { open: Date.now() },
|
|
92
|
+
this.safeDispatchEvent('drain')
|
|
93
|
+
})
|
|
94
|
+
}
|
|
147
95
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return
|
|
152
|
-
}
|
|
96
|
+
sendData (data: Uint8ArrayList): SendResult {
|
|
97
|
+
let sentBytes = 0
|
|
98
|
+
let canSendMore = true
|
|
153
99
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
100
|
+
for (const buf of data) {
|
|
101
|
+
sentBytes += buf.byteLength
|
|
102
|
+
canSendMore = this.socket.write(buf)
|
|
158
103
|
|
|
159
|
-
if (
|
|
160
|
-
|
|
104
|
+
if (!canSendMore) {
|
|
105
|
+
break
|
|
161
106
|
}
|
|
107
|
+
}
|
|
162
108
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
// convert EventEmitter to EventTarget
|
|
170
|
-
const eventTarget = socketToEventTarget(socket)
|
|
171
|
-
|
|
172
|
-
// don't wait forever to close
|
|
173
|
-
const signal = options.signal ?? AbortSignal.timeout(closeTimeout)
|
|
174
|
-
|
|
175
|
-
// wait for any unsent data to be sent
|
|
176
|
-
if (socket.writableLength > 0) {
|
|
177
|
-
maConn.log('%s %s draining socket', direction, lOptsStr)
|
|
178
|
-
await raceEvent(eventTarget, 'drain', signal, {
|
|
179
|
-
errorEvent: 'error'
|
|
180
|
-
})
|
|
181
|
-
maConn.log('%s %s socket drained', direction, lOptsStr)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
await Promise.all([
|
|
185
|
-
raceEvent(eventTarget, 'close', signal, {
|
|
186
|
-
errorEvent: 'error'
|
|
187
|
-
}),
|
|
188
|
-
|
|
189
|
-
// all bytes have been sent we can destroy the socket
|
|
190
|
-
socket.destroy()
|
|
191
|
-
])
|
|
192
|
-
} catch (err: any) {
|
|
193
|
-
this.abort(err)
|
|
194
|
-
} finally {
|
|
195
|
-
closePromise.resolve()
|
|
196
|
-
}
|
|
197
|
-
},
|
|
109
|
+
return {
|
|
110
|
+
sentBytes,
|
|
111
|
+
canSendMore
|
|
112
|
+
}
|
|
113
|
+
}
|
|
198
114
|
|
|
199
|
-
|
|
200
|
-
|
|
115
|
+
async sendClose (options?: AbortOptions): Promise<void> {
|
|
116
|
+
if (this.socket.destroyed) {
|
|
117
|
+
return
|
|
118
|
+
}
|
|
201
119
|
|
|
202
|
-
|
|
203
|
-
socket.destroy()
|
|
120
|
+
this.socket.destroySoon()
|
|
204
121
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
// set the close time here. the tests should be refactored to reflect
|
|
208
|
-
// reality.
|
|
209
|
-
maConn.timeline.close = Date.now()
|
|
210
|
-
},
|
|
122
|
+
await pEvent(this.socket, 'close', options)
|
|
123
|
+
}
|
|
211
124
|
|
|
212
|
-
|
|
125
|
+
sendReset (): void {
|
|
126
|
+
this.socket.resetAndDestroy()
|
|
213
127
|
}
|
|
214
128
|
|
|
215
|
-
|
|
216
|
-
|
|
129
|
+
sendPause (): void {
|
|
130
|
+
this.socket.pause()
|
|
131
|
+
}
|
|
217
132
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
addEventListener: (type: any, cb: any) => {
|
|
221
|
-
obj.addListener(type, cb)
|
|
222
|
-
},
|
|
223
|
-
removeEventListener: (type: any, cb: any) => {
|
|
224
|
-
obj.removeListener(type, cb)
|
|
225
|
-
}
|
|
133
|
+
sendResume (): void {
|
|
134
|
+
this.socket.resume()
|
|
226
135
|
}
|
|
136
|
+
}
|
|
227
137
|
|
|
228
|
-
|
|
229
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Convert a socket into a MultiaddrConnection
|
|
140
|
+
* https://github.com/libp2p/interface-transport#multiaddrconnection
|
|
141
|
+
*/
|
|
142
|
+
export const toMultiaddrConnection = (init: TCPSocketMultiaddrConnectionInit): MultiaddrConnection => {
|
|
143
|
+
return new TCPSocketMultiaddrConnection(init)
|
|
230
144
|
}
|
package/src/tcp.ts
CHANGED
|
@@ -75,6 +75,7 @@ export class TCP implements Transport<TCPDialEvents> {
|
|
|
75
75
|
async dial (ma: Multiaddr, options: TCPDialOptions): Promise<Connection> {
|
|
76
76
|
options.keepAlive = options.keepAlive ?? true
|
|
77
77
|
options.noDelay = options.noDelay ?? true
|
|
78
|
+
options.allowHalfOpen = options.allowHalfOpen ?? false
|
|
78
79
|
|
|
79
80
|
// options.signal destroys the socket before 'connect' event
|
|
80
81
|
const socket = await this._connect(ma, options)
|
|
@@ -82,13 +83,13 @@ export class TCP implements Transport<TCPDialEvents> {
|
|
|
82
83
|
let maConn: MultiaddrConnection
|
|
83
84
|
|
|
84
85
|
try {
|
|
85
|
-
maConn = toMultiaddrConnection(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
socketCloseTimeout: this.opts.socketCloseTimeout,
|
|
86
|
+
maConn = toMultiaddrConnection({
|
|
87
|
+
socket,
|
|
88
|
+
inactivityTimeout: this.opts.outboundSocketInactivityTimeout,
|
|
89
89
|
metrics: this.metrics?.events,
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
direction: 'outbound',
|
|
91
|
+
remoteAddr: ma,
|
|
92
|
+
log: this.log.newScope('connection')
|
|
92
93
|
})
|
|
93
94
|
} catch (err: any) {
|
|
94
95
|
this.metrics?.errors.increment({ outbound_to_connection: true })
|
|
@@ -120,7 +121,7 @@ export class TCP implements Transport<TCPDialEvents> {
|
|
|
120
121
|
...options
|
|
121
122
|
}) as (IpcSocketConnectOpts & TcpSocketConnectOpts)
|
|
122
123
|
|
|
123
|
-
this.log('dialing %a', ma)
|
|
124
|
+
this.log('dialing %a with opts %o', ma, cOpts)
|
|
124
125
|
rawSocket = net.connect(cOpts)
|
|
125
126
|
|
|
126
127
|
const onError = (err: Error): void => {
|
|
@@ -192,8 +193,7 @@ export class TCP implements Transport<TCPDialEvents> {
|
|
|
192
193
|
maxConnections: this.opts.maxConnections,
|
|
193
194
|
backlog: this.opts.backlog,
|
|
194
195
|
closeServerOnMaxConnections: this.opts.closeServerOnMaxConnections,
|
|
195
|
-
|
|
196
|
-
socketCloseTimeout: this.opts.socketCloseTimeout,
|
|
196
|
+
inactivityTimeout: this.opts.inboundSocketInactivityTimeout,
|
|
197
197
|
metrics: this.components.metrics,
|
|
198
198
|
logger: this.components.logger
|
|
199
199
|
})
|
package/src/utils.ts
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import os from 'os'
|
|
2
2
|
import path from 'path'
|
|
3
|
+
import { InvalidParametersError } from '@libp2p/interface'
|
|
4
|
+
import { getNetConfig } from '@libp2p/utils'
|
|
5
|
+
import { CODE_UNIX } from '@multiformats/multiaddr'
|
|
6
|
+
import { Unix } from '@multiformats/multiaddr-matcher'
|
|
3
7
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
4
8
|
import type { ListenOptions, IpcSocketConnectOpts, TcpSocketConnectOpts } from 'net'
|
|
5
9
|
|
|
6
10
|
export type NetConfig = ListenOptions | (IpcSocketConnectOpts & TcpSocketConnectOpts)
|
|
7
11
|
|
|
8
|
-
export function multiaddrToNetConfig (addr: Multiaddr,
|
|
9
|
-
|
|
12
|
+
export function multiaddrToNetConfig (addr: Multiaddr, options: NetConfig = {}): NetConfig {
|
|
13
|
+
if (Unix.exactMatch(addr)) {
|
|
14
|
+
const listenPath = addr.getComponents().find(c => c.code === CODE_UNIX)?.value
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
if (listenPath == null) {
|
|
17
|
+
throw new InvalidParametersError(`Multiaddr ${addr} was not a Unix address`)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// unix socket listening
|
|
13
21
|
if (os.platform() === 'win32') {
|
|
14
22
|
// Use named pipes on Windows systems.
|
|
15
23
|
return { path: path.join('\\\\.\\pipe\\', listenPath) }
|
|
@@ -18,12 +26,15 @@ export function multiaddrToNetConfig (addr: Multiaddr, config: NetConfig = {}):
|
|
|
18
26
|
}
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
const
|
|
29
|
+
const config = getNetConfig(addr)
|
|
30
|
+
const host = config.host
|
|
31
|
+
const port = config.port
|
|
22
32
|
|
|
23
33
|
// tcp listening
|
|
24
34
|
return {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
ipv6Only:
|
|
35
|
+
host,
|
|
36
|
+
port,
|
|
37
|
+
ipv6Only: config.type === 'ip6',
|
|
38
|
+
...options
|
|
28
39
|
}
|
|
29
40
|
}
|