GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/out/../src/udp_wrap.cc Lines: 194 206 94.2 %
Date: 2016-11-30 Branches: 49 92 53.3 %

Line Branch Exec Source
1
#include "udp_wrap.h"
2
#include "env.h"
3
#include "env-inl.h"
4
#include "node_buffer.h"
5
#include "handle_wrap.h"
6
#include "req-wrap.h"
7
#include "req-wrap-inl.h"
8
#include "util.h"
9
#include "util-inl.h"
10
11
#include <stdlib.h>
12
13
14
namespace node {
15
16
using v8::Array;
17
using v8::Context;
18
using v8::EscapableHandleScope;
19
using v8::External;
20
using v8::FunctionCallbackInfo;
21
using v8::FunctionTemplate;
22
using v8::HandleScope;
23
using v8::Integer;
24
using v8::Local;
25
using v8::Object;
26
using v8::PropertyAttribute;
27
using v8::PropertyCallbackInfo;
28
using v8::String;
29
using v8::Undefined;
30
using v8::Value;
31
32
33
123
class SendWrap : public ReqWrap<uv_udp_send_t> {
34
 public:
35
  SendWrap(Environment* env, Local<Object> req_wrap_obj, bool have_callback);
36
  inline bool have_callback() const;
37
  size_t msg_size;
38
  size_t self_size() const override { return sizeof(*this); }
39
 private:
40
  const bool have_callback_;
41
};
42
43
44
SendWrap::SendWrap(Environment* env,
45
                   Local<Object> req_wrap_obj,
46
                   bool have_callback)
47
    : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPSENDWRAP),
48
123
      have_callback_(have_callback) {
49
123
  Wrap(req_wrap_obj, this);
50
}
51
52
53
inline bool SendWrap::have_callback() const {
54
  return have_callback_;
55
}
56
57
58
123
static void NewSendWrap(const FunctionCallbackInfo<Value>& args) {
59
123
  CHECK(args.IsConstructCall());
60
123
}
61
62
63
100
UDPWrap::UDPWrap(Environment* env, Local<Object> object, AsyncWrap* parent)
64
    : HandleWrap(env,
65
                 object,
66
                 reinterpret_cast<uv_handle_t*>(&handle_),
67
100
                 AsyncWrap::PROVIDER_UDPWRAP) {
68
200
  int r = uv_udp_init(env->event_loop(), &handle_);
69
100
  CHECK_EQ(r, 0);  // can't fail anyway
70
100
}
71
72
73
1566
void UDPWrap::Initialize(Local<Object> target,
74
                         Local<Value> unused,
75
                         Local<Context> context) {
76
1566
  Environment* env = Environment::GetCurrent(context);
77
78
3132
  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
79
3132
  t->InstanceTemplate()->SetInternalFieldCount(1);
80
1566
  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"));
81
82
  enum PropertyAttribute attributes =
83
1566
      static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
84
9396
  t->InstanceTemplate()->SetAccessor(env->fd_string(),
85
                                     UDPWrap::GetFD,
86
                                     nullptr,
87
                                     env->as_external(),
88
                                     v8::DEFAULT,
89
1566
                                     attributes);
90
91
1566
  env->SetProtoMethod(t, "bind", Bind);
92
1566
  env->SetProtoMethod(t, "send", Send);
93
1566
  env->SetProtoMethod(t, "bind6", Bind6);
94
1566
  env->SetProtoMethod(t, "send6", Send6);
95
1566
  env->SetProtoMethod(t, "close", Close);
96
1566
  env->SetProtoMethod(t, "recvStart", RecvStart);
97
1566
  env->SetProtoMethod(t, "recvStop", RecvStop);
98
  env->SetProtoMethod(t, "getsockname",
99
1566
                      GetSockOrPeerName<UDPWrap, uv_udp_getsockname>);
100
1566
  env->SetProtoMethod(t, "addMembership", AddMembership);
101
1566
  env->SetProtoMethod(t, "dropMembership", DropMembership);
102
1566
  env->SetProtoMethod(t, "setMulticastTTL", SetMulticastTTL);
103
1566
  env->SetProtoMethod(t, "setMulticastLoopback", SetMulticastLoopback);
104
1566
  env->SetProtoMethod(t, "setBroadcast", SetBroadcast);
105
1566
  env->SetProtoMethod(t, "setTTL", SetTTL);
106
107
1566
  env->SetProtoMethod(t, "ref", HandleWrap::Ref);
108
1566
  env->SetProtoMethod(t, "unref", HandleWrap::Unref);
109
1566
  env->SetProtoMethod(t, "hasRef", HandleWrap::HasRef);
110
111
4698
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"), t->GetFunction());
112
1566
  env->set_udp_constructor_function(t->GetFunction());
113
114
  // Create FunctionTemplate for SendWrap
115
  Local<FunctionTemplate> swt =
116
3132
      FunctionTemplate::New(env->isolate(), NewSendWrap);
117
3132
  swt->InstanceTemplate()->SetInternalFieldCount(1);
118
1566
  swt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"));
119
6264
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"),
120
1566
              swt->GetFunction());
