GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/stream_wrap.cc Lines: 177 182 97.3 %
Date: 2020-05-27 22:15:15 Branches: 55 84 65.5 %

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
4117
void LibuvStreamWrap::Initialize(Local<Object> target,
57
                                 Local<Value> unused,
58
                                 Local<Context> context,
59
                                 void* priv) {
60
4117
  Environment* env = Environment::GetCurrent(context);
61
62
  auto is_construct_call_callback =
63
728996
      [](const FunctionCallbackInfo<Value>& args) {
64
360381
    CHECK(args.IsConstructCall());
65
360381
    StreamReq::ResetObject(args.This());
66
728996
  };
67
  Local<FunctionTemplate> sw =
68
4117
      FunctionTemplate::New(env->isolate(), is_construct_call_callback);
69
8234
  sw->InstanceTemplate()->SetInternalFieldCount(StreamReq::kInternalFieldCount);
70
  Local<String> wrapString =
71
4117
      FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap");
72
4117
  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
20585
  sw->InstanceTemplate()->Set(
82
      env->oncomplete_string(),
83
4117
      v8::Null(env->isolate()));
84
20585
  sw->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "callback"),
85
4117
      v8::Null(env->isolate()));
86
20585
  sw->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "handle"),
87
4117
      v8::Null(env->isolate()));
88
89
8234
  sw->Inherit(AsyncWrap::GetConstructorTemplate(env));
90
91
8234
  target->Set(env->context(),
92
              wrapString,
93
20585
              sw->GetFunction(env->context()).ToLocalChecked()).Check();
94
4117
  env->set_shutdown_wrap_template(sw->InstanceTemplate());
95
96
  Local<FunctionTemplate> ww =
97
4117
      FunctionTemplate::New(env->isolate(), is_construct_call_callback);
98
12351
  ww->InstanceTemplate()->SetInternalFieldCount(
99
4117
      StreamReq::kInternalFieldCount);
100
  Local<String> writeWrapString =
101
4117
      FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap");
102
4117
  ww->SetClassName(writeWrapString);
103
8234
  ww->Inherit(AsyncWrap::GetConstructorTemplate(env));
104
8234
  target->Set(env->context(),
105
              writeWrapString,
106
20585
              ww->GetFunction(env->context()).ToLocalChecked()).Check();
107
4117
  env->set_write_wrap_template(ww->InstanceTemplate());
108
109
16468
  NODE_DEFINE_CONSTANT(target, kReadBytesOrError);
110
16468
  NODE_DEFINE_CONSTANT(target, kArrayBufferOffset);
111
16468
  NODE_DEFINE_CONSTANT(target, kBytesWritten);
112
16468
  NODE_DEFINE_CONSTANT(target, kLastWriteWasAsync);
113
8234
  target->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "streamBaseState"),
114
16468
              env->stream_base_state().GetJSArray()).Check();
115
4117
}
116
117
118
16294
LibuvStreamWrap::LibuvStreamWrap(Environment* env,
119
                                 Local<Object> object,
120
                                 uv_stream_t* stream,
121
16294
                                 AsyncWrap::ProviderType provider)
122
    : HandleWrap(env,
123
                 object,
124
                 reinterpret_cast<uv_handle_t*>(stream),
125
                 provider),
126
      StreamBase(env),
