%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/
Upload File :
Create Path :
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/stream_wrap.cc

// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "stream_wrap.h"
#include "stream_base-inl.h"

#include "env-inl.h"
#include "handle_wrap.h"
#include "node_buffer.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "pipe_wrap.h"
#include "req_wrap-inl.h"
#include "tcp_wrap.h"
#include "udp_wrap.h"
#include "util-inl.h"

#include <cstring>  // memcpy()
#include <climits>  // INT_MAX


namespace node {

using errors::TryCatchScope;
using v8::Context;
using v8::DontDelete;
using v8::EscapableHandleScope;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Isolate;
using v8::JustVoid;
using v8::Local;
using v8::Maybe;
using v8::MaybeLocal;
using v8::Nothing;
using v8::Object;
using v8::PropertyAttribute;
using v8::ReadOnly;
using v8::Signature;
using v8::Value;

void IsConstructCallCallback(const FunctionCallbackInfo<Value>& args) {
  CHECK(args.IsConstructCall());
  StreamReq::ResetObject(args.This());
}

void LibuvStreamWrap::Initialize(Local<Object> target,
                                 Local<Value> unused,
                                 Local<Context> context,
                                 void* priv) {
  Environment* env = Environment::GetCurrent(context);
  Isolate* isolate = env->isolate();

  Local<FunctionTemplate> sw =
      NewFunctionTemplate(isolate, IsConstructCallCallback);
  sw->InstanceTemplate()->SetInternalFieldCount(StreamReq::kInternalFieldCount);

  // we need to set handle and callback to null,
  // so that those fields are created and functions
  // do not become megamorphic
  // Fields:
  // - oncomplete
  // - callback
  // - handle
  sw->InstanceTemplate()->Set(env->oncomplete_string(), v8::Null(isolate));
  sw->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(isolate, "callback"),
                              v8::Null(isolate));
  sw->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(isolate, "handle"),
                              v8::Null(isolate));

  sw->Inherit(AsyncWrap::GetConstructorTemplate(env));

  SetConstructorFunction(context, target, "ShutdownWrap", sw);
  env->set_shutdown_wrap_template(sw->InstanceTemplate());

  Local<FunctionTemplate> ww =
      FunctionTemplate::New(isolate, IsConstructCallCallback);
  ww->InstanceTemplate()->SetInternalFieldCount(
      StreamReq::kInternalFieldCount);
  ww->Inherit(AsyncWrap::GetConstructorTemplate(env));
  SetConstructorFunction(context, target, "WriteWrap", ww);
  env->set_write_wrap_template(ww->InstanceTemplate());

  NODE_DEFINE_CONSTANT(target, kReadBytesOrError);
  NODE_DEFINE_CONSTANT(target, kArrayBufferOffset);
  NODE_DEFINE_CONSTANT(target, kBytesWritten);
  NODE_DEFINE_CONSTANT(target, kLastWriteWasAsync);
  target
      ->Set(context,
            FIXED_ONE_BYTE_STRING(isolate, "streamBaseState"),
            env->stream_base_state().GetJSArray())
      .Check();
}

void LibuvStreamWrap::RegisterExternalReferences(
    ExternalReferenceRegistry* registry) {
  registry->Register(IsConstructCallCallback);
  registry->Register(GetWriteQueueSize);
  registry->Register(SetBlocking);
  StreamBase::RegisterExternalReferences(registry);
}

LibuvStreamWrap::LibuvStreamWrap(Environment* env,
                                 Local<Object> object,
                                 uv_stream_t* stream,
                                 AsyncWrap::ProviderType provider)
    : HandleWrap(env,
                 object,
                 reinterpret_cast<uv_handle_t*>(stream),
                 provider),
      StreamBase(env),
      stream_(stream) {
  StreamBase::AttachToObject(object);
}


Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate(
    Environment* env) {
  Local<FunctionTemplate> tmpl = env->libuv_stream_wrap_ctor_template();
  if (tmpl.IsEmpty()) {
    Isolate* isolate = env->isolate();
    tmpl = NewFunctionTemplate(isolate, nullptr);
    tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "LibuvStreamWrap"));
    tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
    tmpl->InstanceTemplate()->SetInternalFieldCount(
        StreamBase::kInternalFieldCount);
    Local<FunctionTemplate> get_write_queue_size =
        FunctionTemplate::New(isolate,
                              GetWriteQueueSize,
                              Local<Value>(),
                              Signature::New(isolate, tmpl));
    tmpl->PrototypeTemplate()->SetAccessorProperty(
        env->write_queue_size_string(),
        get_write_queue_size,
        Local<FunctionTemplate>(),
        static_cast<PropertyAttribute>(ReadOnly | DontDelete));
    SetProtoMethod(isolate, tmpl, "setBlocking", SetBlocking);
    StreamBase::AddMethods(env, tmpl);
    env->set_libuv_stream_wrap_ctor_template(tmpl);
  }
  return tmpl;
}


