Browse Source

don't crash when queued write fails

v0.8.7-release
Igor Zinkovsky 13 years ago
parent
commit
0dcc43316f
  1. 62
      lib/net.js
  2. 16
      test/simple/test-net-write-after-close.js

62
lib/net.js

@ -84,6 +84,7 @@ function initSocketHandle(self) {
self._flags = 0;
self._connectQueueSize = 0;
self.destroyed = false;
self.errorEmitted = false;
self.bytesRead = 0;
self.bytesWritten = 0;
@ -244,7 +245,7 @@ Socket.prototype.end = function(data, encoding) {
var shutdownReq = this._handle.shutdown();
if (!shutdownReq) {
this.destroy(errnoException(errno, 'shutdown'));
this._destroy(errnoException(errno, 'shutdown'));
return false;
}
@ -267,7 +268,7 @@ function afterShutdown(status, handle, req) {
}
if (self._flags & FLAG_GOT_EOF || !self.readable) {
self.destroy();
self._destroy();
} else {
}
}
@ -278,7 +279,7 @@ Socket.prototype.destroySoon = function() {
this._flags |= FLAG_DESTROY_SOON;
if (this._pendingWriteReqs == 0) {
this.destroy();
this._destroy();
}
};
@ -290,11 +291,24 @@ Socket.prototype._connectQueueCleanUp = function(exception) {
};
Socket.prototype.destroy = function(exception) {
if (this.destroyed) return;
Socket.prototype._destroy = function(exception, cb) {
var self = this;
function fireErrorCallbacks() {
if (cb) cb(exception);
if (exception && !self.errorEmitted) {
process.nextTick(function() {
self.emit('error', exception);
});
self.errorEmitted = true;
}
};
if (this.destroyed) {
fireErrorCallbacks();
return;
}
self._connectQueueCleanUp();
debug('destroy');
@ -315,8 +329,9 @@ Socket.prototype.destroy = function(exception) {
this._handle = null;
}
fireErrorCallbacks();
process.nextTick(function() {
if (exception) self.emit('error', exception);
self.emit('close', exception ? true : false);
});
@ -324,6 +339,11 @@ Socket.prototype.destroy = function(exception) {
};
Socket.prototype.destroy = function(exception) {
this._destroy(exception);
}
function onread(buffer, offset, length) {
var handle = this;
var self = handle.socket;
@ -362,7 +382,7 @@ function onread(buffer, offset, length) {
// We call destroy() before end(). 'close' not emitted until nextTick so
// the 'end' event will come first as required.
if (!self.writable) self.destroy();
if (!self.writable) self._destroy();
if (!self.allowHalfOpen) self.end();
if (self._events && self._events['end']) self.emit('end');
@ -370,9 +390,9 @@ function onread(buffer, offset, length) {
} else {
// Error
if (errno == 'ECONNRESET') {
self.destroy();
self._destroy();
} else {
self.destroy(errnoException(errno, 'read'));
self._destroy(errnoException(errno, 'read'));
}
}
}
@ -450,13 +470,16 @@ Socket.prototype.write = function(data, arg1, arg2) {
Socket.prototype._write = function(data, encoding, cb) {
timers.active(this);
if (!this._handle) throw new Error('This socket is closed.');
if (!this._handle) {
this._destroy(new Error('This socket is closed.'), cb);
return false;
}
// `encoding` is unused right now, `data` is always a buffer.
var writeReq = this._handle.write(data);
if (!writeReq) {
this.destroy(errnoException(errno, 'write'));
this._destroy(errnoException(errno, 'write'), cb);
return false;
}
@ -477,7 +500,7 @@ function afterWrite(status, handle, req, buffer) {
}
if (status) {
self.destroy(errnoException(errno, 'write'));
self._destroy(errnoException(errno, 'write'), req.cb);
return;
}
@ -494,7 +517,7 @@ function afterWrite(status, handle, req, buffer) {
if (req.cb) req.cb();
if (self._pendingWriteReqs == 0 && self._flags & FLAG_DESTROY_SOON) {
self.destroy();
self._destroy();
}
}
@ -522,7 +545,7 @@ function connect(self, address, port, addressType) {
if (connectReq !== null) {
connectReq.oncomplete = afterConnect;
} else {
self.destroy(errnoException(errno, 'connect'));
self._destroy(errnoException(errno, 'connect'));
}
}
@ -570,7 +593,7 @@ Socket.prototype.connect = function(port /* [host], [cb] */) {
// error event to the next tick.
process.nextTick(function() {
self.emit('error', err);
self.destroy();
self._destroy();
});
} else {
timers.active(self);
@ -619,8 +642,9 @@ function afterConnect(status, handle, req, readable, writable) {
if (self._connectQueue) {
debug('Drain the connect queue');
for (var i = 0; i < self._connectQueue.length; i++) {
self._write.apply(self, self._connectQueue[i]);
var connectQueue = self._connectQueue;
for (var i = 0; i < connectQueue.length; i++) {
self._write.apply(self, connectQueue[i]);
}
self._connectQueueCleanUp();
}
@ -634,7 +658,7 @@ function afterConnect(status, handle, req, readable, writable) {
}
} else {
self._connectQueueCleanUp();
self.destroy(errnoException(errno, 'connect'));
self._destroy(errnoException(errno, 'connect'));
}
}

16
test/simple/test-net-write-after-close.js

@ -24,21 +24,23 @@ var assert = require('assert');
var net = require('net');
var gotError = false;
var gotWriteCB = false;
process.on('exit', function() {
assert(gotError);
assert(gotWriteCB);
});
var server = net.createServer(function(socket) {
setTimeout(function() {
assert.throws(
function() {
socket.write('test');
},
/This socket is closed/
);
socket.on('error', function(error) {
server.close();
gotError = true;
});
setTimeout(function() {
socket.write('test', function(e) {
gotWriteCB = true;
});
}, 250);
});

Loading…
Cancel
Save