• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_sockaddr-inl.h"
26 #include "handle_wrap.h"
27 #include "req_wrap-inl.h"
28 #include "util-inl.h"
29 
30 namespace node {
31 
32 using v8::Array;
33 using v8::Context;
34 using v8::DontDelete;
35 using v8::FunctionCallbackInfo;
36 using v8::FunctionTemplate;
37 using v8::HandleScope;
38 using v8::Integer;
39 using v8::Local;
40 using v8::MaybeLocal;
41 using v8::Object;
42 using v8::PropertyAttribute;
43 using v8::ReadOnly;
44 using v8::Signature;
45 using v8::String;
46 using v8::Uint32;
47 using v8::Undefined;
48 using v8::Value;
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 
SendWrap(Environment * env,Local<Object> req_wrap_obj,bool have_callback)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 
have_callback() const73 bool SendWrap::have_callback() const {
74   return have_callback_;
75 }
76 
~UDPListener()77 UDPListener::~UDPListener() {
78   if (wrap_ != nullptr)
79     wrap_->set_listener(nullptr);
80 }
81 
~UDPWrapBase()82 UDPWrapBase::~UDPWrapBase() {
83   set_listener(nullptr);
84 }
85 
listener() const86 UDPListener* UDPWrapBase::listener() const {
87   CHECK_NOT_NULL(listener_);
88   return listener_;
89 }
90 
set_listener(UDPListener * listener)91 void UDPWrapBase::set_listener(UDPListener* listener) {
92   if (listener_ != nullptr)
93     listener_->wrap_ = nullptr;
94   listener_ = listener;
95   if (listener_ != nullptr) {
96     CHECK_NULL(listener_->wrap_);
97     listener_->wrap_ = this;
98   }
99 }
100 
FromObject(Local<Object> obj)101 UDPWrapBase* UDPWrapBase::FromObject(Local<Object> obj) {
102   CHECK_GT(obj->InternalFieldCount(), UDPWrapBase::kUDPWrapBaseField);
103   return static_cast<UDPWrapBase*>(
104       obj->GetAlignedPointerFromInternalField(UDPWrapBase::kUDPWrapBaseField));
105 }
106 
AddMethods(Environment * env,Local<FunctionTemplate> t)107 void UDPWrapBase::AddMethods(Environment* env, Local<FunctionTemplate> t) {
108   env->SetProtoMethod(t, "recvStart", RecvStart);
109   env->SetProtoMethod(t, "recvStop", RecvStop);
110 }
111 
UDPWrap(Environment * env,Local<Object> object)112 UDPWrap::UDPWrap(Environment* env, Local<Object> object)
113     : HandleWrap(env,
114                  object,
115                  reinterpret_cast<uv_handle_t*>(&handle_),
116                  AsyncWrap::PROVIDER_UDPWRAP) {
117   object->SetAlignedPointerInInternalField(
118       UDPWrapBase::kUDPWrapBaseField, static_cast<UDPWrapBase*>(this));
119 
120   int r = uv_udp_init(env->event_loop(), &handle_);
121   CHECK_EQ(r, 0);  // can't fail anyway
122 
123   set_listener(this);
124 }
125 
126 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)127 void UDPWrap::Initialize(Local<Object> target,
128                          Local<Value> unused,
129                          Local<Context> context,
130                          void* priv) {
131   Environment* env = Environment::GetCurrent(context);
132 
133   Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
134   t->InstanceTemplate()->SetInternalFieldCount(
135       UDPWrapBase::kInternalFieldCount);
136   Local<String> udpString =
137       FIXED_ONE_BYTE_STRING(env->isolate(), "UDP");
138   t->SetClassName(udpString);
139 
140   enum PropertyAttribute attributes =
141       static_cast<PropertyAttribute>(ReadOnly | DontDelete);
142 
143   Local<Signature> signature = Signature::New(env->isolate(), t);
144 
145   Local<FunctionTemplate> get_fd_templ =
146       FunctionTemplate::New(env->isolate(),
147                             UDPWrap::GetFD,
148                             env->as_callback_data(),
149                             signature);
150 
151   t->PrototypeTemplate()->SetAccessorProperty(env->fd_string(),
152                                               get_fd_templ,
153                                               Local<FunctionTemplate>(),
154                                               attributes);
155 
156   UDPWrapBase::AddMethods(env, t);
157   env->SetProtoMethod(t, "open", Open);
158   env->SetProtoMethod(t, "bind", Bind);
159   env->SetProtoMethod(t, "connect", Connect);
160   env->SetProtoMethod(t, "send", Send);
161   env->SetProtoMethod(t, "bind6", Bind6);
162   env->SetProtoMethod(t, "connect6", Connect6);
163   env->SetProtoMethod(t, "send6", Send6);
164   env->SetProtoMethod(t, "disconnect", Disconnect);
165   env->SetProtoMethod(t, "getpeername",
166                       GetSockOrPeerName<UDPWrap, uv_udp_getpeername>);
167   env->SetProtoMethod(t, "getsockname",
168                       GetSockOrPeerName<UDPWrap, uv_udp_getsockname>);
169   env->SetProtoMethod(t, "addMembership", AddMembership);
170   env->SetProtoMethod(t, "dropMembership", DropMembership);
171   env->SetProtoMethod(t, "addSourceSpecificMembership",
172                       AddSourceSpecificMembership);
173   env->SetProtoMethod(t, "dropSourceSpecificMembership",
174                       DropSourceSpecificMembership);
175   env->SetProtoMethod(t, "setMulticastInterface", SetMulticastInterface);
176   env->SetProtoMethod(t, "setMulticastTTL", SetMulticastTTL);
177   env->SetProtoMethod(t, "setMulticastLoopback", SetMulticastLoopback);
178   env->SetProtoMethod(t, "setBroadcast", SetBroadcast);
179   env->SetProtoMethod(t, "setTTL", SetTTL);
180   env->SetProtoMethod(t, "bufferSize", BufferSize);
181 
182   t->Inherit(HandleWrap::GetConstructorTemplate(env));
183 
184   target->Set(env->context(),
185               udpString,
186               t->GetFunction(env->context()).ToLocalChecked()).Check();
187   env->set_udp_constructor_function(
188       t->GetFunction(env->context()).ToLocalChecked());
189 
190   // Create FunctionTemplate for SendWrap
191   Local<FunctionTemplate> swt =
192       BaseObject::MakeLazilyInitializedJSTemplate(env);
193   swt->Inherit(AsyncWrap::GetConstructorTemplate(env));
194   Local<String> sendWrapString =
195       FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap");
196   swt->SetClassName(sendWrapString);
197   target->Set(env->context(),
198               sendWrapString,
199               swt->GetFunction(env->context()).ToLocalChecked()).Check();
200 
201   Local<Object> constants = Object::New(env->isolate());
202   NODE_DEFINE_CONSTANT(constants, UV_UDP_IPV6ONLY);
203   target->Set(context,
204               env->constants_string(),
205               constants).Check();
206 }
207 
208 
New(const FunctionCallbackInfo<Value> & args)209 void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
210   CHECK(args.IsConstructCall());
211   Environment* env = Environment::GetCurrent(args);
212   new UDPWrap(env, args.This());
213 }
214 
215 
GetFD(const FunctionCallbackInfo<Value> & args)216 void UDPWrap::GetFD(const FunctionCallbackInfo<Value>& args) {
217   int fd = UV_EBADF;
218 #if !defined(_WIN32)
219   UDPWrap* wrap = Unwrap<UDPWrap>(args.This());
220   if (wrap != nullptr)
221     uv_fileno(reinterpret_cast<uv_handle_t*>(&wrap->handle_), &fd);
222 #endif
223   args.GetReturnValue().Set(fd);
224 }
225 
sockaddr_for_family(int address_family,const char * address,const unsigned short port,struct sockaddr_storage * addr)226 int sockaddr_for_family(int address_family,
227                         const char* address,
228                         const unsigned short port,
229                         struct sockaddr_storage* addr) {
230   switch (address_family) {
231     case AF_INET:
232       return uv_ip4_addr(address, port, reinterpret_cast<sockaddr_in*>(addr));
233     case AF_INET6:
234       return uv_ip6_addr(address, port, reinterpret_cast<sockaddr_in6*>(addr));
235     default:
236       CHECK(0 && "unexpected address family");
237   }
238 }
239 
DoBind(const FunctionCallbackInfo<Value> & args,int family)240 void UDPWrap::DoBind(const FunctionCallbackInfo<Value>& args, int family) {
241   UDPWrap* wrap;
242   ASSIGN_OR_RETURN_UNWRAP(&wrap,
243                           args.Holder(),
244                           args.GetReturnValue().Set(UV_EBADF));
245 
246   // bind(ip, port, flags)
247   CHECK_EQ(args.Length(), 3);
248 
249   node::Utf8Value address(args.GetIsolate(), args[0]);
250   Local<Context> ctx = args.GetIsolate()->GetCurrentContext();
251   uint32_t port, flags;
252   if (!args[1]->Uint32Value(ctx).To(&port) ||
253       !args[2]->Uint32Value(ctx).To(&flags))
254     return;
255   struct sockaddr_storage addr_storage;
256   int err = sockaddr_for_family(family, address.out(), port, &addr_storage);
257   if (err == 0) {
258     err = uv_udp_bind(&wrap->handle_,
259                       reinterpret_cast<const sockaddr*>(&addr_storage),
260                       flags);
261   }
262 
263   if (err == 0)
264     wrap->listener()->OnAfterBind();
265 
266   args.GetReturnValue().Set(err);
267 }
268 
269 
DoConnect(const FunctionCallbackInfo<Value> & args,int family)270 void UDPWrap::DoConnect(const FunctionCallbackInfo<Value>& args, int family) {
271   UDPWrap* wrap;
272   ASSIGN_OR_RETURN_UNWRAP(&wrap,
273                           args.Holder(),
274                           args.GetReturnValue().Set(UV_EBADF));
275 
276   CHECK_EQ(args.Length(), 2);
277 
278   node::Utf8Value address(args.GetIsolate(), args[0]);
279   Local<Context> ctx = args.GetIsolate()->GetCurrentContext();
280   uint32_t port;
281   if (!args[1]->Uint32Value(ctx).To(&port))
282     return;
283   struct sockaddr_storage addr_storage;
284   int err = sockaddr_for_family(family, address.out(), port, &addr_storage);
285   if (err == 0) {
286     err = uv_udp_connect(&wrap->handle_,
287                          reinterpret_cast<const sockaddr*>(&addr_storage));
288   }
289 
290   args.GetReturnValue().Set(err);
291 }
292 
293 
Open(const FunctionCallbackInfo<Value> & args)294 void UDPWrap::Open(const FunctionCallbackInfo<Value>& args) {
295   UDPWrap* wrap;
296   ASSIGN_OR_RETURN_UNWRAP(&wrap,
297                           args.Holder(),
298                           args.GetReturnValue().Set(UV_EBADF));
299   CHECK(args[0]->IsNumber());
300   int fd = static_cast<int>(args[0].As<Integer>()->Value());
301   int err = uv_udp_open(&wrap->handle_, fd);
302 
303   args.GetReturnValue().Set(err);
304 }
305 
306 
Bind(const FunctionCallbackInfo<Value> & args)307 void UDPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
308   DoBind(args, AF_INET);
309 }
310 
311 
Bind6(const FunctionCallbackInfo<Value> & args)312 void UDPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
313   DoBind(args, AF_INET6);
314 }
315 
316 
BufferSize(const FunctionCallbackInfo<Value> & args)317 void UDPWrap::BufferSize(const FunctionCallbackInfo<Value>& args) {
318   Environment* env = Environment::GetCurrent(args);
319   UDPWrap* wrap;
320   ASSIGN_OR_RETURN_UNWRAP(&wrap,
321                           args.Holder(),
322                           args.GetReturnValue().Set(UV_EBADF));
323 
324   CHECK(args[0]->IsUint32());
325   CHECK(args[1]->IsBoolean());
326   bool is_recv = args[1].As<v8::Boolean>()->Value();
327   const char* uv_func_name = is_recv ? "uv_recv_buffer_size" :
328                                        "uv_send_buffer_size";
329 
330   if (!args[0]->IsInt32()) {
331     env->CollectUVExceptionInfo(args[2], UV_EINVAL, uv_func_name);
332     return args.GetReturnValue().SetUndefined();
333   }
334 
335   uv_handle_t* handle = reinterpret_cast<uv_handle_t*>(&wrap->handle_);
336   int size = static_cast<int>(args[0].As<Uint32>()->Value());
337   int err;
338 
339   if (is_recv)
340     err = uv_recv_buffer_size(handle, &size);
341   else
342     err = uv_send_buffer_size(handle, &size);
343 
344   if (err != 0) {
345     env->CollectUVExceptionInfo(args[2], err, uv_func_name);
346     return args.GetReturnValue().SetUndefined();
347   }
348 
349   args.GetReturnValue().Set(size);
350 }
351 
352 
Connect(const FunctionCallbackInfo<Value> & args)353 void UDPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
354   DoConnect(args, AF_INET);
355 }
356 
357 
Connect6(const FunctionCallbackInfo<Value> & args)358 void UDPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
359   DoConnect(args, AF_INET6);
360 }
361 
362 
Disconnect(const FunctionCallbackInfo<Value> & args)363 void UDPWrap::Disconnect(const FunctionCallbackInfo<Value>& args) {
364   UDPWrap* wrap;
365   ASSIGN_OR_RETURN_UNWRAP(&wrap,
366                           args.Holder(),
367                           args.GetReturnValue().Set(UV_EBADF));
368 
369   CHECK_EQ(args.Length(), 0);
370 
371   int err = uv_udp_connect(&wrap->handle_, nullptr);
372 
373   args.GetReturnValue().Set(err);
374 }
375 
376 #define X(name, fn)                                                            \
377   void UDPWrap::name(const FunctionCallbackInfo<Value>& args) {                \
378     UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());                            \
379     Environment* env = wrap->env();                                            \
380     CHECK_EQ(args.Length(), 1);                                                \
381     int flag;                                                                  \
382     if (!args[0]->Int32Value(env->context()).To(&flag)) {                      \
383       return;                                                                  \
384     }                                                                          \
385     int err = wrap == nullptr ? UV_EBADF : fn(&wrap->handle_, flag);           \
386     args.GetReturnValue().Set(err);                                            \
387   }
388 
X(SetTTL,uv_udp_set_ttl)389 X(SetTTL, uv_udp_set_ttl)
390 X(SetBroadcast, uv_udp_set_broadcast)
391 X(SetMulticastTTL, uv_udp_set_multicast_ttl)
392 X(SetMulticastLoopback, uv_udp_set_multicast_loop)
393 
394 #undef X
395 
396 void UDPWrap::SetMulticastInterface(const FunctionCallbackInfo<Value>& args) {
397   UDPWrap* wrap;
398   ASSIGN_OR_RETURN_UNWRAP(&wrap,
399                           args.Holder(),
400                           args.GetReturnValue().Set(UV_EBADF));
401 
402   CHECK_EQ(args.Length(), 1);
403   CHECK(args[0]->IsString());
404 
405   Utf8Value iface(args.GetIsolate(), args[0]);
406 
407   const char* iface_cstr = *iface;
408 
409   int err = uv_udp_set_multicast_interface(&wrap->handle_, iface_cstr);
410   args.GetReturnValue().Set(err);
411 }
412 
SetMembership(const FunctionCallbackInfo<Value> & args,uv_membership membership)413 void UDPWrap::SetMembership(const FunctionCallbackInfo<Value>& args,
414                             uv_membership membership) {
415   UDPWrap* wrap;
416   ASSIGN_OR_RETURN_UNWRAP(&wrap,
417                           args.Holder(),
418                           args.GetReturnValue().Set(UV_EBADF));
419 
420   CHECK_EQ(args.Length(), 2);
421 
422   node::Utf8Value address(args.GetIsolate(), args[0]);
423   node::Utf8Value iface(args.GetIsolate(), args[1]);
424 
425   const char* iface_cstr = *iface;
426   if (args[1]->IsUndefined() || args[1]->IsNull()) {
427       iface_cstr = nullptr;
428   }
429 
430   int err = uv_udp_set_membership(&wrap->handle_,
431                                   *address,
432                                   iface_cstr,
433                                   membership);
434   args.GetReturnValue().Set(err);
435 }
436 
437 
AddMembership(const FunctionCallbackInfo<Value> & args)438 void UDPWrap::AddMembership(const FunctionCallbackInfo<Value>& args) {
439   SetMembership(args, UV_JOIN_GROUP);
440 }
441 
442 
DropMembership(const FunctionCallbackInfo<Value> & args)443 void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) {
444   SetMembership(args, UV_LEAVE_GROUP);
445 }
446 
SetSourceMembership(const FunctionCallbackInfo<Value> & args,uv_membership membership)447 void UDPWrap::SetSourceMembership(const FunctionCallbackInfo<Value>& args,
448                                   uv_membership membership) {
449   UDPWrap* wrap;
450   ASSIGN_OR_RETURN_UNWRAP(&wrap,
451                           args.Holder(),
452                           args.GetReturnValue().Set(UV_EBADF));
453 
454   CHECK_EQ(args.Length(), 3);
455 
456   node::Utf8Value source_address(args.GetIsolate(), args[0]);
457   node::Utf8Value group_address(args.GetIsolate(), args[1]);
458   node::Utf8Value iface(args.GetIsolate(), args[2]);
459 
460   if (*iface == nullptr) return;
461   const char* iface_cstr = *iface;
462   if (args[2]->IsUndefined() || args[2]->IsNull()) {
463     iface_cstr = nullptr;
464   }
465 
466   int err = uv_udp_set_source_membership(&wrap->handle_,
467                                          *group_address,
468                                          iface_cstr,
469                                          *source_address,
470                                          membership);
471   args.GetReturnValue().Set(err);
472 }
473 
AddSourceSpecificMembership(const FunctionCallbackInfo<Value> & args)474 void UDPWrap::AddSourceSpecificMembership(
475   const FunctionCallbackInfo<Value>& args) {
476   SetSourceMembership(args, UV_JOIN_GROUP);
477 }
478 
479 
DropSourceSpecificMembership(const FunctionCallbackInfo<Value> & args)480 void UDPWrap::DropSourceSpecificMembership(
481   const FunctionCallbackInfo<Value>& args) {
482   SetSourceMembership(args, UV_LEAVE_GROUP);
483 }
484 
485 
DoSend(const FunctionCallbackInfo<Value> & args,int family)486 void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
487   Environment* env = Environment::GetCurrent(args);
488 
489   UDPWrap* wrap;
490   ASSIGN_OR_RETURN_UNWRAP(&wrap,
491                           args.Holder(),
492                           args.GetReturnValue().Set(UV_EBADF));
493 
494   CHECK(args.Length() == 4 || args.Length() == 6);
495   CHECK(args[0]->IsObject());
496   CHECK(args[1]->IsArray());
497   CHECK(args[2]->IsUint32());
498 
499   bool sendto = args.Length() == 6;
500   if (sendto) {
501     // send(req, list, list.length, port, address, hasCallback)
502     CHECK(args[3]->IsUint32());
503     CHECK(args[4]->IsString());
504     CHECK(args[5]->IsBoolean());
505   } else {
506     // send(req, list, list.length, hasCallback)
507     CHECK(args[3]->IsBoolean());
508   }
509 
510   Local<Array> chunks = args[1].As<Array>();
511   // it is faster to fetch the length of the
512   // array in js-land
513   size_t count = args[2].As<Uint32>()->Value();
514 
515   MaybeStackBuffer<uv_buf_t, 16> bufs(count);
516 
517   // construct uv_buf_t array
518   for (size_t i = 0; i < count; i++) {
519     Local<Value> chunk;
520     if (!chunks->Get(env->context(), i).ToLocal(&chunk)) return;
521 
522     size_t length = Buffer::Length(chunk);
523 
524     bufs[i] = uv_buf_init(Buffer::Data(chunk), length);
525   }
526 
527   int err = 0;
528   struct sockaddr_storage addr_storage;
529   sockaddr* addr = nullptr;
530   if (sendto) {
531     const unsigned short port = args[3].As<Uint32>()->Value();
532     node::Utf8Value address(env->isolate(), args[4]);
533     err = sockaddr_for_family(family, address.out(), port, &addr_storage);
534     if (err == 0)
535       addr = reinterpret_cast<sockaddr*>(&addr_storage);
536   }
537 
538   if (err == 0) {
539     wrap->current_send_req_wrap_ = args[0].As<Object>();
540     wrap->current_send_has_callback_ =
541         sendto ? args[5]->IsTrue() : args[3]->IsTrue();
542 
543     err = wrap->Send(*bufs, count, addr);
544 
545     wrap->current_send_req_wrap_.Clear();
546     wrap->current_send_has_callback_ = false;
547   }
548 
549   args.GetReturnValue().Set(err);
550 }
551 
Send(uv_buf_t * bufs_ptr,size_t count,const sockaddr * addr)552 ssize_t UDPWrap::Send(uv_buf_t* bufs_ptr,
553                       size_t count,
554                       const sockaddr* addr) {
555   if (IsHandleClosing()) return UV_EBADF;
556 
557   size_t msg_size = 0;
558   for (size_t i = 0; i < count; i++)
559     msg_size += bufs_ptr[i].len;
560 
561   int err = 0;
562   if (!UNLIKELY(env()->options()->test_udp_no_try_send)) {
563     err = uv_udp_try_send(&handle_, bufs_ptr, count, addr);
564     if (err == UV_ENOSYS || err == UV_EAGAIN) {
565       err = 0;
566     } else if (err >= 0) {
567       size_t sent = err;
568       while (count > 0 && bufs_ptr->len <= sent) {
569         sent -= bufs_ptr->len;
570         bufs_ptr++;
571         count--;
572       }
573       if (count > 0) {
574         CHECK_LT(sent, bufs_ptr->len);
575         bufs_ptr->base += sent;
576         bufs_ptr->len -= sent;
577       } else {
578         CHECK_EQ(static_cast<size_t>(err), msg_size);
579         // + 1 so that the JS side can distinguish 0-length async sends from
580         // 0-length sync sends.
581         return msg_size + 1;
582       }
583     }
584   }
585 
586   if (err == 0) {
587     AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
588     ReqWrap<uv_udp_send_t>* req_wrap = listener()->CreateSendWrap(msg_size);
589     if (req_wrap == nullptr) return UV_ENOSYS;
590 
591     err = req_wrap->Dispatch(
592         uv_udp_send,
593         &handle_,
594         bufs_ptr,
595         count,
596         addr,
597         uv_udp_send_cb{[](uv_udp_send_t* req, int status) {
598           UDPWrap* self = ContainerOf(&UDPWrap::handle_, req->handle);
599           self->listener()->OnSendDone(
600               ReqWrap<uv_udp_send_t>::from_req(req), status);
601         }});
602     if (err)
603       delete req_wrap;
604   }
605 
606   return err;
607 }
608 
609 
CreateSendWrap(size_t msg_size)610 ReqWrap<uv_udp_send_t>* UDPWrap::CreateSendWrap(size_t msg_size) {
611   SendWrap* req_wrap = new SendWrap(env(),
612                                     current_send_req_wrap_,
613                                     current_send_has_callback_);
614   req_wrap->msg_size = msg_size;
615   return req_wrap;
616 }
617 
618 
Send(const FunctionCallbackInfo<Value> & args)619 void UDPWrap::Send(const FunctionCallbackInfo<Value>& args) {
620   DoSend(args, AF_INET);
621 }
622 
623 
Send6(const FunctionCallbackInfo<Value> & args)624 void UDPWrap::Send6(const FunctionCallbackInfo<Value>& args) {
625   DoSend(args, AF_INET6);
626 }
627 
628 
GetAsyncWrap()629 AsyncWrap* UDPWrap::GetAsyncWrap() {
630   return this;
631 }
632 
GetPeerName()633 SocketAddress UDPWrap::GetPeerName() {
634   return SocketAddress::FromPeerName(handle_);
635 }
636 
GetSockName()637 SocketAddress UDPWrap::GetSockName() {
638   return SocketAddress::FromSockName(handle_);
639 }
640 
RecvStart(const FunctionCallbackInfo<Value> & args)641 void UDPWrapBase::RecvStart(const FunctionCallbackInfo<Value>& args) {
642   UDPWrapBase* wrap = UDPWrapBase::FromObject(args.Holder());
643   args.GetReturnValue().Set(wrap == nullptr ? UV_EBADF : wrap->RecvStart());
644 }
645 
RecvStart()646 int UDPWrap::RecvStart() {
647   if (IsHandleClosing()) return UV_EBADF;
648   int err = uv_udp_recv_start(&handle_, OnAlloc, OnRecv);
649   // UV_EALREADY means that the socket is already bound but that's okay
650   if (err == UV_EALREADY)
651     err = 0;
652   return err;
653 }
654 
655 
RecvStop(const FunctionCallbackInfo<Value> & args)656 void UDPWrapBase::RecvStop(const FunctionCallbackInfo<Value>& args) {
657   UDPWrapBase* wrap = UDPWrapBase::FromObject(args.Holder());
658   args.GetReturnValue().Set(wrap == nullptr ? UV_EBADF : wrap->RecvStop());
659 }
660 
RecvStop()661 int UDPWrap::RecvStop() {
662   if (IsHandleClosing()) return UV_EBADF;
663   return uv_udp_recv_stop(&handle_);
664 }
665 
666 
OnSendDone(ReqWrap<uv_udp_send_t> * req,int status)667 void UDPWrap::OnSendDone(ReqWrap<uv_udp_send_t>* req, int status) {
668   std::unique_ptr<SendWrap> req_wrap{static_cast<SendWrap*>(req)};
669   if (req_wrap->have_callback()) {
670     Environment* env = req_wrap->env();
671     HandleScope handle_scope(env->isolate());
672     Context::Scope context_scope(env->context());
673     Local<Value> arg[] = {
674       Integer::New(env->isolate(), status),
675       Integer::New(env->isolate(), req_wrap->msg_size),
676     };
677     req_wrap->MakeCallback(env->oncomplete_string(), 2, arg);
678   }
679 }
680 
681 
OnAlloc(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)682 void UDPWrap::OnAlloc(uv_handle_t* handle,
683                       size_t suggested_size,
684                       uv_buf_t* buf) {
685   UDPWrap* wrap = ContainerOf(&UDPWrap::handle_,
686                               reinterpret_cast<uv_udp_t*>(handle));
687   *buf = wrap->listener()->OnAlloc(suggested_size);
688 }
689 
OnAlloc(size_t suggested_size)690 uv_buf_t UDPWrap::OnAlloc(size_t suggested_size) {
691   return env()->AllocateManaged(suggested_size).release();
692 }
693 
OnRecv(uv_udp_t * handle,ssize_t nread,const uv_buf_t * buf,const sockaddr * addr,unsigned int flags)694 void UDPWrap::OnRecv(uv_udp_t* handle,
695                      ssize_t nread,
696                      const uv_buf_t* buf,
697                      const sockaddr* addr,
698                      unsigned int flags) {
699   UDPWrap* wrap = ContainerOf(&UDPWrap::handle_, handle);
700   wrap->listener()->OnRecv(nread, *buf, addr, flags);
701 }
702 
OnRecv(ssize_t nread,const uv_buf_t & buf_,const sockaddr * addr,unsigned int flags)703 void UDPWrap::OnRecv(ssize_t nread,
704                      const uv_buf_t& buf_,
705                      const sockaddr* addr,
706                      unsigned int flags) {
707   Environment* env = this->env();
708   AllocatedBuffer buf(env, buf_);
709   if (nread == 0 && addr == nullptr) {
710     return;
711   }
712 
713   HandleScope handle_scope(env->isolate());
714   Context::Scope context_scope(env->context());
715 
716   Local<Value> argv[] = {
717     Integer::New(env->isolate(), nread),
718     object(),
719     Undefined(env->isolate()),
720     Undefined(env->isolate())
721   };
722 
723   if (nread < 0) {
724     MakeCallback(env->onmessage_string(), arraysize(argv), argv);
725     return;
726   }
727 
728   buf.Resize(nread);
729   argv[2] = buf.ToBuffer().ToLocalChecked();
730   argv[3] = AddressToJS(env, addr);
731   MakeCallback(env->onmessage_string(), arraysize(argv), argv);
732 }
733 
Instantiate(Environment * env,AsyncWrap * parent,UDPWrap::SocketType type)734 MaybeLocal<Object> UDPWrap::Instantiate(Environment* env,
735                                         AsyncWrap* parent,
736                                         UDPWrap::SocketType type) {
737   AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent);
738 
739   // If this assert fires then Initialize hasn't been called yet.
740   CHECK_EQ(env->udp_constructor_function().IsEmpty(), false);
741   return env->udp_constructor_function()->NewInstance(env->context());
742 }
743 
744 
745 }  // namespace node
746 
747 NODE_MODULE_CONTEXT_AWARE_INTERNAL(udp_wrap, node::UDPWrap::Initialize)
748