@@ -28,7 +28,7 @@ import QUICStream from './QUICStream';
2828import { quiche } from './native' ;
2929import * as events from './events' ;
3030import * as utils from './utils' ;
31- import { never } from './utils' ;
31+ import { never , promise } from './utils' ;
3232import * as errors from './errors' ;
3333
3434/**
@@ -207,6 +207,103 @@ class QUICConnection extends EventTarget {
207207 protected count = 0 ;
208208 protected verifyCallback : VerifyCallback | undefined ;
209209
210+ public static createQUICConnection (
211+ args :
212+ | {
213+ type : 'client' ;
214+ scid : QUICConnectionId ;
215+ dcid ?: undefined ;
216+ remoteInfo : RemoteInfo ;
217+ config : QUICConfig ;
218+ socket : QUICSocket ;
219+ reasonToCode ?: StreamReasonToCode ;
220+ codeToReason ?: StreamCodeToReason ;
221+ verifyCallback ?: VerifyCallback ;
222+ logger ?: Logger ;
223+ }
224+ | {
225+ type : 'server' ;
226+ scid : QUICConnectionId ;
227+ dcid : QUICConnectionId ;
228+ remoteInfo : RemoteInfo ;
229+ config : QUICConfig ;
230+ socket : QUICSocket ;
231+ reasonToCode ?: StreamReasonToCode ;
232+ codeToReason ?: StreamCodeToReason ;
233+ verifyCallback ?: VerifyCallback ;
234+ logger ?: Logger ;
235+ } ,
236+ ctx ?: Partial < ContextTimed > ,
237+ ) : PromiseCancellable < QUICConnection > ;
238+ @timedCancellable ( true , Infinity , errors . ErrorQUICConnectionStartTimeOut )
239+ public static async createQUICConnection (
240+ args :
241+ | {
242+ type : 'client' ;
243+ scid : QUICConnectionId ;
244+ dcid ?: undefined ;
245+ remoteInfo : RemoteInfo ;
246+ config : QUICConfig ;
247+ socket : QUICSocket ;
248+ reasonToCode ?: StreamReasonToCode ;
249+ codeToReason ?: StreamCodeToReason ;
250+ verifyCallback ?: VerifyCallback ;
251+ logger ?: Logger ;
252+ }
253+ | {
254+ type : 'server' ;
255+ scid : QUICConnectionId ;
256+ dcid : QUICConnectionId ;
257+ remoteInfo : RemoteInfo ;
258+ config : QUICConfig ;
259+ socket : QUICSocket ;
260+ reasonToCode ?: StreamReasonToCode ;
261+ codeToReason ?: StreamCodeToReason ;
262+ verifyCallback ?: VerifyCallback ;
263+ logger ?: Logger ;
264+ } ,
265+ @context ctx : ContextTimed ,
266+ ) : Promise < QUICConnection > {
267+ ctx . signal . throwIfAborted ( ) ;
268+ const abortProm = promise < never > ( ) ;
269+ const abortHandler = ( ) => {
270+ abortProm . rejectP ( ctx . signal . reason ) ;
271+ } ;
272+ ctx . signal . addEventListener ( 'abort' , abortHandler ) ;
273+ const connection = new this ( args ) ;
274+ // This ensures that TLS has been established and verified on both sides
275+ try {
276+ await Promise . race ( [
277+ Promise . all ( [
278+ connection . start ( ) ,
279+ connection . establishedP ,
280+ connection . secureEstablishedP ,
281+ ] ) ,
282+ abortProm . p ,
283+ ] ) ;
284+ } catch ( e ) {
285+ await connection . stop ( {
286+ applicationError : false ,
287+ errorCode : 42 , // FIXME: use a proper code
288+ errorMessage : e . message ,
289+ force : true ,
290+ } ) ;
291+ throw e ;
292+ } finally {
293+ ctx . signal . removeEventListener ( 'abort' , abortHandler ) ;
294+ }
295+ connection . logger . warn ( 'secured' ) ;
296+ // After this is done
297+ // We need to establish the keep alive interval time
298+ if ( connection . config . keepAliveIntervalTime != null ) {
299+ connection . startKeepAliveIntervalTimer (
300+ connection . config . keepAliveIntervalTime ,
301+ ) ;
302+ }
303+
304+ return connection ;
305+ }
306+
210307 public constructor ( {
211308 type,
212309 scid,
@@ -351,79 +448,13 @@ class QUICConnection extends EventTarget {
351448 }
352449
353450 /**
354- * This is the same as basically waiting for `secureEstablishedP`
355- * While this is occurring one can call the `recv` and `send` to make this happen
451+ * This will set up the connection initiate sending
356452 */
357- public start ( ctx ?: Partial < ContextTimed > ) : PromiseCancellable < void > ;
358- @timedCancellable ( true , Infinity , errors . ErrorQUICConnectionStartTimeOut )
359- public async start ( @context ctx : ContextTimed ) : Promise < void > {
453+ public async start ( ) : Promise < void > {
360454 this . logger . info ( `Start ${ this . constructor . name } ` ) ;
361- ctx . signal . throwIfAborted ( ) ;
362- const abortHandler = ( r ) => {
363- this . rejectEstablishedP ( r ) ;
364- this . rejectSecureEstablishedP ( r ) ;
365-
366- // Is this actually true?
367- // Technically the connection is closed
368- this . rejectClosedP ( r ) ;
369- } ;
370- ctx . signal . addEventListener ( 'abort' , abortHandler ) ;
371455 // Set the connection up
372456 this . socket . connectionMap . set ( this . connectionId , this ) ;
373- // Waits for the first short packet after establishment
374- // This ensures that TLS has been established and verified on both sides
375457 await this . send ( ) ;
376- await this . secureEstablishedP
377- . 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- } )
416- . finally ( ( ) => {
417- ctx . signal . removeEventListener ( 'abort' , abortHandler ) ;
418- } ) ;
419- this . logger . warn ( 'secured' ) ;
420- // After this is done
421- // We need to established the keep alive interval time
422- if ( this . config . keepAliveIntervalTime != null ) {
423- this . startKeepAliveIntervalTimer ( this . config . keepAliveIntervalTime ) ;
424- }
425- // Do we remove the on abort event listener?
426- // I forgot...
427458 this . logger . info ( `Started ${ this . constructor . name } ` ) ;
428459 }
429460
@@ -472,7 +503,8 @@ class QUICConnection extends EventTarget {
472503 this . stopKeepAliveIntervalTimer ( ) ;
473504 try {
474505 mon = mon ?? new Monitor < RWLockWriter > ( this . lockbox , RWLockWriter ) ;
475- await mon . withF ( this . lockCode , async ( mon ) => {
506+ // Trigger closing connection in the background and await close later.
507+ void mon . withF ( this . lockCode , async ( mon ) => {
476508 // If this is already closed, then `Done` will be thrown
477509 // Otherwise it can send `CONNECTION_CLOSE` frame
478510 // This can be 0x1c close at the QUIC layer or no errors
@@ -481,10 +513,19 @@ class QUICConnection extends EventTarget {
481513 // 1 packet containing a `CONNECTION_CLOSE` frame too
482514 // (with `NO_ERROR` code if appropriate)
483515 // It must enter into a draining state, and no other packets can be sent
484- this . conn . close ( applicationError , errorCode , Buffer . from ( errorMessage ) ) ;
485- // If we get a `Done` exception we don't bother calling send
486- // The send only gets sent if the `Done` is not the case
487- await this . send ( mon ) ;
516+ try {
517+ this . conn . close (
518+ applicationError ,
519+ errorCode ,
520+ Buffer . from ( errorMessage ) ,
521+ ) ;
522+ // If we get a `Done` exception we don't bother calling send
523+ // The send only gets sent if the `Done` is not the case
524+ await this . send ( mon ) ;
525+ } catch ( e ) {
526+ // Ignore 'Done' if already closed
527+ if ( e . message !== 'Done' ) throw e ;
528+ }
488529 } ) ;
489530 } catch ( e ) {
490531 // If the connection is already closed, `Done` will be thrown
@@ -507,9 +548,15 @@ class QUICConnection extends EventTarget {
507548 this . socket . connectionMap . delete ( this . connectionId ) ;
508549
509550 if ( this . conn . isTimedOut ( ) ) {
551+ const error = this . secured
552+ ? new errors . ErrorQUICConnectionIdleTimeOut ( )
553+ : new errors . ErrorQUICConnectionStartTimeOut ( ) ;
554+
555+ this . rejectEstablishedP ( error ) ;
556+ this . rejectSecureEstablishedP ( error ) ;
510557 this . dispatchEvent (
511558 new events . QUICConnectionErrorEvent ( {
512- detail : new errors . ErrorQUICConnectionIdleTimeOut ( ) ,
559+ detail : error ,
513560 } ) ,
514561 ) ;
515562 }
@@ -521,14 +568,17 @@ class QUICConnection extends EventTarget {
521568 peerError . reason ,
522569 ) . toString ( ) } (${ peerError . errorCode } )`;
523570 this . logger . info ( message ) ;
571+ const error = new errors . ErrorQUICConnectionInternal ( message , {
572+ data : {
573+ type : 'local' ,
574+ ...peerError ,
575+ } ,
576+ } ) ;
577+ this . rejectEstablishedP ( error ) ;
578+ this . rejectSecureEstablishedP ( error ) ;
524579 this . dispatchEvent (
525580 new events . QUICConnectionErrorEvent ( {
526- detail : new errors . ErrorQUICConnectionInternal ( message , {
527- data : {
528- type : 'local' ,
529- ...peerError ,
530- } ,
531- } ) ,
581+ detail : error ,
532582 } ) ,
533583 ) ;
534584 }
@@ -539,14 +589,17 @@ class QUICConnection extends EventTarget {
539589 localError . reason ,
540590 ) . toString ( ) } (${ localError . errorCode } )`;
541591 this . logger . info ( message ) ;
592+ const error = new errors . ErrorQUICConnectionInternal ( message , {
593+ data : {
594+ type : 'local' ,
595+ ...localError ,
596+ } ,
597+ } ) ;
598+ this . rejectEstablishedP ( error ) ;
599+ this . rejectSecureEstablishedP ( error ) ;
542600 this . dispatchEvent (
543601 new events . QUICConnectionErrorEvent ( {
544- detail : new errors . ErrorQUICConnectionInternal ( message , {
545- data : {
546- type : 'local' ,
547- ...localError ,
548- } ,
549- } ) ,
602+ detail : error ,
550603 } ) ,
551604 ) ;
552605 }
@@ -864,7 +917,6 @@ class QUICConnection extends EventTarget {
864917 // Then we just have to proceed!
865918 // Plus if we are called here
866919 this . resolveClosedP ( ) ;
867-
868920 await this . stop (
869921 this . conn . localError ( ) ?? this . conn . peerError ( ) ?? { } ,
870922 mon ,
0 commit comments