LibuvStreamWrap* LibuvStreamWrap::From(Environment* env, Local<Object> object) {
  Local<FunctionTemplate> sw = env->libuv_stream_wrap_ctor_template();
  CHECK(!sw.IsEmpty() && sw->HasInstance(object));
  return Unwrap<LibuvStreamWrap>(object);
}


int LibuvStreamWrap::GetFD() {
#ifdef _WIN32
  return fd_;
#else
  int fd = -1;
  if (stream() != nullptr)
    uv_fileno(reinterpret_cast<uv_handle_t*>(stream()), &fd);
  return fd;
#endif
}


bool LibuvStreamWrap::IsAlive() {
  return HandleWrap::IsAlive(this);
}


bool LibuvStreamWrap::IsClosing() {
  return uv_is_closing(reinterpret_cast<uv_handle_t*>(stream()));
}


AsyncWrap* LibuvStreamWrap::GetAsyncWrap() {
  return static_cast<AsyncWrap*>(this);
}


bool LibuvStreamWrap::IsIPCPipe() {
  return is_named_pipe_ipc();
}

int LibuvStreamWrap::ReadStart() {
  return uv_read_start(
      stream(),
      [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
        static_cast<LibuvStreamWrap*>(handle->data)
            ->OnUvAlloc(suggested_size, buf);
      },
      [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
        LibuvStreamWrap* wrap = static_cast<LibuvStreamWrap*>(stream->data);
        TryCatchScope try_catch(wrap->env());
        try_catch.SetVerbose(true);
        wrap->OnUvRead(nread, buf);
      });
}


int LibuvStreamWrap::ReadStop() {
  return uv_read_stop(stream());
}


void LibuvStreamWrap::OnUvAlloc(size_t suggested_size, uv_buf_t* buf) {
  HandleScope scope(env()->isolate());
  Context::Scope context_scope(env()->context());

  *buf = EmitAlloc(suggested_size);
}

template <class WrapType>
static MaybeLocal<Object> AcceptHandle(Environment* env,
                                       LibuvStreamWrap* parent) {
  static_assert(std::is_base_of<LibuvStreamWrap, WrapType>::value ||
                std::is_base_of<UDPWrap, WrapType>::value,
                "Can only accept stream handles");

  EscapableHandleScope scope(env->isolate());
  Local<Object> wrap_obj;

  if (!WrapType::Instantiate(env, parent, WrapType::SOCKET).ToLocal(&wrap_obj))
    return Local<Object>();

  HandleWrap* wrap = Unwrap<HandleWrap>(wrap_obj);
  CHECK_NOT_NULL(wrap);
  uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(wrap->GetHandle());
  CHECK_NOT_NULL(stream);

  if (uv_accept(parent->stream(), stream))
    ABORT();

  return scope.Escape(wrap_obj);
}

Maybe<void> LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) {
  HandleScope scope(env()->isolate());
  Context::Scope context_scope(env()->context());
  uv_handle_type type = UV_UNKNOWN_HANDLE;

  if (is_named_pipe_ipc() &&
      uv_pipe_pending_count(reinterpret_cast<uv_pipe_t*>(stream())) > 0) {
    type = uv_pipe_pending_type(reinterpret_cast<uv_pipe_t*>(stream()));
  }

  // We should not be getting this callback if someone has already called
  // uv_close() on the handle.
  CHECK_EQ(persistent().IsEmpty(), false);

  if (nread > 0) {
    MaybeLocal<Object> pending_obj;

    if (type == UV_TCP) {
      pending_obj = AcceptHandle<TCPWrap>(env(), this);
    } else if (type == UV_NAMED_PIPE) {
      pending_obj = AcceptHandle<PipeWrap>(env(), this);
    } else if (type == UV_UDP) {
      pending_obj = AcceptHandle<UDPWrap>(env(), this);
    } else {
      CHECK_EQ(type, UV_UNKNOWN_HANDLE);
    }

    Local<Object> local_pending_obj;
    if (type != UV_UNKNOWN_HANDLE &&
        (!pending_obj.ToLocal(&local_pending_obj) ||
         object()
             ->Set(env()->context(),
                   env()->pending_handle_string(),
                   local_pending_obj)
             .IsNothing())) {
      return Nothing<void>();
    }
  }

  EmitRead(nread, *buf);
  return JustVoid();
}

