Родитель
d019eac5b5
Коммит
640912d18a
|
@ -651,7 +651,7 @@ Socket.prototype._writeGeneric = function(writev, data, encoding, cb) {
|
|||
}
|
||||
|
||||
if (err)
|
||||
return this._destroy(errnoException(err, 'write'), cb);
|
||||
return this._destroy(errnoException(err, 'write', req.error), cb);
|
||||
|
||||
this._bytesDispatched += req.bytes;
|
||||
|
||||
|
@ -745,7 +745,7 @@ Socket.prototype.__defineGetter__('bytesWritten', function() {
|
|||
});
|
||||
|
||||
|
||||
function afterWrite(status, handle, req) {
|
||||
function afterWrite(status, handle, req, err) {
|
||||
var self = handle.owner;
|
||||
if (self !== process.stderr && self !== process.stdout)
|
||||
debug('afterWrite', status);
|
||||
|
@ -757,7 +757,7 @@ function afterWrite(status, handle, req) {
|
|||
}
|
||||
|
||||
if (status < 0) {
|
||||
var ex = errnoException(status, 'write');
|
||||
var ex = errnoException(status, 'write', err);
|
||||
debug('write failure', ex);
|
||||
self._destroy(ex, req.cb);
|
||||
return;
|
||||
|
|
|
@ -677,10 +677,13 @@ exports.pump = exports.deprecate(function(readStream, writeStream, callback) {
|
|||
|
||||
|
||||
var uv;
|
||||
exports._errnoException = function(err, syscall) {
|
||||
exports._errnoException = function(err, syscall, original) {
|
||||
if (isUndefined(uv)) uv = process.binding('uv');
|
||||
var errname = uv.errname(err);
|
||||
var e = new Error(syscall + ' ' + errname);
|
||||
var message = syscall + ' ' + errname;
|
||||
if (original)
|
||||
message += ' ' + original;
|
||||
var e = new Error(message);
|
||||
e.code = errname;
|
||||
e.errno = errname;
|
||||
e.syscall = syscall;
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace node {
|
|||
V(domain_string, "domain") \
|
||||
V(enter_string, "enter") \
|
||||
V(errno_string, "errno") \
|
||||
V(error_string, "error") \
|
||||
V(exit_string, "exit") \
|
||||
V(exponent_string, "exponent") \
|
||||
V(exports_string, "exports") \
|
||||
|
|
|
@ -215,6 +215,9 @@ void StreamWrap::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
|
|||
req_wrap->Dispatched();
|
||||
req_wrap_obj->Set(env->bytes_string(),
|
||||
Integer::NewFromUnsigned(length, node_isolate));
|
||||
const char* msg = wrap->callbacks()->Error();
|
||||
if (msg != NULL)
|
||||
req_wrap_obj->Set(env->error_string(), OneByteString(env->isolate(), msg));
|
||||
|
||||
if (err) {
|
||||
req_wrap->~WriteWrap();
|
||||
|
@ -300,6 +303,9 @@ void StreamWrap::WriteStringImpl(const FunctionCallbackInfo<Value>& args) {
|
|||
req_wrap->Dispatched();
|
||||
req_wrap->object()->Set(env->bytes_string(),
|
||||
Integer::NewFromUnsigned(data_size, node_isolate));
|
||||
const char* msg = wrap->callbacks()->Error();
|
||||
if (msg != NULL)
|
||||
req_wrap_obj->Set(env->error_string(), OneByteString(env->isolate(), msg));
|
||||
|
||||
if (err) {
|
||||
req_wrap->~WriteWrap();
|
||||
|
@ -401,6 +407,9 @@ void StreamWrap::Writev(const FunctionCallbackInfo<Value>& args) {
|
|||
req_wrap->Dispatched();
|
||||
req_wrap->object()->Set(env->bytes_string(),
|
||||
Number::New(node_isolate, bytes));
|
||||
const char* msg = wrap->callbacks()->Error();
|
||||
if (msg != NULL)
|
||||
req_wrap_obj->Set(env->error_string(), OneByteString(env->isolate(), msg));
|
||||
|
||||
if (err) {
|
||||
req_wrap->~WriteWrap();
|
||||
|
@ -441,14 +450,19 @@ void StreamWrap::AfterWrite(uv_write_t* req, int status) {
|
|||
// Unref handle property
|
||||
Local<Object> req_wrap_obj = req_wrap->object();
|
||||
req_wrap_obj->Delete(env->handle_string());
|
||||
wrap->callbacks_->AfterWrite(req_wrap);
|
||||
wrap->callbacks()->AfterWrite(req_wrap);
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Integer::New(status, node_isolate),
|
||||
wrap->object(),
|
||||
req_wrap_obj
|
||||
req_wrap_obj,
|
||||
Undefined()
|
||||
};
|
||||
|
||||
const char* msg = wrap->callbacks()->Error();
|
||||
if (msg != NULL)
|
||||
argv[3] = OneByteString(env->isolate(), msg);
|
||||
|
||||
req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
|
||||
|
||||
req_wrap->~WriteWrap();
|
||||
|
@ -499,6 +513,11 @@ void StreamWrap::AfterShutdown(uv_shutdown_t* req, int status) {
|
|||
}
|
||||
|
||||
|
||||
const char* StreamWrapCallbacks::Error() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int StreamWrapCallbacks::DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
|
|
|
@ -73,6 +73,7 @@ class StreamWrapCallbacks {
|
|||
virtual ~StreamWrapCallbacks() {
|
||||
}
|
||||
|
||||
virtual const char* Error();
|
||||
virtual int DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
|
|
139
src/tls_wrap.cc
139
src/tls_wrap.cc
|
@ -58,6 +58,10 @@ static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL
|
|||
| XN_FLAG_FN_SN;
|
||||
|
||||
|
||||
size_t TLSCallbacks::error_off_;
|
||||
char TLSCallbacks::error_buf_[1024];
|
||||
|
||||
|
||||
TLSCallbacks::TLSCallbacks(Environment* env,
|
||||
Kind kind,
|
||||
Handle<Object> sc,
|
||||
|
@ -71,15 +75,16 @@ TLSCallbacks::TLSCallbacks(Environment* env,
|
|||
enc_out_(NULL),
|
||||
clear_in_(NULL),
|
||||
write_size_(0),
|
||||
pending_write_item_(NULL),
|
||||
started_(false),
|
||||
established_(false),
|
||||
shutdown_(false),
|
||||
error_(NULL),
|
||||
eof_(false) {
|
||||
node::Wrap<TLSCallbacks>(object(), this);
|
||||
|
||||
// Initialize queue for clearIn writes
|
||||
QUEUE_INIT(&write_item_queue_);
|
||||
QUEUE_INIT(&pending_write_items_);
|
||||
|
||||
// We've our own session callbacks
|
||||
SSL_CTX_sess_set_get_cb(sc_->ctx_, SSLWrap<TLSCallbacks>::GetSessionCallback);
|
||||
|
@ -102,25 +107,52 @@ TLSCallbacks::~TLSCallbacks() {
|
|||
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
||||
sni_context_.Dispose();
|
||||
#endif // SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
||||
|
||||
// Move all writes to pending
|
||||
MakePending();
|
||||
|
||||
// And destroy
|
||||
while (!QUEUE_EMPTY(&pending_write_items_)) {
|
||||
QUEUE* q = QUEUE_HEAD(&pending_write_items_);
|
||||
QUEUE_REMOVE(q);
|
||||
|
||||
WriteItem* wi = QUEUE_DATA(q, WriteItem, member_);
|
||||
delete wi;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TLSCallbacks::InvokeQueued(int status) {
|
||||
// Empty queue - ignore call
|
||||
if (pending_write_item_ == NULL)
|
||||
void TLSCallbacks::MakePending() {
|
||||
// Aliases
|
||||
QUEUE* from = &write_item_queue_;
|
||||
QUEUE* to = &pending_write_items_;
|
||||
|
||||
if (QUEUE_EMPTY(from))
|
||||
return;
|
||||
|
||||
QUEUE* q = &pending_write_item_->member_;
|
||||
pending_write_item_ = NULL;
|
||||
// Add items to pending
|
||||
QUEUE_ADD(to, from);
|
||||
|
||||
// Empty original queue
|
||||
QUEUE_INIT(from);
|
||||
}
|
||||
|
||||
|
||||
bool TLSCallbacks::InvokeQueued(int status) {
|
||||
if (QUEUE_EMPTY(&pending_write_items_))
|
||||
return false;
|
||||
|
||||
// Process old queue
|
||||
while (q != &write_item_queue_) {
|
||||
QUEUE* next = static_cast<QUEUE*>(QUEUE_NEXT(q));
|
||||
WriteItem* wi = CONTAINER_OF(q, WriteItem, member_);
|
||||
while (!QUEUE_EMPTY(&pending_write_items_)) {
|
||||
QUEUE* q = QUEUE_HEAD(&pending_write_items_);
|
||||
QUEUE_REMOVE(q);
|
||||
|
||||
WriteItem* wi = QUEUE_DATA(q, WriteItem, member_);
|
||||
wi->cb_(&wi->w_->req_, status);
|
||||
delete wi;
|
||||
q = next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -276,16 +308,13 @@ void TLSCallbacks::EncOut() {
|
|||
return;
|
||||
|
||||
// Split-off queue
|
||||
if (established_ && !QUEUE_EMPTY(&write_item_queue_)) {
|
||||
pending_write_item_ = CONTAINER_OF(QUEUE_NEXT(&write_item_queue_),
|
||||
WriteItem,
|
||||
member_);
|
||||
QUEUE_INIT(&write_item_queue_);
|
||||
}
|
||||
if (established_ && !QUEUE_EMPTY(&write_item_queue_))
|
||||
MakePending();
|
||||
|
||||
// No data to write
|
||||
if (BIO_pending(enc_out_) == 0) {
|
||||
InvokeQueued(0);
|
||||
if (clear_in_->Length() == 0)
|
||||
InvokeQueued(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -314,7 +343,6 @@ void TLSCallbacks::EncOut() {
|
|||
|
||||
void TLSCallbacks::EncOutCb(uv_write_t* req, int status) {
|
||||
TLSCallbacks* callbacks = static_cast<TLSCallbacks*>(req->data);
|
||||
Environment* env = callbacks->env();
|
||||
|
||||
// Handle error
|
||||
if (status) {
|
||||
|
@ -323,12 +351,6 @@ void TLSCallbacks::EncOutCb(uv_write_t* req, int status) {
|
|||
return;
|
||||
|
||||
// Notify about error
|
||||
HandleScope handle_scope(env->isolate());
|
||||
Context::Scope context_scope(env->context());
|
||||
Local<Value> arg = String::Concat(
|
||||
FIXED_ONE_BYTE_STRING(node_isolate, "write cb error, status: "),
|
||||
Integer::New(status, node_isolate)->ToString());
|
||||
callbacks->MakeCallback(env->onerror_string(), 1, &arg);
|
||||
callbacks->InvokeQueued(status);
|
||||
return;
|
||||
}
|
||||
|
@ -342,7 +364,33 @@ void TLSCallbacks::EncOutCb(uv_write_t* req, int status) {
|
|||
}
|
||||
|
||||
|
||||
Local<Value> TLSCallbacks::GetSSLError(int status, int* err) {
|
||||
int TLSCallbacks::PrintErrorsCb(const char* str, size_t len, void* arg) {
|
||||
size_t to_copy = error_off_;
|
||||
size_t avail = sizeof(error_buf_) - error_off_ - 1;
|
||||
|
||||
if (avail > to_copy)
|
||||
to_copy = avail;
|
||||
|
||||
memcpy(error_buf_, str, avail);
|
||||
error_off_ += avail;
|
||||
assert(error_off_ < sizeof(error_buf_));
|
||||
|
||||
// Zero-terminate
|
||||
error_buf_[error_off_] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char* TLSCallbacks::PrintErrors() {
|
||||
error_off_ = 0;
|
||||
ERR_print_errors_cb(PrintErrorsCb, this);
|
||||
|
||||
return error_buf_;
|
||||
}
|
||||
|
||||
|
||||
Local<Value> TLSCallbacks::GetSSLError(int status, int* err, const char** msg) {
|
||||
HandleScope scope(node_isolate);
|
||||
|
||||
*err = SSL_get_error(ssl_, status);
|
||||
|
@ -356,19 +404,18 @@ Local<Value> TLSCallbacks::GetSSLError(int status, int* err) {
|
|||
break;
|
||||
default:
|
||||
{
|
||||
BUF_MEM* mem;
|
||||
BIO* bio;
|
||||
|
||||
assert(*err == SSL_ERROR_SSL || *err == SSL_ERROR_SYSCALL);
|
||||
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
assert(bio != NULL);
|
||||
ERR_print_errors(bio);
|
||||
BIO_get_mem_ptr(bio, &mem);
|
||||
const char* buf = PrintErrors();
|
||||
|
||||
Local<String> message =
|
||||
OneByteString(node_isolate, mem->data, mem->length);
|
||||
OneByteString(node_isolate, buf, strlen(buf));
|
||||
Local<Value> exception = Exception::Error(message);
|
||||
BIO_free_all(bio);
|
||||
|
||||
if (msg != NULL) {
|
||||
assert(*msg == NULL);
|
||||
*msg = buf;
|
||||
}
|
||||
|
||||
return scope.Close(exception);
|
||||
}
|
||||
|
@ -409,7 +456,7 @@ void TLSCallbacks::ClearOut() {
|
|||
|
||||
if (read == -1) {
|
||||
int err;
|
||||
Handle<Value> arg = GetSSLError(read, &err);
|
||||
Local<Value> arg = GetSSLError(read, &err, NULL);
|
||||
|
||||
if (!arg.IsEmpty()) {
|
||||
MakeCallback(env()->onerror_string(), 1, &arg);
|
||||
|
@ -445,15 +492,25 @@ bool TLSCallbacks::ClearIn() {
|
|||
|
||||
// Error or partial write
|
||||
int err;
|
||||
Handle<Value> arg = GetSSLError(written, &err);
|
||||
Local<Value> arg = GetSSLError(written, &err, &error_);
|
||||
if (!arg.IsEmpty()) {
|
||||
MakeCallback(env()->onerror_string(), 1, &arg);
|
||||
MakePending();
|
||||
if (!InvokeQueued(UV_EPROTO))
|
||||
error_ = NULL;
|
||||
clear_in_->Reset();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char* TLSCallbacks::Error() {
|
||||
const char* ret = error_;
|
||||
error_ = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int TLSCallbacks::DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
|
@ -508,11 +565,9 @@ int TLSCallbacks::DoWrite(WriteWrap* w,
|
|||
int err;
|
||||
HandleScope handle_scope(env()->isolate());
|
||||
Context::Scope context_scope(env()->context());
|
||||
Handle<Value> arg = GetSSLError(written, &err);
|
||||
if (!arg.IsEmpty()) {
|
||||
MakeCallback(env()->onerror_string(), 1, &arg);
|
||||
return -1;
|
||||
}
|
||||
Local<Value> arg = GetSSLError(written, &err, &error_);
|
||||
if (!arg.IsEmpty())
|
||||
return UV_EPROTO;
|
||||
|
||||
// No errors, queue rest
|
||||
for (; i < count; i++)
|
||||
|
|
|
@ -50,6 +50,7 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
|
|||
v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context);
|
||||
|
||||
const char* Error();
|
||||
int DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
|
@ -98,7 +99,8 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
|
|||
static void EncOutCb(uv_write_t* req, int status);
|
||||
bool ClearIn();
|
||||
void ClearOut();
|
||||
void InvokeQueued(int status);
|
||||
void MakePending();
|
||||
bool InvokeQueued(int status);
|
||||
|
||||
inline void Cycle() {
|
||||
ClearIn();
|
||||
|
@ -106,7 +108,10 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
|
|||
EncOut();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> GetSSLError(int status, int* err);
|
||||
v8::Local<v8::Value> GetSSLError(int status, int* err, const char** msg);
|
||||
const char* PrintErrors();
|
||||
|
||||
static int PrintErrorsCb(const char* str, size_t len, void* arg);
|
||||
static void OnClientHelloParseEnd(void* arg);
|
||||
|
||||
static void Wrap(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
@ -133,10 +138,11 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
|
|||
size_t write_size_;
|
||||
size_t write_queue_size_;
|
||||
QUEUE write_item_queue_;
|
||||
WriteItem* pending_write_item_;
|
||||
QUEUE pending_write_items_;
|
||||
bool started_;
|
||||
bool established_;
|
||||
bool shutdown_;
|
||||
const char* error_;
|
||||
|
||||
// If true - delivered EOF to the js-land, either after `close_notify`, or
|
||||
// after the `UV_EOF` on socket.
|
||||
|
@ -145,6 +151,9 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
|
|||
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
||||
v8::Persistent<v8::Value> sni_context_;
|
||||
#endif // SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
||||
|
||||
static size_t error_off_;
|
||||
static char error_buf_[1024];
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
|
|
@ -83,7 +83,7 @@ var server = tls.createServer({ ca: ca, cert: cert, key: key }, function(conn) {
|
|||
connectError = err;
|
||||
this.destroy();
|
||||
server.close();
|
||||
});
|
||||
}).write('123');
|
||||
});
|
||||
|
||||
process.on('exit', function() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче