GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: udp_wrap.cc Lines: 356 384 92.7 %
Date: 2022-08-02 04:16:51 Branches: 130 223 58.3 %

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 "node_errors.h"
26
#include "node_sockaddr-inl.h"
27
#include "handle_wrap.h"
28
#include "req_wrap-inl.h"
29
#include "util-inl.h"
30
31
namespace node {
32
33
using errors::TryCatchScope;
34
using v8::Array;
35
using v8::ArrayBuffer;
36
using v8::BackingStore;
37
using v8::Boolean;
38
using v8::Context;
39
using v8::DontDelete;
40
using v8::FunctionCallbackInfo;
41
using v8::FunctionTemplate;
42
using v8::HandleScope;
43
using v8::Integer;
44
using v8::Isolate;
45
using v8::Local;
46
using v8::MaybeLocal;
47
using v8::Object;
48
using v8::PropertyAttribute;
49
using v8::ReadOnly;
50
using v8::Signature;
51
using v8::Uint32;
52
using v8::Undefined;
53
using v8::Value;
54
55
class SendWrap : public ReqWrap<uv_udp_send_t> {
56
 public:
57
  SendWrap(Environment* env, Local<Object> req_wrap_obj, bool have_callback);
58
  inline bool have_callback() const;
59
  size_t msg_size;
60
61
1
  SET_NO_MEMORY_INFO()
62
1
  SET_MEMORY_INFO_NAME(SendWrap)
63
1
  SET_SELF_SIZE(SendWrap)
64
65
 private:
66
  const bool have_callback_;
67
};
68
69
70
2
SendWrap::SendWrap(Environment* env,
71
                   Local<Object> req_wrap_obj,
72
2
                   bool have_callback)
73
    : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPSENDWRAP),
74
2
      have_callback_(have_callback) {
75
2
}
76
77
78
2
bool SendWrap::have_callback() const {
79
2
  return have_callback_;
80
}
81
82
1044
UDPListener::~UDPListener() {
83
522
  if (wrap_ != nullptr)
84
522
    wrap_->set_listener(nullptr);
85
}
86
87
1044
UDPWrapBase::~UDPWrapBase() {
88
522
  set_listener(nullptr);
89
}
90
91
2150
UDPListener* UDPWrapBase::listener() const {
92
2150
  CHECK_NOT_NULL(listener_);
93
2150
  return listener_;
94
}
95
96
794
void UDPWrapBase::set_listener(UDPListener* listener) {
97
794
  if (listener_ != nullptr)
98
261
    listener_->wrap_ = nullptr;
99
794
  listener_ = listener;
100
794
  if (listener_ != nullptr) {
101
272
    CHECK_NULL(listener_->wrap_);
102
272
    listener_->wrap_ = this;
103
  }
104
794
}
105
106
284
UDPWrapBase* UDPWrapBase::FromObject(Local<Object> obj) {
107
284
  CHECK_GT(obj->InternalFieldCount(), UDPWrapBase::kUDPWrapBaseField);
108
  return static_cast<UDPWrapBase*>(
109
568
      obj->GetAlignedPointerFromInternalField(UDPWrapBase::kUDPWrapBaseField));
110
}
111
112
5249
void UDPWrapBase::AddMethods(Environment* env, Local<FunctionTemplate> t) {
113
5249
  SetProtoMethod(env->isolate(), t, "recvStart", RecvStart);
114
5249
  SetProtoMethod(env->isolate(), t, "recvStop", RecvStop);
115
5249
}
116
117
272
UDPWrap::UDPWrap(Environment* env, Local<Object> object)
118
    : HandleWrap(env,
119
                 object,
120
272
                 reinterpret_cast<uv_handle_t*>(&handle_),
121
272
                 AsyncWrap::PROVIDER_UDPWRAP) {
122
272
  object->SetAlignedPointerInInternalField(
123
      UDPWrapBase::kUDPWrapBaseField, static_cast<UDPWrapBase*>(this));
124
125
272
  int r = uv_udp_init(env->event_loop(), &handle_);
126
272
  CHECK_EQ(r, 0);  // can't fail anyway
127
128
272
  set_listener(this);
129
272
}
130
131
132
5249
void UDPWrap::Initialize(Local<Object> target,
133
                         Local<Value> unused,
134
                         Local<Context> context,
135
                         void* priv) {
136
5249
  Environment* env = Environment::GetCurrent(context);
137
5249
  Isolate* isolate = env->isolate();
138
139
5249
  Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New);
