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