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