void LibuvStreamWrap::GetWriteQueueSize(
    const FunctionCallbackInfo<Value>& info) {
  LibuvStreamWrap* wrap;
  ASSIGN_OR_RETURN_UNWRAP(&wrap, info.This());

  if (wrap->stream() == nullptr) {
    info.GetReturnValue().Set(0);
    return;
  }

  uint32_t write_queue_size = wrap->stream()->write_queue_size;
  info.GetReturnValue().Set(write_queue_size);
}


void LibuvStreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) {
  LibuvStreamWrap* wrap;
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());

  CHECK_GT(args.Length(), 0);
  if (!wrap->IsAlive())
    return args.GetReturnValue().Set(UV_EINVAL);

  bool enable = args[0]->IsTrue();
  args.GetReturnValue().Set(uv_stream_set_blocking(wrap->stream(), enable));
}

typedef SimpleShutdownWrap<ReqWrap<uv_shutdown_t>> LibuvShutdownWrap;
typedef SimpleWriteWrap<ReqWrap<uv_write_t>> LibuvWriteWrap;

ShutdownWrap* LibuvStreamWrap::CreateShutdownWrap(Local<Object> object) {
  return new LibuvShutdownWrap(this, object);
}

WriteWrap* LibuvStreamWrap::CreateWriteWrap(Local<Object> object) {
  return new LibuvWriteWrap(this, object);
}


int LibuvStreamWrap::DoShutdown(ShutdownWrap* req_wrap_) {
  LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(req_wrap_);
  return req_wrap->Dispatch(uv_shutdown, stream(), AfterUvShutdown);
}


void LibuvStreamWrap::AfterUvShutdown(uv_shutdown_t* req, int status) {
  LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(
      LibuvShutdownWrap::from_req(req));
  CHECK_NOT_NULL(req_wrap);
  HandleScope scope(req_wrap->env()->isolate());
  Context::Scope context_scope(req_wrap->env()->context());
  req_wrap->Done(status);
}


// NOTE: Call to this function could change both `buf`'s and `count`'s
// values, shifting their base and decrementing their length. This is
// required in order to skip the data that was successfully written via
// uv_try_write().
int LibuvStreamWrap::DoTryWrite(uv_buf_t** bufs, size_t* count) {
  int err;
  size_t written;
  uv_buf_t* vbufs = *bufs;
  size_t vcount = *count;

  err = uv_try_write(stream(), vbufs, vcount);
  if (err == UV_ENOSYS || err == UV_EAGAIN)
    return 0;
  if (err < 0)
    return err;

  // Slice off the buffers: skip all written buffers and slice the one that
  // was partially written.
  written = err;
  for (; vcount > 0; vbufs++, vcount--) {
    // Slice
    if (vbufs[0].len > written) {
      vbufs[0].base += written;
      vbufs[0].len -= written;
      written = 0;
      break;

    // Discard
    } else {
      written -= vbufs[0].len;
    }
  }

  *bufs = vbufs;
  *count = vcount;

  return 0;
}


int LibuvStreamWrap::DoWrite(WriteWrap* req_wrap,
                             uv_buf_t* bufs,
                             size_t count,
                             uv_stream_t* send_handle) {
  LibuvWriteWrap* w = static_cast<LibuvWriteWrap*>(req_wrap);
  return w->Dispatch(uv_write2,
                     stream(),
                     bufs,
                     count,
                     send_handle,
                     AfterUvWrite);
}



void LibuvStreamWrap::AfterUvWrite(uv_write_t* req, int status) {
  LibuvWriteWrap* req_wrap = static_cast<LibuvWriteWrap*>(
      LibuvWriteWrap::from_req(req));
  CHECK_NOT_NULL(req_wrap);
  HandleScope scope(req_wrap->env()->isolate());
  Context::Scope context_scope(req_wrap->env()->context());
  req_wrap->Done(status);
}

}  // namespace node

NODE_BINDING_CONTEXT_AWARE_INTERNAL(stream_wrap,
                                    node::LibuvStreamWrap::Initialize)
NODE_BINDING_EXTERNAL_REFERENCE(
    stream_wrap, node::LibuvStreamWrap::RegisterExternalReferences)

Zerion Mini Shell 1.0