diff --git a/example/fullchain.pem b/example/fullchain.pem new file mode 100644 index 00000000..a47b38fd --- /dev/null +++ b/example/fullchain.pem @@ -0,0 +1,56 @@ +-----BEGIN CERTIFICATE----- +MIIFBDCCA+ygAwIBAgISA94pDcZO/REqWtXzzvWMOkaXMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA0MTUxNjA4MDBaFw0x +NjA3MTQxNjA4MDBaMBsxGTAXBgNVBAMTEHF1aWMuY2xlbWVudGUuaW8wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3RBFkQVkwAiJ1KEhmQ1S3xkWev3qA +BBSj/2Cxe8uIC6v8oy/nV7Fj9JFlve7S3kJD/SJm7QFTF42vMkPVBG2xP4gmiwgC +0dweP4BVPfOP6ghMpz2iwE5oWaRJX8hUVgSGhS4OGjgShnYLztsldnvz0/vkAo7W +9+CYmUVdV77OZBD6SmN4H6V0D6BdjbelluZUVI6jcCG9BJxShEmuiCpbBDwzOuO6 +kjzYjJflOqmKwZu9Vn58xGuXjy7CjdOb7QJf44+Gx4SsvV+bisX8bricSLBVZ6VS +wmnCgnitPrRcy2x/5GgwvR6HitfUeWaVHTmf+m35ZQmAbvR5cqt6JG+/AgMBAAGj +ggIRMIICDTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG +AQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFIkwEhLNueagmTAPrBOYgNI/ +/I+mMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMHAGCCsGAQUFBwEB +BGQwYjAvBggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0 +Lm9yZy8wLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlw +dC5vcmcvMBsGA1UdEQQUMBKCEHF1aWMuY2xlbWVudGUuaW8wgf4GA1UdIASB9jCB +8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRw +Oi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENl +cnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFy +dGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRl +IFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0 +b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAG2/zVQd6cdZPVUehS2CBi7Vj87CjUQXZ ++KeaVciClvzszF7M4VDYav5n9KuX53aYHz5QHFBYwFrvBUdm/4HZcZbiEgxNsvIj +He7X98hmEe2WvHcog8kwu7oaQQ0NG6nJGXSpYklFZIrfGcWUXreVYV/iAKr68VRr ++9JGomzyvWrb5nEdnc5cR5M9Jz+JpRLsWfjppYk8kL3D8bi/JtEhwyXGkzUzUzdJ ++VGzUnlZs2qB9g12f1maxBSh8tDpDPZXXfCKrQLtaXFseMjVGGnD0ZK8d4Oft7gn +SEAPvTi0dpSsoihdSaSR0AVpyUZTuPd+IKy6IZR7WUKT0akmSn1FJQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- diff --git a/example/privkey.pem b/example/privkey.pem new file mode 100644 index 00000000..71d9af8d --- /dev/null +++ b/example/privkey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC3RBFkQVkwAiJ1 +KEhmQ1S3xkWev3qABBSj/2Cxe8uIC6v8oy/nV7Fj9JFlve7S3kJD/SJm7QFTF42v +MkPVBG2xP4gmiwgC0dweP4BVPfOP6ghMpz2iwE5oWaRJX8hUVgSGhS4OGjgShnYL +ztsldnvz0/vkAo7W9+CYmUVdV77OZBD6SmN4H6V0D6BdjbelluZUVI6jcCG9BJxS +hEmuiCpbBDwzOuO6kjzYjJflOqmKwZu9Vn58xGuXjy7CjdOb7QJf44+Gx4SsvV+b +isX8bricSLBVZ6VSwmnCgnitPrRcy2x/5GgwvR6HitfUeWaVHTmf+m35ZQmAbvR5 +cqt6JG+/AgMBAAECggEBAIoF+8sz5EXh9a2izxQltZJLA3gR4eK0MA9rcJl7EMi/ +caJuDNABHZqYQUENEOdDeUjXRqeZ7Bt2a8D87FVsZmjN3m6Y20m0YEFvtel9JQjI +S8PfWO5QQz0X9kFEoA3UUsg1WYBJgt2A4zr1adsHJ0d16gnJW2bPfRmwpastQIkT +ULBjqL/pWIcmLlx5aV7AdWpMQYUKFJmzT/fQbQUpimtsUcWisUFR86hs+XPTfRtR +3Gqw0/nZw7tL+Zu2JkGXr+irV3R/tVeEUM+O1M073rKfFkK/NAbjJRCnzhv0Himj +PcsRdtdQRKLzU6m8Q0cODZQwIYxaI6bgU3h84spp9/ECgYEA7DjyhzGtFQrNO/3c +1pkeNPp4y6NTgBRJ1nwx2yCzt9sSmi9laqxBmD84Kryhdbuxu9qsM/hY4hIfaGpJ +w9g6rV0MxTSrqcwmFzA3WFYKnvLYkRd+4XvIDds/ablHAifLRHTClniDUXAFzyu7 +xpwbhCJ9KAW3G+wT5PtD6ANfqDMCgYEAxpwUtXinPKUj3cc6GLM2Bf4JYkt5o67Z +p8+zrRtD82xVr70rVmjN8jA+/vsTdLr+x+j8hBMYI47A1ipgSYYR3IOllvFyA/rb +jrq5YnJTEVxbHJufmU8n2ycALbCk9X0jjX3fs3JV+ZjPsmaKFetekQRNBL5U6mkR +iJXXkfohfkUCgYAE9MDp4zntaheaPZ5Hhlji5appI1kaI9LUxDBLl6kNn3QJdhsb +nNeXeSQViXWdwb1d4p2gTYKX46dzCl/X0w6QGpatAIjlfBoEfId8u/lnElNG4AZS +dsVgvQvcjP2XZvxVyFlYzNh8eew1R4aeCSJuqEaV82C/HjngoQDwujlkjwKBgQCu +hfb4pEYo12CWAPx/OfON/nZWhsYj3IDsompcAiqK3DbLj+pmKwBWAqlIvG6TU8KQ +/p3unSzICihPybsEwKgvYwt+gTpUXvrSCCjhZl6yUbrKf8IWIOWAAVx5ydCa29UC +/4o0kJMWGn7gYJSUwFhADEx1j57kwWEj6bAdWXRXFQKBgQCLIdb9Qb6t9lcrNuGE +OlhYundDeaV1AggNebbmoB5KejNHPyalnjK0MNLf4KwHfCrDFY/54HGGslVdQSMd +Kl3l1L9H4eK8C6qP7Koh9J5Uey8kaIR12L3Afw8Gx7w+S48zo9LzrPoj8GwzOfH3 +D3Iz0NBdmZDK/BDSq2B9ByYIRg== +-----END PRIVATE KEY----- diff --git a/h2quic/integration_test.go b/h2quic/integration_test.go index 4c89ac6f..a39bad39 100644 --- a/h2quic/integration_test.go +++ b/h2quic/integration_test.go @@ -25,13 +25,13 @@ import ( . "github.com/onsi/gomega/gexec" ) -const port = "6729" -const host = "127.0.0.1" -const addr = host + ":" + port - -const dataLen = 50 * 1024 - var _ = Describe("Integration tests", func() { + const port = "6729" + const host = "127.0.0.1" + const addr = host + ":" + port + + const dataLen = 50 * 1024 + var ( server *h2quic.Server clientPath string diff --git a/h2quic/server_test.go b/h2quic/server_test.go index bc54c1bd..097540fb 100644 --- a/h2quic/server_test.go +++ b/h2quic/server_test.go @@ -2,7 +2,9 @@ package h2quic import ( "net/http" + "os" "sync" + "time" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" @@ -27,6 +29,9 @@ func (s *mockSession) GetOrOpenStream(id protocol.StreamID) (utils.Stream, error func (s *mockSession) Close(error) error { s.closed = true; return nil } var _ = Describe("H2 server", func() { + const port = "4826" + const addr = "127.0.0.1:" + port + var ( s *Server session *mockSession @@ -201,4 +206,98 @@ var _ = Describe("H2 server", func() { Expect(hdr).To(Equal(expected)) }) }) + + It("should error when ListenAndServe is called with s.Server nil", func() { + err := (&Server{}).ListenAndServe() + Expect(err).To(MatchError("use of h2quic.Server without http.Server")) + }) + + It("should nop-Close() when s.server is nil", func() { + err := (&Server{}).Close() + Expect(err).NotTo(HaveOccurred()) + }) + + Context("ListenAndServe", func() { + BeforeEach(func() { + s.Server.Addr = addr + }) + + AfterEach(func() { + time.Sleep(10 * time.Millisecond) + err := s.Close() + Expect(err).NotTo(HaveOccurred()) + }) + + It("works", func(done Done) { + go func() { + defer GinkgoRecover() + err := s.ListenAndServe() + Expect(err).NotTo(HaveOccurred()) + close(done) + }() + time.Sleep(10 * time.Millisecond) + err := s.Close() + Expect(err).NotTo(HaveOccurred()) + }, 0.5) + + It("may only be called once", func(done Done) { + go func() { + defer GinkgoRecover() + err := s.ListenAndServe() + Expect(err).NotTo(HaveOccurred()) + close(done) + }() + time.Sleep(10 * time.Millisecond) + err := s.ListenAndServe() + Expect(err).To(MatchError("ListenAndServe may only be called once")) + err = s.Close() + Expect(err).NotTo(HaveOccurred()) + }, 0.5) + }) + + Context("ListenAndServeTLS", func() { + path := os.Getenv("GOPATH") + path += "/src/github.com/lucas-clemente/quic-go/example/" + + BeforeEach(func() { + s.Server.Addr = addr + }) + + AfterEach(func() { + time.Sleep(10 * time.Millisecond) + err := s.Close() + Expect(err).NotTo(HaveOccurred()) + }) + + It("works", func(done Done) { + go func() { + defer GinkgoRecover() + err := s.ListenAndServeTLS(path+"fullchain.pem", path+"privkey.pem") + Expect(err).NotTo(HaveOccurred()) + close(done) + }() + time.Sleep(10 * time.Millisecond) + err := s.Close() + Expect(err).NotTo(HaveOccurred()) + }, 0.5) + + It("may only be called once", func(done Done) { + go func() { + defer GinkgoRecover() + err := s.ListenAndServeTLS(path+"fullchain.pem", path+"privkey.pem") + Expect(err).NotTo(HaveOccurred()) + close(done) + }() + time.Sleep(10 * time.Millisecond) + err := s.ListenAndServeTLS(path+"fullchain.pem", path+"privkey.pem") + Expect(err).To(MatchError("ListenAndServe may only be called once")) + err = s.Close() + Expect(err).NotTo(HaveOccurred()) + }, 0.5) + }) + + It("closes gracefully", func() { + err := s.CloseGracefully(0) + Expect(err).NotTo(HaveOccurred()) + }) }) diff --git a/server.go b/server.go index 2e218514..b99ba653 100644 --- a/server.go +++ b/server.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/tls" "net" + "strings" "sync" "github.com/lucas-clemente/quic-go/crypto" @@ -79,6 +80,9 @@ func (s *Server) ListenAndServe() error { data := make([]byte, protocol.MaxPacketSize) n, remoteAddr, err := conn.ReadFromUDP(data) if err != nil { + if strings.HasSuffix(err.Error(), "use of closed network connection") { + return nil + } return err } data = data[:n] @@ -102,6 +106,9 @@ func (s *Server) Close() error { if s.conn == nil { return nil } + defer func() { + s.conn = nil + }() return s.conn.Close() } diff --git a/server_test.go b/server_test.go index 57f4a232..dd84106d 100644 --- a/server_test.go +++ b/server_test.go @@ -97,7 +97,7 @@ var _ = Describe("Server", func() { go func() { defer GinkgoRecover() err := server.ListenAndServe() - Expect(err).To(HaveOccurred()) + Expect(err).ToNot(HaveOccurred()) close(done) }() @@ -136,7 +136,7 @@ var _ = Describe("Server", func() { go func() { defer GinkgoRecover() err := server.ListenAndServe() - Expect(err).To(HaveOccurred()) + Expect(err).NotTo(HaveOccurred()) close(done) }()