GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/udp_wrap.cc Lines: 40 221 18.1 %
Date: 2019-02-01 22:03:38 Branches: 0 144 0.0 %

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 "udp_wrap.h"
23
#include "env-inl.h"
24
#include "node_buffer.h"
25
#include "handle_wrap.h"
26
#include "req_wrap-inl.h"
27
#include "util-inl.h"
28
29
namespace node {
30
31
using v8::Array;
32
using v8::Context;
33
using v8::FunctionCallbackInfo;
34
using v8::FunctionTemplate;
35
using v8::HandleScope;
36
using v8::Integer;
37
using v8::Local;
38
using v8::MaybeLocal;
39
using v8::Object;
40
using v8::PropertyAttribute;
41
using v8::Signature;
42
using v8::String;
43
using v8::Uint32;
44
using v8::Undefined;
45
using v8::Value;
46
47
using AsyncHooks = Environment::AsyncHooks;
48
49
50
class SendWrap : public ReqWrap<uv_udp_send_t> {
51
 public:
52
  SendWrap(Environment* env, Local<Object> req_wrap_obj, bool have_callback);
53
  inline bool have_callback() const;
54
  size_t msg_size;
55
56
  SET_NO_MEMORY_INFO()
57
  SET_MEMORY_INFO_NAME(SendWrap)
58
  SET_SELF_SIZE(SendWrap)
59
60
 private:
61
  const bool have_callback_;
62
};
63
64
65
SendWrap::SendWrap(Environment* env,
66
                   Local<Object> req_wrap_obj,
67
                   bool have_callback)
68
    : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPSENDWRAP),
69
      have_callback_(have_callback) {
70
}
71
72
73
inline bool SendWrap::have_callback() const {
74
  return have_callback_;
75
}
76
77
78
UDPWrap::UDPWrap(Environment* env, Local<Object> object)
79
    : HandleWrap(env,
80
                 object,
81
                 reinterpret_cast<uv_handle_t*>(&handle_),
82
                 AsyncWrap::PROVIDER_UDPWRAP) {
83
  int r = uv_udp_init(env->event_loop(), &handle_);
84
  CHECK_EQ(r, 0);  // can't fail anyway
85
}
86
87
88
153
void UDPWrap::Initialize(Local<Object> target,
89
                         Local<Value> unused,
90
                         Local<Context> context,
91
                         void* priv) {
92
153
  Environment* env = Environment::GetCurrent(context);
93
94
153
  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
95
306
  t->InstanceTemplate()->SetInternalFieldCount(1);
96
  Local<String> udpString =
97
153
      FIXED_ONE_BYTE_STRING(env->isolate(), "UDP");
98
153
  t->SetClassName(udpString);
99
100
  enum PropertyAttribute attributes =
101
153
      static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
102
103
153
  Local<Signature> signature = Signature::New(env->isolate(), t);
104
105
  Local<FunctionTemplate> get_fd_templ =
106
      FunctionTemplate::New(env->isolate(),
107
                            UDPWrap::GetFD,
108
                            env->as_external(),
109
306
                            signature);
110
111
459
  t->PrototypeTemplate()->SetAccessorProperty(env->fd_string(),
112
                                              get_fd_templ,
113
                                              Local<FunctionTemplate>(),
114
459
                                              attributes);
115
116
153
  env->SetProtoMethod(t, "open", Open);
117
153
  env->SetProtoMethod(t, "bind", Bind);
118
153
  env->SetProtoMethod(t, "send", Send);
119
153
  env->SetProtoMethod(t, "bind6", Bind6);
120
153
  env->SetProtoMethod(t, "send6", Send6);
121
153
  env->SetProtoMethod(t, "recvStart", RecvStart);
122
153
  env->SetProtoMethod(t, "recvStop", RecvStop);
123
  env->SetProtoMethod(t, "getsockname",
124
153
                      GetSockOrPeerName<UDPWrap, uv_udp_getsockname>);
125
153
  env->SetProtoMethod(t, "addMembership", AddMembership);
126
153
  env->SetProtoMethod(t, "dropMembership", DropMembership);
127
153
  env->SetProtoMethod(t, "setMulticastInterface", SetMulticastInterface);
128
153
  env->SetProtoMethod(t, "setMulticastTTL", SetMulticastTTL);
129
153
  env->SetProtoMethod(t, "setMulticastLoopback", SetMulticastLoopback);
130
153
  env->SetProtoMethod(t, "setBroadcast", SetBroadcast);
131
153
  env->SetProtoMethod(t, "setTTL", SetTTL);
132
153
  env->SetProtoMethod(t, "bufferSize", BufferSize);
133
134
306
  t->Inherit(HandleWrap::GetConstructorTemplate(env));
135
136
  target->Set(env->context(),
137
              udpString,
138
765
              t->GetFunction(env->context()).ToLocalChecked()).FromJust();
139
  env->set_udp_constructor_function(
140
459
      t->GetFunction(env->context()).ToLocalChecked());
141
142
  // Create FunctionTemplate for SendWrap
143
  Local<FunctionTemplate> swt =
144
153
      BaseObject::MakeLazilyInitializedJSTemplate(env);
145
306
  swt->Inherit(AsyncWrap::GetConstructorTemplate(env));
146
  Local<String> sendWrapString =
147
153
      FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap");
148
153
  swt->SetClassName(sendWrapString);
149
  target->Set(env->context(),
150
              sendWrapString,
151
765
              swt->GetFunction(env->context()).ToLocalChecked()).FromJust();
152
153
153
  Local<Object> constants = Object::New(env->isolate());
154
612
  NODE_DEFINE_CONSTANT(constants, UV_UDP_IPV6ONLY);
155
  target->Set(context,
156
              env->constants_string(),
157
459
              constants).FromJust();
158
153
}
159
160
161
void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
162
  CHECK(args.IsConstructCall());
