@@ -142,20 +142,35 @@ void UDPWrapBase::RegisterExternalReferences(
142142 registry->Register (RecvStop);
143143}
144144
145- UDPWrap::UDPWrap (Environment* env, Local<Object> object)
145+ UDPWrap::UDPWrap (Environment* env, Local<Object> object, uint32_t msg_count )
146146 : HandleWrap(env,
147147 object,
148148 reinterpret_cast <uv_handle_t *>(&handle_),
149149 AsyncWrap::PROVIDER_UDPWRAP) {
150150 object->SetAlignedPointerInInternalField (
151151 UDPWrapBase::kUDPWrapBaseField , static_cast <UDPWrapBase*>(this ));
152-
153- int r = uv_udp_init (env->event_loop (), &handle_);
152+ int r;
153+ if (msg_count > 0 ) {
154+ r = uv_udp_init_ex (env->event_loop (),
155+ &handle_,
156+ AF_UNSPEC | UV_UDP_RECVMMSG);
157+ } else {
158+ r = uv_udp_init (env->event_loop (), &handle_);
159+ }
154160 CHECK_EQ (r, 0 ); // can't fail anyway
155-
161+ msg_count_ = msg_count;
162+ mmsg_buf_ = uv_buf_init (nullptr , 0 );
156163 set_listener (this );
157164}
158165
166+ UDPWrap::~UDPWrap () {
167+ // Libuv does not release the memory of memory which allocated
168+ // by handle->alloc_cb when we call close in handle->read_cb,
169+ // so we should release the memory here if necessary.
170+ if (using_recvmmsg ()) {
171+ release_buf ();
172+ }
173+ }
159174
160175void UDPWrap::Initialize (Local<Object> target,
161176 Local<Value> unused,
@@ -270,8 +285,12 @@ void UDPWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
270285
271286void UDPWrap::New (const FunctionCallbackInfo<Value>& args) {
272287 CHECK (args.IsConstructCall ());
288+ uint32_t msg_count = 0 ;
289+ if (args[0 ]->IsUint32 ()) {
290+ msg_count = args[0 ].As <Uint32>()->Value ();
291+ }
273292 Environment* env = Environment::GetCurrent (args);
274- new UDPWrap (env, args.This ());
293+ new UDPWrap (env, args.This (), msg_count );
275294}
276295
277296
@@ -741,6 +760,12 @@ void UDPWrap::OnAlloc(uv_handle_t* handle,
741760}
742761
743762uv_buf_t UDPWrap::OnAlloc (size_t suggested_size) {
763+ if (using_recvmmsg ()) {
764+ suggested_size *= msg_count_;
765+ mmsg_buf_ = uv_buf_init (reinterpret_cast <char *>(malloc (suggested_size)),
766+ suggested_size);
767+ return mmsg_buf_;
768+ }
744769 return env ()->allocate_managed_buffer (suggested_size);
745770}
746771
@@ -759,7 +784,17 @@ void UDPWrap::OnRecv(ssize_t nread,
759784 unsigned int flags) {
760785 Environment* env = this ->env ();
761786 Isolate* isolate = env->isolate ();
762- std::unique_ptr<BackingStore> bs = env->release_managed_buffer (buf_);
787+ std::unique_ptr<BackingStore> bs;
788+
789+ auto cleanup = OnScopeLeave ([&]() {
790+ if (using_recvmmsg () && (nread <= 0 || (flags & UV_UDP_MMSG_FREE))) {
791+ release_buf ();
792+ }
793+ });
794+
795+ if (!using_recvmmsg ()) {
796+ bs = env->release_managed_buffer (buf_);
797+ }
763798 if (nread == 0 && addr == nullptr ) {
764799 return ;
765800 }
@@ -778,6 +813,10 @@ void UDPWrap::OnRecv(ssize_t nread,
778813 return ;
779814 } else if (nread == 0 ) {
780815 bs = ArrayBuffer::NewBackingStore (isolate, 0 );
816+ } else if (using_recvmmsg ()) {
817+ bs = ArrayBuffer::NewBackingStore (
818+ isolate, nread, BackingStoreInitializationMode::kUninitialized );
819+ memcpy (bs->Data (), buf_.base , nread);
781820 } else if (static_cast <size_t >(nread) != bs->ByteLength ()) {
782821 CHECK_LE (static_cast <size_t >(nread), bs->ByteLength ());
783822 std::unique_ptr<BackingStore> old_bs = std::move (bs);
0 commit comments