Race condition when getting remoteAddress of connection #7566
Description
If the connection has already been closed before the connect
event is handled by user code, the remoteAddress
of the connection will not be available.
Reproducing this is very hard but I managed to get it working sometimes with gnu netcat version 0.7.1 with the close flag, executed on another machine:
hostname | nc -nc <ip> 1337
Testcase
var net = require('net');
var assert = require('assert');
net.createServer(function (c) {
assert(c.remoteAddress);
}).listen(1337);
Output
assert.js:92
throw new assert.AssertionError({
^
AssertionError: "undefined" == true
at Server.<anonymous> (/private/tmp/socket-race-condition/test.js:6:3)
at Server.EventEmitter.emit (events.js:95:17)
at TCP.onconnection (net.js:1191:8)
More info
Information about the socket can be provided when calling accept
, however libuv
ignores that data:
https://github.com/joyent/libuv/blob/9b4f2b84f10c96efa37910f324bc66e27aec3828/src/unix/core.c#L406
Instead, when doing c.remoteAddress
a call to getpeername
is executed.
remoteAddress
https://github.com/joyent/node/blob/940974ed039d3c9a8befe608d9c95b2ffdb457d3/lib/net.js#L569_getpeername
https://github.com/joyent/node/blob/940974ed039d3c9a8befe608d9c95b2ffdb457d3/lib/net.js#L555TCPWrap::GetPeerName
https://github.com/joyent/node/blob/940974ed039d3c9a8befe608d9c95b2ffdb457d3/src/tcp_wrap.cc#L182uv_tcp_getpeername
https://github.com/joyent/libuv/blob/9b4f2b84f10c96efa37910f324bc66e27aec3828/src/unix/tcp.c#L187
I think that the only reliable way to get the remoteAddress
is to get it from the accept
call and store it along with the connection.
Additional error
In addition to the assertion error, if I only log the c.remoteAddress
and don't terminate the process, I will get the following error. It's not emitted on the server (net.createServer
) and thus I can't trap it with server.on('error', ...)
.
Error: read ECONNRESET
at errnoException (net.js:904:11)
at TCP.onread (net.js:558:19)
syscall: read
code: ECONNRESET