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

Commit a684292

Browse files
committed
quic: use UDP code from dgram
This simplifies the code quite a bit.
1 parent 641b7ed commit a684292

9 files changed

+291
-674
lines changed

lib/internal/quic/core.js

+56-74
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ const {
3838
owner_symbol,
3939
},
4040
} = require('internal/async_hooks');
41+
const dgram = require('dgram');
42+
const internalDgram = require('internal/dgram');
43+
44+
const {
45+
constants: {
46+
UV_UDP_IPV6ONLY,
47+
UV_UDP_REUSEADDR,
48+
}
49+
} = internalBinding('udp_wrap');
4150

4251
const {
4352
writeGeneric,
@@ -59,7 +68,6 @@ const {
5968
const {
6069
codes: {
6170
ERR_INVALID_ARG_TYPE,
62-
ERR_INVALID_ARG_VALUE,
6371
ERR_INVALID_CALLBACK,
6472
ERR_OUT_OF_RANGE,
6573
ERR_QUIC_ERROR,
@@ -90,8 +98,6 @@ const {
9098
constants: {
9199
AF_INET,
92100
AF_INET6,
93-
UV_UDP_IPV6ONLY,
94-
UV_UDP_REUSEADDR,
95101
NGTCP2_ALPN_H3,
96102
NGTCP2_MAX_CIDLEN,
97103
NGTCP2_MIN_CIDLEN,
@@ -221,11 +227,6 @@ function setTransportParams(config) {
221227
sessionConfig[IDX_QUIC_SESSION_CONFIG_COUNT] = flags;
222228
}
223229

224-
// Called when the socket has been bound and is ready for use
225-
function onSocketReady(fd) {
226-
this[owner_symbol][kReady](fd);
227-
}
228-
229230
// Called when the socket is closed
230231
function onSocketClose() {
231232
this[owner_symbol].destroy();
@@ -436,7 +437,6 @@ function onSessionSilentClose(statelessReset, code, family) {
436437

437438
// Register the callbacks with the QUIC internal binding.
438439
setCallbacks({
439-
onSocketReady,
440440
onSocketClose,
441441
onSocketError,
442442
onSocketServerBusy,
@@ -620,6 +620,8 @@ class QuicSocket extends EventEmitter {
620620
#type = undefined;
621621
#alpn = undefined;
622622
#stats = undefined;
623+
#udpSocket = undefined;
624+
#udpHandle = undefined;
623625

624626
constructor(options = {}) {
625627
const {
@@ -667,11 +669,17 @@ class QuicSocket extends EventEmitter {
667669
const socketOptions =
668670
(validateAddress ? QUICSOCKET_OPTIONS_VALIDATE_ADDRESS : 0) |
669671
(validateAddressLRU ? QUICSOCKET_OPTIONS_VALIDATE_ADDRESS_LRU : 0);
672+
this.#udpSocket = dgram.createSocket(type === AF_INET6 ? 'udp6' : 'udp4');
673+
// TODO(addaleax): Ideally, we would not be needing to store the handle
674+
// separately, and only pass it to the QuicSocketHandle constructor.
675+
this.#udpHandle = this.#udpSocket[internalDgram.kStateSymbol].handle;
670676
const handle =
671677
new QuicSocketHandle(
678+
this.#udpHandle,
672679
socketOptions,
673680
retryTokenTimeout,
674681
maxConnectionsPerHost);
682+
this.#udpHandle.quicSocket = handle;
675683
handle[owner_symbol] = this;
676684
this[async_id_symbol] = handle.getAsyncId();
677685
this[kSetHandle](handle);
@@ -728,14 +736,16 @@ class QuicSocket extends EventEmitter {
728736
const flags =
729737
(this.#reuseAddr ? UV_UDP_REUSEADDR : 0) ||
730738
(this.#ipv6Only ? UV_UDP_IPV6ONLY : 0);
731-
const ret = this[kHandle].bind(this.#type, ip, this.#port || 0, flags);
739+
const ret = this.#udpHandle.bind(ip, this.#port || 0, flags);
732740
if (ret) {
733741
this.destroy(exceptionWithHostPort(ret, 'bind', ip, this.#port || 0));
734742
return;
735743
}
736744

737745
if (typeof callback === 'function')
738746
callback();
747+
748+
this[kReady](this.#udpHandle.fd);
739749
}
740750

741751
// The kReady function is called after the socket has been bound to the
@@ -913,20 +923,23 @@ class QuicSocket extends EventEmitter {
913923
if (handle !== undefined) {
914924
this[kSetHandle]();
915925
handle[owner_symbol] = undefined;
916-
handle.close((err) => {
917-
// If an error occurs while attempting to close, it will take
918-
// precedence over any original error specified on the args
919-
// TODO(@jasnell): Alternatively we might set the original
920-
// error as a property on the new error.
921-
if (err) error = err;
922-
923-
// Capture a copy of the stats as they will no longer be
924-
// available once this function returns.
925-
this.#stats = new BigInt64Array(handle.stats);
926-
927-
if (error) process.nextTick(emit.bind(this, 'error', error));
928-
process.nextTick(emit.bind(this, 'close'));
929-
});
926+
handle.ondone = () => {
927+
this.#udpSocket.close((err) => {
928+
// If an error occurs while attempting to close, it will take
929+
// precedence over any original error specified on the args
930+
// TODO(@jasnell): Alternatively we might set the original
931+
// error as a property on the new error.
932+
if (err) error = err;
933+
934+
// Capture a copy of the stats as they will no longer be
935+
// available once this function returns.
936+
this.#stats = new BigInt64Array(handle.stats);
937+
938+
if (error) process.nextTick(emit.bind(this, 'error', error));
939+
process.nextTick(emit.bind(this, 'close'));
940+
});
941+
};
942+
handle.waitForPendingCallbacks();
930943
}
931944
}
932945

@@ -1064,14 +1077,14 @@ class QuicSocket extends EventEmitter {
10641077
ref() {
10651078
if (this.#state === kSocketDestroyed)
10661079
throw new ERR_QUICSOCKET_DESTROYED('ref');
1067-
this[kHandle].ref();
1080+
this.#udpSocket.ref();
10681081
return this;
10691082
}
10701083

10711084
unref() {
10721085
if (this.#state === kSocketDestroyed)
10731086
throw new ERR_QUICSOCKET_DESTROYED('unref');
1074-
this[kHandle].unref();
1087+
this.#udpSocket.unref();
10751088
return this;
10761089
}
10771090

@@ -1082,11 +1095,16 @@ class QuicSocket extends EventEmitter {
10821095
get address() {
10831096
const out = {};
10841097
if (this.#state !== kSocketDestroyed) {
1085-
const err = this[kHandle].getsockname(out);
1086-
// If err is returned, socket is not bound.
1087-
// Return empty object
1088-
if (err)
1089-
return {};
1098+
try {
1099+
return this.#udpSocket.address();
1100+
} catch (err) {
1101+
if (err.code === 'EBADF') {
1102+
// If there is an EBADF error, the socket is not bound.
1103+
// Return empty object
1104+
return {};
1105+
}
1106+
throw err;
1107+
}
10901108
}
10911109
return out;
10921110
}
@@ -1114,85 +1132,49 @@ class QuicSocket extends EventEmitter {
11141132
setTTL(ttl) {
11151133
if (this.#state === kSocketDestroyed)
11161134
throw new ERR_QUICSOCKET_DESTROYED('setTTL');
1117-
if (typeof ttl !== 'number')
1118-
throw new ERR_INVALID_ARG_TYPE('ttl', 'number', ttl);
1119-
if (ttl < 1 || ttl > 255)
1120-
throw new ERR_INVALID_ARG_VALUE('ttl', ttl);
1121-
const err = this[kHandle].setTTL(ttl);
1122-
if (err)
1123-
throw errnoException(err, 'dropMembership');
1135+
this.#udpSocket.setTTL(ttl);
11241136
return this;
11251137
}
11261138

11271139
setMulticastTTL(ttl) {
11281140
if (this.#state === kSocketDestroyed)
11291141
throw new ERR_QUICSOCKET_DESTROYED('setMulticastTTL');
1130-
if (typeof ttl !== 'number')
1131-
throw new ERR_INVALID_ARG_TYPE('ttl', 'number', ttl);
1132-
if (ttl < 1 || ttl > 255)
1133-
throw new ERR_INVALID_ARG_VALUE('ttl', ttl);
1134-
const err = this[kHandle].setMulticastTTL(ttl);
1135-
if (err)
1136-
throw errnoException(err, 'dropMembership');
1142+
this.#udpSocket.setMulticastTTL(ttl);
11371143
return this;
11381144
}
11391145

11401146
setBroadcast(on = true) {
11411147
if (this.#state === kSocketDestroyed)
11421148
throw new ERR_QUICSOCKET_DESTROYED('setBroadcast');
1143-
if (typeof on !== 'boolean')
1144-
throw new ERR_INVALID_ARG_TYPE('on', 'boolean', on);
1145-
const err = this[kHandle].setBroadcast(on);
1146-
if (err)
1147-
throw errnoException(err, 'dropMembership');
1149+
this.#udpSocket.setBroadcast(on);
11481150
return this;
11491151
}
11501152

11511153
setMulticastLoopback(on = true) {
11521154
if (this.#state === kSocketDestroyed)
11531155
throw new ERR_QUICSOCKET_DESTROYED('setMulticastLoopback');
1154-
if (typeof on !== 'boolean')
1155-
throw new ERR_INVALID_ARG_TYPE('on', 'boolean', on);
1156-
const err = this[kHandle].setMulticastLoopback(on);
1157-
if (err)
1158-
throw errnoException(err, 'dropMembership');
1156+
this.#udpSocket.setMulticastLoopback(on);
11591157
return this;
11601158
}
11611159

11621160
setMulticastInterface(iface) {
11631161
if (this.#state === kSocketDestroyed)
11641162
throw new ERR_QUICSOCKET_DESTROYED('setMulticastInterface');
1165-
if (typeof iface !== 'string')
1166-
throw new ERR_INVALID_ARG_TYPE('iface', 'string', iface);
1167-
const err = this[kHandle].setMulticastInterface(iface);
1168-
if (err)
1169-
throw errnoException(err, 'dropMembership');
1163+
this.#udpSocket.setMulticastInterface(iface);
11701164
return this;
11711165
}
11721166

11731167
addMembership(address, iface) {
11741168
if (this.#state === kSocketDestroyed)
11751169
throw new ERR_QUICSOCKET_DESTROYED('addMembership');
1176-
if (typeof address !== 'string')
1177-
throw new ERR_INVALID_ARG_TYPE('address', 'string', address);
1178-
if (typeof iface !== 'string')
1179-
throw new ERR_INVALID_ARG_TYPE('iface', 'string', iface);
1180-
const err = this[kHandle].addMembership(address, iface);
1181-
if (err)
1182-
throw errnoException(err, 'addMembership');
1170+
this.#udpSocket.addMembership(address, iface);
11831171
return this;
11841172
}
11851173

11861174
dropMembership(address, iface) {
11871175
if (this.#state === kSocketDestroyed)
11881176
throw new ERR_QUICSOCKET_DESTROYED('dropMembership');
1189-
if (typeof address !== 'string')
1190-
throw new ERR_INVALID_ARG_TYPE('address', 'string', address);
1191-
if (typeof iface !== 'string')
1192-
throw new ERR_INVALID_ARG_TYPE('iface', 'string', iface);
1193-
const err = this[kHandle].dropMembership(address, iface);
1194-
if (err)
1195-
throw errnoException(err, 'dropMembership');
1177+
this.#udpSocket.dropMembership(address, iface);
11961178
return this;
11971179
}
11981180

src/async_wrap.h

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ namespace node {
5959
V(QUERYWRAP) \
6060
V(QUICCLIENTSESSION) \
6161
V(QUICSERVERSESSION) \
62+
V(QUICSENDWRAP) \
6263
V(QUICSOCKET) \
6364
V(QUICSTREAM) \
6465
V(SHUTDOWNWRAP) \

src/env.h

-1
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,6 @@ constexpr size_t kFsStatsBufferLength =
427427
# define QUIC_ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) \
428428
V(quic_on_socket_close_function, v8::Function) \
429429
V(quic_on_socket_error_function, v8::Function) \
430-
V(quic_on_socket_ready_function, v8::Function) \
431430
V(quic_on_socket_server_busy_function, v8::Function) \
432431
V(quic_on_session_cert_function, v8::Function) \
433432
V(quic_on_session_client_hello_function, v8::Function) \

src/node_quic.cc

-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ void QuicSetCallbacks(const FunctionCallbackInfo<Value>& args) {
4747
env->set_quic_on_##callback##_function(fn.As<Function>()); \
4848
} while (0)
4949

50-
SETFUNCTION("onSocketReady", socket_ready);
5150
SETFUNCTION("onSocketClose", socket_close);
5251
SETFUNCTION("onSocketError", socket_error);
5352
SETFUNCTION("onSessionReady", session_ready);
@@ -164,8 +163,6 @@ void Initialize(Local<Object> target,
164163
NODE_DEFINE_CONSTANT(constants, SSL_OP_SINGLE_ECDH_USE);
165164
NODE_DEFINE_CONSTANT(constants, TLS1_3_VERSION);
166165
NODE_DEFINE_CONSTANT(constants, UV_EBADF);
167-
NODE_DEFINE_CONSTANT(constants, UV_UDP_IPV6ONLY);
168-
NODE_DEFINE_CONSTANT(constants, UV_UDP_REUSEADDR);
169166

170167
NODE_DEFINE_CONSTANT(constants, IDX_QUIC_SESSION_ACTIVE_CONNECTION_ID_LIMIT);
171168
NODE_DEFINE_CONSTANT(constants, IDX_QUIC_SESSION_MAX_STREAM_DATA_BIDI_LOCAL);

0 commit comments

Comments
 (0)