140
10498
  t->InstanceTemplate()->SetInternalFieldCount(
141
      UDPWrapBase::kInternalFieldCount);
142
143
5249
  enum PropertyAttribute attributes =
144
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
145
146
5249
  Local<Signature> signature = Signature::New(isolate, t);
147
148
  Local<FunctionTemplate> get_fd_templ =
149
5249
      FunctionTemplate::New(isolate, UDPWrap::GetFD, Local<Value>(), signature);
150
151
20996
  t->PrototypeTemplate()->SetAccessorProperty(env->fd_string(),
152
                                              get_fd_templ,
153
                                              Local<FunctionTemplate>(),
154
                                              attributes);
155
156
5249
  UDPWrapBase::AddMethods(env, t);
157
5249
  SetProtoMethod(isolate, t, "open", Open);
158
5249
  SetProtoMethod(isolate, t, "bind", Bind);
159
5249
  SetProtoMethod(isolate, t, "connect", Connect);
160
5249
  SetProtoMethod(isolate, t, "send", Send);
161
5249
  SetProtoMethod(isolate, t, "bind6", Bind6);
162
5249
  SetProtoMethod(isolate, t, "connect6", Connect6);
163
5249
  SetProtoMethod(isolate, t, "send6", Send6);
164
5249
  SetProtoMethod(isolate, t, "disconnect", Disconnect);
165
5249
  SetProtoMethod(isolate,
166
                 t,
167
                 "getpeername",
168
                 GetSockOrPeerName<UDPWrap, uv_udp_getpeername>);
169
5249
  SetProtoMethod(isolate,
170
                 t,
171
                 "getsockname",
172
                 GetSockOrPeerName<UDPWrap, uv_udp_getsockname>);
173
5249
  SetProtoMethod(isolate, t, "addMembership", AddMembership);
174
5249
  SetProtoMethod(isolate, t, "dropMembership", DropMembership);
175
5249
  SetProtoMethod(
176
      isolate, t, "addSourceSpecificMembership", AddSourceSpecificMembership);
177
5249
  SetProtoMethod(
178
      isolate, t, "dropSourceSpecificMembership", DropSourceSpecificMembership);
179
5249
  SetProtoMethod(isolate, t, "setMulticastInterface", SetMulticastInterface);
180
5249
  SetProtoMethod(isolate, t, "setMulticastTTL", SetMulticastTTL);
181
5249
  SetProtoMethod(isolate, t, "setMulticastLoopback", SetMulticastLoopback);
182
5249
  SetProtoMethod(isolate, t, "setBroadcast", SetBroadcast);
183
5249
  SetProtoMethod(isolate, t, "setTTL", SetTTL);
184
5249
  SetProtoMethod(isolate, t, "bufferSize", BufferSize);
185
186
5249
  t->Inherit(HandleWrap::GetConstructorTemplate(env));
187
188
5249
  SetConstructorFunction(context, target, "UDP", t);
189
10498
  env->set_udp_constructor_function(t->GetFunction(context).ToLocalChecked());
190
191
  // Create FunctionTemplate for SendWrap
192
  Local<FunctionTemplate> swt =
193
5249
      BaseObject::MakeLazilyInitializedJSTemplate(env);
194
5249
  swt->Inherit(AsyncWrap::GetConstructorTemplate(env));
195
5249
  SetConstructorFunction(context, target, "SendWrap", swt);
196
197
5249
  Local<Object> constants = Object::New(isolate);
198
15747
  NODE_DEFINE_CONSTANT(constants, UV_UDP_IPV6ONLY);