163
  Environment* env = Environment::GetCurrent(args);
164
  new UDPWrap(env, args.This());
165
}
166
167
168
void UDPWrap::GetFD(const FunctionCallbackInfo<Value>& args) {
169
  int fd = UV_EBADF;
170
#if !defined(_WIN32)
171
  UDPWrap* wrap = Unwrap<UDPWrap>(args.This());
172
  if (wrap != nullptr)
173
    uv_fileno(reinterpret_cast<uv_handle_t*>(&wrap->handle_), &fd);
174
#endif
175
  args.GetReturnValue().Set(fd);
176
}
177
178
179
void UDPWrap::DoBind(const FunctionCallbackInfo<Value>& args, int family) {
180
  UDPWrap* wrap;
181
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
182
                          args.Holder(),
183
                          args.GetReturnValue().Set(UV_EBADF));
184
185
  // bind(ip, port, flags)
186
  CHECK_EQ(args.Length(), 3);
187
188
  node::Utf8Value address(args.GetIsolate(), args[0]);
189
  Local<Context> ctx = args.GetIsolate()->GetCurrentContext();
190
  uint32_t port, flags;
191
  if (!args[1]->Uint32Value(ctx).To(&port) ||
192
      !args[2]->Uint32Value(ctx).To(&flags))
193
    return;
194
  char addr[sizeof(sockaddr_in6)];
195
  int err;
196
197
  switch (family) {
198
  case AF_INET:
199
    err = uv_ip4_addr(*address, port, reinterpret_cast<sockaddr_in*>(&addr));
200
    break;
201
  case AF_INET6:
202
    err = uv_ip6_addr(*address, port, reinterpret_cast<sockaddr_in6*>(&addr));
203
    break;
204
  default:
205
    CHECK(0 && "unexpected address family");
206
    ABORT();
207
  }
