Skip to content
This repository was archived by the owner on Aug 11, 2020. It is now read-only.

Commit 70aa77d

Browse files
committed
[WIP] Testing QUIC without real UDP handle
1 parent 7830b8c commit 70aa77d

File tree

6 files changed

+239
-1
lines changed

6 files changed

+239
-1
lines changed

lib/internal/quic/core.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ const kSetSocket = Symbol('kSetSocket');
178178
const kStreamClose = Symbol('kStreamClose');
179179
const kStreamReset = Symbol('kStreamReset');
180180
const kTrackWriteState = Symbol('kTrackWriteState');
181+
const kUDPHandleForTesting = Symbol('kUDPHandleForTesting');
181182
const kVersionNegotiation = Symbol('kVersionNegotiation');
182183
const kWriteGeneric = Symbol('kWriteGeneric');
183184

@@ -677,6 +678,11 @@ class QuicSocket extends EventEmitter {
677678
(validateAddress ? QUICSOCKET_OPTIONS_VALIDATE_ADDRESS : 0) |
678679
(validateAddressLRU ? QUICSOCKET_OPTIONS_VALIDATE_ADDRESS_LRU : 0);
679680
this.#udpSocket = dgram.createSocket(type === AF_INET6 ? 'udp6' : 'udp4');
681+
if (typeof options[kUDPHandleForTesting] === 'object') {
682+
this.#udpSocket.bind(options[kUDPHandleForTesting]);
683+
this.#state = kSocketBound;
684+
process.nextTick(() => this[kReady](undefined));
685+
}
680686
const udpHandle = this.#udpSocket[internalDgram.kStateSymbol].handle;
681687
const handle =
682688
new QuicSocketHandle(
@@ -2384,7 +2390,8 @@ function createSocket(options = {}) {
23842390
}
23852391

23862392
module.exports = {
2387-
createSocket
2393+
createSocket,
2394+
kUDPHandleForTesting
23882395
};
23892396

23902397
/* eslint-enable no-use-before-define */

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@
524524
'src/js_native_api_v8.h',
525525
'src/js_native_api_v8_internals.h',
526526
'src/js_stream.cc',
527+
'src/js_udp_wrap.cc',
527528
'src/module_wrap.cc',
528529
'src/node.cc',
529530
'src/node_api.cc',

src/async_wrap.h

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ namespace node {
5151
V(HTTPINCOMINGMESSAGE) \
5252
V(HTTPCLIENTREQUEST) \
5353
V(JSSTREAM) \
54+
V(JSUDPWRAP) \
5455
V(MESSAGEPORT) \
5556
V(PIPECONNECTWRAP) \
5657
V(PIPESERVERWRAP) \

src/js_udp_wrap.cc

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#include "udp_wrap.h"
2+
#include "async_wrap-inl.h"
3+
#include "node_errors.h"
4+
5+
namespace node {
6+
7+
using errors::TryCatchScope;
8+
using v8::Array;
9+
using v8::Context;
10+
using v8::FunctionCallbackInfo;
11+
using v8::FunctionTemplate;
12+
using v8::HandleScope;
13+
using v8::Int32;
14+
using v8::Local;
15+
using v8::Object;
16+
using v8::String;
17+
using v8::Value;
18+
19+
class JSUDPWrap final : public UDPWrapBase, public AsyncWrap {
20+
public:
21+
JSUDPWrap(Environment* env, Local<Object> obj);
22+
23+
int RecvStart() override;
24+
int RecvStop() override;
25+
ssize_t Send(uv_buf_t* bufs,
26+
size_t nbufs,
27+
const sockaddr* addr) override;
28+
int GetPeerName(sockaddr* name, int* namelen) override;
29+
int GetSockName(sockaddr* name, int* namelen) override;
30+
int GetSockaddr(sockaddr* name, int* namelen, bool peer);
31+
AsyncWrap* GetAsyncWrap() override { return this; }
32+
33+
static void New(const FunctionCallbackInfo<Value>& args);
34+
static void EmitReceived(const FunctionCallbackInfo<Value>& args);
35+
static void OnSendDone(const FunctionCallbackInfo<Value>& args);
36+
static void OnAfterBind(const FunctionCallbackInfo<Value>& args);
37+
38+
static void Initialize(Local<Object> target,
39+
Local<Value> unused,
40+
Local<Context> context,
41+
void* priv);
42+
SET_NO_MEMORY_INFO()
43+
SET_MEMORY_INFO_NAME(JSUDPWrap)
44+
SET_SELF_SIZE(JSUDPWrap)
45+
};
46+
47+
JSUDPWrap::JSUDPWrap(Environment* env, Local<Object> obj)
48+
: AsyncWrap(env, obj, PROVIDER_JSUDPWRAP) {
49+
MakeWeak();
50+
51+
obj->SetAlignedPointerInInternalField(
52+
kUDPWrapBaseField, static_cast<UDPWrapBase*>(this));
53+
}
54+
55+
int JSUDPWrap::RecvStart() {
56+
HandleScope scope(env()->isolate());
57+
Context::Scope context_scope(env()->context());
58+
TryCatchScope try_catch(env());
59+
Local<Value> value;
60+
int32_t value_int = UV_EPROTO;
61+
if (!MakeCallback(env()->onreadstart_string(), 0, nullptr).ToLocal(&value) ||
62+
!value->Int32Value(env()->context()).To(&value_int)) {
63+
if (try_catch.HasCaught() && !try_catch.HasTerminated())
64+
errors::TriggerUncaughtException(env()->isolate(), try_catch);
65+
}
66+
return value_int;
67+
}
68+
69+
int JSUDPWrap::RecvStop() {
70+
HandleScope scope(env()->isolate());
71+
Context::Scope context_scope(env()->context());
72+
TryCatchScope try_catch(env());
73+
Local<Value> value;
74+
int32_t value_int = UV_EPROTO;
75+
if (!MakeCallback(env()->onreadstop_string(), 0, nullptr).ToLocal(&value) ||
76+
!value->Int32Value(env()->context()).To(&value_int)) {
77+
if (try_catch.HasCaught() && !try_catch.HasTerminated())
78+
errors::TriggerUncaughtException(env()->isolate(), try_catch);
79+
}
80+
return value_int;
81+
}
82+
83+
ssize_t JSUDPWrap::Send(uv_buf_t* bufs,
84+
size_t nbufs,
85+
const sockaddr* addr) {
86+
HandleScope scope(env()->isolate());
87+
Context::Scope context_scope(env()->context());
88+
TryCatchScope try_catch(env());
89+
Local<Value> value;
90+
int64_t value_int = UV_EPROTO;
91+
size_t total_len = 0;
92+
93+
MaybeStackBuffer<Local<Value>, 16> buffers(nbufs);
94+
for (size_t i = 0; i < nbufs; i++) {
95+
buffers[i] = Buffer::Copy(env(), bufs[i].base, bufs[i].len)
96+
.ToLocalChecked();
97+
total_len += bufs[i].len;
98+
}
99+
100+
Local<Value> args[] = {
101+
listener()->CreateSendWrap(total_len)->object(),
102+
Array::New(env()->isolate(), buffers.out(), nbufs),
103+
AddressToJS(env(), addr)
104+
};
105+
106+
if (!MakeCallback(env()->onwrite_string(), arraysize(args), args)
107+
.ToLocal(&value) ||
108+
!value->IntegerValue(env()->context()).To(&value_int)) {
109+
if (try_catch.HasCaught() && !try_catch.HasTerminated())
110+
errors::TriggerUncaughtException(env()->isolate(), try_catch);
111+
}
112+
return value_int;
113+
}
114+
115+
int JSUDPWrap::GetPeerName(sockaddr* name, int* namelen) {
116+
return GetSockaddr(name, namelen, true);
117+
}
118+
119+
int JSUDPWrap::GetSockName(sockaddr* name, int* namelen) {
120+
return GetSockaddr(name, namelen, false);
121+
}
122+
123+
int JSUDPWrap::GetSockaddr(sockaddr* name, int* namelen, bool peer) {
124+
// TODO(addaleax): Maybe turn this into a real JS-based method.
125+
sockaddr_in addr_in;
126+
CHECK_EQ(uv_ip4_addr("127.0.0.1", 1337, &addr_in), 0);
127+
memcpy(name, &addr_in,
128+
std::min(static_cast<size_t>(*namelen), sizeof(addr_in)));
129+
*namelen = sizeof(addr_in);
130+
return 0;
131+
}
132+
133+
void JSUDPWrap::New(const FunctionCallbackInfo<Value>& args) {
134+
Environment* env = Environment::GetCurrent(args);
135+
CHECK(args.IsConstructCall());
136+
new JSUDPWrap(env, args.Holder());
137+
}
138+
139+
void JSUDPWrap::EmitReceived(const FunctionCallbackInfo<Value>& args) {
140+
JSUDPWrap* wrap;
141+
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
142+
Environment* env = wrap->env();
143+
144+
ArrayBufferViewContents<char> buffer(args[0]);
145+
const char* data = buffer.data();
146+
int len = buffer.length();
147+
148+
CHECK(args[1]->IsInt32()); // family
149+
CHECK(args[2]->IsString()); // address
150+
CHECK(args[3]->IsInt32()); // port
151+
CHECK(args[4]->IsInt32()); // flags
152+
int family = args[1].As<Int32>()->Value() == 4 ? AF_INET : AF_INET6;
153+
Utf8Value address(env->isolate(), args[2]);
154+
int port = args[3].As<Int32>()->Value();
155+
int flags = args[3].As<Int32>()->Value();
156+
157+
sockaddr_storage addr;
158+
CHECK_EQ(sockaddr_for_family(family, *address, port, &addr), 0);
159+
160+
// Repeatedly ask the stream's owner for memory, copy the data that we
161+
// just read from JS into those buffers and emit them as reads.
162+
while (len != 0) {
163+
uv_buf_t buf = wrap->listener()->OnAlloc(len);
164+
ssize_t avail = len;
165+
if (static_cast<ssize_t>(buf.len) < avail)
166+
avail = buf.len;
167+
168+
memcpy(buf.base, data, avail);
169+
data += avail;
170+
len -= avail;
171+
wrap->listener()->OnRecv(
172+
avail, buf, reinterpret_cast<sockaddr*>(&addr), flags);
173+
}
174+
}
175+
176+
void JSUDPWrap::OnSendDone(const FunctionCallbackInfo<Value>& args) {
177+
JSUDPWrap* wrap;
178+
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
179+
180+
CHECK(args[0]->IsObject());
181+
CHECK(args[1]->IsInt32());
182+
ReqWrap<uv_udp_send_t>* req_wrap;
183+
ASSIGN_OR_RETURN_UNWRAP(&wrap, args[0].As<Object>());
184+
int status = args[1].As<Int32>()->Value();
185+
186+
wrap->listener()->OnSendDone(req_wrap, status);
187+
}
188+
189+
void JSUDPWrap::OnAfterBind(const FunctionCallbackInfo<Value>& args) {
190+
JSUDPWrap* wrap;
191+
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
192+
193+
wrap->listener()->OnAfterBind();
194+
}
195+
196+
void JSUDPWrap::Initialize(Local<Object> target,
197+
Local<Value> unused,
198+
Local<Context> context,
199+
void* priv) {
200+
Environment* env = Environment::GetCurrent(context);
201+
202+
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
203+
Local<String> js_udp_wrap_string =
204+
FIXED_ONE_BYTE_STRING(env->isolate(), "JSUDPWrap");
205+
t->SetClassName(js_udp_wrap_string);
206+
t->InstanceTemplate()
207+
->SetInternalFieldCount(UDPWrapBase::kUDPWrapBaseField + 1);
208+
t->Inherit(AsyncWrap::GetConstructorTemplate(env));
209+
210+
UDPWrapBase::AddMethods(env, t);
211+
env->SetProtoMethod(t, "emitReceived", EmitReceived);
212+
env->SetProtoMethod(t, "onSendDone", OnSendDone);
213+
env->SetProtoMethod(t, "onAfterBind", OnAfterBind);
214+
215+
target->Set(env->context(),
216+
js_udp_wrap_string,
217+
t->GetFunction(context).ToLocalChecked()).Check();
218+
}
219+
220+
221+
} // namespace node
222+
223+
NODE_MODULE_CONTEXT_AWARE_INTERNAL(js_udp_wrap, node::JSUDPWrap::Initialize)

src/node_binding.cc

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
V(http_parser) \
6565
V(inspector) \
6666
V(js_stream) \
67+
V(js_udp_wrap) \
6768
V(messaging) \
6869
V(module_wrap) \
6970
V(native_module) \

src/udp_wrap.h

+5
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ class UDPWrap final : public HandleWrap,
205205
v8::Local<v8::Object> current_send_req_wrap_;
206206
};
207207

208+
int sockaddr_for_family(int address_family,
209+
const char* address,
210+
const unsigned short port,
211+
sockaddr_storage* addr);
212+
208213
} // namespace node
209214

210215
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

0 commit comments

Comments
 (0)