Skip to content

Commit 2022036

Browse files
fix: abort connection only when abortConnectionOnPingFailure is true (#2684)
Enforce the abortConnectionOnPingFailure flag to only abort connections when it is true. Fixes #2678 --------- Co-authored-by: Alex Potsides <alex@achingbrain.net>
1 parent 81ebe4e commit 2022036

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

packages/libp2p/src/connection-monitor.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { randomBytes } from '@libp2p/crypto'
2-
import { serviceCapabilities } from '@libp2p/interface'
2+
import { serviceCapabilities, setMaxListeners } from '@libp2p/interface'
33
import { AdaptiveTimeout } from '@libp2p/utils/adaptive-timeout'
44
import { byteStream } from 'it-byte-stream'
55
import type { ComponentLogger, Logger, Metrics, Startable } from '@libp2p/interface'
@@ -11,6 +11,7 @@ const PROTOCOL_VERSION = '1.0.0'
1111
const PROTOCOL_NAME = 'ping'
1212
const PROTOCOL_PREFIX = 'ipfs'
1313
const PING_LENGTH = 32
14+
const DEFAULT_ABORT_CONNECTION_ON_PING_FAILURE = true
1415

1516
export interface ConnectionMonitorInit {
1617
/**
@@ -65,14 +66,15 @@ export class ConnectionMonitor implements Startable {
6566
private readonly pingIntervalMs: number
6667
private abortController?: AbortController
6768
private readonly timeout: AdaptiveTimeout
69+
private readonly abortConnectionOnPingFailure: boolean
6870

6971
constructor (components: ConnectionMonitorComponents, init: ConnectionMonitorInit = {}) {
7072
this.components = components
7173
this.protocol = `/${init.protocolPrefix ?? PROTOCOL_PREFIX}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}`
7274

7375
this.log = components.logger.forComponent('libp2p:connection-monitor')
7476
this.pingIntervalMs = init.pingInterval ?? DEFAULT_PING_INTERVAL_MS
75-
77+
this.abortConnectionOnPingFailure = init.abortConnectionOnPingFailure ?? DEFAULT_ABORT_CONNECTION_ON_PING_FAILURE
7678
this.timeout = new AdaptiveTimeout({
7779
...(init.pingTimeout ?? {}),
7880
metrics: components.metrics,
@@ -88,6 +90,7 @@ export class ConnectionMonitor implements Startable {
8890

8991
start (): void {
9092
this.abortController = new AbortController()
93+
setMaxListeners(Infinity, this.abortController.signal)
9194

9295
this.heartbeatInterval = setInterval(() => {
9396
this.components.connectionManager.getConnections().forEach(conn => {
@@ -131,8 +134,14 @@ export class ConnectionMonitor implements Startable {
131134
}
132135
})
133136
.catch(err => {
134-
this.log.error('error during heartbeat, aborting connection', err)
135-
conn.abort(err)
137+
this.log.error('error during heartbeat', err)
138+
139+
if (this.abortConnectionOnPingFailure) {
140+
this.log.error('aborting connection due to ping failure')
141+
conn.abort(err)
142+
} else {
143+
this.log('connection ping failed, but not aborting due to abortConnectionOnPingFailure flag')
144+
}
136145
})
137146
})
138147
}, this.pingIntervalMs)

packages/libp2p/test/connection-monitor/index.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,46 @@ describe('connection monitor', () => {
129129

130130
components.connectionManager.getConnections.returns([connection])
131131

132+
await delay(500)
133+
134+
expect(connection.abort).to.have.property('called', true)
135+
})
136+
137+
it('should not abort a connection that fails when abortConnectionOnPingFailure is false', async () => {
138+
monitor = new ConnectionMonitor(components, {
139+
pingInterval: 10,
140+
abortConnectionOnPingFailure: false
141+
})
142+
143+
await start(monitor)
144+
145+
const connection = stubInterface<Connection>()
146+
connection.newStream.withArgs('/ipfs/ping/1.0.0').callsFake(async (protocols, opts) => {
147+
throw new ConnectionClosedError('Connection closed')
148+
})
149+
150+
components.connectionManager.getConnections.returns([connection])
151+
152+
await delay(500)
153+
154+
expect(connection.abort).to.have.property('called', false)
155+
})
156+
157+
it('should abort a connection that fails when abortConnectionOnPingFailure is true', async () => {
158+
monitor = new ConnectionMonitor(components, {
159+
pingInterval: 10,
160+
abortConnectionOnPingFailure: true
161+
})
162+
163+
await start(monitor)
164+
165+
const connection = stubInterface<Connection>()
166+
connection.newStream.withArgs('/ipfs/ping/1.0.0').callsFake(async (protocols, opts) => {
167+
throw new ConnectionClosedError('Connection closed')
168+
})
169+
170+
components.connectionManager.getConnections.returns([connection])
171+
132172
await delay(100)
133173

134174
expect(connection.abort).to.have.property('called', true)

0 commit comments

Comments
 (0)