199
15747
  NODE_DEFINE_CONSTANT(constants, UV_UDP_REUSEADDR);
200
5249
  target->Set(context,
201
              env->constants_string(),
202
10498
              constants).Check();
203
5249
}
204
205
206
272
void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
207
272
  CHECK(args.IsConstructCall());
208
272
  Environment* env = Environment::GetCurrent(args);
209
272
  new UDPWrap(env, args.This());
210
272
}
211
212
213
21
void UDPWrap::GetFD(const FunctionCallbackInfo<Value>& args) {
214
21
  int fd = UV_EBADF;
215
#if !defined(_WIN32)
216
21
  UDPWrap* wrap = Unwrap<UDPWrap>(args.This());
217
21
  if (wrap != nullptr)
218
20
    uv_fileno(reinterpret_cast<uv_handle_t*>(&wrap->handle_), &fd);
219
#endif
220
21
  args.GetReturnValue().Set(fd);
221
21
}
222
223
710
int sockaddr_for_family(int address_family,
224
                        const char* address,
225
                        const unsigned short port,
226
                        struct sockaddr_storage* addr) {
227
710
  switch (address_family) {
228
654
    case AF_INET:
229
654
      return uv_ip4_addr(address, port, reinterpret_cast<sockaddr_in*>(addr));
230
56
    case AF_INET6:
231
56
      return uv_ip6_addr(address, port, reinterpret_cast<sockaddr_in6*>(addr));
232
    default:
233
      CHECK(0 && "unexpected address family");
234
  }
235
}
236
237
163
void UDPWrap::DoBind(const FunctionCallbackInfo<Value>& args, int family) {
238
  UDPWrap* wrap;
239
163
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
240
                          args.Holder(),
241
                          args.GetReturnValue().Set(UV_EBADF));
242
243
  // bind(ip, port, flags)
244
163
  CHECK_EQ(args.Length(), 3);
245
246
163
  node::Utf8Value address(args.GetIsolate(), args[0]);
247
163
  Local<Context> ctx = args.GetIsolate()->GetCurrentContext();
248
  uint32_t port, flags;
249
489
  if (!args[1]->Uint32Value(ctx).To(&port) ||
250

489
      !args[2]->Uint32Value(ctx).To(&flags))
251
    return;
252
  struct sockaddr_storage addr_storage;
253
163
  int err = sockaddr_for_family(family, address.out(), port, &addr_storage);
254
163
  if (err == 0) {
255
162
    err = uv_udp_bind(&wrap->handle_,
256
                      reinterpret_cast<const sockaddr*>(&addr_storage),
257
                      flags);
258
  }
259
260
163
  if (err == 0)
261
138
    wrap->listener()->OnAfterBind();
262
263
326
  args.GetReturnValue().Set(err);
264
}
265
266
267
13
void UDPWrap::DoConnect(const FunctionCallbackInfo<Value>& args, int family) {
268
  UDPWrap* wrap;
269
13
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
270
                          args.Holder(),
271
                          args.GetReturnValue().Set(UV_EBADF));
272
273
13
  CHECK_EQ(args.Length(), 2);
274
275
13
  node::Utf8Value address(args.GetIsolate(), args[0]);
276
13
  Local<Context> ctx = args.GetIsolate()->GetCurrentContext();
277
  uint32_t port;
278
26
  if (!args[1]->Uint32Value(ctx).To(&port))
279
    return;
280
  struct sockaddr_storage addr_storage;
281
13
  int err = sockaddr_for_family(family, address.out(), port, &addr_storage);
282
13
  if (err == 0) {
283
13
    err = uv_udp_connect(&wrap->handle_,
284
                         reinterpret_cast<const sockaddr*>(&addr_storage));
285
  }
286
287
26
  args.GetReturnValue().Set(err);
288
}
289
290
291
6
void UDPWrap::Open(const FunctionCallbackInfo<Value>& args) {
292
  UDPWrap* wrap;
293
6
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
294
                          args.Holder(),
295
                          args.GetReturnValue().Set(UV_EBADF));
