GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/pipe_wrap.cc Lines: 117 121 96.7 %
Date: 2016-07-23 Branches: 25 46 54.3 %

Line Exec Source
1
#include "pipe_wrap.h"
2
3
#include "async-wrap.h"
4
#include "env.h"
5
#include "env-inl.h"
6
#include "handle_wrap.h"
7
#include "node.h"
8
#include "node_buffer.h"
9
#include "node_wrap.h"
10
#include "req-wrap.h"
11
#include "req-wrap-inl.h"
12
#include "stream_wrap.h"
13
#include "util-inl.h"
14
#include "util.h"
15
16
namespace node {
17
18
using v8::Boolean;
19
using v8::Context;
20
using v8::EscapableHandleScope;
21
using v8::External;
22
using v8::Function;
23
using v8::FunctionCallbackInfo;
24
using v8::FunctionTemplate;
25
using v8::HandleScope;
26
using v8::Integer;
27
using v8::Local;
28
using v8::Object;
29
using v8::String;
30
using v8::Undefined;
31
using v8::Value;
32
33
34
// TODO(bnoordhuis) share with TCPWrap?
35
14
class PipeConnectWrap : public ReqWrap<uv_connect_t> {
36
 public:
37
  PipeConnectWrap(Environment* env, Local<Object> req_wrap_obj);
38
39
  size_t self_size() const override { return sizeof(*this); }
40
};
41
42
43
14
PipeConnectWrap::PipeConnectWrap(Environment* env, Local<Object> req_wrap_obj)
44
14
    : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPECONNECTWRAP) {
45
14
  Wrap(req_wrap_obj, this);
46
14
}
47
48
49
14
static void NewPipeConnectWrap(const FunctionCallbackInfo<Value>& args) {
50
14
  CHECK(args.IsConstructCall());
51
14
}
52
53
54
1178
uv_pipe_t* PipeWrap::UVHandle() {
55
1178
  return &handle_;
56
}
57
58
59
11
Local<Object> PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) {
60
22
  EscapableHandleScope handle_scope(env->isolate());
61
22
  CHECK_EQ(false, env->pipe_constructor_template().IsEmpty());
62
11
  Local<Function> constructor = env->pipe_constructor_template()->GetFunction();
63
11
  CHECK_EQ(false, constructor.IsEmpty());
64
22
  Local<Value> ptr = External::New(env->isolate(), parent);
65
  Local<Object> instance =
66
22
      constructor->NewInstance(env->context(), 1, &ptr).ToLocalChecked();
67
22
  return handle_scope.Escape(instance);
68
}
69
70
71
1512
void PipeWrap::Initialize(Local<Object> target,
72
                          Local<Value> unused,
73
                          Local<Context> context) {
74
1512
  Environment* env = Environment::GetCurrent(context);
75
76
3024
  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
77
1512
  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Pipe"));
78
3024
  t->InstanceTemplate()->SetInternalFieldCount(1);
79
80
1512
  env->SetProtoMethod(t, "close", HandleWrap::Close);
81
1512
  env->SetProtoMethod(t, "unref", HandleWrap::Unref);
82
1512
  env->SetProtoMethod(t, "ref", HandleWrap::Ref);
83
1512
  env->SetProtoMethod(t, "hasRef", HandleWrap::HasRef);
84
85
1512
  StreamWrap::AddMethods(env, t);
86
87
1512
  env->SetProtoMethod(t, "bind", Bind);
88
1512
  env->SetProtoMethod(t, "listen", Listen);
89
1512
  env->SetProtoMethod(t, "connect", Connect);
90
1512
  env->SetProtoMethod(t, "open", Open);
91
92
#ifdef _WIN32
93
  env->SetProtoMethod(t, "setPendingInstances", SetPendingInstances);
94
#endif
95
96
4536
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Pipe"), t->GetFunction());
97
1512
  env->set_pipe_constructor_template(t);
98
99
  // Create FunctionTemplate for PipeConnectWrap.
100
  Local<FunctionTemplate> cwt =
101
3024
      FunctionTemplate::New(env->isolate(), NewPipeConnectWrap);
102
3024
  cwt->InstanceTemplate()->SetInternalFieldCount(1);
103
1512
  cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"));
104
6048
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"),
105
1512
              cwt->GetFunction());