208
209
  if (err == 0) {
210
    err = uv_udp_bind(&wrap->handle_,
211
                      reinterpret_cast<const sockaddr*>(&addr),
212
                      flags);
213
  }
214
215
  args.GetReturnValue().Set(err);
216
}
217
218
219
void UDPWrap::Open(const FunctionCallbackInfo<Value>& args) {
220
  UDPWrap* wrap;
221
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
222
                          args.Holder(),
223
                          args.GetReturnValue().Set(UV_EBADF));
224
  CHECK(args[0]->IsNumber());
225
  int fd = static_cast<int>(args[0].As<Integer>()->Value());
226
  int err = uv_udp_open(&wrap->handle_, fd);
227
228
  args.GetReturnValue().Set(err);
229
}
230
231
232
void UDPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
233
  DoBind(args, AF_INET);
234
}
235
236
237
void UDPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
238
  DoBind(args, AF_INET6);
239
}
240
241
242
void UDPWrap::BufferSize(const FunctionCallbackInfo<Value>& args) {
243
  Environment* env = Environment::GetCurrent(args);
244
  UDPWrap* wrap;
245
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
246
                          args.Holder(),
247
                          args.GetReturnValue().Set(UV_EBADF));
248
249
  CHECK(args[0]->IsUint32());
250
  CHECK(args[1]->IsBoolean());
251
  bool is_recv = args[1].As<v8::Boolean>()->Value();
252
  const char* uv_func_name = is_recv ? "uv_recv_buffer_size" :
253
                                       "uv_send_buffer_size";
254
255
  if (!args[0]->IsInt32()) {
256
    env->CollectUVExceptionInfo(args[2], UV_EINVAL, uv_func_name);
257
    return args.GetReturnValue().SetUndefined();
258
  }
259
260
  uv_handle_t* handle = reinterpret_cast<uv_handle_t*>(&wrap->handle_);
261
  int size = static_cast<int>(args[0].As<Uint32>()->Value());
262
  int err;
263
264
  if (is_recv)
265
    err = uv_recv_buffer_size(handle, &size);
266
  else
267
    err = uv_send_buffer_size(handle, &size);
268
269
  if (err != 0) {
270
    env->CollectUVExceptionInfo(args[2], err, uv_func_name);
271
    return args.GetReturnValue().SetUndefined();
272
  }
273
274
  args.GetReturnValue().Set(size);
275
}
276
277
#define X(name, fn)                                                            \
278
  void UDPWrap::name(const FunctionCallbackInfo<Value>& args) {                \
279
    UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());                            \
280
    Environment* env = wrap->env();                                            \
281
    CHECK_EQ(args.Length(), 1);                                                \
282
    int flag;                                                                  \
283
    if (!args[0]->Int32Value(env->context()).To(&flag)) {                      \
284
      return;                                                                  \
285
    }                                                                          \
286
    int err = wrap == nullptr ? UV_EBADF : fn(&wrap->handle_, flag);           \
287
    args.GetReturnValue().Set(err);                                            \
288
  }
289
290
X(SetTTL, uv_udp_set_ttl)
291
X(SetBroadcast, uv_udp_set_broadcast)
292
X(SetMulticastTTL, uv_udp_set_multicast_ttl)
293
X(SetMulticastLoopback, uv_udp_set_multicast_loop)
294
295
#undef X
296
297
void UDPWrap::SetMulticastInterface(const FunctionCallbackInfo<Value>& args) {
298
  UDPWrap* wrap;
299
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
300
                          args.Holder(),
301
                          args.GetReturnValue().Set(UV_EBADF));
302
303
  CHECK_EQ(args.Length(), 1);
304
  CHECK(args[0]->IsString());
305
306
  Utf8Value iface(args.GetIsolate(), args[0]);
307
308
  const char* iface_cstr = *iface;
309
310
  int err = uv_udp_set_multicast_interface(&wrap->handle_, iface_cstr);