296
6
  CHECK(args[0]->IsNumber());
297
12
  int fd = static_cast<int>(args[0].As<Integer>()->Value());
298
6
  int err = uv_udp_open(&wrap->handle_, fd);
299
300
12
  args.GetReturnValue().Set(err);
301
}
302
303
304
150
void UDPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
305
150
  DoBind(args, AF_INET);
306
150
}
307
308
309
13
void UDPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
310
13
  DoBind(args, AF_INET6);
311
13
}
312
313
314
30
void UDPWrap::BufferSize(const FunctionCallbackInfo<Value>& args) {
315
30
  Environment* env = Environment::GetCurrent(args);
316
  UDPWrap* wrap;
317
36
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
318
                          args.Holder(),
319
                          args.GetReturnValue().Set(UV_EBADF));
320
321
30
  CHECK(args[0]->IsUint32());
322
30
  CHECK(args[1]->IsBoolean());
323
60
  bool is_recv = args[1].As<Boolean>()->Value();
324

30
  const char* uv_func_name = is_recv ? "uv_recv_buffer_size" :
325
                                       "uv_send_buffer_size";
326
327
30
  if (!args[0]->IsInt32()) {
328
2
    env->CollectUVExceptionInfo(args[2], UV_EINVAL, uv_func_name);
329
4
    return args.GetReturnValue().SetUndefined();
330
  }
331
332
28
  uv_handle_t* handle = reinterpret_cast<uv_handle_t*>(&wrap->handle_);
333
56
  int size = static_cast<int>(args[0].As<Uint32>()->Value());
334
  int err;
335
336
28
  if (is_recv)
337
15
    err = uv_recv_buffer_size(handle, &size);
338
  else
339
13
    err = uv_send_buffer_size(handle, &size);
340
341
28
  if (err != 0) {
342
4
    env->CollectUVExceptionInfo(args[2], err, uv_func_name);
343
8
    return args.GetReturnValue().SetUndefined();
344
  }
345
346
48
  args.GetReturnValue().Set(size);
347
}
348
349
350
13
void UDPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
351
13
  DoConnect(args, AF_INET);
352
13
}
353
354
355
void UDPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
356
  DoConnect(args, AF_INET6);
357
}
358
359
360
1
void UDPWrap::Disconnect(const FunctionCallbackInfo<Value>& args) {
361
  UDPWrap* wrap;
362
1
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
363
                          args.Holder(),
364
                          args.GetReturnValue().Set(UV_EBADF));
365
366
1
  CHECK_EQ(args.Length(), 0);
367
368
1
  int err = uv_udp_connect(&wrap->handle_, nullptr);
369
370
2
  args.GetReturnValue().Set(err);
371
}
372
373
#define X(name, fn)                                                            \
374
  void UDPWrap::name(const FunctionCallbackInfo<Value>& args) {                \
375
    UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());                            \
376
    if (wrap == nullptr) {                                                     \
377
      args.GetReturnValue().Set(UV_EBADF);                                     \
378
      return;                                                                  \
379
    }                                                                          \
380
    Environment* env = wrap->env();                                            \
381
    CHECK_EQ(args.Length(), 1);                                                \
382
    int flag;                                                                  \
383
    if (!args[0]->Int32Value(env->context()).To(&flag)) {                      \
384
      return;                                                                  \
385
    }                                                                          \
386
    int err = fn(&wrap->handle_, flag);                                        \
387
    args.GetReturnValue().Set(err);                                            \
388
  }
389
390

14
X(SetTTL, uv_udp_set_ttl)
391

21
X(SetBroadcast, uv_udp_set_broadcast)
392

14
X(SetMulticastTTL, uv_udp_set_multicast_ttl)
393

21
X(SetMulticastLoopback, uv_udp_set_multicast_loop)
394
395
#undef X
396
397
6
void UDPWrap::SetMulticastInterface(const FunctionCallbackInfo<Value>& args) {
398
  UDPWrap* wrap;
399
6
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
400
                          args.Holder(),
401
                          args.GetReturnValue().Set(UV_EBADF));
