Skip to content

bufferSize of net.Socket sometimes returns double the actual value #34078

Closed
@BTOdell

Description

@BTOdell
  • Version: v14.4.0
  • Platform: Linux 97fdeff5e333 4.4.0-184-generic Ubuntu SMP x86_64 GNU/Linux
  • Subsystem: net

What steps will reproduce the bug?

I'm using the WebSocket library ws to handle connections from a browser over a VPN. The bufferedAmount property of ws uses the bufferSize property of the underlying net.Socket object (from the http.createServer function). I've narrowed the bug down to know the incorrect value is only coming from the bufferSize property in Node.js itself.

How often does it reproduce? Is there a required condition?

I'm able to reproduce it reliably in my Linux/Docker environment under certain (slow) network conditions.
This issue seems to happen when the socket is being written to quickly, to the point where write callbacks are getting delayed and batched up (several are called together in quick succession).

What is the expected behavior?

The bufferSize should never be greater than the actual number of bytes that were sent to the socket.

What do you see instead?

Each time I send a WebSocket packet, I add the length of the packet onto my own 'pending' queue and I remove it from the queue when I receive the send/write callback. After I send the data to the WebSocket, I query the bufferSize property and the writableLength property of the underlying TCP socket.

Using this TS code:

console.log("Old pending size: " + this.pending.reduce((prev, curr) => prev + curr.byteLength, 0));
console.log("Sending data of length: " + dataByteLength);
this.socket.send(data, cb);
this.pending.unshift(newPendingRecord);
console.log("New pending size: " + this.pending.reduce((prev, curr) => prev + curr.byteLength, 0));
...
const pending: DataRecord[] = this.pending;
const pendingBytes: number = pending.reduce((prev, curr) => prev + curr.byteLength, 0);
const sock: Socket = (this.socket as any)._socket; // get the underlying TCP socket from the WebSocket
const bufferSize: number = sock.bufferSize;
const bytesSent: number = pendingBytes - bufferSize;
console.log("Pending bytes (" + pendingBytes + ") - bufferSize (" + bufferSize + ") = " + bytesSent);
console.log("writableLength: " + sock.writableLength);

I get this output:

Old pending size: 0
Sending data of length: 56205
New pending size: 56205
Pending bytes (56205) - bufferSize (112418) = -56213
writableLength: 56209

Additional information

I tracked down the code in Node.js that implements the bufferSize property: https://github.com/nodejs/node/blob/master/lib/net.js#L544

Using the printed value of writableLength (56209), that means the value of this[kLastWriteQueueSize] is also 56209. My guess is that one of the values is not getting cleared at the right time. Maybe it's because the Node.js event loop is getting held up by all of the other write requests? I don't know enough about Node.js internals to keep debugging this issue further.

Metadata

Metadata

Assignees

No one assigned

    Labels

    netIssues and PRs related to the net subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions