Skip to content

Commit 98b4c17

Browse files
committed
wip: handling connections draining before closing socket
* Related #9 [ci skip]
1 parent 60dc01c commit 98b4c17

File tree

3 files changed

+74
-21
lines changed

3 files changed

+74
-21
lines changed

src/QUICClient.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class QUICClient extends EventTarget {
9191
const {
9292
p: errorP,
9393
rejectP: rejectErrorP
94-
} = utils.promise();
94+
} = utils.promise<never>();
9595
const handleQUICSocketError = (e: events.QUICSocketErrorEvent) => {
9696
rejectErrorP(e.detail);
9797
};
@@ -174,11 +174,25 @@ class QUICClient extends EventTarget {
174174
try {
175175
await Promise.race([connection.establishedP, errorP]);
176176
} catch (e) {
177+
logger.error(e.toString());
178+
// console.error(e);
179+
logger.debug(`Is shared?: ${isSocketShared}`);
180+
// Waiting for connection to destroy
181+
const destroyedProm = utils.promise<void>();
182+
connection.addEventListener('destroy', ()=> {
183+
destroyedProm.resolveP();
184+
},
185+
{
186+
once: true,
187+
},
188+
)
189+
await destroyedProm.p;
177190
if (!isSocketShared) {
178191
// Stop our own socket
179192
await socket.stop();
180193
}
181-
throw e;
194+
// Wrapping error to contain both stack traces
195+
throw new errors.ErrorQUICClient(e.message, {cause: e});
182196
}
183197

184198
// Remove the temporary socket error handler

src/QUICConnection.ts

+19-8
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ class QUICConnection extends EventTarget {
251251
}
252252

253253
/**
254-
* This provides the ability to destroy with a specific error
254+
* This provides the ability to destroy with a specific error. This will wait for the connection to fully drain.
255255
*/
256256
public async destroy(
257257
{
@@ -265,6 +265,11 @@ class QUICConnection extends EventTarget {
265265
} = {}
266266
) {
267267
this.logger.info(`Destroy ${this.constructor.name}`);
268+
const localError = this.conn.localError();
269+
const peerError = this.conn.peerError();
270+
if (localError != null) console.log(localError);
271+
if (peerError != null) console.log(peerError);
272+
console.log(this.conn.peerError());
268273
for (const stream of this.streamMap.values()) {
269274
await stream.destroy();
270275
}
@@ -288,15 +293,18 @@ class QUICConnection extends EventTarget {
288293
utils.never();
289294
}
290295
}
296+
console.log(this.conn.isClosed(), this.conn.isDraining());
291297
// If it is not closed, it could still be draining
292-
if (!this.conn.isClosed()) {
298+
if (this.conn.isDraining()) {
293299
// The `recv`, `send`, `timeout`, and `on_timeout` should continue to be called
294300
const { p: closeP, resolveP: resolveCloseP } = utils.promise();
295301
this.resolveCloseP = resolveCloseP;
302+
// FIXME: we need to process `send` AND `recv` until the connection is closed.
296303
await Promise.all([
297304
this.send(),
298305
closeP
299306
]);
307+
console.log('asd')
300308
}
301309
this.connectionMap.delete(this.connectionId);
302310
this.dispatchEvent(new events.QUICConnectionDestroyEvent());
@@ -339,6 +347,9 @@ class QUICConnection extends EventTarget {
339347
this.logger.debug(`Did a recv ${data.byteLength}`);
340348
this.conn.recv(data, recvInfo);
341349
} catch (e) {
350+
this.logger.error(e.toString());
351+
// console.error(e);
352+
// console.log(this.conn.isClosed());
342353
// Depending on the exception, the `this.conn.recv`
343354
// may have automatically started closing the connection
344355
this.dispatchEvent(
@@ -427,13 +438,12 @@ class QUICConnection extends EventTarget {
427438

428439
try {
429440
if (this.conn.isClosed()) {
430-
431-
432441
if (this.resolveCloseP != null) this.resolveCloseP();
433442
return;
434-
} else if (this.conn.isDraining()) {
435-
return;
436443
}
444+
// else if (this.conn.isDraining()) {
445+
// return;
446+
// }
437447
const sendBuffer = new Uint8Array(quiche.MAX_DATAGRAM_SIZE);
438448
let sendLength: number;
439449
let sendInfo: SendInfo;
@@ -481,7 +491,7 @@ class QUICConnection extends EventTarget {
481491
sendInfo.to.host
482492
);
483493
} catch (e) {
484-
console.error(e);
494+
this.logger.error(e.toString())
485495
this.dispatchEvent(new events.QUICConnectionErrorEvent({ detail: e }));
486496
return;
487497
}
@@ -491,11 +501,12 @@ class QUICConnection extends EventTarget {
491501
this.logger.debug('SEND FINALLY');
492502

493503
this.setTimeout();
504+
this.logger.debug(`connection is closed?: ${this.conn.isClosed()}`)
505+
this.logger.debug(`connection is draining?: ${this.conn.isDraining()}`)
494506
if (
495507
this[status] !== 'destroying' &&
496508
(this.conn.isClosed() || this.conn.isDraining())
497509
) {
498-
499510
this.logger.debug('CALLING DESTROY');
500511

501512
await this.destroy();

tests/QUICClient.test.ts

+39-11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { fc } from '@fast-check/jest';
1313
import * as tlsUtils from './tlsUtils';
1414
import * as certFixtures from './fixtures/certFixtures';
1515
import { promise } from "@/utils";
16+
import { sleep } from './utils';
1617

1718
const tlsArb = fc.constant(certFixtures.tlsConfigFileRSA1);
1819
// const tlsArb = tlsUtils.tlsConfigArb(tlsUtils.keyPairsArb(1));
@@ -74,7 +75,8 @@ describe(QUICClient.name, () => {
7475
crypto,
7576
logger: logger.getChild(QUICServer.name),
7677
config: {
77-
tlsConfig
78+
tlsConfig,
79+
verifyPeer: false,
7880
}
7981
});
8082
server.addEventListener('connection', handleConnectionEventP);
@@ -87,6 +89,9 @@ describe(QUICClient.name, () => {
8789
localHost: '::' as Host,
8890
crypto,
8991
logger: logger.getChild(QUICClient.name),
92+
config: {
93+
verifyPeer: false,
94+
}
9095
});
9196
const conn = (await connectionEventP).detail;
9297
expect(conn.localHost).toBe('127.0.0.1');
@@ -101,7 +106,8 @@ describe(QUICClient.name, () => {
101106
crypto,
102107
logger: logger.getChild(QUICServer.name),
103108
config: {
104-
tlsConfig
109+
tlsConfig,
110+
verifyPeer: false,
105111
}
106112
});
107113
server.addEventListener('connection', handleConnectionEventP);
@@ -114,7 +120,10 @@ describe(QUICClient.name, () => {
114120
port: server.port,
115121
localHost: '::' as Host,
116122
crypto,
117-
logger: logger.getChild(QUICClient.name)
123+
logger: logger.getChild(QUICClient.name),
124+
config: {
125+
verifyPeer: false,
126+
}
118127
});
119128
const conn = (await connectionEventP).detail;
120129
expect(conn.localHost).toBe('::1');
@@ -129,7 +138,8 @@ describe(QUICClient.name, () => {
129138
crypto,
130139
logger: logger.getChild(QUICServer.name),
131140
config: {
132-
tlsConfig
141+
tlsConfig,
142+
verifyPeer: false,
133143
}
134144
});
135145
server.addEventListener('connection', handleConnectionEventP);
@@ -142,7 +152,10 @@ describe(QUICClient.name, () => {
142152
port: server.port,
143153
localHost: '::' as Host,
144154
crypto,
145-
logger: logger.getChild(QUICClient.name)
155+
logger: logger.getChild(QUICClient.name),
156+
config: {
157+
verifyPeer: false,
158+
}
146159
});
147160
const conn = (await connectionEventP).detail;
148161
expect(conn.localHost).toBe('::');
@@ -163,6 +176,7 @@ describe(QUICClient.name, () => {
163176
logger: logger.getChild(QUICClient.name),
164177
config: {
165178
maxIdleTimeout: 1000,
179+
verifyPeer: false,
166180
}
167181
})).rejects.toThrow(errors.ErrorQUICConnectionTimeout);
168182
});
@@ -187,7 +201,8 @@ describe(QUICClient.name, () => {
187201
crypto,
188202
logger: logger.getChild(QUICServer.name),
189203
config: {
190-
tlsConfig: certFixtures.tlsConfigFileRSA1
204+
tlsConfig: certFixtures.tlsConfigFileRSA1,
205+
verifyPeer: false,
191206
}
192207
});
193208
server.addEventListener('connection', handleConnectionEventP);
@@ -200,6 +215,9 @@ describe(QUICClient.name, () => {
200215
localHost: '::' as Host,
201216
crypto,
202217
logger: logger.getChild(QUICClient.name),
218+
config: {
219+
verifyPeer: false,
220+
}
203221
});
204222
const peerCertChainInitial = client1.connection.conn.peerCertChain()
205223
server.updateConfig({
@@ -216,7 +234,8 @@ describe(QUICClient.name, () => {
216234
crypto,
217235
logger: logger.getChild(QUICServer.name),
218236
config: {
219-
tlsConfig: certFixtures.tlsConfigFileRSA1
237+
tlsConfig: certFixtures.tlsConfigFileRSA1,
238+
verifyPeer: false,
220239
}
221240
});
222241
server.addEventListener('connection', handleConnectionEventP);
@@ -229,6 +248,9 @@ describe(QUICClient.name, () => {
229248
localHost: '::' as Host,
230249
crypto,
231250
logger: logger.getChild(QUICClient.name),
251+
config: {
252+
verifyPeer: false,
253+
}
232254
});
233255
const peerCertChainInitial = client1.connection.conn.peerCertChain()
234256
server.updateConfig({
@@ -241,6 +263,9 @@ describe(QUICClient.name, () => {
241263
localHost: '::' as Host,
242264
crypto,
243265
logger: logger.getChild(QUICClient.name),
266+
config: {
267+
verifyPeer: false,
268+
}
244269
});
245270
const peerCertChainNew = client2.connection.conn.peerCertChain()
246271
expect(peerCertChainNew![0].toString()).not.toStrictEqual(peerCertChainInitial![0].toString());
@@ -255,15 +280,17 @@ describe(QUICClient.name, () => {
255280
crypto,
256281
logger: logger.getChild(QUICServer.name),
257282
config: {
258-
tlsConfig: certFixtures.tlsConfigFileRSA1,
259-
verifyPeer: true,
260-
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile
283+
tlsConfig: certFixtures.tlsConfigFileRSA2,
284+
verifyPeer: false,
285+
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile,
286+
logKeys: "tmp/key.log",
261287
}
262288
});
263289
const handleConnectionEventProm = promise<any>()
264290
server.addEventListener('connection', handleConnectionEventProm.resolveP);
265291
await server.start({
266292
host: '127.0.0.1' as Host,
293+
port: 55555 as Port,
267294
});
268295
// Connection should succeed
269296
const client = await QUICClient.createQUICClient({
@@ -273,11 +300,12 @@ describe(QUICClient.name, () => {
273300
crypto,
274301
logger: logger.getChild(QUICClient.name),
275302
config: {
276-
verifyPeer: false,
303+
verifyPeer: true,
277304
tlsConfig: certFixtures.tlsConfigFileRSA2,
278305
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile
279306
}
280307
});
308+
console.log('wait for connection');
281309
await handleConnectionEventProm.p
282310
await client.destroy();
283311
await server.stop();

0 commit comments

Comments
 (0)