github.com/MerlinKodo/quic-go@v0.39.2/example/echo/echo.go (about) 1 package main 2 3 import ( 4 "context" 5 "crypto/rand" 6 "crypto/rsa" 7 "crypto/tls" 8 "crypto/x509" 9 "encoding/pem" 10 "fmt" 11 "io" 12 "log" 13 "math/big" 14 15 "github.com/MerlinKodo/quic-go" 16 ) 17 18 const addr = "localhost:4242" 19 20 const message = "foobar" 21 22 // We start a server echoing data on the first stream the client opens, 23 // then connect with a client, send the message, and wait for its receipt. 24 func main() { 25 go func() { log.Fatal(echoServer()) }() 26 27 err := clientMain() 28 if err != nil { 29 panic(err) 30 } 31 } 32 33 // Start a server that echos all data on the first stream opened by the client 34 func echoServer() error { 35 listener, err := quic.ListenAddr(addr, generateTLSConfig(), nil) 36 if err != nil { 37 return err 38 } 39 conn, err := listener.Accept(context.Background()) 40 if err != nil { 41 return err 42 } 43 stream, err := conn.AcceptStream(context.Background()) 44 if err != nil { 45 panic(err) 46 } 47 // Echo through the loggingWriter 48 _, err = io.Copy(loggingWriter{stream}, stream) 49 return err 50 } 51 52 func clientMain() error { 53 tlsConf := &tls.Config{ 54 InsecureSkipVerify: true, 55 NextProtos: []string{"quic-echo-example"}, 56 } 57 conn, err := quic.DialAddr(context.Background(), addr, tlsConf, nil) 58 if err != nil { 59 return err 60 } 61 62 stream, err := conn.OpenStreamSync(context.Background()) 63 if err != nil { 64 return err 65 } 66 67 fmt.Printf("Client: Sending '%s'\n", message) 68 _, err = stream.Write([]byte(message)) 69 if err != nil { 70 return err 71 } 72 73 buf := make([]byte, len(message)) 74 _, err = io.ReadFull(stream, buf) 75 if err != nil { 76 return err 77 } 78 fmt.Printf("Client: Got '%s'\n", buf) 79 80 return nil 81 } 82 83 // A wrapper for io.Writer that also logs the message. 84 type loggingWriter struct{ io.Writer } 85 86 func (w loggingWriter) Write(b []byte) (int, error) { 87 fmt.Printf("Server: Got '%s'\n", string(b)) 88 return w.Writer.Write(b) 89 } 90 91 // Setup a bare-bones TLS config for the server 92 func generateTLSConfig() *tls.Config { 93 key, err := rsa.GenerateKey(rand.Reader, 1024) 94 if err != nil { 95 panic(err) 96 } 97 template := x509.Certificate{SerialNumber: big.NewInt(1)} 98 certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) 99 if err != nil { 100 panic(err) 101 } 102 keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 103 certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 104 105 tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) 106 if err != nil { 107 panic(err) 108 } 109 return &tls.Config{ 110 Certificates: []tls.Certificate{tlsCert}, 111 NextProtos: []string{"quic-echo-example"}, 112 } 113 }