Skip to content

Commit

Permalink
feat: detect closed connections with TCP keepalive (#712)
Browse files Browse the repository at this point in the history
If two peers connect and one disconnects, the other won't necessarily
know.

1. Alex and Charlie connect. Alex sees that they are connected to 1
   device.
2. Charlie disconnects from wifi. Alex still sees a connection to 1
   device, even though the connection should be broken.

We can fix this in several ways. I think the best is to enable
[TCP keepalive], which effectively sends a packet every second asking,
"is this connection still on?".

I did not add unit tests for this (I could not think of a good way) but
did test manually in CoMapeo with two Android devices.

[TCP keepalive]: https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
  • Loading branch information
EvanHahn authored Jun 27, 2024
1 parent 14f27c4 commit f480798
Showing 1 changed file with 13 additions and 2 deletions.
15 changes: 13 additions & 2 deletions src/discovery/local-discovery.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import { Logger } from '../logger.js'
/** @typedef {{ publicKey: Buffer, secretKey: Buffer }} Keypair */
/** @typedef {import('../utils.js').OpenedNoiseStream<net.Socket>} OpenedNoiseStream */

const TCP_KEEP_ALIVE_OPTIONS = {
keepAlive: true,
keepAliveInitialDelay: 10_000,
}
export const ERR_DUPLICATE = 'Duplicate connection'

/**
Expand Down Expand Up @@ -52,7 +56,10 @@ export class LocalDiscovery extends TypedEmitter {
this.#log('socket error', e.message)
}
this.#identityKeypair = identityKeypair
this.#server = net.createServer(this.#handleTcpConnection.bind(this, false))
this.#server = net.createServer(
TCP_KEEP_ALIVE_OPTIONS,
this.#handleTcpConnection.bind(this, false)
)
this.#server.on('error', (e) => {
this.#log('Server error', e)
})
Expand Down Expand Up @@ -90,7 +97,11 @@ export class LocalDiscovery extends TypedEmitter {
this.#log(`Already connected to ${name.slice(0, 7)}`)
return
}
const socket = net.connect(port, address)
const socket = net.connect({
host: address,
port,
...TCP_KEEP_ALIVE_OPTIONS,
})
socket.on('error', this.#handleSocketError)
socket.once('connect', () => {
this.#handleTcpConnection(true, socket)
Expand Down

0 comments on commit f480798

Please sign in to comment.