Skip to content

Commit 0ff5fb3

Browse files
committed
wip: handling connections draining before closing socket
* Related #9 [ci skip]
1 parent af9b746 commit 0ff5fb3

File tree

3 files changed

+159
-20
lines changed

3 files changed

+159
-20
lines changed

src/QUICClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class QUICClient extends EventTarget {
192192
await socket.stop();
193193
}
194194
// Wrapping error to contain both stack traces
195-
throw new errors.ErrorQUICClient(e.message, {cause: e});
195+
throw e;
196196
}
197197

198198
// Remove the temporary socket error handler

src/QUICConnection.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,6 @@ 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());
273268
for (const stream of this.streamMap.values()) {
274269
await stream.destroy();
275270
}
@@ -293,21 +288,23 @@ class QUICConnection extends EventTarget {
293288
utils.never();
294289
}
295290
}
296-
console.log(this.conn.isClosed(), this.conn.isDraining());
297291
// If it is not closed, it could still be draining
298292
if (this.conn.isDraining()) {
299293
// The `recv`, `send`, `timeout`, and `on_timeout` should continue to be called
300294
const { p: closeP, resolveP: resolveCloseP } = utils.promise();
301295
this.resolveCloseP = resolveCloseP;
302-
// FIXME: we need to process `send` AND `recv` until the connection is closed.
303296
await Promise.all([
304297
this.send(),
305298
closeP
306299
]);
307-
console.log('asd')
308300
}
309301
this.connectionMap.delete(this.connectionId);
310302
this.dispatchEvent(new events.QUICConnectionDestroyEvent());
303+
// Clean up timeout
304+
if (this.timer != null) {
305+
clearTimeout(this.timer);
306+
delete this.timer;
307+
}
311308
this.logger.info(`Destroyed ${this.constructor.name}`);
312309
}
313310

tests/QUICClient.test.ts

Lines changed: 153 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ import * as utils from '@/utils';
77
import * as testsUtils from './utils';
88
import * as errors from '@/errors';
99
import { fc } from '@fast-check/jest';
10-
import * as tlsUtils from './tlsUtils';
1110
import * as certFixtures from './fixtures/certFixtures';
1211
import { promise } from "@/utils";
13-
import { sleep } from './utils';
1412

