Skip to content

Commit 9cc653d

Browse files
committed
tests: fixing up client tests
- Fixed up start erroring out. - Fixed up graceful TLS test. - Cleaning up. [ci skip]
1 parent 225babf commit 9cc653d

File tree

8 files changed

+1453
-1550
lines changed

8 files changed

+1453
-1550
lines changed

src/QUICClient.ts

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import type { PromiseCancellable } from '@matrixai/async-cancellable';
22
import type { ContextTimed } from '@matrixai/contexts';
3-
import type { ClientCrypto, Host, Hostname, Port, VerifyCallback } from './types';
3+
import type {
4+
ClientCrypto,
5+
Host,
6+
Hostname,
7+
Port,
8+
VerifyCallback,
9+
} from './types';
410
import type { Config } from './native/types';
511
import type QUICConnectionMap from './QUICConnectionMap';
612
import type {
@@ -48,6 +54,8 @@ class QUICClient extends EventTarget {
4854
protected config: Config;
4955
protected _connection: QUICConnection;
5056
protected connectionMap: QUICConnectionMap;
57+
// Used to track address string for logging ONLY
58+
protected address: string;
5159

5260
/**
5361
* Creates a QUIC Client
@@ -211,17 +219,12 @@ class QUICClient extends EventTarget {
211219
ctx.signal.addEventListener('abort', (r) => {
212220
abortController.abort(r);
213221
});
214-
console.log('bsd');
215222
try {
216223
await Promise.race([
217224
connection.start({ ...ctx, signal: abortController.signal }),
218-
socketErrorP.catch(e => {
219-
console.error(e);
220-
throw e;
221-
}),
225+
socketErrorP,
222226
]);
223227
} catch (e) {
224-
console.error(e);
225228
// In case the `connection.start` is on-going, we need to abort it
226229
abortController.abort(e);
227230
if (!isSocketShared) {
@@ -232,16 +235,14 @@ class QUICClient extends EventTarget {
232235
} finally {
233236
socket.removeEventListener('socketError', handleQUICSocketError);
234237
}
235-
console.log('bsd')
238+
address = utils.buildAddress(host_, port);
236239
const client = new this({
237240
socket,
238241
connection,
239242
isSocketShared,
243+
address,
240244
logger,
241245
});
242-
console.log('bsd')
243-
address = utils.buildAddress(host_, port);
244-
console.log('bsd')
245246
logger.info(`Created ${this.name} to ${address}`);
246247
return client;
247248
}
@@ -339,18 +340,21 @@ class QUICClient extends EventTarget {
339340
socket,
340341
isSocketShared,
341342
connection,
343+
address,
342344
logger,
343345
}: {
344346
socket: QUICSocket;
345347
isSocketShared: boolean;
346348
connection: QUICConnection;
349+
address: string;
347350
logger: Logger;
348351
}) {
349352
super();
350353
this.logger = logger;
351354
this.socket = socket;
352355
this.isSocketShared = isSocketShared;
353356
this._connection = connection;
357+
this.address = address;
354358
// Listen on all socket events
355359
socket.addEventListener('socketError', this.handleQUICSocketEvents);
356360
socket.addEventListener('socketStop', this.handleQUICSocketEvents);
@@ -402,25 +406,25 @@ class QUICClient extends EventTarget {
402406
}: {
403407
force?: boolean;
404408
} = {}) {
405-
const address = utils.buildAddress(this.socket.host, this.socket.port);
409+
const address = this.address;
406410
this.logger.info(`Destroy ${this.constructor.name} on ${address}`);
407411
// Listen on all socket events
408412
this.socket.removeEventListener('socketError', this.handleQUICSocketEvents);
409413
this.socket.removeEventListener('socketStop', this.handleQUICSocketEvents);
410414
// Listen on all connection events
411-
this.connection.removeEventListener(
415+
this._connection.removeEventListener(
412416
'connectionStream',
413417
this.handleQUICConnectionEvents,
414418
);
415-
this.connection.removeEventListener(
419+
this._connection.removeEventListener(
416420
'connectionStop',
417421
this.handleQUICConnectionEvents,
418422
);
419-
this.connection.removeEventListener(
423+
this._connection.removeEventListener(
420424
'connectionError',
421425
this.handleQUICConnectionEvents,
422426
);
423-
this.connection.removeEventListener(
427+
this._connection.removeEventListener(
424428
'streamDestroy',
425429
this.handleQUICConnectionEvents,
426430
);

src/QUICConnection.ts

Lines changed: 86 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,33 @@ import type { PromiseCancellable } from '@matrixai/async-cancellable';
22
import type { ContextTimed } from '@matrixai/contexts';
33
import type QUICSocket from './QUICSocket';
44
import type QUICConnectionId from './QUICConnectionId';
5-
import type { Host, Port, RemoteInfo, StreamId } from './types';
5+
import type {
6+
Host,
7+
Port,
8+
QUICConfig,
9+
RemoteInfo,
10+
StreamCodeToReason,
11+
StreamId,
12+
StreamReasonToCode,
13+
} from './types';
614
import type { Connection, ConnectionErrorCode, SendInfo } from './native/types';
7-
import type { StreamCodeToReason, StreamReasonToCode } from './types';
8-
import type { QUICConfig } from './types';
9-
import { Monitor, RWLockWriter } from '@matrixai/async-locks';
15+
import { Lock, LockBox, Monitor, RWLockWriter } from '@matrixai/async-locks';
1016
import {
11-
StartStop,
1217
ready,
13-
status,
1418
running,
19+
StartStop,
20+
status,
1521
} from '@matrixai/async-init/dist/StartStop';
1622
import Logger from '@matrixai/logger';
17-
import { Lock, LockBox } from '@matrixai/async-locks';
1823
import { Timer } from '@matrixai/timer';
1924
import { context, timedCancellable } from '@matrixai/contexts/dist/decorators';
2025
import { buildQuicheConfig } from './config';
2126
import QUICStream from './QUICStream';
2227
import { quiche } from './native';
2328
import * as events from './events';
2429
import * as utils from './utils';
25-
import * as errors from './errors';
2630
import { never } from './utils';
31+
import * as errors from './errors';
2732

2833
// FIXME
2934
type VerifyCallback = (certs: Array<string>) => void;
@@ -369,7 +374,45 @@ class QUICConnection extends EventTarget {
369374
// Waits for the first short packet after establishment
370375
// This ensures that TLS has been established and verified on both sides
371376
await this.send();
372-
await this.secureEstablishedP;
377+
await this.secureEstablishedP.catch((e) => {
378+
this.socket.connectionMap.delete(this.connectionId);
379+
380+
if (this.conn.isTimedOut()) {
381+
// We don't dispatch an event here, it was already done in the timeout.
382+
throw new errors.ErrorQUICConnectionStartTimeOut();
383+
}
384+
385+
// Emit error if local error
386+
const localError = this.conn.localError();
387+
if (localError != null) {
388+
const message = `connection start failed with localError ${Buffer.from(
389+
localError.reason,
390+
).toString()}(${localError.errorCode})`;
391+
this.logger.info(message);
392+
throw new errors.ErrorQUICConnectionInternal(message, {
393+
data: {
394+
type: 'local',
395+
...localError,
396+
},
397+
});
398+
}
399+
// Emit error if peer error
400+
const peerError = this.conn.peerError();
401+
if (peerError != null) {
402+
const message = `Connection start failed with peerError ${Buffer.from(
403+
peerError.reason,
404+
).toString()}(${peerError.errorCode})`;
405+
this.logger.info(message);
406+
throw new errors.ErrorQUICConnectionInternal(message, {
407+
data: {
408+
type: 'local',
409+
...peerError,
410+
},
411+
});
412+
}
413+
// Throw the default error if none of the above were true, this shouldn't really happen
414+
throw e;
415+
});
373416
this.logger.warn('secured');
374417
// After this is done
375418
// We need to established the keep alive interval time
@@ -460,6 +503,14 @@ class QUICConnection extends EventTarget {
460503
// But during `start` we are just waiting
461504
this.socket.connectionMap.delete(this.connectionId);
462505

506+
if (this.conn.isTimedOut()) {
507+
this.dispatchEvent(
508+
new events.QUICConnectionErrorEvent({
509+
detail: new errors.ErrorQUICConnectionIdleTimeOut(),
510+
}),
511+
);
512+
}
513+
463514
// Emit error if peer error
464515
const peerError = this.conn.peerError();
465516
if (peerError != null) {
@@ -469,15 +520,12 @@ class QUICConnection extends EventTarget {
469520
this.logger.info(message);
470521
this.dispatchEvent(
471522
new events.QUICConnectionErrorEvent({
472-
detail: new errors.ErrorQUICConnectionInternal(
473-
message,
474-
{
475-
data: {
476-
type: 'local',
477-
...peerError,
478-
}
523+
detail: new errors.ErrorQUICConnectionInternal(message, {
524+
data: {
525+
type: 'local',
526+
...peerError,
479527
},
480-
),
528+
}),
481529
}),
482530
);
483531
}
@@ -490,15 +538,12 @@ class QUICConnection extends EventTarget {
490538
this.logger.info(message);
491539
this.dispatchEvent(
492540
new events.QUICConnectionErrorEvent({
493-
detail: new errors.ErrorQUICConnectionInternal(
494-
message,
495-
{
496-
data: {
497-
type: 'local',
498-
...localError,
499-
}
500-
}
501-
),
541+
detail: new errors.ErrorQUICConnectionInternal(message, {
542+
data: {
543+
type: 'local',
544+
...localError,
545+
},
546+
}),
502547
}),
503548
);
504549
}
@@ -578,7 +623,7 @@ class QUICConnection extends EventTarget {
578623
// Short indicates that the peer has completed TLS verification
579624
if (!this.shortReceived) {
580625
const header = quiche.Header.fromSlice(data, quiche.MAX_CONN_ID_LEN);
581-
// if short frame
626+
// If short frame
582627
if (header.ty === 5) {
583628
this.shortReceived = true;
584629
this.conn.sendAckEliciting();
@@ -594,7 +639,7 @@ class QUICConnection extends EventTarget {
594639
if (this.count >= 1) {
595640
this.secured = true;
596641
this.resolveSecureEstablishedP();
597-
// this.dispatchEvent(new events.QUICConnectionRemoteSecureEvent()); TODO
642+
// This.dispatchEvent(new events.QUICConnectionRemoteSecureEvent()); TODO
598643
}
599644
this.count += 1;
600645
}
@@ -757,9 +802,7 @@ class QUICConnection extends EventTarget {
757802
this.customVerified = true;
758803
const peerCerts = this.conn.peerCertChain();
759804
if (peerCerts == null) never();
760-
const peerCertsPem = peerCerts.map((c) =>
761-
utils.certificateDERToPEM(c),
762-
);
805+
const peerCertsPem = peerCerts.map((c) => utils.certificateDERToPEM(c));
763806
// Dispatching certs available event
764807
// this.dispatchEvent(new events.QUICConnectionRemoteCertEvent()); TODO
765808
try {
@@ -833,6 +876,7 @@ class QUICConnection extends EventTarget {
833876
const connTimeOutHandler = async () => {
834877
// This can only be called when the timeout has occurred
835878
// This transitions the connection state
879+
this.logger.debug('CALLING ON TIMEOUT');
836880
this.conn.onTimeout();
837881

838882
// At this point...
@@ -847,26 +891,16 @@ class QUICConnection extends EventTarget {
847891
// So if it is timed out, it gets closed too
848892
// But if it is is timed out due to idle we raise an error
849893

850-
if (this.conn.isTimedOut()) {
851-
// This is just a dispatch on the connection error
852-
// Note that this may cause the client to attempt
853-
// to stop the socket and stuff
854-
// The client should ignore this event error
855-
// Because it's actually being handled
856-
// On the other hand...
857-
// If we randomly fail here
858-
// It's correct to properly raise an event
859-
// To bubble up....
860-
861-
this.dispatchEvent(
862-
new events.QUICConnectionErrorEvent({
863-
detail: new errors.ErrorQUICConnectionIdleTimeOut(),
864-
}),
865-
);
866-
}
867-
868894
// At the same time, we may in fact be closed too
869895
if (this.conn.isClosed()) {
896+
// If it was still starting waiting for the secure event,
897+
// we need to reject that promise.
898+
if (this[status] === 'starting') {
899+
this.rejectSecureEstablishedP(
900+
new errors.ErrorQUICConnectionInternal('Connection has closed!'),
901+
);
902+
}
903+
870904
// We actually finally closed here
871905
// Actually the question is that this could be an error
872906
// The act of closing is an error?
@@ -903,8 +937,9 @@ class QUICConnection extends EventTarget {
903937
const timeout = this.conn.timeout();
904938
// If this is `null`, then technically there's nothing to do
905939
if (timeout == null) return;
940+
// Allow an extra 1ms for the delay to fully complete so we can avoid a repeated 0ms delay
906941
this.connTimeOutTimer = new Timer({
907-
delay: timeout,
942+
delay: timeout + 1,
908943
handler: connTimeOutHandler,
909944
});
910945
};
@@ -916,6 +951,7 @@ class QUICConnection extends EventTarget {
916951
if (this.connTimeOutTimer != null) {
917952
this.connTimeOutTimer.cancel();
918953
}
954+
this.logger.debug(`timeout created with delay ${timeout}`);
919955
this.connTimeOutTimer = new Timer({
920956
delay: timeout,
921957
handler: connTimeOutHandler,

src/QUICServer.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import type {
66
StreamCodeToReason,
77
StreamReasonToCode,
88
QUICConfig,
9-
ServerCrypto, VerifyCallback
9+
ServerCrypto,
10+
VerifyCallback,
1011
} from './types';
1112
import type { Header } from './native/types';
1213
import type QUICConnectionMap from './QUICConnectionMap';
@@ -345,8 +346,12 @@ class QUICServer extends EventTarget {
345346
`${QUICConnection.name} ${scid.toString().slice(32)}-${clientConnRef}`,
346347
),
347348
});
348-
await connection.start(); // TODO: pass ctx
349-
console.log('dispatching');
349+
try {
350+
await connection.start(); // TODO: pass ctx
351+
} catch (e) {
352+
// Ignoring any errors here as a failure to connect
353+
return;
354+
}
350355
this.dispatchEvent(
351356
new events.QUICServerConnectionEvent({ detail: connection }),
352357
);

0 commit comments

Comments
 (0)