106
1512
}
107
108
109
1780
void PipeWrap::New(const FunctionCallbackInfo<Value>& args) {
110
  // This constructor should not be exposed to public javascript.
111
  // Therefore we assert that we are not trying to call this as a
112
  // normal function.
113
1780
  CHECK(args.IsConstructCall());
114
1780
  Environment* env = Environment::GetCurrent(args);
115
1780
  if (args[0]->IsExternal()) {
116
22
    void* ptr = args[0].As<External>()->Value();
117
11
    new PipeWrap(env, args.This(), false, static_cast<AsyncWrap*>(ptr));
118
  } else {
119
3538
    new PipeWrap(env, args.This(), args[0]->IsTrue(), nullptr);
120
  }
121
1780
}
122
123
124
1780
PipeWrap::PipeWrap(Environment* env,
125
                   Local<Object> object,
126
                   bool ipc,
127
                   AsyncWrap* parent)
128
    : StreamWrap(env,
129
                 object,
130
                 reinterpret_cast<uv_stream_t*>(&handle_),
131
                 AsyncWrap::PROVIDER_PIPEWRAP,
132
1780
                 parent) {
133
3560
  int r = uv_pipe_init(env->event_loop(), &handle_, ipc);
134
1780
  CHECK_EQ(r, 0);  // How do we proxy this error up to javascript?
135
                   // Suggestion: uv_pipe_init() returns void.
136
1780
  UpdateWriteQueueSize();
137
1780
}
138
139
140
16
void PipeWrap::Bind(const FunctionCallbackInfo<Value>& args) {
141
  PipeWrap* wrap;
142
16
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
143
48
  node::Utf8Value name(args.GetIsolate(), args[0]);
144
16
  int err = uv_pipe_bind(&wrap->handle_, *name);
145
32
  args.GetReturnValue().Set(err);
146
}
147
148
149
#ifdef _WIN32
150
void PipeWrap::SetPendingInstances(const FunctionCallbackInfo<Value>& args) {
151
  PipeWrap* wrap;
152
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
153
  int instances = args[0]->Int32Value();
154
  uv_pipe_pending_instances(&wrap->handle_, instances);
155
}
156
#endif
157
158
159
15
void PipeWrap::Listen(const FunctionCallbackInfo<Value>& args) {
160
  PipeWrap* wrap;
161
15
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
162
15
  int backlog = args[0]->Int32Value();
163
15
  int err = uv_listen(reinterpret_cast<uv_stream_t*>(&wrap->handle_),
164
                      backlog,
165
15
                      OnConnection);
166
30
  args.GetReturnValue().Set(err);
167
}
168
169
170
// TODO(bnoordhuis) maybe share with TCPWrap?
171
10
void PipeWrap::OnConnection(uv_stream_t* handle, int status) {
172
10
  PipeWrap* pipe_wrap = static_cast<PipeWrap*>(handle->data);
173
10
  CHECK_EQ(&pipe_wrap->handle_, reinterpret_cast<uv_pipe_t*>(handle));
174
175
10
  Environment* env = pipe_wrap->env();
176
20
  HandleScope handle_scope(env->isolate());
177
30
  Context::Scope context_scope(env->context());
178
179
  // We should not be getting this callback if someone as already called
180
  // uv_close() on the handle.
181
20
  CHECK_EQ(pipe_wrap->persistent().IsEmpty(), false);
182
183
  Local<Value> argv[] = {
184
    Integer::New(env->isolate(), status),
185
    Undefined(env->isolate())
186
40
  };
187
188
10
  if (status != 0) {
189
    pipe_wrap->MakeCallback(env->onconnection_string(), arraysize(argv), argv);
190
    return;
191
  }
192
193
  // Instanciate the client javascript object and handle.
194
10
  Local<Object> client_obj = Instantiate(env, pipe_wrap);
195
196
  // Unwrap the client javascript object.
197
  PipeWrap* wrap;
198
10
  ASSIGN_OR_RETURN_UNWRAP(&wrap, client_obj);
199
10
  uv_stream_t* client_handle = reinterpret_cast<uv_stream_t*>(&wrap->handle_);
200
10
  if (uv_accept(handle, client_handle))
201
    return;
202
203
  // Successful accept. Call the onconnection callback in JavaScript land.
204
10
  argv[1] = client_obj;
205
20
  pipe_wrap->MakeCallback(env->onconnection_string(), arraysize(argv), argv);
206
}
207
208
// TODO(bnoordhuis) Maybe share this with TCPWrap?
209
14
void PipeWrap::AfterConnect(uv_connect_t* req, int status) {
210
14
  PipeConnectWrap* req_wrap = static_cast<PipeConnectWrap*>(req->data);
211
14
  PipeWrap* wrap = static_cast<PipeWrap*>(req->handle->data);
212
14
  CHECK_EQ(req_wrap->env(), wrap->env());
213
14
  Environment* env = wrap->env();
214
215
28
  HandleScope handle_scope(env->isolate());
216
42
  Context::Scope context_scope(env->context());
217
218
  // The wrap and request objects should still be there.
219
28
  CHECK_EQ(req_wrap->persistent().IsEmpty(), false);
220
28
  CHECK_EQ(wrap->persistent().IsEmpty(), false);
221
222
  bool readable, writable;
223
224
14
  if (status) {
225
    readable = writable = 0;
226
  } else {
227
10
    readable = uv_is_readable(req->handle) != 0;
228
10
    writable = uv_is_writable(req->handle) != 0;
229
  }
230
231
28
  Local<Object> req_wrap_obj = req_wrap->object();
232
  Local<Value> argv[5] = {
233
    Integer::New(env->isolate(), status),
234
    wrap->object(),
235
    req_wrap_obj,
236
    Boolean::New(env->isolate(), readable),
237
    Boolean::New(env->isolate(), writable)
238
126
  };
239
240
28
  req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv);
