github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/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/metacubex/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 defer listener.Close() 40 41 conn, err := listener.Accept(context.Background()) 42 if err != nil { 43 return err 44 } 45 46 stream, err := conn.AcceptStream(context.Background()) 47 if err != nil { 48 panic(err) 49 } 50 defer stream.Close() 51 52 // Echo through the loggingWriter 53 _, err = io.Copy(loggingWriter{stream}, stream) 54 return err 55 } 56 57 func clientMain() error { 58 tlsConf := &tls.Config{ 59 InsecureSkipVerify: true, 60 NextProtos: []string{"quic-echo-example"}, 61 } 62 conn, err := quic.DialAddr(context.Background(), addr, tlsConf, nil) 63 if err != nil { 64 return err 65 } 66 defer conn.CloseWithError(0, "") 67 68 stream, err := conn.OpenStreamSync(context.Background()) 69 if err != nil { 70 return err 71 } 72 defer stream.Close() 73 74 fmt.Printf("Client: Sending '%s'\n", message) 75 _, err = stream.Write([]byte(message)) 76 if err != nil { 77 return err 78 } 79 80 buf := make([]byte, len(message)) 81 _, err = io.ReadFull(stream, buf) 82 if err != nil { 83 return err 84 } 85 fmt.Printf("Client: Got '%s'\n", buf) 86 87 return nil 88 } 89 90 // A wrapper for io.Writer that also logs the message. 91 type loggingWriter struct{ io.Writer } 92 93 func (w loggingWriter) Write(b []byte) (int, error) { 94 fmt.Printf("Server: Got '%s'\n", string(b)) 95 return w.Writer.Write(b) 96 } 97 98 // Setup a bare-bones TLS config for the server 99 func generateTLSConfig() *tls.Config { 100 key, err := rsa.GenerateKey(rand.Reader, 1024) 101 if err != nil { 102 panic(err) 103 } 104 template := x509.Certificate{SerialNumber: big.NewInt(1)} 105 certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) 106 if err != nil { 107 panic(err) 108 } 109 keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 110 certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 111 112 tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) 113 if err != nil { 114 panic(err) 115 } 116 return &tls.Config{ 117 Certificates: []tls.Certificate{tlsCert}, 118 NextProtos: []string{"quic-echo-example"}, 119 } 120 }