github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/prio_packs_example/example_traffic.go (about)

     1  package main
     2  
     3  // https://fossies.org/linux/quic-go/example/echo/echo.go
     4  // if error:
     5  // sudo sysctl -w net.core.rmem_max=2500000
     6  // sudo sysctl -w net.core.wmem_max=2500000
     7  
     8  import (
     9  	"context"
    10  	"crypto/rand"
    11  	"crypto/rsa"
    12  	"crypto/tls"
    13  	"crypto/x509"
    14  	"encoding/pem"
    15  	"fmt"
    16  	"math/big"
    17  	"os"
    18  
    19  	"github.com/danielpfeifer02/quic-go-prio-packs"
    20  	"github.com/danielpfeifer02/quic-go-prio-packs/crypto_turnoff"
    21  	"github.com/danielpfeifer02/quic-go-prio-packs/priority_setting"
    22  )
    23  
    24  const addr = "192.168.11.2:4242"
    25  
    26  const message = "foobar"
    27  
    28  // We start a server echoing data on the first stream the client opens,
    29  // then connect with a client, send the message, and wait for its receipt.
    30  func main() {
    31  
    32  	// check that there is an argument
    33  	if len(os.Args) != 2 {
    34  		fmt.Println("Usage: go run example.go server|client")
    35  		return
    36  	}
    37  
    38  	crypto_turnoff.CRYPTO_TURNED_OFF = true
    39  
    40  	// check if the argument is "server" or "client"
    41  	is_server := os.Args[1] == "server"
    42  	is_client := os.Args[1] == "client"
    43  
    44  	if is_server {
    45  		err := echoServer()
    46  		if err != nil {
    47  			panic(err)
    48  		}
    49  	} else if is_client {
    50  		err := clientMain()
    51  		if err != nil {
    52  			panic(err)
    53  		}
    54  	} else {
    55  		fmt.Println("Usage: go run example.go server|client")
    56  		return
    57  	}
    58  }
    59  
    60  // Start a server that echos all data on the first stream opened by the client
    61  func echoServer() error {
    62  
    63  	listener, err := quic.ListenAddr(addr, generateTLSConfig(), generateQUICConfig())
    64  	if err != nil {
    65  		return err
    66  	}
    67  	defer listener.Close()
    68  
    69  	// Accept the incoming connection from the client
    70  	conn, err := listener.Accept(context.Background())
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	go func() {
    76  		for {
    77  			buf, err := conn.ReceiveDatagram(context.Background())
    78  			if err != nil {
    79  				panic(err)
    80  			}
    81  			fmt.Printf("	>>Server: Got '%s'\n", string(buf))
    82  			err = conn.SendDatagram(buf)
    83  			if err != nil {
    84  				panic(err)
    85  			}
    86  			fmt.Println("	>>Server: Echoing via datagram")
    87  		}
    88  	}()
    89  
    90  	// Accept the first stream opened by the client
    91  	stream_high_prio, err := conn.AcceptStream(context.Background())
    92  	if err != nil {
    93  		panic(err)
    94  	}
    95  	defer stream_high_prio.Close()
    96  
    97  	// Handle the first stream opened by the client
    98  	// in a separate goroutine
    99  	go ListenAndRepeat(stream_high_prio)
   100  
   101  	// Accept the second stream opened by the client
   102  	stream_low_prio, err2 := conn.AcceptStream(context.Background())
   103  	if err2 != nil {
   104  		panic(err2)
   105  	}
   106  	defer stream_low_prio.Close()
   107  
   108  	// Handle the second stream opened by the client
   109  	// in the current goroutine
   110  	// Echo through the loggingWriter
   111  	ListenAndRepeat(stream_low_prio)
   112  
   113  	return nil
   114  }
   115  
   116  func ListenAndRepeat(stream quic.Stream) {
   117  	fmt.Println("Echo up and running")
   118  	for {
   119  		// Read and echo the message
   120  		buf := make([]byte, 1024)
   121  		n, err := stream.Read(buf)
   122  		if err != nil {
   123  			panic(err)
   124  		}
   125  		fmt.Printf("	>>Server: Got '%s'\n	>>Server: Echoing on same stream\n", string(buf[:n]))
   126  		_, err = stream.Write(buf)
   127  		if err != nil {
   128  			panic(err)
   129  		}
   130  	}
   131  
   132  }
   133  
   134  func clientMain() error {
   135  	tlsConf := &tls.Config{
   136  		InsecureSkipVerify: true,
   137  		NextProtos:         []string{"quic-echo-example"},
   138  	}
   139  	conn, err := quic.DialAddr(context.Background(), addr, tlsConf, generateQUICConfig())
   140  	if err != nil {
   141  		return err
   142  	}
   143  	defer conn.CloseWithError(0, "")
   144  
   145  	// Open a new stream with high priority
   146  	stream_high_prio, err := conn.OpenStreamSyncWithPriority(context.Background(), priority_setting.HighPriority)
   147  	if err != nil {
   148  		return err
   149  	}
   150  	defer stream_high_prio.Close()
   151  	fmt.Printf("Prio of stream one (clientside): %d\n", stream_high_prio.Priority())
   152  
   153  	// Open a new stream with low priority
   154  	stream_low_prio, err := conn.OpenStreamSyncWithPriority(context.Background(), priority_setting.LowPriority)
   155  	if err != nil {
   156  		return err
   157  	}
   158  	defer stream_low_prio.Close()
   159  	fmt.Printf("Prio of stream two (clientside): %d\n", stream_low_prio.Priority())
   160  
   161  	for {
   162  
   163  		// Print info field for the user
   164  		fmt.Println("What would you like to do?")
   165  		fmt.Println("1: Send a message with high priority over stream")
   166  		fmt.Println("2: Send a message with low priority over stream")
   167  		fmt.Println("3: Send a message with high priority via datagrams")
   168  		fmt.Println("4: Send a message with low priority via datagrans")
   169  		fmt.Println("5: Quit")
   170  
   171  		// Read the user's choice
   172  		var choice int
   173  		fmt.Scan(&choice)
   174  		// clear screen on terminal
   175  		fmt.Print("\033[H\033[2J")
   176  
   177  		var stream quic.Stream
   178  		var is_stream bool = false
   179  		var datagram_prio priority_setting.Priority
   180  
   181  		// Check the user's choice
   182  		switch choice {
   183  		case 1:
   184  			stream = stream_high_prio
   185  			is_stream = true
   186  		case 2:
   187  			stream = stream_low_prio
   188  			is_stream = true
   189  		case 3:
   190  			datagram_prio = priority_setting.HighPriority
   191  		case 4:
   192  			datagram_prio = priority_setting.LowPriority
   193  		case 5:
   194  			return nil
   195  		default:
   196  			fmt.Println("Invalid choice")
   197  			continue
   198  		}
   199  
   200  		fmt.Printf("	>>Client: Sending '%s'\n", message)
   201  
   202  		var buf []byte
   203  		var n int
   204  		if is_stream {
   205  			_, err := stream.Write([]byte(message))
   206  			if err != nil {
   207  				return err
   208  			}
   209  
   210  			buf = make([]byte, 1024)
   211  			n, err = stream.Read(buf)
   212  			if err != nil {
   213  				return err
   214  			}
   215  		} else {
   216  			err := conn.SendDatagramWithPriority([]byte(message), datagram_prio)
   217  			if err != nil {
   218  				return err
   219  			}
   220  
   221  			buf, err = conn.ReceiveDatagram(context.Background())
   222  			if err != nil {
   223  				return err
   224  			}
   225  			n = len(buf)
   226  		}
   227  
   228  		fmt.Printf("	>>Client: Got '%s'\n\n", buf[:n])
   229  
   230  	}
   231  }
   232  
   233  // Setup a bare-bones TLS config for the server
   234  func generateTLSConfig() *tls.Config {
   235  	key, err := rsa.GenerateKey(rand.Reader, 1024)
   236  	if err != nil {
   237  		panic(err)
   238  	}
   239  	template := x509.Certificate{SerialNumber: big.NewInt(1)}
   240  	certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
   241  	if err != nil {
   242  		panic(err)
   243  	}
   244  	keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
   245  	certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
   246  
   247  	tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
   248  	if err != nil {
   249  		panic(err)
   250  	}
   251  
   252  	// Create a KeyLogWriter
   253  	keyLogFile, err := os.OpenFile("tls.keylog", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
   254  	if err != nil {
   255  		panic(err)
   256  	}
   257  	// defer keyLogFile.Close() // TODO why not close?
   258  
   259  	return &tls.Config{
   260  		Certificates: []tls.Certificate{tlsCert},
   261  		NextProtos:   []string{"quic-echo-example"},
   262  		KeyLogWriter: keyLogFile,
   263  		CipherSuites: []uint16{tls.TLS_CHACHA20_POLY1305_SHA256},
   264  	}
   265  }
   266  
   267  func generateQUICConfig() *quic.Config {
   268  	return &quic.Config{
   269  		EnableDatagrams: true,
   270  	}
   271  }