diff --git a/example/main.go b/example/main.go index 81263f971..e0f3257b8 100644 --- a/example/main.go +++ b/example/main.go @@ -2,7 +2,6 @@ package main import ( "crypto/md5" - "crypto/tls" "errors" "flag" "fmt" @@ -11,13 +10,13 @@ import ( "log" "mime/multipart" "net/http" + "os" "strings" "sync" _ "net/http/pprof" "github.com/lucas-clemente/quic-go/h2quic" - "github.com/lucas-clemente/quic-go/testdata" "github.com/lucas-clemente/quic-go/utils" ) @@ -109,8 +108,9 @@ func main() { verbose := flag.Bool("v", false, "verbose") bs := binds{} flag.Var(&bs, "bind", "bind to") - certPath := flag.String("certpath", "", "certificate directory") + certPath := flag.String("certpath", os.Getenv("GOPATH")+"/src/github.com/lucas-clemente/quic-go/example/", "certificate directory") www := flag.String("www", "/var/www", "www data") + tcp := flag.Bool("tcp", false, "also listen on TCP") flag.Parse() if *verbose { @@ -119,19 +119,8 @@ func main() { utils.SetLogLevel(utils.LogLevelInfo) } - var tlsConfig *tls.Config - if *certPath == "" { - tlsConfig = testdata.GetTLSConfig() - } else { - var err error - cert, err := tls.LoadX509KeyPair(*certPath+"/fullchain.pem", *certPath+"/privkey.pem") - if err != nil { - panic(err) - } - tlsConfig = &tls.Config{ - Certificates: []tls.Certificate{cert}, - } - } + certFile := *certPath + "/fullchain.pem" + keyFile := *certPath + "/privkey.pem" http.Handle("/", http.FileServer(http.Dir(*www))) @@ -144,14 +133,12 @@ func main() { for _, b := range bs { bCap := b go func() { - server := h2quic.Server{ - // CloseAfterFirstRequest: true, - Server: &http.Server{ - Addr: bCap, - TLSConfig: tlsConfig, - }, + var err error + if *tcp { + err = h2quic.ListenAndServe(bCap, certFile, keyFile, nil) + } else { + err = h2quic.ListenAndServeQUIC(bCap, certFile, keyFile, nil) } - err := server.ListenAndServe() if err != nil { fmt.Println(err) } diff --git a/h2quic/server.go b/h2quic/server.go index a4f75388d..4e301b55a 100644 --- a/h2quic/server.go +++ b/h2quic/server.go @@ -257,3 +257,79 @@ func ListenAndServeQUIC(addr, certFile, keyFile string, handler http.Handler) er } return server.ListenAndServeTLS(certFile, keyFile) } + +// ListenAndServe listens on the given network address for both, TLS and QUIC +// connetions in parallel. It returns if one of the two returns an error. +// http.DefaultServeMux is used when handler is nil. +// The correct Alt-Svc headers for QUIC are set. +func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error { + // Load certs + var err error + certs := make([]tls.Certificate, 1) + certs[0], err = tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return err + } + // We currently only use the cert-related stuff from tls.Config, + // so we don't need to make a full copy. + config := &tls.Config{ + Certificates: certs, + } + + // Open the listeners + udpAddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + return err + } + udpConn, err := net.ListenUDP("udp", udpAddr) + if err != nil { + return err + } + defer udpConn.Close() + + tcpAddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return err + } + tcpConn, err := net.ListenTCP("tcp", tcpAddr) + if err != nil { + return err + } + defer tcpConn.Close() + + // Start the servers + httpServer := &http.Server{ + Addr: addr, + TLSConfig: config, + } + + quicServer := &Server{ + Server: httpServer, + } + + if handler == nil { + handler = http.DefaultServeMux + } + httpServer.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + quicServer.SetQuicHeaders(w.Header()) + handler.ServeHTTP(w, r) + }) + + hErr := make(chan error) + qErr := make(chan error) + go func() { + hErr <- httpServer.Serve(tcpConn) + }() + go func() { + qErr <- quicServer.Serve(udpConn) + }() + + select { + case err := <-hErr: + quicServer.Close() + return err + case err := <-qErr: + // Cannot close the HTTP server or wait for requests to complete properly :/ + return err + } +}