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