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