402
403
6
  CHECK_EQ(args.Length(), 1);
404
12
  CHECK(args[0]->IsString());
405
406
6
  Utf8Value iface(args.GetIsolate(), args[0]);
407
408
6
  const char* iface_cstr = *iface;
409
410
6
  int err = uv_udp_set_multicast_interface(&wrap->handle_, iface_cstr);
411
12
  args.GetReturnValue().Set(err);
412
}
413
414
2
void UDPWrap::SetMembership(const FunctionCallbackInfo<Value>& args,
415
                            uv_membership membership) {
416
  UDPWrap* wrap;
417
2
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
418
                          args.Holder(),
419
                          args.GetReturnValue().Set(UV_EBADF));
420
421
2
  CHECK_EQ(args.Length(), 2);
422
423
4
  node::Utf8Value address(args.GetIsolate(), args[0]);
424
2
  node::Utf8Value iface(args.GetIsolate(), args[1]);
425
426
2
  const char* iface_cstr = *iface;
427

4
  if (args[1]->IsUndefined() || args[1]->IsNull()) {
428
2
      iface_cstr = nullptr;
429
  }
430
431
2
  int err = uv_udp_set_membership(&wrap->handle_,
432
2
                                  *address,
433
                                  iface_cstr,
434
                                  membership);
435
4
  args.GetReturnValue().Set(err);
436
}
437
438
439
1
void UDPWrap::AddMembership(const FunctionCallbackInfo<Value>& args) {
440
1
  SetMembership(args, UV_JOIN_GROUP);
441
1
}
442
443
444
1
void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) {
445
1
  SetMembership(args, UV_LEAVE_GROUP);
446
1
}
447
448
2
void UDPWrap::SetSourceMembership(const FunctionCallbackInfo<Value>& args,
449
                                  uv_membership membership) {
450
  UDPWrap* wrap;
451
2
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
452
                          args.Holder(),
453
                          args.GetReturnValue().Set(UV_EBADF));
454
455
2
  CHECK_EQ(args.Length(), 3);
456
457
2
  node::Utf8Value source_address(args.GetIsolate(), args[0]);
458
2
  node::Utf8Value group_address(args.GetIsolate(), args[1]);
459
2
  node::Utf8Value iface(args.GetIsolate(), args[2]);
460
461
2
  if (*iface == nullptr) return;
462
2
  const char* iface_cstr = *iface;
463

4
  if (args[2]->IsUndefined() || args[2]->IsNull()) {
464
2
    iface_cstr = nullptr;
465
  }
466
467
2
  int err = uv_udp_set_source_membership(&wrap->handle_,
468
2
                                         *group_address,
469
                                         iface_cstr,
470
2
                                         *source_address,
471
                                         membership);
472
4
  args.GetReturnValue().Set(err);
473
}
474
475
1
void UDPWrap::AddSourceSpecificMembership(
476
  const FunctionCallbackInfo<Value>& args) {
477
1
  SetSourceMembership(args, UV_JOIN_GROUP);
478
1
}
479
480
481
1
void UDPWrap::DropSourceSpecificMembership(
482
  const FunctionCallbackInfo<Value>& args) {
483
1
  SetSourceMembership(args, UV_LEAVE_GROUP);
484
1
}
485
486
487
550
void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
488
550
  Environment* env = Environment::GetCurrent(args);
489
490
  UDPWrap* wrap;
491
550
  ASSIGN_OR_RETURN_UNWRAP(&wrap,
492
                          args.Holder(),
493
                          args.GetReturnValue().Set(UV_EBADF));
494
495

1084
  CHECK(args.Length() == 4 || args.Length() == 6);
496
550
  CHECK(args[0]->IsObject());
497
550
  CHECK(args[1]->IsArray());
498
550
  CHECK(args[2]->IsUint32());
499
500
550
  bool sendto = args.Length() == 6;
