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: 105 161 65.2 %
Date: 2019-02-01 22:03:38 Branches: 29 86 33.7 %

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 <string.h>  // memcpy()
35
#include <limits.h>  // 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
156
void LibuvStreamWrap::Initialize(Local<Object> target,
55
                                 Local<Value> unused,
56
                                 Local<Context> context,
57
                                 void* priv) {
58
156
  Environment* env = Environment::GetCurrent(context);
59
60
  auto is_construct_call_callback =
61
2040
      [](const FunctionCallbackInfo<Value>& args) {
62
864
    CHECK(args.IsConstructCall());
63
864
    StreamReq::ResetObject(args.This());
64
2040
  };
65
  Local<FunctionTemplate> sw =
66
156
      FunctionTemplate::New(env->isolate(), is_construct_call_callback);
67
312
  sw->InstanceTemplate()->SetInternalFieldCount(StreamReq::kStreamReqField + 1);
68
  Local<String> wrapString =
69
156
      FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap");
70
156
  sw->SetClassName(wrapString);
71
312
  sw->Inherit(AsyncWrap::GetConstructorTemplate(env));
72
  target->Set(env->context(),
73
              wrapString,
74
780
              sw->GetFunction(env->context()).ToLocalChecked()).FromJust();
75
156
  env->set_shutdown_wrap_template(sw->InstanceTemplate());
76
77
  Local<FunctionTemplate> ww =
78
156
      FunctionTemplate::New(env->isolate(), is_construct_call_callback);
79
312
  ww->InstanceTemplate()->SetInternalFieldCount(StreamReq::kStreamReqField + 1);
80
  Local<String> writeWrapString =
81
156
      FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap");
82
156
  ww->SetClassName(writeWrapString);
83
312
  ww->Inherit(AsyncWrap::GetConstructorTemplate(env));
84
  target->Set(env->context(),
85
              writeWrapString,
86
780
              ww->GetFunction(env->context()).ToLocalChecked()).FromJust();
87
156
  env->set_write_wrap_template(ww->InstanceTemplate());
88
89
624
  NODE_DEFINE_CONSTANT(target, kReadBytesOrError);
90
624
  NODE_DEFINE_CONSTANT(target, kArrayBufferOffset);
91
624
  NODE_DEFINE_CONSTANT(target, kBytesWritten);
92
624
  NODE_DEFINE_CONSTANT(target, kLastWriteWasAsync);
93
  target->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "streamBaseState"),
94
624
              env->stream_base_state().GetJSArray()).FromJust();
95
156
}
96
97
98
704
LibuvStreamWrap::LibuvStreamWrap(Environment* env,
99
                                 Local<Object> object,
100
                                 uv_stream_t* stream,
101
                                 AsyncWrap::ProviderType provider)
102
    : HandleWrap(env,
103
                 object,
104
                 reinterpret_cast<uv_handle_t*>(stream),
105
                 provider),
106
      StreamBase(env),
107
704
      stream_(stream) {
108
704
}
109
110
111
476
Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate(
112
    Environment* env) {
113
476
  Local<FunctionTemplate> tmpl = env->libuv_stream_wrap_ctor_template();
114
476
  if (tmpl.IsEmpty()) {
115
164
    tmpl = env->NewFunctionTemplate(nullptr);
116
    tmpl->SetClassName(
117
328
        FIXED_ONE_BYTE_STRING(env->isolate(), "LibuvStreamWrap"));
118
328
    tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
119
    Local<FunctionTemplate> get_write_queue_size =
120
        FunctionTemplate::New(env->isolate(),
121
                              GetWriteQueueSize,
122
                              env->as_external(),
123
328
                              Signature::New(env->isolate(), tmpl));
124
492
    tmpl->PrototypeTemplate()->SetAccessorProperty(
125
        env->write_queue_size_string(),
126
        get_write_queue_size,
127
        Local<FunctionTemplate>(),
128
492
        static_cast<PropertyAttribute>(ReadOnly | DontDelete));
129
164
    env->SetProtoMethod(tmpl, "setBlocking", SetBlocking);
130
164
    StreamBase::AddMethods<LibuvStreamWrap>(env, tmpl);
131
164
    env->set_libuv_stream_wrap_ctor_template(tmpl);
132
  }
133
476
  return tmpl;
134
}
135
136
137
498
LibuvStreamWrap* LibuvStreamWrap::From(Environment* env, Local<Object> object) {
138
498
  Local<FunctionTemplate> sw = env->libuv_stream_wrap_ctor_template();
139


1992
  CHECK(!sw.IsEmpty() && sw->HasInstance(object));
140
498
  return Unwrap<LibuvStreamWrap>(object);
141
}
142
143
144
18
int LibuvStreamWrap::GetFD() {
145
#ifdef _WIN32
146
  return fd_;
147
#else
148
18
  int fd = -1;
149
18
  if (stream() != nullptr)
150
18
    uv_fileno(reinterpret_cast<uv_handle_t*>(stream()), &fd);
151
18
  return fd;
152
#endif
153
}
154
155
156
1229
bool LibuvStreamWrap::IsAlive() {
157
1229
  return HandleWrap::IsAlive(this);
158
}
159
160
161
bool LibuvStreamWrap::IsClosing() {
162
  return uv_is_closing(reinterpret_cast<uv_handle_t*>(stream()));
163
}
164
165
166
1020
AsyncWrap* LibuvStreamWrap::GetAsyncWrap() {
167
1020
  return static_cast<AsyncWrap*>(this);
168
}
169
170
171
864
bool LibuvStreamWrap::IsIPCPipe() {
172
864
  return is_named_pipe_ipc();
173
}
174
175
176
346
int LibuvStreamWrap::ReadStart() {
177
  return uv_read_start(stream(), [](uv_handle_t* handle,
178
                                    size_t suggested_size,
179
2384
                                    uv_buf_t* buf) {
180
1019
    static_cast<LibuvStreamWrap*>(handle->data)->OnUvAlloc(suggested_size, buf);
181
4770
  }, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
182
1020
    static_cast<LibuvStreamWrap*>(stream->data)->OnUvRead(nread, buf);
183
2724
  });
