Skip to content

Commit

Permalink
feat: reverse the ping-pong mechanism
Browse files Browse the repository at this point in the history
The ping packets will now be sent by the server, because the timers set in the browsers are not
reliable enough. We suspect that a lot of timeout problems came from timer being delayed on the
client-side.

Breaking change: v3.x clients will not be able to connect anymore (they will send a ping packet and
timeout while waiting for a pong packet)

Related: #312
  • Loading branch information
darrachequesne committed Feb 3, 2020
1 parent 2ae2520 commit c1ec931
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 14 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ A representation of a client. _Inherits from EventEmitter_.
- `type`: packet type
- `data`: packet data (if type is message)
- `packetCreate`
- Called before a socket sends a packet (`message`, `pong`)
- Called before a socket sends a packet (`message`, `ping`)
- **Arguments**
- `type`: packet type
- `data`: packet data (if type is message)
Expand Down
42 changes: 33 additions & 9 deletions lib/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Socket extends EventEmitter {
this.checkIntervalTimer = null;
this.upgradeTimeoutTimer = null;
this.pingTimeoutTimer = null;
this.pingIntervalTimer = null;

this.setTransport(transport);
this.onOpen();
Expand Down Expand Up @@ -60,7 +61,7 @@ class Socket extends EventEmitter {
}

this.emit("open");
this.setPingTimeout();
this.schedulePing();
}

/**
Expand All @@ -77,12 +78,12 @@ class Socket extends EventEmitter {

// Reset ping timeout on any packet, incoming data is a good sign of
// other side's liveness
this.setPingTimeout();
this.resetPingTimeout(this.server.pingInterval + this.server.pingTimeout);

switch (packet.type) {
case "ping":
debug("got ping");
this.sendPacket("pong");
case "pong":
debug("got pong");
this.schedulePing();
this.emit("heartbeat");
break;

Expand Down Expand Up @@ -112,15 +113,34 @@ class Socket extends EventEmitter {
}

/**
* Sets and resets ping timeout timer based on client pings.
* Pings client every `this.pingInterval` and expects response
* within `this.pingTimeout` or closes connection.
*
* @api private
*/
setPingTimeout() {
schedulePing() {
clearTimeout(this.pingIntervalTimer);
this.pingIntervalTimer = setTimeout(() => {
debug(
"writing ping packet - expecting pong within %sms",
this.server.pingTimeout
);
this.sendPacket("ping");
this.resetPingTimeout(this.server.pingTimeout);
}, this.server.pingInterval);
}

/**
* Resets ping timeout.
*
* @api private
*/
resetPingTimeout(timeout) {
clearTimeout(this.pingTimeoutTimer);
this.pingTimeoutTimer = setTimeout(() => {
if (this.readyState === "closed") return;
this.onClose("ping timeout");
}, this.server.pingInterval + this.server.pingTimeout);
}, timeout);
}

/**
Expand Down Expand Up @@ -191,7 +211,7 @@ class Socket extends EventEmitter {
self.clearTransport();
self.setTransport(transport);
self.emit("upgrade", transport);
self.setPingTimeout();
self.schedulePing();
self.flush();
if (self.readyState === "closing") {
transport.close(function() {
Expand Down Expand Up @@ -283,7 +303,11 @@ class Socket extends EventEmitter {
onClose(reason, description) {
if ("closed" !== this.readyState) {
this.readyState = "closed";

// clear timers
clearInterval(this.pingIntervalTimer);
clearTimeout(this.pingTimeoutTimer);

clearInterval(this.checkIntervalTimer);
this.checkIntervalTimer = null;
clearTimeout(this.upgradeTimeoutTimer);
Expand Down
8 changes: 4 additions & 4 deletions test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -1011,8 +1011,8 @@ describe("server", function() {

engine.on("connection", function(conn) {
conn.once("heartbeat", function() {
socket.onPacket = function() {};
setTimeout(function() {
socket.onPacket = function() {};
expect(clientCloseReason).to.be(null);
}, 150);
setTimeout(function() {
Expand Down Expand Up @@ -2396,15 +2396,15 @@ describe("server", function() {
});
});

it("should emit when receives ping", function(done) {
it("should emit when receives pong", function(done) {
var engine = listen({ allowUpgrades: false, pingInterval: 4 }, function(
port
) {
eioc("ws://localhost:%d".s(port));
engine.on("connection", function(conn) {
conn.on("packet", function(packet) {
conn.close();
expect(packet.type).to.be("ping");
expect(packet.type).to.be("pong");
done();
});
});
Expand Down Expand Up @@ -2435,7 +2435,7 @@ describe("server", function() {
engine.on("connection", function(conn) {
conn.on("packetCreate", function(packet) {
conn.close();
expect(packet.type).to.be("pong");
expect(packet.type).to.be("ping");
done();
});
});
Expand Down

0 comments on commit c1ec931

Please sign in to comment.