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: 168 173 97.1 %
Date: 2019-10-08 22:34:21 Branches: 56 86 65.1 %

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::ReadOnly;
50
using v8::Signature;
51
using v8::Value;
52
53
54
4760
void LibuvStreamWrap::Initialize(Local<Object> target,
55
                                 Local<Value> unused,
56
                                 Local<Context> context,
57
                                 void* priv) {
58
4760
  Environment* env = Environment::GetCurrent(context);
59
60
  auto is_construct_call_callback =
61
1880218
      [](const FunctionCallbackInfo<Value>& args) {
62
935349
    CHECK(args.IsConstructCall());
63
935349
    StreamReq::ResetObject(args.This());
64
1880218
  };
65
  Local<FunctionTemplate> sw =
66
4760
      FunctionTemplate::New(env->isolate(), is_construct_call_callback);
67
4760
  sw->InstanceTemplate()->SetInternalFieldCount(
68
9520
      StreamReq::kStreamReqField + 1 + 3);
69
  Local<String> wrapString =
70
4760
      FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap");
71
4760
  sw->SetClassName(wrapString);
72
73
  // we need to set handle and callback to null,
74
  // so that those fields are created and functions
75
  // do not become megamorphic
76
  // Fields:
77
  // - oncomplete
78
  // - callback
79
  // - handle
80
14280
  sw->InstanceTemplate()->Set(
81
      FIXED_ONE_BYTE_STRING(env->isolate(), "oncomplete"),
82
19040
      v8::Null(env->isolate()));
83
14280
  sw->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "callback"),
84
19040
      v8::Null(env->isolate()));
85
14280
  sw->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "handle"),
86
19040
      v8::Null(env->isolate()));
87
88
9520
  sw->Inherit(AsyncWrap::GetConstructorTemplate(env));
89
90
  target->Set(env->context(),
91
              wrapString,
92
23800
              sw->GetFunction(env->context()).ToLocalChecked()).Check();
93
4760
  env->set_shutdown_wrap_template(sw->InstanceTemplate());
94
95
  Local<FunctionTemplate> ww =
96
4760
      FunctionTemplate::New(env->isolate(), is_construct_call_callback);
97
9520
  ww->InstanceTemplate()->SetInternalFieldCount(StreamReq::kStreamReqField + 1);
98
  Local<String> writeWrapString =
99
4760
      FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap");
100
4760
  ww->SetClassName(writeWrapString);
101
9520
  ww->Inherit(AsyncWrap::GetConstructorTemplate(env));
102
  target->Set(env->context(),
103
              writeWrapString,
104
23800
              ww->GetFunction(env->context()).ToLocalChecked()).Check();
105
4760
  env->set_write_wrap_template(ww->InstanceTemplate());
106
107
19040
  NODE_DEFINE_CONSTANT(target, kReadBytesOrError);
108
19040
  NODE_DEFINE_CONSTANT(target, kArrayBufferOffset);
109
19040
  NODE_DEFINE_CONSTANT(target, kBytesWritten);
110
19040
  NODE_DEFINE_CONSTANT(target, kLastWriteWasAsync);
111
  target->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "streamBaseState"),
112
19040
              env->stream_base_state().GetJSArray()).Check();
113
4760
}
114
115
116
46130
LibuvStreamWrap::LibuvStreamWrap(Environment* env,
117
                                 Local<Object> object,
118
                                 uv_stream_t* stream,
119
                                 AsyncWrap::ProviderType provider)
120
    : HandleWrap(env,
121
                 object,
122
                 reinterpret_cast<uv_handle_t*>(stream),
123
                 provider),
124
      StreamBase(env),