241
242
14
  delete req_wrap;
243
14
}
244
245
246
555
void PipeWrap::Open(const FunctionCallbackInfo<Value>& args) {
247
555
  Environment* env = Environment::GetCurrent(args);
248
249
  PipeWrap* wrap;
250
555
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
251
252
555
  int fd = args[0]->Int32Value();
253
254
555
  int err = uv_pipe_open(&wrap->handle_, fd);
255
256
555
  if (err != 0)
257
    env->isolate()->ThrowException(UVException(err, "uv_pipe_open"));
258
}
259
260
261
14
void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) {
262
14
  Environment* env = Environment::GetCurrent(args);
263
264
  PipeWrap* wrap;
265
14
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
266
267
14
  CHECK(args[0]->IsObject());
268
28
  CHECK(args[1]->IsString());
269
270
28
  Local<Object> req_wrap_obj = args[0].As<Object>();
271
28
  node::Utf8Value name(env->isolate(), args[1]);
272
273
14
  PipeConnectWrap* req_wrap = new PipeConnectWrap(env, req_wrap_obj);
274
14
  uv_pipe_connect(&req_wrap->req_,
275
                  &wrap->handle_,
276
14
                  *name,
277
14
                  AfterConnect);
278
28
  req_wrap->Dispatched();
279
280
28
  args.GetReturnValue().Set(0);  // uv_pipe_connect() doesn't return errors.
281
}
282
283
284
}  // namespace node
285
286
1569
NODE_MODULE_CONTEXT_AWARE_BUILTIN(pipe_wrap, node::PipeWrap::Initialize)