Skip to content

Commit aafdc2f

Browse files
committed
quic: replace ipv6Only option with 'udp6-only' type
Since the `ipv6Only` option was mutually exclusive with using `'udp6'`, making it it's own type simplifies things a bit. PR-URL: #34283 Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent 48404a1 commit aafdc2f

File tree

6 files changed

+42
-104
lines changed

6 files changed

+42
-104
lines changed

doc/api/quic.md

+6-16
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,9 @@ added: REPLACEME
260260
IPv6 address or a host name. If a host name is given, it will be resolved
261261
to an IP address.
262262
* `port` {number} The local port to bind to.
263-
* `type` {string} Either `'udp4'` or `'upd6'` to use either IPv4 or IPv6,
264-
respectively. **Default**: `'udp4'`.
265-
* `ipv6Only` {boolean} If `type` is `'udp6'`, then setting `ipv6Only` to
266-
`true` will disable dual-stack support on the UDP binding -- that is,
267-
binding to address `'::'` will not make `'0.0.0.0'` be bound. The option
268-
is ignored if `type` is `'udp4'`. **Default**: `false`.
263+
* `type` {string} Can be one of `'udp4'`, `'upd6'`, or `'udp6-only'` to
264+
use IPv4, IPv6, or IPv6 with dual-stack mode disabled.
265+
**Default**: `'udp4'`.
269266
* `lookup` {Function} A custom DNS lookup function. Default `dns.lookup()`.
270267
* `maxConnections` {number} The maximum number of total active inbound
271268
connections.
@@ -1450,12 +1447,9 @@ added: REPLACEME
14501447
IPv6 address or a host name. If a host name is given, it will be resolved
14511448
to an IP address.
14521449
* `port` {number} The local port to bind to.
1453-
* `type` {string} Either `'udp4'` or `'upd6'` to use either IPv4 or IPv6,
1454-
respectively. **Default**: `'udp4'`.
1455-
* `ipv6Only` {boolean} If `type` is `'udp6'`, then setting `ipv6Only` to
1456-
`true` will disable dual-stack support on the UDP binding -- that is,
1457-
binding to address `'::'` will not make `'0.0.0.0'` be bound. The option
1458-
is ignored if `type` is `'udp4'`. **Default**: `false`.
1450+
* `type` {string} Can be one of `'udp4'`, `'upd6'`, or `'udp6-only'` to
1451+
use IPv4, IPv6, or IPv6 with dual-stack mode disabled.
1452+
**Default**: `'udp4'`.
14591453
* Returns: {QuicEndpoint}
14601454

14611455
Creates and adds a new `QuicEndpoint` to the `QuicSocket` instance.
@@ -1600,10 +1594,6 @@ added: REPLACEME
16001594
`SSL_OP_CIPHER_SERVER_PREFERENCE` to be set in `secureOptions`, see
16011595
[OpenSSL Options][] for more information.
16021596
* `idleTimeout` {number}
1603-
* `ipv6Only` {boolean} If `type` is `'udp6'`, then setting `ipv6Only` to
1604-
`true` will disable dual-stack support on the UDP binding -- that is,
1605-
binding to address `'::'` will not make `'0.0.0.0'` be bound. The option
1606-
is ignored if `type` is `'udp4'`. **Default**: `false`.
16071597
* `key` {string|string[]|Buffer|Buffer[]|Object[]} Private keys in PEM format.
16081598
PEM allows the option of private keys being encrypted. Encrypted keys will
16091599
be decrypted with `options.passphrase`. Multiple keys using different

lib/internal/quic/core.js

