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 |
|
94 |
MaybeLocal<Object> PipeWrap::Instantiate(Environment* env, |
51 |
|
|
AsyncWrap* parent, |
52 |
|
|
PipeWrap::SocketType type) { |
53 |
|
94 |
EscapableHandleScope handle_scope(env->isolate()); |
54 |
|
94 |
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent); |
55 |
✗✓ |
188 |
CHECK_EQ(false, env->pipe_constructor_template().IsEmpty()); |
56 |
|
94 |
Local<Function> constructor = env->pipe_constructor_template() |
57 |
|
94 |
->GetFunction(env->context()) |
58 |
|
94 |
.ToLocalChecked(); |
59 |
✗✓ |
94 |
CHECK_EQ(false, constructor.IsEmpty()); |
60 |
|
188 |
Local<Value> type_value = Int32::New(env->isolate(), type); |
61 |
|
|
return handle_scope.EscapeMaybe( |
62 |
|
188 |
constructor->NewInstance(env->context(), 1, &type_value)); |
63 |
|
|
} |
64 |
|
|
|
65 |
|
|
|
66 |
|
6391 |
void PipeWrap::Initialize(Local<Object> target, |
67 |
|
|
Local<Value> unused, |
68 |
|
|
Local<Context> context, |
69 |
|
|
void* priv) { |
70 |
|
6391 |
Environment* env = Environment::GetCurrent(context); |
71 |
|
6391 |
Isolate* isolate = env->isolate(); |
72 |
|
|
|
73 |
|
6391 |
Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New); |
74 |
|
12782 |
t->InstanceTemplate() |
75 |
|
6391 |
->SetInternalFieldCount(StreamBase::kInternalFieldCount); |
76 |
|
|
|
77 |
|
6391 |
t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env)); |
78 |
|
|
|
79 |
|
6391 |
SetProtoMethod(isolate, t, "bind", Bind); |
80 |
|
6391 |
SetProtoMethod(isolate, t, "listen", Listen); |
81 |
|
6391 |
SetProtoMethod(isolate, t, "connect", Connect); |
82 |
|
6391 |
SetProtoMethod(isolate, t, "open", Open); |
83 |
|
|
|
84 |
|
|
#ifdef _WIN32 |
85 |
|
|
SetProtoMethod(isolate, t, "setPendingInstances", SetPendingInstances); |
86 |
|
|
#endif |
87 |
|
|
|
88 |
|
6391 |
SetProtoMethod(isolate, t, "fchmod", Fchmod); |
89 |
|
|
|
90 |
|
6391 |
SetConstructorFunction(context, target, "Pipe", t); |
91 |
|
6391 |
env->set_pipe_constructor_template(t); |
92 |
|
|
|
93 |
|
|
// Create FunctionTemplate for PipeConnectWrap. |
94 |
|
6391 |
auto cwt = BaseObject::MakeLazilyInitializedJSTemplate(env); |
95 |
|
6391 |
cwt->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
96 |
|
6391 |
SetConstructorFunction(context, target, "PipeConnectWrap", cwt); |
97 |
|
|
|
98 |
|
|
// Define constants |
99 |
|
6391 |
Local<Object> constants = Object::New(env->isolate()); |
100 |
|
19173 |
NODE_DEFINE_CONSTANT(constants, SOCKET); |
101 |
|
19173 |
NODE_DEFINE_CONSTANT(constants, SERVER); |
102 |
|
19173 |
NODE_DEFINE_CONSTANT(constants, IPC); |
103 |
|
19173 |
NODE_DEFINE_CONSTANT(constants, UV_READABLE); |
104 |
|
19173 |
NODE_DEFINE_CONSTANT(constants, UV_WRITABLE); |
105 |
|
6391 |
target->Set(context, |
106 |
|
|
env->constants_string(), |
107 |
|
12782 |
constants).Check(); |
108 |
|
6391 |
} |
109 |
|
|
|
110 |
|
5639 |
void PipeWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
111 |
|
5639 |
registry->Register(New); |
112 |
|
5639 |
registry->Register(Bind); |
113 |
|
5639 |
registry->Register(Listen); |
114 |
|
5639 |
registry->Register(Connect); |
115 |
|
5639 |
registry->Register(Open); |
116 |
|
|
#ifdef _WIN32 |
117 |
|
|
registry->Register(SetPendingInstances); |
118 |
|
|
#endif |
119 |
|
5639 |
registry->Register(Fchmod); |
120 |
|
5639 |
} |
121 |
|
|
|
122 |
|
6926 |
void 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 |
✗✓ |
6926 |
CHECK(args.IsConstructCall()); |
127 |
✗✓ |
6926 |
CHECK(args[0]->IsInt32()); |
128 |
|
6926 |
Environment* env = Environment::GetCurrent(args); |
129 |
|
|
|
130 |
|
13852 |
int type_value = args[0].As<Int32>()->Value(); |
131 |
|
6926 |
PipeWrap::SocketType type = static_cast<PipeWrap::SocketType>(type_value); |
132 |
|
|
|
133 |
|
|
bool ipc; |
134 |
|
|
ProviderType provider; |
135 |
✓✓✓✗
|
6926 |
switch (type) { |
136 |
|
5894 |
case SOCKET: |
137 |
|
5894 |
provider = PROVIDER_PIPEWRAP; |
138 |
|
5894 |
ipc = false; |
139 |
|
5894 |
break; |
140 |
|
53 |
case SERVER: |
141 |
|
53 |
provider = PROVIDER_PIPESERVERWRAP; |
142 |
|
53 |
ipc = false; |
143 |
|
53 |
break; |
144 |
|
979 |
case IPC: |
145 |
|
979 |
provider = PROVIDER_PIPEWRAP; |
146 |
|
979 |
ipc = true; |
147 |
|
979 |
break; |
148 |
|
|
default: |
149 |
|
|
UNREACHABLE(); |
150 |
|
|
} |
151 |
|
|
|
152 |
|
6926 |
new PipeWrap(env, args.This(), provider, ipc); |
153 |
|
6926 |
} |
154 |
|
|
|
155 |
|
|
|
156 |
|
6926 |
PipeWrap::PipeWrap(Environment* env, |
157 |
|
|
Local<Object> object, |
158 |
|
|
ProviderType provider, |
159 |
|
6926 |
bool ipc) |
160 |
|
6926 |
: ConnectionWrap(env, object, provider) { |
161 |
|
6926 |
int r = uv_pipe_init(env->event_loop(), &handle_, ipc); |
162 |
✗✓ |
6926 |
CHECK_EQ(r, 0); // How do we proxy this error up to javascript? |
163 |
|
|
// Suggestion: uv_pipe_init() returns void. |
164 |
|
6926 |
} |
165 |
|
|
|
166 |
|
|
|
167 |
|
58 |
void PipeWrap::Bind(const FunctionCallbackInfo<Value>& args) { |
168 |
|
|
PipeWrap* wrap; |
169 |
✗✓ |
58 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
170 |
|
58 |
node::Utf8Value name(args.GetIsolate(), args[0]); |
171 |
|
58 |
int err = uv_pipe_bind(&wrap->handle_, *name); |
172 |
|
116 |
args.GetReturnValue().Set(err); |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
|
176 |
|
|
#ifdef _WIN32 |
177 |
|
|
void 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 |
|
|
|
187 |
|
2 |
void PipeWrap::Fchmod(const v8::FunctionCallbackInfo<v8::Value>& args) { |
188 |
|
|
PipeWrap* wrap; |
189 |
✗✓ |
2 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
190 |
✗✓ |
2 |
CHECK(args[0]->IsInt32()); |
191 |
|
4 |
int mode = args[0].As<Int32>()->Value(); |
192 |
|
2 |
int err = uv_pipe_chmod(&wrap->handle_, mode); |
193 |
|
4 |
args.GetReturnValue().Set(err); |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
|
197 |
|
50 |
void PipeWrap::Listen(const FunctionCallbackInfo<Value>& args) { |
198 |
|
|
PipeWrap* wrap; |
199 |
✗✓ |
50 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
200 |
|
50 |
Environment* env = wrap->env(); |
201 |
|
|
int backlog; |
202 |
✗✓ |
100 |
if (!args[0]->Int32Value(env->context()).To(&backlog)) return; |
203 |
|
50 |
int err = uv_listen(reinterpret_cast<uv_stream_t*>(&wrap->handle_), |
204 |
|
|
backlog, |
205 |
|
|
OnConnection); |
206 |
|
100 |
args.GetReturnValue().Set(err); |
207 |
|
|
} |
208 |
|
|
|
209 |
|
|
|
210 |
|
2149 |
void PipeWrap::Open(const FunctionCallbackInfo<Value>& args) { |
211 |
|
2149 |
Environment* env = Environment::GetCurrent(args); |
212 |
|
|
|
213 |
|
|
PipeWrap* wrap; |
214 |
✗✓ |
2149 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
215 |
|
|
|
216 |
|
|
int fd; |
217 |
✗✓ |
4298 |
if (!args[0]->Int32Value(env->context()).To(&fd)) return; |
218 |
|
|
|
219 |
|
2149 |
int err = uv_pipe_open(&wrap->handle_, fd); |
220 |
|
2149 |
wrap->set_fd(fd); |
221 |
|
|
|
222 |
✗✓ |
2149 |
if (err != 0) |
223 |
|
|
env->ThrowUVException(err, "uv_pipe_open"); |
224 |
|
|
} |
225 |
|
|
|
226 |
|
|
|
227 |
|
59 |
void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) { |
228 |
|
59 |
Environment* env = Environment::GetCurrent(args); |
229 |
|
|
|
230 |
|
|
PipeWrap* wrap; |
231 |
✗✓ |
59 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
232 |
|
|
|
233 |
✗✓ |
59 |
CHECK(args[0]->IsObject()); |
234 |
✗✓ |
118 |
CHECK(args[1]->IsString()); |
235 |
|
|
|
236 |
✓✗ |
118 |
Local<Object> req_wrap_obj = args[0].As<Object>(); |
237 |
|
59 |
node::Utf8Value name(env->isolate(), args[1]); |
238 |
|
|
|
239 |
|
|
ConnectWrap* req_wrap = |
240 |
|
59 |
new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPECONNECTWRAP); |
241 |
|
59 |
req_wrap->Dispatch(uv_pipe_connect, |
242 |
|
59 |
&wrap->handle_, |
243 |
|
|
*name, |
244 |
|
|
AfterConnect); |
245 |
|
|
|
246 |
✓✓✓✓
|
88 |
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE2(net, native), |
247 |
|
|
"connect", |
248 |
|
|
req_wrap, |
249 |
|
|
"pipe_path", |
250 |
|
|
TRACE_STR_COPY(*name)); |
251 |
|
|
|
252 |
|
118 |
args.GetReturnValue().Set(0); // uv_pipe_connect() doesn't return errors. |
253 |
|
|
} |
254 |
|
|
|
255 |
|
|
|
256 |
|
|
} // namespace node |
257 |
|
|
|
258 |
|
5710 |
NODE_BINDING_CONTEXT_AWARE_INTERNAL(pipe_wrap, node::PipeWrap::Initialize) |
259 |
|
5639 |
NODE_BINDING_EXTERNAL_REFERENCE(pipe_wrap, |
260 |
|
|
node::PipeWrap::RegisterExternalReferences) |