1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
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"},
}
}
|