@@ -24,7 +24,9 @@ import {
2424import Logger from '@matrixai/logger' ;
2525import { Timer } from '@matrixai/timer' ;
2626import { context , timedCancellable } from '@matrixai/contexts/dist/decorators' ;
27- import { buildQuicheConfig } from './config' ;
27+ import { withF } from '@matrixai/resources' ;
28+ import { utils as contextsUtils } from '@matrixai/contexts' ;
29+ import { buildQuicheConfig , minIdleTimeout } from './config' ;
2830import QUICStream from './QUICStream' ;
2931import { quiche } from './native' ;
3032import * as events from './events' ;
@@ -235,7 +237,11 @@ class QUICConnection extends EventTarget {
235237 } ,
236238 ctx ?: Partial < ContextTimedInput > ,
237239 ) : PromiseCancellable < QUICConnection > ;
238- @timedCancellable ( true , Infinity , errors . ErrorQUICConnectionStartTimeOut )
240+ @timedCancellable (
241+ true ,
242+ minIdleTimeout ,
243+ errors . ErrorQUICConnectionStartTimeOut ,
244+ )
239245 public static async createQUICConnection (
240246 args :
241247 | {
@@ -265,40 +271,20 @@ class QUICConnection extends EventTarget {
265271 } ,
266272 @context ctx : ContextTimed ,
267273 ) : Promise < QUICConnection > {
268- const timeoutTime = ctx . timer . getTimeout ( ) ;
269- if ( timeoutTime !== Infinity && timeoutTime >= args . config . maxIdleTimeout ) {
270- throw new errors . ErrorQUICConnectionInvalidConfig (
271- 'connection timeout timer must be strictly less than maxIdleTimeout' ,
272- ) ;
273- }
274274 ctx . signal . throwIfAborted ( ) ;
275275 const abortProm = promise < never > ( ) ;
276276 const abortHandler = ( ) => {
277277 abortProm . rejectP ( ctx . signal . reason ) ;
278278 } ;
279279 ctx . signal . addEventListener ( 'abort' , abortHandler ) ;
280280 const connection = new this ( args ) ;
281- const startProm = connection . start ( ) . then ( async ( ) => {
282- // If this is a server connection, we need to process the packet that created it
283- if ( args . type === 'server' ) {
284- await utils . withMonitor (
285- undefined ,
286- connection . lockbox ,
287- RWLockWriter ,
288- async ( mon ) => {
289- await mon . withF ( connection . lockCode , async ( mon ) => {
290- await connection . recv ( args . data , args . remoteInfo , mon ) ;
291- await connection . send ( mon ) ;
292- } ) ;
293- } ,
294- ) ;
295- }
296- } ) ;
281+ // If it's a server connection we want to pass the initial packet
282+ const data = args . type === 'server' ? args . data : undefined ;
297283 // This ensures that TLS has been established and verified on both sides
298284 try {
299285 await Promise . race ( [
300286 Promise . all ( [
301- startProm ,
287+ connection . start ( data ) ,
302288 connection . establishedP ,
303289 connection . secureEstablishedP ,
304290 ] ) ,
@@ -471,12 +457,25 @@ class QUICConnection extends EventTarget {
471457
472458 /**
473459 * This will set up the connection initiate sending
460+ * @param data - the initial packet that triggered the creation of the connection.
474461 */
475- public async start ( ) : Promise < void > {
462+ public async start ( data ?: Uint8Array ) : Promise < void > {
476463 this . logger . info ( `Start ${ this . constructor . name } ` ) ;
477464 // Set the connection up
478465 this . socket . connectionMap . set ( this . connectionId , this ) ;
479- await this . send ( ) ;
466+ await withF (
467+ [ contextsUtils . monitor ( this . lockbox , RWLockWriter ) ] ,
468+ async ( [ mon ] ) => {
469+ if ( data != null ) {
470+ await this . recv (
471+ data ,
472+ { host : this . _remoteHost , port : this . _remotePort } ,
473+ mon ,
474+ ) ;
475+ }
476+ await this . send ( mon ) ;
477+ } ,
478+ ) ;
480479 this . logger . info ( `Started ${ this . constructor . name } ` ) ;
481480 }
482481
@@ -535,7 +534,7 @@ class QUICConnection extends EventTarget {
535534 this . stopKeepAliveIntervalTimer ( ) ;
536535
537536 // Trigger closing connection in the background and await close later.
538- void utils . withMonitor ( mon , this . lockbox , RWLockWriter , async ( mon ) => {
537+ void this . withMonitor ( mon , this . lockbox , RWLockWriter , async ( mon ) => {
539538 await mon . withF ( this . lockCode , async ( mon ) => {
540539 // If this is already closed, then `Done` will be thrown
541540 // Otherwise it can send `CONNECTION_CLOSE` frame
@@ -665,13 +664,15 @@ class QUICConnection extends EventTarget {
665664 public async recv (
666665 data : Uint8Array ,
667666 remoteInfo : RemoteInfo ,
668- mon : Monitor < RWLockWriter > ,
667+ mon ? : Monitor < RWLockWriter > ,
669668 ) : Promise < void > {
670- if ( ! mon . isLocked ( this . lockCode ) ) {
671- return mon . withF ( this . lockCode , async ( mon ) => {
672- return this . recv ( data , remoteInfo , mon ) ;
673- } ) ;
674- }
669+ await this . withMonitor ( mon , this . lockbox , RWLockWriter , async ( mon ) => {
670+ if ( ! mon . isLocked ( this . lockCode ) ) {
671+ return mon . withF ( this . lockCode , async ( mon ) => {
672+ return this . recv ( data , remoteInfo , mon ) ;
673+ } ) ;
674+ }
675+ } ) ;
675676
676677 try {
677678 // The remote information may be changed on each receive
@@ -775,7 +776,7 @@ class QUICConnection extends EventTarget {
775776 * @internal
776777 */
777778 public async send ( mon ?: Monitor < RWLockWriter > ) : Promise < void > {
778- await utils . withMonitor ( mon , this . lockbox , RWLockWriter , async ( mon ) => {
779+ await this . withMonitor ( mon , this . lockbox , RWLockWriter , async ( mon ) => {
779780 if ( ! mon . isLocked ( this . lockCode ) ) {
780781 return mon . withF ( this . lockCode , async ( mon ) => {
781782 return this . send ( mon ) ;
@@ -1083,6 +1084,26 @@ class QUICConnection extends EventTarget {
10831084 return quicStream ;
10841085 } ) ;
10851086 }
1087+
1088+ /**
1089+ * Used as a clean way to create a new monitor if it doesn't exist, otherwise uses the existing one.
1090+ */
1091+ protected async withMonitor < T > (
1092+ mon : Monitor < RWLockWriter > | undefined ,
1093+ lockBox : LockBox < RWLockWriter > ,
1094+ lockConstructor : { new ( ) : RWLockWriter } ,
1095+ f : ( mon : Monitor < RWLockWriter > ) => Promise < T > ,
1096+ locksPending ?: Map < string , { count : number } > ,
1097+ ) : Promise < T > {
1098+ if ( mon == null ) {
1099+ return await withF (
1100+ [ contextsUtils . monitor ( lockBox , lockConstructor , locksPending ) ] ,
1101+ ( [ mon ] ) => f ( mon ) ,
1102+ ) ;
1103+ } else {
1104+ return f ( mon ) ;
1105+ }
1106+ }
10861107}
10871108
10881109export default QUICConnection ;
0 commit comments