121
1566
}
122
123
124
100
void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
125
100
  CHECK(args.IsConstructCall());
126
100
  Environment* env = Environment::GetCurrent(args);
127
100
  if (args.Length() == 0) {
128
89
    new UDPWrap(env, args.This(), nullptr);
129
11
  } else if (args[0]->IsExternal()) {
130
    new UDPWrap(env,
131
22
                args.This(),
132
22
                static_cast<AsyncWrap*>(args[0].As<External>()->Value()));
133
  } else {
134
    UNREACHABLE();
135
  }
136
100
}
137
138
139
2
void UDPWrap::GetFD(Local<String>, const PropertyCallbackInfo<Value>& args) {
140
2
  int fd = UV_EBADF;
141
#if !defined(_WIN32)
142
4
  HandleScope scope(args.GetIsolate());
143
2
  UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
144
2
  if (wrap != nullptr)
145
    uv_fileno(reinterpret_cast<uv_handle_t*>(&wrap->handle_), &fd);
146
#endif
147
6
  args.GetReturnValue().Set(fd);
148
2
}
149
150
151
50
void UDPWrap::DoBind(const FunctionCallbackInfo<Value>& args, int family) {
152
  UDPWrap* wrap;
153
50
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
154
                          args.Holder(),
155
                          args.GetReturnValue().Set(UV_EBADF));
156
157
  // bind(ip, port, flags)
158
50
  CHECK_EQ(args.Length(), 3);
159
160
150
  node::Utf8Value address(args.GetIsolate(), args[0]);
161
50
  const int port = args[1]->Uint32Value();
162
50
  const int flags = args[2]->Uint32Value();
163
  char addr[sizeof(sockaddr_in6)];
164
  int err;
165
166
50
  switch (family) {
167
  case AF_INET:
168
46
    err = uv_ip4_addr(*address, port, reinterpret_cast<sockaddr_in*>(&addr));
169
46
    break;
170
  case AF_INET6:
171
4
    err = uv_ip6_addr(*address, port, reinterpret_cast<sockaddr_in6*>(&addr));
172
4
    break;
173
  default:
174
    CHECK(0 && "unexpected address family");
175
    ABORT();
176
  }
177
178
50
  if (err == 0) {
179
50
    err = uv_udp_bind(&wrap->handle_,
180
                      reinterpret_cast<const sockaddr*>(&addr),
181
50
                      flags);
182
  }
183
184
100
  args.GetReturnValue().Set(err);
185
}
186
187
188
46
void UDPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
189
46
  DoBind(args, AF_INET);
190
46
}
191
192
193
4
void UDPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
194
4
  DoBind(args, AF_INET6);
195
4
}
196
197
198
#define X(name, fn)                                                           \
199
  void UDPWrap::name(const FunctionCallbackInfo<Value>& args) {               \
200
    UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());                           \
201
    CHECK_EQ(args.Length(), 1);                                               \
202
    int flag = args[0]->Int32Value();                                         \
203
    int err = wrap == nullptr ? UV_EBADF : fn(&wrap->handle_, flag);          \
204
    args.GetReturnValue().Set(err);                                           \
205
  }
206
207

6
X(SetTTL, uv_udp_set_ttl)
208

6
X(SetBroadcast, uv_udp_set_broadcast)
209

