1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22#include "pipe_wrap.h" 23 24#include "async_wrap.h" 25#include "connect_wrap.h" 26#include "connection_wrap.h" 27#include "env-inl.h" 28#include "handle_wrap.h" 29#include "node.h" 30#include "node_buffer.h" 31#include "node_external_reference.h" 32#include "stream_base-inl.h" 33#include "stream_wrap.h" 34#include "util-inl.h" 35 36namespace node { 37 38using v8::Context; 39using v8::EscapableHandleScope; 40using v8::Function; 41using v8::FunctionCallbackInfo; 42using v8::FunctionTemplate; 43using v8::Int32; 44using v8::Isolate; 45using v8::Local; 46using v8::MaybeLocal; 47using v8::Object; 48using v8::Value; 49 50MaybeLocal<Object> PipeWrap::Instantiate(Environment* env, 51 AsyncWrap* parent, 52 PipeWrap::SocketType type) { 53 EscapableHandleScope handle_scope(env->isolate()); 54 AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent); 55 CHECK_EQ(false, env->pipe_constructor_template().IsEmpty()); 56 Local<Function> constructor = env->pipe_constructor_template() 57 ->GetFunction(env->context()) 58 .ToLocalChecked(); 59 CHECK_EQ(false, constructor.IsEmpty()); 60 Local<Value> type_value = Int32::New(env->isolate(), type); 61 return handle_scope.EscapeMaybe( 62 constructor->NewInstance(env->context(), 1, &type_value)); 63} 64 65 66void PipeWrap::Initialize(Local<Object> target, 67 Local<Value> unused, 68 Local<Context> context, 69 void* priv) { 70 Environment* env = Environment::GetCurrent(context); 71 Isolate* isolate = env->isolate(); 72 73 Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New); 74 t->InstanceTemplate() 75 ->SetInternalFieldCount(StreamBase::kInternalFieldCount); 76 77 t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env)); 78 79 SetProtoMethod(isolate, t, "bind", Bind); 80 SetProtoMethod(isolate, t, "listen", Listen); 81 SetProtoMethod(isolate, t, "connect", Connect); 82 SetProtoMethod(isolate, t, "open", Open); 83 84#ifdef _WIN32 85 SetProtoMethod(isolate, t, "setPendingInstances", SetPendingInstances); 86#endif 87 88 SetProtoMethod(isolate, t, "fchmod", Fchmod); 89 90 SetConstructorFunction(context, target, "Pipe", t); 91 env->set_pipe_constructor_template(t); 92 93 // Create FunctionTemplate for PipeConnectWrap. 94 auto cwt = BaseObject::MakeLazilyInitializedJSTemplate(env); 95 cwt->Inherit(AsyncWrap::GetConstructorTemplate(env)); 96 SetConstructorFunction(context, target, "PipeConnectWrap", cwt); 97 98 // Define constants 99 Local<Object> constants = Object::New(env->isolate()); 100 NODE_DEFINE_CONSTANT(constants, SOCKET); 101 NODE_DEFINE_CONSTANT(constants, SERVER); 102 NODE_DEFINE_CONSTANT(constants, IPC); 103 NODE_DEFINE_CONSTANT(constants, UV_READABLE); 104 NODE_DEFINE_CONSTANT(constants, UV_WRITABLE); 105 target->Set(context, 106 env->constants_string(), 107 constants).Check(); 108} 109 110void PipeWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry) { 111 registry->Register(New); 112 registry->Register(Bind); 113 registry->Register(Listen); 114 registry->Register(Connect); 115 registry->Register(Open); 116#ifdef _WIN32 117 registry->Register(SetPendingInstances); 118#endif 119 registry->Register(Fchmod); 120} 121 122void PipeWrap::New(const FunctionCallbackInfo<Value>& args) { 123 // This constructor should not be exposed to public javascript. 124 // Therefore we assert that we are not trying to call this as a 125 // normal function. 126 CHECK(args.IsConstructCall()); 127 CHECK(args[0]->IsInt32()); 128 Environment* env = Environment::GetCurrent(args); 129 130 int type_value = args[0].As<Int32>()->Value(); 131 PipeWrap::SocketType type = static_cast<PipeWrap::SocketType>(type_value); 132 133 bool ipc; 134 ProviderType provider; 135 switch (type) { 136 case SOCKET: 137 provider = PROVIDER_PIPEWRAP; 138 ipc = false; 139 break; 140 case SERVER: 141 provider = PROVIDER_PIPESERVERWRAP; 142 ipc = false; 143 break; 144 case IPC: 145 provider = PROVIDER_PIPEWRAP; 146 ipc = true; 147 break; 148 default: 149 UNREACHABLE(); 150 } 151 152 new PipeWrap(env, args.This(), provider, ipc); 153} 154 155 156PipeWrap::PipeWrap(Environment* env, 157 Local<Object> object, 158 ProviderType provider, 159 bool ipc) 160 : ConnectionWrap(env, object, provider) { 161 int r = uv_pipe_init(env->event_loop(), &handle_, ipc); 162 CHECK_EQ(r, 0); // How do we proxy this error up to javascript? 163 // Suggestion: uv_pipe_init() returns void. 164} 165 166 167void PipeWrap::Bind(const FunctionCallbackInfo<Value>& args) { 168 PipeWrap* wrap; 169 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 170 node::Utf8Value name(args.GetIsolate(), args[0]); 171 int err = uv_pipe_bind(&wrap->handle_, *name); 172 args.GetReturnValue().Set(err); 173} 174 175 176#ifdef _WIN32 177void PipeWrap::SetPendingInstances(const FunctionCallbackInfo<Value>& args) { 178 PipeWrap* wrap; 179 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 180 CHECK(args[0]->IsInt32()); 181 int instances = args[0].As<Int32>()->Value(); 182 uv_pipe_pending_instances(&wrap->handle_, instances); 183} 184#endif 185 186 187void PipeWrap::Fchmod(const v8::FunctionCallbackInfo<v8::Value>& args) { 188 PipeWrap* wrap; 189 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 190 CHECK(args[0]->IsInt32()); 191 int mode = args[0].As<Int32>()->Value(); 192 int err = uv_pipe_chmod(&wrap->handle_, mode); 193 args.GetReturnValue().Set(err); 194} 195 196 197void PipeWrap::Listen(const FunctionCallbackInfo<Value>& args) { 198 PipeWrap* wrap; 199 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 200 Environment* env = wrap->env(); 201 int backlog; 202 if (!args[0]->Int32Value(env->context()).To(&backlog)) return; 203 int err = uv_listen(reinterpret_cast<uv_stream_t*>(&wrap->handle_), 204 backlog, 205 OnConnection); 206 args.GetReturnValue().Set(err); 207} 208 209 210void PipeWrap::Open(const FunctionCallbackInfo<Value>& args) { 211 Environment* env = Environment::GetCurrent(args); 212 213 PipeWrap* wrap; 214 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 215 216 int fd; 217 if (!args[0]->Int32Value(env->context()).To(&fd)) return; 218 219 int err = uv_pipe_open(&wrap->handle_, fd); 220 if (err == 0) wrap->set_fd(fd); 221 222 args.GetReturnValue().Set(err); 223} 224 225 226void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) { 227 Environment* env = Environment::GetCurrent(args); 228 229 PipeWrap* wrap; 230 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 231 232 CHECK(args[0]->IsObject()); 233 CHECK(args[1]->IsString()); 234 235 Local<Object> req_wrap_obj = args[0].As<Object>(); 236 node::Utf8Value name(env->isolate(), args[1]); 237 238 ConnectWrap* req_wrap = 239 new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPECONNECTWRAP); 240 req_wrap->Dispatch(uv_pipe_connect, 241 &wrap->handle_, 242 *name, 243 AfterConnect); 244 245 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE2(net, native), 246 "connect", 247 req_wrap, 248 "pipe_path", 249 TRACE_STR_COPY(*name)); 250 251 args.GetReturnValue().Set(0); // uv_pipe_connect() doesn't return errors. 252} 253 254 255} // namespace node 256 257NODE_BINDING_CONTEXT_AWARE_INTERNAL(pipe_wrap, node::PipeWrap::Initialize) 258NODE_BINDING_EXTERNAL_REFERENCE(pipe_wrap, 259 node::PipeWrap::RegisterExternalReferences) 260