501
550
  if (sendto) {
502
    // send(req, list, list.length, port, address, hasCallback)
503
534
    CHECK(args[3]->IsUint32());
504
1068
    CHECK(args[4]->IsString());
505
534
    CHECK(args[5]->IsBoolean());
506
  } else {
507
    // send(req, list, list.length, hasCallback)
508
16
    CHECK(args[3]->IsBoolean());
509
  }
510
511
1100
  Local<Array> chunks = args[1].As<Array>();
512
  // it is faster to fetch the length of the
513
  // array in js-land
514
1100
  size_t count = args[2].As<Uint32>()->Value();
515
516
550
  MaybeStackBuffer<uv_buf_t, 16> bufs(count);
517
518
  // construct uv_buf_t array
519
1109
  for (size_t i = 0; i < count; i++) {
520
    Local<Value> chunk;
521
1118
    if (!chunks->Get(env->context(), i).ToLocal(&chunk)) return;
522
523
559
    size_t length = Buffer::Length(chunk);
524
525
559
    bufs[i] = uv_buf_init(Buffer::Data(chunk), length);
526
  }
527
528
550
  int err = 0;
529
  struct sockaddr_storage addr_storage;
530
550
  sockaddr* addr = nullptr;
531
550
  if (sendto) {
532
1068
    const unsigned short port = args[3].As<Uint32>()->Value();
533
1068
    node::Utf8Value address(env->isolate(), args[4]);
534
534
    err = sockaddr_for_family(family, address.out(), port, &addr_storage);
535
534
    if (err == 0)
536
534
      addr = reinterpret_cast<sockaddr*>(&addr_storage);
537
  }
538
539
550
  if (err == 0) {
540
550
    wrap->current_send_req_wrap_ = args[0].As<Object>();
541
550
    wrap->current_send_has_callback_ =
542
1100
        sendto ? args[5]->IsTrue() : args[3]->IsTrue();
543
544
550
    err = static_cast<int>(wrap->Send(*bufs, count, addr));
545
546
550
    wrap->current_send_req_wrap_.Clear();
547
550
    wrap->current_send_has_callback_ = false;
548
  }
549
550
1100
  args.GetReturnValue().Set(err);
