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