package main import ( "context" "crypto/ed25519" "crypto/rand" "crypto/tls" "crypto/x509" "fmt" "io" "log" "math/big" "github.com/quic-go/quic-go" ) const addr = "localhost:4242" const message = "foobar" // We start a server echoing data on the first stream the client opens, // then connect with a client, send the message, and wait for its receipt. func main() { go func() { log.Fatal(echoServer()) }() if err := clientMain(); err != nil { panic(err) } } // Start a server that echos all data on the first stream opened by the client func echoServer() error { listener, err := quic.ListenAddr(addr, generateTLSConfig(), nil) if err != nil { return err } defer listener.Close() conn, err := listener.Accept(context.Background()) if err != nil { return err } stream, err := conn.AcceptStream(context.Background()) if err != nil { panic(err) } defer stream.Close() // Echo through the loggingWriter _, err = io.Copy(loggingWriter{stream}, stream) return err } func clientMain() error { tlsConf := &tls.Config{ InsecureSkipVerify: true, NextProtos: []string{"quic-echo-example"}, } conn, err := quic.DialAddr(context.Background(), addr, tlsConf, nil) if err != nil { return err } defer conn.CloseWithError(0, "") stream, err := conn.OpenStreamSync(context.Background()) if err != nil { return err } defer stream.Close() fmt.Printf("Client: Sending '%s'\n", message) if _, err := stream.Write([]byte(message)); err != nil { return err } buf := make([]byte, len(message)) if _, err := io.ReadFull(stream, buf); err != nil { return err } fmt.Printf("Client: Got '%s'\n", buf) return nil } // A wrapper for io.Writer that also logs the message. type loggingWriter struct{ io.Writer } func (w loggingWriter) Write(b []byte) (int, error) { fmt.Printf("Server: Got '%s'\n", string(b)) return w.Writer.Write(b) } // Setup a bare-bones TLS config for the server func generateTLSConfig() *tls.Config { _, priv, err := ed25519.GenerateKey(rand.Reader) if err != nil { panic(err) } template := x509.Certificate{SerialNumber: big.NewInt(1)} certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv) if err != nil { panic(err) } return &tls.Config{ Certificates: []tls.Certificate{{ Certificate: [][]byte{certDER}, PrivateKey: priv, }}, NextProtos: []string{"quic-echo-example"}, } }