+22-27
Original file line numberDiff line numberDiff line change
@@ -611,10 +611,10 @@ class QuicEndpoint {
611611
const state = this[kInternalState];
612612
state.socket = socket;
613613
state.address = address || (type === AF_INET6 ? '::' : '0.0.0.0');
614-
state.ipv6Only = !!ipv6Only;
614+
state.ipv6Only = ipv6Only;
615615
state.lookup = lookup || (type === AF_INET6 ? lookup6 : lookup4);
616616
state.port = port;
617-
state.reuseAddr = !!reuseAddr;
617+
state.reuseAddr = reuseAddr;
618618
state.type = type;
619619
state.udpSocket = dgram.createSocket(type === AF_INET6 ? 'udp6' : 'udp4');
620620

@@ -696,20 +696,26 @@ class QuicEndpoint {
696696
state.socket[kEndpointBound](this);
697697
}
698698

699-
[kDestroy](error) {
699+
destroy(error) {
700+
if (this.destroyed)
701+
return;
702+
703+
const state = this[kInternalState];
704+
state.state = kSocketDestroyed;
705+
700706
const handle = this[kHandle];
701-
if (handle !== undefined) {
702-
this[kHandle] = undefined;
703-
handle[owner_symbol] = undefined;
704-
handle.ondone = () => {
705-
const state = this[kInternalState];
706-
state.udpSocket.close((err) => {
707-
if (err) error = err;
708-
state.socket[kEndpointClose](this, error);
709-
});
710-
};
711-
handle.waitForPendingCallbacks();
712-
}
707+
if (handle === undefined)
708+
return;
709+
710+
this[kHandle] = undefined;
711+
handle[owner_symbol] = undefined;
712+
handle.ondone = () => {
713+
state.udpSocket.close((err) => {
714+
if (err) error = err;
715+
state.socket[kEndpointClose](this, error);
716+
});
717+
};
718+
handle.waitForPendingCallbacks();
713719
}
714720

715721
// If the QuicEndpoint is bound, returns an object detailing
@@ -825,14 +831,6 @@ class QuicEndpoint {
825831
state.udpSocket.unref();
826832
return this;
827833
}
828-
829-
destroy(error) {
830-
const state = this[kInternalState];
831-
if (this.destroyed)
832-
return;
833-
state.state = kSocketDestroyed;
834-
this[kDestroy](error);
835-
}
836834
}
837835

838836
// QuicSocket wraps a UDP socket plus the associated TLS context and QUIC
@@ -1195,7 +1193,7 @@ class QuicSocket extends EventEmitter {
11951193
port,
11961194
type = 'udp4',
11971195
} = { ...preferredAddress };
1198-
const typeVal = getSocketType(type);
1196+
const [ typeVal ] = getSocketType(type);
11991197
// If preferred address is set, we need to perform a lookup on it
12001198
// to get the IP address. Only after that lookup completes can we
12011199
// continue with the listen operation, passing in the resolved
@@ -2331,7 +2329,6 @@ class QuicClientSession extends QuicSession {
23312329
autoStart: true,
23322330
dcid: undefined,
23332331
handshakeStarted: false,
2334-
ipv6Only: undefined,
23352332
minDHSize: undefined,
23362333
port: undefined,
23372334
ready: 0,
@@ -2355,7 +2352,6 @@ class QuicClientSession extends QuicSession {
23552352
autoStart,
23562353
alpn,
23572354
dcid,
2358-
ipv6Only,
23592355
minDHSize,
23602356
port,
23612357
preferredAddressPolicy,
@@ -2383,7 +2379,6 @@ class QuicClientSession extends QuicSession {
23832379
state.autoStart = autoStart;
23842380
state.handshakeStarted = autoStart;
23852381
state.dcid = dcid;
2386-
state.ipv6Only = ipv6Only;
23872382
state.minDHSize = minDHSize;
23882383
state.port = port || 0;
23892384
state.preferredAddressPolicy = preferredAddressPolicy;

lib/internal/quic/util.js

+10-17
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,9 @@ function validateNumber(value, name,
140140

141141
function getSocketType(type = 'udp4') {
142142
switch (type) {
143-
case 'udp4': return AF_INET;
144-
case 'udp6': return AF_INET6;
143+
case 'udp4': return [AF_INET, false];
144+
case 'udp6': return [AF_INET6, false];
145+
case 'udp6-only': return [AF_INET6, true];
145146
}
146147
throw new ERR_INVALID_ARG_VALUE('options.type', type);
147148
}
@@ -366,7 +367,6 @@ function validateQuicClientSessionOptions(options = {}) {
366367
address = 'localhost',
367368
alpn = '',
368369
dcid: dcid_value,
369-
ipv6Only = false,
370370
minDHSize = 1024,
371371
port = 0,
372372
preferredAddressPolicy = 'ignore',
@@ -434,7 +434,6 @@ function validateQuicClientSessionOptions(options = {}) {
434434
if (preferredAddressPolicy !== undefined)
435435
validateString(preferredAddressPolicy, 'options.preferredAddressPolicy');
436436

437-
validateBoolean(ipv6Only, 'options.ipv6Only');
438437
validateBoolean(requestOCSP, 'options.requestOCSP');
439438
validateBoolean(verifyHostnameIdentity, 'options.verifyHostnameIdentity');
440439
validateBoolean(qlog, 'options.qlog');
@@ -444,7 +443,6 @@ function validateQuicClientSessionOptions(options = {}) {
444443
address,
445444
alpn,
446445
dcid,
447-
ipv6Only,
448446
minDHSize,
449447
port,
450448
preferredAddressPolicy:
@@ -495,7 +493,6 @@ function validateQuicEndpointOptions(options = {}, name = 'options') {
495493
throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
496494
const {
497495
address,
498-
ipv6Only = false,
499496
lookup,
500497
port = 0,
501498
reuseAddr = false,
@@ -507,17 +504,17 @@ function validateQuicEndpointOptions(options = {}, name = 'options') {
507504
validatePort(port, 'options.port');
508505
validateString(type, 'options.type');
509506
validateLookup(lookup);
510-
validateBoolean(ipv6Only, 'options.ipv6Only');
511507
validateBoolean(reuseAddr, 'options.reuseAddr');
512508
validateBoolean(preferred, 'options.preferred');
509+
const [typeVal, ipv6Only] = getSocketType(type);
513510
return {
514-
address,
511+
type: typeVal,
515512
ipv6Only,
513+
address,
516514
lookup,
517515
port,
518516
preferred,
519517
reuseAddr,
520-
type: getSocketType(type),
521518
};
522519
}
523520

@@ -536,15 +533,13 @@ function validateQuicSocketOptions(options = {}) {
536533
retryTokenTimeout = DEFAULT_RETRYTOKEN_EXPIRATION,
537534
server = {},
538535
statelessResetSecret,
539-
type = endpoint.type || 'udp4',
540536
validateAddressLRU = false,
541537
validateAddress = false,
542538
} = options;
543539

544-
validateQuicEndpointOptions(endpoint, 'options.endpoint');
540+
const { type } = validateQuicEndpointOptions(endpoint, 'options.endpoint');
545541
validateObject(client, 'options.client');
546542
validateObject(server, 'options.server');
547-
validateString(type, 'options.type');
548543
validateLookup(lookup);
549544
validateBoolean(validateAddress, 'options.validateAddress');
550545
validateBoolean(validateAddressLRU, 'options.validateAddressLRU');
@@ -595,7 +590,7 @@ function validateQuicSocketOptions(options = {}) {
595590
maxStatelessResetsPerHost,
596591
retryTokenTimeout,
597592
server,
598-
type: getSocketType(type),
593+
type,
599594
validateAddress: validateAddress || validateAddressLRU,
600595
validateAddressLRU,
601596
qlog,
@@ -642,10 +637,8 @@ function validateQuicSocketConnectOptions(options = {}) {
642637
} = options;
643638
if (address !== undefined)
644639
validateString(address, 'options.address');
645-
return {
646-
type: getSocketType(type),
647-
address,
648-
};
640+
const [typeVal] = getSocketType(type);
641+
return { type: typeVal, address };
649642
}
650643

651644
function validateCreateSecureContextOptions(options = {}) {

test/parallel/test-quic-errors-quicsocket-connect.js

-7
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,6 @@ const client = createQuicSocket();
131131
});
132132
});
133133

134-
['a', 1n, 1, [], {}].forEach((ipv6Only) => {
135-
assert.throws(() => client.connect({ ipv6Only }), {
136-
code: 'ERR_INVALID_ARG_TYPE'
137-
});
138-
});
139-
140134
[1, 1n, false, [], {}].forEach((preferredAddressPolicy) => {
141135
assert.throws(() => client.connect({ preferredAddressPolicy }), {
142136
code: 'ERR_INVALID_ARG_TYPE'
@@ -202,7 +196,6 @@ assert.throws(() => client.connect(), {
202196
// Client QuicSession Related:
203197
//
204198
// [x] idleTimeout - must be a number greater than zero
205-
// [x] ipv6Only - must be a boolean
206199
// [x] activeConnectionIdLimit - must be a number between 2 and 8
207200
// [x] maxAckDelay - must be a number greater than zero
208201
// [x] maxData - must be a number greater than zero

test/parallel/test-quic-errors-quicsocket-create.js

-7
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,6 @@ const { createQuicSocket } = require('net');
4747
});
4848
});
4949

50-
// Test invalid QuicSocket ipv6Only argument option
51-
[1, NaN, 1n, null, {}, []].forEach((ipv6Only) => {
52-
assert.throws(() => createQuicSocket({ endpoint: { ipv6Only } }), {
53-
code: 'ERR_INVALID_ARG_TYPE'
54-
});
55-
});
56-
5750
// Test invalid QuicSocket reuseAddr argument option
5851
[1, NaN, 1n, null, {}, []].forEach((reuseAddr) => {
5952
assert.throws(() => createQuicSocket({ endpoint: { reuseAddr } }), {

test/parallel/test-quic-ipv6only.js

+4-30
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,10 @@ const { once } = require('events');
1919

2020
const kALPN = 'zzz';
2121

22-
// Setting `type` to `udp4` while setting `ipv6Only` to `true` is possible.
23-
// The ipv6Only setting will be ignored.
24-
async function ipv4() {
25-
const server = createQuicSocket({
26-
endpoint: {
27-
type: 'udp4',
28-
ipv6Only: true
29-
}
30-
});
31-
server.on('error', common.mustNotCall());
32-
server.listen({ key, cert, ca, alpn: kALPN });
33-
await once(server, 'ready');
34-
server.close();
35-
}
36-
3722
// Connecting to ipv6 server using "127.0.0.1" should work when
3823
// `ipv6Only` is set to `false`.
3924
async function ipv6() {
40-
const server = createQuicSocket({
41-
endpoint: {
42-
type: 'udp6',
43-
ipv6Only: false
44-
} });
25+
const server = createQuicSocket({ endpoint: { type: 'udp6' } });
4526
const client = createQuicSocket({ client: { key, cert, ca, alpn: kALPN } });
4627

4728
server.listen({ key, cert, ca, alpn: kALPN });
@@ -54,8 +35,7 @@ async function ipv6() {
5435

5536
const session = client.connect({
5637
address: common.localhostIPv4,
57-
port: server.endpoints[0].address.port,
58-
ipv6Only: true,
38+
port: server.endpoints[0].address.port
5939
});
6040

6141
await once(session, 'secure');
@@ -77,11 +57,7 @@ async function ipv6() {
7757
// When the `ipv6Only` set to `true`, a client cann't connect to it
7858
// through "127.0.0.1".
7959
async function ipv6Only() {
80-
const server = createQuicSocket({
81-
endpoint: {
82-
type: 'udp6',
83-
ipv6Only: true
84-
} });
60+
const server = createQuicSocket({ endpoint: { type: 'udp6-only' } });
8561
const client = createQuicSocket({ client: { key, cert, ca, alpn: kALPN } });
8662

8763
server.listen({ key, cert, ca, alpn: kALPN });
@@ -95,7 +71,6 @@ async function ipv6Only() {
9571
address: common.localhostIPv4,
9672
port: server.endpoints[0].address.port,
9773
idleTimeout: common.platformTimeout(1),
98-
ipv6Only: true,
9974
});
10075

10176
session.on('secure', common.mustNotCall());
@@ -144,8 +119,7 @@ async function mismatch() {
144119
]);
145120
}
146121

147-
ipv4()
148-
.then(ipv6)
122+
ipv6()
149123
.then(ipv6Only)
150124
.then(mismatch)
151125
.then(common.mustCall());

0 commit comments

Comments
 (0)