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 "stream_wrap.h" |
23 |
|
|
#include "stream_base-inl.h" |
24 |
|
|
|
25 |
|
|
#include "env-inl.h" |
26 |
|
|
#include "handle_wrap.h" |
27 |
|
|
#include "node_buffer.h" |
28 |
|
|
#include "node_errors.h" |
29 |
|
|
#include "node_external_reference.h" |
30 |
|
|
#include "pipe_wrap.h" |
31 |
|
|
#include "req_wrap-inl.h" |
32 |
|
|
#include "tcp_wrap.h" |
33 |
|
|
#include "udp_wrap.h" |
34 |
|
|
#include "util-inl.h" |
35 |
|
|
|
36 |
|
|
#include <cstring> // memcpy() |
37 |
|
|
#include <climits> // INT_MAX |
38 |
|
|
|
39 |
|
|
|
40 |
|
|
namespace node { |
41 |
|
|
|
42 |
|
|
using errors::TryCatchScope; |
43 |
|
|
using v8::Context; |
44 |
|
|
using v8::DontDelete; |
45 |
|
|
using v8::EscapableHandleScope; |
46 |
|
|
using v8::FunctionCallbackInfo; |
47 |
|
|
using v8::FunctionTemplate; |
48 |
|
|
using v8::HandleScope; |
49 |
|
|
using v8::Isolate; |
50 |
|
|
using v8::JustVoid; |
51 |
|
|
using v8::Local; |
52 |
|
|
using v8::Maybe; |
53 |
|
|
using v8::MaybeLocal; |
54 |
|
|
using v8::Nothing; |
55 |
|
|
using v8::Object; |
56 |
|
|
using v8::PropertyAttribute; |
57 |
|
|
using v8::ReadOnly; |
58 |
|
|
using v8::Signature; |
59 |
|
|
using v8::Value; |
60 |
|
|
|
61 |
|
121093 |
void IsConstructCallCallback(const FunctionCallbackInfo<Value>& args) { |
62 |
✗✓ |
121093 |
CHECK(args.IsConstructCall()); |
63 |
|
121093 |
StreamReq::ResetObject(args.This()); |
64 |
|
121093 |
} |
65 |
|
|
|
66 |
|
788 |
void LibuvStreamWrap::Initialize(Local<Object> target, |
67 |
|
|
Local<Value> unused, |
68 |
|
|
Local<Context> context, |
69 |
|
|
void* priv) { |
70 |
|
788 |
Environment* env = Environment::GetCurrent(context); |
71 |
|
788 |
Isolate* isolate = env->isolate(); |
72 |
|
|
|
73 |
|
|
Local<FunctionTemplate> sw = |
74 |
|
788 |
NewFunctionTemplate(isolate, IsConstructCallCallback); |
75 |
|
1576 |
sw->InstanceTemplate()->SetInternalFieldCount(StreamReq::kInternalFieldCount); |
76 |
|
|
|
77 |
|
|
// we need to set handle and callback to null, |
78 |
|
|
// so that those fields are created and functions |
79 |
|
|
// do not become megamorphic |
80 |
|
|
// Fields: |
81 |
|
|
// - oncomplete |
82 |
|
|
// - callback |
83 |
|
|
// - handle |
84 |
|
3152 |
sw->InstanceTemplate()->Set(env->oncomplete_string(), v8::Null(isolate)); |
85 |
|
3152 |
sw->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(isolate, "callback"), |
86 |
|
|
v8::Null(isolate)); |
87 |
|
3152 |
sw->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(isolate, "handle"), |
88 |
|
|
v8::Null(isolate)); |
89 |
|
|
|
90 |
|
788 |
sw->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
91 |
|
|
|
92 |
|
788 |
SetConstructorFunction(context, target, "ShutdownWrap", sw); |
93 |
|
788 |
env->set_shutdown_wrap_template(sw->InstanceTemplate()); |
94 |
|
|
|
95 |
|
|
Local<FunctionTemplate> ww = |
96 |
|
788 |
FunctionTemplate::New(isolate, IsConstructCallCallback); |
97 |
|
1576 |
ww->InstanceTemplate()->SetInternalFieldCount( |
98 |
|
|
StreamReq::kInternalFieldCount); |
99 |
|
788 |
ww->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
100 |
|
788 |
SetConstructorFunction(context, target, "WriteWrap", ww); |
101 |
|
788 |
env->set_write_wrap_template(ww->InstanceTemplate()); |
102 |
|
|
|
103 |
|
2364 |
NODE_DEFINE_CONSTANT(target, kReadBytesOrError); |
104 |
|
2364 |
NODE_DEFINE_CONSTANT(target, kArrayBufferOffset); |
105 |
|
2364 |
NODE_DEFINE_CONSTANT(target, kBytesWritten); |
106 |
|
2364 |
NODE_DEFINE_CONSTANT(target, kLastWriteWasAsync); |
107 |
|
|
target |
108 |
|
788 |
->Set(context, |
109 |
|
|
FIXED_ONE_BYTE_STRING(isolate, "streamBaseState"), |
110 |
|
2364 |
env->stream_base_state().GetJSArray()) |
111 |
|
|
.Check(); |
112 |
|
788 |
} |
113 |
|
|
|
114 |
|
5528 |
void LibuvStreamWrap::RegisterExternalReferences( |
115 |
|
|
ExternalReferenceRegistry* registry) { |
116 |
|
5528 |
registry->Register(IsConstructCallCallback); |
117 |
|
5528 |
registry->Register(GetWriteQueueSize); |
118 |
|
5528 |
registry->Register(SetBlocking); |
119 |
|
5528 |
StreamBase::RegisterExternalReferences(registry); |
120 |
|
5528 |
} |
121 |
|
|
|
122 |
|
19707 |
LibuvStreamWrap::LibuvStreamWrap(Environment* env, |
123 |
|
|
Local<Object> object, |
124 |
|
|
uv_stream_t* stream, |
125 |
|
19707 |
AsyncWrap::ProviderType provider) |
126 |
|
|
: HandleWrap(env, |
127 |
|
|
object, |
128 |
|
|
reinterpret_cast<uv_handle_t*>(stream), |
129 |
|
|
provider), |
130 |
|
|
StreamBase(env), |
131 |
|
19707 |
stream_(stream) { |
132 |
|
19707 |
StreamBase::AttachToObject(object); |
133 |
|
19707 |
} |
134 |
|
|
|
135 |
|
|
|
136 |
|
17433 |
Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate( |
137 |
|
|
Environment* env) { |
138 |
|
17433 |
Local<FunctionTemplate> tmpl = env->libuv_stream_wrap_ctor_template(); |
139 |
✓✓ |
17433 |
if (tmpl.IsEmpty()) { |
140 |
|
6271 |
Isolate* isolate = env->isolate(); |
141 |
|
6271 |
tmpl = NewFunctionTemplate(isolate, nullptr); |
142 |
|
6271 |
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "LibuvStreamWrap")); |
143 |
|
6271 |
tmpl->Inherit(HandleWrap::GetConstructorTemplate(env)); |
144 |
|
12542 |
tmpl->InstanceTemplate()->SetInternalFieldCount( |
145 |
|
|
StreamBase::kInternalFieldCount); |
146 |
|
|
Local<FunctionTemplate> get_write_queue_size = |
147 |
|
|
FunctionTemplate::New(isolate, |
148 |
|
|
GetWriteQueueSize, |
149 |
|
|
Local<Value>(), |
150 |
|
6271 |
Signature::New(isolate, tmpl)); |
151 |
|
25084 |
tmpl->PrototypeTemplate()->SetAccessorProperty( |
152 |
|
|
env->write_queue_size_string(), |
153 |
|
|
get_write_queue_size, |
154 |
|
|
Local<FunctionTemplate>(), |
155 |
|
|
static_cast<PropertyAttribute>(ReadOnly | DontDelete)); |
156 |
|
6271 |
SetProtoMethod(isolate, tmpl, "setBlocking", SetBlocking); |
157 |
|
6271 |
StreamBase::AddMethods(env, tmpl); |
158 |
|
6271 |
env->set_libuv_stream_wrap_ctor_template(tmpl); |
159 |
|
|
} |
160 |
|
17433 |
return tmpl; |
161 |
|
|
} |
162 |
|
|
|
163 |
|
|
|
164 |
|
4455 |
LibuvStreamWrap* LibuvStreamWrap::From(Environment* env, Local<Object> object) { |
165 |
|
4455 |
Local<FunctionTemplate> sw = env->libuv_stream_wrap_ctor_template(); |
166 |
✓✗✗✓ ✗✓ |
8910 |
CHECK(!sw.IsEmpty() && sw->HasInstance(object)); |
167 |
|
4455 |
return Unwrap<LibuvStreamWrap>(object); |
168 |
|
|
} |
169 |
|
|
|
170 |
|
|
|
171 |
|
151 |
int LibuvStreamWrap::GetFD() { |
172 |
|
|
#ifdef _WIN32 |
173 |
|
|
return fd_; |
174 |
|
|
#else |
175 |
|
151 |
int fd = -1; |
176 |
✓✗ |
151 |
if (stream() != nullptr) |
177 |
|
151 |
uv_fileno(reinterpret_cast<uv_handle_t*>(stream()), &fd); |
178 |
|
151 |
return fd; |
179 |
|
|
#endif |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
|
183 |
|
121640 |
bool LibuvStreamWrap::IsAlive() { |
184 |
|
121640 |
return HandleWrap::IsAlive(this); |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
|
188 |
|
3 |
bool LibuvStreamWrap::IsClosing() { |
189 |
|
3 |
return uv_is_closing(reinterpret_cast<uv_handle_t*>(stream())); |
190 |
|
|
} |
191 |
|
|
|
192 |
|
|
|
193 |
|
165505 |
AsyncWrap* LibuvStreamWrap::GetAsyncWrap() { |
194 |
|
165505 |
return static_cast<AsyncWrap*>(this); |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
|
198 |
|
27819 |
bool LibuvStreamWrap::IsIPCPipe() { |
199 |
|
27819 |
return is_named_pipe_ipc(); |
200 |
|
|
} |
201 |
|
|
|
202 |
|
22229 |
int LibuvStreamWrap::ReadStart() { |
203 |
|
44458 |
return uv_read_start( |
204 |
|
|
stream(), |
205 |
|
73260 |
[](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { |
206 |
|
73260 |
static_cast<LibuvStreamWrap*>(handle->data) |
207 |
|
73260 |
->OnUvAlloc(suggested_size, buf); |
208 |
|
73260 |
}, |
209 |
|
73492 |
[](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { |
210 |
|
73492 |
LibuvStreamWrap* wrap = static_cast<LibuvStreamWrap*>(stream->data); |
211 |
|
146770 |
TryCatchScope try_catch(wrap->env()); |
212 |
|
73492 |
try_catch.SetVerbose(true); |
213 |
|
73492 |
wrap->OnUvRead(nread, buf); |
214 |
|
22229 |
}); |
215 |
|
|
} |
216 |
|
|
|
217 |
|
|
|
218 |
|
9299 |
int LibuvStreamWrap::ReadStop() { |
219 |
|
9299 |
return uv_read_stop(stream()); |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
|
223 |
|
73260 |
void LibuvStreamWrap::OnUvAlloc(size_t suggested_size, uv_buf_t* buf) { |
224 |
|
146520 |
HandleScope scope(env()->isolate()); |
225 |
|
73260 |
Context::Scope context_scope(env()->context()); |
226 |
|
|
|
227 |
|
73260 |
*buf = EmitAlloc(suggested_size); |
228 |
|
73260 |
} |
229 |
|
|
|
230 |
|
|
template <class WrapType> |
231 |
|
398 |
static MaybeLocal<Object> AcceptHandle(Environment* env, |
232 |
|
|
LibuvStreamWrap* parent) { |
233 |
|
|
static_assert(std::is_base_of<LibuvStreamWrap, WrapType>::value || |
234 |
|
|
std::is_base_of<UDPWrap, WrapType>::value, |
235 |
|
|
"Can only accept stream handles"); |
236 |
|
|
|
237 |
|
398 |
EscapableHandleScope scope(env->isolate()); |
238 |
|
|
Local<Object> wrap_obj; |
239 |
|
|
|
240 |
✗✓ |
796 |
if (!WrapType::Instantiate(env, parent, WrapType::SOCKET).ToLocal(&wrap_obj)) |
241 |
|
|
return Local<Object>(); |
242 |
|
|
|
243 |
|
398 |
HandleWrap* wrap = Unwrap<HandleWrap>(wrap_obj); |
244 |
✗✓ |
398 |
CHECK_NOT_NULL(wrap); |
245 |
|
398 |
uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(wrap->GetHandle()); |
246 |
✗✓ |
398 |
CHECK_NOT_NULL(stream); |
247 |
|
|
|
248 |
✗✓ |
398 |
if (uv_accept(parent->stream(), stream)) |
249 |
|
|
ABORT(); |
250 |
|
|
|
251 |
|
398 |
return scope.Escape(wrap_obj); |
252 |
|
|
} |
253 |
|
|
|
254 |
|
73492 |
Maybe<void> LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) { |
255 |
|
146770 |
HandleScope scope(env()->isolate()); |
256 |
|
73492 |
Context::Scope context_scope(env()->context()); |
257 |
|
73492 |
uv_handle_type type = UV_UNKNOWN_HANDLE; |
258 |
|
|
|
259 |
✓✓✓✓ ✓✓ |
77921 |
if (is_named_pipe_ipc() && |
260 |
|
4429 |
uv_pipe_pending_count(reinterpret_cast<uv_pipe_t*>(stream())) > 0) { |
261 |
|
199 |
type = uv_pipe_pending_type(reinterpret_cast<uv_pipe_t*>(stream())); |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
// We should not be getting this callback if someone has already called |
265 |
|
|
// uv_close() on the handle. |
266 |
✗✓ |
73492 |
CHECK_EQ(persistent().IsEmpty(), false); |
267 |
|
|
|
268 |
✓✓ |
73492 |
if (nread > 0) { |
269 |
|
|
MaybeLocal<Object> pending_obj; |
270 |
|
|
|
271 |
✓✓ |
67303 |
if (type == UV_TCP) { |
272 |
|
130 |
pending_obj = AcceptHandle<TCPWrap>(env(), this); |
273 |
✓✓ |
67173 |
} else if (type == UV_NAMED_PIPE) { |
274 |
|
36 |
pending_obj = AcceptHandle<PipeWrap>(env(), this); |
275 |
✓✓ |
67137 |
} else if (type == UV_UDP) { |
276 |
|
33 |
pending_obj = AcceptHandle<UDPWrap>(env(), this); |
277 |
|
|
} else { |
278 |
✗✓ |
67104 |
CHECK_EQ(type, UV_UNKNOWN_HANDLE); |
279 |
|
|
} |
280 |
|
|
|
281 |
|
|
Local<Object> local_pending_obj; |
282 |
✓✓ |
67502 |
if (type != UV_UNKNOWN_HANDLE && |
283 |
✓✗ |
199 |
(!pending_obj.ToLocal(&local_pending_obj) || |
284 |
|
199 |
object() |
285 |
|
67303 |
->Set(env()->context(), |
286 |
|
|
env()->pending_handle_string(), |
287 |
✗✓ |
67701 |
local_pending_obj) |
288 |
✗✓ |
199 |
.IsNothing())) { |
289 |
|
|
return Nothing<void>(); |
290 |
|
|
} |
291 |
|
|
} |
292 |
|
|
|
293 |
|
73492 |
EmitRead(nread, *buf); |
294 |
|
73278 |
return JustVoid(); |
295 |
|
|
} |
296 |
|
|
|
297 |
|
5613 |
void LibuvStreamWrap::GetWriteQueueSize( |
298 |
|
|
const FunctionCallbackInfo<Value>& info) { |
299 |
|
|
LibuvStreamWrap* wrap; |
300 |
✗✓ |
5613 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, info.This()); |
301 |
|
|
|
302 |
✗✓ |
5613 |
if (wrap->stream() == nullptr) { |
303 |
|
|
info.GetReturnValue().Set(0); |
304 |
|
|
return; |
305 |
|
|
} |
306 |
|
|
|
307 |
|
5613 |
uint32_t write_queue_size = wrap->stream()->write_queue_size; |
308 |
✓✗ |
11226 |
info.GetReturnValue().Set(write_queue_size); |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
|
312 |
|
56 |
void LibuvStreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) { |
313 |
|
|
LibuvStreamWrap* wrap; |
314 |
✗✓ |
56 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
315 |
|
|
|
316 |
✗✓ |
56 |
CHECK_GT(args.Length(), 0); |
317 |
✗✓ |
56 |
if (!wrap->IsAlive()) |
318 |
|
|
return args.GetReturnValue().Set(UV_EINVAL); |
319 |
|
|
|
320 |
|
56 |
bool enable = args[0]->IsTrue(); |
321 |
|
112 |
args.GetReturnValue().Set(uv_stream_set_blocking(wrap->stream(), enable)); |
322 |
|
|
} |
323 |
|
|
|
324 |
|
|
typedef SimpleShutdownWrap<ReqWrap<uv_shutdown_t>> LibuvShutdownWrap; |
325 |
|
|
typedef SimpleWriteWrap<ReqWrap<uv_write_t>> LibuvWriteWrap; |
326 |
|
|
|
327 |
|
7647 |
ShutdownWrap* LibuvStreamWrap::CreateShutdownWrap(Local<Object> object) { |
328 |
|
7647 |
return new LibuvShutdownWrap(this, object); |
329 |
|
|
} |
330 |
|
|
|
331 |
|
287 |
WriteWrap* LibuvStreamWrap::CreateWriteWrap(Local<Object> object) { |
332 |
|
287 |
return new LibuvWriteWrap(this, object); |
333 |
|
|
} |
334 |
|
|
|
335 |
|
|
|
336 |
|
7647 |
int LibuvStreamWrap::DoShutdown(ShutdownWrap* req_wrap_) { |
337 |
|
7647 |
LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(req_wrap_); |
338 |
|
7647 |
return req_wrap->Dispatch(uv_shutdown, stream(), AfterUvShutdown); |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
|
342 |
|
7644 |
void LibuvStreamWrap::AfterUvShutdown(uv_shutdown_t* req, int status) { |
343 |
✓✗ |
7644 |
LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>( |
344 |
|
7644 |
LibuvShutdownWrap::from_req(req)); |
345 |
✗✓ |
7644 |
CHECK_NOT_NULL(req_wrap); |
346 |
|
15288 |
HandleScope scope(req_wrap->env()->isolate()); |
347 |
|
7644 |
Context::Scope context_scope(req_wrap->env()->context()); |
348 |
|
7644 |
req_wrap->Done(status); |
349 |
|
7644 |
} |
350 |
|
|
|
351 |
|
|
|
352 |
|
|
// NOTE: Call to this function could change both `buf`'s and `count`'s |
353 |
|
|
// values, shifting their base and decrementing their length. This is |
354 |
|
|
// required in order to skip the data that was successfully written via |
355 |
|
|
// uv_try_write(). |
356 |
|
121389 |
int LibuvStreamWrap::DoTryWrite(uv_buf_t** bufs, size_t* count) { |
357 |
|
|
int err; |
358 |
|
|
size_t written; |
359 |
|
121389 |
uv_buf_t* vbufs = *bufs; |
360 |
|
121389 |
size_t vcount = *count; |
361 |
|
|
|
362 |
|
121389 |
err = uv_try_write(stream(), vbufs, vcount); |
363 |
✓✗✓✓
|
121389 |
if (err == UV_ENOSYS || err == UV_EAGAIN) |
364 |
|
7 |
return 0; |
365 |
✓✓ |
121382 |
if (err < 0) |
366 |
|
2187 |
return err; |
367 |
|
|
|
368 |
|
|
// Slice off the buffers: skip all written buffers and slice the one that |
369 |
|
|
// was partially written. |
370 |
|
119195 |
written = err; |
371 |
✓✓ |
316630 |
for (; vcount > 0; vbufs++, vcount--) { |
372 |
|
|
// Slice |
373 |
✓✓ |
197570 |
if (vbufs[0].len > written) { |
374 |
|
135 |
vbufs[0].base += written; |
375 |
|
135 |
vbufs[0].len -= written; |
376 |
|
135 |
written = 0; |
377 |
|
135 |
break; |
378 |
|
|
|
379 |
|
|
// Discard |
380 |
|
|
} else { |
381 |
|
197435 |
written -= vbufs[0].len; |
382 |
|
|
} |
383 |
|
|
} |
384 |
|
|
|
385 |
|
119195 |
*bufs = vbufs; |
386 |
|
119195 |
*count = vcount; |
387 |
|
|
|
388 |
|
119195 |
return 0; |
389 |
|
|
} |
390 |
|
|
|
391 |
|
|
|
392 |
|
287 |
int LibuvStreamWrap::DoWrite(WriteWrap* req_wrap, |
393 |
|
|
uv_buf_t* bufs, |
394 |
|
|
size_t count, |
395 |
|
|
uv_stream_t* send_handle) { |
396 |
|
287 |
LibuvWriteWrap* w = static_cast<LibuvWriteWrap*>(req_wrap); |
397 |
|
287 |
return w->Dispatch(uv_write2, |
398 |
|
|
stream(), |
399 |
|
|
bufs, |
400 |
|
|
count, |
401 |
|
|
send_handle, |
402 |
|
287 |
AfterUvWrite); |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
|
406 |
|
|
|
407 |
|
285 |
void LibuvStreamWrap::AfterUvWrite(uv_write_t* req, int status) { |
408 |
✓✗ |
285 |
LibuvWriteWrap* req_wrap = static_cast<LibuvWriteWrap*>( |
409 |
|
285 |
LibuvWriteWrap::from_req(req)); |
410 |
✗✓ |
285 |
CHECK_NOT_NULL(req_wrap); |
411 |
|
569 |
HandleScope scope(req_wrap->env()->isolate()); |
412 |
|
285 |
Context::Scope context_scope(req_wrap->env()->context()); |
413 |
|
285 |
req_wrap->Done(status); |
414 |
|
284 |
} |
415 |
|
|
|
416 |
|
|
} // namespace node |
417 |
|
|
|
418 |
|
5598 |
NODE_MODULE_CONTEXT_AWARE_INTERNAL(stream_wrap, |
419 |
|
|
node::LibuvStreamWrap::Initialize) |
420 |
|
5528 |
NODE_MODULE_EXTERNAL_REFERENCE( |
421 |
|
|
stream_wrap, node::LibuvStreamWrap::RegisterExternalReferences) |