184
}
185
186
187
1
int LibuvStreamWrap::ReadStop() {
188
1
  return uv_read_stop(stream());
189
}
190
191
192
1019
void LibuvStreamWrap::OnUvAlloc(size_t suggested_size, uv_buf_t* buf) {
193
1019
  HandleScope scope(env()->isolate());
194
1019
  Context::Scope context_scope(env()->context());
195
196
2038
  *buf = EmitAlloc(suggested_size);
197
1019
}
198
199
template <class WrapType>
200
static MaybeLocal<Object> AcceptHandle(Environment* env,
201
                                       LibuvStreamWrap* parent) {
202
  static_assert(std::is_base_of<LibuvStreamWrap, WrapType>::value ||
203
                std::is_base_of<UDPWrap, WrapType>::value,
204
                "Can only accept stream handles");
205
206
  EscapableHandleScope scope(env->isolate());
207
  Local<Object> wrap_obj;
208
209
  if (!WrapType::Instantiate(env, parent, WrapType::SOCKET).ToLocal(&wrap_obj))
210
    return Local<Object>();
211
212
  HandleWrap* wrap = Unwrap<HandleWrap>(wrap_obj);
213
  CHECK_NOT_NULL(wrap);
214
  uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(wrap->GetHandle());
215
  CHECK_NOT_NULL(stream);
216
217
  if (uv_accept(parent->stream(), stream))
218
    ABORT();
219
220
  return scope.Escape(wrap_obj);
221
}
222
223
224
1020
void LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) {
225
1020
  HandleScope scope(env()->isolate());
226
1020
  Context::Scope context_scope(env()->context());
227
1020
  uv_handle_type type = UV_UNKNOWN_HANDLE;
228
229

1197
  if (is_named_pipe_ipc() &&
230
177
      uv_pipe_pending_count(reinterpret_cast<uv_pipe_t*>(stream())) > 0) {
231
    type = uv_pipe_pending_type(reinterpret_cast<uv_pipe_t*>(stream()));
232
  }
233
234
  // We should not be getting this callback if someone has already called
235
  // uv_close() on the handle.
236
2040
  CHECK_EQ(persistent().IsEmpty(), false);
237
238
1020
  if (nread > 0) {
239
    MaybeLocal<Object> pending_obj;
240
241
692
    if (type == UV_TCP) {
242
      pending_obj = AcceptHandle<TCPWrap>(env(), this);
243
692
    } else if (type == UV_NAMED_PIPE) {
244
      pending_obj = AcceptHandle<PipeWrap>(env(), this);
245
692
    } else if (type == UV_UDP) {
246
      pending_obj = AcceptHandle<UDPWrap>(env(), this);
247
    } else {
248
692
      CHECK_EQ(type, UV_UNKNOWN_HANDLE);
249
    }
250
251
692
    if (!pending_obj.IsEmpty()) {
252
      object()
253
          ->Set(env()->context(),
254
                env()->pending_handle_string(),
255
                pending_obj.ToLocalChecked())
256
          .FromJust();
257
    }
258
  }
259
260
2032
  EmitRead(nread, *buf);
261
1012
}
262
263
264
218
void LibuvStreamWrap::GetWriteQueueSize(
265
    const FunctionCallbackInfo<Value>& info) {
266
  LibuvStreamWrap* wrap;
267
218
  ASSIGN_OR_RETURN_UNWRAP(&wrap, info.This());
268
269
218
  if (wrap->stream() == nullptr) {
270
    info.GetReturnValue().Set(0);
271
    return;
272
  }
273
274
218
  uint32_t write_queue_size = wrap->stream()->write_queue_size;
275
436
  info.GetReturnValue().Set(write_queue_size);
276
}
277
278
279
void LibuvStreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) {
280
  LibuvStreamWrap* wrap;
281
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
282
283
  CHECK_GT(args.Length(), 0);
284
  if (!wrap->IsAlive())
285
    return args.GetReturnValue().Set(UV_EINVAL);
286
287
  bool enable = args[0]->IsTrue();
288
  args.GetReturnValue().Set(uv_stream_set_blocking(wrap->stream(), enable));
289
}
290
291
typedef SimpleShutdownWrap<ReqWrap<uv_shutdown_t>> LibuvShutdownWrap;
292
typedef SimpleWriteWrap<ReqWrap<uv_write_t>> LibuvWriteWrap;
293
294
ShutdownWrap* LibuvStreamWrap::CreateShutdownWrap(Local<Object> object) {
295
  return new LibuvShutdownWrap(this, object);
296
}
297
298
WriteWrap* LibuvStreamWrap::CreateWriteWrap(Local<Object> object) {
299
  return new LibuvWriteWrap(this, object);
300
}
301
302
303
int LibuvStreamWrap::DoShutdown(ShutdownWrap* req_wrap_) {
304
  LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(req_wrap_);
305
  return req_wrap->Dispatch(uv_shutdown, stream(), AfterUvShutdown);
306
}
307
308
309
void LibuvStreamWrap::AfterUvShutdown(uv_shutdown_t* req, int status) {
310
  LibuvShutdownWrap* req_wrap = static_cast<LibuvShutdownWrap*>(
311
      LibuvShutdownWrap::from_req(req));
312
  CHECK_NOT_NULL(req_wrap);
313
  HandleScope scope(req_wrap->env()->isolate());
314
  Context::Scope context_scope(req_wrap->env()->context());
315
  req_wrap->Done(status);
316
}
317
318
319
// NOTE: Call to this function could change both `buf`'s and `count`'s
320
// values, shifting their base and decrementing their length. This is
321
// required in order to skip the data that was successfully written via
322
// uv_try_write().
323
864
int LibuvStreamWrap::DoTryWrite(uv_buf_t** bufs, size_t* count) {
324
  int err;
325
  size_t written;
326
864
  uv_buf_t* vbufs = *bufs;
327
864
  size_t vcount = *count;
328
329
864
  err = uv_try_write(stream(), vbufs, vcount);
330

864
  if (err == UV_ENOSYS || err == UV_EAGAIN)
331
    return 0;
332
864
  if (err < 0)
333
1
    return err;
334
335
  // Slice off the buffers: skip all written buffers and slice the one that
336
  // was partially written.
337
863
  written = err;
338
1726
  for (; vcount > 0; vbufs++, vcount--) {
339
    // Slice
340
863
    if (vbufs[0].len > written) {
341
      vbufs[0].base += written;
342
      vbufs[0].len -= written;
343
      written = 0;
344
      break;
345
346
    // Discard
347
    } else {
348
863
      written -= vbufs[0].len;
349
    }
350
  }
351
352
863
  *bufs = vbufs;
353
863
  *count = vcount;
354
355
863
  return 0;
356
}
357
358
359
int LibuvStreamWrap::DoWrite(WriteWrap* req_wrap,
360
                             uv_buf_t* bufs,
361
                             size_t count,
362
                             uv_stream_t* send_handle) {
363
  LibuvWriteWrap* w = static_cast<LibuvWriteWrap*>(req_wrap);
364
  return w->Dispatch(uv_write2,
365
                     stream(),
366
                     bufs,
367
                     count,
368
                     send_handle,
369
                     AfterUvWrite);
370
}
371
372
373
374
void LibuvStreamWrap::AfterUvWrite(uv_write_t* req, int status) {
375
  LibuvWriteWrap* req_wrap = static_cast<LibuvWriteWrap*>(
376
      LibuvWriteWrap::from_req(req));
377
  CHECK_NOT_NULL(req_wrap);
378
  HandleScope scope(req_wrap->env()->isolate());
379
  Context::Scope context_scope(req_wrap->env()->context());
380
  req_wrap->Done(status);
381
}
382
383
}  // namespace node
384
385
164
NODE_MODULE_CONTEXT_AWARE_INTERNAL(stream_wrap,
386
                                   node::LibuvStreamWrap::Initialize)