TLS: simplify logic

v0.7.4-release
Ryan Dahl 2011-05-06 16:48:44 -07:00
parent fc8afd45c7
commit 55bff5bab9
1 changed files with 86 additions and 97 deletions

View File

@ -51,7 +51,7 @@ function CryptoStream(pair) {
this.readable = this.writable = true;
this._writeState = true;
this._paused = false;
this._pending = [];
this._pendingCallbacks = [];
this._pendingBytes = 0;
@ -90,11 +90,10 @@ CryptoStream.prototype.write = function(data /* , encoding, cb */) {
this._pending.push(data);
this._pendingCallbacks.push(cb);
this._pendingBytes += data.length;
this.pair._writeCalled = true;
this.pair._cycle();
this.pair.cycle();
return this._pendingBytes < 128 * 1024;
};
@ -102,14 +101,14 @@ CryptoStream.prototype.write = function(data /* , encoding, cb */) {
CryptoStream.prototype.pause = function() {
debug('paused ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted'));
this._writeState = false;
this._paused = true;
};
CryptoStream.prototype.resume = function() {
debug('resume ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted'));
this._writeState = true;
this.pair._cycle();
this._paused = false;
this.pair.cycle();
};
@ -147,8 +146,8 @@ function parseCertString(s) {
CryptoStream.prototype.getPeerCertificate = function() {
if (this.pair._ssl) {
var c = this.pair._ssl.getPeerCertificate();
if (this.pair.ssl) {
var c = this.pair.ssl.getPeerCertificate();
if (c) {
if (c.issuer) c.issuer = parseCertString(c.issuer);
@ -162,8 +161,8 @@ CryptoStream.prototype.getPeerCertificate = function() {
CryptoStream.prototype.getCipher = function(err) {
if (this.pair._ssl) {
return this.pair._ssl.getCurrentCipher();
if (this.pair.ssl) {
return this.pair.ssl.getCurrentCipher();
} else {
return null;
}
@ -171,23 +170,22 @@ CryptoStream.prototype.getCipher = function(err) {
CryptoStream.prototype.end = function(d) {
if (this.writable) {
if (this.pair._done) return;
if (this.pair._doneFlag) return;
if (!this.writable) return;
if (d) {
this.write(d);
}
this._pending.push(END_OF_FILE);
this._pendingCallbacks.push(null);
// If this is an encrypted stream then we need to disable further 'data'
// events.
this.writable = false;
this.pair._cycle();
if (d) {
this.write(d);
}
this._pending.push(END_OF_FILE);
this._pendingCallbacks.push(null);
// If this is an encrypted stream then we need to disable further 'data'
// events.
this.writable = false;
this.pair.cycle();
};
@ -201,8 +199,8 @@ CryptoStream.prototype.destroySoon = function(err) {
CryptoStream.prototype.destroy = function(err) {
if (this.pair._done) return;
this.pair._destroy();
if (this.pair._doneFlag) return;
this.pair.destroy();
};
@ -211,9 +209,9 @@ CryptoStream.prototype._done = function() {
if (this.pair.cleartext._doneFlag &&
this.pair.encrypted._doneFlag &&
!this.pair._done) {
!this.pair._doneFlag) {
// If both streams are done:
this.pair._destroy();
this.pair.destroy();
}
};
@ -241,7 +239,7 @@ CryptoStream.prototype._push = function() {
return;
}
while (this._writeState == true) {
while (!this._paused) {
var bytesRead = 0;
var chunkBytes = 0;
var pool = new Buffer(16 * 4096); // alloc every time?
@ -249,18 +247,18 @@ CryptoStream.prototype._push = function() {
do {
chunkBytes = this._pusher(pool, bytesRead, pool.length - bytesRead);
if (this.pair._ssl && this.pair._ssl.error) {
this.pair._error();
if (this.pair.ssl && this.pair.ssl.error) {
this.pair.error();
return;
}
this.pair._maybeInitFinished();
this.pair.maybeInitFinished();
if (chunkBytes >= 0) {
bytesRead += chunkBytes;
}
} while ((chunkBytes > 0) && (bytesRead < pool.length));
} while (chunkBytes > 0 && bytesRead < pool.length);
assert(bytesRead >= 0);
@ -313,7 +311,7 @@ CryptoStream.prototype._pull = function() {
assert(havePending || this._pendingBytes == 0);
while (this._pending.length > 0) {
if (!this.pair._ssl) break;
if (!this.pair.ssl) break;
var tmp = this._pending.shift();
var cb = this._pendingCallbacks.shift();
@ -330,7 +328,7 @@ CryptoStream.prototype._pull = function() {
assert(this === this.pair.cleartext);
debug('end cleartext');
this.pair._ssl.shutdown();
this.pair.ssl.shutdown();
// TODO check if we get EAGAIN From shutdown, would have to do it
// again. should unshift END_OF_FILE back onto pending and wait for
@ -338,7 +336,7 @@ CryptoStream.prototype._pull = function() {
this.pair.encrypted._destroyAfterPush = true;
}
this.pair._cycle();
this.pair.cycle();
this._done()
return;
}
@ -347,12 +345,12 @@ CryptoStream.prototype._pull = function() {
var rv = this._puller(tmp);
if (this.pair._ssl && this.pair._ssl.error) {
this.pair._error();
if (this.pair.ssl && this.pair.ssl.error) {
this.pair.error();
return;
}
this.pair._maybeInitFinished();
this.pair.maybeInitFinished();
if (rv === 0 || rv < 0) {
this._pending.unshift(tmp);
@ -384,8 +382,8 @@ util.inherits(CleartextStream, CryptoStream);
CleartextStream.prototype._internallyPendingBytes = function() {
if (this.pair._ssl) {
return this.pair._ssl.clearPending();
if (this.pair.ssl) {
return this.pair.ssl.clearPending();
} else {
return 0;
}
@ -394,14 +392,14 @@ CleartextStream.prototype._internallyPendingBytes = function() {
CleartextStream.prototype._puller = function(b) {
debug('clearIn ' + b.length + ' bytes');
return this.pair._ssl.clearIn(b, 0, b.length);
return this.pair.ssl.clearIn(b, 0, b.length);
};
CleartextStream.prototype._pusher = function(pool, offset, length) {
debug('reading from clearOut');
if (!this.pair._ssl) return -1;
return this.pair._ssl.clearOut(pool, offset, length);
if (!this.pair.ssl) return -1;
return this.pair.ssl.clearOut(pool, offset, length);
};
@ -412,8 +410,8 @@ util.inherits(EncryptedStream, CryptoStream);
EncryptedStream.prototype._internallyPendingBytes = function() {
if (this.pair._ssl) {
return this.pair._ssl.encPending();
if (this.pair.ssl) {
return this.pair.ssl.encPending();
} else {
return 0;
}
@ -422,14 +420,14 @@ EncryptedStream.prototype._internallyPendingBytes = function() {
EncryptedStream.prototype._puller = function(b) {
debug('writing from encIn');
return this.pair._ssl.encIn(b, 0, b.length);
return this.pair.ssl.encIn(b, 0, b.length);
};
EncryptedStream.prototype._pusher = function(pool, offset, length) {
debug('reading from encOut');
if (!this.pair._ssl) return -1;
return this.pair._ssl.encOut(pool, offset, length);
if (!this.pair.ssl) return -1;
return this.pair.ssl.encOut(pool, offset, length);
};
@ -453,9 +451,7 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
this._isServer = isServer ? true : false;
this._encWriteState = true;
this._clearWriteState = true;
this._done = false;
var crypto = require('crypto');
this._doneFlag = false;
if (!credentials) {
this.credentials = crypto.createCredentials();
@ -473,7 +469,7 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
this._rejectUnauthorized = rejectUnauthorized ? true : false;
this._requestCert = requestCert ? true : false;
this._ssl = new Connection(this.credentials.context,
this.ssl = new Connection(this.credentials.context,
this._isServer ? true : false,
this._requestCert,
this._rejectUnauthorized);
@ -486,8 +482,8 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
this.encrypted = new EncryptedStream(this);
process.nextTick(function() {
self._ssl.start();
self._cycle();
self.ssl.start();
self.cycle();
});
}
@ -535,59 +531,54 @@ exports.createSecurePair = function(credentials,
* Because it is also called everywhere, we also check if the connection has
* completed negotiation and emit 'secure' from here if it has.
*/
SecurePair.prototype._cycle = function(depth) {
depth = depth ? depth : 0;
if (this._done) {
return;
}
SecurePair.prototype.cycle = function(depth) {
if (this._doneFlag) return;
if(depth == 0) this._writeCalled = false;
depth = depth ? depth : 0;
if (depth == 0) this._writeCalled = false;
var established = this._secureEstablished;
if (!this._cycleEncryptedPullLock) {
this._cycleEncryptedPullLock = true;
if (!this.cycleEncryptedPullLock) {
this.cycleEncryptedPullLock = true;
debug("encrypted._pull");
this.encrypted._pull();
this._cycleEncryptedPullLock = false;
this.cycleEncryptedPullLock = false;
}
if (!this._cycleCleartextPullLock) {
this._cycleCleartextPullLock = true;
if (!this.cycleCleartextPullLock) {
this.cycleCleartextPullLock = true;
debug("cleartext._pull");
this.cleartext._pull();
this._cycleCleartextPullLock = false;
this.cycleCleartextPullLock = false;
}
if (!this._cycleCleartextPushLock) {
this._cycleCleartextPushLock = true;
if (!this.cycleCleartextPushLock) {
this.cycleCleartextPushLock = true;
debug("cleartext._push");
this.cleartext._push();
this._cycleCleartextPushLock = false;
this.cycleCleartextPushLock = false;
}
if (!this._cycleEncryptedPushLock) {
this._cycleEncryptedPushLock = true;
if (!this.cycleEncryptedPushLock) {
this.cycleEncryptedPushLock = true;
debug("encrypted._push");
this.encrypted._push();
this._cycleEncryptedPushLock = false;
}
if (this._done) {
return;
this.cycleEncryptedPushLock = false;
}
if ((!established && this._secureEstablished) ||
(depth == 0 && this._writeCalled)) {
// If we were not established but now we are, let's cycle again.
// Or if there is some data to write...
this._cycle(depth + 1);
this.cycle(depth + 1);
}
};
SecurePair.prototype._maybeInitFinished = function() {
if (this._ssl && !this._secureEstablished && this._ssl.isInitFinished()) {
SecurePair.prototype.maybeInitFinished = function() {
if (this.ssl && !this._secureEstablished && this.ssl.isInitFinished()) {
this._secureEstablished = true;
debug('secure established');
this.emit('secure');
@ -595,14 +586,14 @@ SecurePair.prototype._maybeInitFinished = function() {
};
SecurePair.prototype._destroy = function() {
SecurePair.prototype.destroy = function() {
var self = this;
if (!this._done) {
this._done = true;
this._ssl.error = null;
this._ssl.close();
this._ssl = null;
if (!this._doneFlag) {
this._doneFlag = true;
this.ssl.error = null;
this.ssl.close();
this.ssl = null;
self.encrypted.writable = self.encrypted.readable = false;
self.cleartext.writable = self.cleartext.readable = false;
@ -612,23 +603,21 @@ SecurePair.prototype._destroy = function() {
self.cleartext.emit('close');
});
}
this._cycle();
};
SecurePair.prototype._error = function() {
SecurePair.prototype.error = function() {
if (!this._secureEstablished) {
this._destroy();
this.destroy();
} else {
var err = this._ssl.error;
this._ssl.error = null;
var err = this.ssl.error;
this.ssl.error = null;
if (this._isServer &&
this._rejectUnauthorized &&
/peer did not return a certificate/.test(err.message)) {
// Not really an error.
this._destroy();
this.destroy();
} else {
this.cleartext.emit('error', err);
}
@ -749,13 +738,13 @@ function Server(/* [options], listener */) {
cleartext._controlReleased = true;
self.emit('secureConnection', pair.cleartext, pair.encrypted);
} else {
var verifyError = pair._ssl.verifyError();
var verifyError = pair.ssl.verifyError();
if (verifyError) {
pair.cleartext.authorizationError = verifyError;
if (self.rejectUnauthorized) {
socket.destroy();
pair._destroy();
pair.destroy();
} else {
cleartext._controlReleased = true;
self.emit('secureConnection', pair.cleartext, pair.encrypted);
@ -851,7 +840,7 @@ exports.connect = function(port /* host, options, cb */) {
socket.connect(port, host);
pair.on('secure', function() {
var verifyError = pair._ssl.verifyError();
var verifyError = pair.ssl.verifyError();
if (verifyError) {
cleartext.authorized = false;