import { Flight1 } from "./flight/client/flight1" ; import { parsePacket } from "./record/receive" ; import { ServerHelloVerifyRequest } from "./handshake/message/server/helloVerifyRequest" ; import { Flight3 } from "./flight/client/flight3" ; import { HandshakeType } from "./handshake/const" ; import { Flight5 } from "./flight/client/flight5" ; import { FragmentedHandshake } from "./record/message/fragment" ; import { ContentType } from "./record/const" ; import { SessionType } from "./cipher/suites/abstract" ; import { DtlsSocket , Options } from "./socket" ; import { DtlsContext } from "./context/dtls" ; import { CipherContext } from "./context/cipher" ; import { SrtpContext } from "./context/srtp" ; export class DtlsClient extends DtlsSocket { private flight4Buffer : FragmentedHandshake [ ] = [ ] ; constructor ( options ) { super ( options , true ) ; this . udp . socket . onData = this . udpOnMessage ; } connect ( ) { this . dtls = new DtlsContext ( this . options ) ; this . cipher = new CipherContext ( this . options . cert , this . options . key , SessionType . CLIENT ) ; this . srtp = new SrtpContext ( ) ; new Flight1 ( this . udp , this . dtls , this . cipher ) . exec ( this . extensions ) ; } private udpOnMessage = ( data ) => { const messages = parsePacket ( this . dtls , this . cipher ) ( data ) ; if ( messages . length === 0 ) { return ; } switch ( messages [ messages . length - 1 ] . type ) { case ContentType . handshake : { this . handleHandshakes ( messages . map ( ( v ) => v . data as FragmentedHandshake ) . filter ( ( v ) => v ) ) ; } break ; case ContentType . applicationData : { this . onData ( messages [ 0 ] . data as Buffer ) ; } break ; case ContentType . alert : console . log ( "on alert" , messages [ messages . length - 1 ] . data ) ; this . onClose ( ) ; break ; } } ; private handleHandshakes ( handshakes ) { if ( this . flight4Buffer . length > 0 ) { this . flight4Buffer = [ ... this . flight4Buffer , ... handshakes ] ; } else if ( handshakes [ 0 ] . msg_type === HandshakeType . server_hello ) { this . flight4Buffer = handshakes ; } switch ( handshakes . slice ( - 1 ) [ 0 ] . msg_type ) { case HandshakeType . hello_verify_request : { const verifyReq = ServerHelloVerifyRequest . deSerialize ( handshakes [ 0 ] . fragment ) ; new Flight3 ( this . udp , this . dtls ) . exec ( verifyReq ) ; } break ; case HandshakeType . server_hello_done : { const fragments = [ HandshakeType . server_hello , HandshakeType . certificate , HandshakeType . server_key_exchange , HandshakeType . certificate_request , HandshakeType . server_hello_done , ] . map ( ( type ) => { const fragments = FragmentedHandshake . findAllFragments ( this . flight4Buffer , type ) ; if ( fragments . length === 0 ) return ( undefined as any ) as FragmentedHandshake ; return FragmentedHandshake . assemble ( fragments ) ; } ) . filter ( ( v ) => v ) ; this . flight4Buffer = [ ] ; new Flight5 ( this . udp , this . dtls , this . cipher , this . srtp ) . exec ( fragments ) ; } break ; case HandshakeType . finished : { this . dtls . flight = 7 ; if ( this . onConnect ) this . onConnect ( ) ; } break ; } } }