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  }