xref: /aosp_15_r20/external/openscreen/osp/go/quic.go (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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