From c18816d341d933215c41476257bc2d6fe086cede Mon Sep 17 00:00:00 2001 From: Atsushi Watanabe Date: Fri, 13 Jan 2023 09:53:45 +0900 Subject: [PATCH] Expose error values Make it possible to compare errors using errors.Is(). --- association.go | 88 ++++++++++++++++--------------- chunk_abort.go | 9 ++-- chunk_cookie_ack.go | 7 ++- chunk_cookie_echo.go | 7 ++- chunk_error.go | 9 ++-- chunk_forward_tsn.go | 13 ++--- chunk_heartbeat.go | 23 ++++---- chunk_heartbeat_ack.go | 17 +++--- chunk_init.go | 37 ++++++------- chunk_init_ack.go | 37 ++++++------- chunk_init_common.go | 13 ++--- chunk_payload_data.go | 7 ++- chunk_reconfig.go | 15 +++--- chunk_selective_ack.go | 13 ++--- chunk_shutdown.go | 9 ++-- chunk_shutdown_ack.go | 7 ++- chunk_shutdown_complete.go | 7 ++- chunk_test.go | 6 +-- chunkheader.go | 13 ++--- error_cause.go | 7 ++- error_cause_protocol_violation.go | 7 ++- packet.go | 17 +++--- param.go | 5 +- param_outgoing_reset_request.go | 7 ++- param_reconfig_response.go | 7 ++- param_requested_hmac_algorithm.go | 5 +- paramheader.go | 17 +++--- paramtype.go | 7 ++- pending_queue.go | 17 +++--- stream.go | 17 +++--- vnet_test.go | 2 +- 31 files changed, 251 insertions(+), 201 deletions(-) diff --git a/association.go b/association.go index 91b92fc3..fb0f9ad6 100644 --- a/association.go +++ b/association.go @@ -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 ( @@ -246,7 +248,7 @@ func Server(config Config) (*Association, error) { } return a, nil case <-a.readLoopCloseCh: - return nil, errAssociationClosedBeforeConn + return nil, ErrAssociationClosedBeforeConn } } @@ -262,7 +264,7 @@ func Client(config Config) (*Association, error) { } return a, nil case <-a.readLoopCloseCh: - return nil, errAssociationClosedBeforeConn + return nil, ErrAssociationClosedBeforeConn } } @@ -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"), } @@ -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{} @@ -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) @@ -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. @@ -930,7 +932,7 @@ 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. @@ -938,7 +940,7 @@ func checkPacket(p *packet) error { // 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 @@ -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 } } } @@ -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? @@ -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{} @@ -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 { @@ -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 { @@ -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++ @@ -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. @@ -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)) } @@ -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) } } @@ -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)) } @@ -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 @@ -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 } diff --git a/chunk_abort.go b/chunk_abort.go index 9288412e..702f82de 100644 --- a/chunk_abort.go +++ b/chunk_abort.go @@ -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 { @@ -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 @@ -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()) diff --git a/chunk_cookie_ack.go b/chunk_cookie_ack.go index 742529cb..0bbf2900 100644 --- a/chunk_cookie_ack.go +++ b/chunk_cookie_ack.go @@ -18,7 +18,10 @@ 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 { @@ -26,7 +29,7 @@ func (c *chunkCookieAck) unmarshal(raw []byte) error { } 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 diff --git a/chunk_cookie_echo.go b/chunk_cookie_echo.go index 3aaced3d..e8548ee1 100644 --- a/chunk_cookie_echo.go +++ b/chunk_cookie_echo.go @@ -22,7 +22,10 @@ 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 { @@ -30,7 +33,7 @@ func (c *chunkCookieEcho) unmarshal(raw []byte) error { } 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 diff --git a/chunk_error.go b/chunk_error.go index d58d752c..ec03397c 100644 --- a/chunk_error.go +++ b/chunk_error.go @@ -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 { @@ -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 @@ -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()) diff --git a/chunk_forward_tsn.go b/chunk_forward_tsn.go index 8f04d93f..abadd6d6 100644 --- a/chunk_forward_tsn.go +++ b/chunk_forward_tsn.go @@ -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 { @@ -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:]) @@ -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) @@ -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...) } @@ -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:]) diff --git a/chunk_heartbeat.go b/chunk_heartbeat.go index 7db97cdf..abbd4fc0 100644 --- a/chunk_heartbeat.go +++ b/chunk_heartbeat.go @@ -38,36 +38,37 @@ type chunkHeartbeat struct { params []param } +// Heartbeat chunk errors var ( - errChunkTypeNotHeartbeat = errors.New("ChunkType is not of type HEARTBEAT") - errHeartbeatNotLongEnoughInfo = errors.New("heartbeat is not long enough to contain Heartbeat Info") - errParseParamTypeFailed = errors.New("failed to parse param type") - errHeartbeatParam = errors.New("heartbeat should only have HEARTBEAT param") - errHeartbeatChunkUnmarshal = errors.New("failed unmarshalling param in Heartbeat Chunk") + ErrChunkTypeNotHeartbeat = errors.New("ChunkType is not of type HEARTBEAT") + ErrHeartbeatNotLongEnoughInfo = errors.New("heartbeat is not long enough to contain Heartbeat Info") + ErrParseParamTypeFailed = errors.New("failed to parse param type") + ErrHeartbeatParam = errors.New("heartbeat should only have HEARTBEAT param") + ErrHeartbeatChunkUnmarshal = errors.New("failed unmarshalling param in Heartbeat Chunk") ) func (h *chunkHeartbeat) unmarshal(raw []byte) error { if err := h.chunkHeader.unmarshal(raw); err != nil { return err } else if h.typ != ctHeartbeat { - return fmt.Errorf("%w: actually is %s", errChunkTypeNotHeartbeat, h.typ.String()) + return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotHeartbeat, h.typ.String()) } if len(raw) <= chunkHeaderSize { - return fmt.Errorf("%w: %d", errHeartbeatNotLongEnoughInfo, len(raw)) + return fmt.Errorf("%w: %d", ErrHeartbeatNotLongEnoughInfo, len(raw)) } pType, err := parseParamType(raw[chunkHeaderSize:]) if err != nil { - return fmt.Errorf("%w: %v", errParseParamTypeFailed, err) + return fmt.Errorf("%w: %v", ErrParseParamTypeFailed, err) } if pType != heartbeatInfo { - return fmt.Errorf("%w: instead have %s", errHeartbeatParam, pType.String()) + return fmt.Errorf("%w: instead have %s", ErrHeartbeatParam, pType.String()) } p, err := buildParam(pType, raw[chunkHeaderSize:]) if err != nil { - return fmt.Errorf("%w: %v", errHeartbeatChunkUnmarshal, err) + return fmt.Errorf("%w: %v", ErrHeartbeatChunkUnmarshal, err) } h.params = append(h.params, p) @@ -75,7 +76,7 @@ func (h *chunkHeartbeat) unmarshal(raw []byte) error { } func (h *chunkHeartbeat) Marshal() ([]byte, error) { - return nil, errUnimplemented + return nil, ErrUnimplemented } func (h *chunkHeartbeat) check() (abort bool, err error) { diff --git a/chunk_heartbeat_ack.go b/chunk_heartbeat_ack.go index feb822c2..9e68c714 100644 --- a/chunk_heartbeat_ack.go +++ b/chunk_heartbeat_ack.go @@ -38,34 +38,35 @@ type chunkHeartbeatAck struct { params []param } +// Heartbeat ack chunk errors var ( - errUnimplemented = errors.New("unimplemented") - errHeartbeatAckParams = errors.New("heartbeat Ack must have one param") - errHeartbeatAckNotHeartbeatInfo = errors.New("heartbeat Ack must have one param, and it should be a HeartbeatInfo") - errHeartbeatAckMarshalParam = errors.New("unable to marshal parameter for Heartbeat Ack") + ErrUnimplemented = errors.New("unimplemented") + ErrHeartbeatAckParams = errors.New("heartbeat Ack must have one param") + ErrHeartbeatAckNotHeartbeatInfo = errors.New("heartbeat Ack must have one param, and it should be a HeartbeatInfo") + ErrHeartbeatAckMarshalParam = errors.New("unable to marshal parameter for Heartbeat Ack") ) func (h *chunkHeartbeatAck) unmarshal(raw []byte) error { - return errUnimplemented + return ErrUnimplemented } func (h *chunkHeartbeatAck) marshal() ([]byte, error) { if len(h.params) != 1 { - return nil, errHeartbeatAckParams + return nil, ErrHeartbeatAckParams } switch h.params[0].(type) { case *paramHeartbeatInfo: // ParamHeartbeatInfo is valid default: - return nil, errHeartbeatAckNotHeartbeatInfo + return nil, ErrHeartbeatAckNotHeartbeatInfo } out := make([]byte, 0) for idx, p := range h.params { pp, err := p.marshal() if err != nil { - return nil, fmt.Errorf("%w: %v", errHeartbeatAckMarshalParam, err) + return nil, fmt.Errorf("%w: %v", ErrHeartbeatAckMarshalParam, err) } out = append(out, pp...) diff --git a/chunk_init.go b/chunk_init.go index 8a2a1cda..75341d8d 100644 --- a/chunk_init.go +++ b/chunk_init.go @@ -24,16 +24,17 @@ type chunkInit struct { chunkInitCommon } +// Init chunk errors var ( - errChunkTypeNotTypeInit = errors.New("ChunkType is not of type INIT") - errChunkValueNotLongEnough = errors.New("chunk Value isn't long enough for mandatory parameters exp") - errChunkTypeInitFlagZero = errors.New("ChunkType of type INIT flags must be all 0") - errChunkTypeInitUnmarshalFailed = errors.New("failed to unmarshal INIT body") - errChunkTypeInitMarshalFailed = errors.New("failed marshaling INIT common data") - errChunkTypeInitInitateTagZero = errors.New("ChunkType of type INIT ACK InitiateTag must not be 0") - errInitInboundStreamRequestZero = errors.New("INIT ACK inbound stream request must be > 0") - errInitOutboundStreamRequestZero = errors.New("INIT ACK outbound stream request must be > 0") - errInitAdvertisedReceiver1500 = errors.New("INIT ACK Advertised Receiver Window Credit (a_rwnd) must be >= 1500") + ErrChunkTypeNotTypeInit = errors.New("ChunkType is not of type INIT") + ErrChunkValueNotLongEnough = errors.New("chunk Value isn't long enough for mandatory parameters exp") + ErrChunkTypeInitFlagZero = errors.New("ChunkType of type INIT flags must be all 0") + ErrChunkTypeInitUnmarshalFailed = errors.New("failed to unmarshal INIT body") + ErrChunkTypeInitMarshalFailed = errors.New("failed marshaling INIT common data") + ErrChunkTypeInitInitateTagZero = errors.New("ChunkType of type INIT ACK InitiateTag must not be 0") + ErrInitInboundStreamRequestZero = errors.New("INIT ACK inbound stream request must be > 0") + ErrInitOutboundStreamRequestZero = errors.New("INIT ACK outbound stream request must be > 0") + ErrInitAdvertisedReceiver1500 = errors.New("INIT ACK Advertised Receiver Window Credit (a_rwnd) must be >= 1500") ) func (i *chunkInit) unmarshal(raw []byte) error { @@ -42,20 +43,20 @@ func (i *chunkInit) unmarshal(raw []byte) error { } if i.typ != ctInit { - return fmt.Errorf("%w: actually is %s", errChunkTypeNotTypeInit, i.typ.String()) + return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotTypeInit, i.typ.String()) } else if len(i.raw) < initChunkMinLength { - return fmt.Errorf("%w: %d actual: %d", errChunkValueNotLongEnough, initChunkMinLength, len(i.raw)) + return fmt.Errorf("%w: %d actual: %d", ErrChunkValueNotLongEnough, initChunkMinLength, len(i.raw)) } // The Chunk Flags field in INIT is reserved, and all bits in it should // be set to 0 by the sender and ignored by the receiver. The sequence // of parameters within an INIT can be processed in any order. if i.flags != 0 { - return errChunkTypeInitFlagZero + return ErrChunkTypeInitFlagZero } if err := i.chunkInitCommon.unmarshal(i.raw); err != nil { - return fmt.Errorf("%w: %v", errChunkTypeInitUnmarshalFailed, err) + return fmt.Errorf("%w: %v", ErrChunkTypeInitUnmarshalFailed, err) } return nil @@ -64,7 +65,7 @@ func (i *chunkInit) unmarshal(raw []byte) error { func (i *chunkInit) marshal() ([]byte, error) { initShared, err := i.chunkInitCommon.marshal() if err != nil { - return nil, fmt.Errorf("%w: %v", errChunkTypeInitMarshalFailed, err) + return nil, fmt.Errorf("%w: %v", ErrChunkTypeInitMarshalFailed, err) } i.chunkHeader.typ = ctInit @@ -86,7 +87,7 @@ func (i *chunkInit) check() (abort bool, err error) { // association by transmitting an ABORT. if i.initiateTag == 0 { abort = true - return abort, errChunkTypeInitInitateTagZero + return abort, ErrChunkTypeInitInitateTagZero } // Defines the maximum number of streams the sender of this INIT @@ -101,7 +102,7 @@ func (i *chunkInit) check() (abort bool, err error) { // the association. if i.numInboundStreams == 0 { abort = true - return abort, errInitInboundStreamRequestZero + return abort, ErrInitInboundStreamRequestZero } // Defines the number of outbound streams the sender of this INIT @@ -113,7 +114,7 @@ func (i *chunkInit) check() (abort bool, err error) { if i.numOutboundStreams == 0 { abort = true - return abort, errInitOutboundStreamRequestZero + return abort, ErrInitOutboundStreamRequestZero } // An SCTP receiver MUST be able to receive a minimum of 1500 bytes in @@ -122,7 +123,7 @@ func (i *chunkInit) check() (abort bool, err error) { // ACK. if i.advertisedReceiverWindowCredit < 1500 { abort = true - return abort, errInitAdvertisedReceiver1500 + return abort, ErrInitAdvertisedReceiver1500 } return false, nil diff --git a/chunk_init_ack.go b/chunk_init_ack.go index 02a3344b..ed6dd12a 100644 --- a/chunk_init_ack.go +++ b/chunk_init_ack.go @@ -24,16 +24,17 @@ type chunkInitAck struct { chunkInitCommon } +// Init ack chunk errors var ( - errChunkTypeNotInitAck = errors.New("ChunkType is not of type INIT ACK") - errChunkNotLongEnoughForParams = errors.New("chunk Value isn't long enough for mandatory parameters exp") - errChunkTypeInitAckFlagZero = errors.New("ChunkType of type INIT ACK flags must be all 0") - errInitAckUnmarshalFailed = errors.New("failed to unmarshal INIT body") - errInitCommonDataMarshalFailed = errors.New("failed marshaling INIT common data") - errChunkTypeInitAckInitateTagZero = errors.New("ChunkType of type INIT ACK InitiateTag must not be 0") - errInitAckInboundStreamRequestZero = errors.New("INIT ACK inbound stream request must be > 0") - errInitAckOutboundStreamRequestZero = errors.New("INIT ACK outbound stream request must be > 0") - errInitAckAdvertisedReceiver1500 = errors.New("INIT ACK Advertised Receiver Window Credit (a_rwnd) must be >= 1500") + ErrChunkTypeNotInitAck = errors.New("ChunkType is not of type INIT ACK") + ErrChunkNotLongEnoughForParams = errors.New("chunk Value isn't long enough for mandatory parameters exp") + ErrChunkTypeInitAckFlagZero = errors.New("ChunkType of type INIT ACK flags must be all 0") + ErrInitAckUnmarshalFailed = errors.New("failed to unmarshal INIT body") + ErrInitCommonDataMarshalFailed = errors.New("failed marshaling INIT common data") + ErrChunkTypeInitAckInitateTagZero = errors.New("ChunkType of type INIT ACK InitiateTag must not be 0") + ErrInitAckInboundStreamRequestZero = errors.New("INIT ACK inbound stream request must be > 0") + ErrInitAckOutboundStreamRequestZero = errors.New("INIT ACK outbound stream request must be > 0") + ErrInitAckAdvertisedReceiver1500 = errors.New("INIT ACK Advertised Receiver Window Credit (a_rwnd) must be >= 1500") ) func (i *chunkInitAck) unmarshal(raw []byte) error { @@ -42,20 +43,20 @@ func (i *chunkInitAck) unmarshal(raw []byte) error { } if i.typ != ctInitAck { - return fmt.Errorf("%w: actually is %s", errChunkTypeNotInitAck, i.typ.String()) + return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotInitAck, i.typ.String()) } else if len(i.raw) < initChunkMinLength { - return fmt.Errorf("%w: %d actual: %d", errChunkNotLongEnoughForParams, initChunkMinLength, len(i.raw)) + return fmt.Errorf("%w: %d actual: %d", ErrChunkNotLongEnoughForParams, initChunkMinLength, len(i.raw)) } // The Chunk Flags field in INIT is reserved, and all bits in it should // be set to 0 by the sender and ignored by the receiver. The sequence // of parameters within an INIT can be processed in any order. if i.flags != 0 { - return errChunkTypeInitAckFlagZero + return ErrChunkTypeInitAckFlagZero } if err := i.chunkInitCommon.unmarshal(i.raw); err != nil { - return fmt.Errorf("%w: %v", errInitAckUnmarshalFailed, err) + return fmt.Errorf("%w: %v", ErrInitAckUnmarshalFailed, err) } return nil @@ -64,7 +65,7 @@ func (i *chunkInitAck) unmarshal(raw []byte) error { func (i *chunkInitAck) marshal() ([]byte, error) { initShared, err := i.chunkInitCommon.marshal() if err != nil { - return nil, fmt.Errorf("%w: %v", errInitCommonDataMarshalFailed, err) + return nil, fmt.Errorf("%w: %v", ErrInitCommonDataMarshalFailed, err) } i.chunkHeader.typ = ctInitAck @@ -87,7 +88,7 @@ func (i *chunkInitAck) check() (abort bool, err error) { // purpose. if i.initiateTag == 0 { abort = true - return abort, errChunkTypeInitAckInitateTagZero + return abort, ErrChunkTypeInitAckInitateTagZero } // Defines the maximum number of streams the sender of this INIT ACK @@ -102,7 +103,7 @@ func (i *chunkInitAck) check() (abort bool, err error) { // destroy the association discarding its TCB. if i.numInboundStreams == 0 { abort = true - return abort, errInitAckInboundStreamRequestZero + return abort, ErrInitAckInboundStreamRequestZero } // Defines the number of outbound streams the sender of this INIT ACK @@ -115,7 +116,7 @@ func (i *chunkInitAck) check() (abort bool, err error) { if i.numOutboundStreams == 0 { abort = true - return abort, errInitAckOutboundStreamRequestZero + return abort, ErrInitAckOutboundStreamRequestZero } // An SCTP receiver MUST be able to receive a minimum of 1500 bytes in @@ -124,7 +125,7 @@ func (i *chunkInitAck) check() (abort bool, err error) { // ACK. if i.advertisedReceiverWindowCredit < 1500 { abort = true - return abort, errInitAckAdvertisedReceiver1500 + return abort, ErrInitAckAdvertisedReceiver1500 } return false, nil diff --git a/chunk_init_common.go b/chunk_init_common.go index 14535cab..9730f3c0 100644 --- a/chunk_init_common.go +++ b/chunk_init_common.go @@ -53,10 +53,11 @@ const ( initOptionalVarHeaderLength = 4 ) +// Init chunk errors var ( - errInitChunkParseParamTypeFailed = errors.New("failed to parse param type") - errInitChunkUnmarshalParam = errors.New("failed unmarshalling param in Init Chunk") - errInitAckMarshalParam = errors.New("unable to marshal parameter for INIT/INITACK") + ErrInitChunkParseParamTypeFailed = errors.New("failed to parse param type") + ErrInitChunkUnmarshalParam = errors.New("failed unmarshalling param in Init Chunk") + ErrInitAckMarshalParam = errors.New("unable to marshal parameter for INIT/INITACK") ) func (i *chunkInitCommon) unmarshal(raw []byte) error { @@ -89,11 +90,11 @@ func (i *chunkInitCommon) unmarshal(raw []byte) error { if remaining > initOptionalVarHeaderLength { pType, err := parseParamType(raw[offset:]) if err != nil { - return fmt.Errorf("%w: %v", errInitChunkParseParamTypeFailed, err) + return fmt.Errorf("%w: %v", ErrInitChunkParseParamTypeFailed, err) } p, err := buildParam(pType, raw[offset:]) if err != nil { - return fmt.Errorf("%w: %v", errInitChunkUnmarshalParam, err) + return fmt.Errorf("%w: %v", ErrInitChunkUnmarshalParam, err) } i.params = append(i.params, p) padding := getPadding(p.length()) @@ -117,7 +118,7 @@ func (i *chunkInitCommon) marshal() ([]byte, error) { for idx, p := range i.params { pp, err := p.marshal() if err != nil { - return nil, fmt.Errorf("%w: %v", errInitAckMarshalParam, err) + return nil, fmt.Errorf("%w: %v", ErrInitAckMarshalParam, err) } out = append(out, pp...) diff --git a/chunk_payload_data.go b/chunk_payload_data.go index eecc7c8c..7a98fcb5 100644 --- a/chunk_payload_data.go +++ b/chunk_payload_data.go @@ -97,7 +97,10 @@ const ( PayloadTypeWebRTCBinaryEmpty PayloadProtocolIdentifier = 57 ) -var errChunkPayloadSmall = errors.New("packet is smaller than the header size") +// Data chunk errors +var ( + ErrChunkPayloadSmall = errors.New("packet is smaller than the header size") +) func (p PayloadProtocolIdentifier) String() string { switch p { @@ -127,7 +130,7 @@ func (p *chunkPayloadData) unmarshal(raw []byte) error { p.endingFragment = p.flags&payloadDataEndingFragmentBitmask != 0 if len(raw) < payloadDataHeaderSize { - return errChunkPayloadSmall + return ErrChunkPayloadSmall } p.tsn = binary.BigEndian.Uint32(p.raw[0:]) p.streamIdentifier = binary.BigEndian.Uint16(p.raw[4:]) diff --git a/chunk_reconfig.go b/chunk_reconfig.go index c827a40a..8688b591 100644 --- a/chunk_reconfig.go +++ b/chunk_reconfig.go @@ -28,10 +28,11 @@ type chunkReconfig struct { paramB param } +// Reconfigure chunk errors var ( - errChunkParseParamTypeFailed = errors.New("failed to parse param type") - errChunkMarshalParamAReconfigFailed = errors.New("unable to marshal parameter A for reconfig") - errChunkMarshalParamBReconfigFailed = errors.New("unable to marshal parameter B for reconfig") + ErrChunkParseParamTypeFailed = errors.New("failed to parse param type") + ErrChunkMarshalParamAReconfigFailed = errors.New("unable to marshal parameter A for reconfig") + ErrChunkMarshalParamBReconfigFailed = errors.New("unable to marshal parameter B for reconfig") ) func (c *chunkReconfig) unmarshal(raw []byte) error { @@ -40,7 +41,7 @@ func (c *chunkReconfig) unmarshal(raw []byte) error { } pType, err := parseParamType(c.raw) if err != nil { - return fmt.Errorf("%w: %v", errChunkParseParamTypeFailed, err) + return fmt.Errorf("%w: %v", ErrChunkParseParamTypeFailed, err) } a, err := buildParam(pType, c.raw) if err != nil { @@ -53,7 +54,7 @@ func (c *chunkReconfig) unmarshal(raw []byte) error { if len(c.raw) > offset { pType, err := parseParamType(c.raw[offset:]) if err != nil { - return fmt.Errorf("%w: %v", errChunkParseParamTypeFailed, err) + return fmt.Errorf("%w: %v", ErrChunkParseParamTypeFailed, err) } b, err := buildParam(pType, c.raw[offset:]) if err != nil { @@ -68,7 +69,7 @@ func (c *chunkReconfig) unmarshal(raw []byte) error { func (c *chunkReconfig) marshal() ([]byte, error) { out, err := c.paramA.marshal() if err != nil { - return nil, fmt.Errorf("%w: %v", errChunkMarshalParamAReconfigFailed, err) + return nil, fmt.Errorf("%w: %v", ErrChunkMarshalParamAReconfigFailed, err) } if c.paramB != nil { // Pad param A @@ -76,7 +77,7 @@ func (c *chunkReconfig) marshal() ([]byte, error) { outB, err := c.paramB.marshal() if err != nil { - return nil, fmt.Errorf("%w: %v", errChunkMarshalParamBReconfigFailed, err) + return nil, fmt.Errorf("%w: %v", ErrChunkMarshalParamBReconfigFailed, err) } out = append(out, outB...) diff --git a/chunk_selective_ack.go b/chunk_selective_ack.go index 00f83dba..28223a92 100644 --- a/chunk_selective_ack.go +++ b/chunk_selective_ack.go @@ -46,10 +46,11 @@ type gapAckBlock struct { end uint16 } +// Selective ack chunk errors var ( - errChunkTypeNotSack = errors.New("ChunkType is not of type SACK") - errSackSizeNotLargeEnoughInfo = errors.New("SACK Chunk size is not large enough to contain header") - errSackSizeNotMatchPredicted = errors.New("SACK Chunk size does not match predicted amount from header values") + ErrChunkTypeNotSack = errors.New("ChunkType is not of type SACK") + ErrSackSizeNotLargeEnoughInfo = errors.New("SACK Chunk size is not large enough to contain header") + ErrSackSizeNotMatchPredicted = errors.New("SACK Chunk size does not match predicted amount from header values") ) // String makes gapAckBlock printable @@ -75,11 +76,11 @@ func (s *chunkSelectiveAck) unmarshal(raw []byte) error { } if s.typ != ctSack { - return fmt.Errorf("%w: actually is %s", errChunkTypeNotSack, s.typ.String()) + return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotSack, s.typ.String()) } if len(s.raw) < selectiveAckHeaderSize { - return fmt.Errorf("%w: %v remaining, needs %v bytes", errSackSizeNotLargeEnoughInfo, + return fmt.Errorf("%w: %v remaining, needs %v bytes", ErrSackSizeNotLargeEnoughInfo, len(s.raw), selectiveAckHeaderSize) } @@ -89,7 +90,7 @@ func (s *chunkSelectiveAck) unmarshal(raw []byte) error { s.duplicateTSN = make([]uint32, binary.BigEndian.Uint16(s.raw[10:])) if len(s.raw) != selectiveAckHeaderSize+(4*len(s.gapAckBlocks)+(4*len(s.duplicateTSN))) { - return errSackSizeNotMatchPredicted + return ErrSackSizeNotMatchPredicted } offset := selectiveAckHeaderSize diff --git a/chunk_shutdown.go b/chunk_shutdown.go index be0371a8..bcd9fc15 100644 --- a/chunk_shutdown.go +++ b/chunk_shutdown.go @@ -26,9 +26,10 @@ const ( cumulativeTSNAckLength = 4 ) +// Shutdown chunk errors var ( - errInvalidChunkSize = errors.New("invalid chunk size") - errChunkTypeNotShutdown = errors.New("ChunkType is not of type SHUTDOWN") + ErrInvalidChunkSize = errors.New("invalid chunk size") + ErrChunkTypeNotShutdown = errors.New("ChunkType is not of type SHUTDOWN") ) func (c *chunkShutdown) unmarshal(raw []byte) error { @@ -37,11 +38,11 @@ func (c *chunkShutdown) unmarshal(raw []byte) error { } if c.typ != ctShutdown { - return fmt.Errorf("%w: actually is %s", errChunkTypeNotShutdown, c.typ.String()) + return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotShutdown, c.typ.String()) } if len(c.raw) != cumulativeTSNAckLength { - return errInvalidChunkSize + return ErrInvalidChunkSize } c.cumulativeTSNAck = binary.BigEndian.Uint32(c.raw[0:]) diff --git a/chunk_shutdown_ack.go b/chunk_shutdown_ack.go index f575dbbd..a8bb8d0c 100644 --- a/chunk_shutdown_ack.go +++ b/chunk_shutdown_ack.go @@ -18,7 +18,10 @@ type chunkShutdownAck struct { chunkHeader } -var errChunkTypeNotShutdownAck = errors.New("ChunkType is not of type SHUTDOWN-ACK") +// Shutdown ack chunk errors +var ( + ErrChunkTypeNotShutdownAck = errors.New("ChunkType is not of type SHUTDOWN-ACK") +) func (c *chunkShutdownAck) unmarshal(raw []byte) error { if err := c.chunkHeader.unmarshal(raw); err != nil { @@ -26,7 +29,7 @@ func (c *chunkShutdownAck) unmarshal(raw []byte) error { } if c.typ != ctShutdownAck { - return fmt.Errorf("%w: actually is %s", errChunkTypeNotShutdownAck, c.typ.String()) + return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotShutdownAck, c.typ.String()) } return nil diff --git a/chunk_shutdown_complete.go b/chunk_shutdown_complete.go index 99883f34..4de045d6 100644 --- a/chunk_shutdown_complete.go +++ b/chunk_shutdown_complete.go @@ -18,7 +18,10 @@ type chunkShutdownComplete struct { chunkHeader } -var errChunkTypeNotShutdownComplete = errors.New("ChunkType is not of type SHUTDOWN-COMPLETE") +// Shutdown complete chunk errors +var ( + ErrChunkTypeNotShutdownComplete = errors.New("ChunkType is not of type SHUTDOWN-COMPLETE") +) func (c *chunkShutdownComplete) unmarshal(raw []byte) error { if err := c.chunkHeader.unmarshal(raw); err != nil { @@ -26,7 +29,7 @@ func (c *chunkShutdownComplete) unmarshal(raw []byte) error { } if c.typ != ctShutdownComplete { - return fmt.Errorf("%w: actually is %s", errChunkTypeNotShutdownComplete, c.typ.String()) + return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotShutdownComplete, c.typ.String()) } return nil diff --git a/chunk_test.go b/chunk_test.go index 67088626..349b21a2 100644 --- a/chunk_test.go +++ b/chunk_test.go @@ -102,9 +102,9 @@ func TestInitMarshalUnmarshal(t *testing.T) { initAck.numInboundStreams = 1 initAck.initiateTag = 123 initAck.advertisedReceiverWindowCredit = 1024 - cookie, errRand := newRandomStateCookie() - if errRand != nil { - t.Fatalf("Failed to generate random state cookie: %v", errRand) + cookie, ErrRand := newRandomStateCookie() + if ErrRand != nil { + t.Fatalf("Failed to generate random state cookie: %v", ErrRand) } initAck.params = []param{cookie} diff --git a/chunkheader.go b/chunkheader.go index be2a1226..f6f0d716 100644 --- a/chunkheader.go +++ b/chunkheader.go @@ -33,15 +33,16 @@ const ( chunkHeaderSize = 4 ) +// SCTP chunk header errors var ( - errChunkHeaderTooSmall = errors.New("raw is too small for a SCTP chunk") - errChunkHeaderNotEnoughSpace = errors.New("not enough data left in SCTP packet to satisfy requested length") - errChunkHeaderPaddingNonZero = errors.New("chunk padding is non-zero at offset") + ErrChunkHeaderTooSmall = errors.New("raw is too small for a SCTP chunk") + ErrChunkHeaderNotEnoughSpace = errors.New("not enough data left in SCTP packet to satisfy requested length") + ErrChunkHeaderPaddingNonZero = errors.New("chunk padding is non-zero at offset") ) func (c *chunkHeader) unmarshal(raw []byte) error { if len(raw) < chunkHeaderSize { - return fmt.Errorf("%w: raw only %d bytes, %d is the minimum length", errChunkHeaderTooSmall, len(raw), chunkHeaderSize) + return fmt.Errorf("%w: raw only %d bytes, %d is the minimum length", ErrChunkHeaderTooSmall, len(raw), chunkHeaderSize) } c.typ = chunkType(raw[0]) @@ -53,7 +54,7 @@ func (c *chunkHeader) unmarshal(raw []byte) error { lengthAfterValue := len(raw) - (chunkHeaderSize + valueLength) if lengthAfterValue < 0 { - return fmt.Errorf("%w: remain %d req %d ", errChunkHeaderNotEnoughSpace, valueLength, len(raw)-chunkHeaderSize) + return fmt.Errorf("%w: remain %d req %d ", ErrChunkHeaderNotEnoughSpace, valueLength, len(raw)-chunkHeaderSize) } else if lengthAfterValue < 4 { // https://tools.ietf.org/html/rfc4960#section-3.2 // The Chunk Length field does not count any chunk padding. @@ -67,7 +68,7 @@ func (c *chunkHeader) unmarshal(raw []byte) error { for i := lengthAfterValue; i > 0; i-- { paddingOffset := chunkHeaderSize + valueLength + (i - 1) if raw[paddingOffset] != 0 { - return fmt.Errorf("%w: %d ", errChunkHeaderPaddingNonZero, paddingOffset) + return fmt.Errorf("%w: %d ", ErrChunkHeaderPaddingNonZero, paddingOffset) } } } diff --git a/error_cause.go b/error_cause.go index a511c133..9e5e68d8 100644 --- a/error_cause.go +++ b/error_cause.go @@ -18,7 +18,10 @@ type errorCause interface { errorCauseCode() errorCauseCode } -var errBuildErrorCaseHandle = errors.New("BuildErrorCause does not handle") +// Error and abort chunk errors +var ( + ErrBuildErrorCaseHandle = errors.New("BuildErrorCause does not handle") +) // buildErrorCause delegates the building of a error cause from raw bytes to the correct structure func buildErrorCause(raw []byte) (errorCause, error) { @@ -35,7 +38,7 @@ func buildErrorCause(raw []byte) (errorCause, error) { case userInitiatedAbort: e = &errorCauseUserInitiatedAbort{} default: - return nil, fmt.Errorf("%w: %s", errBuildErrorCaseHandle, c.String()) + return nil, fmt.Errorf("%w: %s", ErrBuildErrorCaseHandle, c.String()) } if err := e.unmarshal(raw); err != nil { diff --git a/error_cause_protocol_violation.go b/error_cause_protocol_violation.go index 3379ea24..b6136852 100644 --- a/error_cause_protocol_violation.go +++ b/error_cause_protocol_violation.go @@ -27,7 +27,10 @@ type errorCauseProtocolViolation struct { additionalInformation []byte } -var errProtocolViolationUnmarshal = errors.New("unable to unmarshal Protocol Violation error") +// Abort chunk errors +var ( + ErrProtocolViolationUnmarshal = errors.New("unable to unmarshal Protocol Violation error") +) func (e *errorCauseProtocolViolation) marshal() ([]byte, error) { e.raw = e.additionalInformation @@ -37,7 +40,7 @@ func (e *errorCauseProtocolViolation) marshal() ([]byte, error) { func (e *errorCauseProtocolViolation) unmarshal(raw []byte) error { err := e.errorCauseHeader.unmarshal(raw) if err != nil { - return fmt.Errorf("%w: %v", errProtocolViolationUnmarshal, err) + return fmt.Errorf("%w: %v", ErrProtocolViolationUnmarshal, err) } e.additionalInformation = e.raw diff --git a/packet.go b/packet.go index f1765adb..1c17e696 100644 --- a/packet.go +++ b/packet.go @@ -59,16 +59,17 @@ const ( packetHeaderSize = 12 ) +// SCTP packet errors var ( - errPacketRawTooSmall = errors.New("raw is smaller than the minimum length for a SCTP packet") - errParseSCTPChunkNotEnoughData = errors.New("unable to parse SCTP chunk, not enough data for complete header") - errUnmarshalUnknownChunkType = errors.New("failed to unmarshal, contains unknown chunk type") - errChecksumMismatch = errors.New("checksum mismatch theirs") + ErrPacketRawTooSmall = errors.New("raw is smaller than the minimum length for a SCTP packet") + ErrParseSCTPChunkNotEnoughData = errors.New("unable to parse SCTP chunk, not enough data for complete header") + ErrUnmarshalUnknownChunkType = errors.New("failed to unmarshal, contains unknown chunk type") + ErrChecksumMismatch = errors.New("checksum mismatch theirs") ) func (p *packet) unmarshal(raw []byte) error { if len(raw) < packetHeaderSize { - return fmt.Errorf("%w: raw only %d bytes, %d is the minimum length", errPacketRawTooSmall, len(raw), packetHeaderSize) + return fmt.Errorf("%w: raw only %d bytes, %d is the minimum length", ErrPacketRawTooSmall, len(raw), packetHeaderSize) } p.sourcePort = binary.BigEndian.Uint16(raw[0:]) @@ -81,7 +82,7 @@ func (p *packet) unmarshal(raw []byte) error { if offset == len(raw) { break } else if offset+chunkHeaderSize > len(raw) { - return fmt.Errorf("%w: offset %d remaining %d", errParseSCTPChunkNotEnoughData, offset, len(raw)) + return fmt.Errorf("%w: offset %d remaining %d", ErrParseSCTPChunkNotEnoughData, offset, len(raw)) } var c chunk @@ -115,7 +116,7 @@ func (p *packet) unmarshal(raw []byte) error { case ctShutdownComplete: c = &chunkShutdownComplete{} default: - return fmt.Errorf("%w: %s", errUnmarshalUnknownChunkType, chunkType(raw[offset]).String()) + return fmt.Errorf("%w: %s", ErrUnmarshalUnknownChunkType, chunkType(raw[offset]).String()) } if err := c.unmarshal(raw[offset:]); err != nil { @@ -129,7 +130,7 @@ func (p *packet) unmarshal(raw []byte) error { theirChecksum := binary.LittleEndian.Uint32(raw[8:]) ourChecksum := generatePacketChecksum(raw) if theirChecksum != ourChecksum { - return fmt.Errorf("%w: %d ours: %d", errChecksumMismatch, theirChecksum, ourChecksum) + return fmt.Errorf("%w: %d ours: %d", ErrChecksumMismatch, theirChecksum, ourChecksum) } return nil } diff --git a/param.go b/param.go index b7887c5b..a2393534 100644 --- a/param.go +++ b/param.go @@ -10,7 +10,8 @@ type param interface { length() int } -var errParamTypeUnhandled = errors.New("unhandled ParamType") +// ErrParamTypeUnhandled is returned if unknown parameter type is specified. +var ErrParamTypeUnhandled = errors.New("unhandled ParamType") func buildParam(t paramType, rawParam []byte) (param, error) { switch t { @@ -35,6 +36,6 @@ func buildParam(t paramType, rawParam []byte) (param, error) { case reconfigResp: return (¶mReconfigResponse{}).unmarshal(rawParam) default: - return nil, fmt.Errorf("%w: %v", errParamTypeUnhandled, t) + return nil, fmt.Errorf("%w: %v", ErrParamTypeUnhandled, t) } } diff --git a/param_outgoing_reset_request.go b/param_outgoing_reset_request.go index ceae1789..8ec0bf6c 100644 --- a/param_outgoing_reset_request.go +++ b/param_outgoing_reset_request.go @@ -52,7 +52,10 @@ type paramOutgoingResetRequest struct { streamIdentifiers []uint16 } -var errSSNResetRequestParamTooShort = errors.New("outgoing SSN reset request parameter too short") +// Outgoing reset request parameter errors +var ( + ErrSSNResetRequestParamTooShort = errors.New("outgoing SSN reset request parameter too short") +) func (r *paramOutgoingResetRequest) marshal() ([]byte, error) { r.typ = outSSNResetReq @@ -72,7 +75,7 @@ func (r *paramOutgoingResetRequest) unmarshal(raw []byte) (param, error) { return nil, err } if len(r.raw) < paramOutgoingResetRequestStreamIdentifiersOffset { - return nil, errSSNResetRequestParamTooShort + return nil, ErrSSNResetRequestParamTooShort } r.reconfigRequestSequenceNumber = binary.BigEndian.Uint32(r.raw) r.reconfigResponseSequenceNumber = binary.BigEndian.Uint32(r.raw[4:]) diff --git a/param_reconfig_response.go b/param_reconfig_response.go index d9eab551..e3bfab5a 100644 --- a/param_reconfig_response.go +++ b/param_reconfig_response.go @@ -45,7 +45,10 @@ const ( reconfigResultInProgress reconfigResult = 6 ) -var errReconfigRespParamTooShort = errors.New("reconfig response parameter too short") +// Reconfiguration response errors +var ( + ErrReconfigRespParamTooShort = errors.New("reconfig response parameter too short") +) func (t reconfigResult) String() string { switch t { @@ -83,7 +86,7 @@ func (r *paramReconfigResponse) unmarshal(raw []byte) (param, error) { return nil, err } if len(r.raw) < 8 { - return nil, errReconfigRespParamTooShort + return nil, ErrReconfigRespParamTooShort } r.reconfigResponseSequenceNumber = binary.BigEndian.Uint32(r.raw) r.result = reconfigResult(binary.BigEndian.Uint32(r.raw[4:])) diff --git a/param_requested_hmac_algorithm.go b/param_requested_hmac_algorithm.go index 895f3d75..d546af88 100644 --- a/param_requested_hmac_algorithm.go +++ b/param_requested_hmac_algorithm.go @@ -15,7 +15,8 @@ const ( hmacSHA256 hmacAlgorithm = 3 ) -var errInvalidAlgorithmType = errors.New("invalid algorithm type") +// ErrInvalidAlgorithmType is returned if unknown auth algorithm is specified. +var ErrInvalidAlgorithmType = errors.New("invalid algorithm type") func (c hmacAlgorithm) String() string { switch c { @@ -64,7 +65,7 @@ func (r *paramRequestedHMACAlgorithm) unmarshal(raw []byte) (param, error) { case hmacSHA256: r.availableAlgorithms = append(r.availableAlgorithms, a) default: - return nil, fmt.Errorf("%w: %v", errInvalidAlgorithmType, a) + return nil, fmt.Errorf("%w: %v", ErrInvalidAlgorithmType, a) } i += 2 diff --git a/paramheader.go b/paramheader.go index f814d461..2f4a4640 100644 --- a/paramheader.go +++ b/paramheader.go @@ -17,11 +17,12 @@ const ( paramHeaderLength = 4 ) +// Parameter header parse errors var ( - errParamHeaderTooShort = errors.New("param header too short") - errParamHeaderSelfReportedLengthShorter = errors.New("param self reported length is shorter than header length") - errParamHeaderSelfReportedLengthLonger = errors.New("param self reported length is longer than header length") - errParamHeaderParseFailed = errors.New("failed to parse param type") + ErrParamHeaderTooShort = errors.New("param header too short") + ErrParamHeaderSelfReportedLengthShorter = errors.New("param self reported length is shorter than header length") + ErrParamHeaderSelfReportedLengthLonger = errors.New("param self reported length is longer than header length") + ErrParamHeaderParseFailed = errors.New("failed to parse param type") ) func (p *paramHeader) marshal() ([]byte, error) { @@ -37,20 +38,20 @@ func (p *paramHeader) marshal() ([]byte, error) { func (p *paramHeader) unmarshal(raw []byte) error { if len(raw) < paramHeaderLength { - return errParamHeaderTooShort + return ErrParamHeaderTooShort } paramLengthPlusHeader := binary.BigEndian.Uint16(raw[2:]) if int(paramLengthPlusHeader) < paramHeaderLength { - return fmt.Errorf("%w: param self reported length (%d) shorter than header length (%d)", errParamHeaderSelfReportedLengthShorter, int(paramLengthPlusHeader), paramHeaderLength) + return fmt.Errorf("%w: param self reported length (%d) shorter than header length (%d)", ErrParamHeaderSelfReportedLengthShorter, int(paramLengthPlusHeader), paramHeaderLength) } if len(raw) < int(paramLengthPlusHeader) { - return fmt.Errorf("%w: param length (%d) shorter than its self reported length (%d)", errParamHeaderSelfReportedLengthLonger, len(raw), int(paramLengthPlusHeader)) + return fmt.Errorf("%w: param length (%d) shorter than its self reported length (%d)", ErrParamHeaderSelfReportedLengthLonger, len(raw), int(paramLengthPlusHeader)) } typ, err := parseParamType(raw[0:]) if err != nil { - return fmt.Errorf("%w: %v", errParamHeaderParseFailed, err) + return fmt.Errorf("%w: %v", ErrParamHeaderParseFailed, err) } p.typ = typ p.raw = raw[paramHeaderLength:paramLengthPlusHeader] diff --git a/paramtype.go b/paramtype.go index 9fe2cf14..2db73dde 100644 --- a/paramtype.go +++ b/paramtype.go @@ -39,11 +39,14 @@ const ( adaptLayerInd paramType = 49158 // Adaptation Layer Indication (0xC006) [RFC5061] ) -var errParamPacketTooShort = errors.New("packet to short") +// Parameter packet errors +var ( + ErrParamPacketTooShort = errors.New("packet to short") +) func parseParamType(raw []byte) (paramType, error) { if len(raw) < 2 { - return paramType(0), errParamPacketTooShort + return paramType(0), ErrParamPacketTooShort } return paramType(binary.BigEndian.Uint16(raw)), nil } diff --git a/pending_queue.go b/pending_queue.go index a6e1a7a5..8082cf52 100644 --- a/pending_queue.go +++ b/pending_queue.go @@ -48,10 +48,11 @@ type pendingQueue struct { unorderedIsSelected bool } +// Pending queue errors var ( - errUnexpectedChuckPoppedUnordered = errors.New("unexpected chunk popped (unordered)") - errUnexpectedChuckPoppedOrdered = errors.New("unexpected chunk popped (ordered)") - errUnexpectedQState = errors.New("unexpected q state (should've been selected)") + ErrUnexpectedChuckPoppedUnordered = errors.New("unexpected chunk popped (unordered)") + ErrUnexpectedChuckPoppedOrdered = errors.New("unexpected chunk popped (ordered)") + ErrUnexpectedQState = errors.New("unexpected q state (should've been selected)") ) func newPendingQueue() *pendingQueue { @@ -90,12 +91,12 @@ func (q *pendingQueue) pop(c *chunkPayloadData) error { if q.unorderedIsSelected { popped = q.unorderedQueue.pop() if popped != c { - return errUnexpectedChuckPoppedUnordered + return ErrUnexpectedChuckPoppedUnordered } } else { popped = q.orderedQueue.pop() if popped != c { - return errUnexpectedChuckPoppedOrdered + return ErrUnexpectedChuckPoppedOrdered } } if popped.endingFragment { @@ -103,12 +104,12 @@ func (q *pendingQueue) pop(c *chunkPayloadData) error { } } else { if !c.beginningFragment { - return errUnexpectedQState + return ErrUnexpectedQState } if c.unordered { popped := q.unorderedQueue.pop() if popped != c { - return errUnexpectedChuckPoppedUnordered + return ErrUnexpectedChuckPoppedUnordered } if !popped.endingFragment { q.selected = true @@ -117,7 +118,7 @@ func (q *pendingQueue) pop(c *chunkPayloadData) error { } else { popped := q.orderedQueue.pop() if popped != c { - return errUnexpectedChuckPoppedOrdered + return ErrUnexpectedChuckPoppedOrdered } if !popped.endingFragment { q.selected = true diff --git a/stream.go b/stream.go index fd2c5fc7..43038ee1 100644 --- a/stream.go +++ b/stream.go @@ -45,10 +45,11 @@ func (ss StreamState) String() string { return "unknown" } +// SCTP stream errors var ( - errOutboundPacketTooLarge = errors.New("outbound packet larger than maximum message size") - errStreamClosed = errors.New("stream closed") - errReadDeadlineExceeded = fmt.Errorf("read deadline exceeded: %w", os.ErrDeadlineExceeded) + ErrOutboundPacketTooLarge = errors.New("outbound packet larger than maximum message size") + ErrStreamClosed = errors.New("stream closed") + ErrReadDeadlineExceeded = fmt.Errorf("read deadline exceeded: %w", os.ErrDeadlineExceeded) ) // Stream represents an SCTP stream @@ -155,7 +156,7 @@ func (s *Stream) SetReadDeadline(deadline time.Time) error { } if s.readErr != nil { - if !errors.Is(s.readErr, errReadDeadlineExceeded) { + if !errors.Is(s.readErr, ErrReadDeadlineExceeded) { return nil } s.readErr = nil @@ -173,7 +174,7 @@ func (s *Stream) SetReadDeadline(deadline time.Time) error { case <-t.C: s.lock.Lock() if s.readErr == nil { - s.readErr = errReadDeadlineExceeded + s.readErr = ErrReadDeadlineExceeded } s.readTimeoutCancel = nil s.lock.Unlock() @@ -257,18 +258,18 @@ func (s *Stream) Write(p []byte) (n int, err error) { func (s *Stream) WriteSCTP(p []byte, ppi PayloadProtocolIdentifier) (int, error) { maxMessageSize := s.association.MaxMessageSize() if len(p) > int(maxMessageSize) { - return 0, fmt.Errorf("%w: %v", errOutboundPacketTooLarge, math.MaxUint16) + return 0, fmt.Errorf("%w: %v", ErrOutboundPacketTooLarge, math.MaxUint16) } if s.State() != StreamStateOpen { - return 0, errStreamClosed + return 0, ErrStreamClosed } chunks := s.packetize(p, ppi) n := len(p) err := s.association.sendPayloadData(chunks) if err != nil { - return n, errStreamClosed + return n, ErrStreamClosed } return n, nil } diff --git a/vnet_test.go b/vnet_test.go index 996f495e..058bc242 100644 --- a/vnet_test.go +++ b/vnet_test.go @@ -542,7 +542,7 @@ func TestStreamClose(t *testing.T) { _, err = stream.Write([]byte{1}) - assert.Equal(t, err, errStreamClosed, "after closed should not allow write") + assert.Equal(t, err, ErrStreamClosed, "after closed should not allow write") // Check if RECONFIG was actually dropped assert.Equal(t, 0, venv.numToDropReconfig, "should be zero")