1513
const tlsArb = fc.oneof(
1614
certFixtures.tlsConfigExampleArb,
@@ -270,22 +268,81 @@ describe(QUICClient.name, () => {
270268
});
271269
})
272270
describe('graceful tls handshake', () => {
273-
test('handshake succeeds', async () => {
271+
test('server verification succeeds', async () => {
274272
const server = new QUICServer({
275273
crypto,
276274
logger: logger.getChild(QUICServer.name),
277275
config: {
278-
tlsConfig: certFixtures.tlsConfigFileRSA2,
276+
tlsConfig: certFixtures.tlsConfigFileRSA1,
277+
verifyPeer: false,
278+
}
279+
});
280+
const handleConnectionEventProm = promise<any>()
281+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
282+
await server.start({
283+
host: '127.0.0.1' as Host,
284+
});
285+
// Connection should succeed
286+
const client = await QUICClient.createQUICClient({
287+
host: '::ffff:127.0.0.1' as Host,
288+
port: server.port,
289+
localHost: '::' as Host,
290+
crypto,
291+
logger: logger.getChild(QUICClient.name),
292+
config: {
293+
verifyPeer: true,
294+
verifyFromPemFile: certFixtures.tlsConfigFileRSA1.certChainFromPemFile,
295+
}
296+
});
297+
await handleConnectionEventProm.p
298+
await client.destroy();
299+
await server.stop();
300+
})
301+
test('client verification succeeds', async () => {
302+
const server = new QUICServer({
303+
crypto,
304+
logger: logger.getChild(QUICServer.name),
305+
config: {
306+
tlsConfig: certFixtures.tlsConfigFileRSA1,
307+
verifyPeer: true,
308+
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile,
309+
}
310+
});
311+
const handleConnectionEventProm = promise<any>()
312+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
313+
await server.start({
314+
host: '127.0.0.1' as Host,
315+
});
316+
// Connection should succeed
317+
const client = await QUICClient.createQUICClient({
318+
host: '::ffff:127.0.0.1' as Host,
319+
port: server.port,
320+
localHost: '::' as Host,
321+
crypto,
322+
logger: logger.getChild(QUICClient.name),
323+
config: {
279324
verifyPeer: false,
325+
tlsConfig: certFixtures.tlsConfigFileRSA2,
326+
}
327+
});
328+
await handleConnectionEventProm.p
329+
await client.destroy();
330+
await server.stop();
331+
})
332+
test('client and server verification succeeds', async () => {
333+
const server = new QUICServer({
334+
crypto,
335+
logger: logger.getChild(QUICServer.name),
336+
config: {
337+
tlsConfig: certFixtures.tlsConfigFileRSA1,
338+
verifyPeer: true,
280339
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile,
281-
logKeys: "tmp/key.log",
282340
}
283341
});
284342
const handleConnectionEventProm = promise<any>()
285343
server.addEventListener('connection', handleConnectionEventProm.resolveP);
286344
await server.start({
287345
host: '127.0.0.1' as Host,
288-
port: 55555 as Port,
289346
});
290347
// Connection should succeed
291348
const client = await QUICClient.createQUICClient({
@@ -297,17 +354,102 @@ describe(QUICClient.name, () => {
297354
config: {
298355
verifyPeer: true,
299356
tlsConfig: certFixtures.tlsConfigFileRSA2,
300-
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile
357+
verifyFromPemFile: certFixtures.tlsConfigFileRSA1.certChainFromPemFile,
358+
301359
}
302360
});
303-
console.log('wait for connection');
304361
await handleConnectionEventProm.p
305362
await client.destroy();
306363
await server.stop();
307364
})
308-
test.todo('handshake fails validation for server')
309-
test.todo('handshake fails validation for client')
310-
test.todo('handshake fails validation for both')
365+
test('graceful failure verifying server', async () => {
366+
const server = new QUICServer({
367+
crypto,
368+
logger: logger.getChild(QUICServer.name),
369+
config: {
370+
tlsConfig: certFixtures.tlsConfigFileRSA1,
371+
verifyPeer: false,
372+
}
373+
});
374+
const handleConnectionEventProm = promise<any>()
375+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
376+
await server.start({
377+
host: '127.0.0.1' as Host,
378+
});
379+
// Connection should succeed
380+
await expect(QUICClient.createQUICClient({
381+
host: '::ffff:127.0.0.1' as Host,
382+
port: server.port,
383+
localHost: '::' as Host,
384+
crypto,
385+
logger: logger.getChild(QUICClient.name),
386+
config: {
387+
verifyPeer: true,
388+
}
389+
})).toReject();
390+
await handleConnectionEventProm.p
391+
await server.stop();
392+
})
393+
test('graceful failure verifying client', async () => {
394+
const server = new QUICServer({
395+
crypto,
396+
logger: logger.getChild(QUICServer.name),
397+
config: {
398+
tlsConfig: certFixtures.tlsConfigFileRSA1,
399+
verifyPeer: true,
400+
}
401+
});
402+
const handleConnectionEventProm = promise<any>()
403+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
404+
await server.start({
405+
host: '127.0.0.1' as Host,
406+
});
407+
// Connection should succeed
408+
await expect(QUICClient.createQUICClient({
409+
host: '::ffff:127.0.0.1' as Host,
410+
port: server.port,
411+
localHost: '::' as Host,
412+
crypto,
413+
logger: logger.getChild(QUICClient.name),
414+
config: {
415+
verifyPeer: false,
416+
tlsConfig: certFixtures.tlsConfigFileRSA2,
417+
}
418+
})).toReject();
419+
await handleConnectionEventProm.p
420+
await server.stop();
421+
})
422+
test('graceful failure verifying client amd server', async () => {
423+
const server = new QUICServer({
424+
crypto,
425+
logger: logger.getChild(QUICServer.name),
426+
config: {
427+
tlsConfig: certFixtures.tlsConfigFileRSA1,
428+
verifyPeer: true,
429+
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile,
430+
}
431+
});
432+
const handleConnectionEventProm = promise<any>()
433+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
434+
await server.start({
435+
host: '127.0.0.1' as Host,
436+
});
437+
// Connection should succeed
438+
await expect(QUICClient.createQUICClient({
439+
host: '::ffff:127.0.0.1' as Host,
440+
port: server.port,
441+
localHost: '::' as Host,
442+
crypto,
443+
logger: logger.getChild(QUICClient.name),
444+
config: {
445+
verifyPeer: true,
446+
tlsConfig: certFixtures.tlsConfigFileRSA2,
447+
verifyFromPemFile: certFixtures.tlsConfigFileRSA1.certChainFromPemFile,
448+
}
449+
})).toReject();
450+
await handleConnectionEventProm.p
451+
await server.stop();
452+
})
311453
})
312454

313455
// test('dual stack to dual stack', async () => {

0 commit comments

Comments
 (0)