1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22#include "udp_wrap.h" 23#include "env-inl.h" 24#include "node_buffer.h" 25#include "node_errors.h" 26#include "node_sockaddr-inl.h" 27#include "handle_wrap.h" 28#include "req_wrap-inl.h" 29#include "util-inl.h" 30 31namespace node { 32 33using errors::TryCatchScope; 34using v8::Array; 35using v8::ArrayBuffer; 36using v8::BackingStore; 37using v8::Boolean; 38using v8::Context; 39using v8::DontDelete; 40using v8::FunctionCallbackInfo; 41using v8::FunctionTemplate; 42using v8::HandleScope; 43using v8::Integer; 44using v8::Isolate; 45using v8::Local; 46using v8::MaybeLocal; 47using v8::Object; 48using v8::PropertyAttribute; 49using v8::ReadOnly; 50using v8::Signature; 51using v8::Uint32; 52using v8::Undefined; 53using v8::Value; 54 55namespace { 56template <int (*fn)(uv_udp_t*, int)> 57void SetLibuvInt32(const FunctionCallbackInfo<Value>& args) { 58 UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder()); 59 if (wrap == nullptr) { 60 args.GetReturnValue().Set(UV_EBADF); 61 return; 62 } 63 Environment* env = wrap->env(); 64 CHECK_EQ(args.Length(), 1); 65 int flag; 66 if (!args[0]->Int32Value(env->context()).To(&flag)) { 67 return; 68 } 69 int err = fn(wrap->GetLibuvHandle(), flag); 70 args.GetReturnValue().Set(err); 71} 72} // namespace 73 74class SendWrap : public ReqWrap<uv_udp_send_t> { 75 public: 76 SendWrap(Environment* env, Local<Object> req_wrap_obj, bool have_callback); 77 inline bool have_callback() const; 78 size_t msg_size; 79 80 SET_NO_MEMORY_INFO() 81 SET_MEMORY_INFO_NAME(SendWrap) 82 SET_SELF_SIZE(SendWrap) 83 84 private: 85 const bool have_callback_; 86}; 87 88 89SendWrap::SendWrap(Environment* env, 90 Local<Object> req_wrap_obj, 91 bool have_callback) 92 : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPSENDWRAP), 93 have_callback_(have_callback) { 94} 95 96 97bool SendWrap::have_callback() const { 98 return have_callback_; 99} 100 101UDPListener::~UDPListener() { 102 if (wrap_ != nullptr) 103 wrap_->set_listener(nullptr); 104} 105 106UDPWrapBase::~UDPWrapBase() { 107 set_listener(nullptr); 108} 109 110UDPListener* UDPWrapBase::listener() const { 111 CHECK_NOT_NULL(listener_); 112 return listener_; 113} 114 115void UDPWrapBase::set_listener(UDPListener* listener) { 116 if (listener_ != nullptr) 117 listener_->wrap_ = nullptr; 118 listener_ = listener; 119 if (listener_ != nullptr) { 120 CHECK_NULL(listener_->wrap_); 121 listener_->wrap_ = this; 122 } 123} 124 125UDPWrapBase* UDPWrapBase::FromObject(Local<Object> obj) { 126 CHECK_GT(obj->InternalFieldCount(), UDPWrapBase::kUDPWrapBaseField); 127 return static_cast<UDPWrapBase*>( 128 obj->GetAlignedPointerFromInternalField(UDPWrapBase::kUDPWrapBaseField)); 129} 130 131void UDPWrapBase::AddMethods(Environment* env, Local<FunctionTemplate> t) { 132 SetProtoMethod(env->isolate(), t, "recvStart", RecvStart); 133 SetProtoMethod(env->isolate(), t, "recvStop", RecvStop); 134} 135 136UDPWrap::UDPWrap(Environment* env, Local<Object> object) 137 : HandleWrap(env, 138 object, 139 reinterpret_cast<uv_handle_t*>(&handle_), 140 AsyncWrap::PROVIDER_UDPWRAP) { 141 object->SetAlignedPointerInInternalField( 142 UDPWrapBase::kUDPWrapBaseField, static_cast<UDPWrapBase*>(this)); 143 144 int r = uv_udp_init(env->event_loop(), &handle_); 145 CHECK_EQ(r, 0); // can't fail anyway 146 147 set_listener(this); 148} 149 150 151void UDPWrap::Initialize(Local<Object> target, 152 Local<Value> unused, 153 Local<Context> context, 154 void* priv) { 155 Environment* env = Environment::GetCurrent(context); 156 Isolate* isolate = env->isolate(); 157 158 Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New); 159 t->InstanceTemplate()->SetInternalFieldCount( 160 UDPWrapBase::kInternalFieldCount); 161 162 enum PropertyAttribute attributes = 163 static_cast<PropertyAttribute>(ReadOnly | DontDelete); 164 165 Local<Signature> signature = Signature::New(isolate, t); 166 167 Local<FunctionTemplate> get_fd_templ = 168 FunctionTemplate::New(isolate, UDPWrap::GetFD, Local<Value>(), signature); 169 170 t->PrototypeTemplate()->SetAccessorProperty(env->fd_string(), 171 get_fd_templ, 172 Local<FunctionTemplate>(), 173 attributes); 174 175 UDPWrapBase::AddMethods(env, t); 176 SetProtoMethod(isolate, t, "open", Open); 177 SetProtoMethod(isolate, t, "bind", Bind); 178 SetProtoMethod(isolate, t, "connect", Connect); 179 SetProtoMethod(isolate, t, "send", Send); 180 SetProtoMethod(isolate, t, "bind6", Bind6); 181 SetProtoMethod(isolate, t, "connect6", Connect6); 182 SetProtoMethod(isolate, t, "send6", Send6); 183 SetProtoMethod(isolate, t, "disconnect", Disconnect); 184 SetProtoMethod(isolate, 185 t, 186 "getpeername", 187 GetSockOrPeerName<UDPWrap, uv_udp_getpeername>); 188 SetProtoMethod(isolate, 189 t, 190 "getsockname", 191 GetSockOrPeerName<UDPWrap, uv_udp_getsockname>); 192 SetProtoMethod(isolate, t, "addMembership", AddMembership); 193 SetProtoMethod(isolate, t, "dropMembership", DropMembership); 194 SetProtoMethod( 195 isolate, t, "addSourceSpecificMembership", AddSourceSpecificMembership); 196 SetProtoMethod( 197 isolate, t, "dropSourceSpecificMembership", DropSourceSpecificMembership); 198 SetProtoMethod(isolate, t, "setMulticastInterface", SetMulticastInterface); 199 SetProtoMethod( 200 isolate, t, "setMulticastTTL", SetLibuvInt32<uv_udp_set_multicast_ttl>); 201 SetProtoMethod(isolate, 202 t, 203 "setMulticastLoopback", 204 SetLibuvInt32<uv_udp_set_multicast_loop>); 205 SetProtoMethod( 206 isolate, t, "setBroadcast", SetLibuvInt32<uv_udp_set_broadcast>); 207 SetProtoMethod(isolate, t, "setTTL", SetLibuvInt32<uv_udp_set_ttl>); 208 SetProtoMethod(isolate, t, "bufferSize", BufferSize); 209 SetProtoMethodNoSideEffect(isolate, t, "getSendQueueSize", GetSendQueueSize); 210 SetProtoMethodNoSideEffect( 211 isolate, t, "getSendQueueCount", GetSendQueueCount); 212 213 t->Inherit(HandleWrap::GetConstructorTemplate(env)); 214 215 SetConstructorFunction(context, target, "UDP", t); 216 env->set_udp_constructor_function(t->GetFunction(context).ToLocalChecked()); 217 218 // Create FunctionTemplate for SendWrap 219 Local<FunctionTemplate> swt = 220 BaseObject::MakeLazilyInitializedJSTemplate(env); 221 swt->Inherit(AsyncWrap::GetConstructorTemplate(env)); 222 SetConstructorFunction(context, target, "SendWrap", swt); 223 224 Local<Object> constants = Object::New(isolate); 225 NODE_DEFINE_CONSTANT(constants, UV_UDP_IPV6ONLY); 226 NODE_DEFINE_CONSTANT(constants, UV_UDP_REUSEADDR); 227 target->Set(context, 228 env->constants_string(), 229 constants).Check(); 230} 231 232 233void UDPWrap::New(const FunctionCallbackInfo<Value>& args) { 234 CHECK(args.IsConstructCall()); 235 Environment* env = Environment::GetCurrent(args); 236 new UDPWrap(env, args.This()); 237} 238 239 240void UDPWrap::GetFD(const FunctionCallbackInfo<Value>& args) { 241 int fd = UV_EBADF; 242#if !defined(_WIN32) 243 UDPWrap* wrap = Unwrap<UDPWrap>(args.This()); 244 if (wrap != nullptr) 245 uv_fileno(reinterpret_cast<uv_handle_t*>(&wrap->handle_), &fd); 246#endif 247 args.GetReturnValue().Set(fd); 248} 249 250int sockaddr_for_family(int address_family, 251 const char* address, 252 const unsigned short port, 253 struct sockaddr_storage* addr) { 254 switch (address_family) { 255 case AF_INET: 256 return uv_ip4_addr(address, port, reinterpret_cast<sockaddr_in*>(addr)); 257 case AF_INET6: 258 return uv_ip6_addr(address, port, reinterpret_cast<sockaddr_in6*>(addr)); 259 default: 260 UNREACHABLE("unexpected address family"); 261 } 262} 263 264void UDPWrap::DoBind(const FunctionCallbackInfo<Value>& args, int family) { 265 UDPWrap* wrap; 266 ASSIGN_OR_RETURN_UNWRAP(&wrap, 267 args.Holder(), 268 args.GetReturnValue().Set(UV_EBADF)); 269 270 // bind(ip, port, flags) 271 CHECK_EQ(args.Length(), 3); 272 273 node::Utf8Value address(args.GetIsolate(), args[0]); 274 Local<Context> ctx = args.GetIsolate()->GetCurrentContext(); 275 uint32_t port, flags; 276 if (!args[1]->Uint32Value(ctx).To(&port) || 277 !args[2]->Uint32Value(ctx).To(&flags)) 278 return; 279 struct sockaddr_storage addr_storage; 280 int err = sockaddr_for_family(family, address.out(), port, &addr_storage); 281 if (err == 0) { 282 err = uv_udp_bind(&wrap->handle_, 283 reinterpret_cast<const sockaddr*>(&addr_storage), 284 flags); 285 } 286 287 if (err == 0) 288 wrap->listener()->OnAfterBind(); 289 290 args.GetReturnValue().Set(err); 291} 292 293 294void UDPWrap::DoConnect(const FunctionCallbackInfo<Value>& args, int family) { 295 UDPWrap* wrap; 296 ASSIGN_OR_RETURN_UNWRAP(&wrap, 297 args.Holder(), 298 args.GetReturnValue().Set(UV_EBADF)); 299 300 CHECK_EQ(args.Length(), 2); 301 302 node::Utf8Value address(args.GetIsolate(), args[0]); 303 Local<Context> ctx = args.GetIsolate()->GetCurrentContext(); 304 uint32_t port; 305 if (!args[1]->Uint32Value(ctx).To(&port)) 306 return; 307 struct sockaddr_storage addr_storage; 308 int err = sockaddr_for_family(family, address.out(), port, &addr_storage); 309 if (err == 0) { 310 err = uv_udp_connect(&wrap->handle_, 311 reinterpret_cast<const sockaddr*>(&addr_storage)); 312 } 313 314 args.GetReturnValue().Set(err); 315} 316 317 318void UDPWrap::Open(const FunctionCallbackInfo<Value>& args) { 319 UDPWrap* wrap; 320 ASSIGN_OR_RETURN_UNWRAP(&wrap, 321 args.Holder(), 322 args.GetReturnValue().Set(UV_EBADF)); 323 CHECK(args[0]->IsNumber()); 324 int fd = static_cast<int>(args[0].As<Integer>()->Value()); 325 int err = uv_udp_open(&wrap->handle_, fd); 326 327 args.GetReturnValue().Set(err); 328} 329 330 331void UDPWrap::Bind(const FunctionCallbackInfo<Value>& args) { 332 DoBind(args, AF_INET); 333} 334 335 336void UDPWrap::Bind6(const FunctionCallbackInfo<Value>& args) { 337 DoBind(args, AF_INET6); 338} 339 340 341void UDPWrap::BufferSize(const FunctionCallbackInfo<Value>& args) { 342 Environment* env = Environment::GetCurrent(args); 343 UDPWrap* wrap; 344 ASSIGN_OR_RETURN_UNWRAP(&wrap, 345 args.Holder(), 346 args.GetReturnValue().Set(UV_EBADF)); 347 348 CHECK(args[0]->IsUint32()); 349 CHECK(args[1]->IsBoolean()); 350 bool is_recv = args[1].As<Boolean>()->Value(); 351 const char* uv_func_name = is_recv ? "uv_recv_buffer_size" : 352 "uv_send_buffer_size"; 353 354 if (!args[0]->IsInt32()) { 355 env->CollectUVExceptionInfo(args[2], UV_EINVAL, uv_func_name); 356 return args.GetReturnValue().SetUndefined(); 357 } 358 359 uv_handle_t* handle = reinterpret_cast<uv_handle_t*>(&wrap->handle_); 360 int size = static_cast<int>(args[0].As<Uint32>()->Value()); 361 int err; 362 363 if (is_recv) 364 err = uv_recv_buffer_size(handle, &size); 365 else 366 err = uv_send_buffer_size(handle, &size); 367 368 if (err != 0) { 369 env->CollectUVExceptionInfo(args[2], err, uv_func_name); 370 return args.GetReturnValue().SetUndefined(); 371 } 372 373 args.GetReturnValue().Set(size); 374} 375 376 377void UDPWrap::Connect(const FunctionCallbackInfo<Value>& args) { 378 DoConnect(args, AF_INET); 379} 380 381 382void UDPWrap::Connect6(const FunctionCallbackInfo<Value>& args) { 383 DoConnect(args, AF_INET6); 384} 385 386 387void UDPWrap::Disconnect(const FunctionCallbackInfo<Value>& args) { 388 UDPWrap* wrap; 389 ASSIGN_OR_RETURN_UNWRAP(&wrap, 390 args.Holder(), 391 args.GetReturnValue().Set(UV_EBADF)); 392 393 CHECK_EQ(args.Length(), 0); 394 395 int err = uv_udp_connect(&wrap->handle_, nullptr); 396 397 args.GetReturnValue().Set(err); 398} 399 400void UDPWrap::SetMulticastInterface(const FunctionCallbackInfo<Value>& args) { 401 UDPWrap* wrap; 402 ASSIGN_OR_RETURN_UNWRAP(&wrap, 403 args.Holder(), 404 args.GetReturnValue().Set(UV_EBADF)); 405 406 CHECK_EQ(args.Length(), 1); 407 CHECK(args[0]->IsString()); 408 409 Utf8Value iface(args.GetIsolate(), args[0]); 410 411 const char* iface_cstr = *iface; 412 413 int err = uv_udp_set_multicast_interface(&wrap->handle_, iface_cstr); 414 args.GetReturnValue().Set(err); 415} 416 417void UDPWrap::SetMembership(const FunctionCallbackInfo<Value>& args, 418 uv_membership membership) { 419 UDPWrap* wrap; 420 ASSIGN_OR_RETURN_UNWRAP(&wrap, 421 args.Holder(), 422 args.GetReturnValue().Set(UV_EBADF)); 423 424 CHECK_EQ(args.Length(), 2); 425 426 node::Utf8Value address(args.GetIsolate(), args[0]); 427 node::Utf8Value iface(args.GetIsolate(), args[1]); 428 429 const char* iface_cstr = *iface; 430 if (args[1]->IsUndefined() || args[1]->IsNull()) { 431 iface_cstr = nullptr; 432 } 433 434 int err = uv_udp_set_membership(&wrap->handle_, 435 *address, 436 iface_cstr, 437 membership); 438 args.GetReturnValue().Set(err); 439} 440 441 442void UDPWrap::AddMembership(const FunctionCallbackInfo<Value>& args) { 443 SetMembership(args, UV_JOIN_GROUP); 444} 445 446 447void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) { 448 SetMembership(args, UV_LEAVE_GROUP); 449} 450 451void UDPWrap::SetSourceMembership(const FunctionCallbackInfo<Value>& args, 452 uv_membership membership) { 453 UDPWrap* wrap; 454 ASSIGN_OR_RETURN_UNWRAP(&wrap, 455 args.Holder(), 456 args.GetReturnValue().Set(UV_EBADF)); 457 458 CHECK_EQ(args.Length(), 3); 459 460 node::Utf8Value source_address(args.GetIsolate(), args[0]); 461 node::Utf8Value group_address(args.GetIsolate(), args[1]); 462 node::Utf8Value iface(args.GetIsolate(), args[2]); 463 464 if (*iface == nullptr) return; 465 const char* iface_cstr = *iface; 466 if (args[2]->IsUndefined() || args[2]->IsNull()) { 467 iface_cstr = nullptr; 468 } 469 470 int err = uv_udp_set_source_membership(&wrap->handle_, 471 *group_address, 472 iface_cstr, 473 *source_address, 474 membership); 475 args.GetReturnValue().Set(err); 476} 477 478void UDPWrap::AddSourceSpecificMembership( 479 const FunctionCallbackInfo<Value>& args) { 480 SetSourceMembership(args, UV_JOIN_GROUP); 481} 482 483 484void UDPWrap::DropSourceSpecificMembership( 485 const FunctionCallbackInfo<Value>& args) { 486 SetSourceMembership(args, UV_LEAVE_GROUP); 487} 488 489 490void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) { 491 Environment* env = Environment::GetCurrent(args); 492 493 UDPWrap* wrap; 494 ASSIGN_OR_RETURN_UNWRAP(&wrap, 495 args.Holder(), 496 args.GetReturnValue().Set(UV_EBADF)); 497 498 CHECK(args.Length() == 4 || args.Length() == 6); 499 CHECK(args[0]->IsObject()); 500 CHECK(args[1]->IsArray()); 501 CHECK(args[2]->IsUint32()); 502 503 bool sendto = args.Length() == 6; 504 if (sendto) { 505 // send(req, list, list.length, port, address, hasCallback) 506 CHECK(args[3]->IsUint32()); 507 CHECK(args[4]->IsString()); 508 CHECK(args[5]->IsBoolean()); 509 } else { 510 // send(req, list, list.length, hasCallback) 511 CHECK(args[3]->IsBoolean()); 512 } 513 514 Local<Array> chunks = args[1].As<Array>(); 515 // it is faster to fetch the length of the 516 // array in js-land 517 size_t count = args[2].As<Uint32>()->Value(); 518 519 MaybeStackBuffer<uv_buf_t, 16> bufs(count); 520 521 // construct uv_buf_t array 522 for (size_t i = 0; i < count; i++) { 523 Local<Value> chunk; 524 if (!chunks->Get(env->context(), i).ToLocal(&chunk)) return; 525 526 size_t length = Buffer::Length(chunk); 527 528 bufs[i] = uv_buf_init(Buffer::Data(chunk), length); 529 } 530 531 int err = 0; 532 struct sockaddr_storage addr_storage; 533 sockaddr* addr = nullptr; 534 if (sendto) { 535 const unsigned short port = args[3].As<Uint32>()->Value(); 536 node::Utf8Value address(env->isolate(), args[4]); 537 err = sockaddr_for_family(family, address.out(), port, &addr_storage); 538 if (err == 0) 539 addr = reinterpret_cast<sockaddr*>(&addr_storage); 540 } 541 542 if (err == 0) { 543 wrap->current_send_req_wrap_ = args[0].As<Object>(); 544 wrap->current_send_has_callback_ = 545 sendto ? args[5]->IsTrue() : args[3]->IsTrue(); 546 547 err = static_cast<int>(wrap->Send(*bufs, count, addr)); 548 549 wrap->current_send_req_wrap_.Clear(); 550 wrap->current_send_has_callback_ = false; 551 } 552 553 args.GetReturnValue().Set(err); 554} 555 556ssize_t UDPWrap::Send(uv_buf_t* bufs_ptr, 557 size_t count, 558 const sockaddr* addr) { 559 if (IsHandleClosing()) return UV_EBADF; 560 561 size_t msg_size = 0; 562 for (size_t i = 0; i < count; i++) 563 msg_size += bufs_ptr[i].len; 564 565 int err = 0; 566 if (!UNLIKELY(env()->options()->test_udp_no_try_send)) { 567 err = uv_udp_try_send(&handle_, bufs_ptr, count, addr); 568 if (err == UV_ENOSYS || err == UV_EAGAIN) { 569 err = 0; 570 } else if (err >= 0) { 571 size_t sent = err; 572 while (count > 0 && bufs_ptr->len <= sent) { 573 sent -= bufs_ptr->len; 574 bufs_ptr++; 575 count--; 576 } 577 if (count > 0) { 578 CHECK_LT(sent, bufs_ptr->len); 579 bufs_ptr->base += sent; 580 bufs_ptr->len -= sent; 581 } else { 582 CHECK_EQ(static_cast<size_t>(err), msg_size); 583 // + 1 so that the JS side can distinguish 0-length async sends from 584 // 0-length sync sends. 585 return msg_size + 1; 586 } 587 } 588 } 589 590 if (err == 0) { 591 AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this); 592 ReqWrap<uv_udp_send_t>* req_wrap = listener()->CreateSendWrap(msg_size); 593 if (req_wrap == nullptr) return UV_ENOSYS; 594 595 err = req_wrap->Dispatch( 596 uv_udp_send, 597 &handle_, 598 bufs_ptr, 599 count, 600 addr, 601 uv_udp_send_cb{[](uv_udp_send_t* req, int status) { 602 UDPWrap* self = ContainerOf(&UDPWrap::handle_, req->handle); 603 self->listener()->OnSendDone( 604 ReqWrap<uv_udp_send_t>::from_req(req), status); 605 }}); 606 if (err) 607 delete req_wrap; 608 } 609 610 return err; 611} 612 613 614ReqWrap<uv_udp_send_t>* UDPWrap::CreateSendWrap(size_t msg_size) { 615 SendWrap* req_wrap = new SendWrap(env(), 616 current_send_req_wrap_, 617 current_send_has_callback_); 618 req_wrap->msg_size = msg_size; 619 return req_wrap; 620} 621 622 623void UDPWrap::Send(const FunctionCallbackInfo<Value>& args) { 624 DoSend(args, AF_INET); 625} 626 627 628void UDPWrap::Send6(const FunctionCallbackInfo<Value>& args) { 629 DoSend(args, AF_INET6); 630} 631 632 633AsyncWrap* UDPWrap::GetAsyncWrap() { 634 return this; 635} 636 637SocketAddress UDPWrap::GetPeerName() { 638 return SocketAddress::FromPeerName(handle_); 639} 640 641SocketAddress UDPWrap::GetSockName() { 642 return SocketAddress::FromSockName(handle_); 643} 644 645void UDPWrapBase::RecvStart(const FunctionCallbackInfo<Value>& args) { 646 UDPWrapBase* wrap = UDPWrapBase::FromObject(args.Holder()); 647 args.GetReturnValue().Set(wrap == nullptr ? UV_EBADF : wrap->RecvStart()); 648} 649 650int UDPWrap::RecvStart() { 651 if (IsHandleClosing()) return UV_EBADF; 652 int err = uv_udp_recv_start(&handle_, OnAlloc, OnRecv); 653 // UV_EALREADY means that the socket is already bound but that's okay 654 if (err == UV_EALREADY) 655 err = 0; 656 return err; 657} 658 659 660void UDPWrapBase::RecvStop(const FunctionCallbackInfo<Value>& args) { 661 UDPWrapBase* wrap = UDPWrapBase::FromObject(args.Holder()); 662 args.GetReturnValue().Set(wrap == nullptr ? UV_EBADF : wrap->RecvStop()); 663} 664 665int UDPWrap::RecvStop() { 666 if (IsHandleClosing()) return UV_EBADF; 667 return uv_udp_recv_stop(&handle_); 668} 669 670 671void UDPWrap::OnSendDone(ReqWrap<uv_udp_send_t>* req, int status) { 672 BaseObjectPtr<SendWrap> req_wrap{static_cast<SendWrap*>(req)}; 673 if (req_wrap->have_callback()) { 674 Environment* env = req_wrap->env(); 675 HandleScope handle_scope(env->isolate()); 676 Context::Scope context_scope(env->context()); 677 Local<Value> arg[] = { 678 Integer::New(env->isolate(), status), 679 Integer::New(env->isolate(), req_wrap->msg_size), 680 }; 681 req_wrap->MakeCallback(env->oncomplete_string(), 2, arg); 682 } 683} 684 685 686void UDPWrap::OnAlloc(uv_handle_t* handle, 687 size_t suggested_size, 688 uv_buf_t* buf) { 689 UDPWrap* wrap = ContainerOf(&UDPWrap::handle_, 690 reinterpret_cast<uv_udp_t*>(handle)); 691 *buf = wrap->listener()->OnAlloc(suggested_size); 692} 693 694uv_buf_t UDPWrap::OnAlloc(size_t suggested_size) { 695 return env()->allocate_managed_buffer(suggested_size); 696} 697 698void UDPWrap::OnRecv(uv_udp_t* handle, 699 ssize_t nread, 700 const uv_buf_t* buf, 701 const sockaddr* addr, 702 unsigned int flags) { 703 UDPWrap* wrap = ContainerOf(&UDPWrap::handle_, handle); 704 wrap->listener()->OnRecv(nread, *buf, addr, flags); 705} 706 707void UDPWrap::OnRecv(ssize_t nread, 708 const uv_buf_t& buf_, 709 const sockaddr* addr, 710 unsigned int flags) { 711 Environment* env = this->env(); 712 Isolate* isolate = env->isolate(); 713 std::unique_ptr<BackingStore> bs = env->release_managed_buffer(buf_); 714 if (nread == 0 && addr == nullptr) { 715 return; 716 } 717 718 HandleScope handle_scope(isolate); 719 Context::Scope context_scope(env->context()); 720 721 Local<Value> argv[] = { 722 Integer::New(isolate, static_cast<int32_t>(nread)), 723 object(), 724 Undefined(isolate), 725 Undefined(isolate)}; 726 727 if (nread < 0) { 728 MakeCallback(env->onmessage_string(), arraysize(argv), argv); 729 return; 730 } else if (nread == 0) { 731 bs = ArrayBuffer::NewBackingStore(isolate, 0); 732 } else { 733 CHECK_LE(static_cast<size_t>(nread), bs->ByteLength()); 734 bs = BackingStore::Reallocate(isolate, std::move(bs), nread); 735 } 736 737 Local<Object> address; 738 { 739 bool has_caught = false; 740 { 741 TryCatchScope try_catch(env); 742 if (!AddressToJS(env, addr).ToLocal(&address)) { 743 DCHECK(try_catch.HasCaught() && !try_catch.HasTerminated()); 744 argv[2] = try_catch.Exception(); 745 DCHECK(!argv[2].IsEmpty()); 746 has_caught = true; 747 } 748 } 749 if (has_caught) { 750 DCHECK(!argv[2].IsEmpty()); 751 MakeCallback(env->onerror_string(), arraysize(argv), argv); 752 return; 753 } 754 } 755 756 Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, std::move(bs)); 757 { 758 bool has_caught = false; 759 { 760 TryCatchScope try_catch(env); 761 if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&argv[2])) { 762 DCHECK(try_catch.HasCaught() && !try_catch.HasTerminated()); 763 argv[2] = try_catch.Exception(); 764 DCHECK(!argv[2].IsEmpty()); 765 has_caught = true; 766 } 767 } 768 if (has_caught) { 769 DCHECK(!argv[2].IsEmpty()); 770 MakeCallback(env->onerror_string(), arraysize(argv), argv); 771 return; 772 } 773 } 774 775 argv[3] = address; 776 MakeCallback(env->onmessage_string(), arraysize(argv), argv); 777} 778 779MaybeLocal<Object> UDPWrap::Instantiate(Environment* env, 780 AsyncWrap* parent, 781 UDPWrap::SocketType type) { 782 AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent); 783 784 // If this assert fires then Initialize hasn't been called yet. 785 CHECK_EQ(env->udp_constructor_function().IsEmpty(), false); 786 return env->udp_constructor_function()->NewInstance(env->context()); 787} 788 789void UDPWrap::GetSendQueueSize(const FunctionCallbackInfo<Value>& args) { 790 UDPWrap* wrap; 791 ASSIGN_OR_RETURN_UNWRAP( 792 &wrap, args.Holder(), args.GetReturnValue().Set(UV_EBADF)); 793 794 size_t size = uv_udp_get_send_queue_size(&wrap->handle_); 795 args.GetReturnValue().Set(static_cast<double>(size)); 796} 797 798void UDPWrap::GetSendQueueCount(const FunctionCallbackInfo<Value>& args) { 799 UDPWrap* wrap; 800 ASSIGN_OR_RETURN_UNWRAP( 801 &wrap, args.Holder(), args.GetReturnValue().Set(UV_EBADF)); 802 803 size_t count = uv_udp_get_send_queue_count(&wrap->handle_); 804 args.GetReturnValue().Set(static_cast<double>(count)); 805} 806 807} // namespace node 808 809NODE_BINDING_CONTEXT_AWARE_INTERNAL(udp_wrap, node::UDPWrap::Initialize) 810