125
46130
      stream_(stream) {
126
46130
  StreamBase::AttachToObject(object);
127
46130
}
128
129
130
13898
Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate(
131
    Environment* env) {
132
13898
  Local<FunctionTemplate> tmpl = env->libuv_stream_wrap_ctor_template();
133
13898
  if (tmpl.IsEmpty()) {
134
4742
    tmpl = env->NewFunctionTemplate(nullptr);
135
    tmpl->SetClassName(
136
9484
        FIXED_ONE_BYTE_STRING(env->isolate(), "LibuvStreamWrap"));
137
9484
    tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
138
4742
    tmpl->InstanceTemplate()->SetInternalFieldCount(
139
9484
        StreamBase::kStreamBaseFieldCount);
140
    Local<FunctionTemplate> get_write_queue_size =
141
        FunctionTemplate::New(env->isolate(),
142
                              GetWriteQueueSize,
143
                              env->as_callback_data(),
144
9484
                              Signature::New(env->isolate(), tmpl));
145
14226
    tmpl->PrototypeTemplate()->SetAccessorProperty(
146
        env->write_queue_size_string(),
147
        get_write_queue_size,
148
        Local<FunctionTemplate>(),
149
14226
        static_cast<PropertyAttribute>(ReadOnly | DontDelete));
150
4742
    env->SetProtoMethod(tmpl, "setBlocking", SetBlocking);
151
4742
    StreamBase::AddMethods(env, tmpl);
152
4742
    env->set_libuv_stream_wrap_ctor_template(tmpl);
153
  }
154
13898
  return tmpl;
155
}
156
157
158
3986
LibuvStreamWrap* LibuvStreamWrap::From(Environment* env, Local<Object> object) {
159
3986
  Local<FunctionTemplate> sw = env->libuv_stream_wrap_ctor_template();
160


15944
  CHECK(!sw.IsEmpty() && sw->HasInstance(object));
161
3986
  return Unwrap<LibuvStreamWrap>(object);
162
}
163
164
165
195
int LibuvStreamWrap::GetFD() {
166
#ifdef _WIN32
167
  return fd_;
168
#else
169
195
  int fd = -1;
170
195
  if (stream() != nullptr)
171
195
    uv_fileno(reinterpret_cast<uv_handle_t*>(stream()), &fd);
172
195
  return fd;
173
#endif
174
}
175
176
177
951159
bool LibuvStreamWrap::IsAlive() {
178
951159
  return HandleWrap::IsAlive(this);
179
}
180
181
182
3
bool LibuvStreamWrap::IsClosing() {
183
3
  return uv_is_closing(reinterpret_cast<uv_handle_t*>(stream()));
184
}
185
186
187
1360131
AsyncWrap* LibuvStreamWrap::GetAsyncWrap() {
188
1360131
  return static_cast<AsyncWrap*>(this);
189
}
190
191
192
713472
bool LibuvStreamWrap::IsIPCPipe() {
193
713472
  return is_named_pipe_ipc();
194
}
195
196
197
42259
int LibuvStreamWrap::ReadStart() {
198
  return uv_read_start(stream(), [](uv_handle_t* handle,
199
                                    size_t suggested_size,
200
1019679
                                    uv_buf_t* buf) {
201
488710
    static_cast<LibuvStreamWrap*>(handle->data)->OnUvAlloc(suggested_size, buf);
202
2039842
  }, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
203
488952
    static_cast<LibuvStreamWrap*>(stream->data)->OnUvRead(nread, buf);
204
1062342
  });
