echo.go 2.5 KB

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