551
}
552
553
550
ssize_t UDPWrap::Send(uv_buf_t* bufs_ptr,
554
                      size_t count,
555
                      const sockaddr* addr) {
556
550
  if (IsHandleClosing()) return UV_EBADF;
557
558
550
  size_t msg_size = 0;
559
1109
  for (size_t i = 0; i < count; i++)
560
559
    msg_size += bufs_ptr[i].len;
561
562
550
  int err = 0;
563
550
  if (!UNLIKELY(env()->options()->test_udp_no_try_send)) {
564
548
    err = uv_udp_try_send(&handle_, bufs_ptr, count, addr);
565

548
    if (err == UV_ENOSYS || err == UV_EAGAIN) {
566
      err = 0;
567
548
    } else if (err >= 0) {
568
547
      size_t sent = err;
569

1103
      while (count > 0 && bufs_ptr->len <= sent) {
570
556
        sent -= bufs_ptr->len;
571
556
        bufs_ptr++;
572
556
        count--;
573
      }
574
547
      if (count > 0) {
575
        CHECK_LT(sent, bufs_ptr->len);
576
        bufs_ptr->base += sent;
577
        bufs_ptr->len -= sent;
578
      } else {
579
547
        CHECK_EQ(static_cast<size_t>(err), msg_size);
580
        // + 1 so that the JS side can distinguish 0-length async sends from
581
        // 0-length sync sends.
582
547
        return msg_size + 1;
583
      }
584
    }
585
  }
586
587
3
  if (err == 0) {
588
2
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
589
2
    ReqWrap<uv_udp_send_t>* req_wrap = listener()->CreateSendWrap(msg_size);
590
2
    if (req_wrap == nullptr) return UV_ENOSYS;
591
592
2
    err = req_wrap->Dispatch(
593
        uv_udp_send,
594
        &handle_,
595
        bufs_ptr,
596
        count,
597
        addr,
598
2
        uv_udp_send_cb{[](uv_udp_send_t* req, int status) {
599
2
          UDPWrap* self = ContainerOf(&UDPWrap::handle_, req->handle);
600
4
          self->listener()->OnSendDone(
601
2
              ReqWrap<uv_udp_send_t>::from_req(req), status);
602
2
        }});
603
2
    if (err)
604
      delete req_wrap;
605
  }
606
607
3
  return err;
608
}
609
610
611
2
ReqWrap<uv_udp_send_t>* UDPWrap::CreateSendWrap(size_t msg_size) {
612
2
  SendWrap* req_wrap = new SendWrap(env(),
613
4
                                    current_send_req_wrap_,
614
2
                                    current_send_has_callback_);
615
2
  req_wrap->msg_size = msg_size;
616
2
  return req_wrap;
617
}
618
619
620
507
void UDPWrap::Send(const FunctionCallbackInfo<Value>& args) {
621
507
  DoSend(args, AF_INET);
622
507
}
623
624
625
43
void UDPWrap::Send6(const FunctionCallbackInfo<Value>& args) {
626
43
  DoSend(args, AF_INET6);
627
43
}
628
629
630
AsyncWrap* UDPWrap::GetAsyncWrap() {
631
  return this;
632
}
633
634
SocketAddress UDPWrap::GetPeerName() {
635
  return SocketAddress::FromPeerName(handle_);
636
}
637
638
SocketAddress UDPWrap::GetSockName() {
639
  return SocketAddress::FromSockName(handle_);
640
}
641
642
148
void UDPWrapBase::RecvStart(const FunctionCallbackInfo<Value>& args) {
643
148
  UDPWrapBase* wrap = UDPWrapBase::FromObject(args.Holder());
644
148
  args.GetReturnValue().Set(wrap == nullptr ? UV_EBADF : wrap->RecvStart());
645
148
}
646
647
148
int UDPWrap::RecvStart() {
648
148
  if (IsHandleClosing()) return UV_EBADF;
649
148
  int err = uv_udp_recv_start(&handle_, OnAlloc, OnRecv);
650
  // UV_EALREADY means that the socket is already bound but that's okay
651
148
  if (err == UV_EALREADY)
652
    err = 0;
653
148
  return err;
654
}
655
656
657
136
void UDPWrapBase::RecvStop(const FunctionCallbackInfo<Value>& args) {
658
136
  UDPWrapBase* wrap = UDPWrapBase::FromObject(args.Holder());
659
136
  args.GetReturnValue().Set(wrap == nullptr ? UV_EBADF : wrap->RecvStop());
660
136
}
661
662
136
int UDPWrap::RecvStop() {
663
136
  if (IsHandleClosing()) return UV_EBADF;
664
136
  return uv_udp_recv_stop(&handle_);
665
}
666
667
668
2
void UDPWrap::OnSendDone(ReqWrap<uv_udp_send_t>* req, int status) {
669
4
  std::unique_ptr<SendWrap> req_wrap{static_cast<SendWrap*>(req)};
670
2
  if (req_wrap->have_callback()) {
671
2
    Environment* env = req_wrap->env();
672
4
    HandleScope handle_scope(env->isolate());
673
2
    Context::Scope context_scope(env->context());
674
    Local<Value> arg[] = {
675
      Integer::New(env->isolate(), status),
676
4
      Integer::New(env->isolate(), req_wrap->msg_size),
677
4
    };
678
2
    req_wrap->MakeCallback(env->oncomplete_string(), 2, arg);
679
  }
680
2
}
681
682
683
1004
void UDPWrap::OnAlloc(uv_handle_t* handle,
684
                      size_t suggested_size,
685
                      uv_buf_t* buf) {
686
1004
  UDPWrap* wrap = ContainerOf(&UDPWrap::handle_,
687
1004
                              reinterpret_cast<uv_udp_t*>(handle));
688
1004
  *buf = wrap->listener()->OnAlloc(suggested_size);
689
1004
}
690
691
1004
uv_buf_t UDPWrap::OnAlloc(size_t suggested_size) {
692
1004
  return env()->allocate_managed_buffer(suggested_size);
693
}
694
695
1004
void UDPWrap::OnRecv(uv_udp_t* handle,
696
                     ssize_t nread,
697
                     const uv_buf_t* buf,
698
                     const sockaddr* addr,
699
                     unsigned int flags) {
700
1004
  UDPWrap* wrap = ContainerOf(&UDPWrap::handle_, handle);
701
1004
  wrap->listener()->OnRecv(nread, *buf, addr, flags);
702
1004
}
703
704
1004
void UDPWrap::OnRecv(ssize_t nread,
705
                     const uv_buf_t& buf_,
706
                     const sockaddr* addr,
707
                     unsigned int flags) {
708
1004
  Environment* env = this->env();
709
1004
  Isolate* isolate = env->isolate();
710
1004
  std::unique_ptr<BackingStore> bs = env->release_managed_buffer(buf_);
711

1004
  if (nread == 0 && addr == nullptr) {
712
424
    return;
713
  }
714
715
580
  HandleScope handle_scope(isolate);
716
580
  Context::Scope context_scope(env->context());
717
718
  Local<Value> argv[] = {
719
      Integer::New(isolate, static_cast<int32_t>(nread)),
720
      object(),
721
      Undefined(isolate),
722
2320
      Undefined(isolate)};
723
724
580
  if (nread < 0) {
725
    MakeCallback(env->onmessage_string(), arraysize(argv), argv);
726
    return;
727
580
  } else if (nread == 0) {
728
6
    bs = ArrayBuffer::NewBackingStore(isolate, 0);
729
  } else {
730
574
    CHECK_LE(static_cast<size_t>(nread), bs->ByteLength());
731
574
    bs = BackingStore::Reallocate(isolate, std::move(bs), nread);
732
  }
733
734
  Local<Object> address;
735
  {
736
580
    bool has_caught = false;
737
    {
738
1160
      TryCatchScope try_catch(env);
739
1160
      if (!AddressToJS(env, addr).ToLocal(&address)) {
740
        DCHECK(try_catch.HasCaught() && !try_catch.HasTerminated());
741
        argv[2] = try_catch.Exception();
742
        DCHECK(!argv[2].IsEmpty());
743
        has_caught = true;
744
      }
745
    }
746
580
    if (has_caught) {
747
      DCHECK(!argv[2].IsEmpty());
748
      MakeCallback(env->onerror_string(), arraysize(argv), argv);
749
      return;
750
    }
751
  }
752
753
580
  Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, std::move(bs));