127
16294
      stream_(stream) {
128
16294
  StreamBase::AttachToObject(object);
129
16294
}
130
131
132
11952
Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate(
133
    Environment* env) {
134
11952
  Local<FunctionTemplate> tmpl = env->libuv_stream_wrap_ctor_template();
135
11952
  if (tmpl.IsEmpty()) {
136
4092
    tmpl = env->NewFunctionTemplate(nullptr);
137
8184
    tmpl->SetClassName(
138
4092
        FIXED_ONE_BYTE_STRING(env->isolate(), "LibuvStreamWrap"));
139
8184
    tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
140
12276
    tmpl->InstanceTemplate()->SetInternalFieldCount(
141
4092
        StreamBase::kInternalFieldCount);
142
    Local<FunctionTemplate> get_write_queue_size =
143
        FunctionTemplate::New(env->isolate(),
144
                              GetWriteQueueSize,
145
                              Local<Value>(),
146
8184
                              Signature::New(env->isolate(), tmpl));
147
16368
    tmpl->PrototypeTemplate()->SetAccessorProperty(
148
        env->write_queue_size_string(),
149
        get_write_queue_size,
150
        Local<FunctionTemplate>(),
151
4092
        static_cast<PropertyAttribute>(ReadOnly | DontDelete));
152
4092
    env->SetProtoMethod(tmpl, "setBlocking", SetBlocking);
153
4092
    StreamBase::AddMethods(env, tmpl);
154
4092
    env->set_libuv_stream_wrap_ctor_template(tmpl);
155
  }
156
11952
  return tmpl;
157
}
158
159
160
3274
LibuvStreamWrap* LibuvStreamWrap::From(Environment* env, Local<Object> object) {
161
3274
  Local<FunctionTemplate> sw = env->libuv_stream_wrap_ctor_template();
162

6548
  CHECK(!sw.IsEmpty() && sw->HasInstance(object));
163
3274
  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
352468
bool LibuvStreamWrap::IsAlive() {
180
352468
  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
647812
AsyncWrap* LibuvStreamWrap::GetAsyncWrap() {
190
647812
  return static_cast<AsyncWrap*>(this);
191
}
192
193
194
271385
bool LibuvStreamWrap::IsIPCPipe() {
195
271385
  return is_named_pipe_ipc();
196
}
197
198
199
13543
int LibuvStreamWrap::ReadStart() {
200
27086
  return uv_read_start(stream(), [](uv_handle_t* handle,
201
                                    size_t suggested_size,
202
664795
                                    uv_buf_t* buf) {
203
325626
    static_cast<LibuvStreamWrap*>(handle->data)->OnUvAlloc(suggested_size, buf);
204
1330072
  }, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
205
325867
    static_cast<LibuvStreamWrap*>(stream->data)->OnUvRead(nread, buf);
206
692278
  });
207
}
208
209
210
8501
int LibuvStreamWrap::ReadStop() {
211
8501
  return uv_read_stop(stream());
212
}
213
214
215
325626
void LibuvStreamWrap::OnUvAlloc(size_t suggested_size, uv_buf_t* buf) {
216
651252
  HandleScope scope(env()->isolate());
217
325626
  Context::Scope context_scope(env()->context());
218
219
325626
  *buf = EmitAlloc(suggested_size);
220
325626
}
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
325867
void LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) {
248
651649
  HandleScope scope(env()->isolate());
249
325867
  Context::Scope context_scope(env()->context());
250
325867
  uv_handle_type type = UV_UNKNOWN_HANDLE;
251
252

327373
  if (is_named_pipe_ipc() &&
253
1506
      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
651734
  CHECK_EQ(persistent().IsEmpty(), false);
260
261
325867
  if (nread > 0) {
262
    MaybeLocal<Object> pending_obj;
263
264
320366
    if (type == UV_TCP) {
265
129
      pending_obj = AcceptHandle<TCPWrap>(env(), this);
266
320237
    } else if (type == UV_NAMED_PIPE) {
267
1
      pending_obj = AcceptHandle<PipeWrap>(env(), this);
268
320236
    } else if (type == UV_UDP) {
269
24
      pending_obj = AcceptHandle<UDPWrap>(env(), this);
270
    } else {
271
320212
      CHECK_EQ(type, UV_UNKNOWN_HANDLE);
272
    }
273
274
320366
    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
325867
  EmitRead(nread, *buf);
284
325782
}
285
286
287
1246
void LibuvStreamWrap::GetWriteQueueSize(
288
    const FunctionCallbackInfo<Value>& info) {
289
  LibuvStreamWrap* wrap;
290
1246
  ASSIGN_OR_RETURN_UNWRAP(&wrap, info.This());
291
292
1246
  if (wrap->stream() == nullptr) {
293
    info.GetReturnValue().Set(0);
294
    return;
295
  }
296
297
1246
  uint32_t write_queue_size = wrap->stream()->write_queue_size;
298
2492
  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
6481
ShutdownWrap* LibuvStreamWrap::CreateShutdownWrap(Local<Object> object) {
318
6481
  return new LibuvShutdownWrap(this, object);
319
}
320
321
497
WriteWrap* LibuvStreamWrap::CreateWriteWrap(Local<Object> object) {
322
497
  return new LibuvWriteWrap(this, object);
323
}
324
325
326
6481
int LibuvStreamWrap::DoShutdown(ShutdownWrap* req_wrap_) {
327
6481
  LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(req_wrap_);
328
6481
  return req_wrap->Dispatch(uv_shutdown, stream(), AfterUvShutdown);
329
}
330
331
332
6478
void LibuvStreamWrap::AfterUvShutdown(uv_shutdown_t* req, int status) {
333
6478
  LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(
334
12956
      LibuvShutdownWrap::from_req(req));
335
6478
  CHECK_NOT_NULL(req_wrap);
336
12956
  HandleScope scope(req_wrap->env()->isolate());
337
6478
  Context::Scope context_scope(req_wrap->env()->context());
338
6478
  req_wrap->Done(status);
339
6478
}
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
362999
int LibuvStreamWrap::DoTryWrite(uv_buf_t** bufs, size_t* count) {
347
  int err;
348
  size_t written;
349
362999
  uv_buf_t* vbufs = *bufs;
350
362999
  size_t vcount = *count;
351
352
362999
  err = uv_try_write(stream(), vbufs, vcount);
353

362999
  if (err == UV_ENOSYS || err == UV_EAGAIN)
354
88
    return 0;
355
362911
  if (err < 0)
356
137
    return err;
357
358
  // Slice off the buffers: skip all written buffers and slice the one that
359
  // was partially written.
360
362774
  written = err;
361
1232238
  for (; vcount > 0; vbufs++, vcount--) {
362
    // Slice
363
435040
    if (vbufs[0].len > written) {
364
308
      vbufs[0].base += written;
365
308
      vbufs[0].len -= written;
366
308
      written = 0;
367
308
      break;
368
369
    // Discard
370
    } else {
371
434732
      written -= vbufs[0].len;
372
    }
373
  }
374
375
362774
  *bufs = vbufs;
376
362774
  *count = vcount;
377
378
362774
  return 0;
379
}
380
381
382
497
int LibuvStreamWrap::DoWrite(WriteWrap* req_wrap,
383
                             uv_buf_t* bufs,
384
                             size_t count,
385
                             uv_stream_t* send_handle) {
386
497
  LibuvWriteWrap* w = static_cast<LibuvWriteWrap*>(req_wrap);
387
497
  return w->Dispatch(uv_write2,
388
                     stream(),
389
                     bufs,
390
                     count,
391
                     send_handle,
392
497
                     AfterUvWrite);
393
}
394
395
396
397
496
void LibuvStreamWrap::AfterUvWrite(uv_write_t* req, int status) {
398
496
  LibuvWriteWrap* req_wrap = static_cast<LibuvWriteWrap*>(
399
992
      LibuvWriteWrap::from_req(req));
400
496
  CHECK_NOT_NULL(req_wrap);
401
991
  HandleScope scope(req_wrap->env()->isolate());
402
496
  Context::Scope context_scope(req_wrap->env()->context());
403
496
  req_wrap->Done(status);
404
495
}
405
406
}  // namespace node
407
408
4325
NODE_MODULE_CONTEXT_AWARE_INTERNAL(stream_wrap,
409
                                   node::LibuvStreamWrap::Initialize)