12
X(SetMulticastTTL, uv_udp_set_multicast_ttl)
210
X(SetMulticastLoopback, uv_udp_set_multicast_loop)
211
212
#undef X
213
214
215
6
void UDPWrap::SetMembership(const FunctionCallbackInfo<Value>& args,
216
                            uv_membership membership) {
217
  UDPWrap* wrap;
218
6
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
219
                          args.Holder(),
220
                          args.GetReturnValue().Set(UV_EBADF));
221
222
6
  CHECK_EQ(args.Length(), 2);
223
224
18
  node::Utf8Value address(args.GetIsolate(), args[0]);
225
18
  node::Utf8Value iface(args.GetIsolate(), args[1]);
226
227
6
  const char* iface_cstr = *iface;
228

18
  if (args[1]->IsUndefined() || args[1]->IsNull()) {
229
6
      iface_cstr = nullptr;
230
  }
231
232
6
  int err = uv_udp_set_membership(&wrap->handle_,
233
6
                                  *address,
234
                                  iface_cstr,
235
6
                                  membership);
236
12
  args.GetReturnValue().Set(err);
237
}
238
239
240
3
void UDPWrap::AddMembership(const FunctionCallbackInfo<Value>& args) {
241
3
  SetMembership(args, UV_JOIN_GROUP);
242
3
}
243
244
245
3
void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) {
246
3
  SetMembership(args, UV_LEAVE_GROUP);
247
3
}
248
249
250
123
void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
251
123
  Environment* env = Environment::GetCurrent(args);
252
253
  UDPWrap* wrap;
254
123
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
255
                          args.Holder(),
256
                          args.GetReturnValue().Set(UV_EBADF));
257
258
  // send(req, list, list.length, port, address, hasCallback)
259
123
  CHECK(args[0]->IsObject());
260
123
  CHECK(args[1]->IsArray());
261
123
  CHECK(args[2]->IsUint32());
262
123
  CHECK(args[3]->IsUint32());
263
246
  CHECK(args[4]->IsString());
264
123
  CHECK(args[5]->IsBoolean());
265
266
246
  Local<Object> req_wrap_obj = args[0].As<Object>();
267
246
  Local<Array> chunks = args[1].As<Array>();
268
  // it is faster to fetch the length of the
269
  // array in js-land
270
123
  size_t count = args[2]->Uint32Value();
271
123
  const unsigned short port = args[3]->Uint32Value();
272
246
  node::Utf8Value address(env->isolate(), args[4]);
273
123
  const bool have_callback = args[5]->IsTrue();
274
275
246
  SendWrap* req_wrap = new SendWrap(env, req_wrap_obj, have_callback);
276
123
  size_t msg_size = 0;
277
278
246
  MaybeStackBuffer<uv_buf_t, 16> bufs(count);
279
280
  // construct uv_buf_t array
281
248
  for (size_t i = 0; i < count; i++) {
282
125
    Local<Value> chunk = chunks->Get(i);
283
284
125
    size_t length = Buffer::Length(chunk);
285
286
125
    bufs[i] = uv_buf_init(Buffer::Data(chunk), length);
287
125
    msg_size += length;
288
  }
289
290
123
  req_wrap->msg_size = msg_size;
291
292
  char addr[sizeof(sockaddr_in6)];
293
  int err;
294
295
123
  switch (family) {
296
  case AF_INET:
297
119
    err = uv_ip4_addr(*address, port, reinterpret_cast<sockaddr_in*>(&addr));
298
119
    break;
299
  case AF_INET6:
300
4
    err = uv_ip6_addr(*address, port, reinterpret_cast<sockaddr_in6*>(&addr));
301
4
    break;
302
  default:
303
    CHECK(0 && "unexpected address family");
304
    ABORT();
305
  }
306
307
123
  if (err == 0) {
308
244
    err = uv_udp_send(req_wrap->req(),
309
                      &wrap->handle_,
310
122
                      *bufs,
311
                      count,
312
                      reinterpret_cast<const sockaddr*>(&addr),
313
122
                      OnSend);
314
  }
315
316
246
  req_wrap->Dispatched();
317
123
  if (err)
318
1
    delete req_wrap;
319
320
246
  args.GetReturnValue().Set(err);
