Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues reported by golangsci-lint #574

Merged
merged 2 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions message/codes/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"errors"
"fmt"
"strconv"

"github.com/plgd-dev/go-coap/v3/pkg/math"
)

// A Code is an unsigned 16-bit coap code as defined in the coap spec.
Expand Down Expand Up @@ -94,14 +96,15 @@ var strToCode = map[string]Code{
}

func getMaxCodeLen() int {
// max uint32 as string binary representation: "0b" + 32 digits
max := 34
// maxLen uint32 as string binary representation: "0b" + 32 digits
maxLen := 34
for k := range strToCode {
if len(k) > max {
max = len(k)
kLen := len(k)
if kLen > maxLen {
maxLen = kLen
}
}
return max
return maxLen
}

func init() {
Expand All @@ -128,8 +131,7 @@ func (c *Code) UnmarshalJSON(b []byte) error {
if ci >= _maxCode {
return fmt.Errorf("invalid code: %q", ci)
}

*c = Code(ci)
*c = math.CastTo[Code](ci)
return nil
}

Expand Down
4 changes: 3 additions & 1 deletion message/encodeDecodeUint32.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package message

import (
"encoding/binary"

"github.com/plgd-dev/go-coap/v3/pkg/math"
)

func EncodeUint32(buf []byte, value uint32) (int, error) {
Expand All @@ -18,7 +20,7 @@ func EncodeUint32(buf []byte, value uint32) (int, error) {
if len(buf) < 2 {
return 2, ErrTooSmall
}
binary.BigEndian.PutUint16(buf, uint16(value))
binary.BigEndian.PutUint16(buf, math.CastTo[uint16](value))
return 2, nil
case value <= max3ByteNumber:
if len(buf) < 3 {
Expand Down
7 changes: 4 additions & 3 deletions message/getmid.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"sync/atomic"
"time"

pkgMath "github.com/plgd-dev/go-coap/v3/pkg/math"
pkgRand "github.com/plgd-dev/go-coap/v3/pkg/rand"
)

Expand All @@ -16,17 +17,17 @@ var msgID = uint32(RandMID())

// GetMID generates a message id for UDP. (0 <= mid <= 65535)
func GetMID() int32 {
return int32(uint16(atomic.AddUint32(&msgID, 1)))
return int32(pkgMath.CastTo[uint16](atomic.AddUint32(&msgID, 1)))
}

func RandMID() int32 {
b := make([]byte, 4)
_, err := rand.Read(b)
if err != nil {
// fallback to cryptographically insecure pseudo-random generator
return int32(uint16(weakRng.Uint32() >> 16))
return int32(pkgMath.CastTo[uint16](weakRng.Uint32() >> 16))
}
return int32(uint16(binary.BigEndian.Uint32(b)))
return int32(pkgMath.CastTo[uint16](binary.BigEndian.Uint32(b)))
}

// ValidateMID validates a message id for UDP. (0 <= mid <= 65535)
Expand Down
20 changes: 18 additions & 2 deletions message/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"encoding/binary"
"errors"
"strconv"

"github.com/plgd-dev/go-coap/v3/pkg/math"
"golang.org/x/exp/constraints"
)

const (
Expand Down Expand Up @@ -236,6 +239,18 @@ func ToMediaType(v string) (MediaType, error) {
return 0, errors.New("not found")
}

func MediaTypeFromNumber[T constraints.Integer](v T) (MediaType, error) {
mt, err := math.SafeCastTo[MediaType](v)
if err != nil {
return MediaType(0), err
}
_, ok := mediaTypeToString[mt]
if !ok {
return MediaType(0), errors.New("invalid value")
}
return mt, nil
}

func extendOpt(opt int) (int, int) {
ext := 0
if opt >= ExtendOptionByteAddend {
Expand Down Expand Up @@ -269,7 +284,7 @@ func marshalOptionHeaderExt(buf []byte, opt, ext int) (int, error) {
return 1, ErrTooSmall
case ExtendOptionWordCode:
if len(buf) > 1 {
binary.BigEndian.PutUint16(buf, uint16(ext))
binary.BigEndian.PutUint16(buf, math.CastTo[uint16](ext))
return 2, nil
}
return 2, ErrTooSmall
Expand Down Expand Up @@ -435,7 +450,8 @@ func (o *Option) Unmarshal(data []byte, optionDefs map[OptionID]OptionDef, optio
// Skip unrecognized options (RFC7252 section 5.4.1)
return len(data), nil
}
if uint32(len(data)) < def.MinLen || uint32(len(data)) > def.MaxLen {
dataLen := math.CastTo[uint32](len(data))
if dataLen < def.MinLen || dataLen > def.MaxLen {
// Skip options with illegal value length (RFC7252 section 5.4.3)
return len(data), nil
}
Expand Down
12 changes: 9 additions & 3 deletions message/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package message

import (
"errors"
"fmt"
"strings"

"github.com/plgd-dev/go-coap/v3/pkg/math"
)

// Options Container of COAP Options, It must be always sort'ed after modification.
Expand Down Expand Up @@ -207,7 +210,7 @@ func (options Options) GetUint32(id OptionID) (uint32, error) {
// ContentFormat gets the content format of body.
func (options Options) ContentFormat() (MediaType, error) {
v, err := options.GetUint32(ContentFormat)
return MediaType(v), err
return math.CastTo[MediaType](v), err
}

// GetString gets the string value of the first option with the given ID.
Expand Down Expand Up @@ -353,7 +356,7 @@ func (options Options) SetAccept(buf []byte, contentFormat MediaType) (Options,
// Accept gets accept option.
func (options Options) Accept() (MediaType, error) {
v, err := options.GetUint32(Accept)
return MediaType(v), err
return math.CastTo[MediaType](v), err
}

// Find returns range of type options. First number is index and second number is index of next option type.
Expand Down Expand Up @@ -576,7 +579,10 @@ func (options *Options) Unmarshal(data []byte, optionDefs map[OptionID]OptionDef
}

option := Option{}
oid := OptionID(prev + delta)
oid, err := math.SafeCastTo[OptionID](prev + delta)
if err != nil {
return -1, fmt.Errorf("%w: %w", ErrOptionNotFound, err)
}
proc, err = option.Unmarshal(data[:length], optionDefs, oid)
if err != nil {
return -1, err
Expand Down
9 changes: 5 additions & 4 deletions message/pool/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/go-coap/v3/message/codes"
"github.com/plgd-dev/go-coap/v3/net"
"github.com/plgd-dev/go-coap/v3/pkg/math"
"go.uber.org/atomic"
)

Expand Down Expand Up @@ -373,7 +374,7 @@ func (r *Message) AddOptionUint32(opt message.OptionID, value uint32) {

func (r *Message) ContentFormat() (message.MediaType, error) {
v, err := r.GetOptionUint32(message.ContentFormat)
return message.MediaType(v), err
return math.CastTo[message.MediaType](v), err
}

func (r *Message) HasOption(id message.OptionID) bool {
Expand All @@ -392,15 +393,15 @@ func (r *Message) Observe() (uint32, error) {
return r.GetOptionUint32(message.Observe)
}

// SetAccept set's accept option.
// SetAccept sets accept option.
func (r *Message) SetAccept(contentFormat message.MediaType) {
r.SetOptionUint32(message.Accept, uint32(contentFormat))
}

// Accept get's accept option.
// Accept gets accept option.
func (r *Message) Accept() (message.MediaType, error) {
v, err := r.GetOptionUint32(message.Accept)
return message.MediaType(v), err
return math.CastTo[message.MediaType](v), err
}

func (r *Message) BodySize() (int64, error) {
Expand Down
25 changes: 17 additions & 8 deletions net/blockwise/blockwise.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/plgd-dev/go-coap/v3/message/pool"
"github.com/plgd-dev/go-coap/v3/net/responsewriter"
"github.com/plgd-dev/go-coap/v3/pkg/cache"
"github.com/plgd-dev/go-coap/v3/pkg/math"
"golang.org/x/sync/semaphore"
)

Expand Down Expand Up @@ -98,13 +99,13 @@ func EncodeBlockOption(szx SZX, blockNumber int64, moreBlocksFollowing bool) (ui
if blockNumber > maxBlockNumber {
return 0, ErrBlockNumberExceedLimit
}
blockVal := uint32(blockNumber << 4)
blockVal := math.CastTo[uint32](blockNumber << 4)
m := uint32(0)
if moreBlocksFollowing {
m = 1
}
blockVal += m << 3
blockVal += uint32(szx)
blockVal += math.CastTo[uint32](szx)
return blockVal, nil
}

Expand All @@ -115,7 +116,7 @@ func DecodeBlockOption(blockVal uint32) (szx SZX, blockNumber int64, moreBlocksF
return
}

szx = SZX(blockVal & szxMask) // masking for the SZX
szx = math.CastTo[SZX](blockVal & szxMask) // masking for the SZX
if (blockVal & moreBlocksFollowingMask) != 0 { // masking for the "M"
moreBlocksFollowing = true
}
Expand Down Expand Up @@ -238,7 +239,11 @@ func (b *BlockWise[C]) Do(r *pool.Message, maxSzx SZX, maxMessageSize uint32, do
}
req := b.cloneMessage(r)
defer b.cc.ReleaseMessage(req)
req.SetOptionUint32(message.Size1, uint32(payloadSize))
payloadSizeUint32, err := math.SafeCastTo[uint32](payloadSize)
if err != nil {
return nil, fmt.Errorf("cannot set payload size: %w", err)
}
req.SetOptionUint32(message.Size1, payloadSizeUint32)
block, err := EncodeBlockOption(maxSzx, 0, true)
if err != nil {
return nil, fmt.Errorf("cannot encode block option(%v, %v, %v) to bw request: %w", maxSzx, 0, true, err)
Expand Down Expand Up @@ -436,9 +441,7 @@ func (b *BlockWise[C]) createSendingMessage(sendingMessage *pool.Message, maxSZX
b.cc.ReleaseMessage(sendMessage)
return nil, false, payloadSizeError(err)
}
if szx > maxSZX {
szx = maxSZX
}
szx = getSzx(szx, maxSZX)
newBufLen := bufferSize(szx, maxMessageSize)
off := num * szx.Size()
if blockType == message.Block1 {
Expand Down Expand Up @@ -471,13 +474,19 @@ func (b *BlockWise[C]) createSendingMessage(sendingMessage *pool.Message, maxSZX
return nil, false, fmt.Errorf("cannot read response: %w", err)
}

payloadSizeUint32, err := math.SafeCastTo[uint32](payloadSize)
if err != nil {
b.cc.ReleaseMessage(sendMessage)
return nil, false, fmt.Errorf("cannot set payload size: %w", err)
}
sendMessage.SetOptionUint32(sizeType, payloadSizeUint32)

buf = buf[:readed]
sendMessage.SetBody(bytes.NewReader(buf))
more = true
if offSeek+int64(readed) == payloadSize {
more = false
}
sendMessage.SetOptionUint32(sizeType, uint32(payloadSize))
num = (offSeek) / szx.Size()
block, err = EncodeBlockOption(szx, num, more)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions options/commonOptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (o MuxHandlerOpt) UDPClientApply(cfg *udpClient.Config) {
cfg.Handler = mux.ToHandler[*udpClient.Conn](o.m)
}

// WithMux set's multiplexer for handle requests.
// WithMux sets multiplexer for handle requests.
func WithMux(m mux.Handler) MuxHandlerOpt {
return MuxHandlerOpt{
m: m,
Expand Down Expand Up @@ -148,7 +148,7 @@ func (o ContextOpt) UDPClientApply(cfg *udpClient.Config) {
cfg.Ctx = o.ctx
}

// WithContext set's parent context of server.
// WithContext sets parent context of server.
func WithContext(ctx context.Context) ContextOpt {
return ContextOpt{ctx: ctx}
}
Expand Down
61 changes: 61 additions & 0 deletions pkg/math/cast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package math

import (
"fmt"
"log"
"reflect"
"unsafe"

"golang.org/x/exp/constraints"
)

// Max returns maximal value for given integer type
func Max[T constraints.Integer]() T {
size := unsafe.Sizeof(T(0))
switch reflect.TypeOf((*T)(nil)).Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return T(1<<(size*8-1) - 1) // 2^(n-1) - 1 for signed integers
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return T(1<<(size*8) - 1) // 2^n - 1 for unsigned integers
default:
panic("unsupported type")
}
}

// Min returns minimal value for given integer type
func Min[T constraints.Integer]() T {
size := unsafe.Sizeof(T(0))
switch reflect.TypeOf((*T)(nil)).Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return T(int64(-1) << (size*8 - 1)) // -2^(n-1)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return T(0)
default:
panic("unsupported type")
}
}

// CastTo casts one integer type to another with bounds checking and returns error in case of overflow
func SafeCastTo[T, F constraints.Integer](from F) (T, error) {
if from > 0 && uint64(Max[T]()) < uint64(from) {
return T(0), fmt.Errorf("value(%v) exceeds the maximum value for type(%v)", from, Max[T]())
}
if from < 0 && int64(Min[T]()) > int64(from) {
return T(0), fmt.Errorf("value(%v) exceeds the minimum value for type(%v)", from, Min[T]())
}
return T(from), nil
}

// CastTo casts one integer type to another without bounds checking
func CastTo[T, F constraints.Integer](from F) T {
return T(from)
}

// MustSafeCastTo casts one integer type to another with bounds checking and panics in case of overflow
func MustSafeCastTo[T, F constraints.Integer](from F) T {
to, err := SafeCastTo[T](from)
if err != nil {
log.Panicf("value (%v) out of bounds for type %T", from, T(0))
}
return to
}
Loading
Loading