GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/stream_wrap.cc Lines: 158 163 96.9 %
Date: 2019-01-07 12:15:22 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 <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::Object;
48
using v8::ReadOnly;
49
using v8::Signature;
50
using v8::Value;
51
52
53
3381
void LibuvStreamWrap::Initialize(Local<Object> target,
54
                                 Local<Value> unused,
55
                                 Local<Context> context,
56
                                 void* priv) {
57
3381
  Environment* env = Environment::GetCurrent(context);
58
59
  auto is_construct_call_callback =
60
756336
      [](const FunctionCallbackInfo<Value>& args) {
61
374787
    CHECK(args.IsConstructCall());
62
374787
    StreamReq::ResetObject(args.This());
63
756336
  };
64
  Local<FunctionTemplate> sw =
65
3381
      FunctionTemplate::New(env->isolate(), is_construct_call_callback);
66
6762
  sw->InstanceTemplate()->SetInternalFieldCount(StreamReq::kStreamReqField + 1);
67
  Local<String> wrapString =
68
3381
      FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap");
69
3381
  sw->SetClassName(wrapString);
70
6762
  sw->Inherit(AsyncWrap::GetConstructorTemplate(env));
71
  target->Set(env->context(),
72
              wrapString,
73
16905
              sw->GetFunction(env->context()).ToLocalChecked()).FromJust();
74
3381
  env->set_shutdown_wrap_template(sw->InstanceTemplate());
75
76
  Local<FunctionTemplate> ww =
77
3381
      FunctionTemplate::New(env->isolate(), is_construct_call_callback);
78
6762
  ww->InstanceTemplate()->SetInternalFieldCount(StreamReq::kStreamReqField + 1);
79
  Local<String> writeWrapString =
80
3381
      FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap");
81
3381
  ww->SetClassName(writeWrapString);
82
6762
  ww->Inherit(AsyncWrap::GetConstructorTemplate(env));
83
  target->Set(env->context(),
84
              writeWrapString,
85
16905
              ww->GetFunction(env->context()).ToLocalChecked()).FromJust();
86
3381
  env->set_write_wrap_template(ww->InstanceTemplate());
87
88
13524
  NODE_DEFINE_CONSTANT(target, kReadBytesOrError);
89
13524
  NODE_DEFINE_CONSTANT(target, kArrayBufferOffset);
90
13524
  NODE_DEFINE_CONSTANT(target, kBytesWritten);
91
13524
  NODE_DEFINE_CONSTANT(target, kLastWriteWasAsync);
92
  target->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "streamBaseState"),
93
13524
              env->stream_base_state().GetJSArray()).FromJust();
94
3381
}
95
96
97
13965
LibuvStreamWrap::LibuvStreamWrap(Environment* env,
98
                                 Local<Object> object,
99
                                 uv_stream_t* stream,
100
                                 AsyncWrap::ProviderType provider)
101
    : HandleWrap(env,
102
                 object,
103
                 reinterpret_cast<uv_handle_t*>(stream),
104
                 provider),
105
      StreamBase(env),