311
  args.GetReturnValue().Set(err);
312
}
313
314
void UDPWrap::SetMembership(const FunctionCallbackInfo<Value>& args,
315
                            uv_membership membership) {
316
  UDPWrap* wrap;
317
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
318
                          args.Holder(),
319
                          args.GetReturnValue().Set(UV_EBADF));
320
321
  CHECK_EQ(args.Length(), 2);
322
323
  node::Utf8Value address(args.GetIsolate(), args[0]);
324
  node::Utf8Value iface(args.GetIsolate(), args[1]);
325
326
  const char* iface_cstr = *iface;
327
  if (args[1]->IsUndefined() || args[1]->IsNull()) {
328
      iface_cstr = nullptr;
329
  }
330
331
  int err = uv_udp_set_membership(&wrap->handle_,
332
                                  *address,
333
                                  iface_cstr,
334
                                  membership);
335
  args.GetReturnValue().Set(err);
336
}
337
338
339
void UDPWrap::AddMembership(const FunctionCallbackInfo<Value>& args) {
340
  SetMembership(args, UV_JOIN_GROUP);
341
}
342
343
344
void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) {
345
  SetMembership(args, UV_LEAVE_GROUP);
346
}
347
348
349
void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
350
  Environment* env = Environment::GetCurrent(args);
351
352
  UDPWrap* wrap;
353
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
354
                          args.Holder(),
355
                          args.GetReturnValue().Set(UV_EBADF));
356
357
  // send(req, list, list.length, port, address, hasCallback)
358
  CHECK(args[0]->IsObject());
359
  CHECK(args[1]->IsArray());
360
  CHECK(args[2]->IsUint32());
361
  CHECK(args[3]->IsUint32());
362
  CHECK(args[4]->IsString());
363
  CHECK(args[5]->IsBoolean());
364
365
  Local<Object> req_wrap_obj = args[0].As<Object>();
366
  Local<Array> chunks = args[1].As<Array>();
367
  // it is faster to fetch the length of the
368
  // array in js-land
369
  size_t count = args[2].As<Uint32>()->Value();
370
  const unsigned short port = args[3].As<Uint32>()->Value();
371
  node::Utf8Value address(env->isolate(), args[4]);
372
  const bool have_callback = args[5]->IsTrue();
373
374
  SendWrap* req_wrap;
375
  {
376
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(wrap);
377
    req_wrap = new SendWrap(env, req_wrap_obj, have_callback);
378
  }
379
  size_t msg_size = 0;
380
381
  MaybeStackBuffer<uv_buf_t, 16> bufs(count);
382
383
  // construct uv_buf_t array
384
  for (size_t i = 0; i < count; i++) {
385
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
386
387
    size_t length = Buffer::Length(chunk);
388
389
    bufs[i] = uv_buf_init(Buffer::Data(chunk), length);
390
    msg_size += length;
391
  }
392
393
  req_wrap->msg_size = msg_size;
394
395
  char addr[sizeof(sockaddr_in6)];
396
  int err;
397
398
  switch (family) {
399
  case AF_INET:
400
    err = uv_ip4_addr(*address, port, reinterpret_cast<sockaddr_in*>(&addr));
401
    break;
402
  case AF_INET6:
403
    err = uv_ip6_addr(*address, port, reinterpret_cast<sockaddr_in6*>(&addr));
404
    break;
405
  default:
406
    CHECK(0 && "unexpected address family");
407
    ABORT();
408
  }
409
410
  if (err == 0) {
411
    err = req_wrap->Dispatch(uv_udp_send,
412
                             &wrap->handle_,
413
                             *bufs,
414
                             count,
415
                             reinterpret_cast<const sockaddr*>(&addr),
416
                             OnSend);
417
  }
418
419
  if (err)
420
    delete req_wrap;
421
422
  args.GetReturnValue().Set(err);
