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