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