Skip to content

Commit c9d4992

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

File tree

3 files changed

+160
-20
lines changed

3 files changed

+160
-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: 154 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ 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';
12+
import * as tlsUtils from './tlsUtils';
1413

1514
const tlsArb = fc.oneof(
1615
certFixtures.tlsConfigExampleArb,
@@ -270,22 +269,81 @@ describe(QUICClient.name, () => {
270269
});
271270
})
272271
describe('graceful tls handshake', () => {
273-
test('handshake succeeds', async () => {
272+
test('server verification succeeds', async () => {
274273
const server = new QUICServer({
275274
crypto,
276275
logger: logger.getChild(QUICServer.name),
277276
config: {
278-
tlsConfig: certFixtures.tlsConfigFileRSA2,
277+
tlsConfig: certFixtures.tlsConfigFileRSA1,
279278
verifyPeer: false,
279+
}
280+
});
281+
const handleConnectionEventProm = promise<any>()
282+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
283+
await server.start({
284+
host: '127.0.0.1' as Host,
285+
});
286+
// Connection should succeed
287+
const client = await QUICClient.createQUICClient({
288+
host: '::ffff:127.0.0.1' as Host,
289+
port: server.port,
290+
localHost: '::' as Host,
291+
crypto,
292+
logger: logger.getChild(QUICClient.name),
293+
config: {
294+
verifyPeer: true,
295+
verifyFromPemFile: certFixtures.tlsConfigFileRSA1.certChainFromPemFile,
296+
}
297+
});
298+
await handleConnectionEventProm.p
299+
await client.destroy();
300+
await server.stop();
301+
})
302+
test('client verification succeeds', async () => {
303+
const server = new QUICServer({
304+
crypto,
305+
logger: logger.getChild(QUICServer.name),
306+
config: {
307+
tlsConfig: certFixtures.tlsConfigFileRSA1,
308+
verifyPeer: true,
309+
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile,
310+
}
311+
});
312+
const handleConnectionEventProm = promise<any>()
313+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
314+
await server.start({
315+
host: '127.0.0.1' as Host,
316+
});
317+
// Connection should succeed
318+
const client = await QUICClient.createQUICClient({
319+
host: '::ffff:127.0.0.1' as Host,
320+
port: server.port,
321+
localHost: '::' as Host,
322+
crypto,
323+
logger: logger.getChild(QUICClient.name),
324+
config: {
325+
verifyPeer: false,
326+
tlsConfig: certFixtures.tlsConfigFileRSA2,
327+
}
328+
});
329+
await handleConnectionEventProm.p
330+
await client.destroy();
331+
await server.stop();
332+
})
333+
test('client and server verification succeeds', async () => {
334+
const server = new QUICServer({
335+
crypto,
336+
logger: logger.getChild(QUICServer.name),
337+
config: {
338+
tlsConfig: certFixtures.tlsConfigFileRSA1,
339+
verifyPeer: true,
280340
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile,
281-
logKeys: "tmp/key.log",
282341
}
283342
});
284343
const handleConnectionEventProm = promise<any>()
285344
server.addEventListener('connection', handleConnectionEventProm.resolveP);
286345
await server.start({
287346
host: '127.0.0.1' as Host,
288-
port: 55555 as Port,
289347
});
290348
// Connection should succeed
291349
const client = await QUICClient.createQUICClient({
@@ -297,17 +355,102 @@ describe(QUICClient.name, () => {
297355
config: {
298356
verifyPeer: true,
299357
tlsConfig: certFixtures.tlsConfigFileRSA2,
300-
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile
358+
verifyFromPemFile: certFixtures.tlsConfigFileRSA1.certChainFromPemFile,
359+
301360
}
302361
});
303-
console.log('wait for connection');
304362
await handleConnectionEventProm.p
305363
await client.destroy();
306364
await server.stop();
307365
})
308-
test.todo('handshake fails validation for server')
309-
test.todo('handshake fails validation for client')
310-
test.todo('handshake fails validation for both')
366+
test('graceful failure verifying server', async () => {
367+
const server = new QUICServer({
368+
crypto,
369+
logger: logger.getChild(QUICServer.name),
370+
config: {
371+
tlsConfig: certFixtures.tlsConfigFileRSA1,
372+
verifyPeer: false,
373+
}
374+
});
375+
const handleConnectionEventProm = promise<any>()
376+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
377+
await server.start({
378+
host: '127.0.0.1' as Host,
379+
});
380+
// Connection should succeed
381+
await expect(QUICClient.createQUICClient({
382+
host: '::ffff:127.0.0.1' as Host,
383+
port: server.port,
384+
localHost: '::' as Host,
385+
crypto,
386+
logger: logger.getChild(QUICClient.name),
387+
config: {
388+
verifyPeer: true,
389+
}
390+
})).toReject();
391+
await handleConnectionEventProm.p
392+
await server.stop();
393+
})
394+
test('graceful failure verifying client', async () => {
395+
const server = new QUICServer({
396+
crypto,
397+
logger: logger.getChild(QUICServer.name),
398+
config: {
399+
tlsConfig: certFixtures.tlsConfigFileRSA1,
400+
verifyPeer: true,
401+
}
402+
});
403+
const handleConnectionEventProm = promise<any>()
404+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
405+
await server.start({
406+
host: '127.0.0.1' as Host,
407+
});
408+
// Connection should succeed
409+
await expect(QUICClient.createQUICClient({
410+
host: '::ffff:127.0.0.1' as Host,
411+
port: server.port,
412+
localHost: '::' as Host,
413+
crypto,
414+
logger: logger.getChild(QUICClient.name),
415+
config: {
416+
verifyPeer: false,
417+
tlsConfig: certFixtures.tlsConfigFileRSA2,
418+
}
419+
})).toReject();
420+
await handleConnectionEventProm.p
421+
await server.stop();
422+
})
423+
test('graceful failure verifying client amd server', async () => {
424+
const server = new QUICServer({
425+
crypto,
426+
logger: logger.getChild(QUICServer.name),
427+
config: {
428+
tlsConfig: certFixtures.tlsConfigFileRSA1,
429+
verifyPeer: true,
430+
verifyFromPemFile: certFixtures.tlsConfigFileRSA2.certChainFromPemFile,
431+
}
432+
});
433+
const handleConnectionEventProm = promise<any>()
434+
server.addEventListener('connection', handleConnectionEventProm.resolveP);
435+
await server.start({
436+
host: '127.0.0.1' as Host,
437+
});
438+
// Connection should succeed
439+
await expect(QUICClient.createQUICClient({
440+
host: '::ffff:127.0.0.1' as Host,
441+
port: server.port,
442+
localHost: '::' as Host,
443+
crypto,
444+
logger: logger.getChild(QUICClient.name),
445+
config: {
446+
verifyPeer: true,
447+
tlsConfig: certFixtures.tlsConfigFileRSA2,
448+
verifyFromPemFile: certFixtures.tlsConfigFileRSA1.certChainFromPemFile,
449+
}
450+
})).toReject();
451+
await handleConnectionEventProm.p
452+
await server.stop();
453+
})
311454
})
312455

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

0 commit comments

Comments
 (0)