1*3f982cf4SFabien Sanglard// Copyright 2018 The Chromium Authors. All rights reserved. 2*3f982cf4SFabien Sanglard// Use of this source code is governed by a BSD-style license that can be 3*3f982cf4SFabien Sanglard// found in the LICENSE file. 4*3f982cf4SFabien Sanglard 5*3f982cf4SFabien Sanglardpackage osp 6*3f982cf4SFabien Sanglard 7*3f982cf4SFabien Sanglard// TODO(jophba): 8*3f982cf4SFabien Sanglard// - avoid NetworkIdleTimeout 9*3f982cf4SFabien Sanglard// - make a client object that can send and receive more than one stream 10*3f982cf4SFabien Sanglard// - make a server object that can send and receive more than one stream 11*3f982cf4SFabien Sanglard 12*3f982cf4SFabien Sanglardimport ( 13*3f982cf4SFabien Sanglard "context" 14*3f982cf4SFabien Sanglard "crypto/rand" 15*3f982cf4SFabien Sanglard "crypto/rsa" 16*3f982cf4SFabien Sanglard "crypto/tls" 17*3f982cf4SFabien Sanglard "crypto/x509" 18*3f982cf4SFabien Sanglard "encoding/pem" 19*3f982cf4SFabien Sanglard "fmt" 20*3f982cf4SFabien Sanglard "io" 21*3f982cf4SFabien Sanglard "log" 22*3f982cf4SFabien Sanglard "math/big" 23*3f982cf4SFabien Sanglard 24*3f982cf4SFabien Sanglard quic "github.com/lucas-clemente/quic-go" 25*3f982cf4SFabien Sanglard) 26*3f982cf4SFabien Sanglard 27*3f982cf4SFabien Sanglardfunc GenerateTlsCert() (*tls.Certificate, error) { 28*3f982cf4SFabien Sanglard key, err := rsa.GenerateKey(rand.Reader, 1024) 29*3f982cf4SFabien Sanglard if err != nil { 30*3f982cf4SFabien Sanglard return nil, err 31*3f982cf4SFabien Sanglard } 32*3f982cf4SFabien Sanglard template := x509.Certificate{SerialNumber: big.NewInt(1)} 33*3f982cf4SFabien Sanglard certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) 34*3f982cf4SFabien Sanglard if err != nil { 35*3f982cf4SFabien Sanglard return nil, err 36*3f982cf4SFabien Sanglard } 37*3f982cf4SFabien Sanglard keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 38*3f982cf4SFabien Sanglard certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 39*3f982cf4SFabien Sanglard 40*3f982cf4SFabien Sanglard tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) 41*3f982cf4SFabien Sanglard if err != nil { 42*3f982cf4SFabien Sanglard return nil, err 43*3f982cf4SFabien Sanglard } 44*3f982cf4SFabien Sanglard return &tlsCert, nil 45*3f982cf4SFabien Sanglard} 46*3f982cf4SFabien Sanglard 47*3f982cf4SFabien Sanglardfunc readAllStreams(ctx context.Context, session quic.Session, streams chan<- io.ReadWriteCloser) { 48*3f982cf4SFabien Sanglard for !done(ctx) { 49*3f982cf4SFabien Sanglard stream, err := session.AcceptStream() 50*3f982cf4SFabien Sanglard if err != nil && !done(ctx) { 51*3f982cf4SFabien Sanglard log.Println("Failed to accept stream with QUIC", err.Error()) 52*3f982cf4SFabien Sanglard } 53*3f982cf4SFabien Sanglard streams <- stream 54*3f982cf4SFabien Sanglard } 55*3f982cf4SFabien Sanglard} 56*3f982cf4SFabien Sanglard 57*3f982cf4SFabien Sanglard// Returns a quic.Session object with a .OpenStreamSync method to send streams 58*3f982cf4SFabien Sanglardfunc DialAsQuicClient(ctx context.Context, hostname string, port int) (quic.Session, error) { 59*3f982cf4SFabien Sanglard // TODO(jophba): Change InsecureSkipVerify 60*3f982cf4SFabien Sanglard tlsConfig := &tls.Config{InsecureSkipVerify: true} 61*3f982cf4SFabien Sanglard addr := fmt.Sprintf("%s:%d", hostname, port) 62*3f982cf4SFabien Sanglard session, err := quic.DialAddrContext(ctx, addr, tlsConfig, nil) 63*3f982cf4SFabien Sanglard return session, err 64*3f982cf4SFabien Sanglard} 65*3f982cf4SFabien Sanglard 66*3f982cf4SFabien Sanglard// Reads in streams 67*3f982cf4SFabien Sanglardfunc RunQuicServer(ctx context.Context, port int, cert tls.Certificate, streams chan<- io.ReadWriteCloser) error { 68*3f982cf4SFabien Sanglard addr := fmt.Sprintf(":%d", port) 69*3f982cf4SFabien Sanglard tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}} 70*3f982cf4SFabien Sanglard listener, err := quic.ListenAddr(addr, tlsConfig, nil) 71*3f982cf4SFabien Sanglard if err != nil { 72*3f982cf4SFabien Sanglard return err 73*3f982cf4SFabien Sanglard } 74*3f982cf4SFabien Sanglard go func() { 75*3f982cf4SFabien Sanglard waitUntilDone(ctx) 76*3f982cf4SFabien Sanglard listener.Close() 77*3f982cf4SFabien Sanglard }() 78*3f982cf4SFabien Sanglard for { 79*3f982cf4SFabien Sanglard session, err := listener.Accept() 80*3f982cf4SFabien Sanglard if err != nil && !done(ctx) { 81*3f982cf4SFabien Sanglard log.Println("Failed to accept session with QUIC:", err.Error()) 82*3f982cf4SFabien Sanglard } 83*3f982cf4SFabien Sanglard go readAllStreams(ctx, session, streams) 84*3f982cf4SFabien Sanglard } 85*3f982cf4SFabien Sanglard} 86