Skip to content

Commit

Permalink
net: use _final instead of on('finish')
Browse files Browse the repository at this point in the history
Shutting down the connection is what `_final` is there for.
  • Loading branch information
addaleax committed Feb 21, 2018
1 parent 6bdc18c commit 906bbef
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 17 deletions.
2 changes: 2 additions & 0 deletions lib/internal/streams/destroy.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ function undestroy() {
this._writableState.destroyed = false;
this._writableState.ended = false;
this._writableState.ending = false;
this._writableState.finalCalled = false;
this._writableState.prefinished = false;
this._writableState.finished = false;
this._writableState.errorEmitted = false;
}
Expand Down
28 changes: 16 additions & 12 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ function Socket(options) {
}

// shut down the socket when we're finished with it.
this.on('finish', onSocketFinish);
this.on('_socketEnd', onSocketEnd);

initSocketHandle(this);
Expand Down Expand Up @@ -303,39 +302,42 @@ Socket.prototype._unrefTimer = function _unrefTimer() {

function shutdownSocket(self, callback) {
var req = new ShutdownWrap();
req.oncomplete = callback;
req.oncomplete = afterShutdown;
req.handle = self._handle;
req.callback = callback;
return self._handle.shutdown(req);
}

// the user has called .end(), and all the bytes have been
// sent out to the other side.
function onSocketFinish() {
// If still connecting - defer handling 'finish' until 'connect' will happen
Socket.prototype._final = function(cb) {
// If still connecting - defer handling `_final` until 'connect' will happen
if (this.connecting) {
debug('osF: not yet connected');
return this.once('connect', onSocketFinish);
debug('_final: not yet connected');
return this.once('connect', () => this._final(cb));
}

debug('onSocketFinish');
if (!this.readable || this._readableState.ended) {
debug('oSF: ended, destroy', this._readableState);
debug('_final: ended, destroy', this._readableState);
cb();
return this.destroy();
}

debug('oSF: not ended, call shutdown()');
debug('_final: not ended, call shutdown()');

// otherwise, just shutdown, or destroy() if not possible
if (!this._handle || !this._handle.shutdown)
if (!this._handle || !this._handle.shutdown) {
cb();
return this.destroy();
}

var err = defaultTriggerAsyncIdScope(
this[async_id_symbol], shutdownSocket, this, afterShutdown
this[async_id_symbol], shutdownSocket, this, cb
);

if (err)
return this.destroy(errnoException(err, 'shutdown'));
}
};


function afterShutdown(status, handle) {
Expand All @@ -344,6 +346,8 @@ function afterShutdown(status, handle) {
debug('afterShutdown destroyed=%j', self.destroyed,
self._readableState);

this.callback();

// callback may come after call to destroy.
if (self.destroyed)
return;
Expand Down
12 changes: 7 additions & 5 deletions test/async-hooks/test-shutdownwrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ let endedConnection = false;
function onconnection(c) {
assert.strictEqual(hooks.activitiesOfTypes('SHUTDOWNWRAP').length, 0);
c.end();
endedConnection = true;
const as = hooks.activitiesOfTypes('SHUTDOWNWRAP');
assert.strictEqual(as.length, 1);
checkInvocations(as[0], { init: 1 }, 'after ending client connection');
this.close(onserverClosed);
process.nextTick(() => {
endedConnection = true;
const as = hooks.activitiesOfTypes('SHUTDOWNWRAP');
assert.strictEqual(as.length, 1);
checkInvocations(as[0], { init: 1 }, 'after ending client connection');
this.close(onserverClosed);
});
}

function onconnected() {
Expand Down
14 changes: 14 additions & 0 deletions test/parallel/test-stream-writable-destroy.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,17 @@ const { inherits } = require('util');
assert.strictEqual(expected, err);
}));
}

{
// Checks that `._undestroy()` restores the state so that `final` will be
// called again.
const write = new Writable({
write: common.mustNotCall(),
final: common.mustCall((cb) => cb(), 2)
});

write.end();
write.destroy();
write._undestroy();
write.end();
}

0 comments on commit 906bbef

Please sign in to comment.