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 1 commit
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
18 changes: 15 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,10 @@ 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
if err != nil {
return MediaType(0), err
}
return MediaTypeFromNumber(v)
}

// GetString gets the string value of the first option with the given ID.
Expand Down Expand Up @@ -353,7 +359,10 @@ 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
if err != nil {
return MediaType(0), err
}
return MediaTypeFromNumber(v)
}

// 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 +585,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
10 changes: 8 additions & 2 deletions message/pool/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,10 @@ 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
if err != nil {
return message.MediaType(0), err
}
return message.MediaTypeFromNumber(v)
}

func (r *Message) HasOption(id message.OptionID) bool {
Expand All @@ -400,7 +403,10 @@ func (r *Message) SetAccept(contentFormat message.MediaType) {
// Accept get's accept option.
func (r *Message) Accept() (message.MediaType, error) {
v, err := r.GetOptionUint32(message.Accept)
return message.MediaType(v), err
if err != nil {
return message.MediaType(0), err
}
return message.MediaTypeFromNumber(v)
}

func (r *Message) BodySize() (int64, error) {
Expand Down
23 changes: 16 additions & 7 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 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
56 changes: 56 additions & 0 deletions pkg/math/cast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package math

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

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

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")
}
}

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")
}
}

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
}

func CastTo[T, F constraints.Integer](from F) T {
return T(from)
}

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