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