Repository: pion/dtls
Pull request #227 (2020-03-20 05:52:29)

Fix error type naming
According to https://github.com/golang/go/wiki/Errors#naming
> Error types end in "Error"


codecov[bot]: # [Codecov](https://codecov.io/gh/pion/dtls/pull/227?src=pr&el=h1) Report
> Merging [#227](https://codecov.io/gh/pion/dtls/pull/227?src=pr&el=desc) into [master](https://codecov.io/gh/pion/dtls/commit/d5cce09442d3c5db4a18e6e170de3c09f20508f2&el=desc) will **decrease** coverage by `0.07%`.
> The diff coverage is `80.95%`.

[![Impacted file tree graph](https://codecov.io/gh/pion/dtls/pull/227/graphs/tree.svg?width=650&height=150&src=pr&token=bcCB2jB88I)](https://codecov.io/gh/pion/dtls/pull/227?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #227      +/-   ##
==========================================
- Coverage   76.80%   76.72%   -0.08%     
==========================================
  Files          76       76              
  Lines        4095     4095              
==========================================
- Hits         3145     3142       -3     
- Misses        647      650       +3     
  Partials      303      303              
```

| Flag | Coverage Δ | |
|---|---|---|
| #go | `76.76% <80.95%> (-0.08%)` | :arrow_down: |
| #wasm | `71.51% <76.19%> (ø)` | |

| [Impacted Files](https://codecov.io/gh/pion/dtls/pull/227?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [errors.go](https://codecov.io/gh/pion/dtls/pull/227/diff?src=pr&el=tree#diff-ZXJyb3JzLmdv) | `79.41% <78.94%> (ø)` | |
| [signature\_hash\_algorithm.go](https://codecov.io/gh/pion/dtls/pull/227/diff?src=pr&el=tree#diff-c2lnbmF0dXJlX2hhc2hfYWxnb3JpdGhtLmdv) | `88.09% <100.00%> (ø)` | |
| [internal/net/deadline/deadline.go](https://codecov.io/gh/pion/dtls/pull/227/diff?src=pr&el=tree#diff-aW50ZXJuYWwvbmV0L2RlYWRsaW5lL2RlYWRsaW5lLmdv) | `82.45% <0.00%> (-3.51%)` | :arrow_down: |
| [internal/net/dpipe/dpipe.go](https://codecov.io/gh/pion/dtls/pull/227/diff?src=pr&el=tree#diff-aW50ZXJuYWwvbmV0L2RwaXBlL2RwaXBlLmdv) | `94.11% <0.00%> (-2.36%)` | :arrow_down: |
| [conn.go](https://codecov.io/gh/pion/dtls/pull/227/diff?src=pr&el=tree#diff-Y29ubi5nbw==) | `83.07% <0.00%> (-0.18%)` | :arrow_down: |
| [internal/net/connctx/connctx.go](https://codecov.io/gh/pion/dtls/pull/227/diff?src=pr&el=tree#diff-aW50ZXJuYWwvbmV0L2Nvbm5jdHgvY29ubmN0eC5nbw==) | `91.35% <0.00%> (+2.46%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pion/dtls/pull/227?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pion/dtls/pull/227?src=pr&el=footer). Last update [d5cce09...bcdc658](https://codecov.io/gh/pion/dtls/pull/227?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/conn.go b/conn.go
index 0516561..ed59bd1 100644
--- a/conn.go
+++ b/conn.go
@@ -48,7 +48,6 @@ type Conn struct {
 
 	encryptedPackets [][]byte
 
-	connectionClosed       bool
 	connectionClosedByUser bool
 	closeLock              sync.Mutex
 	closed                 *closer.Closer
@@ -279,8 +278,6 @@ func (c *Conn) Read(p []byte) (n int, err error) {
 		select {
 		case <-c.readDeadline.Done():
 			return 0, errDeadlineExceeded
-		case <-c.closed.Done():
-			return 0, io.EOF
 		case out, ok := <-c.decrypted:
 			if !ok {
 				return 0, io.EOF
@@ -458,6 +455,12 @@ func (c *Conn) processPacket(p *packet) ([]byte, error) {
 		c.state.localSequenceNumber = append(c.state.localSequenceNumber, uint64(0))
 	}
 	seq := atomic.AddUint64(&c.state.localSequenceNumber[epoch], 1) - 1
+	if seq > maxSequenceNumber {
+		// RFC 6347 Section 4.1.0
+		// The implementation must either abandon an association or rehandshake
+		// prior to allowing the sequence number to wrap.
+		return nil, errSequenceNumberOverflow
+	}
 	p.record.recordLayerHeader.sequenceNumber = seq
 
 	rawPacket, err := p.record.Marshal()
@@ -490,6 +493,9 @@ func (c *Conn) processHandshakePacket(p *packet, h *handshake) ([][]byte, error)
 
 	for _, handshakeFragment := range handshakeFragments {
 		seq := atomic.AddUint64(&c.state.localSequenceNumber[epoch], 1) - 1
+		if seq > maxSequenceNumber {
+			return nil, errSequenceNumberOverflow
+		}
 
 		recordLayerHeader := &recordLayerHeader{
 			protocolVersion: p.record.recordLayerHeader.protocolVersion,
@@ -761,10 +767,6 @@ func (c *Conn) handleIncomingPacket(buf []byte, enqueue bool) (bool, *alert, err
 			return false, &alert{alertLevelFatal, alertUnexpectedMessage}, fmt.Errorf("ApplicationData with epoch of 0")
 		}
 
-		if c.isConnectionClosed() {
-			return false, nil, io.EOF
-		}
-
 		markPacketAsValid()
 
 		select {
@@ -842,6 +844,11 @@ func (c *Conn) handshake(ctx context.Context, cfg *handshakeConfig, initialFligh
 		}
 	}()
 	go func() {
+		defer func() {
+			// Escaping read loop.
+			// It's safe to close decrypted channnel now.
+			close(c.decrypted)
+		}()
 		defer c.handshakeLoopsFinished.Done()
 		for {
 			if err := c.readAndBuffer(ctxRead); err != nil {
@@ -916,7 +923,6 @@ func (c *Conn) translateHandshakeCtxError(err error) error {
 func (c *Conn) close(byUser bool) error {
 	c.cancelHandshaker()
 	c.cancelHandshakeReader()
-	c.closed.Close()
 
 	if c.isHandshakeCompletedSuccessfully() && byUser {
 		// Discard error from notify() to return non-error on the first user call of Close()
@@ -930,9 +936,7 @@ func (c *Conn) close(byUser bool) error {
 	if byUser {
 		c.connectionClosedByUser = true
 	}
-	if !c.connectionClosed {
-		c.connectionClosed = true
-	}
+	c.closed.Close()
 	c.closeLock.Unlock()
 
 	if closedByUser {
@@ -943,9 +947,12 @@ func (c *Conn) close(byUser bool) error {
 }
 
 func (c *Conn) isConnectionClosed() bool {
-	c.closeLock.Lock()
-	defer c.closeLock.Unlock()
-	return c.connectionClosed
+	select {
+	case <-c.closed.Done():
+		return true
+	default:
+		return false
+	}
 }
 
 func (c *Conn) setLocalEpoch(epoch uint16) {
diff --git a/errors.go b/errors.go
index 4546411..ea7cbb8 100644
--- a/errors.go
+++ b/errors.go
@@ -13,136 +13,136 @@ import (
 
 // Typed errors
 var (
-	ErrConnClosed = &ErrFatal{errors.New("conn is closed")}
-
-	errDeadlineExceeded = &ErrTimeout{xerrors.Errorf("read/write timeout: %w", context.DeadlineExceeded)}
-
-	errBufferTooSmall               = &ErrTemporary{errors.New("buffer is too small")}
-	errContextUnsupported           = &ErrTemporary{errors.New("context is not supported for ExportKeyingMaterial")}
-	errDTLSPacketInvalidLength      = &ErrTemporary{errors.New("packet is too short")}
-	errHandshakeInProgress          = &ErrTemporary{errors.New("handshake is in progress")}
-	errInvalidContentType           = &ErrTemporary{errors.New("invalid content type")}
-	errInvalidMAC                   = &ErrTemporary{errors.New("invalid mac")}
-	errInvalidPacketLength          = &ErrTemporary{errors.New("packet length and declared length do not match")}
-	errReservedExportKeyingMaterial = &ErrTemporary{errors.New("ExportKeyingMaterial can not be used with a reserved label")}
-
-	errCertificateVerifyNoCertificate   = &ErrFatal{errors.New("client sent certificate verify but we have no certificate to verify")}
-	errCipherSuiteNoIntersection        = &ErrFatal{errors.New("client+server do not support any shared cipher suites")}
-	errCipherSuiteUnset                 = &ErrFatal{errors.New("server hello can not be created without a cipher suite")}
-	errClientCertificateNotVerified     = &ErrFatal{errors.New("client sent certificate but did not verify it")}
-	errClientCertificateRequired        = &ErrFatal{errors.New("server required client verification, but got none")}
-	errClientNoMatchingSRTPProfile      = &ErrFatal{errors.New("server responded with SRTP Profile we do not support")}
-	errClientRequiredButNoServerEMS     = &ErrFatal{errors.New("client required Extended Master Secret extension, but server does not support it")}
-	errCompressionMethodUnset           = &ErrFatal{errors.New("server hello can not be created without a compression method")}
-	errCookieMismatch                   = &ErrFatal{errors.New("client+server cookie does not match")}
-	errCookieTooLong                    = &ErrFatal{errors.New("cookie must not be longer then 255 bytes")}
-	errHandshakeTimeout                 = &ErrFatal{xerrors.Errorf("the connection timed out during the handshake: %w", context.DeadlineExceeded)}
-	errIdentityNoPSK                    = &ErrFatal{errors.New("PSK Identity Hint provided but PSK is nil")}
-	errInvalidCertificate               = &ErrFatal{errors.New("no certificate provided")}
-	errInvalidCipherSpec                = &ErrFatal{errors.New("cipher spec invalid")}
-	errInvalidCipherSuite               = &ErrFatal{errors.New("invalid or unknown cipher suite")}
-	errInvalidClientKeyExchange         = &ErrFatal{errors.New("unable to determine if ClientKeyExchange is a public key or PSK Identity")}
-	errInvalidCompressionMethod         = &ErrFatal{errors.New("invalid or unknown compression method")}
-	errInvalidECDSASignature            = &ErrFatal{errors.New("ECDSA signature contained zero or negative values")}
-	errInvalidEllipticCurveType         = &ErrFatal{errors.New("invalid or unknown elliptic curve type")}
-	errInvalidExtensionType             = &ErrFatal{errors.New("invalid extension type")}
-	errInvalidHashAlgorithm             = &ErrFatal{errors.New("invalid hash algorithm")}
-	errInvalidNamedCurve                = &ErrFatal{errors.New("invalid named curve")}
-	errInvalidPrivateKey                = &ErrFatal{errors.New("invalid private key type")}
-	errInvalidSNIFormat                 = &ErrFatal{errors.New("invalid server name format")}
-	errInvalidSignatureAlgorithm        = &ErrFatal{errors.New("invalid signature algorithm")}
-	errKeySignatureMismatch             = &ErrFatal{errors.New("expected and actual key signature do not match")}
-	errNilNextConn                      = &ErrFatal{errors.New("Conn can not be created with a nil nextConn")}
-	errNoAvailableCipherSuites          = &ErrFatal{errors.New("connection can not be created, no CipherSuites satisfy this Config")}
-	errNoAvailableSignatureSchemes      = &ErrFatal{errors.New("connection can not be created, no SignatureScheme satisfy this Config")}
-	errNoCertificates                   = &ErrFatal{errors.New("no certificates configured")}
-	errNoConfigProvided                 = &ErrFatal{errors.New("no config provided")}
-	errNoSupportedEllipticCurves        = &ErrFatal{errors.New("client requested zero or more elliptic curves that are not supported by the server")}
-	errUnsupportedProtocolVersion       = &ErrFatal{errors.New("unsupported protocol version")}
-	errPSKAndCertificate                = &ErrFatal{errors.New("Certificate and PSK provided")} // nolint:stylecheck
-	errPSKAndIdentityMustBeSetForClient = &ErrFatal{errors.New("PSK and PSK Identity Hint must both be set for client")}
-	errRequestedButNoSRTPExtension      = &ErrFatal{errors.New("SRTP support was requested but server did not respond with use_srtp extension")}
-	errServerMustHaveCertificate        = &ErrFatal{errors.New("Certificate is mandatory for server")} // nolint:stylecheck
-	errServerNoMatchingSRTPProfile      = &ErrFatal{errors.New("client requested SRTP but we have no matching profiles")}
-	errServerRequiredButNoClientEMS     = &ErrFatal{errors.New("server requires the Extended Master Secret extension, but the client does not support it")}
-	errVerifyDataMismatch               = &ErrFatal{errors.New("expected and actual verify data does not match")}
-
-	errHandshakeMessageUnset             = &ErrInternal{errors.New("handshake message unset, unable to marshal")}
-	errInvalidFlight                     = &ErrInternal{errors.New("invalid flight number")}
-	errKeySignatureGenerateUnimplemented = &ErrInternal{errors.New("unable to generate key signature, unimplemented")}
-	errKeySignatureVerifyUnimplemented   = &ErrInternal{errors.New("unable to verify key signature, unimplemented")}
-	errLengthMismatch                    = &ErrInternal{errors.New("data length and declared length do not match")}
-	errNotEnoughRoomForNonce             = &ErrInternal{errors.New("buffer not long enough to contain nonce")}
-	errNotImplemented                    = &ErrInternal{errors.New("feature has not been implemented yet")}
-	errSequenceNumberOverflow            = &ErrInternal{errors.New("sequence number overflow")}
-	errUnableToMarshalFragmented         = &ErrInternal{errors.New("unable to marshal fragmented handshakes")}
+	ErrConnClosed = &FatalError{errors.New("conn is closed")}
+
+	errDeadlineExceeded = &TimeoutError{xerrors.Errorf("read/write timeout: %w", context.DeadlineExceeded)}
+
+	errBufferTooSmall               = &TemporaryError{errors.New("buffer is too small")}
+	errContextUnsupported           = &TemporaryError{errors.New("context is not supported for ExportKeyingMaterial")}
+	errDTLSPacketInvalidLength      = &TemporaryError{errors.New("packet is too short")}
+	errHandshakeInProgress          = &TemporaryError{errors.New("handshake is in progress")}
+	errInvalidContentType           = &TemporaryError{errors.New("invalid content type")}
+	errInvalidMAC                   = &TemporaryError{errors.New("invalid mac")}
+	errInvalidPacketLength          = &TemporaryError{errors.New("packet length and declared length do not match")}
+	errReservedExportKeyingMaterial = &TemporaryError{errors.New("ExportKeyingMaterial can not be used with a reserved label")}
+
+	errCertificateVerifyNoCertificate   = &FatalError{errors.New("client sent certificate verify but we have no certificate to verify")}
+	errCipherSuiteNoIntersection        = &FatalError{errors.New("client+server do not support any shared cipher suites")}
+	errCipherSuiteUnset                 = &FatalError{errors.New("server hello can not be created without a cipher suite")}
+	errClientCertificateNotVerified     = &FatalError{errors.New("client sent certificate but did not verify it")}
+	errClientCertificateRequired        = &FatalError{errors.New("server required client verification, but got none")}
+	errClientNoMatchingSRTPProfile      = &FatalError{errors.New("server responded with SRTP Profile we do not support")}
+	errClientRequiredButNoServerEMS     = &FatalError{errors.New("client required Extended Master Secret extension, but server does not support it")}
+	errCompressionMethodUnset           = &FatalError{errors.New("server hello can not be created without a compression method")}
+	errCookieMismatch                   = &FatalError{errors.New("client+server cookie does not match")}
+	errCookieTooLong                    = &FatalError{errors.New("cookie must not be longer then 255 bytes")}
+	errHandshakeTimeout                 = &FatalError{xerrors.Errorf("the connection timed out during the handshake: %w", context.DeadlineExceeded)}
+	errIdentityNoPSK                    = &FatalError{errors.New("PSK Identity Hint provided but PSK is nil")}
+	errInvalidCertificate               = &FatalError{errors.New("no certificate provided")}
+	errInvalidCipherSpec                = &FatalError{errors.New("cipher spec invalid")}
+	errInvalidCipherSuite               = &FatalError{errors.New("invalid or unknown cipher suite")}
+	errInvalidClientKeyExchange         = &FatalError{errors.New("unable to determine if ClientKeyExchange is a public key or PSK Identity")}
+	errInvalidCompressionMethod         = &FatalError{errors.New("invalid or unknown compression method")}
+	errInvalidECDSASignature            = &FatalError{errors.New("ECDSA signature contained zero or negative values")}
+	errInvalidEllipticCurveType         = &FatalError{errors.New("invalid or unknown elliptic curve type")}
+	errInvalidExtensionType             = &FatalError{errors.New("invalid extension type")}
+	errInvalidHashAlgorithm             = &FatalError{errors.New("invalid hash algorithm")}
+	errInvalidNamedCurve                = &FatalError{errors.New("invalid named curve")}
+	errInvalidPrivateKey                = &FatalError{errors.New("invalid private key type")}
+	errInvalidSNIFormat                 = &FatalError{errors.New("invalid server name format")}
+	errInvalidSignatureAlgorithm        = &FatalError{errors.New("invalid signature algorithm")}
+	errKeySignatureMismatch             = &FatalError{errors.New("expected and actual key signature do not match")}
+	errNilNextConn                      = &FatalError{errors.New("Conn can not be created with a nil nextConn")}
+	errNoAvailableCipherSuites          = &FatalError{errors.New("connection can not be created, no CipherSuites satisfy this Config")}
+	errNoAvailableSignatureSchemes      = &FatalError{errors.New("connection can not be created, no SignatureScheme satisfy this Config")}
+	errNoCertificates                   = &FatalError{errors.New("no certificates configured")}
+	errNoConfigProvided                 = &FatalError{errors.New("no config provided")}
+	errNoSupportedEllipticCurves        = &FatalError{errors.New("client requested zero or more elliptic curves that are not supported by the server")}
+	errUnsupportedProtocolVersion       = &FatalError{errors.New("unsupported protocol version")}
+	errPSKAndCertificate                = &FatalError{errors.New("Certificate and PSK provided")} // nolint:stylecheck
+	errPSKAndIdentityMustBeSetForClient = &FatalError{errors.New("PSK and PSK Identity Hint must both be set for client")}
+	errRequestedButNoSRTPExtension      = &FatalError{errors.New("SRTP support was requested but server did not respond with use_srtp extension")}
+	errServerMustHaveCertificate        = &FatalError{errors.New("Certificate is mandatory for server")} // nolint:stylecheck
+	errServerNoMatchingSRTPProfile      = &FatalError{errors.New("client requested SRTP but we have no matching profiles")}
+	errServerRequiredButNoClientEMS     = &FatalError{errors.New("server requires the Extended Master Secret extension, but the client does not support it")}
+	errVerifyDataMismatch               = &FatalError{errors.New("expected and actual verify data does not match")}
+
+	errHandshakeMessageUnset             = &InternalError{errors.New("handshake message unset, unable to marshal")}
+	errInvalidFlight                     = &InternalError{errors.New("invalid flight number")}
+	errKeySignatureGenerateUnimplemented = &InternalError{errors.New("unable to generate key signature, unimplemented")}
+	errKeySignatureVerifyUnimplemented   = &InternalError{errors.New("unable to verify key signature, unimplemented")}
+	errLengthMismatch                    = &InternalError{errors.New("data length and declared length do not match")}
+	errNotEnoughRoomForNonce             = &InternalError{errors.New("buffer not long enough to contain nonce")}
+	errNotImplemented                    = &InternalError{errors.New("feature has not been implemented yet")}
+	errSequenceNumberOverflow            = &InternalError{errors.New("sequence number overflow")}
+	errUnableToMarshalFragmented         = &InternalError{errors.New("unable to marshal fragmented handshakes")}
 )
 
-// ErrFatal indicates that the DTLS connection is no longer available.
+// FatalError indicates that the DTLS connection is no longer available.
 // It is mainly caused by wrong configuration of server or client.
-type ErrFatal struct {
+type FatalError struct {
 	Err error
 }
 
-// ErrInternal indicates and internal error caused by the implementation, and the DTLS connection is no longer available.
+// InternalError indicates and internal error caused by the implementation, and the DTLS connection is no longer available.
 // It is mainly caused by bugs or tried to use unimplemented features.
-type ErrInternal struct {
+type InternalError struct {
 	Err error
 }
 
-// ErrTemporary indicates that the DTLS connection is still available, but the request was failed temporary.
-type ErrTemporary struct {
+// TemporaryError indicates that the DTLS connection is still available, but the request was failed temporary.
+type TemporaryError struct {
 	Err error
 }
 
-// ErrTimeout indicates that the request was timed out.
-type ErrTimeout struct {
+// TimeoutError indicates that the request was timed out.
+type TimeoutError struct {
 	Err error
 }
 
 // Timeout implements net.Error.Timeout()
-func (*ErrFatal) Timeout() bool { return false }
+func (*FatalError) Timeout() bool { return false }
 
 // Temporary implements net.Error.Temporary()
-func (*ErrFatal) Temporary() bool { return false }
+func (*FatalError) Temporary() bool { return false }
 
 // Unwrap implements Go1.13 error unwrapper.
-func (e *ErrFatal) Unwrap() error { return e.Err }
+func (e *FatalError) Unwrap() error { return e.Err }
 
-func (e *ErrFatal) Error() string { return fmt.Sprintf("dtls fatal: %v", e.Err) }
+func (e *FatalError) Error() string { return fmt.Sprintf("dtls fatal: %v", e.Err) }
 
 // Timeout implements net.Error.Timeout()
-func (*ErrInternal) Timeout() bool { return false }
+func (*InternalError) Timeout() bool { return false }
 
 // Temporary implements net.Error.Temporary()
-func (*ErrInternal) Temporary() bool { return false }
+func (*InternalError) Temporary() bool { return false }
 
 // Unwrap implements Go1.13 error unwrapper.
-func (e *ErrInternal) Unwrap() error { return e.Err }
+func (e *InternalError) Unwrap() error { return e.Err }
 
-func (e *ErrInternal) Error() string { return fmt.Sprintf("dtls internal: %v", e.Err) }
+func (e *InternalError) Error() string { return fmt.Sprintf("dtls internal: %v", e.Err) }
 
 // Timeout implements net.Error.Timeout()
-func (*ErrTemporary) Timeout() bool { return false }
+func (*TemporaryError) Timeout() bool { return false }
 
 // Temporary implements net.Error.Temporary()
-func (*ErrTemporary) Temporary() bool { return true }
+func (*TemporaryError) Temporary() bool { return true }
 
 // Unwrap implements Go1.13 error unwrapper.
-func (e *ErrTemporary) Unwrap() error { return e.Err }
+func (e *TemporaryError) Unwrap() error { return e.Err }
 
-func (e *ErrTemporary) Error() string { return fmt.Sprintf("dtls temporary: %v", e.Err) }
+func (e *TemporaryError) Error() string { return fmt.Sprintf("dtls temporary: %v", e.Err) }
 
 // Timeout implements net.Error.Timeout()
-func (*ErrTimeout) Timeout() bool { return true }
+func (*TimeoutError) Timeout() bool { return true }
 
 // Temporary implements net.Error.Temporary()
-func (*ErrTimeout) Temporary() bool { return true }
+func (*TimeoutError) Temporary() bool { return true }
 
 // Unwrap implements Go1.13 error unwrapper.
-func (e *ErrTimeout) Unwrap() error { return e.Err }
+func (e *TimeoutError) Unwrap() error { return e.Err }
 
-func (e *ErrTimeout) Error() string { return fmt.Sprintf("dtls timeout: %v", e.Err) }
+func (e *TimeoutError) Error() string { return fmt.Sprintf("dtls timeout: %v", e.Err) }
 
 // errAlert wraps DTLS alert notification as an error
 type errAlert struct {
@@ -168,14 +168,14 @@ func netError(err error) error {
 	case (*net.OpError):
 		if se, ok := e.Err.(*os.SyscallError); ok {
 			if se.Timeout() {
-				return &ErrTimeout{err}
+				return &TimeoutError{err}
 			}
 			if isOpErrorTemporary(se) {
-				return &ErrTemporary{err}
+				return &TemporaryError{err}
 			}
 		}
 	case (net.Error):
 		return err
 	}
-	return &ErrFatal{err}
+	return &FatalError{err}
 }
diff --git a/signature_hash_algorithm.go b/signature_hash_algorithm.go
index 58ac63b..c8a15ad 100644
--- a/signature_hash_algorithm.go
+++ b/signature_hash_algorithm.go
@@ -61,13 +61,13 @@ func parseSignatureSchemes(sigs []tls.SignatureScheme) ([]signatureHashAlgorithm
 	for _, ss := range sigs {
 		sig := signatureAlgorithm(ss & 0xFF)
 		if _, ok := signatureAlgorithms[sig]; !ok {
-			return nil, &ErrFatal{
+			return nil, &FatalError{
 				xerrors.Errorf("SignatureScheme %04x: %w", ss, errInvalidSignatureAlgorithm),
 			}
 		}
 		h := hashAlgorithm(ss >> 8)
 		if _, ok := hashAlgorithms[h]; !ok {
-			return nil, &ErrFatal{
+			return nil, &FatalError{
 				xerrors.Errorf("SignatureScheme %04x: %w", ss, errInvalidHashAlgorithm),
 			}
 		}


Test patch:
diff --git a/conn_test.go b/conn_test.go
index 0922f53..82916e2 100644
--- a/conn_test.go
+++ b/conn_test.go
@@ -11,6 +11,7 @@ import (
 	"io"
 	"net"
 	"sync"
+	"sync/atomic"
 	"testing"
 	"time"
 
@@ -145,6 +146,76 @@ func TestReadWriteDeadline(t *testing.T) {
 	}
 }
 
+func TestSequenceNumberOverflow(t *testing.T) {
+	// Limit runtime in case of deadlocks
+	lim := test.TimeOut(5 * time.Second)
+	defer lim.Stop()
+
+	// Check for leaking routines
+	report := test.CheckRoutines(t)
+	defer report()
+
+	t.Run("ApplicationData", func(t *testing.T) {
+		ca, cb, err := pipeMemory()
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		atomic.StoreUint64(&ca.state.localSequenceNumber[1], maxSequenceNumber)
+		if _, werr := ca.Write(make([]byte, 100)); werr != nil {
+			t.Errorf("Write must send message with maximum sequence number, but errord: %v", werr)
+		}
+		if _, werr := ca.Write(make([]byte, 100)); werr != errSequenceNumberOverflow {
+			t.Errorf("Write must abandonsend message with maximum sequence number, but errord: %v", werr)
+		}
+
+		if err := ca.Close(); err != nil {
+			t.Error(err)
+		}
+		if err := cb.Close(); err != nil {
+			t.Error(err)
+		}
+	})
+	t.Run("Handshake", func(t *testing.T) {
+		ca, cb, err := pipeMemory()
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+		defer cancel()
+
+		atomic.StoreUint64(&ca.state.localSequenceNumber[0], maxSequenceNumber+1)
+
+		// Try to send handshake packet.
+		if werr := ca.writePackets(ctx, []*packet{
+			{
+				record: &recordLayer{
+					recordLayerHeader: recordLayerHeader{
+						protocolVersion: protocolVersion1_2,
+					},
+					content: &handshake{
+						handshakeMessage: &handshakeMessageClientHello{
+							version:            protocolVersion1_2,
+							cookie:             make([]byte, 64),
+							cipherSuites:       defaultCipherSuites(),
+							compressionMethods: defaultCompressionMethods,
+						}},
+				},
+			},
+		}); werr != errSequenceNumberOverflow {
+			t.Errorf("Connection must fail on handshake packet reaches maximum sequence number")
+		}
+
+		if err := ca.Close(); err != nil {
+			t.Error(err)
+		}
+		if err := cb.Close(); err != nil {
+			t.Error(err)
+		}
+	})
+}
+
 func pipeMemory() (*Conn, *Conn, error) {
 	// In memory pipe
 	ca, cb := dpipe.Pipe()
diff --git a/errors_test.go b/errors_test.go
index a5a511e..c9607a7 100644
--- a/errors_test.go
+++ b/errors_test.go
@@ -17,19 +17,19 @@ func TestErrorUnwrap(t *testing.T) {
 		errUnwrapped []error
 	}{
 		{
-			&ErrFatal{errExample},
+			&FatalError{errExample},
 			[]error{errExample},
 		},
 		{
-			&ErrTemporary{errExample},
+			&TemporaryError{errExample},
 			[]error{errExample},
 		},
 		{
-			&ErrInternal{errExample},
+			&InternalError{errExample},
 			[]error{errExample},
 		},
 		{
-			&ErrTimeout{errExample},
+			&TimeoutError{errExample},
 			[]error{errExample},
 		},
 	}
@@ -55,10 +55,10 @@ func TestErrorNetError(t *testing.T) {
 		str                string
 		timeout, temporary bool
 	}{
-		{&ErrFatal{errExample}, "dtls fatal: an example error", false, false},
-		{&ErrTemporary{errExample}, "dtls temporary: an example error", false, true},
-		{&ErrInternal{errExample}, "dtls internal: an example error", false, false},
-		{&ErrTimeout{errExample}, "dtls timeout: an example error", true, true},
+		{&FatalError{errExample}, "dtls fatal: an example error", false, false},
+		{&TemporaryError{errExample}, "dtls temporary: an example error", false, true},
+		{&InternalError{errExample}, "dtls internal: an example error", false, false},
+		{&TimeoutError{errExample}, "dtls timeout: an example error", true, true},
 	}
 	for _, c := range cases {
 		c := c