205
}
206
207
208
1644
int LibuvStreamWrap::ReadStop() {
209
1644
  return uv_read_stop(stream());
210
}
211
212
213
488710
void LibuvStreamWrap::OnUvAlloc(size_t suggested_size, uv_buf_t* buf) {
214
488710
  HandleScope scope(env()->isolate());
215
488710
  Context::Scope context_scope(env()->context());
216
217
977420
  *buf = EmitAlloc(suggested_size);
218
488710
}
219
220
template <class WrapType>
221
153
static MaybeLocal<Object> AcceptHandle(Environment* env,
222
                                       LibuvStreamWrap* parent) {
223
  static_assert(std::is_base_of<LibuvStreamWrap, WrapType>::value ||
224
                std::is_base_of<UDPWrap, WrapType>::value,
225
                "Can only accept stream handles");
226
227
153
  EscapableHandleScope scope(env->isolate());
228
  Local<Object> wrap_obj;
229
230

306
  if (!WrapType::Instantiate(env, parent, WrapType::SOCKET).ToLocal(&wrap_obj))
231
    return Local<Object>();
232
233
153
  HandleWrap* wrap = Unwrap<HandleWrap>(wrap_obj);
234

153
  CHECK_NOT_NULL(wrap);
235
153
  uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(wrap->GetHandle());
236

153
  CHECK_NOT_NULL(stream);
237
238

153
  if (uv_accept(parent->stream(), stream))
239
    ABORT();
240
241
153
  return scope.Escape(wrap_obj);
242
}
243
244
245
488952
void LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) {
246
488952
  HandleScope scope(env()->isolate());
247
488952
  Context::Scope context_scope(env()->context());
248
488952
  uv_handle_type type = UV_UNKNOWN_HANDLE;
249
250

491630
  if (is_named_pipe_ipc() &&
251
2678
      uv_pipe_pending_count(reinterpret_cast<uv_pipe_t*>(stream())) > 0) {
252
153
    type = uv_pipe_pending_type(reinterpret_cast<uv_pipe_t*>(stream()));
253
  }
254
255
  // We should not be getting this callback if someone has already called
256
  // uv_close() on the handle.
257
977904
  CHECK_EQ(persistent().IsEmpty(), false);
258
259
488952
  if (nread > 0) {
260
    MaybeLocal<Object> pending_obj;
261
262
454303
    if (type == UV_TCP) {
263
127
      pending_obj = AcceptHandle<TCPWrap>(env(), this);
264
454176
    } else if (type == UV_NAMED_PIPE) {
265
1
      pending_obj = AcceptHandle<PipeWrap>(env(), this);
266
454175
    } else if (type == UV_UDP) {
267
25
      pending_obj = AcceptHandle<UDPWrap>(env(), this);
268
    } else {
269
454150
      CHECK_EQ(type, UV_UNKNOWN_HANDLE);
270
    }
271
272
454303
    if (!pending_obj.IsEmpty()) {
273
153
      object()
274
          ->Set(env()->context(),
275
                env()->pending_handle_string(),
276
765
                pending_obj.ToLocalChecked())
277
306
          .Check();
278
    }
279
  }
280
281
977824
  EmitRead(nread, *buf);
282
488872
}
283
284
285
12772
void LibuvStreamWrap::GetWriteQueueSize(
286
    const FunctionCallbackInfo<Value>& info) {
287
  LibuvStreamWrap* wrap;
288
12772
  ASSIGN_OR_RETURN_UNWRAP(&wrap, info.This());
289
290
12772
  if (wrap->stream() == nullptr) {
291
    info.GetReturnValue().Set(0);
292
    return;
293
  }
294
295
12772
  uint32_t write_queue_size = wrap->stream()->write_queue_size;
296
25544
  info.GetReturnValue().Set(write_queue_size);
297
}
298
299
300
27
void LibuvStreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) {
301
  LibuvStreamWrap* wrap;
302
27
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
303
304
27
  CHECK_GT(args.Length(), 0);
305
27
  if (!wrap->IsAlive())
306
    return args.GetReturnValue().Set(UV_EINVAL);
307
308
54
  bool enable = args[0]->IsTrue();
309
81
  args.GetReturnValue().Set(uv_stream_set_blocking(wrap->stream(), enable));
310
}
311
312
typedef SimpleShutdownWrap<ReqWrap<uv_shutdown_t>> LibuvShutdownWrap;
313
typedef SimpleWriteWrap<ReqWrap<uv_write_t>> LibuvWriteWrap;
314
315
32435
ShutdownWrap* LibuvStreamWrap::CreateShutdownWrap(Local<Object> object) {
316
32435
  return new LibuvShutdownWrap(this, object);
317
}
318
319
353
WriteWrap* LibuvStreamWrap::CreateWriteWrap(Local<Object> object) {
320
353
  return new LibuvWriteWrap(this, object);
321
}
322
323
324
32435
int LibuvStreamWrap::DoShutdown(ShutdownWrap* req_wrap_) {
325
32435
  LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(req_wrap_);
326
32435
  return req_wrap->Dispatch(uv_shutdown, stream(), AfterUvShutdown);
327
}
328
329
330
32434
void LibuvStreamWrap::AfterUvShutdown(uv_shutdown_t* req, int status) {
331
  LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(
332
32434
      LibuvShutdownWrap::from_req(req));
333
32434
  CHECK_NOT_NULL(req_wrap);
334
32434
  HandleScope scope(req_wrap->env()->isolate());
335
32434
  Context::Scope context_scope(req_wrap->env()->context());
336
64868
  req_wrap->Done(status);
337
32434
}
338
339
340
// NOTE: Call to this function could change both `buf`'s and `count`'s
341
// values, shifting their base and decrementing their length. This is
342
// required in order to skip the data that was successfully written via
343
// uv_try_write().
344
911857
int LibuvStreamWrap::DoTryWrite(uv_buf_t** bufs, size_t* count) {
345
  int err;
346
  size_t written;
347
911857
  uv_buf_t* vbufs = *bufs;
348
911857
  size_t vcount = *count;
349
350
911857
  err = uv_try_write(stream(), vbufs, vcount);
351

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