423
}
424
425
426
void UDPWrap::Send(const FunctionCallbackInfo<Value>& args) {
427
  DoSend(args, AF_INET);
428
}
429
430
431
void UDPWrap::Send6(const FunctionCallbackInfo<Value>& args) {
432
  DoSend(args, AF_INET6);
433
}
434
435
436
void UDPWrap::RecvStart(const FunctionCallbackInfo<Value>& args) {
437
  UDPWrap* wrap;
438
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
439
                          args.Holder(),
440
                          args.GetReturnValue().Set(UV_EBADF));
441
  int err = uv_udp_recv_start(&wrap->handle_, OnAlloc, OnRecv);
442
  // UV_EALREADY means that the socket is already bound but that's okay
443
  if (err == UV_EALREADY)
444
    err = 0;
445
  args.GetReturnValue().Set(err);
446
}
447
448
449
void UDPWrap::RecvStop(const FunctionCallbackInfo<Value>& args) {
450
  UDPWrap* wrap;
451
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
452
                          args.Holder(),
453
                          args.GetReturnValue().Set(UV_EBADF));
454
  int r = uv_udp_recv_stop(&wrap->handle_);
455
  args.GetReturnValue().Set(r);
456
}
457
458
459
void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
460
  SendWrap* req_wrap = static_cast<SendWrap*>(req->data);
461
  if (req_wrap->have_callback()) {
462
    Environment* env = req_wrap->env();
463
    HandleScope handle_scope(env->isolate());
464
    Context::Scope context_scope(env->context());
465
    Local<Value> arg[] = {
466
      Integer::New(env->isolate(), status),
467
      Integer::New(env->isolate(), req_wrap->msg_size),
468
    };
469
    req_wrap->MakeCallback(env->oncomplete_string(), 2, arg);
470
  }
471
  delete req_wrap;
472
}
473
474
475
void UDPWrap::OnAlloc(uv_handle_t* handle,
476
                      size_t suggested_size,
477
                      uv_buf_t* buf) {
478
  buf->base = node::Malloc(suggested_size);
479
  buf->len = suggested_size;
480
}
481
482
483
void UDPWrap::OnRecv(uv_udp_t* handle,
484
                     ssize_t nread,
485
                     const uv_buf_t* buf,
486
                     const struct sockaddr* addr,
487
                     unsigned int flags) {
488
  if (nread == 0 && addr == nullptr) {
489
    if (buf->base != nullptr)
490
      free(buf->base);
491
    return;
492
  }
493
494
  UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
495
  Environment* env = wrap->env();
496
497
  HandleScope handle_scope(env->isolate());
498
  Context::Scope context_scope(env->context());
499
500
  Local<Object> wrap_obj = wrap->object();
501
  Local<Value> argv[] = {
502
    Integer::New(env->isolate(), nread),
503
    wrap_obj,
504
    Undefined(env->isolate()),
505
    Undefined(env->isolate())
506
  };
507
508
  if (nread < 0) {
509
    if (buf->base != nullptr)
510
      free(buf->base);
511
    wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
512
    return;
513
  }
514
515
  char* base = node::UncheckedRealloc(buf->base, nread);
516
  argv[2] = Buffer::New(env, base, nread).ToLocalChecked();
517
  argv[3] = AddressToJS(env, addr);
518
  wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
519
}
520
521
MaybeLocal<Object> UDPWrap::Instantiate(Environment* env,
522
                                        AsyncWrap* parent,
523
                                        UDPWrap::SocketType type) {
524
  AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent);
525
526
  // If this assert fires then Initialize hasn't been called yet.
527
  CHECK_EQ(env->udp_constructor_function().IsEmpty(), false);
528
  return env->udp_constructor_function()->NewInstance(env->context());
529
}
530
531
532
}  // namespace node
533
534
164
NODE_MODULE_CONTEXT_AWARE_INTERNAL(udp_wrap, node::UDPWrap::Initialize)