Skip to content

Commit

Permalink
Expose error values
Browse files Browse the repository at this point in the history
Make it possible to compare errors using errors.Is().
  • Loading branch information
at-wat committed Jan 13, 2023
1 parent 7ca78e8 commit c18816d
Show file tree
Hide file tree
Showing 31 changed files with 251 additions and 201 deletions.
88 changes: 45 additions & 43 deletions association.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,30 @@ import (
)

// Use global random generator to properly seed by crypto grade random.
var globalMathRandomGenerator = randutil.NewMathRandomGenerator() // nolint:gochecknoglobals

// Association errors
var (
globalMathRandomGenerator = randutil.NewMathRandomGenerator() // nolint:gochecknoglobals
errChunk = errors.New("abort chunk, with following errors")
errShutdownNonEstablished = errors.New("shutdown called in non-established state")
errAssociationClosedBeforeConn = errors.New("association closed before connecting")
errSilentlyDiscard = errors.New("silently discard")
errInitNotStoredToSend = errors.New("the init not stored to send")
errCookieEchoNotStoredToSend = errors.New("cookieEcho not stored to send")
errSCTPPacketSourcePortZero = errors.New("sctp packet must not have a source port of 0")
errSCTPPacketDestinationPortZero = errors.New("sctp packet must not have a destination port of 0")
errInitChunkBundled = errors.New("init chunk must not be bundled with any other chunk")
errInitChunkVerifyTagNotZero = errors.New("init chunk expects a verification tag of 0 on the packet when out-of-the-blue")
errHandleInitState = errors.New("todo: handle Init when in state")
errInitAckNoCookie = errors.New("no cookie in InitAck")
errInflightQueueTSNPop = errors.New("unable to be popped from inflight queue TSN")
errTSNRequestNotExist = errors.New("requested non-existent TSN")
errResetPacketInStateNotExist = errors.New("sending reset packet in non-established state")
errParamterType = errors.New("unexpected parameter type")
errPayloadDataStateNotExist = errors.New("sending payload data in non-established state")
errChunkTypeUnhandled = errors.New("unhandled chunk type")
errHandshakeInitAck = errors.New("handshake failed (INIT ACK)")
errHandshakeCookieEcho = errors.New("handshake failed (COOKIE ECHO)")
ErrChunk = errors.New("abort chunk, with following errors")
ErrShutdownNonEstablished = errors.New("shutdown called in non-established state")
ErrAssociationClosedBeforeConn = errors.New("association closed before connecting")
ErrSilentlyDiscard = errors.New("silently discard")
ErrInitNotStoredToSend = errors.New("the init not stored to send")
ErrCookieEchoNotStoredToSend = errors.New("cookieEcho not stored to send")
ErrSCTPPacketSourcePortZero = errors.New("sctp packet must not have a source port of 0")
ErrSCTPPacketDestinationPortZero = errors.New("sctp packet must not have a destination port of 0")
ErrInitChunkBundled = errors.New("init chunk must not be bundled with any other chunk")
ErrInitChunkVerifyTagNotZero = errors.New("init chunk expects a verification tag of 0 on the packet when out-of-the-blue")
ErrHandleInitState = errors.New("todo: handle Init when in state")
ErrInitAckNoCookie = errors.New("no cookie in InitAck")
ErrInflightQueueTSNPop = errors.New("unable to be popped from inflight queue TSN")
ErrTSNRequestNotExist = errors.New("requested non-existent TSN")
ErrResetPacketInStateNotExist = errors.New("sending reset packet in non-established state")
ErrParamterType = errors.New("unexpected parameter type")
ErrPayloadDataStateNotExist = errors.New("sending payload data in non-established state")
ErrChunkTypeUnhandled = errors.New("unhandled chunk type")
ErrHandshakeInitAck = errors.New("handshake failed (INIT ACK)")
ErrHandshakeCookieEcho = errors.New("handshake failed (COOKIE ECHO)")
)

const (
Expand Down Expand Up @@ -246,7 +248,7 @@ func Server(config Config) (*Association, error) {
}
return a, nil
case <-a.readLoopCloseCh:
return nil, errAssociationClosedBeforeConn
return nil, ErrAssociationClosedBeforeConn
}
}

Expand All @@ -262,7 +264,7 @@ func Client(config Config) (*Association, error) {
}
return a, nil
case <-a.readLoopCloseCh:
return nil, errAssociationClosedBeforeConn
return nil, ErrAssociationClosedBeforeConn
}
}

