I'm receiving 'read ECONNRESET' errors from my Node.js application (might be client or server connections, I'm not sure).
As part of fixing these, I'd like to do some local testing, and preferably set up automated tests for it. I want to write a Node client & server that hard resets connections as soon as they're established, so that I can test this.
Setting up the server/client is easy, but I'm not sure how to forcibly reset the connection to reproduce the issue I'm seeing here. The Node socket docs don't mention resets anywhere
Any ideas?
There's no perfect solution to this, as far as I can tell, but I've found two options for this, and filed a bug against Node to add proper support.
For my problem (start an HTTP request, then RST the socket) I found two solutions:
Destroy the socket just before receiving a packet
const net = require('net');
const socket = new net.Socket();
socket.connect(8000, "127.0.0.1", () => {
socket.write(
'GET / HTTP/1.1\n' +
'Host: example.com\n\n'
);
setTimeout(() => socket.destroy(), 0);
});
If you know you're about to receive a packet on this connection, you can destroy()
the socket immediately beforehand. This does not send an RST, but will send an RST in response to future packets.
To do this, you need to race to destroy the socket after your message is written, but before the response arrives. For local connections especially this can be tricky - the setTimeout(() => socket.destroy(), 0)
is the most reliable solution I've found, but YMMV, and it's certainly not guaranteed. I expected the write()
callback to work more reliably, but it doesn't seem to.
Use another language (i.e. Python)
For me, I've now fallen back to using Python for testing, since it has direct control for this. To send a RST packet in Python:
import socket
import time
import struct
TCP_IP = '127.0.0.1'
TCP_PORT = 8000
# Connect to the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.connect((TCP_IP, TCP_PORT))
# Start an HTTP request
s.send("GET / HTTP/1.1\r\n\
Host: example.com\r\n\
\r\n")
time.sleep(0.1)
# RST the socket without reading the response
# See https://stackoverflow.com/a/6440364/68051 for context
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
s.close()
Hopefully the Node team will take a look at adding similar support soon (see https://github.com/nodejs/node/issues/27428), but the above may be helpful in the meantime.