321
}
322
323
324
119
void UDPWrap::Send(const FunctionCallbackInfo<Value>& args) {
325
119
  DoSend(args, AF_INET);
326
119
}
327
328
329
4
void UDPWrap::Send6(const FunctionCallbackInfo<Value>& args) {
330
4
  DoSend(args, AF_INET6);
331
4
}
332
333
334
52
void UDPWrap::RecvStart(const FunctionCallbackInfo<Value>& args) {
335
  UDPWrap* wrap;
336
52
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
337
                          args.Holder(),
338
                          args.GetReturnValue().Set(UV_EBADF));
339
52
  int err = uv_udp_recv_start(&wrap->handle_, OnAlloc, OnRecv);
340
  // UV_EALREADY means that the socket is already bound but that's okay
341
52
  if (err == UV_EALREADY)
342
    err = 0;
343
104
  args.GetReturnValue().Set(err);
344
}
345
346
347
49
void UDPWrap::RecvStop(const FunctionCallbackInfo<Value>& args) {
348
  UDPWrap* wrap;
349
49
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
350
                          args.Holder(),
351
                          args.GetReturnValue().Set(UV_EBADF));
352
49
  int r = uv_udp_recv_stop(&wrap->handle_);
353
98
  args.GetReturnValue().Set(r);
354
}
355
356
357
122
void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
358
122
  SendWrap* req_wrap = static_cast<SendWrap*>(req->data);
359
122
  if (req_wrap->have_callback()) {
360
60
    Environment* env = req_wrap->env();
361
120
    HandleScope handle_scope(env->isolate());
362
180
    Context::Scope context_scope(env->context());
363
    Local<Value> arg[] = {
364
      Integer::New(env->isolate(), status),
365
60
      Integer::New(env->isolate(), req_wrap->msg_size),
366
240
    };
367
60
    req_wrap->MakeCallback(env->oncomplete_string(), 2, arg);
368
  }
369
122
  delete req_wrap;
370
122
}
371
372
373
251
void UDPWrap::OnAlloc(uv_handle_t* handle,
374
                      size_t suggested_size,
375
                      uv_buf_t* buf) {
376
251
  buf->base = node::Malloc(suggested_size);
377
251
  buf->len = suggested_size;
378
251
}
379
380
381
251
void UDPWrap::OnRecv(uv_udp_t* handle,
382
                     ssize_t nread,
383
                     const uv_buf_t* buf,
384
                     const struct sockaddr* addr,
385
                     unsigned int flags) {
386
251
  if (nread == 0 && addr == nullptr) {
387
134
    if (buf->base != nullptr)
388
134
      free(buf->base);
389
134
    return;
390
  }
391
392
117
  UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
393
117
  Environment* env = wrap->env();
394
395
234
  HandleScope handle_scope(env->isolate());
396
351
  Context::Scope context_scope(env->context());
397
398
234
  Local<Object> wrap_obj = wrap->object();
399
  Local<Value> argv[] = {
400
    Integer::New(env->isolate(), nread),
401
    wrap_obj,
402
    Undefined(env->isolate()),
403
    Undefined(env->isolate())
404
819
  };
405
406
117
  if (nread < 0) {
407
    if (buf->base != nullptr)
408
      free(buf->base);
409
    wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
410
    return;
411
  }
412
413
117
  char* base = node::UncheckedRealloc(buf->base, nread);
414
351
  argv[2] = Buffer::New(env, base, nread).ToLocalChecked();
415
234
  argv[3] = AddressToJS(env, addr);
416
234
  wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
417
}
418
419
420
11
Local<Object> UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
421
22
  EscapableHandleScope scope(env->isolate());
422
  // If this assert fires then Initialize hasn't been called yet.
423
22
  CHECK_EQ(env->udp_constructor_function().IsEmpty(), false);
424
22
  Local<Value> ptr = External::New(env->isolate(), parent);
425
22
  return scope.Escape(env->udp_constructor_function()
426
55
      ->NewInstance(env->context(), 1, &ptr).ToLocalChecked());
427
}
428
429
430
11
uv_udp_t* UDPWrap::UVHandle() {
431
11
  return &handle_;
432
}
433
434
435
}  // namespace node
436
437
1705
NODE_MODULE_CONTEXT_AWARE_BUILTIN(udp_wrap, node::UDPWrap::Initialize)