Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Manager leaks an EIO socket when disconnect is called right before connecting again #1014

Closed
benjamin-albert opened this issue Oct 23, 2016 · 1 comment
Labels
bug Something isn't working
Milestone

Comments

@benjamin-albert
Copy link

benjamin-albert commented Oct 23, 2016

Steps to reproduce

server.js:

var io = require('socket.io')(1337);

io.of('/asd');
io.of('/foo');

client.js:

var io = require('./');
var manager = io.Manager('http://localhost:1337', { transports: ['websocket'] });

var fooSocket = manager.socket('/foo');
fooSocket.on('connect', function() {
  // This disconnect should not break
  // the conection of the asdSocket.
  fooSocket.disconnect();

  var asdSocket = manager.socket('/asd');

  // Only fail if reconnect_attempt it emitted
  // even if the IEO Socket was successfully opened.
  manager.engine.on('open', function() {
    asdSocket.on('reconnect_attempt', function() {
      console.error('Why reconnect? This is a bug!');
    });
  })

  asdSocket.on('connect', function() {
    asdSocket.disconnect();
    console.error('Node.js should exit after all clients have disconnected');
  });
});

Expected behavior

Node.js should exit after all clients have disconnected.

Actual behavior

Node.js freezes for about a second (before it tries to reconnect) and then it stays open forever (doesn't exit).

Workaround

I am aware that the proper way to do something like this is to first connect to the second namespace and then disconnect from the first namespace.

However I don't think something like this should leak an IEO socket.

Setup

  • OS: macOS Version 10.12
  • browser: Node.js v4.6.1
  • socket.io version: 1.5.0

Other information

See this commit in my fix_eio_leak branch which adds a failing test to test/connection.js

Stay tuned for a pull request that fixes this bug.

benjamin-albert added a commit to benjamin-albert/socket.io-client that referenced this issue Oct 24, 2016
darrachequesne added a commit that referenced this issue Nov 18, 2021
Previously, calling `socket.disconnect().connect()` could, if the
connection was upgraded to WebSocket, result in "disconnect" being
emitted twice, and an engine being leaked.

Here's what happened:

> socket.disconnect()

- calls `socket.destroy()` so the socket doesn't listen to the manager events anymore
- then calls `manager._close()` which closes the underlying engine but not the manager itself (it waits for the "close" event of the engine)

> socket.connect()

- calls `socket.subEvents()` so the socket does listen to the manager events
- calls `manager.open()` which creates a new engine

And then the first engine emits a "close" event, which is forwarded to
the socket, hence the second "disconnect" event.

Related: #1014
sunrise30 added a commit to sunrise30/socket.io-client that referenced this issue Jan 8, 2022
Previously, calling `socket.disconnect().connect()` could, if the
connection was upgraded to WebSocket, result in "disconnect" being
emitted twice, and an engine being leaked.

Here's what happened:

> socket.disconnect()

- calls `socket.destroy()` so the socket doesn't listen to the manager events anymore
- then calls `manager._close()` which closes the underlying engine but not the manager itself (it waits for the "close" event of the engine)

> socket.connect()

- calls `socket.subEvents()` so the socket does listen to the manager events
- calls `manager.open()` which creates a new engine

And then the first engine emits a "close" event, which is forwarded to
the socket, hence the second "disconnect" event.

Related: socketio/socket.io-client#1014
@darrachequesne
Copy link
Member

For future readers:

This should be fixed by 99c2cb8, included in socket.io-client@4.4.0.

@darrachequesne darrachequesne added this to the 4.4.0 milestone Apr 13, 2022
@darrachequesne darrachequesne added the bug Something isn't working label Apr 13, 2022
darrachequesne added a commit that referenced this issue Jun 6, 2022
Previously, calling `socket.disconnect().connect()` could, if the
connection was upgraded to WebSocket, result in "disconnect" being
emitted twice, and an engine being leaked.

Here's what happened:

> socket.disconnect()

- calls `socket.destroy()` so the socket doesn't listen to the manager events anymore
- then calls `manager._close()` which closes the underlying engine but not the manager itself (it waits for the "close" event of the engine)

> socket.connect()

- calls `socket.subEvents()` so the socket does listen to the manager events
- calls `manager.open()` which creates a new engine

And then the first engine emits a "close" event, which is forwarded to
the socket, hence the second "disconnect" event.

Related: #1014

Backported from 99c2cb8
darrachequesne added a commit that referenced this issue Jun 25, 2022
Previously, calling `socket.disconnect().connect()` could, if the
connection was upgraded to WebSocket, result in "disconnect" being
emitted twice, and an engine being leaked.

Here's what happened:

> socket.disconnect()

- calls `socket.destroy()` so the socket doesn't listen to the manager events anymore
- then calls `manager._close()` which closes the underlying engine but not the manager itself (it waits for the "close" event of the engine)

> socket.connect()

- calls `socket.subEvents()` so the socket does listen to the manager events
- calls `manager.open()` which creates a new engine

And then the first engine emits a "close" event, which is forwarded to
the socket, hence the second "disconnect" event.

Related: #1014

Backported from 99c2cb8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants