'How to use Node.js' TLSSocket to connect (and reconnect) to a server?
I have a toy IRC bot that I've been hacking on, and it has the ability to connect to multiple servers at once, both unencrypted and over TLS. Originally my connection code looked like this:
constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
this.host = host;
this.port = port
? port
: tlsEnabled
? 6697
: 6667;
this.tlsEnabled = tlsEnabled;
this.nick = nick;
this.channels = channels;
this.client = this.tlsEnabled
? tls.connect({host: this.host, port: this.port, timeout: 180000}, () => this.sendClientRegistration())
: net.connect({host: this.host, port: this.port, timeout: 180000}, () => this.sendClientRegistration());
[...]
this.client.on('close', (hadError) => {
logMessage('INFO', this.host, `Connection to ${host} closed`);
try {
setTimeout(() => this.client.connect({host: this.host, port: this.port}, () => this.sendClientRegistration()), 60000);
} catch (err) {
logMessage('INFO', this.host, `Failed to reconnect to ${this.host}`);
}
});
}
It mostly worked fine, except if the connection to the server was interrupted for long enough I'd end up with a MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 connect listeners added to [Socket] message and it'd never reconnect.
I refactored the connection code to look like this:
constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
this.host = host;
this.port = port
? port
: tlsEnabled
? 6697
: 6667;
this.tlsEnabled = tlsEnabled;
this.nick = nick;
this.channels = channels;
this.client = this.tlsEnabled
? new tls.TLSSocket(new net.Socket())
: new net.Socket();
[...]
this.client.on('close', () => {
logMessage('INFO', this.host, `Connection to ${host} closed`);
try {
setTimeout(() => this.connect(), 60000);
} catch (err) {
logMessage('INFO', this.host, `Failed to reconnect to ${this.host}`);
}
});
this.connect();
}
connect() {
this.client.connect({host: this.host, port: this.port});
}
And while that works perfectly for a non-TLS connection and will happily try to reconnect as many times as needed without creating too many event listeners, with a TLS connection it doesn't even try to connect, if I have one single TLS connection in my config, the application just exits cleanly immediately.
I came across this answer that seems very similar, but I haven't had any luck figuring out how to actually get it working for my case, and the Node.js TLS documentation hasn't been enlightening either. It says this for the socket option for tls.connect():
socket <stream.Duplex>Establish secure connection on a given socket rather than creating a new socket. Typically, this is an instance ofnet.Socket, but anyDuplexstream is allowed. If this option is specified,path,hostandportare ignored, except for certificate validation. Usually, a socket is already connected when passed totls.connect(), but it can be connected later. Connection/disconnection/destruction ofsocketis the user's responsibility; callingtls.connect()will not causenet.connect()to be called.
I updated the connection code again to look like this:
constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
this.host = host;
this.port = port
? port
: tlsEnabled
? 6697
: 6667;
this.tlsEnabled = tlsEnabled;
this.nick = nick;
this.channels = channels;
this.client = new net.Socket();
[...]
this.connect();
}
connect() {
if (this.tlsEnabled) {
tls.connect({
socket: this.client,
})
}
this.client.connect({host: this.host, port: this.port});
}
But clearly I'm doing it wrong because I end up with Error: read ECONNRESET error in my application, and the IRC server ngircd says SSL protocol error: SSL_accept (error:1408F10B:SSL routines:ssl3_get_record:wrong version number).
How is tls.connect() meant to work when you pass an existing socket?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
