/src/node/src/pipe_wrap.cc
Line | Count | Source (jump to first uncovered line) |
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 | | |
36 | | namespace node { |
37 | | |
38 | | using v8::Context; |
39 | | using v8::EscapableHandleScope; |
40 | | using v8::Function; |
41 | | using v8::FunctionCallbackInfo; |
42 | | using v8::FunctionTemplate; |
43 | | using v8::Int32; |
44 | | using v8::Isolate; |
45 | | using v8::Local; |
46 | | using v8::MaybeLocal; |
47 | | using v8::Object; |
48 | | using v8::Value; |
49 | | |
50 | | MaybeLocal<Object> PipeWrap::Instantiate(Environment* env, |
51 | | AsyncWrap* parent, |
52 | 0 | PipeWrap::SocketType type) { |
53 | 0 | EscapableHandleScope handle_scope(env->isolate()); |
54 | 0 | AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent); |
55 | 0 | CHECK_EQ(false, env->pipe_constructor_template().IsEmpty()); |
56 | 0 | Local<Function> constructor = env->pipe_constructor_template() |
57 | 0 | ->GetFunction(env->context()) |
58 | 0 | .ToLocalChecked(); |
59 | 0 | CHECK_EQ(false, constructor.IsEmpty()); |
60 | 0 | Local<Value> type_value = Int32::New(env->isolate(), type); |
61 | 0 | return handle_scope.EscapeMaybe( |
62 | 0 | constructor->NewInstance(env->context(), 1, &type_value)); |
63 | 0 | } |
64 | | |
65 | | void PipeWrap::Initialize(Local<Object> target, |
66 | | Local<Value> unused, |
67 | | Local<Context> context, |
68 | 82.9k | void* priv) { |
69 | 82.9k | Environment* env = Environment::GetCurrent(context); |
70 | 82.9k | Isolate* isolate = env->isolate(); |
71 | | |
72 | 82.9k | Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New); |
73 | 82.9k | t->InstanceTemplate()->SetInternalFieldCount(StreamBase::kInternalFieldCount); |
74 | | |
75 | 82.9k | t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env)); |
76 | | |
77 | 82.9k | SetProtoMethod(isolate, t, "bind", Bind); |
78 | 82.9k | SetProtoMethod(isolate, t, "listen", Listen); |
79 | 82.9k | SetProtoMethod(isolate, t, "connect", Connect); |
80 | 82.9k | SetProtoMethod(isolate, t, "open", Open); |
81 | | |
82 | | #ifdef _WIN32 |
83 | | SetProtoMethod(isolate, t, "setPendingInstances", SetPendingInstances); |
84 | | #endif |
85 | | |
86 | 82.9k | SetProtoMethod(isolate, t, "fchmod", Fchmod); |
87 | | |
88 | 82.9k | SetConstructorFunction(context, target, "Pipe", t); |
89 | 82.9k | env->set_pipe_constructor_template(t); |
90 | | |
91 | | // Create FunctionTemplate for PipeConnectWrap. |
92 | 82.9k | auto cwt = BaseObject::MakeLazilyInitializedJSTemplate(env); |
93 | 82.9k | cwt->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
94 | 82.9k | SetConstructorFunction(context, target, "PipeConnectWrap", cwt); |
95 | | |
96 | | // Define constants |
97 | 82.9k | Local<Object> constants = Object::New(env->isolate()); |
98 | 82.9k | NODE_DEFINE_CONSTANT(constants, SOCKET); |
99 | 82.9k | NODE_DEFINE_CONSTANT(constants, SERVER); |
100 | 82.9k | NODE_DEFINE_CONSTANT(constants, IPC); |
101 | 82.9k | NODE_DEFINE_CONSTANT(constants, UV_READABLE); |
102 | 82.9k | NODE_DEFINE_CONSTANT(constants, UV_WRITABLE); |
103 | 82.9k | target->Set(context, env->constants_string(), constants).Check(); |
104 | 82.9k | } |
105 | | |
106 | 0 | void PipeWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
107 | 0 | registry->Register(New); |
108 | 0 | registry->Register(Bind); |
109 | 0 | registry->Register(Listen); |
110 | 0 | registry->Register(Connect); |
111 | 0 | registry->Register(Open); |
112 | | #ifdef _WIN32 |
113 | | registry->Register(SetPendingInstances); |
114 | | #endif |
115 | 0 | registry->Register(Fchmod); |
116 | 0 | } |
117 | | |
118 | 82.3k | void PipeWrap::New(const FunctionCallbackInfo<Value>& args) { |
119 | | // This constructor should not be exposed to public javascript. |
120 | | // Therefore we assert that we are not trying to call this as a |
121 | | // normal function. |
122 | 82.3k | CHECK(args.IsConstructCall()); |
123 | 82.3k | CHECK(args[0]->IsInt32()); |
124 | 82.3k | Environment* env = Environment::GetCurrent(args); |
125 | | |
126 | 82.3k | int type_value = args[0].As<Int32>()->Value(); |
127 | 82.3k | PipeWrap::SocketType type = static_cast<PipeWrap::SocketType>(type_value); |
128 | | |
129 | 82.3k | bool ipc; |
130 | 82.3k | ProviderType provider; |
131 | 82.3k | switch (type) { |
132 | 82.3k | case SOCKET: |
133 | 82.3k | provider = PROVIDER_PIPEWRAP; |
134 | 82.3k | ipc = false; |
135 | 82.3k | break; |
136 | 0 | case SERVER: |
137 | 0 | provider = PROVIDER_PIPESERVERWRAP; |
138 | 0 | ipc = false; |
139 | 0 | break; |
140 | 0 | case IPC: |
141 | 0 | provider = PROVIDER_PIPEWRAP; |
142 | 0 | ipc = true; |
143 | 0 | break; |
144 | 0 | default: |
145 | 0 | UNREACHABLE(); |
146 | 82.3k | } |
147 | | |
148 | 82.3k | new PipeWrap(env, args.This(), provider, ipc); |
149 | 82.3k | } |
150 | | |
151 | | PipeWrap::PipeWrap(Environment* env, |
152 | | Local<Object> object, |
153 | | ProviderType provider, |
154 | | bool ipc) |
155 | 82.3k | : ConnectionWrap(env, object, provider) { |
156 | 82.3k | int r = uv_pipe_init(env->event_loop(), &handle_, ipc); |
157 | 82.3k | CHECK_EQ(r, 0); // How do we proxy this error up to javascript? |
158 | | // Suggestion: uv_pipe_init() returns void. |
159 | 82.3k | } |
160 | | |
161 | 0 | void PipeWrap::Bind(const FunctionCallbackInfo<Value>& args) { |
162 | 0 | PipeWrap* wrap; |
163 | 0 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
164 | 0 | node::Utf8Value name(args.GetIsolate(), args[0]); |
165 | 0 | int err = uv_pipe_bind2(&wrap->handle_, *name, name.length(), 0); |
166 | 0 | args.GetReturnValue().Set(err); |
167 | 0 | } |
168 | | |
169 | | #ifdef _WIN32 |
170 | | void PipeWrap::SetPendingInstances(const FunctionCallbackInfo<Value>& args) { |
171 | | PipeWrap* wrap; |
172 | | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
173 | | CHECK(args[0]->IsInt32()); |
174 | | int instances = args[0].As<Int32>()->Value(); |
175 | | uv_pipe_pending_instances(&wrap->handle_, instances); |
176 | | } |
177 | | #endif |
178 | | |
179 | 0 | void PipeWrap::Fchmod(const v8::FunctionCallbackInfo<v8::Value>& args) { |
180 | 0 | PipeWrap* wrap; |
181 | 0 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
182 | 0 | CHECK(args[0]->IsInt32()); |
183 | 0 | int mode = args[0].As<Int32>()->Value(); |
184 | 0 | int err = uv_pipe_chmod(&wrap->handle_, mode); |
185 | 0 | args.GetReturnValue().Set(err); |
186 | 0 | } |
187 | | |
188 | 0 | void PipeWrap::Listen(const FunctionCallbackInfo<Value>& args) { |
189 | 0 | PipeWrap* wrap; |
190 | 0 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
191 | 0 | Environment* env = wrap->env(); |
192 | 0 | int backlog; |
193 | 0 | if (!args[0]->Int32Value(env->context()).To(&backlog)) return; |
194 | 0 | int err = uv_listen( |
195 | 0 | reinterpret_cast<uv_stream_t*>(&wrap->handle_), backlog, OnConnection); |
196 | 0 | args.GetReturnValue().Set(err); |
197 | 0 | } |
198 | | |
199 | 82.3k | void PipeWrap::Open(const FunctionCallbackInfo<Value>& args) { |
200 | 82.3k | Environment* env = Environment::GetCurrent(args); |
201 | | |
202 | 82.3k | PipeWrap* wrap; |
203 | 82.3k | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
204 | | |
205 | 82.3k | int fd; |
206 | 82.3k | if (!args[0]->Int32Value(env->context()).To(&fd)) return; |
207 | | |
208 | 82.3k | int err = uv_pipe_open(&wrap->handle_, fd); |
209 | 82.3k | if (err == 0) wrap->set_fd(fd); |
210 | | |
211 | 82.3k | args.GetReturnValue().Set(err); |
212 | 82.3k | } |
213 | | |
214 | 0 | void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) { |
215 | 0 | Environment* env = Environment::GetCurrent(args); |
216 | |
|
217 | 0 | PipeWrap* wrap; |
218 | 0 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
219 | | |
220 | 0 | CHECK(args[0]->IsObject()); |
221 | 0 | CHECK(args[1]->IsString()); |
222 | | |
223 | 0 | Local<Object> req_wrap_obj = args[0].As<Object>(); |
224 | 0 | node::Utf8Value name(env->isolate(), args[1]); |
225 | |
|
226 | 0 | ConnectWrap* req_wrap = |
227 | 0 | new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPECONNECTWRAP); |
228 | 0 | int err = req_wrap->Dispatch( |
229 | 0 | uv_pipe_connect2, &wrap->handle_, *name, name.length(), 0, AfterConnect); |
230 | 0 | if (err) { |
231 | 0 | delete req_wrap; |
232 | 0 | } else { |
233 | 0 | const char* path_type = (*name)[0] == '\0' ? "abstract socket" : "file"; |
234 | 0 | const char* pipe_path = (*name)[0] == '\0' ? (*name) + 1 : *name; |
235 | 0 | TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(TRACING_CATEGORY_NODE2(net, native), |
236 | 0 | "connect", |
237 | 0 | req_wrap, |
238 | 0 | "path_type", |
239 | 0 | path_type, |
240 | 0 | "pipe_path", |
241 | 0 | TRACE_STR_COPY(pipe_path)); |
242 | 0 | } |
243 | |
|
244 | 0 | args.GetReturnValue().Set(err); |
245 | 0 | } |
246 | | |
247 | | } // namespace node |
248 | | |
249 | | NODE_BINDING_CONTEXT_AWARE_INTERNAL(pipe_wrap, node::PipeWrap::Initialize) |
250 | | NODE_BINDING_EXTERNAL_REFERENCE(pipe_wrap, |
251 | | node::PipeWrap::RegisterExternalReferences) |