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