Expand Down Expand Up @@ -310,7 +312,7 @@ func createAssociation(config Config) *Association {
handshakeCompletedCh: make(chan error),
cumulativeTSNAckPoint: tsn - 1,
advancedPeerTSNAckPoint: tsn - 1,
silentError: errSilentlyDiscard,
silentError: ErrSilentlyDiscard,
stats: &associationStats{},
log: config.LoggerFactory.NewLogger("sctp"),
}
Expand Down Expand Up @@ -366,7 +368,7 @@ func (a *Association) init(isClient bool) {
func (a *Association) sendInit() error {
a.log.Debugf("[%s] sending INIT", a.name)
if a.storedInit == nil {
return errInitNotStoredToSend
return ErrInitNotStoredToSend
}

outbound := &packet{}
Expand All @@ -387,7 +389,7 @@ func (a *Association) sendInit() error {
// caller must hold a.lock
func (a *Association) sendCookieEcho() error {
if a.storedCookieEcho == nil {
return errCookieEchoNotStoredToSend
return ErrCookieEchoNotStoredToSend
}

a.log.Debugf("[%s] sending COOKIE-ECHO", a.name)
Expand All @@ -413,7 +415,7 @@ func (a *Association) Shutdown(ctx context.Context) error {
state := a.getState()

if state != established {
return fmt.Errorf("%w: shutdown %s", errShutdownNonEstablished, a.name)
return fmt.Errorf("%w: shutdown %s", ErrShutdownNonEstablished, a.name)
}

// Attempt a graceful shutdown.
Expand Down Expand Up @@ -930,15 +932,15 @@ func checkPacket(p *packet) error {
// identify the association to which this packet belongs. The port
// number 0 MUST NOT be used.
if p.sourcePort == 0 {
return errSCTPPacketSourcePortZero
return ErrSCTPPacketSourcePortZero
}

// This is the SCTP port number to which this packet is destined.
// The receiving host will use this port number to de-multiplex the
// SCTP packet to the correct receiving endpoint/application. The
// port number 0 MUST NOT be used.
if p.destinationPort == 0 {
return errSCTPPacketDestinationPortZero
return ErrSCTPPacketDestinationPortZero
}

// Check values on the packet that are specific to a particular chunk type
Expand All @@ -949,13 +951,13 @@ func checkPacket(p *packet) error {
// They MUST be the only chunks present in the SCTP packets that carry
// them.
if len(p.chunks) != 1 {
return errInitChunkBundled
return ErrInitChunkBundled
}

// A packet containing an INIT chunk MUST have a zero Verification
// Tag.
if p.verificationTag != 0 {
return errInitChunkVerifyTagNotZero
return ErrInitChunkVerifyTagNotZero
}
}
}
Expand Down Expand Up @@ -1037,7 +1039,7 @@ func (a *Association) handleInit(p *packet, i *chunkInit) ([]*packet, error) {
if state != closed && state != cookieWait && state != cookieEchoed {
// 5.2.2. Unexpected INIT in States Other than CLOSED, COOKIE-ECHOED,
// COOKIE-WAIT, and SHUTDOWN-ACK-SENT
return nil, fmt.Errorf("%w: %s", errHandleInitState, getAssociationStateString(state))
return nil, fmt.Errorf("%w: %s", ErrHandleInitState, getAssociationStateString(state))
}

// Should we be setting any of these permanently until we've ACKed further?
Expand Down Expand Up @@ -1153,7 +1155,7 @@ func (a *Association) handleInitAck(p *packet, i *chunkInitAck) error {
a.log.Warnf("[%s] not using ForwardTSN (on initAck)", a.name)
}
if cookieParam == nil {
return errInitAckNoCookie
return ErrInitAckNoCookie
}

a.storedCookieEcho = &chunkCookieEcho{}
Expand Down Expand Up @@ -1415,7 +1417,7 @@ func (a *Association) processSelectiveAck(d *chunkSelectiveAck) (map[uint16]int,
for i := a.cumulativeTSNAckPoint + 1; sna32LTE(i, d.cumulativeTSNAck); i++ {
c, ok := a.inflightQueue.pop(i)
if !ok {
return nil, 0, fmt.Errorf("%w: %v", errInflightQueueTSNPop, i)
return nil, 0, fmt.Errorf("%w: %v", ErrInflightQueueTSNPop, i)
}

if !c.acked {
Expand Down Expand Up @@ -1470,7 +1472,7 @@ func (a *Association) processSelectiveAck(d *chunkSelectiveAck) (map[uint16]int,
tsn := d.cumulativeTSNAck + uint32(i)
c, ok := a.inflightQueue.get(tsn)
if !ok {
return nil, 0, fmt.Errorf("%w: %v", errTSNRequestNotExist, tsn)
return nil, 0, fmt.Errorf("%w: %v", ErrTSNRequestNotExist, tsn)
}

if !c.acked {
Expand Down Expand Up @@ -1586,7 +1588,7 @@ func (a *Association) processFastRetransmission(cumTSNAckPoint, htna uint32, cum
for tsn := cumTSNAckPoint + 1; sna32LT(tsn, maxTSN); tsn++ {
c, ok := a.inflightQueue.get(tsn)
if !ok {
return fmt.Errorf("%w: %v", errTSNRequestNotExist, tsn)
return fmt.Errorf("%w: %v", ErrTSNRequestNotExist, tsn)
}
if !c.acked && !c.abandoned() && c.missIndicator < 3 {
c.missIndicator++
Expand Down Expand Up @@ -1805,7 +1807,7 @@ func (a *Association) handleAbort(c *chunkAbort) error {

_ = a.close()

return fmt.Errorf("[%s] %w: %s", a.name, errChunk, errStr)
return fmt.Errorf("[%s] %w: %s", a.name, ErrChunk, errStr)
}

// createForwardTSN generates ForwardTSN chunk.
Expand Down Expand Up @@ -1963,7 +1965,7 @@ func (a *Association) sendResetRequest(streamIdentifier uint16) error {

state := a.getState()
if state != established {
return fmt.Errorf("%w: state=%s", errResetPacketInStateNotExist,
return fmt.Errorf("%w: state=%s", ErrResetPacketInStateNotExist,
getAssociationStateString(state))
}

Expand Down Expand Up @@ -2001,7 +2003,7 @@ func (a *Association) handleReconfigParam(raw param) (*packet, error) {
}
return nil, nil //nolint:nilnil
default:
return nil, fmt.Errorf("%w: %t", errParamterType, p)
return nil, fmt.Errorf("%w: %t", ErrParamterType, p)
}
}

Expand Down Expand Up @@ -2162,7 +2164,7 @@ func (a *Association) sendPayloadData(chunks []*chunkPayloadData) error {

state := a.getState()
if state != established {
return fmt.Errorf("%w: state=%s", errPayloadDataStateNotExist,
return fmt.Errorf("%w: state=%s", ErrPayloadDataStateNotExist,
getAssociationStateString(state))
}

Expand Down Expand Up @@ -2367,7 +2369,7 @@ func (a *Association) handleChunk(p *packet, c chunk) error {
err = a.handleShutdownComplete(c)

default:
err = errChunkTypeUnhandled
err = ErrChunkTypeUnhandled
}

// Log and return, the only condition that is fatal is a ABORT chunk
Expand Down Expand Up @@ -2495,13 +2497,13 @@ func (a *Association) onRetransmissionFailure(id int) {

if id == timerT1Init {
a.log.Errorf("[%s] retransmission failure: T1-init", a.name)
a.handshakeCompletedCh <- errHandshakeInitAck
a.handshakeCompletedCh <- ErrHandshakeInitAck
return
}

if id == timerT1Cookie {
a.log.Errorf("[%s] retransmission failure: T1-cookie", a.name)
a.handshakeCompletedCh <- errHandshakeCookieEcho
a.handshakeCompletedCh <- ErrHandshakeCookieEcho
return
}

Expand Down
9 changes: 5 additions & 4 deletions chunk_abort.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ type chunkAbort struct {
errorCauses []errorCause
}

// Abort chunk errors
var (
errChunkTypeNotAbort = errors.New("ChunkType is not of type ABORT")
errBuildAbortChunkFailed = errors.New("failed build Abort Chunk")
ErrChunkTypeNotAbort = errors.New("ChunkType is not of type ABORT")
ErrBuildAbortChunkFailed = errors.New("failed build Abort Chunk")
)

func (a *chunkAbort) unmarshal(raw []byte) error {
Expand All @@ -42,7 +43,7 @@ func (a *chunkAbort) unmarshal(raw []byte) error {
}

if a.typ != ctAbort {
return fmt.Errorf("%w: actually is %s", errChunkTypeNotAbort, a.typ.String())
return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotAbort, a.typ.String())
}

offset := chunkHeaderSize
Expand All @@ -53,7 +54,7 @@ func (a *chunkAbort) unmarshal(raw []byte) error {

e, err := buildErrorCause(raw[offset:])
if err != nil {
return fmt.Errorf("%w: %v", errBuildAbortChunkFailed, err)
return fmt.Errorf("%w: %v", ErrBuildAbortChunkFailed, err)
}

offset += int(e.length())
Expand Down
7 changes: 5 additions & 2 deletions chunk_cookie_ack.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ type chunkCookieAck struct {
chunkHeader
}

var errChunkTypeNotCookieAck = errors.New("ChunkType is not of type COOKIEACK")
// Cookie ack chunk errors
var (
ErrChunkTypeNotCookieAck = errors.New("ChunkType is not of type COOKIEACK")
)

func (c *chunkCookieAck) unmarshal(raw []byte) error {
if err := c.chunkHeader.unmarshal(raw); err != nil {
return err
}

if c.typ != ctCookieAck {
return fmt.Errorf("%w: actually is %s", errChunkTypeNotCookieAck, c.typ.String())
return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotCookieAck, c.typ.String())
}

return nil
Expand Down
7 changes: 5 additions & 2 deletions chunk_cookie_echo.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@ type chunkCookieEcho struct {
cookie []byte
}

var errChunkTypeNotCookieEcho = errors.New("ChunkType is not of type COOKIEECHO")
// Cookie echo chunk errors
var (
ErrChunkTypeNotCookieEcho = errors.New("ChunkType is not of type COOKIEECHO")
)

func (c *chunkCookieEcho) unmarshal(raw []byte) error {
if err := c.chunkHeader.unmarshal(raw); err != nil {
return err
}

if c.typ != ctCookieEcho {
return fmt.Errorf("%w: actually is %s", errChunkTypeNotCookieEcho, c.typ.String())
return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotCookieEcho, c.typ.String())
}
c.cookie = c.raw

Expand Down
9 changes: 5 additions & 4 deletions chunk_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ type chunkError struct {
errorCauses []errorCause
}

// Error chunk errors
var (
errChunkTypeNotCtError = errors.New("ChunkType is not of type ctError")
errBuildErrorChunkFailed = errors.New("failed build Error Chunk")
ErrChunkTypeNotCtError = errors.New("ChunkType is not of type ctError")
ErrBuildErrorChunkFailed = errors.New("failed build Error Chunk")
)

func (a *chunkError) unmarshal(raw []byte) error {
Expand All @@ -49,7 +50,7 @@ func (a *chunkError) unmarshal(raw []byte) error {
}

if a.typ != ctError {
return fmt.Errorf("%w, actually is %s", errChunkTypeNotCtError, a.typ.String())
return fmt.Errorf("%w, actually is %s", ErrChunkTypeNotCtError, a.typ.String())
}

offset := chunkHeaderSize
Expand All @@ -60,7 +61,7 @@ func (a *chunkError) unmarshal(raw []byte) error {

e, err := buildErrorCause(raw[offset:])
if err != nil {
return fmt.Errorf("%w: %v", errBuildErrorChunkFailed, err)
return fmt.Errorf("%w: %v", ErrBuildErrorChunkFailed, err)
}

offset += int(e.length())
Expand Down
13 changes: 7 additions & 6 deletions chunk_forward_tsn.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ const (
forwardTSNStreamLength = 4
)

// Forward TSN chunk errors
var (
errMarshalStreamFailed = errors.New("failed to marshal stream")
errChunkTooShort = errors.New("chunk too short")
ErrMarshalStreamFailed = errors.New("failed to marshal stream")
ErrChunkTooShort = errors.New("chunk too short")
)

func (c *chunkForwardTSN) unmarshal(raw []byte) error {
Expand All @@ -54,7 +55,7 @@ func (c *chunkForwardTSN) unmarshal(raw []byte) error {
}

if len(c.raw) < newCumulativeTSNLength {
return errChunkTooShort
return ErrChunkTooShort
}

c.newCumulativeTSN = binary.BigEndian.Uint32(c.raw[0:])
Expand All @@ -65,7 +66,7 @@ func (c *chunkForwardTSN) unmarshal(raw []byte) error {
s := chunkForwardTSNStream{}

if err := s.unmarshal(c.raw[offset:]); err != nil {
return fmt.Errorf("%w: %v", errMarshalStreamFailed, err)
return fmt.Errorf("%w: %v", ErrMarshalStreamFailed, err)
}

c.streams = append(c.streams, s)
Expand All @@ -84,7 +85,7 @@ func (c *chunkForwardTSN) marshal() ([]byte, error) {
for _, s := range c.streams {
b, err := s.marshal()
if err != nil {
return nil, fmt.Errorf("%w: %v", errMarshalStreamFailed, err)
return nil, fmt.Errorf("%w: %v", ErrMarshalStreamFailed, err)
}
out = append(out, b...)
}
Expand Down Expand Up @@ -129,7 +130,7 @@ func (s *chunkForwardTSNStream) length() int {

func (s *chunkForwardTSNStream) unmarshal(raw []byte) error {
if len(raw) < forwardTSNStreamLength {
return errChunkTooShort
return ErrChunkTooShort
}
s.identifier = binary.BigEndian.Uint16(raw[0:])
s.sequence = binary.BigEndian.Uint16(raw[2:])
Expand Down
Loading

0 comments on commit c18816d

Please sign in to comment.