106
13965
      stream_(stream) {
107
13965
}
108
109
110
10193
Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate(
111
    Environment* env) {
112
10193
  Local<FunctionTemplate> tmpl = env->libuv_stream_wrap_ctor_template();
113
10193
  if (tmpl.IsEmpty()) {
114
3431
    tmpl = env->NewFunctionTemplate(nullptr);
115
    tmpl->SetClassName(
116
6862
        FIXED_ONE_BYTE_STRING(env->isolate(), "LibuvStreamWrap"));
117
6862
    tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
118
    Local<FunctionTemplate> get_write_queue_size =
119
        FunctionTemplate::New(env->isolate(),
120
                              GetWriteQueueSize,
121
                              env->as_external(),
122
6862
                              Signature::New(env->isolate(), tmpl));
123
10293
    tmpl->PrototypeTemplate()->SetAccessorProperty(
124
        env->write_queue_size_string(),
125
        get_write_queue_size,
126
        Local<FunctionTemplate>(),
127
10293
        static_cast<PropertyAttribute>(ReadOnly | DontDelete));
128
3431
    env->SetProtoMethod(tmpl, "setBlocking", SetBlocking);
129
3431
    StreamBase::AddMethods<LibuvStreamWrap>(env, tmpl);
130
3431
    env->set_libuv_stream_wrap_ctor_template(tmpl);
131
  }
132
10193
  return tmpl;
133
}
134
135
136
2572
LibuvStreamWrap* LibuvStreamWrap::From(Environment* env, Local<Object> object) {
137
2572
  Local<FunctionTemplate> sw = env->libuv_stream_wrap_ctor_template();
138


10288
  CHECK(!sw.IsEmpty() && sw->HasInstance(object));
139
2572
  return Unwrap<LibuvStreamWrap>(object);
140
}
141
142
143
127
int LibuvStreamWrap::GetFD() {
144
#ifdef _WIN32
145
  return fd_;
146
#else
147
127
  int fd = -1;
148
127
  if (stream() != nullptr)
149
127
    uv_fileno(reinterpret_cast<uv_handle_t*>(stream()), &fd);
150
127
  return fd;
151
#endif
152
}
153
154
155
362701
bool LibuvStreamWrap::IsAlive() {
156
362701
  return HandleWrap::IsAlive(this);
157
}
158
159
160
3
bool LibuvStreamWrap::IsClosing() {
161
3
  return uv_is_closing(reinterpret_cast<uv_handle_t*>(stream()));
162
}
163
164
165
291237
AsyncWrap* LibuvStreamWrap::GetAsyncWrap() {
166
291237
  return static_cast<AsyncWrap*>(this);
167
}
168
169
170
284783
bool LibuvStreamWrap::IsIPCPipe() {
171
284783
  return is_named_pipe_ipc();
172
}
173
174
175
10747
int LibuvStreamWrap::ReadStart() {
176
  return uv_read_start(stream(), [](uv_handle_t* handle,
177
                                    size_t suggested_size,
178
644703
                                    uv_buf_t* buf) {
179
316978
    static_cast<LibuvStreamWrap*>(handle->data)->OnUvAlloc(suggested_size, buf);
180
1289824
  }, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
181
317187
    static_cast<LibuvStreamWrap*>(stream->data)->OnUvRead(nread, buf);
182
655792
  });
183
}
184
185
186
1883
int LibuvStreamWrap::ReadStop() {
187
1883
  return uv_read_stop(stream());
188
}
189
190
191
316978
void LibuvStreamWrap::OnUvAlloc(size_t suggested_size, uv_buf_t* buf) {
192
316978
  HandleScope scope(env()->isolate());
193
316978
  Context::Scope context_scope(env()->context());
194
195
633956
  *buf = EmitAlloc(suggested_size);
196
316978
}
197
198
199
200
template <class WrapType>
201
159
static Local<Object> AcceptHandle(Environment* env, 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
159
  EscapableHandleScope scope(env->isolate());
207
  Local<Object> wrap_obj;
208
209
159
  wrap_obj = WrapType::Instantiate(env, parent, WrapType::SOCKET);
210

159
  if (wrap_obj.IsEmpty())
211
    return Local<Object>();
212
213
159
  HandleWrap* wrap = Unwrap<HandleWrap>(wrap_obj);
214

159
  CHECK_NOT_NULL(wrap);
215
159
  uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(wrap->GetHandle());
216

159
  CHECK_NOT_NULL(stream);
217
218

159
  if (uv_accept(parent->stream(), stream))
219
    ABORT();
220
221
159
  return scope.Escape(wrap_obj);
222
}
223
224
225
317187
void LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) {
226
317187
  HandleScope scope(env()->isolate());
227
317187
  Context::Scope context_scope(env()->context());
228
317187
  uv_handle_type type = UV_UNKNOWN_HANDLE;
229
230

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

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