754
  {
755
580
    bool has_caught = false;
756
    {
757
1160
      TryCatchScope try_catch(env);
758
1160
      if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&argv[2])) {
759
        DCHECK(try_catch.HasCaught() && !try_catch.HasTerminated());
760
        argv[2] = try_catch.Exception();
761
        DCHECK(!argv[2].IsEmpty());
762
        has_caught = true;
763
      }
764
    }
765
580
    if (has_caught) {
766
      DCHECK(!argv[2].IsEmpty());
767
      MakeCallback(env->onerror_string(), arraysize(argv), argv);
768
      return;
769
    }
770
  }
771
772
580
  argv[3] = address;
773
580
  MakeCallback(env->onmessage_string(), arraysize(argv), argv);
774
}
775
776
32
MaybeLocal<Object> UDPWrap::Instantiate(Environment* env,
777
                                        AsyncWrap* parent,
778
                                        UDPWrap::SocketType type) {
779
32
  AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent);
780
781
  // If this assert fires then Initialize hasn't been called yet.
782
64
  CHECK_EQ(env->udp_constructor_function().IsEmpty(), false);
783
64
  return env->udp_constructor_function()->NewInstance(env->context());
784
}
785
786
787
}  // namespace node
788
789
5368
NODE_MODULE_CONTEXT_AWARE_INTERNAL(udp_wrap, node::UDPWrap::Initialize)